]> mj.ucw.cz Git - home-hw.git/blob - bsb/daemon/bsb-monitor.c
BSB: Daemon for Turris communicating via MQTT
[home-hw.git] / bsb / daemon / bsb-monitor.c
1 /*
2  *      Boiler System Bus Interface Daemon
3  *
4  *      (c) 2020 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
13 #include <unistd.h>
14
15 #include <libusb.h>
16
17 static struct libusb_context *usb_ctxt;
18 static struct libusb_device_handle *devh;
19
20 typedef unsigned char byte;
21 typedef uint32_t u32;
22 typedef unsigned int uint;
23
24 #include "../firmware/interface.h"
25
26 static void die(const char *msg, ...)
27 {
28         va_list args;
29         va_start(args, msg);
30
31         vfprintf(stderr, msg, args);
32         fputc('\n', stderr);
33
34         exit(1);
35 }
36
37 static void usb_error(const char *msg, ...)
38 {
39         va_list args;
40         va_start(args, msg);
41         vfprintf(stderr, msg, args);
42         fputc('\n', stderr);
43         va_end(args);
44
45         if (devh) {
46                 libusb_close(devh);
47                 devh = NULL;
48         }
49 }
50
51 static void open_device(void)
52 {
53         int err;
54         libusb_device **devlist;
55         ssize_t devn = libusb_get_device_list(usb_ctxt, &devlist);
56         if (devn < 0)
57                 die("Cannot enumerate USB devices: error %d", (int) devn);
58
59         for (ssize_t i=0; i<devn; i++) {
60                 struct libusb_device_descriptor desc;
61                 libusb_device *dev = devlist[i];
62                 if (!libusb_get_device_descriptor(dev, &desc)) {
63                         if (desc.idVendor == BSB_USB_VENDOR && desc.idProduct == BSB_USB_PRODUCT) {
64                                 fprintf(stderr, "Found device at usb%d.%d\n", libusb_get_bus_number(dev), libusb_get_device_address(dev));
65
66                                 if (err = libusb_open(dev, &devh)) {
67                                         usb_error("Cannot open device: error %d", err);
68                                         goto out;
69                                 }
70                                 libusb_reset_device(devh);
71                                 if (err = libusb_claim_interface(devh, 0)) {
72                                         usb_error("Cannot claim interface: error %d", err);
73                                         goto out;
74                                 }
75
76                                 goto out;
77                         }
78                 }
79         }
80
81 out:
82         libusb_free_device_list(devlist, 1);
83 }
84
85 static inline uint get_u32_le(byte *p)
86 {
87         return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
88 }
89
90 static const char * const stat_names[] = {
91 #define P(x) #x,
92         BSB_STATS
93 #undef P
94 };
95
96 static void show_stats(byte *resp, uint len)
97 {
98         printf("# Stats:");
99         for (uint i=0; 4*i + 3 < (uint) len; i++)
100                 printf(" %s=%u", (i < sizeof(stat_names) / sizeof(stat_names[0]) ? stat_names[i] : "?"), get_u32_le(resp+4*i));
101         printf("\n");
102
103         fflush(stdout);
104 }
105
106 static void show_packet(byte *pkt, uint len)
107 {
108         time_t now = time(NULL);
109         struct tm *tm = localtime(&now);
110         char timebuf[64];
111         strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm);
112         printf("%s ", timebuf);
113
114         if (!len) {
115                 printf("ERROR: Received empty frame!\n");
116                 return;
117         }
118
119         byte status = *pkt++;
120         len--;
121
122         if (!len) {
123                 printf("ERROR: Transmit status: %u\n", status);
124                 return;
125         }
126
127 #if 0
128         printf(": [%d]", status);
129         for (uint i=0; i<len; i++)
130                 printf(" %02x", pkt[i]);
131         putchar('\n');
132 #endif
133
134         printf("%02x -> %02x: ", pkt[BF_SRC] ^ 0x80, pkt[BF_DEST]);
135         if (status)
136                 printf("[REPLY] ");
137         switch (pkt[4]) {
138                 case 2:
139                         printf("INFO %04x:%04x =", (pkt[5]<<8) | pkt[6], (pkt[7]<<8) | pkt[8]);
140                         for (uint i=9; i<len; i++)
141                                 printf(" %02x", pkt[i]);
142                         putchar('\n');
143                         break;
144                 case 6:
145                         printf("GET %04x:%04x\n", (pkt[6]<<8) | pkt[5], (pkt[7]<<8) | pkt[8]);
146                         break;
147                 case 7:
148                         printf("RET %04x:%04x =", (pkt[5]<<8) | pkt[6], (pkt[7]<<8) | pkt[8]);
149                         for (uint i=9; i<len; i++)
150                                 printf(" %02x", pkt[i]);
151                         putchar('\n');
152                         break;
153                 default:
154                         printf("??? type=%02x\n", pkt[4]);
155         }
156
157         fflush(stdout);
158 }
159
160 int main(void)
161 {
162         int err;
163         if (err = libusb_init(&usb_ctxt))
164                 die("Cannot initialize libusb: error %d", err);
165         // libusb_set_debug(usb_ctxt, 3);
166         open_device();
167
168         time_t now = time(NULL);
169         time_t last_stats = 0;
170         time_t last_query = now;
171         int received;
172         byte resp[64];
173
174         for (;;) {
175                 if (!devh) {
176                         fprintf(stderr, "Waiting for device to appear...\n");
177                         while (!devh) {
178                                 sleep(5);
179                                 open_device();
180                         }
181                 }
182
183                 now = time(NULL);
184                 if (last_stats + 60 < now) {
185                         if ((received = libusb_control_transfer(devh, 0xc0, 0x00, 0, 0, resp, sizeof(resp), 1000)) < 0) {
186                                 usb_error("Receive failed: error %d", received);
187                                 continue;
188                         }
189
190                         show_stats(resp, received);
191                         last_stats = now;
192                 }
193
194                 if (last_query + 10 < now) {
195                         byte pkt[] = { 0xdc, 0xc2, 0x00, 0x0b, 0x06, 0x3d, 0x2e, 0x11, 0x25, 0x00, 0x00 };
196                         if (err = libusb_bulk_transfer(devh, 0x01, pkt, sizeof(pkt), &received, 2000)) {
197                                 printf("Send failed: error %d\n", err);
198                                 // usb_error("Receive failed: error %d", received);
199                                 // continue;
200                         } else {
201                                 // printf("Send OK: %d bytes\n", received);
202                         }
203                         last_query = now;
204                 }
205
206                 if (err = libusb_interrupt_transfer(devh, 0x82, resp, 64, &received, 1000)) {
207                         if (err != LIBUSB_ERROR_TIMEOUT)
208                                 usb_error("Receive failed: error %d", err);
209                         continue;
210                 }
211
212                 show_packet(resp, received);
213         }
214 }