twinkle_stick/main.c

156 lines
4.1 KiB
C

#include <string.h>
#include <stdbool.h>
#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);
}