]> mj.ucw.cz Git - home-hw.git/commitdiff
Clock firmware and host daemon
authorMartin Mares <mj@ucw.cz>
Sun, 23 Feb 2020 11:11:15 +0000 (12:11 +0100)
committerMartin Mares <mj@ucw.cz>
Sun, 23 Feb 2020 11:11:15 +0000 (12:11 +0100)
clock/README [new file with mode: 0644]
clock/firmware/Makefile [new file with mode: 0644]
clock/firmware/config.h [new file with mode: 0644]
clock/firmware/kerm [new file with mode: 0644]
clock/firmware/main.c [new file with mode: 0644]
clock/host/Makefile [new file with mode: 0644]
clock/host/burrow-clock.c [new file with mode: 0644]
clock/host/test.c [new file with mode: 0644]

diff --git a/clock/README b/clock/README
new file mode 100644 (file)
index 0000000..8252003
--- /dev/null
@@ -0,0 +1,31 @@
+Assignment of peripherals and pins
+==================================
+
+I2C1   BMP085
+I2C2   display
+USART1 debugging
+
+
+                          Blue Pill pinout
+                       +--------------------+
+                       | VBATT         3.3V |
+BluePill LED           | PC13           GND |
+                       | PC14            5V |
+                       | PC15           PB9 |
+                       | PA0            PB8 |
+                       | PA1            PB7 |  BMP085 SDA
+                       | PA2            PB6 |  BMP085 SCL
+                       | PA3            PB5 |  BMP085 conversion done
+                       | PA4            PB4 |
+                       | PA5            PB3 |
+                       | PA6           PA15 |
+                       | PA7           PA12 |
+                       | PB0           PA11 |
+                       | PB1           PA10 |  RXD1 - debugging console
+display SCL            | PB10           PA9 |  TXD1 - debugging console
+display        SDA             | PB11           PA8 |
+                       | RESET         PB15 |
+                       | 3.3 V         PB14 |
+                       | GND           PB13 |
+                       | GND           PB12 |
+                       +--------------------+
diff --git a/clock/firmware/Makefile b/clock/firmware/Makefile
new file mode 100644 (file)
index 0000000..c54fa11
--- /dev/null
@@ -0,0 +1,6 @@
+ROOT=../..
+BINARY=clock
+OBJS=main.o
+LIB_OBJS=util-debug.o ds18b20.o
+
+include $(ROOT)/mk/bluepill.mk
diff --git a/clock/firmware/config.h b/clock/firmware/config.h
new file mode 100644 (file)
index 0000000..24b1b42
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ *     Burrow Clock -- Configuration
+ *
+ *     (c) 2019 Martin Mareš <mj@ucw.cz>
+ */
+
+// Processor clock
+
+#define CPU_CLOCK_MHZ 72
+
+// Debugging port
+
+#define DEBUG_USART USART1
+#define DEBUG_LED_BLUEPILL
diff --git a/clock/firmware/kerm b/clock/firmware/kerm
new file mode 100644 (file)
index 0000000..988f567
--- /dev/null
@@ -0,0 +1,5 @@
+set port /dev/ttyUSB0
+set speed 115200
+set flow-control none
+set carrier-watch off
+connect
diff --git a/clock/firmware/main.c b/clock/firmware/main.c
new file mode 100644 (file)
index 0000000..b2b7cc3
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *     Clock with Barometer
+ *
+ *     (c) 2018--2019 Martin Mareš <mj@ucw.cz>
+ */
+
+FIXME: Partial code...
+
+#include "util.h"
+
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/cm3/systick.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/timer.h>
+#include <libopencm3/stm32/usart.h>
+
+#include <string.h>
+
+static void clock_init(void)
+{
+       rcc_clock_setup_in_hse_8mhz_out_72mhz();
+
+       rcc_periph_clock_enable(RCC_GPIOB);
+       rcc_periph_clock_enable(RCC_GPIOC);
+       rcc_periph_clock_enable(RCC_USART1);
+       rcc_periph_clock_enable(RCC_USB);
+
+       rcc_periph_reset_pulse(RST_GPIOB);
+       rcc_periph_reset_pulse(RST_GPIOC);
+       rcc_periph_reset_pulse(RST_USART1);
+       rcc_periph_reset_pulse(RST_USB);
+}
+
+static void gpio_init(void)
+{
+       // Switch JTAG off to free up pins
+       gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0);
+
+       // PA9 = TXD1 for debugging console
+       gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
+
+       // PA10 = RXD1 for debugging console
+       gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10);
+
+       // PC13 = BluePill LED
+       gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
+       gpio_clear(GPIOC, GPIO13);
+}
+
+static volatile u32 ms_ticks;
+
+void sys_tick_handler(void)
+{
+       ms_ticks++;
+}
+
+static void tick_init(void)
+{
+       systick_set_frequency(1000, 72000000);
+       systick_counter_enable();
+       systick_interrupt_enable();
+}
+
+#if 0
+static void delay_ms(uint ms)
+{
+       u32 start_ticks = ms_ticks;
+       while (ms_ticks - start_ticks < ms)
+               ;
+}
+#endif
+
+static void usart_init(void)
+{
+       usart_set_baudrate(USART1, 115200);
+       usart_set_databits(USART1, 8);
+       usart_set_stopbits(USART1, USART_STOPBITS_1);
+       usart_set_mode(USART1, USART_MODE_TX_RX);
+       usart_set_parity(USART1, USART_PARITY_NONE);
+       usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
+
+       usart_enable(USART1);
+}
+
+static const struct usb_device_descriptor dev = {
+       .bLength = USB_DT_DEVICE_SIZE,
+       .bDescriptorType = USB_DT_DEVICE,
+       .bcdUSB = 0x0200,
+       .bDeviceClass = 0xFF,
+       .bDeviceSubClass = 0,
+       .bDeviceProtocol = 0,
+       .bMaxPacketSize0 = 64,
+       .idVendor = 0xCAFE,
+       .idProduct = 0xCAFE,
+       .bcdDevice = 0x0200,
+       .iManufacturer = 1,
+       .iProduct = 2,
+       .iSerialNumber = 3,
+       .bNumConfigurations = 1,
+};
+
+static const struct usb_endpoint_descriptor endpoints[] = {{
+       .bLength = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType = USB_DT_ENDPOINT,
+       .bEndpointAddress = 0x81,
+       .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+       .wMaxPacketSize = 64,
+       .bInterval = 1,
+}};
+
+static const struct usb_interface_descriptor iface = {
+       .bLength = USB_DT_INTERFACE_SIZE,
+       .bDescriptorType = USB_DT_INTERFACE,
+       .bInterfaceNumber = 0,
+       .bAlternateSetting = 0,
+       .bNumEndpoints = 1,
+       .bInterfaceClass = 0xFF,
+       .bInterfaceSubClass = 0,
+       .bInterfaceProtocol = 0,
+       .iInterface = 0,
+       .endpoint = endpoints,
+};
+
+static const struct usb_interface ifaces[] = {{
+       .num_altsetting = 1,
+       .altsetting = &iface,
+}};
+
+static const struct usb_config_descriptor config = {
+       .bLength = USB_DT_CONFIGURATION_SIZE,
+       .bDescriptorType = USB_DT_CONFIGURATION,
+       .wTotalLength = 0,
+       .bNumInterfaces = 1,
+       .bConfigurationValue = 1,
+       .iConfiguration = 0,
+       .bmAttributes = 0x80,
+       .bMaxPower = 50,        // multiplied by 2 mA
+       .interface = ifaces,
+};
+
+static const char *usb_strings[] = {
+       "Hippo Computing Inc.",
+       "Space Alert Thermometer",
+       "42",
+};
+
+uint8_t usbd_control_buffer[64];
+
+static void ep81_cb(usbd_device *usbd_dev, uint8_t ep UNUSED)
+{
+       byte buf[4];
+       if (ds_sensors[0].address[0] && ds_sensors[0].current_temp != DS_TEMP_UNKNOWN) {
+               put_u32_be(buf, (u32) ds_sensors[0].current_temp);
+       } else {
+               put_u32_be(buf, 0x80000000);
+       }
+       usbd_ep_write_packet(usbd_dev, 0x81, buf, sizeof(buf));
+}
+
+static void set_config_cb(usbd_device *usbd_dev, uint16_t wValue UNUSED)
+{
+       usbd_ep_setup(usbd_dev, 0x81, USB_ENDPOINT_ATTR_BULK, 64, ep81_cb);
+       ep81_cb(usbd_dev, 0);
+}
+
+int main(void)
+{
+       clock_init();
+       gpio_init();
+       tick_init();
+       usart_init();
+
+       // Simulate USB disconnect
+       gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
+       gpio_clear(GPIOA, GPIO11 | GPIO12);
+       delay_ms(1000);
+
+       usbd_device *usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, 4, usbd_control_buffer, sizeof(usbd_control_buffer));
+       usbd_register_set_config_callback(usbd_dev, set_config_cb);
+       u32 last_ds_step = 0;
+
+       for (;;) {
+               if (ms_ticks - last_ds_step >= 100) {
+                       debug_led_toggle();
+                       ds_step();
+                       last_ds_step = ms_ticks;
+               }
+
+               // XXX: libopencm3 usbd does not use interrupts at the moment, need to poll...
+               // wait_for_interrupt();
+               usbd_poll(usbd_dev);
+       }
+
+       return 0;
+}
diff --git a/clock/host/Makefile b/clock/host/Makefile
new file mode 100644 (file)
index 0000000..d99cfd4
--- /dev/null
@@ -0,0 +1,18 @@
+UCWCF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --cflags libucw)
+UCWLF:=$(shell PKG_CONFIG_PATH=$(LIBUCW)/lib/pkgconfig pkg-config --libs libucw)
+
+CFLAGS=-std=gnu99 -O2 -Wall -Wextra -Wno-parentheses $(UCWCF)
+LDLIBS=-lusb-1.0 $(UCWLF)
+
+all: test burrow-clock
+
+test: test.c
+
+burrow-clock: burrow-clock.c
+burrow-clock: LDLIBS += -lmosquitto
+
+install: all
+       install burrow-clock /usr/local/sbin/
+
+clean:
+       rm -f burrow-clock test
diff --git a/clock/host/burrow-clock.c b/clock/host/burrow-clock.c
new file mode 100644 (file)
index 0000000..4055743
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ *     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", 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_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++;
+       }
+
+       return 0;
+}
diff --git a/clock/host/test.c b/clock/host/test.c
new file mode 100644 (file)
index 0000000..30426fb
--- /dev/null
@@ -0,0 +1,102 @@
+#include <ucw/lib.h>
+#include <ucw/unaligned.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <time.h>
+#include <libusb-1.0/libusb.h>
+
+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)
+           {
+             printf("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);
+}
+
+int main(void)
+{
+  int err;
+  if (err = libusb_init(&usb_ctxt))
+    {
+      fprintf(stderr, "Cannot initialize libusb: error %d\n", err);
+      exit(1);
+    }
+  // libusb_set_debug(usb_ctxt, 3);
+
+  libusb_device *dev = find_device();
+
+  if (err = libusb_open(dev, &devh))
+    {
+      fprintf(stderr, "Cannot open device: error %d\n", err);
+      exit(1);
+    }
+  libusb_reset_device(devh);
+  if (err = libusb_claim_interface(devh, 0))
+    {
+      fprintf(stderr, "Cannot claim interface: error %d\n", err);
+      exit(1);
+    }
+
+  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);
+      // printf("Transferred %d bytes\n", transferred);
+
+      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 t = get_u32_be(resp);
+         int p = get_u32_be(resp + 4);
+         uint cnt = get_u32_be(resp + 8);
+         msg(L_INFO, "Temperature %d ddegC, pressure %d Pa, cnt %u", t, p, cnt);
+       }
+
+      sleep(1);
+    }
+
+  return 0;
+}