|
- /*-
- * 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 <si_usb.h>
-
- #include <rs485frame.h>
-
- #include <misc.h>
-
- #include <stdbool.h>
- #include <stdint.h>
- #include <string.h>
-
- #include <sysinit.h>
-
- #include <usb_device.h>
- SYSINIT_VF(usb_cdc, SI_SUB_USB, SI_ORDER_MIDDLE, MX_USB_DEVICE_Init);
-
- /* XXX - where's a better place? */
- extern PCD_HandleTypeDef hpcd_USB_FS;
-
- void
- USB_LP_IRQHandler(void)
- {
-
- HAL_PCD_IRQHandler(&hpcd_USB_FS);
- }
-
- static int dorx = 0;
- static uint8_t rxbuf[128];
- static int gotrxdone = 0;
- static int gottxdone = 0;
- static int goterr = 0;
- static int rxbufsize = 0;
- static int rxbuftrunc = 0;
-
- static void
- c13led(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(c13led, SI_SUB_HAL, SI_ORDER_SECOND, c13led, NULL);
-
- #if 0
- #undef usb_printf
- #define usb_printf debug_printf
- #endif
-
- 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)
- {
-
- gottxdone = 1;
- }
-
- void
- errfunc(void)
- {
-
- goterr = 1;
- }
-
- void
- rxdone(const uint8_t *payload, size_t size)
- {
-
- if (size > sizeof rxbuf) {
- size = sizeof rxbuf;
- rxbuftrunc = 1;
- }
-
- memcpy(rxbuf, payload, size);
- rxbufsize = size;
- gotrxdone = 1;
- }
-
- 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;
- }
- rs485_starttx(pktbuf, len / 2);
- return;
- }
- usb_printf("line: %.*s", end - start, start);
- fflush(vcp_usb);
- }
-
- static void
- WaitForIRQ()
- {
-
- __disable_irq();
- HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
- __enable_irq( );
- }
-
- int
- main(void)
- {
-
- sysinit_run();
-
- debug_printf("starting...\n");
-
- #if 0
- int i;
- for (i = 0; i < 5; i++) {
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
- HAL_Delay(250);
- HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
- HAL_Delay(250);
- }
- #endif
-
- 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
-
- char inpbuf[1024];
- char *lastcheck;
- char *endchr;
- int inpbufpos = 0;
- int cpylen;
-
- rs485_register(txdone, rxdone, errfunc);
-
- rs485_startrx();
-
- unsigned lasttick = -1;
- uint32_t gt;
- loop:
- /*
- * This is disabled as when it's enabled, it causes a hang
- * when sending USB data. The USB CDC end point never becomes
- * unbusy to allow the next send to progress.
- */
- #if 0
- /*
- * A ms delay isn't a big deal, so no special locking is
- * used to make sure we don't got to sleep w/ data pending.
- */
- WaitForIRQ();
- #else
- (void)WaitForIRQ;
- #endif
-
- gt = HAL_GetTick();
- if (lasttick != gt / 1000) {
- lasttick = gt / 1000;
- //usb_printf("tick: %u\r\n", lasttick);
- }
-
- if (goterr) {
- //usb_printf("error\r\n");
- goterr = 0;
- dorx = 1;
- }
-
- if (gottxdone) {
- usb_printf("txdone\r\n");
-
- dorx = 1;
- gottxdone = 0;
- }
-
- if (gotrxdone) {
- if (rxbuftrunc) {
- rxbuftrunc = 0;
- //usb_printf("rxdone: buffer overflow\r\n");
- } else {
- usb_printf("rxdone: size: %u\r\ndata: ", rxbufsize);
- hexdump(rxbuf, rxbufsize);
- usb_printf("\r\n");
- }
- dorx = 1;
- gotrxdone = 0;
- }
-
- if (dorx) {
- //usb_printf("dorx\r\n");
- rs485_startrx();
- //usb_printf("startrx res: %s\r\n", rs485err);
- dorx = 0;
- }
-
- /* 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;
- }
|