mirror of https://github.com/g4klx/MMDVM.git
Add RSSI reporting to FM and AX.25
This commit is contained in:
parent
7ef0d992d9
commit
3e079f58ad
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
* Copyright (C) 2020,2023 by Jonathan Naylor G4KLX
|
||||||
* Copyright 2015-2019 Mobilinkd LLC <rob@mobilinkd.com>
|
* Copyright 2015-2019 Mobilinkd LLC <rob@mobilinkd.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -85,7 +85,9 @@ m_hdlcOnes(0U),
|
||||||
m_hdlcFlag(false),
|
m_hdlcFlag(false),
|
||||||
m_hdlcBuffer(0U),
|
m_hdlcBuffer(0U),
|
||||||
m_hdlcBits(0U),
|
m_hdlcBits(0U),
|
||||||
m_hdlcState(AX25_IDLE)
|
m_hdlcState(AX25_IDLE),
|
||||||
|
m_rssiAccum(0U),
|
||||||
|
m_rssiCount(0U)
|
||||||
{
|
{
|
||||||
m_delayLine = new bool[DELAY_LEN];
|
m_delayLine = new bool[DELAY_LEN];
|
||||||
|
|
||||||
|
@ -101,7 +103,7 @@ m_hdlcState(AX25_IDLE)
|
||||||
m_iirHistory[i] = 0.0F;
|
m_iirHistory[i] = 0.0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame)
|
bool CAX25Demodulator::process(q15_t* samples, const uint16_t* rssi, uint8_t length, CAX25Frame& frame)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
|
@ -119,6 +121,9 @@ bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame
|
||||||
::arm_fir_fast_q15(&m_lpfFilter, buffer, fc, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_lpfFilter, buffer, fc, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < length; i++) {
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
m_rssiAccum += rssi[i];
|
||||||
|
m_rssiCount++;
|
||||||
|
|
||||||
bool bit = fc[i] >= 0;
|
bool bit = fc[i] >= 0;
|
||||||
bool sample = PLL(bit);
|
bool sample = PLL(bit);
|
||||||
|
|
||||||
|
@ -266,6 +271,8 @@ bool CAX25Demodulator::HDLC(bool b)
|
||||||
// Start of frame data.
|
// Start of frame data.
|
||||||
m_hdlcState = AX25_RECEIVE;
|
m_hdlcState = AX25_RECEIVE;
|
||||||
m_frame.append(m_hdlcBuffer);
|
m_frame.append(m_hdlcBuffer);
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
m_hdlcBits = 0U;
|
m_hdlcBits = 0U;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -315,5 +322,19 @@ float32_t CAX25Demodulator::iir(float32_t input)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t CAX25Demodulator::getRSSI()
|
||||||
|
{
|
||||||
|
if (m_rssiCount > 0U) {
|
||||||
|
uint16_t rssi = m_rssiAccum / m_rssiCount;
|
||||||
|
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
|
||||||
|
return rssi;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
* Copyright (C) 2020,2023 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -36,12 +36,14 @@ class CAX25Demodulator {
|
||||||
public:
|
public:
|
||||||
CAX25Demodulator(int8_t n);
|
CAX25Demodulator(int8_t n);
|
||||||
|
|
||||||
bool process(q15_t* samples, uint8_t length, CAX25Frame& frame);
|
bool process(q15_t* samples, const uint16_t* rssi, uint8_t length, CAX25Frame& frame);
|
||||||
|
|
||||||
void setTwist(int8_t n);
|
void setTwist(int8_t n);
|
||||||
|
|
||||||
bool isDCD();
|
bool isDCD();
|
||||||
|
|
||||||
|
uint16_t getRSSI();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CAX25Frame m_frame;
|
CAX25Frame m_frame;
|
||||||
CAX25Twist m_twist;
|
CAX25Twist m_twist;
|
||||||
|
@ -63,6 +65,8 @@ private:
|
||||||
uint16_t m_hdlcBuffer;
|
uint16_t m_hdlcBuffer;
|
||||||
uint16_t m_hdlcBits;
|
uint16_t m_hdlcBits;
|
||||||
AX25_STATE m_hdlcState;
|
AX25_STATE m_hdlcState;
|
||||||
|
uint32_t m_rssiAccum;
|
||||||
|
uint16_t m_rssiCount;
|
||||||
|
|
||||||
bool delay(bool b);
|
bool delay(bool b);
|
||||||
bool NRZI(bool b);
|
bool NRZI(bool b);
|
||||||
|
|
34
AX25RX.cpp
34
AX25RX.cpp
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
* Copyright (C) 2020,2023 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -86,7 +86,7 @@ m_c(0xF6U)
|
||||||
initRand();
|
initRand();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAX25RX::samples(q15_t* samples, uint8_t length)
|
void CAX25RX::samples(q15_t* samples, const uint16_t* rssi, uint8_t length)
|
||||||
{
|
{
|
||||||
q15_t output[RX_BLOCK_SIZE];
|
q15_t output[RX_BLOCK_SIZE];
|
||||||
::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE);
|
||||||
|
@ -95,32 +95,56 @@ 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, rssi, length, frame);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
||||||
m_lastFCS = frame.m_fcs;
|
m_lastFCS = frame.m_fcs;
|
||||||
m_count = 0U;
|
m_count = 0U;
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
uint16_t rssi = m_demod1.getRSSI();
|
||||||
|
if (rssi > 0U)
|
||||||
|
serial.writeAX25DataEx(rssi, frame.m_data, frame.m_length - 2U);
|
||||||
|
else
|
||||||
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
#else
|
||||||
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
DEBUG1("Decoder 1 reported");
|
DEBUG1("Decoder 1 reported");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = m_demod2.process(output, length, frame);
|
ret = m_demod2.process(output, rssi, length, frame);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
||||||
m_lastFCS = frame.m_fcs;
|
m_lastFCS = frame.m_fcs;
|
||||||
m_count = 0U;
|
m_count = 0U;
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
uint16_t rssi = m_demod2.getRSSI();
|
||||||
|
if (rssi > 0U)
|
||||||
|
serial.writeAX25DataEx(rssi, frame.m_data, frame.m_length - 2U);
|
||||||
|
else
|
||||||
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
#else
|
||||||
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
DEBUG1("Decoder 2 reported");
|
DEBUG1("Decoder 2 reported");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = m_demod3.process(output, length, frame);
|
ret = m_demod3.process(output, rssi, length, frame);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
||||||
m_lastFCS = frame.m_fcs;
|
m_lastFCS = frame.m_fcs;
|
||||||
m_count = 0U;
|
m_count = 0U;
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
uint16_t rssi = m_demod3.getRSSI();
|
||||||
|
if (rssi > 0U)
|
||||||
|
serial.writeAX25DataEx(rssi, frame.m_data, frame.m_length - 2U);
|
||||||
|
else
|
||||||
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
#else
|
||||||
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
DEBUG1("Decoder 3 reported");
|
DEBUG1("Decoder 3 reported");
|
||||||
}
|
}
|
||||||
|
|
4
AX25RX.h
4
AX25RX.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
* Copyright (C) 2020,2023 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -29,7 +29,7 @@ class CAX25RX {
|
||||||
public:
|
public:
|
||||||
CAX25RX();
|
CAX25RX();
|
||||||
|
|
||||||
void samples(q15_t* samples, uint8_t length);
|
void samples(q15_t* samples, const uint16_t* rssi, uint8_t length);
|
||||||
|
|
||||||
void setParams(int8_t twist, uint8_t slotTime, uint8_t pPersist);
|
void setParams(int8_t twist, uint8_t slotTime, uint8_t pPersist);
|
||||||
|
|
||||||
|
|
37
FM.cpp
37
FM.cpp
|
@ -80,22 +80,24 @@ m_inputRFRB(2401U), // 100ms of audio + 1 sample
|
||||||
m_outputRFRB(2400U), // 100ms of audio
|
m_outputRFRB(2400U), // 100ms of audio
|
||||||
m_inputExtRB(),
|
m_inputExtRB(),
|
||||||
m_rfSignal(false),
|
m_rfSignal(false),
|
||||||
m_extSignal(false)
|
m_extSignal(false),
|
||||||
|
m_rssiAccum(0U),
|
||||||
|
m_rssiCount(0U)
|
||||||
{
|
{
|
||||||
m_reverseTimer.setTimeout(0U, 150U);
|
m_reverseTimer.setTimeout(0U, 150U);
|
||||||
|
|
||||||
insertDelay(100U);
|
insertDelay(100U);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::samples(bool cos, q15_t* samples, uint8_t length)
|
void CFM::samples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length)
|
||||||
{
|
{
|
||||||
if (m_linkMode)
|
if (m_linkMode)
|
||||||
linkSamples(cos, samples, length);
|
linkSamples(cos, samples, length);
|
||||||
else
|
else
|
||||||
repeaterSamples(cos, samples, length);
|
repeaterSamples(cos, samples, rssi, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::repeaterSamples(bool cos, q15_t* samples, uint8_t length)
|
void CFM::repeaterSamples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length)
|
||||||
{
|
{
|
||||||
if (m_cosInvert)
|
if (m_cosInvert)
|
||||||
cos = !cos;
|
cos = !cos;
|
||||||
|
@ -104,6 +106,11 @@ void CFM::repeaterSamples(bool cos, q15_t* samples, uint8_t length)
|
||||||
|
|
||||||
uint8_t i = 0U;
|
uint8_t i = 0U;
|
||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
|
if (m_state == FS_RELAYING_RF) {
|
||||||
|
m_rssiAccum += rssi[i];
|
||||||
|
m_rssiCount++;
|
||||||
|
}
|
||||||
|
|
||||||
// ARMv7-M has hardware integer division
|
// ARMv7-M has hardware integer division
|
||||||
q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel);
|
q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel);
|
||||||
|
|
||||||
|
@ -613,6 +620,9 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
|
||||||
m_state = FS_RELAYING_RF;
|
m_state = FS_RELAYING_RF;
|
||||||
serial.writeFMStatus(m_state);
|
serial.writeFMStatus(m_state);
|
||||||
|
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
|
||||||
if (m_callsignAtStart)
|
if (m_callsignAtStart)
|
||||||
sendCallsign();
|
sendCallsign();
|
||||||
}
|
}
|
||||||
|
@ -689,6 +699,9 @@ void CFM::kerchunkRFStateDuplex(bool validSignal)
|
||||||
m_state = FS_RELAYING_RF;
|
m_state = FS_RELAYING_RF;
|
||||||
serial.writeFMStatus(m_state);
|
serial.writeFMStatus(m_state);
|
||||||
|
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
|
||||||
m_kerchunkTimer.stop();
|
m_kerchunkTimer.stop();
|
||||||
if (m_callsignAtStart && m_callsignAtLatch) {
|
if (m_callsignAtStart && m_callsignAtLatch) {
|
||||||
sendCallsign();
|
sendCallsign();
|
||||||
|
@ -716,6 +729,16 @@ void CFM::kerchunkRFStateDuplex(bool validSignal)
|
||||||
void CFM::relayingRFStateDuplex(bool validSignal)
|
void CFM::relayingRFStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
if (m_rssiCount >= 24000U) {
|
||||||
|
uint16_t rssi = m_rssiAccum / m_rssiCount;
|
||||||
|
serial.writeFMRSSI(rssi);
|
||||||
|
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
||||||
DEBUG1("State to TIMEOUT_RF");
|
DEBUG1("State to TIMEOUT_RF");
|
||||||
m_state = FS_TIMEOUT_RF;
|
m_state = FS_TIMEOUT_RF;
|
||||||
|
@ -786,6 +809,9 @@ void CFM::relayingRFWaitStateDuplex(bool validSignal)
|
||||||
m_state = FS_RELAYING_RF;
|
m_state = FS_RELAYING_RF;
|
||||||
serial.writeFMStatus(m_state);
|
serial.writeFMStatus(m_state);
|
||||||
|
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
|
||||||
m_ackDelayTimer.stop();
|
m_ackDelayTimer.stop();
|
||||||
} else {
|
} else {
|
||||||
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
|
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
|
||||||
|
@ -977,6 +1003,9 @@ void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal)
|
||||||
m_state = FS_RELAYING_RF;
|
m_state = FS_RELAYING_RF;
|
||||||
serial.writeFMStatus(m_state);
|
serial.writeFMStatus(m_state);
|
||||||
|
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
|
||||||
DEBUG1("Stop ack");
|
DEBUG1("Stop ack");
|
||||||
m_rfAck.stop();
|
m_rfAck.stop();
|
||||||
m_extAck.stop();
|
m_extAck.stop();
|
||||||
|
|
6
FM.h
6
FM.h
|
@ -40,7 +40,7 @@ class CFM {
|
||||||
public:
|
public:
|
||||||
CFM();
|
CFM();
|
||||||
|
|
||||||
void samples(bool cos, q15_t* samples, uint8_t length);
|
void samples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
|
@ -94,10 +94,12 @@ private:
|
||||||
CFMUpSampler m_inputExtRB;
|
CFMUpSampler m_inputExtRB;
|
||||||
bool m_rfSignal;
|
bool m_rfSignal;
|
||||||
bool m_extSignal;
|
bool m_extSignal;
|
||||||
|
uint32_t m_rssiAccum;
|
||||||
|
uint16_t m_rssiCount;
|
||||||
|
|
||||||
void stateMachine(bool validRFSignal, bool validExtSignal);
|
void stateMachine(bool validRFSignal, bool validExtSignal);
|
||||||
|
|
||||||
void repeaterSamples(bool cos, q15_t* samples, uint8_t length);
|
void repeaterSamples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length);
|
||||||
void linkSamples(bool cos, q15_t* samples, uint8_t length);
|
void linkSamples(bool cos, q15_t* samples, uint8_t length);
|
||||||
|
|
||||||
void duplexStateMachine(bool validRFSignal, bool validExtSignal);
|
void duplexStateMachine(bool validRFSignal, bool validExtSignal);
|
||||||
|
|
18
IO.cpp
18
IO.cpp
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020,2021,2023 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
|
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
|
@ -506,9 +506,9 @@ void CIO::process()
|
||||||
if (m_fmEnable) {
|
if (m_fmEnable) {
|
||||||
bool cos = getCOSInt();
|
bool cos = getCOSInt();
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
|
fm.samples(cos, dcSamples, rssi, RX_BLOCK_SIZE);
|
||||||
#else
|
#else
|
||||||
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
fm.samples(cos, samples, rssi, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -516,9 +516,9 @@ void CIO::process()
|
||||||
#if defined(MODE_FM) && defined(MODE_AX25)
|
#if defined(MODE_FM) && defined(MODE_AX25)
|
||||||
if (m_ax25Enable) {
|
if (m_ax25Enable) {
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
|
ax25RX.samples(dcSamples, rssi, RX_BLOCK_SIZE);
|
||||||
#else
|
#else
|
||||||
ax25RX.samples(samples, RX_BLOCK_SIZE);
|
ax25RX.samples(samples, rssi, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -627,18 +627,18 @@ void CIO::process()
|
||||||
else if (m_modemState == STATE_FM) {
|
else if (m_modemState == STATE_FM) {
|
||||||
bool cos = getCOSInt();
|
bool cos = getCOSInt();
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
|
fm.samples(cos, dcSamples, rssi, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
#if defined(MODE_AX25)
|
#if defined(MODE_AX25)
|
||||||
if (m_ax25Enable)
|
if (m_ax25Enable)
|
||||||
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
|
ax25RX.samples(dcSamples, rssi, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
fm.samples(cos, samples, rssi, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
#if defined(MODE_AX25)
|
#if defined(MODE_AX25)
|
||||||
if (m_ax25Enable)
|
if (m_ax25Enable)
|
||||||
ax25RX.samples(samples, RX_BLOCK_SIZE);
|
ax25RX.samples(samples, rssi, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013,2015-2021 by Jonathan Naylor G4KLX
|
* Copyright (C) 2013,2015-2021,2023 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -72,6 +72,7 @@ const uint8_t MMDVM_M17_EOT = 0x49U;
|
||||||
const uint8_t MMDVM_POCSAG_DATA = 0x50U;
|
const uint8_t MMDVM_POCSAG_DATA = 0x50U;
|
||||||
|
|
||||||
const uint8_t MMDVM_AX25_DATA = 0x55U;
|
const uint8_t MMDVM_AX25_DATA = 0x55U;
|
||||||
|
const uint8_t MMDVM_AX25_DATA_EX = 0x56U;
|
||||||
|
|
||||||
const uint8_t MMDVM_FM_PARAMS1 = 0x60U;
|
const uint8_t MMDVM_FM_PARAMS1 = 0x60U;
|
||||||
const uint8_t MMDVM_FM_PARAMS2 = 0x61U;
|
const uint8_t MMDVM_FM_PARAMS2 = 0x61U;
|
||||||
|
@ -80,6 +81,7 @@ const uint8_t MMDVM_FM_PARAMS4 = 0x63U;
|
||||||
const uint8_t MMDVM_FM_DATA = 0x65U;
|
const uint8_t MMDVM_FM_DATA = 0x65U;
|
||||||
const uint8_t MMDVM_FM_STATUS = 0x66U;
|
const uint8_t MMDVM_FM_STATUS = 0x66U;
|
||||||
const uint8_t MMDVM_FM_EOT = 0x67U;
|
const uint8_t MMDVM_FM_EOT = 0x67U;
|
||||||
|
const uint8_t MMDVM_FM_RSSI = 0x68U;
|
||||||
|
|
||||||
const uint8_t MMDVM_ACK = 0x70U;
|
const uint8_t MMDVM_ACK = 0x70U;
|
||||||
const uint8_t MMDVM_NAK = 0x7FU;
|
const uint8_t MMDVM_NAK = 0x7FU;
|
||||||
|
@ -1838,6 +1840,25 @@ void CSerialPort::writeFMStatus(uint8_t status)
|
||||||
writeInt(1U, reply, 4U);
|
writeInt(1U, reply, 4U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSerialPort::writeFMRSSI(uint16_t rssi)
|
||||||
|
{
|
||||||
|
if (m_modemState != STATE_FM && m_modemState != STATE_IDLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_fmEnable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t reply[10U];
|
||||||
|
|
||||||
|
reply[0U] = MMDVM_FRAME_START;
|
||||||
|
reply[1U] = 5U;
|
||||||
|
reply[2U] = MMDVM_FM_RSSI;
|
||||||
|
reply[3U] = (rssi >> 8) & 0xFFU;
|
||||||
|
reply[4U] = (rssi >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
writeInt(1U, reply, 5U);
|
||||||
|
}
|
||||||
|
|
||||||
void CSerialPort::writeFMEOT()
|
void CSerialPort::writeFMEOT()
|
||||||
{
|
{
|
||||||
if (m_modemState != STATE_FM && m_modemState != STATE_IDLE)
|
if (m_modemState != STATE_FM && m_modemState != STATE_IDLE)
|
||||||
|
@ -1888,6 +1909,44 @@ void CSerialPort::writeAX25Data(const uint8_t* data, uint16_t length)
|
||||||
writeInt(1U, reply, length + 3U);
|
writeInt(1U, reply, length + 3U);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSerialPort::writeAX25DataEx(uint16_t rssi, const uint8_t* data, uint16_t length)
|
||||||
|
{
|
||||||
|
if (m_modemState != STATE_FM && m_modemState != STATE_IDLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_ax25Enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t reply[512U];
|
||||||
|
|
||||||
|
reply[0U] = MMDVM_FRAME_START;
|
||||||
|
|
||||||
|
if (length > 250U) {
|
||||||
|
reply[1U] = 0U;
|
||||||
|
reply[2U] = (length + 6U) - 255U;
|
||||||
|
reply[3U] = MMDVM_AX25_DATA_EX;
|
||||||
|
|
||||||
|
reply[4U] = (rssi >> 8) & 0xFFU;
|
||||||
|
reply[5U] = (rssi >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
for (uint16_t i = 0U; i < length; i++)
|
||||||
|
reply[i + 6U] = data[i];
|
||||||
|
|
||||||
|
writeInt(1U, reply, length + 6U);
|
||||||
|
} else {
|
||||||
|
reply[1U] = length + 5U;
|
||||||
|
reply[2U] = MMDVM_AX25_DATA_EX;
|
||||||
|
|
||||||
|
reply[3U] = (rssi >> 8) & 0xFFU;
|
||||||
|
reply[4U] = (rssi >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
for (uint16_t i = 0U; i < length; i++)
|
||||||
|
reply[i + 5U] = data[i];
|
||||||
|
|
||||||
|
writeInt(1U, reply, length + 5U);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SERIAL_REPEATER)
|
#if defined(SERIAL_REPEATER)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020,2021,2023 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -73,11 +73,13 @@ public:
|
||||||
|
|
||||||
#if defined(MODE_AX25)
|
#if defined(MODE_AX25)
|
||||||
void writeAX25Data(const uint8_t* data, uint16_t length);
|
void writeAX25Data(const uint8_t* data, uint16_t length);
|
||||||
|
void writeAX25DataEx(uint16_t rssi, const uint8_t* data, uint16_t length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(MODE_FM)
|
#if defined(MODE_FM)
|
||||||
void writeFMData(const uint8_t* data, uint16_t length);
|
void writeFMData(const uint8_t* data, uint16_t length);
|
||||||
void writeFMStatus(uint8_t status);
|
void writeFMStatus(uint8_t status);
|
||||||
|
void writeFMRSSI(uint16_t rssi);
|
||||||
void writeFMEOT();
|
void writeFMEOT();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue