]> mj.ucw.cz Git - arexx.git/blobdiff - arexxd.c
Clear all librrd errors by calling rrd_clear_error()
[arexx.git] / arexxd.c
index 8030c0377cbc6c2aed623ad6fc8d7d8832030101..0358db145ba9d1d36953c9123f7f71c61918a486 100644 (file)
--- a/arexxd.c
+++ b/arexxd.c
@@ -29,6 +29,7 @@ static int use_syslog;
 static int debug_mode;
 static int debug_packets;
 static int debug_raw_data;
+static int debug_usb;
 static char *log_dir = DEFAULT_LOG_DIR;
 
 static void die(char *fmt, ...)
@@ -112,10 +113,10 @@ static void arg_push(const char *fmt, ...)
        arg_pos += len;
 }
 
-static void rrd_point(time_t t, int id, double val, char *unit)
+static void rrd_point(time_t t, const char *name, double val, char *unit)
 {
        char rr_name[256];
-       snprintf(rr_name, sizeof(rr_name), "sensor-%d.rrd", id);
+       snprintf(rr_name, sizeof(rr_name), "sensor-%s.rrd", name);
 
        struct stat st;
        if (stat(rr_name, &st) < 0 || !st.st_size) {
@@ -140,6 +141,7 @@ static void rrd_point(time_t t, int id, double val, char *unit)
                rrd_create(arg_cnt, arg_ptr);
                if (rrd_test_error()) {
                        log_error("rrd_create on %s failed: %s", rr_name, rrd_get_error());
+                       rrd_clear_error();
                        return;
                }
        }
@@ -148,28 +150,39 @@ static void rrd_point(time_t t, int id, double val, char *unit)
        arg_push(rr_name);
        arg_push("%d:%f", t, val);
        rrd_update(arg_cnt, arg_ptr);
-       if (rrd_test_error())
+       if (rrd_test_error()) {
                log_error("rrd_update on %s failed: %s", rr_name, rrd_get_error());
+               rrd_clear_error();
+       }
 }
 
 /*** Transforms ***/
 
 #define TIME_OFFSET 946681200          // Timestamp of 2000-01-01 00:00:00
 
-static int data_point_counter;
+static int data_point_counter;         // Since last log message
 
-static double correct_point(int id, double val)
+static double correct_point(int id, double val, const char **name)
 {
        /*
-        *  Manually calculated corrections for my sensors.
+        *  Manually calculated corrections and renames for my sensors.
         *  Replace with your formulae.
         */
        switch (id) {
                case 10415:
+                       *name = "ursarium";
                        return val - 0.93;
+               case 10707:
+                       *name = "balcony";
+                       return val - 0.71;
                case 19246:
+                       *name = "catarium";
                        return val + 0.49;
+               case 19247:
+                       *name = "catarium-rh";
+                       return val;
                case 12133:
+                       *name = "outside";
                        return val + 0.44;
                default:
                        return val;
@@ -178,18 +191,22 @@ static double correct_point(int id, double val)
 
 static void cooked_point(time_t t, int id, double val, char *unit, int q)
 {
-       double val2 = correct_point(id, val);
+       char namebuf[16];
+       snprintf(namebuf, sizeof(namebuf), "%d", id);
+       const char *name = namebuf;
+
+       double val2 = correct_point(id, val, &name);
 
        if (debug_raw_data) {
                struct tm tm;
                localtime_r(&t, &tm);
                char tbuf[64];
                strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", &tm);
-               printf("== %s id=%d val=%.3f val2=%.3f unit=%s q=%d\n", tbuf, id, val, val2, unit, q);
+               printf("== %s id=%d name=%s val=%.3f val2=%.3f unit=%s q=%d\n", tbuf, id, name, val, val2, unit, q);
        }
 
        data_point_counter++;
-       rrd_point(t, id, val2, unit);
+       rrd_point(t, name, val2, unit);
 }
 
 static void raw_point(int t, int id, int raw, int q)
@@ -286,6 +303,56 @@ static void raw_point(int t, int id, int raw, int q)
 
 /*** USB interface ***/
 
+static int rx_endpoint, tx_endpoint;
+
+static int parse_descriptors(libusb_device *dev)
+{
+       int err;
+       struct libusb_config_descriptor *desc;
+
+       if (err = libusb_get_active_config_descriptor(dev, &desc)) {
+               log_error("libusb_get_config_descriptor failed: error %d", err);
+               return 0;
+       }
+       if (desc->bNumInterfaces != 1) {
+               log_error("Unexpected number of interfaces: %d", desc->bNumInterfaces);
+               goto failed;
+       }
+
+       const struct libusb_interface *iface = &desc->interface[0];
+       if (iface->num_altsetting != 1) {
+               log_error("Unexpected number of alternate interface settings: %d", iface->num_altsetting);
+               goto failed;
+       }
+
+       const struct libusb_interface_descriptor *ifd = &iface->altsetting[0];
+       if (ifd->bNumEndpoints != 2) {
+               log_error("Unexpected number of endpoints: %d", ifd->bNumEndpoints);
+               goto failed;
+       }
+
+       rx_endpoint = tx_endpoint = -1;
+       for (int i=0; i<2; i++) {
+               const struct libusb_endpoint_descriptor *epd = &ifd->endpoint[i];
+               if (epd->bEndpointAddress & 0x80)
+                       rx_endpoint = epd->bEndpointAddress;
+               else
+                       tx_endpoint = epd->bEndpointAddress;
+       }
+       if (rx_endpoint < 0 || tx_endpoint < 0) {
+               log_error("Failed to identify endpoints");
+               goto failed;
+       }
+
+       log_pkt("Found endpoints: rx==%02x tx=%02x\n", rx_endpoint, tx_endpoint);
+       libusb_free_config_descriptor(desc);
+       return 1;
+
+failed:
+       libusb_free_config_descriptor(desc);
+       return 0;
+}
+
 static int find_device(void)
 {
        libusb_device **devlist;
@@ -301,6 +368,8 @@ static int find_device(void)
                if (!libusb_get_device_descriptor(dev, &desc)) {
                        if (desc.idVendor == 0x0451 && desc.idProduct == 0x3211) {
                                log_info("Arexx data logger found at usb%d.%d", libusb_get_bus_number(dev), libusb_get_device_address(dev));
+                               if (!parse_descriptors(dev))
+                                       continue;
                                int err;
                                if (err = libusb_open(dev, &devh)) {
                                        log_error("libusb_open() failed: error %d", err);
@@ -324,6 +393,8 @@ failed:
 
 static void release_device(void)
 {
+       libusb_release_interface(devh, 0);
+       libusb_reset_device(devh);
        libusb_close(devh);
        devh = NULL;
 }
@@ -352,7 +423,7 @@ static int send_and_receive(byte *req, byte *reply)
        }
 
        int err, transferred;
-       if (err = libusb_bulk_transfer(devh, 0x01, req, 64, &transferred, 200)) {
+       if (err = libusb_bulk_transfer(devh, tx_endpoint, req, 64, &transferred, 200)) {
                if (err == LIBUSB_ERROR_TIMEOUT) {
                        log_pkt(">> xmit timed out\n");
                        return 0;
@@ -365,7 +436,7 @@ static int send_and_receive(byte *req, byte *reply)
                log_pkt(">> xmit %d bytes\n", transferred);
                dump_packet(req);
        }
-       if (err = libusb_bulk_transfer(devh, 0x81, reply, 64, &transferred, 200)) {
+       if (err = libusb_bulk_transfer(devh, rx_endpoint, reply, 64, &transferred, 200)) {
                if (err == LIBUSB_ERROR_TIMEOUT) {
                        log_pkt("<< recv timed out\n");
                        return 0;
@@ -473,6 +544,7 @@ static void set_clock(void)
 
 /*** Main ***/
 
+static sigset_t term_sigs;
 static volatile sig_atomic_t want_shutdown;
 
 static void sigterm_handler(int sig __attribute__((unused)))
@@ -480,6 +552,14 @@ static void sigterm_handler(int sig __attribute__((unused)))
        want_shutdown = 1;
 }
 
+static void interruptible_msleep(int ms)
+{
+       sigprocmask(SIG_UNBLOCK, &term_sigs, NULL);
+       struct timespec ts = { .tv_sec = ms/1000, .tv_nsec = (ms%1000) * 1000000 };
+       nanosleep(&ts, NULL);
+       sigprocmask(SIG_BLOCK, &term_sigs, NULL);
+}
+
 static const struct option long_options[] = {
        { "debug",              0, NULL, 'd' },
        { "log-dir",            1, NULL, 'l' },
@@ -498,6 +578,7 @@ Options:\n\
 -l, --log-dir=<dir>    Directory where all received data should be stored\n\
 -p, --debug-packets    Log all packets sent and received\n\
 -r, --debug-raw                Log conversion from raw values\n\
+-u, --debug-usb                Enable libusb debug messages (to stdout/stderr)\n\
 ");
        exit(1);
 }
@@ -505,7 +586,7 @@ Options:\n\
 int main(int argc, char **argv)
 {
        int opt;
-       while ((opt = getopt_long(argc, argv, "dl:pr", long_options, NULL)) >= 0)
+       while ((opt = getopt_long(argc, argv, "dl:pru", long_options, NULL)) >= 0)
                switch (opt) {
                        case 'd':
                                debug_mode++;
@@ -519,6 +600,9 @@ int main(int argc, char **argv)
                        case 'r':
                                debug_raw_data++;
                                break;
+                       case 'u':
+                               debug_usb++;
+                               break;
                        default:
                                usage();
                }
@@ -528,7 +612,8 @@ int main(int argc, char **argv)
        int err;
        if (err = libusb_init(&usb_ctxt))
                die("Cannot initialize libusb: error %d", err);
-       // libusb_set_debug(usb_ctxt, 3);
+       if (debug_usb)
+               libusb_set_debug(usb_ctxt, 3);
 
        if (!debug_mode) {
                if (chdir(log_dir) < 0)
@@ -553,7 +638,6 @@ int main(int argc, char **argv)
        sigaction(SIGTERM, &sa, NULL);
        sigaction(SIGINT, &sa, NULL);
 
-       sigset_t term_sigs;
        sigemptyset(&term_sigs);
        sigaddset(&term_sigs, SIGTERM);
        sigaddset(&term_sigs, SIGINT);
@@ -566,7 +650,7 @@ int main(int argc, char **argv)
                                inited = 1;
                                log_error("Data logger not connected, waiting until it appears");
                        }
-                       sleep(30);
+                       interruptible_msleep(30000);
                        continue;
                }
                log_info("Listening");
@@ -598,17 +682,17 @@ int main(int argc, char **argv)
                        want_sleep = 1;
                        if (err > 0 && parse_packet(reply))
                                want_sleep = 0;
-                       sigprocmask(SIG_UNBLOCK, &term_sigs, NULL);
                        if (want_sleep) {
-                               sleep(4);
+                               interruptible_msleep(4000);
                                want_stats = 1;
-                       }
-                       sigprocmask(SIG_BLOCK, &term_sigs, NULL);
+                       } else
+                               interruptible_msleep(5);
                }
 
                log_info("Disconnecting data logger");
                release_device();
                inited = 0;
+               interruptible_msleep(10000);
        }
 
        log_info("Terminated");