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 */ /**