@ -41,65 +41,36 @@ along with VP-Digi. If not, see <http://www.gnu.org/licenses/>.
# define DCD_INC 7
# define DCD_INC 7
# define DCD_PLLTUNE 0
# 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 PLLINC 536870912 / / PLL tick increment value
# define PLLLOCKED 0.74 / / PLL adjustment value when locked
# define PLLLOCKED 0.74 / / PLL adjustment value when locked
# define PLLNOTLOCKED 0.50 / / PLL adjustment value when not locked
# define PLLNOTLOCKED 0.50 / / PLL adjustment value when not locked
# define PTT_ON GPIOB->BSRR = GPIO_BSRR_BS7
# define PTT_ON GPIOB->BSRR = GPIO_BSRR_BS7
# define PTT_OFF GPIOB->BSRR = GPIO_BSRR_BR7
# define PTT_OFF GPIOB->BSRR = GPIO_BSRR_BR7
# define DCD_ON (GPIOC->BSRR = GPIO_BSRR_BR13)
# define DCD_ON (GPIOC->BSRR = GPIO_BSRR_BR13)
# define DCD_OFF (GPIOC->BSRR = GPIO_BSRR_BS13)
# 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 )
* @ 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 ,
728 ,
- 13418 ,
- 13418 ,
- 554 ,
- 554 ,
@ -113,7 +84,8 @@ const int16_t bpf1200[8] = {
/**
/**
* @ brief BPF filter with 2200 Hz tone 6 dB deemphasis
* @ brief BPF filter with 2200 Hz tone 6 dB deemphasis
*/
*/
const int16_t bpf1200inv [ 8 ] = {
static const int16_t invBpfCoeffs [ 8 ] =
{
- 10513 ,
- 10513 ,
- 10854 ,
- 10854 ,
9589 ,
9589 ,
@ -124,11 +96,15 @@ const int16_t bpf1200inv[8] = {
- 879
- 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
* @ 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
* 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 ,
- 6128 ,
- 5974 ,
- 5974 ,
- 2503 ,
- 2503 ,
@ -146,54 +122,70 @@ const int16_t lpf1200[15] = {
- 6128
- 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 setP tt( uint8_t state ) ;
uint8_t Afsk_dcdState ( void )
uint8_t ModemD cdState( void )
{
{
return dcd ;
return dcd ;
}
}
uint8_t Afsk_isTxTestOngoing ( void )
uint8_t ModemI sTxTestOngoing( void )
{
{
if ( modState . txTestState ! = TEST_DISABLED )
if ( txTestState ! = TEST_DISABLED )
return 1 ;
return 1 ;
return 0 ;
return 0 ;
}
}
void Afsk_clearRMS ( uint8_t modemNo )
void ModemC learRMS( 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_g etRMS( 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
* @ brief Set DCD LED
* @ param [ in ] state 0 - OFF , 1 - ON
* @ param [ in ] state 0 - OFF , 1 - ON
*/
*/
static void afsk_d cd( uint8_t state )
static void setD cd( uint8_t state )
{
{
if ( state )
if ( state )
{
{
@ -219,33 +211,33 @@ void DMA1_Channel2_IRQHandler(void)
{
{
DMA1 - > IFCR | = DMA_IFCR_CTCIF2 ;
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 ( partialD cd) / / DCD on any of the demodulators
{
{
dcd = 1 ;
dcd = 1 ;
afsk_dcd ( 1 ) ;
setD cd( 1 ) ;
}
}
else if ( ( demod1 . dcd = = 0 ) & & ( demod2 . dcd = = 0 ) ) / / no DCD on both demodulators
else / / no DCD on both demodulators
{
{
dcd = 0 ;
dcd = 0 ;
afsk_d cd( 0 ) ;
setD cd( 0 ) ;
}
}
}
}
}
}
/**
/**
* @ brief ISR for pushing DAC samples
* @ brief ISR for pushing DAC samples
*/
*/
@ -254,19 +246,18 @@ void TIM1_UP_IRQHandler(void)
{
{
TIM1 - > SR & = ~ TIM_SR_UIF ;
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
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 ;
TIM3 - > SR & = ~ TIM_SR_UIF ;
if ( modState . txTestState = = TEST_DISABLED ) / / transmitting normal data
if ( txTestState = = TEST_DISABLED ) / / transmitting normal data
{
{
if ( Ax25_g etTxBit ( ) = = 0 ) / / get next bit and check if it ' s 0
if ( Ax25G etTxBit ( ) = = 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
/ / if 1 , no symbol change
}
}
else / / transmit test mode
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
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
* @ param [ in ] * dem Demodulator state
* @ return Current tone ( 0 or 1 )
* @ 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 - > RMSenergy + = ( ( sample > > 1 ) * ( sample > > 1 ) ) ; / / square the sample and add it to the sum
dem - > RMSsampleCount + + ; / / increment number of samples
dem - > RMSsampleCount + + ; / / increment number of samples
if ( dem - > emphasis ! = EMPHASIS_NONE ) / / preemphasis / deemphasis is used
if ( dem - > emphasis ! = EMPHASIS_NONE ) / / preemphasis / deemphasis is used
{
{
int32_t out = 0 ; / / filtered output
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 [ i ] = dem - > rawSample [ i - 1 ] ; / / shift old samples
dem - > rawSample [ 0 ] = sample ; / / store new sample
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 )
if ( dem - > emphasis = = PREEMPHASIS )
out + = bpf1200 [ i ] * dem - > rawSample [ i ] ; / / use preemphasis
out + = bpfCoeffs [ i ] * dem - > rawSample [ i ] ; / / use preemphasis
else
else
out + = bpf1200 inv[ i ] * dem - > rawSample [ i ] ; / / use deemphasis
out + = invBpfCoeffs [ i ] * dem - > rawSample [ i ] ; / / use deemphasis
}
}
dem - > rxSample [ dem - > rxSampleIdx ] = ( out > > 15 ) ; / / store filtered sample
dem - > rxSample [ dem - > rxSampleIdx ] = ( out > > 15 ) ; / / store filtered sample
}
}
else / / no pre / deemphasis
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
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 ;
uint64_t hi = 0 , lo = 0 ;
hi = ( ( outHiI > > 12 ) * ( outHiI > > 12 ) ) + ( ( outHiQ > > 12 ) * ( outHiQ > > 12 ) ) ; / / calculate output tone levels
hi = ( ( outHiI > > 12 ) * ( outHiI > > 12 ) ) + ( ( outHiQ > > 12 ) * ( outHiQ > > 12 ) ) ; / / calculate output tone levels
lo = ( ( outLoI > > 12 ) * ( outLoI > > 12 ) ) + ( ( outLoQ > > 12 ) * ( outLoQ > > 12 ) ) ;
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
dem - > dcdLastSymbol = dcdSymbol ; / / store last symbol for symbol change detection
if ( dem - > dcdCounter > DCD_MAXPULSE ) / / maximum DCD counter value reached
if ( dem - > dcdCounter > DCD_MAXPULSE ) / / maximum DCD counter value reached
dem - > dcdCounter = DCD_MAXPULSE ; / / avoid " sticky " DCD and counter overflow
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
/ / filter out signal faster than 1200 baud
int64_t out = 0 ;
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 [ i ] = dem - > lpfSample [ i - 1 ] ;
dem - > lpfSample [ 0 ] = ( int64_t ) hi - ( int64_t ) lo ;
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 ;
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
* @ brief Decode received symbol : bit recovery , NRZI decoding and pass the decoded bit to higher level protocol
* @ param [ in ] symbol Received symbol
* @ 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
/ / This function provides bit / clock recovery and NRZI decoding
/ / Bit recovery is based on PLL which is described in the function above ( DCD PLL )
/ / 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 ) ;
dem - > rawSymbols | = ( symbol & 1 ) ;
if ( ( dem - > pll < 0 ) & & ( dem - > lastPll > 0 ) ) / / PLL counter overflow , sample symbol , decode NRZI and process in higher layer
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
dem - > syncSymbols < < = 1 ; / / shift recovered ( received , synchronized ) bit register
@ -456,18 +433,18 @@ static void afsk_decode(uint8_t symbol, Demod *dem)
/ / NRZI decoding
/ / NRZI decoding
if ( ( ( dem - > syncSymbols & 0x03 ) = = 0 b11 ) | | ( ( dem - > syncSymbols & 0x03 ) = = 0 b00 ) ) / / two last symbols are the same - no symbol transition - decoded bit 1
if ( ( ( dem - > syncSymbols & 0x03 ) = = 0 b11 ) | | ( ( dem - > syncSymbols & 0x03 ) = = 0 b00 ) ) / / two last symbols are the same - no symbol transition - decoded bit 1
{
{
Ax25_b itParse ( 1 , ( dem = = & demod1 ) ? 0 : 1 ) ;
Ax25B itParse ( 1 , demo d ) ;
}
}
else / / symbol transition - decoded bit 0
else / / symbol transition - decoded bit 0
{
{
Ax25_b itParse ( 0 , ( dem = = & demod1 ) ? 0 : 1 ) ;
Ax25B itParse ( 0 , demo d ) ;
}
}
}
}
if ( ( ( dem - > rawSymbols & 0x03 ) = = 0 b10 ) | | ( ( dem - > rawSymbols & 0x03 ) = = 0 b01 ) ) / / if there was a symbol transition , adjust PLL
if ( ( ( dem - > rawSymbols & 0x03 ) = = 0 b10 ) | | ( ( dem - > rawSymbols & 0x03 ) = = 0 b01 ) ) / / if there was a symbol transition , adjust PLL
{
{
if ( Ax25_g etRxStage ( ( dem = = & demod1 ) ? 0 : 1 ) ! = RX_STAGE_FRAME ) / / not in a frame
if ( Ax25G etRxStage( demo d ) ! = RX_STAGE_FRAME ) / / not in a frame
{
{
dem - > pll = ( int ) ( dem - > pll * PLLNOTLOCKED ) ; / / adjust PLL faster
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_t xTestStop( ) ; / / stop this test
if ( txTestState ! = TEST_DISABLED ) / / TX test is already running
ModemTxTestStop ( ) ; / / stop this test
afsk_p tt( 1 ) ; / / PTT on
modState . txTestState = type ;
setP tt( 1 ) ; / / PTT on
txTestState = type ;
/ / DAC timer
/ / DAC timer
TIM1 - > PSC = 17 ; / / 72 / 18 = 4 MHz
TIM1 - > PSC = 17 ; / / 72 / 18 = 4 MHz
TIM1 - > DIER = TIM_DIER_UIE ; / / enable interrupt
TIM1 - > DIER = TIM_DIER_UIE ; / / enable interrupt
TIM1 - > CR1 | = TIM_CR1_CEN ; / / enable timer
TIM1 - > CR1 | = TIM_CR1_CEN ; / / enable timer
TIM2 - > CR1 & = ~ TIM_CR1_CEN ; / / disable RX timer
TIM2 - > CR1 & = ~ TIM_CR1_CEN ; / / disable RX timer
NVIC_DisableIRQ ( DMA1_Channel2_IRQn ) ; / / disable RX DMA interrupt
NVIC_DisableIRQ ( DMA1_Channel2_IRQn ) ; / / disable RX DMA interrupt
NVIC_EnableIRQ ( TIM1_UP_IRQn ) ; / / enable timer 1 for PWM
NVIC_EnableIRQ ( TIM1_UP_IRQn ) ; / / enable timer 1 for PWM
if ( type = = TEST_MARK )
if ( type = = TEST_MARK )
{
{
TIM1 - > ARR = modState . m arkFreq ;
TIM1 - > ARR = markFreq ;
} else if ( type = = TEST_SPACE )
} else if ( type = = TEST_SPACE )
{
{
TIM1 - > ARR = modState . spaceFreq ;
TIM1 - > ARR = spaceFreq ;
}
}
else / / alternating tones
else / / alternating tones
{
{
/ / enable baudrate generator
/ / enable baudrate generator
TIM3 - > PSC = 71 ; / / 72 / 72 = 1 MHz
TIM3 - > PSC = 71 ; / / 72 / 72 = 1 MHz
TIM3 - > DIER = TIM_DIER_UIE ; / / enable interrupt
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
TIM3 - > CR1 = TIM_CR1_CEN ; / / enable timer
NVIC_EnableIRQ ( TIM3_IRQn ) ; / / enable interrupt in NVIC
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
TIM3 - > CR1 & = ~ TIM_CR1_CEN ; / / turn off timers
TIM1 - > CR1 & = ~ TIM_CR1_CEN ;
TIM1 - > CR1 & = ~ TIM_CR1_CEN ;
@ -537,16 +507,13 @@ void Afsk_txTestStop(void)
NVIC_DisableIRQ ( TIM1_UP_IRQn ) ;
NVIC_DisableIRQ ( TIM1_UP_IRQn ) ;
NVIC_EnableIRQ ( DMA1_Channel2_IRQn ) ;
NVIC_EnableIRQ ( DMA1_Channel2_IRQn ) ;
afsk_p tt( 0 ) ; / / PTT off
setP tt( 0 ) ; / / PTT off
}
}
/**
* @ brief Configure and start TX
* @ warning Transmission should be started with Ax25_transmitBuffer
*/
void Afsk_transmitStart ( void )
void ModemTransmitStart ( void )
{
{
afsk_p tt( 1 ) ; / / PTT on
setPtt ( 1 ) ; / / PTT on
TIM1 - > PSC = 17 ;
TIM1 - > PSC = 17 ;
TIM1 - > DIER | = TIM_DIER_UIE ;
TIM1 - > DIER | = TIM_DIER_UIE ;
@ -554,7 +521,7 @@ void Afsk_transmitStart(void)
TIM3 - > PSC = 71 ;
TIM3 - > PSC = 71 ;
TIM3 - > DIER | = TIM_DIER_UIE ;
TIM3 - > DIER | = TIM_DIER_UIE ;
TIM3 - > ARR = modState . baudRate ;
TIM3 - > ARR = baudRate ;
TIM3 - > CR1 = TIM_CR1_CEN ;
TIM3 - > CR1 = TIM_CR1_CEN ;
TIM1 - > CR1 = TIM_CR1_CEN ;
TIM1 - > CR1 = TIM_CR1_CEN ;
@ -563,14 +530,13 @@ void Afsk_transmitStart(void)
NVIC_DisableIRQ ( DMA1_Channel2_IRQn ) ;
NVIC_DisableIRQ ( DMA1_Channel2_IRQn ) ;
NVIC_EnableIRQ ( TIM1_UP_IRQn ) ;
NVIC_EnableIRQ ( TIM1_UP_IRQn ) ;
NVIC_EnableIRQ ( TIM3_IRQn ) ;
NVIC_EnableIRQ ( TIM3_IRQn ) ;
}
}
/**
/**
* @ brief Stop TX and go back to RX
* @ brief Stop TX and go back to RX
*/
*/
void Afsk_t ransmitStop( void )
void ModemT ransmitStop( void )
{
{
TIM2 - > CR1 | = TIM_CR1_CEN ;
TIM2 - > CR1 | = TIM_CR1_CEN ;
@ -581,7 +547,7 @@ void Afsk_transmitStop(void)
NVIC_DisableIRQ ( TIM3_IRQn ) ;
NVIC_DisableIRQ ( TIM3_IRQn ) ;
NVIC_EnableIRQ ( DMA1_Channel2_IRQn ) ;
NVIC_EnableIRQ ( DMA1_Channel2_IRQn ) ;
afsk_p tt( 0 ) ;
setP tt( 0 ) ;
TIM4 - > CCR1 = 44 ; / / set around 50 % duty cycle
TIM4 - > CCR1 = 44 ; / / set around 50 % duty cycle
}
}
@ -590,7 +556,7 @@ void Afsk_transmitStop(void)
* @ brief Controls PTT output
* @ brief Controls PTT output
* @ param [ in ] state 0 - PTT off , 1 - PTT on
* @ param [ in ] state 0 - PTT off , 1 - PTT on
*/
*/
static void afsk_p tt( uint8_t state )
static void setP tt( uint8_t state )
{
{
if ( state )
if ( state )
PTT_ON ;
PTT_ON ;
@ -603,11 +569,11 @@ static void afsk_ptt(uint8_t state)
/**
/**
* @ brief Initialize AFSK module
* @ brief Initialize AFSK module
*/
*/
void Afsk_i nit( void )
void ModemI nit( 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
* TIM4 is the PWM generator with no software interrupt
* TIM2 is the RX sampling timer with no software interrupt , but it directly calls DMA
* 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 ;
RCC - > AHBENR | = RCC_AHBENR_DMA1EN ;
GPIOC - > CRH | = GPIO_CRH_MODE13_1 ; / / DCD LED on PC13
GPIOC - > CRH | = GPIO_CRH_MODE13_1 ; / / DCD LED on PC13
GPIOC - > CRH & = ~ GPIO_CRH_MODE13_0 ;
GPIOC - > CRH & = ~ GPIO_CRH_MODE13_0 ;
GPIOC - > CRH & = ~ GPIO_CRH_CNF13 ;
GPIOC - > CRH & = ~ GPIO_CRH_CNF13 ;
GPIOB - > CRH & = ~ 429490176 0; / / R2R output on PB12 - PB15
GPIOB - > CRH | = 572653568 ;
GPIOB - > CRH & = ~ 0xFFFF000 0; / / R2R output on PB12 - PB15
GPIOB - > CRH | = 0x22220000 ;
GPIOA - > CRL & = ~ GPIO_CRL_CNF0 ; / / ADC input on PA0
GPIOA - > CRL & = ~ GPIO_CRL_CNF0 ; / / ADC input on PA0
GPIOA - > CRL & = ~ GPIO_CRL_MODE0 ;
GPIOA - > CRL & = ~ GPIO_CRL_MODE0 ;
@ -654,9 +619,11 @@ void Afsk_init(void)
ADC1 - > CR2 | = ADC_CR2_ADON ; / / ADC on
ADC1 - > CR2 | = ADC_CR2_ADON ; / / ADC on
ADC1 - > CR2 | = ADC_CR2_RSTCAL ; / / calibrate ADC
ADC1 - > CR2 | = ADC_CR2_RSTCAL ; / / calibrate ADC
while ( ADC1 - > CR2 & ADC_CR2_RSTCAL ) ;
while ( ADC1 - > CR2 & ADC_CR2_RSTCAL )
;
ADC1 - > CR2 | = ADC_CR2_CAL ;
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_EXTTRIG ;
ADC1 - > CR2 | = ADC_CR2_SWSTART ; / / start ADC conversion
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 - > CCR | = DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_TCIE ; / / circular mode , memory increment and interrupt
DMA1_Channel2 - > CNDTR = 4 ; / / 4 samples
DMA1_Channel2 - > CNDTR = 4 ; / / 4 samples
DMA1_Channel2 - > CPAR = ( uint32_t ) & ( ADC1 - > DR ) ; / / ADC data register address
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
DMA1_Channel2 - > CCR | = DMA_CCR_EN ; / / enable DMA
NVIC_EnableIRQ ( DMA1_Channel2_IRQn ) ;
NVIC_EnableIRQ ( DMA1_Channel2_IRQn ) ;
@ -680,42 +647,39 @@ void Afsk_init(void)
TIM2 - > ARR = 103 ; / / 4 MHz / 104 = ~ 38400 Hz ( 4 * 9600 Hz for 4 x oversampling )
TIM2 - > ARR = 103 ; / / 4 MHz / 104 = ~ 38400 Hz ( 4 * 9600 Hz for 4 x oversampling )
TIM2 - > CR1 | = TIM_CR1_CEN ; / / enable timer
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_FREQUE NCY / MODEM_BAUDRATE ) ;
coeffLoQ [ i ] = 4095.f * sinf ( 2.f * 3.1416f * ( float ) i / ( float ) N * MODEM_MARK_FREQUE NCY / 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 ( afskCf g. usePWM )
modState . dacSine [ i ] = ( ( sinf ( 2.f * 3.1416f * ( float ) i / ( float ) DACSINELEN ) + 1.f ) * 45.f ) ;
if ( ModemConfi g. usePWM )
dacSine [ i ] = ( ( sinf ( 2.f * 3.1416f * ( float ) i / ( float ) DAC_SINE_SIZE ) + 1.f ) * 45.f ) ;
else
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 ( afskCf g. flatAudioIn ) / / when used with flat audio input , use deemphasis and flat modems
if ( ModemConfi g. 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
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 ( afskCf g. usePWM )
if ( ModemConfi g. usePWM )
{
{
RCC - > APB1ENR | = RCC_APB1ENR_TIM4EN ; / / configure timer
RCC - > APB1ENR | = RCC_APB1ENR_TIM4EN ; / / configure timer