]> mj.ucw.cz Git - arexx.git/blobdiff - arexxd.c
Web: Cleanup
[arexx.git] / arexxd.c
index 6e301a05e0617b5d2055c40548bb98d48848497d..8879d2b8f3888c5503731ea51bcb3b483e3966e7 100644 (file)
--- a/arexxd.c
+++ b/arexxd.c
@@ -1,7 +1,7 @@
 /*
  *     Linux Interfece for Arexx Data Loggers
  *
- *     (c) 2011 Martin Mares <mj@ucw.cz>
+ *     (c) 2011-2012 Martin Mares <mj@ucw.cz>
  */
 
 #include <stdio.h>
 #include <time.h>
 #include <getopt.h>
 #include <syslog.h>
-#include <pwd.h>
-#include <grp.h>
+#include <signal.h>
 #include <sys/stat.h>
 #include <libusb-1.0/libusb.h>
 #include <rrd.h>
 
-#define LOG_PATH "/var/log/arexxd"
+#define DEFAULT_LOG_DIR "/var/log/arexxd"
 
 typedef unsigned char byte;
 static libusb_context *usb_ctxt;
@@ -30,6 +29,7 @@ static int use_syslog;
 static int debug_mode;
 static int debug_packets;
 static int debug_raw_data;
+static char *log_dir = DEFAULT_LOG_DIR;
 
 static void die(char *fmt, ...)
 {
@@ -83,7 +83,6 @@ static void log_pkt(char *fmt, ...)
 
 /*** RRD interface ***/
 
-#define SLOT_SIZE 10                                   // 10 seconds per averaging slot
 #define MAX_ARGS 20
 #define MAX_ARG_SIZE 1024
 
@@ -113,10 +112,10 @@ static void arg_push(const char *fmt, ...)
        arg_pos += len;
 }
 
-static void rrd_point(time_t t, int id, double val)
+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) {
@@ -128,9 +127,16 @@ static void rrd_point(time_t t, int id, double val)
                arg_push("%d", (int) time(NULL) - 28*86400);
                arg_push("--step");
                arg_push("60");
-               arg_push("DS:temp:GAUGE:300:0:10000");          // Anything over 10 kW is considered a ghost
+               if (!strcmp(unit, "%RH"))
+                       arg_push("DS:rh:GAUGE:300:0:100");
+               else if (!strcmp(unit, "ppm"))
+                       arg_push("DS:ppm:GAUGE:300:0:1000000");
+               else
+                       arg_push("DS:temp:GAUGE:300:-200:200");
                arg_push("RRA:AVERAGE:0.25:1:20160");           // Last 14 days with full resolution
                arg_push("RRA:AVERAGE:0.25:60:88800");          // Last 10 years with 1h resolution
+               arg_push("RRA:MIN:0.25:60:88800");              // including minima and maxima
+               arg_push("RRA:MAX:0.25:60:88800");
                rrd_create(arg_cnt, arg_ptr);
                if (rrd_test_error()) {
                        log_error("rrd_create on %s failed: %s", rr_name, rrd_get_error());
@@ -150,18 +156,50 @@ static void rrd_point(time_t t, int id, double val)
 
 #define TIME_OFFSET 946681200          // Timestamp of 2000-01-01 00:00:00
 
-static void cooked_point(time_t t, int id, double val, char *unit, int q)
-{
-       struct tm tm;
-       localtime_r(&t, &tm);
+static int data_point_counter;         // Since last log message
 
-       char tbuf[64];
-       strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", &tm);
+static double correct_point(int id, double val, const char **name)
+{
+       /*
+        *  Manually calculated corrections and renames for my sensors.
+        *  Replace with your formulae.
+        */
+       switch (id) {
+               case 10415:
+                       *name = "ursarium";
+                       return val - 0.93;
+               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;
+       }
+}
 
-       if (debug_raw_data)
-               printf("== %s id=%d val=%.3f unit=%s q=%d\n", tbuf, id, val, unit, q);
+static void cooked_point(time_t t, int id, double val, char *unit, int q)
+{
+       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 name=%s val=%.3f val2=%.3f unit=%s q=%d\n", tbuf, id, name, val, val2, unit, q);
+       }
 
-       rrd_point(t, id, val);
+       data_point_counter++;
+       rrd_point(t, name, val2, unit);
 }
 
 static void raw_point(int t, int id, int raw, int q)
@@ -272,7 +310,7 @@ static int find_device(void)
                libusb_device *dev = devlist[i];
                if (!libusb_get_device_descriptor(dev, &desc)) {
                        if (desc.idVendor == 0x0451 && desc.idProduct == 0x3211) {
-                               log_info("Arexx USB receiver found at usb%d.%d", libusb_get_bus_number(dev), libusb_get_device_address(dev));
+                               log_info("Arexx data logger found at usb%d.%d", libusb_get_bus_number(dev), libusb_get_device_address(dev));
                                int err;
                                if (err = libusb_open(dev, &devh)) {
                                        log_error("libusb_open() failed: error %d", err);
@@ -313,12 +351,23 @@ static void dump_packet(byte *pkt)
 
 static int send_and_receive(byte *req, byte *reply)
 {
+       if (debug_packets) {
+               time_t t = time(NULL);
+               struct tm tm;
+               localtime_r(&t, &tm);
+
+               char tbuf[64];
+               strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", &tm);
+               log_pkt("## %s\n", tbuf);
+       }
+
        int err, transferred;
        if (err = libusb_bulk_transfer(devh, 0x01, req, 64, &transferred, 200)) {
                if (err == LIBUSB_ERROR_TIMEOUT) {
                        log_pkt(">> xmit timed out\n");
                        return 0;
                }
+               log_pkt(">> xmit error %d\n", err);
                log_error("Transmit error: %d", err);
                return err;
        }
@@ -328,9 +377,10 @@ static int send_and_receive(byte *req, byte *reply)
        }
        if (err = libusb_bulk_transfer(devh, 0x81, reply, 64, &transferred, 200)) {
                if (err == LIBUSB_ERROR_TIMEOUT) {
-                       log_pkt(">> recv timed out\n");
+                       log_pkt("<< recv timed out\n");
                        return 0;
                }
+               log_pkt("<< recv error %d\n", err);
                log_error("Receive error: %d", err);
                return err;
        }
@@ -412,8 +462,6 @@ static int parse_packet(byte *reply)
 
 static void set_clock(void)
 {
-       log_info("Synchronizing receiver time");
-
        byte req[64], reply[64];
        memset(req, 0, 64);
        req[0] = 4;
@@ -435,28 +483,50 @@ static void set_clock(void)
 
 /*** Main ***/
 
+static volatile sig_atomic_t want_shutdown;
+
+static void sigterm_handler(int sig __attribute__((unused)))
+{
+       want_shutdown = 1;
+}
+
 static const struct option long_options[] = {
        { "debug",              0, NULL, 'd' },
-       { "log-packets",        0, NULL, 'p' },
+       { "log-dir",            1, NULL, 'l' },
+       { "debug-packets",      0, NULL, 'p' },
+       { "debug-raw",          0, NULL, 'r' },
        { NULL,                 0, NULL, 0 },
 };
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: arexxd [--debug] [--log-packets]\n");
+       fprintf(stderr, "\n\
+Usage: arexxd <options>\n\
+\n\
+Options:\n\
+-d, --debug            Debug mode (no chdir, no fork, no syslog)\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\
+");
        exit(1);
 }
 
 int main(int argc, char **argv)
 {
        int opt;
-       while ((opt = getopt_long(argc, argv, "dp", long_options, NULL)) >= 0)
+       while ((opt = getopt_long(argc, argv, "dl:pr", long_options, NULL)) >= 0)
                switch (opt) {
                        case 'd':
                                debug_mode++;
                                break;
+                       case 'l':
+                               log_dir = optarg;
+                               break;
                        case 'p':
                                debug_packets++;
+                               break;
+                       case 'r':
                                debug_raw_data++;
                                break;
                        default:
@@ -471,8 +541,8 @@ int main(int argc, char **argv)
        // libusb_set_debug(usb_ctxt, 3);
 
        if (!debug_mode) {
-               if (chdir(LOG_PATH) < 0)
-                       die("Cannot change directory to %s: %m", LOG_PATH);
+               if (chdir(log_dir) < 0)
+                       die("Cannot change directory to %s: %m", log_dir);
                if (debug_packets || debug_raw_data) {
                        close(1);
                        if (open("debug", O_WRONLY | O_CREAT | O_APPEND, 0666) < 0)
@@ -489,40 +559,68 @@ int main(int argc, char **argv)
                use_syslog = 1;
        }
 
+       struct sigaction sa = { .sa_handler = sigterm_handler };
+       sigaction(SIGTERM, &sa, NULL);
+       sigaction(SIGINT, &sa, NULL);
+
+       sigset_t term_sigs;
+       sigemptyset(&term_sigs);
+       sigaddset(&term_sigs, SIGTERM);
+       sigaddset(&term_sigs, SIGINT);
+       sigprocmask(SIG_BLOCK, &term_sigs, NULL);
+
        int inited = 0;
-       for (;;) {
+       while (!want_shutdown) {
                if (!find_device()) {
                        if (!inited) {
                                inited = 1;
-                               log_error("Receiver not connected, waiting until it appears");
+                               log_error("Data logger not connected, waiting until it appears");
                        }
                        sleep(30);
                        continue;
                }
-
-               inited = 1;
-
-               int sync_in = 0;
-               for (;;) {
-                       if (!sync_in) {
+               log_info("Listening");
+
+               time_t last_sync = 0;
+               time_t last_show = 0;
+               int want_stats = 0;
+               int want_sleep = 0;
+               data_point_counter = 0;
+               while (!want_shutdown) {
+                       time_t now = time(NULL);
+                       if (now > last_sync + 900) {
+                               log_info("Synchronizing data logger time");
                                set_clock();
-                               sync_in = 100;
+                               last_sync = now;
                        }
+                       if (want_stats && now > last_show + 300) {
+                               log_info("Stats: received %d data points", data_point_counter);
+                               data_point_counter = 0;
+                               last_show = now;
+                       }
+
                        byte req[64], reply[64];
                        memset(req, 0, sizeof(req));
                        req[0] = 3;
                        err = send_and_receive(req, reply);
                        if (err < 0)
                                break;
+                       want_sleep = 1;
                        if (err > 0 && parse_packet(reply))
-                               continue;
-                       sleep(4);
-                       sync_in--;
+                               want_sleep = 0;
+                       sigprocmask(SIG_UNBLOCK, &term_sigs, NULL);
+                       if (want_sleep) {
+                               sleep(4);
+                               want_stats = 1;
+                       }
+                       sigprocmask(SIG_BLOCK, &term_sigs, NULL);
                }
 
-               log_info("Disconnecting receiver");
+               log_info("Disconnecting data logger");
                release_device();
+               inited = 0;
        }
 
+       log_info("Terminated");
        return 0;
 }