--- /dev/null
+/*
+ * MJ's desktop clock daemon
+ *
+ * (c) 2018 Martin Mares <mj@ucw.cz>
+ */
+
+#include <ucw/lib.h>
+#include <ucw/log.h>
+#include <ucw/opt.h>
+#include <ucw/unaligned.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <libusb-1.0/libusb.h>
+#include <mosquitto.h>
+
+static struct mosquitto *mosq;
+
+struct libusb_context *usb_ctxt;
+struct libusb_device_handle *devh;
+
+static libusb_device *find_device(void)
+{
+ libusb_device **devlist;
+ ssize_t devn = libusb_get_device_list(usb_ctxt, &devlist);
+ if (devn < 0) {
+ fprintf(stderr, "Cannot enumerate USB devices: error %d\n", (int) devn);
+ exit(1);
+ }
+
+ for (ssize_t i=0; i<devn; i++) {
+ struct libusb_device_descriptor desc;
+ libusb_device *dev = devlist[i];
+ if (!libusb_get_device_descriptor(dev, &desc)) {
+ if (desc.idVendor == 0x4242 && desc.idProduct == 0x0001) {
+ msg(L_INFO, "Found device at usb%d.%d\n", libusb_get_bus_number(dev), libusb_get_device_address(dev));
+ // FIXME: Free device list
+ return dev;
+ }
+ }
+ }
+
+ libusb_free_device_list(devlist, 1);
+ fprintf(stderr, "Device not found\n");
+ exit(1);
+}
+
+static void mqtt_publish(const char *topic, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ char m[256];
+ int l = vsnprintf(m, sizeof(m), fmt, args);
+ if (mosquitto_publish(mosq, NULL, topic, l, m, 0, true) != MOSQ_ERR_SUCCESS)
+ msg(L_ERROR, "Mosquitto: publish failed");
+ va_end(args);
+}
+
+static void mqtt_conn_callback(struct mosquitto *mosq UNUSED, void *obj UNUSED, int status)
+{
+ if (!status) {
+ msg(L_DEBUG, "MQTT: Connection established");
+ mqtt_publish("status/clock", "ok");
+ }
+}
+
+static int use_daemon;
+static int use_debug;
+
+static struct opt_section options = {
+ OPT_ITEMS {
+ OPT_HELP("A daemon for controlling the solid state relay module via MQTT"),
+ OPT_HELP(""),
+ OPT_HELP("Options:"),
+ OPT_BOOL('d', "debug", use_debug, 0, "\tLog debugging messages"),
+ OPT_BOOL(0, "daemon", use_daemon, 0, "\tDaemonize"),
+ OPT_HELP_OPTION,
+ OPT_CONF_OPTIONS,
+ OPT_END
+ }
+};
+
+int main(int argc UNUSED, char **argv)
+{
+ log_init(argv[0]);
+ opt_parse(&options, argv+1);
+
+ if (use_daemon) {
+ struct log_stream *ls = log_new_syslog("daemon", LOG_PID);
+ log_set_default_stream(ls);
+ }
+ if (!use_debug)
+ log_default_stream()->levels &= ~(1U << L_DEBUG);
+
+ mosquitto_lib_init();
+ mosq = mosquitto_new("clock", 1, NULL);
+ if (!mosq)
+ die("Mosquitto: initialization failed");
+
+ mosquitto_connect_callback_set(mosq, mqtt_conn_callback);
+
+ if (mosquitto_will_set(mosq, "status/clock", 4, "dead", 0, true) != MOSQ_ERR_SUCCESS)
+ die("Mosquitto: unable to set will");
+
+ if (mosquitto_connect_async(mosq, "10.32.184.5", 1883, 60) != MOSQ_ERR_SUCCESS)
+ die("Mosquitto: connect failed");
+
+ if (mosquitto_loop_start(mosq))
+ die("Mosquitto: cannot start service thread");
+
+ int err;
+ if (err = libusb_init(&usb_ctxt))
+ die("Cannot initialize libusb: error %d", err);
+ libusb_set_debug(usb_ctxt, 3);
+
+ libusb_device *dev = find_device();
+
+ if (err = libusb_open(dev, &devh))
+ die("Cannot open device: error %d", err);
+ libusb_reset_device(devh);
+ if (err = libusb_claim_interface(devh, 0))
+ die("Cannot claim interface: error %d", err);
+
+ uint cnt = 0;
+ for (;;) {
+ time_t t = time(NULL);
+ struct tm *tm = localtime(&t);
+
+ unsigned char req[8] = {
+ tm->tm_hour / 10,
+ tm->tm_hour % 10,
+ (tm->tm_sec % 2 ? 10 : 0xff),
+ tm->tm_min / 10,
+ tm->tm_min % 10,
+ };
+ int transferred;
+ if (err = libusb_bulk_transfer(devh, 0x01, req, 8, &transferred, 2000))
+ die("Transfer failed: error %d", err);
+
+ unsigned char resp[64];
+ int received;
+ if (err = libusb_bulk_transfer(devh, 0x82, resp, 64, &received, 2000))
+ die("Receive failed: error %d\n", err);
+ // printf("Received %d bytes\n", received);
+ if (received >= 12) {
+ int temp = get_u32_be(resp);
+ int press = get_u32_be(resp + 4);
+ uint cycle = get_u32_be(resp + 8);
+ msg(L_DEBUG, "Temperature %d ddegC, pressure %d Pa, cycle %u", temp, press, cycle);
+ if (!(cnt % 10)) {
+ mqtt_publish("burrow/temp/clock", "%.1f %llu", temp / 10., (long long) t);
+ mqtt_publish("burrow/pressure/clock", "%d %llu", press, (long long) t);
+ }
+ }
+
+ sleep(1);
+ cnt++;
+ }
+
+ return 0;
+}