Code complete, but untested.

This commit is contained in:
Jonathan Naylor 2020-06-11 10:02:11 +01:00
parent 121c76f3d8
commit c2959466fd
5 changed files with 131 additions and 12 deletions

View File

@ -53,6 +53,7 @@ const uint32_t PLL_FILTER_LEN = 7U;
float32_t PLL_FILTER_COEFFS[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F}; float32_t PLL_FILTER_COEFFS[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F};
CAX25Demodulator::CAX25Demodulator(float32_t* coeffs, uint16_t length) : CAX25Demodulator::CAX25Demodulator(float32_t* coeffs, uint16_t length) :
m_frame(),
m_audioFilter(), m_audioFilter(),
m_audioState(), m_audioState(),
m_lpfFilter(), m_lpfFilter(),
@ -64,7 +65,12 @@ m_pllFilter(),
m_pllState(), m_pllState(),
m_pllLast(false), m_pllLast(false),
m_pllBits(1U), m_pllBits(1U),
m_pllCount(0.0F) m_pllCount(0.0F),
m_hdlcOnes(0U),
m_hdlcFlag(false),
m_hdlcBuffer(0U),
m_hdlcBits(0U),
m_hdlcState(AX25_IDLE)
{ {
m_delayLine = new bool[2U * DELAY_LEN]; m_delayLine = new bool[2U * DELAY_LEN];
@ -110,10 +116,17 @@ bool CAX25Demodulator::process(const q15_t* samples, uint8_t length, CAX25Frame&
if (sample) { if (sample) {
// We will only ever get one frame because there are // We will only ever get one frame because there are
// not enough bits in a block for more than one. // not enough bits in a block for more than one.
if (result) if (result) {
hdlc_decoder_(NRZI(bit), true); HDLC(NRZI(bit));
else } else {
result = hdlc_decoder_(NRZI(bit), true); result = HDLC(NRZI(bit));
if (result) {
::memcpy(frame.m_data, m_frame.m_data, AX25_MAX_PACKET_LEN);
frame.m_length = frame.m_length;
frame.m_fcs = m_frame.m_fcs;
m_frame.m_length = 0U;
}
}
} }
} }
@ -171,3 +184,83 @@ bool CAX25Demodulator::PLL(bool input)
return sample; return sample;
} }
bool CAX25Demodulator::HDLC(bool b)
{
bool result = false;
if (m_hdlcOnes == 5U) {
if (b) {
// flag byte
m_hdlcFlag = true;
} else {
// bit stuffing...
m_hdlcFlag = false;
m_hdlcOnes = 0U;
return result;
}
}
m_hdlcBuffer >>= 1;
m_hdlcBuffer |= b ? 128U : 0U;
m_hdlcBits++; // Free-running until Sync byte.
if (b)
m_hdlcOnes++;
else
m_hdlcOnes = 0U;
if (m_hdlcFlag) {
switch (m_hdlcBuffer) {
case 0x7E:
if (m_frame.m_length > 0U) {
result = m_frame.checkCRC();
if (!result)
m_frame.m_length = 0U;
}
m_hdlcState = AX25_SYNC;
m_hdlcFlag = false;
m_hdlcBits = 0U;
break;
case 0xFE:
// Frame aborted
m_frame.m_length = 0U;
m_hdlcState = AX25_IDLE;
m_hdlcFlag = false;
m_hdlcBits = 0U;
break;
default:
break;
}
return result;
}
switch (m_hdlcState) {
case AX25_IDLE:
break;
case AX25_SYNC:
if (m_hdlcBits == 8U) { // 8th bit.
// Start of frame data.
m_hdlcState = AX25_RECEIVE;
m_frame.append(m_hdlcBuffer);
m_hdlcBits = 0U;
}
break;
case AX25_RECEIVE:
if (m_hdlcBits == 8U) { // 8th bit.
m_frame.append(m_hdlcBuffer);
m_hdlcBits = 0U;
}
break;
default:
break;
}
return result;
}

View File

@ -23,6 +23,11 @@
#include "AX25Frame.h" #include "AX25Frame.h"
enum AX25_STATE {
AX25_IDLE,
AX25_SYNC,
AX25_RECEIVE
};
class CAX25Demodulator { class CAX25Demodulator {
public: public:
@ -31,6 +36,7 @@ public:
bool process(const q15_t* samples, uint8_t length, CAX25Frame& frame); bool process(const q15_t* samples, uint8_t length, CAX25Frame& frame);
private: private:
CAX25Frame m_frame;
arm_fir_instance_f32 m_audioFilter; arm_fir_instance_f32 m_audioFilter;
float32_t m_audioState[20U]; float32_t m_audioState[20U];
arm_fir_instance_q15 m_lpfFilter; arm_fir_instance_q15 m_lpfFilter;
@ -43,10 +49,16 @@ private:
bool m_pllLast; bool m_pllLast;
uint8_t m_pllBits; uint8_t m_pllBits;
float32_t m_pllCount; float32_t m_pllCount;
uint16_t m_hdlcOnes;
bool m_hdlcFlag;
uint16_t m_hdlcBuffer;
uint16_t m_hdlcBits;
AX25_STATE m_hdlcState;
bool delay(bool b); bool delay(bool b);
bool NRZI(bool b); bool NRZI(bool b);
bool PLL(bool b); bool PLL(bool b);
bool HDLC(bool b);
}; };
#endif #endif

View File

@ -61,6 +61,16 @@ m_fcs(0U)
{ {
} }
bool CAX25Frame::append(uint16_t c)
{
if (m_length == AX25_MAX_PACKET_LEN)
return false;
m_data[m_length++] = uint8_t(c);
return true;
}
bool CAX25Frame::checkCRC() bool CAX25Frame::checkCRC()
{ {
union { union {

View File

@ -21,13 +21,17 @@
#include "Config.h" #include "Config.h"
const uint16_t AX25_MAX_PACKET_LEN = 300U;
class CAX25Frame { class CAX25Frame {
public: public:
CAX25Frame(); CAX25Frame();
bool append(uint16_t c);
bool checkCRC(); bool checkCRC();
uint8_t m_data[300U]; uint8_t m_data[AX25_MAX_PACKET_LEN];
uint16_t m_length; uint16_t m_length;
uint16_t m_fcs; uint16_t m_fcs;
}; };

View File

@ -114,29 +114,29 @@ void CAX25RX::samples(q15_t* samples, uint8_t length)
CAX25Frame frame; CAX25Frame frame;
bool ret = m_demod1.process(output, length, frame); bool ret = m_demod1.process(output, length, frame);
if (ret) { if (ret && frame.m_length > 10U) {
if (m_lastFCS != frame.m_fcs) { if (m_lastFCS != frame.m_fcs) {
DEBUG1("Decoder 1 reported"); DEBUG1("Decoder 1 reported");
m_lastFCS = frame.m_fcs; m_lastFCS = frame.m_fcs;
serial.writeAX25Data(frame.m_data, frame.m_length); serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
} }
} }
ret = m_demod2.process(output, length, frame); ret = m_demod2.process(output, length, frame);
if (ret) { if (ret && frame.m_length > 10U) {
if (m_lastFCS != frame.m_fcs) { if (m_lastFCS != frame.m_fcs) {
DEBUG1("Decoder 2 reported"); DEBUG1("Decoder 2 reported");
m_lastFCS = frame.m_fcs; m_lastFCS = frame.m_fcs;
serial.writeAX25Data(frame.m_data, frame.m_length); serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
} }
} }
ret = m_demod3.process(output, length, frame); ret = m_demod3.process(output, length, frame);
if (ret) { if (ret && frame.m_length > 10U) {
if (m_lastFCS != frame.m_fcs) { if (m_lastFCS != frame.m_fcs) {
DEBUG1("Decoder 3 reported"); DEBUG1("Decoder 3 reported");
m_lastFCS = frame.m_fcs; m_lastFCS = frame.m_fcs;
serial.writeAX25Data(frame.m_data, frame.m_length); serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
} }
} }
} }