Browse Source

major code refactoring and rewrite

pull/25/head
Piotr Wilkon 2 years ago
parent
commit
5a1427ad11
24 changed files with 2253 additions and 3112 deletions
  1. +39
    -28
      Inc/ax25.h
  2. +10
    -10
      Inc/beacon.h
  3. +53
    -19
      Inc/common.h
  4. +3
    -70
      Inc/config.h
  5. +10
    -12
      Inc/digipeater.h
  6. +0
    -43
      Inc/drivers/afsk.h_bak
  7. +44
    -37
      Inc/drivers/modem.h
  8. +5
    -2
      Inc/drivers/systick.h
  9. +53
    -75
      Inc/drivers/uart.h
  10. +2
    -2
      Inc/drivers/watchdog.h
  11. +28
    -60
      Inc/terminal.h
  12. +1
    -3
      Inc/usbd_cdc_if.h
  13. +308
    -246
      Src/ax25.c
  14. +31
    -43
      Src/beacon.c
  15. +121
    -96
      Src/common.c
  16. +214
    -147
      Src/config.c
  17. +171
    -187
      Src/digipeater.c
  18. +160
    -196
      Src/drivers/modem.c
  19. +3
    -2
      Src/drivers/systick.c
  20. +135
    -177
      Src/drivers/uart.c
  21. +2
    -2
      Src/drivers/watchdog.c
  22. +138
    -162
      Src/main.c
  23. +689
    -1471
      Src/terminal.c
  24. +33
    -22
      Src/usbd_cdc_if.c

+ 39
- 28
Inc/ax25.h View File

@ -18,46 +18,57 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#ifndef AX25_H_
#define AX25_H_
#define FRAMELEN (150) //single frame max length
#define FRAMEBUFLEN (600) //circural frame buffer (multiple frames) length
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>
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_ */

+ 10
- 10
Inc/beacon.h View File

@ -21,35 +21,35 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#include <stdint.h>
#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. WIDE1<sp>1SP2<sp><sp><sp>2<NUL>, <NUL> 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_ */

+ 53
- 19
Inc/common.h View File

@ -18,20 +18,25 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#define COMMON_H_
#include <stdint.h>
#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_ */

+ 3
- 70
Inc/config.h View File

@ -22,88 +22,21 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#include <stdint.h>
#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_ */

+ 10
- 12
Inc/digipeater.h View File

@ -21,9 +21,7 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#include <stdint.h>
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_ */

+ 0
- 43
Inc/drivers/afsk.h_bak View File

@ -1,43 +0,0 @@
#ifndef DRIVERS_AFSK_H_
#define DRIVERS_AFSK_H_
//#define ALVLDBG
#include "systick.h"
#include "stm32f10x.h"
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#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

+ 44
- 37
Inc/drivers/modem.h View File

@ -20,98 +20,105 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#include <stdint.h>
//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

+ 5
- 2
Inc/drivers/systick.h View File

@ -19,12 +19,15 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#define SYSTICK_H_
#include <stdint.h>
#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_ */

+ 53
- 75
Inc/drivers/uart.h View File

@ -18,124 +18,102 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#ifndef UART_H_
#define UART_H_
#define UARTBUFLEN 250
#include "stm32f1xx.h"
#include <stdint.h>
#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

+ 2
- 2
Inc/drivers/watchdog.h View File

@ -23,12 +23,12 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
/**
* @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_ */

+ 28
- 60
Inc/terminal.h View File

@ -21,71 +21,39 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#include "drivers/uart.h"
#include <stdint.h>
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_ */

+ 1
- 3
Inc/usbd_cdc_if.h View File

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


+ 308
- 246
Src/ax25.c View File

@ -20,6 +20,44 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#include "drivers/modem.h"
#include "common.h"
#include "drivers/systick.h"
#include <stdbool.h>
struct Ax25ProtoConfig Ax25Config;
//values below must be kept consistent so that FRAME_BUFFER_SIZE >= FRAME_MAX_SIZE * FRAME_MAX_COUNT
#define FRAME_MAX_SIZE (150) //single frame max length for RX
#define FRAME_MAX_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));
}

+ 31
- 43
Src/beacon.c View File

@ -23,40 +23,40 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#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;
}
}


+ 121
- 96
Src/common.c View File

@ -22,152 +22,148 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#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;
}

+ 214
- 147
Src/config.c View File

@ -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 <http://www.gnu.org/licenses/>.
along with VP-DigiConfig. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
@ -26,26 +26,94 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#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;
}

+ 171
- 187
Src/digipeater.c View File

@ -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 <http://www.gnu.org/licenses/>.
along with VP-DigiConfig. If not, see <http://www.gnu.org/licenses/>.
*/
#include "digipeater.h"
@ -24,31 +24,51 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#include <math.h>
#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++;
}

+ 160
- 196
Src/drivers/modem.c View File

@ -41,65 +41,36 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#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


+ 3
- 2
Src/drivers/systick.c View File

@ -16,6 +16,7 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
*/
#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
}

+ 135
- 177
Src/drivers/uart.c View File

@ -24,94 +24,89 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#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));
}
}

+ 2
- 2
Src/drivers/watchdog.c View File

@ -18,7 +18,7 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
#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
}

+ 138
- 162
Src/main.c View File

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


+ 689
- 1471
Src/terminal.c
File diff suppressed because it is too large
View File


+ 33
- 22
Src/usbd_cdc_if.c View File

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


Loading…
Cancel
Save