mirror of
https://github.com/g4klx/MMDVM.git
synced 2026-10-15 16:24:11 +02:00
Compare commits
160
Commits
FM_Ext
...
M17_AX25_FM
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee07f76bd5 | ||
|
|
d063a1da1e | ||
|
|
6a4dad4c44 | ||
|
|
ed6bd66fab | ||
|
|
1a07a6f0d1 | ||
|
|
70bf47f93e | ||
|
|
a5eaafc7e0 | ||
|
|
2200945857 | ||
|
|
63a8e61a45 | ||
|
|
7275f65e44 | ||
|
|
2aabdb61ab | ||
|
|
96c0e5b141 | ||
|
|
9c883cfafd | ||
|
|
8a1ab88c3a | ||
|
|
f4e1c0b401 | ||
|
|
43b53fe2fc | ||
|
|
6517229f87 | ||
|
|
d0557ab723 | ||
|
|
b5d106dcb6 | ||
|
|
34cbff41c9 | ||
|
|
752e13821f | ||
|
|
86b45c15eb | ||
|
|
4fa0e052f8 | ||
|
|
0736a5cbe8 | ||
|
|
6ffb68450c | ||
|
|
1ad20fd4a0 | ||
|
|
34f6dfc5bb | ||
|
|
1e065ba17f | ||
|
|
1df7d7a7fc | ||
|
|
7e919b12f7 | ||
|
|
bada4d9285 | ||
|
|
9ae4a5376d | ||
|
|
8038ce9c9c | ||
|
|
842dcdb5c5 | ||
|
|
f7ead5cc0e | ||
|
|
b155597693 | ||
|
|
7148cf9f7d | ||
|
|
9440b43114 | ||
|
|
c06a83660f | ||
|
|
657e71238d | ||
|
|
510d433906 | ||
|
|
ff39a9031b | ||
|
|
4f3aa8b7e1 | ||
|
|
a35b8f929a | ||
|
|
6d0335b357 | ||
|
|
54f4dcabf0 | ||
|
|
19e2ccf150 | ||
|
|
0c4f49fa68 | ||
|
|
98ebefe84b | ||
|
|
029e7eef4a | ||
|
|
ca4fff2ba6 | ||
|
|
23ba73cabd | ||
|
|
519af80ac4 | ||
|
|
c5b542f438 | ||
|
|
3503e0cc2a | ||
|
|
955578789d | ||
|
|
061e10e395 | ||
|
|
fa9040fdf0 | ||
|
|
8240225371 | ||
|
|
f2c7c19444 | ||
|
|
2e5f174cdd | ||
|
|
d144ce6f1c | ||
|
|
31744a237a | ||
|
|
46c0958704 | ||
|
|
99d2a0d822 | ||
|
|
81518bf74c | ||
|
|
dd5a465a39 | ||
|
|
a345586ee9 | ||
|
|
55c89a4413 | ||
|
|
60f87072ba | ||
|
|
f2d2033733 | ||
|
|
0334b5a791 | ||
|
|
a62fd814ae | ||
|
|
02000c8049 | ||
|
|
2509ab5ba1 | ||
|
|
2de9e4d533 | ||
|
|
fda1e3dcf4 | ||
|
|
cb3ed795d0 | ||
|
|
632ddda68b | ||
|
|
b6093406ad | ||
|
|
8d9b49bdb0 | ||
|
|
625ec93af8 | ||
|
|
b2111553c6 | ||
|
|
252d54a484 | ||
|
|
1ad9799123 | ||
|
|
6d67b9f104 | ||
|
|
fb85505433 | ||
|
|
823b91c97d | ||
|
|
2a001f491d | ||
|
|
b5ba384495 | ||
|
|
d8f138066e | ||
|
|
6964251122 | ||
|
|
0fca178bd7 | ||
|
|
a60ecb3e57 | ||
|
|
a2978d9e91 | ||
|
|
e304f5cce2 | ||
|
|
99a7df7c13 | ||
|
|
6dfe1a9271 | ||
|
|
9ff59570c7 | ||
|
|
d5e9b5a315 | ||
|
|
1ac0628c1c | ||
|
|
dc41fd83d2 | ||
|
|
20013e3adc | ||
|
|
5960fb97f3 | ||
|
|
8f8dc92a14 | ||
|
|
ccdbe126e0 | ||
|
|
d29a0bc3a6 | ||
|
|
4ff057069b | ||
|
|
f8d8f85841 | ||
|
|
ad77fd60fd | ||
|
|
aab8f5469f | ||
|
|
f1d6a8b36e | ||
|
|
843997ccad | ||
|
|
d5f2d1c382 | ||
|
|
c99f50575d | ||
|
|
29c8cf9414 | ||
|
|
2c6e2c2a11 | ||
|
|
8d10555dc9 | ||
|
|
14d5098018 | ||
|
|
52a351d0f1 | ||
|
|
43f84ae968 | ||
|
|
a73376671c | ||
|
|
759efd1da4 | ||
|
|
ea0c1953cc | ||
|
|
a29cb23a75 | ||
|
|
bb66c72ef3 | ||
|
|
2da28ede64 | ||
|
|
a7ac55795d | ||
|
|
835ef46aef | ||
|
|
3de10fe98b | ||
|
|
7ad70d04a4 | ||
|
|
e210062365 | ||
|
|
f9fcdc5292 | ||
|
|
33d922b8c2 | ||
|
|
114c2bcb15 | ||
|
|
6dbda2795a | ||
|
|
6a80d0ec09 | ||
|
|
0e8f20e1cc | ||
|
|
af11be16dc | ||
|
|
e332dbba8e | ||
|
|
746d915bf9 | ||
|
|
c896cf823e | ||
|
|
c2959466fd | ||
|
|
121c76f3d8 | ||
|
|
22cb16f831 | ||
|
|
57e18e337f | ||
|
|
e1d1ac4a4d | ||
|
|
64fe59382f | ||
|
|
a2e2853241 | ||
|
|
598d32287d | ||
|
|
53d8cfa360 | ||
|
|
7fabddd7f1 | ||
|
|
2cf2ce4dfa | ||
|
|
5f29808b80 | ||
|
|
063b21f999 | ||
|
|
89b8641955 | ||
|
|
6397c720e8 | ||
|
|
50c1e5aa3f | ||
|
|
970d02773f | ||
|
|
ff375abb0e |
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(AX25DEFINES_H)
|
||||||
|
#define AX25DEFINES_H
|
||||||
|
|
||||||
|
const uint8_t AX25_RADIO_SYMBOL_LENGTH = 20U; // At 24 kHz sample rate
|
||||||
|
|
||||||
|
const uint8_t AX25_FRAME_START = 0x7EU;
|
||||||
|
const uint8_t AX25_FRAME_END = 0x7EU;
|
||||||
|
const uint8_t AX25_FRAME_ABORT = 0xFEU;
|
||||||
|
|
||||||
|
const uint8_t AX25_MAX_ONES = 5U;
|
||||||
|
|
||||||
|
const uint16_t AX25_MIN_FRAME_LENGTH = 17U; // Callsign (7) + Callsign (7) + Control (1) + Checksum (2)
|
||||||
|
|
||||||
|
const uint16_t AX25_MAX_FRAME_LENGTH = 330U; // Callsign (7) + Callsign (7) + 8 Digipeaters (56) +
|
||||||
|
// Control (1) + PID (1) + Data (256) + Checksum (2)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,319 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright 2015-2019 Mobilinkd LLC <[email protected]>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AX25Demodulator.h"
|
||||||
|
#include "AX25Defines.h"
|
||||||
|
|
||||||
|
const float32_t SAMPLE_RATE = 24000.0F;
|
||||||
|
const float32_t SYMBOL_RATE = 1200.0F;
|
||||||
|
|
||||||
|
const uint16_t DELAY_LEN = 11U;
|
||||||
|
|
||||||
|
const float32_t SAMPLES_PER_SYMBOL = SAMPLE_RATE / SYMBOL_RATE;
|
||||||
|
const float32_t PLL_LIMIT = SAMPLES_PER_SYMBOL / 2.0F;
|
||||||
|
|
||||||
|
const uint32_t LPF_FILTER_LEN = 48U;
|
||||||
|
|
||||||
|
q15_t LPF_FILTER_COEFFS[] = {
|
||||||
|
-2, -8, -17, -28, -40, -47, -47, -34,
|
||||||
|
-5, 46, 122, 224, 354, 510, 689, 885,
|
||||||
|
1092, 1302, 1506, 1693, 1856, 1987, 2077, 2124,
|
||||||
|
2124, 2077, 1987, 1856, 1693, 1506, 1302, 1092,
|
||||||
|
885, 689, 510, 354, 224, 122, 46, -5,
|
||||||
|
-34, -47, -47, -40, -28, -17, -8, -2
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lock low-pass filter taps (80Hz Bessel)
|
||||||
|
// scipy.signal:
|
||||||
|
// b, a = bessel(4, [80.0/(1200/2)], 'lowpass')
|
||||||
|
//
|
||||||
|
const uint8_t PLL_IIR_SIZE = 5U;
|
||||||
|
|
||||||
|
const float32_t PLL_LOCK_B[] = {
|
||||||
|
1.077063e-03,4.308253e-03,6.462379e-03,4.308253e-03,1.077063e-03};
|
||||||
|
|
||||||
|
const float32_t PLL_LOCK_A[] = {
|
||||||
|
1.000000e+00,-2.774567e+00,2.962960e+00,-1.437990e+00,2.668296e-01};
|
||||||
|
|
||||||
|
// 64 Hz loop filter.
|
||||||
|
// scipy.signal:
|
||||||
|
// loop_coeffs = firwin(9, [64.0/(1200/2)], width = None,
|
||||||
|
// pass_zero = True, scale = True, window='hann')
|
||||||
|
//
|
||||||
|
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};
|
||||||
|
|
||||||
|
CAX25Demodulator::CAX25Demodulator(int8_t n) :
|
||||||
|
m_frame(),
|
||||||
|
m_twist(n),
|
||||||
|
m_lpfFilter(),
|
||||||
|
m_lpfState(),
|
||||||
|
m_delayLine(NULL),
|
||||||
|
m_delayPos(0U),
|
||||||
|
m_nrziState(false),
|
||||||
|
m_pllFilter(),
|
||||||
|
m_pllState(),
|
||||||
|
m_pllLast(false),
|
||||||
|
m_pllBits(1U),
|
||||||
|
m_pllCount(0.0F),
|
||||||
|
m_pllJitter(0.0F),
|
||||||
|
m_pllDCD(false),
|
||||||
|
m_iirHistory(),
|
||||||
|
m_hdlcOnes(0U),
|
||||||
|
m_hdlcFlag(false),
|
||||||
|
m_hdlcBuffer(0U),
|
||||||
|
m_hdlcBits(0U),
|
||||||
|
m_hdlcState(AX25_IDLE)
|
||||||
|
{
|
||||||
|
m_delayLine = new bool[DELAY_LEN];
|
||||||
|
|
||||||
|
m_lpfFilter.numTaps = LPF_FILTER_LEN;
|
||||||
|
m_lpfFilter.pState = m_lpfState;
|
||||||
|
m_lpfFilter.pCoeffs = LPF_FILTER_COEFFS;
|
||||||
|
|
||||||
|
m_pllFilter.numTaps = PLL_FILTER_LEN;
|
||||||
|
m_pllFilter.pState = m_pllState;
|
||||||
|
m_pllFilter.pCoeffs = PLL_FILTER_COEFFS;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < PLL_IIR_SIZE; i++)
|
||||||
|
m_iirHistory[i] = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
q15_t fa[RX_BLOCK_SIZE];
|
||||||
|
m_twist.process(samples, fa, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
|
int16_t buffer[RX_BLOCK_SIZE];
|
||||||
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
bool level = (fa[i] >= 0);
|
||||||
|
bool delayed = delay(level);
|
||||||
|
buffer[i] = (int16_t(level ^ delayed) << 1) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
q15_t fc[RX_BLOCK_SIZE];
|
||||||
|
::arm_fir_fast_q15(&m_lpfFilter, buffer, fc, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
bool bit = fc[i] >= 0;
|
||||||
|
bool sample = PLL(bit);
|
||||||
|
|
||||||
|
if (sample) {
|
||||||
|
// We will only ever get one frame because there are
|
||||||
|
// not enough bits in a block for more than one.
|
||||||
|
if (result) {
|
||||||
|
HDLC(NRZI(bit));
|
||||||
|
} else {
|
||||||
|
result = HDLC(NRZI(bit));
|
||||||
|
if (result) {
|
||||||
|
// Copy the frame data.
|
||||||
|
::memcpy(frame.m_data, m_frame.m_data, AX25_MAX_PACKET_LEN);
|
||||||
|
frame.m_length = m_frame.m_length;
|
||||||
|
frame.m_fcs = m_frame.m_fcs;
|
||||||
|
m_frame.m_length = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::delay(bool b)
|
||||||
|
{
|
||||||
|
bool r = m_delayLine[m_delayPos];
|
||||||
|
|
||||||
|
m_delayLine[m_delayPos++] = b;
|
||||||
|
|
||||||
|
if (m_delayPos >= DELAY_LEN)
|
||||||
|
m_delayPos = 0U;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::NRZI(bool b)
|
||||||
|
{
|
||||||
|
bool result = (b == m_nrziState);
|
||||||
|
|
||||||
|
m_nrziState = b;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::PLL(bool input)
|
||||||
|
{
|
||||||
|
bool sample = false;
|
||||||
|
|
||||||
|
if (input != m_pllLast || m_pllBits > 16U) {
|
||||||
|
// Record transition.
|
||||||
|
m_pllLast = input;
|
||||||
|
|
||||||
|
if (m_pllCount > PLL_LIMIT)
|
||||||
|
m_pllCount -= SAMPLES_PER_SYMBOL;
|
||||||
|
|
||||||
|
float32_t adjust = m_pllBits > 16U ? 5.0F : 0.0F;
|
||||||
|
float32_t offset = m_pllCount / float32_t(m_pllBits);
|
||||||
|
float32_t jitter;
|
||||||
|
::arm_fir_f32(&m_pllFilter, &offset, &jitter, 1U);
|
||||||
|
|
||||||
|
float32_t absOffset = adjust;
|
||||||
|
if (offset < 0.0F)
|
||||||
|
absOffset -= offset;
|
||||||
|
else
|
||||||
|
absOffset += offset;
|
||||||
|
m_pllJitter = iir(absOffset);
|
||||||
|
|
||||||
|
m_pllCount -= jitter / 2.0F;
|
||||||
|
m_pllBits = 1U;
|
||||||
|
} else {
|
||||||
|
if (m_pllCount > PLL_LIMIT) {
|
||||||
|
sample = true;
|
||||||
|
m_pllCount -= SAMPLES_PER_SYMBOL;
|
||||||
|
m_pllBits++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pllCount += 1.0F;
|
||||||
|
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::HDLC(bool b)
|
||||||
|
{
|
||||||
|
if (m_hdlcOnes == AX25_MAX_ONES) {
|
||||||
|
if (b) {
|
||||||
|
// flag byte
|
||||||
|
m_hdlcFlag = true;
|
||||||
|
} else {
|
||||||
|
// bit stuffing...
|
||||||
|
m_hdlcFlag = false;
|
||||||
|
m_hdlcOnes = 0U;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
switch (m_hdlcBuffer) {
|
||||||
|
case AX25_FRAME_END:
|
||||||
|
if (m_frame.m_length >= AX25_MIN_FRAME_LENGTH) {
|
||||||
|
result = m_frame.checkCRC();
|
||||||
|
if (!result)
|
||||||
|
m_frame.m_length = 0U;
|
||||||
|
} else {
|
||||||
|
m_frame.m_length = 0U;
|
||||||
|
}
|
||||||
|
m_hdlcState = AX25_SYNC;
|
||||||
|
m_hdlcFlag = false;
|
||||||
|
m_hdlcBits = 0U;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AX25_FRAME_ABORT:
|
||||||
|
// 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 false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25Demodulator::setTwist(int8_t n)
|
||||||
|
{
|
||||||
|
m_twist.setTwist(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::isDCD()
|
||||||
|
{
|
||||||
|
if (m_pllJitter <= (SAMPLES_PER_SYMBOL * 0.03F))
|
||||||
|
m_pllDCD = true;
|
||||||
|
else if (m_pllJitter >= (SAMPLES_PER_SYMBOL * 0.15F))
|
||||||
|
m_pllDCD = false;
|
||||||
|
|
||||||
|
return m_pllDCD;
|
||||||
|
}
|
||||||
|
|
||||||
|
float32_t CAX25Demodulator::iir(float32_t input)
|
||||||
|
{
|
||||||
|
for (int8_t i = int8_t(PLL_IIR_SIZE) - 1; i != 0; i--)
|
||||||
|
m_iirHistory[i] = m_iirHistory[i - 1];
|
||||||
|
|
||||||
|
m_iirHistory[0] = input;
|
||||||
|
for (uint8_t i = 1U; i < PLL_IIR_SIZE; i++)
|
||||||
|
m_iirHistory[0] -= PLL_LOCK_A[i] * m_iirHistory[i];
|
||||||
|
|
||||||
|
float32_t result = 0.0F;
|
||||||
|
for (uint8_t i = 0U; i < PLL_IIR_SIZE; i++)
|
||||||
|
result += PLL_LOCK_B[i] * m_iirHistory[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
|
||||||
|
#if !defined(AX25Demodulator_H)
|
||||||
|
#define AX25Demodulator_H
|
||||||
|
|
||||||
|
#include "AX25Frame.h"
|
||||||
|
#include "AX25Twist.h"
|
||||||
|
|
||||||
|
enum AX25_STATE {
|
||||||
|
AX25_IDLE,
|
||||||
|
AX25_SYNC,
|
||||||
|
AX25_RECEIVE
|
||||||
|
};
|
||||||
|
|
||||||
|
class CAX25Demodulator {
|
||||||
|
public:
|
||||||
|
CAX25Demodulator(int8_t n);
|
||||||
|
|
||||||
|
bool process(q15_t* samples, uint8_t length, CAX25Frame& frame);
|
||||||
|
|
||||||
|
void setTwist(int8_t n);
|
||||||
|
|
||||||
|
bool isDCD();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CAX25Frame m_frame;
|
||||||
|
CAX25Twist m_twist;
|
||||||
|
arm_fir_instance_q15 m_lpfFilter;
|
||||||
|
q15_t m_lpfState[70U]; // NoTaps + BlockSize - 1, 48 + 20 - 1 plus some spare
|
||||||
|
bool* m_delayLine;
|
||||||
|
uint16_t m_delayPos;
|
||||||
|
bool m_nrziState;
|
||||||
|
arm_fir_instance_f32 m_pllFilter;
|
||||||
|
float32_t m_pllState[20U]; // NoTaps + BlockSize - 1, 7 + 1 - 1 plus some spare
|
||||||
|
bool m_pllLast;
|
||||||
|
uint8_t m_pllBits;
|
||||||
|
float32_t m_pllCount;
|
||||||
|
float32_t m_pllJitter;
|
||||||
|
bool m_pllDCD;
|
||||||
|
float32_t m_iirHistory[5U];
|
||||||
|
uint16_t m_hdlcOnes;
|
||||||
|
bool m_hdlcFlag;
|
||||||
|
uint16_t m_hdlcBuffer;
|
||||||
|
uint16_t m_hdlcBits;
|
||||||
|
AX25_STATE m_hdlcState;
|
||||||
|
|
||||||
|
bool delay(bool b);
|
||||||
|
bool NRZI(bool b);
|
||||||
|
bool PLL(bool b);
|
||||||
|
bool HDLC(bool b);
|
||||||
|
float32_t iir(float32_t input);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AX25Frame.h"
|
||||||
|
|
||||||
|
const uint16_t CCITT_TABLE[] = {
|
||||||
|
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
|
||||||
|
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
|
||||||
|
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
|
||||||
|
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
|
||||||
|
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
|
||||||
|
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
|
||||||
|
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
|
||||||
|
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
|
||||||
|
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
|
||||||
|
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
|
||||||
|
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
|
||||||
|
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
|
||||||
|
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
|
||||||
|
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
|
||||||
|
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
|
||||||
|
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
|
||||||
|
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
|
||||||
|
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
|
||||||
|
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
|
||||||
|
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
|
||||||
|
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
|
||||||
|
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
|
||||||
|
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
|
||||||
|
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
|
||||||
|
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
|
||||||
|
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
|
||||||
|
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
|
||||||
|
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
|
||||||
|
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
|
||||||
|
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
|
||||||
|
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
|
||||||
|
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78 };
|
||||||
|
|
||||||
|
CAX25Frame::CAX25Frame(const uint8_t* data, uint16_t length) :
|
||||||
|
m_data(),
|
||||||
|
m_length(0U),
|
||||||
|
m_fcs(0U)
|
||||||
|
{
|
||||||
|
for (uint16_t i = 0U; i < length && i < (AX25_MAX_PACKET_LEN - 2U); i++)
|
||||||
|
m_data[m_length++] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
CAX25Frame::CAX25Frame() :
|
||||||
|
m_data(),
|
||||||
|
m_length(0U),
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
uint16_t crc16;
|
||||||
|
uint8_t crc8[2U];
|
||||||
|
};
|
||||||
|
|
||||||
|
crc16 = 0xFFFFU;
|
||||||
|
for (uint16_t i = 0U; i < (m_length - 2U); i++)
|
||||||
|
crc16 = uint16_t(crc8[1U]) ^ CCITT_TABLE[crc8[0U] ^ m_data[i]];
|
||||||
|
|
||||||
|
crc16 = ~crc16;
|
||||||
|
|
||||||
|
if (crc8[0U] == m_data[m_length - 2U] && crc8[1U] == m_data[m_length - 1U]) {
|
||||||
|
m_fcs = crc16;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25Frame::addCRC()
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
uint16_t crc16;
|
||||||
|
uint8_t crc8[2U];
|
||||||
|
};
|
||||||
|
|
||||||
|
crc16 = 0xFFFFU;
|
||||||
|
for (uint16_t i = 0U; i < m_length; i++)
|
||||||
|
crc16 = uint16_t(crc8[1U]) ^ CCITT_TABLE[crc8[0U] ^ m_data[i]];
|
||||||
|
|
||||||
|
crc16 = ~crc16;
|
||||||
|
|
||||||
|
m_fcs = crc16;
|
||||||
|
|
||||||
|
m_data[m_length++] = crc8[0U];
|
||||||
|
m_data[m_length++] = crc8[1U];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
|
||||||
|
#if !defined(AX25Frame_H)
|
||||||
|
#define AX25Frame_H
|
||||||
|
|
||||||
|
const uint16_t AX25_MAX_PACKET_LEN = 300U;
|
||||||
|
|
||||||
|
class CAX25Frame {
|
||||||
|
public:
|
||||||
|
CAX25Frame(const uint8_t* data, uint16_t length);
|
||||||
|
CAX25Frame();
|
||||||
|
|
||||||
|
bool append(uint16_t c);
|
||||||
|
|
||||||
|
bool checkCRC();
|
||||||
|
|
||||||
|
void addCRC();
|
||||||
|
|
||||||
|
uint8_t m_data[AX25_MAX_PACKET_LEN];
|
||||||
|
uint16_t m_length;
|
||||||
|
uint16_t m_fcs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+211
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AX25RX.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generated with Scipy Filter, 152 coefficients, 1100-2300Hz bandpass,
|
||||||
|
* Hann window, starting and ending 0 value coefficients removed.
|
||||||
|
*
|
||||||
|
* np.array(
|
||||||
|
* firwin2(152,
|
||||||
|
* [
|
||||||
|
* 0.0,
|
||||||
|
* 1000.0/(sample_rate/2),
|
||||||
|
* 1100.0/(sample_rate/2),
|
||||||
|
* 2350.0/(sample_rate/2),
|
||||||
|
* 2500.0/(sample_rate/2),
|
||||||
|
* 1.0
|
||||||
|
* ],
|
||||||
|
* [0,0,1,1,0,0],
|
||||||
|
* antisymmetric = False,
|
||||||
|
* window='hann') * 32768,
|
||||||
|
* dtype=int)[10:-10]
|
||||||
|
*/
|
||||||
|
|
||||||
|
const uint32_t FILTER_LEN = 130U;
|
||||||
|
|
||||||
|
q15_t FILTER_COEFFS[] = {
|
||||||
|
5, 12, 18, 21, 19, 11, -2, -15, -25, -27,
|
||||||
|
-21, -11, -3, -5, -19, -43, -69, -83, -73, -35,
|
||||||
|
27, 98, 155, 180, 163, 109, 39, -20, -45, -26,
|
||||||
|
23, 74, 89, 39, -81, -247, -407, -501, -480, -334,
|
||||||
|
-92, 175, 388, 479, 429, 275, 99, 5, 68, 298,
|
||||||
|
626, 913, 994, 740, 115, -791, -1770, -2544, -2847, -2509,
|
||||||
|
-1527, -76, 1518, 2875, 3653, 3653, 2875, 1518, -76, -1527,
|
||||||
|
-2509, -2847, -2544, -1770, -791, 115, 740, 994, 913, 626,
|
||||||
|
298, 68, 5, 99, 275, 429, 479, 388, 175, -92,
|
||||||
|
-334, -480, -501, -407, -247, -81, 39, 89, 74, 23,
|
||||||
|
-26, -45, -20, 39, 109, 163, 180, 155, 98, 27,
|
||||||
|
-35, -73, -83, -69, -43, -19, -5, -3, -11, -21,
|
||||||
|
-27, -25, -15, -2, 11, 19, 21, 18, 12, 5
|
||||||
|
};
|
||||||
|
|
||||||
|
CAX25RX::CAX25RX() :
|
||||||
|
m_filter(),
|
||||||
|
m_state(),
|
||||||
|
m_demod1(3),
|
||||||
|
m_demod2(6),
|
||||||
|
m_demod3(9),
|
||||||
|
m_lastFCS(0U),
|
||||||
|
m_count(0U),
|
||||||
|
m_slotTime(30U),
|
||||||
|
m_slotCount(0U),
|
||||||
|
m_pPersist(128U),
|
||||||
|
m_dcd(false),
|
||||||
|
m_canTX(false),
|
||||||
|
m_x(1U),
|
||||||
|
m_a(0xB7U),
|
||||||
|
m_b(0x73U),
|
||||||
|
m_c(0xF6U)
|
||||||
|
{
|
||||||
|
m_filter.numTaps = FILTER_LEN;
|
||||||
|
m_filter.pState = m_state;
|
||||||
|
m_filter.pCoeffs = FILTER_COEFFS;
|
||||||
|
|
||||||
|
initRand();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25RX::samples(q15_t* samples, uint8_t length)
|
||||||
|
{
|
||||||
|
q15_t output[RX_BLOCK_SIZE];
|
||||||
|
::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
|
m_count++;
|
||||||
|
|
||||||
|
CAX25Frame frame;
|
||||||
|
|
||||||
|
bool ret = m_demod1.process(output, length, frame);
|
||||||
|
if (ret) {
|
||||||
|
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
||||||
|
m_lastFCS = frame.m_fcs;
|
||||||
|
m_count = 0U;
|
||||||
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
}
|
||||||
|
DEBUG1("Decoder 1 reported");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = m_demod2.process(output, length, frame);
|
||||||
|
if (ret) {
|
||||||
|
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
||||||
|
m_lastFCS = frame.m_fcs;
|
||||||
|
m_count = 0U;
|
||||||
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
}
|
||||||
|
DEBUG1("Decoder 2 reported");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = m_demod3.process(output, length, frame);
|
||||||
|
if (ret) {
|
||||||
|
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
||||||
|
m_lastFCS = frame.m_fcs;
|
||||||
|
m_count = 0U;
|
||||||
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
}
|
||||||
|
DEBUG1("Decoder 3 reported");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_slotCount += RX_BLOCK_SIZE;
|
||||||
|
if (m_slotCount >= m_slotTime) {
|
||||||
|
m_slotCount = 0U;
|
||||||
|
|
||||||
|
bool dcd1 = m_demod1.isDCD();
|
||||||
|
bool dcd2 = m_demod2.isDCD();
|
||||||
|
bool dcd3 = m_demod3.isDCD();
|
||||||
|
|
||||||
|
if (dcd1 || dcd2 || dcd3) {
|
||||||
|
if (!m_dcd) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
m_dcd = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_canTX = false;
|
||||||
|
} else {
|
||||||
|
if (m_dcd) {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
m_dcd = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_canTX = m_pPersist >= rand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25RX::canTX() const
|
||||||
|
{
|
||||||
|
return m_canTX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25RX::setParams(int8_t twist, uint8_t slotTime, uint8_t pPersist)
|
||||||
|
{
|
||||||
|
m_demod1.setTwist(twist - 3);
|
||||||
|
m_demod2.setTwist(twist);
|
||||||
|
m_demod3.setTwist(twist + 3);
|
||||||
|
|
||||||
|
m_slotTime = slotTime * 240U; // Slot time in samples
|
||||||
|
m_pPersist = pPersist;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Taken from https://www.electro-tech-online.com/threads/ultra-fast-pseudorandom-number-generator-for-8-bit.124249/
|
||||||
|
//X ABC Algorithm Random Number Generator for 8-Bit Devices:
|
||||||
|
//This is a small PRNG, experimentally verified to have at least a 50 million byte period
|
||||||
|
//by generating 50 million bytes and observing that there were no overapping sequences and repeats.
|
||||||
|
//This generator passes serial correlation, entropy , Monte Carlo Pi value, arithmetic mean,
|
||||||
|
//And many other statistical tests. This generator may have a period of up to 2^32, but this has
|
||||||
|
//not been verified.
|
||||||
|
//
|
||||||
|
// By XORing 3 bytes into the a,b, and c registers, you can add in entropy from
|
||||||
|
//an external source easily.
|
||||||
|
//
|
||||||
|
//This generator is free to use, but is not suitable for cryptography due to its short period(by //cryptographic standards) and simple construction. No attempt was made to make this generator
|
||||||
|
// suitable for cryptographic use.
|
||||||
|
//
|
||||||
|
//Due to the use of a constant counter, the generator should be resistant to latching up.
|
||||||
|
//A significant performance gain is had in that the x variable is only ever incremented.
|
||||||
|
//
|
||||||
|
//Only 4 bytes of ram are needed for the internal state, and generating a byte requires 3 XORs , //2 ADDs, one bit shift right , and one increment. Difficult or slow operations like multiply, etc
|
||||||
|
//were avoided for maximum speed on ultra low power devices.
|
||||||
|
|
||||||
|
|
||||||
|
void CAX25RX::initRand() //Can also be used to seed the rng with more entropy during use.
|
||||||
|
{
|
||||||
|
m_a = (m_a ^ m_c ^ m_x);
|
||||||
|
m_b = (m_b + m_a);
|
||||||
|
m_c = (m_c + (m_b >> 1) ^ m_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CAX25RX::rand()
|
||||||
|
{
|
||||||
|
m_x++; //x is incremented every round and is not affected by any other variable
|
||||||
|
|
||||||
|
m_a = (m_a ^ m_c ^ m_x); //note the mix of addition and XOR
|
||||||
|
m_b = (m_b + m_a); //And the use of very few instructions
|
||||||
|
m_c = (m_c + (m_b >> 1) ^ m_a); //the right shift is to ensure that high-order bits from b can affect
|
||||||
|
|
||||||
|
return uint8_t(m_c); //low order bits of other variables
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
|
||||||
|
#if !defined(AX25RX_H)
|
||||||
|
#define AX25RX_H
|
||||||
|
|
||||||
|
#include "AX25Demodulator.h"
|
||||||
|
|
||||||
|
class CAX25RX {
|
||||||
|
public:
|
||||||
|
CAX25RX();
|
||||||
|
|
||||||
|
void samples(q15_t* samples, uint8_t length);
|
||||||
|
|
||||||
|
void setParams(int8_t twist, uint8_t slotTime, uint8_t pPersist);
|
||||||
|
|
||||||
|
bool canTX() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
arm_fir_instance_q15 m_filter;
|
||||||
|
q15_t m_state[160U]; // NoTaps + BlockSize - 1, 130 + 20 - 1 plus some spare
|
||||||
|
CAX25Demodulator m_demod1;
|
||||||
|
CAX25Demodulator m_demod2;
|
||||||
|
CAX25Demodulator m_demod3;
|
||||||
|
uint16_t m_lastFCS;
|
||||||
|
uint32_t m_count;
|
||||||
|
uint32_t m_slotTime;
|
||||||
|
uint32_t m_slotCount;
|
||||||
|
uint8_t m_pPersist;
|
||||||
|
bool m_dcd;
|
||||||
|
bool m_canTX;
|
||||||
|
uint8_t m_x;
|
||||||
|
uint8_t m_a;
|
||||||
|
uint8_t m_b;
|
||||||
|
uint8_t m_c;
|
||||||
|
|
||||||
|
void initRand();
|
||||||
|
uint8_t rand();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+191
@@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AX25TX.h"
|
||||||
|
|
||||||
|
#include "AX25Defines.h"
|
||||||
|
#include "AX25Frame.h"
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t START_FLAG[] = { AX25_FRAME_START };
|
||||||
|
const uint8_t END_FLAG[] = { AX25_FRAME_END };
|
||||||
|
|
||||||
|
const uint8_t BIT_MASK_TABLE1[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
|
||||||
|
|
||||||
|
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE1[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE1[(i)&7])
|
||||||
|
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE1[(i)&7])
|
||||||
|
|
||||||
|
const uint8_t BIT_MASK_TABLE2[] = { 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U };
|
||||||
|
|
||||||
|
#define WRITE_BIT2(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE2[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE2[(i)&7])
|
||||||
|
#define READ_BIT2(p,i) (p[(i)>>3] & BIT_MASK_TABLE2[(i)&7])
|
||||||
|
|
||||||
|
const uint16_t AUDIO_TABLE_LEN = 120U;
|
||||||
|
|
||||||
|
const q15_t AUDIO_TABLE_DATA[] = {
|
||||||
|
0, 214, 428, 641, 851, 1060, 1265, 1468, 1666, 1859, 2048, 2230, 2407, 2577, 2740, 2896, 3043, 3182, 3313, 3434, 3546, 3649,
|
||||||
|
3741, 3823, 3895, 3955, 4006, 4045, 4073, 4089, 4095, 4089, 4073, 4045, 4006, 3955, 3895, 3823, 3741, 3649, 3546, 3434, 3313,
|
||||||
|
3182, 3043, 2896, 2740, 2577, 2407, 2230, 2048, 1859, 1666, 1468, 1265, 1060, 851, 641, 428, 214, 0, -214, -428, -641, -851,
|
||||||
|
-1060, -1265, -1468, -1666, -1859, -2047, -2230, -2407, -2577, -2740, -2896, -3043, -3182, -3313, -3434, -3546, -3649, -3741,
|
||||||
|
-3823, -3895, -3955, -4006, -4045, -4073, -4089, -4095, -4089, -4073, -4045, -4006, -3955, -3895, -3823, -3741, -3649, -3546,
|
||||||
|
-3434, -3313, -3182, -3043, -2896, -2740, -2577, -2407, -2230, -2047, -1859, -1666, -1468, -1265, -1060, -851, -641, -428, -214
|
||||||
|
};
|
||||||
|
|
||||||
|
CAX25TX::CAX25TX() :
|
||||||
|
m_poBuffer(),
|
||||||
|
m_poLen(0U),
|
||||||
|
m_poPtr(0U),
|
||||||
|
m_txDelay(360U),
|
||||||
|
m_tablePtr(0U),
|
||||||
|
m_nrzi(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25TX::process()
|
||||||
|
{
|
||||||
|
if (m_poLen == 0U)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_duplex) {
|
||||||
|
if (m_poPtr == 0U) {
|
||||||
|
bool tx = ax25RX.canTX();
|
||||||
|
if (!tx)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > AX25_RADIO_SYMBOL_LENGTH) {
|
||||||
|
bool b = READ_BIT1(m_poBuffer, m_poPtr) != 0U;
|
||||||
|
m_poPtr++;
|
||||||
|
|
||||||
|
writeBit(b);
|
||||||
|
|
||||||
|
space -= AX25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
if (m_poPtr >= m_poLen) {
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_poLen = 0U;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length)
|
||||||
|
{
|
||||||
|
CAX25Frame frame(data, length);
|
||||||
|
frame.addCRC();
|
||||||
|
|
||||||
|
m_poLen = 0U;
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_nrzi = false;
|
||||||
|
m_tablePtr = 0U;
|
||||||
|
|
||||||
|
// Add TX delay
|
||||||
|
for (uint16_t i = 0U; i < m_txDelay; i++, m_poLen++) {
|
||||||
|
bool preamble = NRZI(false);
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, preamble);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the Start Flag
|
||||||
|
for (uint16_t i = 0U; i < 8U; i++, m_poLen++) {
|
||||||
|
bool b1 = READ_BIT1(START_FLAG, i) != 0U;
|
||||||
|
bool b2 = NRZI(b1);
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, b2);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ones = 0U;
|
||||||
|
for (uint16_t i = 0U; i < (frame.m_length * 8U); i++) {
|
||||||
|
bool b1 = READ_BIT2(frame.m_data, i) != 0U;
|
||||||
|
bool b2 = NRZI(b1);
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, b2);
|
||||||
|
m_poLen++;
|
||||||
|
|
||||||
|
if (b1) {
|
||||||
|
ones++;
|
||||||
|
if (ones == AX25_MAX_ONES) {
|
||||||
|
// Bit stuffing
|
||||||
|
bool b = NRZI(false);
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, b);
|
||||||
|
m_poLen++;
|
||||||
|
ones = 0U;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ones = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the End Flag
|
||||||
|
for (uint16_t i = 0U; i < 8U; i++, m_poLen++) {
|
||||||
|
bool b1 = READ_BIT1(END_FLAG, i) != 0U;
|
||||||
|
bool b2 = NRZI(b1);
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, b2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25TX::writeBit(bool b)
|
||||||
|
{
|
||||||
|
q15_t buffer[AX25_RADIO_SYMBOL_LENGTH];
|
||||||
|
for (uint8_t i = 0U; i < AX25_RADIO_SYMBOL_LENGTH; i++) {
|
||||||
|
q15_t value = AUDIO_TABLE_DATA[m_tablePtr];
|
||||||
|
|
||||||
|
if (b) {
|
||||||
|
// De-emphasise the lower frequency by 6dB
|
||||||
|
value >>= 2;
|
||||||
|
m_tablePtr += 6U;
|
||||||
|
} else {
|
||||||
|
m_tablePtr += 11U;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i] = value;
|
||||||
|
|
||||||
|
if (m_tablePtr >= AUDIO_TABLE_LEN)
|
||||||
|
m_tablePtr -= AUDIO_TABLE_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
io.write(STATE_AX25, buffer, AX25_RADIO_SYMBOL_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25TX::setTXDelay(uint8_t delay)
|
||||||
|
{
|
||||||
|
m_txDelay = delay * 12U;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CAX25TX::getSpace() const
|
||||||
|
{
|
||||||
|
return m_poLen == 0U ? 255U : 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25TX::NRZI(bool b)
|
||||||
|
{
|
||||||
|
if (!b)
|
||||||
|
m_nrzi = !m_nrzi;
|
||||||
|
|
||||||
|
return m_nrzi;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
|
||||||
|
#if !defined(AX25TX_H)
|
||||||
|
#define AX25TX_H
|
||||||
|
|
||||||
|
class CAX25TX {
|
||||||
|
public:
|
||||||
|
CAX25TX();
|
||||||
|
|
||||||
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
|
void process();
|
||||||
|
|
||||||
|
void setTXDelay(uint8_t delay);
|
||||||
|
|
||||||
|
uint8_t getSpace() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t m_poBuffer[600U];
|
||||||
|
uint16_t m_poLen;
|
||||||
|
uint16_t m_poPtr;
|
||||||
|
uint16_t m_txDelay;
|
||||||
|
uint16_t m_tablePtr;
|
||||||
|
bool m_nrzi;
|
||||||
|
|
||||||
|
void writeBit(bool b);
|
||||||
|
bool NRZI(bool b);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+316
@@ -0,0 +1,316 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AX25Twist.h"
|
||||||
|
|
||||||
|
// 1200Hz = -12dB, 2200Hz = 0dB; 3381Hz cutoff; cosine.
|
||||||
|
q15_t dB12[] = {
|
||||||
|
176,
|
||||||
|
-812,
|
||||||
|
-3916,
|
||||||
|
-7586,
|
||||||
|
23536,
|
||||||
|
-7586,
|
||||||
|
-3916,
|
||||||
|
-812,
|
||||||
|
176
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -11dB, 2200Hz = 0dB; 3258Hz cutoff; cosine.
|
||||||
|
q15_t dB11[] = {
|
||||||
|
121,
|
||||||
|
-957,
|
||||||
|
-3959,
|
||||||
|
-7383,
|
||||||
|
23871,
|
||||||
|
-7383,
|
||||||
|
-3959,
|
||||||
|
-957,
|
||||||
|
121
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -10dB, 2200Hz = 0dB; 3118Hz cutoff; cosine.
|
||||||
|
q15_t dB10[] = {
|
||||||
|
56,
|
||||||
|
-1110,
|
||||||
|
-3987,
|
||||||
|
-7141,
|
||||||
|
24254,
|
||||||
|
-7141,
|
||||||
|
-3987,
|
||||||
|
-1110,
|
||||||
|
56
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -9dB, 2200Hz = 0dB; 2959Hz cutoff; cosine.
|
||||||
|
q15_t dB9[] = {
|
||||||
|
-19,
|
||||||
|
-1268,
|
||||||
|
-3994,
|
||||||
|
-6856,
|
||||||
|
24688,
|
||||||
|
-6856,
|
||||||
|
-3994,
|
||||||
|
-1268,
|
||||||
|
-19
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -8dB, 2200Hz = 0dB; 2778Hz cutoff; cosine.
|
||||||
|
q15_t dB8[] = {
|
||||||
|
-104,
|
||||||
|
-1424,
|
||||||
|
-3968,
|
||||||
|
-6516,
|
||||||
|
25182,
|
||||||
|
-6516,
|
||||||
|
-3968,
|
||||||
|
-1424,
|
||||||
|
-104
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -7dB, 2200Hz = 0dB; 2573Hz cutoff; cosine.
|
||||||
|
q15_t dB7[] = {
|
||||||
|
-196,
|
||||||
|
-1565,
|
||||||
|
-3896,
|
||||||
|
-6114,
|
||||||
|
25742,
|
||||||
|
-6114,
|
||||||
|
-3896,
|
||||||
|
-1565,
|
||||||
|
-196
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -6dB, 2200Hz = 0dB; 2343Hz cutoff; cosine.
|
||||||
|
q15_t dB6[] = {
|
||||||
|
-288,
|
||||||
|
-1676,
|
||||||
|
-3761,
|
||||||
|
-5642,
|
||||||
|
26370,
|
||||||
|
-5642,
|
||||||
|
-3761,
|
||||||
|
-1676,
|
||||||
|
-288
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -5dB, 2200Hz = 0dB; 2085Hz cutoff; cosine.
|
||||||
|
q15_t dB5[] = {
|
||||||
|
-370,
|
||||||
|
-1735,
|
||||||
|
-3545,
|
||||||
|
-5088,
|
||||||
|
27075,
|
||||||
|
-5088,
|
||||||
|
-3545,
|
||||||
|
-1735,
|
||||||
|
-370
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -4dB, 2200Hz = 0dB; 1790Hz cutoff; cosine.
|
||||||
|
q15_t dB4[] = {
|
||||||
|
-432,
|
||||||
|
-1715,
|
||||||
|
-3220,
|
||||||
|
-4427,
|
||||||
|
27880,
|
||||||
|
-4427,
|
||||||
|
-3220,
|
||||||
|
-1715,
|
||||||
|
-432
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -3dB, 2200Hz = 0dB; 1456Hz cutoff; cosine.
|
||||||
|
q15_t dB3[] = {
|
||||||
|
-452,
|
||||||
|
-1582,
|
||||||
|
-2759,
|
||||||
|
-3646,
|
||||||
|
28792,
|
||||||
|
-3646,
|
||||||
|
-2759,
|
||||||
|
-1582,
|
||||||
|
-452
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -2dB, 2200Hz = 0dB; 1070Hz cutoff; cosine.
|
||||||
|
q15_t dB2[] = {
|
||||||
|
-408,
|
||||||
|
-1295,
|
||||||
|
-2123,
|
||||||
|
-2710,
|
||||||
|
29846,
|
||||||
|
-2710,
|
||||||
|
-2123,
|
||||||
|
-1295,
|
||||||
|
-408
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -1dB, 2200Hz = 0dB; 605Hz cutoff; cosine.
|
||||||
|
q15_t dB1[] = {
|
||||||
|
-268,
|
||||||
|
-795,
|
||||||
|
-1244,
|
||||||
|
-1546,
|
||||||
|
31116,
|
||||||
|
-1546,
|
||||||
|
-1244,
|
||||||
|
-795,
|
||||||
|
-268
|
||||||
|
};
|
||||||
|
|
||||||
|
q15_t dB0[] = {
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
32767,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -1dB; 4130Hz cutoff; cosine.
|
||||||
|
q15_t dB_1[] = {
|
||||||
|
-419,
|
||||||
|
-177,
|
||||||
|
3316,
|
||||||
|
8650,
|
||||||
|
11278,
|
||||||
|
8650,
|
||||||
|
3316,
|
||||||
|
-177,
|
||||||
|
-419
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -2dB; 3190Hz cutoff; cosine.
|
||||||
|
q15_t dB_2[] = {
|
||||||
|
-90,
|
||||||
|
1033,
|
||||||
|
3975,
|
||||||
|
7267,
|
||||||
|
8711,
|
||||||
|
7267,
|
||||||
|
3975,
|
||||||
|
1033,
|
||||||
|
-90
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -3dB; 2330Hz cutoff; cosine.
|
||||||
|
q15_t dB_3[] = {
|
||||||
|
292,
|
||||||
|
1680,
|
||||||
|
3752,
|
||||||
|
5615,
|
||||||
|
6362,
|
||||||
|
5615,
|
||||||
|
3752,
|
||||||
|
1680,
|
||||||
|
292
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -4dB; 2657Hz cutoff; boxcar.
|
||||||
|
q15_t dB_4[] = {
|
||||||
|
917,
|
||||||
|
3024,
|
||||||
|
5131,
|
||||||
|
6684,
|
||||||
|
7255,
|
||||||
|
6684,
|
||||||
|
5131,
|
||||||
|
3024,
|
||||||
|
917
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -5dB; 2360Hz cutoff; boxcar.
|
||||||
|
q15_t dB_5[] = {
|
||||||
|
1620,
|
||||||
|
3339,
|
||||||
|
4925,
|
||||||
|
6042,
|
||||||
|
6444,
|
||||||
|
6042,
|
||||||
|
4925,
|
||||||
|
3339,
|
||||||
|
1620
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -6dB; 2067Hz cutoff; boxcar.
|
||||||
|
q15_t dB_6[] = {
|
||||||
|
2161,
|
||||||
|
3472,
|
||||||
|
4605,
|
||||||
|
5373,
|
||||||
|
5644,
|
||||||
|
5373,
|
||||||
|
4605,
|
||||||
|
3472,
|
||||||
|
2161
|
||||||
|
};
|
||||||
|
|
||||||
|
q15_t* coeffs[] = {
|
||||||
|
dB12,
|
||||||
|
dB11,
|
||||||
|
dB10,
|
||||||
|
dB9,
|
||||||
|
dB8,
|
||||||
|
dB7,
|
||||||
|
dB6,
|
||||||
|
dB5,
|
||||||
|
dB4,
|
||||||
|
dB3,
|
||||||
|
dB2,
|
||||||
|
dB1,
|
||||||
|
dB0,
|
||||||
|
dB_1,
|
||||||
|
dB_2,
|
||||||
|
dB_3,
|
||||||
|
dB_4,
|
||||||
|
dB_5,
|
||||||
|
dB_6
|
||||||
|
};
|
||||||
|
|
||||||
|
CAX25Twist::CAX25Twist(int8_t n) :
|
||||||
|
m_filter(),
|
||||||
|
m_state()
|
||||||
|
{
|
||||||
|
setTwist(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25Twist::process(q15_t* in, q15_t* out, uint8_t length)
|
||||||
|
{
|
||||||
|
::arm_fir_fast_q15(&m_filter, in, out, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25Twist::setTwist(int8_t n)
|
||||||
|
{
|
||||||
|
uint8_t twist = uint8_t(n + 6);
|
||||||
|
|
||||||
|
m_filter.numTaps = 9;
|
||||||
|
m_filter.pState = m_state;
|
||||||
|
m_filter.pCoeffs = coeffs[twist];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
|
||||||
|
#if !defined(AX25Twist_H)
|
||||||
|
#define AX25Twist_H
|
||||||
|
|
||||||
|
class CAX25Twist {
|
||||||
|
public:
|
||||||
|
CAX25Twist(int8_t n);
|
||||||
|
|
||||||
|
void process(q15_t* in, q15_t* out, uint8_t length);
|
||||||
|
|
||||||
|
void setTwist(int8_t n);
|
||||||
|
|
||||||
|
private:
|
||||||
|
arm_fir_instance_q15 m_filter;
|
||||||
|
q15_t m_state[40U]; // NoTaps + BlockSize - 1, 9 + 20 - 1 plus some spare
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 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
|
||||||
@@ -125,7 +125,7 @@ void CCWIdTX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCWIdTX::write(const uint8_t* data, uint8_t length)
|
uint8_t CCWIdTX::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
::memset(m_poBuffer, 0x00U, 1000U * sizeof(uint8_t));
|
::memset(m_poBuffer, 0x00U, 1000U * sizeof(uint8_t));
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016,2020 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
|
||||||
* 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
|
||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2015,2020 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
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "CalDMR.h"
|
#include "CalDMR.h"
|
||||||
|
|
||||||
@@ -208,7 +211,7 @@ void CCalDMR::dmrdmo1k()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCalDMR::write(const uint8_t* data, uint8_t length)
|
uint8_t CCalDMR::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -221,3 +224,5 @@ uint8_t CCalDMR::write(const uint8_t* data, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2015,2020 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
|
||||||
@@ -17,10 +17,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#if !defined(CALDMR_H)
|
#if !defined(CALDMR_H)
|
||||||
#define CALDMR_H
|
#define CALDMR_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
enum DMRCAL1K {
|
enum DMRCAL1K {
|
||||||
@@ -41,7 +44,7 @@ public:
|
|||||||
void createData1k(uint8_t n);
|
void createData1k(uint8_t n);
|
||||||
void createDataDMO1k(uint8_t n);
|
void createDataDMO1k(uint8_t n);
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_transmit;
|
bool m_transmit;
|
||||||
@@ -53,3 +56,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2016,2020 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
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "CalDStarRX.h"
|
#include "CalDStarRX.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
@@ -24,7 +27,7 @@
|
|||||||
const unsigned int BUFFER_LENGTH = 200U;
|
const unsigned int BUFFER_LENGTH = 200U;
|
||||||
|
|
||||||
const uint32_t PLLMAX = 0x10000U;
|
const uint32_t PLLMAX = 0x10000U;
|
||||||
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_BIT_LENGTH;
|
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
const uint32_t INC = PLLINC / 32U;
|
const uint32_t INC = PLLINC / 32U;
|
||||||
|
|
||||||
// D-Star bit order version of 0x55 0x2D 0x16
|
// D-Star bit order version of 0x55 0x2D 0x16
|
||||||
@@ -126,3 +129,5 @@ void CCalDStarRX::process(q15_t value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2020 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
|
||||||
@@ -16,10 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
|
|
||||||
#if !defined(CALDSTARRX_H)
|
#if !defined(CALDSTARRX_H)
|
||||||
#define CALDSTARRX_H
|
#define CALDSTARRX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "DStarDefines.h"
|
#include "DStarDefines.h"
|
||||||
|
|
||||||
class CCalDStarRX {
|
class CCalDStarRX {
|
||||||
@@ -40,3 +43,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2016,2020 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
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "CalDStarTX.h"
|
#include "CalDStarTX.h"
|
||||||
|
|
||||||
@@ -162,7 +165,7 @@ void CCalDStarTX::process()
|
|||||||
m_count = (m_count + 1U) % (30U * 21U);
|
m_count = (m_count + 1U) % (30U * 21U);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCalDStarTX::write(const uint8_t* data, uint8_t length)
|
uint8_t CCalDStarTX::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -181,3 +184,5 @@ uint8_t CCalDStarTX::write(const uint8_t* data, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2020 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
|
||||||
@@ -16,17 +16,20 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
|
|
||||||
#if !defined(CALDSTARTX_H)
|
#if !defined(CALDSTARTX_H)
|
||||||
#define CALDSTARTX_H
|
#define CALDSTARTX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "DStarDefines.h"
|
#include "DStarDefines.h"
|
||||||
|
|
||||||
class CCalDStarTX {
|
class CCalDStarTX {
|
||||||
public:
|
public:
|
||||||
CCalDStarTX();
|
CCalDStarTX();
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
@@ -37,3 +40,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2015,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
* Copyright (C) 2020 by Phil Taylor M0VSE
|
* Copyright (C) 2020 by Phil Taylor M0VSE
|
||||||
*
|
*
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "CalFM.h"
|
#include "CalFM.h"
|
||||||
|
|
||||||
@@ -116,7 +119,7 @@ void CCalFM::process()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t CCalFM::write(const uint8_t* data, uint8_t length)
|
uint8_t CCalFM::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -125,3 +128,6 @@ uint8_t CCalFM::write(const uint8_t* data, uint8_t length)
|
|||||||
|
|
||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2015,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
* Copyright (C) 2020 by Phil Taylor M0VSE
|
* Copyright (C) 2020 by Phil Taylor M0VSE
|
||||||
*
|
*
|
||||||
@@ -18,11 +18,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#if !defined(CALFM_H)
|
#if !defined(CALFM_H)
|
||||||
#define CALFM_H
|
#define CALFM_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
class CCalFM {
|
class CCalFM {
|
||||||
public:
|
public:
|
||||||
CCalFM();
|
CCalFM();
|
||||||
@@ -35,7 +37,7 @@ public:
|
|||||||
void fm25kcal();
|
void fm25kcal();
|
||||||
void fm30kcal();
|
void fm30kcal();
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t m_frequency;
|
uint16_t m_frequency;
|
||||||
@@ -49,3 +51,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2020 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
|
||||||
@@ -17,6 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "CalNXDN.h"
|
#include "CalNXDN.h"
|
||||||
|
|
||||||
@@ -79,7 +83,7 @@ void CCalNXDN::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCalNXDN::write(const uint8_t* data, uint8_t length)
|
uint8_t CCalNXDN::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -92,3 +96,5 @@ uint8_t CCalNXDN::write(const uint8_t* data, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2020 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
|
||||||
@@ -16,11 +17,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
|
||||||
#if !defined(CALNXDN_H)
|
#if !defined(CALNXDN_H)
|
||||||
#define CALNXDN_H
|
#define CALNXDN_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
enum NXDNCAL1K {
|
enum NXDNCAL1K {
|
||||||
NXDNCAL1K_IDLE,
|
NXDNCAL1K_IDLE,
|
||||||
NXDNCAL1K_TX
|
NXDNCAL1K_TX
|
||||||
@@ -32,7 +35,7 @@ public:
|
|||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_transmit;
|
bool m_transmit;
|
||||||
@@ -42,3 +45,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2020 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
|
||||||
@@ -17,6 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "CalP25.h"
|
#include "CalP25.h"
|
||||||
|
|
||||||
@@ -82,7 +86,7 @@ void CCalP25::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCalP25::write(const uint8_t* data, uint8_t length)
|
uint8_t CCalP25::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -95,3 +99,5 @@ uint8_t CCalP25::write(const uint8_t* data, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2020 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
|
||||||
@@ -16,10 +17,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
|
||||||
#if !defined(CALP25_H)
|
#if !defined(CALP25_H)
|
||||||
#define CALP25_H
|
#define CALP25_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "P25Defines.h"
|
#include "P25Defines.h"
|
||||||
|
|
||||||
enum P25CAL1K {
|
enum P25CAL1K {
|
||||||
@@ -34,7 +38,7 @@ public:
|
|||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_transmit;
|
bool m_transmit;
|
||||||
@@ -43,3 +47,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2019 by Florian Wolters DF2ET
|
* Copyright (C) 2019 by Florian Wolters DF2ET
|
||||||
|
* Copyright (C) 2020 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
|
||||||
@@ -17,10 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_POCSAG)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "CalPOCSAG.h"
|
#include "CalPOCSAG.h"
|
||||||
|
|
||||||
|
|
||||||
CCalPOCSAG::CCalPOCSAG() :
|
CCalPOCSAG::CCalPOCSAG() :
|
||||||
m_state(POCSAGCAL_IDLE)
|
m_state(POCSAGCAL_IDLE)
|
||||||
{
|
{
|
||||||
@@ -38,7 +41,7 @@ void CCalPOCSAG::process()
|
|||||||
pocsagTX.writeByte(0xAAU);
|
pocsagTX.writeByte(0xAAU);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCalPOCSAG::write(const uint8_t* data, uint8_t length)
|
uint8_t CCalPOCSAG::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -47,3 +50,6 @@ uint8_t CCalPOCSAG::write(const uint8_t* data, uint8_t length)
|
|||||||
|
|
||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+9
-3
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2019 by Florian Wolters DF2ET
|
* Copyright (C) 2019 by Florian Wolters DF2ET
|
||||||
|
* Copyright (C) 2020 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
|
||||||
@@ -16,11 +17,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_POCSAG)
|
||||||
|
|
||||||
#if !defined(CALPOCSAG_H)
|
#if !defined(CALPOCSAG_H)
|
||||||
#define CALPOCSAG_H
|
#define CALPOCSAG_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
enum POCSAGCAL {
|
enum POCSAGCAL {
|
||||||
POCSAGCAL_IDLE,
|
POCSAGCAL_IDLE,
|
||||||
POCSAGCAL_TX
|
POCSAGCAL_TX
|
||||||
@@ -32,10 +35,13 @@ public:
|
|||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
POCSAGCAL m_state;
|
POCSAGCAL m_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,37 @@
|
|||||||
#if !defined(CONFIG_H)
|
#if !defined(CONFIG_H)
|
||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
|
|
||||||
|
// Allow for the selection of which modes to compile into the firmware. This is particularly useful for processors
|
||||||
|
// which have limited code space and processing power like the STM32F103, which is found on older/cheaper boards.
|
||||||
|
|
||||||
|
// Enable D-Star support.
|
||||||
|
#define MODE_DSTAR
|
||||||
|
|
||||||
|
// Enable DMR support.
|
||||||
|
#define MODE_DMR
|
||||||
|
|
||||||
|
// Enable System Fusion support.
|
||||||
|
#define MODE_YSF
|
||||||
|
|
||||||
|
// Enable P25 phase 1 support.
|
||||||
|
#define MODE_P25
|
||||||
|
|
||||||
|
// Enable NXDN support, the boxcar filter sometimes improves the performance of NXDN receive on some systems.
|
||||||
|
#define MODE_NXDN
|
||||||
|
#define USE_NXDN_BOXCAR
|
||||||
|
|
||||||
|
// Enable M17 support.
|
||||||
|
#define MODE_M17
|
||||||
|
|
||||||
|
// Enable POCSAG support.
|
||||||
|
#define MODE_POCSAG
|
||||||
|
|
||||||
|
// Enable FM support.
|
||||||
|
#define MODE_FM
|
||||||
|
|
||||||
|
// Enable AX.25 support, this is only enabled if FM is also enabled.
|
||||||
|
#define MODE_AX25
|
||||||
|
|
||||||
// Allow for the use of high quality external clock oscillators
|
// Allow for the use of high quality external clock oscillators
|
||||||
// The number is the frequency of the oscillator in Hertz.
|
// The number is the frequency of the oscillator in Hertz.
|
||||||
//
|
//
|
||||||
@@ -35,16 +66,16 @@
|
|||||||
// For 19.2 MHz
|
// For 19.2 MHz
|
||||||
// #define EXTERNAL_OSC 19200000
|
// #define EXTERNAL_OSC 19200000
|
||||||
|
|
||||||
// Use a higher baudrate for host communication. Required for FM network !
|
// Select a baud rate for host communication. The faster speeds are needed for external FM to work.
|
||||||
#define SERIAL_SPEED 115200 //suitable for most older boards (Arduino, Due STM32F1_POG etc). External FM will NOT work with this !
|
// #define SERIAL_SPEED 115200 // Suitable for most older boards (Arduino Due, STM32F1_POG, etc). External FM will NOT work with this!
|
||||||
// #define SERIAL_SPEED 230400 // Only works on newer board M4, M7, Teensy. External FM might work with this
|
// #define SERIAL_SPEED 230400 // Only works on newer boards like fast M4, M7, Teensy 3.x. External FM might work with this
|
||||||
// #define SERIAL_SPEED 460800 // Only works on newer board M4, M7, Teensy. External FM should work with this
|
#define SERIAL_SPEED 460800 // Only works on newer boards like fast M4, M7, Teensy 3.x. External FM should work with this
|
||||||
|
|
||||||
// Allow the use of the COS line to lockout the modem
|
// Allow the use of the COS line to lockout the modem
|
||||||
// #define USE_COS_AS_LOCKOUT
|
// #define USE_COS_AS_LOCKOUT
|
||||||
|
|
||||||
// Use pins to output the current mode via LEDs
|
// Use pins to output the current mode via LEDs
|
||||||
// #define MODE_LEDS
|
#define MODE_LEDS
|
||||||
|
|
||||||
// For the original Arduino Due pin layout
|
// For the original Arduino Due pin layout
|
||||||
// #define ARDUINO_DUE_PAPA
|
// #define ARDUINO_DUE_PAPA
|
||||||
@@ -54,7 +85,7 @@
|
|||||||
#define STM32F1_POG
|
#define STM32F1_POG
|
||||||
#else
|
#else
|
||||||
// For the ZUM V1.0 and V1.0.1 boards pin layout
|
// For the ZUM V1.0 and V1.0.1 boards pin layout
|
||||||
#define ARDUINO_DUE_ZUM_V10
|
// #define ARDUINO_DUE_ZUM_V10
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For the SP8NTH board
|
// For the SP8NTH board
|
||||||
@@ -71,10 +102,13 @@
|
|||||||
// #define VK6MST_TEENSY_PI3_SHIELD_I2C
|
// #define VK6MST_TEENSY_PI3_SHIELD_I2C
|
||||||
|
|
||||||
// Pass RSSI information to the host
|
// Pass RSSI information to the host
|
||||||
// #define SEND_RSSI_DATA
|
#define SEND_RSSI_DATA
|
||||||
|
|
||||||
// Use the modem as a serial repeater for Nextion displays
|
// Use the modem as a serial repeater for Nextion displays
|
||||||
// #define SERIAL_REPEATER
|
#define SERIAL_REPEATER
|
||||||
|
|
||||||
|
// Use the modem as an I2C repeater for OLED displays
|
||||||
|
// #define I2C_REPEATER
|
||||||
|
|
||||||
// To reduce CPU load, you can remove the DC blocker by commenting out the next line
|
// To reduce CPU load, you can remove the DC blocker by commenting out the next line
|
||||||
#define USE_DCBLOCKER
|
#define USE_DCBLOCKER
|
||||||
@@ -86,10 +120,20 @@
|
|||||||
// Use the YSF and P25 LEDs for NXDN
|
// Use the YSF and P25 LEDs for NXDN
|
||||||
// #define USE_ALTERNATE_NXDN_LEDS
|
// #define USE_ALTERNATE_NXDN_LEDS
|
||||||
|
|
||||||
|
// Use the D-Star and P25 LEDs for M17
|
||||||
|
#define USE_ALTERNATE_M17_LEDS
|
||||||
|
|
||||||
// Use the D-Star and DMR LEDs for POCSAG
|
// Use the D-Star and DMR LEDs for POCSAG
|
||||||
// #define USE_ALTERNATE_POCSAG_LEDS
|
#define USE_ALTERNATE_POCSAG_LEDS
|
||||||
|
|
||||||
// Use the D-Star and YSF LEDs for FM
|
// Use the D-Star and YSF LEDs for FM
|
||||||
#define USE_ALTERNATE_FM_LEDS
|
#define USE_ALTERNATE_FM_LEDS
|
||||||
|
|
||||||
|
#if defined(STM32F1_POG)
|
||||||
|
// Slower boards need to run their serial at 115200 baud
|
||||||
|
#undef SERIAL_SPEED
|
||||||
|
#define SERIAL_SPEED 115200
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 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
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DMRDMORX.h"
|
#include "DMRDMORX.h"
|
||||||
#include "DMRSlotType.h"
|
#include "DMRSlotType.h"
|
||||||
@@ -423,3 +426,6 @@ void CDMRDMORX::writeRSSIData(uint8_t* frame)
|
|||||||
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
|
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2020 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
|
||||||
@@ -16,10 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#if !defined(DMRDMORX_H)
|
#if !defined(DMRDMORX_H)
|
||||||
#define DMRDMORX_H
|
#define DMRDMORX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
const uint16_t DMO_BUFFER_LENGTH_SAMPLES = 1440U; // 60ms at 24 kHz
|
const uint16_t DMO_BUFFER_LENGTH_SAMPLES = 1440U; // 60ms at 24 kHz
|
||||||
@@ -67,3 +70,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
*
|
*
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DMRSlotType.h"
|
#include "DMRSlotType.h"
|
||||||
|
|
||||||
@@ -104,7 +107,7 @@ void CDMRDMOTX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -161,3 +164,5 @@ void CDMRDMOTX::setTXDelay(uint8_t delay)
|
|||||||
m_txDelay = 1200U;
|
m_txDelay = 1200U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2020 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
|
||||||
@@ -17,10 +17,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#if !defined(DMRDMOTX_H)
|
#if !defined(DMRDMOTX_H)
|
||||||
#define DMRDMOTX_H
|
#define DMRDMOTX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
@@ -29,7 +32,7 @@ class CDMRDMOTX {
|
|||||||
public:
|
public:
|
||||||
CDMRDMOTX();
|
CDMRDMOTX();
|
||||||
|
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
@@ -51,3 +54,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 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
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DMRIdleRX.h"
|
#include "DMRIdleRX.h"
|
||||||
#include "DMRSlotType.h"
|
#include "DMRSlotType.h"
|
||||||
@@ -209,3 +212,6 @@ void CDMRIdleRX::setColorCode(uint8_t colorCode)
|
|||||||
{
|
{
|
||||||
m_colorCode = colorCode;
|
m_colorCode = colorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2020 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
|
||||||
@@ -16,10 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#if !defined(DMRIDLERX_H)
|
#if !defined(DMRIDLERX_H)
|
||||||
#define DMRIDLERX_H
|
#define DMRIDLERX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
class CDMRIdleRX {
|
class CDMRIdleRX {
|
||||||
@@ -49,3 +52,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2020 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
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DMRRX.h"
|
#include "DMRRX.h"
|
||||||
|
|
||||||
@@ -68,3 +71,5 @@ void CDMRRX::reset()
|
|||||||
m_slot2RX.reset();
|
m_slot2RX.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2020 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
|
||||||
@@ -16,10 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#if !defined(DMRRX_H)
|
#if !defined(DMRRX_H)
|
||||||
#define DMRRX_H
|
#define DMRRX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "DMRSlotRX.h"
|
#include "DMRSlotRX.h"
|
||||||
|
|
||||||
class CDMRRX {
|
class CDMRRX {
|
||||||
@@ -40,3 +43,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 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
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DMRSlotRX.h"
|
#include "DMRSlotRX.h"
|
||||||
#include "DMRSlotType.h"
|
#include "DMRSlotType.h"
|
||||||
@@ -400,3 +403,6 @@ void CDMRSlotRX::writeRSSIData(uint8_t* frame)
|
|||||||
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
|
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2020 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
|
||||||
@@ -16,10 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#if !defined(DMRSLOTRX_H)
|
#if !defined(DMRSLOTRX_H)
|
||||||
#define DMRSLOTRX_H
|
#define DMRSLOTRX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
enum DMRRX_STATE {
|
enum DMRRX_STATE {
|
||||||
@@ -70,3 +73,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2020 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
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DMRSlotType.h"
|
#include "DMRSlotType.h"
|
||||||
|
|
||||||
@@ -285,3 +288,5 @@ void CDMRSlotType::encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) c
|
|||||||
frame[20U] = (frame[20U] & 0x03U) | ((slotType[1U] << 6) & 0xC0U) | ((slotType[2U] >> 2) & 0x3CU);
|
frame[20U] = (frame[20U] & 0x03U) | ((slotType[1U] << 6) & 0xC0U) | ((slotType[2U] >> 2) & 0x3CU);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2020 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
|
||||||
@@ -16,6 +16,10 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#if !defined(DMRSLOTTYPE_H)
|
#if !defined(DMRSLOTTYPE_H)
|
||||||
#define DMRSLOTTYPE_H
|
#define DMRSLOTTYPE_H
|
||||||
|
|
||||||
@@ -35,3 +39,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
*
|
*
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DMRSlotType.h"
|
#include "DMRSlotType.h"
|
||||||
|
|
||||||
@@ -144,7 +147,7 @@ void CDMRTX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDMRTX::writeData1(const uint8_t* data, uint8_t length)
|
uint8_t CDMRTX::writeData1(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -168,7 +171,7 @@ uint8_t CDMRTX::writeData1(const uint8_t* data, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDMRTX::writeData2(const uint8_t* data, uint8_t length)
|
uint8_t CDMRTX::writeData2(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -192,7 +195,7 @@ uint8_t CDMRTX::writeData2(const uint8_t* data, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint8_t length)
|
uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 9U)
|
if (length != 9U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -208,7 +211,7 @@ uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDMRTX::writeAbort(const uint8_t* data, uint8_t length)
|
uint8_t CDMRTX::writeAbort(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -414,3 +417,6 @@ uint32_t CDMRTX::getFrameCount()
|
|||||||
{
|
{
|
||||||
return m_frameCount;
|
return m_frameCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2020 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
|
||||||
@@ -17,10 +17,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
|
||||||
#if !defined(DMRTX_H)
|
#if !defined(DMRTX_H)
|
||||||
#define DMRTX_H
|
#define DMRTX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
@@ -38,11 +41,11 @@ class CDMRTX {
|
|||||||
public:
|
public:
|
||||||
CDMRTX();
|
CDMRTX();
|
||||||
|
|
||||||
uint8_t writeData1(const uint8_t* data, uint8_t length);
|
uint8_t writeData1(const uint8_t* data, uint16_t length);
|
||||||
uint8_t writeData2(const uint8_t* data, uint8_t length);
|
uint8_t writeData2(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
uint8_t writeShortLC(const uint8_t* data, uint8_t length);
|
uint8_t writeShortLC(const uint8_t* data, uint16_t length);
|
||||||
uint8_t writeAbort(const uint8_t* data, uint8_t length);
|
uint8_t writeAbort(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void setStart(bool start);
|
void setStart(bool start);
|
||||||
void setCal(bool start);
|
void setCal(bool start);
|
||||||
@@ -83,3 +86,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+37
-17
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2015,2017,2020 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
|
||||||
@@ -19,30 +19,50 @@
|
|||||||
#if !defined(DSTARDEFINES_H)
|
#if !defined(DSTARDEFINES_H)
|
||||||
#define DSTARDEFINES_H
|
#define DSTARDEFINES_H
|
||||||
|
|
||||||
const unsigned int DSTAR_RADIO_BIT_LENGTH = 5U; // At 24 kHz sample rate
|
const unsigned int DSTAR_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
|
||||||
|
|
||||||
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
|
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
|
||||||
const unsigned int DSTAR_HEADER_LENGTH_BITS = DSTAR_HEADER_LENGTH_BYTES * 8U;
|
|
||||||
|
|
||||||
const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U;
|
const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U;
|
||||||
const unsigned int DSTAR_FEC_SECTION_LENGTH_BITS = 660U;
|
const unsigned int DSTAR_FEC_SECTION_LENGTH_SYMBOLS = 660U;
|
||||||
|
const unsigned int DSTAR_FEC_SECTION_LENGTH_SAMPLES = DSTAR_FEC_SECTION_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U;
|
const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U;
|
||||||
const unsigned int DSTAR_DATA_LENGTH_BITS = DSTAR_DATA_LENGTH_BYTES * 8U;
|
const unsigned int DSTAR_DATA_LENGTH_SYMBOLS = DSTAR_DATA_LENGTH_BYTES * 8U;
|
||||||
|
const unsigned int DSTAR_DATA_LENGTH_SAMPLES = DSTAR_DATA_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
const uint8_t DSTAR_EOT_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
const unsigned int DSTAR_END_SYNC_LENGTH_BYTES = 6U;
|
||||||
const unsigned int DSTAR_EOT_LENGTH_BYTES = 6U;
|
const unsigned int DSTAR_END_SYNC_LENGTH_BITS = DSTAR_END_SYNC_LENGTH_BYTES * 8U;
|
||||||
const unsigned int DSTAR_EOT_LENGTH_BITS = DSTAR_EOT_LENGTH_BYTES * 8U;
|
|
||||||
|
|
||||||
const uint8_t DSTAR_DATA_SYNC_LENGTH_BYTES = 3U;
|
const unsigned int DSTAR_FRAME_SYNC_LENGTH_BYTES = 3U;
|
||||||
const uint8_t DSTAR_DATA_SYNC_LENGTH_BITS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U;
|
const unsigned int DSTAR_FRAME_SYNC_LENGTH_SYMBOLS = DSTAR_FRAME_SYNC_LENGTH_BYTES * 8U;
|
||||||
|
const unsigned int DSTAR_FRAME_SYNC_LENGTH_SAMPLES = DSTAR_FRAME_SYNC_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16};
|
const unsigned int DSTAR_DATA_SYNC_LENGTH_BYTES = 3U;
|
||||||
|
const unsigned int DSTAR_DATA_SYNC_LENGTH_SYMBOLS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U;
|
||||||
|
const unsigned int DSTAR_DATA_SYNC_LENGTH_SAMPLES = DSTAR_DATA_SYNC_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U;
|
const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16};
|
||||||
const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U;
|
|
||||||
|
|
||||||
const uint8_t DSTAR_SCRAMBLER_BYTES[] = {0x70U, 0x4FU, 0x93U};
|
// D-Star bit order version of 0x55 0x6E 0x0A
|
||||||
|
const uint32_t DSTAR_FRAME_SYNC_DATA = 0x00557650U;
|
||||||
|
const uint32_t DSTAR_FRAME_SYNC_MASK = 0x00FFFFFFU;
|
||||||
|
const bool DSTAR_FRAME_SYNC_SYMBOLS[] = {false, true, false, true, false, true, false, true, false, true, true, true, false, true, true, false, false, true, false, true, false, false, false, false};
|
||||||
|
|
||||||
|
// D-Star bit order version of 0x55 0x2D 0x16
|
||||||
|
const uint32_t DSTAR_DATA_SYNC_DATA = 0x00AAB468U;
|
||||||
|
const uint32_t DSTAR_DATA_SYNC_MASK = 0x00FFFFFFU;
|
||||||
|
const bool DSTAR_DATA_SYNC_SYMBOLS[] = {true, false, true, false, true, false, true, false, true, false, true, true, false, true, false, false, false, true, true, false, true, false, false, false};
|
||||||
|
|
||||||
|
// D-Star bit order version of 0x55 0x55 0xC8 0x7A
|
||||||
|
const uint32_t DSTAR_END_SYNC_DATA = 0xAAAA135EU;
|
||||||
|
const uint32_t DSTAR_END_SYNC_MASK = 0xFFFFFFFFU;
|
||||||
|
const uint8_t DSTAR_END_SYNC_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U;
|
||||||
|
const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U;
|
||||||
|
|
||||||
|
const uint8_t DSTAR_SCRAMBLER_BYTES[] = {0x70U, 0x4FU, 0x93U};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+249
-142
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -18,31 +18,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DStarRX.h"
|
#include "DStarRX.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
const unsigned int BUFFER_LENGTH = 200U;
|
const unsigned int MAX_FRAMES = 150U;
|
||||||
|
|
||||||
const uint32_t PLLMAX = 0x10000U;
|
|
||||||
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_BIT_LENGTH;
|
|
||||||
const uint32_t INC = PLLINC / 32U;
|
|
||||||
|
|
||||||
const unsigned int MAX_SYNC_BITS = 100U * DSTAR_DATA_LENGTH_BITS;
|
|
||||||
|
|
||||||
// D-Star bit order version of 0x55 0x55 0x6E 0x0A
|
// D-Star bit order version of 0x55 0x55 0x6E 0x0A
|
||||||
const uint32_t FRAME_SYNC_DATA = 0x00557650U;
|
const uint64_t FRAME_SYNC_DATA = 0x0000000000557650U;
|
||||||
const uint32_t FRAME_SYNC_MASK = 0x00FFFFFFU;
|
const uint64_t FRAME_SYNC_MASK = 0x0000000000FFFFFFU;
|
||||||
const uint8_t FRAME_SYNC_ERRS = 2U;
|
const uint8_t FRAME_SYNC_ERRS = 2U;
|
||||||
|
|
||||||
// D-Star bit order version of 0x55 0x2D 0x16
|
// D-Star bit order version of 0x55 0x2D 0x16
|
||||||
const uint32_t DATA_SYNC_DATA = 0x00AAB468U;
|
const uint64_t DATA_SYNC_DATA = 0x0000000000AAB468U;
|
||||||
const uint32_t DATA_SYNC_MASK = 0x00FFFFFFU;
|
const uint64_t DATA_SYNC_MASK = 0x0000000000FFFFFFU;
|
||||||
const uint8_t DATA_SYNC_ERRS = 2U;
|
const uint8_t DATA_SYNC_ERRS = 2U;
|
||||||
|
|
||||||
// D-Star bit order version of 0x55 0x55 0xC8 0x7A
|
// D-Star bit order version of 0x55 0x55 0xC8 0x7A
|
||||||
const uint32_t END_SYNC_DATA = 0xAAAA135EU;
|
const uint64_t END_SYNC_DATA = 0x0000AAAAAAAA135EU;
|
||||||
const uint32_t END_SYNC_MASK = 0xFFFFFFFFU;
|
const uint64_t END_SYNC_MASK = 0x0000FFFFFFFFFFFFU;
|
||||||
const uint8_t END_SYNC_ERRS = 1U;
|
const uint8_t END_SYNC_ERRS = 1U;
|
||||||
|
|
||||||
const uint8_t BIT_MASK_TABLE0[] = {0x7FU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0xFEU};
|
const uint8_t BIT_MASK_TABLE0[] = {0x7FU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0xFEU};
|
||||||
@@ -237,14 +234,24 @@ const uint16_t CCITT_TABLE[] = {
|
|||||||
0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U,
|
0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U,
|
||||||
0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U};
|
0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U};
|
||||||
|
|
||||||
|
const uint16_t NOENDPTR = 9999U;
|
||||||
|
|
||||||
CDStarRX::CDStarRX() :
|
CDStarRX::CDStarRX() :
|
||||||
m_pll(0U),
|
|
||||||
m_prev(false),
|
|
||||||
m_rxState(DSRXS_NONE),
|
m_rxState(DSRXS_NONE),
|
||||||
m_patternBuffer(0x00U),
|
m_bitBuffer(),
|
||||||
m_rxBuffer(),
|
m_headerBuffer(),
|
||||||
m_rxBufferBits(0U),
|
m_dataBuffer(),
|
||||||
m_dataBits(0U),
|
m_bitPtr(0U),
|
||||||
|
m_headerPtr(0U),
|
||||||
|
m_dataPtr(0U),
|
||||||
|
m_startPtr(NOENDPTR),
|
||||||
|
m_syncPtr(NOENDPTR),
|
||||||
|
m_minSyncPtr(NOENDPTR),
|
||||||
|
m_maxSyncPtr(NOENDPTR),
|
||||||
|
m_maxFrameCorr(0),
|
||||||
|
m_maxDataCorr(0),
|
||||||
|
m_frameCount(0U),
|
||||||
|
m_countdown(0U),
|
||||||
m_mar(0U),
|
m_mar(0U),
|
||||||
m_pathMetric(),
|
m_pathMetric(),
|
||||||
m_pathMemory0(),
|
m_pathMemory0(),
|
||||||
@@ -259,14 +266,20 @@ m_rssiCount(0U)
|
|||||||
|
|
||||||
void CDStarRX::reset()
|
void CDStarRX::reset()
|
||||||
{
|
{
|
||||||
m_pll = 0U;
|
m_rxState = DSRXS_NONE;
|
||||||
m_prev = false;
|
m_headerPtr = 0U;
|
||||||
m_rxState = DSRXS_NONE;
|
m_dataPtr = 0U;
|
||||||
m_patternBuffer = 0x00U;
|
m_bitPtr = 0U;
|
||||||
m_rxBufferBits = 0U;
|
m_maxFrameCorr = 0;
|
||||||
m_dataBits = 0U;
|
m_maxDataCorr = 0;
|
||||||
m_rssiAccum = 0U;
|
m_startPtr = NOENDPTR;
|
||||||
m_rssiCount = 0U;
|
m_syncPtr = NOENDPTR;
|
||||||
|
m_minSyncPtr = NOENDPTR;
|
||||||
|
m_maxSyncPtr = NOENDPTR;
|
||||||
|
m_frameCount = 0U;
|
||||||
|
m_countdown = 0U;
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length)
|
void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length)
|
||||||
@@ -275,125 +288,117 @@ void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t lengt
|
|||||||
m_rssiAccum += rssi[i];
|
m_rssiAccum += rssi[i];
|
||||||
m_rssiCount++;
|
m_rssiCount++;
|
||||||
|
|
||||||
bool bit = samples[i] < 0;
|
q15_t sample = samples[i];
|
||||||
|
|
||||||
if (bit != m_prev) {
|
m_bitBuffer[m_bitPtr] <<= 1;
|
||||||
if (m_pll < (PLLMAX / 2U))
|
if (sample < 0)
|
||||||
m_pll += INC;
|
m_bitBuffer[m_bitPtr] |= 0x01U;
|
||||||
else
|
|
||||||
m_pll -= INC;
|
m_dataBuffer[m_dataPtr] = sample;
|
||||||
|
|
||||||
|
switch (m_rxState) {
|
||||||
|
case DSRXS_HEADER:
|
||||||
|
processHeader(sample);
|
||||||
|
break;
|
||||||
|
case DSRXS_DATA:
|
||||||
|
processData();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
processNone(sample);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_prev = bit;
|
m_dataPtr++;
|
||||||
|
if (m_dataPtr >= DSTAR_DATA_LENGTH_SAMPLES)
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
|
||||||
m_pll += PLLINC;
|
m_bitPtr++;
|
||||||
|
if (m_bitPtr >= DSTAR_RADIO_SYMBOL_LENGTH)
|
||||||
if (m_pll >= PLLMAX) {
|
m_bitPtr = 0U;
|
||||||
m_pll -= PLLMAX;
|
|
||||||
|
|
||||||
switch (m_rxState) {
|
|
||||||
case DSRXS_NONE:
|
|
||||||
processNone(bit);
|
|
||||||
break;
|
|
||||||
case DSRXS_HEADER:
|
|
||||||
processHeader(bit);
|
|
||||||
break;
|
|
||||||
case DSRXS_DATA:
|
|
||||||
processData(bit);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDStarRX::processNone(bool bit)
|
void CDStarRX::processNone(q15_t sample)
|
||||||
{
|
{
|
||||||
m_patternBuffer <<= 1;
|
|
||||||
if (bit)
|
|
||||||
m_patternBuffer |= 0x01U;
|
|
||||||
|
|
||||||
// Fuzzy matching of the frame sync sequence
|
// Fuzzy matching of the frame sync sequence
|
||||||
if (countBits32((m_patternBuffer & FRAME_SYNC_MASK) ^ FRAME_SYNC_DATA) <= FRAME_SYNC_ERRS) {
|
bool ret = correlateFrameSync();
|
||||||
DEBUG1("DStarRX: found frame sync in None");
|
if (ret) {
|
||||||
|
m_countdown = 5U;
|
||||||
|
|
||||||
::memset(m_rxBuffer, 0x00U, DSTAR_FEC_SECTION_LENGTH_BYTES);
|
m_headerBuffer[m_headerPtr] = sample;
|
||||||
m_rxBufferBits = 0U;
|
m_headerPtr++;
|
||||||
|
|
||||||
m_rssiAccum = 0U;
|
m_rssiAccum = 0U;
|
||||||
m_rssiCount = 0U;
|
m_rssiCount = 0U;
|
||||||
|
|
||||||
m_rxState = DSRXS_HEADER;
|
m_rxState = DSRXS_HEADER;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exact matching of the data sync bit sequence
|
// Fuzzy matching of the data sync bit sequence
|
||||||
if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) == 0U) {
|
ret = correlateDataSync();
|
||||||
|
if (ret) {
|
||||||
DEBUG1("DStarRX: found data sync in None");
|
DEBUG1("DStarRX: found data sync in None");
|
||||||
|
|
||||||
io.setDecode(true);
|
io.setDecode(true);
|
||||||
io.setADCDetection(true);
|
io.setADCDetection(true);
|
||||||
|
|
||||||
// Suppress RSSI on the dummy sync message
|
m_rxState = DSRXS_DATA;
|
||||||
m_rssiAccum = 0U;
|
|
||||||
m_rssiCount = 0U;
|
|
||||||
|
|
||||||
::memcpy(m_rxBuffer, DSTAR_DATA_SYNC_BYTES, DSTAR_DATA_LENGTH_BYTES);
|
|
||||||
writeRSSIData(m_rxBuffer);
|
|
||||||
|
|
||||||
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
|
|
||||||
m_rxBufferBits = 0U;
|
|
||||||
|
|
||||||
m_dataBits = MAX_SYNC_BITS;
|
|
||||||
m_rxState = DSRXS_DATA;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDStarRX::processHeader(bool bit)
|
void CDStarRX::processHeader(q15_t sample)
|
||||||
{
|
{
|
||||||
m_patternBuffer <<= 1;
|
if (m_countdown > 0U) {
|
||||||
if (bit)
|
correlateFrameSync();
|
||||||
m_patternBuffer |= 0x01U;
|
m_countdown--;
|
||||||
|
}
|
||||||
|
|
||||||
WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit);
|
m_headerBuffer[m_headerPtr] = sample;
|
||||||
m_rxBufferBits++;
|
m_headerPtr++;
|
||||||
|
|
||||||
// A full FEC header
|
// A full FEC header
|
||||||
if (m_rxBufferBits == DSTAR_FEC_SECTION_LENGTH_BITS) {
|
if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH)) {
|
||||||
// Process the scrambling, interleaving and FEC, then return if the chcksum was correct
|
uint8_t buffer[DSTAR_FEC_SECTION_LENGTH_BYTES];
|
||||||
unsigned char header[DSTAR_HEADER_LENGTH_BYTES];
|
samplesToBits(m_headerBuffer, DSTAR_RADIO_SYMBOL_LENGTH, DSTAR_FEC_SECTION_LENGTH_SYMBOLS, buffer, DSTAR_FEC_SECTION_LENGTH_SAMPLES);
|
||||||
bool ok = rxHeader(m_rxBuffer, header);
|
|
||||||
if (ok) {
|
// Process the scrambling, interleaving and FEC, then return true if the chcksum was correct
|
||||||
|
uint8_t header[DSTAR_HEADER_LENGTH_BYTES];
|
||||||
|
bool ok = rxHeader(buffer, header);
|
||||||
|
if (!ok) {
|
||||||
|
// The checksum failed, return to looking for syncs
|
||||||
|
m_rxState = DSRXS_NONE;
|
||||||
|
m_maxFrameCorr = 0;
|
||||||
|
m_maxDataCorr = 0;
|
||||||
|
} else {
|
||||||
io.setDecode(true);
|
io.setDecode(true);
|
||||||
io.setADCDetection(true);
|
io.setADCDetection(true);
|
||||||
|
|
||||||
writeRSSIHeader(header);
|
writeRSSIHeader(header);
|
||||||
|
|
||||||
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
|
|
||||||
m_rxBufferBits = 0U;
|
|
||||||
|
|
||||||
m_rxState = DSRXS_DATA;
|
|
||||||
m_dataBits = MAX_SYNC_BITS;
|
|
||||||
} else {
|
|
||||||
// The checksum failed, return to looking for syncs
|
|
||||||
m_rxState = DSRXS_NONE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ready to start the first data section
|
||||||
|
if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + 2U * DSTAR_RADIO_SYMBOL_LENGTH)) {
|
||||||
|
m_frameCount = 0U;
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
|
||||||
|
m_startPtr = 476U;
|
||||||
|
m_syncPtr = 471U;
|
||||||
|
m_maxSyncPtr = 472U;
|
||||||
|
m_minSyncPtr = 470U;
|
||||||
|
|
||||||
|
DEBUG5("DStarRX: calc start/sync/max/min", m_startPtr, m_syncPtr, m_maxSyncPtr, m_minSyncPtr);
|
||||||
|
|
||||||
|
m_rxState = DSRXS_DATA;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDStarRX::processData(bool bit)
|
void CDStarRX::processData()
|
||||||
{
|
{
|
||||||
m_patternBuffer <<= 1;
|
|
||||||
if (bit)
|
|
||||||
m_patternBuffer |= 0x01U;
|
|
||||||
|
|
||||||
WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit);
|
|
||||||
m_rxBufferBits++;
|
|
||||||
|
|
||||||
// Fuzzy matching of the end frame sequences
|
// Fuzzy matching of the end frame sequences
|
||||||
if (countBits32((m_patternBuffer & END_SYNC_MASK) ^ END_SYNC_DATA) <= END_SYNC_ERRS) {
|
if (countBits64((m_bitBuffer[m_bitPtr] & DSTAR_END_SYNC_MASK) ^ DSTAR_END_SYNC_DATA) <= END_SYNC_ERRS) {
|
||||||
DEBUG1("DStarRX: Found end sync in Data");
|
DEBUG1("DStarRX: Found end sync in Data");
|
||||||
|
|
||||||
io.setDecode(false);
|
io.setDecode(false);
|
||||||
@@ -401,35 +406,24 @@ void CDStarRX::processData(bool bit)
|
|||||||
|
|
||||||
serial.writeDStarEOT();
|
serial.writeDStarEOT();
|
||||||
|
|
||||||
|
m_maxFrameCorr = 0;
|
||||||
|
m_maxDataCorr = 0;
|
||||||
|
|
||||||
m_rxState = DSRXS_NONE;
|
m_rxState = DSRXS_NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fuzzy matching of the data sync bit sequence
|
// Fuzzy matching of the data sync bit sequence
|
||||||
bool syncSeen = false;
|
if (m_minSyncPtr < m_maxSyncPtr) {
|
||||||
if (m_rxBufferBits >= (DSTAR_DATA_LENGTH_BITS - 3U)) {
|
if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr)
|
||||||
if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) <= DATA_SYNC_ERRS) {
|
correlateDataSync();
|
||||||
m_rxBufferBits = DSTAR_DATA_LENGTH_BITS;
|
} else {
|
||||||
m_dataBits = MAX_SYNC_BITS;
|
if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr)
|
||||||
syncSeen = true;
|
correlateDataSync();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if the sync is arriving late
|
// We've not seen a data sync for too long, signal RXLOST and change to RX_NONE
|
||||||
if (m_rxBufferBits == DSTAR_DATA_LENGTH_BITS && !syncSeen) {
|
if (m_frameCount >= MAX_FRAMES) {
|
||||||
for (uint8_t i = 1U; i <= 3U; i++) {
|
|
||||||
uint32_t syncMask = DATA_SYNC_MASK >> i;
|
|
||||||
uint32_t syncData = DATA_SYNC_DATA >> i;
|
|
||||||
if (countBits32((m_patternBuffer & syncMask) ^ syncData) <= DATA_SYNC_ERRS) {
|
|
||||||
m_rxBufferBits -= i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_dataBits--;
|
|
||||||
|
|
||||||
if (m_dataBits == 0U) {
|
|
||||||
DEBUG1("DStarRX: data sync timed out, lost lock");
|
DEBUG1("DStarRX: data sync timed out, lost lock");
|
||||||
|
|
||||||
io.setDecode(false);
|
io.setDecode(false);
|
||||||
@@ -437,24 +431,35 @@ void CDStarRX::processData(bool bit)
|
|||||||
|
|
||||||
serial.writeDStarLost();
|
serial.writeDStarLost();
|
||||||
|
|
||||||
|
m_maxFrameCorr = 0;
|
||||||
|
m_maxDataCorr = 0;
|
||||||
|
|
||||||
m_rxState = DSRXS_NONE;
|
m_rxState = DSRXS_NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a data frame to the host if the required number of bits have been received, or if a data sync has been seen
|
// Send a data frame to the host if the required number of bits have been received
|
||||||
if (m_rxBufferBits == DSTAR_DATA_LENGTH_BITS) {
|
if (m_dataPtr == m_maxSyncPtr) {
|
||||||
if (syncSeen) {
|
uint8_t buffer[DSTAR_DATA_LENGTH_BYTES + 2U];
|
||||||
m_rxBuffer[9U] = DSTAR_DATA_SYNC_BYTES[9U];
|
samplesToBits(m_dataBuffer, m_startPtr, DSTAR_DATA_LENGTH_SYMBOLS, buffer, DSTAR_DATA_LENGTH_SAMPLES);
|
||||||
m_rxBuffer[10U] = DSTAR_DATA_SYNC_BYTES[10U];
|
|
||||||
m_rxBuffer[11U] = DSTAR_DATA_SYNC_BYTES[11U];
|
|
||||||
writeRSSIData(m_rxBuffer);
|
|
||||||
} else {
|
|
||||||
serial.writeDStarData(m_rxBuffer, DSTAR_DATA_LENGTH_BYTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the next frame
|
if ((m_frameCount % 21U) == 0U) {
|
||||||
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
|
if (m_frameCount == 0U) {
|
||||||
m_rxBufferBits = 0U;
|
buffer[9U] = DSTAR_DATA_SYNC_BYTES[9U];
|
||||||
|
buffer[10U] = DSTAR_DATA_SYNC_BYTES[10U];
|
||||||
|
buffer[11U] = DSTAR_DATA_SYNC_BYTES[11U];
|
||||||
|
DEBUG5("DStarRX: found start/sync/max/min", m_startPtr, m_syncPtr, m_maxSyncPtr, m_minSyncPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeRSSIData(buffer);
|
||||||
|
} else {
|
||||||
|
serial.writeDStarData(buffer, DSTAR_DATA_LENGTH_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_frameCount++;
|
||||||
|
|
||||||
|
m_maxFrameCorr = 0;
|
||||||
|
m_maxDataCorr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,6 +505,105 @@ void CDStarRX::writeRSSIData(unsigned char* data)
|
|||||||
m_rssiCount = 0U;
|
m_rssiCount = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CDStarRX::correlateFrameSync()
|
||||||
|
{
|
||||||
|
if (countBits64((m_bitBuffer[m_bitPtr] & DSTAR_FRAME_SYNC_MASK) ^ DSTAR_FRAME_SYNC_DATA) <= FRAME_SYNC_ERRS) {
|
||||||
|
uint16_t ptr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_FRAME_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
|
||||||
|
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
q31_t corr = 0;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < DSTAR_FRAME_SYNC_LENGTH_SYMBOLS; i++) {
|
||||||
|
q15_t val = m_dataBuffer[ptr];
|
||||||
|
|
||||||
|
if (DSTAR_FRAME_SYNC_SYMBOLS[i])
|
||||||
|
corr -= val;
|
||||||
|
else
|
||||||
|
corr += val;
|
||||||
|
|
||||||
|
ptr += DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
|
||||||
|
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (corr > m_maxFrameCorr) {
|
||||||
|
m_maxFrameCorr = corr;
|
||||||
|
m_headerPtr = 0U;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarRX::correlateDataSync()
|
||||||
|
{
|
||||||
|
uint8_t maxErrs = 0U;
|
||||||
|
if (m_rxState == DSRXS_DATA)
|
||||||
|
maxErrs = DATA_SYNC_ERRS;
|
||||||
|
|
||||||
|
if (countBits64((m_bitBuffer[m_bitPtr] & DSTAR_DATA_SYNC_MASK) ^ DSTAR_DATA_SYNC_DATA) <= maxErrs) {
|
||||||
|
uint16_t ptr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_DATA_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
|
||||||
|
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
q31_t corr = 0;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < DSTAR_DATA_SYNC_LENGTH_SYMBOLS; i++) {
|
||||||
|
q15_t val = m_dataBuffer[ptr];
|
||||||
|
|
||||||
|
if (DSTAR_DATA_SYNC_SYMBOLS[i])
|
||||||
|
corr -= val;
|
||||||
|
else
|
||||||
|
corr += val;
|
||||||
|
|
||||||
|
ptr += DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
|
||||||
|
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (corr > m_maxDataCorr) {
|
||||||
|
m_maxDataCorr = corr;
|
||||||
|
m_frameCount = 0U;
|
||||||
|
|
||||||
|
m_syncPtr = m_dataPtr;
|
||||||
|
|
||||||
|
m_startPtr = m_dataPtr + DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (m_startPtr >= DSTAR_DATA_LENGTH_SAMPLES)
|
||||||
|
m_startPtr -= DSTAR_DATA_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
m_maxSyncPtr = m_syncPtr + 1U;
|
||||||
|
if (m_maxSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES)
|
||||||
|
m_maxSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
m_minSyncPtr = m_syncPtr + DSTAR_DATA_LENGTH_SAMPLES - 1U;
|
||||||
|
if (m_minSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES)
|
||||||
|
m_minSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarRX::samplesToBits(const q15_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit)
|
||||||
|
{
|
||||||
|
for (uint16_t i = 0U; i < count; i++) {
|
||||||
|
q15_t sample = inBuffer[start];
|
||||||
|
|
||||||
|
if (sample < 0)
|
||||||
|
WRITE_BIT2(outBuffer, i, true);
|
||||||
|
else
|
||||||
|
WRITE_BIT2(outBuffer, i, false);
|
||||||
|
|
||||||
|
start += DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (start >= limit)
|
||||||
|
start -= limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CDStarRX::rxHeader(uint8_t* in, uint8_t* out)
|
bool CDStarRX::rxHeader(uint8_t* in, uint8_t* out)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -715,3 +819,6 @@ bool CDStarRX::checksum(const uint8_t* header) const
|
|||||||
|
|
||||||
return crc8[0U] == header[DSTAR_HEADER_LENGTH_BYTES - 2U] && crc8[1U] == header[DSTAR_HEADER_LENGTH_BYTES - 1U];
|
return crc8[0U] == header[DSTAR_HEADER_LENGTH_BYTES - 2U] && crc8[1U] == header[DSTAR_HEADER_LENGTH_BYTES - 1U];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2020 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
|
||||||
@@ -16,10 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
|
|
||||||
#if !defined(DSTARRX_H)
|
#if !defined(DSTARRX_H)
|
||||||
#define DSTARRX_H
|
#define DSTARRX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "DStarDefines.h"
|
#include "DStarDefines.h"
|
||||||
|
|
||||||
enum DSRX_STATE {
|
enum DSRX_STATE {
|
||||||
@@ -37,13 +40,21 @@ public:
|
|||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_pll;
|
|
||||||
bool m_prev;
|
|
||||||
DSRX_STATE m_rxState;
|
DSRX_STATE m_rxState;
|
||||||
uint32_t m_patternBuffer;
|
uint64_t m_bitBuffer[DSTAR_RADIO_SYMBOL_LENGTH];
|
||||||
uint8_t m_rxBuffer[100U];
|
q15_t m_headerBuffer[DSTAR_FEC_SECTION_LENGTH_SAMPLES + 2U * DSTAR_RADIO_SYMBOL_LENGTH];
|
||||||
unsigned int m_rxBufferBits;
|
q15_t m_dataBuffer[DSTAR_DATA_LENGTH_SAMPLES];
|
||||||
unsigned int m_dataBits;
|
uint16_t m_bitPtr;
|
||||||
|
uint16_t m_headerPtr;
|
||||||
|
uint16_t m_dataPtr;
|
||||||
|
uint16_t m_startPtr;
|
||||||
|
uint16_t m_syncPtr;
|
||||||
|
uint16_t m_minSyncPtr;
|
||||||
|
uint16_t m_maxSyncPtr;
|
||||||
|
q31_t m_maxFrameCorr;
|
||||||
|
q31_t m_maxDataCorr;
|
||||||
|
uint16_t m_frameCount;
|
||||||
|
uint8_t m_countdown;
|
||||||
unsigned int m_mar;
|
unsigned int m_mar;
|
||||||
int m_pathMetric[4U];
|
int m_pathMetric[4U];
|
||||||
unsigned int m_pathMemory0[42U];
|
unsigned int m_pathMemory0[42U];
|
||||||
@@ -54,9 +65,12 @@ private:
|
|||||||
uint32_t m_rssiAccum;
|
uint32_t m_rssiAccum;
|
||||||
uint16_t m_rssiCount;
|
uint16_t m_rssiCount;
|
||||||
|
|
||||||
void processNone(bool bit);
|
void processNone(q15_t sample);
|
||||||
void processHeader(bool bit);
|
void processHeader(q15_t sample);
|
||||||
void processData(bool bit);
|
void processData();
|
||||||
|
bool correlateFrameSync();
|
||||||
|
bool correlateDataSync();
|
||||||
|
void samplesToBits(const q15_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit);
|
||||||
void writeRSSIHeader(unsigned char* header);
|
void writeRSSIHeader(unsigned char* header);
|
||||||
void writeRSSIData(unsigned char* data);
|
void writeRSSIData(unsigned char* data);
|
||||||
bool rxHeader(uint8_t* in, uint8_t* out);
|
bool rxHeader(uint8_t* in, uint8_t* out);
|
||||||
@@ -68,3 +82,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+16
-11
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DStarTX.h"
|
#include "DStarTX.h"
|
||||||
|
|
||||||
@@ -198,7 +201,7 @@ m_txDelay(60U) // 100ms
|
|||||||
{
|
{
|
||||||
::memset(m_modState, 0x00U, 20U * sizeof(q15_t));
|
::memset(m_modState, 0x00U, 20U * sizeof(q15_t));
|
||||||
|
|
||||||
m_modFilter.L = DSTAR_RADIO_BIT_LENGTH;
|
m_modFilter.L = DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
m_modFilter.phaseLength = GAUSSIAN_0_35_FILTER_PHASE_LEN;
|
m_modFilter.phaseLength = GAUSSIAN_0_35_FILTER_PHASE_LEN;
|
||||||
m_modFilter.pCoeffs = GAUSSIAN_0_35_FILTER;
|
m_modFilter.pCoeffs = GAUSSIAN_0_35_FILTER;
|
||||||
m_modFilter.pState = m_modState;
|
m_modFilter.pState = m_modState;
|
||||||
@@ -216,8 +219,8 @@ void CDStarTX::process()
|
|||||||
for (uint16_t i = 0U; i < m_txDelay; i++)
|
for (uint16_t i = 0U; i < m_txDelay; i++)
|
||||||
m_poBuffer[m_poLen++] = BIT_SYNC;
|
m_poBuffer[m_poLen++] = BIT_SYNC;
|
||||||
} else {
|
} else {
|
||||||
uint8_t dummy;
|
|
||||||
// Pop the type byte off
|
// Pop the type byte off
|
||||||
|
uint8_t dummy;
|
||||||
m_buffer.get(dummy);
|
m_buffer.get(dummy);
|
||||||
|
|
||||||
uint8_t header[DSTAR_HEADER_LENGTH_BYTES];
|
uint8_t header[DSTAR_HEADER_LENGTH_BYTES];
|
||||||
@@ -255,8 +258,8 @@ void CDStarTX::process()
|
|||||||
m_buffer.get(dummy);
|
m_buffer.get(dummy);
|
||||||
|
|
||||||
for (uint8_t j = 0U; j < 3U; j++) {
|
for (uint8_t j = 0U; j < 3U; j++) {
|
||||||
for (uint8_t i = 0U; i < DSTAR_EOT_LENGTH_BYTES; i++)
|
for (uint8_t i = 0U; i < DSTAR_END_SYNC_LENGTH_BYTES; i++)
|
||||||
m_poBuffer[m_poLen++] = DSTAR_EOT_BYTES[i];
|
m_poBuffer[m_poLen++] = DSTAR_END_SYNC_BYTES[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
m_poPtr = 0U;
|
m_poPtr = 0U;
|
||||||
@@ -265,11 +268,11 @@ void CDStarTX::process()
|
|||||||
if (m_poLen > 0U) {
|
if (m_poLen > 0U) {
|
||||||
uint16_t space = io.getSpace();
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
while (space > (8U * DSTAR_RADIO_BIT_LENGTH)) {
|
while (space > (8U * DSTAR_RADIO_SYMBOL_LENGTH)) {
|
||||||
uint8_t c = m_poBuffer[m_poPtr++];
|
uint8_t c = m_poBuffer[m_poPtr++];
|
||||||
writeByte(c);
|
writeByte(c);
|
||||||
|
|
||||||
space -= 8U * DSTAR_RADIO_BIT_LENGTH;
|
space -= 8U * DSTAR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
if (m_poPtr >= m_poLen) {
|
if (m_poPtr >= m_poLen) {
|
||||||
m_poPtr = 0U;
|
m_poPtr = 0U;
|
||||||
@@ -280,7 +283,7 @@ void CDStarTX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDStarTX::writeHeader(const uint8_t* header, uint8_t length)
|
uint8_t CDStarTX::writeHeader(const uint8_t* header, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != DSTAR_HEADER_LENGTH_BYTES)
|
if (length != DSTAR_HEADER_LENGTH_BYTES)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -299,7 +302,7 @@ uint8_t CDStarTX::writeHeader(const uint8_t* header, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDStarTX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CDStarTX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != DSTAR_DATA_LENGTH_BYTES)
|
if (length != DSTAR_DATA_LENGTH_BYTES)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -415,7 +418,7 @@ void CDStarTX::txHeader(const uint8_t* in, uint8_t* out) const
|
|||||||
void CDStarTX::writeByte(uint8_t c)
|
void CDStarTX::writeByte(uint8_t c)
|
||||||
{
|
{
|
||||||
q15_t inBuffer[8U];
|
q15_t inBuffer[8U];
|
||||||
q15_t outBuffer[DSTAR_RADIO_BIT_LENGTH * 8U];
|
q15_t outBuffer[DSTAR_RADIO_SYMBOL_LENGTH * 8U];
|
||||||
|
|
||||||
uint8_t mask = 0x01U;
|
uint8_t mask = 0x01U;
|
||||||
|
|
||||||
@@ -430,7 +433,7 @@ void CDStarTX::writeByte(uint8_t c)
|
|||||||
|
|
||||||
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 8U);
|
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 8U);
|
||||||
|
|
||||||
io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U);
|
io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_SYMBOL_LENGTH * 8U);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDStarTX::setTXDelay(uint8_t delay)
|
void CDStarTX::setTXDelay(uint8_t delay)
|
||||||
@@ -446,3 +449,5 @@ uint8_t CDStarTX::getSpace() const
|
|||||||
return m_buffer.getSpace() / (DSTAR_DATA_LENGTH_BYTES + 1U);
|
return m_buffer.getSpace() / (DSTAR_DATA_LENGTH_BYTES + 1U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2020 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
|
||||||
@@ -16,19 +16,21 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
|
|
||||||
#if !defined(DSTARTX_H)
|
#if !defined(DSTARTX_H)
|
||||||
#define DSTARTX_H
|
#define DSTARTX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
class CDStarTX {
|
class CDStarTX {
|
||||||
public:
|
public:
|
||||||
CDStarTX();
|
CDStarTX();
|
||||||
|
|
||||||
uint8_t writeHeader(const uint8_t* header, uint8_t length);
|
uint8_t writeHeader(const uint8_t* header, uint16_t length);
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
uint8_t writeEOT();
|
uint8_t writeEOT();
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
@@ -52,3 +54,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2021 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
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
#define DEBUG3(a,b,c) serial.writeDebug((a),(b),(c))
|
#define DEBUG3(a,b,c) serial.writeDebug((a),(b),(c))
|
||||||
#define DEBUG4(a,b,c,d) serial.writeDebug((a),(b),(c),(d))
|
#define DEBUG4(a,b,c,d) serial.writeDebug((a),(b),(c),(d))
|
||||||
#define DEBUG5(a,b,c,d,e) serial.writeDebug((a),(b),(c),(d),(e))
|
#define DEBUG5(a,b,c,d,e) serial.writeDebug((a),(b),(c),(d),(e))
|
||||||
|
#define DEBUG_DUMP(a,b) serial.writeDebugDump((a),(b))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
* Copyright (C) 2020,2021 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
|
||||||
@@ -17,21 +17,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "FM.h"
|
#include "FM.h"
|
||||||
|
|
||||||
|
|
||||||
const uint16_t FM_TX_BLOCK_SIZE = 100U;
|
const uint16_t FM_TX_BLOCK_SIZE = 100U;
|
||||||
const uint16_t FM_SERIAL_BLOCK_SIZE = 84U;//this is the number of sample pairs to send over serial. One sample pair is 3bytes.
|
const uint16_t FM_SERIAL_BLOCK_SIZE = 80U;//this is the number of sample pairs to send over serial. One sample pair is 3bytes.
|
||||||
//three times this value shall never exceed 252
|
//three times this value shall never exceed 252
|
||||||
const uint16_t FM_SERIAL_BLOCK_SIZE_BYTES = FM_SERIAL_BLOCK_SIZE * 3U;
|
const uint16_t FM_SERIAL_BLOCK_SIZE_BYTES = FM_SERIAL_BLOCK_SIZE * 3U;
|
||||||
|
|
||||||
|
|
||||||
CFM::CFM() :
|
CFM::CFM() :
|
||||||
m_callsign(),
|
m_callsign(),
|
||||||
m_rfAck(),
|
m_rfAck(),
|
||||||
m_extAck(),
|
m_extAck(),
|
||||||
m_ctcssRX(),
|
m_ctcssRX(),
|
||||||
m_ctcssTX(),
|
m_ctcssTX(),
|
||||||
|
m_squelch(),
|
||||||
m_timeoutTone(),
|
m_timeoutTone(),
|
||||||
m_state(FS_LISTENING),
|
m_state(FS_LISTENING),
|
||||||
m_callsignAtStart(false),
|
m_callsignAtStart(false),
|
||||||
@@ -41,39 +45,49 @@ m_callsignTimer(),
|
|||||||
m_timeoutTimer(),
|
m_timeoutTimer(),
|
||||||
m_holdoffTimer(),
|
m_holdoffTimer(),
|
||||||
m_kerchunkTimer(),
|
m_kerchunkTimer(),
|
||||||
m_kerchunkTX(true),
|
|
||||||
m_ackMinTimer(),
|
m_ackMinTimer(),
|
||||||
m_ackDelayTimer(),
|
m_ackDelayTimer(),
|
||||||
m_hangTimer(),
|
m_hangTimer(),
|
||||||
m_statusTimer(),
|
m_statusTimer(),
|
||||||
|
m_reverseTimer(),
|
||||||
|
m_needReverse(false),
|
||||||
m_filterStage1( 724, 1448, 724, 32768, -37895, 21352),//3rd order Cheby Filter 300 to 2700Hz, 0.2dB passband ripple, sampling rate 24kHz
|
m_filterStage1( 724, 1448, 724, 32768, -37895, 21352),//3rd order Cheby Filter 300 to 2700Hz, 0.2dB passband ripple, sampling rate 24kHz
|
||||||
m_filterStage2(32768, 0,-32768, 32768, -50339, 19052),
|
m_filterStage2(32768, 0,-32768, 32768, -50339, 19052),
|
||||||
m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460),
|
m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460),
|
||||||
m_blanking(),
|
m_blanking(),
|
||||||
m_useCOS(true),
|
m_accessMode(1U),
|
||||||
|
m_linkMode(false),
|
||||||
m_cosInvert(false),
|
m_cosInvert(false),
|
||||||
|
m_noiseSquelch(false),
|
||||||
m_rfAudioBoost(1U),
|
m_rfAudioBoost(1U),
|
||||||
m_extAudioBoost(1U),
|
m_extAudioBoost(1U),
|
||||||
m_downsampler(400U),// 100 ms of audio
|
m_downSampler(400U),// 100 ms of audio
|
||||||
m_extEnabled(false),
|
m_extEnabled(false),
|
||||||
m_rxLevel(1),
|
m_rxLevel(1),
|
||||||
m_inputRFRB(2401U), // 100ms of audio + 1 sample
|
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_extSignal(false)
|
||||||
{
|
{
|
||||||
m_statusTimer.setTimeout(1U, 0U);
|
m_statusTimer.setTimeout(1U, 0U);
|
||||||
|
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, uint8_t length)
|
||||||
{
|
{
|
||||||
if (m_useCOS) {
|
if (m_linkMode)
|
||||||
if (m_cosInvert)
|
linkSamples(cos, samples, length);
|
||||||
cos = !cos;
|
else
|
||||||
} else {
|
repeaterSamples(cos, samples, length);
|
||||||
cos = true;
|
}
|
||||||
}
|
|
||||||
|
void CFM::repeaterSamples(bool cos, q15_t* samples, uint8_t length)
|
||||||
|
{
|
||||||
|
if (m_cosInvert)
|
||||||
|
cos = !cos;
|
||||||
|
|
||||||
clock(length);
|
clock(length);
|
||||||
|
|
||||||
@@ -81,34 +95,82 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
|
|||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
// 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);
|
||||||
uint8_t ctcssState = m_ctcssRX.process(currentRFSample);
|
|
||||||
|
|
||||||
if (!m_useCOS) {
|
if (m_noiseSquelch)
|
||||||
// Delay the audio by 100ms to better match the CTCSS detector output
|
cos = m_squelch.process(currentRFSample);
|
||||||
m_inputRFRB.put(currentRFSample);
|
|
||||||
m_inputRFRB.get(currentRFSample);
|
|
||||||
}
|
|
||||||
|
|
||||||
q15_t currentExtSample;
|
q15_t currentExtSample;
|
||||||
bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow
|
bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow
|
||||||
inputExt = inputExt && m_extEnabled;
|
inputExt = inputExt && m_extEnabled;
|
||||||
|
|
||||||
if (!inputExt && (CTCSS_NOT_READY(ctcssState)) && m_modemState != STATE_FM) {
|
switch (m_accessMode) {
|
||||||
//Not enough samples to determine if you have CTCSS, just carry on. But only if we haven't any external data in the queue
|
case 0U:
|
||||||
continue;
|
if (!inputExt && !cos && m_modemState != STATE_FM)
|
||||||
} else if ((inputExt || CTCSS_READY(ctcssState)) && m_modemState != STATE_FM) {
|
continue;
|
||||||
//we had enough samples for CTCSS and we are in some other mode than FM
|
else
|
||||||
bool validCTCSS = CTCSS_VALID(ctcssState);
|
stateMachine(cos, inputExt);
|
||||||
stateMachine(validCTCSS && cos, inputExt);
|
break;
|
||||||
if (m_modemState != STATE_FM)
|
|
||||||
continue;
|
case 1U: {
|
||||||
} else if ((inputExt || CTCSS_NOT_READY(ctcssState)) && m_modemState == STATE_FM && i == length - 1) {
|
bool ctcss = m_ctcssRX.process(currentRFSample);
|
||||||
//Not enough samples for CTCSS but we already are in FM, trigger the state machine
|
|
||||||
//but do not trigger the state machine on every single sample, save CPU!
|
// Delay the audio by 100ms to better match the CTCSS detector output
|
||||||
bool validCTCSS = CTCSS_VALID(ctcssState);
|
m_inputRFRB.put(currentRFSample);
|
||||||
stateMachine(validCTCSS && cos, inputExt);
|
m_inputRFRB.get(currentRFSample);
|
||||||
|
|
||||||
|
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
|
||||||
|
// No CTCSS detected, just carry on
|
||||||
|
continue;
|
||||||
|
} else if ((inputExt || ctcss) && m_modemState != STATE_FM) {
|
||||||
|
// We had CTCSS or external input
|
||||||
|
stateMachine(ctcss, inputExt);
|
||||||
|
if (m_state == FS_LISTENING)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
stateMachine(ctcss, inputExt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2U: {
|
||||||
|
bool ctcss = m_ctcssRX.process(currentRFSample);
|
||||||
|
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
|
||||||
|
// No CTCSS detected, just carry on
|
||||||
|
continue;
|
||||||
|
} else if ((inputExt || (ctcss && cos)) && m_modemState != STATE_FM) {
|
||||||
|
// We had CTCSS or external input
|
||||||
|
stateMachine(ctcss && cos, inputExt);
|
||||||
|
if (m_state == FS_LISTENING)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
stateMachine(ctcss && cos, inputExt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
bool ctcss = m_ctcssRX.process(currentRFSample);
|
||||||
|
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
|
||||||
|
// No CTCSS detected, just carry on
|
||||||
|
continue;
|
||||||
|
} else if ((inputExt || (ctcss && cos)) && m_modemState != STATE_FM) {
|
||||||
|
// We had CTCSS or external input
|
||||||
|
stateMachine(ctcss && cos, inputExt);
|
||||||
|
if (m_state == FS_LISTENING)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
stateMachine(cos, inputExt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_modemState != STATE_FM)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (m_state == FS_LISTENING && !m_rfAck.isWanted() && !m_extAck.isWanted() && !m_callsign.isWanted() && !m_reverseTimer.isRunning())
|
||||||
|
continue;
|
||||||
|
|
||||||
q15_t currentSample = currentRFSample;
|
q15_t currentSample = currentRFSample;
|
||||||
q15_t currentBoost = m_rfAudioBoost;
|
q15_t currentBoost = m_rfAudioBoost;
|
||||||
if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
|
if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
|
||||||
@@ -117,14 +179,24 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only let RF audio through when relaying RF audio
|
// Only let RF audio through when relaying RF audio
|
||||||
if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
|
if (m_duplex) {
|
||||||
currentSample = m_blanking.process(currentSample);
|
if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF || m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
|
||||||
if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF))
|
currentSample = m_blanking.process(currentSample);
|
||||||
m_downsampler.addSample(currentSample);
|
if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF))
|
||||||
|
m_downSampler.addSample(currentSample);
|
||||||
|
|
||||||
currentSample *= currentBoost;
|
currentSample *= currentBoost;
|
||||||
|
} else {
|
||||||
|
currentSample = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
currentSample = 0;
|
if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
|
||||||
|
currentSample *= currentBoost;
|
||||||
|
} else {
|
||||||
|
if (m_extEnabled && (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF))
|
||||||
|
m_downSampler.addSample(currentSample);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_callsign.isRunning() && !m_extAck.isRunning())
|
if (!m_callsign.isRunning() && !m_extAck.isRunning())
|
||||||
@@ -140,12 +212,114 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
|
|||||||
currentSample += m_callsign.getLowAudio();
|
currentSample += m_callsign.getLowAudio();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
|
||||||
|
|
||||||
if (!m_callsign.isRunning() && !m_rfAck.isRunning() && !m_extAck.isRunning())
|
if (!m_callsign.isRunning() && !m_rfAck.isRunning() && !m_extAck.isRunning())
|
||||||
currentSample += m_timeoutTone.getAudio();
|
currentSample += m_timeoutTone.getAudio();
|
||||||
|
|
||||||
|
currentSample += m_ctcssTX.getAudio(m_reverseTimer.isRunning());
|
||||||
|
|
||||||
|
m_outputRFRB.put(currentSample);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::linkSamples(bool cos, q15_t* samples, uint8_t length)
|
||||||
|
{
|
||||||
|
if (m_cosInvert)
|
||||||
|
cos = !cos;
|
||||||
|
|
||||||
|
clock(length);
|
||||||
|
|
||||||
|
uint8_t i = 0U;
|
||||||
|
for (; i < length; i++) {
|
||||||
|
// ARMv7-M has hardware integer division
|
||||||
|
q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel);
|
||||||
|
|
||||||
|
if (m_noiseSquelch)
|
||||||
|
cos = m_squelch.process(currentRFSample);
|
||||||
|
|
||||||
|
q15_t currentExtSample;
|
||||||
|
bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow
|
||||||
|
inputExt = inputExt && m_extEnabled;
|
||||||
|
|
||||||
|
switch (m_accessMode) {
|
||||||
|
case 0U:
|
||||||
|
if (!inputExt && !cos && m_modemState != STATE_FM)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
stateMachine(cos, inputExt);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1U: {
|
||||||
|
bool ctcss = m_ctcssRX.process(currentRFSample);
|
||||||
|
|
||||||
|
// Delay the audio by 100ms to better match the CTCSS detector output
|
||||||
|
m_inputRFRB.put(currentRFSample);
|
||||||
|
m_inputRFRB.get(currentRFSample);
|
||||||
|
|
||||||
|
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
|
||||||
|
// No CTCSS detected, just carry on
|
||||||
|
continue;
|
||||||
|
} else if ((inputExt || ctcss) && m_modemState != STATE_FM) {
|
||||||
|
// We had CTCSS or external input
|
||||||
|
stateMachine(ctcss, inputExt);
|
||||||
|
if (m_state == FS_LISTENING)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
stateMachine(ctcss, inputExt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2U: {
|
||||||
|
bool ctcss = m_ctcssRX.process(currentRFSample);
|
||||||
|
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
|
||||||
|
// No CTCSS detected, just carry on
|
||||||
|
continue;
|
||||||
|
} else if ((inputExt || (ctcss && cos)) && m_modemState != STATE_FM) {
|
||||||
|
// We had CTCSS or external input
|
||||||
|
stateMachine(ctcss && cos, inputExt);
|
||||||
|
if (m_state == FS_LISTENING)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
stateMachine(ctcss && cos, inputExt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
bool ctcss = m_ctcssRX.process(currentRFSample);
|
||||||
|
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
|
||||||
|
// No CTCSS detected, just carry on
|
||||||
|
continue;
|
||||||
|
} else if ((inputExt || (ctcss && cos)) && m_modemState != STATE_FM) {
|
||||||
|
// We had CTCSS or external input
|
||||||
|
stateMachine(ctcss && cos, inputExt);
|
||||||
|
if (m_state == FS_LISTENING)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
stateMachine(cos, inputExt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_modemState != STATE_FM)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (m_rfSignal && m_extEnabled) {
|
||||||
|
q15_t currentSample = m_blanking.process(currentRFSample);
|
||||||
|
m_downSampler.addSample(currentSample);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_extSignal)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
q15_t currentSample = currentExtSample * m_extAudioBoost;
|
||||||
|
|
||||||
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
|
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
|
||||||
|
|
||||||
currentSample += m_ctcssTX.getAudio();
|
currentSample += m_ctcssTX.getAudio(m_reverseTimer.isRunning());
|
||||||
|
|
||||||
m_outputRFRB.put(currentSample);
|
m_outputRFRB.put(currentSample);
|
||||||
}
|
}
|
||||||
@@ -177,7 +351,7 @@ void CFM::process()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_extEnabled) {
|
if (m_extEnabled) {
|
||||||
uint16_t length = m_downsampler.getData();
|
uint16_t length = m_downSampler.getData();
|
||||||
|
|
||||||
if (length >= FM_SERIAL_BLOCK_SIZE) {
|
if (length >= FM_SERIAL_BLOCK_SIZE) {
|
||||||
if (length > FM_SERIAL_BLOCK_SIZE)
|
if (length > FM_SERIAL_BLOCK_SIZE)
|
||||||
@@ -186,7 +360,7 @@ void CFM::process()
|
|||||||
TSamplePairPack serialSamples[FM_SERIAL_BLOCK_SIZE];
|
TSamplePairPack serialSamples[FM_SERIAL_BLOCK_SIZE];
|
||||||
|
|
||||||
for (uint16_t j = 0U; j < length; j++)
|
for (uint16_t j = 0U; j < length; j++)
|
||||||
m_downsampler.getPackedData(serialSamples[j]);
|
m_downSampler.getPackedData(serialSamples[j]);
|
||||||
|
|
||||||
serial.writeFMData((uint8_t*)serialSamples, length * sizeof(TSamplePairPack));
|
serial.writeFMData((uint8_t*)serialSamples, length * sizeof(TSamplePairPack));
|
||||||
}
|
}
|
||||||
@@ -204,6 +378,7 @@ void CFM::reset()
|
|||||||
m_ackDelayTimer.stop();
|
m_ackDelayTimer.stop();
|
||||||
m_hangTimer.stop();
|
m_hangTimer.stop();
|
||||||
m_statusTimer.stop();
|
m_statusTimer.stop();
|
||||||
|
m_reverseTimer.stop();
|
||||||
|
|
||||||
m_ctcssRX.reset();
|
m_ctcssRX.reset();
|
||||||
m_rfAck.stop();
|
m_rfAck.stop();
|
||||||
@@ -214,7 +389,12 @@ void CFM::reset()
|
|||||||
m_outputRFRB.reset();
|
m_outputRFRB.reset();
|
||||||
m_inputExtRB.reset();
|
m_inputExtRB.reset();
|
||||||
|
|
||||||
m_downsampler.reset();
|
m_downSampler.reset();
|
||||||
|
m_squelch.reset();
|
||||||
|
|
||||||
|
m_needReverse = false;
|
||||||
|
m_rfSignal = false;
|
||||||
|
m_extSignal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CFM::setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch)
|
uint8_t CFM::setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch)
|
||||||
@@ -245,17 +425,18 @@ uint8_t CFM::setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_
|
|||||||
return m_rfAck.setParams(rfAck, speed, frequency, level, level);
|
return m_rfAck.setParams(rfAck, speed, frequency, level, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, bool kerchunkTX, uint8_t hangTime, bool useCOS, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel)
|
uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool linkMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel)
|
||||||
{
|
{
|
||||||
m_useCOS = useCOS;
|
m_accessMode = accessMode;
|
||||||
m_cosInvert = cosInvert;
|
m_linkMode = linkMode;
|
||||||
|
m_cosInvert = cosInvert;
|
||||||
|
m_noiseSquelch = noiseSquelch;
|
||||||
|
|
||||||
m_rfAudioBoost = q15_t(rfAudioBoost);
|
m_rfAudioBoost = q15_t(rfAudioBoost);
|
||||||
|
|
||||||
m_timeoutTimer.setTimeout(timeout, 0U);
|
m_timeoutTimer.setTimeout(timeout, 0U);
|
||||||
|
|
||||||
m_kerchunkTimer.setTimeout(kerchunkTime, 0U);
|
m_kerchunkTimer.setTimeout(kerchunkTime, 0U);
|
||||||
m_kerchunkTX = kerchunkTX;
|
|
||||||
|
|
||||||
m_hangTimer.setTimeout(hangTime, 0U);
|
m_hangTimer.setTimeout(hangTime, 0U);
|
||||||
|
|
||||||
@@ -264,6 +445,8 @@ uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFreque
|
|||||||
|
|
||||||
m_rxLevel = rxLevel; //q15_t(255)/q15_t(rxLevel >> 1);
|
m_rxLevel = rxLevel; //q15_t(255)/q15_t(rxLevel >> 1);
|
||||||
|
|
||||||
|
m_squelch.setParams(squelchHighThreshold, squelchLowThreshold);
|
||||||
|
|
||||||
uint8_t ret = m_ctcssRX.setParams(ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold);
|
uint8_t ret = m_ctcssRX.setParams(ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold);
|
||||||
if (ret != 0U)
|
if (ret != 0U)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -281,51 +464,113 @@ uint8_t CFM::setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CFM::stateMachine(bool validRFSignal, bool validExtSignal)
|
void CFM::stateMachine(bool validRFSignal, bool validExtSignal)
|
||||||
|
{
|
||||||
|
if (m_linkMode) {
|
||||||
|
linkStateMachine(validRFSignal, validExtSignal);
|
||||||
|
} else {
|
||||||
|
if (m_duplex)
|
||||||
|
duplexStateMachine(validRFSignal, validExtSignal);
|
||||||
|
else
|
||||||
|
simplexStateMachine(validRFSignal, validExtSignal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::simplexStateMachine(bool validRFSignal, bool validExtSignal)
|
||||||
{
|
{
|
||||||
switch (m_state) {
|
switch (m_state) {
|
||||||
case FS_LISTENING:
|
case FS_LISTENING:
|
||||||
listeningState(validRFSignal, validExtSignal);
|
listeningStateSimplex(validRFSignal, validExtSignal);
|
||||||
break;
|
|
||||||
case FS_KERCHUNK_RF:
|
|
||||||
kerchunkRFState(validRFSignal);
|
|
||||||
break;
|
break;
|
||||||
case FS_RELAYING_RF:
|
case FS_RELAYING_RF:
|
||||||
relayingRFState(validRFSignal);
|
relayingRFStateSimplex(validRFSignal);
|
||||||
break;
|
break;
|
||||||
case FS_RELAYING_WAIT_RF:
|
case FS_RELAYING_WAIT_RF:
|
||||||
relayingRFWaitState(validRFSignal);
|
relayingRFWaitStateSimplex(validRFSignal);
|
||||||
break;
|
break;
|
||||||
case FS_TIMEOUT_RF:
|
case FS_TIMEOUT_RF:
|
||||||
timeoutRFState(validRFSignal);
|
timeoutRFStateSimplex(validRFSignal);
|
||||||
break;
|
break;
|
||||||
case FS_TIMEOUT_WAIT_RF:
|
case FS_TIMEOUT_WAIT_RF:
|
||||||
timeoutRFWaitState(validRFSignal);
|
timeoutRFStateSimplex(validRFSignal);
|
||||||
break;
|
|
||||||
case FS_KERCHUNK_EXT:
|
|
||||||
kerchunkExtState(validExtSignal);
|
|
||||||
break;
|
break;
|
||||||
case FS_RELAYING_EXT:
|
case FS_RELAYING_EXT:
|
||||||
relayingExtState(validExtSignal);
|
relayingExtStateSimplex(validExtSignal);
|
||||||
break;
|
break;
|
||||||
case FS_RELAYING_WAIT_EXT:
|
case FS_RELAYING_WAIT_EXT:
|
||||||
relayingExtWaitState(validExtSignal);
|
relayingExtWaitStateSimplex(validExtSignal);
|
||||||
break;
|
break;
|
||||||
case FS_TIMEOUT_EXT:
|
case FS_TIMEOUT_EXT:
|
||||||
timeoutExtState(validExtSignal);
|
timeoutExtStateSimplex(validExtSignal);
|
||||||
break;
|
break;
|
||||||
case FS_TIMEOUT_WAIT_EXT:
|
case FS_TIMEOUT_WAIT_EXT:
|
||||||
timeoutExtWaitState(validExtSignal);
|
timeoutExtWaitStateSimplex(validExtSignal);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == FS_LISTENING) {
|
||||||
|
if (!m_reverseTimer.isRunning() && m_needReverse)
|
||||||
|
m_reverseTimer.start();
|
||||||
|
|
||||||
|
if (m_reverseTimer.isRunning() && m_reverseTimer.hasExpired()) {
|
||||||
|
m_reverseTimer.stop();
|
||||||
|
m_needReverse = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::duplexStateMachine(bool validRFSignal, bool validExtSignal)
|
||||||
|
{
|
||||||
|
switch (m_state) {
|
||||||
|
case FS_LISTENING:
|
||||||
|
listeningStateDuplex(validRFSignal, validExtSignal);
|
||||||
|
break;
|
||||||
|
case FS_KERCHUNK_RF:
|
||||||
|
kerchunkRFStateDuplex(validRFSignal);
|
||||||
|
break;
|
||||||
|
case FS_RELAYING_RF:
|
||||||
|
relayingRFStateDuplex(validRFSignal);
|
||||||
|
break;
|
||||||
|
case FS_RELAYING_WAIT_RF:
|
||||||
|
relayingRFWaitStateDuplex(validRFSignal);
|
||||||
|
break;
|
||||||
|
case FS_TIMEOUT_RF:
|
||||||
|
timeoutRFStateDuplex(validRFSignal);
|
||||||
|
break;
|
||||||
|
case FS_TIMEOUT_WAIT_RF:
|
||||||
|
timeoutRFWaitStateDuplex(validRFSignal);
|
||||||
|
break;
|
||||||
|
case FS_KERCHUNK_EXT:
|
||||||
|
kerchunkExtStateDuplex(validExtSignal);
|
||||||
|
break;
|
||||||
|
case FS_RELAYING_EXT:
|
||||||
|
relayingExtStateDuplex(validExtSignal);
|
||||||
|
break;
|
||||||
|
case FS_RELAYING_WAIT_EXT:
|
||||||
|
relayingExtWaitStateDuplex(validExtSignal);
|
||||||
|
break;
|
||||||
|
case FS_TIMEOUT_EXT:
|
||||||
|
timeoutExtStateDuplex(validExtSignal);
|
||||||
|
break;
|
||||||
|
case FS_TIMEOUT_WAIT_EXT:
|
||||||
|
timeoutExtWaitStateDuplex(validExtSignal);
|
||||||
break;
|
break;
|
||||||
case FS_HANG:
|
case FS_HANG:
|
||||||
hangState(validRFSignal, validExtSignal);
|
hangStateDuplex(validRFSignal, validExtSignal);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_state == FS_LISTENING && !m_rfAck.isWanted() && !m_extAck.isWanted() && !m_callsign.isWanted()) {
|
if (m_state == FS_LISTENING && !m_rfAck.isWanted() && !m_extAck.isWanted() && !m_callsign.isWanted()) {
|
||||||
m_outputRFRB.reset();
|
if (!m_reverseTimer.isRunning() && m_needReverse)
|
||||||
m_downsampler.reset();
|
m_reverseTimer.start();
|
||||||
|
|
||||||
|
if (m_reverseTimer.isRunning() && m_reverseTimer.hasExpired()) {
|
||||||
|
m_reverseTimer.stop();
|
||||||
|
m_needReverse = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,6 +584,7 @@ void CFM::clock(uint8_t length)
|
|||||||
m_ackDelayTimer.clock(length);
|
m_ackDelayTimer.clock(length);
|
||||||
m_hangTimer.clock(length);
|
m_hangTimer.clock(length);
|
||||||
m_statusTimer.clock(length);
|
m_statusTimer.clock(length);
|
||||||
|
m_reverseTimer.clock(length);
|
||||||
|
|
||||||
if (m_statusTimer.isRunning() && m_statusTimer.hasExpired()) {
|
if (m_statusTimer.isRunning() && m_statusTimer.hasExpired()) {
|
||||||
serial.writeFMStatus(m_state);
|
serial.writeFMStatus(m_state);
|
||||||
@@ -346,7 +592,7 @@ void CFM::clock(uint8_t length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::listeningState(bool validRFSignal, bool validExtSignal)
|
void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
|
||||||
{
|
{
|
||||||
if (validRFSignal) {
|
if (validRFSignal) {
|
||||||
if (m_kerchunkTimer.getTimeout() > 0U) {
|
if (m_kerchunkTimer.getTimeout() > 0U) {
|
||||||
@@ -362,12 +608,13 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal)
|
|||||||
sendCallsign();
|
sendCallsign();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_state == FS_RELAYING_RF || (m_state == FS_KERCHUNK_RF && m_kerchunkTX)) {
|
if (m_state == FS_RELAYING_RF || m_state == FS_KERCHUNK_RF) {
|
||||||
insertSilence(50U);
|
insertSilence(50U);
|
||||||
|
|
||||||
beginRelaying();
|
beginRelaying();
|
||||||
|
|
||||||
m_callsignTimer.start();
|
m_callsignTimer.start();
|
||||||
|
m_reverseTimer.stop();
|
||||||
|
|
||||||
io.setDecode(true);
|
io.setDecode(true);
|
||||||
io.setADCDetection(true);
|
io.setADCDetection(true);
|
||||||
@@ -389,12 +636,13 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal)
|
|||||||
sendCallsign();
|
sendCallsign();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_state == FS_RELAYING_EXT || (m_state == FS_KERCHUNK_EXT && m_kerchunkTX)) {
|
if (m_state == FS_RELAYING_EXT || m_state == FS_KERCHUNK_EXT) {
|
||||||
insertSilence(50U);
|
insertSilence(50U);
|
||||||
|
|
||||||
beginRelaying();
|
beginRelaying();
|
||||||
|
|
||||||
m_callsignTimer.start();
|
m_callsignTimer.start();
|
||||||
|
m_reverseTimer.stop();
|
||||||
|
|
||||||
m_statusTimer.start();
|
m_statusTimer.start();
|
||||||
serial.writeFMStatus(m_state);
|
serial.writeFMStatus(m_state);
|
||||||
@@ -402,26 +650,41 @@ void CFM::listeningState(bool validRFSignal, bool validExtSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::kerchunkRFState(bool validSignal)
|
void CFM::listeningStateSimplex(bool validRFSignal, bool validExtSignal)
|
||||||
|
{
|
||||||
|
if (validRFSignal) {
|
||||||
|
DEBUG1("State to RELAYING_RF");
|
||||||
|
m_state = FS_RELAYING_RF;
|
||||||
|
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
|
m_timeoutTimer.start();
|
||||||
|
m_reverseTimer.stop();
|
||||||
|
|
||||||
|
m_statusTimer.start();
|
||||||
|
serial.writeFMStatus(m_state);
|
||||||
|
} else if (validExtSignal) {
|
||||||
|
DEBUG1("State to RELAYING_EXT");
|
||||||
|
m_state = FS_RELAYING_EXT;
|
||||||
|
|
||||||
|
insertSilence(50U);
|
||||||
|
|
||||||
|
m_timeoutTimer.start();
|
||||||
|
m_reverseTimer.stop();
|
||||||
|
|
||||||
|
m_statusTimer.start();
|
||||||
|
serial.writeFMStatus(m_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::kerchunkRFStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
if (m_kerchunkTimer.hasExpired()) {
|
if (m_kerchunkTimer.hasExpired()) {
|
||||||
DEBUG1("State to RELAYING_RF");
|
DEBUG1("State to RELAYING_RF");
|
||||||
m_state = FS_RELAYING_RF;
|
m_state = FS_RELAYING_RF;
|
||||||
m_kerchunkTimer.stop();
|
m_kerchunkTimer.stop();
|
||||||
if (!m_kerchunkTX) {
|
|
||||||
insertSilence(50U);
|
|
||||||
|
|
||||||
beginRelaying();
|
|
||||||
|
|
||||||
m_callsignTimer.start();
|
|
||||||
|
|
||||||
io.setDecode(true);
|
|
||||||
io.setADCDetection(true);
|
|
||||||
|
|
||||||
m_statusTimer.start();
|
|
||||||
serial.writeFMStatus(m_state);
|
|
||||||
}
|
|
||||||
if (m_callsignAtStart && m_callsignAtLatch) {
|
if (m_callsignAtStart && m_callsignAtLatch) {
|
||||||
sendCallsign();
|
sendCallsign();
|
||||||
m_callsignTimer.start();
|
m_callsignTimer.start();
|
||||||
@@ -438,13 +701,13 @@ void CFM::kerchunkRFState(bool validSignal)
|
|||||||
m_ackMinTimer.stop();
|
m_ackMinTimer.stop();
|
||||||
m_callsignTimer.stop();
|
m_callsignTimer.stop();
|
||||||
m_statusTimer.stop();
|
m_statusTimer.stop();
|
||||||
|
m_needReverse = true;
|
||||||
if (m_extEnabled)
|
if (m_extEnabled)
|
||||||
serial.writeFMEOT();
|
serial.writeFMEOT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::relayingRFState(bool validSignal)
|
void CFM::relayingRFStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
||||||
@@ -475,7 +738,32 @@ void CFM::relayingRFState(bool validSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::relayingRFWaitState(bool validSignal)
|
void CFM::relayingRFStateSimplex(bool validSignal)
|
||||||
|
{
|
||||||
|
if (validSignal) {
|
||||||
|
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
||||||
|
DEBUG1("State to TIMEOUT_RF");
|
||||||
|
m_state = FS_TIMEOUT_RF;
|
||||||
|
|
||||||
|
m_timeoutTimer.stop();
|
||||||
|
|
||||||
|
if (m_extEnabled)
|
||||||
|
serial.writeFMEOT();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
|
DEBUG1("State to RELAYING_WAIT_RF");
|
||||||
|
m_state = FS_RELAYING_WAIT_RF;
|
||||||
|
m_ackDelayTimer.start();
|
||||||
|
|
||||||
|
if (m_extEnabled)
|
||||||
|
serial.writeFMEOT();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::relayingRFWaitStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
io.setDecode(true);
|
io.setDecode(true);
|
||||||
@@ -513,23 +801,32 @@ void CFM::relayingRFWaitState(bool validSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::kerchunkExtState(bool validSignal)
|
void CFM::relayingRFWaitStateSimplex(bool validSignal)
|
||||||
|
{
|
||||||
|
if (validSignal) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
|
DEBUG1("State to RELAYING_RF");
|
||||||
|
m_state = FS_RELAYING_RF;
|
||||||
|
m_ackDelayTimer.stop();
|
||||||
|
} else {
|
||||||
|
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
|
||||||
|
DEBUG1("State to LISTENING");
|
||||||
|
m_state = FS_LISTENING;
|
||||||
|
m_ackDelayTimer.stop();
|
||||||
|
m_timeoutTimer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::kerchunkExtStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
if (m_kerchunkTimer.hasExpired()) {
|
if (m_kerchunkTimer.hasExpired()) {
|
||||||
DEBUG1("State to RELAYING_EXT");
|
DEBUG1("State to RELAYING_EXT");
|
||||||
m_state = FS_RELAYING_EXT;
|
m_state = FS_RELAYING_EXT;
|
||||||
m_kerchunkTimer.stop();
|
m_kerchunkTimer.stop();
|
||||||
if (!m_kerchunkTX) {
|
|
||||||
insertSilence(50U);
|
|
||||||
|
|
||||||
beginRelaying();
|
|
||||||
|
|
||||||
m_callsignTimer.start();
|
|
||||||
|
|
||||||
m_statusTimer.start();
|
|
||||||
serial.writeFMStatus(m_state);
|
|
||||||
}
|
|
||||||
if (m_callsignAtStart && m_callsignAtLatch) {
|
if (m_callsignAtStart && m_callsignAtLatch) {
|
||||||
sendCallsign();
|
sendCallsign();
|
||||||
m_callsignTimer.start();
|
m_callsignTimer.start();
|
||||||
@@ -543,10 +840,11 @@ void CFM::kerchunkExtState(bool validSignal)
|
|||||||
m_ackMinTimer.stop();
|
m_ackMinTimer.stop();
|
||||||
m_callsignTimer.stop();
|
m_callsignTimer.stop();
|
||||||
m_statusTimer.stop();
|
m_statusTimer.stop();
|
||||||
|
m_needReverse = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::relayingExtState(bool validSignal)
|
void CFM::relayingExtStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
||||||
@@ -568,7 +866,23 @@ void CFM::relayingExtState(bool validSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::relayingExtWaitState(bool validSignal)
|
void CFM::relayingExtStateSimplex(bool validSignal)
|
||||||
|
{
|
||||||
|
if (validSignal) {
|
||||||
|
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
||||||
|
DEBUG1("State to TIMEOUT_EXT");
|
||||||
|
m_state = FS_TIMEOUT_EXT;
|
||||||
|
|
||||||
|
m_timeoutTimer.stop();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG1("State to RELAYING_WAIT_EXT");
|
||||||
|
m_state = FS_RELAYING_WAIT_EXT;
|
||||||
|
m_ackDelayTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::relayingExtWaitStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
DEBUG1("State to RELAYING_EXT");
|
DEBUG1("State to RELAYING_EXT");
|
||||||
@@ -603,7 +917,24 @@ void CFM::relayingExtWaitState(bool validSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::hangState(bool validRFSignal, bool validExtSignal)
|
void CFM::relayingExtWaitStateSimplex(bool validSignal)
|
||||||
|
{
|
||||||
|
if (validSignal) {
|
||||||
|
DEBUG1("State to RELAYING_EXT");
|
||||||
|
m_state = FS_RELAYING_EXT;
|
||||||
|
m_ackDelayTimer.stop();
|
||||||
|
} else {
|
||||||
|
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
|
||||||
|
DEBUG1("State to LISTENING");
|
||||||
|
m_state = FS_LISTENING;
|
||||||
|
m_ackDelayTimer.stop();
|
||||||
|
m_timeoutTimer.stop();
|
||||||
|
m_needReverse = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal)
|
||||||
{
|
{
|
||||||
if (validRFSignal) {
|
if (validRFSignal) {
|
||||||
io.setDecode(true);
|
io.setDecode(true);
|
||||||
@@ -633,7 +964,7 @@ void CFM::hangState(bool validRFSignal, bool validExtSignal)
|
|||||||
sendCallsign();
|
sendCallsign();
|
||||||
|
|
||||||
m_callsignTimer.stop();
|
m_callsignTimer.stop();
|
||||||
|
m_needReverse = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,7 +974,7 @@ void CFM::hangState(bool validRFSignal, bool validExtSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::timeoutRFState(bool validSignal)
|
void CFM::timeoutRFStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (!validSignal) {
|
if (!validSignal) {
|
||||||
io.setDecode(false);
|
io.setDecode(false);
|
||||||
@@ -664,7 +995,20 @@ void CFM::timeoutRFState(bool validSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::timeoutRFWaitState(bool validSignal)
|
void CFM::timeoutRFStateSimplex(bool validSignal)
|
||||||
|
{
|
||||||
|
if (!validSignal) {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
|
DEBUG1("State to TIMEOUT_WAIT_RF");
|
||||||
|
m_state = FS_TIMEOUT_WAIT_RF;
|
||||||
|
|
||||||
|
m_ackDelayTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::timeoutRFWaitStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
io.setDecode(true);
|
io.setDecode(true);
|
||||||
@@ -693,7 +1037,26 @@ void CFM::timeoutRFWaitState(bool validSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::timeoutExtState(bool validSignal)
|
void CFM::timeoutRFWaitStateSimplex(bool validSignal)
|
||||||
|
{
|
||||||
|
if (validSignal) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
|
DEBUG1("State to TIMEOUT_RF");
|
||||||
|
m_state = FS_TIMEOUT_RF;
|
||||||
|
m_ackDelayTimer.stop();
|
||||||
|
} else {
|
||||||
|
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
|
||||||
|
DEBUG1("State to LISTENING");
|
||||||
|
m_state = FS_LISTENING;
|
||||||
|
m_ackDelayTimer.stop();
|
||||||
|
m_timeoutTimer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::timeoutExtStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (!validSignal) {
|
if (!validSignal) {
|
||||||
DEBUG1("State to TIMEOUT_WAIT_EXT");
|
DEBUG1("State to TIMEOUT_WAIT_EXT");
|
||||||
@@ -707,7 +1070,16 @@ void CFM::timeoutExtState(bool validSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::timeoutExtWaitState(bool validSignal)
|
void CFM::timeoutExtStateSimplex(bool validSignal)
|
||||||
|
{
|
||||||
|
if (!validSignal) {
|
||||||
|
DEBUG1("State to TIMEOUT_WAIT_EXT");
|
||||||
|
m_state = FS_TIMEOUT_WAIT_EXT;
|
||||||
|
m_ackDelayTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::timeoutExtWaitStateDuplex(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
DEBUG1("State to TIMEOUT_EXT");
|
DEBUG1("State to TIMEOUT_EXT");
|
||||||
@@ -732,6 +1104,81 @@ void CFM::timeoutExtWaitState(bool validSignal)
|
|||||||
m_callsignTimer.start();
|
m_callsignTimer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CFM::timeoutExtWaitStateSimplex(bool validSignal)
|
||||||
|
{
|
||||||
|
if (validSignal) {
|
||||||
|
DEBUG1("State to TIMEOUT_EXT");
|
||||||
|
m_state = FS_TIMEOUT_EXT;
|
||||||
|
m_ackDelayTimer.stop();
|
||||||
|
} else {
|
||||||
|
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
|
||||||
|
DEBUG1("State to LISTENING");
|
||||||
|
m_state = FS_LISTENING;
|
||||||
|
m_ackDelayTimer.stop();
|
||||||
|
m_timeoutTimer.stop();
|
||||||
|
m_needReverse = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFM::linkStateMachine(bool validRFSignal, bool validExtSignal)
|
||||||
|
{
|
||||||
|
if (validRFSignal && !m_rfSignal) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
|
if (!m_extSignal) {
|
||||||
|
DEBUG1("State to RELAYING_RF");
|
||||||
|
m_state = FS_RELAYING_RF;
|
||||||
|
m_statusTimer.start();
|
||||||
|
serial.writeFMStatus(m_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rfSignal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validExtSignal && !m_extSignal) {
|
||||||
|
if (!m_rfSignal) {
|
||||||
|
DEBUG1("State to RELAYING_EXT");
|
||||||
|
m_state = FS_RELAYING_EXT;
|
||||||
|
m_statusTimer.start();
|
||||||
|
serial.writeFMStatus(m_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
insertSilence(50U);
|
||||||
|
|
||||||
|
m_extSignal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validRFSignal && m_rfSignal) {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
|
if (!m_extSignal) {
|
||||||
|
DEBUG1("State to LISTENING");
|
||||||
|
m_state = FS_LISTENING;
|
||||||
|
m_statusTimer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rfSignal = false;
|
||||||
|
|
||||||
|
if (m_extEnabled)
|
||||||
|
serial.writeFMEOT();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validExtSignal && m_extSignal) {
|
||||||
|
if (!m_rfSignal) {
|
||||||
|
DEBUG1("State to LISTENING");
|
||||||
|
m_state = FS_LISTENING;
|
||||||
|
m_statusTimer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_needReverse = true;
|
||||||
|
m_extSignal = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CFM::sendCallsign()
|
void CFM::sendCallsign()
|
||||||
{
|
{
|
||||||
if (m_holdoffTimer.isRunning()) {
|
if (m_holdoffTimer.isRunning()) {
|
||||||
@@ -780,3 +1227,6 @@ void CFM::insertSilence(uint16_t ms)
|
|||||||
for (uint32_t i = 0U; i < nSamples; i++)
|
for (uint32_t i = 0U; i < nSamples; i++)
|
||||||
m_outputRFRB.put(0);
|
m_outputRFRB.put(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
* Copyright (C) 2020,2021 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
|
||||||
@@ -16,11 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#if !defined(FM_H)
|
#if !defined(FM_H)
|
||||||
#define FM_H
|
#define FM_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
#include "FMBlanking.h"
|
#include "FMBlanking.h"
|
||||||
#include "FMCTCSSRX.h"
|
#include "FMCTCSSRX.h"
|
||||||
#include "FMCTCSSTX.h"
|
#include "FMCTCSSTX.h"
|
||||||
@@ -29,8 +31,9 @@
|
|||||||
#include "FMTimer.h"
|
#include "FMTimer.h"
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
#include "FMDirectForm1.h"
|
#include "FMDirectForm1.h"
|
||||||
#include "FMDownsampler.h"
|
#include "FMDownSampler.h"
|
||||||
#include "FMUpSampler.h"
|
#include "FMUpSampler.h"
|
||||||
|
#include "FMNoiseSquelch.h"
|
||||||
|
|
||||||
enum FM_STATE {
|
enum FM_STATE {
|
||||||
FS_LISTENING,
|
FS_LISTENING,
|
||||||
@@ -60,7 +63,7 @@ public:
|
|||||||
|
|
||||||
uint8_t setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch);
|
uint8_t setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch);
|
||||||
uint8_t setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_t minTime, uint16_t delay, uint8_t level);
|
uint8_t setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_t minTime, uint16_t delay, uint8_t level);
|
||||||
uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, bool kerchunkTX, uint8_t hangTime, bool useCOS, bool cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel);
|
uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool linkMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel);
|
||||||
uint8_t setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t frequency, uint8_t level);
|
uint8_t setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t frequency, uint8_t level);
|
||||||
|
|
||||||
uint8_t getSpace() const;
|
uint8_t getSpace() const;
|
||||||
@@ -73,6 +76,7 @@ private:
|
|||||||
CFMKeyer m_extAck;
|
CFMKeyer m_extAck;
|
||||||
CFMCTCSSRX m_ctcssRX;
|
CFMCTCSSRX m_ctcssRX;
|
||||||
CFMCTCSSTX m_ctcssTX;
|
CFMCTCSSTX m_ctcssTX;
|
||||||
|
CFMNoiseSquelch m_squelch;
|
||||||
CFMTimeout m_timeoutTone;
|
CFMTimeout m_timeoutTone;
|
||||||
FM_STATE m_state;
|
FM_STATE m_state;
|
||||||
bool m_callsignAtStart;
|
bool m_callsignAtStart;
|
||||||
@@ -82,39 +86,62 @@ private:
|
|||||||
CFMTimer m_timeoutTimer;
|
CFMTimer m_timeoutTimer;
|
||||||
CFMTimer m_holdoffTimer;
|
CFMTimer m_holdoffTimer;
|
||||||
CFMTimer m_kerchunkTimer;
|
CFMTimer m_kerchunkTimer;
|
||||||
bool m_kerchunkTX;
|
|
||||||
CFMTimer m_ackMinTimer;
|
CFMTimer m_ackMinTimer;
|
||||||
CFMTimer m_ackDelayTimer;
|
CFMTimer m_ackDelayTimer;
|
||||||
CFMTimer m_hangTimer;
|
CFMTimer m_hangTimer;
|
||||||
CFMTimer m_statusTimer;
|
CFMTimer m_statusTimer;
|
||||||
|
CFMTimer m_reverseTimer;
|
||||||
|
bool m_needReverse;
|
||||||
CFMDirectFormI m_filterStage1;
|
CFMDirectFormI m_filterStage1;
|
||||||
CFMDirectFormI m_filterStage2;
|
CFMDirectFormI m_filterStage2;
|
||||||
CFMDirectFormI m_filterStage3;
|
CFMDirectFormI m_filterStage3;
|
||||||
CFMBlanking m_blanking;
|
CFMBlanking m_blanking;
|
||||||
bool m_useCOS;
|
uint8_t m_accessMode;
|
||||||
|
bool m_linkMode;
|
||||||
bool m_cosInvert;
|
bool m_cosInvert;
|
||||||
|
bool m_noiseSquelch;
|
||||||
q15_t m_rfAudioBoost;
|
q15_t m_rfAudioBoost;
|
||||||
q15_t m_extAudioBoost;
|
q15_t m_extAudioBoost;
|
||||||
CFMDownsampler m_downsampler;
|
CFMDownSampler m_downSampler;
|
||||||
bool m_extEnabled;
|
bool m_extEnabled;
|
||||||
q15_t m_rxLevel;
|
q15_t m_rxLevel;
|
||||||
CRingBuffer<q15_t> m_inputRFRB;
|
CRingBuffer<q15_t> m_inputRFRB;
|
||||||
CRingBuffer<q15_t> m_outputRFRB;
|
CRingBuffer<q15_t> m_outputRFRB;
|
||||||
CFMUpSampler m_inputExtRB;
|
CFMUpSampler m_inputExtRB;
|
||||||
|
bool m_rfSignal;
|
||||||
|
bool m_extSignal;
|
||||||
|
|
||||||
void stateMachine(bool validRFSignal, bool validExtSignal);
|
void stateMachine(bool validRFSignal, bool validExtSignal);
|
||||||
void listeningState(bool validRFSignal, bool validExtSignal);
|
|
||||||
void kerchunkRFState(bool validSignal);
|
void repeaterSamples(bool cos, q15_t* samples, uint8_t length);
|
||||||
void relayingRFState(bool validSignal);
|
void linkSamples(bool cos, q15_t* samples, uint8_t length);
|
||||||
void relayingRFWaitState(bool validSignal);
|
|
||||||
void timeoutRFState(bool validSignal);
|
void duplexStateMachine(bool validRFSignal, bool validExtSignal);
|
||||||
void timeoutRFWaitState(bool validSignal);
|
void listeningStateDuplex(bool validRFSignal, bool validExtSignal);
|
||||||
void kerchunkExtState(bool validSignal);
|
void kerchunkRFStateDuplex(bool validSignal);
|
||||||
void relayingExtState(bool validSignal);
|
void relayingRFStateDuplex(bool validSignal);
|
||||||
void relayingExtWaitState(bool validSignal);
|
void relayingRFWaitStateDuplex(bool validSignal);
|
||||||
void timeoutExtState(bool validSignal);
|
void timeoutRFStateDuplex(bool validSignal);
|
||||||
void timeoutExtWaitState(bool validSignal);
|
void timeoutRFWaitStateDuplex(bool validSignal);
|
||||||
void hangState(bool validRFSignal, bool validExtSignal);
|
void kerchunkExtStateDuplex(bool validSignal);
|
||||||
|
void relayingExtStateDuplex(bool validSignal);
|
||||||
|
void relayingExtWaitStateDuplex(bool validSignal);
|
||||||
|
void timeoutExtStateDuplex(bool validSignal);
|
||||||
|
void timeoutExtWaitStateDuplex(bool validSignal);
|
||||||
|
void hangStateDuplex(bool validRFSignal, bool validExtSignal);
|
||||||
|
|
||||||
|
void simplexStateMachine(bool validRFSignal, bool validExtSignal);
|
||||||
|
void listeningStateSimplex(bool validRFSignal, bool validExtSignal);
|
||||||
|
void relayingRFStateSimplex(bool validSignal);
|
||||||
|
void relayingRFWaitStateSimplex(bool validSignal);
|
||||||
|
void timeoutRFStateSimplex(bool validSignal);
|
||||||
|
void timeoutRFWaitStateSimplex(bool validSignal);
|
||||||
|
void relayingExtStateSimplex(bool validSignal);
|
||||||
|
void relayingExtWaitStateSimplex(bool validSignal);
|
||||||
|
void timeoutExtStateSimplex(bool validSignal);
|
||||||
|
void timeoutExtWaitStateSimplex(bool validSignal);
|
||||||
|
|
||||||
|
void linkStateMachine(bool validRFSignal, bool validExtSignal);
|
||||||
|
|
||||||
void clock(uint8_t length);
|
void clock(uint8_t length);
|
||||||
|
|
||||||
@@ -126,3 +153,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "FMBlanking.h"
|
#include "FMBlanking.h"
|
||||||
|
|
||||||
@@ -80,3 +83,6 @@ q15_t CFMBlanking::process(q15_t sample)
|
|||||||
|
|
||||||
return sample;
|
return sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -16,11 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#if !defined(FMBlanking_H)
|
#if !defined(FMBlanking_H)
|
||||||
#define FMBlanking_H
|
#define FMBlanking_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
class CFMBlanking {
|
class CFMBlanking {
|
||||||
public:
|
public:
|
||||||
CFMBlanking();
|
CFMBlanking();
|
||||||
@@ -39,3 +41,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+16
-16
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "FMCTCSSRX.h"
|
#include "FMCTCSSRX.h"
|
||||||
|
|
||||||
@@ -87,7 +90,7 @@ m_lowThreshold(0),
|
|||||||
m_count(0U),
|
m_count(0U),
|
||||||
m_q0(0),
|
m_q0(0),
|
||||||
m_q1(0),
|
m_q1(0),
|
||||||
m_result(CTS_NONE)
|
m_state(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,13 +114,11 @@ uint8_t CFMCTCSSRX::setParams(uint8_t frequency, uint8_t highThreshold, uint8_t
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CFMCTCSSRX::process(q15_t sample)
|
bool CFMCTCSSRX::process(q15_t sample)
|
||||||
{
|
{
|
||||||
//get more dynamic into the decoder by multiplying the sample by 1.5
|
//get more dynamic into the decoder by multiplying the sample by 1.5
|
||||||
q31_t sample31 = q31_t(sample) + (q31_t(sample) >> 1);
|
q31_t sample31 = q31_t(sample) + (q31_t(sample) >> 1);
|
||||||
|
|
||||||
m_result &= ~CTS_READY;
|
|
||||||
|
|
||||||
q31_t q2 = m_q1;
|
q31_t q2 = m_q1;
|
||||||
m_q1 = m_q0;
|
m_q1 = m_q0;
|
||||||
|
|
||||||
@@ -149,33 +150,32 @@ uint8_t CFMCTCSSRX::process(q15_t sample)
|
|||||||
// value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2
|
// value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2
|
||||||
q31_t value = t2 + t4 - t9;
|
q31_t value = t2 + t4 - t9;
|
||||||
|
|
||||||
bool previousCTCSSValid = CTCSS_VALID(m_result);
|
bool previousState = m_state;
|
||||||
|
|
||||||
q31_t threshold = m_highThreshold;
|
q31_t threshold = m_highThreshold;
|
||||||
if (previousCTCSSValid)
|
if (previousState)
|
||||||
threshold = m_lowThreshold;
|
threshold = m_lowThreshold;
|
||||||
|
|
||||||
m_result |= CTS_READY;
|
m_state = value >= threshold;
|
||||||
if (value >= threshold)
|
|
||||||
m_result |= CTS_VALID;
|
|
||||||
else
|
|
||||||
m_result &= ~CTS_VALID;
|
|
||||||
|
|
||||||
if (previousCTCSSValid != CTCSS_VALID(m_result))
|
if (previousState != m_state)
|
||||||
DEBUG4("CTCSS Value / Threshold / Valid", value, threshold, CTCSS_VALID(m_result));
|
DEBUG4("CTCSS Value / Threshold / Valid", value, threshold, m_state);
|
||||||
|
|
||||||
m_count = 0U;
|
m_count = 0U;
|
||||||
m_q0 = 0;
|
m_q0 = 0;
|
||||||
m_q1 = 0;
|
m_q1 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_result;
|
return m_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFMCTCSSRX::reset()
|
void CFMCTCSSRX::reset()
|
||||||
{
|
{
|
||||||
m_q0 = 0;
|
m_q0 = 0;
|
||||||
m_q1 = 0;
|
m_q1 = 0;
|
||||||
m_result = CTS_NONE;
|
m_state = false;
|
||||||
m_count = 0U;
|
m_count = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-12
@@ -16,19 +16,12 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(FMCTCSSRX_H)
|
|
||||||
#define FMCTCSSRX_H
|
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
const uint8_t CTS_NONE = 0U;
|
#if defined(MODE_FM)
|
||||||
const uint8_t CTS_READY = 1U;
|
|
||||||
const uint8_t CTS_VALID = 2U;
|
|
||||||
|
|
||||||
#define CTCSS_READY(a) ((a & CTS_READY) != 0)
|
#if !defined(FMCTCSSRX_H)
|
||||||
#define CTCSS_NOT_READY(a) ((a & CTS_READY) == 0)
|
#define FMCTCSSRX_H
|
||||||
#define CTCSS_VALID(a) ((a & CTS_VALID) != 0)
|
|
||||||
#define CTCSS_NOT_VALID(a) ((a & CTS_VALID) == 0)
|
|
||||||
|
|
||||||
class CFMCTCSSRX {
|
class CFMCTCSSRX {
|
||||||
public:
|
public:
|
||||||
@@ -36,7 +29,7 @@ public:
|
|||||||
|
|
||||||
uint8_t setParams(uint8_t frequency, uint8_t highThreshold, uint8_t lowThreshold);
|
uint8_t setParams(uint8_t frequency, uint8_t highThreshold, uint8_t lowThreshold);
|
||||||
|
|
||||||
uint8_t process(q15_t sample);
|
bool process(q15_t sample);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
@@ -47,7 +40,10 @@ private:
|
|||||||
uint16_t m_count;
|
uint16_t m_count;
|
||||||
q31_t m_q0;
|
q31_t m_q0;
|
||||||
q31_t m_q1;
|
q31_t m_q1;
|
||||||
uint8_t m_result;
|
bool m_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+12
-3
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "FMCTCSSTX.h"
|
#include "FMCTCSSTX.h"
|
||||||
|
|
||||||
@@ -115,11 +118,17 @@ uint8_t CFMCTCSSTX::setParams(uint8_t frequency, uint8_t level)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
q15_t CFMCTCSSTX::getAudio()
|
q15_t CFMCTCSSTX::getAudio(bool reverse)
|
||||||
{
|
{
|
||||||
q15_t sample = m_values[m_n++];
|
q15_t sample = m_values[m_n++];
|
||||||
if(m_n >= m_length)
|
if (m_n >= m_length)
|
||||||
m_n = 0U;
|
m_n = 0U;
|
||||||
|
|
||||||
return sample;
|
if (reverse)
|
||||||
|
return -sample;
|
||||||
|
else
|
||||||
|
return sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -16,18 +16,20 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#if !defined(FMCTCSSTX_H)
|
#if !defined(FMCTCSSTX_H)
|
||||||
#define FMCTCSSTX_H
|
#define FMCTCSSTX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
class CFMCTCSSTX {
|
class CFMCTCSSTX {
|
||||||
public:
|
public:
|
||||||
CFMCTCSSTX();
|
CFMCTCSSTX();
|
||||||
|
|
||||||
uint8_t setParams(uint8_t frequency, uint8_t level);
|
uint8_t setParams(uint8_t frequency, uint8_t level);
|
||||||
|
|
||||||
q15_t getAudio();
|
q15_t getAudio(bool reverse);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
q15_t* m_values;
|
q15_t* m_values;
|
||||||
@@ -36,3 +38,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-1
@@ -29,6 +29,10 @@ THE SOFTWARE.
|
|||||||
|
|
||||||
// based on https://raw.githubusercontent.com/berndporr/iir_fixed_point/master/DirectFormI.h
|
// based on https://raw.githubusercontent.com/berndporr/iir_fixed_point/master/DirectFormI.h
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#ifndef DIRECTFORMI_H_
|
#ifndef DIRECTFORMI_H_
|
||||||
@@ -108,4 +112,7 @@ private:
|
|||||||
q31_t c_a1,c_a2; // IIR
|
q31_t c_a1,c_a2; // IIR
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DIRECTFORMI_H */
|
#endif /* DIRECTFORMI_H */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "FMDownsampler.h"
|
|
||||||
|
|
||||||
CFMDownsampler::CFMDownsampler(uint16_t length) :
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
|
#include "FMDownSampler.h"
|
||||||
|
|
||||||
|
CFMDownSampler::CFMDownSampler(uint16_t length) :
|
||||||
m_ringBuffer(length),
|
m_ringBuffer(length),
|
||||||
m_samplePack(0U),
|
m_samplePack(0U),
|
||||||
m_samplePackPointer(NULL),
|
m_samplePackPointer(NULL),
|
||||||
@@ -29,7 +32,7 @@ m_sampleIndex(0U)
|
|||||||
m_samplePackPointer = (uint8_t*)&m_samplePack;
|
m_samplePackPointer = (uint8_t*)&m_samplePack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFMDownsampler::addSample(q15_t sample)
|
void CFMDownSampler::addSample(q15_t sample)
|
||||||
{
|
{
|
||||||
uint32_t usample = uint32_t(int32_t(sample) + 2048);
|
uint32_t usample = uint32_t(int32_t(sample) + 2048);
|
||||||
//only take one of three samples
|
//only take one of three samples
|
||||||
@@ -54,21 +57,24 @@ void CFMDownsampler::addSample(q15_t sample)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_sampleIndex++;
|
m_sampleIndex++;
|
||||||
if(m_sampleIndex >= 6U)//did we pack two samples ?
|
if (m_sampleIndex >= 6U)//did we pack two samples ?
|
||||||
m_sampleIndex = 0U;
|
m_sampleIndex = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFMDownsampler::getPackedData(TSamplePairPack& data)
|
bool CFMDownSampler::getPackedData(TSamplePairPack& data)
|
||||||
{
|
{
|
||||||
return m_ringBuffer.get(data);
|
return m_ringBuffer.get(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t CFMDownsampler::getData()
|
uint16_t CFMDownSampler::getData()
|
||||||
{
|
{
|
||||||
return m_ringBuffer.getData();
|
return m_ringBuffer.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFMDownsampler::reset()
|
void CFMDownSampler::reset()
|
||||||
{
|
{
|
||||||
m_sampleIndex = 0U;
|
m_sampleIndex = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -17,19 +17,26 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#if !defined(FMDOWNSAMPLER_H)
|
#if !defined(FMDOWNSAMPLER_H)
|
||||||
#define FMDOWNSAMPLER_H
|
#define FMDOWNSAMPLER_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
#include "FMSamplePairPack.h"
|
#include "FMSamplePairPack.h"
|
||||||
|
|
||||||
class CFMDownsampler {
|
class CFMDownSampler {
|
||||||
public:
|
public:
|
||||||
CFMDownsampler(uint16_t length);
|
CFMDownSampler(uint16_t length);
|
||||||
|
|
||||||
void addSample(q15_t sample);
|
void addSample(q15_t sample);
|
||||||
|
|
||||||
bool getPackedData(TSamplePairPack& data);
|
bool getPackedData(TSamplePairPack& data);
|
||||||
|
|
||||||
uint16_t getData();
|
uint16_t getData();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -40,3 +47,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "FMKeyer.h"
|
#include "FMKeyer.h"
|
||||||
|
|
||||||
@@ -214,3 +217,6 @@ bool CFMKeyer::isRunning() const
|
|||||||
{
|
{
|
||||||
return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U;
|
return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#if !defined(FMKeyer_H)
|
#if !defined(FMKeyer_H)
|
||||||
#define FMKeyer_H
|
#define FMKeyer_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
class CFMKeyer {
|
class CFMKeyer {
|
||||||
public:
|
public:
|
||||||
CFMKeyer();
|
CFMKeyer();
|
||||||
@@ -52,3 +54,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "FMNoiseSquelch.h"
|
||||||
|
|
||||||
|
// 4500Hz centre frequency
|
||||||
|
const q31_t COEFF_DIV_TWO = 821806413;
|
||||||
|
|
||||||
|
// 400Hz bandwidth
|
||||||
|
const uint16_t N = 24000U / 400U;
|
||||||
|
|
||||||
|
CFMNoiseSquelch::CFMNoiseSquelch() :
|
||||||
|
m_highThreshold(0),
|
||||||
|
m_lowThreshold(0),
|
||||||
|
m_count(0U),
|
||||||
|
m_q0(0),
|
||||||
|
m_q1(0),
|
||||||
|
m_state(false),
|
||||||
|
m_validCount(0U)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMNoiseSquelch::setParams(uint8_t highThreshold, uint8_t lowThreshold)
|
||||||
|
{
|
||||||
|
m_highThreshold = q31_t(highThreshold);
|
||||||
|
m_lowThreshold = q31_t(lowThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMNoiseSquelch::process(q15_t sample)
|
||||||
|
{
|
||||||
|
//get more dynamic into the decoder by multiplying the sample by 64
|
||||||
|
q31_t sample31 = q31_t(sample) << 6; //+ (q31_t(sample) >> 1);
|
||||||
|
|
||||||
|
q31_t q2 = m_q1;
|
||||||
|
m_q1 = m_q0;
|
||||||
|
|
||||||
|
// Q31 multiplication, t3 = m_coeffDivTwo * 2 * m_q1
|
||||||
|
q63_t t1 = COEFF_DIV_TWO * m_q1;
|
||||||
|
q31_t t2 = __SSAT((t1 >> 31), 31);
|
||||||
|
q31_t t3 = t2 * 2;
|
||||||
|
|
||||||
|
// m_q0 = m_coeffDivTwo * m_q1 * 2 - q2 + sample
|
||||||
|
m_q0 = t3 - q2 + sample31;
|
||||||
|
|
||||||
|
m_count++;
|
||||||
|
if (m_count == N) {
|
||||||
|
// Q31 multiplication, t2 = m_q0 * m_q0
|
||||||
|
q63_t t1 = q63_t(m_q0) * q63_t(m_q0);
|
||||||
|
q31_t t2 = __SSAT((t1 >> 31), 31);
|
||||||
|
|
||||||
|
// Q31 multiplication, t4 = m_q0 * m_q0
|
||||||
|
q63_t t3 = q63_t(m_q1) * q63_t(m_q1);
|
||||||
|
q31_t t4 = __SSAT((t3 >> 31), 31);
|
||||||
|
|
||||||
|
// Q31 multiplication, t9 = m_q0 * m_q1 * m_coeffDivTwo * 2
|
||||||
|
q63_t t5 = q63_t(m_q0) * q63_t(m_q1);
|
||||||
|
q31_t t6 = __SSAT((t5 >> 31), 31);
|
||||||
|
q63_t t7 = t6 * COEFF_DIV_TWO;
|
||||||
|
q31_t t8 = __SSAT((t7 >> 31), 31);
|
||||||
|
q31_t t9 = t8 * 2;
|
||||||
|
|
||||||
|
// value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2
|
||||||
|
q31_t value = t2 + t4 - t9;
|
||||||
|
|
||||||
|
bool previousState = m_state;
|
||||||
|
|
||||||
|
q31_t threshold = m_highThreshold;
|
||||||
|
if (previousState)
|
||||||
|
threshold = m_lowThreshold;
|
||||||
|
|
||||||
|
if (!m_state) {
|
||||||
|
if (value < threshold)
|
||||||
|
m_validCount++;
|
||||||
|
else
|
||||||
|
m_validCount = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state) {
|
||||||
|
if (value >= threshold)
|
||||||
|
m_invalidCount++;
|
||||||
|
else
|
||||||
|
m_invalidCount = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_state = m_validCount >= 10U && m_invalidCount < 10U;
|
||||||
|
|
||||||
|
if(previousState && !m_state)
|
||||||
|
m_invalidCount = 0U;
|
||||||
|
|
||||||
|
if (previousState != m_state) {
|
||||||
|
DEBUG4("Noise Squelch Value / Threshold / Valid", value, threshold, m_state);
|
||||||
|
DEBUG3("Valid Count / Invalid Count", m_validCount, m_invalidCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_count = 0U;
|
||||||
|
m_q0 = 0;
|
||||||
|
m_q1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMNoiseSquelch::reset()
|
||||||
|
{
|
||||||
|
m_q0 = 0;
|
||||||
|
m_q1 = 0;
|
||||||
|
m_state = false;
|
||||||
|
m_count = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
|
#if !defined(FMNOISESQUELCH_H)
|
||||||
|
#define FMNOISESQUELCH_H
|
||||||
|
|
||||||
|
class CFMNoiseSquelch {
|
||||||
|
public:
|
||||||
|
CFMNoiseSquelch();
|
||||||
|
|
||||||
|
void setParams(uint8_t highThreshold, uint8_t lowThreshold);
|
||||||
|
|
||||||
|
bool process(q15_t sample);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
q31_t m_highThreshold;
|
||||||
|
q31_t m_lowThreshold;
|
||||||
|
uint16_t m_count;
|
||||||
|
q31_t m_q0;
|
||||||
|
q31_t m_q1;
|
||||||
|
bool m_state;
|
||||||
|
uint8_t m_validCount;
|
||||||
|
uint8_t m_invalidCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+8
-1
@@ -17,6 +17,10 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#if !defined(TSAMPLEPACK_H)
|
#if !defined(TSAMPLEPACK_H)
|
||||||
#define TSAMPLEPACK_H
|
#define TSAMPLEPACK_H
|
||||||
|
|
||||||
@@ -26,4 +30,7 @@ struct TSamplePairPack {
|
|||||||
uint8_t byte2;
|
uint8_t byte2;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+11
-7
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "FMTimeout.h"
|
#include "FMTimeout.h"
|
||||||
|
|
||||||
@@ -36,24 +39,22 @@ m_n(0U)
|
|||||||
|
|
||||||
void CFMTimeout::setParams(uint8_t level)
|
void CFMTimeout::setParams(uint8_t level)
|
||||||
{
|
{
|
||||||
m_level = q15_t(level * 128);
|
m_level = q15_t(level * 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
q15_t CFMTimeout::getAudio()
|
q15_t CFMTimeout::getAudio()
|
||||||
{
|
{
|
||||||
q15_t sample = 0U;
|
q15_t sample = 0;
|
||||||
if (!m_running)
|
if (!m_running)
|
||||||
return sample;
|
return sample;
|
||||||
|
|
||||||
if (m_pos > 12000U) {
|
if (m_pos >= 12000U) {
|
||||||
q31_t sample = BUSY_AUDIO[m_n] * m_level;
|
q31_t sample31 = BUSY_AUDIO[m_n] * m_level;
|
||||||
sample = q15_t(__SSAT((sample >> 15), 16));
|
sample = q15_t(__SSAT((sample31 >> 15), 16));
|
||||||
|
|
||||||
m_n++;
|
m_n++;
|
||||||
if (m_n >= BUSY_AUDIO_LEN)
|
if (m_n >= BUSY_AUDIO_LEN)
|
||||||
m_n = 0U;
|
m_n = 0U;
|
||||||
} else {
|
|
||||||
sample = 0U;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pos++;
|
m_pos++;
|
||||||
@@ -74,3 +75,6 @@ void CFMTimeout::stop()
|
|||||||
{
|
{
|
||||||
m_running = false;
|
m_running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -16,11 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#if !defined(FMTimeout_H)
|
#if !defined(FMTimeout_H)
|
||||||
#define FMTimeout_H
|
#define FMTimeout_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
class CFMTimeout {
|
class CFMTimeout {
|
||||||
public:
|
public:
|
||||||
CFMTimeout();
|
CFMTimeout();
|
||||||
@@ -40,3 +42,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "FMTimer.h"
|
#include "FMTimer.h"
|
||||||
|
|
||||||
@@ -68,3 +71,6 @@ bool CFMTimer::hasExpired() const
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#if !defined(FMTimer_H)
|
#if !defined(FMTimer_H)
|
||||||
#define FMTimer_H
|
#define FMTimer_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
class CFMTimer {
|
class CFMTimer {
|
||||||
public:
|
public:
|
||||||
CFMTimer();
|
CFMTimer();
|
||||||
@@ -45,3 +47,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-1
@@ -17,6 +17,10 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#include "FMUpSampler.h"
|
#include "FMUpSampler.h"
|
||||||
|
|
||||||
const uint32_t FM_UPSAMPLE_MASK = 0x00000FFFU;
|
const uint32_t FM_UPSAMPLE_MASK = 0x00000FFFU;
|
||||||
@@ -94,4 +98,7 @@ uint16_t CFMUpSampler::getSpace() const
|
|||||||
{
|
{
|
||||||
//return available space in bytes
|
//return available space in bytes
|
||||||
return m_samples.getSpace() * sizeof(TSamplePairPack);
|
return m_samples.getSpace() * sizeof(TSamplePairPack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -18,10 +18,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
|
||||||
#if !defined(FMUPSAMPLER_H)
|
#if !defined(FMUPSAMPLER_H)
|
||||||
#define FMUPSAMPLER_H
|
#define FMUPSAMPLER_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
#include "FMSamplePairPack.h"
|
#include "FMSamplePairPack.h"
|
||||||
|
|
||||||
@@ -45,4 +48,7 @@ private:
|
|||||||
bool m_running;
|
bool m_running;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ enum MMDVM_STATE {
|
|||||||
STATE_P25 = 4,
|
STATE_P25 = 4,
|
||||||
STATE_NXDN = 5,
|
STATE_NXDN = 5,
|
||||||
STATE_POCSAG = 6,
|
STATE_POCSAG = 6,
|
||||||
|
STATE_M17 = 7,
|
||||||
STATE_FM = 10,
|
STATE_FM = 10,
|
||||||
|
STATE_AX25 = 11,
|
||||||
|
|
||||||
// Dummy states start at 90
|
// Dummy states start at 90
|
||||||
STATE_NXDNCAL1K = 91,
|
STATE_NXDNCAL1K = 91,
|
||||||
@@ -85,6 +87,8 @@ enum MMDVM_STATE {
|
|||||||
#include "YSFTX.h"
|
#include "YSFTX.h"
|
||||||
#include "P25RX.h"
|
#include "P25RX.h"
|
||||||
#include "P25TX.h"
|
#include "P25TX.h"
|
||||||
|
#include "M17RX.h"
|
||||||
|
#include "M17TX.h"
|
||||||
#include "NXDNRX.h"
|
#include "NXDNRX.h"
|
||||||
#include "NXDNTX.h"
|
#include "NXDNTX.h"
|
||||||
#include "POCSAGTX.h"
|
#include "POCSAGTX.h"
|
||||||
@@ -97,6 +101,8 @@ enum MMDVM_STATE {
|
|||||||
#include "CalPOCSAG.h"
|
#include "CalPOCSAG.h"
|
||||||
#include "CalRSSI.h"
|
#include "CalRSSI.h"
|
||||||
#include "CWIdTX.h"
|
#include "CWIdTX.h"
|
||||||
|
#include "AX25RX.h"
|
||||||
|
#include "AX25TX.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "IO.h"
|
#include "IO.h"
|
||||||
#include "FM.h"
|
#include "FM.h"
|
||||||
@@ -124,7 +130,9 @@ extern bool m_ysfEnable;
|
|||||||
extern bool m_p25Enable;
|
extern bool m_p25Enable;
|
||||||
extern bool m_nxdnEnable;
|
extern bool m_nxdnEnable;
|
||||||
extern bool m_pocsagEnable;
|
extern bool m_pocsagEnable;
|
||||||
|
extern bool m_m17Enable;
|
||||||
extern bool m_fmEnable;
|
extern bool m_fmEnable;
|
||||||
|
extern bool m_ax25Enable;
|
||||||
|
|
||||||
extern bool m_duplex;
|
extern bool m_duplex;
|
||||||
|
|
||||||
@@ -134,9 +142,15 @@ extern bool m_dcd;
|
|||||||
extern CSerialPort serial;
|
extern CSerialPort serial;
|
||||||
extern CIO io;
|
extern CIO io;
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
extern CDStarRX dstarRX;
|
extern CDStarRX dstarRX;
|
||||||
extern CDStarTX dstarTX;
|
extern CDStarTX dstarTX;
|
||||||
|
|
||||||
|
extern CCalDStarRX calDStarRX;
|
||||||
|
extern CCalDStarTX calDStarTX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
extern CDMRIdleRX dmrIdleRX;
|
extern CDMRIdleRX dmrIdleRX;
|
||||||
extern CDMRRX dmrRX;
|
extern CDMRRX dmrRX;
|
||||||
extern CDMRTX dmrTX;
|
extern CDMRTX dmrTX;
|
||||||
@@ -144,28 +158,51 @@ extern CDMRTX dmrTX;
|
|||||||
extern CDMRDMORX dmrDMORX;
|
extern CDMRDMORX dmrDMORX;
|
||||||
extern CDMRDMOTX dmrDMOTX;
|
extern CDMRDMOTX dmrDMOTX;
|
||||||
|
|
||||||
|
extern CCalDMR calDMR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_YSF)
|
||||||
extern CYSFRX ysfRX;
|
extern CYSFRX ysfRX;
|
||||||
extern CYSFTX ysfTX;
|
extern CYSFTX ysfTX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
extern CP25RX p25RX;
|
extern CP25RX p25RX;
|
||||||
extern CP25TX p25TX;
|
extern CP25TX p25TX;
|
||||||
|
|
||||||
|
extern CCalP25 calP25;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
extern CNXDNRX nxdnRX;
|
extern CNXDNRX nxdnRX;
|
||||||
extern CNXDNTX nxdnTX;
|
extern CNXDNTX nxdnTX;
|
||||||
|
|
||||||
extern CPOCSAGTX pocsagTX;
|
extern CCalNXDN calNXDN;
|
||||||
|
#endif
|
||||||
|
|
||||||
extern CFM fm;
|
#if defined(MODE_POCSAG)
|
||||||
|
extern CPOCSAGTX pocsagTX;
|
||||||
|
extern CCalPOCSAG calPOCSAG;
|
||||||
|
#endif
|
||||||
|
|
||||||
extern CCalDStarRX calDStarRX;
|
#if defined(MODE_M17)
|
||||||
extern CCalDStarTX calDStarTX;
|
extern CM17RX m17RX;
|
||||||
extern CCalDMR calDMR;
|
extern CM17TX m17TX;
|
||||||
extern CCalFM calFM;
|
#endif
|
||||||
extern CCalP25 calP25;
|
|
||||||
extern CCalNXDN calNXDN;
|
#if defined(MODE_FM)
|
||||||
extern CCalPOCSAG calPOCSAG;
|
extern CFM fm;
|
||||||
extern CCalRSSI calRSSI;
|
extern CCalFM calFM;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
extern CAX25RX ax25RX;
|
||||||
|
extern CAX25TX ax25TX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern CCalRSSI calRSSI;
|
||||||
|
|
||||||
extern CCWIdTX cwIdTX;
|
extern CCWIdTX cwIdTX;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -22,16 +22,34 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "IO.h"
|
#include "IO.h"
|
||||||
|
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
// Generated using [b, a] = butter(1, 0.001) in MATLAB
|
// Generated using [b, a] = butter(1, 0.001) in MATLAB
|
||||||
static q31_t DC_FILTER[] = {3367972, 0, 3367972, 0, 2140747704, 0}; // {b0, 0, b1, b2, -a1, -a2}
|
static q31_t DC_FILTER[] = {3367972, 0, 3367972, 0, 2140747704, 0}; // {b0, 0, b1, b2, -a1, -a2}
|
||||||
const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage
|
const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DMR) || defined(MODE_YSF)
|
||||||
// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
|
// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
|
||||||
static q15_t RRC_0_2_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995,
|
static q15_t RRC_0_2_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995,
|
||||||
11237, 14331, 15464, 14331, 11237, 6995, 2667, -770, -2706, -3040, -2144, -675, 683, 1450, 1472, 909, 112,
|
11237, 14331, 15464, 14331, 11237, 6995, 2667, -770, -2706, -3040, -2144, -675, 683, 1450, 1472, 909, 112,
|
||||||
-553, -847, -731, -340, 104, 401, 0};
|
-553, -847, -731, -340, 104, 401, 0};
|
||||||
const uint16_t RRC_0_2_FILTER_LEN = 42U;
|
const uint16_t RRC_0_2_FILTER_LEN = 42U;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
// Generated using rcosdesign(0.5, 8, 5, 'sqrt') in MATLAB
|
||||||
|
static q15_t RRC_0_5_FILTER[] = {-147, -88, 72, 220, 223, 46, -197, -285, -79, 334, 623, 390, -498, -1691, -2363, -1556, 1284, 5872, 11033,
|
||||||
|
15109, 16656, 15109, 11033, 5872, 1284, -1556, -2363, -1691, -498, 390, 623, 334, -79, -285, -197, 46, 223,
|
||||||
|
220, 72, -88, -147, 0};
|
||||||
|
const uint16_t RRC_0_5_FILTER_LEN = 42U;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
#if defined(USE_NXDN_BOXCAR)
|
||||||
|
// One symbol boxcar filter
|
||||||
|
static q15_t BOXCAR10_FILTER[] = {6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000};
|
||||||
|
const uint16_t BOXCAR10_FILTER_LEN = 10U;
|
||||||
|
#else
|
||||||
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
|
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
|
||||||
static q15_t NXDN_0_2_FILTER[] = {284, 198, 73, -78, -240, -393, -517, -590, -599, -533, -391, -181, 79, 364, 643, 880, 1041, 1097, 1026, 819,
|
static q15_t NXDN_0_2_FILTER[] = {284, 198, 73, -78, -240, -393, -517, -590, -599, -533, -391, -181, 79, 364, 643, 880, 1041, 1097, 1026, 819,
|
||||||
483, 39, -477, -1016, -1516, -1915, -2150, -2164, -1914, -1375, -545, 557, 1886, 3376, 4946, 6502, 7946, 9184,
|
483, 39, -477, -1016, -1516, -1915, -2150, -2164, -1914, -1375, -545, 557, 1886, 3376, 4946, 6502, 7946, 9184,
|
||||||
@@ -43,14 +61,20 @@ const uint16_t NXDN_0_2_FILTER_LEN = 82U;
|
|||||||
static q15_t NXDN_ISINC_FILTER[] = {790, -1085, -1073, -553, 747, 2341, 3156, 2152, -893, -4915, -7834, -7536, -3102, 4441, 12354, 17394, 17394,
|
static q15_t NXDN_ISINC_FILTER[] = {790, -1085, -1073, -553, 747, 2341, 3156, 2152, -893, -4915, -7834, -7536, -3102, 4441, 12354, 17394, 17394,
|
||||||
12354, 4441, -3102, -7536, -7834, -4915, -893, 2152, 3156, 2341, 747, -553, -1073, -1085, 790};
|
12354, 4441, -3102, -7536, -7834, -4915, -893, 2152, 3156, 2341, 747, -553, -1073, -1085, 790};
|
||||||
const uint16_t NXDN_ISINC_FILTER_LEN = 32U;
|
const uint16_t NXDN_ISINC_FILTER_LEN = 32U;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
// Generated using gaussfir(0.5, 4, 5) in MATLAB
|
// Generated using gaussfir(0.5, 4, 5) in MATLAB
|
||||||
static q15_t GAUSSIAN_0_5_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0};
|
static q15_t GAUSSIAN_0_5_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0};
|
||||||
const uint16_t GAUSSIAN_0_5_FILTER_LEN = 12U;
|
const uint16_t GAUSSIAN_0_5_FILTER_LEN = 12U;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
// One symbol boxcar filter
|
// One symbol boxcar filter
|
||||||
static q15_t BOXCAR_FILTER[] = {12000, 12000, 12000, 12000, 12000, 0};
|
static q15_t BOXCAR5_FILTER[] = {12000, 12000, 12000, 12000, 12000, 0};
|
||||||
const uint16_t BOXCAR_FILTER_LEN = 6U;
|
const uint16_t BOXCAR5_FILTER_LEN = 6U;
|
||||||
|
#endif
|
||||||
|
|
||||||
const uint16_t DC_OFFSET = 2048U;
|
const uint16_t DC_OFFSET = 2048U;
|
||||||
|
|
||||||
@@ -59,18 +83,37 @@ m_started(false),
|
|||||||
m_rxBuffer(RX_RINGBUFFER_SIZE),
|
m_rxBuffer(RX_RINGBUFFER_SIZE),
|
||||||
m_txBuffer(TX_RINGBUFFER_SIZE),
|
m_txBuffer(TX_RINGBUFFER_SIZE),
|
||||||
m_rssiBuffer(RX_RINGBUFFER_SIZE),
|
m_rssiBuffer(RX_RINGBUFFER_SIZE),
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
m_dcFilter(),
|
m_dcFilter(),
|
||||||
m_dcState(),
|
m_dcState(),
|
||||||
m_rrcFilter(),
|
#endif
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
m_gaussianFilter(),
|
m_gaussianFilter(),
|
||||||
m_boxcarFilter(),
|
m_gaussianState(),
|
||||||
|
#endif
|
||||||
|
#if defined(MODE_DMR) || defined(MODE_YSF)
|
||||||
|
m_rrc02Filter(),
|
||||||
|
m_rrc02State(),
|
||||||
|
#endif
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
m_boxcar5Filter(),
|
||||||
|
m_boxcar5State(),
|
||||||
|
#endif
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
#if defined(USE_NXDN_BOXCAR)
|
||||||
|
m_boxcar10Filter(),
|
||||||
|
m_boxcar10State(),
|
||||||
|
#else
|
||||||
m_nxdnFilter(),
|
m_nxdnFilter(),
|
||||||
m_nxdnISincFilter(),
|
m_nxdnISincFilter(),
|
||||||
m_rrcState(),
|
|
||||||
m_gaussianState(),
|
|
||||||
m_boxcarState(),
|
|
||||||
m_nxdnState(),
|
m_nxdnState(),
|
||||||
m_nxdnISincState(),
|
m_nxdnISincState(),
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
m_rrc05Filter(),
|
||||||
|
m_rrc05State(),
|
||||||
|
#endif
|
||||||
m_pttInvert(false),
|
m_pttInvert(false),
|
||||||
m_rxLevel(128 * 128),
|
m_rxLevel(128 * 128),
|
||||||
m_cwIdTXLevel(128 * 128),
|
m_cwIdTXLevel(128 * 128),
|
||||||
@@ -79,10 +122,13 @@ m_dmrTXLevel(128 * 128),
|
|||||||
m_ysfTXLevel(128 * 128),
|
m_ysfTXLevel(128 * 128),
|
||||||
m_p25TXLevel(128 * 128),
|
m_p25TXLevel(128 * 128),
|
||||||
m_nxdnTXLevel(128 * 128),
|
m_nxdnTXLevel(128 * 128),
|
||||||
|
m_m17TXLevel(128 * 128),
|
||||||
m_pocsagTXLevel(128 * 128),
|
m_pocsagTXLevel(128 * 128),
|
||||||
m_fmTXLevel(128 * 128),
|
m_fmTXLevel(128 * 128),
|
||||||
|
m_ax25TXLevel(128 * 128),
|
||||||
m_rxDCOffset(DC_OFFSET),
|
m_rxDCOffset(DC_OFFSET),
|
||||||
m_txDCOffset(DC_OFFSET),
|
m_txDCOffset(DC_OFFSET),
|
||||||
|
m_useCOSAsLockout(false),
|
||||||
m_ledCount(0U),
|
m_ledCount(0U),
|
||||||
m_ledValue(true),
|
m_ledValue(true),
|
||||||
m_detect(false),
|
m_detect(false),
|
||||||
@@ -91,30 +137,45 @@ m_dacOverflow(0U),
|
|||||||
m_watchdog(0U),
|
m_watchdog(0U),
|
||||||
m_lockout(false)
|
m_lockout(false)
|
||||||
{
|
{
|
||||||
::memset(m_rrcState, 0x00U, 70U * sizeof(q15_t));
|
#if defined(USE_DCBLOCKER)
|
||||||
::memset(m_gaussianState, 0x00U, 40U * sizeof(q15_t));
|
|
||||||
::memset(m_boxcarState, 0x00U, 30U * sizeof(q15_t));
|
|
||||||
::memset(m_nxdnState, 0x00U, 110U * sizeof(q15_t));
|
|
||||||
::memset(m_nxdnISincState, 0x00U, 60U * sizeof(q15_t));
|
|
||||||
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
|
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
|
||||||
|
|
||||||
m_dcFilter.numStages = DC_FILTER_STAGES;
|
m_dcFilter.numStages = DC_FILTER_STAGES;
|
||||||
m_dcFilter.pState = m_dcState;
|
m_dcFilter.pState = m_dcState;
|
||||||
m_dcFilter.pCoeffs = DC_FILTER;
|
m_dcFilter.pCoeffs = DC_FILTER;
|
||||||
m_dcFilter.postShift = 0;
|
m_dcFilter.postShift = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
m_rrcFilter.numTaps = RRC_0_2_FILTER_LEN;
|
#if defined(MODE_DSTAR)
|
||||||
m_rrcFilter.pState = m_rrcState;
|
::memset(m_gaussianState, 0x00U, 40U * sizeof(q15_t));
|
||||||
m_rrcFilter.pCoeffs = RRC_0_2_FILTER;
|
|
||||||
|
|
||||||
m_gaussianFilter.numTaps = GAUSSIAN_0_5_FILTER_LEN;
|
m_gaussianFilter.numTaps = GAUSSIAN_0_5_FILTER_LEN;
|
||||||
m_gaussianFilter.pState = m_gaussianState;
|
m_gaussianFilter.pState = m_gaussianState;
|
||||||
m_gaussianFilter.pCoeffs = GAUSSIAN_0_5_FILTER;
|
m_gaussianFilter.pCoeffs = GAUSSIAN_0_5_FILTER;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DMR) || defined(MODE_YSF)
|
||||||
|
::memset(m_rrc02State, 0x00U, 70U * sizeof(q15_t));
|
||||||
|
m_rrc02Filter.numTaps = RRC_0_2_FILTER_LEN;
|
||||||
|
m_rrc02Filter.pState = m_rrc02State;
|
||||||
|
m_rrc02Filter.pCoeffs = RRC_0_2_FILTER;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
::memset(m_boxcar5State, 0x00U, 30U * sizeof(q15_t));
|
||||||
|
m_boxcar5Filter.numTaps = BOXCAR5_FILTER_LEN;
|
||||||
|
m_boxcar5Filter.pState = m_boxcar5State;
|
||||||
|
m_boxcar5Filter.pCoeffs = BOXCAR5_FILTER;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
#if defined(USE_NXDN_BOXCAR)
|
||||||
|
::memset(m_boxcar10State, 0x00U, 40U * sizeof(q15_t));
|
||||||
|
m_boxcar10Filter.numTaps = BOXCAR10_FILTER_LEN;
|
||||||
|
m_boxcar10Filter.pState = m_boxcar10State;
|
||||||
|
m_boxcar10Filter.pCoeffs = BOXCAR10_FILTER;
|
||||||
|
#else
|
||||||
|
::memset(m_nxdnState, 0x00U, 110U * sizeof(q15_t));
|
||||||
|
::memset(m_nxdnISincState, 0x00U, 60U * sizeof(q15_t));
|
||||||
|
|
||||||
m_boxcarFilter.numTaps = BOXCAR_FILTER_LEN;
|
|
||||||
m_boxcarFilter.pState = m_boxcarState;
|
|
||||||
m_boxcarFilter.pCoeffs = BOXCAR_FILTER;
|
|
||||||
|
|
||||||
m_nxdnFilter.numTaps = NXDN_0_2_FILTER_LEN;
|
m_nxdnFilter.numTaps = NXDN_0_2_FILTER_LEN;
|
||||||
m_nxdnFilter.pState = m_nxdnState;
|
m_nxdnFilter.pState = m_nxdnState;
|
||||||
m_nxdnFilter.pCoeffs = NXDN_0_2_FILTER;
|
m_nxdnFilter.pCoeffs = NXDN_0_2_FILTER;
|
||||||
@@ -122,6 +183,15 @@ m_lockout(false)
|
|||||||
m_nxdnISincFilter.numTaps = NXDN_ISINC_FILTER_LEN;
|
m_nxdnISincFilter.numTaps = NXDN_ISINC_FILTER_LEN;
|
||||||
m_nxdnISincFilter.pState = m_nxdnISincState;
|
m_nxdnISincFilter.pState = m_nxdnISincState;
|
||||||
m_nxdnISincFilter.pCoeffs = NXDN_ISINC_FILTER;
|
m_nxdnISincFilter.pCoeffs = NXDN_ISINC_FILTER;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
::memset(m_rrc05State, 0x00U, 70U * sizeof(q15_t));
|
||||||
|
m_rrc05Filter.numTaps = RRC_0_5_FILTER_LEN;
|
||||||
|
m_rrc05Filter.pState = m_rrc05State;
|
||||||
|
m_rrc05Filter.pCoeffs = RRC_0_5_FILTER;
|
||||||
|
#endif
|
||||||
|
|
||||||
initInt();
|
initInt();
|
||||||
|
|
||||||
@@ -132,7 +202,7 @@ void CIO::selfTest()
|
|||||||
{
|
{
|
||||||
bool ledValue = false;
|
bool ledValue = false;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 6; i++) {
|
for (uint8_t i = 0U; i < 6U; i++) {
|
||||||
ledValue = !ledValue;
|
ledValue = !ledValue;
|
||||||
|
|
||||||
// We exclude PTT to avoid trigger the transmitter
|
// We exclude PTT to avoid trigger the transmitter
|
||||||
@@ -143,21 +213,40 @@ void CIO::selfTest()
|
|||||||
setDMRInt(ledValue);
|
setDMRInt(ledValue);
|
||||||
setYSFInt(ledValue);
|
setYSFInt(ledValue);
|
||||||
setP25Int(ledValue);
|
setP25Int(ledValue);
|
||||||
|
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||||
setNXDNInt(ledValue);
|
setNXDNInt(ledValue);
|
||||||
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
setM17Int(ledValue);
|
||||||
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
setPOCSAGInt(ledValue);
|
setPOCSAGInt(ledValue);
|
||||||
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||||
setFMInt(ledValue);
|
setFMInt(ledValue);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
delayInt(250);
|
delayInt(250);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MODE_LEDS)
|
#if defined(MODE_LEDS)
|
||||||
setDStarInt(true);
|
setDStarInt(false);
|
||||||
setDMRInt(false);
|
setDMRInt(false);
|
||||||
setYSFInt(false);
|
setYSFInt(false);
|
||||||
setP25Int(false);
|
setP25Int(false);
|
||||||
|
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||||
setNXDNInt(false);
|
setNXDNInt(false);
|
||||||
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
setM17Int(false);
|
||||||
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
setPOCSAGInt(false);
|
setPOCSAGInt(false);
|
||||||
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||||
setFMInt(false);
|
setFMInt(false);
|
||||||
|
#endif
|
||||||
|
setDStarInt(true);
|
||||||
|
|
||||||
delayInt(250);
|
delayInt(250);
|
||||||
setDMRInt(true);
|
setDMRInt(true);
|
||||||
@@ -173,6 +262,11 @@ void CIO::selfTest()
|
|||||||
setNXDNInt(true);
|
setNXDNInt(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
delayInt(250);
|
||||||
|
setM17Int(true);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
delayInt(250);
|
delayInt(250);
|
||||||
setPOCSAGInt(true);
|
setPOCSAGInt(true);
|
||||||
@@ -191,6 +285,11 @@ void CIO::selfTest()
|
|||||||
setPOCSAGInt(false);
|
setPOCSAGInt(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
delayInt(250);
|
||||||
|
setM17Int(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||||
delayInt(250);
|
delayInt(250);
|
||||||
setNXDNInt(false);
|
setNXDNInt(false);
|
||||||
@@ -219,7 +318,7 @@ void CIO::start()
|
|||||||
|
|
||||||
m_started = true;
|
m_started = true;
|
||||||
|
|
||||||
setMode();
|
setMode(STATE_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIO::process()
|
void CIO::process()
|
||||||
@@ -228,11 +327,12 @@ void CIO::process()
|
|||||||
if (m_started) {
|
if (m_started) {
|
||||||
// Two seconds timeout
|
// Two seconds timeout
|
||||||
if (m_watchdog >= 48000U) {
|
if (m_watchdog >= 48000U) {
|
||||||
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_POCSAG) {
|
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_M17 || m_modemState == STATE_POCSAG) {
|
||||||
|
#if defined(MODE_DMR)
|
||||||
if (m_modemState == STATE_DMR && m_tx)
|
if (m_modemState == STATE_DMR && m_tx)
|
||||||
dmrTX.setStart(false);
|
dmrTX.setStart(false);
|
||||||
m_modemState = STATE_IDLE;
|
#endif
|
||||||
setMode();
|
setMode(STATE_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_watchdog = 0U;
|
m_watchdog = 0U;
|
||||||
@@ -256,9 +356,8 @@ void CIO::process()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_COS_AS_LOCKOUT)
|
if (m_useCOSAsLockout)
|
||||||
m_lockout = getCOSInt();
|
m_lockout = getCOSInt();
|
||||||
#endif
|
|
||||||
|
|
||||||
// Switch off the transmitter if needed
|
// Switch off the transmitter if needed
|
||||||
if (m_txBuffer.getData() == 0U && m_tx) {
|
if (m_txBuffer.getData() == 0U && m_tx) {
|
||||||
@@ -310,6 +409,7 @@ void CIO::process()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_modemState == STATE_IDLE) {
|
if (m_modemState == STATE_IDLE) {
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
if (m_dstarEnable) {
|
if (m_dstarEnable) {
|
||||||
q15_t GMSKVals[RX_BLOCK_SIZE];
|
q15_t GMSKVals[RX_BLOCK_SIZE];
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
@@ -319,45 +419,79 @@ void CIO::process()
|
|||||||
#endif
|
#endif
|
||||||
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
|
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
if (m_p25Enable) {
|
if (m_p25Enable) {
|
||||||
q15_t P25Vals[RX_BLOCK_SIZE];
|
q15_t P25Vals[RX_BLOCK_SIZE];
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, P25Vals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_boxcar5Filter, dcSamples, P25Vals, RX_BLOCK_SIZE);
|
||||||
#else
|
#else
|
||||||
::arm_fir_fast_q15(&m_boxcarFilter, samples, P25Vals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_boxcar5Filter, samples, P25Vals, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
|
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
if (m_nxdnEnable) {
|
if (m_nxdnEnable) {
|
||||||
|
q15_t NXDNVals[RX_BLOCK_SIZE];
|
||||||
|
#if defined(USE_NXDN_BOXCAR)
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
|
::arm_fir_fast_q15(&m_boxcar10Filter, dcSamples, NXDNVals, RX_BLOCK_SIZE);
|
||||||
|
#else
|
||||||
|
::arm_fir_fast_q15(&m_boxcar10Filter, samples, NXDNVals, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
q15_t NXDNValsTmp[RX_BLOCK_SIZE];
|
q15_t NXDNValsTmp[RX_BLOCK_SIZE];
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE);
|
||||||
#else
|
#else
|
||||||
::arm_fir_fast_q15(&m_nxdnFilter, samples, NXDNValsTmp, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_nxdnFilter, samples, NXDNValsTmp, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
q15_t NXDNVals[RX_BLOCK_SIZE];
|
|
||||||
::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
|
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (m_dmrEnable || m_ysfEnable) {
|
#if defined(MODE_DMR)
|
||||||
q15_t RRCVals[RX_BLOCK_SIZE];
|
if (m_dmrEnable) {
|
||||||
::arm_fir_fast_q15(&m_rrcFilter, samples, RRCVals, RX_BLOCK_SIZE);
|
q15_t DMRVals[RX_BLOCK_SIZE];
|
||||||
|
::arm_fir_fast_q15(&m_rrc02Filter, samples, DMRVals, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
if (m_ysfEnable)
|
if (m_duplex)
|
||||||
ysfRX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
|
dmrIdleRX.samples(DMRVals, RX_BLOCK_SIZE);
|
||||||
|
else
|
||||||
if (m_dmrEnable) {
|
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
|
||||||
if (m_duplex)
|
|
||||||
dmrIdleRX.samples(RRCVals, RX_BLOCK_SIZE);
|
|
||||||
else
|
|
||||||
dmrDMORX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_YSF)
|
||||||
|
if (m_ysfEnable) {
|
||||||
|
q15_t YSFVals[RX_BLOCK_SIZE];
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
|
::arm_fir_fast_q15(&m_rrc02Filter, dcSamples, YSFVals, RX_BLOCK_SIZE);
|
||||||
|
#else
|
||||||
|
::arm_fir_fast_q15(&m_rrc02Filter, samples, YSFVals, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
|
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
if (m_m17Enable) {
|
||||||
|
q15_t RRCVals[RX_BLOCK_SIZE];
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
|
::arm_fir_fast_q15(&m_rrc05Filter, dcSamples, RRCVals, RX_BLOCK_SIZE);
|
||||||
|
#else
|
||||||
|
::arm_fir_fast_q15(&m_rrc05Filter, samples, RRCVals, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
|
m17RX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
if (m_fmEnable) {
|
if (m_fmEnable) {
|
||||||
bool cos = getCOSInt();
|
bool cos = getCOSInt();
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
@@ -366,7 +500,21 @@ void CIO::process()
|
|||||||
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else if (m_modemState == STATE_DSTAR) {
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_FM) && defined(MODE_AX25)
|
||||||
|
if (m_ax25Enable) {
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
|
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
|
||||||
|
#else
|
||||||
|
ax25RX.samples(samples, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
|
else if (m_modemState == STATE_DSTAR) {
|
||||||
if (m_dstarEnable) {
|
if (m_dstarEnable) {
|
||||||
q15_t GMSKVals[RX_BLOCK_SIZE];
|
q15_t GMSKVals[RX_BLOCK_SIZE];
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
@@ -376,10 +524,14 @@ void CIO::process()
|
|||||||
#endif
|
#endif
|
||||||
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
|
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
} else if (m_modemState == STATE_DMR) {
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
|
else if (m_modemState == STATE_DMR) {
|
||||||
if (m_dmrEnable) {
|
if (m_dmrEnable) {
|
||||||
q15_t DMRVals[RX_BLOCK_SIZE];
|
q15_t DMRVals[RX_BLOCK_SIZE];
|
||||||
::arm_fir_fast_q15(&m_rrcFilter, samples, DMRVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_rrc02Filter, samples, DMRVals, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
// If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs
|
// If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs
|
||||||
@@ -391,52 +543,106 @@ void CIO::process()
|
|||||||
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
|
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (m_modemState == STATE_YSF) {
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_YSF)
|
||||||
|
else if (m_modemState == STATE_YSF) {
|
||||||
if (m_ysfEnable) {
|
if (m_ysfEnable) {
|
||||||
q15_t YSFVals[RX_BLOCK_SIZE];
|
q15_t YSFVals[RX_BLOCK_SIZE];
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
::arm_fir_fast_q15(&m_rrcFilter, dcSamples, YSFVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_rrc02Filter, dcSamples, YSFVals, RX_BLOCK_SIZE);
|
||||||
#else
|
#else
|
||||||
::arm_fir_fast_q15(&m_rrcFilter, samples, YSFVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_rrc02Filter, samples, YSFVals, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
|
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
} else if (m_modemState == STATE_P25) {
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
else if (m_modemState == STATE_P25) {
|
||||||
if (m_p25Enable) {
|
if (m_p25Enable) {
|
||||||
q15_t P25Vals[RX_BLOCK_SIZE];
|
q15_t P25Vals[RX_BLOCK_SIZE];
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, P25Vals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_boxcar5Filter, dcSamples, P25Vals, RX_BLOCK_SIZE);
|
||||||
#else
|
#else
|
||||||
::arm_fir_fast_q15(&m_boxcarFilter, samples, P25Vals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_boxcar5Filter, samples, P25Vals, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
|
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
} else if (m_modemState == STATE_NXDN) {
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
else if (m_modemState == STATE_NXDN) {
|
||||||
if (m_nxdnEnable) {
|
if (m_nxdnEnable) {
|
||||||
|
q15_t NXDNVals[RX_BLOCK_SIZE];
|
||||||
|
#if defined(USE_NXDN_BOXCAR)
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
|
::arm_fir_fast_q15(&m_boxcar10Filter, dcSamples, NXDNVals, RX_BLOCK_SIZE);
|
||||||
|
#else
|
||||||
|
::arm_fir_fast_q15(&m_boxcar10Filter, samples, NXDNVals, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
q15_t NXDNValsTmp[RX_BLOCK_SIZE];
|
q15_t NXDNValsTmp[RX_BLOCK_SIZE];
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE);
|
||||||
#else
|
#else
|
||||||
::arm_fir_fast_q15(&m_nxdnFilter, samples, NXDNValsTmp, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_nxdnFilter, samples, NXDNValsTmp, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
q15_t NXDNVals[RX_BLOCK_SIZE];
|
|
||||||
::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
|
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
} else if (m_modemState == STATE_FM) {
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
else if (m_modemState == STATE_M17) {
|
||||||
|
if (m_m17Enable) {
|
||||||
|
q15_t M17Vals[RX_BLOCK_SIZE];
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
|
::arm_fir_fast_q15(&m_rrc05Filter, dcSamples, M17Vals, RX_BLOCK_SIZE);
|
||||||
|
#else
|
||||||
|
::arm_fir_fast_q15(&m_rrc05Filter, samples, M17Vals, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
|
m17RX.samples(M17Vals, rssi, RX_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_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, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
if (m_ax25Enable)
|
||||||
|
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
if (m_ax25Enable)
|
||||||
|
ax25RX.samples(samples, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
} else if (m_modemState == STATE_DSTARCAL) {
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
|
else if (m_modemState == STATE_DSTARCAL) {
|
||||||
q15_t GMSKVals[RX_BLOCK_SIZE];
|
q15_t GMSKVals[RX_BLOCK_SIZE];
|
||||||
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
calDStarRX.samples(GMSKVals, RX_BLOCK_SIZE);
|
calDStarRX.samples(GMSKVals, RX_BLOCK_SIZE);
|
||||||
} else if (m_modemState == STATE_RSSICAL) {
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
else if (m_modemState == STATE_RSSICAL) {
|
||||||
calRSSI.samples(rssi, RX_BLOCK_SIZE);
|
calRSSI.samples(rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -474,12 +680,18 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
|
|||||||
case STATE_NXDN:
|
case STATE_NXDN:
|
||||||
txLevel = m_nxdnTXLevel;
|
txLevel = m_nxdnTXLevel;
|
||||||
break;
|
break;
|
||||||
|
case STATE_M17:
|
||||||
|
txLevel = m_m17TXLevel;
|
||||||
|
break;
|
||||||
case STATE_POCSAG:
|
case STATE_POCSAG:
|
||||||
txLevel = m_pocsagTXLevel;
|
txLevel = m_pocsagTXLevel;
|
||||||
break;
|
break;
|
||||||
case STATE_FM:
|
case STATE_FM:
|
||||||
txLevel = m_fmTXLevel;
|
txLevel = m_fmTXLevel;
|
||||||
break;
|
break;
|
||||||
|
case STATE_AX25:
|
||||||
|
txLevel = m_ax25TXLevel;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
txLevel = m_cwIdTXLevel;
|
txLevel = m_cwIdTXLevel;
|
||||||
break;
|
break;
|
||||||
@@ -519,20 +731,41 @@ void CIO::setADCDetection(bool detect)
|
|||||||
m_detect = detect;
|
m_detect = detect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIO::setMode()
|
void CIO::setMode(MMDVM_STATE state)
|
||||||
{
|
{
|
||||||
|
if (state == m_modemState)
|
||||||
|
return;
|
||||||
|
|
||||||
#if defined(MODE_LEDS)
|
#if defined(MODE_LEDS)
|
||||||
setDStarInt(m_modemState == STATE_DSTAR);
|
switch (m_modemState) {
|
||||||
setDMRInt(m_modemState == STATE_DMR);
|
case STATE_DSTAR: setDStarInt(false); break;
|
||||||
setYSFInt(m_modemState == STATE_YSF);
|
case STATE_DMR: setDMRInt(false); break;
|
||||||
setP25Int(m_modemState == STATE_P25);
|
case STATE_YSF: setYSFInt(false); break;
|
||||||
setNXDNInt(m_modemState == STATE_NXDN);
|
case STATE_P25: setP25Int(false); break;
|
||||||
setPOCSAGInt(m_modemState == STATE_POCSAG);
|
case STATE_NXDN: setNXDNInt(false); break;
|
||||||
setFMInt(m_modemState == STATE_FM);
|
case STATE_M17: setM17Int(false); break;
|
||||||
|
case STATE_POCSAG: setPOCSAGInt(false); break;
|
||||||
|
case STATE_FM: setFMInt(false); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case STATE_DSTAR: setDStarInt(true); break;
|
||||||
|
case STATE_DMR: setDMRInt(true); break;
|
||||||
|
case STATE_YSF: setYSFInt(true); break;
|
||||||
|
case STATE_P25: setP25Int(true); break;
|
||||||
|
case STATE_NXDN: setNXDNInt(true); break;
|
||||||
|
case STATE_M17: setM17Int(true); break;
|
||||||
|
case STATE_POCSAG: setPOCSAGInt(true); break;
|
||||||
|
case STATE_FM: setFMInt(true); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
m_modemState = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, int16_t txDCOffset, int16_t rxDCOffset)
|
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t m17TXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout)
|
||||||
{
|
{
|
||||||
m_pttInvert = pttInvert;
|
m_pttInvert = pttInvert;
|
||||||
|
|
||||||
@@ -543,11 +776,15 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
|
|||||||
m_ysfTXLevel = q15_t(ysfTXLevel * 128);
|
m_ysfTXLevel = q15_t(ysfTXLevel * 128);
|
||||||
m_p25TXLevel = q15_t(p25TXLevel * 128);
|
m_p25TXLevel = q15_t(p25TXLevel * 128);
|
||||||
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
|
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
|
||||||
|
m_m17TXLevel = q15_t(m17TXLevel * 128);
|
||||||
m_pocsagTXLevel = q15_t(pocsagTXLevel * 128);
|
m_pocsagTXLevel = q15_t(pocsagTXLevel * 128);
|
||||||
m_fmTXLevel = q15_t(fmTXLevel * 128);
|
m_fmTXLevel = q15_t(fmTXLevel * 128);
|
||||||
|
m_ax25TXLevel = q15_t(ax25TXLevel * 128);
|
||||||
|
|
||||||
m_rxDCOffset = DC_OFFSET + rxDCOffset;
|
m_rxDCOffset = DC_OFFSET + rxDCOffset;
|
||||||
m_txDCOffset = DC_OFFSET + txDCOffset;
|
m_txDCOffset = DC_OFFSET + txDCOffset;
|
||||||
|
|
||||||
|
m_useCOSAsLockout = useCOSAsLockout;
|
||||||
|
|
||||||
if (rxInvert)
|
if (rxInvert)
|
||||||
m_rxLevel = -m_rxLevel;
|
m_rxLevel = -m_rxLevel;
|
||||||
@@ -558,6 +795,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
|
|||||||
m_ysfTXLevel = -m_ysfTXLevel;
|
m_ysfTXLevel = -m_ysfTXLevel;
|
||||||
m_p25TXLevel = -m_p25TXLevel;
|
m_p25TXLevel = -m_p25TXLevel;
|
||||||
m_nxdnTXLevel = -m_nxdnTXLevel;
|
m_nxdnTXLevel = -m_nxdnTXLevel;
|
||||||
|
m_m17TXLevel = -m_m17TXLevel;
|
||||||
m_pocsagTXLevel = -m_pocsagTXLevel;
|
m_pocsagTXLevel = -m_pocsagTXLevel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,11 +42,11 @@ public:
|
|||||||
|
|
||||||
void setDecode(bool dcd);
|
void setDecode(bool dcd);
|
||||||
void setADCDetection(bool detect);
|
void setADCDetection(bool detect);
|
||||||
void setMode();
|
void setMode(MMDVM_STATE state);
|
||||||
|
|
||||||
void interrupt();
|
void interrupt();
|
||||||
|
|
||||||
void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, int16_t txDCOffset, int16_t rxDCOffset);
|
void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t m17TXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout);
|
||||||
|
|
||||||
void getOverflow(bool& adcOverflow, bool& dacOverflow);
|
void getOverflow(bool& adcOverflow, bool& dacOverflow);
|
||||||
|
|
||||||
@@ -58,6 +58,10 @@ public:
|
|||||||
void resetWatchdog();
|
void resetWatchdog();
|
||||||
uint32_t getWatchdog();
|
uint32_t getWatchdog();
|
||||||
|
|
||||||
|
uint8_t getCPU() const;
|
||||||
|
|
||||||
|
void getUDID(uint8_t* buffer);
|
||||||
|
|
||||||
void selfTest();
|
void selfTest();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -67,19 +71,42 @@ private:
|
|||||||
CRingBuffer<TSample> m_txBuffer;
|
CRingBuffer<TSample> m_txBuffer;
|
||||||
CRingBuffer<uint16_t> m_rssiBuffer;
|
CRingBuffer<uint16_t> m_rssiBuffer;
|
||||||
|
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
arm_biquad_casd_df1_inst_q31 m_dcFilter;
|
arm_biquad_casd_df1_inst_q31 m_dcFilter;
|
||||||
q31_t m_dcState[4];
|
q31_t m_dcState[4];
|
||||||
|
#endif
|
||||||
|
|
||||||
arm_fir_instance_q15 m_rrcFilter;
|
#if defined(MODE_DSTAR)
|
||||||
arm_fir_instance_q15 m_gaussianFilter;
|
arm_fir_instance_q15 m_gaussianFilter;
|
||||||
arm_fir_instance_q15 m_boxcarFilter;
|
q15_t m_gaussianState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DMR) || defined(MODE_YSF)
|
||||||
|
arm_fir_instance_q15 m_rrc02Filter;
|
||||||
|
q15_t m_rrc02State[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
arm_fir_instance_q15 m_boxcar5Filter;
|
||||||
|
q15_t m_boxcar5State[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
#if defined(USE_NXDN_BOXCAR)
|
||||||
|
arm_fir_instance_q15 m_boxcar10Filter;
|
||||||
|
q15_t m_boxcar10State[40U]; // NoTaps + BlockSize - 1, 10 + 20 - 1 plus some spare
|
||||||
|
#else
|
||||||
arm_fir_instance_q15 m_nxdnFilter;
|
arm_fir_instance_q15 m_nxdnFilter;
|
||||||
arm_fir_instance_q15 m_nxdnISincFilter;
|
arm_fir_instance_q15 m_nxdnISincFilter;
|
||||||
q15_t m_rrcState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
|
|
||||||
q15_t m_gaussianState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare
|
|
||||||
q15_t m_boxcarState[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
|
|
||||||
q15_t m_nxdnState[110U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare
|
q15_t m_nxdnState[110U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare
|
||||||
q15_t m_nxdnISincState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare
|
q15_t m_nxdnISincState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
arm_fir_instance_q15 m_rrc05Filter;
|
||||||
|
q15_t m_rrc05State[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
|
||||||
|
#endif
|
||||||
|
|
||||||
bool m_pttInvert;
|
bool m_pttInvert;
|
||||||
q15_t m_rxLevel;
|
q15_t m_rxLevel;
|
||||||
@@ -89,12 +116,16 @@ private:
|
|||||||
q15_t m_ysfTXLevel;
|
q15_t m_ysfTXLevel;
|
||||||
q15_t m_p25TXLevel;
|
q15_t m_p25TXLevel;
|
||||||
q15_t m_nxdnTXLevel;
|
q15_t m_nxdnTXLevel;
|
||||||
|
q15_t m_m17TXLevel;
|
||||||
q15_t m_pocsagTXLevel;
|
q15_t m_pocsagTXLevel;
|
||||||
q15_t m_fmTXLevel;
|
q15_t m_fmTXLevel;
|
||||||
|
q15_t m_ax25TXLevel;
|
||||||
|
|
||||||
uint16_t m_rxDCOffset;
|
uint16_t m_rxDCOffset;
|
||||||
uint16_t m_txDCOffset;
|
uint16_t m_txDCOffset;
|
||||||
|
|
||||||
|
bool m_useCOSAsLockout;
|
||||||
|
|
||||||
uint32_t m_ledCount;
|
uint32_t m_ledCount;
|
||||||
bool m_ledValue;
|
bool m_ledValue;
|
||||||
|
|
||||||
@@ -123,6 +154,7 @@ private:
|
|||||||
void setP25Int(bool on);
|
void setP25Int(bool on);
|
||||||
void setNXDNInt(bool on);
|
void setNXDNInt(bool on);
|
||||||
void setPOCSAGInt(bool on);
|
void setPOCSAGInt(bool on);
|
||||||
|
void setM17Int(bool on);
|
||||||
void setFMInt(bool on);
|
void setFMInt(bool on);
|
||||||
|
|
||||||
void delayInt(unsigned int dly);
|
void delayInt(unsigned int dly);
|
||||||
|
|||||||
@@ -107,6 +107,9 @@ void CIO::initInt()
|
|||||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||||
pinMode(PIN_NXDN, OUTPUT);
|
pinMode(PIN_NXDN, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
pinMode(PIN_M17, OUTPUT);
|
||||||
|
#endif
|
||||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
pinMode(PIN_POCSAG, OUTPUT);
|
pinMode(PIN_POCSAG, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
@@ -253,6 +256,16 @@ void CIO::setNXDNInt(bool on)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIO::setM17Int(bool on)
|
||||||
|
{
|
||||||
|
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
|
||||||
|
digitalWrite(PIN_P25, on ? HIGH : LOW);
|
||||||
|
#else
|
||||||
|
digitalWrite(PIN_M17, on ? HIGH : LOW);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void CIO::setPOCSAGInt(bool on)
|
void CIO::setPOCSAGInt(bool on)
|
||||||
{
|
{
|
||||||
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
@@ -278,4 +291,33 @@ void CIO::delayInt(unsigned int dly)
|
|||||||
delay(dly);
|
delay(dly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t CIO::getCPU() const
|
||||||
|
{
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code taken from https://github.com/emagii/at91sam3s/blob/master/examples/eefc_uniqueid/main.c
|
||||||
|
void CIO::getUDID(uint8_t* buffer)
|
||||||
|
{
|
||||||
|
uint32_t status;
|
||||||
|
|
||||||
|
EFC1->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
|
||||||
|
do {
|
||||||
|
status = EFC1->EEFC_FSR;
|
||||||
|
} while ( (status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY );
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 16; i+=4) {
|
||||||
|
buffer[i + 0] = *(uint32_t *)(IFLASH1_ADDR + i) >> 24;
|
||||||
|
buffer[i + 1] = *(uint32_t *)(IFLASH1_ADDR + i) >> 16;
|
||||||
|
buffer[i + 2] = *(uint32_t *)(IFLASH1_ADDR + i) >> 8;
|
||||||
|
buffer[i + 3] = *(uint32_t *)(IFLASH1_ADDR + i) >> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFC1->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
|
||||||
|
do {
|
||||||
|
status = EFC1->EEFC_FSR;
|
||||||
|
} while ( (status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY );
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -59,12 +59,21 @@
|
|||||||
#elif defined(STM32F4_DVM)
|
#elif defined(STM32F4_DVM)
|
||||||
#include "pins/pins_f4_stm32dvm_v3.h"
|
#include "pins/pins_f4_stm32dvm_v3.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F7_DVM)
|
||||||
|
#include "pins/pins_f7_stm32dvm_v5.h"
|
||||||
|
|
||||||
#elif defined(DRCC_DVM_NQF)
|
#elif defined(DRCC_DVM_NQF)
|
||||||
#include "pins/pins_f4_drcc_nqf.h"
|
#include "pins/pins_f4_drcc_nqf.h"
|
||||||
|
|
||||||
|
#elif defined(DRCC_DVM_HHP446)
|
||||||
|
#include "pins/pins_f4_drcc_hhp446.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||||
|
#include "pins/pins_f4_stm32eda.h"
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error "A valid board type macro need to be defined."
|
#error "A valid board type macro need to be defined."
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif //#ifndef _IO_PINS_H
|
#endif //#ifndef _IO_PINS_H
|
||||||
|
|||||||
@@ -106,6 +106,14 @@ void CIO::initInt()
|
|||||||
GPIO_Init(PORT_NXDN, &GPIO_InitStruct);
|
GPIO_Init(PORT_NXDN, &GPIO_InitStruct);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
// M17 pin
|
||||||
|
RCC_AHB1PeriphClockCmd(RCC_Per_M17, ENABLE);
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_M17;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
|
||||||
|
GPIO_Init(PORT_M17, &GPIO_InitStruct);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
// POCSAG pin
|
// POCSAG pin
|
||||||
RCC_AHB1PeriphClockCmd(RCC_Per_POCSAG, ENABLE);
|
RCC_AHB1PeriphClockCmd(RCC_Per_POCSAG, ENABLE);
|
||||||
@@ -157,6 +165,14 @@ void CIO::initInt()
|
|||||||
GPIO_Init(PORT_MNXDN, &GPIO_InitStruct);
|
GPIO_Init(PORT_MNXDN, &GPIO_InitStruct);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
// M17 mode pin
|
||||||
|
RCC_AHB1PeriphClockCmd(RCC_Per_MM17, ENABLE);
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_MM17;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
|
||||||
|
GPIO_Init(PORT_MM17, &GPIO_InitStruct);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
// POCSAG mode pin
|
// POCSAG mode pin
|
||||||
RCC_AHB1PeriphClockCmd(RCC_Per_MPOCSAG, ENABLE);
|
RCC_AHB1PeriphClockCmd(RCC_Per_MPOCSAG, ENABLE);
|
||||||
@@ -440,6 +456,27 @@ void CIO::setNXDNInt(bool on)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIO::setM17Int(bool on)
|
||||||
|
{
|
||||||
|
#if defined(MODE_LEDS)
|
||||||
|
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
GPIO_WriteBit(PORT_DSTAR, PIN_DSTAR, on ? Bit_SET : Bit_RESET);
|
||||||
|
GPIO_WriteBit(PORT_P25, PIN_P25, on ? Bit_SET : Bit_RESET);
|
||||||
|
#else
|
||||||
|
GPIO_WriteBit(PORT_M17, PIN_M17, on ? Bit_SET : Bit_RESET);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
|
||||||
|
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
GPIO_WriteBit(PORT_MDSTAR, PIN_MDSTAR, on ? Bit_SET : Bit_RESET);
|
||||||
|
GPIO_WriteBit(PORT_MP25, PIN_MP25, on ? Bit_SET : Bit_RESET);
|
||||||
|
#else
|
||||||
|
GPIO_WriteBit(PORT_MM17, PIN_MM17, on ? Bit_SET : Bit_RESET);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void CIO::setPOCSAGInt(bool on)
|
void CIO::setPOCSAGInt(bool on)
|
||||||
{
|
{
|
||||||
#if defined(MODE_LEDS)
|
#if defined(MODE_LEDS)
|
||||||
@@ -508,4 +545,21 @@ void CIO::delayInt(unsigned int dly)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t CIO::getCPU() const
|
||||||
|
{
|
||||||
|
return 2U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIO::getUDID(uint8_t* buffer)
|
||||||
|
{
|
||||||
|
#if defined(STM32F4XX)
|
||||||
|
::memcpy(buffer, (void *)0x1FFF7A10, 12U);
|
||||||
|
#elif defined(STM32F722xx)
|
||||||
|
::memcpy(buffer, (void *)0x1FF07A10, 12U);
|
||||||
|
#elif defined(STM32F767xx)
|
||||||
|
::memcpy(buffer, (void *)0x1FF0F420, 12U);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+39
-46
@@ -23,7 +23,6 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "IO.h"
|
#include "IO.h"
|
||||||
|
|
||||||
|
|
||||||
#if defined(STM32F1)
|
#if defined(STM32F1)
|
||||||
|
|
||||||
#if defined(STM32F1_POG)
|
#if defined(STM32F1_POG)
|
||||||
@@ -41,7 +40,6 @@ YSF PB8 output
|
|||||||
P25 PB9 output
|
P25 PB9 output
|
||||||
NXDN PB10 output
|
NXDN PB10 output
|
||||||
POCSAG PB11 output
|
POCSAG PB11 output
|
||||||
FM PB12 output
|
|
||||||
|
|
||||||
RX PB0 analog input (ADC1_8)
|
RX PB0 analog input (ADC1_8)
|
||||||
RSSI PB1 analog input (ADC2_9)
|
RSSI PB1 analog input (ADC2_9)
|
||||||
@@ -85,9 +83,6 @@ USART1_RXD PA10 input (AF)
|
|||||||
#define PIN_POCSAG 11
|
#define PIN_POCSAG 11
|
||||||
#define PORT_POCSAG GPIOB
|
#define PORT_POCSAG GPIOB
|
||||||
#define BB_POCSAG *((bitband_t)BITBAND_PERIPH(&PORT_POCSAG->ODR, PIN_POCSAG))
|
#define BB_POCSAG *((bitband_t)BITBAND_PERIPH(&PORT_POCSAG->ODR, PIN_POCSAG))
|
||||||
#define PIN_FM 14
|
|
||||||
#define PORT_FM GPIOB
|
|
||||||
#define BB_FM *((bitband_t)BITBAND_PERIPH(&PORT_FM->ODR, PIN_FM))
|
|
||||||
|
|
||||||
#define PIN_RX 0
|
#define PIN_RX 0
|
||||||
#define PIN_RX_ADC_CH 8
|
#define PIN_RX_ADC_CH 8
|
||||||
@@ -158,35 +153,16 @@ void GPIOConfigPin(GPIO_TypeDef *port_ptr, uint32_t pin, uint32_t mode_cnf_value
|
|||||||
#if defined(STM32F1_POG)
|
#if defined(STM32F1_POG)
|
||||||
void FancyLEDEffect()
|
void FancyLEDEffect()
|
||||||
{
|
{
|
||||||
int ledCount = 10;
|
bitband_t foo[] = {&BB_LED, &BB_COSLED, &BB_PTT, &BB_DMR, &BB_DSTAR, &BB_YSF, &BB_P25};
|
||||||
|
|
||||||
bitband_t foo[] = {&BB_LED, &BB_COSLED, &BB_PTT, &BB_DMR, &BB_DSTAR, &BB_YSF, &BB_P25,
|
for(int i=0; i<7; i++){
|
||||||
#if defined(USE_ALTERNATE_NXDN_LEDS)
|
*foo[i] = 0x01;
|
||||||
NULL,
|
|
||||||
#else
|
|
||||||
&BB_NXDN,
|
|
||||||
#endif
|
|
||||||
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
|
||||||
NULL,
|
|
||||||
#else
|
|
||||||
&BB_POCSAG,
|
|
||||||
#endif
|
|
||||||
#if defined(USE_ALTERNATE_FM_LEDS)
|
|
||||||
NULL};
|
|
||||||
#else
|
|
||||||
&BB_FM};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(int i=0; i<ledCount; i++){
|
|
||||||
if(foo[i] != NULL)
|
|
||||||
*foo[i] = 0x01;
|
|
||||||
}
|
}
|
||||||
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1);
|
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1);
|
||||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
||||||
delay(SystemCoreClock/1000*100);
|
delay(SystemCoreClock/1000*100);
|
||||||
for(int i=0; i<ledCount; i++){
|
for(int i=0; i<7; i++){
|
||||||
if(foo[i] != NULL)
|
*foo[i] = 0x00;
|
||||||
*foo[i] = 0x00;
|
|
||||||
}
|
}
|
||||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||||
delay(SystemCoreClock/1000*20);
|
delay(SystemCoreClock/1000*20);
|
||||||
@@ -195,22 +171,18 @@ void FancyLEDEffect()
|
|||||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||||
|
|
||||||
*foo[0] = 0x01;
|
*foo[0] = 0x01;
|
||||||
for(int i=1; i<ledCount; i++){
|
for(int i=1; i<7; i++){
|
||||||
delay(SystemCoreClock/1000*10);
|
delay(SystemCoreClock/1000*10);
|
||||||
if (foo[i-1] != NULL)
|
*foo[i-1] = 0x00;
|
||||||
*foo[i-1] = 0x00;
|
*foo[i] = 0x01;
|
||||||
if (foo[i] != NULL)
|
|
||||||
*foo[i] = 0x01;
|
|
||||||
}
|
}
|
||||||
for(int i=ledCount - 2; i>=0; i--) {
|
for(int i=5; i>=0; i--){
|
||||||
delay(SystemCoreClock/1000*10);
|
delay(SystemCoreClock/1000*10);
|
||||||
if (foo[i+1] != NULL)
|
*foo[i+1] = 0x00;
|
||||||
*foo[i+1] = 0x00;
|
*foo[i] = 0x01;
|
||||||
if (foo[i] != NULL)
|
|
||||||
*foo[i] = 0x01;
|
|
||||||
}
|
}
|
||||||
delay(SystemCoreClock/1000*10);
|
delay(SystemCoreClock/1000*10);
|
||||||
*foo[0] = 0x00;
|
*foo[5+1-6] = 0x00;
|
||||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
|
||||||
delay(SystemCoreClock/1000*10);
|
delay(SystemCoreClock/1000*10);
|
||||||
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
|
||||||
@@ -252,12 +224,12 @@ static inline void GPIOInit()
|
|||||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||||
GPIOConfigPin(PORT_NXDN, PIN_NXDN, GPIO_CRL_MODE0_1);
|
GPIOConfigPin(PORT_NXDN, PIN_NXDN, GPIO_CRL_MODE0_1);
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
GPIOConfigPin(PORT_M17, PIN_M17, GPIO_CRL_MODE0_1);
|
||||||
|
#endif
|
||||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
GPIOConfigPin(PORT_POCSAG, PIN_POCSAG, GPIO_CRL_MODE0_1);
|
GPIOConfigPin(PORT_POCSAG, PIN_POCSAG, GPIO_CRL_MODE0_1);
|
||||||
#endif
|
#endif
|
||||||
#if !defined(USE_ALTERNATE_FM_LEDS)
|
|
||||||
GPIOConfigPin(PORT_FM, PIN_FM, GPIO_CRL_MODE0_1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GPIOConfigPin(PORT_RX, PIN_RX, 0);
|
GPIOConfigPin(PORT_RX, PIN_RX, 0);
|
||||||
#if defined(SEND_RSSI_DATA)
|
#if defined(SEND_RSSI_DATA)
|
||||||
@@ -479,6 +451,16 @@ void CIO::setNXDNInt(bool on)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIO::setM17Int(bool on)
|
||||||
|
{
|
||||||
|
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
BB_DSTAR = !!on;
|
||||||
|
BB_P25 = !!on;
|
||||||
|
#else
|
||||||
|
BB_M17 = !!on;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void CIO::setPOCSAGInt(bool on)
|
void CIO::setPOCSAGInt(bool on)
|
||||||
{
|
{
|
||||||
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
@@ -494,8 +476,6 @@ void CIO::setFMInt(bool on)
|
|||||||
#if defined(USE_ALTERNATE_FM_LEDS)
|
#if defined(USE_ALTERNATE_FM_LEDS)
|
||||||
BB_DSTAR = !!on;
|
BB_DSTAR = !!on;
|
||||||
BB_YSF = !!on;
|
BB_YSF = !!on;
|
||||||
#else
|
|
||||||
BB_FM = !!on;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,4 +484,17 @@ void CIO::delayInt(unsigned int dly)
|
|||||||
delay(dly);
|
delay(dly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t CIO::getCPU() const
|
||||||
|
{
|
||||||
|
return 2U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIO::getUDID(uint8_t* buffer)
|
||||||
|
{
|
||||||
|
#if defined(STM32F105xC)
|
||||||
|
::memcpy(buffer, (void *)0x1FFFF7E8, 12U);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,9 @@ void CIO::initInt()
|
|||||||
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||||
pinMode(PIN_NXDN, OUTPUT);
|
pinMode(PIN_NXDN, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
pinMode(PIN_M17, OUTPUT);
|
||||||
|
#endif
|
||||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
pinMode(PIN_POCSAG, OUTPUT);
|
pinMode(PIN_POCSAG, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
@@ -237,6 +240,16 @@ void CIO::setNXDNInt(bool on)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIO::setM17Int(bool on)
|
||||||
|
{
|
||||||
|
#if defined(USE_ALTERNATE_M17_LEDS)
|
||||||
|
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
|
||||||
|
digitalWrite(PIN_P25, on ? HIGH : LOW);
|
||||||
|
#else
|
||||||
|
digitalWrite(PIN_M17, on ? HIGH : LOW);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void CIO::setPOCSAGInt(bool on)
|
void CIO::setPOCSAGInt(bool on)
|
||||||
{
|
{
|
||||||
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
@@ -262,4 +275,15 @@ void CIO::delayInt(unsigned int dly)
|
|||||||
delay(dly);
|
delay(dly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t CIO::getCPU() const
|
||||||
|
{
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CIO::getUDID(uint8_t* buffer)
|
||||||
|
{
|
||||||
|
::memcpy(buffer, (void *)0x4058, 16U);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(M17DEFINES_H)
|
||||||
|
#define M17DEFINES_H
|
||||||
|
|
||||||
|
const unsigned int M17_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
|
||||||
|
|
||||||
|
const unsigned int M17_FRAME_LENGTH_BITS = 384U;
|
||||||
|
const unsigned int M17_FRAME_LENGTH_BYTES = M17_FRAME_LENGTH_BITS / 8U;
|
||||||
|
const unsigned int M17_FRAME_LENGTH_SYMBOLS = M17_FRAME_LENGTH_BITS / 2U;
|
||||||
|
const unsigned int M17_FRAME_LENGTH_SAMPLES = M17_FRAME_LENGTH_SYMBOLS * M17_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const unsigned int M17_SYNC_LENGTH_BITS = 16U;
|
||||||
|
const unsigned int M17_SYNC_LENGTH_BYTES = M17_SYNC_LENGTH_BITS / 8U;
|
||||||
|
const unsigned int M17_SYNC_LENGTH_SYMBOLS = M17_SYNC_LENGTH_BITS / 2U;
|
||||||
|
const unsigned int M17_SYNC_LENGTH_SAMPLES = M17_SYNC_LENGTH_SYMBOLS * M17_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint8_t M17_LINK_SETUP_SYNC_BYTES[] = {0x55U, 0xF7U};
|
||||||
|
const uint8_t M17_STREAM_SYNC_BYTES[] = {0xFFU, 0x5DU};
|
||||||
|
const uint8_t M17_EOF_SYNC_BYTES[] = {0x55U, 0x5DU};
|
||||||
|
|
||||||
|
const uint16_t M17_LINK_SETUP_SYNC_BITS = 0x55F7U;
|
||||||
|
const uint16_t M17_STREAM_SYNC_BITS = 0xFF5DU;
|
||||||
|
const uint16_t M17_EOF_SYNC_BITS = 0x555DU;
|
||||||
|
|
||||||
|
// 5 5 F 7
|
||||||
|
// 01 01 01 01 11 11 01 11
|
||||||
|
// +3 +3 +3 +3 -3 -3 +3 -3
|
||||||
|
|
||||||
|
const int8_t M17_LINK_SETUP_SYNC_SYMBOLS_VALUES[] = {+3, +3, +3, +3, -3, -3, +3, -3};
|
||||||
|
|
||||||
|
const uint8_t M17_LINK_SETUP_SYNC_SYMBOLS = 0xF2U;
|
||||||
|
|
||||||
|
// F F 5 D
|
||||||
|
// 11 11 11 11 01 01 11 01
|
||||||
|
// -3 -3 -3 -3 +3 +3 -3 +3
|
||||||
|
|
||||||
|
const int8_t M17_STREAM_SYNC_SYMBOLS_VALUES[] = {-3, -3, -3, -3, +3, +3, -3, +3};
|
||||||
|
|
||||||
|
const uint8_t M17_STREAM_SYNC_SYMBOLS = 0x0DU;
|
||||||
|
|
||||||
|
// 5 5 5 D
|
||||||
|
// 01 01 01 01 01 01 11 01
|
||||||
|
// +3 +3 +3 +3 +3 +3 -3 +3
|
||||||
|
|
||||||
|
const int8_t M17_EOF_SYNC_SYMBOLS_VALUES[] = {+3, +3, +3, +3, +3, +3, -3, +3};
|
||||||
|
|
||||||
|
const uint8_t M17_EOF_SYNC_SYMBOLS = 0xFDU;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,485 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2017,2020,2021 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "M17RX.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
const q15_t SCALING_FACTOR = 18750; // Q15(0.55)
|
||||||
|
|
||||||
|
const uint8_t MAX_SYNC_BIT_START_ERRS = 0U;
|
||||||
|
const uint8_t MAX_SYNC_BIT_RUN_ERRS = 2U;
|
||||||
|
|
||||||
|
const uint8_t MAX_SYNC_SYMBOL_START_ERRS = 0U;
|
||||||
|
const uint8_t MAX_SYNC_SYMBOL_RUN_ERRS = 1U;
|
||||||
|
|
||||||
|
const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||||
|
|
||||||
|
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
||||||
|
|
||||||
|
const uint8_t NOAVEPTR = 99U;
|
||||||
|
|
||||||
|
const uint16_t NOENDPTR = 9999U;
|
||||||
|
|
||||||
|
const unsigned int MAX_SYNC_FRAMES = 3U + 1U;
|
||||||
|
|
||||||
|
CM17RX::CM17RX() :
|
||||||
|
m_state(M17RXS_NONE),
|
||||||
|
m_bitBuffer(),
|
||||||
|
m_buffer(),
|
||||||
|
m_bitPtr(0U),
|
||||||
|
m_dataPtr(0U),
|
||||||
|
m_startPtr(NOENDPTR),
|
||||||
|
m_endPtr(NOENDPTR),
|
||||||
|
m_syncPtr(NOENDPTR),
|
||||||
|
m_minSyncPtr(NOENDPTR),
|
||||||
|
m_maxSyncPtr(NOENDPTR),
|
||||||
|
m_maxCorr(0),
|
||||||
|
m_lostCount(0U),
|
||||||
|
m_countdown(0U),
|
||||||
|
m_nextState(M17RXS_NONE),
|
||||||
|
m_centre(),
|
||||||
|
m_centreVal(0),
|
||||||
|
m_threshold(),
|
||||||
|
m_thresholdVal(0),
|
||||||
|
m_averagePtr(NOAVEPTR),
|
||||||
|
m_rssiAccum(0U),
|
||||||
|
m_rssiCount(0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17RX::reset()
|
||||||
|
{
|
||||||
|
m_state = M17RXS_NONE;
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
m_bitPtr = 0U;
|
||||||
|
m_maxCorr = 0;
|
||||||
|
m_averagePtr = NOAVEPTR;
|
||||||
|
m_startPtr = NOENDPTR;
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
m_syncPtr = NOENDPTR;
|
||||||
|
m_minSyncPtr = NOENDPTR;
|
||||||
|
m_maxSyncPtr = NOENDPTR;
|
||||||
|
m_centreVal = 0;
|
||||||
|
m_thresholdVal = 0;
|
||||||
|
m_lostCount = 0U;
|
||||||
|
m_countdown = 0U;
|
||||||
|
m_nextState = M17RXS_NONE;
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17RX::samples(const q15_t* samples, uint16_t* rssi, uint8_t length)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0U; i < length; i++) {
|
||||||
|
q15_t sample = samples[i];
|
||||||
|
|
||||||
|
m_rssiAccum += rssi[i];
|
||||||
|
m_rssiCount++;
|
||||||
|
|
||||||
|
m_bitBuffer[m_bitPtr] <<= 1;
|
||||||
|
if (sample < 0)
|
||||||
|
m_bitBuffer[m_bitPtr] |= 0x01U;
|
||||||
|
|
||||||
|
m_buffer[m_dataPtr] = sample;
|
||||||
|
|
||||||
|
switch (m_state) {
|
||||||
|
case M17RXS_LINK_SETUP:
|
||||||
|
case M17RXS_STREAM:
|
||||||
|
processData(sample);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
processNone(sample);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dataPtr++;
|
||||||
|
if (m_dataPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
|
||||||
|
m_bitPtr++;
|
||||||
|
if (m_bitPtr >= M17_RADIO_SYMBOL_LENGTH)
|
||||||
|
m_bitPtr = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17RX::processNone(q15_t sample)
|
||||||
|
{
|
||||||
|
bool ret1 = correlateSync(M17_LINK_SETUP_SYNC_SYMBOLS, M17_LINK_SETUP_SYNC_SYMBOLS_VALUES, M17_LINK_SETUP_SYNC_BYTES, MAX_SYNC_SYMBOL_START_ERRS, MAX_SYNC_BIT_START_ERRS);
|
||||||
|
bool ret2 = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_START_ERRS, MAX_SYNC_BIT_START_ERRS);
|
||||||
|
|
||||||
|
if (ret1 || ret2) {
|
||||||
|
// On the first sync, start the countdown to the state change
|
||||||
|
if (m_countdown == 0U) {
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
|
m_averagePtr = NOAVEPTR;
|
||||||
|
|
||||||
|
m_countdown = 5U;
|
||||||
|
|
||||||
|
if (ret1) m_nextState = M17RXS_LINK_SETUP;
|
||||||
|
if (ret2) m_nextState = M17RXS_STREAM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_countdown > 0U)
|
||||||
|
m_countdown--;
|
||||||
|
|
||||||
|
if (m_countdown == 1U) {
|
||||||
|
m_minSyncPtr = m_syncPtr + M17_FRAME_LENGTH_SAMPLES - 1U;
|
||||||
|
if (m_minSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
m_minSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
m_maxSyncPtr = m_syncPtr + 1U;
|
||||||
|
if (m_maxSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
m_maxSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
m_state = m_nextState;
|
||||||
|
m_countdown = 0U;
|
||||||
|
m_nextState = M17RXS_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17RX::processData(q15_t sample)
|
||||||
|
{
|
||||||
|
bool eof = false;
|
||||||
|
|
||||||
|
if (m_minSyncPtr < m_maxSyncPtr) {
|
||||||
|
if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr) {
|
||||||
|
bool ret = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
|
||||||
|
|
||||||
|
eof = correlateSync(M17_EOF_SYNC_SYMBOLS, M17_EOF_SYNC_SYMBOLS_VALUES, M17_EOF_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
|
||||||
|
|
||||||
|
if (ret) m_state = M17RXS_STREAM;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr) {
|
||||||
|
bool ret = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
|
||||||
|
|
||||||
|
eof = correlateSync(M17_EOF_SYNC_SYMBOLS, M17_EOF_SYNC_SYMBOLS_VALUES, M17_EOF_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
|
||||||
|
|
||||||
|
if (ret) m_state = M17RXS_STREAM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eof) {
|
||||||
|
DEBUG4("M17RX: eof sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
|
||||||
|
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
|
serial.writeM17EOT();
|
||||||
|
|
||||||
|
m_state = M17RXS_NONE;
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
m_averagePtr = NOAVEPTR;
|
||||||
|
m_countdown = 0U;
|
||||||
|
m_nextState = M17RXS_NONE;
|
||||||
|
m_maxCorr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_dataPtr == m_endPtr) {
|
||||||
|
// Only update the centre and threshold if they are from a good sync
|
||||||
|
if (m_lostCount == MAX_SYNC_FRAMES) {
|
||||||
|
m_minSyncPtr = m_syncPtr + M17_FRAME_LENGTH_SAMPLES - 1U;
|
||||||
|
if (m_minSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
m_minSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
m_maxSyncPtr = m_syncPtr + 1U;
|
||||||
|
if (m_maxSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
m_maxSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateLevels(m_startPtr, M17_FRAME_LENGTH_SYMBOLS);
|
||||||
|
|
||||||
|
switch (m_state) {
|
||||||
|
case M17RXS_LINK_SETUP:
|
||||||
|
DEBUG4("M17RX: link setup sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
|
||||||
|
break;
|
||||||
|
case M17RXS_STREAM:
|
||||||
|
DEBUG4("M17RX: stream sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t frame[M17_FRAME_LENGTH_BYTES + 3U];
|
||||||
|
samplesToBits(m_startPtr, M17_FRAME_LENGTH_SYMBOLS, frame, 8U, m_centreVal, m_thresholdVal);
|
||||||
|
|
||||||
|
// We've not seen a stream sync for too long, signal RXLOST and change to RX_NONE
|
||||||
|
m_lostCount--;
|
||||||
|
if (m_lostCount == 0U) {
|
||||||
|
DEBUG1("M17RX: sync timed out, lost lock");
|
||||||
|
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
|
serial.writeM17Lost();
|
||||||
|
|
||||||
|
m_state = M17RXS_NONE;
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
m_averagePtr = NOAVEPTR;
|
||||||
|
m_countdown = 0U;
|
||||||
|
m_nextState = M17RXS_NONE;
|
||||||
|
m_maxCorr = 0;
|
||||||
|
} else {
|
||||||
|
frame[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U;
|
||||||
|
|
||||||
|
switch (m_state) {
|
||||||
|
case M17RXS_LINK_SETUP:
|
||||||
|
writeRSSILinkSetup(frame);
|
||||||
|
break;
|
||||||
|
case M17RXS_STREAM:
|
||||||
|
writeRSSIStream(frame);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_maxCorr = 0;
|
||||||
|
m_nextState = M17RXS_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CM17RX::correlateSync(uint8_t syncSymbols, const int8_t* syncSymbolValues, const uint8_t* syncBytes, uint8_t maxSymbolErrs, uint8_t maxBitErrs)
|
||||||
|
{
|
||||||
|
if (countBits8(m_bitBuffer[m_bitPtr] ^ syncSymbols) <= maxSymbolErrs) {
|
||||||
|
uint16_t ptr = m_dataPtr + M17_FRAME_LENGTH_SAMPLES - M17_SYNC_LENGTH_SAMPLES + M17_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (ptr >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
ptr -= M17_FRAME_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
q31_t corr = 0;
|
||||||
|
q15_t min = 16000;
|
||||||
|
q15_t max = -16000;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < M17_SYNC_LENGTH_SYMBOLS; i++) {
|
||||||
|
q15_t val = m_buffer[ptr];
|
||||||
|
|
||||||
|
if (val > max)
|
||||||
|
max = val;
|
||||||
|
if (val < min)
|
||||||
|
min = val;
|
||||||
|
|
||||||
|
switch (syncSymbolValues[i]) {
|
||||||
|
case +3:
|
||||||
|
corr -= (val + val + val);
|
||||||
|
break;
|
||||||
|
case +1:
|
||||||
|
corr -= val;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
corr += val;
|
||||||
|
break;
|
||||||
|
default: // -3
|
||||||
|
corr += (val + val + val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += M17_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (ptr >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
ptr -= M17_FRAME_LENGTH_SAMPLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (corr > m_maxCorr) {
|
||||||
|
if (m_averagePtr == NOAVEPTR) {
|
||||||
|
m_centreVal = (max + min) >> 1;
|
||||||
|
|
||||||
|
q31_t v1 = (max - m_centreVal) * SCALING_FACTOR;
|
||||||
|
m_thresholdVal = q15_t(v1 >> 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t startPtr = m_dataPtr + M17_FRAME_LENGTH_SAMPLES - M17_SYNC_LENGTH_SAMPLES + M17_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (startPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
startPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
uint8_t sync[M17_SYNC_LENGTH_BYTES];
|
||||||
|
samplesToBits(startPtr, M17_SYNC_LENGTH_SYMBOLS, sync, 0U, m_centreVal, m_thresholdVal);
|
||||||
|
|
||||||
|
uint8_t errs = 0U;
|
||||||
|
for (uint8_t i = 0U; i < M17_SYNC_LENGTH_BYTES; i++)
|
||||||
|
errs += countBits8(sync[i] ^ syncBytes[i]);
|
||||||
|
|
||||||
|
if (errs <= maxBitErrs) {
|
||||||
|
m_maxCorr = corr;
|
||||||
|
m_lostCount = MAX_SYNC_FRAMES;
|
||||||
|
m_syncPtr = m_dataPtr;
|
||||||
|
|
||||||
|
m_startPtr = startPtr;
|
||||||
|
|
||||||
|
m_endPtr = m_dataPtr + M17_FRAME_LENGTH_SAMPLES - M17_SYNC_LENGTH_SAMPLES - 1U;
|
||||||
|
if (m_endPtr >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
m_endPtr -= M17_FRAME_LENGTH_SAMPLES;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17RX::calculateLevels(uint16_t start, uint16_t count)
|
||||||
|
{
|
||||||
|
q15_t maxPos = -16000;
|
||||||
|
q15_t minPos = 16000;
|
||||||
|
q15_t maxNeg = 16000;
|
||||||
|
q15_t minNeg = -16000;
|
||||||
|
|
||||||
|
for (uint16_t i = 0U; i < count; i++) {
|
||||||
|
q15_t sample = m_buffer[start];
|
||||||
|
|
||||||
|
if (sample > 0) {
|
||||||
|
if (sample > maxPos)
|
||||||
|
maxPos = sample;
|
||||||
|
if (sample < minPos)
|
||||||
|
minPos = sample;
|
||||||
|
} else {
|
||||||
|
if (sample < maxNeg)
|
||||||
|
maxNeg = sample;
|
||||||
|
if (sample > minNeg)
|
||||||
|
minNeg = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
start += M17_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (start >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
start -= M17_FRAME_LENGTH_SAMPLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
q15_t posThresh = (maxPos + minPos) >> 1;
|
||||||
|
q15_t negThresh = (maxNeg + minNeg) >> 1;
|
||||||
|
|
||||||
|
q15_t centre = (posThresh + negThresh) >> 1;
|
||||||
|
|
||||||
|
q15_t threshold = posThresh - centre;
|
||||||
|
|
||||||
|
DEBUG5("M17RX: pos/neg/centre/threshold", posThresh, negThresh, centre, threshold);
|
||||||
|
|
||||||
|
if (m_averagePtr == NOAVEPTR) {
|
||||||
|
for (uint8_t i = 0U; i < 16U; i++) {
|
||||||
|
m_centre[i] = centre;
|
||||||
|
m_threshold[i] = threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_averagePtr = 0U;
|
||||||
|
} else {
|
||||||
|
m_centre[m_averagePtr] = centre;
|
||||||
|
m_threshold[m_averagePtr] = threshold;
|
||||||
|
|
||||||
|
m_averagePtr++;
|
||||||
|
if (m_averagePtr >= 16U)
|
||||||
|
m_averagePtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_centreVal = 0;
|
||||||
|
m_thresholdVal = 0;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < 16U; i++) {
|
||||||
|
m_centreVal += m_centre[i];
|
||||||
|
m_thresholdVal += m_threshold[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_centreVal >>= 4;
|
||||||
|
m_thresholdVal >>= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17RX::samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold)
|
||||||
|
{
|
||||||
|
for (uint16_t i = 0U; i < count; i++) {
|
||||||
|
q15_t sample = m_buffer[start] - centre;
|
||||||
|
|
||||||
|
if (sample < -threshold) {
|
||||||
|
WRITE_BIT1(buffer, offset, false);
|
||||||
|
offset++;
|
||||||
|
WRITE_BIT1(buffer, offset, true);
|
||||||
|
offset++;
|
||||||
|
} else if (sample < 0) {
|
||||||
|
WRITE_BIT1(buffer, offset, false);
|
||||||
|
offset++;
|
||||||
|
WRITE_BIT1(buffer, offset, false);
|
||||||
|
offset++;
|
||||||
|
} else if (sample < threshold) {
|
||||||
|
WRITE_BIT1(buffer, offset, true);
|
||||||
|
offset++;
|
||||||
|
WRITE_BIT1(buffer, offset, false);
|
||||||
|
offset++;
|
||||||
|
} else {
|
||||||
|
WRITE_BIT1(buffer, offset, true);
|
||||||
|
offset++;
|
||||||
|
WRITE_BIT1(buffer, offset, true);
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
start += M17_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (start >= M17_FRAME_LENGTH_SAMPLES)
|
||||||
|
start -= M17_FRAME_LENGTH_SAMPLES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17RX::writeRSSILinkSetup(uint8_t* data)
|
||||||
|
{
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
if (m_rssiCount > 0U) {
|
||||||
|
uint16_t rssi = m_rssiAccum / m_rssiCount;
|
||||||
|
|
||||||
|
data[49U] = (rssi >> 8) & 0xFFU;
|
||||||
|
data[50U] = (rssi >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
serial.writeM17LinkSetup(data, M17_FRAME_LENGTH_BYTES + 3U);
|
||||||
|
} else {
|
||||||
|
serial.writeM17LinkSetup(data, M17_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
serial.writeM17LinkSetup(data, M17_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17RX::writeRSSIStream(uint8_t* data)
|
||||||
|
{
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
if (m_rssiCount > 0U) {
|
||||||
|
uint16_t rssi = m_rssiAccum / m_rssiCount;
|
||||||
|
|
||||||
|
data[49U] = (rssi >> 8) & 0xFFU;
|
||||||
|
data[50U] = (rssi >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
serial.writeM17Stream(data, M17_FRAME_LENGTH_BYTES + 3U);
|
||||||
|
} else {
|
||||||
|
serial.writeM17Stream(data, M17_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
serial.writeM17Stream(data, M17_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2017,2020,2021 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
|
||||||
|
#if !defined(M17RX_H)
|
||||||
|
#define M17RX_H
|
||||||
|
|
||||||
|
#include "M17Defines.h"
|
||||||
|
|
||||||
|
enum M17RX_STATE {
|
||||||
|
M17RXS_NONE,
|
||||||
|
M17RXS_LINK_SETUP,
|
||||||
|
M17RXS_STREAM
|
||||||
|
};
|
||||||
|
|
||||||
|
class CM17RX {
|
||||||
|
public:
|
||||||
|
CM17RX();
|
||||||
|
|
||||||
|
void samples(const q15_t* samples, uint16_t* rssi, uint8_t length);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
M17RX_STATE m_state;
|
||||||
|
uint8_t m_bitBuffer[M17_RADIO_SYMBOL_LENGTH];
|
||||||
|
q15_t m_buffer[M17_FRAME_LENGTH_SAMPLES];
|
||||||
|
uint16_t m_bitPtr;
|
||||||
|
uint16_t m_dataPtr;
|
||||||
|
uint16_t m_startPtr;
|
||||||
|
uint16_t m_endPtr;
|
||||||
|
uint16_t m_syncPtr;
|
||||||
|
uint16_t m_minSyncPtr;
|
||||||
|
uint16_t m_maxSyncPtr;
|
||||||
|
q31_t m_maxCorr;
|
||||||
|
uint16_t m_lostCount;
|
||||||
|
uint8_t m_countdown;
|
||||||
|
M17RX_STATE m_nextState;
|
||||||
|
q15_t m_centre[16U];
|
||||||
|
q15_t m_centreVal;
|
||||||
|
q15_t m_threshold[16U];
|
||||||
|
q15_t m_thresholdVal;
|
||||||
|
uint8_t m_averagePtr;
|
||||||
|
uint32_t m_rssiAccum;
|
||||||
|
uint16_t m_rssiCount;
|
||||||
|
|
||||||
|
void processNone(q15_t sample);
|
||||||
|
void processData(q15_t sample);
|
||||||
|
bool correlateSync(uint8_t syncSymbols, const int8_t* syncSymbolValues, const uint8_t* syncBytes, uint8_t maxSymbolErrs, uint8_t maxBitErrs);
|
||||||
|
void calculateLevels(uint16_t start, uint16_t count);
|
||||||
|
void samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
|
||||||
|
void writeRSSILinkSetup(uint8_t* data);
|
||||||
|
void writeRSSIStream(uint8_t* data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2018,2020,2021 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "M17TX.h"
|
||||||
|
|
||||||
|
#include "M17Defines.h"
|
||||||
|
|
||||||
|
// Generated using rcosdesign(0.5, 8, 5, 'sqrt') in MATLAB
|
||||||
|
static q15_t RRC_0_5_FILTER[] = {0, 0, 0, 0, -290, -174, 142, 432, 438, 90, -387, -561, -155, 658, 1225, 767,
|
||||||
|
-980, -3326, -4648, -3062, 2527, 11552, 21705, 29724, 32767, 29724, 21705,
|
||||||
|
11552, 2527, -3062, -4648, -3326, -980, 767, 1225, 658, -155, -561, -387, 90,
|
||||||
|
438, 432, 142, -174, -290}; // numTaps = 45, L = 5
|
||||||
|
const uint16_t RRC_0_5_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
|
||||||
|
|
||||||
|
const q15_t M17_LEVELA = 1481;
|
||||||
|
const q15_t M17_LEVELB = 494;
|
||||||
|
const q15_t M17_LEVELC = -494;
|
||||||
|
const q15_t M17_LEVELD = -1481;
|
||||||
|
|
||||||
|
const uint8_t M17_START_SYNC = 0x77U;
|
||||||
|
const uint8_t M17_END_SYNC = 0xFFU;
|
||||||
|
const uint8_t M17_HANG = 0x00U;
|
||||||
|
|
||||||
|
CM17TX::CM17TX() :
|
||||||
|
m_buffer(TX_BUFFER_LEN),
|
||||||
|
m_modFilter(),
|
||||||
|
m_modState(),
|
||||||
|
m_poBuffer(),
|
||||||
|
m_poLen(0U),
|
||||||
|
m_poPtr(0U),
|
||||||
|
m_txDelay(240U), // 200ms
|
||||||
|
m_txHang(4800U), // 4s
|
||||||
|
m_txCount(0U)
|
||||||
|
{
|
||||||
|
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
||||||
|
|
||||||
|
m_modFilter.L = M17_RADIO_SYMBOL_LENGTH;
|
||||||
|
m_modFilter.phaseLength = RRC_0_5_FILTER_PHASE_LEN;
|
||||||
|
m_modFilter.pCoeffs = RRC_0_5_FILTER;
|
||||||
|
m_modFilter.pState = m_modState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17TX::process()
|
||||||
|
{
|
||||||
|
// If we have M17 data to transmit, do so.
|
||||||
|
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
||||||
|
if (!m_tx) {
|
||||||
|
for (uint16_t i = 0U; i < m_txDelay; i++)
|
||||||
|
m_poBuffer[m_poLen++] = M17_START_SYNC;
|
||||||
|
} else {
|
||||||
|
for (uint8_t i = 0U; i < M17_FRAME_LENGTH_BYTES; i++) {
|
||||||
|
uint8_t c = 0U;
|
||||||
|
m_buffer.get(c);
|
||||||
|
m_poBuffer[m_poLen++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_poLen > 0U) {
|
||||||
|
// Transmit M17 data.
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > (4U * M17_RADIO_SYMBOL_LENGTH)) {
|
||||||
|
uint8_t c = m_poBuffer[m_poPtr++];
|
||||||
|
writeByte(c);
|
||||||
|
|
||||||
|
// Reduce space and reset the hang timer.
|
||||||
|
space -= 4U * M17_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (m_duplex)
|
||||||
|
m_txCount = m_txHang;
|
||||||
|
|
||||||
|
if (m_poPtr >= m_poLen) {
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_poLen = 0U;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (m_txCount > 0U) {
|
||||||
|
// Transmit silence until the hang timer has expired.
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > (4U * M17_RADIO_SYMBOL_LENGTH)) {
|
||||||
|
writeSilence();
|
||||||
|
|
||||||
|
space -= 4U * M17_RADIO_SYMBOL_LENGTH;
|
||||||
|
m_txCount--;
|
||||||
|
|
||||||
|
if (m_txCount == 0U)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CM17TX::writeData(const uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
if (length != (M17_FRAME_LENGTH_BYTES + 1U))
|
||||||
|
return 4U;
|
||||||
|
|
||||||
|
uint16_t space = m_buffer.getSpace();
|
||||||
|
if (space < M17_FRAME_LENGTH_BYTES)
|
||||||
|
return 5U;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < M17_FRAME_LENGTH_BYTES; i++)
|
||||||
|
m_buffer.put(data[i + 1U]);
|
||||||
|
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17TX::writeByte(uint8_t c)
|
||||||
|
{
|
||||||
|
q15_t inBuffer[4U];
|
||||||
|
q15_t outBuffer[M17_RADIO_SYMBOL_LENGTH * 4U];
|
||||||
|
|
||||||
|
const uint8_t MASK = 0xC0U;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < 4U; i++, c <<= 2) {
|
||||||
|
switch (c & MASK) {
|
||||||
|
case 0xC0U:
|
||||||
|
inBuffer[i] = M17_LEVELA;
|
||||||
|
break;
|
||||||
|
case 0x80U:
|
||||||
|
inBuffer[i] = M17_LEVELB;
|
||||||
|
break;
|
||||||
|
case 0x00U:
|
||||||
|
inBuffer[i] = M17_LEVELC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
inBuffer[i] = M17_LEVELD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U);
|
||||||
|
|
||||||
|
io.write(STATE_M17, outBuffer, M17_RADIO_SYMBOL_LENGTH * 4U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17TX::writeSilence()
|
||||||
|
{
|
||||||
|
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
|
||||||
|
q15_t outBuffer[M17_RADIO_SYMBOL_LENGTH * 4U];
|
||||||
|
|
||||||
|
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U);
|
||||||
|
|
||||||
|
io.write(STATE_M17, outBuffer, M17_RADIO_SYMBOL_LENGTH * 4U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17TX::setTXDelay(uint8_t delay)
|
||||||
|
{
|
||||||
|
m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay
|
||||||
|
|
||||||
|
if (m_txDelay > 1200U)
|
||||||
|
m_txDelay = 1200U;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CM17TX::getSpace() const
|
||||||
|
{
|
||||||
|
return m_buffer.getSpace() / M17_FRAME_LENGTH_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM17TX::setParams(uint8_t txHang)
|
||||||
|
{
|
||||||
|
m_txHang = txHang * 1200U;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
|
||||||
|
#if !defined(M17TX_H)
|
||||||
|
#define M17TX_H
|
||||||
|
|
||||||
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
|
class CM17TX {
|
||||||
|
public:
|
||||||
|
CM17TX();
|
||||||
|
|
||||||
|
uint8_t writeData(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
void process();
|
||||||
|
|
||||||
|
void setTXDelay(uint8_t delay);
|
||||||
|
|
||||||
|
uint8_t getSpace() const;
|
||||||
|
|
||||||
|
void setParams(uint8_t txHang);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CRingBuffer<uint8_t> m_buffer;
|
||||||
|
arm_fir_interpolate_instance_q15 m_modFilter;
|
||||||
|
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
||||||
|
uint8_t m_poBuffer[1200U];
|
||||||
|
uint16_t m_poLen;
|
||||||
|
uint16_t m_poPtr;
|
||||||
|
uint16_t m_txDelay;
|
||||||
|
uint32_t m_txHang;
|
||||||
|
uint32_t m_txCount;
|
||||||
|
|
||||||
|
void writeByte(uint8_t c);
|
||||||
|
void writeSilence();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -31,45 +31,75 @@ bool m_dmrEnable = true;
|
|||||||
bool m_ysfEnable = true;
|
bool m_ysfEnable = true;
|
||||||
bool m_p25Enable = true;
|
bool m_p25Enable = true;
|
||||||
bool m_nxdnEnable = true;
|
bool m_nxdnEnable = true;
|
||||||
|
bool m_m17Enable = true;
|
||||||
bool m_pocsagEnable = true;
|
bool m_pocsagEnable = true;
|
||||||
bool m_fmEnable = true;
|
bool m_fmEnable = true;
|
||||||
|
bool m_ax25Enable = true;
|
||||||
|
|
||||||
bool m_duplex = true;
|
bool m_duplex = true;
|
||||||
|
|
||||||
bool m_tx = false;
|
bool m_tx = false;
|
||||||
bool m_dcd = false;
|
bool m_dcd = false;
|
||||||
|
|
||||||
CDStarRX dstarRX;
|
#if defined(MODE_DSTAR)
|
||||||
CDStarTX dstarTX;
|
CDStarRX dstarRX;
|
||||||
|
CDStarTX dstarTX;
|
||||||
CDMRIdleRX dmrIdleRX;
|
|
||||||
CDMRRX dmrRX;
|
|
||||||
CDMRTX dmrTX;
|
|
||||||
|
|
||||||
CDMRDMORX dmrDMORX;
|
|
||||||
CDMRDMOTX dmrDMOTX;
|
|
||||||
|
|
||||||
CYSFRX ysfRX;
|
|
||||||
CYSFTX ysfTX;
|
|
||||||
|
|
||||||
CP25RX p25RX;
|
|
||||||
CP25TX p25TX;
|
|
||||||
|
|
||||||
CNXDNRX nxdnRX;
|
|
||||||
CNXDNTX nxdnTX;
|
|
||||||
|
|
||||||
CPOCSAGTX pocsagTX;
|
|
||||||
|
|
||||||
CFM fm;
|
|
||||||
|
|
||||||
CCalDStarRX calDStarRX;
|
CCalDStarRX calDStarRX;
|
||||||
CCalDStarTX calDStarTX;
|
CCalDStarTX calDStarTX;
|
||||||
CCalDMR calDMR;
|
#endif
|
||||||
CCalP25 calP25;
|
|
||||||
CCalNXDN calNXDN;
|
#if defined(MODE_DMR)
|
||||||
CCalFM calFM;
|
CDMRIdleRX dmrIdleRX;
|
||||||
CCalPOCSAG calPOCSAG;
|
CDMRRX dmrRX;
|
||||||
CCalRSSI calRSSI;
|
CDMRTX dmrTX;
|
||||||
|
|
||||||
|
CDMRDMORX dmrDMORX;
|
||||||
|
CDMRDMOTX dmrDMOTX;
|
||||||
|
|
||||||
|
CCalDMR calDMR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_YSF)
|
||||||
|
CYSFRX ysfRX;
|
||||||
|
CYSFTX ysfTX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
CP25RX p25RX;
|
||||||
|
CP25TX p25TX;
|
||||||
|
|
||||||
|
CCalP25 calP25;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
CNXDNRX nxdnRX;
|
||||||
|
CNXDNTX nxdnTX;
|
||||||
|
|
||||||
|
CCalNXDN calNXDN;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
CM17RX m17RX;
|
||||||
|
CM17TX m17TX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_POCSAG)
|
||||||
|
CPOCSAGTX pocsagTX;
|
||||||
|
CCalPOCSAG calPOCSAG;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
CFM fm;
|
||||||
|
CCalFM calFM;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
CAX25RX ax25RX;
|
||||||
|
CAX25TX ax25TX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CCalRSSI calRSSI;
|
||||||
|
|
||||||
CCWIdTX cwIdTX;
|
CCWIdTX cwIdTX;
|
||||||
|
|
||||||
@@ -88,48 +118,84 @@ void loop()
|
|||||||
io.process();
|
io.process();
|
||||||
|
|
||||||
// The following is for transmitting
|
// The following is for transmitting
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
if (m_dstarEnable && m_modemState == STATE_DSTAR)
|
if (m_dstarEnable && m_modemState == STATE_DSTAR)
|
||||||
dstarTX.process();
|
dstarTX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
if (m_dmrEnable && m_modemState == STATE_DMR) {
|
if (m_dmrEnable && m_modemState == STATE_DMR) {
|
||||||
if (m_duplex)
|
if (m_duplex)
|
||||||
dmrTX.process();
|
dmrTX.process();
|
||||||
else
|
else
|
||||||
dmrDMOTX.process();
|
dmrDMOTX.process();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_YSF)
|
||||||
if (m_ysfEnable && m_modemState == STATE_YSF)
|
if (m_ysfEnable && m_modemState == STATE_YSF)
|
||||||
ysfTX.process();
|
ysfTX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
if (m_p25Enable && m_modemState == STATE_P25)
|
if (m_p25Enable && m_modemState == STATE_P25)
|
||||||
p25TX.process();
|
p25TX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
if (m_nxdnEnable && m_modemState == STATE_NXDN)
|
if (m_nxdnEnable && m_modemState == STATE_NXDN)
|
||||||
nxdnTX.process();
|
nxdnTX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
if (m_m17Enable && m_modemState == STATE_M17)
|
||||||
|
m17TX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_POCSAG)
|
||||||
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
||||||
pocsagTX.process();
|
pocsagTX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM))
|
||||||
|
ax25TX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
if (m_fmEnable && m_modemState == STATE_FM)
|
if (m_fmEnable && m_modemState == STATE_FM)
|
||||||
fm.process();
|
fm.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
if (m_modemState == STATE_DSTARCAL)
|
if (m_modemState == STATE_DSTARCAL)
|
||||||
calDStarTX.process();
|
calDStarTX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
||||||
calDMR.process();
|
calDMR.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
|
||||||
|
calFM.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
if (m_modemState == STATE_P25CAL1K)
|
if (m_modemState == STATE_P25CAL1K)
|
||||||
calP25.process();
|
calP25.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
if (m_modemState == STATE_NXDNCAL1K)
|
if (m_modemState == STATE_NXDNCAL1K)
|
||||||
calNXDN.process();
|
calNXDN.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_POCSAG)
|
||||||
if (m_modemState == STATE_POCSAGCAL)
|
if (m_modemState == STATE_POCSAGCAL)
|
||||||
calPOCSAG.process();
|
calPOCSAG.process();
|
||||||
|
#endif
|
||||||
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K ||m_modemState == STATE_FMCAL30K)
|
|
||||||
calFM.process();
|
|
||||||
|
|
||||||
if (m_modemState == STATE_IDLE)
|
if (m_modemState == STATE_IDLE)
|
||||||
cwIdTX.process();
|
cwIdTX.process();
|
||||||
|
|||||||
@@ -28,45 +28,75 @@ bool m_dmrEnable = true;
|
|||||||
bool m_ysfEnable = true;
|
bool m_ysfEnable = true;
|
||||||
bool m_p25Enable = true;
|
bool m_p25Enable = true;
|
||||||
bool m_nxdnEnable = true;
|
bool m_nxdnEnable = true;
|
||||||
|
bool m_m17Enable = true;
|
||||||
bool m_pocsagEnable = true;
|
bool m_pocsagEnable = true;
|
||||||
bool m_fmEnable = true;
|
bool m_fmEnable = true;
|
||||||
|
bool m_ax25Enable = true;
|
||||||
|
|
||||||
bool m_duplex = true;
|
bool m_duplex = true;
|
||||||
|
|
||||||
bool m_tx = false;
|
bool m_tx = false;
|
||||||
bool m_dcd = false;
|
bool m_dcd = false;
|
||||||
|
|
||||||
CDStarRX dstarRX;
|
#if defined(MODE_DSTAR)
|
||||||
CDStarTX dstarTX;
|
CDStarRX dstarRX;
|
||||||
|
CDStarTX dstarTX;
|
||||||
CDMRIdleRX dmrIdleRX;
|
|
||||||
CDMRRX dmrRX;
|
|
||||||
CDMRTX dmrTX;
|
|
||||||
|
|
||||||
CDMRDMORX dmrDMORX;
|
|
||||||
CDMRDMOTX dmrDMOTX;
|
|
||||||
|
|
||||||
CYSFRX ysfRX;
|
|
||||||
CYSFTX ysfTX;
|
|
||||||
|
|
||||||
CP25RX p25RX;
|
|
||||||
CP25TX p25TX;
|
|
||||||
|
|
||||||
CNXDNRX nxdnRX;
|
|
||||||
CNXDNTX nxdnTX;
|
|
||||||
|
|
||||||
CPOCSAGTX pocsagTX;
|
|
||||||
|
|
||||||
CFM fm;
|
|
||||||
|
|
||||||
CCalDStarRX calDStarRX;
|
CCalDStarRX calDStarRX;
|
||||||
CCalDStarTX calDStarTX;
|
CCalDStarTX calDStarTX;
|
||||||
CCalDMR calDMR;
|
#endif
|
||||||
CCalFM calFM;
|
|
||||||
CCalP25 calP25;
|
#if defined(MODE_DMR)
|
||||||
CCalNXDN calNXDN;
|
CDMRIdleRX dmrIdleRX;
|
||||||
CCalPOCSAG calPOCSAG;
|
CDMRRX dmrRX;
|
||||||
CCalRSSI calRSSI;
|
CDMRTX dmrTX;
|
||||||
|
|
||||||
|
CDMRDMORX dmrDMORX;
|
||||||
|
CDMRDMOTX dmrDMOTX;
|
||||||
|
|
||||||
|
CCalDMR calDMR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_YSF)
|
||||||
|
CYSFRX ysfRX;
|
||||||
|
CYSFTX ysfTX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
CP25RX p25RX;
|
||||||
|
CP25TX p25TX;
|
||||||
|
|
||||||
|
CCalP25 calP25;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
CNXDNRX nxdnRX;
|
||||||
|
CNXDNTX nxdnTX;
|
||||||
|
|
||||||
|
CCalNXDN calNXDN;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
CM17RX m17RX;
|
||||||
|
CM17TX m17TX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_POCSAG)
|
||||||
|
CPOCSAGTX pocsagTX;
|
||||||
|
CCalPOCSAG calPOCSAG;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
|
CFM fm;
|
||||||
|
CCalFM calFM;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
CAX25RX ax25RX;
|
||||||
|
CAX25TX ax25TX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CCalRSSI calRSSI;
|
||||||
|
|
||||||
CCWIdTX cwIdTX;
|
CCWIdTX cwIdTX;
|
||||||
|
|
||||||
@@ -85,49 +115,86 @@ void loop()
|
|||||||
io.process();
|
io.process();
|
||||||
|
|
||||||
// The following is for transmitting
|
// The following is for transmitting
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
if (m_dstarEnable && m_modemState == STATE_DSTAR)
|
if (m_dstarEnable && m_modemState == STATE_DSTAR)
|
||||||
dstarTX.process();
|
dstarTX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
if (m_dmrEnable && m_modemState == STATE_DMR) {
|
if (m_dmrEnable && m_modemState == STATE_DMR) {
|
||||||
if (m_duplex)
|
if (m_duplex)
|
||||||
dmrTX.process();
|
dmrTX.process();
|
||||||
else
|
else
|
||||||
dmrDMOTX.process();
|
dmrDMOTX.process();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_YSF)
|
||||||
if (m_ysfEnable && m_modemState == STATE_YSF)
|
if (m_ysfEnable && m_modemState == STATE_YSF)
|
||||||
ysfTX.process();
|
ysfTX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
if (m_p25Enable && m_modemState == STATE_P25)
|
if (m_p25Enable && m_modemState == STATE_P25)
|
||||||
p25TX.process();
|
p25TX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
if (m_nxdnEnable && m_modemState == STATE_NXDN)
|
if (m_nxdnEnable && m_modemState == STATE_NXDN)
|
||||||
nxdnTX.process();
|
nxdnTX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_M17)
|
||||||
|
if (m_m17Enable && m_modemState == STATE_M17)
|
||||||
|
m17TX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_POCSAG)
|
||||||
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
||||||
pocsagTX.process();
|
pocsagTX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_AX25)
|
||||||
|
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM))
|
||||||
|
ax25TX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
if (m_fmEnable && m_modemState == STATE_FM)
|
if (m_fmEnable && m_modemState == STATE_FM)
|
||||||
fm.process();
|
fm.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DSTAR)
|
||||||
if (m_modemState == STATE_DSTARCAL)
|
if (m_modemState == STATE_DSTARCAL)
|
||||||
calDStarTX.process();
|
calDStarTX.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_DMR)
|
||||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
||||||
calDMR.process();
|
calDMR.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_FM)
|
||||||
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
|
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
|
||||||
calFM.process();
|
calFM.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
if (m_modemState == STATE_P25CAL1K)
|
if (m_modemState == STATE_P25CAL1K)
|
||||||
calP25.process();
|
calP25.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
if (m_modemState == STATE_NXDNCAL1K)
|
if (m_modemState == STATE_NXDNCAL1K)
|
||||||
calNXDN.process();
|
calNXDN.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODE_POCSAG)
|
||||||
if (m_modemState == STATE_POCSAGCAL)
|
if (m_modemState == STATE_POCSAGCAL)
|
||||||
calPOCSAG.process();
|
calPOCSAG.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (m_modemState == STATE_IDLE)
|
if (m_modemState == STATE_IDLE)
|
||||||
cwIdTX.process();
|
cwIdTX.process();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,12 +133,18 @@ DEFS_PI_F722=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_PI -DHSE_VAL
|
|||||||
DEFS_F7M=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_F7M -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
DEFS_F7M=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_F7M -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
# MMDVM_RPT_Hat F0DEI, DB9MAT, DF2ET board:
|
# MMDVM_RPT_Hat F0DEI, DB9MAT, DF2ET board:
|
||||||
DEFS_RPT_HAT=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_RPT_HAT -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
DEFS_RPT_HAT=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_RPT_HAT -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
# STM32F4 DVM board:
|
# RB STM32F4_DVM board:
|
||||||
DEFS_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
DEFS_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
|
# RB STM32F7 DVM board:
|
||||||
|
DEFS_DVM722=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F7_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
# MMDVM_RPT_Hat BG4TGO, BG5HHP board:
|
# MMDVM_RPT_Hat BG4TGO, BG5HHP board:
|
||||||
DEFS_RPT_HAT_TGO=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_RPT_HAT_TGO -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
DEFS_RPT_HAT_TGO=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_RPT_HAT_TGO -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
# DRCC_DVM BG7NQF board:
|
# DRCC_DVM BG7NQF board:
|
||||||
DEFS_DRCC_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DDRCC_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
DEFS_DRCC_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DDRCC_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
|
# WA0EDA F405 MTR2K, MASTR3 board:
|
||||||
|
DEFS_EDA_405=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_EDA_405 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
|
# WA0EDA F446 MTR2K, MASTR3 board:
|
||||||
|
DEFS_EDA_446=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_EDA_446 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
|
|
||||||
|
|
||||||
# Build compiler flags
|
# Build compiler flags
|
||||||
@@ -155,7 +161,7 @@ LDFLAGS_F722 =-T stm32f722_link.ld $(MCFLAGS_F7) --specs=nosys.specs $(INCLUDES_
|
|||||||
# Common flags
|
# Common flags
|
||||||
CFLAGS=-Os -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS
|
CFLAGS=-Os -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS
|
||||||
CXXFLAGS=-Os -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -DCUSTOM_NEW -DNO_EXCEPTIONS
|
CXXFLAGS=-Os -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -DCUSTOM_NEW -DNO_EXCEPTIONS
|
||||||
LDFLAGS=-Os --specs=nano.specs
|
LDFLAGS=-Os --specs=nano.specs -Wl,-Map=bin/mmdvm.map
|
||||||
|
|
||||||
# Build Rules
|
# Build Rules
|
||||||
.PHONY: all release dis pi pi-f722 f4m nucleo f767 dvm drcc_nqf clean
|
.PHONY: all release dis pi pi-f722 f4m nucleo f767 dvm drcc_nqf clean
|
||||||
@@ -218,17 +224,41 @@ f767: LDFLAGS+=$(LDFLAGS_F767)
|
|||||||
f767: release_f7
|
f767: release_f7
|
||||||
|
|
||||||
dvm: GitVersion.h
|
dvm: GitVersion.h
|
||||||
dvm: CFLAGS+=$(CFLAGS_F4) $(DEFS_DVM)
|
dvm: CFLAGS+=$(CFLAGS_F4) $(DEFS_DVM) -DDRCC_DVM_446
|
||||||
dvm: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DVM)
|
dvm: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DVM) -DDRCC_DVM_446
|
||||||
dvm: LDFLAGS+=$(LDFLAGS_F4)
|
dvm: LDFLAGS+=$(LDFLAGS_F4)
|
||||||
dvm: release_f4
|
dvm: release_f4
|
||||||
|
|
||||||
|
dvm722: GitVersion.h
|
||||||
|
dvm722: CFLAGS+=$(CFLAGS_F7) $(DEFS_DVM722) -DDRCC_DVM_722
|
||||||
|
dvm722: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_DVM722) -DDRCC_DVM_722
|
||||||
|
dvm722: LDFLAGS+=$(LDFLAGS_F722)
|
||||||
|
dvm722: release_f7
|
||||||
|
|
||||||
drcc_nqf: GitVersion.h
|
drcc_nqf: GitVersion.h
|
||||||
drcc_nqf: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
|
drcc_nqf: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
|
||||||
drcc_nqf: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
|
drcc_nqf: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
|
||||||
drcc_nqf: LDFLAGS+=$(LDFLAGS_F4)
|
drcc_nqf: LDFLAGS+=$(LDFLAGS_F4)
|
||||||
drcc_nqf: release_f4
|
drcc_nqf: release_f4
|
||||||
|
|
||||||
|
hhp446: GitVersion.h
|
||||||
|
hhp446: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_HHP446
|
||||||
|
hhp446: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_HHP446
|
||||||
|
hhp446: LDFLAGS+=$(LDFLAGS_F4)
|
||||||
|
hhp446: release_f4
|
||||||
|
|
||||||
|
eda405: GitVersion.h
|
||||||
|
eda405: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_405)
|
||||||
|
eda405: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_405)
|
||||||
|
eda405: LDFLAGS+=$(LDFLAGS_F4)
|
||||||
|
eda405: release_f4
|
||||||
|
|
||||||
|
eda446: GitVersion.h
|
||||||
|
eda446: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_446)
|
||||||
|
eda446: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_446)
|
||||||
|
eda446: LDFLAGS+=$(LDFLAGS_F4)
|
||||||
|
eda446: release_f4
|
||||||
|
|
||||||
release_f4: $(BINDIR)
|
release_f4: $(BINDIR)
|
||||||
release_f4: $(OBJDIR_F4)
|
release_f4: $(OBJDIR_F4)
|
||||||
release_f4: $(BINDIR)/$(BINHEX_F4)
|
release_f4: $(BINDIR)/$(BINHEX_F4)
|
||||||
@@ -338,27 +368,27 @@ endif
|
|||||||
deploy-pi:
|
deploy-pi:
|
||||||
ifneq ($(wildcard /usr/local/bin/stm32flash),)
|
ifneq ($(wildcard /usr/local/bin/stm32flash),)
|
||||||
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
||||||
-/usr/local/bin/stm32ld /dev/ttyAMA0 57600 bin/$(BINBIN_F4)
|
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R /dev/ttyAMA0
|
||||||
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R -c /dev/ttyAMA0
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(wildcard /usr/bin/stm32flash),)
|
ifneq ($(wildcard /usr/bin/stm32flash),)
|
||||||
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
||||||
-/usr/bin/stm32ld /dev/ttyAMA0 57600 bin/$(BINBIN_F4)
|
/usr/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R /dev/ttyAMA0
|
||||||
/usr/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R -c /dev/ttyAMA0
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
deploy-f4m: deploy-pi
|
deploy-f4m: deploy-pi
|
||||||
deploy-dvm: deploy-pi
|
deploy-dvm: deploy-pi
|
||||||
|
deploy-eda405: deploy-pi
|
||||||
|
deploy-eda446: deploy-pi
|
||||||
|
|
||||||
deploy-pi-f7:
|
deploy-pi-f7:
|
||||||
ifneq ($(wildcard /usr/local/bin/stm32flash),)
|
ifneq ($(wildcard /usr/local/bin/stm32flash),)
|
||||||
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
||||||
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R -c /dev/ttyAMA0
|
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R /dev/ttyAMA0
|
||||||
|
|
||||||
else ifneq ($(wildcard /usr/bin/stm32flash),)
|
else ifneq ($(wildcard /usr/bin/stm32flash),)
|
||||||
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
||||||
/usr/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R -c /dev/ttyAMA0
|
/usr/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R /dev/ttyAMA0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
deploy-f7m: deploy-pi-f7
|
deploy-f7m: deploy-pi-f7
|
||||||
|
|||||||
+6
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2018,2020 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
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "NXDNRX.h"
|
#include "NXDNRX.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
@@ -403,3 +406,5 @@ void CNXDNRX::writeRSSIData(uint8_t* data)
|
|||||||
m_rssiCount = 0U;
|
m_rssiCount = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020 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
|
||||||
@@ -16,10 +16,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
|
||||||
#if !defined(NXDNRX_H)
|
#if !defined(NXDNRX_H)
|
||||||
#define NXDNRX_H
|
#define NXDNRX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "NXDNDefines.h"
|
#include "NXDNDefines.h"
|
||||||
|
|
||||||
enum NXDNRX_STATE {
|
enum NXDNRX_STATE {
|
||||||
@@ -67,3 +70,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -18,6 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "NXDNTX.h"
|
#include "NXDNTX.h"
|
||||||
|
|
||||||
@@ -123,7 +126,7 @@ void CNXDNTX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CNXDNTX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CNXDNTX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != (NXDN_FRAME_LENGTH_BYTES + 1U))
|
if (length != (NXDN_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -200,3 +203,6 @@ void CNXDNTX::setParams(uint8_t txHang)
|
|||||||
{
|
{
|
||||||
m_txHang = txHang * 600U;
|
m_txHang = txHang * 600U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -16,18 +16,20 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_NXDN)
|
||||||
|
|
||||||
#if !defined(NXDNTX_H)
|
#if !defined(NXDNTX_H)
|
||||||
#define NXDNTX_H
|
#define NXDNTX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
class CNXDNTX {
|
class CNXDNTX {
|
||||||
public:
|
public:
|
||||||
CNXDNTX();
|
CNXDNTX();
|
||||||
|
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
@@ -55,3 +57,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com>
|
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.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
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "P25RX.h"
|
#include "P25RX.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
@@ -535,3 +538,6 @@ void CP25RX::writeRSSILdu(uint8_t* ldu)
|
|||||||
m_rssiAccum = 0U;
|
m_rssiAccum = 0U;
|
||||||
m_rssiCount = 0U;
|
m_rssiCount = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com>
|
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.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
|
||||||
@@ -17,10 +17,13 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
|
||||||
#if !defined(P25RX_H)
|
#if !defined(P25RX_H)
|
||||||
#define P25RX_H
|
#define P25RX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "P25Defines.h"
|
#include "P25Defines.h"
|
||||||
|
|
||||||
enum P25RX_STATE {
|
enum P25RX_STATE {
|
||||||
@@ -72,3 +75,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "P25TX.h"
|
#include "P25TX.h"
|
||||||
|
|
||||||
@@ -120,7 +123,7 @@ void CP25TX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CP25TX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CP25TX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length < (P25_TERM_FRAME_LENGTH_BYTES + 1U))
|
if (length < (P25_TERM_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -198,3 +201,6 @@ void CP25TX::setParams(uint8_t txHang)
|
|||||||
{
|
{
|
||||||
m_txHang = txHang * 1200U;
|
m_txHang = txHang * 1200U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -16,18 +16,20 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_P25)
|
||||||
|
|
||||||
#if !defined(P25TX_H)
|
#if !defined(P25TX_H)
|
||||||
#define P25TX_H
|
#define P25TX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
class CP25TX {
|
class CP25TX {
|
||||||
public:
|
public:
|
||||||
CP25TX();
|
CP25TX();
|
||||||
|
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
@@ -55,3 +57,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -17,6 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_POCSAG)
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "POCSAGTX.h"
|
#include "POCSAGTX.h"
|
||||||
|
|
||||||
@@ -96,7 +99,7 @@ bool CPOCSAGTX::busy()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CPOCSAGTX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CPOCSAGTX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != POCSAG_FRAME_LENGTH_BYTES)
|
if (length != POCSAG_FRAME_LENGTH_BYTES)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -147,3 +150,6 @@ uint8_t CPOCSAGTX::getSpace() const
|
|||||||
{
|
{
|
||||||
return m_buffer.getSpace() / POCSAG_FRAME_LENGTH_BYTES;
|
return m_buffer.getSpace() / POCSAG_FRAME_LENGTH_BYTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
+8
-4
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015-2019 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015-2020 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
|
||||||
@@ -16,18 +16,20 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#if defined(MODE_POCSAG)
|
||||||
|
|
||||||
#if !defined(POCSAGTX_H)
|
#if !defined(POCSAGTX_H)
|
||||||
#define POCSAGTX_H
|
#define POCSAGTX_H
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
class CPOCSAGTX {
|
class CPOCSAGTX {
|
||||||
public:
|
public:
|
||||||
CPOCSAGTX();
|
CPOCSAGTX();
|
||||||
|
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void writeByte(uint8_t c);
|
void writeByte(uint8_t c);
|
||||||
|
|
||||||
@@ -51,3 +53,5 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
This is the source code of the MMDVM firmware that supports D-Star, DMR, System Fusion, P25, NXDN, and POCSAG modes.
|
This is the source code of the MMDVM firmware that supports D-Star, DMR,
|
||||||
|
System Fusion, P25, NXDN, POCSAG, and FM modes.
|
||||||
|
|
||||||
It runs on the Arduino Due, the ST-Micro STM32F1xxx, STM32F4xxx and STM32F7xxx processors, as well as the Teensy 3.1/3.2/3.5/3.6. What these platforms have in common is the use of an ARM Cortex-M3 or M4 processor with a clock speed greater than 70 MHz, and access to at least one analogue to digital converter and one digital to analogue converter.
|
It runs on the Arduino Due, the ST-Micro STM32F1xxx, STM32F4xxx and STM32F7xxx
|
||||||
|
processors, as well as the Teensy 3.1/3.2/3.5/3.6. What these platforms have in
|
||||||
|
common is the use of an ARM Cortex-M3, M4, or M7 processors with a clock speed
|
||||||
|
greater than 70 MHz, and access to at least one analogue to digital converter
|
||||||
|
and one digital to analogue converter.
|
||||||
|
|
||||||
In order to build this software for the Arduino Due, you will need to edit a file within the Arduino GUI and that is detailed in the BUILD.txt file. The STM32 support is being supplied via the Coocox IDE with ARM GCC. The Teensy support uses Teensyduino.
|
In order to build this software for the Arduino Due, you will need to edit a
|
||||||
|
file within the Arduino GUI and that is detailed in the BUILD.txt file. The
|
||||||
|
STM32 support is being supplied via the ARM GCC compiler. The Teensy support
|
||||||
|
uses Teensyduino.
|
||||||
|
|
||||||
This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden.
|
This software is licenced under the GPL v2 and is intended for amateur and
|
||||||
|
educational use only. Use of this software for commercial purposes is strictly
|
||||||
|
forbidden.
|
||||||
|
|||||||
+1
-1
@@ -32,7 +32,7 @@
|
|||||||
#define RINGBUFF_WRITE(ringBuff, dataIn) (ringBuff).data[RINGBUFF_MASK(ringBuff) & ringBuff.wrIdx++] = (dataIn)
|
#define RINGBUFF_WRITE(ringBuff, dataIn) (ringBuff).data[RINGBUFF_MASK(ringBuff) & ringBuff.wrIdx++] = (dataIn)
|
||||||
#define RINGBUFF_READ(ringBuff) ((ringBuff).data[RINGBUFF_MASK(ringBuff) & ((ringBuff).rdIdx++)])
|
#define RINGBUFF_READ(ringBuff) ((ringBuff).data[RINGBUFF_MASK(ringBuff) & ((ringBuff).rdIdx++)])
|
||||||
#define RINGBUFF_EMPTY(ringBuff) ((ringBuff).rdIdx == (ringBuff).wrIdx)
|
#define RINGBUFF_EMPTY(ringBuff) ((ringBuff).rdIdx == (ringBuff).wrIdx)
|
||||||
#define RINGBUFF_FULL(ringBuff) ((RINGBUFF_MASK(ringBuff) & ringFifo.rdIdx) == (RINGBUFF_MASK(ringBuff) & ringFifo.wrIdx))
|
#define RINGBUFF_FULL(ringBuff) ((RINGBUFF_MASK(ringBuff) & ringBuff.rdIdx) == (RINGBUFF_MASK(ringBuff) & ringBuff.wrIdx))
|
||||||
#define RINGBUFF_COUNT(ringBuff) (RINGBUFF_MASK(ringBuff) & ((ringBuff).wrIdx - (ringBuff).rdIdx))
|
#define RINGBUFF_COUNT(ringBuff) (RINGBUFF_MASK(ringBuff) & ((ringBuff).wrIdx - (ringBuff).rdIdx))
|
||||||
|
|
||||||
/* Buffer type */
|
/* Buffer type */
|
||||||
|
|||||||
+1
-1
Submodule STM32F4XX_Lib updated: bcd346f530...18aeb6ea3a
+1
-1
Submodule STM32F7XX_Lib updated: 2d5f4236fa...6241f7c05e
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user