/*- * Copyright 2022 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 #include #include #include #include #include SYSINIT(hal_init, SI_SUB_HAL, SI_ORDER_FIRST, (void (*)(const void *))HAL_Init, NULL); static void clkenable(const void *none) { 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(clkenable, SI_SUB_HAL, SI_ORDER_SECOND, clkenable, NULL); static void oscconfig(const void *none) { RCC_ClkInitTypeDef clkinitstruct; RCC_OscInitTypeDef oscinitstruct; RCC_PeriphCLKInitTypeDef rccperiphclkinit; __HAL_RCC_PWR_CLK_ENABLE(); oscinitstruct = (RCC_OscInitTypeDef){ .OscillatorType = RCC_OSCILLATORTYPE_HSE, .HSEState = RCC_HSE_ON, .HSEPredivValue = RCC_HSE_PREDIV_DIV1, .PLL.PLLMUL = RCC_PLL_MUL9, .PLL.PLLState = RCC_PLL_ON, .PLL.PLLSource = RCC_PLLSOURCE_HSE, }; HAL_RCC_OscConfig(&oscinitstruct); /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 * clocks dividers */ clkinitstruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1; clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2; clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2); /* USB clock selection */ rccperiphclkinit = (RCC_PeriphCLKInitTypeDef){ .PeriphClockSelection = RCC_PERIPHCLK_USB, .UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5, }; HAL_RCCEx_PeriphCLKConfig(&rccperiphclkinit); /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ clkinitstruct = (RCC_ClkInitTypeDef){ .ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2), .SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK, .AHBCLKDivider = RCC_SYSCLK_DIV1, .APB1CLKDivider = RCC_HCLK_DIV2, .APB2CLKDivider = RCC_HCLK_DIV1, }; HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2); } SYSINIT(oscconfig, SI_SUB_HAL, SI_ORDER_THIRD, oscconfig, NULL); char * findeol(char *pos, size_t len) { while (len) { if (*pos == '\r' || *pos == '\n') return pos; pos++; len--; } return NULL; } void hexdump(const uint8_t *ptr, size_t len) { int i; for (i = 0; i < len; i++) usb_printf("%02x", ptr[i]); } void txdone(void) { usb_printf("txdone\r\n"); //Radio.Rx(0); } void txtimeout(void) { usb_printf("txtimeout\r\n"); } void rxdone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) { usb_printf("rxdone: size: %hu, rssi: %hd, snr: %d\r\ndata: ", size, rssi, snr); hexdump(payload, size); usb_printf("\r\n"); } void rxtimeout(void) { usb_printf("rxtimeout\r\n"); } void rxerr(void) { usb_printf("rxerr\r\n"); } static uint8_t hexchartonib(char s) { switch (s) { case '0'...'9': return s - '0'; case 'a'...'f': return s - 'a' + 10; case 'A'...'F': return s - 'A' + 10; default: return -1; } } static bool hexdecode(char *buf, size_t len, uint8_t *out) { uint8_t topchr, botchr; if (len % 2) return false; /* NB: only needed to silence a bad gcc warning */ topchr = -1; while (len) { if (len % 2) { /* bottom nibble */ botchr = hexchartonib(*buf); if (topchr == -1 || botchr == -1) return false; *out = topchr << 4 | botchr; out++; } else { /* top nibble */ topchr = hexchartonib(*buf); } len--; buf++; } return true; } static const char pktstart[] = "pkt:"; static const size_t pktstartlen = sizeof pktstart - 1; static uint8_t pktbuf[128]; static void process_line(char *start, char *end) { size_t len; /* trim off leading CR/NL */ while (start < end && (*start == '\r' || *start == '\n')) start++; len = end - start; if (len >= pktstartlen && memcmp(start, pktstart, sizeof pktstart - 1) == 0) { start += pktstartlen; len -= pktstartlen; if (len % 2) { usb_printf("invalid pkt len\r\n"); return; } if (!hexdecode(start, len, pktbuf)) { usb_printf("invalid pkt\r\n"); return; } //Radio.Send(pktbuf, len / 2); return; } usb_printf("line: %.*s", end - start, start); fflush(vcp_usb); } int main(void) { //debug_printf("starting...\n"); //clkenable(NULL); sysinit_run(); //Radio.Init(&revents); setlinebuf(vcp_usb); #if 1 wait_for_vcp(); /* * This is required to use w/ FreeBSD. This is an issue w/ the * STM32 Core USB library: * https://github.com/STMicroelectronics/STM32CubeL1/issues/10 */ HAL_Delay(50); usb_printf("starting...\r\n"); #endif uint32_t v; char inpbuf[1024]; char *lastcheck; char *endchr; int inpbufpos = 0; int cpylen; loop: //BoardLowPowerHandler(); /* while we have data */ while (CDC_RX_LEN) { /* store last position */ lastcheck = &inpbuf[inpbufpos]; /* calculate how much space left */ cpylen = MIN(sizeof inpbuf - inpbufpos, CDC_RX_LEN); /* copy into buffer */ memcpy(&inpbuf[inpbufpos], CDC_RX_BUFFER, cpylen); /* and point to end of buffer */ inpbufpos += cpylen; do { /* find first end of line characters */ endchr = findeol(lastcheck, cpylen); if (endchr != NULL) { /* if so, process it */ process_line(inpbuf, endchr); /* skip end of line char */ endchr++; /* move remaining buffer to the beginning */ memmove(inpbuf, endchr, inpbufpos - (endchr - inpbuf)); /* and store new length */ inpbufpos = inpbufpos - (endchr - inpbuf); /* mark begining of stream as last checked */ lastcheck = inpbuf; /* and try to process another line */ continue; } else if (inpbufpos == sizeof inpbuf) { /* we overflowed the buffer */ /* XXX - best way is to throw away this line */ inpbufpos = 0; } } while (0); /* if we copied all the data */ if (cpylen == CDC_RX_LEN) { /* declare that we are ready to receive more data */ CDC_RX_LEN = 0; USBD_CDC_ReceivePacket(&hUsbDeviceFS); } else { /* if not, move the remaining to the begining and try again */ memmove(CDC_RX_BUFFER, &CDC_RX_BUFFER[cpylen], CDC_RX_LEN - cpylen); CDC_RX_LEN -= cpylen; } } goto loop; }