From: Martin Mares Date: Sun, 14 May 2023 12:35:03 +0000 (+0200) Subject: Clock: A new daemon X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=a9d52ef421c6de4507ec8d294665e55fc83bfe49;p=home-hw.git Clock: A new daemon --- diff --git a/clock/host/Makefile b/clock/host/Makefile index 18c9d41..17f6a95 100644 --- a/clock/host/Makefile +++ b/clock/host/Makefile @@ -1,13 +1,21 @@ -UCWCF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --cflags libucw) -UCWLF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --libs libucw) +PC=pkg-config +UCW_CFLAGS := $(shell $(PC) --cflags libucw) +UCW_LIBS := $(shell $(PC) --libs libucw) +USB_CFLAGS := $(shell $(PC) --cflags libusb-1.0) +USB_LIBS := $(shell $(PC) --libs libusb-1.0) +UCW_USB = ../../ucw-libusb -CFLAGS=-std=gnu99 -O2 -Wall -Wextra -Wno-parentheses $(UCWCF) -LDLIBS=-lusb-1.0 $(UCWLF) +CFLAGS=-O2 -Wall -Wextra -Wno-parentheses $(UCW_CFLAGS) $(USB_CFLAGS) -I$(UCW_USB) +LDLIBS=$(UCW_LIBS) $(USB_LIBS) -lmosquitto all: burrow-clock -burrow-clock: burrow-clock.c -burrow-clock: LDLIBS += -lmosquitto +burrow-clock: burrow-clock.o usb-mainloop.o usb-helper.o + +burrow-clock.o: burrow-clock.c $(UCW_USB)/usb-helper.h + +%.o: $(UCW_USB)/%.c $(UCW_USB)/usb-mainloop.h $(UCW_USB)/usb-helper.h + $(CC) $(CFLAGS) -c -o $@ $< install: all install burrow-clock /usr/local/sbin/ diff --git a/clock/host/burrow-clock.c b/clock/host/burrow-clock.c index 4055743..d0a99de 100644 --- a/clock/host/burrow-clock.c +++ b/clock/host/burrow-clock.c @@ -1,9 +1,11 @@ /* - * MJ's desktop clock daemon + * MJ's Workshop Clock Daemon * - * (c) 2018 Martin Mares + * (c) 2023 Martin Mares */ +#define LOCAL_DEBUG + #include #include #include @@ -19,36 +21,22 @@ #include #include -static struct mosquitto *mosq; +#include "usb-helper.h" -struct libusb_context *usb_ctxt; -struct libusb_device_handle *devh; +struct device { + struct usb_dev *usb; -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); - } + struct libusb_transfer *rx_transfer, *tx_transfer; + bool rx_in_flight, tx_in_flight; - for (ssize_t i=0; iport); + + struct device *dev = xmalloc_zero(sizeof(*dev)); + u->device = dev; + dev->usb = u; + + dev->rx_transfer = libusb_alloc_transfer(0); + dev->tx_transfer = libusb_alloc_transfer(0); + + dev->clock_timer.handler = clock_timer_handler; + dev->clock_timer.data = dev; + + return true; +} + +void usb_dev_connect(struct usb_dev *u) +{ + struct device *dev = u->device; + USB_DBG(u, "Connected!"); + + timer_add_rel(&dev->clock_timer, 0); + rx_submit(dev); +} + +void usb_dev_cancel(struct usb_dev *u) +{ + struct device *dev = u->device; + USB_DBG(u, "Cancelling transfers"); + + if (dev->rx_in_flight) + libusb_cancel_transfer(dev->rx_transfer); + if (dev->tx_in_flight) + libusb_cancel_transfer(dev->tx_transfer); + + timer_del(&dev->clock_timer); +} + +bool usb_dev_in_flight(struct usb_dev *u) +{ + struct device *dev = u->device; + return dev->rx_in_flight || dev->tx_in_flight; +} + +void usb_dev_cleanup(struct usb_dev *u) +{ + struct device *dev = u->device; + msg(L_INFO, "Disconnected clock at %s", u->port); + + libusb_free_transfer(dev->rx_transfer); + libusb_free_transfer(dev->tx_transfer); +} + +static void tx_callback(struct libusb_transfer *xfer) +{ + struct device *dev = xfer->user_data; + struct usb_dev *u = dev->usb; + + USB_DBG(u, "Bulk TX done (status=%d, len=%d/%d)", xfer->status, xfer->actual_length, xfer->length); + dev->tx_in_flight = false; + + if (xfer->status != LIBUSB_TRANSFER_COMPLETED) + usb_error(u, "Bulk TX transfer failed with status %d", xfer->status); +} + +static void clock_timer_handler(struct main_timer *timer) +{ + struct device *dev = timer->data; + struct usb_dev *u = dev->usb; + msg(L_DEBUG, "Clock tick"); + + if (dev->tx_in_flight) { + msg(L_ERROR, "Transfer overrun"); + timer_add_rel(timer, 1000); + } + + time_t t = time(NULL); + struct tm *tm = localtime(&t); + + unsigned char req[8] = { + tm->tm_hour / 10, + tm->tm_hour % 10, + tm->tm_min / 10, + tm->tm_min % 10, + (tm->tm_sec % 2 ? 0xff : 0), + }; + + libusb_fill_bulk_transfer(dev->tx_transfer, u->devh, 0x01, req, sizeof(req), tx_callback, dev, 5000); + + int err; + if (err = libusb_submit_transfer(dev->tx_transfer)) + usb_error(u, "Cannot submit bulk TX transfer: error %d", err); + else + dev->tx_in_flight = true; + + timer_add_rel(timer, 1000); +} + +static void rx_callback(struct libusb_transfer *xfer) +{ + struct device *dev = xfer->user_data; + struct usb_dev *u = dev->usb; + + USB_DBG(u, "Bulk RX done (status=%d, len=%d/%d)", xfer->status, xfer->actual_length, xfer->length); + dev->rx_in_flight = false; + + if (xfer->status == LIBUSB_TRANSFER_TIMED_OUT) { + // Should not happen + rx_submit(dev); + return; + } + + if (xfer->status != LIBUSB_TRANSFER_COMPLETED) { + usb_error(u, "Bulk RX transfer failed with status %d", xfer->status); + return; + } + + if (xfer->actual_length < 4) { + msg(L_ERROR, "Short RX transfer"); + } else { + u32 key = get_u32_be(dev->rx_buffer); + msg(L_INFO, "IR key %08x", key); + } + + rx_submit(dev); +} + +static void rx_submit(struct device *dev) +{ + struct usb_dev *u = dev->usb; + + libusb_fill_bulk_transfer(dev->rx_transfer, u->devh, 0x82, dev->rx_buffer, sizeof(dev->rx_buffer), rx_callback, dev, 0); + + int err; + if (err = libusb_submit_transfer(dev->rx_transfer)) + usb_error(u, "Cannot submit bulk RX transfer: error %d", err); + else + dev->rx_in_flight = true; +} + +/*** Main loop ***/ + 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("A daemon for controlling MJ's workshop clock"), 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 @@ -90,76 +243,13 @@ 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_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", 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) && press) { - 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++; - } + mqtt_init(); + main_init(); + usb_helper_init(0x4242, 0x0007); + main_loop(); return 0; }