From 5a1427ad11dd232126805371d80cdf001dd9debf Mon Sep 17 00:00:00 2001 From: Piotr Wilkon Date: Thu, 17 Aug 2023 14:57:29 +0200 Subject: [PATCH 1/4] major code refactoring and rewrite --- Inc/ax25.h | 67 +- Inc/beacon.h | 20 +- Inc/common.h | 72 +- Inc/config.h | 73 +- Inc/digipeater.h | 22 +- Inc/drivers/afsk.h_bak | 43 - Inc/drivers/modem.h | 81 +- Inc/drivers/systick.h | 7 +- Inc/drivers/uart.h | 128 +-- Inc/drivers/watchdog.h | 4 +- Inc/terminal.h | 88 +- Inc/usbd_cdc_if.h | 4 +- Src/ax25.c | 554 ++++++----- Src/beacon.c | 74 +- Src/common.c | 217 ++-- Src/config.c | 361 ++++--- Src/digipeater.c | 358 ++++--- Src/drivers/modem.c | 356 +++---- Src/drivers/systick.c | 5 +- Src/drivers/uart.c | 312 +++--- Src/drivers/watchdog.c | 4 +- Src/main.c | 300 +++--- Src/terminal.c | 2160 +++++++++++++--------------------------- Src/usbd_cdc_if.c | 55 +- 24 files changed, 2253 insertions(+), 3112 deletions(-) delete mode 100644 Inc/drivers/afsk.h_bak diff --git a/Inc/ax25.h b/Inc/ax25.h index 62cb223..bb2a910 100644 --- a/Inc/ax25.h +++ b/Inc/ax25.h @@ -18,46 +18,57 @@ along with VP-Digi. If not, see . #ifndef AX25_H_ #define AX25_H_ -#define FRAMELEN (150) //single frame max length -#define FRAMEBUFLEN (600) //circural frame buffer (multiple frames) length - +#include +#include -#include -typedef enum +enum Ax25RxStage { - RX_STAGE_IDLE, + RX_STAGE_IDLE = 0, RX_STAGE_FLAG, RX_STAGE_FRAME, -} RxStage; +}; -typedef struct +struct Ax25ProtoConfig { uint16_t txDelayLength; //TXDelay length in ms uint16_t txTailLength; //TXTail length in ms uint16_t quietTime; //Quiet time in ms uint8_t allowNonAprs; //allow non-APRS packets +}; -} Ax25_config; - -Ax25_config ax25Cfg; +extern struct Ax25ProtoConfig Ax25Config; +/** + * @brief Write frame to transmit buffer + * @param *data Data to transmit + * @param size Data size + * @return Pointer to internal frame handle or NULL on failure + * @attention This function will block if transmission is already in progress + */ +void *Ax25WriteTxFrame(uint8_t *data, uint16_t size); -typedef struct -{ - uint8_t frameBuf[FRAMEBUFLEN]; //cirucal buffer for received frames, frames are separated with 0xFF - uint16_t frameBufWr; //cirucal RX buffer write index - uint16_t frameBufRd; //circural TX buffer read index - uint8_t frameXmit[FRAMEBUFLEN]; //TX frame buffer - uint16_t xmitIdx; //TX frame buffer index - uint16_t sLvl; //RMS of the frame - uint8_t frameReceived; //frame received flag, must be polled in main loop for >0. Bit 0 for frame received on decoder 1, bit 1 for decoder 2 +/** + * @brief Get bitmap of "frame received" flags for each decoder. A non-zero value means that a frame was received + * @return Bitmap of decoder that received the frame + */ +uint8_t Ax25GetReceivedFrameBitmap(void); -} Ax25; +/** + * @brief Clear bitmap of "frame received" flags + */ +void Ax25ClearReceivedFrameBitmap(void); -Ax25 ax25; +/** + * @brief Get next received frame (if available) + * @param **dst Destination buffer that this function allocates and fills + * @param *size Actual frame size + * @param *signalLevel Frame signal level (RMS) + * @return True if frame was read, false if no more frames to read + */ +bool Ax25ReadNextRxFrame(uint8_t **dst, uint16_t *size, uint16_t *signalLevel); /** * @brief Get current RX stage @@ -65,7 +76,7 @@ Ax25 ax25; * @return RX_STATE_IDLE, RX_STATE_FLAG or RX_STATE_FRAME * @warning Only for internal use */ -RxStage Ax25_getRxStage(uint8_t modemNo); +enum Ax25RxStage Ax25GetRxStage(uint8_t modemNo); /** * @brief Parse incoming bit (not symbol!) @@ -74,29 +85,29 @@ RxStage Ax25_getRxStage(uint8_t modemNo); * @param[in] *dem Modem state pointer * @warning Only for internal use */ -void Ax25_bitParse(uint8_t bit, uint8_t modemNo); +void Ax25BitParse(uint8_t bit, uint8_t modemNo); /** * @brief Get next bit to be transmitted * @return Bit to be transmitted * @warning Only for internal use */ -uint8_t Ax25_getTxBit(void); +uint8_t Ax25GetTxBit(void); /** * @brief Initialize transmission and start when possible */ -void Ax25_transmitBuffer(void); +void Ax25TransmitBuffer(void); /** * @brief Start transmitting when possible * @attention Must be continuously polled in main loop */ -void Ax25_transmitCheck(void); +void Ax25TransmitCheck(void); /** * @brief Initialize AX25 module */ -void Ax25_init(void); +void Ax25Init(void); #endif /* AX25_H_ */ diff --git a/Inc/beacon.h b/Inc/beacon.h index 9106104..57b019f 100644 --- a/Inc/beacon.h +++ b/Inc/beacon.h @@ -21,35 +21,35 @@ along with VP-Digi. If not, see . #include +#define BEACON_MAX_PAYLOAD_SIZE 100 - -typedef struct +struct Beacon { uint8_t enable; //enable beacon uint32_t interval; //interval in seconds uint32_t delay; //delay in seconds - uint8_t data[101]; //information field + uint8_t data[BEACON_MAX_PAYLOAD_SIZE + 1]; //information field uint8_t path[15]; //path, 2 parts max, e.g. WIDE11SP22, can be at byte 0, 7 and 14 uint32_t next; //next beacon timestamp -} Beacon; +}; -Beacon beacon[8]; +extern struct Beacon beacon[8]; /** * @brief Send specified beacon - * @param[in] no Beacon number (0-7) + * @param number Beacon number (0-7) */ -void Beacon_send(uint8_t no); +void BeaconSend(uint8_t number); /** - * @brief Check if any beacon should be transmitted and transmit if neccessary + * @brief Check if any beacon should be transmitted and transmit if necessary */ -void Beacon_check(void); +void BeaconCheck(void); /** * @brief Initialize beacon module */ -void Beacon_init(void); +void BeaconInit(void); #endif /* BEACON_H_ */ diff --git a/Inc/common.h b/Inc/common.h index dec1af8..fb2262c 100644 --- a/Inc/common.h +++ b/Inc/common.h @@ -18,20 +18,25 @@ along with VP-Digi. If not, see . #define COMMON_H_ #include +#include "drivers/uart.h" +#define IS_UPPERCASE_ALPHANUMERIC(x) ((((x) >= '0') && ((x) <= '9')) || (((x) >= 'A') && ((x) <= 'Z'))) +#define IS_NUMBER(x) (((x) >= '0') && ((x) <= '9')) #define CRC32_INIT 0xFFFFFFFF -uint8_t call[6]; //device callsign -uint8_t callSsid; //device ssid +struct _GeneralConfig +{ + uint8_t call[6]; //device callsign + uint8_t callSsid; //device ssid + uint8_t dest[7]; //destination address for own beacons. Should be APNV01-0 for VP-Digi, but can be changed. SSID MUST remain 0. + uint8_t kissMonitor; +}; -uint8_t dest[7]; //destination address for own beacons. Should be APNV01-0 for VP-Digi, but can be changed. SSID MUST remain 0. +extern struct _GeneralConfig GeneralConfig; -const uint8_t *versionString; //version string +extern const char versionString[]; //version string -uint8_t autoReset; -uint32_t autoResetTimer; -uint8_t kissMonitor; /** * @brief Generate random number from min to max @@ -39,7 +44,7 @@ uint8_t kissMonitor; * @param[in] max Higher boundary * @return Generated number */ -int16_t rando(int16_t min, int16_t max); +int16_t Random(int16_t min, int16_t max); /** * @brief Convert string to int @@ -47,15 +52,23 @@ int16_t rando(int16_t min, int16_t max); * @param[in] len String length or 0 to detect by strlen() * @return Converted int */ -int64_t strToInt(uint8_t *str, uint8_t len); +int64_t StrToInt(const char *str, uint16_t len); + +///** +// * @brief Convert AX25 frame to TNC2 (readable) format +// * @param *from Input AX25 frame +// * @param len Input frame length +// * @param *to Destination buffer, will be NULL terminated +// * @param limit Destination buffer size limit +// */ +//void ConvertToTNC2(uint8_t *from, uint16_t fromlen, uint8_t *to, uint16_t limit); /** - * @brief Convert AX25 frame to TNC2 (readable) format - * @param[in] *from Input AX25 frame - * @param[in] len Input frame length - * @param[out] *to Destination buffer, will be NULL terminated + * @brief Convert AX25 frame to TNC2 (readable) format and send it through available ports + * @param *from Input AX25 frame + * @param len Input frame length */ -void common_toTNC2(uint8_t *from, uint16_t fromlen, uint8_t *to); +void SendTNC2(uint8_t *from, uint16_t len); /** * @brief Calculate CRC32 @@ -64,13 +77,34 @@ void common_toTNC2(uint8_t *from, uint16_t fromlen, uint8_t *to); * @param[in] n Input data length * @return Calculated CRC32 */ -uint32_t crc32(uint32_t crc0, uint8_t *s, uint64_t n); +uint32_t Crc32(uint32_t crc0, uint8_t *s, uint64_t n); + +/** + * @brief Check if callsign is correct and convert it to AX.25 format + * @param *in Input ASCII callsign + * @param size Input size, not bigger than 6 + * @param *out Output buffer, exactly 6 bytes + * @return True if callsign is valid + */ +bool ParseCallsign(const char *in, uint16_t size, uint8_t *out); + +/** + * @brief Check if callsign with SSID is correct and convert it to AX.25 format + * @param *in Input ASCII callsign with SSID + * @param size Input size + * @param *out Output buffer, exactly 6 bytes + * @param *ssid Output SSID, exactly 1 byte + * @return True if callsign is valid + */ +bool ParseCallsignWithSsid(const char *in, uint16_t size, uint8_t *out, uint8_t *ssid); /** - * @brief Send frame to available UARTs and USB in KISS format - * @param[in] *buf Frame buffer - * @param[in] len Frame buffer length + * @brief Check if SSID is correct and convert it to uint8_t + * @param *in Input ASCII SSID + * @param size Input size + * @param *out Output buffer, exactly 1 byte + * @return True if SSID is valid */ -void SendKiss(uint8_t *buf, uint16_t len); +bool ParseSsid(const char *in, uint16_t size, uint8_t *out); #endif /* COMMON_H_ */ diff --git a/Inc/config.h b/Inc/config.h index 2c1a4a7..1dcb11c 100644 --- a/Inc/config.h +++ b/Inc/config.h @@ -22,88 +22,21 @@ along with VP-Digi. If not, see . #include -#define FLAG_CONFIG_WRITTEN 0x6B - -#define MEM_CONFIG 0x800F000 - -//these are relative addresses, absolute address is calculated as relative address + MEM_CONFIG -//all fields are 16-bit or n*16-bit long, as data in flash is stored in 16-bit words -#define CONFIG_FLAG 0 //configuration written flag -#define CONFIG_CALL 2 -#define CONFIG_SSID 8 -#define CONFIG_TXDELAY 10 -#define CONFIG_TXTAIL 12 -#define CONFIG_TXQUIET 14 -#define CONFIG_RS1BAUD 16 -#define CONFIG_RS2BAUD 20 -#define CONFIG_BEACONS 24 -#define CONFIG_BCIV 26 //beacon intervals -#define CONFIG_BCDL 42 //beacon delays -#define CONFIG_BC0 58 //beacon information fields, null terminated -#define CONFIG_BC1 158 -#define CONFIG_BC2 258 -#define CONFIG_BC3 358 -#define CONFIG_BC4 458 -#define CONFIG_BC5 558 -#define CONFIG_BC6 658 //668 ? it should be 658 e.t.c. -#define CONFIG_BC7 758 -#define CONFIG_BCP0 858 //beacon paths, 14 bytes each -#define CONFIG_BCP1 872 -#define CONFIG_BCP2 886 -#define CONFIG_BCP3 900 -#define CONFIG_BCP4 914 -#define CONFIG_BCP5 928 -#define CONFIG_BCP6 942 -#define CONFIG_BCP7 956 -#define CONFIG_DIGION 970 -#define CONFIG_DIGIEN 972 -#define CONFIG_DIGIVISC 974 //viscous-delay settings in higher half, direct-only in lower half -#define CONFIG_DIGIAL0 976 -#define CONFIG_DIGIAL1 982 -#define CONFIG_DIGIAL2 988 -#define CONFIG_DIGIAL3 994 -#define CONFIG_DIGIAL4 1000 -#define CONFIG_DIGIAL5 1008 -#define CONFIG_DIGIAL6 1016 -#define CONFIG_DIGIAL7 1024 -#define CONFIG_DIGIMAX0 1032 -#define CONFIG_DIGIMAX1 1034 -#define CONFIG_DIGIMAX2 1036 -#define CONFIG_DIGIMAX3 1038 -#define CONFIG_DIGIREP0 1040 -#define CONFIG_DIGIREP1 1042 -#define CONFIG_DIGIREP2 1044 -#define CONFIG_DIGIREP3 1046 -#define CONFIG_DIGITRACE 1048 -#define CONFIG_DIGIDEDUPE 1050 -#define CONFIG_DIGICALLFILEN 1052 -#define CONFIG_DIGIFILLIST 1054 -#define CONFIG_DIGIFILTYPE 1194 -#define CONFIG_AUTORST 1196 -#define CONFIG_DIGISSID4 1198 -#define CONFIG_DIGISSID5 1200 -#define CONFIG_DIGISSID6 1202 -#define CONFIG_DIGISSID7 1204 -#define CONFIG_PWM_FLAT 1206 -#define CONFIG_KISSMONITOR 1208 -#define CONFIG_DEST 1210 -#define CONFIG_ALLOWNONAPRS 1216 -#define CONFIG_XXX 1218 //next address (not used) /** * @brief Store configuration from RAM to Flash */ -void Config_write(void); +void ConfigWrite(void); /** * @brief Erase all configuration */ -void Config_erase(void); +void ConfigErase(void); /** * @brief Read configuration from Flash to RAM * @return 1 if success, 0 if no configuration stored in Flash */ -uint8_t Config_read(void); +uint8_t ConfigRead(void); #endif /* CONFIG_H_ */ diff --git a/Inc/digipeater.h b/Inc/digipeater.h index eacc2da..d75da18 100644 --- a/Inc/digipeater.h +++ b/Inc/digipeater.h @@ -21,9 +21,7 @@ along with VP-Digi. If not, see . #include - - -typedef struct +struct _DigiConfig { uint8_t alias[8][6]; //digi alias list uint8_t ssid[4]; //ssid list for simple aliases @@ -40,8 +38,7 @@ typedef struct uint8_t filterPolarity : 1; //filter polarity: 0 - blacklist, 1- whitelist } Digi; -Digi digi; //digipeater state - +extern struct _DigiConfig DigiConfig; //digipeater state /** @@ -50,18 +47,19 @@ Digi digi; //digipeater state * @param[in] len Frame length * Decides whether the frame should be digipeated or not, processes it and pushes to TX buffer if needed */ -void Digi_digipeat(uint8_t *frame, uint16_t len); +void DigiDigipeat(uint8_t *frame, uint16_t len); /** - * @brief Store duplicate protection hash for the frame already pushed to TX buffer - * @param[in] idx First frame byte index in TX buffer + * @brief Store duplicate protection hash for frame + * @param *buf Frame buffer + * @param size Frame size */ -void Digi_storeDeDupeFromXmitBuf(uint16_t idx); +void DigiStoreDeDupe(uint8_t *buf, uint16_t size); /** - * @brief Refresh viscous-delay buffers and push frames to TX buffer if neccessary - * @attention Should be called constantly + * @brief Refresh viscous-delay buffers and push frames to TX buffer if necessary + * @attention Should be called in main loop */ -void Digi_viscousRefresh(void); +void DigiViscousRefresh(void); #endif /* DIGIPEATER_H_ */ diff --git a/Inc/drivers/afsk.h_bak b/Inc/drivers/afsk.h_bak deleted file mode 100644 index 1cac2de..0000000 --- a/Inc/drivers/afsk.h_bak +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef DRIVERS_AFSK_H_ -#define DRIVERS_AFSK_H_ - -//#define ALVLDBG - -#include "systick.h" -#include "stm32f10x.h" -#include -#include -#include -#include "variables.h" -#include "common.h" -#include "ax25.h" - -#ifdef ALVLDBG -#include "drivers/uart.h" -#endif - -#define NN 8 //probkowanie/baudrate - -#define PTT_ON GPIOC->BSRR = GPIO_BSRR_BS14 -#define PTT_OFF GPIOC->BSRR = GPIO_BSRR_BR14 -#define DCD_ON (GPIOC->BSRR = GPIO_BSRR_BR13) -#define DCD_OFF (GPIOC->BSRR = GPIO_BSRR_BS13) - -void afsk_decode(uint8_t); -int32_t afsk_demod(int16_t); -void DMA1_Channel2_IRQHandler(void) __attribute__ ((interrupt)); -void DMA1_Channel2_IRQHandler(void); -void TIM2_IRQHandler(void) __attribute__ ((interrupt)); -void TIM2_IRQHandler(void); -void TIM3_IRQHandler(void) __attribute__ ((interrupt)); -void TIM3_IRQHandler(void); -void afsk_sendTone(uint8_t); -void afsk_sendFlag(uint8_t); -void afsk_transmitTestStart(uint8_t); -void afsk_transmitTestStop(void); -void afsk_transmitStart(void); -void afsk_transmitStop(void); -void afsk_init(void); - - -#endif diff --git a/Inc/drivers/modem.h b/Inc/drivers/modem.h index 5d7ddf6..19bb73a 100644 --- a/Inc/drivers/modem.h +++ b/Inc/drivers/modem.h @@ -20,98 +20,105 @@ along with VP-Digi. If not, see . #include +//number of parallel demodulators +//each demodulator must be explicitly configured in code +#define MODEM_DEMODULATOR_COUNT 2 -typedef enum +#define MODEM_BAUDRATE 1200.f +#define MODEM_MARK_FREQUENCY 1200.f +#define MODEM_SPACE_FREQUENCY 2200.f + +enum ModemTxTestMode { TEST_DISABLED, TEST_MARK, TEST_SPACE, TEST_ALTERNATING, -} TxTestMode; +}; -typedef struct +struct ModemDemodConfig { uint8_t usePWM : 1; //0 - use R2R, 1 - use PWM uint8_t flatAudioIn : 1; //0 - normal (deemphasized) audio input, 1 - flat audio (unfiltered) input -} Afsk_config; +}; -Afsk_config afskCfg; +extern struct ModemDemodConfig ModemConfig; -typedef enum +enum ModemEmphasis { PREEMPHASIS, DEEMPHASIS, EMPHASIS_NONE -} Emphasis; +}; + /** - * @brief Get current DCD (channel busy) state - * @return 0 if channel free, 1 if busy + * @brief Get filter type (preemphasis, deemphasis etc.) for given modem + * @param modem Modem number + * @return Filter type */ -uint8_t Afsk_dcdState(void); +enum ModemEmphasis ModemGetFilterType(uint8_t modem); /** - * @brief Check if there is an ongoing TX test - * @return 0 if not, 1 if any TX test is enabled + * @brief Get current DCD state + * @return 1 if channel busy, 0 if free */ -uint8_t Afsk_isTxTestOngoing(void); +uint8_t ModemDcdState(void); /** - * @brief Clear RMS meter state for specified modem - * @param[in] modemNo Modem number: 0 or 1 + * @brief Check if there is a TX test mode enabled + * @return 1 if in TX test mode, 0 otherwise */ -void Afsk_clearRMS(uint8_t modemNo); +uint8_t ModemIsTxTestOngoing(void); /** - * @brief Clear RMS value from specified modem - * @param[in] modemNo Modem number: 0 or 1 - * @return RMS + * @brief Clear modem RMS counter + * @param number Modem number */ -uint16_t Afsk_getRMS(uint8_t modemNo); +void ModemClearRMS(uint8_t number); /** - * @brief Current DCD state - * @return 0 if no DCD (channel free), 1 if DCD + * @brief Get RMS value for modem + * @param number Modem number + * @return RMS value */ -uint8_t Afsk_dcdState(void); +uint16_t ModemGetRMS(uint8_t number); /** * @brief Start or restart TX test mode - * @param[in] type TX test type: TEST_MARK, TEST_SPACE or TEST_ALTERNATING + * @param type TX test type: TEST_MARK, TEST_SPACE or TEST_ALTERNATING */ -void Afsk_txTestStart(TxTestMode type); +void ModemTxTestStart(enum ModemTxTestMode type); /** * @brief Stop TX test mode */ -void Afsk_txTestStop(void); - +void ModemTxTestStop(void); /** * @brief Configure and start TX - * @warning Transmission should be started with Ax25_transmitBuffer + * @info This function is used internally by protocol module. + * @warning Use Ax25TransmitStart() to initialize transmission */ -void Afsk_transmitStart(void); +void ModemTransmitStart(void); /** * @brief Stop TX and go back to RX */ -void Afsk_transmitStop(void); +void ModemTransmitStop(void); /** - * @brief Initialize AFSK module + * @brief Initialize modem module */ -void Afsk_init(void); +void ModemInit(void); - -void DMA1_Channel2_IRQHandler(void) __attribute__ ((interrupt)); -void TIM3_IRQHandler(void) __attribute__ ((interrupt)); -void TIM2_IRQHandler(void) __attribute__ ((interrupt)); - +#if (MODEM_DEMODULATOR_COUNT > 8) +#error There may be at most 8 parallel demodulators/decoders +#endif #endif diff --git a/Inc/drivers/systick.h b/Inc/drivers/systick.h index dc0428a..93a5378 100644 --- a/Inc/drivers/systick.h +++ b/Inc/drivers/systick.h @@ -19,12 +19,15 @@ along with VP-Digi. If not, see . #define SYSTICK_H_ #include -#include "stm32f1xx.h" + + +#define SYSTICK_FREQUENCY 100 //systick frequency in Hz +#define SYSTICK_INTERVAL (1000 / SYSTICK_FREQUENCY) //systick interval in milliseconds extern volatile uint32_t ticks; //void SysTick_Handler(void); -void SysTick_init(void); +void SysTickInit(void); #endif /* SYSTICK_H_ */ diff --git a/Inc/drivers/uart.h b/Inc/drivers/uart.h index b2bcf49..3d967cb 100644 --- a/Inc/drivers/uart.h +++ b/Inc/drivers/uart.h @@ -18,124 +18,102 @@ along with VP-Digi. If not, see . #ifndef UART_H_ #define UART_H_ -#define UARTBUFLEN 250 - #include "stm32f1xx.h" #include #include "usbd_cdc_if.h" +#include "ax25.h" + +#define UART_BUFFER_SIZE 250 -typedef enum +enum UartMode { MODE_KISS, MODE_TERM, MODE_MONITOR, -} Uart_mode; +}; -typedef enum +enum UartDataType { + DATA_NOTHING = 0, DATA_KISS, DATA_TERM, - DATA_NOTHING, -} Uart_data_type; +}; typedef struct { volatile USART_TypeDef *port; //UART peripheral uint32_t baudrate; //baudrate 1200-115200 - Uart_data_type rxflag; //rx status - uint8_t txflag; //tx status (1 when transmitting) - uint8_t bufrx[UARTBUFLEN]; //buffer for rx data - uint16_t bufrxidx; //rx data buffer index - uint8_t buftx[UARTBUFLEN]; //circular tx buffer - uint16_t buftxrd, buftxwr; //tx buffer indexes - Uart_mode mode; //uart mode - uint8_t enabled; + enum UartDataType rxType; //rx status + uint8_t enabled : 1; + uint8_t isUsb : 1; + uint8_t rxBuffer[UART_BUFFER_SIZE]; + uint16_t rxBufferHead; + uint8_t txBuffer[UART_BUFFER_SIZE]; + uint16_t txBufferHead, txBufferTail; + uint8_t txBufferFull : 1; + enum UartMode mode; uint32_t kissTimer; } Uart; -Uart uart1, uart2; - -Uart_mode USBmode; -Uart_data_type USBrcvd; -uint8_t USBint; //USB "interrupt" flag - - -/** - * \brief Copy KISS frame(s) from input buffer to APRS TX buffer - * \param[in] *buf Input buffer - * \param[in] len Input buffer size - */ -uint8_t Uart_txKiss(uint8_t *buf, uint16_t len); - +extern Uart Uart1, Uart2, UartUsb; -/** - * \brief Send single byte using USB - * \param[in] data Byte - */ -void uartUSB_sendByte(uint8_t data); +///** +// * \brief Copy KISS frame(s) from input buffer to APRS TX buffer +// * \param[in] *buf Input buffer +// * \param[in] len Input buffer size +// */ +//uint8_t Uart_txKiss(uint8_t *buf, uint16_t len); /** - * \brief Start buffer transmission - * \param[in] *port UART - */ -void uart_transmitStart(Uart *port); - -/** - * \brief Store byte in TX buffer - * \param[in] *port UART - * \param[in] data Data + * @brief Send byte + * @param[in] *port UART + * @param[in] data Data */ -void uart_sendByte(Uart *port, uint8_t data); +void UartSendByte(Uart *port, uint8_t data); /** - * \brief Store string in TX buffer - * \apram[in] *port UART - * \param[in] *data Buffer - * \param[in] len Buffer length or 0 for null-terminated string + * @brief Send string + * @param *port UART + * @param *data Buffer + * @param len Buffer length or 0 for null-terminated string */ -void uart_sendString(Uart *port, uint8_t *data, uint16_t datalen); +void UartSendString(Uart *port, void *data, uint16_t datalen); /** - * \brief Send string using USB - * \param[in] *data Buffer - * \param[in] len Buffer length or 0 for null-terminated string + * @brief Send signed number + * @param *port UART + * @param n Number */ -void uartUSB_sendString(uint8_t* data, uint16_t len); +void UartSendNumber(Uart *port, int32_t n); -/** - * \brief Store number (in ASCII format) in TX buffer - * \param[in] *port UART - * \param[in] n Number - */ -void uart_sendNumber(Uart *port, int32_t n); /** - * \brief Send number (in ASCII format) using USB - * \param[in] n Number + * @brief Initialize UART structures + * @param *port UART [prt + * @param *uart Physical UART peripheral. NULL if USB in CDC mode + * @param baud Baudrate */ -void uartUSB_sendNumber(int32_t n); - +void UartInit(Uart *port, USART_TypeDef *uart, uint32_t baud); /** - * \brief Initialize UART structures - * \param[in] *port UART - * \param[in] *uart Physical UART peripheral - * \param[in] baud Baudrate + * @brief Configure and enable/disable UART + * @param *port UART port + * @param state 0 - disable, 1 - enable */ -void uart_init(Uart *port, USART_TypeDef *uart, uint32_t baud); +void UartConfig(Uart *port, uint8_t state); /** - * \brief Configure and enable/disable UART - * \param[in] *port UART - * \param[in] state 0 - disable, 1 - enable + * @brief Clear RX buffer and flags + * @param *port UART port */ -void uart_config(Uart *port, uint8_t state); +void UartClearRx(Uart *port); /** - * \brief Clear RX buffer and flags - * \param[in] *port UART + * @brief Handle KISS timeout + * @param *port UART pointer + * @attention This function must be polled constantly in main loop for USB UART. */ -void uart_clearRx(Uart *port); +void UartHandleKissTimeout(Uart *port); #endif diff --git a/Inc/drivers/watchdog.h b/Inc/drivers/watchdog.h index 4623368..fb4be59 100644 --- a/Inc/drivers/watchdog.h +++ b/Inc/drivers/watchdog.h @@ -23,12 +23,12 @@ along with VP-Digi. If not, see . /** * @brief Initialize watchdog */ -void Wdog_init(void); +void WdogInit(void); /** * @brief Restart watchdog * @attention Must be called continuously in main loop */ -void Wdog_reset(void); +void WdogReset(void); #endif /* DRIVERS_WATCHDOG_H_ */ diff --git a/Inc/terminal.h b/Inc/terminal.h index 95d62af..45623ce 100644 --- a/Inc/terminal.h +++ b/Inc/terminal.h @@ -21,71 +21,39 @@ along with VP-Digi. If not, see . #include "drivers/uart.h" #include - -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 Send data to all available monitor outputs - * \param[in] *data Data to send - * \param[in] len Data length or 0 for NULL-terminated data - */ -void term_sendMonitor(uint8_t *data, uint16_t len); - -/** - * \brief Send number to all available monitor outputs - * \param[in] data Number to send - */ -void term_sendMonitorNumber(int32_t data); - -/** -* \brief Send terminal buffer using specified stream -* \param[in] way Stream: TERM_ANY, TERM_USB, TERM_UART1, TERM_UART2 -*/ -void term_sendBuf(Terminal_stream way); - -/** - * \brief Push byte to terminal buffer - * \param[in] data Byte to store - */ -void term_sendByte(uint8_t data); - -/** - * \brief Push string to terminal buffer - * \param[in] *data String - * \param[in] len String length or 0 for NULL-terminated string - */ -void term_sendString(uint8_t *data, uint16_t len); - /** - * \brief Push number (in ASCII form) in terminal buffer - * \param[in] n Number + * @brief Send data to all available ports + * @param mode Output mode/data type + * @param *data Data buffer + * @param size Data size */ -void term_sendNumber(int32_t n); +void TermSendToAll(enum UartMode mode, uint8_t *data, uint16_t size); + +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[in] *cmd Data - * \param[in] len Data length - * \param[in] src Source: TERM_USB, TERM_UART1, TERM_UART2 - * \param[in] type Data type: DATA_KISS, DATA_TERM - * \param[in] mode Input mode: MODE_KISS, MODE_TERM, MODE_MONITOR + * \param *src UART structure */ -void term_parse(uint8_t *cmd, uint16_t len, Terminal_stream src, Uart_data_type type, Uart_mode mode); +void TermParse(Uart *src); #endif /* DEBUG_H_ */ diff --git a/Inc/usbd_cdc_if.h b/Inc/usbd_cdc_if.h index 84ca6fa..9792e9a 100644 --- a/Inc/usbd_cdc_if.h +++ b/Inc/usbd_cdc_if.h @@ -91,9 +91,7 @@ extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS; /* USER CODE BEGIN EXPORTED_VARIABLES */ -uint8_t usbrcvdflag; -uint8_t usbcdcdata[UARTBUFLEN]; -uint16_t usbcdcidx; + /* USER CODE END EXPORTED_VARIABLES */ /** diff --git a/Src/ax25.c b/Src/ax25.c index de8666a..941c907 100644 --- a/Src/ax25.c +++ b/Src/ax25.c @@ -20,6 +20,44 @@ along with VP-Digi. If not, see . #include "drivers/modem.h" #include "common.h" #include "drivers/systick.h" +#include + +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_COUNT (10) //max count of frames in buffer +#define FRAME_BUFFER_SIZE (FRAME_MAX_COUNT * FRAME_MAX_SIZE) //circular frame buffer length + +#define STATIC_HEADER_FLAG_COUNT 4 //number of flags sent before each frame +#define STATIC_FOOTER_FLAG_COUNT 8 //number of flags sent after each frame + +#define MAX_TRANSMIT_RETRY_COUNT 8 //max number of retries if channel is busy + +struct FrameHandle +{ + uint16_t start; + uint16_t size; + uint16_t signalLevel; +}; + +static uint8_t rxBuffer[FRAME_BUFFER_SIZE]; //circular buffer for received frames +static uint16_t rxBufferHead = 0; //circular RX buffer write index +static struct FrameHandle rxFrame[FRAME_MAX_COUNT]; +static uint8_t rxFrameHead = 0; +static uint8_t rxFrameTail = 0; +static bool rxFrameBufferFull = false; + +static uint8_t txBuffer[FRAME_BUFFER_SIZE]; //circular TX frame buffer +static uint16_t txBufferHead = 0; //circular TX buffer write index +static uint16_t txBufferTail = 0; +static struct FrameHandle txFrame[FRAME_MAX_COUNT]; +static uint8_t txFrameHead = 0; +static uint8_t txFrameTail = 0; +static bool txFrameBufferFull = false; + +static uint8_t frameReceived; //a bitmap of receivers that received the frame + enum TxStage { @@ -39,89 +77,148 @@ enum TxInitStage TX_INIT_TRANSMITTING }; -struct TxState +static uint8_t txByte = 0; //current TX byte +static uint16_t txByteIdx = 0; //current TX byte index +static int8_t txBitIdx = 0; //current bit index in txByte +static uint16_t txDelayElapsed = 0; //counter of TXDelay bytes already sent +static uint8_t txFlagsElapsed = 0; //counter of flag bytes already sent +static uint8_t txCrcByteIdx = 0; //currently transmitted byte of CRC +static uint8_t txBitstuff = 0; //bit-stuffing counter +static uint16_t txTailElapsed; //counter of TXTail bytes already sent +static uint16_t txCrc = 0xFFFF; //current CRC +static uint32_t txQuiet = 0; //quit time + current tick value +static uint8_t txRetries = 0; //number of TX retries +static enum TxInitStage txInitStage; //current TX initialization stage +static enum TxStage txStage; //current TX stage + +struct RxState { - uint8_t txByte; //current TX byte - int8_t txBitIdx; //current bit index in txByte - uint16_t txDelayElapsed; //counter of TXDelay bytes already sent - uint8_t flagsElapsed; //counter of flag bytes already sent - uint16_t xmitIdx; //current TX byte index in TX buffer - uint8_t crcIdx; //currently transmitted byte of CRC - uint8_t bitstuff; //bit-stuffing counter - uint16_t txTailElapsed; //counter of TXTail bytes already sent - uint16_t txDelay; //number of TXDelay bytes to send - uint16_t txTail; //number of TXTail bytes to send uint16_t crc; //current CRC - uint32_t txQuiet; //quit time + current tick value - uint8_t txRetries; //number of TX retries - enum TxInitStage tx; //current TX initialization stage - enum TxStage txStage; //current TX stage -}; - -volatile struct TxState txState; - - -typedef struct -{ - uint16_t crc; //current CRC - uint8_t frame[FRAMELEN]; //raw frame buffer + uint8_t frame[FRAME_MAX_SIZE]; //raw frame buffer uint16_t frameIdx; //index for raw frame buffer - uint8_t recByte; //byte being currently received - uint8_t rBitIdx; //bit index for recByte + uint8_t receivedByte; //byte being currently received + uint8_t receivedBitIdx; //bit index for recByte uint8_t rawData; //raw data being currently received - RxStage rx; //current RX stage + enum Ax25RxStage rx; //current RX stage uint8_t frameReceived; //frame received flag -} RxState; - -volatile RxState rxState1, rxState2; +}; -uint16_t lastCrc = 0; //CRC of the last received frame. If not 0, a frame was successfully received -uint16_t rxMultiplexDelay = 0; //simple delay for decoder multiplexer to avoid receiving the same frame twice +static volatile struct RxState rxState[MODEM_DEMODULATOR_COUNT]; -RxStage Ax25_getRxStage(uint8_t modemNo) -{ - if(modemNo == 0) - return rxState1.rx; - - return rxState2.rx; -} +static uint16_t lastCrc = 0; //CRC of the last received frame. If not 0, a frame was successfully received +static uint16_t rxMultiplexDelay = 0; //simple delay for decoder multiplexer to avoid receiving the same frame twice +static uint16_t txDelay; //number of TXDelay bytes to send +static uint16_t txTail; //number of TXTail bytes to send +#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)) /** * @brief Recalculate CRC for one bit - * @param[in] bit Input bit + * @param bit Input bit * @param *crc CRC pointer */ -static void ax25_calcCRC(uint8_t bit, uint16_t *crc) { - static uint16_t xor_result; +static void calculateCRC(uint8_t bit, uint16_t *crc) +{ + uint16_t xor_result; xor_result = *crc ^ bit; *crc >>= 1; if (xor_result & 0x0001) { *crc ^= 0x8408; } - return; } -void Ax25_bitParse(uint8_t bit, uint8_t modemNo) +uint8_t Ax25GetReceivedFrameBitmap(void) { - if(lastCrc > 0) //there was a frame received + return frameReceived; +} + +void Ax25ClearReceivedFrameBitmap(void) +{ + frameReceived = 0; +} + +void *Ax25WriteTxFrame(uint8_t *data, uint16_t size) +{ + while(txStage != TX_STAGE_IDLE) + ; + + if((GET_FREE_SIZE(FRAME_BUFFER_SIZE, txBufferHead, txBufferTail) < size) || txFrameBufferFull) + { + return NULL; + } + + + txFrame[txFrameHead].size = size; + txFrame[txFrameHead].start = txBufferHead; + for(uint16_t i = 0; i < size; i++) + { + txBuffer[txBufferHead++] = data[i]; + txBufferHead %= FRAME_BUFFER_SIZE; + } + void *ret = &txFrame[txFrameHead]; + txFrameHead++; + txFrameHead %= FRAME_MAX_COUNT; + if(txFrameHead == txFrameTail) + txFrameBufferFull = true; + return ret; +} + + +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; + } + + for(uint16_t i = 0; i < rxFrame[rxFrameTail].size; i++) + { + (*dst)[i] = rxBuffer[(rxFrame[rxFrameTail].start + i) % FRAME_BUFFER_SIZE]; + } + + *signalLevel = rxFrame[rxFrameTail].signalLevel; + *size = rxFrame[rxFrameTail].size; + + rxFrameBufferFull = false; + rxFrameTail++; + rxFrameTail %= FRAME_MAX_COUNT; + return true; +} + +enum Ax25RxStage Ax25GetRxStage(uint8_t modem) +{ + return rxState[modem].rx; +} + + +void Ax25BitParse(uint8_t bit, uint8_t modem) +{ + if(lastCrc != 0) //there was a frame received { rxMultiplexDelay++; - if(rxMultiplexDelay > 4) //hold it for a while and wait for the other decoder to receive the frame + if(rxMultiplexDelay > (4 * MODEM_DEMODULATOR_COUNT)) //hold it for a while and wait for other decoders to receive the frame { lastCrc = 0; rxMultiplexDelay = 0; - ax25.frameReceived = (rxState1.frameReceived > 0) | ((rxState2.frameReceived > 0) << 1); + for(uint8_t i = 0; i < MODEM_DEMODULATOR_COUNT; i++) + { + frameReceived |= ((rxState[i].frameReceived > 0) << i); + rxState[i].frameReceived = 0; + } } } - RxState *rx = (RxState*)&rxState1; - if(modemNo == 1) - rx = (RxState*)&rxState2; + struct RxState *rx = (struct RxState*)&(rxState[modem]); rx->rawData <<= 1; //store incoming bit rx->rawData |= (bit > 0); @@ -129,7 +226,7 @@ void Ax25_bitParse(uint8_t bit, uint8_t modemNo) if(rx->rawData == 0x7E) //HDLC flag received { - if(rx->rx == RX_STAGE_FRAME) //we are in frame, so this is the end of the frame + if(rx->rx == RX_STAGE_FRAME) //if we are in frame, this is the end of the frame { if((rx->frameIdx > 15)) //correct frame must be at least 16 bytes long { @@ -142,69 +239,55 @@ void Ax25_bitParse(uint8_t bit, uint8_t modemNo) //if non-APRS frames are not allowed, check if this frame has control=0x03 and PID=0xF0 - if(!ax25Cfg.allowNonAprs && ((rx->frame[i + 1] != 0x03) || (rx->frame[i + 2] != 0xf0))) + if(Ax25Config.allowNonAprs || (((rx->frame[i + 1] == 0x03) && (rx->frame[i + 2] == 0xf0)))) { - rx->recByte = 0; - rx->rBitIdx = 0; - rx->frameIdx = 0; - rx->crc = 0xFFFF; - - return; + if((rx->frame[rx->frameIdx - 2] == ((rx->crc & 0xFF) ^ 0xFF)) && (rx->frame[rx->frameIdx - 1] == (((rx->crc >> 8) & 0xFF) ^ 0xFF))) //check CRC + { + rx->frameReceived = 1; + rx->frameIdx -= 2; //remove CRC + if(rx->crc != lastCrc) //the other decoder has not received this frame yet, so store it in main frame buffer + { + lastCrc = rx->crc; //store CRC of this frame + + if(!rxFrameBufferFull) //if enough space, store the frame + { + rxFrame[rxFrameHead].start = rxBufferHead; + rxFrame[rxFrameHead].signalLevel = ModemGetRMS(modem); + rxFrame[rxFrameHead++].size = rx->frameIdx; + rxFrameHead %= FRAME_MAX_COUNT; + if(rxFrameHead == txFrameHead) + rxFrameBufferFull = true; + + for(uint16_t i = 0; i < rx->frameIdx; i++) + { + rxBuffer[rxBufferHead++] = rx->frame[i]; + rxBufferHead %= FRAME_BUFFER_SIZE; + } + + } + } + } } - if ((rx->frame[rx->frameIdx - 2] == ((rx->crc & 0xFF) ^ 0xFF)) && (rx->frame[rx->frameIdx - 1] == (((rx->crc >> 8) & 0xFF) ^ 0xFF))) //check CRC - { - rx->frameReceived = 1; - if(rx->crc != lastCrc) //the other decoder has not received this frame yet, so store it in main frame buffer - { - lastCrc = rx->crc; //store CRC of this frame - ax25.sLvl = Afsk_getRMS(modemNo); //get RMS amplitude of the received frame - uint16_t freebuf = 0; - if(ax25.frameBufWr > ax25.frameBufRd) //check if there is enough free space in buffer - freebuf = FRAMEBUFLEN - ax25.frameBufWr + ax25.frameBufRd - 3; - else - freebuf = ax25.frameBufRd - ax25.frameBufWr - 3; - - if((rx->frameIdx - 2) <= freebuf) //if enough space, store the frame - { - for(uint16_t i = 0; i < rx->frameIdx - 2; i++) - { - ax25.frameBuf[ax25.frameBufWr++] = rx->frame[i]; - ax25.frameBufWr %= (FRAMEBUFLEN); - } - ax25.frameBuf[ax25.frameBufWr++] = 0xFF; //add frame separator - ax25.frameBufWr %= FRAMEBUFLEN; - } - } - } else - { - Afsk_clearRMS(modemNo); - } - } - - rx->recByte = 0; - rx->rBitIdx = 0; - rx->frameIdx = 0; - rx->crc = 0xFFFF; } rx->rx = RX_STAGE_FLAG; - rx->recByte = 0; - rx->rBitIdx = 0; + ModemClearRMS(modem); + rx->receivedByte = 0; + rx->receivedBitIdx = 0; rx->frameIdx = 0; rx->crc = 0xFFFF; - Afsk_clearRMS(modemNo); return; } if((rx->rawData & 0x7F) == 0x7F) //received 7 consecutive ones, this is an error (sometimes called "escape byte") { - Afsk_clearRMS(modemNo); - rx->rx = RX_STAGE_IDLE; - rx->recByte = 0; - rx->rBitIdx = 0; + rx->rx = RX_STAGE_FLAG; + ModemClearRMS(modem); + rx->receivedByte = 0; + rx->receivedBitIdx = 0; rx->frameIdx = 0; rx->crc = 0xFFFF; return; @@ -216,232 +299,220 @@ void Ax25_bitParse(uint8_t bit, uint8_t modemNo) return; - if((rx->rawData & 0x3F) == 0x3E) //dismiss bit 0 added by bitstuffing + if((rx->rawData & 0x3F) == 0x3E) //dismiss bit 0 added by bit stuffing return; if(rx->rawData & 0x01) //received bit 1 - rx->recByte |= 0x80; //store it + rx->receivedByte |= 0x80; //store it - if(++rx->rBitIdx >= 8) //received full byte + if(++rx->receivedBitIdx >= 8) //received full byte { - if(rx->frameIdx > FRAMELEN) //frame is too long + if(rx->frameIdx > FRAME_MAX_SIZE) //frame is too long { rx->rx = RX_STAGE_IDLE; - rx->recByte = 0; - rx->rBitIdx = 0; + ModemClearRMS(modem); + rx->receivedByte = 0; + rx->receivedBitIdx = 0; rx->frameIdx = 0; rx->crc = 0xFFFF; - Afsk_clearRMS(modemNo); return; } if(rx->frameIdx >= 2) //more than 2 bytes received, calculate CRC { for(uint8_t i = 0; i < 8; i++) { - ax25_calcCRC((rx->frame[rx->frameIdx - 2] >> i) & 0x01, &(rx->crc)); + calculateCRC((rx->frame[rx->frameIdx - 2] >> i) & 1, &(rx->crc)); } } rx->rx = RX_STAGE_FRAME; - rx->frame[rx->frameIdx++] = rx->recByte; //store received byte - rx->recByte = 0; - rx->rBitIdx = 0; + rx->frame[rx->frameIdx++] = rx->receivedByte; //store received byte + rx->receivedByte = 0; + rx->receivedBitIdx = 0; } else - rx->recByte >>= 1; + rx->receivedByte >>= 1; } -uint8_t Ax25_getTxBit(void) +uint8_t Ax25GetTxBit(void) { - if(txState.txBitIdx == 8) + if(txBitIdx == 8) { - txState.txBitIdx = 0; - if(txState.txStage == TX_STAGE_PREAMBLE) //transmitting preamble (TXDelay) + txBitIdx = 0; + if(txStage == TX_STAGE_PREAMBLE) //transmitting preamble (TXDelay) { - if(txState.txDelayElapsed < txState.txDelay) //still transmitting + if(txDelayElapsed < txDelay) //still transmitting { - txState.txByte = 0x7E; - txState.txDelayElapsed++; + txByte = 0x7E; + txDelayElapsed++; } else //now transmit initial flags { - txState.txDelayElapsed = 0; - txState.txStage = TX_STAGE_HEADER_FLAGS; + txDelayElapsed = 0; + txStage = TX_STAGE_HEADER_FLAGS; } } - if(txState.txStage == TX_STAGE_HEADER_FLAGS) //transmitting initial flags + if(txStage == TX_STAGE_HEADER_FLAGS) //transmitting initial flags { - if(txState.flagsElapsed < 4) //say we want to transmit 4 flags + if(txFlagsElapsed < STATIC_HEADER_FLAG_COUNT) { - txState.txByte = 0x7E; - txState.flagsElapsed++; + txByte = 0x7E; + txFlagsElapsed++; } else { - txState.flagsElapsed = 0; - txState.txStage = TX_STAGE_DATA; //transmit data + txFlagsElapsed = 0; + txStage = TX_STAGE_DATA; //transmit data } } - if(txState.txStage == TX_STAGE_DATA) //transmitting normal data + if(txStage == TX_STAGE_DATA) //transmitting normal data { - if((ax25.xmitIdx > 10) && (txState.xmitIdx < ax25.xmitIdx)) //send buffer +transmitNormalData: + if((txFrameHead != txFrameTail) || txFrameBufferFull) { - if(ax25.frameXmit[txState.xmitIdx] == 0xFF) //frame separator found + if(txByteIdx < txFrame[txFrameTail].size) //send buffer { - txState.txStage = TX_STAGE_CRC; //transmit CRC - txState.xmitIdx++; + txByte = txBuffer[(txFrame[txFrameTail].start + txByteIdx) % FRAME_BUFFER_SIZE]; + txByteIdx++; } - else //normal bytes + else //end of buffer, send CRC { - txState.txByte = ax25.frameXmit[txState.xmitIdx]; - txState.xmitIdx++; + txStage = TX_STAGE_CRC; //transmit CRC + txCrcByteIdx = 0; } - } else //end of buffer + } + else //no more frames { - ax25.xmitIdx = 0; - txState.xmitIdx = 0; - txState.txStage = TX_STAGE_TAIL; + txByteIdx = 0; + txBitIdx = 0; + txStage = TX_STAGE_TAIL; } } - if(txState.txStage == TX_STAGE_CRC) //transmitting CRC + if(txStage == TX_STAGE_CRC) //transmitting CRC { - - if(txState.crcIdx < 2) + if(txCrcByteIdx <= 1) { - txState.txByte = (txState.crc >> (txState.crcIdx * 8)) ^ 0xFF; - txState.crcIdx++; + txByte = (txCrc & 0xFF) ^ 0xFF; + txCrc >>= 8; + txCrcByteIdx++; } else { - txState.crc = 0xFFFF; - txState.txStage = TX_STAGE_FOOTER_FLAGS; //now transmit flags - txState.crcIdx = 0; + txCrc = 0xFFFF; + txStage = TX_STAGE_FOOTER_FLAGS; //now transmit flags + txFlagsElapsed = 0; } + } - if(txState.txStage == TX_STAGE_FOOTER_FLAGS) + if(txStage == TX_STAGE_FOOTER_FLAGS) { - if(txState.flagsElapsed < 8) //say we want to transmit 8 flags + if(txFlagsElapsed < STATIC_FOOTER_FLAG_COUNT) { - txState.txByte = 0x7E; - txState.flagsElapsed++; - } else + txByte = 0x7E; + txFlagsElapsed++; + } + else { - txState.flagsElapsed = 0; - txState.txStage = TX_STAGE_DATA; //return to normal data transmission stage. There might be a next frame to transmit - if((ax25.xmitIdx > 10) && (txState.xmitIdx < ax25.xmitIdx)) //send buffer - { - if(ax25.frameXmit[txState.xmitIdx] == 0xFF) //frame separator found - { - txState.txStage = TX_STAGE_CRC; //transmit CRC - txState.xmitIdx++; - } - else //normal bytes - { - txState.txByte = ax25.frameXmit[txState.xmitIdx]; - txState.xmitIdx++; - } - } else //end of buffer - { - ax25.xmitIdx = 0; - txState.xmitIdx = 0; - txState.txStage = TX_STAGE_TAIL; - } + txFlagsElapsed = 0; + txStage = TX_STAGE_DATA; //return to normal data transmission stage. There might be a next frame to transmit + txFrameBufferFull = false; + txFrameTail++; + txFrameTail %= FRAME_MAX_COUNT; + goto transmitNormalData; } } - if(txState.txStage == TX_STAGE_TAIL) //transmitting tail + if(txStage == TX_STAGE_TAIL) //transmitting tail { - ax25.xmitIdx = 0; - if(txState.txTailElapsed < txState.txTail) + if(txTailElapsed < txTail) { - txState.txByte = 0x7E; - txState.txTailElapsed++; + txByte = 0x7E; + txTailElapsed++; } else //tail transmitted, stop transmission { - txState.txTailElapsed = 0; - txState.txStage = TX_STAGE_IDLE; - txState.crc = 0xFFFF; - txState.bitstuff = 0; - txState.txByte = 0; - txState.tx = TX_INIT_OFF; - Afsk_transmitStop(); + txTailElapsed = 0; + txStage = TX_STAGE_IDLE; + txCrc = 0xFFFF; + txBitstuff = 0; + txByte = 0; + txInitStage = TX_INIT_OFF; + txBufferTail = txBufferHead; + ModemTransmitStop(); + return 0; } - - } } uint8_t txBit = 0; - if((txState.txStage == TX_STAGE_DATA) || (txState.txStage == TX_STAGE_CRC)) //transmitting normal data or CRC + if((txStage == TX_STAGE_DATA) || (txStage == TX_STAGE_CRC)) //transmitting normal data or CRC { - if(txState.bitstuff == 5) //5 consecutive ones transmitted + if(txBitstuff == 5) //5 consecutive ones transmitted { txBit = 0; //transmit bit-stuffed 0 - txState.bitstuff = 0; + txBitstuff = 0; } else { - if(txState.txByte & 1) //1 being transmitted + if(txByte & 1) //1 being transmitted { - txState.bitstuff++; //increment bit stuffing counter + txBitstuff++; //increment bit stuffing counter txBit = 1; - } else + } + else { txBit = 0; - txState.bitstuff = 0; //0 being transmitted, reset bit stuffing counter + txBitstuff = 0; //0 being transmitted, reset bit stuffing counter } - if(txState.txStage == TX_STAGE_DATA) //calculate CRC only for normal data - ax25_calcCRC(txState.txByte & 1, (uint16_t*)&(txState.crc)); - txState.txByte >>= 1; - txState.txBitIdx++; + if(txStage == TX_STAGE_DATA) //calculate CRC only for normal data + calculateCRC(txByte & 1, &txCrc); + + txByte >>= 1; + txBitIdx++; } } else //transmitting preamble or flags, don't calculate CRC, don't use bit stuffing { - txBit = txState.txByte & 1; - txState.txByte >>= 1; - txState.txBitIdx++; + txBit = txByte & 1; + txByte >>= 1; + txBitIdx++; } return txBit; - } /** * @brief Initialize transmission and start when possible */ -void Ax25_transmitBuffer(void) +void Ax25TransmitBuffer(void) { - if(txState.tx == TX_INIT_WAITING) + if(txInitStage == TX_INIT_WAITING) return; - if(txState.tx == TX_INIT_TRANSMITTING) + if(txInitStage == TX_INIT_TRANSMITTING) return; - if(ax25.xmitIdx > 10) + if((txFrameHead != txFrameTail) || txFrameBufferFull) { - txState.txQuiet = (ticks + (ax25Cfg.quietTime / 10) + rando(0, 20)); //calculate required delay - txState.tx = TX_INIT_WAITING; + txQuiet = (ticks + (Ax25Config.quietTime / SYSTICK_INTERVAL) + Random(0, 200 / SYSTICK_INTERVAL)); //calculate required delay + txInitStage = TX_INIT_WAITING; } - else ax25.xmitIdx = 0; } - - /** * @brief Start transmission immediately * @warning Transmission should be initialized using Ax25_transmitBuffer */ -static void ax25_transmitStart(void) +static void transmitStart(void) { - txState.crc = 0xFFFF; //initial CRC value - txState.txStage = TX_STAGE_PREAMBLE; - txState.txByte = 0; - txState.txBitIdx = 0; - Afsk_transmitStart(); + txCrc = 0xFFFF; //initial CRC value + txStage = TX_STAGE_PREAMBLE; + txByte = 0; + txBitIdx = 0; + txFlagsElapsed = 0; + ModemTransmitStart(); } @@ -449,58 +520,49 @@ static void ax25_transmitStart(void) * @brief Start transmitting when possible * @attention Must be continuously polled in main loop */ -void Ax25_transmitCheck(void) +void Ax25TransmitCheck(void) { - if(txState.tx == TX_INIT_OFF) //TX not initialized at all, nothing to transmit + if(txInitStage == TX_INIT_OFF) //TX not initialized at all, nothing to transmit return; - if(txState.tx == TX_INIT_TRANSMITTING) //already transmitting + if(txInitStage == TX_INIT_TRANSMITTING) //already transmitting return; - if(ax25.xmitIdx < 10) - { - ax25.xmitIdx = 0; - return; - } - - if(Afsk_isTxTestOngoing()) //TX test is enabled, wait for now + if(ModemIsTxTestOngoing()) //TX test is enabled, wait for now return; - if(txState.txQuiet < ticks) //quit time has elapsed + if(txQuiet < ticks) //quit time has elapsed { - if(!Afsk_dcdState()) //channel is free + if(!ModemDcdState()) //channel is free { - txState.tx = TX_INIT_TRANSMITTING; //transmit right now - txState.txRetries = 0; - ax25_transmitStart(); + txInitStage = TX_INIT_TRANSMITTING; //transmit right now + txRetries = 0; + transmitStart(); } else //channel is busy { - if(txState.txRetries == 8) //8th retry occurred, transmit immediately + if(txRetries == MAX_TRANSMIT_RETRY_COUNT) //timeout { - txState.tx = TX_INIT_TRANSMITTING; //transmit right now - txState.txRetries = 0; - ax25_transmitStart(); + txInitStage = TX_INIT_TRANSMITTING; //transmit right now + txRetries = 0; + transmitStart(); } else //still trying { - txState.txQuiet = ticks + rando(10, 50); //try again after some random time - txState.txRetries++; + txQuiet = ticks + Random(100 / SYSTICK_INTERVAL, 500 / SYSTICK_INTERVAL); //try again after some random time + txRetries++; } } } } -void Ax25_init(void) +void Ax25Init(void) { - txState.crc = 0xFFFF; - ax25.frameBufWr = 0; - ax25.frameBufRd = 0; - ax25.xmitIdx = 0; - ax25.frameReceived = 0; + txCrc = 0xFFFF; - rxState1.crc = 0xFFFF; - rxState2.crc = 0xFFFF; + memset((void*)rxState, 0, sizeof(rxState)); + for(uint8_t i = 0; i < (sizeof(rxState) / sizeof(rxState[0])); i++) + rxState[i].crc = 0xFFFF; - txState.txDelay = ((float)ax25Cfg.txDelayLength / 6.66667f); //change milliseconds to byte count - txState.txTail = ((float)ax25Cfg.txTailLength / 6.66667f); + txDelay = ((float)Ax25Config.txDelayLength / (8.f * 1000.f / (float)MODEM_BAUDRATE)); //change milliseconds to byte count + txTail = ((float)Ax25Config.txTailLength / (8.f * 1000.f / (float)MODEM_BAUDRATE)); } diff --git a/Src/beacon.c b/Src/beacon.c index 4587243..02ccf80 100644 --- a/Src/beacon.c +++ b/Src/beacon.c @@ -23,40 +23,40 @@ along with VP-Digi. If not, see . #include "terminal.h" #include "drivers/systick.h" -uint32_t beaconDelay[8] = {0}; - +struct Beacon beacon[8]; +static uint32_t beaconDelay[8] = {0}; +static uint8_t buf[150]; //frame buffer /** * @brief Send specified beacon * @param[in] no Beacon number (0-7) */ -void Beacon_send(uint8_t no) +void BeaconSend(uint8_t number) { - if(beacon[no].enable == 0) + if(beacon[number].enable == 0) return; //beacon disabled - uint8_t buf[150] = {0}; //frame buffer uint16_t idx = 0; - for(uint8_t i = 0; i < 7; i++) //add destination address - buf[idx++] = dest[i]; + for(uint8_t i = 0; i < sizeof(GeneralConfig.dest); i++) //add destination address + buf[idx++] = GeneralConfig.dest[i]; - for(uint8_t i = 0; i < 6; i++) //add source address - buf[idx++] = call[i]; + for(uint8_t i = 0; i < sizeof(GeneralConfig.call); i++) //add source address + buf[idx++] = GeneralConfig.call[i]; - buf[idx++] = ((callSsid << 1) + 0b01100000); //add source ssid + buf[idx++] = ((GeneralConfig.callSsid << 1) + 0b01100000); //add source ssid - if(beacon[no].path[0] > 0) //this beacon has some path set + if(beacon[number].path[0] > 0) //this beacon has some path set { for(uint8_t i = 0; i < 14; i++) //loop through path { - if((beacon[no].path[i] > 0) || (i == 6) || (i == 13)) //normal data, not a NULL symbol + if((beacon[number].path[i] > 0) || (i == 6) || (i == 13)) //normal data, not a NULL symbol { - buf[idx] = (beacon[no].path[i] << 1); //copy path + buf[idx] = beacon[number].path[i]; //copy path if((i == 6) || (i == 13)) //it was and ssid { - buf[idx] += 0b01100000; //add appripriate bits for ssid + buf[idx] = ((buf[idx] << 1) + 0b01100000); //add appropriate bits for ssid } idx++; } @@ -67,47 +67,35 @@ void Beacon_send(uint8_t no) buf[idx - 1] |= 1; //add c-bit on the last element buf[idx++] = 0x03; //control buf[idx++] = 0xF0; //pid - for(uint8_t i = 0; i < strlen((char*)beacon[no].data); i++) + for(uint8_t i = 0; i < strlen((char*)beacon[number].data); i++) { - buf[idx++] = beacon[no].data[i]; //copy beacon comment + buf[idx++] = beacon[number].data[i]; //copy beacon comment } - if((FRAMEBUFLEN - ax25.xmitIdx) > (idx + 2)) //check for free space in TX buffer + void *handle = NULL; + if(NULL != (handle = Ax25WriteTxFrame(buf, idx))) //try to write frame to TX buffer { - uint16_t frameStart = ax25.xmitIdx; //store index - - for(uint8_t i = 0; i < idx; i++) - { - ax25.frameXmit[ax25.xmitIdx++] = buf[i]; //copy frame to main TX buffer - } - - if(kissMonitor) //monitoring mode, send own frames to KISS ports + if(GeneralConfig.kissMonitor) //monitoring mode, send own frames to KISS ports { - SendKiss(ax25.frameXmit, ax25.xmitIdx); + TermSendToAll(MODE_KISS, buf, idx); } - ax25.frameXmit[ax25.xmitIdx++] = 0xFF; //frame separator - Digi_storeDeDupeFromXmitBuf(frameStart); //store frame hash in duplicate protection buffer (to prevent from digipeating own packets) - - uint8_t bufto[200]; - common_toTNC2((uint8_t *)&ax25.frameXmit[frameStart], ax25.xmitIdx - frameStart - 1, bufto); + DigiStoreDeDupe(buf, idx); //store frame hash in duplicate protection buffer (to prevent from digipeating own packets) - term_sendMonitor((uint8_t*)"(AX.25) Transmitting beacon ", 0); + TermSendToAll(MODE_MONITOR, (uint8_t*)"(AX.25) Transmitting beacon ", 0); - term_sendMonitorNumber(no); - term_sendMonitor((uint8_t*)": ", 0); - term_sendMonitor(bufto, 0); - term_sendMonitor((uint8_t*)"\r\n", 0); + TermSendNumberToAll(MODE_MONITOR, number); + TermSendToAll(MODE_MONITOR, (uint8_t*)": ", 0); + SendTNC2(buf, idx); + TermSendToAll(MODE_MONITOR, (uint8_t*)"\r\n", 0); } - - } /** - * @brief Check if any beacon should be transmitted and transmit if neccessary + * @brief Check if any beacon should be transmitted and transmit if necessary */ -void Beacon_check(void) +void BeaconCheck(void) { for(uint8_t i = 0; i < 8; i++) { @@ -120,7 +108,7 @@ void Beacon_check(void) return; beacon[i].next = ticks + beacon[i].interval; //save next beacon timestamp beaconDelay[i] = 0; - Beacon_send(i); + BeaconSend(i); } } } @@ -129,11 +117,11 @@ void Beacon_check(void) /** * @brief Initialize beacon module */ -void Beacon_init(void) +void BeaconInit(void) { for(uint8_t i = 0; i < 8; i++) { - beaconDelay[i] = (beacon[i].delay * 100) + ticks + 3000; //set delay for beacons and add constant 30 seconds of delay + beaconDelay[i] = (beacon[i].delay * SYSTICK_FREQUENCY) + ticks + (30000 / SYSTICK_INTERVAL); //set delay for beacons and add constant 30 seconds of delay beacon[i].next = 0; } } diff --git a/Src/common.c b/Src/common.c index cd12458..c7d075b 100644 --- a/Src/common.c +++ b/Src/common.c @@ -22,152 +22,148 @@ along with VP-Digi. If not, see . #include "drivers/uart.h" #include "usbd_cdc_if.h" -uint8_t call[6] = {'N' << 1, '0' << 1, 'C' << 1, 'A' << 1, 'L' << 1, 'L' << 1}; -uint8_t callSsid = 0; - -uint8_t dest[7] = {130, 160, 156, 172, 96, 98, 96}; //destination address: APNV01-0 by default. SSID MUST remain 0. - -const uint8_t *versionString = (const uint8_t*)"VP-Digi v. 1.2.6\r\nThe open-source standalone APRS digipeater controller and KISS TNC\r\n"; +struct _GeneralConfig GeneralConfig = +{ + .call = {'N' << 1, '0' << 1, 'C' << 1, 'A' << 1, 'L' << 1, 'L' << 1}, + .callSsid = 0, + .dest = {130, 160, 156, 172, 96, 98, 96}, //destination address: APNV01-0 by default. SSID MUST remain 0. + .kissMonitor = 0, +}; -uint8_t autoReset = 0; -uint32_t autoResetTimer = 0; -uint8_t kissMonitor = 0; +const char versionString[] = "VP-Digi v. 1.3.0\r\nThe open-source standalone APRS digipeater controller and KISS TNC\r\n"; +static uint64_t pow10i(uint16_t exp) +{ + if(exp == 0) + return 1; + uint64_t n = 1; + while(exp--) + n *= 10; + return n; +} -int64_t strToInt(uint8_t *str, uint8_t len) +int64_t StrToInt(const char *str, uint16_t len) { if(len == 0) + len = strlen(str); + + int64_t tmp = 0; + for(int32_t i = (len - 1); i >= 0; i--) { - while(1) + if((i == 0) && (str[0] == '-')) { - if(((str[len] > 47) && (str[len] < 58))) - len++; - else - break; - if(len >= 100) - return 0; + return -tmp; } - } - int64_t tmp = 0; - for(int16_t i = (len - 1); i >= 0; i--) - { - if((i == 0) && (str[i] == '-')) - tmp = -tmp; + else if(IS_NUMBER(str[i])) + tmp += ((str[i] - '0') * pow10i(len - 1 - i)); else - tmp += ((str[i] - 48) * pow(10, len - 1 - i)); + return 0; } return tmp; } -int16_t rando(int16_t min, int16_t max) +int16_t Random(int16_t min, int16_t max) { int16_t tmp; - if (max>=min) - max-= min; + if (max >= min) + max -= min; else { - tmp= min - max; - min= max; - max= tmp; + tmp = min - max; + min = max; + max = tmp; } return max ? (rand() % max + min) : min; } - - -void common_toTNC2(uint8_t *from, uint16_t len, uint8_t *to) +static void sendTNC2ToUart(Uart *uart, uint8_t *from, uint16_t len) { - for(uint8_t i = 0; i < 6; i++) //source call { - if((*(from + 7 + i) >> 1) != ' ') //skip spaces + if((from[7 + i] >> 1) != ' ') //skip spaces { - *(to++) = *(from + 7 + i) >> 1; + UartSendByte(uart, from[7 + i] >> 1); } } - uint8_t ssid = ((*(from + 13) >> 1) & 0b00001111); //store ssid + uint8_t ssid = ((from[13] >> 1) & 0b00001111); //store ssid if(ssid > 0) //SSID >0 { - *(to++) = '-'; //add - - if(ssid > 9) - *(to++) = '1'; //ssid >9, so will be -1x - *(to++) = (ssid % 10) + 48; + UartSendByte(uart, '-'); //add - + UartSendNumber(uart, ssid); } - *(to++) = '>'; //first separator - + UartSendByte(uart, '>'); //first separator for(uint8_t i = 0; i < 6; i++) //destination call { - if((*(from + i) >> 1) != ' ') //skip spaces + if((from[i] >> 1) != ' ') //skip spaces { - *(to++) = *(from + i) >> 1; + UartSendByte(uart, from[i] >> 1); } } - ssid = ((*(from + 6) >> 1) & 0b00001111); //store ssid + ssid = ((from[6] >> 1) & 0b00001111); //store ssid if(ssid > 0) //SSID >0 { - *(to++) = '-'; //add - - if(ssid > 9) - *(to++) = '1'; //ssid >9, so will be -1x - *(to++) = (ssid % 10) + 48; + UartSendByte(uart, '-'); //add - + UartSendNumber(uart, ssid); } uint16_t nextPathEl = 14; //next path element index - if(!(*(from + 13) & 1)) //no c-bit in source address, there is a digi path + if(!(from[13] & 1)) //no c-bit in source address, there is a digi path { - - do //analize all path elements + do //analyze all path elements { - *(to++) = ','; //path separator + UartSendByte(uart, ','); //path separator for(uint8_t i = 0; i < 6; i++) //copy element { - if((*(from + nextPathEl + i) >> 1) != ' ') //skip spaces + if((from[nextPathEl + i] >> 1) != ' ') //skip spaces { - *(to++) = *(from + nextPathEl + i) >> 1; + UartSendByte(uart, from[nextPathEl + i] >> 1); } } - ssid = ((*(from + nextPathEl + 6) >> 1) & 0b00001111); //store ssid + ssid = ((from[nextPathEl + 6] >> 1) & 0b00001111); //store ssid if(ssid > 0) //SSID >0 { - *(to++) = '-'; //add - - if(ssid > 9) - *(to++) = '1'; //ssid >9, so will be -1x - *(to++) = (ssid % 10) + 48; + UartSendByte(uart, '-'); //add - + UartSendNumber(uart, ssid); } - if((*(from + nextPathEl + 6) & 128)) //h-bit in ssid - *(to++) = '*'; //add * + if((from[nextPathEl + 6] & 0x80)) //h-bit in ssid + UartSendByte(uart, '*'); //add * nextPathEl += 7; //next path element if(nextPathEl > 56) //too many path elements break; } - while((*(from + nextPathEl - 1) & 1) == 0); //loop until the c-bit is found + while((from[nextPathEl - 1] & 1) == 0); //loop until the c-bit is found } - - *(to++) = ':'; //separator + UartSendByte(uart, ':'); //separator nextPathEl += 2; //skip Control and PID - for(; nextPathEl < len; nextPathEl++) //copy information field - { - *(to++) = *(from + nextPathEl); - } - + UartSendString(uart, &(from[nextPathEl]), len - nextPathEl); //send information field - *(to++) = 0; //terminate with NULL + UartSendByte(uart, 0); //terminate with NULL +} +void SendTNC2(uint8_t *from, uint16_t len) +{ + if(UartUsb.mode == MODE_MONITOR) + sendTNC2ToUart(&UartUsb, from, len); + if(Uart1.mode == MODE_MONITOR) + sendTNC2ToUart(&Uart1, from, len); + if(Uart2.mode == MODE_MONITOR) + sendTNC2ToUart(&Uart2, from, len); } -uint32_t crc32(uint32_t crc0, uint8_t *s, uint64_t n) +uint32_t Crc32(uint32_t crc0, uint8_t *s, uint64_t n) { uint32_t crc = ~crc0; @@ -185,38 +181,67 @@ uint32_t crc32(uint32_t crc0, uint8_t *s, uint64_t n) return ~crc; } -void SendKiss(uint8_t *buf, uint16_t len) +bool ParseCallsign(const char *in, uint16_t size, uint8_t *out) { - Uart *u = &uart1; + if(size > 6) + return false; - for(uint8_t i = 0; i < 2; i++) + uint8_t tmp[6]; + + uint8_t i = 0; + for(; i < size; i++) + { + if(!IS_UPPERCASE_ALPHANUMERIC(in[i])) + return false; + + tmp[i] = in[i] << 1; + } + + for(uint8_t k = 0; k < i; k++) + out[k] = tmp[k]; + + for(; i < 6; i++) + out[i] = ' ' << 1; + + + return true; +} + +bool ParseCallsignWithSsid(const char *in, uint16_t size, uint8_t *out, uint8_t *ssid) +{ + uint16_t ssidPosition = size; + for(uint16_t i = 0; i < size; i++) { - if(u->mode == MODE_KISS) //check if KISS mode + if(in[i] == '-') { - uart_sendByte(u, 0xc0); //send data in kiss format - uart_sendByte(u, 0x00); - for(uint16_t j = 0; j < len; j++) - { - uart_sendByte(u, buf[j]); - } - uart_sendByte(u, 0xc0); - uart_transmitStart(u); + ssidPosition = i; + break; } - u = &uart2; } + ssidPosition++; + if(!ParseCallsign(in, ssidPosition - 1, out)) + return false; - if(USBmode == MODE_KISS) //check if USB in KISS mode + if(ssidPosition == size) { - uint8_t t[2] = {0xc0, 0}; - - CDC_Transmit_FS(&t[0], 1); - CDC_Transmit_FS(&t[1], 1); + *ssid = 0; + return true; + } - for(uint16_t i = 0; i < len; i++) - { - CDC_Transmit_FS(&buf[i], 1); + if(!ParseSsid(&in[ssidPosition], size - ssidPosition, ssid)) + return false; + return true; +} - } - CDC_Transmit_FS(&t[0], 1); +bool ParseSsid(const char *in, uint16_t size, uint8_t *out) +{ + int64_t ssid = StrToInt(in, size); + if((ssid >= 0) && (ssid <= 15)) + { + *out = (uint8_t)ssid; + return true; } + return false; } + + diff --git a/Src/config.c b/Src/config.c index 7369740..c190440 100644 --- a/Src/config.c +++ b/Src/config.c @@ -1,5 +1,5 @@ /* -This file is part of VP-Digi. +This file is part of VP-DigiConfig. 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 @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with VP-Digi. If not, see . +along with VP-DigiConfig. If not, see . */ #include "config.h" @@ -26,26 +26,94 @@ along with VP-Digi. If not, see . #include "stm32f1xx.h" #include "drivers/modem.h" +#define CONFIG_ADDRESS 0x800F000 +#define CONFIG_PAGE_COUNT 2 +#define CONFIG_PAGE_SIZE 1024 //1024 words (2048 bytes) + +#define CONFIG_FLAG_WRITTEN 0x6B + + +//these are relative addresses, absolute address is calculated as relative address + MEM_CONFIG +//all fields are 16-bit or n*16-bit long, as data in flash is stored in 16-bit words +#define CONFIG_FLAG 0 //configuration written flag +#define CONFIG_CALL 2 +#define CONFIG_SSID 8 +#define CONFIG_TXDELAY 10 +#define CONFIG_TXTAIL 12 +#define CONFIG_TXQUIET 14 +#define CONFIG_RS1BAUD 16 +#define CONFIG_RS2BAUD 20 +#define CONFIG_BEACONS 24 +#define CONFIG_BCIV 26 //beacon intervals +#define CONFIG_BCDL 42 //beacon delays +#define CONFIG_BC0 58 //beacon information fields, null terminated +#define CONFIG_BC1 158 +#define CONFIG_BC2 258 +#define CONFIG_BC3 358 +#define CONFIG_BC4 458 +#define CONFIG_BC5 558 +#define CONFIG_BC6 658 +#define CONFIG_BC7 758 +#define CONFIG_BCP0 858 //beacon paths, 14 bytes each +#define CONFIG_BCP1 872 +#define CONFIG_BCP2 886 +#define CONFIG_BCP3 900 +#define CONFIG_BCP4 914 +#define CONFIG_BCP5 928 +#define CONFIG_BCP6 942 +#define CONFIG_BCP7 956 +#define CONFIG_DIGION 970 +#define CONFIG_DIGIEN 972 +#define CONFIG_DIGIVISC 974 //viscous-delay settings in higher half, direct-only in lower half +#define CONFIG_DIGIAL0 976 +#define CONFIG_DIGIAL1 982 +#define CONFIG_DIGIAL2 988 +#define CONFIG_DIGIAL3 994 +#define CONFIG_DIGIAL4 1000 +#define CONFIG_DIGIAL5 1008 +#define CONFIG_DIGIAL6 1016 +#define CONFIG_DIGIAL7 1024 +#define CONFIG_DIGIMAX0 1032 +#define CONFIG_DIGIMAX1 1034 +#define CONFIG_DIGIMAX2 1036 +#define CONFIG_DIGIMAX3 1038 +#define CONFIG_DIGIREP0 1040 +#define CONFIG_DIGIREP1 1042 +#define CONFIG_DIGIREP2 1044 +#define CONFIG_DIGIREP3 1046 +#define CONFIG_DIGITRACE 1048 +#define CONFIG_DIGIDEDUPE 1050 +#define CONFIG_DIGICALLFILEN 1052 +#define CONFIG_DIGIFILLIST 1054 +#define CONFIG_DIGIFILTYPE 1194 +#define CONFIG_DIGISSID4 1196 +#define CONFIG_DIGISSID5 1198 +#define CONFIG_DIGISSID6 1200 +#define CONFIG_DIGISSID7 1202 +#define CONFIG_PWM_FLAT 1204 +#define CONFIG_KISSMONITOR 1206 +#define CONFIG_DEST 1208 +#define CONFIG_ALLOWNONAPRS 1214 +#define CONFIG_XXX 1216 //next address (not used) + + /** * @brief Write word to configuration part in flash * @param[in] address Relative address * @param[in] data Data to write * @warning Flash must be unlocked first */ -static void flash_write(uint32_t address, uint16_t data) +static void write(uint32_t address, uint16_t data) { FLASH->CR |= FLASH_CR_PG; //programming mode - *(volatile uint16_t*)((address + MEM_CONFIG)) = data; //store data + *((volatile uint16_t*)(address + CONFIG_ADDRESS)) = data; //store data - while (FLASH->SR & FLASH_SR_BSY);; //wait for ceompletion + while (FLASH->SR & FLASH_SR_BSY);; //wait for completion if(!(FLASH->SR & FLASH_SR_EOP)) //an error occurred - { FLASH->CR &= ~FLASH_CR_PG; - return; - } else FLASH->SR |= FLASH_SR_EOP; - - //FLASH->CR &= ~FLASH_CR_PG; + else + FLASH->SR |= FLASH_SR_EOP; } /** @@ -55,16 +123,16 @@ static void flash_write(uint32_t address, uint16_t data) * @param[in] len Data length * @warning Flash must be unlocked first */ -static void flash_writeString(uint32_t address, uint8_t *data, uint16_t len) +static void writeString(uint32_t address, uint8_t *data, uint16_t len) { uint16_t i = 0; - for(; i < (len >> 1); i++) + for(; i < (len / 2); i++) { - flash_write(address + (i << 1), *(data + (i << 1)) | (*(data + 1 + (i << 1)) << 8)); //program memory + write(address + (i << 1), *(data + (i << 1)) | (*(data + 1 + (i << 1)) << 8)); //program memory } if((len % 2) > 0) { - flash_write(address + (i << 1), *(data + (i << 1))); //store last byte if number of bytes is odd + write(address + (i << 1), *(data + (i << 1))); //store last byte if number of bytes is odd } } @@ -73,9 +141,9 @@ static void flash_writeString(uint32_t address, uint8_t *data, uint16_t len) * @param[in] address Relative address * @return Data (word) */ -static uint16_t flash_read(uint32_t address) +static uint16_t read(uint32_t address) { - return *(volatile uint16_t*)((address + MEM_CONFIG)); + return *(volatile uint16_t*)((address + CONFIG_ADDRESS)); } /** @@ -84,37 +152,40 @@ static uint16_t flash_read(uint32_t address) * @param[out] *data Data * @param[in] len Byte count */ -static void flash_readString(uint32_t address, uint8_t *data, uint16_t len) +static void readString(uint32_t address, uint8_t *data, uint16_t len) { uint16_t i = 0; for(; i < (len >> 1); i++) { - *(data + (i << 1)) = (uint8_t)flash_read(address + (i << 1)); - *(data + 1 + (i << 1)) = (uint8_t)flash_read(address + 1 + (i << 1)); + *(data + (i << 1)) = (uint8_t)read(address + (i << 1)); + *(data + 1 + (i << 1)) = (uint8_t)read(address + 1 + (i << 1)); } if((len % 2) > 0) { - *(data + (i << 1)) = (uint8_t)flash_read(address + (i << 1)); + *(data + (i << 1)) = (uint8_t)read(address + (i << 1)); } } -void Config_erase(void) +void ConfigErase(void) { FLASH->KEYR = 0x45670123; //unlock memory FLASH->KEYR = 0xCDEF89AB; - while (FLASH->SR & FLASH_SR_BSY);; + while (FLASH->SR & FLASH_SR_BSY) + ; FLASH->CR |= FLASH_CR_PER; //erase mode - for(uint8_t i = 0; i < 2; i++) + for(uint8_t i = 0; i < CONFIG_PAGE_COUNT; i++) { - FLASH->AR = (MEM_CONFIG) + (1024 * i); + FLASH->AR = CONFIG_ADDRESS + (CONFIG_PAGE_SIZE * i); FLASH->CR |= FLASH_CR_STRT; //start erase - while (FLASH->SR & FLASH_SR_BSY);; + while (FLASH->SR & FLASH_SR_BSY) + ; if(!(FLASH->SR & FLASH_SR_EOP)) { FLASH->CR &= ~FLASH_CR_PER; - return; - } else FLASH->SR |= FLASH_SR_EOP; + } + else + FLASH->SR |= FLASH_SR_EOP; } FLASH->CR &= ~FLASH_CR_PER; } @@ -122,106 +193,103 @@ void Config_erase(void) /** * @brief Store configuration from RAM to Flash */ -void Config_write(void) +void ConfigWrite(void) { - Config_erase(); + ConfigErase(); - flash_writeString(CONFIG_CALL, call, 6); - flash_write(CONFIG_SSID, callSsid); - flash_writeString(CONFIG_DEST, dest, 6); - flash_write(CONFIG_TXDELAY, ax25Cfg.txDelayLength); - flash_write(CONFIG_TXTAIL, ax25Cfg.txTailLength); - flash_write(CONFIG_TXQUIET, ax25Cfg.quietTime); - flash_writeString(CONFIG_RS1BAUD, (uint8_t*)&uart1.baudrate, 3); - flash_writeString(CONFIG_RS2BAUD, (uint8_t*)&uart2.baudrate, 3); + writeString(CONFIG_CALL, GeneralConfig.call, sizeof(GeneralConfig.call)); + write(CONFIG_SSID, GeneralConfig.callSsid); + writeString(CONFIG_DEST, GeneralConfig.dest, sizeof(GeneralConfig.dest)); + write(CONFIG_TXDELAY, Ax25Config.txDelayLength); + write(CONFIG_TXTAIL, Ax25Config.txTailLength); + write(CONFIG_TXQUIET, Ax25Config.quietTime); + writeString(CONFIG_RS1BAUD, (uint8_t*)&Uart1.baudrate, 4); + writeString(CONFIG_RS2BAUD, (uint8_t*)&Uart2.baudrate, 4); - flash_write(CONFIG_BEACONS, (beacon[0].enable > 0) | ((beacon[1].enable > 0) << 1) | ((beacon[2].enable > 0) << 2) | ((beacon[3].enable > 0) << 3) | ((beacon[4].enable > 0) << 4) | ((beacon[5].enable > 0) << 5) | ((beacon[6].enable > 0) << 6) | ((beacon[7].enable > 0) << 7)); + write(CONFIG_BEACONS, (beacon[0].enable > 0) | ((beacon[1].enable > 0) << 1) | ((beacon[2].enable > 0) << 2) | ((beacon[3].enable > 0) << 3) | ((beacon[4].enable > 0) << 4) | ((beacon[5].enable > 0) << 5) | ((beacon[6].enable > 0) << 6) | ((beacon[7].enable > 0) << 7)); for(uint8_t s = 0; s < 8; s++) { - flash_write(CONFIG_BCIV + (2 * s), beacon[s].interval / 6000); + write(CONFIG_BCIV + (2 * s), beacon[s].interval / 6000); } for(uint8_t s = 0; s < 8; s++) { - flash_write(CONFIG_BCDL + (2 * s), beacon[s].delay / 60); + write(CONFIG_BCDL + (2 * s), beacon[s].delay / 60); } - flash_writeString(CONFIG_BC0, beacon[0].data, 100); - flash_writeString(CONFIG_BC1, beacon[1].data, 100); - flash_writeString(CONFIG_BC2, beacon[2].data, 100); - flash_writeString(CONFIG_BC3, beacon[3].data, 100); - flash_writeString(CONFIG_BC4, beacon[4].data, 100); - flash_writeString(CONFIG_BC5, beacon[5].data, 100); - flash_writeString(CONFIG_BC6, beacon[6].data, 100); - flash_writeString(CONFIG_BC7, beacon[7].data, 100); - flash_writeString(CONFIG_BCP0, beacon[0].path, 14); - flash_writeString(CONFIG_BCP1, beacon[1].path, 14); - flash_writeString(CONFIG_BCP2, beacon[2].path, 14); - flash_writeString(CONFIG_BCP3, beacon[3].path, 14); - flash_writeString(CONFIG_BCP4, beacon[4].path, 14); - flash_writeString(CONFIG_BCP5, beacon[5].path, 14); - flash_writeString(CONFIG_BCP6, beacon[6].path, 14); - flash_writeString(CONFIG_BCP7, beacon[7].path, 14); - flash_write(CONFIG_DIGION, digi.enable); - flash_write(CONFIG_DIGIEN, digi.enableAlias); - flash_write(CONFIG_DIGIVISC, ((uint16_t)digi.viscous << 8) | (uint16_t)digi.directOnly); - flash_writeString(CONFIG_DIGIAL0, digi.alias[0], 5); - flash_writeString(CONFIG_DIGIAL1, digi.alias[1], 5); - flash_writeString(CONFIG_DIGIAL2, digi.alias[2], 5); - flash_writeString(CONFIG_DIGIAL3, digi.alias[3], 5); - flash_writeString(CONFIG_DIGIAL4, digi.alias[4], 6); - flash_writeString(CONFIG_DIGIAL5, digi.alias[5], 6); - flash_writeString(CONFIG_DIGIAL6, digi.alias[6], 6); - flash_writeString(CONFIG_DIGIAL7, digi.alias[7], 6); - flash_write(CONFIG_DIGISSID4, digi.ssid[0]); - flash_write(CONFIG_DIGISSID5, digi.ssid[1]); - flash_write(CONFIG_DIGISSID6, digi.ssid[2]); - flash_write(CONFIG_DIGISSID7, digi.ssid[3]); - flash_write(CONFIG_DIGIMAX0, digi.max[0]); - flash_write(CONFIG_DIGIMAX1, digi.max[1]); - flash_write(CONFIG_DIGIMAX2, digi.max[2]); - flash_write(CONFIG_DIGIMAX3, digi.max[3]); - flash_write(CONFIG_DIGIREP0, digi.rep[0]); - flash_write(CONFIG_DIGIREP1, digi.rep[1]); - flash_write(CONFIG_DIGIREP2, digi.rep[2]); - flash_write(CONFIG_DIGIREP3, digi.rep[3]); - flash_write(CONFIG_DIGITRACE, digi.traced); - flash_write(CONFIG_DIGIDEDUPE, digi.dupeTime); - flash_write(CONFIG_DIGICALLFILEN, digi.callFilterEnable); - flash_write(CONFIG_DIGIFILTYPE, digi.filterPolarity); - flash_writeString(CONFIG_DIGIFILLIST, digi.callFilter[0], 140); - flash_write(CONFIG_AUTORST, autoReset); - flash_write(CONFIG_PWM_FLAT, afskCfg.usePWM | (afskCfg.flatAudioIn << 1)); - flash_write(CONFIG_KISSMONITOR, kissMonitor); - flash_write(CONFIG_ALLOWNONAPRS, ax25Cfg.allowNonAprs); + writeString(CONFIG_BC0, beacon[0].data, 100); + writeString(CONFIG_BC1, beacon[1].data, 100); + writeString(CONFIG_BC2, beacon[2].data, 100); + writeString(CONFIG_BC3, beacon[3].data, 100); + writeString(CONFIG_BC4, beacon[4].data, 100); + writeString(CONFIG_BC5, beacon[5].data, 100); + writeString(CONFIG_BC6, beacon[6].data, 100); + writeString(CONFIG_BC7, beacon[7].data, 100); + writeString(CONFIG_BCP0, beacon[0].path, 14); + writeString(CONFIG_BCP1, beacon[1].path, 14); + writeString(CONFIG_BCP2, beacon[2].path, 14); + writeString(CONFIG_BCP3, beacon[3].path, 14); + writeString(CONFIG_BCP4, beacon[4].path, 14); + writeString(CONFIG_BCP5, beacon[5].path, 14); + writeString(CONFIG_BCP6, beacon[6].path, 14); + writeString(CONFIG_BCP7, beacon[7].path, 14); + write(CONFIG_DIGION, DigiConfig.enable); + write(CONFIG_DIGIEN, DigiConfig.enableAlias); + write(CONFIG_DIGIVISC, ((uint16_t)DigiConfig.viscous << 8) | (uint16_t)DigiConfig.directOnly); + writeString(CONFIG_DIGIAL0, DigiConfig.alias[0], 5); + writeString(CONFIG_DIGIAL1, DigiConfig.alias[1], 5); + writeString(CONFIG_DIGIAL2, DigiConfig.alias[2], 5); + writeString(CONFIG_DIGIAL3, DigiConfig.alias[3], 5); + writeString(CONFIG_DIGIAL4, DigiConfig.alias[4], 6); + writeString(CONFIG_DIGIAL5, DigiConfig.alias[5], 6); + writeString(CONFIG_DIGIAL6, DigiConfig.alias[6], 6); + writeString(CONFIG_DIGIAL7, DigiConfig.alias[7], 6); + write(CONFIG_DIGISSID4, DigiConfig.ssid[0]); + write(CONFIG_DIGISSID5, DigiConfig.ssid[1]); + write(CONFIG_DIGISSID6, DigiConfig.ssid[2]); + write(CONFIG_DIGISSID7, DigiConfig.ssid[3]); + write(CONFIG_DIGIMAX0, DigiConfig.max[0]); + write(CONFIG_DIGIMAX1, DigiConfig.max[1]); + write(CONFIG_DIGIMAX2, DigiConfig.max[2]); + write(CONFIG_DIGIMAX3, DigiConfig.max[3]); + write(CONFIG_DIGIREP0, DigiConfig.rep[0]); + write(CONFIG_DIGIREP1, DigiConfig.rep[1]); + write(CONFIG_DIGIREP2, DigiConfig.rep[2]); + write(CONFIG_DIGIREP3, DigiConfig.rep[3]); + write(CONFIG_DIGITRACE, DigiConfig.traced); + write(CONFIG_DIGIDEDUPE, DigiConfig.dupeTime); + write(CONFIG_DIGICALLFILEN, DigiConfig.callFilterEnable); + write(CONFIG_DIGIFILTYPE, DigiConfig.filterPolarity); + writeString(CONFIG_DIGIFILLIST, DigiConfig.callFilter[0], sizeof(DigiConfig.callFilter)); + write(CONFIG_PWM_FLAT, ModemConfig.usePWM | (ModemConfig.flatAudioIn << 1)); + write(CONFIG_KISSMONITOR, GeneralConfig.kissMonitor); + write(CONFIG_ALLOWNONAPRS, Ax25Config.allowNonAprs); - flash_write(CONFIG_FLAG, FLAG_CONFIG_WRITTEN); + write(CONFIG_FLAG, CONFIG_FLAG_WRITTEN); FLASH->CR &= ~FLASH_CR_PG; FLASH->CR |= FLASH_CR_LOCK; } -uint8_t Config_read(void) +uint8_t ConfigRead(void) { - if(flash_read(CONFIG_FLAG) != FLAG_CONFIG_WRITTEN) //no configuration stored + if(read(CONFIG_FLAG) != CONFIG_FLAG_WRITTEN) //no configuration stored { return 0; } - flash_readString(CONFIG_CALL, call, 6); - callSsid = (uint8_t)flash_read(CONFIG_SSID); + readString(CONFIG_CALL, GeneralConfig.call, sizeof(GeneralConfig.call)); + GeneralConfig.callSsid = (uint8_t)read(CONFIG_SSID); uint8_t temp[6]; - flash_readString(CONFIG_DEST, temp, 6); + readString(CONFIG_DEST, temp, sizeof(temp)); if((temp[0] >= ('A' << 1)) && (temp[0] <= ('Z' << 1)) && ((temp[0] & 1) == 0)) //check if stored destination address is correct (we just assume it by reading the first byte) { - memcpy(dest, temp, sizeof(uint8_t) * 6); + memcpy(GeneralConfig.dest, temp, sizeof(temp)); } - ax25Cfg.txDelayLength = flash_read(CONFIG_TXDELAY); - ax25Cfg.txTailLength = flash_read(CONFIG_TXTAIL); - ax25Cfg.quietTime = flash_read(CONFIG_TXQUIET); - uart1.baudrate = 0; - uart2.baudrate = 0; - flash_readString(CONFIG_RS1BAUD, (uint8_t*)&uart1.baudrate, 3); - flash_readString(CONFIG_RS2BAUD, (uint8_t*)&uart2.baudrate, 3); - uint8_t bce = (uint8_t)flash_read(CONFIG_BEACONS); + Ax25Config.txDelayLength = read(CONFIG_TXDELAY); + Ax25Config.txTailLength = read(CONFIG_TXTAIL); + Ax25Config.quietTime = read(CONFIG_TXQUIET); + readString(CONFIG_RS1BAUD, (uint8_t*)&Uart1.baudrate, 4); + readString(CONFIG_RS2BAUD, (uint8_t*)&Uart2.baudrate, 4); + uint8_t bce = (uint8_t)read(CONFIG_BEACONS); beacon[0].enable = (bce & 1) > 0; beacon[1].enable = (bce & 2) > 0; beacon[2].enable = (bce & 4) > 0; @@ -230,59 +298,58 @@ uint8_t Config_read(void) beacon[5].enable = (bce & 32) > 0; beacon[6].enable = (bce & 64) > 0; beacon[7].enable = (bce & 128) > 0; - for(uint8_t s = 0; s < 8; s++) + for(uint8_t s = 0; s < (sizeof(beacon) / sizeof(*beacon)); s++) { - beacon[s].interval = flash_read(CONFIG_BCIV + (2 * s)) * 6000; + beacon[s].interval = read(CONFIG_BCIV + (2 * s)) * 6000; } - for(uint8_t s = 0; s < 8; s++) + for(uint8_t s = 0; s < (sizeof(beacon) / sizeof(*beacon)); s++) { - beacon[s].delay = flash_read(CONFIG_BCDL + (2 * s)) * 60; + beacon[s].delay = read(CONFIG_BCDL + (2 * s)) * 60; } - for(uint8_t g = 0; g < 8; g++) + for(uint8_t g = 0; g < (sizeof(beacon) / sizeof(*beacon)); g++) { - flash_readString(CONFIG_BC0 + (g * 100), beacon[g].data, 100); + readString(CONFIG_BC0 + (g * 100), beacon[g].data, 100); } - for(uint8_t g = 0; g < 8; g++) + for(uint8_t g = 0; g < (sizeof(beacon) / sizeof(*beacon)); g++) { - flash_readString(CONFIG_BCP0 + (g * 14), beacon[g].path, 14); + readString(CONFIG_BCP0 + (g * 14), beacon[g].path, 14); } - digi.enable = (uint8_t)flash_read(CONFIG_DIGION); - digi.enableAlias = (uint8_t)flash_read(CONFIG_DIGIEN); - uint16_t t = flash_read(CONFIG_DIGIVISC); - digi.viscous = (t & 0xFF00) >> 8; - digi.directOnly = t & 0xFF; - flash_readString(CONFIG_DIGIAL0, digi.alias[0], 5); - flash_readString(CONFIG_DIGIAL1, digi.alias[1], 5); - flash_readString(CONFIG_DIGIAL2, digi.alias[2], 5); - flash_readString(CONFIG_DIGIAL3, digi.alias[3], 5); - flash_readString(CONFIG_DIGIAL4, digi.alias[4], 6); - flash_readString(CONFIG_DIGIAL5, digi.alias[5], 6); - flash_readString(CONFIG_DIGIAL6, digi.alias[6], 6); - flash_readString(CONFIG_DIGIAL7, digi.alias[7], 6); - digi.ssid[0] = (uint8_t)flash_read(CONFIG_DIGISSID4); - digi.ssid[1] = (uint8_t)flash_read(CONFIG_DIGISSID5); - digi.ssid[2] = (uint8_t)flash_read(CONFIG_DIGISSID6); - digi.ssid[3] = (uint8_t)flash_read(CONFIG_DIGISSID7); - digi.max[0] = (uint8_t)flash_read(CONFIG_DIGIMAX0); - digi.max[1] = (uint8_t)flash_read(CONFIG_DIGIMAX1); - digi.max[2] = (uint8_t)flash_read(CONFIG_DIGIMAX2); - digi.max[3] = (uint8_t)flash_read(CONFIG_DIGIMAX3); - digi.rep[0] = (uint8_t)flash_read(CONFIG_DIGIREP0); - digi.rep[1] = (uint8_t)flash_read(CONFIG_DIGIREP1); - digi.rep[2] = (uint8_t)flash_read(CONFIG_DIGIREP2); - digi.rep[3] = (uint8_t)flash_read(CONFIG_DIGIREP3); - digi.traced = (uint8_t)flash_read(CONFIG_DIGITRACE); - digi.dupeTime = (uint8_t)flash_read(CONFIG_DIGIDEDUPE); - digi.callFilterEnable = (uint8_t)flash_read(CONFIG_DIGICALLFILEN); - digi.filterPolarity = (uint8_t)flash_read(CONFIG_DIGIFILTYPE); - flash_readString(CONFIG_DIGIFILLIST, digi.callFilter[0], 140); - autoReset = (uint8_t)flash_read(CONFIG_AUTORST); - t = (uint8_t)flash_read(CONFIG_PWM_FLAT); - afskCfg.usePWM = t & 1; - afskCfg.flatAudioIn = (t & 2) > 0; - kissMonitor = (flash_read(CONFIG_KISSMONITOR) == 1); - ax25Cfg.allowNonAprs = (flash_read(CONFIG_ALLOWNONAPRS) == 1); + DigiConfig.enable = (uint8_t)read(CONFIG_DIGION); + DigiConfig.enableAlias = (uint8_t)read(CONFIG_DIGIEN); + uint16_t t = read(CONFIG_DIGIVISC); + DigiConfig.viscous = (t & 0xFF00) >> 8; + DigiConfig.directOnly = t & 0xFF; + readString(CONFIG_DIGIAL0, DigiConfig.alias[0], 5); + readString(CONFIG_DIGIAL1, DigiConfig.alias[1], 5); + readString(CONFIG_DIGIAL2, DigiConfig.alias[2], 5); + readString(CONFIG_DIGIAL3, DigiConfig.alias[3], 5); + readString(CONFIG_DIGIAL4, DigiConfig.alias[4], 6); + readString(CONFIG_DIGIAL5, DigiConfig.alias[5], 6); + readString(CONFIG_DIGIAL6, DigiConfig.alias[6], 6); + readString(CONFIG_DIGIAL7, DigiConfig.alias[7], 6); + DigiConfig.ssid[0] = (uint8_t)read(CONFIG_DIGISSID4); + DigiConfig.ssid[1] = (uint8_t)read(CONFIG_DIGISSID5); + DigiConfig.ssid[2] = (uint8_t)read(CONFIG_DIGISSID6); + DigiConfig.ssid[3] = (uint8_t)read(CONFIG_DIGISSID7); + DigiConfig.max[0] = (uint8_t)read(CONFIG_DIGIMAX0); + DigiConfig.max[1] = (uint8_t)read(CONFIG_DIGIMAX1); + DigiConfig.max[2] = (uint8_t)read(CONFIG_DIGIMAX2); + DigiConfig.max[3] = (uint8_t)read(CONFIG_DIGIMAX3); + DigiConfig.rep[0] = (uint8_t)read(CONFIG_DIGIREP0); + DigiConfig.rep[1] = (uint8_t)read(CONFIG_DIGIREP1); + DigiConfig.rep[2] = (uint8_t)read(CONFIG_DIGIREP2); + DigiConfig.rep[3] = (uint8_t)read(CONFIG_DIGIREP3); + DigiConfig.traced = (uint8_t)read(CONFIG_DIGITRACE); + DigiConfig.dupeTime = (uint8_t)read(CONFIG_DIGIDEDUPE); + DigiConfig.callFilterEnable = (uint8_t)read(CONFIG_DIGICALLFILEN); + DigiConfig.filterPolarity = (uint8_t)read(CONFIG_DIGIFILTYPE); + readString(CONFIG_DIGIFILLIST, DigiConfig.callFilter[0], 140); + t = (uint8_t)read(CONFIG_PWM_FLAT); + ModemConfig.usePWM = t & 1; + ModemConfig.flatAudioIn = (t & 2) > 0; + GeneralConfig.kissMonitor = (read(CONFIG_KISSMONITOR) == 1); + Ax25Config.allowNonAprs = (read(CONFIG_ALLOWNONAPRS) == 1); return 1; } diff --git a/Src/digipeater.c b/Src/digipeater.c index 55552e2..15f9ee5 100644 --- a/Src/digipeater.c +++ b/Src/digipeater.c @@ -1,5 +1,5 @@ /* -This file is part of VP-Digi. +This file is part of VP-DigiConfig. 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 @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with VP-Digi. If not, see . +along with VP-DigiConfig. If not, see . */ #include "digipeater.h" @@ -24,31 +24,51 @@ along with VP-Digi. If not, see . #include #include "drivers/systick.h" -#define VISCOUS_DATA_LEN (6) //max frames in viscous-delay buffer -uint8_t viscousBuf[VISCOUS_DATA_LEN][FRAMELEN]; //viscous-delay frames buffer -uint32_t viscousData[VISCOUS_DATA_LEN][2]; //viscous-delay hash and timestamp buffer -#define VISCOUS_HOLD_TIME 500 //viscous-delay hold time in 10 ms units +struct _DigiConfig DigiConfig; +#define VISCOUS_MAX_FRAME_COUNT 20 //max frames in viscous-delay buffer +#define VISCOUS_MAX_FRAME_SIZE 150 -#define DEDUPE_LEN (40) //duplicate protection buffer size (number of hashes) -uint32_t deDupeBuf[DEDUPE_LEN][2]; //duplicate protection hash buffer -uint8_t deDupeIndex = 0; //duplicate protection buffer index +struct ViscousData +{ + uint32_t hash; + uint32_t timeLimit; + uint8_t *frame; + uint16_t size; +}; +static struct ViscousData viscous[VISCOUS_MAX_FRAME_COUNT]; +#define VISCOUS_HOLD_TIME 5000 //viscous-delay hold time in ms + +struct DeDupeData +{ + uint32_t hash; + uint32_t timeLimit; +}; + +#define DEDUPE_SIZE (40) //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 +static uint8_t buf[DIGI_BUFFER_SIZE]; + /** - * @brief Check if frame with specified hash is alread in viscous-delay buffer and delete it if so + * @brief Check if frame with specified hash is already in viscous-delay buffer and delete it if so * @param[in] hash Frame hash * @return 0 if not in buffer, 1 if in buffer */ -static uint8_t digi_viscousCheckAndRemove(uint32_t hash) +static uint8_t viscousCheckAndRemove(uint32_t hash) { - for(uint8_t i = 0; i < VISCOUS_DATA_LEN; i++) + for(uint8_t i = 0; i < VISCOUS_MAX_FRAME_COUNT; i++) { - if(viscousData[i][0] == hash) //matching hash + if(viscous[i].hash == hash) //matching hash { - viscousData[i][0] = 0; //clear slot - viscousData[i][1] = 0; - term_sendMonitor((uint8_t*)"Digipeated frame received, dropping old frame from viscous-delay buffer\r\n", 0); + 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); return 1; } } @@ -57,102 +77,89 @@ static uint8_t digi_viscousCheckAndRemove(uint32_t hash) -void Digi_viscousRefresh(void) +void DigiViscousRefresh(void) { - if(digi.viscous == 0) //viscous-digipeating disabled on every alias + if(DigiConfig.viscous == 0) //viscous digipeating disabled on every alias { return; } - for(uint8_t i = 0; i < VISCOUS_DATA_LEN; i++) + for(uint8_t i = 0; i < VISCOUS_MAX_FRAME_COUNT; i++) { - if((viscousData[i][0] > 0) && ((ticks - viscousData[i][1]) > VISCOUS_HOLD_TIME)) //it's time to transmit this frame + if((viscous[i].timeLimit > 0) && (ticks >= viscous[i].timeLimit)) //it's time to transmit this frame { - uint8_t len = strlen((char*)viscousBuf[i]); - if((len + 2) > (FRAMEBUFLEN - ax25.xmitIdx)) //frame won't fit in tx buffer - { - return; - } - - uint16_t begin = ax25.xmitIdx; - - for(uint8_t j = 0; j < len; j++) //copy frame to tx buffer + void *handle = NULL; + if(NULL != (handle = Ax25WriteTxFrame(viscous[i].frame, viscous[i].size))) { - ax25.frameXmit[ax25.xmitIdx] = viscousBuf[i][j]; - ax25.xmitIdx++; + if(GeneralConfig.kissMonitor) //monitoring mode, send own frames to KISS ports + { + TermSendToAll(MODE_KISS, viscous[i].frame, viscous[i].size); + } + + TermSendToAll(MODE_MONITOR, (uint8_t*)"(AX.25) Transmitting viscous-delayed frame: ", 0); + SendTNC2(viscous[i].frame, viscous[i].size); + TermSendToAll(MODE_MONITOR, (uint8_t*)"\r\n", 0); } - ax25.frameXmit[ax25.xmitIdx] = 0xFF; - ax25.xmitIdx++; - if(kissMonitor) //monitoring mode, send own frames to KISS ports - { - SendKiss(ax25.frameXmit, ax25.xmitIdx - 1); - } - - uint8_t buf[200]; - common_toTNC2((uint8_t*)&ax25.frameXmit[begin], ax25.xmitIdx - begin - 1, buf); - - term_sendMonitor((uint8_t*)"(AX.25) Transmitting viscous-delayed frame: ", 0); - term_sendMonitor(buf, 0); - term_sendMonitor((uint8_t*)"\r\n", 0); - - viscousData[i][0] = 0; - viscousData[i][1] = 0; + viscous[i].hash = 0; //clear slot + viscous[i].timeLimit = 0; + free(viscous[i].frame); + viscous[i].size = 0; } } } /** * @brief Compare callsign with specified call in call filter table - helper function. - * @param[in] *call Callsign - * @param[in] no Callsign filter table index - * @return 0 if matched with call filter, 1 if not + * @param *call Callsign + * @param index Callsign filter table index + * @return 1 if matched, 0 otherwise */ -static uint8_t compareFilterCall(uint8_t *call, uint8_t no) +static uint8_t compareFilterCall(uint8_t *call, uint8_t index) { uint8_t err = 0; for(uint8_t i = 0; i < 6; i++) { - if((digi.callFilter[no][i] < 0xff) && ((call[i] >> 1) != digi.callFilter[no][i])) + if((DigiConfig.callFilter[index][i] < 0xff) && ((call[i] >> 1) != DigiConfig.callFilter[index][i])) err = 1; } - if((digi.callFilter[no][6] < 0xff) && ((call[6] - 96) != digi.callFilter[no][6])) //special case for ssid + if((DigiConfig.callFilter[index][6] < 0xff) && ((call[6] - 96) != DigiConfig.callFilter[index][6])) //special case for ssid err = 1; - return err; + + return (err == 0); } /** * @brief Check frame with call filter * @param[in] *call Callsign in incoming frame * @param[in] alias Digi alias index currently used - * @return 0 if accepted, 1 if rejected + * @return 1 if accepted, 0 if rejected */ static uint8_t filterFrameCheck(uint8_t *call, uint8_t alias) { - //filter by call - if((digi.callFilterEnable >> alias) & 1) //check if enabled + if((DigiConfig.callFilterEnable >> alias) & 1) //check if enabled { - for(uint8_t i = 0; i < 20; i++) + for(uint8_t i = 0; i < (sizeof(DigiConfig.callFilter) / sizeof(DigiConfig.callFilter[0])); i++) { - if(!compareFilterCall(call, i)) //if callsigns match... + if(compareFilterCall(call, i)) //if callsigns match... { - if((digi.filterPolarity) == 0) - return 1; //...and blacklist is enabled, drop the frame + if(DigiConfig.filterPolarity == 0) + return 0; //...and blacklist is enabled, drop the frame else - return 0; //...and whitelist is enabled, accept the frame + return 1; //...and whitelist is enabled, accept the frame } } //if callsign is not on the list... - if((digi.filterPolarity) == 0) - return 0; //...and blacklist is enabled, accept the frame + if((DigiConfig.filterPolarity) == 0) + return 1; //...and blacklist is enabled, accept the frame else - return 1; //...and whitelist is enabled, drop the frame + return 0; //...and whitelist is enabled, drop the frame } //filter by call disabled - return 0; + return 1; } @@ -168,38 +175,43 @@ static uint8_t filterFrameCheck(uint8_t *call, uint8_t alias) */ static void makeFrame(uint8_t *frame, uint16_t elStart, uint16_t len, uint32_t hash, uint8_t alias, uint8_t simple, uint8_t n) { - uint8_t *buf; - uint16_t bufidx = 0; + uint16_t _index = 0; //underlying index for buffer if not in viscous-delay mode + uint8_t *buffer; //buffer to store frame being prepared + uint16_t *index = &_index; //index in buffer uint8_t viscousSlot = 0; //viscous delay frame slot we will use - if((alias < 8) && (digi.viscous & (1 << (alias)))) + if((alias < 8) && (DigiConfig.viscous & (1 << (alias)))) //viscous delay mode { - for(uint8_t i = 0; i < VISCOUS_DATA_LEN; i++) + for(uint8_t i = 0; i < VISCOUS_MAX_FRAME_COUNT; i++) { - if(viscousData[i][0] == 0) //look for the first available slot + if(viscous[i].timeLimit == 0) //look for the first available slot { viscousSlot = i; break; } } - if((len + 7) > FRAMELEN) //if frame length (+ 7 bytes for inserted call) is bigger than buffer size + if((len + 7) > VISCOUS_MAX_FRAME_SIZE) //if frame length (+ 7 bytes for inserted call) is bigger than buffer size return; //drop - buf = viscousBuf[viscousSlot]; + viscous[viscousSlot].frame = malloc(len + 7); + if(NULL == viscous[viscousSlot].frame) + return; + buffer = viscous[viscousSlot].frame; + index = &(viscous[viscousSlot].size); + *index = 0; } else //normal mode { - buf = malloc(FRAMELEN); - if(buf == NULL) + if(sizeof(buf) < (len + 7)) return; + buffer = buf; } - if(alias < 8) { - if(filterFrameCheck(&frame[7], alias)) //push source callsign though the filter + if(!filterFrameCheck(&frame[7], alias)) //push source callsign through the filter return; } uint8_t ssid = (frame[elStart + 6] >> 1) - 48; //store SSID (N) @@ -207,7 +219,7 @@ static void makeFrame(uint8_t *frame, uint16_t elStart, uint16_t len, uint32_t h if(alias < 8) { - if((digi.viscous & (1 << (alias))) || (digi.directOnly & (1 << alias))) //viscous-delay or direct-only enabled + if((DigiConfig.viscous & (1 << (alias))) || (DigiConfig.directOnly & (1 << alias))) //viscous-delay or direct-only enabled { if(elStart != 14) return; //this is not the very first path element, frame not received directly @@ -218,143 +230,117 @@ static void makeFrame(uint8_t *frame, uint16_t elStart, uint16_t len, uint32_t h if(simple) //if this is a simple alias, our own call or we treat n-N as a simple alias { - while(bufidx < (len)) //copy whole frame + while(*index < len) //copy whole frame { - buf[bufidx] = frame[bufidx]; - bufidx++; - if(bufidx >= FRAMELEN) - { - if(buf != NULL) - free(buf); - return; - } + buffer[*index] = frame[*index]; + (*index)++; } - if((alias == 8) || ((digi.traced & (1 << alias)) == 0)) //own call or untraced + + if((alias == 8) || ((DigiConfig.traced & (1 << alias)) == 0)) //own call or untraced { - buf[elStart + 6] += 128; //add h-bit + buffer[elStart + 6] += 128; //add h-bit } else //not our call, but treat it as a simple alias { - for(uint8_t i = 0; i < 6; i++) //replace with own call - buf[elStart + i] = call[i]; + for(uint8_t i = 0; i < sizeof(GeneralConfig.call); i++) //replace with own call + buffer[elStart + i] = GeneralConfig.call[i]; - buf[elStart + 6] &= 1; //clear everything but path end bit - buf[elStart + 6] |= ((callSsid << 1) + 0b11100000); //inset ssid and h-bit + buffer[elStart + 6] &= 1; //clear everything but path end bit + buffer[elStart + 6] |= ((GeneralConfig.callSsid << 1) + 0b11100000); //insert ssid and h-bit } } else //standard n-N alias { - while(bufidx < elStart) //copy all data before current path element + while(*index < elStart) //copy all data before current path element { - buf[bufidx] = frame[bufidx]; - bufidx++; - if(bufidx >= FRAMELEN) - { - if(buf != NULL) - free(buf); - return; - } + buffer[*index] = frame[*index]; + (*index)++; } uint16_t shift = 0; - if((digi.traced & (1 << alias)) || ((ssid == n) && (elStart == 14))) //if this is a traced alias OR it's not, but this is the very first hop for this packet, insert own call + //insert own callsign to path if: + //1. this is a traced alias OR + //2. this is an untraced alias, but it is the very first hop (heard directly) + if((DigiConfig.traced & (1 << alias)) || ((ssid == n) && (elStart == 14))) { - for(uint8_t i = 0; i < 6; i++) //insert own call - buf[bufidx++] = call[i]; + for(uint8_t i = 0; i < sizeof(GeneralConfig.call); i++) //insert own call + buffer[(*index)++] = GeneralConfig.call[i]; - buf[bufidx++] = ((callSsid << 1) + 0b11100000); //insert ssid and h-bit + buffer[(*index)++] = ((GeneralConfig.callSsid << 1) + 0b11100000); //insert ssid and h-bit shift = 7; //additional shift when own call is inserted } - while(bufidx < (len + shift)) //copy rest of the frame + while(*index < (len + shift)) //copy rest of the frame { - buf[bufidx] = frame[bufidx - shift]; - bufidx++; - if(bufidx >= FRAMELEN) - { - if(buf != NULL) - free(buf); - return; - } + buffer[*index] = frame[*index - shift]; + (*index)++; } - buf[elStart + shift + 6] -= 2; //decrement SSID in alias (2 beacuse ssid is shifted left by 1) - if((buf[elStart + shift + 6] & 0b11110) == 0) //if SSID is 0 + buffer[elStart + shift + 6] -= 2; //decrement SSID in alias (2 because ssid is shifted left by 1) + if((buffer[elStart + shift + 6] & 0b11110) == 0) //if SSID is 0 { - buf[elStart + shift + 6] += 128; //add h-bit + buffer[elStart + shift + 6] += 0x80; //add h-bit } } - if((alias < 8) && (digi.viscous & (1 << alias))) + if((alias < 8) && (DigiConfig.viscous & (1 << alias))) { - buf[bufidx++] = 0x00; - viscousData[viscousSlot][0] = hash; - viscousData[viscousSlot][1] = ticks; - term_sendMonitor((uint8_t*)"Saving frame for viscous-delay digipeating\r\n", 0); + viscous[viscousSlot].hash = hash; + viscous[viscousSlot].timeLimit = ticks + (VISCOUS_HOLD_TIME / SYSTICK_INTERVAL); + TermSendToAll(MODE_MONITOR, (uint8_t*)"Saving frame for viscous-delay digipeating\r\n", 0); } else { - if((FRAMEBUFLEN - ax25.xmitIdx) > (bufidx + 2)) + void *handle = NULL; + if(NULL != (handle = Ax25WriteTxFrame(buffer, *index))) { - deDupeIndex %= DEDUPE_LEN; + DigiStoreDeDupe(buffer, *index); - deDupeBuf[deDupeIndex][0] = hash; //store duplicate protection hash - deDupeBuf[deDupeIndex][1] = ticks; //store timestamp - - deDupeIndex++; - - uint16_t begin = ax25.xmitIdx; //store frame beginning in tx buffer - - for(uint16_t i = 0; i < bufidx; i++) //copy frame to tx buffer - { - ax25.frameXmit[ax25.xmitIdx++] = buf[i]; - } - ax25.frameXmit[ax25.xmitIdx++] = 0xFF; - - if(kissMonitor) //monitoring mode, send own frames to KISS ports - { - SendKiss(ax25.frameXmit, ax25.xmitIdx - 1); - } + if(GeneralConfig.kissMonitor) //monitoring mode, send own frames to KISS ports + { + TermSendToAll(MODE_KISS, buffer, *index); + } - common_toTNC2((uint8_t *)&ax25.frameXmit[begin], ax25.xmitIdx - begin - 1, buf); - term_sendMonitor((uint8_t*)"(AX.25) Digipeating frame: ", 0); - term_sendMonitor(buf, 0); - term_sendMonitor((uint8_t*)"\r\n", 0); + TermSendToAll(MODE_MONITOR, (uint8_t*)"(AX.25) Digipeating frame: ", 0); + SendTNC2(buffer, *index); + TermSendToAll(MODE_MONITOR, (uint8_t*)"\r\n", 0); } - free(buf); } } -void Digi_digipeat(uint8_t *frame, uint16_t len) +void DigiDigipeat(uint8_t *frame, uint16_t len) { + if(!DigiConfig.enable) + return; - uint16_t t = 13; //path length for now + uint16_t t = 13; //start from first byte that can contain path end bit while((frame[t] & 1) == 0) //look for path end { + if((t + 7) >= len) + return; t += 7; - if(t > 150) return; } //calculate frame "hash" - uint32_t hash = crc32(CRC32_INIT, frame, 14); //use destination and source adddress, skip path - hash = crc32(hash, &frame[t + 1], len - t - 1); //continue through all remaining data + uint32_t hash = Crc32(CRC32_INIT, frame, 14); //use destination and source address, skip path + hash = Crc32(hash, &frame[t + 1], len - t); //continue through all remaining data - if(digi.viscous) //viscous-delay enabled on any slot + if(DigiConfig.viscous) //viscous-delay enabled on any slot { - if(digi_viscousCheckAndRemove(hash)) //check if this frame was received twice + if(viscousCheckAndRemove(hash)) //check if this frame was received twice return; //if so, drop it } - for(uint8_t i = 0; i < DEDUPE_LEN; i++) //check if frame is already in duplicate filtering buffer + for(uint8_t i = 0; i < DEDUPE_SIZE; i++) //check if frame is already in duplicate filtering buffer { - if(deDupeBuf[i][0] == hash) + if(deDupe[i].hash == hash) { - if((ticks - deDupeBuf[i][1]) <= (digi.dupeTime * 100)) - return; //filter duplicate frame + if(ticks < (deDupe[i].timeLimit)) + return; //filter out duplicate frame } } @@ -365,7 +351,7 @@ void Digi_digipeat(uint8_t *frame, uint16_t len) } - while((frame[t] & 128) == 0) //look for h-bit + while((frame[t] & 0x80) == 0) //look for h-bit { if(t == 13) { @@ -375,17 +361,19 @@ void Digi_digipeat(uint8_t *frame, uint16_t len) } t++; //now t is the index for the first byte in path element we want to process - uint8_t ssid = ((frame[t + 6] >> 1) - 0b00110000); //current path element SSID uint8_t err = 0; - for(uint8_t i = 0; i < 6; i++) //compare with our call + for(uint8_t i = 0; i < sizeof(GeneralConfig.call); i++) //compare with our call { - if(frame[t + i] != call[i]) + if(frame[t + i] != GeneralConfig.call[i]) + { err = 1; + break; + } } - if(ssid != callSsid) //compare SSID also + if(ssid != GeneralConfig.callSsid) //compare SSID also err = 1; if(err == 0) //our callsign is in the path @@ -394,19 +382,18 @@ void Digi_digipeat(uint8_t *frame, uint16_t len) return; } - - for(uint8_t i = 0; i < 4; i++) //check for simple alias match { err = 0; - for(uint8_t j = 0; j < 6; j++) + for(uint8_t j = 0; j < sizeof(DigiConfig.alias[0]); j++) { - if(frame[t + j] != digi.alias[i + 4][j]) + if(frame[t + j] != DigiConfig.alias[i + 4][j]) { err = 1; + break; } } - if(ssid != digi.ssid[i]) + if(ssid != DigiConfig.ssid[i]) err = 1; if(err == 0) //no error @@ -422,11 +409,12 @@ void Digi_digipeat(uint8_t *frame, uint16_t len) { err = 0; uint8_t j = 0; - for(; j < strlen((const char *)digi.alias[i]); j++) + for(; j < strlen((const char *)DigiConfig.alias[i]); j++) { - if(frame[t + j] != digi.alias[i][j]) //check for matching alias + if(frame[t + j] != DigiConfig.alias[i][j]) //check for matching alias { err = 1; //alias not matching + break; } } @@ -435,7 +423,7 @@ void Digi_digipeat(uint8_t *frame, uint16_t len) uint8_t n = ((frame[t + j] >> 1) - 48); //get n from alias (e.g. WIDEn-N) - N is in ssid variable //every path must meet several requirements - //say we have WIDEn-N path + //say we have a WIDEn-N path. Then: //N <= n //0 < n < 8 //0 < N < 8 @@ -443,14 +431,14 @@ void Digi_digipeat(uint8_t *frame, uint16_t len) return; //check if n and N <= digi max - if((n <= digi.max[i]) && (ssid <= digi.max[i])) + if((n <= DigiConfig.max[i]) && (ssid <= DigiConfig.max[i])) { - if(digi.enableAlias & (1 << i)) + if(DigiConfig.enableAlias & (1 << i)) makeFrame(frame, t, len, hash, i, 0, n); //process as a standard n-N frame } - else if((digi.rep[i] > 0) && (n >= digi.rep[i])) //else check if n and N >= digi replace + else if((DigiConfig.rep[i] > 0) && (n >= DigiConfig.rep[i])) //else check if n and N >= digi replace { - if(digi.enableAlias & (1 << i)) + if(DigiConfig.enableAlias & (1 << i)) makeFrame(frame, t, len, hash, i, 1, n); } } @@ -461,28 +449,24 @@ void Digi_digipeat(uint8_t *frame, uint16_t len) -void Digi_storeDeDupeFromXmitBuf(uint16_t idx) +void DigiStoreDeDupe(uint8_t *buf, uint16_t size) { - uint32_t hash = crc32(CRC32_INIT, &ax25.frameXmit[idx], 14); //calculate for destination and source address - + uint32_t hash = Crc32(CRC32_INIT, buf, 14); //calculate for destination and source address uint16_t i = 13; - while((ax25.frameXmit[i] & 1) == 0) //look for path end bit (skip path) + while((buf[i] & 1) == 0) //look for path end bit (skip path) { i++; } i++; - while(ax25.frameXmit[i] != 0xFF) - { - hash = crc32(hash, &ax25.frameXmit[i++], 1); - } + hash = Crc32(hash, &buf[i], size - i); - deDupeIndex %= DEDUPE_LEN; + deDupeCount %= DEDUPE_SIZE; - deDupeBuf[deDupeIndex][0] = hash; - deDupeBuf[deDupeIndex][1] = ticks; + deDupe[deDupeCount].hash = hash; + deDupe[deDupeCount].timeLimit = ticks + (DigiConfig.dupeTime * 10 / SYSTICK_INTERVAL); - deDupeIndex++; + deDupeCount++; } diff --git a/Src/drivers/modem.c b/Src/drivers/modem.c index e1f53c4..ba419af 100644 --- a/Src/drivers/modem.c +++ b/Src/drivers/modem.c @@ -41,65 +41,36 @@ along with VP-Digi. If not, see . #define DCD_INC 7 #define DCD_PLLTUNE 0 -#define NN 8 //samples per symbol -#define DACSINELEN 32 //DAC sine table size +#define N 8 //samples per symbol +#define DAC_SINE_SIZE 32 //DAC sine table size #define PLLINC 536870912 //PLL tick increment value #define PLLLOCKED 0.74 //PLL adjustment value when locked #define PLLNOTLOCKED 0.50 //PLL adjustment value when not locked - #define PTT_ON GPIOB->BSRR = GPIO_BSRR_BS7 #define PTT_OFF GPIOB->BSRR = GPIO_BSRR_BR7 #define DCD_ON (GPIOC->BSRR = GPIO_BSRR_BR13) #define DCD_OFF (GPIOC->BSRR = GPIO_BSRR_BS13) +struct ModemDemodConfig ModemConfig; -struct ModState -{ - TxTestMode txTestState; //current TX test mode - uint16_t dacSine[DACSINELEN]; //sine samples for DAC - uint8_t dacSineIdx; //current sine sample index - uint16_t samples_oversampling[4]; //very raw received samples, filled directly by DMA - uint8_t currentSymbol; //current symbol for NRZI encoding - uint16_t txDelay; //TXDelay length in number of bytes - uint16_t txTail; //TXTail length in number of bytes - uint8_t markFreq; //mark frequency (inter-sample interval) - uint8_t spaceFreq; //space frequency (inter-sample interval) - uint16_t baudRate; //baudrate - int32_t coeffHiI[NN], coeffLoI[NN], coeffHiQ[NN], coeffLoQ[NN]; //correlator IQ coefficients -}; - -volatile struct ModState modState; - - -typedef struct -{ - Emphasis emphasis; //preemphasis/deemphasis - uint8_t rawSymbols; //raw, unsynchronized symbols - uint8_t syncSymbols; //synchronized symbols - int16_t rawSample[8]; //input (raw) samples - int32_t rxSample[16]; //rx samples after pre/deemphasis filter - uint8_t rxSampleIdx; //index for the array above - int64_t lpfSample[16]; //rx samples after final filtering - uint8_t dcd : 1; //DCD state - uint64_t RMSenergy; //frame energy counter (sum of samples squared) - uint32_t RMSsampleCount; //number of samples for RMS - int32_t pll; //bit recovery PLL counter - int32_t lastPll; //last bit recovery PLL counter value - int32_t dcdPll; //DCD PLL main counter - uint8_t dcdLastSymbol; //last symbol for DCD - uint8_t dcdCounter; //DCD "pulse" counter (incremented when RX signal is correct) -} Demod; - -volatile Demod demod1; -volatile Demod demod2; +static enum ModemTxTestMode txTestState; //current TX test mode +static uint16_t dacSine[DAC_SINE_SIZE]; //sine samples for DAC +static uint8_t dacSineIdx; //current sine sample index +static uint16_t samples[4]; //very raw received samples, filled directly by DMA +static uint8_t currentSymbol; //current symbol for NRZI encoding +static uint8_t markFreq; //mark frequency (inter-sample interval) +static uint8_t spaceFreq; //space frequency (inter-sample interval) +static uint16_t baudRate; //baudrate +static int32_t coeffHiI[N], coeffLoI[N], coeffHiQ[N], coeffLoQ[N]; //correlator IQ coefficients +static uint8_t dcd = 0; //multiplexed DCD state from both demodulators -uint8_t dcd = 0; //multiplexed DCD state from both demodulators /** * @brief BPF filter with 2200 Hz tone 6 dB preemphasis (it actually attenuates 1200 Hz tone by 6 dB) */ -const int16_t bpf1200[8] = { +static const int16_t bpfCoeffs[8] = +{ 728, -13418, -554, @@ -113,7 +84,8 @@ const int16_t bpf1200[8] = { /** * @brief BPF filter with 2200 Hz tone 6 dB deemphasis */ -const int16_t bpf1200inv[8] = { +static const int16_t invBpfCoeffs[8] = +{ -10513, -10854, 9589, @@ -124,11 +96,15 @@ const int16_t bpf1200inv[8] = { -879 }; +#define BPF_TAPS (sizeof(bpfCoeffs) / sizeof(*bpfCoeffs) > sizeof(invBpfCoeffs) / sizeof(*invBpfCoeffs) ? \ + sizeof(bpfCoeffs) / sizeof(*bpfCoeffs) : sizeof(invBpfCoeffs) / sizeof(*invBpfCoeffs)) + /** * @brief Output LPF filter to remove data faster than 1200 baud * It actually is a 600 Hz filter: symbols can change at 1200 Hz, but it takes 2 "ticks" to return to the same symbol - that's why it's 600 Hz */ -const int16_t lpf1200[15] = { +static const int16_t lpfCoeffs[15] = +{ -6128, -5974, -2503, @@ -146,54 +122,70 @@ const int16_t lpf1200[15] = { -6128 }; +#define LPF_TAPS (sizeof(lpfCoeffs) / sizeof(*lpfCoeffs)) + + +struct DemodState +{ + enum ModemEmphasis emphasis; //preemphasis/deemphasis + uint8_t rawSymbols; //raw, unsynchronized symbols + uint8_t syncSymbols; //synchronized symbols + int16_t rawSample[BPF_TAPS]; //input (raw) samples + int32_t rxSample[BPF_TAPS]; //rx samples after pre/deemphasis filter + uint8_t rxSampleIdx; //index for the array above + int64_t lpfSample[LPF_TAPS]; //rx samples after final filtering + uint8_t dcd : 1; //DCD state + uint64_t RMSenergy; //frame energy counter (sum of samples squared) + uint32_t RMSsampleCount; //number of samples for RMS + int32_t pll; //bit recovery PLL counter + int32_t lastPll; //last bit recovery PLL counter value + int32_t dcdPll; //DCD PLL main counter + uint8_t dcdLastSymbol; //last symbol for DCD + uint8_t dcdCounter; //DCD "pulse" counter (incremented when RX signal is correct) +}; +static volatile struct DemodState demodState[MODEM_DEMODULATOR_COUNT]; -static void afsk_decode(uint8_t symbol, Demod *dem); -static int32_t afsk_demod(int16_t sample, Demod *dem); -static void afsk_ptt(uint8_t state); +static void decode(uint8_t symbol, uint8_t demod); +static int32_t demodulate(int16_t sample, struct DemodState *dem); +static void setPtt(uint8_t state); -uint8_t Afsk_dcdState(void) +uint8_t ModemDcdState(void) { return dcd; } -uint8_t Afsk_isTxTestOngoing(void) +uint8_t ModemIsTxTestOngoing(void) { - if(modState.txTestState != TEST_DISABLED) + if(txTestState != TEST_DISABLED) return 1; return 0; } -void Afsk_clearRMS(uint8_t modemNo) +void ModemClearRMS(uint8_t modem) { - if(modemNo == 0) - { - demod1.RMSenergy = 0; - demod1.RMSsampleCount = 0; - } - else - { - demod2.RMSenergy = 0; - demod2.RMSsampleCount = 0; - } + + demodState[modem].RMSenergy = 0; + demodState[modem].RMSsampleCount = 0; + } -uint16_t Afsk_getRMS(uint8_t modemNo) +uint16_t ModemGetRMS(uint8_t modem) { - if(modemNo == 0) - { - return sqrtf((float)demod1.RMSenergy / (float)demod1.RMSsampleCount); - } - return sqrtf((float)demod2.RMSenergy / (float)demod2.RMSsampleCount); + return sqrtf((float)demodState[modem].RMSenergy / (float)demodState[modem].RMSsampleCount); } +enum ModemEmphasis ModemGetFilterType(uint8_t modem) +{ + return demodState[modem].emphasis; +} /** * @brief Set DCD LED * @param[in] state 0 - OFF, 1 - ON */ -static void afsk_dcd(uint8_t state) +static void setDcd(uint8_t state) { if(state) { @@ -219,33 +211,33 @@ void DMA1_Channel2_IRQHandler(void) { DMA1->IFCR |= DMA_IFCR_CTCIF2; - int32_t sample = ((modState.samples_oversampling[0] + modState.samples_oversampling[1] + modState.samples_oversampling[2] + modState.samples_oversampling[3]) >> 1) - 4095; //calculate input sample (decimation) - uint8_t symbol = 0; //output symbol + int32_t sample = ((samples[0] + samples[1] + samples[2] + samples[3]) >> 1) - 4095; //calculate input sample (decimation) - //use 2 demodulators - symbol = (afsk_demod(sample, (Demod*)&demod1) > 0); //demodulate sample - afsk_decode(symbol, (Demod*)&demod1); //recover bits, decode NRZI and call higher level function + uint8_t partialDcd = 0; - symbol = (afsk_demod(sample, (Demod*)&demod2) > 0); - afsk_decode(symbol, (Demod*)&demod2); + for(uint8_t i = 0; i < MODEM_DEMODULATOR_COUNT; i++) + { + uint8_t symbol = (demodulate(sample, (struct DemodState*)&demodState[i]) > 0); //demodulate sample + decode(symbol, i); //recover bits, decode NRZI and call higher level function + if(demodState[i].dcd) + partialDcd |= 1; + } - if(demod1.dcd || demod2.dcd) //DCD on any of the demodulators + if(partialDcd) //DCD on any of the demodulators { dcd = 1; - afsk_dcd(1); + setDcd(1); } - else if((demod1.dcd == 0) && (demod2.dcd == 0)) //no DCD on both demodulators + else //no DCD on both demodulators { dcd = 0; - afsk_dcd(0); + setDcd(0); } } } - - /** * @brief ISR for pushing DAC samples */ @@ -254,19 +246,18 @@ void TIM1_UP_IRQHandler(void) { TIM1->SR &= ~TIM_SR_UIF; - modState.dacSineIdx++; - modState.dacSineIdx &= (DACSINELEN - 1); - - if(afskCfg.usePWM) + if(ModemConfig.usePWM) { - TIM4->CCR1 = modState.dacSine[modState.dacSineIdx]; + TIM4->CCR1 = dacSine[dacSineIdx]; } else { - GPIOB->ODR &= ~61440; //zero 4 oldest bits - GPIOB->ODR |= (modState.dacSine[modState.dacSineIdx] << 12); //write sample to 4 oldest bits - + GPIOB->ODR &= ~0xF000; //zero 4 oldest bits + GPIOB->ODR |= (dacSine[dacSineIdx] << 12); //write sample to 4 oldest bits } + + dacSineIdx++; + dacSineIdx &= (DAC_SINE_SIZE - 1); } @@ -278,34 +269,25 @@ void TIM3_IRQHandler(void) { TIM3->SR &= ~TIM_SR_UIF; - if(modState.txTestState == TEST_DISABLED) //transmitting normal data + if(txTestState == TEST_DISABLED) //transmitting normal data { - if(Ax25_getTxBit() == 0) //get next bit and check if it's 0 + if(Ax25GetTxBit() == 0) //get next bit and check if it's 0 { - modState.currentSymbol = modState.currentSymbol ? 0 : 1; //change symbol - NRZI encoding + currentSymbol ^= 1; //change symbol - NRZI encoding } //if 1, no symbol change } else //transmit test mode { - modState.currentSymbol = modState.currentSymbol ? 0 : 1; //change symbol + currentSymbol ^= 1; //change symbol } - if(modState.currentSymbol) //current symbol is space - { + TIM1->CNT = 0; - TIM1->CNT = 0; - TIM1->ARR = modState.spaceFreq; - } + if(currentSymbol) //current symbol is space + TIM1->ARR = spaceFreq; else //mark - { - - TIM1->CNT = 0; - TIM1->ARR = modState.markFreq; - - } - - + TIM1->ARR = markFreq; } @@ -316,30 +298,27 @@ void TIM3_IRQHandler(void) * @param[in] *dem Demodulator state * @return Current tone (0 or 1) */ -static int32_t afsk_demod(int16_t sample, Demod *dem) +static int32_t demodulate(int16_t sample, struct DemodState *dem) { dem->RMSenergy += ((sample >> 1) * (sample >> 1)); //square the sample and add it to the sum dem->RMSsampleCount++; //increment number of samples - - if(dem->emphasis != EMPHASIS_NONE) //preemphasis/deemphasis is used { int32_t out = 0; //filtered output - for(uint8_t i = 7; i > 0; i--) + for(uint8_t i = BPF_TAPS - 1; i > 0; i--) dem->rawSample[i] = dem->rawSample[i - 1]; //shift old samples dem->rawSample[0] = sample; //store new sample - for(uint8_t i = 0; i < 8; i++) + for(uint8_t i = 0; i < BPF_TAPS; i++) { if(dem->emphasis == PREEMPHASIS) - out += bpf1200[i] * dem->rawSample[i]; //use preemphasis + out += bpfCoeffs[i] * dem->rawSample[i]; //use preemphasis else - out += bpf1200inv[i] * dem->rawSample[i]; //use deemphasis + out += invBpfCoeffs[i] * dem->rawSample[i]; //use deemphasis } - dem->rxSample[dem->rxSampleIdx] = (out >> 15); //store filtered sample } else //no pre/deemphasis @@ -347,21 +326,20 @@ static int32_t afsk_demod(int16_t sample, Demod *dem) dem->rxSample[dem->rxSampleIdx] = sample; //store incoming sample } - int64_t outLoI = 0, outLoQ = 0, outHiI = 0, outHiQ = 0; //output values after correlating + dem->rxSampleIdx = (dem->rxSampleIdx + 1) % BPF_TAPS; //increment sample pointer and wrap around if needed - dem->rxSampleIdx = (dem->rxSampleIdx + 1) % NN; //increment sample pointer and wrap around if needed + int64_t outLoI = 0, outLoQ = 0, outHiI = 0, outHiQ = 0; //output values after correlating - for(uint8_t i = 0; i < NN; i++) { - int32_t t = dem->rxSample[(dem->rxSampleIdx + i) % NN]; //read sample - outLoI += t * modState.coeffLoI[i]; //correlate sample - outLoQ += t * modState.coeffLoQ[i]; - outHiI += t * modState.coeffHiI[i]; - outHiQ += t * modState.coeffHiQ[i]; + for(uint8_t i = 0; i < N; i++) { + int32_t t = dem->rxSample[(dem->rxSampleIdx + i) % BPF_TAPS]; //read sample + outLoI += t * coeffLoI[i]; //correlate sample + outLoQ += t * coeffLoQ[i]; + outHiI += t * coeffHiI[i]; + outHiQ += t * coeffHiQ[i]; } uint64_t hi = 0, lo = 0; - hi = ((outHiI >> 12) * (outHiI >> 12)) + ((outHiQ >> 12) * (outHiQ >> 12)); //calculate output tone levels lo = ((outLoI >> 12) * (outLoI >> 12)) + ((outLoQ >> 12) * (outLoQ >> 12)); @@ -395,7 +373,6 @@ static int32_t afsk_demod(int16_t sample, Demod *dem) dem->dcdLastSymbol = dcdSymbol; //store last symbol for symbol change detection - if(dem->dcdCounter > DCD_MAXPULSE) //maximum DCD counter value reached dem->dcdCounter = DCD_MAXPULSE; //avoid "sticky" DCD and counter overflow @@ -407,13 +384,13 @@ static int32_t afsk_demod(int16_t sample, Demod *dem) //filter out signal faster than 1200 baud int64_t out = 0; - for(uint8_t i = 14; i > 0; i--) + for(uint8_t i = LPF_TAPS - 1; i > 0; i--) dem->lpfSample[i] = dem->lpfSample[i - 1]; dem->lpfSample[0] = (int64_t)hi - (int64_t)lo; - for(uint8_t i = 0; i < 15; i++) + for(uint8_t i = 0; i < LPF_TAPS; i++) { - out += lpf1200[i] * dem->lpfSample[i]; + out += lpfCoeffs[i] * dem->lpfSample[i]; } return out > 0; @@ -425,10 +402,11 @@ static int32_t afsk_demod(int16_t sample, Demod *dem) /** * @brief Decode received symbol: bit recovery, NRZI decoding and pass the decoded bit to higher level protocol * @param[in] symbol Received symbol - * @param *dem Demodulator state + * @param demod Demodulator index */ -static void afsk_decode(uint8_t symbol, Demod *dem) +static void decode(uint8_t symbol, uint8_t demod) { + struct DemodState *dem = (struct DemodState*)&demodState[demod]; //This function provides bit/clock recovery and NRZI decoding //Bit recovery is based on PLL which is described in the function above (DCD PLL) @@ -441,7 +419,6 @@ static void afsk_decode(uint8_t symbol, Demod *dem) dem->rawSymbols |= (symbol & 1); - if ((dem->pll < 0) && (dem->lastPll > 0)) //PLL counter overflow, sample symbol, decode NRZI and process in higher layer { dem->syncSymbols <<= 1; //shift recovered (received, synchronized) bit register @@ -456,18 +433,18 @@ static void afsk_decode(uint8_t symbol, Demod *dem) //NRZI decoding if (((dem->syncSymbols & 0x03) == 0b11) || ((dem->syncSymbols & 0x03) == 0b00)) //two last symbols are the same - no symbol transition - decoded bit 1 { - Ax25_bitParse(1, (dem == &demod1) ? 0 : 1); + Ax25BitParse(1, demod); } else //symbol transition - decoded bit 0 { - Ax25_bitParse(0, (dem == &demod1) ? 0 : 1); + Ax25BitParse(0, demod); } } if(((dem->rawSymbols & 0x03) == 0b10) || ((dem->rawSymbols & 0x03) == 0b01)) //if there was a symbol transition, adjust PLL { - if (Ax25_getRxStage((dem == &demod1) ? 0 : 1) != RX_STAGE_FRAME) //not in a frame + if(Ax25GetRxStage(demod) != RX_STAGE_FRAME) //not in a frame { dem->pll = (int)(dem->pll * PLLNOTLOCKED); //adjust PLL faster } @@ -480,54 +457,47 @@ static void afsk_decode(uint8_t symbol, Demod *dem) } -/** - * @brief Start or restart TX test mode - * @param[in] type TX test type: TEST_MARK, TEST_SPACE or TEST_ALTERNATING - */ -void Afsk_txTestStart(TxTestMode type) + +void ModemTxTestStart(enum ModemTxTestMode type) { - if(modState.txTestState != TEST_DISABLED) //TX test is already running - Afsk_txTestStop(); //stop this test + if(txTestState != TEST_DISABLED) //TX test is already running + ModemTxTestStop(); //stop this test - afsk_ptt(1); //PTT on - modState.txTestState = type; + setPtt(1); //PTT on + txTestState = type; //DAC timer TIM1->PSC = 17; //72/18=4 MHz TIM1->DIER = TIM_DIER_UIE; //enable interrupt TIM1->CR1 |= TIM_CR1_CEN; //enable timer - TIM2->CR1 &= ~TIM_CR1_CEN; //disable RX timer - NVIC_DisableIRQ(DMA1_Channel2_IRQn); //disable RX DMA interrupt NVIC_EnableIRQ(TIM1_UP_IRQn); //enable timer 1 for PWM if(type == TEST_MARK) { - TIM1->ARR = modState.markFreq; + TIM1->ARR = markFreq; } else if(type == TEST_SPACE) { - TIM1->ARR = modState.spaceFreq; + TIM1->ARR = spaceFreq; } else //alternating tones { //enable baudrate generator TIM3->PSC = 71; //72/72=1 MHz TIM3->DIER = TIM_DIER_UIE; //enable interrupt - TIM3->ARR = modState.baudRate; //set timer interval + TIM3->ARR = baudRate; //set timer interval TIM3->CR1 = TIM_CR1_CEN; //enable timer NVIC_EnableIRQ(TIM3_IRQn); //enable interrupt in NVIC } } -/** - * @brief Stop TX test mode - */ -void Afsk_txTestStop(void) + +void ModemTxTestStop(void) { - modState.txTestState = TEST_DISABLED; + txTestState = TEST_DISABLED; TIM3->CR1 &= ~TIM_CR1_CEN; //turn off timers TIM1->CR1 &= ~TIM_CR1_CEN; @@ -537,16 +507,13 @@ void Afsk_txTestStop(void) NVIC_DisableIRQ(TIM1_UP_IRQn); NVIC_EnableIRQ(DMA1_Channel2_IRQn); - afsk_ptt(0); //PTT off + setPtt(0); //PTT off } -/** - * @brief Configure and start TX - * @warning Transmission should be started with Ax25_transmitBuffer - */ -void Afsk_transmitStart(void) + +void ModemTransmitStart(void) { - afsk_ptt(1); //PTT on + setPtt(1); //PTT on TIM1->PSC = 17; TIM1->DIER |= TIM_DIER_UIE; @@ -554,7 +521,7 @@ void Afsk_transmitStart(void) TIM3->PSC = 71; TIM3->DIER |= TIM_DIER_UIE; - TIM3->ARR = modState.baudRate; + TIM3->ARR = baudRate; TIM3->CR1 = TIM_CR1_CEN; TIM1->CR1 = TIM_CR1_CEN; @@ -563,14 +530,13 @@ void Afsk_transmitStart(void) NVIC_DisableIRQ(DMA1_Channel2_IRQn); NVIC_EnableIRQ(TIM1_UP_IRQn); NVIC_EnableIRQ(TIM3_IRQn); - } /** * @brief Stop TX and go back to RX */ -void Afsk_transmitStop(void) +void ModemTransmitStop(void) { TIM2->CR1 |= TIM_CR1_CEN; @@ -581,7 +547,7 @@ void Afsk_transmitStop(void) NVIC_DisableIRQ(TIM3_IRQn); NVIC_EnableIRQ(DMA1_Channel2_IRQn); - afsk_ptt(0); + setPtt(0); TIM4->CCR1 = 44; //set around 50% duty cycle } @@ -590,7 +556,7 @@ void Afsk_transmitStop(void) * @brief Controls PTT output * @param[in] state 0 - PTT off, 1 - PTT on */ -static void afsk_ptt(uint8_t state) +static void setPtt(uint8_t state) { if(state) PTT_ON; @@ -603,11 +569,11 @@ static void afsk_ptt(uint8_t state) /** * @brief Initialize AFSK module */ -void Afsk_init(void) +void ModemInit(void) { /** - * TIM1 is used for pushing samples to DAC (R2R or PWM) - * TIM3 is the baudrate generator for TX + * TIM1 is used for pushing samples to DAC (R2R or PWM) at 4 MHz + * TIM3 is the baudrate generator for TX running at 1 MHz * TIM4 is the PWM generator with no software interrupt * TIM2 is the RX sampling timer with no software interrupt, but it directly calls DMA */ @@ -622,13 +588,12 @@ void Afsk_init(void) RCC->AHBENR |= RCC_AHBENR_DMA1EN; - GPIOC->CRH |= GPIO_CRH_MODE13_1; //DCD LED on PC13 GPIOC->CRH &= ~GPIO_CRH_MODE13_0; GPIOC->CRH &= ~GPIO_CRH_CNF13; - GPIOB->CRH &= ~4294901760; //R2R output on PB12-PB15 - GPIOB->CRH |= 572653568; + GPIOB->CRH &= ~0xFFFF0000; //R2R output on PB12-PB15 + GPIOB->CRH |= 0x22220000; GPIOA->CRL &= ~GPIO_CRL_CNF0; //ADC input on PA0 GPIOA->CRL &= ~GPIO_CRL_MODE0; @@ -654,9 +619,11 @@ void Afsk_init(void) ADC1->CR2 |= ADC_CR2_ADON; //ADC on ADC1->CR2 |= ADC_CR2_RSTCAL; //calibrate ADC - while(ADC1->CR2 & ADC_CR2_RSTCAL); + while(ADC1->CR2 & ADC_CR2_RSTCAL) + ; ADC1->CR2 |= ADC_CR2_CAL; - while(ADC1->CR2 & ADC_CR2_CAL); + while(ADC1->CR2 & ADC_CR2_CAL) + ; ADC1->CR2 |= ADC_CR2_EXTTRIG; ADC1->CR2 |= ADC_CR2_SWSTART; //start ADC conversion @@ -670,7 +637,7 @@ void Afsk_init(void) DMA1_Channel2->CCR |= DMA_CCR_MINC | DMA_CCR_CIRC| DMA_CCR_TCIE; //circular mode, memory increment and interrupt DMA1_Channel2->CNDTR = 4; //4 samples DMA1_Channel2->CPAR = (uint32_t)&(ADC1->DR); //ADC data register address - DMA1_Channel2->CMAR = (uint32_t)modState.samples_oversampling; //sample buffer address + DMA1_Channel2->CMAR = (uint32_t)samples; //sample buffer address DMA1_Channel2->CCR |= DMA_CCR_EN; //enable DMA NVIC_EnableIRQ(DMA1_Channel2_IRQn); @@ -680,42 +647,39 @@ void Afsk_init(void) TIM2->ARR = 103; //4MHz / 104 =~38400 Hz (4*9600 Hz for 4x oversampling) TIM2->CR1 |= TIM_CR1_CEN; //enable timer - modState.markFreq = 103; //set mark frequency - modState.spaceFreq = 55; //set space frequency - - modState.baudRate = 832; //set baudrate - - + markFreq = 4000000 / (DAC_SINE_SIZE * (uint32_t)MODEM_MARK_FREQUENCY) - 1; //set mark frequency + spaceFreq = 4000000 / (DAC_SINE_SIZE * (uint32_t)MODEM_SPACE_FREQUENCY) - 1; //set space frequency + baudRate = 1000000 / (uint32_t)MODEM_BAUDRATE - 1; //set baudrate - for(uint8_t i = 0; i < NN; i++) //calculate correlator coefficients + for(uint8_t i = 0; i < N; i++) //calculate correlator coefficients { - modState.coeffLoI[i] = 4095.f * cosf(2.f * 3.1416f * (float)i / (float)NN); - modState.coeffLoQ[i] = 4095.f * sinf(2.f * 3.1416f * (float)i / (float)NN); - modState.coeffHiI[i] = 4095.f * cosf(2.f * 3.1416f * (float)i / (float)NN * 2200.f / 1200.f); - modState.coeffHiQ[i] = 4095.f * sinf(2.f * 3.1416f * (float)i / (float)NN * 2200.f / 1200.f); + coeffLoI[i] = 4095.f * cosf(2.f * 3.1416f * (float)i / (float)N * MODEM_MARK_FREQUENCY / MODEM_BAUDRATE); + coeffLoQ[i] = 4095.f * sinf(2.f * 3.1416f * (float)i / (float)N * MODEM_MARK_FREQUENCY / MODEM_BAUDRATE); + coeffHiI[i] = 4095.f * cosf(2.f * 3.1416f * (float)i / (float)N * MODEM_SPACE_FREQUENCY / MODEM_BAUDRATE); + coeffHiQ[i] = 4095.f * sinf(2.f * 3.1416f * (float)i / (float)N * MODEM_SPACE_FREQUENCY / MODEM_BAUDRATE); } - for(uint8_t i = 0; i < DACSINELEN; i++) //calculate DAC sine samples + for(uint8_t i = 0; i < DAC_SINE_SIZE; i++) //calculate DAC sine samples { - if(afskCfg.usePWM) - modState.dacSine[i] = ((sinf(2.f * 3.1416f * (float)i / (float)DACSINELEN) + 1.f) * 45.f); + if(ModemConfig.usePWM) + dacSine[i] = ((sinf(2.f * 3.1416f * (float)i / (float)DAC_SINE_SIZE) + 1.f) * 45.f); else - modState.dacSine[i] = ((7.f * sinf(2.f * 3.1416f * (float)i / (float)DACSINELEN)) + 8.f); + dacSine[i] = ((7.f * sinf(2.f * 3.1416f * (float)i / (float)DAC_SINE_SIZE)) + 8.f); } - if(afskCfg.flatAudioIn) //when used with flat audio input, use deemphasis and flat modems + if(ModemConfig.flatAudioIn) //when used with flat audio input, use deemphasis and flat modems { - demod1.emphasis = EMPHASIS_NONE; - demod2.emphasis = DEEMPHASIS; + demodState[0].emphasis = EMPHASIS_NONE; + demodState[1].emphasis = DEEMPHASIS; } else //when used with normal (filtered) audio input, use flat and preemphasis modems { - demod1.emphasis = EMPHASIS_NONE; - demod2.emphasis = PREEMPHASIS; + demodState[0].emphasis = EMPHASIS_NONE; + demodState[1].emphasis = PREEMPHASIS; } - if(afskCfg.usePWM) + if(ModemConfig.usePWM) { RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; //configure timer diff --git a/Src/drivers/systick.c b/Src/drivers/systick.c index 12f4f18..82d5208 100644 --- a/Src/drivers/systick.c +++ b/Src/drivers/systick.c @@ -16,6 +16,7 @@ along with VP-Digi. If not, see . */ #include "drivers/systick.h" +#include "stm32f1xx.h" volatile uint32_t ticks = 0; //SysTick counter @@ -25,7 +26,7 @@ volatile uint32_t ticks = 0; //SysTick counter //ticks++; //} -void SysTick_init(void) +void SysTickInit(void) { - SysTick_Config(SystemCoreClock / 100); //SysTick every 10 ms + SysTick_Config(SystemCoreClock / SYSTICK_FREQUENCY); //SysTick every 10 ms } diff --git a/Src/drivers/uart.c b/Src/drivers/uart.c index e7bfa1f..3b458eb 100644 --- a/Src/drivers/uart.c +++ b/Src/drivers/uart.c @@ -24,94 +24,89 @@ along with VP-Digi. If not, see . #include "digipeater.h" -uint8_t USBmode = MODE_KISS; -uint8_t USBrcvd = DATA_NOTHING; -uint8_t USBint = 0; /**< Flaga "przerwania" USB dla obslugi w petli glownej */ - - -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 volatile void uart_handleInterrupt(Uart *port) +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 { port->port->SR &= ~USART_SR_RXNE; - port->bufrx[port->bufrxidx] = port->port->DR; //store it - port->bufrxidx++; - if(port->port == USART1) //handle special functions and characters - term_handleSpecial(TERM_UART1); - else if(port->port == USART2) - term_handleSpecial(TERM_UART2); + port->rxBuffer[port->rxBufferHead++] = port->port->DR; //store it + port->rxBufferHead %= UART_BUFFER_SIZE; - port->bufrxidx %= UARTBUFLEN; +// 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 + 500; //set timeout to 5s in KISS mode + port->kissTimer = ticks + (5000 / SYSTICK_INTERVAL); //set timeout to 5s in KISS mode } if(port->port->SR & USART_SR_IDLE) //line is idle, end of data reception { port->port->DR; //reset idle flag by dummy read - if(port->bufrxidx == 0) - return; //no data, stop - - if((port->bufrx[0] == 0xc0) && (port->bufrx[port->bufrxidx - 1] == 0xc0)) //data starts with 0xc0 and ends with 0xc0 - this is a KISS frame - { - port->rxflag = DATA_KISS; - port->kissTimer = 0; - } - - if(((port->bufrx[port->bufrxidx - 1] == '\r') || (port->bufrx[port->bufrxidx - 1] == '\n'))) //data ends with \r or \n, process as data + if(port->rxBufferHead != 0) { - port->rxflag = DATA_TERM; - port->kissTimer = 0; + if((port->rxBuffer[0] == 0xC0) && (port->rxBuffer[port->rxBufferHead - 1] == 0xC0)) //data starts with 0xc0 and ends with 0xc0 - this is a KISS frame + { + port->rxType = DATA_KISS; + port->kissTimer = 0; + } + else if(((port->rxBuffer[port->rxBufferHead - 1] == '\r') || (port->rxBuffer[port->rxBufferHead - 1] == '\n'))) //data ends with \r or \n, process as data + { + port->rxType = DATA_TERM; + port->kissTimer = 0; + } } - } if(port->port->SR & USART_SR_TXE) //TX buffer empty { - if(port->buftxrd != port->buftxwr) //if there is anything to transmit + if((port->txBufferHead != port->txBufferTail) || port->txBufferFull) //if there is anything to transmit { - port->port->DR = port->buftx[port->buftxrd++]; //push it to the refister - port->buftxrd %= UARTBUFLEN; - } else //nothing more to be transmitted + port->port->DR = port->txBuffer[port->txBufferTail++]; //push it to the refister + port->txBufferTail %= UART_BUFFER_SIZE; + port->txBufferFull = 0; + } + else //nothing more to be transmitted { - port->txflag = 0; //stop transmission port->port->CR1 &= ~USART_CR1_TXEIE; } } @@ -119,159 +114,105 @@ static volatile void uart_handleInterrupt(Uart *port) if((port->kissTimer > 0) && (ticks >= port->kissTimer)) //KISS timer timeout { port->kissTimer = 0; - port->bufrxidx = 0; - memset(port->bufrx, 0, UARTBUFLEN); + port->rxBufferHead = 0; + memset(port->rxBuffer, 0, sizeof(port->rxBuffer)); } } void USART1_IRQHandler(void) __attribute__ ((interrupt)); void USART1_IRQHandler(void) { - uart_handleInterrupt(&uart1); + handleInterrupt(&Uart1); } void USART2_IRQHandler(void) __attribute__ ((interrupt)); void USART2_IRQHandler(void) { - uart_handleInterrupt(&uart2); + handleInterrupt(&Uart2); } - - -void uart_transmitStart(Uart *port) +void UartSendByte(Uart *port, uint8_t data) { - if(port->enabled == 0) - { - port->buftxrd = port->buftxwr; + if(!port->enabled) return; - } - port->txflag = 1; - port->port->CR1 |= USART_CR1_TXEIE; -} - - -void uartUSB_sendByte(uint8_t data) -{ - uint8_t a[1]; - a[0] = data; - CDC_Transmit_FS(a, 1); -} - - -void uart_sendByte(Uart *port, uint8_t data) -{ - while(port->txflag == 1);; - port->buftx[port->buftxwr++] = data; - port->buftxwr %= (UARTBUFLEN); -} - - -void uart_sendString(Uart *port, uint8_t *data, uint16_t len) -{ - - if(len == 0) + if(port->isUsb) { - while(*(data + len) != 0) - { - len++; - if(len == UARTBUFLEN) - break; - } + CDC_Transmit_FS(&data, 1); } - - while(port->txflag == 1);; - uint16_t i = 0; - while(i < len) + else { - port->buftx[port->buftxwr++] = *(data + i); - port->buftxwr %= (UARTBUFLEN); - i++; + while(port->txBufferFull) + ; + port->txBuffer[port->txBufferHead++] = data; + port->txBufferHead %= UART_BUFFER_SIZE; + if(port->txBufferHead == port->txBufferTail) + port->txBufferFull = 1; + if(0 == (port->port->CR1 & USART_CR1_TXEIE)) + port->port->CR1 |= USART_CR1_TXEIE; } - } -void uart_sendNumber(Uart *port, int32_t n) +void UartSendString(Uart *port, void *data, uint16_t len) { - if(n < 0) uart_sendByte(port, '-'); - n = abs(n); - if(n > 999999) uart_sendByte(port, (n / 1000000) + 48); - if(n > 99999) uart_sendByte(port, ((n % 1000000) / 100000) + 48); - if(n > 9999) uart_sendByte(port, ((n % 100000) / 10000) + 48); - if(n > 999) uart_sendByte(port, ((n % 10000) / 1000) + 48); - if(n > 99) uart_sendByte(port, ((n % 1000) / 100) + 48); - if(n > 9) uart_sendByte(port, ((n % 100) / 10) + 48); - uart_sendByte(port, (n % 10) + 48); + if(0 == len) + len = strlen((char*)data); + + for(uint16_t i = 0; i < len; i++) + { + UartSendByte(port, ((uint8_t*)data)[i]); + } } -void uartUSB_sendString(uint8_t *data, uint16_t len) +static unsigned int findHighestPosition(unsigned int n) { + unsigned int i = 1; + while((i * 10) <= n) + i *= 10; - if(len == 0) - { - len = strlen((char*)data); - } - uint16_t i = 0; - uint8_t j = 0; - uint16_t k = len; - //USB is quite specific and data must be send in small packets, say in 40-byte packets - while(i < len) - { - if((k / 40) >= 1) - { - CDC_Transmit_FS(&data[j * 40], 40); - j++; - k -= 40; - i += 40; - } - else - { - CDC_Transmit_FS(&data[i], len - i); - break; - } - } + return i; } - -void uartUSB_sendNumber(int32_t n) +void UartSendNumber(Uart *port, int32_t n) { if(n < 0) - uartUSB_sendByte('-'); + UartSendByte(port, '-'); n = abs(n); - if(n > 999999) uartUSB_sendByte((n / 1000000) + 48); - if(n > 99999) uartUSB_sendByte(((n % 1000000) / 100000) + 48); - if(n > 9999) uartUSB_sendByte(((n % 100000) / 10000) + 48); - if(n > 999) uartUSB_sendByte(((n % 10000) / 1000) + 48); - if(n > 99) uartUSB_sendByte(((n % 1000) / 100) + 48); - if(n > 9) uartUSB_sendByte(((n % 100) / 10) + 48); - uartUSB_sendByte((n % 10) + 48); + unsigned int position = findHighestPosition(n); + while(position) + { + unsigned int number = n / position; + UartSendByte(port, (number + 48)); + n -= (number * position); + position /= 10; + } } - -void uart_init(Uart *port, USART_TypeDef *uart, uint32_t baud) +void UartInit(Uart *port, USART_TypeDef *uart, uint32_t baud) { port->port = uart; port->baudrate = baud; - port->rxflag = DATA_NOTHING; - port->txflag = 0; - port->bufrxidx = 0; - port->buftxrd = 0; - port->buftxwr = 0; + port->rxType = DATA_NOTHING; + port->rxBufferHead = 0; + port->txBufferHead = 0; + port->txBufferTail = 0; + port->txBufferFull = 0; port->mode = MODE_KISS; port->enabled = 0; port->kissTimer = 0; - memset(port->bufrx, 0, UARTBUFLEN); - memset(port->buftx, 0, UARTBUFLEN); + memset(port->rxBuffer, 0, sizeof(port->rxBuffer)); + memset(port->txBuffer, 0, sizeof(port->txBuffer)); } -void uart_config(Uart *port, uint8_t state) +void UartConfig(Uart *port, uint8_t state) { if(port->port == USART1) { + RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; RCC->APB2ENR |= RCC_APB2ENR_USART1EN; GPIOA->CRH |= GPIO_CRH_MODE9_1; GPIOA->CRH &= ~GPIO_CRH_CNF9_0; @@ -293,9 +234,11 @@ void uart_config(Uart *port, uint8_t state) NVIC_DisableIRQ(USART1_IRQn); port->enabled = state > 0; + port->isUsb = 0; } else if(port->port == USART2) { + RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; RCC->APB1ENR |= RCC_APB1ENR_USART2EN; GPIOA->CRL |= GPIO_CRL_MODE2_1; GPIOA->CRL &= ~GPIO_CRL_CNF2_0; @@ -316,14 +259,29 @@ void uart_config(Uart *port, uint8_t state) NVIC_DisableIRQ(USART2_IRQn); port->enabled = state > 0; + port->isUsb = 0; + } + else + { + port->isUsb = 1; + port->enabled = state > 0; } } -void uart_clearRx(Uart *port) +void UartClearRx(Uart *port) { - port->bufrxidx = 0; - port->rxflag = 0; + port->rxBufferHead = 0; + port->rxType = DATA_NOTHING; } +void UartHandleKissTimeout(Uart *port) +{ + if((port->kissTimer > 0) && (ticks >= port->kissTimer)) //KISS timer timeout + { + port->kissTimer = 0; + port->rxBufferHead = 0; + memset(port->rxBuffer, 0, sizeof(port->rxBuffer)); + } +} diff --git a/Src/drivers/watchdog.c b/Src/drivers/watchdog.c index adb585b..52e2f14 100644 --- a/Src/drivers/watchdog.c +++ b/Src/drivers/watchdog.c @@ -18,7 +18,7 @@ along with VP-Digi. If not, see . #include "drivers/watchdog.h" #include "stm32f1xx.h" -void Wdog_init(void) +void WdogInit(void) { IWDG->KR = 0x5555; //configuration mode IWDG->PR = 0b101; //prescaler @@ -27,7 +27,7 @@ void Wdog_init(void) } -void Wdog_reset(void) +void WdogReset(void) { IWDG->KR = 0xAAAA; //reset } diff --git a/Src/main.c b/Src/main.c index d608d79..305d7ef 100644 --- a/Src/main.c +++ b/Src/main.c @@ -85,103 +85,85 @@ static void MX_GPIO_Init(void); /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ + /** - * \brief Handle received frame from RF + * @brief Handle received frame */ -void handleFrame(void) +static void handleFrame(void) { - uint8_t modemReceived = ax25.frameReceived; //store states - ax25.frameReceived = 0; //clear flag + uint8_t modemBitmap = Ax25GetReceivedFrameBitmap(); //store states + Ax25ClearReceivedFrameBitmap(); - uint8_t bufto[FRAMELEN + 30], buf[FRAMELEN]; //buffer for raw frames to TNC2 frames conversion - uint16_t bufidx = 0; - uint16_t i = ax25.frameBufRd; + uint8_t *buf = NULL; + uint16_t size = 0; + uint16_t signalLevel = 0; - while(i != ax25.frameBufWr) + while(Ax25ReadNextRxFrame(&buf, &size, &signalLevel)) { - if(ax25.frameBuf[i] != 0xFF) - { - buf[bufidx++] = ax25.frameBuf[i++]; //store frame in temporary buffer - } - else - { - break; - } - i %= (FRAMEBUFLEN); - } - ax25.frameBufRd = ax25.frameBufWr; - - for(i = 0; i < (bufidx); i++) - { - if(buf[i] & 1) - break; //look for path end bit - } + TermSendToAll(MODE_KISS, buf, size); - SendKiss(buf, bufidx); //send KISS frames if ports available - - if(((USBmode == MODE_MONITOR) || (uart1.mode == MODE_MONITOR) || (uart2.mode == MODE_MONITOR))) - { - common_toTNC2(buf, bufidx, bufto); //convert to TNC2 format - - //in general, the RMS of the frame is calculated (excluding preamble!) - //it it calculated from samples ranging from -4095 to 4095 (amplitude of 4095) - //that should give a RMS of around 2900 for pure sine wave - //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 - ax25.sLvl /= 9; - - if(ax25.sLvl > 100) + if(((UartUsb.mode == MODE_MONITOR) || (Uart1.mode == MODE_MONITOR) || (Uart2.mode == MODE_MONITOR))) { - term_sendMonitor((uint8_t*)"\r\nInput level too high! Please reduce so most stations are around 50-70%.\r\n", 0); - } + //in general, the RMS of the frame is calculated (excluding preamble!) + //it it calculated from samples ranging from -4095 to 4095 (amplitude of 4095) + //that should give a RMS of around 2900 for pure sine wave + //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 + signalLevel /= 9; + + if(signalLevel > 100) + { + TermSendToAll(MODE_MONITOR, (uint8_t*)"\r\nInput level too high! Please reduce so most stations are around 50-70%.\r\n", 0); + } + else if(signalLevel < 10) + { + TermSendToAll(MODE_MONITOR, (uint8_t*)"\r\nInput level too low! Please increase so most stations are around 50-70%.\r\n", 0); + } + + TermSendToAll(MODE_MONITOR, (uint8_t*)"(AX.25) Frame received [", 0); //show which modem received the frame: [FP] (flat and preemphasized), [FD] (flat and deemphasized - in flat audio input mode) + //[F_] (only flat), [_P] (only preemphasized) or [_D] (only deemphasized - in flat audio input mode) + for(uint8_t i = 0; i < MODEM_DEMODULATOR_COUNT; i++) + { + if(modemBitmap & (1 << i)) + { + enum ModemEmphasis m = ModemGetFilterType(i); + switch(m) + { + case PREEMPHASIS: + TermSendToAll(MODE_MONITOR, (uint8_t*)"P", 1); + break; + case DEEMPHASIS: + TermSendToAll(MODE_MONITOR, (uint8_t*)"D", 1); + break; + case EMPHASIS_NONE: + default: + TermSendToAll(MODE_MONITOR, (uint8_t*)"F", 1); + break; + } + } + else + TermSendToAll(MODE_MONITOR, (uint8_t*)"_", 1); + } + + TermSendToAll(MODE_MONITOR, (uint8_t*)"], signal level ", 0); + TermSendNumberToAll(MODE_MONITOR, signalLevel); + TermSendToAll(MODE_MONITOR, (uint8_t*)"%: ", 0); + + SendTNC2(buf, size); + TermSendToAll(MODE_MONITOR, (uint8_t*)"\r\n", 0); - if(ax25.sLvl < 10) - { - term_sendMonitor((uint8_t*)"\r\nInput level too low! Please increase so most stations are around 50-70%.\r\n", 0); - } - - term_sendMonitor((uint8_t*)"(AX.25) Frame received [", 0); //show which modem received the frame: [FP] (flat and preemphasized), [FD] (flat and deemphasized - in flat audio input mode) - //[F_] (only flat), [_P] (only preemphasized) or [_D] (only deemphasized - in flat audio input mode) - uint8_t t[2] = {0}; - if(modemReceived & 1) - { - t[0] = 'F'; } - else - t[0] = '_'; - if(modemReceived & 2) - { - if(afskCfg.flatAudioIn) - t[1] = 'D'; - else - t[1] = 'P'; - } - else - t[1] = '_'; - term_sendMonitor(t, 2); - term_sendMonitor((uint8_t*)"], signal level ", 0); - term_sendMonitorNumber(ax25.sLvl); - term_sendMonitor((uint8_t*)"%: ", 0); - term_sendMonitor(bufto, 0); - term_sendMonitor((uint8_t*)"\r\n", 0); + DigiDigipeat(buf, size); + free(buf); } - - - if(digi.enable) - { - Digi_digipeat(buf, bufidx); - } - - - } @@ -211,15 +193,16 @@ int main(void) /* USER CODE BEGIN SysInit */ - SysTick_init(); + SysTickInit(); //force usb re-enumeration after reset RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //pull D+ to ground for a moment GPIOA->CRH |= GPIO_CRH_MODE12_1; GPIOA->CRH &= ~GPIO_CRH_CNF12; GPIOA->BSRR = GPIO_BSRR_BR12; - uint32_t t = ticks + 10; - while(t > ticks);; + uint32_t t = ticks + (100 / SYSTICK_INTERVAL); + while(t > ticks) + ; GPIOA->CRH &= ~GPIO_CRH_MODE12; GPIOA->CRH |= GPIO_CRH_CNF12_0; @@ -233,117 +216,110 @@ int main(void) - Wdog_init(); //initialize watchdog + WdogInit(); //initialize watchdog + memset(&beacon, 0, sizeof(beacon)); + memset(&Ax25Config, 0, sizeof(Ax25Config)); + memset(&ModemConfig, 0, sizeof(ModemConfig)); + memset(&DigiConfig, 0, sizeof(DigiConfig)); //set some initial values in case there is no configuration saved in memory - uart1.baudrate = 9600; - uart2.baudrate = 9600; - afskCfg.usePWM = 0; - afskCfg.flatAudioIn = 0; - ax25Cfg.quietTime = 300; - ax25Cfg.txDelayLength = 300; - ax25Cfg.txTailLength = 30; - digi.dupeTime = 30; - - Config_read(); + Uart1.baudrate = 9600; + Uart2.baudrate = 9600; + ModemConfig.usePWM = 0; + ModemConfig.flatAudioIn = 0; + Ax25Config.quietTime = 300; + Ax25Config.txDelayLength = 300; + Ax25Config.txTailLength = 30; + DigiConfig.dupeTime = 30; - Ax25_init(); + ConfigRead(); - uart_init(&uart1, USART1, uart1.baudrate); - uart_init(&uart2, USART2, uart2.baudrate); + Ax25Init(); - uart_config(&uart1, 1); - uart_config(&uart2, 1); + UartInit(&Uart1, USART1, Uart1.baudrate); + UartInit(&Uart2, USART2, Uart2.baudrate); + UartInit(&UartUsb, NULL, 1); - Afsk_init(); - Beacon_init(); + UartConfig(&Uart1, 1); + UartConfig(&Uart2, 1); + UartConfig(&UartUsb, 1); - - autoResetTimer = autoReset * 360000; + ModemInit(); + BeaconInit(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ - static uint32_t usbKissTimer = 0; while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ - Wdog_reset(); + WdogReset(); - if(ax25.frameReceived) + if(Ax25GetReceivedFrameBitmap()) handleFrame(); - Digi_viscousRefresh(); //refresh viscous-delay buffers - - - Ax25_transmitBuffer(); //transmit buffer (will return if nothing to be transmitted) - - Ax25_transmitCheck(); //check for pending transmission request - - if(USBint) //USB "interrupt" + DigiViscousRefresh(); //refresh viscous-delay buffers + + Ax25TransmitBuffer(); //transmit buffer (will return if nothing to be transmitted) + + 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) { - 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; - } + TermParse(&UartUsb); + UartClearRx(&UartUsb); } - - if((usbKissTimer > 0) && (ticks >= usbKissTimer)) //USB KISS timer timeout - { - usbcdcidx = 0; - memset(usbcdcdata, 0, UARTBUFLEN); - usbKissTimer = 0; - } - - - if(USBrcvd != DATA_NOTHING) + if(Uart1.rxType != DATA_NOTHING) { - term_parse(usbcdcdata, usbcdcidx, TERM_USB, USBrcvd, USBmode); - USBrcvd = DATA_NOTHING; - usbcdcidx = 0; - memset(usbcdcdata, 0, UARTBUFLEN); + TermParse(&Uart1); + UartClearRx(&Uart1); } - if(uart1.rxflag != DATA_NOTHING) + if(Uart2.rxType != DATA_NOTHING) { - term_parse(uart1.bufrx, uart1.bufrxidx, TERM_UART1, uart1.rxflag, uart1.mode); - uart1.rxflag = DATA_NOTHING; - uart1.bufrxidx = 0; - memset(uart1.bufrx, 0, UARTBUFLEN); - } - if(uart2.rxflag != DATA_NOTHING) - { - term_parse(uart2.bufrx, uart2.bufrxidx, TERM_UART2, uart2.rxflag, uart2.mode); - uart2.rxflag = DATA_NOTHING; - uart2.bufrxidx = 0; - memset(uart2.bufrx, 0, UARTBUFLEN); + TermParse(&Uart2); + UartClearRx(&Uart2); } + UartHandleKissTimeout(&UartUsb); - Beacon_check(); //check beacons + BeaconCheck(); //check beacons - if(((autoResetTimer != 0) && (ticks > autoResetTimer)) || (ticks > 4294960000)) + if(ticks > 0xFFFFF000) NVIC_SystemReset(); - - - } /* USER CODE END 3 */ } diff --git a/Src/terminal.c b/Src/terminal.c index 361bd1e..2b931db 100644 --- a/Src/terminal.c +++ b/Src/terminal.c @@ -1,5 +1,5 @@ /* -This file is part of VP-Digi. +This file is part of VP-DigiConfig. 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 @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with VP-Digi. If not, see . +along with VP-DigiConfig. If not, see . */ #include "terminal.h" @@ -23,738 +23,536 @@ along with VP-Digi. If not, see . #include "drivers/modem.h" #include "ax25.h" -uint8_t termBuf[TERMBUFLEN]; //terminal mode TX buffer -uint16_t termBufIdx = 0; //terminal mode TX buffer index - -uint16_t spLastIdx[3] = {0, 0, 0}; //index buffer was "special" terminal cases +//uint16_t spLastIdx[3] = {0, 0, 0}; //index buffer was "special" terminal cases /** * @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) +//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) { - 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)) + if(port->mode == MODE_KISS) //check if KISS mode { - 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); + UartSendByte(port, 0xc0); //send data in kiss format + UartSendByte(port, 0x00); + UartSendString(port, buf, len); + UartSendByte(port, 0xc0); } - } -/** - * \brief Send data to all available monitor outputs - * \param[in] *data Data to send - * \param[in] len Data length or 0 for NULL-terminated data - */ -void term_sendMonitor(uint8_t *data, uint16_t len) +void TermSendToAll(enum UartMode mode, uint8_t *data, uint16_t size) { - if(USBmode == MODE_MONITOR) - { - uartUSB_sendString(data, len); - } - if((uart1.enabled) && (uart1.mode == MODE_MONITOR)) + if(MODE_KISS == mode) { - uart_sendString(&uart1, data, len); - uart_transmitStart(&uart1); + sendKiss(&Uart1, data, size); + sendKiss(&Uart2, data, size); + sendKiss(&UartUsb, data, size); } - if((uart2.enabled) && (uart2.mode == MODE_MONITOR)) + else if(MODE_MONITOR == mode) { - uart_sendString(&uart2, data, len); - uart_transmitStart(&uart2); + if(UartUsb.mode == MODE_MONITOR) + UartSendString(&UartUsb, data, size); + if(Uart1.mode == MODE_MONITOR) + UartSendString(&Uart1, data, size); + if(Uart2.mode == MODE_MONITOR) + UartSendString(&Uart2, data, size); } + } -/** - * \brief Send number to all available monitor outputs - * \param[in] data Number to send - */ -void term_sendMonitorNumber(int32_t data) +void TermSendNumberToAll(enum UartMode mode, int32_t n) { - if(USBmode == MODE_MONITOR) - { - uartUSB_sendNumber(data); - } - if((uart1.enabled) && (uart1.mode == MODE_MONITOR)) - { - uart_sendNumber(&uart1, data); - uart_transmitStart(&uart1); - } - if((uart2.enabled) && (uart2.mode == MODE_MONITOR)) + if(MODE_MONITOR == mode) { - uart_sendNumber(&uart2, data); - uart_transmitStart(&uart2); + if(UartUsb.mode == MODE_MONITOR) + UartSendNumber(&UartUsb, n); + if(Uart1.mode == MODE_MONITOR) + UartSendNumber(&Uart1, n); + if(Uart2.mode == MODE_MONITOR) + UartSendNumber(&Uart2, n); } + } -/** -* \brief Send terminal buffer using specified stream -* \param[in] way Stream: TERM_ANY, TERM_USB, TERM_UART1, TERM_UART2 -*/ -void term_sendBuf(Terminal_stream way) + + + +static const char monitorHelp[] = "\r\nCommans available in monitor mode:\r\n" + "help - shows this help page\r\n" + "cal {low|high|alt|stop} - transmits/stops transmitter calibration pattern\r\n" + "\tlow - transmits MARK tone, high - transmits SPACE tone, alt - transmits alternating tones (null bytes)\r\n" + "beacon - immediately transmits selected beacon (number from 0 to 7)\r\n" + "kiss - switches to KISS mode\r\n" + "config - switches to config mode\r\n" + "reboot - reboots the device\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" + "print - prints all configuration parameters\r\n" + "list - prints callsign filter list\r\n" + "save - saves configuration and reboots the device\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" + "version - shows full firmware version info\r\n\r\n" + "call - sets callsign with optional SSID\r\n" + "dest
- sets destination address\r\n" + "txdelay <50-2550> - sets TXDelay time (ms)\r\n" + "txtail <10-2550> - sets TXTail time (ms)\r\n" + "quiet <100-2550> - sets quiet time (ms)\r\n" + "rs1baud/rs2baud <1200-115200> - sets UART1/UART2 baudrate\r\n" + "pwm [on/off] - enables/disables PWM. If PWM is off, R2R will be used instead\r\n" + "flat [on/off] - set to \"on\" if flat audio input is used\r\n" + "beacon <0-7> [on/off] - enables/disables specified beacon\r\n" + "beacon <0-7> [iv/dl] <0-720> - sets interval/delay for the specified beacon (min)\r\n" + "beacon <0-7> path /none - sets path for the specified beacon\r\n" + "beacon <0-7> data - sets information field for the specified beacon\r\n" + "digi [on/off] - enables/disables whole digipeater\r\n" + "digi <0-7> [on/off] - enables/disables specified slot\r\n" + "digi <0-7> alias - sets alias for the specified slot\r\n" + "digi <0-3> [max/rep] <0/1-7> - sets maximum/replacement N for the specified slot\r\n" + "digi <0-7> trac [on/off] - enables/disables packet tracing for the specified slot\r\n" + "digi <0-7> viscous [on/off] - enables/disables viscous-delay digipeating for the specified slot\r\n" + "digi <0-7> direct [on/off] - enables/disables direct-only digipeating for the specified slot\r\n"\ + "digi <0-7> filter [on/off] - enables/disables packet filtering for the specified slot\r\n" + "digi filter [black/white] - sets filtering type to blacklist/whitelist\r\n" + "digi dupe <5-255> - sets anti-dupe buffer time (s)\r\n" + "digi list <0-19> [set /remove] - sets/clears specified callsign slot in filter list\r\n" + "monkiss [on/off] - send own and digipeated frames to KISS ports\r\n" + "nonaprs [on/off] - enable reception of non-APRS frames\r\n"; + + + +static void printConfig(Uart *src) { - if((way == TERM_USB) || (way == TERM_ANY)) + UartSendString(src, "Callsign: ", 0); + for(uint8_t i = 0; i < 6; i++) { - uartUSB_sendString(termBuf, termBufIdx); + if(GeneralConfig.call[i] != (' ' << 1)) + UartSendByte(src, GeneralConfig.call[i] >> 1); } - if((way == TERM_UART1) || (way == TERM_ANY)) + UartSendByte(src, '-'); + UartSendNumber(src, GeneralConfig.callSsid); + + UartSendString(src, "\r\nDestination: ", 0); + for(uint8_t i = 0; i < 6; i++) { - for(uint16_t d = 0; d < termBufIdx; d++) - { - uart_sendByte(&uart1, termBuf[d]); - } - uart_transmitStart(&uart1); + if(GeneralConfig.dest[i] != (' ' << 1)) + UartSendByte(src, GeneralConfig.dest[i] >> 1); } - if((way == TERM_UART2) || (way == TERM_ANY)) + + UartSendString(src, "\r\nTXDelay (ms): ", 0); + UartSendNumber(src, Ax25Config.txDelayLength); + UartSendString(src, "\r\nTXTail (ms): ", 0); + UartSendNumber(src, Ax25Config.txTailLength); + UartSendString(src, "\r\nQuiet time (ms): ", 0); + UartSendNumber(src, Ax25Config.quietTime); + UartSendString(src, "\r\nUART1 baudrate: ", 0); + UartSendNumber(src, Uart1.baudrate); + UartSendString(src, "\r\nUART2 baudrate: ", 0); + UartSendNumber(src, Uart2.baudrate); + UartSendString(src, "\r\nDAC type: ", 0); + if(ModemConfig.usePWM) + UartSendString(src, "PWM", 0); + else + UartSendString(src, "R2R", 0); + UartSendString(src, "\r\nFlat audio input: ", 0); + if(ModemConfig.flatAudioIn) + UartSendString(src, "yes", 0); + else + UartSendString(src, "no", 0); + for(uint8_t i = 0; i < (sizeof(beacon) / sizeof(*beacon)); i++) { - for(uint16_t d = 0; d < termBufIdx; d++) - { - uart_sendByte(&uart2, termBuf[d]); + UartSendString(src, "\r\nBeacon ", 0); + UartSendByte(src, i + '0'); + UartSendString(src, ": ", 0); + if(beacon[i].enable) + UartSendString(src, "On, Iv: ", 0); + else + UartSendString(src, "Off, Iv: ", 0); + UartSendNumber(src, beacon[i].interval / 6000); + UartSendString(src, ", Dl: ", 0); + UartSendNumber(src, beacon[i].delay / 60); + UartSendByte(src, ','); + UartSendByte(src, ' '); + if(beacon[i].path[0] != 0) + { + for(uint8_t j = 0; j < 6; j++) + { + if(beacon[i].path[j] != (' ' << 1)) + UartSendByte(src, beacon[i].path[j] >> 1); + } + UartSendByte(src, '-'); + UartSendNumber(src, beacon[i].path[6]); + if(beacon[i].path[7] != 0) + { + UartSendByte(src, ','); + for(uint8_t j = 7; j < 13; j++) + { + if(beacon[i].path[j] != (' ' << 1)) + UartSendByte(src, beacon[i].path[j] >> 1); + } + UartSendByte(src, '-'); + UartSendNumber(src, beacon[i].path[13]); + } } - uart_transmitStart(&uart2); + else + UartSendString(src, "no path", 0); + UartSendByte(src, ','); + UartSendByte(src, ' '); + UartSendString(src, beacon[i].data, 0); } - termBufIdx = 0; -} -/** - * \brief Push byte to terminal buffer - * \param[in] data Byte to store - */ -void term_sendByte(uint8_t data) -{ - if(termBufIdx > TERMBUFLEN - 1) - return; - termBuf[termBufIdx++] = data; -} + UartSendString(src, "\r\nDigipeater: ", 0); + if(DigiConfig.enable) + UartSendString(src, "On\r\n", 0); + else + UartSendString(src, "Off\r\n", 0); -/** - * \brief Push string to terminal buffer - * \param[in] *data String - * \param[in] len String length or 0 for NULL-terminated string - */ -void term_sendString(uint8_t *data, uint16_t len) -{ - if(len != 0) + for(uint8_t i = 0; i < 4; i++) //n-N aliases { - for(uint16_t y= 0; y < len; y++) + UartSendString(src, "Alias ", 0); + if(DigiConfig.alias[i][0] != 0) { - if(termBufIdx > TERMBUFLEN - 1) break; - termBuf[termBufIdx++] = *data; - data++; + for(uint8_t j = 0; j < 5; j++) + { + if(DigiConfig.alias[i][j] != 0) + UartSendByte(src, DigiConfig.alias[i][j] >> 1); + else + break; + } } - } else + UartSendString(src, ": ", 0); + if(DigiConfig.enableAlias & (1 << i)) + UartSendString(src, "On, max: ", 0); + else + UartSendString(src, "Off, max: ", 0); + UartSendNumber(src, DigiConfig.max[i]); + UartSendString(src, ", rep: ", 0); + UartSendNumber(src, DigiConfig.rep[i]); + if(DigiConfig.traced & (1 << i)) + UartSendString(src, ", traced, ", 0); + else + UartSendString(src, ", untraced, ", 0); + if(DigiConfig.viscous & (1 << i)) + UartSendString(src, "viscous-delay, ", 0); + else if(DigiConfig.directOnly & (1 << i)) + UartSendString(src, "direct-only, ", 0); + if(DigiConfig.callFilterEnable & (1 << i)) + UartSendString(src, "filtered\r\n", 0); + else + UartSendString(src, "unfiltered\r\n", 0); + } + for(uint8_t i = 0; i < 4; i++) //simple aliases { - while(*data != 0) + UartSendString(src, "Alias ", 0); + if(DigiConfig.alias[i + 4][0] != 0) { - if(termBufIdx > TERMBUFLEN - 1) break; - termBuf[termBufIdx++] = *data; - data++; - if(termBufIdx > TERMBUFLEN) break; + for(uint8_t j = 0; j < 6; j++) + { + if(DigiConfig.alias[i + 4][j] != 64) + UartSendByte(src, DigiConfig.alias[i + 4][j] >> 1); + } } + UartSendByte(src, '-'); + UartSendNumber(src, DigiConfig.ssid[i]); + UartSendString(src, ": ", 0); + if(DigiConfig.enableAlias & (1 << (i + 4))) + UartSendString(src, "On, ", 0); + else + UartSendString(src, "Off, ", 0); + if(DigiConfig.traced & (1 << (i + 4))) + UartSendString(src, "traced, ", 0); + else + UartSendString(src, "untraced, ", 0); + if(DigiConfig.viscous & (1 << (i + 4))) + UartSendString(src, "viscous-delay, ", 0); + else if(DigiConfig.directOnly & (1 << (i + 4))) + UartSendString(src, "direct-only, ", 0); + if(DigiConfig.callFilterEnable & (1 << (i + 4))) + UartSendString(src, "filtered\r\n", 0); + else + UartSendString(src, "unfiltered\r\n", 0); } - termBuf[termBufIdx] = 0; -} - -/** - * \brief Push number (in ASCII form) in terminal buffer - * \param[in] n Number - */ -void term_sendNumber(int32_t n) -{ - if(n < 0) - n = abs(n); - if(n > 999999) term_sendByte((n / 1000000) + 48); - if(n > 99999) term_sendByte(((n % 1000000) / 100000) + 48); - if(n > 9999) term_sendByte(((n % 100000) / 10000) + 48); - if(n > 999) term_sendByte(((n % 10000) / 1000) + 48); - if(n > 99) term_sendByte(((n % 1000) / 100) + 48); - if(n > 9) term_sendByte(((n % 100) / 10) + 48); - term_sendByte((n % 10) + 48); -} - -/** - * \brief Chceck if received data and command are matching - * \param[in] *data Received data - * \param[in] dlen Data length - * \param[in] *cmd Command - * \return 1 if matching, 0 if not - */ -static uint8_t checkcmd(uint8_t *data, uint8_t dlen, uint8_t *cmd) -{ - for(uint8_t a = 0; a < dlen; a++) + UartSendString(src, "Anti-duplicate buffer hold time (s): ", 0); + UartSendNumber(src, DigiConfig.dupeTime); + UartSendString(src, "\r\nCallsign filter type: ", 0); + if(DigiConfig.filterPolarity) + UartSendString(src, "whitelist\r\n", 0); + else + UartSendString(src, "blacklist\r\n", 0); + UartSendString(src, "Callsign filter list: ", 0); + uint8_t entries = 0; + for(uint8_t i = 0; i < 20; i++) { - if(*(data + a) != *(cmd + a)) - return 0; + if(DigiConfig.callFilter[i][0] != 0) + entries++; } - return 1; + UartSendNumber(src, entries); + UartSendString(src, " entries\r\nKISS monitor: ", 0); + if(GeneralConfig.kissMonitor == 1) + UartSendString(src, "On\r\n", 0); + else + UartSendString(src, "Off\r\n", 0); + UartSendString(src, "Allow non-APRS frames: ", 0); + if(Ax25Config.allowNonAprs == 1) + UartSendString(src, "On\r\n", 0); + else + UartSendString(src, "Off\r\n", 0); } -/** - * \brief Parse and process received data - * \param[in] *cmd Data - * \param[in] len Data length - * \param[in] src Source: TERM_USB, TERM_UART1, TERM_UART2 - * \param[in] type Data type: DATA_KISS, DATA_TERM - * \param[in] mode Input mode: MODE_KISS, MODE_TERM, MODE_MONITOR - */ -void term_parse(uint8_t *cmd, uint16_t len, Terminal_stream src, Uart_data_type type, Uart_mode mode) -{ - if(src == TERM_ANY) //incorrect source - return; - if(checkcmd(cmd, 4, (uint8_t*)"kiss")) +void TermParse(Uart *src) +{ + const char *cmd = (char*)src->rxBuffer; + uint16_t len = src->rxBufferHead; + for(uint16_t i = 0; i < len; i++) { - if(src == TERM_USB) - { - term_sendString((uint8_t*)"USB switched to KISS mode\r\n", 0); - term_sendBuf(TERM_USB); - USBmode = MODE_KISS; - } - else if(src == TERM_UART1) - { - term_sendString((uint8_t*)"UART1 switched to KISS mode\r\n", 0); - term_sendBuf(TERM_UART1); - uart1.mode = MODE_KISS; - } - else if(src == TERM_UART2) + if((cmd[i] == '\r') || (cmd[i] == '\n')) { - term_sendString((uint8_t*)"UART2 switched to KISS mode\r\n", 0); - term_sendBuf(TERM_UART2); - uart2.mode = MODE_KISS; + len = i; + break; } - return; } - if(checkcmd(cmd, 6, (uint8_t*)"config")) + /* + * Terminal mode switching commands + */ + if(!strncmp(cmd, "kiss", 4)) { - term_sendString((uint8_t*)"Switched to configuration mode\r\n" - "Most settings will take effect immidiately, but\r\n" + UartSendString(src, (uint8_t*)"Switched to KISS mode\r\n", 0); + src->mode = MODE_KISS; + return; + } + else if(!strncmp(cmd, "config", 6)) + { + UartSendString(src, (uint8_t*)"Switched to configuration mode\r\n" + "Most settings will take effect immediately, but\r\n" "remember to save the configuration using \"save\"\r\n", 0); - if(src == TERM_USB) - { - term_sendBuf(TERM_USB); - USBmode = MODE_TERM; - } - else if(src == TERM_UART1) - { - term_sendBuf(TERM_UART1); - uart1.mode = MODE_TERM; - } - else if(src == TERM_UART2) - { - term_sendBuf(TERM_UART2); - uart2.mode = MODE_TERM; - } + src->mode = MODE_TERM; return; } - - if(checkcmd(cmd, 7, (uint8_t*)"monitor")) + else if(!strncmp(cmd, "monitor", 7)) { - if(src == TERM_USB) - { - term_sendString((uint8_t*)"USB switched to monitor mode\r\n", 0); - term_sendBuf(TERM_USB); - USBmode = MODE_MONITOR; - } - else if(src == TERM_UART1) - { - term_sendString((uint8_t*)"UART1 switched to monitor mode\r\n", 0); - term_sendBuf(TERM_UART1); - uart1.mode = MODE_MONITOR; - } - else if(src == TERM_UART2) - { - term_sendString((uint8_t*)"UART2 switched to monitor mode\r\n", 0); - term_sendBuf(TERM_UART2); - uart2.mode = MODE_MONITOR; - } + UartSendString(src, (uint8_t*)"USB switched to monitor mode\r\n", 0); + src->mode = MODE_MONITOR; return; } - - if((mode == MODE_KISS) && (type == DATA_KISS)) + /* + * KISS parsing + */ + else if((src->mode == MODE_KISS) && (src->rxType == DATA_KISS)) { - Uart_txKiss(cmd, len); //if received KISS data, transmit KISS frame + //Uart_txKiss(cmd, len); //if received KISS data, transmit KISS frame return; } - - if((mode == MODE_MONITOR) && (type == DATA_TERM)) //monitor mode + /* + * Monitor mode handling + */ + else if((src->mode == MODE_MONITOR) && (src->rxType == DATA_TERM)) //monitor mode { - if(checkcmd(cmd, 4, (uint8_t*)"help")) + if(!strncmp(cmd, "help", 4)) { - term_sendString((uint8_t*)"\r\nCommans available in monitor mode:\r\n", 0); - term_sendString((uint8_t*)"help - shows this help page\r\n", 0); - term_sendString((uint8_t*)"cal {low|high|alt|stop} - transmits/stops transmitter calibration pattern\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"\tlow - transmits MARK tone, high - transmits SPACE tone, alt - transmits alternating tones (null bytes)\r\n", 0); - term_sendString((uint8_t*)"beacon - immediately transmits selected beacon (number from 0 to 7)\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"kiss - switches to KISS mode\r\n", 0); - term_sendString((uint8_t*)"config - switches to config mode\r\n", 0); - term_sendString((uint8_t*)"reboot - reboots the device\r\n", 0); - term_sendString((uint8_t*)"version - shows full firmware version info\r\n\r\n\r\n", 0); - term_sendBuf(src); - return; + UartSendString(src, (char *)monitorHelp, 0); } - if(checkcmd(cmd, 7, (uint8_t*)"version")) + else if(!strncmp(cmd, "version", 7)) { - term_sendString((uint8_t*)versionString, 0); - term_sendBuf(src); - return; + UartSendString(src, (char *)versionString, 0); } - if(checkcmd(cmd, 6, (uint8_t*)"reboot")) + else if(!strncmp(cmd, "reboot", 6)) { NVIC_SystemReset(); - return; } - if(checkcmd(cmd, 7, (uint8_t*)"beacon ")) + else if(!strncmp(cmd, "beacon ", 7)) { - if((cmd[7] > 47) && (cmd[7] < 56)) + if((cmd[7] >= '0') && (cmd[7] <= '7')) { - uint8_t bcno = cmd[7] - 48; - if((beacon[bcno].interval != 0) && (beacon[bcno].enable != 0)) + uint8_t number = cmd[7] - '0'; + if((beacon[number].interval != 0) && (beacon[number].enable != 0)) { - Beacon_send(bcno); - return; + BeaconSend(number); } else { - term_sendString((uint8_t*)"Beacon " , 0); - term_sendNumber(bcno); - term_sendString((uint8_t*)" not enabled. Cannot transmit disabled beacons.\r\n", 0); - term_sendBuf(src); + UartSendString(src, "Beacon " , 0); + UartSendNumber(src, number); + UartSendString(src, " is not enabled. Cannot transmit disabled beacons.\r\n", 0); } - return; } else { - term_sendString((uint8_t*)"Beacon number must be within 0-7 range\r\n", 0); - term_sendBuf(src); - return; + UartSendString(src, "Beacon number must be in range of 0 to 7.\r\n", 0); } } - - if(checkcmd(cmd, 3, (uint8_t*)"cal")) + else if(!strncmp(cmd, "cal", 3)) { - if(checkcmd(&cmd[4], 3, (uint8_t*)"low")) - { - term_sendString((uint8_t*)"Starting low tone calibration transmission\r\n", 0); - term_sendBuf(src); - Afsk_txTestStart(TEST_MARK); - return; - } - else if(checkcmd(&cmd[4], 4, (uint8_t*)"high")) - { - term_sendString((uint8_t*)"Starting high tone calibration transmission\r\n", 0); - term_sendBuf(src); - Afsk_txTestStart(TEST_SPACE); - return; - } - else if(checkcmd(&cmd[4], 3, (uint8_t*)"alt")) - { - term_sendString((uint8_t*)"Starting alternating tones calibration pattern transmission\r\n", 0); - term_sendBuf(src); - Afsk_txTestStart(TEST_ALTERNATING); - return; - } - else if(checkcmd(&cmd[4], 4, (uint8_t*)"stop")) - { - term_sendString((uint8_t*)"Stopping calibration transmission\r\n", 0); - term_sendBuf(src); - Afsk_txTestStop(); - return; - } - term_sendString((uint8_t*)"Usage: cal {low|high|alt|stop}\r\n", 0); - term_sendBuf(src); - return; + if(!strncmp(&cmd[4], "low", 3)) + { + UartSendString(src, "Starting low tone calibration transmission\r\n", 0); + ModemTxTestStart(TEST_MARK); + } + else if(!strncmp(&cmd[4], "high", 4)) + { + UartSendString(src, "Starting high tone calibration transmission\r\n", 0); + ModemTxTestStart(TEST_SPACE); + } + else if(!strncmp(&cmd[4], "alt", 3)) + { + UartSendString(src, "Starting alternating tones calibration transmission\r\n", 0); + ModemTxTestStart(TEST_ALTERNATING); + } + else if(!strncmp(&cmd[4], "stop", 4)) + { + UartSendString(src, "Stopping calibration transmission\r\n", 0); + ModemTxTestStop(); + } + else + UartSendString(src, "Usage: cal {low|high|alt|stop}\r\n", 0); } + else + UartSendString(src, "Unknown command. For command list type \"help\"\r\n", 0); - term_sendString((uint8_t*)"Unknown command. For command list type \"help\"\r\n", 0); - term_sendBuf(src); return; } - if((mode != MODE_TERM)) return; + if(src->mode != MODE_TERM) + return; + + /* + * Configuration mode handling + * + * General commands + */ + bool err = false; - if(checkcmd(cmd, 4, (uint8_t*)"help")) + if(!strncmp(cmd, "help", 4)) { - term_sendString((uint8_t*)"\r\nCommands available in config mode:\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"print - prints all configuration parameters\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"list - prints callsign filter list\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"save - saves configuration and reboots the device\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"eraseall - erases all configurations and reboots the device\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"help - shows this help page\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"reboot - reboots the device\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"version - shows full firmware version info\r\n\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"call - sets callsign\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"ssid <0-15> - sets SSID\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"dest
- sets destination address\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"txdelay <50-2550> - sets TXDelay time (ms)\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"txtail <10-2550> - sets TXTail time (ms)\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"quiet <100-2550> - sets quiet time (ms)\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"rs1baud/rs2baud <1200-115200> - sets UART1/UART2 baudrate\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"pwm [on/off] - enables/disables PWM. If PWM is off, R2R will be used instead\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"flat [on/off] - set to \"on\" if flat audio input is used\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"beacon <0-7> [on/off] - enables/disables specified beacon\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"beacon <0-7> [iv/dl] <0-720> - sets interval/delay for the specified beacon (min)\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"beacon <0-7> path /none - sets path for the specified beacon\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"beacon <0-7> data - sets information field for the specified beacon\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi [on/off] - enables/disables whole digipeater\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi <0-7> [on/off] - enables/disables specified slot\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi <0-7> alias - sets alias for the specified slot\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi <0-3> [max/rep] <0/1-7> - sets maximum/replacement N for the specified slot\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi <0-7> trac [on/off] - enables/disables packet tracing for the specified slot\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi <0-7> viscous [on/off] - enables/disables viscous-delay digipeating for the specified slot\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi <0-7> direct [on/off] - enables/disables direct-only digipeating for the specified slot\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi <0-7> filter [on/off] - enables/disables packet filtering for the specified slot\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi filter [black/white] - sets filtering type to blacklist/whitelist\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi dupe <5-255> - sets anti-dupe buffer time (s)\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"digi list <0-19> [set /remove] - sets/clears specified callsign slot in filter list\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"autoreset <0-255> - sets auto-reset interval (h) - 0 to disable\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"monkiss [on/off] - send own and digipeated frames to KISS ports\r\n", 0); - term_sendBuf(src); - term_sendString((uint8_t*)"nonaprs [on/off] - enable reception of non-APRS frames\r\n", 0); - term_sendBuf(src); - return; + UartSendString(src, (uint8_t*)configHelp, 0); } - if(checkcmd(cmd, 7, (uint8_t*)"version")) + else if(!strncmp(cmd, "version", 7)) { - term_sendString((uint8_t*)versionString, 0); - term_sendBuf(src); - return; + UartSendString(src, (uint8_t*)versionString, 0); } - if(checkcmd(cmd, 6, (uint8_t*)"reboot")) + else if(!strncmp(cmd, "reboot", 6)) { NVIC_SystemReset(); - return; } - if(checkcmd(cmd, 4, (uint8_t*)"save")) + else if(!strncmp(cmd, "save", 4)) { - Config_write(); + ConfigWrite(); NVIC_SystemReset(); - return; } - if(checkcmd(cmd, 8, (uint8_t*)"eraseall")) + else if(!strncmp(cmd, "eraseall", 8)) { - Config_erase(); + ConfigErase(); NVIC_SystemReset(); - return; } - - if(checkcmd(cmd, 5, (uint8_t*)"print")) + else if(!strncmp(cmd, "print", 5)) { - term_sendString((uint8_t*)"Callsign: ", 0); - for(uint8_t i = 0; i < 6; i++) - { - if((call[i]) != 64) - term_sendByte(call[i] >> 1); - } - term_sendByte('-'); - term_sendNumber(callSsid); - - term_sendString((uint8_t*)"\r\nDestination: ", 0); - for(uint8_t i = 0; i < 6; i++) - { - if((dest[i]) != 64) - term_sendByte(dest[i] >> 1); - } - - term_sendString((uint8_t*)"\r\nTXDelay (ms): ", 0); - term_sendNumber(ax25Cfg.txDelayLength); - term_sendString((uint8_t*)"\r\nTXTail (ms): ", 0); - term_sendNumber(ax25Cfg.txTailLength); - term_sendString((uint8_t*)"\r\nQuiet time (ms): ", 0); - term_sendNumber(ax25Cfg.quietTime); - term_sendString((uint8_t*)"\r\nUART1 baudrate: ", 0); - term_sendNumber(uart1.baudrate); - term_sendString((uint8_t*)"\r\nUART2 baudrate: ", 0); - term_sendNumber(uart2.baudrate); - term_sendString((uint8_t*)"\r\nDAC type: ", 0); - if(afskCfg.usePWM) - term_sendString((uint8_t*)"PWM", 0); - else - term_sendString((uint8_t*)"R2R", 0); - term_sendString((uint8_t*)"\r\nFlat audio input: ", 0); - if(afskCfg.flatAudioIn) - term_sendString((uint8_t*)"yes", 0); - else - term_sendString((uint8_t*)"no", 0); - term_sendBuf(src); - for(uint8_t i = 0; i < 8; i++) - { - term_sendString((uint8_t*)"\r\nBeacon ", 0); - term_sendByte(i + 48); - term_sendString((uint8_t*)": ", 0); - if(beacon[i].enable) - term_sendString((uint8_t*)"On, Iv: ", 0); - else - term_sendString((uint8_t*)"Off, Iv: ", 0); - term_sendNumber(beacon[i].interval / 6000); - term_sendString((uint8_t*)", Dl: ", 0); - term_sendNumber(beacon[i].delay / 60); - term_sendByte(','); - term_sendByte(' '); - if(beacon[i].path[0] != 0) - { - for(uint8_t j = 0; j < 6; j++) - { - if(beacon[i].path[j] != 32) term_sendByte(beacon[i].path[j]); - } - term_sendByte('-'); - term_sendNumber(beacon[i].path[6]); - if(beacon[i].path[7] != 0) - { - term_sendByte(','); - for(uint8_t j = 7; j < 13; j++) - { - if(beacon[i].path[j] != 32) term_sendByte(beacon[i].path[j]); - } - term_sendByte('-'); - term_sendNumber(beacon[i].path[13]); - } - } - else term_sendString((uint8_t*)"no path", 0); - term_sendBuf(src); - term_sendByte(','); - term_sendByte(' '); - term_sendString(beacon[i].data, 0); - term_sendBuf(src); - } - - term_sendString((uint8_t*)"\r\nDigipeater: ", 0); - if(digi.enable) - term_sendString((uint8_t*)"On\r\n", 0); - else - term_sendString((uint8_t*)"Off\r\n", 0); - term_sendBuf(src); - - for(uint8_t i = 0; i < 4; i++) //n-N aliases - { - term_sendString((uint8_t*)"Alias ", 0); - if(digi.alias[i][0] != 0) - { - for(uint8_t j = 0; j < 5; j++) - { - if(digi.alias[i][j] != 0) - term_sendByte(digi.alias[i][j] >> 1); - } - } - term_sendString((uint8_t*)": ", 0); - if(digi.enableAlias & (1 << i)) - term_sendString((uint8_t*)"On, max: ", 0); - else - term_sendString((uint8_t*)"Off, max: ", 0); - term_sendNumber(digi.max[i]); - term_sendString((uint8_t*)", rep: ", 0); - term_sendNumber(digi.rep[i]); - if(digi.traced & (1 << i)) - term_sendString((uint8_t*)", traced, ", 0); - else - term_sendString((uint8_t*)", untraced, ", 0); - if(digi.viscous & (1 << i)) - term_sendString((uint8_t*)"viscous-delay, ", 0); - else if(digi.directOnly & (1 << i)) - term_sendString((uint8_t*)"direct-only, ", 0); - if(digi.callFilterEnable & (1 << i)) - term_sendString((uint8_t*)"filtered\r\n", 0); - else - term_sendString((uint8_t*)"unfiltered\r\n", 0); - } - term_sendBuf(src); - for(uint8_t i = 0; i < 4; i++) //simple aliases - { - term_sendString((uint8_t*)"Alias ", 0); - if(digi.alias[i + 4][0] != 0) - { - for(uint8_t j = 0; j < 6; j++) - { - if(digi.alias[i + 4][j] != 64) - term_sendByte(digi.alias[i + 4][j] >> 1); - } - } - term_sendByte('-'); - term_sendNumber(digi.ssid[i]); - term_sendString((uint8_t*)": ", 0); - if(digi.enableAlias & (1 << (i + 4))) - term_sendString((uint8_t*)"On, ", 0); - else - term_sendString((uint8_t*)"Off, ", 0); - if(digi.traced & (1 << (i + 4))) - term_sendString((uint8_t*)"traced, ", 0); - else - term_sendString((uint8_t*)"untraced, ", 0); - if(digi.viscous & (1 << (i + 4))) - term_sendString((uint8_t*)"viscous-delay, ", 0); - else if(digi.directOnly & (1 << (i + 4))) - term_sendString((uint8_t*)"direct-only, ", 0); - if(digi.callFilterEnable & (1 << (i + 4))) - term_sendString((uint8_t*)"filtered\r\n", 0); - else - term_sendString((uint8_t*)"unfiltered\r\n", 0); - } - term_sendBuf(src); - term_sendString((uint8_t*)"Anti-duplicate buffer hold time (s): ", 0); - term_sendNumber(digi.dupeTime); - term_sendString((uint8_t*)"\r\nCallsign filter type: ", 0); - if(digi.filterPolarity) - term_sendString((uint8_t*)"whitelist\r\n", 0); - else - term_sendString((uint8_t*)"blacklist\r\n", 0); - term_sendString((uint8_t*)"Callsign filter list: ", 0); - uint8_t callent = 0; - for(uint8_t i = 0; i < 20; i++) - { - if(digi.callFilter[i][0] != 0) - callent++; - } - if(callent > 9) - { - term_sendByte((callent / 10) + 48); - term_sendByte((callent % 10) + 48); - } else - term_sendByte(callent + 48); - term_sendString((uint8_t*)" entries\r\nAuto-reset every (h): ", 0); - if(autoReset == 0) - term_sendString((uint8_t*)"disabled", 0); - else - term_sendNumber(autoReset); - term_sendString((uint8_t*)"\r\nKISS monitor: ", 0); - if(kissMonitor == 1) - term_sendString((uint8_t*)"On\r\n", 0); - else - term_sendString((uint8_t*)"Off\r\n", 0); - term_sendString((uint8_t*)"Allow non-APRS frames: ", 0); - if(ax25Cfg.allowNonAprs == 1) - term_sendString((uint8_t*)"On\r\n", 0); - else - term_sendString((uint8_t*)"Off\r\n", 0); - term_sendBuf(src); - return; + printConfig(src); } - - - if(checkcmd(cmd, 4, (uint8_t*)"list")) + else if(!strncmp(cmd, "list", 4)) //list calls in call filter table { - term_sendString((uint8_t*)"Callsign filter list: \r\n", 0); + UartSendString(src, "Callsign filter list: \r\n", 0); for(uint8_t i = 0; i < 20; i++) { - term_sendNumber(i); - term_sendString((uint8_t*)". ", 0); - if(digi.callFilter[i][0] != 0) + UartSendNumber(src, i); + UartSendString(src, ". ", 0); + if(DigiConfig.callFilter[i][0] != 0) { uint8_t cl[10] = {0}; uint8_t clidx = 0; for(uint8_t h = 0; h < 6; h++) { - if(digi.callFilter[i][h] == 0xFF) + if(DigiConfig.callFilter[i][h] == 0xFF) //wildcard { uint8_t g = h; uint8_t j = 0; while(g < 6) { - if(digi.callFilter[i][g] != 0xFF) j = 1; + if(DigiConfig.callFilter[i][g] != 0xFF) + j = 1; g++; } if(j == 0) @@ -768,1067 +566,487 @@ void term_parse(uint8_t *cmd, uint16_t len, Terminal_stream src, Uart_data_type } else { - if(digi.callFilter[i][h] != ' ') - cl[clidx++] = digi.callFilter[i][h]; + if(DigiConfig.callFilter[i][h] != ' ') + cl[clidx++] = DigiConfig.callFilter[i][h]; } } - if(digi.callFilter[i][6] == 0xFF) + if(DigiConfig.callFilter[i][6] == 0xFF) { cl[clidx++] = '-'; cl[clidx++] = '*'; } - else if(digi.callFilter[i][6] != 0) + else if(DigiConfig.callFilter[i][6] != 0) { cl[clidx++] = '-'; - if(digi.callFilter[i][6] > 9) + if(DigiConfig.callFilter[i][6] > 9) { - cl[clidx++] = (digi.callFilter[i][6] / 10) + 48; - cl[clidx++] = (digi.callFilter[i][6] % 10) + 48; + cl[clidx++] = (DigiConfig.callFilter[i][6] / 10) + 48; + cl[clidx++] = (DigiConfig.callFilter[i][6] % 10) + 48; } - else cl[clidx++] = digi.callFilter[i][6] + 48; + else cl[clidx++] = DigiConfig.callFilter[i][6] + 48; } - term_sendString(cl, 0); + UartSendString(src, cl, 0); } else - term_sendString((uint8_t*)"empty", 0); - term_sendString((uint8_t*)"\r\n", 0); - term_sendBuf(src); + UartSendString(src, "empty", 0); + UartSendString(src, "\r\n", 0); + return; } - return; } - - if(checkcmd(cmd, 4, (uint8_t*)"call")) + /* + * Settings insertion handling + */ + else if(!strncmp(cmd, "call", 4)) { - uint8_t tmp[6] = {0}; - uint8_t err = 0; - for(uint8_t i = 0; i < 7; i++) - { - if((cmd[5 + i] == '\r') || (cmd[5 + i] == '\n')) - { - if((i == 0)) - err = 1; - break; - } - if(!(((cmd[5 + i] > 47) && (cmd[5 + i] < 58)) || ((cmd[5 + i] > 64) && (cmd[5 + i] < 91)))) //only alphanumeric characters - { - err = 1; - break; - } - if(i == 6) //call too long - { - err = 1; - break; - } - tmp[i] = cmd[5 + i] << 1; - } - if(!err) - for(uint8_t i = 0; i < 6; i++) - { - call[i] = 64; //fill with spaces - if(tmp[i] != 0) - call[i] = tmp[i]; - } - if(err) + + if(!ParseCallsignWithSsid(&cmd[5], len - 5, GeneralConfig.call, &GeneralConfig.callSsid)) { - term_sendString((uint8_t*)"Incorrect callsign!\r\n", 0); + UartSendString(src, "Incorrect callsign!\r\n", 0); + return; } else { - term_sendString((uint8_t*)"OK\r\n", 0); + UartSendString(src, "OK\r\n", 0); } - term_sendBuf(src); return; } - - if(checkcmd(cmd, 4, (uint8_t*)"dest")) + else if(!strncmp(cmd, "dest", 4)) { - uint8_t tmp[6] = {0}; - uint8_t err = 0; - for(uint8_t i = 0; i < 7; i++) - { - if((cmd[5 + i] == '\r') || (cmd[5 + i] == '\n')) - { - if((i == 0)) - err = 1; - break; - } - if(!(((cmd[5 + i] > 47) && (cmd[5 + i] < 58)) || ((cmd[5 + i] > 64) && (cmd[5 + i] < 91)))) //only alphanumeric characters - { - err = 1; - break; - } - if(i == 6) //address too long - { - err = 1; - break; - } - tmp[i] = cmd[5 + i] << 1; - } - if(!err) - for(uint8_t i = 0; i < 6; i++) - { - dest[i] = 64; //fill with spaces - if(tmp[i] != 0) - dest[i] = tmp[i]; - } - if(err) + if(!ParseCallsign(&cmd[5], len - 5, GeneralConfig.dest)) { - term_sendString((uint8_t*)"Incorrect address!\r\n", 0); + UartSendString(src, "Incorrect address!\r\n", 0); + return; } else { - term_sendString((uint8_t*)"OK\r\n", 0); + UartSendString(src, "OK\r\n", 0); } - term_sendBuf(src); - return; } - - if(checkcmd(cmd, 4, (uint8_t*)"ssid")) + else if(!strncmp(cmd, "txdelay", 7)) { - uint8_t tmp[3] = {0}; - uint8_t err = 0; - for(uint8_t i = 0; i < 3; i++) + int64_t t = StrToInt(&cmd[8], len - 8); + if((t > 2550) || (t < 50)) { - if((cmd[5 + i] == '\r') || (cmd[5 + i] == '\n')) - { - if((i == 0)) - err = 1; //no ssid provided - break; - } - if(!(((cmd[5 + i] > 47) && (cmd[5 + i] < 58)))) //only numbers - { - err = 1; - break; - } - if(i == 2) //more than 2 digits in ssid - { - err = 1; - break; - } - tmp[i] = cmd[5 + i]; + UartSendString(src, "Incorrect TXDelay!\r\n", 0); + return; } - if(!err) + else { - uint8_t t = 0; - t = (uint8_t)strToInt(tmp, 0); - if(t > 15) - err = 1; - else - callSsid = t; + Ax25Config.txDelayLength = (uint16_t)t; + UartSendString(src, "OK\r\n", 0); } - if(err) + } + else if(!strncmp(cmd, "txtail", 6)) + { + int64_t t = StrToInt(&cmd[7], len - 7); + if((t > 2550) || (t < 50)) { - term_sendString((uint8_t*)"Incorrect SSID!\r\n", 0); + UartSendString(src, "Incorrect TXTail!\r\n", 0); + return; } else { - term_sendString((uint8_t*)"OK\r\n", 0); + Ax25Config.txTailLength = (uint16_t)t; + UartSendString(src, "OK\r\n", 0); } - term_sendBuf(src); - return; } - if(checkcmd(cmd, 7, (uint8_t*)"txdelay")) + else if(!strncmp(cmd, "quiet", 5)) { - uint8_t tmp[5] = {0}; - uint8_t err = 0; - for(uint8_t i = 0; i < 5; i++) + int64_t t = StrToInt(&cmd[6], len - 6); + if((t > 2550) || (t < 100)) { - if((cmd[8 + i] == '\r') || (cmd[8 + i] == '\n')) - { - if((i == 0)) - err = 1; - break; - } - if(!(((cmd[8 + i] > 47) && (cmd[8 + i] < 58)))) //only digits - { - err = 1; - break; - } - if(i == 4) - { - err = 1; - break; - } - tmp[i] = cmd[8 + i]; - } - if(!err) - { - uint16_t t = 0; - t = (uint16_t)strToInt(tmp, 0); - if((t > 2550) || (t < 50)) - err = 1; - else - ax25Cfg.txDelayLength = t; - } - if(err) - { - term_sendString((uint8_t*)"Incorrect TXDelay!\r\n", 0); - } - else - { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; - } - - if(checkcmd(cmd, 6, (uint8_t*)"txtail")) - { - uint8_t tmp[5] = {0}; - uint8_t err = 0; - for(uint8_t i = 0; i < 5; i++) - { - if((cmd[7 + i] == '\r') || (cmd[7 + i] == '\n')) - { - if((i == 0)) - err = 1; - break; - } - if(!(((cmd[7 + i] > 47) && (cmd[7 + i] < 58)))) //only digits - { - err = 1; - break; - } - if(i == 4) - { - err = 1; - break; - } - tmp[i] = cmd[7 + i]; - } - if(!err) - { - uint16_t t = 0; - t = (uint16_t)strToInt(tmp, 0); - if((t > 2550) || (t < 10)) - err = 1; - else - ax25Cfg.txTailLength = t; - } - if(err) - { - term_sendString((uint8_t*)"Incorrect TXTail!\r\n", 0); + UartSendString(src, "Incorrect quiet time!\r\n", 0); + return; } else { - term_sendString((uint8_t*)"OK\r\n", 0); + Ax25Config.quietTime = (uint16_t)t; } - term_sendBuf(src); - return; } - - if(checkcmd(cmd, 5, (uint8_t*)"quiet")) + else if(!strncmp(cmd, "rs1baud", 7) || !strncmp(cmd, "rs2baud", 7)) { - uint8_t tmp[5] = {0}; - uint8_t err = 0; - for(uint8_t i = 0; i < 5; i++) - { - if((cmd[6 + i] == '\r') || (cmd[6 + i] == '\n')) - { - if((i == 0)) - err = 1; - break; - } - if(!(((cmd[6 + i] > 47) && (cmd[6 + i] < 58)))) - { - err = 1; - break; - } - if(i == 4) - { - err = 1; - break; - } - tmp[i] = cmd[6 + i]; - } - if(!err) - { - uint16_t t = 0; - t = (uint16_t)strToInt(tmp, 0); - if((t > 2550) || (t < 100)) - err = 1; - else - ax25Cfg.quietTime = t; - } - if(err) + int64_t t = StrToInt(&cmd[8], len - 8); + if((t > 115200) || (t < 1200)) { - term_sendString((uint8_t*)"Incorrect quiet time!\r\n", 0); + UartSendString(src, "Incorrect baudrate!\r\n", 0); } else { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; - } - - if(checkcmd(cmd, 7, (uint8_t*)"rs1baud") || checkcmd(cmd, 7, (uint8_t*)"rs2baud")) - { - uint8_t tmp[7] = {0}; - uint8_t err = 0; - for(uint8_t i = 0; i < 7; i++) - { - if((cmd[8 + i] == '\r') || (cmd[8 + i] == '\n')) - { - if((i == 0)) - err = 1; - break; - } - if(!(((cmd[8 + i] > 47) && (cmd[8 + i] < 58)))) - { - err = 1; - break; - } - if(i == 6) - { - err = 1; - break; - } - tmp[i] = cmd[8 + i]; - } - if(!err) - { - uint32_t t = 0; - t = (uint32_t)strToInt(tmp, 0); - if((t > 115200) || (t < 1200)) - err = 1; + if(cmd[2] == '1') + Uart1.baudrate = (uint32_t)t; + else if(cmd[2] == '2') + Uart2.baudrate = (uint32_t)t; else { - if(cmd[2] == '1') - uart1.baudrate = t; - else - uart2.baudrate = t; + UartSendString(src, "Incorrect port number!\r\n", 0); + return; } } - if(err) - { - term_sendString((uint8_t*)"Incorrect baudrate!\r\n", 0); - } - else - { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; } - - if(checkcmd(cmd, 6, (uint8_t*)"beacon")) + else if(!strncmp(cmd, "beacon", 6)) { uint8_t bcno = 0; bcno = cmd[7] - 48; if(bcno > 7) { - term_sendString((uint8_t*)"Incorrect beacon number\r\n", 0); - term_sendBuf(src); + UartSendString(src, "Incorrect beacon number\r\n", 0); + return; } - uint8_t err = 0; - if(cmd[9] == 'o' && cmd[10] == 'n') + if(!strncmp(&cmd[9], "on", 2)) beacon[bcno].enable = 1; - else if(cmd[9] == 'o' && cmd[10] == 'f' && cmd[11] == 'f') + else if(!strncmp(&cmd[9], "off", 3)) beacon[bcno].enable = 0; - else if((cmd[9] == 'i' && cmd[10] == 'v') || (cmd[9] == 'd' && cmd[10] == 'l')) //interval or delay + else if(!strncmp(&cmd[9], "iv", 2) || !strncmp(&cmd[9], "dl", 2)) //interval or delay { - uint8_t tmp[4] = {0}; - - for(uint8_t i = 0; i < 4; i++) + int64_t t = StrToInt(&cmd[12], len - 12); + if(t > 720) { - if((cmd[12 + i] == '\r') || (cmd[12 + i] == '\n')) - { - if((i == 0)) - err = 1; - break; - } - if(!(((cmd[12 + i] > 47) && (cmd[12 + i] < 58)))) - { - err = 1; - break; - } - if(i == 3) - { - err = 1; - break; - } - tmp[i] = cmd[12 + i]; - } - if(!err) - { - uint32_t t = 0; - t = (uint32_t)strToInt(tmp, 0); - if(t > 720) err = 1; - else - { - if(cmd[9] == 'i') - beacon[bcno].interval = t * 6000; - else - beacon[bcno].delay = t * 60; - } + UartSendString(src, "Interval/delay must lesser or equal to 720 minutes\r\n", 0); + return; } + if(!strncmp(&cmd[9], "iv", 2)) + beacon[bcno].interval = t * 6000; + else + beacon[bcno].delay = t * 60; + } - else if((cmd[9] == 'd' && cmd[10] == 'a' && cmd[11] == 't' && cmd[12] == 'a')) + else if(!strncmp(&cmd[9], "data", 4)) { - uint8_t dlen = 0; - if((cmd[len - 1] == '\r') || (cmd[len - 1] == '\n')) - dlen = len - 15; - else - dlen = len - 14; - if(dlen > 99) + if((len - 14) > BEACON_MAX_PAYLOAD_SIZE) { - term_sendString((uint8_t*)"Data too long\r\n", 0); - term_sendBuf(src); + UartSendString(src, "Data is too long\r\n", 0); return; } - uint8_t i = 0; - for(; i < dlen; i++) - { + uint16_t i = 0; + for(; i < (len - 14); i++) beacon[bcno].data[i] = cmd[14 + i]; - } beacon[bcno].data[i] = 0; } - else if((cmd[9] == 'p' && cmd[10] == 'a' && cmd[11] == 't' && cmd[12] == 'h')) + else if(!strncmp(&cmd[9], "path", 4)) { - uint8_t dlen = 0; - if((cmd[len - 2] == '\r') || (cmd[len - 2] == '\n')) - dlen = len - 16; - else - dlen = len - 15; - if((dlen == 4) && (cmd[14] == 'n') && (cmd[15] == 'o') && (cmd[16] == 'n') && (cmd[17] == 'e')) //"none" path + if((len - 14) < 0) { - for(uint8_t i = 0; i < 14; i++) - beacon[bcno].path[i] = 0; + UartSendString(src, "Path cannot be empty. Use \"none\" for empty path. \r\n", 0); + return; + } + if(((len - 14) == 4) && !strncmp(&cmd[14], "none", 4)) //"none" path + { + memset(beacon[bcno].path, 0, sizeof(beacon[bcno].path)); - term_sendString((uint8_t*)"OK\r\n", 0); - term_sendBuf(src); + UartSendString(src, "OK\r\n", 0); return; } - if(dlen == 0) - err = 1; - uint8_t tmp[14] = {0}; - uint8_t elemlen = 0; - uint8_t tmpidx = 0; - if(!err) - for(uint8_t i = 0; i < dlen; i++) + uint8_t tmp[14]; + uint8_t tmpIdx = 0; + uint16_t elementStart = 14; + for(uint8_t i = 0; i < (len - 14); i++) { - if(elemlen > 6) - { - err = 1; - break; - } - if(cmd[14 + i] == '-') + if((cmd[14 + i] == ',') || ((14 + i + 1) == len)) { - uint8_t ssid = 0; - if(((cmd[15 + i] > 47) && (cmd[15 + i] < 58))) - { - ssid = cmd[15 + i] - 48; - } - else - { - err = 1; - break; - } - if(((cmd[16 + i] > 47) && (cmd[16 + i] < 58))) - { - ssid *= 10; - ssid += cmd[16 + i] - 48; - } - else if(!((cmd[16 + i] == ',') || (cmd[16 + i] == '\r') || (cmd[16 + i] == '\n'))) - { - err = 1; - break; - } - if(ssid > 15) + if((14 + i + 1) == len) //end of data { - err = 1; - break; + i++; + tmp[7] = 0; } - else + + if((14 + i - elementStart) > 0) { - while(tmpidx < ((tmpidx > 7) ? 13 : 6)) + if(!ParseCallsignWithSsid(&cmd[elementStart], 14 + i - elementStart, &tmp[tmpIdx], &tmp[tmpIdx + 6])) { - tmp[tmpidx++] = ' '; + err = true; + break; } - tmp[tmpidx++] = ssid; - if(ssid > 10) - i += 2; - else - i++; + tmpIdx += 7; + if(tmpIdx == 14) + break; } - } - else if(cmd[14 + i] == ',') - { - elemlen = 0; - } - else if(((cmd[14 + i] > 47) && (cmd[14 + i] < 58)) || ((cmd[14 + i] > 64) && (cmd[14 + i] < 91))) - { - elemlen++; - tmp[tmpidx++] = cmd[14 + i]; - } - else - { - err = 1; - break; + elementStart = 14 + i + 1; } } if(err) { - term_sendString((uint8_t*)"Incorrect path!\r\n", 0); - term_sendBuf(src); + UartSendString(src, "Incorrect path!\r\n", 0); return; } - for(uint8_t i = 0; i < 14; i++) - beacon[bcno].path[i] = tmp[i]; - err = 0; + memcpy(beacon[bcno].path, tmp, 14); } - - else err = 1; - - if(err == 1) + else { - term_sendString((uint8_t*)"Incorrect command\r\n", 0); + err = true; } - else term_sendString((uint8_t*)"OK\r\n", 0); - term_sendBuf(src); - return; + UartSendString(src, "OK\r\n", 0); } - - if(checkcmd(cmd, 4, (uint8_t*)"digi")) + else if(!strncmp(cmd, "digi", 4)) { - - uint8_t err = 0; - if(cmd[4] == ' ' && cmd[5] == 'o' && cmd[6] == 'n') - digi.enable = 1; - else if(cmd[4] == ' ' && cmd[5] == 'o' && cmd[6] == 'f' && cmd[7] == 'f') - digi.enable = 0; - else if((((cmd[5] > 47) && (cmd[5] < 58))) && (cmd[4] == ' ')) + if(!strncmp(&cmd[5], "on", 2)) + DigiConfig.enable = 1; + else if(!strncmp(&cmd[5], "off", 3)) + DigiConfig.enable = 0; + else if(IS_NUMBER(cmd[5])) { uint8_t alno = 0; alno = cmd[5] - 48; if(alno > 7) { - term_sendString((uint8_t*)"Incorrect alias number\r\n", 0); - term_sendBuf(src); + UartSendString(src, "Incorrect alias number\r\n", 0); return; } - if(checkcmd(&cmd[7], 2, (uint8_t*)"on")) - digi.enableAlias |= (1 << alno); - else if(checkcmd(&cmd[7], 3, (uint8_t*)"off")) - digi.enableAlias &= ~(1 << alno); - else if(checkcmd(&cmd[7], 6, (uint8_t*)"alias ")) + if(!strncmp(&cmd[7], "on", 2)) + DigiConfig.enableAlias |= (1 << alno); + else if(!strncmp(&cmd[7], "off", 3)) + DigiConfig.enableAlias &= ~(1 << alno); + else if(!strncmp(&cmd[7], "alias ", 6)) { - uint8_t tmp[5] = {0}; - uint8_t err = 0; - if(alno < 4) //New-N aliases { - for(uint8_t i = 0; i < 6; i++) + if((len - 13) <= 5) { - if((cmd[13 + i] == '\r') || (cmd[13 + i] == '\n')) - { - if((i == 0)) - err = 1; - break; - } - if(!(((cmd[13 + i] > 47) && (cmd[13 + i] < 58)) || ((cmd[13 + i] > 64) && (cmd[13 + i] < 91)))) - { - err = 1; - break; - } - if(i == 5) - { - err = 1; - break; - } - tmp[i] = cmd[13 + i] << 1; - } - if(!err) for(uint8_t i = 0; i < 5; i++) - { - digi.alias[alno][i] = tmp[i]; - } - if(err) - { - term_sendString((uint8_t*)"Incorrect alias!\r\n", 0); + if(false == (err = !ParseCallsign(&cmd[13], len - 13, DigiConfig.alias[alno]))) + DigiConfig.alias[alno][len - 13] = 0; } else - { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; + err = true; } else //simple aliases { - uint8_t dlen = 0; - if((cmd[len - 2] == '\r') || (cmd[len - 2] == '\n')) - dlen = len - 16; - else - dlen = len - 14; - - if(dlen == 0) - err = 1; - - uint8_t tmp[6] = {0}; - uint8_t tmpidx = 0; - uint8_t elemlen = 0; - uint8_t ssid = 0; - if(!err) - for(uint8_t i = 0; i < dlen; i++) - { - if(elemlen > 6) - { - err = 1; - break; - } - if(cmd[13 + i] == '-') - { - if(((cmd[14 + i] > 47) && (cmd[14 + i] < 58))) - { - ssid = cmd[14 + i] - 48; - } - else - { - err = 1; - break; - } - if(((cmd[15 + i] > 47) && (cmd[15 + i] < 58))) - { - ssid *= 10; - ssid += cmd[15 + i] - 48; - } - else if(!((cmd[15 + i] == '\r') || (cmd[15 + i] == '\n'))) - { - err = 1; - break; - } - if(ssid > 15) err = 1; - break; - } - else if(((cmd[13 + i] > 47) && (cmd[13 + i] < 58)) || ((cmd[13 + i] > 64) && (cmd[13 + i] < 91))) - { - elemlen++; - tmp[tmpidx++] = cmd[13 + i]; - } - else - { - err = 1; - break; - } - } - if(err) - { - term_sendString((uint8_t*)"Incorrect alias!\r\n", 0); - term_sendBuf(src); - return; - } - - - for(uint8_t i = 0; i < 6; i++) + if(!ParseCallsignWithSsid(&cmd[13], len - 13, DigiConfig.alias[alno], &DigiConfig.ssid[alno - 4])) { - digi.alias[alno][i] = 64; - if(tmp[i] != 0) - digi.alias[alno][i] = tmp[i] << 1; + err = true; } - digi.ssid[alno - 4] = ssid; - err = 0; } - - } - - else if((checkcmd(&cmd[7], 4, (uint8_t*)"max ") || checkcmd(&cmd[7], 4, (uint8_t*)"rep ")) && (alno < 4)) - { - - uint8_t err = 0; - - if(!((cmd[12] == '\r') || (cmd[12] == '\n'))) + if(err) { - err = 1; + UartSendString(src, "Incorrect alias!\r\n", 0); + return; } - if(!(((cmd[11] > 47) && (cmd[11] < 58)))) + UartSendString(src, "OK\r\n", 0); + } + else if((!strncmp(&cmd[7], "max ", 4) || !strncmp(&cmd[7], "rep ", 4)) && (alno < 4)) + { + int64_t t = StrToInt(&cmd[11], len - 11); + if(!strncmp(&cmd[7], "max ", 4) && (t >= 1 || t <= 7)) { - err = 1; + DigiConfig.max[alno] = t; } - - uint8_t val = cmd[11] - 48; - if(cmd[7] == 'm' && (val < 1 || val > 7)) - err = 1; - if(cmd[7] == 'r' && (val > 7)) - err = 1; - - if(err) + else if(!strncmp(&cmd[7], "rep ", 4) && (t <= 7)) { - term_sendString((uint8_t*)"Incorrect value!\r\n", 0); + DigiConfig.rep[alno] = t; } else { - if(cmd[7] == 'm') - digi.max[alno] = val; - else digi.rep[alno] = val; - term_sendString((uint8_t*)"OK\r\n", 0); + UartSendString(src, "Incorrect value!\r\n", 0); + return; } - term_sendBuf(src); - return; } - else if(checkcmd(&cmd[7], 5, (uint8_t*)"trac ")) + else if(!strncmp(&cmd[7], "trac ", 5)) { - if(cmd[12] == 'o' && cmd[13] == 'n') - digi.traced |= 1 << alno; - else if(cmd[12] == 'o' && cmd[13] == 'f' && cmd[14] == 'f') - digi.traced &= ~(1 << alno); - else err = 1; + if(!strncmp(&cmd[12], "on", 2)) + DigiConfig.traced |= 1 << alno; + else if(!strncmp(&cmd[12], "off", 3)) + DigiConfig.traced &= ~(1 << alno); + else + { + err = true; + } } - else if(checkcmd(&cmd[7], 7, (uint8_t*)"filter ")) + else if(!strncmp(&cmd[7], "filter ", 7)) { - if(cmd[14] == 'o' && cmd[15] == 'n') - digi.callFilterEnable |= 1 << alno; - else if(cmd[14] == 'o' && cmd[15] == 'f' && cmd[16] == 'f') - digi.callFilterEnable &= ~(1 << alno); - else err = 1; + if(!strncmp(&cmd[14], "on", 2)) + DigiConfig.callFilterEnable |= 1 << alno; + else if(!strncmp(&cmd[14], "off", 3)) + DigiConfig.callFilterEnable &= ~(1 << alno); + else + { + err = true; + } } - else if(checkcmd(&cmd[7], 8, (uint8_t*)"viscous ")) + else if(!strncmp(&cmd[7], "viscous ", 8)) { - if(cmd[15] == 'o' && cmd[16] == 'n') + if(!strncmp(&cmd[15], "on", 2)) { - digi.viscous |= (1 << alno); - digi.directOnly &= ~(1 << alno); //disable directonly mode + DigiConfig.viscous |= (1 << alno); + DigiConfig.directOnly &= ~(1 << alno); //disable directonly mode } - else if(cmd[15] == 'o' && cmd[16] == 'f' && cmd[17] == 'f') - digi.viscous &= ~(1 << alno); + else if(!strncmp(&cmd[15], "off", 3)) + DigiConfig.viscous &= ~(1 << alno); else - err = 1; + { + err = true; + } } - else if(checkcmd(&cmd[7], 7, (uint8_t*)"direct ")) + else if(!strncmp(&cmd[7], "direct ", 7)) { - if(cmd[14] == 'o' && cmd[15] == 'n') + if(!strncmp(&cmd[14], "on", 2)) + { + DigiConfig.directOnly |= (1 << alno); + DigiConfig.viscous &= ~(1 << alno); //disable viscous delay mode + } + else if(!strncmp(&cmd[14], "off", 3)) + DigiConfig.directOnly &= ~(1 << alno); + else { - digi.directOnly |= (1 << alno); - digi.viscous &= ~(1 << alno); //disable viscous delay mode + err = true; } - else if(cmd[14] == 'o' && cmd[15] == 'f' && cmd[16] == 'f') - digi.directOnly &= ~(1 << alno); - else err = 1; } + else + err = true; } - else if(checkcmd(&cmd[5], 7, (uint8_t*)"filter ")) + else if(!strncmp(&cmd[5], "filter ", 7)) { - if(checkcmd(&cmd[12], 5, (uint8_t*)"white")) - digi.filterPolarity = 1; - else if(checkcmd(&cmd[12], 5, (uint8_t*)"black")) - digi.filterPolarity = 0; + if(!strncmp(&cmd[12], "white", 5)) + DigiConfig.filterPolarity = 1; + else if(!strncmp(&cmd[12], "black", 5)) + DigiConfig.filterPolarity = 0; else - err = 1; + err = true; } - else if(checkcmd(&cmd[5], 5, (uint8_t*)"dupe ")) + else if(!strncmp(&cmd[5], "dupe ", 5)) { - uint8_t tmp[4] = {0}; - uint8_t err = 0; - for(uint8_t i = 0; i < 4; i++) - { - if((cmd[10 + i] == '\r') || (cmd[10 + i] == '\n')) - { - if((i == 0)) - err = 1; - break; - } - if(!(((cmd[10 + i] > 47) && (cmd[10 + i] < 58)))) - { - err = 1; - break; - } - if(i == 3) - { - err = 1; - break; - } - tmp[i] = cmd[10 + i]; - } - if(!err) - { - uint16_t t = 0; - t = (uint16_t)strToInt(tmp, 0); - if((t > 255) || (t < 5)) - err = 1; - else - digi.dupeTime = (uint8_t)t; - } - if(err) + int64_t t = StrToInt(&cmd[10], len - 10); + if((t > 255) || (t < 5)) { - term_sendString((uint8_t*)"Incorrect anti-dupe time!\r\n", 0); + UartSendString(src, "Incorrect anti-dupe time!\r\n", 0); + return; } else - { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; + DigiConfig.dupeTime = (uint8_t)t; } - else if(checkcmd(&cmd[5], 5, (uint8_t*)"list ")) + else if(!strncmp(&cmd[5], "list ", 5)) { - uint8_t no = 0; - if((((cmd[10] > 47) && (cmd[10] < 58)))) + uint16_t shift = 10; + + while(shift < len) { - no = cmd[10] - 48; - } - else err = 1; + if(cmd[shift] == ' ') + break; - if((((cmd[11] > 47) && (cmd[11] < 58))) && !err) + shift++; + } + int64_t number = StrToInt(&cmd[10], shift - 10); + if((number < 0) || (number >= (sizeof(DigiConfig.callFilter) / sizeof(*(DigiConfig.callFilter))))) { - no *= 10; - no += cmd[11] - 48; + UartSendString(src, "Incorrect filter slot!\r\n", 0); + return; } - - if(no > 19) err = 1; - - uint8_t shift = 12; - if(no > 9) shift = 13; - - if(checkcmd(&cmd[shift], 4, (uint8_t*)"set ")) + shift++; + if((len - shift) < 4) { - uint8_t dlen = 0; - if((cmd[len - 2] == '\r') || (cmd[len - 2] == '\n')) - dlen = len - shift - 7; - else - dlen = len - shift - 5; + UartSendString(src, "Incorrect format!\r\n", 0); + return; + } - if(dlen == 0) - err = 1; - uint8_t j = 0; - uint8_t h = 0; + if(!strncmp(&cmd[shift], "set ", 4)) + { + shift += 4; - volatile uint8_t tmp[7] = {0}; + uint8_t tmp[7] = {0}; + uint16_t tmpIdx = 0; - if(!err) for(j = 0; j < dlen; j++) - { - if(cmd[shift + 4 + j] == '-') + for(uint16_t i = 0; i < len; i++) + { + if(cmd[shift + i] == '-') //SSID separator { - if((cmd[shift + 5 + j] == '*') || (cmd[shift + 5 + j] == '?')) - { + if((cmd[shift + i + 1] == '*') || (cmd[shift + i + 1] == '?')) //and there is any wildcard tmp[6] = 0xFF; - break; - } - if((dlen - 1 - j) == 2) - { - if((cmd[shift + 6 + j] > 47) && (cmd[shift + 6 + j] < 58)) - tmp[6] += cmd[shift + 6 + j] - 48; - else - err = 1; - if((cmd[shift + 5 + j] > 47) && (cmd[shift + 5 + j] < 58)) - tmp[6] += (cmd[shift + 5 + j] - 48) * 10; - else - err = 1; - if(tmp[6] > 15) - err = 1; - } - else if((cmd[shift + 5 + j] > 47) && (cmd[shift + 5 + j] < 58)) - tmp[6] += cmd[shift + 5 + j] - 48; - else - err = 1; + else if(!ParseSsid(&cmd[shift + i + 1], len - (shift + i + 1), &tmp[6])) //otherwise it is a normal SSID + err = true; break; } - if(cmd[shift + 4 + j] == '?') + else if(cmd[shift + i] == '?') { - tmp[j] = 0xFF; - continue; - } else if(cmd[shift + 4 + j] == '*') + tmp[tmpIdx++] = 0xFF; + } + else if(cmd[shift + i] == '*') { - h = j; - while(h < 6) + while(tmpIdx < 6) { - tmp[h] = 0xFF; - h++; + tmp[tmpIdx++] = 0xFF; } continue; } - if(((cmd[shift + 4 + j] > 47) && (cmd[shift + 4 + j] < 58)) || ((cmd[shift + 4 + j] > 64) && (cmd[shift + 4 + j] < 91))) tmp[j] = cmd[shift + 4 + j]; - else err = 1; - } + else if(IS_UPPERCASE_ALPHANUMERIC(cmd[shift + i])) + tmp[tmpIdx++] = cmd[shift + i]; + else + { + err = true; + break; + } + } if(!err) { - while((j + h) < 6) //fill with spaces + while(tmpIdx < 6) //fill with spaces { - tmp[j] = ' '; - j++; + tmp[tmpIdx++] = ' '; } - for(uint8_t i = 0; i < 7; i++) - digi.callFilter[no][i] = tmp[i]; + + memcpy(DigiConfig.callFilter[number], tmp, 7); } else { - term_sendString((uint8_t*)"Incorrect format!\r\n", 0); - term_sendBuf(src); + UartSendString(src, "Incorrect format!\r\n", 0); return; } } - else if(checkcmd(&cmd[shift], 6, (uint8_t*)"remove")) - { - for(uint8_t i = 0; i < 7; i++) - digi.callFilter[no][i] = 0; - } - else - err = 1; - - - if(err) - { - term_sendString((uint8_t*)"Incorrect command!\r\n", 0); - } - else - { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; - } - else err = 1; - - if(err == 1) - { - term_sendString((uint8_t*)"Incorrect command\r\n", 0); - } - else term_sendString((uint8_t*)"OK\r\n", 0); - - term_sendBuf(src); - return; - } - - - if(checkcmd(cmd, 10, (uint8_t*)"autoreset ")) - { - uint8_t tmp[4] = {0}; - uint8_t err = 0; - for(uint8_t i = 0; i < 4; i++) - { - if((cmd[10 + i] == '\r') || (cmd[10 + i] == '\n')) - { - if((i == 0)) - err = 1; - break; - } - if(!(((cmd[10 + i] > 47) && (cmd[10 + i] < 58)))) + else if(!strncmp(&cmd[shift], "remove", 6)) { - err = 1; - break; + memset(DigiConfig.callFilter[number], 0, 7); } - if(i == 3) - { - err = 1; - break; - } - tmp[i] = cmd[10 + i]; - } - if(!err) - { - uint8_t t = 0; - t = strToInt(tmp, 0); - if(t > 255) - err = 1; else - autoReset = t; - } - if(err) - { - term_sendString((uint8_t*)"Incorrect time interval!\r\n", 0); + err = true; } else - { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; + err = true; } - if(checkcmd(cmd, 4, (uint8_t*)"pwm ")) + else if(!strncmp(cmd, "pwm ", 4)) { - uint8_t err = 0; - if(checkcmd(&cmd[4], 2, (uint8_t*)"on")) - afskCfg.usePWM = 1; - else if(checkcmd(&cmd[4], 3, (uint8_t*)"off")) - afskCfg.usePWM = 0; - else - err = 1; - - if(err) - { - term_sendString((uint8_t*)"Incorrect command!\r\n", 0); - } + if(!strncmp(&cmd[4], "on", 2)) + ModemConfig.usePWM = 1; + else if(!strncmp(&cmd[4], "off", 3)) + ModemConfig.usePWM = 0; else - { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; + err = true; } - if(checkcmd(cmd, 5, (uint8_t*)"flat ")) + else if(!strncmp(cmd, "flat ", 5)) { - uint8_t err = 0; - if(checkcmd(&cmd[5], 2, (uint8_t*)"on")) - afskCfg.flatAudioIn = 1; - else if(checkcmd(&cmd[5], 3, (uint8_t*)"off")) - afskCfg.flatAudioIn = 0; + if(!strncmp(&cmd[5], "on", 2)) + ModemConfig.flatAudioIn = 1; + else if(!strncmp(&cmd[5], "off", 3)) + ModemConfig.flatAudioIn = 0; else - err = 1; - - if(err) - { - term_sendString((uint8_t*)"Incorrect command!\r\n", 0); - } - else - { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; + err = true; } - - if(checkcmd(cmd, 8, (uint8_t*)"monkiss ")) + else if(!strncmp(cmd, "monkiss ", 8)) { - uint8_t err = 0; - if(checkcmd(&cmd[8], 2, (uint8_t*)"on")) - kissMonitor = 1; - else if(checkcmd(&cmd[8], 3, (uint8_t*)"off")) - kissMonitor = 0; + if(!strncmp(&cmd[8], "on", 2)) + GeneralConfig.kissMonitor = 1; + else if(!strncmp(&cmd[8], "off", 3)) + GeneralConfig.kissMonitor = 0; else - err = 1; - - if(err) - { - term_sendString((uint8_t*)"Incorrect command!\r\n", 0); - } - else - { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; + err = true; } - if(checkcmd(cmd, 8, (uint8_t*)"nonaprs ")) + else if(!strncmp(cmd, "nonaprs ", 8)) { - uint8_t err = 0; - if(checkcmd(&cmd[8], 2, (uint8_t*)"on")) - ax25Cfg.allowNonAprs = 1; - else if(checkcmd(&cmd[8], 3, (uint8_t*)"off")) - ax25Cfg.allowNonAprs = 0; + if(!strncmp(&cmd[8], "on", 2)) + Ax25Config.allowNonAprs = 1; + else if(!strncmp(&cmd[8], "off", 2)) + Ax25Config.allowNonAprs = 0; else - err = 1; - - if(err) - { - term_sendString((uint8_t*)"Incorrect command!\r\n", 0); - } - else - { - term_sendString((uint8_t*)"OK\r\n", 0); - } - term_sendBuf(src); - return; + err = true; } - - term_sendString((uint8_t*)"Unknown command. For command list type \"help\"\r\n", 0); - term_sendBuf(src); + else + UartSendString(src, "Unknown command. For command list type \"help\"\r\n", 0); + if(err) + UartSendString(src, "Incorrect command\r\n", 0); + else + UartSendString(src, "OK\r\n", 0); } diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index 6880d53..3cc6912 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -24,6 +24,7 @@ /* USER CODE BEGIN INCLUDE */ #include "drivers/uart.h" +#include "drivers/systick.h" /* USER CODE END INCLUDE */ /* Private typedef -----------------------------------------------------------*/ @@ -132,7 +133,7 @@ static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length); static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len); /* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */ - +static void handleUsbInterrupt(Uart *port); /* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */ /** @@ -264,32 +265,18 @@ static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) { /* USER CODE BEGIN 6 */ - /** - * Z tej funkcji zaraz po odebraniu danych chcemy wyjsc, bo pozostanie w niej zablokuje mozliwosc nadawania czegokolwiek przez USB. - * Poza tym ta funkcja jest tak naprawde czescia ISR. - * Ustawiamy wiec flage z informacja, co odebralismy i to przetwarzamy w innym miejscu (w petli glownej). - */ - USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); USBD_CDC_ReceivePacket(&hUsbDeviceFS); //this function receives 64 bytes max. //add them to the buffer and set USB "interrupt" flag - for(uint16_t cv = 0; cv < *Len; cv++) + for(uint16_t i = 0; i < *Len; i++) { - usbcdcdata[usbcdcidx++] = *(Buf + cv); - if(usbcdcidx == UARTBUFLEN) - { - usbcdcidx = 0; - return USBD_FAIL; - } - USBint = 1; + UartUsb.rxBuffer[UartUsb.rxBufferHead++] = Buf[i]; + UartUsb.rxBufferHead %= UART_BUFFER_SIZE; } - - - - + handleUsbInterrupt(&UartUsb); return (USBD_OK); /* USER CODE END 6 */ @@ -312,15 +299,16 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) /* USER CODE BEGIN 7 */ if(hUsbDeviceFS.dev_state != 3) return USBD_BUSY; USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; - if (hcdc->TxState > 1){ //jesli cos wiekszego od 1, to USB nie jest podlaczone + if (hcdc->TxState > 1) + { return USBD_BUSY; } uint32_t to = 0; while(hcdc->TxState != 0) { - //czekamy dopoki USB jest zajete, bo inaczej bedziemy tracic dane to++; - if(to > 90000) return USBD_FAIL; //trzeba bylo zrobic jakis timeout + if(to > 90000) //wait for a while if USB busy + return USBD_FAIL; } USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); @@ -330,7 +318,30 @@ 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 + if(port->rxBufferHead != 0) + { + if((port->rxBuffer[0] == 0xC0) && (port->rxBuffer[port->rxBufferHead - 1] == 0xC0)) //data starts with 0xc0 and ends with 0xc0 - this is a KISS frame + { + port->rxType = DATA_KISS; + port->kissTimer = 0; + } + else if(((port->rxBuffer[port->rxBufferHead - 1] == '\r') || (port->rxBuffer[port->rxBufferHead - 1] == '\n'))) //data ends with \r or \n, process as data + { + port->rxType = DATA_TERM; + port->kissTimer = 0; + } + } +} /* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */ /** From 665d2106838b5cff6d96ed82a3af6c75e723ed2a Mon Sep 17 00:00:00 2001 From: sq8vps Date: Fri, 18 Aug 2023 12:50:33 +0200 Subject: [PATCH 2/4] 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] From 00431f97161407419f5da43be73f73819b32d2ea Mon Sep 17 00:00:00 2001 From: Piotr Wilkon Date: Tue, 29 Aug 2023 10:16:34 +0200 Subject: [PATCH 3/4] beacon send bug fix and copyrights --- Inc/ax25.h | 2 ++ Inc/beacon.h | 2 ++ Inc/common.h | 3 +++ Inc/config.h | 2 ++ Inc/digipeater.h | 2 ++ Inc/drivers/modem.h | 2 ++ Inc/drivers/systick.h | 3 ++- Inc/drivers/uart.h | 2 ++ Inc/drivers/watchdog.h | 2 ++ Inc/main.h | 2 ++ Inc/terminal.h | 2 ++ Src/ax25.c | 3 +++ Src/beacon.c | 4 +++- Src/common.c | 2 ++ Src/config.c | 4 +++- Src/digipeater.c | 6 ++++-- Src/drivers/modem.c | 2 ++ Src/drivers/systick.c | 2 ++ Src/drivers/uart.c | 2 ++ Src/drivers/watchdog.c | 2 ++ Src/main.c | 2 ++ Src/terminal.c | 6 ++++-- 22 files changed, 52 insertions(+), 7 deletions(-) diff --git a/Inc/ax25.h b/Inc/ax25.h index fb26893..1c524db 100644 --- a/Inc/ax25.h +++ b/Inc/ax25.h @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Inc/beacon.h b/Inc/beacon.h index 57b019f..9608e8e 100644 --- a/Inc/beacon.h +++ b/Inc/beacon.h @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Inc/common.h b/Inc/common.h index fb2262c..1b01005 100644 --- a/Inc/common.h +++ b/Inc/common.h @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify @@ -14,6 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with VP-Digi. If not, see . */ + #ifndef COMMON_H_ #define COMMON_H_ diff --git a/Inc/config.h b/Inc/config.h index 1dcb11c..9a5425a 100644 --- a/Inc/config.h +++ b/Inc/config.h @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Inc/digipeater.h b/Inc/digipeater.h index d75da18..e127673 100644 --- a/Inc/digipeater.h +++ b/Inc/digipeater.h @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Inc/drivers/modem.h b/Inc/drivers/modem.h index 19bb73a..d6b4cf7 100644 --- a/Inc/drivers/modem.h +++ b/Inc/drivers/modem.h @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Inc/drivers/systick.h b/Inc/drivers/systick.h index 5367e6e..175264e 100644 --- a/Inc/drivers/systick.h +++ b/Inc/drivers/systick.h @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify @@ -14,7 +16,6 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with VP-Digi. If not, see . */ - #ifndef SYSTICK_H_ #define SYSTICK_H_ diff --git a/Inc/drivers/uart.h b/Inc/drivers/uart.h index e8153eb..588b373 100644 --- a/Inc/drivers/uart.h +++ b/Inc/drivers/uart.h @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Inc/drivers/watchdog.h b/Inc/drivers/watchdog.h index fb4be59..29fd911 100644 --- a/Inc/drivers/watchdog.h +++ b/Inc/drivers/watchdog.h @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Inc/main.h b/Inc/main.h index 2b36bf2..b6a45b6 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -19,6 +19,8 @@ */ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Inc/terminal.h b/Inc/terminal.h index 001e36a..4392d2b 100644 --- a/Inc/terminal.h +++ b/Inc/terminal.h @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Src/ax25.c b/Src/ax25.c index 4dd5e10..3dbce4e 100644 --- a/Src/ax25.c +++ b/Src/ax25.c @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify @@ -440,6 +442,7 @@ uint8_t Ax25GetTxBit(void) else { txFlagsElapsed = 0; + txByteIdx = 0; txStage = TX_STAGE_DATA; //return to normal data transmission stage. There might be a next frame to transmit txFrameBufferFull = false; txFrameTail++; diff --git a/Src/beacon.c b/Src/beacon.c index 9462b0c..98d89ec 100644 --- a/Src/beacon.c +++ b/Src/beacon.c @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify @@ -105,7 +107,7 @@ void BeaconCheck(void) if((beacon[i].interval > 0) && ((SysTickGet() >= beacon[i].next) || (beacon[i].next == 0))) { if(beaconDelay[i] > SysTickGet()) //check for beacon delay (only for the very first transmission) - return; + continue; beacon[i].next = SysTickGet() + beacon[i].interval; //save next beacon timestamp beaconDelay[i] = 0; BeaconSend(i); diff --git a/Src/common.c b/Src/common.c index c7d075b..0b1be09 100644 --- a/Src/common.c +++ b/Src/common.c @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Src/config.c b/Src/config.c index 1839b18..893aeb9 100644 --- a/Src/config.c +++ b/Src/config.c @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify @@ -12,7 +14,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with VP-DigiConfig. If not, see . +along with VP-Digi. If not, see . */ #include "config.h" diff --git a/Src/digipeater.c b/Src/digipeater.c index 78c925c..8cbce4b 100644 --- a/Src/digipeater.c +++ b/Src/digipeater.c @@ -1,5 +1,7 @@ /* -This file is part of VP-DigiConfig. +Copyright 2020-2023 Piotr Wilkon + +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 @@ -12,7 +14,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with VP-DigiConfig. If not, see . +along with VP-Digi. If not, see . */ #include "digipeater.h" diff --git a/Src/drivers/modem.c b/Src/drivers/modem.c index ba419af..c27fa6b 100644 --- a/Src/drivers/modem.c +++ b/Src/drivers/modem.c @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Src/drivers/systick.c b/Src/drivers/systick.c index 64f1b55..7e18dd0 100644 --- a/Src/drivers/systick.c +++ b/Src/drivers/systick.c @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Src/drivers/uart.c b/Src/drivers/uart.c index 968f29e..544bcdb 100644 --- a/Src/drivers/uart.c +++ b/Src/drivers/uart.c @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Src/drivers/watchdog.c b/Src/drivers/watchdog.c index 52e2f14..935eb47 100644 --- a/Src/drivers/watchdog.c +++ b/Src/drivers/watchdog.c @@ -1,4 +1,6 @@ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Src/main.c b/Src/main.c index 53c891c..0ae2db8 100644 --- a/Src/main.c +++ b/Src/main.c @@ -17,6 +17,8 @@ ****************************************************************************** */ /* +Copyright 2020-2023 Piotr Wilkon + This file is part of VP-Digi. VP-Digi is free software: you can redistribute it and/or modify diff --git a/Src/terminal.c b/Src/terminal.c index 5a99b73..f4ef73f 100644 --- a/Src/terminal.c +++ b/Src/terminal.c @@ -1,5 +1,7 @@ /* -This file is part of VP-DigiConfig. +Copyright 2020-2023 Piotr Wilkon + +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 @@ -12,7 +14,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with VP-DigiConfig. If not, see . +along with VP-Digi. If not, see . */ #include "terminal.h" From bd6b7f5286f4dd57ab79cd981408a05a01988ee5 Mon Sep 17 00:00:00 2001 From: Piotr Wilkon Date: Tue, 29 Aug 2023 11:06:55 +0200 Subject: [PATCH 4/4] changelog and readme --- CHANGELOG.md | 32 ++++++++++++++++++++++---------- README.md | 2 +- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b9f3e1..8a16a44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,25 @@ -# 1.2.6 (2023-08-29) +# 1.3.0 (2023-08-30) +## New features +* Callsign is now set together with SSID using ```call ``` +* ```time``` command to show uptime +## Removed features +* ```ssid``` command is removed +* Auto-reset functionality and ```autoreset``` command is removed +## Bug fixes +* When beacon *n* delay hadn't passed yet, beacon *n+1*, *n+2*, ... were not sent regardless of their delay +* Bugs with line ending parsing +## Other +* Major code refactoring and rewrite +* Got rid of *uart_transmitStart()* routine +* USB sending is handled the same way as UART +* New way of TX and RX frame handling to improve non-APRS compatibility +* Much bigger frame buffer +* Minimized number of temporary buffers +* All *malloc()*s removed +* Added copyright notice as required by GNU GPL +## Known bugs +* none +# 1.2.6 (2023-07-29) ## New features * Added ```nonaprs [on/off]``` command that enables reception of non-APRS frames, e.g. for full Packet Radio use ## Bug fixes @@ -43,15 +64,6 @@ * none ## Known bugs * USB in KISS mode has problem with TX frames -# 1.2.2 (2022-06-11) -## New features -* none -## Bug fixes -* Default de-dupe time was 0, backspace was sometimes stored in config, frame length was not checked in viscous delay mode -## Other -* none -## Known bugs -* USB in KISS mode has problem with TX frames # 1.2.1 (2021-10-13) ## New features * none diff --git a/README.md b/README.md index 2f467cc..5b7f1fe 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ VP-Digi is a functional, cheap, easy to assemble and configure STM32-based APRS If you are not interested in source code, this repository is not for you. You can find full project description, schematics, compiled firmware and instructions [on my website](https://sq8l.pzk.pl/index.php/vp-digi-cheap-and-functional-aprs-digipeater-controller-with-kiss-modem/). ## Source code usage -The firmware was written using System Workbench for STM32 (SW4STM32) and you should be able to import this repository directly to the IDE. The source code is publicly available since version 1.3.0. +The firmware was written using System Workbench for STM32 (SW4STM32) and you should be able to import this repository directly to the IDE. The source code is publicly available since version 1.2.0. ## Technical description The project was designed to be running on a Blue Pill board (STM32F103C8T6) with 8MHz crystal. The firmware was written using only register operations (with ST headers) and CMSIS libraries. The HAL is there only for USB. The code is (quite) extensively commented where needed, so it shouldn't be very hard to understand.