/*- * Copyright 2021 John-Mark Gurney. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "usb_hid_def.h" #include "stm32f1xx.h" #include "stm32f1xx_hal.h" #include #include #include #include #include #include #include #include static struct pktbuf rxpktbuf; static volatile int dorx = 0; static uint8_t rxbuf[128]; static volatile int gotrxdone = 0; static volatile int gottxdone = 0; static volatile int goterr = 0; static volatile int rxbufsize = 0; static volatile int rxbuftrunc = 0; enum { CMD_TERMINATE = 1, CMD_WAITFOR = 2, CMD_RUNFOR = 3, CMD_PING = 4, CMD_SETUNSET = 5, CMD_ADV = 6, CMD_CLEAR = 7, CMD_KEY = 8, }; static struct comms_state cs; static void c13led(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); GPIO_InitStruct = (GPIO_InitTypeDef){ .Pin = GPIO_PIN_13, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, }; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); } SYSINIT_VF(c13led, SI_SUB_HAL, SI_ORDER_SECOND, c13led); void txdone(void) { gottxdone = 1; } void errfunc(void) { debug_printf("error\n"); goterr = 1; } struct pktbuf shared_key_buf = { .pkt = (uint8_t *)"abcd1234", .pktlen = 8, }; static uint32_t rxts; void rxdone(const uint8_t *payload, size_t size) { if (size > sizeof rxbuf) { size = sizeof rxbuf; rxbuftrunc = 1; } debug_printf("rx: %d: %02x %02x ...\n", size, payload[0], payload[1]); memcpy(rxbuf, payload, size); rxbufsize = size; gotrxdone = 1; rxts = HAL_GetTick(); } static inline uint32_t letoh_32(uint8_t *v) { return v[0] | (v[1] << 8) | (v[2] << 16) | ((unsigned)v[3] << 24); } static inline void htole_32(uint8_t *d, uint32_t v) { d[0] = v; d[1] = v >> 8; d[2] = v >> 16; d[3] = v >> 24; } struct chaninfo { GPIO_TypeDef *bank; uint16_t pinnum; bool init; bool invert; } chans[] = { [0] = { .bank = GPIOB, .pinnum = GPIO_PIN_5, .invert = true, }, [1] = { .bank = GPIOB, .pinnum = GPIO_PIN_6, .invert = true, }, [2] = { .bank = GPIOB, .pinnum = GPIO_PIN_7, .invert = true, }, [3] = { .bank = GPIOB, .pinnum = GPIO_PIN_9, .invert = true, }, /* Turn on LED at start */ [4] = { .bank = GPIOB, .pinnum = GPIO_PIN_8, .init = true, }, }; #define nitems(x) (sizeof(x) / sizeof *(x)) static void set_chan(uint32_t chan, bool val) { struct chaninfo ci; if (chan < nitems(chans)) { ci = chans[chan]; HAL_GPIO_WritePin(ci.bank, ci.pinnum, val ^ ci.invert ? GPIO_PIN_SET : GPIO_PIN_RESET); } } static void setup_gpio(void) { GPIO_InitTypeDef GPIO_InitStruct; int i; for (i = 0; i < nitems(chans); i++) { GPIO_InitStruct = (GPIO_InitTypeDef){ .Pin = chans[i].pinnum, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, }; HAL_GPIO_Init(chans[i].bank, &GPIO_InitStruct); set_chan(i, chans[i].init); } } SYSINIT_VF(setup_gpio, SI_SUB_STANDARD, SI_ORDER_ANY, setup_gpio); static struct sched { uint32_t cmd; uint32_t end_wait_tick; /* end if running, otherwise how long to wait */ uint32_t chan; } schedule[20]; static int schedpos; /* position in schedule, % nitems(schedule)*/ static int schedcnt; /* total items waiting */ #define SCHED_ITEM(x) (schedule[(schedpos + x) % nitems(schedule)]) #define SCHED_HEAD SCHED_ITEM(0) #define SCHED_TAIL SCHED_ITEM(schedcnt) static void start_sched(struct sched *sched) { sched->end_wait_tick += uwTick; if (sched->cmd == CMD_RUNFOR) set_chan(sched->chan, 1); } static bool canproc_sched() { /* nothing to do? */ if (schedcnt == 0) return false; /* not yet expired */ if (uwTick < SCHED_HEAD.end_wait_tick) return false; return true; } static void process_sched() { if (!canproc_sched()) return; if (SCHED_HEAD.cmd == CMD_RUNFOR) set_chan(SCHED_HEAD.chan, 0); /* we are done, advance */ schedpos++; schedcnt--; if (schedcnt) start_sched(&SCHED_HEAD); } static void enqueue_sched(uint32_t cmd, uint32_t ticks, uint32_t chan) { if (schedcnt >= nitems(schedule)) return; SCHED_TAIL = (struct sched){ .cmd = cmd, .end_wait_tick = ticks, .chan = chan, }; if (schedcnt == 0) start_sched(&SCHED_HEAD); schedcnt++; } static void procmsg(struct pktbuf inbuf, struct pktbuf *outbuf) { uint32_t args[5]; uint32_t keycnt; int i, r, apos, cnt; i = 1; apos = 0; for (i = 1, apos = 0; apos < sizeof args / sizeof *args && i + 4 <= inbuf.pktlen; i += 4, apos++) { args[apos] = letoh_32(&inbuf.pkt[i]); } outbuf->pkt[0] = inbuf.pkt[0]; outbuf->pktlen = 1; switch (inbuf.pkt[0]) { case CMD_WAITFOR: if (apos == 1) enqueue_sched(CMD_WAITFOR, args[0], -1); break; case CMD_RUNFOR: if (apos == 2) enqueue_sched(CMD_RUNFOR, args[0], args[1]); break; case CMD_PING: break; case CMD_SETUNSET: if (apos == 2) set_chan(args[0], args[1]); break; case CMD_ADV: cnt = 1; if (apos == 1) cnt = args[0]; for (i = 0; i < cnt && i < schedcnt; i++) SCHED_ITEM(i).end_wait_tick = 0; break; case CMD_CLEAR: if (schedcnt) schedcnt = 1; break; case CMD_KEY: i = 1; keycnt = 0; for (i = 1; i + REPORT_SIZE <= inbuf.pktlen; i += REPORT_SIZE) { r = report_insert(&inbuf.pkt[i]); if (!r) break; keycnt++; } htole_32(&outbuf->pkt[1], keycnt); outbuf->pktlen = 5; break; default: outbuf->pkt[0] = 0; break; } } static void setup_button() { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct = (GPIO_InitTypeDef){ .Pin = GPIO_PIN_7, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_LOW, }; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } SYSINIT_VF(setup_button, SI_SUB_STANDARD, SI_ORDER_ANY, setup_button); /* check if the button has been pushed, returns true once for each "push" */ static int button_pushed(void) { static uint32_t lasthightick; static uint32_t waspushed; uint32_t tick; uint8_t pinstate; tick = HAL_GetTick(); pinstate = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7); if (pinstate) { /* Reset button state */ waspushed = 0; lasthightick = tick; return 0; } /* only return IF the it's been held for 5ms & wasn't returned before */ if (tick - lasthightick > 5 && !waspushed) { waspushed = 1; return 1; } return 0; } static const uint8_t hexkeymap[] = { [0] = 0x27, [1] = 0x1e, [2] = 0x1f, [3] = 0x20, [4] = 0x21, [5] = 0x22, [6] = 0x23, [7] = 0x24, [8] = 0x25, [9] = 0x26, [10] = 0x04, [11] = 0x05, [12] = 0x06, [13] = 0x07, [14] = 0x08, [15] = 0x09, }; static_assert(sizeof hexkeymap == 16); volatile uint32_t v; void report_blocking_insert(uint8_t rep[REPORT_SIZE]) { int inserted; do { report_process(); inserted = report_insert(rep); } while(!inserted); } int main() { struct strobepkikey keys; debug_printf("starting..."); #if 0 /* turn on LED */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET); #endif keys = get_key(); comms_init(&cs, procmsg, NULL, &keys.privkey, &keys.pubkey); /* Clear out pointer to private key. */ keys.privkey = (struct pktbuf){}; rs485_register(txdone, rxdone, errfunc); uint8_t txbuf[128] = "i'mhere"; struct pktbuf txpktbuf; txpktbuf = (struct pktbuf){ .pkt = txbuf, .pktlen = 7, }; //rs485_starttx(txpktbuf.pkt, txpktbuf.pktlen); dorx = 1; int laststartrx = 0; loop: while (canproc_sched()) process_sched(); #if 0 BoardLowPowerHandler(); #else //(void)BoardLowPowerHandler; #endif /* process any pending keys */ report_process(); if (button_pushed()) { /* Send the public key */ uint8_t pubkey[EC_PUBLIC_BYTES]; uint8_t reportbuf[REPORT_SIZE]; const uint8_t *buf; int remainnibbles; uint8_t lastkey, key; get_pubkey(pubkey); buf = pubkey; remainnibbles = keys.pubkey.pktlen * 2; memset(reportbuf, 0, sizeof reportbuf); /* clear any previous key presses */ report_blocking_insert(reportbuf); for (remainnibbles = keys.pubkey.pktlen * 2; remainnibbles; remainnibbles--) { /* top nibble when even, bottom when odd */ if (remainnibbles & 1) { key = hexkeymap[buf[0] & 0xf]; buf++; } else key = hexkeymap[buf[0] >> 4]; lastkey = reportbuf[2]; /* * if previous key matches, we need to "up" it, to make * a transition, otherwise, speed things along. */ if (key == lastkey) { reportbuf[2] = 0; report_blocking_insert(reportbuf); } reportbuf[2] = key; report_blocking_insert(reportbuf); } /* clear last key */ reportbuf[2] = 0; report_blocking_insert(reportbuf); } if (gottxdone) { dorx = 1; gottxdone = 0; } if (gotrxdone) { rxpktbuf = (struct pktbuf){ .pkt = rxbuf, .pktlen = rxbufsize, }; txpktbuf = (struct pktbuf){ .pkt = txbuf, .pktlen = sizeof txbuf, }; /* process available packet */ #if 1 uint32_t gt; gt = HAL_GetTick(); reset_timer(); start_timer(); comms_process(&cs, rxpktbuf, &txpktbuf); stop_timer(); debug_printf("comproc: %u cycles, ticks: %u, fromrx: %u\n", getCycles(), HAL_GetTick() - gt, HAL_GetTick() - rxts); #else txpktbuf = rxpktbuf; #endif //debug_printf("totx: %d: %02x %02x ...\n", txpktbuf.pktlen, txpktbuf.pkt[0], txpktbuf.pkt[1]); gotrxdone = false; if (txpktbuf.pktlen) { int i; //debug_printf("rx to tx: %d\n", HAL_GetTick() - rxts); for (i = 0; i < 1; i++) { //HAL_Delay(20); rs485_starttx(txpktbuf.pkt, txpktbuf.pktlen); } /* Make sure we don't interrupt tx */ laststartrx = HAL_GetTick(); } else { dorx = 1; } } if (dorx || goterr || HAL_GetTick() > laststartrx + 1000000) { //usb_printf("dorx\r\n"); laststartrx = HAL_GetTick(); rs485_startrx(); //usb_printf("startrx res: %s\r\n", rs485err); dorx = 0; } goto loop; }