#include #include #include "ch.h" #include "hal.h" #include "usbcfg.h" #include "led.h" #include "log.h" /* * HID report sizes (data only, excluding the report ID byte prepended by the * USB host). These match the LampArray HID descriptor in usbcfg.c. */ #define RPT1_LEN 22 /* LampArrayAttributesReport */ #define RPT3_LEN 28 /* LampAttributesResponseReport */ #define RPT6_LEN 1 /* LampArrayControlReport */ /* * Called from ISR context — fill buf with the response for report `id`. * buf[0] must be set to the report ID; *len must be set to the total length. * Return false to stall (unknown ID). */ bool isr_hid_get_report(uint8_t id, uint8_t *buf, size_t *len) { switch (id) { case 1: /* LampArrayAttributesReport */ *len = 1 + RPT1_LEN; memset(buf, 0, *len); buf[0] = 1; /* LampCount, BoundingBox*, LampArrayKind, MinUpdateInterval all zero */ return true; case 3: /* LampAttributesResponseReport */ *len = 1 + RPT3_LEN; memset(buf, 0, *len); buf[0] = 3; /* All lamp attribute fields zero until real lamp state is added */ return true; case 6: /* LampArrayControlReport */ *len = 1 + RPT6_LEN; buf[0] = 6; buf[1] = 0; /* AutonomousMode = 0 (host-controlled) */ return true; default: return false; } } /* * Called from ISR context — process an incoming SET_REPORT payload. * buf[0] is the report ID; len includes that byte. */ void isr_hid_set_report(uint8_t id, const uint8_t *buf, size_t len) { (void)buf; (void)len; switch (id) { case 2: /* LampAttributesRequestReport — which lamp to query next */ break; case 4: /* LampMultiUpdateReport — set up to 8 lamps */ break; case 5: /* LampRangeUpdateReport — set a range of lamps */ break; case 6: /* LampArrayControlReport — autonomous mode flag */ break; default: break; } } static void serial_write(const uint8_t *data, size_t len) { chnWrite((BaseChannel *)&SDU1, data, len); } #define SERIAL_LINE_BUF 128 static THD_WORKING_AREA(waSerial, 512); static THD_FUNCTION(SerialThread, arg) { (void)arg; chRegSetThreadName("serial"); char buf[SERIAL_LINE_BUF]; int len; while (true) { while (SDU1.config->usbp->state != USB_ACTIVE || !cdc_dtr) chThdSleepMilliseconds(100); len = 0; chnWrite((BaseChannel *)&SDU1, (uint8_t *)"> ", 2); while (SDU1.config->usbp->state == USB_ACTIVE && cdc_dtr) { msg_t c = chnGetTimeout((BaseChannel *)&SDU1, TIME_MS2I(100)); if (c < MSG_OK) continue; uint8_t ch = (uint8_t)c; if (ch == '\r' || ch == '\n') { chnWrite((BaseChannel *)&SDU1, (uint8_t *)"\r\n", 2); if (len > 0) { chnWrite((BaseChannel *)&SDU1, (uint8_t *)buf, (size_t)len); chnWrite((BaseChannel *)&SDU1, (uint8_t *)"\r\n", 2); len = 0; } chnWrite((BaseChannel *)&SDU1, (uint8_t *)"> ", 2); } else if (ch == 0x08 || ch == 0x7F) { /* backspace / DEL */ if (len > 0) { len--; chnWrite((BaseChannel *)&SDU1, (uint8_t *)"\b \b", 3); } } else if (ch >= 0x20 && ch < 0x7F) { /* printable ASCII */ if (len < SERIAL_LINE_BUF - 1) { buf[len++] = (char)ch; chnWrite((BaseChannel *)&SDU1, &ch, 1); } } } } } int main(void) { halInit(); chSysInit(); sduObjectInit(&SDU1); sduStart(&SDU1, &serusbcfg); usbDisconnectBus(&USBD1); chThdSleepMilliseconds(1500); usbStart(&USBD1, &usbcfg); usbConnectBus(&USBD1); chThdCreateStatic(waSerial, sizeof(waSerial), NORMALPRIO+1, SerialThread, NULL); led_init(chThdGetSelfX()); for (uint32_t i = 0; i < NUM_DRIVERS; i++) { chEvtRegisterMask(&led_drivers[i].event_source, &event_listeners[i], EVENT_MASK(i)); } log_init(serial_write); chThdSleepMilliseconds(3000); uint8_t color = C_DARK_PURPLE; while(true) { color = (color == C_DARK_PURPLE) ? C_DARK_CYAN : C_DARK_PURPLE; memset(framebuffer, color, sizeof(framebuffer)); led_draw(event_listeners); chThdSleepMilliseconds(500); } chThdSleepMilliseconds(TIME_INFINITE); }