kopia lustrzana https://github.com/sq8vps/vp-digi
Porównaj commity
4 Commity
1d923864fb
...
8d83ab5cfa
Autor | SHA1 | Data |
---|---|---|
Piotr Wilkon | 8d83ab5cfa | |
sq8vps | 8189de2e0f | |
sq8vps | 6dae655f45 | |
sq8vps | b329dfddf4 |
38
CHANGELOG.md
38
CHANGELOG.md
|
@ -1,3 +1,41 @@
|
|||
# 2.0.0 (2023-09-05)
|
||||
## New features
|
||||
* New modems: AFSK Bell 103 (300 Bd, 1600/1800 Hz), GFSK G3RUH (9600 Bd), AFSK V.23 (1200 Bd, 1300/2100 Hz)
|
||||
* FX.25 (AX.25 with Reed-Solomon FEC) support
|
||||
## Bug fixes
|
||||
* none
|
||||
## Other
|
||||
* New signal level measurement method
|
||||
## Known bugs
|
||||
* none
|
||||
# 1.3.3 (2023-09-04)
|
||||
## New features
|
||||
* none
|
||||
## Bug fixes
|
||||
* RX buffer pointers bug fix
|
||||
* AX.25 to TNC2 converter bug with non-UI frames
|
||||
## Other
|
||||
* New KISS handling method to support long and multiple frames
|
||||
## Known bugs
|
||||
* none
|
||||
# 1.3.2 (2023-08-31)
|
||||
## New features
|
||||
* none
|
||||
## Bug fixes
|
||||
* Duplicate protection was not working properly
|
||||
## Other
|
||||
* none
|
||||
## Known bugs
|
||||
* none
|
||||
# 1.3.1 (2023-08-30)
|
||||
## New features
|
||||
* none
|
||||
## Bug fixes
|
||||
* Non-APRS switch was not stored in memory
|
||||
## Other
|
||||
* PWM is now the default option
|
||||
## Known bugs
|
||||
* none
|
||||
# 1.3.0 (2023-08-30)
|
||||
## New features
|
||||
* Callsign is now set together with SSID using ```call <call-SSID>```
|
||||
|
|
17
Inc/ax25.h
17
Inc/ax25.h
|
@ -25,6 +25,17 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#define AX25_NOT_FX25 255
|
||||
|
||||
#ifndef ENABLE_FX25
|
||||
//for AX.25 308 bytes is the theoretical max size assuming 2-byte Control, 256-byte info field and 5 digi address fields
|
||||
#define AX25_FRAME_MAX_SIZE (308) //single frame max length
|
||||
#else
|
||||
//in FX.25 mode the block can be 255 bytes long at most, and the AX.25 frame itself must be even smaller
|
||||
//frames that are too long are sent as standard AX.25 frames
|
||||
//Reed-Solomon library needs a bit of memory and the frame buffer must be smaller
|
||||
//otherwise we run out of RAM
|
||||
#define AX25_FRAME_MAX_SIZE (265) //single frame max length
|
||||
#endif
|
||||
|
||||
enum Ax25RxStage
|
||||
{
|
||||
RX_STAGE_IDLE = 0,
|
||||
|
@ -47,12 +58,6 @@ struct Ax25ProtoConfig
|
|||
|
||||
extern struct Ax25ProtoConfig Ax25Config;
|
||||
|
||||
/**
|
||||
* @brief Transmit one or more frames encoded in KISS format
|
||||
* @param *buf Inout buffer
|
||||
* @param len Buffer size
|
||||
*/
|
||||
void Ax25TxKiss(uint8_t *buf, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Write frame to transmit buffer
|
||||
|
|
|
@ -23,7 +23,7 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "usbd_cdc_if.h"
|
||||
#include "ax25.h"
|
||||
|
||||
#define UART_BUFFER_SIZE 250
|
||||
#define UART_BUFFER_SIZE 130
|
||||
|
||||
enum UartMode
|
||||
{
|
||||
|
@ -35,7 +35,6 @@ enum UartMode
|
|||
enum UartDataType
|
||||
{
|
||||
DATA_NOTHING = 0,
|
||||
DATA_KISS,
|
||||
DATA_TERM,
|
||||
DATA_USB,
|
||||
};
|
||||
|
@ -53,20 +52,14 @@ typedef struct
|
|||
uint16_t txBufferHead, txBufferTail;
|
||||
uint8_t txBufferFull : 1;
|
||||
enum UartMode mode;
|
||||
uint32_t kissTimer;
|
||||
uint16_t lastRxBufferHead; //for special characters handling
|
||||
uint8_t kissBuffer[AX25_FRAME_MAX_SIZE + 1];
|
||||
uint16_t kissBufferHead;
|
||||
} Uart;
|
||||
|
||||
extern Uart Uart1, Uart2, UartUsb;
|
||||
|
||||
|
||||
///**
|
||||
// * \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 Send byte
|
||||
* @param[in] *port UART
|
||||
|
@ -111,11 +104,4 @@ void UartConfig(Uart *port, uint8_t state);
|
|||
*/
|
||||
void UartClearRx(Uart *port);
|
||||
|
||||
/**
|
||||
* @brief Handle KISS timeout
|
||||
* @param *port UART pointer
|
||||
* @attention This function must be polled constantly in main loop for USB UART.
|
||||
*/
|
||||
void UartHandleKissTimeout(Uart *port);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KISS_H_
|
||||
#define KISS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "drivers/uart.h"
|
||||
|
||||
/**
|
||||
* @brief Convert AX.25 frame to KISS and send
|
||||
* @param *port UART structure
|
||||
* @param *buf Frame buffer
|
||||
* @param size Frame size
|
||||
*/
|
||||
void KissSend(Uart *port, uint8_t *buf, uint16_t size);
|
||||
|
||||
/**
|
||||
* @brief Parse bytes received from UART to form a KISS frame (possibly) and send this frame
|
||||
* @param *port UART structure
|
||||
* @param data Received byte
|
||||
*/
|
||||
void KissParse(Uart *port, uint8_t data);
|
||||
|
||||
#endif /* KISS_H_ */
|
66
Src/ax25.c
66
Src/ax25.c
|
@ -29,21 +29,12 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
struct Ax25ProtoConfig Ax25Config;
|
||||
|
||||
//values below must be kept consistent so that FRAME_BUFFER_SIZE >= FRAME_MAX_SIZE * FRAME_MAX_COUNT
|
||||
#ifndef ENABLE_FX25
|
||||
//for AX.25 308 bytes is the theoretical max size assuming 2-byte Control, 256-byte info field and 5 digi address fields
|
||||
#define FRAME_MAX_SIZE (308) //single frame max length
|
||||
#else
|
||||
//in FX.25 mode the block can be 255 bytes long at most, and the AX.25 frame itself must be even smaller
|
||||
//frames that are too long are sent as standard AX.25 frames
|
||||
//Reed-Solomon library needs a bit of memory and the frame buffer must be smaller
|
||||
//otherwise we run out of RAM
|
||||
#define FRAME_MAX_SIZE (265) //single frame max length
|
||||
#ifdef ENABLE_FX25
|
||||
#include "fx25.h"
|
||||
#endif
|
||||
|
||||
#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 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
|
||||
|
@ -126,7 +117,7 @@ static enum TxStage txStage; //current TX stage
|
|||
struct RxState
|
||||
{
|
||||
uint16_t crc; //current CRC
|
||||
uint8_t frame[FRAME_MAX_SIZE]; //raw frame buffer
|
||||
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
|
||||
|
@ -147,7 +138,7 @@ static uint16_t rxMultiplexDelay = 0; //simple delay for decoder multiplexer to
|
|||
static uint16_t txDelay; //number of TXDelay bytes to send
|
||||
static uint16_t txTail; //number of TXTail bytes to send
|
||||
|
||||
static uint8_t outputFrameBuffer[FRAME_MAX_SIZE];
|
||||
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))
|
||||
|
@ -178,31 +169,6 @@ void Ax25ClearReceivedFrameBitmap(void)
|
|||
frameReceived = 0;
|
||||
}
|
||||
|
||||
void Ax25TxKiss(uint8_t *buf, uint16_t len)
|
||||
{
|
||||
if(len < 18) //frame is too small
|
||||
{
|
||||
return;
|
||||
}
|
||||
for(uint16_t i = 0; i < len; i++)
|
||||
{
|
||||
if(buf[i] == 0xC0) //frame start marker
|
||||
{
|
||||
uint16_t end = i + 1;
|
||||
while(end < len)
|
||||
{
|
||||
if(buf[end] == 0xC0)
|
||||
break;
|
||||
end++;
|
||||
}
|
||||
if(end == len) //no frame end marker found
|
||||
return;
|
||||
Ax25WriteTxFrame(&buf[i + 2], end - (i + 2)); //skip modem number and send frame
|
||||
DigiStoreDeDupe(&buf[i + 2], end - (i + 2));
|
||||
i = end; //move pointer to the next byte if there are more consecutive frames
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void removeLastFrameFromRxBuffer(void)
|
||||
{
|
||||
|
@ -435,9 +401,6 @@ endParseFx25Frame:
|
|||
|
||||
void *Ax25WriteTxFrame(uint8_t *data, uint16_t size)
|
||||
{
|
||||
while(txStage != TX_STAGE_IDLE)
|
||||
;
|
||||
|
||||
if(txFrameBufferFull)
|
||||
return NULL;
|
||||
|
||||
|
@ -471,10 +434,12 @@ void *Ax25WriteTxFrame(uint8_t *data, uint16_t size)
|
|||
|
||||
|
||||
void *ret = &txFrame[txFrameHead];
|
||||
__disable_irq();
|
||||
txFrameHead++;
|
||||
txFrameHead %= FRAME_MAX_COUNT;
|
||||
if(txFrameHead == txFrameTail)
|
||||
txFrameBufferFull = true;
|
||||
__enable_irq();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -497,10 +462,11 @@ bool Ax25ReadNextRxFrame(uint8_t **dst, uint16_t *size, int8_t *peak, int8_t *va
|
|||
*size = rxFrame[rxFrameTail].size;
|
||||
*corrected = rxFrame[rxFrameTail].corrected;
|
||||
|
||||
__disable_irq();
|
||||
rxFrameBufferFull = false;
|
||||
|
||||
rxFrameTail++;
|
||||
rxFrameTail %= FRAME_MAX_COUNT;
|
||||
__enable_irq();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -594,10 +560,12 @@ void Ax25BitParse(uint8_t bit, uint8_t modem)
|
|||
rxFrame[rxFrameHead].fx25Mode = NULL;
|
||||
#endif
|
||||
rxFrame[rxFrameHead].corrected = AX25_NOT_FX25;
|
||||
__disable_irq();
|
||||
rxFrame[rxFrameHead++].size = rx->frameIdx;
|
||||
rxFrameHead %= FRAME_MAX_COUNT;
|
||||
if(rxFrameHead == txFrameHead)
|
||||
if(rxFrameHead == rxFrameTail)
|
||||
rxFrameBufferFull = true;
|
||||
__enable_irq();
|
||||
|
||||
for(uint16_t i = 0; i < rx->frameIdx; i++)
|
||||
{
|
||||
|
@ -629,7 +597,7 @@ void Ax25BitParse(uint8_t bit, uint8_t modem)
|
|||
{
|
||||
//this condition must not be checked when FX.25 is enabled
|
||||
//because FX.25 parity bytes and tags contain >= 7 consecutive ones
|
||||
if((rx->rawData & 0x7F) == 0x7F) //received 7 consecutive ones, this is an error (sometimes called "escape byte")
|
||||
if((rx->rawData & 0x7F) == 0x7F) //received 7 consecutive ones, this is an error
|
||||
{
|
||||
rx->rx = RX_STAGE_FLAG;
|
||||
rx->receivedByte = 0;
|
||||
|
@ -678,7 +646,7 @@ void Ax25BitParse(uint8_t bit, uint8_t modem)
|
|||
#else
|
||||
rx->rx = RX_STAGE_FRAME;
|
||||
#endif
|
||||
if(rx->frameIdx >= FRAME_MAX_SIZE) //frame is too long
|
||||
if(rx->frameIdx >= AX25_FRAME_MAX_SIZE) //frame is too long
|
||||
{
|
||||
rx->rx = RX_STAGE_IDLE;
|
||||
rx->receivedByte = 0;
|
||||
|
@ -750,8 +718,10 @@ transmitTag:
|
|||
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];
|
||||
|
@ -760,10 +730,12 @@ transmitNormalData:
|
|||
#ifdef ENABLE_FX25
|
||||
else if(txFrame[txFrameTail].fx25Mode != NULL)
|
||||
{
|
||||
__disable_irq();
|
||||
txFrameBufferFull = false;
|
||||
txFrameTail++;
|
||||
txFrameTail %= FRAME_MAX_COUNT;
|
||||
txByteIdx = 0;
|
||||
__enable_irq();
|
||||
if((txFrameHead != txFrameTail) || txFrameBufferFull)
|
||||
{
|
||||
if(txFrame[txFrameTail].fx25Mode != NULL)
|
||||
|
@ -788,6 +760,7 @@ transmitNormalData:
|
|||
else //no more frames
|
||||
{
|
||||
transmitTail:
|
||||
__enable_irq();
|
||||
txByteIdx = 0;
|
||||
txBitIdx = 0;
|
||||
txStage = TX_STAGE_TAIL;
|
||||
|
@ -819,6 +792,7 @@ transmitTail:
|
|||
else
|
||||
{
|
||||
txFlagsElapsed = 0;
|
||||
__disable_irq();
|
||||
txFrameBufferFull = false;
|
||||
txFrameTail++;
|
||||
txFrameTail %= FRAME_MAX_COUNT;
|
||||
|
@ -826,11 +800,13 @@ transmitTail:
|
|||
#ifdef ENABLE_FX25
|
||||
if(((txFrameHead != txFrameTail) || txFrameBufferFull) && (txFrame[txFrameTail].fx25Mode != NULL))
|
||||
{
|
||||
__enable_irq();
|
||||
txStage = TX_STAGE_CORRELATION_TAG;
|
||||
txTagByteIdx = 0;
|
||||
goto transmitTag;
|
||||
}
|
||||
#endif
|
||||
__enable_irq();
|
||||
txStage = TX_STAGE_DATA; //return to normal data transmission stage. There might be a next frame to transmit
|
||||
goto transmitNormalData;
|
||||
}
|
||||
|
|
11
Src/common.c
11
Src/common.c
|
@ -148,11 +148,16 @@ static void sendTNC2ToUart(Uart *uart, uint8_t *from, uint16_t len)
|
|||
|
||||
}
|
||||
|
||||
UartSendByte(uart, ':'); //separator
|
||||
UartSendByte(uart, ':'); //separator
|
||||
|
||||
nextPathEl += 2; //skip Control and PID
|
||||
if((from[nextPathEl] & 0b11101111) == 0b00000011) //check if UI packet
|
||||
{
|
||||
nextPathEl += 2; //skip Control and PID
|
||||
|
||||
UartSendString(uart, &(from[nextPathEl]), len - nextPathEl); //send information field
|
||||
UartSendString(uart, &(from[nextPathEl]), len - nextPathEl); //send information field
|
||||
}
|
||||
else
|
||||
UartSendString(uart, "<not UI packet>", 0);
|
||||
|
||||
UartSendByte(uart, 0); //terminate with NULL
|
||||
}
|
||||
|
|
|
@ -50,8 +50,7 @@ static struct DeDupeData deDupe[DEDUPE_SIZE]; //duplicate protection hash buffer
|
|||
static uint8_t deDupeCount = 0; //duplicate protection buffer index
|
||||
|
||||
|
||||
#define DIGI_BUFFER_SIZE 308 //308 is the theoretical max under some assumptions, see ax25.c
|
||||
static uint8_t buf[DIGI_BUFFER_SIZE];
|
||||
static uint8_t buf[AX25_FRAME_MAX_SIZE];
|
||||
|
||||
/**
|
||||
* @brief Check if frame with specified hash is already in viscous-delay buffer and delete it if so
|
||||
|
@ -198,7 +197,7 @@ static void makeFrame(uint8_t *frame, uint16_t elStart, uint16_t len, uint32_t h
|
|||
}
|
||||
else //normal mode
|
||||
{
|
||||
if((uint32_t)sizeof(buf) < (len + 7))
|
||||
if((uint16_t)sizeof(buf) < (len + 7))
|
||||
return;
|
||||
buffer = buf;
|
||||
}
|
||||
|
|
|
@ -593,7 +593,7 @@ void ModemTxTestStart(enum ModemTxTestMode type)
|
|||
|
||||
if(ModemConfig.modem == MODEM_9600)
|
||||
{
|
||||
TIM1->ARR = 103;
|
||||
TIM1->ARR = markStep;
|
||||
//enable baudrate generator
|
||||
TIM3->CR1 = TIM_CR1_CEN; //enable timer
|
||||
NVIC_EnableIRQ(TIM3_IRQn); //enable interrupt in NVIC
|
||||
|
@ -637,7 +637,7 @@ void ModemTransmitStart(void)
|
|||
{
|
||||
setPtt(1); //PTT on
|
||||
if(ModemConfig.modem == MODEM_9600)
|
||||
TIM1->ARR = 103;
|
||||
TIM1->ARR = markStep;
|
||||
|
||||
TIM3->CR1 = TIM_CR1_CEN;
|
||||
TIM1->CR1 = TIM_CR1_CEN;
|
||||
|
@ -688,8 +688,8 @@ void ModemInit(void)
|
|||
memset(demodState, 0, sizeof(demodState));
|
||||
|
||||
/**
|
||||
* TIM1 is used for pushing samples to DAC (R2R or PWM) (clocked at 4 MHz)
|
||||
* TIM3 is the baudrate generator for TX (clocked at 1 MHz)
|
||||
* TIM1 is used for pushing samples to DAC (R2R or PWM) (clocked at 18 MHz)
|
||||
* TIM3 is the baudrate generator for TX (clocked at 18 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
|
||||
*/
|
||||
|
@ -764,11 +764,11 @@ void ModemInit(void)
|
|||
TIM2->DIER |= TIM_DIER_UDE; //enable calling DMA on timer tick
|
||||
|
||||
//TX DAC timer
|
||||
TIM1->PSC = 17; //72/18=4 MHz
|
||||
TIM1->PSC = 3; //72/4=18 MHz
|
||||
TIM1->DIER |= TIM_DIER_UIE;
|
||||
|
||||
//baudrate timer
|
||||
TIM3->PSC = 3; //72/9=18 MHz
|
||||
TIM3->PSC = 3; //72/4=18 MHz
|
||||
TIM3->DIER |= TIM_DIER_UIE;
|
||||
|
||||
if(ModemConfig.modem > MODEM_9600)
|
||||
|
@ -905,6 +905,7 @@ void ModemInit(void)
|
|||
demodCount = 1;
|
||||
N = N9600;
|
||||
baudRate = 9600.f;
|
||||
markFreq = 38400.f / (float)DAC_SINE_SIZE; //use as DAC sample rate
|
||||
|
||||
demodState[0].pllStep = PLL9600_STEP;
|
||||
demodState[0].pllLockedAdjust = PLL9600_LOCKED_TUNE;
|
||||
|
@ -925,8 +926,8 @@ void ModemInit(void)
|
|||
|
||||
TIM2->CR1 |= TIM_CR1_CEN; //enable DMA timer
|
||||
|
||||
markStep = 4000000 / (DAC_SINE_SIZE * markFreq) - 1;
|
||||
spaceStep = 4000000 / (DAC_SINE_SIZE * spaceFreq) - 1;
|
||||
markStep = 18000000 / (DAC_SINE_SIZE * markFreq) - 1;
|
||||
spaceStep = 18000000 / (DAC_SINE_SIZE * spaceFreq) - 1;
|
||||
baudRateStep = 18000000 / baudRate - 1;
|
||||
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "common.h"
|
||||
#include <string.h>
|
||||
#include "digipeater.h"
|
||||
#include "kiss.h"
|
||||
|
||||
Uart Uart1, Uart2, UartUsb;
|
||||
|
||||
|
@ -30,28 +31,22 @@ static void handleInterrupt(Uart *port)
|
|||
if(port->port->SR & USART_SR_RXNE) //byte received
|
||||
{
|
||||
port->port->SR &= ~USART_SR_RXNE;
|
||||
port->rxBuffer[port->rxBufferHead++] = port->port->DR; //store it
|
||||
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->mode == MODE_KISS)
|
||||
port->kissTimer = SysTickGet() + (5000 / SYSTICK_INTERVAL); //set timeout to 5s in KISS mode
|
||||
}
|
||||
if(port->port->SR & USART_SR_IDLE) //line is idle, end of data reception
|
||||
{
|
||||
port->port->DR; //reset idle flag by dummy read
|
||||
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
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +54,7 @@ static void handleInterrupt(Uart *port)
|
|||
{
|
||||
if((port->txBufferHead != port->txBufferTail) || port->txBufferFull) //if there is anything to transmit
|
||||
{
|
||||
port->port->DR = port->txBuffer[port->txBufferTail++]; //push it to the refister
|
||||
port->port->DR = port->txBuffer[port->txBufferTail++];
|
||||
port->txBufferTail %= UART_BUFFER_SIZE;
|
||||
port->txBufferFull = 0;
|
||||
}
|
||||
|
@ -68,13 +63,6 @@ static void handleInterrupt(Uart *port)
|
|||
port->port->CR1 &= ~USART_CR1_TXEIE;
|
||||
}
|
||||
}
|
||||
|
||||
if((port->kissTimer > 0) && (SysTickGet() >= port->kissTimer)) //KISS timer timeout
|
||||
{
|
||||
port->kissTimer = 0;
|
||||
port->rxBufferHead = 0;
|
||||
memset(port->rxBuffer, 0, sizeof(port->rxBuffer));
|
||||
}
|
||||
}
|
||||
|
||||
void USART1_IRQHandler(void) __attribute__ ((interrupt));
|
||||
|
@ -160,10 +148,11 @@ void UartInit(Uart *port, USART_TypeDef *uart, uint32_t baud)
|
|||
port->txBufferFull = 0;
|
||||
port->mode = MODE_KISS;
|
||||
port->enabled = 0;
|
||||
port->kissTimer = 0;
|
||||
port->kissBufferHead = 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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -235,12 +224,3 @@ void UartClearRx(Uart *port)
|
|||
port->rxType = DATA_NOTHING;
|
||||
}
|
||||
|
||||
void UartHandleKissTimeout(Uart *port)
|
||||
{
|
||||
if((port->kissTimer > 0) && (SysTickGet() >= port->kissTimer)) //KISS timer timeout
|
||||
{
|
||||
port->kissTimer = 0;
|
||||
port->rxBufferHead = 0;
|
||||
memset(port->rxBuffer, 0, sizeof(port->rxBuffer));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "kiss.h"
|
||||
#include "ax25.h"
|
||||
#include "digipeater.h"
|
||||
|
||||
void KissSend(Uart *port, uint8_t *buf, uint16_t size)
|
||||
{
|
||||
if(port->mode == MODE_KISS)
|
||||
{
|
||||
UartSendByte(port, 0xC0);
|
||||
UartSendByte(port, 0x00);
|
||||
for(uint16_t i = 0; i < size; i++)
|
||||
{
|
||||
if(buf[i] == 0xC0) //frame end in data
|
||||
{
|
||||
UartSendByte(port, 0xDB); //frame escape
|
||||
UartSendByte(port, 0xDC); //transposed frame end
|
||||
}
|
||||
else if(buf[i] == 0xDB) //frame escape in data
|
||||
{
|
||||
UartSendByte(port, 0xDB); //frame escape
|
||||
UartSendByte(port, 0xDD); //transposed frame escape
|
||||
}
|
||||
else
|
||||
UartSendByte(port, buf[i]);
|
||||
}
|
||||
UartSendByte(port, 0xC0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void KissParse(Uart *port, uint8_t data)
|
||||
{
|
||||
if(data == 0xC0) //frame end marker
|
||||
{
|
||||
if(port->kissBufferHead < 16) //command+source+destination+Control=16
|
||||
{
|
||||
port->kissBufferHead = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if((port->kissBuffer[0] & 0xF) != 0) //check if this is an actual frame
|
||||
{
|
||||
port->kissBufferHead = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
//simple sanity check
|
||||
//check if LSbits in the first 13 bytes are set to 0
|
||||
//they should always be in an AX.25 frame
|
||||
for(uint8_t i = 0; i < 13; i++)
|
||||
{
|
||||
if((port->kissBuffer[i + 1] & 1) != 0)
|
||||
{
|
||||
port->kissBufferHead = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Ax25WriteTxFrame(&port->kissBuffer[1], port->kissBufferHead - 1);
|
||||
DigiStoreDeDupe(&port->kissBuffer[1], port->kissBufferHead - 1);
|
||||
port->kissBufferHead = 0;
|
||||
return;
|
||||
}
|
||||
else if(port->kissBufferHead > 0)
|
||||
{
|
||||
if((data == 0xDC) && (port->kissBuffer[port->kissBufferHead - 1] == 0xDB)) //escape character with transposed frame end
|
||||
{
|
||||
port->kissBuffer[port->kissBufferHead - 1] = 0xC0;
|
||||
return;
|
||||
}
|
||||
else if((data == 0xDD) && (port->kissBuffer[port->kissBufferHead - 1] == 0xDB)) //escape character with transposed escape character
|
||||
{
|
||||
port->kissBuffer[port->kissBufferHead - 1] = 0xDB;
|
||||
return;
|
||||
}
|
||||
}
|
||||
port->kissBuffer[port->kissBufferHead++] = data;
|
||||
port->kissBufferHead %= sizeof(port->kissBuffer);
|
||||
}
|
|
@ -224,7 +224,7 @@ int main(void)
|
|||
//set some initial values in case there is no configuration saved in memory
|
||||
Uart1.baudrate = 9600;
|
||||
Uart2.baudrate = 9600;
|
||||
ModemConfig.usePWM = 1;
|
||||
ModemConfig.usePWM = 1; //use PWM by default
|
||||
ModemConfig.flatAudioIn = 0;
|
||||
Ax25Config.quietTime = 300;
|
||||
Ax25Config.txDelayLength = 300;
|
||||
|
@ -291,7 +291,6 @@ int main(void)
|
|||
TermParse(&Uart2);
|
||||
UartClearRx(&Uart2);
|
||||
}
|
||||
UartHandleKissTimeout(&UartUsb);
|
||||
|
||||
BeaconCheck(); //check beacons
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ along with VP-DigiConfig. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "drivers/modem.h"
|
||||
#include "ax25.h"
|
||||
#include "drivers/systick.h"
|
||||
#include "kiss.h"
|
||||
|
||||
void TermHandleSpecial(Uart *u)
|
||||
{
|
||||
|
@ -57,25 +58,13 @@ void TermHandleSpecial(Uart *u)
|
|||
|
||||
}
|
||||
|
||||
|
||||
static void sendKiss(Uart *port, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
if(port->mode == MODE_KISS) //check if KISS mode
|
||||
{
|
||||
UartSendByte(port, 0xc0); //send data in kiss format
|
||||
UartSendByte(port, 0x00);
|
||||
UartSendString(port, buf, len);
|
||||
UartSendByte(port, 0xc0);
|
||||
}
|
||||
}
|
||||
|
||||
void TermSendToAll(enum UartMode mode, uint8_t *data, uint16_t size)
|
||||
{
|
||||
if(MODE_KISS == mode)
|
||||
{
|
||||
sendKiss(&Uart1, data, size);
|
||||
sendKiss(&Uart2, data, size);
|
||||
sendKiss(&UartUsb, data, size);
|
||||
KissSend(&Uart1, data, size);
|
||||
KissSend(&Uart2, data, size);
|
||||
KissSend(&UartUsb, data, size);
|
||||
}
|
||||
else if(MODE_MONITOR == mode)
|
||||
{
|
||||
|
@ -86,7 +75,6 @@ void TermSendToAll(enum UartMode mode, uint8_t *data, uint16_t size)
|
|||
if(Uart2.mode == MODE_MONITOR)
|
||||
UartSendString(&Uart2, data, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TermSendNumberToAll(enum UartMode mode, int32_t n)
|
||||
|
@ -403,14 +391,6 @@ void TermParse(Uart *src)
|
|||
src->mode = MODE_MONITOR;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* KISS parsing
|
||||
*/
|
||||
else if((src->mode == MODE_KISS) && (src->rxType == DATA_KISS))
|
||||
{
|
||||
Ax25TxKiss(src->rxBuffer, src->rxBufferHead);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Monitor mode handling
|
||||
*/
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "drivers/uart.h"
|
||||
#include "drivers/systick.h"
|
||||
#include "terminal.h"
|
||||
#include "kiss.h"
|
||||
/* USER CODE END INCLUDE */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
|
@ -274,6 +275,7 @@ static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
|
|||
for(uint16_t i = 0; i < *Len; i++)
|
||||
{
|
||||
UartUsb.rxBuffer[UartUsb.rxBufferHead++] = Buf[i];
|
||||
KissParse(&UartUsb, Buf[i]);
|
||||
UartUsb.rxBufferHead %= UART_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
|
@ -322,20 +324,11 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
|
|||
/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
|
||||
static void handleUsbInterrupt(Uart *port)
|
||||
{
|
||||
if(port->mode == MODE_KISS)
|
||||
port->kissTimer = SysTickGet() + (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
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
# This is an NUCLEO-F103RB board with a single STM32F103RBTx chip
|
||||
#
|
||||
# Generated by System Workbench for STM32
|
||||
# Take care that such file, as generated, may be overridden without any early notice. Please have a look to debug launch configuration setup(s)
|
||||
|
||||
source [find interface/stlink.cfg]
|
||||
|
||||
set WORKAREASIZE 0x5000
|
||||
|
||||
transport select "hla_swd"
|
||||
|
||||
set CHIPNAME STM32F103RBTx
|
||||
set BOARDNAME NUCLEO-F103RB
|
||||
|
||||
# CHIPNAMES state
|
||||
set CHIPNAME_CPU0_ACTIVATED 1
|
||||
|
||||
# Enable debug when in low power modes
|
||||
set ENABLE_LOW_POWER 1
|
||||
|
||||
# Stop Watchdog counters when halt
|
||||
set STOP_WATCHDOG 1
|
||||
|
||||
# STlink Debug clock frequency
|
||||
set CLOCK_FREQ 4000
|
||||
|
||||
# use software system reset
|
||||
reset_config none
|
||||
set CONNECT_UNDER_RESET 0
|
||||
|
||||
# BCTM CPU variables
|
||||
|
||||
|
||||
|
||||
source [find target/stm32f1x.cfg]
|
|
@ -1,35 +0,0 @@
|
|||
# This is an NUCLEO-F103RB board with a single STM32F103RBTx chip
|
||||
#
|
||||
# Generated by System Workbench for STM32
|
||||
# Take care that such file, as generated, may be overridden without any early notice. Please have a look to debug launch configuration setup(s)
|
||||
|
||||
source [find interface/stlink.cfg]
|
||||
|
||||
set WORKAREASIZE 0x5000
|
||||
|
||||
transport select "hla_swd"
|
||||
|
||||
set CHIPNAME STM32F103RBTx
|
||||
set BOARDNAME NUCLEO-F103RB
|
||||
|
||||
# CHIPNAMES state
|
||||
set CHIPNAME_CPU0_ACTIVATED 1
|
||||
|
||||
# Enable debug when in low power modes
|
||||
set ENABLE_LOW_POWER 1
|
||||
|
||||
# Stop Watchdog counters when halt
|
||||
set STOP_WATCHDOG 1
|
||||
|
||||
# STlink Debug clock frequency
|
||||
set CLOCK_FREQ 4000
|
||||
|
||||
# use software system reset
|
||||
reset_config none
|
||||
set CONNECT_UNDER_RESET 0
|
||||
|
||||
# BCTM CPU variables
|
||||
|
||||
|
||||
|
||||
source [find target/stm32f1x.cfg]
|
Ładowanie…
Reference in New Issue