mirror of
https://github.com/g4klx/MMDVM.git
synced 2026-10-15 16:24:11 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d67b9f104 | ||
|
|
fb85505433 | ||
|
|
823b91c97d | ||
|
|
0fca178bd7 | ||
|
|
a60ecb3e57 | ||
|
|
a2978d9e91 | ||
|
|
e304f5cce2 | ||
|
|
99a7df7c13 | ||
|
|
6dfe1a9271 | ||
|
|
d5e9b5a315 | ||
|
|
1ac0628c1c | ||
|
|
dc41fd83d2 | ||
|
|
20013e3adc | ||
|
|
8f8dc92a14 | ||
|
|
ccdbe126e0 | ||
|
|
4ff057069b | ||
|
|
f8d8f85841 | ||
|
|
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,266 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
#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 = 96U;
|
||||||
|
|
||||||
|
q15_t LPF_FILTER_COEFFS[] = {
|
||||||
|
0, 0, 0, 1, 2, 5, 8, 12, 18, 23,
|
||||||
|
29, 33, 36, 36, 33, 25, 13, -5, -28, -57,
|
||||||
|
-89, -123, -159, -194, -225, -249, -264, -267, -254, -224,
|
||||||
|
-175, -104, -12, 102, 236, 389, 557, 738, 926, 1117,
|
||||||
|
1306, 1486, 1654, 1802, 1927, 2025, 2092, 2126, 2126, 2092,
|
||||||
|
2025, 1927, 1802, 1654, 1486, 1306, 1117, 926, 738, 557,
|
||||||
|
389, 236, 102, -12, -104, -175, -224, -254, -267, -264,
|
||||||
|
-249, -225, -194, -159, -123, -89, -57, -28, -5, 13,
|
||||||
|
25, 33, 36, 36, 33, 29, 23, 18, 12, 8,
|
||||||
|
5, 2, 1, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 offset = m_pllCount / float32_t(m_pllBits);
|
||||||
|
float32_t jitter;
|
||||||
|
::arm_fir_f32(&m_pllFilter, &offset, &jitter, 1U);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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(AX25Demodulator_H)
|
||||||
|
#define AX25Demodulator_H
|
||||||
|
|
||||||
|
#include "Config.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);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CAX25Frame m_frame;
|
||||||
|
CAX25Twist m_twist;
|
||||||
|
arm_fir_instance_q15 m_lpfFilter;
|
||||||
|
q15_t m_lpfState[120U]; // NoTaps + BlockSize - 1, 96 + 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;
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
#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];
|
||||||
|
}
|
||||||
|
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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(AX25Frame_H)
|
||||||
|
#define AX25Frame_H
|
||||||
|
|
||||||
|
#include "Config.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
|
||||||
|
|
||||||
+120
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
#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 = 132;
|
||||||
|
q15_t FILTER_COEFFS[] = {
|
||||||
|
0, 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, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
CAX25RX::CAX25RX() :
|
||||||
|
m_filter(),
|
||||||
|
m_state(),
|
||||||
|
m_demod1(3),
|
||||||
|
m_demod2(6),
|
||||||
|
m_demod3(9),
|
||||||
|
m_lastFCS(0U),
|
||||||
|
m_count(0U)
|
||||||
|
{
|
||||||
|
m_filter.numTaps = FILTER_LEN;
|
||||||
|
m_filter.pState = m_state;
|
||||||
|
m_filter.pCoeffs = FILTER_COEFFS;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25RX::setParams(int8_t twist)
|
||||||
|
{
|
||||||
|
m_demod1.setTwist(twist - 3);
|
||||||
|
m_demod2.setTwist(twist);
|
||||||
|
m_demod3.setTwist(twist + 3);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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(AX25RX_H)
|
||||||
|
#define AX25RX_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#include "AX25Demodulator.h"
|
||||||
|
|
||||||
|
class CAX25RX {
|
||||||
|
public:
|
||||||
|
CAX25RX();
|
||||||
|
|
||||||
|
void samples(q15_t* samples, uint8_t length);
|
||||||
|
|
||||||
|
void setParams(int8_t twist);
|
||||||
|
|
||||||
|
private:
|
||||||
|
arm_fir_instance_q15 m_filter;
|
||||||
|
q15_t m_state[160U]; // NoTaps + BlockSize - 1, 132 + 20 - 1 plus some spare
|
||||||
|
CAX25Demodulator m_demod1;
|
||||||
|
CAX25Demodulator m_demod2;
|
||||||
|
CAX25Demodulator m_demod3;
|
||||||
|
uint16_t m_lastFCS;
|
||||||
|
uint32_t m_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+180
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
#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_twist(-6),
|
||||||
|
m_poBuffer(),
|
||||||
|
m_poLen(0U),
|
||||||
|
m_poPtr(0U),
|
||||||
|
m_txDelay(120U),
|
||||||
|
m_tablePtr(0U),
|
||||||
|
m_nrzi(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25TX::process()
|
||||||
|
{
|
||||||
|
if (m_poLen == 0U)
|
||||||
|
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 (already NRZI)
|
||||||
|
for (uint16_t i = 0U; i < m_txDelay; i++, m_poLen++)
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, false);
|
||||||
|
|
||||||
|
// 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 in[AX25_RADIO_SYMBOL_LENGTH];
|
||||||
|
for (uint8_t i = 0U; i < AX25_RADIO_SYMBOL_LENGTH; i++) {
|
||||||
|
in[i] = AUDIO_TABLE_DATA[m_tablePtr];
|
||||||
|
if (b)
|
||||||
|
m_tablePtr += 6U;
|
||||||
|
else
|
||||||
|
m_tablePtr += 11U;
|
||||||
|
|
||||||
|
if (m_tablePtr >= AUDIO_TABLE_LEN)
|
||||||
|
m_tablePtr -= AUDIO_TABLE_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
q15_t out[AX25_RADIO_SYMBOL_LENGTH];
|
||||||
|
m_twist.process(in, out, AX25_RADIO_SYMBOL_LENGTH);
|
||||||
|
|
||||||
|
io.write(STATE_AX25, out, AX25_RADIO_SYMBOL_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25TX::setParams(int8_t twist)
|
||||||
|
{
|
||||||
|
m_twist.setTwist(twist);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
bool result = (b == m_nrzi);
|
||||||
|
|
||||||
|
m_nrzi = b;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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(AX25TX_H)
|
||||||
|
#define AX25TX_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#include "AX25Twist.h"
|
||||||
|
|
||||||
|
class CAX25TX {
|
||||||
|
public:
|
||||||
|
CAX25TX();
|
||||||
|
|
||||||
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
|
void process();
|
||||||
|
|
||||||
|
void setParams(int8_t twist);
|
||||||
|
|
||||||
|
void setTXDelay(uint8_t delay);
|
||||||
|
|
||||||
|
uint8_t getSpace() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CAX25Twist m_twist;
|
||||||
|
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
|
||||||
|
|
||||||
+311
@@ -0,0 +1,311 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
#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];
|
||||||
|
}
|
||||||
|
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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(AX25Twist_H)
|
||||||
|
#define AX25Twist_H
|
||||||
|
|
||||||
|
#include "Config.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
|
||||||
|
|
||||||
+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();
|
||||||
|
|
||||||
|
|||||||
+2
-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
|
||||||
@@ -208,7 +208,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;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -41,7 +41,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;
|
||||||
|
|||||||
+2
-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
|
||||||
@@ -162,7 +162,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;
|
||||||
|
|||||||
+2
-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
|
||||||
@@ -26,7 +26,7 @@ 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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
*
|
*
|
||||||
@@ -116,7 +116,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;
|
||||||
|
|||||||
@@ -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
|
||||||
*
|
*
|
||||||
@@ -35,7 +35,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;
|
||||||
|
|||||||
+2
-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
|
||||||
@@ -79,7 +80,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;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -32,7 +33,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;
|
||||||
|
|||||||
+2
-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
|
||||||
@@ -82,7 +83,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;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -34,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;
|
||||||
|
|||||||
+2
-1
@@ -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
|
||||||
@@ -38,7 +39,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;
|
||||||
|
|||||||
+2
-1
@@ -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
|
||||||
@@ -32,7 +33,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:
|
||||||
POCSAGCAL m_state;
|
POCSAGCAL m_state;
|
||||||
|
|||||||
@@ -35,11 +35,8 @@
|
|||||||
// For 19.2 MHz
|
// For 19.2 MHz
|
||||||
// #define EXTERNAL_OSC 19200000
|
// #define EXTERNAL_OSC 19200000
|
||||||
|
|
||||||
// Allow the use of the COS line to lockout the modem
|
|
||||||
// #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
|
||||||
|
|||||||
+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
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
*
|
*
|
||||||
@@ -104,7 +104,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;
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
@@ -29,7 +29,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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
*
|
*
|
||||||
@@ -144,7 +144,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 +168,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 +192,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 +208,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;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -38,11 +38,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);
|
||||||
|
|||||||
+3
-3
@@ -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
|
||||||
@@ -277,7 +277,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;
|
||||||
@@ -296,7 +296,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;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -27,8 +27,8 @@ 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();
|
||||||
|
|||||||
@@ -20,6 +20,14 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "FM.h"
|
#include "FM.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access Mode values are:
|
||||||
|
* 0 - Carrier access with COS
|
||||||
|
* 1 - CTCSS only access without COS
|
||||||
|
* 2 - CTCSS only access with COS
|
||||||
|
* 3 - CTCSS only access with COS to start, then carrier access with COS
|
||||||
|
*/
|
||||||
|
|
||||||
CFM::CFM() :
|
CFM::CFM() :
|
||||||
m_callsign(),
|
m_callsign(),
|
||||||
m_rfAck(),
|
m_rfAck(),
|
||||||
@@ -37,11 +45,12 @@ m_kerchunkTimer(),
|
|||||||
m_ackMinTimer(),
|
m_ackMinTimer(),
|
||||||
m_ackDelayTimer(),
|
m_ackDelayTimer(),
|
||||||
m_hangTimer(),
|
m_hangTimer(),
|
||||||
|
m_reverseTimer(),
|
||||||
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_cosInvert(false),
|
m_cosInvert(false),
|
||||||
m_rfAudioBoost(1U),
|
m_rfAudioBoost(1U),
|
||||||
m_downsampler(128U),//Size might need adjustement
|
m_downsampler(128U),//Size might need adjustement
|
||||||
@@ -49,17 +58,15 @@ m_rxLevel(1),
|
|||||||
m_inputRB(4800U), // 200ms of audio
|
m_inputRB(4800U), // 200ms of audio
|
||||||
m_outputRB(2400U) // 100ms of audio
|
m_outputRB(2400U) // 100ms of audio
|
||||||
{
|
{
|
||||||
|
m_reverseTimer.setTimeout(0U, 150U);
|
||||||
|
|
||||||
insertDelay(100U);
|
insertDelay(100U);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::samples(bool cos, const q15_t* samples, uint8_t length)
|
void CFM::samples(bool cos, const q15_t* samples, uint8_t length)
|
||||||
{
|
{
|
||||||
if (m_useCOS) {
|
if (m_cosInvert)
|
||||||
if (m_cosInvert)
|
cos = !cos;
|
||||||
cos = !cos;
|
|
||||||
} else {
|
|
||||||
cos = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
clock(length);
|
clock(length);
|
||||||
|
|
||||||
@@ -68,36 +75,56 @@ void CFM::samples(bool cos, const q15_t* samples, uint8_t length)
|
|||||||
// ARMv7-M has hardware integer division
|
// ARMv7-M has hardware integer division
|
||||||
q15_t currentSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel);
|
q15_t currentSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel);
|
||||||
|
|
||||||
uint8_t ctcssState = m_ctcssRX.process(currentSample);
|
switch (m_accessMode) {
|
||||||
|
case 0U:
|
||||||
|
stateMachine(cos);
|
||||||
|
break;
|
||||||
|
|
||||||
if (!m_useCOS) {
|
case 1U: {
|
||||||
// Delay the audio by 100ms to better match the CTCSS detector output
|
uint8_t ctcssState = m_ctcssRX.process(currentSample);
|
||||||
m_inputRB.put(currentSample);
|
|
||||||
m_inputRB.get(currentSample);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CTCSS_NOT_READY(ctcssState) && m_modemState != STATE_FM) {
|
// Delay the audio by 100ms to better match the CTCSS detector output
|
||||||
//Not enough samples to determine if you have CTCSS, just carry on
|
m_inputRB.put(currentSample);
|
||||||
continue;
|
m_inputRB.get(currentSample);
|
||||||
} else if (CTCSS_READY(ctcssState) && m_modemState != STATE_FM) {
|
|
||||||
//we had enough samples for CTCSS and we are in some other mode than FM
|
if (CTCSS_NOT_READY(ctcssState) && m_modemState != STATE_FM) {
|
||||||
bool validCTCSS = CTCSS_VALID(ctcssState);
|
// Not enough samples to determine if you have CTCSS, just carry on
|
||||||
stateMachine(validCTCSS && cos);
|
} else {
|
||||||
if (m_modemState != STATE_FM)
|
bool validCTCSS = CTCSS_VALID(ctcssState);
|
||||||
continue;
|
stateMachine(validCTCSS);
|
||||||
} else if (CTCSS_READY(ctcssState) && m_modemState == STATE_FM) {
|
}
|
||||||
//We had enough samples for CTCSS and we are in FM mode, trigger the state machine
|
}
|
||||||
bool validCTCSS = CTCSS_VALID(ctcssState);
|
break;
|
||||||
stateMachine(validCTCSS && cos);
|
|
||||||
if (m_modemState != STATE_FM)
|
case 2U: {
|
||||||
|
uint8_t ctcssState = m_ctcssRX.process(currentSample);
|
||||||
|
if (CTCSS_NOT_READY(ctcssState) && m_modemState != STATE_FM) {
|
||||||
|
// Not enough samples to determine if you have CTCSS, just carry on
|
||||||
|
} else {
|
||||||
|
bool validCTCSS = CTCSS_VALID(ctcssState);
|
||||||
|
stateMachine(validCTCSS && cos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
uint8_t ctcssState = m_ctcssRX.process(currentSample);
|
||||||
|
if (CTCSS_NOT_READY(ctcssState) && m_modemState != STATE_FM) {
|
||||||
|
// Not enough samples to determine if you have CTCSS, just carry on
|
||||||
|
} else if (CTCSS_READY(ctcssState) && m_modemState != STATE_FM) {
|
||||||
|
// We had enough samples for CTCSS and we are in some other mode than FM
|
||||||
|
bool validCTCSS = CTCSS_VALID(ctcssState);
|
||||||
|
stateMachine(validCTCSS && cos);
|
||||||
|
} else {
|
||||||
|
stateMachine(cos);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
} else if (CTCSS_NOT_READY(ctcssState) && m_modemState == STATE_FM && i == length - 1) {
|
|
||||||
//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!
|
|
||||||
bool validCTCSS = CTCSS_VALID(ctcssState);
|
|
||||||
stateMachine(validCTCSS && cos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_modemState != STATE_FM)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Only let audio through when relaying audio
|
// Only let audio through when relaying audio
|
||||||
if (m_state == FS_RELAYING || m_state == FS_KERCHUNK) {
|
if (m_state == FS_RELAYING || m_state == FS_KERCHUNK) {
|
||||||
// m_downsampler.addSample(currentSample);
|
// m_downsampler.addSample(currentSample);
|
||||||
@@ -117,15 +144,14 @@ void CFM::samples(bool cos, const 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())
|
if (!m_callsign.isRunning() && !m_rfAck.isRunning())
|
||||||
currentSample += m_timeoutTone.getAudio();
|
currentSample += m_timeoutTone.getAudio();
|
||||||
|
|
||||||
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
|
currentSample += m_ctcssTX.getAudio(m_reverseTimer.isRunning());
|
||||||
|
|
||||||
currentSample += m_ctcssTX.getAudio();
|
m_outputRB.put(currentSample);
|
||||||
|
|
||||||
if (m_modemState == STATE_FM)
|
|
||||||
m_outputRB.put(currentSample);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +172,7 @@ void CFM::reset()
|
|||||||
m_ackMinTimer.stop();
|
m_ackMinTimer.stop();
|
||||||
m_ackDelayTimer.stop();
|
m_ackDelayTimer.stop();
|
||||||
m_hangTimer.stop();
|
m_hangTimer.stop();
|
||||||
|
m_reverseTimer.stop();
|
||||||
|
|
||||||
m_ctcssRX.reset();
|
m_ctcssRX.reset();
|
||||||
m_rfAck.stop();
|
m_rfAck.stop();
|
||||||
@@ -183,10 +210,10 @@ 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, 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 cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel)
|
||||||
{
|
{
|
||||||
m_useCOS = useCOS;
|
m_accessMode = accessMode;
|
||||||
m_cosInvert = cosInvert;
|
m_cosInvert = cosInvert;
|
||||||
|
|
||||||
m_rfAudioBoost = q15_t(rfAudioBoost);
|
m_rfAudioBoost = q15_t(rfAudioBoost);
|
||||||
|
|
||||||
@@ -235,14 +262,20 @@ void CFM::stateMachine(bool validSignal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_state == FS_LISTENING && m_modemState == STATE_FM) {
|
if (m_state == FS_LISTENING && m_modemState == STATE_FM) {
|
||||||
DEBUG1("Change to STATE_IDLE");
|
if (!m_callsign.isWanted() && !m_rfAck.isWanted() && !m_reverseTimer.isRunning())
|
||||||
m_modemState = STATE_IDLE;
|
m_reverseTimer.start();
|
||||||
m_callsignTimer.stop();
|
|
||||||
m_timeoutTimer.stop();
|
if (!m_callsign.isWanted() && !m_rfAck.isWanted() && m_reverseTimer.isRunning() && m_reverseTimer.hasExpired()) {
|
||||||
m_kerchunkTimer.stop();
|
DEBUG1("Change to STATE_IDLE");
|
||||||
m_ackMinTimer.stop();
|
m_modemState = STATE_IDLE;
|
||||||
m_ackDelayTimer.stop();
|
m_callsignTimer.stop();
|
||||||
m_hangTimer.stop();
|
m_timeoutTimer.stop();
|
||||||
|
m_kerchunkTimer.stop();
|
||||||
|
m_ackMinTimer.stop();
|
||||||
|
m_ackDelayTimer.stop();
|
||||||
|
m_hangTimer.stop();
|
||||||
|
m_reverseTimer.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,6 +288,7 @@ void CFM::clock(uint8_t length)
|
|||||||
m_ackMinTimer.clock(length);
|
m_ackMinTimer.clock(length);
|
||||||
m_ackDelayTimer.clock(length);
|
m_ackDelayTimer.clock(length);
|
||||||
m_hangTimer.clock(length);
|
m_hangTimer.clock(length);
|
||||||
|
m_reverseTimer.clock(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CFM::listeningState(bool validSignal)
|
void CFM::listeningState(bool validSignal)
|
||||||
@@ -278,6 +312,10 @@ void CFM::listeningState(bool validSignal)
|
|||||||
beginRelaying();
|
beginRelaying();
|
||||||
|
|
||||||
m_callsignTimer.start();
|
m_callsignTimer.start();
|
||||||
|
m_reverseTimer.stop();
|
||||||
|
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
DEBUG1("Change to STATE_FM");
|
DEBUG1("Change to STATE_FM");
|
||||||
m_modemState = STATE_FM;
|
m_modemState = STATE_FM;
|
||||||
@@ -297,6 +335,9 @@ void CFM::kerchunkState(bool validSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
DEBUG1("State to LISTENING");
|
DEBUG1("State to LISTENING");
|
||||||
m_state = FS_LISTENING;
|
m_state = FS_LISTENING;
|
||||||
m_kerchunkTimer.stop();
|
m_kerchunkTimer.stop();
|
||||||
@@ -317,6 +358,9 @@ void CFM::relayingState(bool validSignal)
|
|||||||
m_timeoutTone.start();
|
m_timeoutTone.start();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
DEBUG1("State to RELAYING_WAIT");
|
DEBUG1("State to RELAYING_WAIT");
|
||||||
m_state = FS_RELAYING_WAIT;
|
m_state = FS_RELAYING_WAIT;
|
||||||
m_ackDelayTimer.start();
|
m_ackDelayTimer.start();
|
||||||
@@ -331,6 +375,9 @@ void CFM::relayingState(bool validSignal)
|
|||||||
void CFM::relayingWaitState(bool validSignal)
|
void CFM::relayingWaitState(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
DEBUG1("State to RELAYING");
|
DEBUG1("State to RELAYING");
|
||||||
m_state = FS_RELAYING;
|
m_state = FS_RELAYING;
|
||||||
m_ackDelayTimer.stop();
|
m_ackDelayTimer.stop();
|
||||||
@@ -366,6 +413,9 @@ void CFM::relayingWaitState(bool validSignal)
|
|||||||
void CFM::hangState(bool validSignal)
|
void CFM::hangState(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
DEBUG1("State to RELAYING");
|
DEBUG1("State to RELAYING");
|
||||||
m_state = FS_RELAYING;
|
m_state = FS_RELAYING;
|
||||||
DEBUG1("Stop ack");
|
DEBUG1("Stop ack");
|
||||||
@@ -393,6 +443,9 @@ void CFM::hangState(bool validSignal)
|
|||||||
void CFM::timeoutState(bool validSignal)
|
void CFM::timeoutState(bool validSignal)
|
||||||
{
|
{
|
||||||
if (!validSignal) {
|
if (!validSignal) {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
|
||||||
DEBUG1("State to TIMEOUT_WAIT");
|
DEBUG1("State to TIMEOUT_WAIT");
|
||||||
m_state = FS_TIMEOUT_WAIT;
|
m_state = FS_TIMEOUT_WAIT;
|
||||||
m_ackDelayTimer.start();
|
m_ackDelayTimer.start();
|
||||||
@@ -407,6 +460,9 @@ void CFM::timeoutState(bool validSignal)
|
|||||||
void CFM::timeoutWaitState(bool validSignal)
|
void CFM::timeoutWaitState(bool validSignal)
|
||||||
{
|
{
|
||||||
if (validSignal) {
|
if (validSignal) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
|
||||||
DEBUG1("State to TIMEOUT");
|
DEBUG1("State to TIMEOUT");
|
||||||
m_state = FS_TIMEOUT;
|
m_state = FS_TIMEOUT;
|
||||||
m_ackDelayTimer.stop();
|
m_ackDelayTimer.stop();
|
||||||
|
|||||||
@@ -56,7 +56,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, 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 cosInvert, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CFMKeyer m_callsign;
|
CFMKeyer m_callsign;
|
||||||
@@ -75,11 +75,12 @@ private:
|
|||||||
CFMTimer m_ackMinTimer;
|
CFMTimer m_ackMinTimer;
|
||||||
CFMTimer m_ackDelayTimer;
|
CFMTimer m_ackDelayTimer;
|
||||||
CFMTimer m_hangTimer;
|
CFMTimer m_hangTimer;
|
||||||
|
CFMTimer m_reverseTimer;
|
||||||
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_cosInvert;
|
bool m_cosInvert;
|
||||||
q15_t m_rfAudioBoost;
|
q15_t m_rfAudioBoost;
|
||||||
CFMDownsampler m_downsampler;
|
CFMDownsampler m_downsampler;
|
||||||
|
|||||||
+6
-3
@@ -115,11 +115,14 @@ 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;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ public:
|
|||||||
|
|
||||||
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;
|
||||||
|
|||||||
@@ -205,6 +205,11 @@ void CFMKeyer::stop()
|
|||||||
m_audioPos = 0U;
|
m_audioPos = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CFMKeyer::isWanted() const
|
||||||
|
{
|
||||||
|
return m_wanted;
|
||||||
|
}
|
||||||
|
|
||||||
bool CFMKeyer::isRunning() const
|
bool CFMKeyer::isRunning() const
|
||||||
{
|
{
|
||||||
return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U;
|
return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U;
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ public:
|
|||||||
|
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
|
|
||||||
|
bool isWanted() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_wanted;
|
bool m_wanted;
|
||||||
uint8_t m_poBuffer[1000U];
|
uint8_t m_poBuffer[1000U];
|
||||||
|
|||||||
+5
-7
@@ -36,24 +36,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++;
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ enum MMDVM_STATE {
|
|||||||
STATE_NXDN = 5,
|
STATE_NXDN = 5,
|
||||||
STATE_POCSAG = 6,
|
STATE_POCSAG = 6,
|
||||||
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,
|
||||||
@@ -96,6 +97,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,6 +127,7 @@ extern bool m_p25Enable;
|
|||||||
extern bool m_nxdnEnable;
|
extern bool m_nxdnEnable;
|
||||||
extern bool m_pocsagEnable;
|
extern bool m_pocsagEnable;
|
||||||
extern bool m_fmEnable;
|
extern bool m_fmEnable;
|
||||||
|
extern bool m_ax25Enable;
|
||||||
|
|
||||||
extern bool m_duplex;
|
extern bool m_duplex;
|
||||||
|
|
||||||
@@ -154,7 +158,9 @@ extern CNXDNTX nxdnTX;
|
|||||||
|
|
||||||
extern CPOCSAGTX pocsagTX;
|
extern CPOCSAGTX pocsagTX;
|
||||||
|
|
||||||
extern CFM fm;
|
extern CFM fm;
|
||||||
|
extern CAX25RX ax25RX;
|
||||||
|
extern CAX25TX ax25TX;
|
||||||
|
|
||||||
extern CCalDStarRX calDStarRX;
|
extern CCalDStarRX calDStarRX;
|
||||||
extern CCalDStarTX calDStarTX;
|
extern CCalDStarTX calDStarTX;
|
||||||
@@ -168,3 +174,4 @@ extern CCalRSSI calRSSI;
|
|||||||
extern CCWIdTX cwIdTX;
|
extern CCWIdTX cwIdTX;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -81,8 +81,10 @@ m_p25TXLevel(128 * 128),
|
|||||||
m_nxdnTXLevel(128 * 128),
|
m_nxdnTXLevel(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),
|
||||||
@@ -256,9 +258,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) {
|
||||||
@@ -362,6 +363,14 @@ void CIO::process()
|
|||||||
fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
|
fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
|
||||||
#else
|
#else
|
||||||
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ax25Enable) {
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
|
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
|
||||||
|
#else
|
||||||
|
ax25RX.samples(samples, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else if (m_modemState == STATE_DSTAR) {
|
} else if (m_modemState == STATE_DSTAR) {
|
||||||
@@ -426,8 +435,12 @@ void CIO::process()
|
|||||||
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 (m_ax25Enable)
|
||||||
|
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
|
||||||
#else
|
#else
|
||||||
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
||||||
|
if (m_ax25Enable)
|
||||||
|
ax25RX.samples(samples, RX_BLOCK_SIZE);
|
||||||
#endif
|
#endif
|
||||||
} else if (m_modemState == STATE_DSTARCAL) {
|
} else if (m_modemState == STATE_DSTARCAL) {
|
||||||
q15_t GMSKVals[RX_BLOCK_SIZE];
|
q15_t GMSKVals[RX_BLOCK_SIZE];
|
||||||
@@ -477,6 +490,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
|
|||||||
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;
|
||||||
@@ -529,7 +545,7 @@ void CIO::setMode()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
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 pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout)
|
||||||
{
|
{
|
||||||
m_pttInvert = pttInvert;
|
m_pttInvert = pttInvert;
|
||||||
|
|
||||||
@@ -542,10 +558,13 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
|
|||||||
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
|
m_nxdnTXLevel = q15_t(nxdnTXLevel * 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;
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public:
|
|||||||
|
|
||||||
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 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);
|
||||||
|
|
||||||
@@ -87,10 +87,13 @@ private:
|
|||||||
q15_t m_nxdnTXLevel;
|
q15_t m_nxdnTXLevel;
|
||||||
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;
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,9 @@
|
|||||||
#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(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."
|
||||||
|
|
||||||
|
|||||||
+12
-44
@@ -41,7 +41,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 +84,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 +154,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 +172,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;
|
||||||
@@ -255,9 +228,6 @@ static inline void GPIOInit()
|
|||||||
#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)
|
||||||
@@ -495,8 +465,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ bool m_p25Enable = true;
|
|||||||
bool m_nxdnEnable = true;
|
bool m_nxdnEnable = 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;
|
||||||
|
|
||||||
@@ -61,6 +62,8 @@ CNXDNTX nxdnTX;
|
|||||||
CPOCSAGTX pocsagTX;
|
CPOCSAGTX pocsagTX;
|
||||||
|
|
||||||
CFM fm;
|
CFM fm;
|
||||||
|
CAX25RX ax25RX;
|
||||||
|
CAX25TX ax25TX;
|
||||||
|
|
||||||
CCalDStarRX calDStarRX;
|
CCalDStarRX calDStarRX;
|
||||||
CCalDStarTX calDStarTX;
|
CCalDStarTX calDStarTX;
|
||||||
@@ -110,6 +113,9 @@ void loop()
|
|||||||
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
||||||
pocsagTX.process();
|
pocsagTX.process();
|
||||||
|
|
||||||
|
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM))
|
||||||
|
ax25TX.process();
|
||||||
|
|
||||||
if (m_fmEnable && m_modemState == STATE_FM)
|
if (m_fmEnable && m_modemState == STATE_FM)
|
||||||
fm.process();
|
fm.process();
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ bool m_p25Enable = true;
|
|||||||
bool m_nxdnEnable = true;
|
bool m_nxdnEnable = 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;
|
||||||
|
|
||||||
@@ -58,6 +59,8 @@ CNXDNTX nxdnTX;
|
|||||||
CPOCSAGTX pocsagTX;
|
CPOCSAGTX pocsagTX;
|
||||||
|
|
||||||
CFM fm;
|
CFM fm;
|
||||||
|
CAX25RX ax25RX;
|
||||||
|
CAX25 ax25TX;
|
||||||
|
|
||||||
CCalDStarRX calDStarRX;
|
CCalDStarRX calDStarRX;
|
||||||
CCalDStarTX calDStarTX;
|
CCalDStarTX calDStarTX;
|
||||||
@@ -107,6 +110,9 @@ void loop()
|
|||||||
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
||||||
pocsagTX.process();
|
pocsagTX.process();
|
||||||
|
|
||||||
|
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM))
|
||||||
|
ax25TX.process();
|
||||||
|
|
||||||
if (m_fmEnable && m_modemState == STATE_FM)
|
if (m_fmEnable && m_modemState == STATE_FM)
|
||||||
fm.process();
|
fm.process();
|
||||||
|
|
||||||
|
|||||||
@@ -139,6 +139,10 @@ DEFS_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVM -DHSE_VA
|
|||||||
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 +159,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
|
||||||
@@ -229,6 +233,18 @@ 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
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -350,6 +366,8 @@ 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),)
|
||||||
|
|||||||
+4
-7
@@ -54,7 +54,7 @@ m_poBuffer(),
|
|||||||
m_poLen(0U),
|
m_poLen(0U),
|
||||||
m_poPtr(0U),
|
m_poPtr(0U),
|
||||||
m_txDelay(240U), // 200ms
|
m_txDelay(240U), // 200ms
|
||||||
m_txHang(6000U), // 5s
|
m_txHang(3000U), // 5s
|
||||||
m_txCount(0U)
|
m_txCount(0U)
|
||||||
{
|
{
|
||||||
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
||||||
@@ -72,10 +72,7 @@ m_txCount(0U)
|
|||||||
|
|
||||||
void CNXDNTX::process()
|
void CNXDNTX::process()
|
||||||
{
|
{
|
||||||
if (m_buffer.getData() == 0U && m_poLen == 0U && m_txCount == 0U)
|
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_poLen == 0U) {
|
|
||||||
if (!m_tx) {
|
if (!m_tx) {
|
||||||
for (uint16_t i = 0U; i < m_txDelay; i++)
|
for (uint16_t i = 0U; i < m_txDelay; i++)
|
||||||
m_poBuffer[m_poLen++] = NXDN_SYNC;
|
m_poBuffer[m_poLen++] = NXDN_SYNC;
|
||||||
@@ -125,7 +122,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,5 +197,5 @@ uint8_t CNXDNTX::getSpace() const
|
|||||||
|
|
||||||
void CNXDNTX::setParams(uint8_t txHang)
|
void CNXDNTX::setParams(uint8_t txHang)
|
||||||
{
|
{
|
||||||
m_txHang = txHang * 1200U;
|
m_txHang = txHang * 600U;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ 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();
|
||||||
|
|
||||||
|
|||||||
@@ -70,10 +70,7 @@ m_txCount(0U)
|
|||||||
|
|
||||||
void CP25TX::process()
|
void CP25TX::process()
|
||||||
{
|
{
|
||||||
if (m_buffer.getData() == 0U && m_poLen == 0U && m_txCount == 0U)
|
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_poLen == 0U) {
|
|
||||||
if (!m_tx) {
|
if (!m_tx) {
|
||||||
for (uint16_t i = 0U; i < m_txDelay; i++)
|
for (uint16_t i = 0U; i < m_txDelay; i++)
|
||||||
m_poBuffer[m_poLen++] = P25_START_SYNC;
|
m_poBuffer[m_poLen++] = P25_START_SYNC;
|
||||||
@@ -121,7 +118,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;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ 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();
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
@@ -95,7 +95,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;
|
||||||
|
|||||||
+2
-2
@@ -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
|
||||||
@@ -27,7 +27,7 @@ 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);
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
+404
-318
@@ -65,6 +65,8 @@ const uint8_t MMDVM_NXDN_LOST = 0x41U;
|
|||||||
|
|
||||||
const uint8_t MMDVM_POCSAG_DATA = 0x50U;
|
const uint8_t MMDVM_POCSAG_DATA = 0x50U;
|
||||||
|
|
||||||
|
const uint8_t MMDVM_AX25_DATA = 0x55U;
|
||||||
|
|
||||||
const uint8_t MMDVM_FM_PARAMS1 = 0x60U;
|
const uint8_t MMDVM_FM_PARAMS1 = 0x60U;
|
||||||
const uint8_t MMDVM_FM_PARAMS2 = 0x61U;
|
const uint8_t MMDVM_FM_PARAMS2 = 0x61U;
|
||||||
const uint8_t MMDVM_FM_PARAMS3 = 0x62U;
|
const uint8_t MMDVM_FM_PARAMS3 = 0x62U;
|
||||||
@@ -103,7 +105,7 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U;
|
|||||||
#define HW_TYPE "MMDVM"
|
#define HW_TYPE "MMDVM"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DESCRIPTION "20200512 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM)"
|
#define DESCRIPTION "20200714 (D-Star/DMR/System Fusion/P25/NXDN/POCSAG/FM/AX.25)"
|
||||||
|
|
||||||
#if defined(GITVERSION)
|
#if defined(GITVERSION)
|
||||||
#define concat(h, a, b, c) h " " a " " b " GitID #" c ""
|
#define concat(h, a, b, c) h " " a " " b " GitID #" c ""
|
||||||
@@ -176,6 +178,8 @@ void CSerialPort::getStatus()
|
|||||||
reply[3U] |= 0x20U;
|
reply[3U] |= 0x20U;
|
||||||
if (m_fmEnable)
|
if (m_fmEnable)
|
||||||
reply[3U] |= 0x40U;
|
reply[3U] |= 0x40U;
|
||||||
|
if (m_ax25Enable)
|
||||||
|
reply[3U] |= 0x80U;
|
||||||
|
|
||||||
reply[4U] = uint8_t(m_modemState);
|
reply[4U] = uint8_t(m_modemState);
|
||||||
|
|
||||||
@@ -240,7 +244,12 @@ void CSerialPort::getStatus()
|
|||||||
else
|
else
|
||||||
reply[12U] = 0U;
|
reply[12U] = 0U;
|
||||||
|
|
||||||
writeInt(1U, reply, 13);
|
if (m_ax25Enable)
|
||||||
|
reply[13U] = ax25TX.getSpace();
|
||||||
|
else
|
||||||
|
reply[13U] = 0U;
|
||||||
|
|
||||||
|
writeInt(1U, reply, 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSerialPort::getVersion()
|
void CSerialPort::getVersion()
|
||||||
@@ -262,16 +271,17 @@ void CSerialPort::getVersion()
|
|||||||
writeInt(1U, reply, count);
|
writeInt(1U, reply, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
uint8_t CSerialPort::setConfig(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length < 21U)
|
if (length < 24U)
|
||||||
return 4U;
|
return 4U;
|
||||||
|
|
||||||
bool rxInvert = (data[0U] & 0x01U) == 0x01U;
|
bool rxInvert = (data[0U] & 0x01U) == 0x01U;
|
||||||
bool txInvert = (data[0U] & 0x02U) == 0x02U;
|
bool txInvert = (data[0U] & 0x02U) == 0x02U;
|
||||||
bool pttInvert = (data[0U] & 0x04U) == 0x04U;
|
bool pttInvert = (data[0U] & 0x04U) == 0x04U;
|
||||||
bool ysfLoDev = (data[0U] & 0x08U) == 0x08U;
|
bool ysfLoDev = (data[0U] & 0x08U) == 0x08U;
|
||||||
bool simplex = (data[0U] & 0x80U) == 0x80U;
|
bool useCOSAsLockout = (data[0U] & 0x20U) == 0x20U;
|
||||||
|
bool simplex = (data[0U] & 0x80U) == 0x80U;
|
||||||
|
|
||||||
m_debug = (data[0U] & 0x10U) == 0x10U;
|
m_debug = (data[0U] & 0x10U) == 0x10U;
|
||||||
|
|
||||||
@@ -282,6 +292,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
|||||||
bool nxdnEnable = (data[1U] & 0x10U) == 0x10U;
|
bool nxdnEnable = (data[1U] & 0x10U) == 0x10U;
|
||||||
bool pocsagEnable = (data[1U] & 0x20U) == 0x20U;
|
bool pocsagEnable = (data[1U] & 0x20U) == 0x20U;
|
||||||
bool fmEnable = (data[1U] & 0x40U) == 0x40U;
|
bool fmEnable = (data[1U] & 0x40U) == 0x40U;
|
||||||
|
bool ax25Enable = (data[1U] & 0x80U) == 0x80U;
|
||||||
|
|
||||||
uint8_t txDelay = data[2U];
|
uint8_t txDelay = data[2U];
|
||||||
if (txDelay > 50U)
|
if (txDelay > 50U)
|
||||||
@@ -335,6 +346,16 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
|||||||
|
|
||||||
uint8_t nxdnTXHang = data[20U];
|
uint8_t nxdnTXHang = data[20U];
|
||||||
|
|
||||||
|
uint8_t ax25TXLevel = data[21U];
|
||||||
|
|
||||||
|
int8_t ax25RXTwist = int8_t(data[22U]) - 128;
|
||||||
|
if (ax25RXTwist < -4 || ax25RXTwist > 10)
|
||||||
|
return 4U;
|
||||||
|
|
||||||
|
int8_t ax25TXTwist = int8_t(data[23U]) - 128;
|
||||||
|
if (ax25TXTwist < -4 || ax25TXTwist > 10)
|
||||||
|
return 4U;
|
||||||
|
|
||||||
setMode(modemState);
|
setMode(modemState);
|
||||||
|
|
||||||
m_dstarEnable = dstarEnable;
|
m_dstarEnable = dstarEnable;
|
||||||
@@ -344,6 +365,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
|||||||
m_nxdnEnable = nxdnEnable;
|
m_nxdnEnable = nxdnEnable;
|
||||||
m_pocsagEnable = pocsagEnable;
|
m_pocsagEnable = pocsagEnable;
|
||||||
m_fmEnable = fmEnable;
|
m_fmEnable = fmEnable;
|
||||||
|
m_ax25Enable = ax25Enable;
|
||||||
m_duplex = !simplex;
|
m_duplex = !simplex;
|
||||||
|
|
||||||
dstarTX.setTXDelay(txDelay);
|
dstarTX.setTXDelay(txDelay);
|
||||||
@@ -352,6 +374,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
|||||||
dmrDMOTX.setTXDelay(txDelay);
|
dmrDMOTX.setTXDelay(txDelay);
|
||||||
nxdnTX.setTXDelay(txDelay);
|
nxdnTX.setTXDelay(txDelay);
|
||||||
pocsagTX.setTXDelay(txDelay);
|
pocsagTX.setTXDelay(txDelay);
|
||||||
|
ax25TX.setTXDelay(txDelay);
|
||||||
|
|
||||||
dmrTX.setColorCode(colorCode);
|
dmrTX.setColorCode(colorCode);
|
||||||
dmrRX.setColorCode(colorCode);
|
dmrRX.setColorCode(colorCode);
|
||||||
@@ -362,15 +385,17 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
|
|||||||
ysfTX.setParams(ysfLoDev, ysfTXHang);
|
ysfTX.setParams(ysfLoDev, ysfTXHang);
|
||||||
p25TX.setParams(p25TXHang);
|
p25TX.setParams(p25TXHang);
|
||||||
nxdnTX.setParams(nxdnTXHang);
|
nxdnTX.setParams(nxdnTXHang);
|
||||||
|
ax25RX.setParams(ax25RXTwist);
|
||||||
|
ax25TX.setParams(ax25TXTwist);
|
||||||
|
|
||||||
io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, txDCOffset, rxDCOffset);
|
io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, pocsagTXLevel, fmTXLevel, ax25TXLevel, txDCOffset, rxDCOffset, useCOSAsLockout);
|
||||||
|
|
||||||
io.start();
|
io.start();
|
||||||
|
|
||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CSerialPort::setFMParams1(const uint8_t* data, uint8_t length)
|
uint8_t CSerialPort::setFMParams1(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length < 8U)
|
if (length < 8U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -395,7 +420,7 @@ uint8_t CSerialPort::setFMParams1(const uint8_t* data, uint8_t length)
|
|||||||
return fm.setCallsign(callsign, speed, frequency, time, holdoff, highLevel, lowLevel, callAtStart, callAtEnd, callAtLatch);
|
return fm.setCallsign(callsign, speed, frequency, time, holdoff, highLevel, lowLevel, callAtStart, callAtEnd, callAtLatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CSerialPort::setFMParams2(const uint8_t* data, uint8_t length)
|
uint8_t CSerialPort::setFMParams2(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length < 6U)
|
if (length < 6U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -415,7 +440,7 @@ uint8_t CSerialPort::setFMParams2(const uint8_t* data, uint8_t length)
|
|||||||
return fm.setAck(ack, speed, frequency, minTime, delay, level);
|
return fm.setAck(ack, speed, frequency, minTime, delay, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length)
|
uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length < 12U)
|
if (length < 12U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -431,17 +456,17 @@ uint8_t CSerialPort::setFMParams3(const uint8_t* data, uint8_t length)
|
|||||||
uint8_t kerchunkTime = data[6U];
|
uint8_t kerchunkTime = data[6U];
|
||||||
uint8_t hangTime = data[7U];
|
uint8_t hangTime = data[7U];
|
||||||
|
|
||||||
bool useCOS = (data[8U] & 0x01U) == 0x01U;
|
uint8_t accessMode = data[8U] & 0x7FU;
|
||||||
bool cosInvert = (data[8U] & 0x02U) == 0x02U;
|
bool cosInvert = (data[8U] & 0x80U) == 0x80U;
|
||||||
|
|
||||||
uint8_t rfAudioBoost = data[9U];
|
uint8_t rfAudioBoost = data[9U];
|
||||||
uint8_t maxDev = data[10U];
|
uint8_t maxDev = data[10U];
|
||||||
uint8_t rxLevel = data[11U];
|
uint8_t rxLevel = data[11U];
|
||||||
|
|
||||||
return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, useCOS, cosInvert, rfAudioBoost, maxDev, rxLevel);
|
return fm.setMisc(timeout, timeoutLevel, ctcssFrequency, ctcssHighThreshold, ctcssLowThreshold, ctcssLevel, kerchunkTime, hangTime, accessMode, cosInvert, rfAudioBoost, maxDev, rxLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
|
uint8_t CSerialPort::setMode(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length < 1U)
|
if (length < 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -592,15 +617,25 @@ void CSerialPort::process()
|
|||||||
m_buffer[0U] = c;
|
m_buffer[0U] = c;
|
||||||
m_ptr = 1U;
|
m_ptr = 1U;
|
||||||
m_len = 0U;
|
m_len = 0U;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
m_ptr = 0U;
|
m_ptr = 0U;
|
||||||
m_len = 0U;
|
m_len = 0U;
|
||||||
}
|
}
|
||||||
} else if (m_ptr == 1U) {
|
} else if (m_ptr == 1U) {
|
||||||
// Handle the frame length
|
// Handle the frame length, 1/2
|
||||||
m_len = m_buffer[m_ptr] = c;
|
m_len = m_buffer[m_ptr] = c;
|
||||||
m_ptr = 2U;
|
m_ptr = 2U;
|
||||||
|
} else if (m_ptr == 2U) {
|
||||||
|
// Handle the frame length, 2/2
|
||||||
|
m_buffer[m_ptr] = c;
|
||||||
|
m_ptr = 3U;
|
||||||
|
|
||||||
|
if (m_len == 0U)
|
||||||
|
m_len = c + 255U;
|
||||||
|
|
||||||
|
// The full packet has been received, process it
|
||||||
|
if (m_ptr == m_len)
|
||||||
|
processMessage(m_buffer + 3U, m_len - 3U);
|
||||||
} else {
|
} else {
|
||||||
// Any other bytes are added to the buffer
|
// Any other bytes are added to the buffer
|
||||||
m_buffer[m_ptr] = c;
|
m_buffer[m_ptr] = c;
|
||||||
@@ -608,304 +643,10 @@ void CSerialPort::process()
|
|||||||
|
|
||||||
// The full packet has been received, process it
|
// The full packet has been received, process it
|
||||||
if (m_ptr == m_len) {
|
if (m_ptr == m_len) {
|
||||||
uint8_t err = 2U;
|
if (m_len > 255U)
|
||||||
|
processMessage(m_buffer + 4U, m_len - 4U);
|
||||||
switch (m_buffer[2U]) {
|
else
|
||||||
case MMDVM_GET_STATUS:
|
processMessage(m_buffer + 3U, m_len - 3U);
|
||||||
getStatus();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_GET_VERSION:
|
|
||||||
getVersion();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_SET_CONFIG:
|
|
||||||
err = setConfig(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (err == 0U)
|
|
||||||
sendACK();
|
|
||||||
else
|
|
||||||
sendNAK(err);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_SET_MODE:
|
|
||||||
err = setMode(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (err == 0U)
|
|
||||||
sendACK();
|
|
||||||
else
|
|
||||||
sendNAK(err);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_SET_FREQ:
|
|
||||||
sendACK();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_FM_PARAMS1:
|
|
||||||
err = setFMParams1(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (err == 0U) {
|
|
||||||
sendACK();
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid FM params 1", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_FM_PARAMS2:
|
|
||||||
err = setFMParams2(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (err == 0U) {
|
|
||||||
sendACK();
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid FM params 2", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_FM_PARAMS3:
|
|
||||||
err = setFMParams3(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (err == 0U) {
|
|
||||||
sendACK();
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid FM params 3", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_CAL_DATA:
|
|
||||||
if (m_modemState == STATE_DSTARCAL)
|
|
||||||
err = calDStarTX.write(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
|
||||||
err = calDMR.write(m_buffer + 3U, m_len - 3U);
|
|
||||||
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)
|
|
||||||
err = calFM.write(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (m_modemState == STATE_P25CAL1K)
|
|
||||||
err = calP25.write(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (m_modemState == STATE_NXDNCAL1K)
|
|
||||||
err = calNXDN.write(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (m_modemState == STATE_POCSAGCAL)
|
|
||||||
err = calPOCSAG.write(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (err == 0U) {
|
|
||||||
sendACK();
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid calibration data", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_SEND_CWID:
|
|
||||||
err = 5U;
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
err = cwIdTX.write(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (err != 0U) {
|
|
||||||
DEBUG2("Invalid CW Id data", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_DSTAR_HEADER:
|
|
||||||
if (m_dstarEnable) {
|
|
||||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR)
|
|
||||||
err = dstarTX.writeHeader(m_buffer + 3U, m_len - 3U);
|
|
||||||
}
|
|
||||||
if (err == 0U) {
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
setMode(STATE_DSTAR);
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid D-Star header", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_DSTAR_DATA:
|
|
||||||
if (m_dstarEnable) {
|
|
||||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR)
|
|
||||||
err = dstarTX.writeData(m_buffer + 3U, m_len - 3U);
|
|
||||||
}
|
|
||||||
if (err == 0U) {
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
setMode(STATE_DSTAR);
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid D-Star data", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_DSTAR_EOT:
|
|
||||||
if (m_dstarEnable) {
|
|
||||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR)
|
|
||||||
err = dstarTX.writeEOT();
|
|
||||||
}
|
|
||||||
if (err == 0U) {
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
setMode(STATE_DSTAR);
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid D-Star EOT", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_DMR_DATA1:
|
|
||||||
if (m_dmrEnable) {
|
|
||||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) {
|
|
||||||
if (m_duplex)
|
|
||||||
err = dmrTX.writeData1(m_buffer + 3U, m_len - 3U);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (err == 0U) {
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
setMode(STATE_DMR);
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid DMR data", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_DMR_DATA2:
|
|
||||||
if (m_dmrEnable) {
|
|
||||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) {
|
|
||||||
if (m_duplex)
|
|
||||||
err = dmrTX.writeData2(m_buffer + 3U, m_len - 3U);
|
|
||||||
else
|
|
||||||
err = dmrDMOTX.writeData(m_buffer + 3U, m_len - 3U);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (err == 0U) {
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
setMode(STATE_DMR);
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid DMR data", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_DMR_START:
|
|
||||||
if (m_dmrEnable) {
|
|
||||||
err = 4U;
|
|
||||||
if (m_len == 4U) {
|
|
||||||
if (m_buffer[3U] == 0x01U && m_modemState == STATE_DMR) {
|
|
||||||
if (!m_tx)
|
|
||||||
dmrTX.setStart(true);
|
|
||||||
err = 0U;
|
|
||||||
} else if (m_buffer[3U] == 0x00U && m_modemState == STATE_DMR) {
|
|
||||||
if (m_tx)
|
|
||||||
dmrTX.setStart(false);
|
|
||||||
err = 0U;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (err != 0U) {
|
|
||||||
DEBUG2("Received invalid DMR start", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_DMR_SHORTLC:
|
|
||||||
if (m_dmrEnable)
|
|
||||||
err = dmrTX.writeShortLC(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (err != 0U) {
|
|
||||||
DEBUG2("Received invalid DMR Short LC", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_DMR_ABORT:
|
|
||||||
if (m_dmrEnable)
|
|
||||||
err = dmrTX.writeAbort(m_buffer + 3U, m_len - 3U);
|
|
||||||
if (err != 0U) {
|
|
||||||
DEBUG2("Received invalid DMR Abort", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_YSF_DATA:
|
|
||||||
if (m_ysfEnable) {
|
|
||||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_YSF)
|
|
||||||
err = ysfTX.writeData(m_buffer + 3U, m_len - 3U);
|
|
||||||
}
|
|
||||||
if (err == 0U) {
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
setMode(STATE_YSF);
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid System Fusion data", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_P25_HDR:
|
|
||||||
if (m_p25Enable) {
|
|
||||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_P25)
|
|
||||||
err = p25TX.writeData(m_buffer + 3U, m_len - 3U);
|
|
||||||
}
|
|
||||||
if (err == 0U) {
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
setMode(STATE_P25);
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid P25 header", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_P25_LDU:
|
|
||||||
if (m_p25Enable) {
|
|
||||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_P25)
|
|
||||||
err = p25TX.writeData(m_buffer + 3U, m_len - 3U);
|
|
||||||
}
|
|
||||||
if (err == 0U) {
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
setMode(STATE_P25);
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid P25 LDU", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_NXDN_DATA:
|
|
||||||
if (m_nxdnEnable) {
|
|
||||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_NXDN)
|
|
||||||
err = nxdnTX.writeData(m_buffer + 3U, m_len - 3U);
|
|
||||||
}
|
|
||||||
if (err == 0U) {
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
setMode(STATE_NXDN);
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid NXDN data", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_POCSAG_DATA:
|
|
||||||
if (m_pocsagEnable) {
|
|
||||||
if (m_modemState == STATE_IDLE || m_modemState == STATE_POCSAG)
|
|
||||||
err = pocsagTX.writeData(m_buffer + 3U, m_len - 3U);
|
|
||||||
}
|
|
||||||
if (err == 0U) {
|
|
||||||
if (m_modemState == STATE_IDLE)
|
|
||||||
setMode(STATE_POCSAG);
|
|
||||||
} else {
|
|
||||||
DEBUG2("Received invalid POCSAG data", err);
|
|
||||||
sendNAK(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMDVM_TRANSPARENT:
|
|
||||||
case MMDVM_QSO_INFO:
|
|
||||||
// Do nothing on the MMDVM.
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if defined(SERIAL_REPEATER)
|
|
||||||
case MMDVM_SERIAL: {
|
|
||||||
for (uint8_t i = 3U; i < m_len; i++)
|
|
||||||
m_repeat.put(m_buffer[i]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Handle this, send a NAK back
|
|
||||||
sendNAK(1U);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ptr = 0U;
|
|
||||||
m_len = 0U;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -935,6 +676,319 @@ void CSerialPort::process()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSerialPort::processMessage(const uint8_t* buffer, uint16_t length)
|
||||||
|
{
|
||||||
|
uint8_t err = 2U;
|
||||||
|
|
||||||
|
switch (m_buffer[2U]) {
|
||||||
|
case MMDVM_GET_STATUS:
|
||||||
|
getStatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_GET_VERSION:
|
||||||
|
getVersion();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_SET_CONFIG:
|
||||||
|
err = setConfig(buffer, length);
|
||||||
|
if (err == 0U)
|
||||||
|
sendACK();
|
||||||
|
else
|
||||||
|
sendNAK(err);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_SET_MODE:
|
||||||
|
err = setMode(buffer, length);
|
||||||
|
if (err == 0U)
|
||||||
|
sendACK();
|
||||||
|
else
|
||||||
|
sendNAK(err);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_SET_FREQ:
|
||||||
|
sendACK();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_FM_PARAMS1:
|
||||||
|
err = setFMParams1(buffer, length);
|
||||||
|
if (err == 0U) {
|
||||||
|
sendACK();
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid FM params 1", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_FM_PARAMS2:
|
||||||
|
err = setFMParams2(buffer, length);
|
||||||
|
if (err == 0U) {
|
||||||
|
sendACK();
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid FM params 2", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_FM_PARAMS3:
|
||||||
|
err = setFMParams3(buffer, length);
|
||||||
|
if (err == 0U) {
|
||||||
|
sendACK();
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid FM params 3", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_CAL_DATA:
|
||||||
|
if (m_modemState == STATE_DSTARCAL)
|
||||||
|
err = calDStarTX.write(buffer, length);
|
||||||
|
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
||||||
|
err = calDMR.write(buffer, length);
|
||||||
|
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)
|
||||||
|
err = calFM.write(buffer, length);
|
||||||
|
if (m_modemState == STATE_P25CAL1K)
|
||||||
|
err = calP25.write(buffer, length);
|
||||||
|
if (m_modemState == STATE_NXDNCAL1K)
|
||||||
|
err = calNXDN.write(buffer, length);
|
||||||
|
if (m_modemState == STATE_POCSAGCAL)
|
||||||
|
err = calPOCSAG.write(buffer, length);
|
||||||
|
if (err == 0U) {
|
||||||
|
sendACK();
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid calibration data", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_SEND_CWID:
|
||||||
|
err = 5U;
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
err = cwIdTX.write(buffer, length);
|
||||||
|
if (err != 0U) {
|
||||||
|
DEBUG2("Invalid CW Id data", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_DSTAR_HEADER:
|
||||||
|
if (m_dstarEnable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR)
|
||||||
|
err = dstarTX.writeHeader(buffer, length);
|
||||||
|
}
|
||||||
|
if (err == 0U) {
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
setMode(STATE_DSTAR);
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid D-Star header", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_DSTAR_DATA:
|
||||||
|
if (m_dstarEnable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR)
|
||||||
|
err = dstarTX.writeData(buffer, length);
|
||||||
|
}
|
||||||
|
if (err == 0U) {
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
setMode(STATE_DSTAR);
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid D-Star data", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_DSTAR_EOT:
|
||||||
|
if (m_dstarEnable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR)
|
||||||
|
err = dstarTX.writeEOT();
|
||||||
|
}
|
||||||
|
if (err == 0U) {
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
setMode(STATE_DSTAR);
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid D-Star EOT", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_DMR_DATA1:
|
||||||
|
if (m_dmrEnable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) {
|
||||||
|
if (m_duplex)
|
||||||
|
err = dmrTX.writeData1(buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (err == 0U) {
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
setMode(STATE_DMR);
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid DMR data", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_DMR_DATA2:
|
||||||
|
if (m_dmrEnable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) {
|
||||||
|
if (m_duplex)
|
||||||
|
err = dmrTX.writeData2(buffer, length);
|
||||||
|
else
|
||||||
|
err = dmrDMOTX.writeData(buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (err == 0U) {
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
setMode(STATE_DMR);
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid DMR data", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_DMR_START:
|
||||||
|
if (m_dmrEnable) {
|
||||||
|
err = 4U;
|
||||||
|
if (m_len == 4U) {
|
||||||
|
if (m_buffer[3U] == 0x01U && m_modemState == STATE_DMR) {
|
||||||
|
if (!m_tx)
|
||||||
|
dmrTX.setStart(true);
|
||||||
|
err = 0U;
|
||||||
|
} else if (m_buffer[3U] == 0x00U && m_modemState == STATE_DMR) {
|
||||||
|
if (m_tx)
|
||||||
|
dmrTX.setStart(false);
|
||||||
|
err = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (err != 0U) {
|
||||||
|
DEBUG2("Received invalid DMR start", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_DMR_SHORTLC:
|
||||||
|
if (m_dmrEnable)
|
||||||
|
err = dmrTX.writeShortLC(buffer, length);
|
||||||
|
if (err != 0U) {
|
||||||
|
DEBUG2("Received invalid DMR Short LC", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_DMR_ABORT:
|
||||||
|
if (m_dmrEnable)
|
||||||
|
err = dmrTX.writeAbort(buffer, length);
|
||||||
|
if (err != 0U) {
|
||||||
|
DEBUG2("Received invalid DMR Abort", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_YSF_DATA:
|
||||||
|
if (m_ysfEnable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_YSF)
|
||||||
|
err = ysfTX.writeData(buffer, length);
|
||||||
|
}
|
||||||
|
if (err == 0U) {
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
setMode(STATE_YSF);
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid System Fusion data", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_P25_HDR:
|
||||||
|
if (m_p25Enable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_P25)
|
||||||
|
err = p25TX.writeData(buffer, length);
|
||||||
|
}
|
||||||
|
if (err == 0U) {
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
setMode(STATE_P25);
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid P25 header", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_P25_LDU:
|
||||||
|
if (m_p25Enable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_P25)
|
||||||
|
err = p25TX.writeData(buffer, length);
|
||||||
|
}
|
||||||
|
if (err == 0U) {
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
setMode(STATE_P25);
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid P25 LDU", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_NXDN_DATA:
|
||||||
|
if (m_nxdnEnable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_NXDN)
|
||||||
|
err = nxdnTX.writeData(buffer, length);
|
||||||
|
}
|
||||||
|
if (err == 0U) {
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
setMode(STATE_NXDN);
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid NXDN data", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_POCSAG_DATA:
|
||||||
|
if (m_pocsagEnable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_POCSAG)
|
||||||
|
err = pocsagTX.writeData(buffer, length);
|
||||||
|
}
|
||||||
|
if (err == 0U) {
|
||||||
|
if (m_modemState == STATE_IDLE)
|
||||||
|
setMode(STATE_POCSAG);
|
||||||
|
} else {
|
||||||
|
DEBUG2("Received invalid POCSAG data", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_AX25_DATA:
|
||||||
|
if (m_ax25Enable) {
|
||||||
|
if (m_modemState == STATE_IDLE || m_modemState == STATE_FM)
|
||||||
|
err = ax25TX.writeData(buffer, length);
|
||||||
|
}
|
||||||
|
if (err != 0U) {
|
||||||
|
DEBUG2("Received invalid AX.25 data", err);
|
||||||
|
sendNAK(err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMDVM_TRANSPARENT:
|
||||||
|
case MMDVM_QSO_INFO:
|
||||||
|
// Do nothing on the MMDVM.
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if defined(SERIAL_REPEATER)
|
||||||
|
case MMDVM_SERIAL: {
|
||||||
|
for (uint8_t i = 3U; i < m_len; i++)
|
||||||
|
m_repeat.put(m_buffer[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Handle this, send a NAK back
|
||||||
|
sendNAK(1U);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ptr = 0U;
|
||||||
|
m_len = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
void CSerialPort::writeDStarHeader(const uint8_t* header, uint8_t length)
|
void CSerialPort::writeDStarHeader(const uint8_t* header, uint8_t length)
|
||||||
{
|
{
|
||||||
if (m_modemState != STATE_DSTAR && m_modemState != STATE_IDLE)
|
if (m_modemState != STATE_DSTAR && m_modemState != STATE_IDLE)
|
||||||
@@ -1197,6 +1251,38 @@ void CSerialPort::writeNXDNLost()
|
|||||||
writeInt(1U, reply, 3);
|
writeInt(1U, reply, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSerialPort::writeAX25Data(const uint8_t* data, uint16_t length)
|
||||||
|
{
|
||||||
|
if (m_modemState != STATE_FM && m_modemState != STATE_IDLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_ax25Enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t reply[512U];
|
||||||
|
|
||||||
|
reply[0U] = MMDVM_FRAME_START;
|
||||||
|
|
||||||
|
if (length > 252U) {
|
||||||
|
reply[1U] = 0U;
|
||||||
|
reply[2U] = (length + 4U) - 255U;
|
||||||
|
reply[3U] = MMDVM_AX25_DATA;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < length; i++)
|
||||||
|
reply[i + 4U] = data[i];
|
||||||
|
|
||||||
|
writeInt(1U, reply, length + 4U);
|
||||||
|
} else {
|
||||||
|
reply[1U] = length + 3U;
|
||||||
|
reply[2U] = MMDVM_AX25_DATA;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < length; i++)
|
||||||
|
reply[i + 3U] = data[i];
|
||||||
|
|
||||||
|
writeInt(1U, reply, length + 3U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSerialPort::writeCalData(const uint8_t* data, uint8_t length)
|
void CSerialPort::writeCalData(const uint8_t* data, uint8_t length)
|
||||||
{
|
{
|
||||||
if (m_modemState != STATE_DSTARCAL)
|
if (m_modemState != STATE_DSTARCAL)
|
||||||
|
|||||||
+12
-9
@@ -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
|
||||||
@@ -50,6 +50,8 @@ public:
|
|||||||
void writeNXDNData(const uint8_t* data, uint8_t length);
|
void writeNXDNData(const uint8_t* data, uint8_t length);
|
||||||
void writeNXDNLost();
|
void writeNXDNLost();
|
||||||
|
|
||||||
|
void writeAX25Data(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void writeCalData(const uint8_t* data, uint8_t length);
|
void writeCalData(const uint8_t* data, uint8_t length);
|
||||||
void writeRSSIData(const uint8_t* data, uint8_t length);
|
void writeRSSIData(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
@@ -60,9 +62,9 @@ public:
|
|||||||
void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3, int16_t n4);
|
void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3, int16_t n4);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t m_buffer[256U];
|
uint8_t m_buffer[512U];
|
||||||
uint8_t m_ptr;
|
uint16_t m_ptr;
|
||||||
uint8_t m_len;
|
uint16_t m_len;
|
||||||
bool m_debug;
|
bool m_debug;
|
||||||
CSerialRB m_repeat;
|
CSerialRB m_repeat;
|
||||||
|
|
||||||
@@ -70,12 +72,13 @@ private:
|
|||||||
void sendNAK(uint8_t err);
|
void sendNAK(uint8_t err);
|
||||||
void getStatus();
|
void getStatus();
|
||||||
void getVersion();
|
void getVersion();
|
||||||
uint8_t setConfig(const uint8_t* data, uint8_t length);
|
uint8_t setConfig(const uint8_t* data, uint16_t length);
|
||||||
uint8_t setMode(const uint8_t* data, uint8_t length);
|
uint8_t setMode(const uint8_t* data, uint16_t length);
|
||||||
void setMode(MMDVM_STATE modemState);
|
void setMode(MMDVM_STATE modemState);
|
||||||
uint8_t setFMParams1(const uint8_t* data, uint8_t length);
|
uint8_t setFMParams1(const uint8_t* data, uint16_t length);
|
||||||
uint8_t setFMParams2(const uint8_t* data, uint8_t length);
|
uint8_t setFMParams2(const uint8_t* data, uint16_t length);
|
||||||
uint8_t setFMParams3(const uint8_t* data, uint8_t length);
|
uint8_t setFMParams3(const uint8_t* data, uint16_t length);
|
||||||
|
void processMessage(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
// Hardware versions
|
// Hardware versions
|
||||||
void beginInt(uint8_t n, int speed);
|
void beginInt(uint8_t n, int speed);
|
||||||
|
|||||||
+7
-7
@@ -50,7 +50,7 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ************* USART1 ***************** */
|
/* ************* USART1 ***************** */
|
||||||
#if defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_F7M) || defined(STM32F722_PI) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || (defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER)) || defined(DRCC_DVM)
|
#if defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_F7M) || defined(STM32F722_PI) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || (defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER)) || defined(DRCC_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||||
|
|
||||||
volatile uint8_t TXSerialfifo1[TX_SERIAL_FIFO_SIZE];
|
volatile uint8_t TXSerialfifo1[TX_SERIAL_FIFO_SIZE];
|
||||||
volatile uint8_t RXSerialfifo1[RX_SERIAL_FIFO_SIZE];
|
volatile uint8_t RXSerialfifo1[RX_SERIAL_FIFO_SIZE];
|
||||||
@@ -841,7 +841,7 @@ void CSerialPort::beginInt(uint8_t n, int speed)
|
|||||||
case 1U:
|
case 1U:
|
||||||
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
||||||
InitUSART3(speed);
|
InitUSART3(speed);
|
||||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM)
|
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||||
InitUSART1(speed);
|
InitUSART1(speed);
|
||||||
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
||||||
InitUSART2(speed);
|
InitUSART2(speed);
|
||||||
@@ -869,7 +869,7 @@ int CSerialPort::availableInt(uint8_t n)
|
|||||||
case 1U:
|
case 1U:
|
||||||
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
||||||
return AvailUSART3();
|
return AvailUSART3();
|
||||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM)
|
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||||
return AvailUSART1();
|
return AvailUSART1();
|
||||||
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
||||||
return AvailUSART2();
|
return AvailUSART2();
|
||||||
@@ -895,7 +895,7 @@ int CSerialPort::availableForWriteInt(uint8_t n)
|
|||||||
case 1U:
|
case 1U:
|
||||||
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
||||||
return AvailForWriteUSART3();
|
return AvailForWriteUSART3();
|
||||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM)
|
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||||
return AvailForWriteUSART1();
|
return AvailForWriteUSART1();
|
||||||
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
||||||
return AvailForWriteUSART2();
|
return AvailForWriteUSART2();
|
||||||
@@ -906,7 +906,7 @@ int CSerialPort::availableForWriteInt(uint8_t n)
|
|||||||
#if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER)
|
#if defined(STM32F4_NUCLEO) && defined(STM32F4_NUCLEO_ARDUINO_HEADER)
|
||||||
return AvailForWriteUSART1();
|
return AvailForWriteUSART1();
|
||||||
#elif defined(DRCC_DVM)
|
#elif defined(DRCC_DVM)
|
||||||
AvailForWriteUSART2();
|
return AvailForWriteUSART2();
|
||||||
#else
|
#else
|
||||||
return AvailForWriteUART5();
|
return AvailForWriteUART5();
|
||||||
#endif
|
#endif
|
||||||
@@ -921,7 +921,7 @@ uint8_t CSerialPort::readInt(uint8_t n)
|
|||||||
case 1U:
|
case 1U:
|
||||||
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
#if defined(STM32F4_DISCOVERY) || defined(STM32F7_NUCLEO)
|
||||||
return ReadUSART3();
|
return ReadUSART3();
|
||||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM)
|
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||||
return ReadUSART1();
|
return ReadUSART1();
|
||||||
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
#elif defined(STM32F4_NUCLEO) || defined(STM32F4_RPT_HAT_TGO)
|
||||||
return ReadUSART2();
|
return ReadUSART2();
|
||||||
@@ -949,7 +949,7 @@ void CSerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool
|
|||||||
WriteUSART3(data, length);
|
WriteUSART3(data, length);
|
||||||
if (flush)
|
if (flush)
|
||||||
TXSerialFlush3();
|
TXSerialFlush3();
|
||||||
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM)
|
#elif defined(STM32F4_PI) || defined(STM32F4_F4M) || defined(STM32F722_PI) || defined(STM32F722_F7M) || defined(STM32F722_RPT_HAT) || defined(STM32F4_DVM) || defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||||
WriteUSART1(data, length);
|
WriteUSART1(data, length);
|
||||||
if (flush)
|
if (flush)
|
||||||
TXSerialFlush1();
|
TXSerialFlush1();
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const uint8_t NOAVEPTR = 99U;
|
|||||||
|
|
||||||
const uint16_t NOENDPTR = 9999U;
|
const uint16_t NOENDPTR = 9999U;
|
||||||
|
|
||||||
const unsigned int MAX_SYNC_FRAMES = 4U + 1U;
|
const unsigned int MAX_SYNC_FRAMES = 1U + 1U;
|
||||||
|
|
||||||
CYSFRX::CYSFRX() :
|
CYSFRX::CYSFRX() :
|
||||||
m_state(YSFRXS_NONE),
|
m_state(YSFRXS_NONE),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2018,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
|
||||||
@@ -66,9 +66,6 @@ m_txCount(0U)
|
|||||||
|
|
||||||
void CYSFTX::process()
|
void CYSFTX::process()
|
||||||
{
|
{
|
||||||
if (m_buffer.getData() == 0U && m_poLen == 0U && m_txCount == 0U)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// If we have YSF data to transmit, do so.
|
// If we have YSF data to transmit, do so.
|
||||||
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
||||||
if (!m_tx) {
|
if (!m_tx) {
|
||||||
@@ -119,7 +116,7 @@ void CYSFTX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CYSFTX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CYSFTX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != (YSF_FRAME_LENGTH_BYTES + 1U))
|
if (length != (YSF_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -191,4 +188,3 @@ void CYSFTX::setParams(bool on, uint8_t txHang)
|
|||||||
m_loDev = on;
|
m_loDev = on;
|
||||||
m_txHang = txHang * 1200U;
|
m_txHang = txHang * 1200U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -27,7 +27,7 @@ class CYSFTX {
|
|||||||
public:
|
public:
|
||||||
CYSFTX();
|
CYSFTX();
|
||||||
|
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
|
|||||||
+33
-29
@@ -22,36 +22,40 @@
|
|||||||
/*
|
/*
|
||||||
Pin definitions for DRCC_DVM BG7NQF board rev1
|
Pin definitions for DRCC_DVM BG7NQF board rev1
|
||||||
|
|
||||||
PTT PB12 output
|
TX/PTT_LED PB12 output
|
||||||
LED_PTT PB4 output
|
RX/COS_LED PB5 output
|
||||||
LED_COS PB5 output
|
STATUS_LED PB10 output
|
||||||
LED_SRV PB10 output
|
|
||||||
COS PB13 input
|
|
||||||
|
|
||||||
DSTAR N/A
|
COS_IN PB13 input
|
||||||
DMR N/A
|
|
||||||
YSF N/A
|
|
||||||
P25 N/A
|
|
||||||
NXDN N/A
|
|
||||||
POCSAG N/A
|
|
||||||
|
|
||||||
MDSTAR PB14 output
|
DSTAR N/A
|
||||||
MDMR PB8 output
|
DMR N/A
|
||||||
MYSF PB9 output
|
YSF N/A
|
||||||
MP25 PB15 output
|
P25 N/A
|
||||||
MNXDN N/A
|
NXDN N/A
|
||||||
MPOCSAG N/A
|
POCSAG N/A
|
||||||
|
|
||||||
RX PB0 analog input
|
MDMR/BIT0 PB8 output
|
||||||
RSSI PB1 analog input
|
MYSF/BIT1 PB9 output
|
||||||
TX PA4 analog output
|
MDSTAR/BIT2 PB14 output
|
||||||
|
MP25/BIT3 PB15 output Generic Mode Pins
|
||||||
|
MNXDN N/A
|
||||||
|
MPOCSAG N/A
|
||||||
|
|
||||||
EXT_CLK PA15 input
|
RX PA0 analog input
|
||||||
|
RSSI PA1 analog input
|
||||||
|
TX PA4 analog output
|
||||||
|
|
||||||
UART1_TX PA9 output
|
EXT_CLK PA15 input
|
||||||
UART1_RX PA10 output
|
|
||||||
UART2_TX PA2 output
|
UART1_TX PA9 output
|
||||||
UART2_RX PA3 output
|
UART1_RX PA10 output Host Data Communication
|
||||||
|
|
||||||
|
UART2_TX PA2 output
|
||||||
|
UART2_RX PA3 output Nextion Data Communication
|
||||||
|
|
||||||
|
I2C1_SCL PB6 output
|
||||||
|
I2C1_SDA PB7 output OLED Data Communication as master
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -124,13 +128,13 @@ UART2_RX PA3 output
|
|||||||
|
|
||||||
#define PIN_RX GPIO_Pin_0
|
#define PIN_RX GPIO_Pin_0
|
||||||
#define PIN_RX_CH ADC_Channel_0
|
#define PIN_RX_CH ADC_Channel_0
|
||||||
#define PORT_RX GPIOB
|
#define PORT_RX GPIOA
|
||||||
#define RCC_Per_RX RCC_AHB1Periph_GPIOB
|
#define RCC_Per_RX RCC_AHB1Periph_GPIOA
|
||||||
|
|
||||||
#define PIN_RSSI GPIO_Pin_1
|
#define PIN_RSSI GPIO_Pin_1
|
||||||
#define PIN_RSSI_CH ADC_Channel_1
|
#define PIN_RSSI_CH ADC_Channel_1
|
||||||
#define PORT_RSSI GPIOB
|
#define PORT_RSSI GPIOA
|
||||||
#define RCC_Per_RSSI RCC_AHB1Periph_GPIOB
|
#define RCC_Per_RSSI RCC_AHB1Periph_GPIOA
|
||||||
|
|
||||||
#define PIN_TX GPIO_Pin_4
|
#define PIN_TX GPIO_Pin_4
|
||||||
#define PIN_TX_CH DAC_Channel_1
|
#define PIN_TX_CH DAC_Channel_1
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019,2020 by BG5HHP
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PINS_F4_STM32EDA
|
||||||
|
#define _PINS_F4_STM32EDA
|
||||||
|
|
||||||
|
/*
|
||||||
|
Pin definitions for STM32F4 STM32-DVM-MTR2K & STM32-DVM-MASTR3:
|
||||||
|
|
||||||
|
COS PB13 input
|
||||||
|
PTT PB12 output
|
||||||
|
COSLED PB4 output
|
||||||
|
LED PB3 output
|
||||||
|
|
||||||
|
P25 PB8 output
|
||||||
|
NXDN PB9 output
|
||||||
|
DSTAR PB6 output
|
||||||
|
DMR PB5 output
|
||||||
|
YSF PB7 output
|
||||||
|
POCSAG PC10 output
|
||||||
|
FM PC11 output
|
||||||
|
|
||||||
|
RX PB0 analog input
|
||||||
|
RSSI PB1 analog input
|
||||||
|
TX PA4 analog output
|
||||||
|
|
||||||
|
EXT_CLK PA15 input
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PIN_COS GPIO_Pin_13
|
||||||
|
#define PORT_COS GPIOB
|
||||||
|
#define RCC_Per_COS RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
|
||||||
|
#define PIN_PTT GPIO_Pin_12
|
||||||
|
#define PORT_PTT GPIOB
|
||||||
|
#define RCC_Per_PTT RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
#define PIN_COSLED GPIO_Pin_4
|
||||||
|
#define PORT_COSLED GPIOB
|
||||||
|
#define RCC_Per_COSLED RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
#define PIN_LED GPIO_Pin_3
|
||||||
|
#define PORT_LED GPIOB
|
||||||
|
#define RCC_Per_LED RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
#define PIN_P25 GPIO_Pin_8
|
||||||
|
#define PORT_P25 GPIOB
|
||||||
|
#define RCC_Per_P25 RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
#define PIN_NXDN GPIO_Pin_9
|
||||||
|
#define PORT_NXDN GPIOB
|
||||||
|
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
#define PIN_DSTAR GPIO_Pin_6
|
||||||
|
#define PORT_DSTAR GPIOB
|
||||||
|
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
#define PIN_DMR GPIO_Pin_5
|
||||||
|
#define PORT_DMR GPIOB
|
||||||
|
#define RCC_Per_DMR RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
#define PIN_YSF GPIO_Pin_7
|
||||||
|
#define PORT_YSF GPIOB
|
||||||
|
#define RCC_Per_YSF RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
#define PIN_POCSAG GPIO_Pin_10
|
||||||
|
#define PORT_POCSAG GPIOC
|
||||||
|
#define RCC_Per_POCSAG RCC_AHB1Periph_GPIOC
|
||||||
|
|
||||||
|
#define PIN_FM GPIO_Pin_11
|
||||||
|
#define PORT_FM GPIOC
|
||||||
|
#define RCC_Per_FM RCC_AHB1Periph_GPIOC
|
||||||
|
|
||||||
|
#define PIN_EXT_CLK GPIO_Pin_15
|
||||||
|
#define SRC_EXT_CLK GPIO_PinSource15
|
||||||
|
#define PORT_EXT_CLK GPIOA
|
||||||
|
|
||||||
|
#define PIN_RX GPIO_Pin_0
|
||||||
|
#define PIN_RX_CH ADC_Channel_8
|
||||||
|
#define PORT_RX GPIOB
|
||||||
|
#define RCC_Per_RX RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
#define PIN_RSSI GPIO_Pin_1
|
||||||
|
#define PIN_RSSI_CH ADC_Channel_9
|
||||||
|
#define PORT_RSSI GPIOB
|
||||||
|
#define RCC_Per_RSSI RCC_AHB1Periph_GPIOB
|
||||||
|
|
||||||
|
#define PIN_TX GPIO_Pin_4
|
||||||
|
#define PIN_TX_CH DAC_Channel_1
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Reference in New Issue
Block a user