diff --git a/.cproject b/.cproject
index 9795aef..6dcb8d2 100644
--- a/.cproject
+++ b/.cproject
@@ -1,193 +1,398 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/Src/digipeater.c b/Core/Src/digipeater.c
index 14424a3..bf87e46 100644
--- a/Core/Src/digipeater.c
+++ b/Core/Src/digipeater.c
@@ -454,6 +454,8 @@ void DigiStoreDeDupe(uint8_t *buf, uint16_t size)
while((buf[i] & 1) == 0) //look for path end bit (skip path)
{
i++;
+ if(i == size)
+ return;
}
i++;
diff --git a/Core/Src/kiss.c b/Core/Src/kiss.c
index 8421629..a879327 100644
--- a/Core/Src/kiss.c
+++ b/Core/Src/kiss.c
@@ -95,6 +95,26 @@ void KissParse(Uart *port, uint8_t data)
}
}
+ uint16_t pathEnd = 0;
+
+ //find path end bit (C-bit)
+ for(uint16_t i = 0; i < port->kissBufferHead; i++)
+ {
+ if((port->kissBuffer[i + 1] & 1) != 0)
+ {
+ pathEnd = i + 1;
+ break;
+ }
+ }
+
+ //C-bit must lay on a 7 byte boundary (every path element is 7 bytes long)
+ if(pathEnd % 7)
+ {
+ port->kissBufferHead = 0;
+ return;
+ }
+
+
__disable_irq();
port->kissProcessingOngoing = 1;
port->kissTempBufferHead = 0;
diff --git a/Src/ax25.c b/Src/ax25.c
deleted file mode 100644
index 805366b..0000000
--- a/Src/ax25.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
-Copyright 2020-2023 Piotr Wilkon
-
-This file is part of VP-Digi.
-
-VP-Digi is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or
-(at your option) any later version.
-
-VP-Digi is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-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 .
-*/
-
-#include "ax25.h"
-#include
-#include "drivers/modem.h"
-#include "common.h"
-#include "drivers/systick.h"
-#include
-#include "digipeater.h"
-
-struct Ax25ProtoConfig Ax25Config;
-
-
-#define FRAME_MAX_COUNT (10) //max count of frames in buffer
-#define FRAME_BUFFER_SIZE (FRAME_MAX_COUNT * AX25_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
-{
- TX_STAGE_IDLE,
- TX_STAGE_PREAMBLE,
- TX_STAGE_HEADER_FLAGS,
- TX_STAGE_DATA,
- TX_STAGE_CRC,
- TX_STAGE_FOOTER_FLAGS,
- TX_STAGE_TAIL,
-};
-
-enum TxInitStage
-{
- TX_INIT_OFF,
- TX_INIT_WAITING,
- TX_INIT_TRANSMITTING
-};
-
-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
-{
- uint16_t crc; //current CRC
- uint8_t frame[AX25_FRAME_MAX_SIZE]; //raw frame buffer
- uint16_t frameIdx; //index for raw frame buffer
- uint8_t receivedByte; //byte being currently received
- uint8_t receivedBitIdx; //bit index for recByte
- uint8_t rawData; //raw data being currently received
- enum Ax25RxStage rx; //current RX stage
- uint8_t frameReceived; //frame received flag
-};
-
-static volatile struct RxState rxState[MODEM_DEMODULATOR_COUNT];
-
-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
-
-static uint8_t outputFrameBuffer[AX25_FRAME_MAX_SIZE];
-
-#define GET_FREE_SIZE(max, head, tail) (((head) < (tail)) ? ((tail) - (head)) : ((max) - (head) + (tail)))
-#define GET_USED_SIZE(max, head, tail) (max - GET_FREE_SIZE(max, head, tail))
-
-/**
- * @brief Recalculate CRC for one bit
- * @param bit Input bit
- * @param *crc CRC pointer
- */
-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;
- }
-}
-
-uint8_t Ax25GetReceivedFrameBitmap(void)
-{
- return frameReceived;
-}
-
-void Ax25ClearReceivedFrameBitmap(void)
-{
- frameReceived = 0;
-}
-
-
-void *Ax25WriteTxFrame(uint8_t *data, uint16_t size)
-{
- 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];
- __disable_irq();
- txFrameHead++;
- txFrameHead %= FRAME_MAX_COUNT;
- if(txFrameHead == txFrameTail)
- txFrameBufferFull = true;
- __enable_irq();
- return ret;
-}
-
-
-bool Ax25ReadNextRxFrame(uint8_t **dst, uint16_t *size, uint16_t *signalLevel)
-{
- if((rxFrameHead == rxFrameTail) && !rxFrameBufferFull)
- {
- return false;
- }
-
- *dst = outputFrameBuffer;
-
- 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;
-
- __disable_irq();
- rxFrameBufferFull = false;
- rxFrameTail++;
- rxFrameTail %= FRAME_MAX_COUNT;
- __enable_irq();
- 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 * MODEM_DEMODULATOR_COUNT)) //hold it for a while and wait for other decoders to receive the frame
- {
- lastCrc = 0;
- rxMultiplexDelay = 0;
- for(uint8_t i = 0; i < MODEM_DEMODULATOR_COUNT; i++)
- {
- frameReceived |= ((rxState[i].frameReceived > 0) << i);
- rxState[i].frameReceived = 0;
- }
- }
-
- }
-
-
- struct RxState *rx = (struct RxState*)&(rxState[modem]);
-
- rx->rawData <<= 1; //store incoming bit
- rx->rawData |= (bit > 0);
-
-
- if(rx->rawData == 0x7E) //HDLC flag received
- {
- 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
- {
- uint16_t i = 0;
- for(; i < rx->frameIdx - 2; i++) //look for path end bit
- {
- if(rx->frame[i] & 1)
- break;
- }
-
- //if non-APRS frames are not allowed, check if this frame has control=0x03 and PID=0xF0
-
- if(Ax25Config.allowNonAprs || (((rx->frame[i + 1] == 0x03) && (rx->frame[i + 2] == 0xf0))))
- {
- 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);
- __disable_irq();
- rxFrame[rxFrameHead++].size = rx->frameIdx;
- rxFrameHead %= FRAME_MAX_COUNT;
- if(rxFrameHead == rxFrameTail)
- rxFrameBufferFull = true;
- __enable_irq();
-
- for(uint16_t i = 0; i < rx->frameIdx; i++)
- {
- rxBuffer[rxBufferHead++] = rx->frame[i];
- rxBufferHead %= FRAME_BUFFER_SIZE;
- }
-
- }
- }
- }
- }
-
- }
-
- }
- rx->rx = RX_STAGE_FLAG;
- ModemClearRMS(modem);
- rx->receivedByte = 0;
- rx->receivedBitIdx = 0;
- rx->frameIdx = 0;
- rx->crc = 0xFFFF;
- return;
- }
-
-
- if((rx->rawData & 0x7F) == 0x7F) //received 7 consecutive ones, this is an error
- {
- rx->rx = RX_STAGE_FLAG;
- ModemClearRMS(modem);
- rx->receivedByte = 0;
- rx->receivedBitIdx = 0;
- rx->frameIdx = 0;
- rx->crc = 0xFFFF;
- return;
- }
-
-
-
- if(rx->rx == RX_STAGE_IDLE) //not in a frame, don't go further
- return;
-
-
- if((rx->rawData & 0x3F) == 0x3E) //dismiss bit 0 added by bit stuffing
- return;
-
- if(rx->rawData & 0x01) //received bit 1
- rx->receivedByte |= 0x80; //store it
-
- if(++rx->receivedBitIdx >= 8) //received full byte
- {
- if(rx->frameIdx > AX25_FRAME_MAX_SIZE) //frame is too long
- {
- rx->rx = RX_STAGE_IDLE;
- ModemClearRMS(modem);
- rx->receivedByte = 0;
- rx->receivedBitIdx = 0;
- rx->frameIdx = 0;
- rx->crc = 0xFFFF;
- return;
- }
- if(rx->frameIdx >= 2) //more than 2 bytes received, calculate CRC
- {
- for(uint8_t i = 0; i < 8; i++)
- {
- calculateCRC((rx->frame[rx->frameIdx - 2] >> i) & 1, &(rx->crc));
- }
- }
- rx->rx = RX_STAGE_FRAME;
- rx->frame[rx->frameIdx++] = rx->receivedByte; //store received byte
- rx->receivedByte = 0;
- rx->receivedBitIdx = 0;
- }
- else
- rx->receivedByte >>= 1;
-}
-
-
-uint8_t Ax25GetTxBit(void)
-{
- if(txBitIdx == 8)
- {
- txBitIdx = 0;
- if(txStage == TX_STAGE_PREAMBLE) //transmitting preamble (TXDelay)
- {
- if(txDelayElapsed < txDelay) //still transmitting
- {
- txByte = 0x7E;
- txDelayElapsed++;
- }
- else //now transmit initial flags
- {
- txDelayElapsed = 0;
- txStage = TX_STAGE_HEADER_FLAGS;
- }
-
- }
- if(txStage == TX_STAGE_HEADER_FLAGS) //transmitting initial flags
- {
- if(txFlagsElapsed < STATIC_HEADER_FLAG_COUNT)
- {
- txByte = 0x7E;
- txFlagsElapsed++;
- }
- else
- {
- txFlagsElapsed = 0;
- txStage = TX_STAGE_DATA; //transmit data
- }
- }
- if(txStage == TX_STAGE_DATA) //transmitting normal data
- {
-transmitNormalData:
- __disable_irq();
- if((txFrameHead != txFrameTail) || txFrameBufferFull)
- {
- __enable_irq();
- if(txByteIdx < txFrame[txFrameTail].size) //send buffer
- {
- txByte = txBuffer[(txFrame[txFrameTail].start + txByteIdx) % FRAME_BUFFER_SIZE];
- txByteIdx++;
- }
- else //end of buffer, send CRC
- {
- txStage = TX_STAGE_CRC; //transmit CRC
- txCrcByteIdx = 0;
- }
- }
- else //no more frames
- {
- __enable_irq();
- txByteIdx = 0;
- txBitIdx = 0;
- txStage = TX_STAGE_TAIL;
- }
- }
- if(txStage == TX_STAGE_CRC) //transmitting CRC
- {
- if(txCrcByteIdx <= 1)
- {
- txByte = (txCrc & 0xFF) ^ 0xFF;
- txCrc >>= 8;
- txCrcByteIdx++;
- }
- else
- {
- txCrc = 0xFFFF;
- txStage = TX_STAGE_FOOTER_FLAGS; //now transmit flags
- txFlagsElapsed = 0;
- }
-
- }
- if(txStage == TX_STAGE_FOOTER_FLAGS)
- {
- if(txFlagsElapsed < STATIC_FOOTER_FLAG_COUNT)
- {
- txByte = 0x7E;
- txFlagsElapsed++;
- }
- else
- {
- txFlagsElapsed = 0;
- txByteIdx = 0;
- txStage = TX_STAGE_DATA; //return to normal data transmission stage. There might be a next frame to transmit
- __disable_irq();
- txFrameBufferFull = false;
- txFrameTail++;
- txFrameTail %= FRAME_MAX_COUNT;
- __enable_irq();
- goto transmitNormalData;
- }
- }
- if(txStage == TX_STAGE_TAIL) //transmitting tail
- {
- if(txTailElapsed < txTail)
- {
- txByte = 0x7E;
- txTailElapsed++;
- }
- else //tail transmitted, stop transmission
- {
- 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((txStage == TX_STAGE_DATA) || (txStage == TX_STAGE_CRC)) //transmitting normal data or CRC
- {
- if(txBitstuff == 5) //5 consecutive ones transmitted
- {
- txBit = 0; //transmit bit-stuffed 0
- txBitstuff = 0;
- }
- else
- {
- if(txByte & 1) //1 being transmitted
- {
- txBitstuff++; //increment bit stuffing counter
- txBit = 1;
- }
- else
- {
- txBit = 0;
- txBitstuff = 0; //0 being transmitted, reset bit stuffing counter
- }
- 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 = txByte & 1;
- txByte >>= 1;
- txBitIdx++;
- }
- return txBit;
-}
-
-/**
- * @brief Initialize transmission and start when possible
- */
-void Ax25TransmitBuffer(void)
-{
- if(txInitStage == TX_INIT_WAITING)
- return;
- if(txInitStage == TX_INIT_TRANSMITTING)
- return;
-
- if((txFrameHead != txFrameTail) || txFrameBufferFull)
- {
- txQuiet = (SysTickGet() + (Ax25Config.quietTime / SYSTICK_INTERVAL) + Random(0, 200 / SYSTICK_INTERVAL)); //calculate required delay
- txInitStage = TX_INIT_WAITING;
- }
-}
-
-
-
-/**
- * @brief Start transmission immediately
- * @warning Transmission should be initialized using Ax25_transmitBuffer
- */
-static void transmitStart(void)
-{
- txCrc = 0xFFFF; //initial CRC value
- txStage = TX_STAGE_PREAMBLE;
- txByte = 0;
- txBitIdx = 0;
- txFlagsElapsed = 0;
- ModemTransmitStart();
-}
-
-
-/**
- * @brief Start transmitting when possible
- * @attention Must be continuously polled in main loop
- */
-void Ax25TransmitCheck(void)
-{
- if(txInitStage == TX_INIT_OFF) //TX not initialized at all, nothing to transmit
- return;
- if(txInitStage == TX_INIT_TRANSMITTING) //already transmitting
- return;
-
- if(ModemIsTxTestOngoing()) //TX test is enabled, wait for now
- return;
-
- if(txQuiet < SysTickGet()) //quit time has elapsed
- {
- if(!ModemDcdState()) //channel is free
- {
- txInitStage = TX_INIT_TRANSMITTING; //transmit right now
- txRetries = 0;
- transmitStart();
- }
- else //channel is busy
- {
- if(txRetries == MAX_TRANSMIT_RETRY_COUNT) //timeout
- {
- txInitStage = TX_INIT_TRANSMITTING; //transmit right now
- txRetries = 0;
- transmitStart();
- }
- else //still trying
- {
- txQuiet = SysTickGet() + Random(100 / SYSTICK_INTERVAL, 500 / SYSTICK_INTERVAL); //try again after some random time
- txRetries++;
- }
- }
- }
-}
-
-void Ax25Init(void)
-{
- txCrc = 0xFFFF;
-
- memset((void*)rxState, 0, sizeof(rxState));
- for(uint8_t i = 0; i < (sizeof(rxState) / sizeof(rxState[0])); i++)
- rxState[i].crc = 0xFFFF;
-
- txDelay = ((float)Ax25Config.txDelayLength / (8.f * 1000.f / (float)MODEM_BAUDRATE)); //change milliseconds to byte count
- txTail = ((float)Ax25Config.txTailLength / (8.f * 1000.f / (float)MODEM_BAUDRATE));
-}
diff --git a/Src/drivers/modem.c b/Src/drivers/modem.c
deleted file mode 100644
index c27fa6b..0000000
--- a/Src/drivers/modem.c
+++ /dev/null
@@ -1,711 +0,0 @@
-/*
-Copyright 2020-2023 Piotr Wilkon
-
-This file is part of VP-Digi.
-
-VP-Digi is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or
-(at your option) any later version.
-
-VP-Digi is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-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 .
-*/
-
-#include "drivers/modem.h"
-#include "drivers/systick.h"
-#include "ax25.h"
-#include "stm32f1xx.h"
-#include
-#include
-#include "common.h"
-
-
-/*
- * Configuration for PLL-based data carrier detection
- * DCD_MAXPULSE is the maximum value of the DCD pulse counter
- * DCD_THRES is the threshold value of the DCD pulse counter. When reached the input signal is assumed to be valid
- * DCD_MAXPULSE and DCD_THRES difference sets the DCD "inertia" so that the DCD state won't change rapidly when a valid signal is present
- * DCD_DEC is the DCD pulse counter decrementation value when symbol changes too far from PLL counter zero
- * DCD_INC is the DCD pulse counter incrementation value when symbol changes near the PLL counter zero
- * DCD_PLLTUNE is the DCD timing coefficient when symbol changes, pll_counter = pll_counter * DCD_PLLTUNE
- * The DCD mechanism is described in afsk_demod().
- * All values were selected by trial and error
- */
-#define DCD_MAXPULSE 100
-#define DCD_THRES 30
-#define DCD_DEC 1
-#define DCD_INC 7
-#define DCD_PLLTUNE 0
-
-#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;
-
-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
-
-
-/**
- * @brief BPF filter with 2200 Hz tone 6 dB preemphasis (it actually attenuates 1200 Hz tone by 6 dB)
- */
-static const int16_t bpfCoeffs[8] =
-{
- 728,
- -13418,
- -554,
- 19493,
- -554,
- -13418,
- 728,
- 2104
-};
-
-/**
- * @brief BPF filter with 2200 Hz tone 6 dB deemphasis
- */
-static const int16_t invBpfCoeffs[8] =
-{
- -10513,
- -10854,
- 9589,
- 23884,
- 9589,
- -10854,
- -10513,
- -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
- */
-static const int16_t lpfCoeffs[15] =
-{
- -6128,
- -5974,
- -2503,
- 4125,
- 12679,
- 21152,
- 27364,
- 29643,
- 27364,
- 21152,
- 12679,
- 4125,
- -2503,
- -5974,
- -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 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 ModemDcdState(void)
-{
- return dcd;
-}
-
-uint8_t ModemIsTxTestOngoing(void)
-{
- if(txTestState != TEST_DISABLED)
- return 1;
-
- return 0;
-}
-
-void ModemClearRMS(uint8_t modem)
-{
-
- demodState[modem].RMSenergy = 0;
- demodState[modem].RMSsampleCount = 0;
-
-}
-
-uint16_t ModemGetRMS(uint8_t modem)
-{
- 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 setDcd(uint8_t state)
-{
- if(state)
- {
- GPIOC->BSRR = GPIO_BSRR_BR13;
- GPIOB->BSRR = GPIO_BSRR_BS5;
- }
- else
- {
- GPIOC->BSRR = GPIO_BSRR_BS13;
- GPIOB->BSRR = GPIO_BSRR_BR5;
- }
-}
-
-
-/**
- * @brief ISR for demodulator
- * Called at 9600 Hz by DMA
- */
-void DMA1_Channel2_IRQHandler(void) __attribute__ ((interrupt));
-void DMA1_Channel2_IRQHandler(void)
-{
- if(DMA1->ISR & DMA_ISR_TCIF2)
- {
- DMA1->IFCR |= DMA_IFCR_CTCIF2;
-
- int32_t sample = ((samples[0] + samples[1] + samples[2] + samples[3]) >> 1) - 4095; //calculate input sample (decimation)
-
- uint8_t partialDcd = 0;
-
- 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(partialDcd) //DCD on any of the demodulators
- {
- dcd = 1;
- setDcd(1);
- }
- else //no DCD on both demodulators
- {
- dcd = 0;
- setDcd(0);
- }
- }
-}
-
-
-
-/**
- * @brief ISR for pushing DAC samples
- */
-void TIM1_UP_IRQHandler(void) __attribute__ ((interrupt));
-void TIM1_UP_IRQHandler(void)
-{
- TIM1->SR &= ~TIM_SR_UIF;
-
- if(ModemConfig.usePWM)
- {
- TIM4->CCR1 = dacSine[dacSineIdx];
- }
- else
- {
- GPIOB->ODR &= ~0xF000; //zero 4 oldest bits
- GPIOB->ODR |= (dacSine[dacSineIdx] << 12); //write sample to 4 oldest bits
- }
-
- dacSineIdx++;
- dacSineIdx &= (DAC_SINE_SIZE - 1);
-}
-
-
-/**
- * @brief ISR for baudrate generator timer. NRZI encoding is done here.
- */
-void TIM3_IRQHandler(void) __attribute__ ((interrupt));
-void TIM3_IRQHandler(void)
-{
- TIM3->SR &= ~TIM_SR_UIF;
-
- if(txTestState == TEST_DISABLED) //transmitting normal data
- {
- if(Ax25GetTxBit() == 0) //get next bit and check if it's 0
- {
- currentSymbol ^= 1; //change symbol - NRZI encoding
- }
- //if 1, no symbol change
- }
- else //transmit test mode
- {
- currentSymbol ^= 1; //change symbol
- }
-
- TIM1->CNT = 0;
-
- if(currentSymbol) //current symbol is space
- TIM1->ARR = spaceFreq;
- else //mark
- TIM1->ARR = markFreq;
-
-}
-
-
-/**
- * @brief Demodulate received sample (4x oversampling)
- * @param[in] sample Received sample
- * @param[in] *dem Demodulator state
- * @return Current tone (0 or 1)
- */
-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 = 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 < BPF_TAPS; i++)
- {
- if(dem->emphasis == PREEMPHASIS)
- out += bpfCoeffs[i] * dem->rawSample[i]; //use preemphasis
- else
- out += invBpfCoeffs[i] * dem->rawSample[i]; //use deemphasis
- }
- dem->rxSample[dem->rxSampleIdx] = (out >> 15); //store filtered sample
- }
- else //no pre/deemphasis
- {
- dem->rxSample[dem->rxSampleIdx] = sample; //store incoming sample
- }
-
- dem->rxSampleIdx = (dem->rxSampleIdx + 1) % BPF_TAPS; //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 < 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));
-
- //DCD using PLL
- //PLL is running nominally at 1200 Hz (= baudrate)
- //PLL timer is counting up and eventually overflows to a minimal negative value
- //so it crosses zero in the middle
- //tone change should happen somewhere near this zero-crossing (in ideal case of exactly same TX and RX baudrates)
- //nothing is ideal, so we need to have some region around zero where tone change is expected
- //if tone changed inside this region, then we add something to the DCD pulse counter (and adjust counter phase for the counter to be closer to 0)
- //if tone changes outside this region, then we subtract something from the DCD pulse counter
- //if some DCD pulse threshold is reached, then we claim that the incoming signal is correct and set DCD flag
- //when configured properly, it's generally immune to noise, as the detected tone changes much faster than 1200 baud
- //it's also important to set some maximum value for DCD counter, otherwise the DCD is "sticky"
-
- dem->dcdPll = (signed)((unsigned)(dem->dcdPll) + ((unsigned)PLLINC)); //keep PLL ticking at the frequency equal to baudrate
-
- uint8_t dcdSymbol = (hi > lo); //get current symbol
-
- if(dcdSymbol != dem->dcdLastSymbol) //tone changed
- {
- if(abs(dem->dcdPll) < PLLINC) //tone change occurred near zero
- dem->dcdCounter += DCD_INC; //increase DCD counter
- else //tone change occurred far from zero
- {
- if(dem->dcdCounter >= DCD_DEC) //avoid overflow
- dem->dcdCounter -= DCD_DEC; //decrease DCD counter
- }
- dem->dcdPll = (int)(dem->dcdPll * DCD_PLLTUNE); //adjust PLL
- }
-
- 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
-
- if(dem->dcdCounter > DCD_THRES) //DCD threshold reached
- dem->dcd = 1; //DCD!
- else //below DCD threshold
- dem->dcd = 0; //no DCD
-
- //filter out signal faster than 1200 baud
- int64_t out = 0;
-
- 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 < LPF_TAPS; i++)
- {
- out += lpfCoeffs[i] * dem->lpfSample[i];
- }
-
- return out > 0;
-}
-
-
-
-
-/**
- * @brief Decode received symbol: bit recovery, NRZI decoding and pass the decoded bit to higher level protocol
- * @param[in] symbol Received symbol
- * @param demod Demodulator index
- */
-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)
- //Current symbol is sampled at PLL counter overflow, so symbol transition should occur at PLL counter zero
- dem->lastPll = dem->pll; //store last clock state
-
- dem->pll = (signed)((unsigned)(dem->pll) + (unsigned)PLLINC); //keep PLL running
-
- dem->rawSymbols <<= 1; //store received unsynchronized symbol
- 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
-
- uint8_t t = dem->rawSymbols & 0x07; //take last three symbols for sampling. Seems that 1 symbol is not enough, but 3 symbols work well
- if(t == 0b111 || t == 0b110 || t == 0b101 || t == 0b011) //if there are 2 or 3 ones, then the received symbol is 1
- {
- dem->syncSymbols |= 1; //push to recovered symbols register
- }
- //if there 2 or 3 zeros, no need to add anything to the register
-
- //NRZI decoding
- if (((dem->syncSymbols & 0x03) == 0b11) || ((dem->syncSymbols & 0x03) == 0b00)) //two last symbols are the same - no symbol transition - decoded bit 1
- {
- Ax25BitParse(1, demod);
- }
- else //symbol transition - decoded bit 0
- {
- Ax25BitParse(0, demod);
- }
- }
-
- if(((dem->rawSymbols & 0x03) == 0b10) || ((dem->rawSymbols & 0x03) == 0b01)) //if there was a symbol transition, adjust PLL
- {
-
- if(Ax25GetRxStage(demod) != RX_STAGE_FRAME) //not in a frame
- {
- dem->pll = (int)(dem->pll * PLLNOTLOCKED); //adjust PLL faster
- }
- else //in a frame
- {
- dem->pll = (int)(dem->pll * PLLLOCKED); //adjust PLL slower
- }
- }
-
-}
-
-
-
-void ModemTxTestStart(enum ModemTxTestMode type)
-{
- if(txTestState != TEST_DISABLED) //TX test is already running
- ModemTxTestStop(); //stop this test
-
- 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 = markFreq;
- } else if(type == TEST_SPACE)
- {
- 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 = baudRate; //set timer interval
- TIM3->CR1 = TIM_CR1_CEN; //enable timer
- NVIC_EnableIRQ(TIM3_IRQn); //enable interrupt in NVIC
- }
-}
-
-
-void ModemTxTestStop(void)
-{
- txTestState = TEST_DISABLED;
-
- TIM3->CR1 &= ~TIM_CR1_CEN; //turn off timers
- TIM1->CR1 &= ~TIM_CR1_CEN;
- TIM2->CR1 |= TIM_CR1_CEN; //enable RX timer
-
- NVIC_DisableIRQ(TIM3_IRQn);
- NVIC_DisableIRQ(TIM1_UP_IRQn);
- NVIC_EnableIRQ(DMA1_Channel2_IRQn);
-
- setPtt(0); //PTT off
-}
-
-
-void ModemTransmitStart(void)
-{
- setPtt(1); //PTT on
-
- TIM1->PSC = 17;
- TIM1->DIER |= TIM_DIER_UIE;
-
-
- TIM3->PSC = 71;
- TIM3->DIER |= TIM_DIER_UIE;
- TIM3->ARR = baudRate;
-
- TIM3->CR1 = TIM_CR1_CEN;
- TIM1->CR1 = TIM_CR1_CEN;
- TIM2->CR1 &= ~TIM_CR1_CEN;
-
- NVIC_DisableIRQ(DMA1_Channel2_IRQn);
- NVIC_EnableIRQ(TIM1_UP_IRQn);
- NVIC_EnableIRQ(TIM3_IRQn);
-}
-
-
-/**
- * @brief Stop TX and go back to RX
- */
-void ModemTransmitStop(void)
-{
-
- TIM2->CR1 |= TIM_CR1_CEN;
- TIM3->CR1 &= ~TIM_CR1_CEN;
- TIM1->CR1 &= ~TIM_CR1_CEN;
-
- NVIC_DisableIRQ(TIM1_UP_IRQn);
- NVIC_DisableIRQ(TIM3_IRQn);
- NVIC_EnableIRQ(DMA1_Channel2_IRQn);
-
- setPtt(0);
-
- TIM4->CCR1 = 44; //set around 50% duty cycle
-}
-
-/**
- * @brief Controls PTT output
- * @param[in] state 0 - PTT off, 1 - PTT on
- */
-static void setPtt(uint8_t state)
-{
- if(state)
- PTT_ON;
- else
- PTT_OFF;
-}
-
-
-
-/**
- * @brief Initialize AFSK module
- */
-void ModemInit(void)
-{
- /**
- * 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
- */
-
- RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
- RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
- RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
- RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
- RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
- RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
- RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
- 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 &= ~0xFFFF0000; //R2R output on PB12-PB15
- GPIOB->CRH |= 0x22220000;
-
- GPIOA->CRL &= ~GPIO_CRL_CNF0; //ADC input on PA0
- GPIOA->CRL &= ~GPIO_CRL_MODE0;
-
-
- GPIOB->CRL |= GPIO_CRL_MODE7_1; //PTT output on PB7
- GPIOB->CRL &= ~GPIO_CRL_MODE7_0;
- GPIOB->CRL &= ~GPIO_CRL_CNF7;
-
- GPIOB->CRL |= GPIO_CRL_MODE5_1; //2nd DCD LED on PB5
- GPIOB->CRL &= ~GPIO_CRL_MODE5_0;
- GPIOB->CRL &= ~GPIO_CRL_CNF5;
-
-
- RCC->CFGR |= RCC_CFGR_ADCPRE_1; //ADC prescaler /6
- RCC->CFGR &= ~RCC_CFGR_ADCPRE_0;
-
- ADC1->CR2 |= ADC_CR2_CONT; //continuous conversion
- ADC1->CR2 |= ADC_CR2_EXTSEL;
- ADC1->SQR1 &= ~ADC_SQR1_L; //1 conversion
- ADC1->SMPR2 |= ADC_SMPR2_SMP0_2; //41.5 cycle sampling
- ADC1->SQR3 &= ~ADC_SQR3_SQ1; //channel 0 is first in the sequence
- ADC1->CR2 |= ADC_CR2_ADON; //ADC on
-
- ADC1->CR2 |= ADC_CR2_RSTCAL; //calibrate ADC
- while(ADC1->CR2 & ADC_CR2_RSTCAL)
- ;
- ADC1->CR2 |= ADC_CR2_CAL;
- while(ADC1->CR2 & ADC_CR2_CAL)
- ;
-
- ADC1->CR2 |= ADC_CR2_EXTTRIG;
- ADC1->CR2 |= ADC_CR2_SWSTART; //start ADC conversion
-
- //prepare DMA
- DMA1_Channel2->CCR |= DMA_CCR_MSIZE_0; //16 bit memory region
- DMA1_Channel2->CCR &= ~DMA_CCR_MSIZE_1;
- DMA1_Channel2->CCR |= DMA_CCR_PSIZE_0;
- DMA1_Channel2->CCR &= ~DMA_CCR_PSIZE_1;
-
- 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)samples; //sample buffer address
- DMA1_Channel2->CCR |= DMA_CCR_EN; //enable DMA
-
- NVIC_EnableIRQ(DMA1_Channel2_IRQn);
-
- TIM2->PSC = 17; //72/18=4 MHz
- TIM2->DIER |= TIM_DIER_UDE; //enable calling DMA on timer tick
- TIM2->ARR = 103; //4MHz / 104 =~38400 Hz (4*9600 Hz for 4x oversampling)
- TIM2->CR1 |= TIM_CR1_CEN; //enable timer
-
- 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 < N; i++) //calculate correlator coefficients
- {
- 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 < DAC_SINE_SIZE; i++) //calculate DAC sine samples
- {
- if(ModemConfig.usePWM)
- dacSine[i] = ((sinf(2.f * 3.1416f * (float)i / (float)DAC_SINE_SIZE) + 1.f) * 45.f);
- else
- dacSine[i] = ((7.f * sinf(2.f * 3.1416f * (float)i / (float)DAC_SINE_SIZE)) + 8.f);
- }
-
- if(ModemConfig.flatAudioIn) //when used with flat audio input, use deemphasis and flat modems
- {
- demodState[0].emphasis = EMPHASIS_NONE;
- demodState[1].emphasis = DEEMPHASIS;
- }
- else //when used with normal (filtered) audio input, use flat and preemphasis modems
- {
- demodState[0].emphasis = EMPHASIS_NONE;
- demodState[1].emphasis = PREEMPHASIS;
- }
-
- if(ModemConfig.usePWM)
- {
- RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; //configure timer
-
- GPIOB->CRL |= GPIO_CRL_CNF6_1; //configure pin for PWM
- GPIOB->CRL |= GPIO_CRL_MODE6;
- GPIOB->CRL &= ~GPIO_CRL_CNF6_0;
-
- //set up PWM generation
- TIM4->PSC = 7; //72MHz/8=9MHz
- TIM4->ARR = 90; //9MHz/90=100kHz
-
- TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;
- TIM4->CCER |= TIM_CCER_CC1E;
- TIM4->CCR1 = 44; //initial duty cycle
-
- TIM4->CR1 |= TIM_CR1_CEN;
- }
-
-}
-
-
-
-
-
-/**
- * @}
- */
diff --git a/Src/drivers/uart.c b/Src/drivers/uart.c
deleted file mode 100644
index 69c544d..0000000
--- a/Src/drivers/uart.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
-Copyright 2020-2023 Piotr Wilkon
-
-This file is part of VP-Digi.
-
-VP-Digi is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or
-(at your option) any later version.
-
-VP-Digi is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-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 .
-*/
-
-#include "drivers/uart.h"
-#include "drivers/systick.h"
-#include "terminal.h"
-#include "ax25.h"
-#include "common.h"
-#include
-#include "digipeater.h"
-#include "kiss.h"
-
-Uart Uart1, Uart2, UartUsb;
-
-static void handleInterrupt(Uart *port)
-{
- if(port->port->SR & USART_SR_RXNE) //byte received
- {
- port->port->SR &= ~USART_SR_RXNE;
- uint8_t data = port->port->DR;
- port->rxBuffer[port->rxBufferHead++] = data; //store it
- port->rxBufferHead %= UART_BUFFER_SIZE;
-
- KissParse(port, data);
- TermHandleSpecial(port);
- }
- 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->rxBufferHead != 0)
- {
- 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;
- }
- }
- }
- if(port->port->SR & USART_SR_TXE) //TX buffer empty
- {
- if((port->txBufferHead != port->txBufferTail) || port->txBufferFull) //if there is anything to transmit
- {
- port->port->DR = port->txBuffer[port->txBufferTail++]; //push it to the register
- port->txBufferTail %= UART_BUFFER_SIZE;
- port->txBufferFull = 0;
- }
- else //nothing more to be transmitted
- {
- port->port->CR1 &= ~USART_CR1_TXEIE;
- }
- }
-}
-
-void USART1_IRQHandler(void) __attribute__ ((interrupt));
-void USART1_IRQHandler(void)
-{
- handleInterrupt(&Uart1);
-}
-
-void USART2_IRQHandler(void) __attribute__ ((interrupt));
-void USART2_IRQHandler(void)
-{
- handleInterrupt(&Uart2);
-}
-
-
-void UartSendByte(Uart *port, uint8_t data)
-{
- if(!port->enabled)
- return;
-
- if(port->isUsb)
- {
- CDC_Transmit_FS(&data, 1);
- }
- else
- {
- 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 UartSendString(Uart *port, void *data, uint16_t len)
-{
- if(0 == len)
- len = strlen((char*)data);
-
- for(uint16_t i = 0; i < len; i++)
- {
- UartSendByte(port, ((uint8_t*)data)[i]);
- }
-}
-
-
-static unsigned int findHighestPosition(unsigned int n)
-{
- unsigned int i = 1;
- while((i * 10) <= n)
- i *= 10;
-
- return i;
-}
-
-void UartSendNumber(Uart *port, int32_t n)
-{
- if(n < 0)
- UartSendByte(port, '-');
- n = abs(n);
- unsigned int position = findHighestPosition(n);
- while(position)
- {
- unsigned int number = n / position;
- UartSendByte(port, (number + 48));
- n -= (number * position);
- position /= 10;
- }
-}
-
-void UartInit(Uart *port, USART_TypeDef *uart, uint32_t baud)
-{
- port->port = uart;
- port->baudrate = baud;
- port->rxType = DATA_NOTHING;
- port->rxBufferHead = 0;
- port->txBufferHead = 0;
- port->txBufferTail = 0;
- port->txBufferFull = 0;
- port->kissBufferHead = 0;
- port->mode = MODE_KISS;
- port->enabled = 0;
- port->lastRxBufferHead = 0;
- memset(port->rxBuffer, 0, sizeof(port->rxBuffer));
- memset(port->txBuffer, 0, sizeof(port->txBuffer));
- memset(port->kissBuffer, 0, sizeof(port->kissBuffer));
-}
-
-
-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;
- GPIOA->CRH |= GPIO_CRH_CNF9_1;
- GPIOA->CRH |= GPIO_CRH_CNF10_0;
- GPIOA->CRH &= ~GPIO_CRH_CNF10_1;
-
- USART1->BRR = (SystemCoreClock / (port->baudrate));
-
- if(state)
- USART1->CR1 |= USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_IDLEIE;
- else
- USART1->CR1 &= (~USART_CR1_RXNEIE) & (~USART_CR1_TE) & (~USART_CR1_RE) & (~USART_CR1_UE) & (~USART_CR1_IDLEIE);
-
- NVIC_SetPriority(USART1_IRQn, 2);
- if(state)
- NVIC_EnableIRQ(USART1_IRQn);
- else
- 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;
- GPIOA->CRL |= GPIO_CRL_CNF2_1;
- GPIOA->CRL |= GPIO_CRL_CNF3_0;
- GPIOA->CRL &= ~GPIO_CRL_CNF3_1;
-
- USART2->BRR = (SystemCoreClock / (port->baudrate * 2));
- if(state)
- USART2->CR1 |= USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_IDLEIE;
- else
- USART2->CR1 &= (~USART_CR1_RXNEIE) & (~USART_CR1_TE) & (~USART_CR1_RE) & (~USART_CR1_UE) & (~USART_CR1_IDLEIE);
-
- NVIC_SetPriority(USART2_IRQn, 2);
- if(state)
- NVIC_EnableIRQ(USART2_IRQn);
- else
- NVIC_DisableIRQ(USART2_IRQn);
-
- port->enabled = state > 0;
- port->isUsb = 0;
- }
- else
- {
- port->isUsb = 1;
- port->enabled = state > 0;
- }
-
-}
-
-
-void UartClearRx(Uart *port)
-{
- port->rxBufferHead = 0;
- port->rxType = DATA_NOTHING;
-}