From 665d2106838b5cff6d96ed82a3af6c75e723ed2a Mon Sep 17 00:00:00 2001 From: sq8vps Date: Fri, 18 Aug 2023 12:50:33 +0200 Subject: [PATCH] ax25 send, removed all mallocs --- Inc/ax25.h | 9 +- Inc/drivers/systick.h | 6 +- Inc/drivers/uart.h | 2 + Inc/terminal.h | 34 +++---- STM32F103C8Tx_FLASH.ld | 4 +- Src/ax25.c | 45 +++++++-- Src/beacon.c | 8 +- Src/config.c | 2 +- Src/digipeater.c | 23 ++--- Src/drivers/systick.c | 12 +++ Src/drivers/uart.c | 51 +--------- Src/main.c | 53 +++-------- Src/terminal.c | 210 +++++++++++++++++------------------------ Src/usbd_cdc_if.c | 9 +- vp-digi Debug.cfg | 35 +++++++ vp-digi Release.cfg | 35 +++++++ 16 files changed, 270 insertions(+), 268 deletions(-) create mode 100644 vp-digi Debug.cfg create mode 100644 vp-digi Release.cfg diff --git a/Inc/ax25.h b/Inc/ax25.h index bb2a910..fb26893 100644 --- a/Inc/ax25.h +++ b/Inc/ax25.h @@ -41,6 +41,13 @@ struct Ax25ProtoConfig extern struct Ax25ProtoConfig Ax25Config; +/** + * @brief Transmit one or more frames encoded in KISS format + * @param *buf Inout buffer + * @param len Buffer size + */ +void Ax25TxKiss(uint8_t *buf, uint16_t len); + /** * @brief Write frame to transmit buffer * @param *data Data to transmit @@ -63,7 +70,7 @@ void Ax25ClearReceivedFrameBitmap(void); /** * @brief Get next received frame (if available) - * @param **dst Destination buffer that this function allocates and fills + * @param **dst Pointer to internal buffer * @param *size Actual frame size * @param *signalLevel Frame signal level (RMS) * @return True if frame was read, false if no more frames to read diff --git a/Inc/drivers/systick.h b/Inc/drivers/systick.h index 93a5378..5367e6e 100644 --- a/Inc/drivers/systick.h +++ b/Inc/drivers/systick.h @@ -26,8 +26,10 @@ along with VP-Digi. If not, see . extern volatile uint32_t ticks; -//void SysTick_Handler(void); - void SysTickInit(void); +uint32_t SysTickGet(void); + +void Delay(uint32_t ms); + #endif /* SYSTICK_H_ */ diff --git a/Inc/drivers/uart.h b/Inc/drivers/uart.h index 3d967cb..e8153eb 100644 --- a/Inc/drivers/uart.h +++ b/Inc/drivers/uart.h @@ -37,6 +37,7 @@ enum UartDataType DATA_NOTHING = 0, DATA_KISS, DATA_TERM, + DATA_USB, }; typedef struct @@ -53,6 +54,7 @@ typedef struct uint8_t txBufferFull : 1; enum UartMode mode; uint32_t kissTimer; + uint16_t lastRxBufferHead; //for special characters handling } Uart; extern Uart Uart1, Uart2, UartUsb; diff --git a/Inc/terminal.h b/Inc/terminal.h index 45623ce..001e36a 100644 --- a/Inc/terminal.h +++ b/Inc/terminal.h @@ -29,30 +29,24 @@ along with VP-Digi. If not, see . */ void TermSendToAll(enum UartMode mode, uint8_t *data, uint16_t size); +/** + * @brief Send signed number to all available ports + * @param mode Output mode/data type + * @param n Number to send + */ void TermSendNumberToAll(enum UartMode mode, int32_t n); -//typedef enum -//{ -// TERM_ANY, -// TERM_USB, -// TERM_UART1, -// TERM_UART2 -//} Terminal_stream; -// -//#define TERMBUFLEN 300 -// -///** -// * @brief Handle "special" terminal cases like backspace or local echo -// * @param[in] src Source: TERM_USB, TERM_UART1, TERM_UART2 -// * @attention Must be called for every received data -// */ -//void term_handleSpecial(Terminal_stream src); -// -// /** - * \brief Parse and process received data - * \param *src UART structure + * @brief Handle "special" terminal cases like backspace or local echo + * @param *u UART structure + * @attention Must be called for every received data + */ +void TermHandleSpecial(Uart *u); + +/** + * @brief Parse and process received data + * @param *src UART structure */ void TermParse(Uart *src); diff --git a/STM32F103C8Tx_FLASH.ld b/STM32F103C8Tx_FLASH.ld index 529d412..e9b1ef0 100644 --- a/STM32F103C8Tx_FLASH.ld +++ b/STM32F103C8Tx_FLASH.ld @@ -55,8 +55,8 @@ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _estack = 0x20005000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ -_Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ +_Min_Heap_Size = 0x080; /* required amount of heap */ +_Min_Stack_Size = 0x200; /* required amount of stack */ /* Specify the memory areas */ MEMORY diff --git a/Src/ax25.c b/Src/ax25.c index 941c907..4dd5e10 100644 --- a/Src/ax25.c +++ b/Src/ax25.c @@ -21,11 +21,13 @@ along with VP-Digi. If not, see . #include "common.h" #include "drivers/systick.h" #include +#include "digipeater.h" struct Ax25ProtoConfig Ax25Config; //values below must be kept consistent so that FRAME_BUFFER_SIZE >= FRAME_MAX_SIZE * FRAME_MAX_COUNT -#define FRAME_MAX_SIZE (150) //single frame max length for RX +#define FRAME_MAX_SIZE (308) //single frame max length for RX +//308 bytes is the theoretical max size assuming 2-byte Control, 256-byte info field and 5 digi address fields #define FRAME_MAX_COUNT (10) //max count of frames in buffer #define FRAME_BUFFER_SIZE (FRAME_MAX_COUNT * FRAME_MAX_SIZE) //circular frame buffer length @@ -111,6 +113,8 @@ static uint16_t rxMultiplexDelay = 0; //simple delay for decoder multiplexer to static uint16_t txDelay; //number of TXDelay bytes to send static uint16_t txTail; //number of TXTail bytes to send +static uint8_t outputFrameBuffer[FRAME_MAX_SIZE]; + #define GET_FREE_SIZE(max, head, tail) (((head) < (tail)) ? ((tail) - (head)) : ((max) - (head) + (tail))) #define GET_USED_SIZE(max, head, tail) (max - GET_FREE_SIZE(max, head, tail)) @@ -140,6 +144,32 @@ void Ax25ClearReceivedFrameBitmap(void) frameReceived = 0; } +void Ax25TxKiss(uint8_t *buf, uint16_t len) +{ + if(len < 18) //frame is too small + { + return; + } + for(uint16_t i = 0; i < len; i++) + { + if(buf[i] == 0xC0) //frame start marker + { + uint16_t end = i + 1; + while(end < len) + { + if(buf[end] == 0xC0) + break; + end++; + } + if(end == len) //no frame end marker found + return; + Ax25WriteTxFrame(&buf[i + 2], end - (i + 2)); //skip modem number and send frame + DigiStoreDeDupe(&buf[i + 2], end - (i + 2)); + i = end; //move pointer to the next byte if there are more consecutive frames + } + } +} + void *Ax25WriteTxFrame(uint8_t *data, uint16_t size) { while(txStage != TX_STAGE_IDLE) @@ -172,12 +202,7 @@ bool Ax25ReadNextRxFrame(uint8_t **dst, uint16_t *size, uint16_t *signalLevel) if((rxFrameHead == rxFrameTail) && !rxFrameBufferFull) return false; - *dst = malloc(rxFrame[rxFrameTail].size); - if(NULL == dst) - { - *size = 0; - return false; - } + *dst = outputFrameBuffer; for(uint16_t i = 0; i < rxFrame[rxFrameTail].size; i++) { @@ -494,7 +519,7 @@ void Ax25TransmitBuffer(void) if((txFrameHead != txFrameTail) || txFrameBufferFull) { - txQuiet = (ticks + (Ax25Config.quietTime / SYSTICK_INTERVAL) + Random(0, 200 / SYSTICK_INTERVAL)); //calculate required delay + txQuiet = (SysTickGet() + (Ax25Config.quietTime / SYSTICK_INTERVAL) + Random(0, 200 / SYSTICK_INTERVAL)); //calculate required delay txInitStage = TX_INIT_WAITING; } } @@ -530,7 +555,7 @@ void Ax25TransmitCheck(void) if(ModemIsTxTestOngoing()) //TX test is enabled, wait for now return; - if(txQuiet < ticks) //quit time has elapsed + if(txQuiet < SysTickGet()) //quit time has elapsed { if(!ModemDcdState()) //channel is free { @@ -548,7 +573,7 @@ void Ax25TransmitCheck(void) } else //still trying { - txQuiet = ticks + Random(100 / SYSTICK_INTERVAL, 500 / SYSTICK_INTERVAL); //try again after some random time + txQuiet = SysTickGet() + Random(100 / SYSTICK_INTERVAL, 500 / SYSTICK_INTERVAL); //try again after some random time txRetries++; } } diff --git a/Src/beacon.c b/Src/beacon.c index 02ccf80..9462b0c 100644 --- a/Src/beacon.c +++ b/Src/beacon.c @@ -102,11 +102,11 @@ void BeaconCheck(void) if(beacon[i].enable == 0) continue; - if((beacon[i].interval > 0) && ((ticks >= beacon[i].next) || (beacon[i].next == 0))) + if((beacon[i].interval > 0) && ((SysTickGet() >= beacon[i].next) || (beacon[i].next == 0))) { - if(beaconDelay[i] > ticks) //check for beacon delay (only for the very first transmission) + if(beaconDelay[i] > SysTickGet()) //check for beacon delay (only for the very first transmission) return; - beacon[i].next = ticks + beacon[i].interval; //save next beacon timestamp + beacon[i].next = SysTickGet() + beacon[i].interval; //save next beacon timestamp beaconDelay[i] = 0; BeaconSend(i); } @@ -121,7 +121,7 @@ void BeaconInit(void) { for(uint8_t i = 0; i < 8; i++) { - beaconDelay[i] = (beacon[i].delay * SYSTICK_FREQUENCY) + ticks + (30000 / SYSTICK_INTERVAL); //set delay for beacons and add constant 30 seconds of delay + beaconDelay[i] = (beacon[i].delay * SYSTICK_FREQUENCY) + SysTickGet() + (30000 / SYSTICK_INTERVAL); //set delay for beacons and add constant 30 seconds of delay beacon[i].next = 0; } } diff --git a/Src/config.c b/Src/config.c index c190440..1839b18 100644 --- a/Src/config.c +++ b/Src/config.c @@ -1,5 +1,5 @@ /* -This file is part of VP-DigiConfig. +This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/Src/digipeater.c b/Src/digipeater.c index 15f9ee5..78c925c 100644 --- a/Src/digipeater.c +++ b/Src/digipeater.c @@ -26,14 +26,14 @@ along with VP-DigiConfig. If not, see . struct _DigiConfig DigiConfig; -#define VISCOUS_MAX_FRAME_COUNT 20 //max frames in viscous-delay buffer +#define VISCOUS_MAX_FRAME_COUNT 10 //max frames in viscous-delay buffer #define VISCOUS_MAX_FRAME_SIZE 150 struct ViscousData { uint32_t hash; uint32_t timeLimit; - uint8_t *frame; + uint8_t frame[VISCOUS_MAX_FRAME_SIZE]; uint16_t size; }; static struct ViscousData viscous[VISCOUS_MAX_FRAME_COUNT]; @@ -45,12 +45,12 @@ struct DeDupeData uint32_t timeLimit; }; -#define DEDUPE_SIZE (40) //duplicate protection buffer size (number of hashes) +#define DEDUPE_SIZE (50) //duplicate protection buffer size (number of hashes) static struct DeDupeData deDupe[DEDUPE_SIZE]; //duplicate protection hash buffer static uint8_t deDupeCount = 0; //duplicate protection buffer index -#define DIGI_BUFFER_SIZE 200 +#define DIGI_BUFFER_SIZE 308 //308 is the theoretical max under some assumptions, see ax25.c static uint8_t buf[DIGI_BUFFER_SIZE]; /** @@ -66,9 +66,8 @@ static uint8_t viscousCheckAndRemove(uint32_t hash) { viscous[i].hash = 0; //clear slot viscous[i].timeLimit = 0; - free(viscous[i].frame); viscous[i].size = 0; - //term_sendMonitor((uint8_t*)"Digipeated frame received, dropping old frame from viscous-delay buffer\r\n", 0); + TermSendToAll(MODE_MONITOR, (uint8_t*)"Digipeated frame received, dropping old frame from viscous-delay buffer\r\n", 0); return 1; } } @@ -86,7 +85,7 @@ void DigiViscousRefresh(void) for(uint8_t i = 0; i < VISCOUS_MAX_FRAME_COUNT; i++) { - if((viscous[i].timeLimit > 0) && (ticks >= viscous[i].timeLimit)) //it's time to transmit this frame + if((viscous[i].timeLimit > 0) && (SysTickGet() >= viscous[i].timeLimit)) //it's time to transmit this frame { void *handle = NULL; if(NULL != (handle = Ax25WriteTxFrame(viscous[i].frame, viscous[i].size))) @@ -103,7 +102,6 @@ void DigiViscousRefresh(void) viscous[i].hash = 0; //clear slot viscous[i].timeLimit = 0; - free(viscous[i].frame); viscous[i].size = 0; } } @@ -194,9 +192,6 @@ static void makeFrame(uint8_t *frame, uint16_t elStart, uint16_t len, uint32_t h if((len + 7) > VISCOUS_MAX_FRAME_SIZE) //if frame length (+ 7 bytes for inserted call) is bigger than buffer size return; //drop - viscous[viscousSlot].frame = malloc(len + 7); - if(NULL == viscous[viscousSlot].frame) - return; buffer = viscous[viscousSlot].frame; index = &(viscous[viscousSlot].size); *index = 0; @@ -288,7 +283,7 @@ static void makeFrame(uint8_t *frame, uint16_t elStart, uint16_t len, uint32_t h if((alias < 8) && (DigiConfig.viscous & (1 << alias))) { viscous[viscousSlot].hash = hash; - viscous[viscousSlot].timeLimit = ticks + (VISCOUS_HOLD_TIME / SYSTICK_INTERVAL); + viscous[viscousSlot].timeLimit = SysTickGet() + (VISCOUS_HOLD_TIME / SYSTICK_INTERVAL); TermSendToAll(MODE_MONITOR, (uint8_t*)"Saving frame for viscous-delay digipeating\r\n", 0); } else @@ -339,7 +334,7 @@ void DigiDigipeat(uint8_t *frame, uint16_t len) { if(deDupe[i].hash == hash) { - if(ticks < (deDupe[i].timeLimit)) + if(SysTickGet() < (deDupe[i].timeLimit)) return; //filter out duplicate frame } } @@ -466,7 +461,7 @@ void DigiStoreDeDupe(uint8_t *buf, uint16_t size) deDupeCount %= DEDUPE_SIZE; deDupe[deDupeCount].hash = hash; - deDupe[deDupeCount].timeLimit = ticks + (DigiConfig.dupeTime * 10 / SYSTICK_INTERVAL); + deDupe[deDupeCount].timeLimit = SysTickGet() + (DigiConfig.dupeTime * 10 / SYSTICK_INTERVAL); deDupeCount++; } diff --git a/Src/drivers/systick.c b/Src/drivers/systick.c index 82d5208..64f1b55 100644 --- a/Src/drivers/systick.c +++ b/Src/drivers/systick.c @@ -30,3 +30,15 @@ void SysTickInit(void) { SysTick_Config(SystemCoreClock / SYSTICK_FREQUENCY); //SysTick every 10 ms } + +uint32_t SysTickGet(void) +{ + return ticks; +} + +void Delay(uint32_t ms) +{ + uint32_t target = SysTickGet() + ms / SYSTICK_INTERVAL; + while(target > SysTickGet()) + ; +} diff --git a/Src/drivers/uart.c b/Src/drivers/uart.c index 3b458eb..968f29e 100644 --- a/Src/drivers/uart.c +++ b/Src/drivers/uart.c @@ -21,49 +21,10 @@ along with VP-Digi. If not, see . #include "ax25.h" #include "common.h" #include - #include "digipeater.h" Uart Uart1, Uart2, UartUsb; -//uint8_t Uart_txKiss(uint8_t *buf, uint16_t len) -//{ -// if(len < 10) //frame is too small -// { -// return 1; -// } -// -// uint16_t framebegin = 0; -// uint8_t framestatus = 0; //0 - frame not started, 1 - frame start found, 2 - in a frame, 3 - frame end found -// -// for(uint16_t i = 0; i < len; i++) -// { -// if(*(buf + i) == 0xc0) //found KISS frame delimiter -// { -// if((i > 2) && (framestatus == 2)) //we are already in frame, this is the ending marker -// { -// framestatus = 3; -// ax25.frameXmit[ax25.xmitIdx++] = 0xFF; //write frame separator -// Digi_storeDeDupeFromXmitBuf(framebegin); //store duplicate protection hash -// if((FRAMEBUFLEN - ax25.xmitIdx) < (len - i + 2)) //there might be next frame in input buffer, but if there is no space for it, drop it -// break; -// } -// } -// else if((*(buf + i) == 0x00) && (*(buf + i - 1) == 0xC0) && ((framestatus == 0) || (framestatus == 3))) //found frame delimiter, modem number (0x00) and we are not in a frame yet or preceding frame has been processed -// { -// framestatus = 1; //copy next frame -// framebegin = ax25.xmitIdx; -// } -// else if((framestatus == 1) || (framestatus == 2)) //we are in a frame -// { -// ax25.frameXmit[ax25.xmitIdx++] = *(buf + i); //copy data -// framestatus = 2; -// } -// } -// -// return 0; -//} - static void handleInterrupt(Uart *port) { if(port->port->SR & USART_SR_RXNE) //byte received @@ -72,13 +33,10 @@ static void handleInterrupt(Uart *port) port->rxBuffer[port->rxBufferHead++] = port->port->DR; //store it port->rxBufferHead %= UART_BUFFER_SIZE; -// if(port->port == USART1) //handle special functions and characters -// term_handleSpecial(TERM_UART1); -// else if(port->port == USART2) -// term_handleSpecial(TERM_UART2); + TermHandleSpecial(port); if(port->mode == MODE_KISS) - port->kissTimer = ticks + (5000 / SYSTICK_INTERVAL); //set timeout to 5s in KISS mode + port->kissTimer = SysTickGet() + (5000 / SYSTICK_INTERVAL); //set timeout to 5s in KISS mode } if(port->port->SR & USART_SR_IDLE) //line is idle, end of data reception { @@ -111,7 +69,7 @@ static void handleInterrupt(Uart *port) } } - if((port->kissTimer > 0) && (ticks >= port->kissTimer)) //KISS timer timeout + if((port->kissTimer > 0) && (SysTickGet() >= port->kissTimer)) //KISS timer timeout { port->kissTimer = 0; port->rxBufferHead = 0; @@ -203,6 +161,7 @@ void UartInit(Uart *port, USART_TypeDef *uart, uint32_t baud) port->mode = MODE_KISS; port->enabled = 0; port->kissTimer = 0; + port->lastRxBufferHead = 0; memset(port->rxBuffer, 0, sizeof(port->rxBuffer)); memset(port->txBuffer, 0, sizeof(port->txBuffer)); } @@ -278,7 +237,7 @@ void UartClearRx(Uart *port) void UartHandleKissTimeout(Uart *port) { - if((port->kissTimer > 0) && (ticks >= port->kissTimer)) //KISS timer timeout + if((port->kissTimer > 0) && (SysTickGet() >= port->kissTimer)) //KISS timer timeout { port->kissTimer = 0; port->rxBufferHead = 0; diff --git a/Src/main.c b/Src/main.c index 305d7ef..53c891c 100644 --- a/Src/main.c +++ b/Src/main.c @@ -94,7 +94,7 @@ static void handleFrame(void) uint8_t modemBitmap = Ax25GetReceivedFrameBitmap(); //store states Ax25ClearReceivedFrameBitmap(); - uint8_t *buf = NULL; + uint8_t *buf; uint16_t size = 0; uint16_t signalLevel = 0; @@ -113,7 +113,7 @@ static void handleFrame(void) //for pure square wave it should be equal to the amplitude (around 4095) //real data contains lots of imperfections (especially mark/space amplitude imbalance) and this value is far smaller than 2900 for standard frames //division by 9 was selected by trial and error to provide a value of 100(%) when the input signal had peak-peak voltage of 3.3V - //this probably should be done in a different way, like some peak amplitude tracing + //TODO: this probably should be done in a different way, like some peak amplitude tracing signalLevel /= 9; if(signalLevel > 100) @@ -141,9 +141,11 @@ static void handleFrame(void) TermSendToAll(MODE_MONITOR, (uint8_t*)"D", 1); break; case EMPHASIS_NONE: - default: TermSendToAll(MODE_MONITOR, (uint8_t*)"F", 1); break; + default: + TermSendToAll(MODE_MONITOR, (uint8_t*)"*", 1); + break; } } else @@ -161,8 +163,6 @@ static void handleFrame(void) DigiDigipeat(buf, size); - - free(buf); } } @@ -200,9 +200,7 @@ int main(void) GPIOA->CRH |= GPIO_CRH_MODE12_1; GPIOA->CRH &= ~GPIO_CRH_CNF12; GPIOA->BSRR = GPIO_BSRR_BR12; - uint32_t t = ticks + (100 / SYSTICK_INTERVAL); - while(t > ticks) - ; + Delay(100); GPIOA->CRH &= ~GPIO_CRH_MODE12; GPIOA->CRH |= GPIO_CRH_CNF12_0; @@ -269,39 +267,16 @@ int main(void) Ax25TransmitCheck(); //check for pending transmission request -// if(USBint) //USB "interrupt" -// { -// USBint = 0; //clear -// -// if(USBmode == MODE_KISS) //is USB in KISS mode? -// usbKissTimer = ticks + 500; //set timeout to 5s -// -// term_handleSpecial(TERM_USB); //handle special characters (e.g. backspace) -// if((usbcdcdata[0] == 0xc0) && /*(usbcdcdata[1] == 0x00) &&*/ (usbcdcdata[usbcdcidx - 1] == 0xc0)) //probably a KISS frame -// { -// USBrcvd = DATA_KISS; -// usbKissTimer = 0; -// } -// -// if(((usbcdcdata[usbcdcidx - 1] == '\r') || (usbcdcdata[usbcdcidx - 1] == '\n'))) //proabably a command -// { -// USBrcvd = DATA_TERM; -// usbKissTimer = 0; -// } -// } -// -// if((usbKissTimer > 0) && (ticks >= usbKissTimer)) //USB KISS timer timeout -// { -// usbcdcidx = 0; -// memset(usbcdcdata, 0, UARTBUFLEN); -// usbKissTimer = 0; -// } - if(UartUsb.rxType != DATA_NOTHING) { - TermParse(&UartUsb); - UartClearRx(&UartUsb); + TermHandleSpecial(&UartUsb); + if(UartUsb.rxType != DATA_USB) + { + TermParse(&UartUsb); + UartClearRx(&UartUsb); + } + UartUsb.rxType = DATA_NOTHING; } if(Uart1.rxType != DATA_NOTHING) { @@ -318,7 +293,7 @@ int main(void) BeaconCheck(); //check beacons - if(ticks > 0xFFFFF000) + if(SysTickGet() > 0xFFFFF000) NVIC_SystemReset(); } /* USER CODE END 3 */ diff --git a/Src/terminal.c b/Src/terminal.c index 2b931db..5a99b73 100644 --- a/Src/terminal.c +++ b/Src/terminal.c @@ -22,91 +22,40 @@ along with VP-DigiConfig. If not, see . #include "config.h" #include "drivers/modem.h" #include "ax25.h" +#include "drivers/systick.h" +void TermHandleSpecial(Uart *u) +{ + if(u->mode == MODE_KISS) //don't do anything in KISS mode + { + u->lastRxBufferHead = 0; + return; + } + if(u->lastRxBufferHead >= u->rxBufferHead) //UART RX buffer index was probably cleared + u->lastRxBufferHead = 0; -//uint16_t spLastIdx[3] = {0, 0, 0}; //index buffer was "special" terminal cases + if(u->rxBuffer[u->rxBufferHead - 1] == '\b') //user entered backspace + { + if(u->rxBufferHead > 1) //there was some data in buffer + { + u->rxBufferHead -= 2; //remove backspace and preceding character + UartSendString(u, "\b \b", 3); //backspace (one character left), remove backspaced character (send space) and backspace again + if(u->lastRxBufferHead > 0) + u->lastRxBufferHead--; //1 character was removed + } + else //no preceding character + u->rxBufferHead = 0; + } + uint16_t t = u->rxBufferHead; //store last index + if(u->lastRxBufferHead < t) //local echo handling + { + UartSendString(u, &u->rxBuffer[u->lastRxBufferHead], t - u->lastRxBufferHead); //echo characters entered by user + if((u->rxBuffer[t - 1] == '\r') || (u->rxBuffer[t - 1] == '\n')) + UartSendString(u, "\r\n", 2); + u->lastRxBufferHead = t; + } -/** - * @brief Handle "special" terminal cases like backspace or local echo - * @param[in] src Source: TERM_USB, TERM_UART1, TERM_UART2 - * @attention Must be called for every received data - */ -//void term_handleSpecial(Terminal_stream src) -//{ -// if(src == TERM_USB) -// { -// if(USBmode == MODE_KISS) //don't do anything in KISS mode -// { -// spLastIdx[0] = 0; -// return; -// } -// if(spLastIdx[0] >= usbcdcidx) //USB RX buffer index was probably cleared -// spLastIdx[0] = 0; -// -// if(usbcdcdata[usbcdcidx - 1] == '\b') //user entered backspace -// { -// if(usbcdcidx > 1) //there was some data in buffer -// { -// usbcdcidx -= 2; //remove backspace and preceding character -// CDC_Transmit_FS((uint8_t*)"\b \b", 3); //backspace (one character left), remove backspaced character (send space) and backspace again -// if(spLastIdx[0] > 0) -// spLastIdx[0]--; //1 character was removed -// } -// else //there was only a backspace -// usbcdcidx = 0; -// } -// uint16_t t = usbcdcidx; //store last index -// if(spLastIdx[0] < t) //local echo handling -// { -// CDC_Transmit_FS(&usbcdcdata[spLastIdx[0]], t - spLastIdx[0]); //echo characters entered by user -// if((usbcdcdata[t - 1] == '\r') || (usbcdcdata[t - 1] == '\n')) -// CDC_Transmit_FS((uint8_t*)"\r\n", 2); -// spLastIdx[0] = t; -// } -// } -// else if((src == TERM_UART1) || (src == TERM_UART2)) -// { -// Uart *u = &uart1; -// uint8_t nr = 1; -// if(src == TERM_UART2) -// { -// u = &uart2; -// nr = 2; -// } -// -// -// if(u->mode == MODE_KISS) //don't do anything in KISS mode -// { -// spLastIdx[nr] = 0; -// return; -// } -// if(spLastIdx[nr] >= u->bufrxidx) //UART RX buffer index was probably cleared -// spLastIdx[nr] = 0; -// -// if(u->bufrx[u->bufrxidx - 1] == '\b') //user entered backspace -// { -// if(u->bufrxidx > 1) //there was some data in buffer -// { -// u->bufrxidx -= 2; //remove backspace and preceding character -// uart_sendString(u, (uint8_t*)"\b \b", 3); //backspace (one character left), remove backspaced character (send space) and backspace again -// if(spLastIdx[nr] > 0) -// spLastIdx[nr]--; //1 character was removed -// } -// else //there was only a backspace -// u->bufrxidx = 0; -// } -// uint16_t t = u->bufrxidx; //store last index -// if(spLastIdx[nr] < t) //local echo handling -// { -// uart_sendString(u, &u->bufrx[spLastIdx[nr]], t - spLastIdx[nr]); //echo characters entered by user -// if((u->bufrx[t - 1] == '\r') || (u->bufrx[t - 1] == '\n')) -// uart_sendString(u, (uint8_t*)"\r\n", 2); -// spLastIdx[nr] = t; -// } -// uart_transmitStart(u); -// } -// -//} +} static void sendKiss(Uart *port, uint8_t *buf, uint16_t len) @@ -165,6 +114,7 @@ static const char monitorHelp[] = "\r\nCommans available in monitor mode:\r\n" "kiss - switches to KISS mode\r\n" "config - switches to config mode\r\n" "reboot - reboots the device\r\n" + "time - show time since boot\r\n" "version - shows full firmware version info\r\n\r\n\r\n"; static const char configHelp[] = "\r\nCommands available in config mode:\r\n" @@ -174,6 +124,7 @@ static const char configHelp[] = "\r\nCommands available in config mode:\r\n" "eraseall - erases all configurations and reboots the device\r\n" "help - shows this help page\r\n" "reboot - reboots the device\r\n" + "time - show time since boot\r\n" "version - shows full firmware version info\r\n\r\n" "call - sets callsign with optional SSID\r\n" "dest
- sets destination address\r\n" @@ -381,6 +332,12 @@ static void printConfig(Uart *src) UartSendString(src, "Off\r\n", 0); } +static void sendTime(Uart *src) +{ + UartSendString(src, "Time since boot: ", 0); + UartSendNumber(src, SysTickGet() * SYSTICK_INTERVAL / 60000); //convert from ms to minutes + UartSendString(src, " minutes\r\n", 0); +} void TermParse(Uart *src) { @@ -414,7 +371,7 @@ void TermParse(Uart *src) } else if(!strncmp(cmd, "monitor", 7)) { - UartSendString(src, (uint8_t*)"USB switched to monitor mode\r\n", 0); + UartSendString(src, (uint8_t*)"Switched to monitor mode\r\n", 0); src->mode = MODE_MONITOR; return; } @@ -423,7 +380,7 @@ void TermParse(Uart *src) */ else if((src->mode == MODE_KISS) && (src->rxType == DATA_KISS)) { - //Uart_txKiss(cmd, len); //if received KISS data, transmit KISS frame + Ax25TxKiss(src->rxBuffer, src->rxBufferHead); return; } /* @@ -434,15 +391,22 @@ void TermParse(Uart *src) if(!strncmp(cmd, "help", 4)) { UartSendString(src, (char *)monitorHelp, 0); + return; } else if(!strncmp(cmd, "version", 7)) { UartSendString(src, (char *)versionString, 0); + return; } else if(!strncmp(cmd, "reboot", 6)) { NVIC_SystemReset(); } + else if(!strncmp(cmd, "time", 4)) + { + sendTime(src); + return; + } else if(!strncmp(cmd, "beacon ", 7)) { if((cmd[7] >= '0') && (cmd[7] <= '7')) @@ -509,10 +473,17 @@ void TermParse(Uart *src) if(!strncmp(cmd, "help", 4)) { UartSendString(src, (uint8_t*)configHelp, 0); + return; } else if(!strncmp(cmd, "version", 7)) { UartSendString(src, (uint8_t*)versionString, 0); + return; + } + else if(!strncmp(cmd, "time", 4)) + { + sendTime(src); + return; } else if(!strncmp(cmd, "reboot", 6)) { @@ -531,6 +502,7 @@ void TermParse(Uart *src) else if(!strncmp(cmd, "print", 5)) { printConfig(src); + return; } else if(!strncmp(cmd, "list", 4)) //list calls in call filter table { @@ -542,56 +514,60 @@ void TermParse(Uart *src) if(DigiConfig.callFilter[i][0] != 0) { uint8_t cl[10] = {0}; - uint8_t clidx = 0; - for(uint8_t h = 0; h < 6; h++) + uint8_t clIdx = 0; + for(uint8_t j = 0; j < 6; j++) { - if(DigiConfig.callFilter[i][h] == 0xFF) //wildcard + if(DigiConfig.callFilter[i][j] == 0xFF) //wildcard { - uint8_t g = h; - uint8_t j = 0; - while(g < 6) + bool partialWildcard = false; + for(uint8_t k = j; k < 6; k++) //check if there are all characters wildcarded { - if(DigiConfig.callFilter[i][g] != 0xFF) - j = 1; - g++; + if(DigiConfig.callFilter[i][k] != 0xFF) + { + partialWildcard = true; + break; + } } - if(j == 0) + if(partialWildcard == false) //all characters wildcarded { - cl[clidx++] = '*'; + cl[clIdx++] = '*'; break; - } else + } + else { - cl[clidx++] = '?'; + cl[clIdx++] = '?'; } } else { - if(DigiConfig.callFilter[i][h] != ' ') - cl[clidx++] = DigiConfig.callFilter[i][h]; + if(DigiConfig.callFilter[i][j] != ' ') + cl[clIdx++] = DigiConfig.callFilter[i][j]; } } - if(DigiConfig.callFilter[i][6] == 0xFF) + if(DigiConfig.callFilter[i][6] == 0xFF) //wildcard on SSID { - cl[clidx++] = '-'; - cl[clidx++] = '*'; + cl[clIdx++] = '-'; + cl[clIdx++] = '*'; } else if(DigiConfig.callFilter[i][6] != 0) { - cl[clidx++] = '-'; + cl[clIdx++] = '-'; if(DigiConfig.callFilter[i][6] > 9) { - cl[clidx++] = (DigiConfig.callFilter[i][6] / 10) + 48; - cl[clidx++] = (DigiConfig.callFilter[i][6] % 10) + 48; + cl[clIdx++] = (DigiConfig.callFilter[i][6] / 10) + '0'; + cl[clIdx++] = (DigiConfig.callFilter[i][6] % 10) + '0'; } - else cl[clidx++] = DigiConfig.callFilter[i][6] + 48; + else + cl[clIdx++] = DigiConfig.callFilter[i][6] + '0'; } UartSendString(src, cl, 0); } else UartSendString(src, "empty", 0); + UartSendString(src, "\r\n", 0); - return; } + return; } /* * Settings insertion handling @@ -604,11 +580,6 @@ void TermParse(Uart *src) UartSendString(src, "Incorrect callsign!\r\n", 0); return; } - else - { - UartSendString(src, "OK\r\n", 0); - } - return; } else if(!strncmp(cmd, "dest", 4)) { @@ -617,10 +588,6 @@ void TermParse(Uart *src) UartSendString(src, "Incorrect address!\r\n", 0); return; } - else - { - UartSendString(src, "OK\r\n", 0); - } } else if(!strncmp(cmd, "txdelay", 7)) { @@ -633,7 +600,6 @@ void TermParse(Uart *src) else { Ax25Config.txDelayLength = (uint16_t)t; - UartSendString(src, "OK\r\n", 0); } } else if(!strncmp(cmd, "txtail", 6)) @@ -647,10 +613,8 @@ void TermParse(Uart *src) else { Ax25Config.txTailLength = (uint16_t)t; - UartSendString(src, "OK\r\n", 0); } } - else if(!strncmp(cmd, "quiet", 5)) { int64_t t = StrToInt(&cmd[6], len - 6); @@ -778,8 +742,6 @@ void TermParse(Uart *src) { err = true; } - - UartSendString(src, "OK\r\n", 0); } else if(!strncmp(cmd, "digi", 4)) { @@ -824,7 +786,6 @@ void TermParse(Uart *src) UartSendString(src, "Incorrect alias!\r\n", 0); return; } - UartSendString(src, "OK\r\n", 0); } else if((!strncmp(&cmd[7], "max ", 4) || !strncmp(&cmd[7], "rep ", 4)) && (alno < 4)) { @@ -949,7 +910,7 @@ void TermParse(Uart *src) uint8_t tmp[7] = {0}; uint16_t tmpIdx = 0; - for(uint16_t i = 0; i < len; i++) + for(uint16_t i = 0; i < (len - shift); i++) { if(cmd[shift + i] == '-') //SSID separator { @@ -1042,7 +1003,10 @@ void TermParse(Uart *src) err = true; } else + { UartSendString(src, "Unknown command. For command list type \"help\"\r\n", 0); + return; + } if(err) diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index 3cc6912..0bb8c0e 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -25,6 +25,7 @@ /* USER CODE BEGIN INCLUDE */ #include "drivers/uart.h" #include "drivers/systick.h" +#include "terminal.h" /* USER CODE END INCLUDE */ /* Private typedef -----------------------------------------------------------*/ @@ -276,6 +277,7 @@ static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) UartUsb.rxBufferHead %= UART_BUFFER_SIZE; } + UartUsb.rxType = DATA_USB; handleUsbInterrupt(&UartUsb); return (USBD_OK); @@ -320,13 +322,8 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) /* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */ static void handleUsbInterrupt(Uart *port) { -// if(port->port == USART1) //handle special functions and characters -// term_handleSpecial(TERM_UART1); -// else if(port->port == USART2) -// term_handleSpecial(TERM_UART2); - if(port->mode == MODE_KISS) - port->kissTimer = ticks + (5000 / SYSTICK_INTERVAL); //set timeout to 5s in KISS mode + port->kissTimer = SysTickGet() + (5000 / SYSTICK_INTERVAL); //set timeout to 5s in KISS mode if(port->rxBufferHead != 0) { diff --git a/vp-digi Debug.cfg b/vp-digi Debug.cfg new file mode 100644 index 0000000..e285a09 --- /dev/null +++ b/vp-digi Debug.cfg @@ -0,0 +1,35 @@ +# This is an NUCLEO-F103RB board with a single STM32F103RBTx chip +# +# Generated by System Workbench for STM32 +# Take care that such file, as generated, may be overridden without any early notice. Please have a look to debug launch configuration setup(s) + +source [find interface/stlink.cfg] + +set WORKAREASIZE 0x5000 + +transport select "hla_swd" + +set CHIPNAME STM32F103RBTx +set BOARDNAME NUCLEO-F103RB + +# CHIPNAMES state +set CHIPNAME_CPU0_ACTIVATED 1 + +# Enable debug when in low power modes +set ENABLE_LOW_POWER 1 + +# Stop Watchdog counters when halt +set STOP_WATCHDOG 1 + +# STlink Debug clock frequency +set CLOCK_FREQ 4000 + +# use software system reset +reset_config none +set CONNECT_UNDER_RESET 0 + +# BCTM CPU variables + + + +source [find target/stm32f1x.cfg] diff --git a/vp-digi Release.cfg b/vp-digi Release.cfg new file mode 100644 index 0000000..e285a09 --- /dev/null +++ b/vp-digi Release.cfg @@ -0,0 +1,35 @@ +# This is an NUCLEO-F103RB board with a single STM32F103RBTx chip +# +# Generated by System Workbench for STM32 +# Take care that such file, as generated, may be overridden without any early notice. Please have a look to debug launch configuration setup(s) + +source [find interface/stlink.cfg] + +set WORKAREASIZE 0x5000 + +transport select "hla_swd" + +set CHIPNAME STM32F103RBTx +set BOARDNAME NUCLEO-F103RB + +# CHIPNAMES state +set CHIPNAME_CPU0_ACTIVATED 1 + +# Enable debug when in low power modes +set ENABLE_LOW_POWER 1 + +# Stop Watchdog counters when halt +set STOP_WATCHDOG 1 + +# STlink Debug clock frequency +set CLOCK_FREQ 4000 + +# use software system reset +reset_config none +set CONNECT_UNDER_RESET 0 + +# BCTM CPU variables + + + +source [find target/stm32f1x.cfg]