Compare commits

..
112 Commits
Author SHA1 Message Date
Jonathan Naylor 15227d9cec Merge branch 'master' into mqtt 2024-10-02 16:10:09 +01:00
Jonathan Naylor c3246dbcb7 Merge branch 'master' of https://github.com/g4klx/MMDVM 2024-10-02 16:05:48 +01:00
Jonathan Naylor 65c51bf849 Merge branch 'master' into mqtt 2024-08-01 12:55:06 +01:00
Jonathan Naylor edd60caad3 Remove the deprecated register keyword. 2024-07-31 19:25:59 +01:00
Jonathan Naylor b8a0f7b1cf Merge pull request #343 from mytechguyri/master
Added option to configure Serial Repeater baud rate
2024-03-10 18:28:44 +00:00
John Tetreault 28e564738e Added option to configure Serial Repeater baud rate so end user can set to 115,200 for high speed Nextion display 2024-03-10 14:19:21 -04:00
Jonathan Naylor a7fddc37e1 Don't send a status when the FM repeater is reset, it causes a loop. 2023-11-18 16:45:36 +00:00
Jonathan Naylor a8bf99037e Merge branch 'master' into mqtt 2023-11-09 19:13:12 +00:00
Jonathan Naylor 029e6df4b9 Remove support for STM32F1* boards, they're just too slow. 2023-11-09 19:08:15 +00:00
Jonathan Naylor 85d3086d4c Restart the RSSI ADC conversion in the STM32 interrupt to match the signal ADC. 2023-10-10 20:06:50 +01:00
Jonathan Naylor ccf3b7301e Make the type correct for silence frames. 2023-10-10 20:03:01 +01:00
Jonathan Naylor 6b3a811ae7 Simplify the serial repeater code. 2023-10-05 19:49:17 +01:00
Jonathan Naylor 508018c89c Add the MMDVM serial protocol document from December 2015. 2023-09-22 16:51:03 +01:00
Jonathan Naylor 3e079f58ad Add RSSI reporting to FM and AX.25 2023-08-02 17:34:52 +01:00
Jonathan Naylor 7ef0d992d9 Improve the status reporting for FM mode. 2023-01-18 14:30:02 +00:00
Jonathan Naylor bf23a94038 Merge pull request #334 from n0mjs710/master 2023-01-09 15:17:17 +00:00
Cort Buffington b2755864ef Adding support for WA0EDA STM32-DVM-MTR2K v2.0d with FM LED, and a (commented) line to compile for 500000 serial port speed to support the WA0EDA MODEMs and others that use Armbian + AllWinner H2/H3 SOC that does not support 4600800. 2023-01-09 07:06:42 -06:00
Jonathan Naylor 7276ca3929 Update Version.h 2022-11-21 19:14:24 +00:00
Jonathan Naylor d14b9dede3 Update Version.h 2022-11-21 19:14:14 +00:00
Jonathan Naylor de87d77ad6 Merge pull request #330 from spongegovo/pocsagax25_fix
Fixed Serial protocol issue where MMDVMHost could not send POCSAG or AX25 to the MMDVM
2022-11-21 19:13:21 +00:00
spongegovo 2626ad5580 Update SerialPort.cpp 2022-11-20 09:15:59 +11:00
Jonathan Naylor 031b078e76 Merge pull request #327 from shawnchain/fix_ax25_dac_overflow_error 2022-09-13 14:09:12 +01:00
Shawn Chain 5d987969a9 The AX25 sine value ranges from 0-4095, and inside io.write() will perform the calculation (value * q15_t(txLevel) >> 15) which may exceed 4096 and cause the DAC Overflow error 2022-09-13 20:18:03 +08:00
Jonathan Naylor f898390956 Bump the version date. 2021-12-20 23:00:13 +00:00
Jonathan Naylor f8d1cc7aed Fix crash on long data frames. 2021-12-20 22:57:40 +00:00
Jonathan Naylor cf9fa93cb9 Include the ARM copyright in the README file. 2021-12-18 22:38:26 +00:00
Jonathan Naylor 69adaf2ebb Update SerialTeensy.cpp 2021-12-18 22:34:24 +00:00
Jonathan Naylor 7f4ae790ba Update STM32Utils.h 2021-12-18 22:31:48 +00:00
Jonathan Naylor 416fc8fc8b Update the README. 2021-12-13 10:31:10 +00:00
Jonathan Naylor 5b79356ddb Merge pull request #324 from 1tilen/master
Added PB15 to comment with pins, changed STM32F4 to STM32F7 in line 23
2021-11-14 19:51:29 +00:00
Tilen 26fc87aca6 Added PB15 to comment with pins, changed STM32F4 to STM32F7 in line 23 2021-11-14 19:21:35 +01:00
Jonathan Naylor 54745130c2 Add the transmit function. 2021-10-27 21:28:43 +01:00
Jonathan Naylor f65d52bf2f Add M17 calibration mode. 2021-10-27 19:37:58 +01:00
Jonathan Naylor 5800b33f21 Split the DMR and YSF filtering 2021-10-26 20:51:21 +01:00
Jonathan Naylor 105dba2c27 Merge branch 'master' of github.com:g4klx/MMDVM 2021-10-26 17:43:51 +01:00
Jonathan Naylor 777cc9f2ea Fix typo 2021-10-26 17:43:34 +01:00
Jonathan Naylor e879b4615a Merge branch 'master' of https://github.com/g4klx/MMDVM 2021-10-25 20:03:36 +01:00
Jonathan Naylor 8d69fc59be Update the README file 2021-10-25 20:03:17 +01:00
Jonathan Naylor 2f4e9cc269 Remove unused configuration option 2021-10-25 19:47:31 +01:00
Jonathan Naylor ee07f76bd5 Split the repeater and link mode audio paths. 2021-09-30 18:16:51 +01:00
Jonathan Naylor d063a1da1e Change the EOT handling on TX. 2021-09-19 14:25:12 +01:00
Jonathan Naylor 6a4dad4c44 Change the LinkMode state machine. 2021-09-06 22:50:40 +01:00
Jonathan Naylor ed6bd66fab Rename SimpleMode to LinkMode. 2021-09-06 21:53:01 +01:00
Jonathan Naylor 1a07a6f0d1 Add more details to the simple FM state machine. 2021-09-05 19:46:01 +01:00
Jonathan Naylor 70bf47f93e Add a bery simple FM mode for internet gatewaying. 2021-09-05 19:06:56 +01:00
Jonathan Naylor a5eaafc7e0 Change a method name. 2021-08-26 17:39:52 +01:00
Jonathan Naylor 2200945857 Change the EOF sync pattern for simplicity. 2021-08-26 16:50:18 +01:00
Jonathan Naylor 63a8e61a45 Update to send and receive the new EOF marker. 2021-08-25 21:11:09 +01:00
Jonathan Naylor 7275f65e44 Reset the transmit levels to be correct. 2021-08-23 21:07:17 +01:00
Jonathan Naylor 2aabdb61ab Remove the last traces of M17 packet mode and fix a buffer overrun bug. 2021-08-08 18:55:09 +01:00
Jonathan Naylor 96c0e5b141 Fix compiler warnings when building for POG style boards. 2021-07-19 21:20:57 +01:00
Jonathan Naylor 9c883cfafd Revert "Restore SerialRB for POG builds."
This reverts commit 8a1ab88c3a.
2021-07-01 22:58:59 +01:00
Jonathan Naylor 8a1ab88c3a Restore SerialRB for POG builds. 2021-07-01 22:28:59 +01:00
Jonathan Naylor f4e1c0b401 Fix a potential issue with reporting the wrong command type in ACK and NAK messages. 2021-06-17 16:55:59 +01:00
Jonathan Naylor 43b53fe2fc Add a dummy return for the setting of the FM parameters when FM is not enabled. 2021-05-08 23:48:52 +01:00
Jonathan Naylor 6517229f87 Bump the version date. 2021-05-08 23:24:36 +01:00
Jonathan Naylor d0557ab723 Fix merge mistake which disabled serial access to the RB V5 board. 2021-05-08 23:22:25 +01:00
Jonathan Naylor b5d106dcb6 Merge branch 'master' into M17_AX25_FM 2021-05-05 21:01:19 +01:00
Jonathan Naylor 34cbff41c9 Merge pull request #317 from N4IRS/master 2021-05-02 15:00:12 +01:00
Steve N4IRS 752e13821f Add STM32F7-DVM board 2021-05-02 07:19:24 -04:00
Jonathan Naylor 86b45c15eb Merge branch 'master' into M17_AX25_FM 2021-04-20 20:38:14 +01:00
Jonathan Naylor 4fa0e052f8 Merge pull request #316 from N4IRS/master
RB STM32_DVM_F7 support
2021-04-20 12:51:10 +01:00
Steve N4IRS 0736a5cbe8 RB STM32_DVM_F7 support 2021-04-18 09:50:46 -04:00
Jonathan Naylor 6ffb68450c Allow for hex dumps of modem data by the host. 2021-04-11 18:15:19 +01:00
Jonathan Naylor 1ad20fd4a0 Disable packet mode in M17. 2021-04-07 19:02:04 +01:00
Jonathan Naylor 34f6dfc5bb Simplification of the M17 receiver. 2021-03-14 18:24:30 +00:00
Jonathan Naylor 1e065ba17f Fix and simplify the M17 receiver. 2021-03-14 17:53:28 +00:00
Jonathan Naylor 1df7d7a7fc Change the FM serial block size to 80. 2021-03-07 19:01:46 +00:00
Jonathan Naylor 7e919b12f7 Clean up the M17 synchronisation logic. 2021-01-02 12:24:11 +00:00
Jonathan Naylor bada4d9285 Add M17 packet mode support. 2021-01-01 13:17:02 +00:00
Jonathan Naylor 9ae4a5376d Merge branch 'master' into M17_AX25_FM 2021-01-01 13:01:56 +00:00
Jonathan Naylor 8038ce9c9c Merge pull request #308 from shawnchain/drcc_dvm_hhp_board_support
Add DRCC_DVM_HHP446 board support
2021-01-01 12:32:01 +00:00
Shawn Chain 842dcdb5c5 Add DRCC_DVM_HHP446 board support 2021-01-01 19:48:07 +08:00
Jonathan Naylor f7ead5cc0e Update the M17 sync vectors. 2020-12-26 12:42:16 +00:00
Jonathan Naylor b155597693 Merge branch 'master' into M17_AX25_FM 2020-12-14 09:53:38 +00:00
Jonathan Naylor 7148cf9f7d Add I2C support. 2020-12-14 09:46:53 +00:00
Jonathan Naylor 9440b43114 Simplify the D-Star fast data support. 2020-12-14 09:45:53 +00:00
Jonathan Naylor c06a83660f Merge pull request #306 from timclassic/dstar-match-full-last-data-frame
Detect full 48 bits of last data frame in a D-Star transmission
2020-12-14 09:37:05 +00:00
Tim Stewart 657e71238d Detect full 48 bits of last data frame in a transmission
While testing new support for DV Fast Data, I ran across a particular
image that reliably generated a bit sequence that the MDMVM firmware
interpreted as an end-of-transmission.  I dug a bit and discovered
that MMDVM only matches on 32 bits of the last data frame instead of
the full 48 bits.

See http://www.arrl.org/files/file/D-STAR.pdf section 2.1.2, item (6)
for details.
2020-12-05 13:37:06 -05:00
Jonathan Naylor 510d433906 Merge pull request #305 from dg0tm/M17_AX25_FM
Fixing Arduino Unique Identifier byte order
2020-11-28 15:27:16 +00:00
Christoph Kottke ff39a9031b Fixing Arduino Unique Identifier byte order 2020-11-28 16:25:08 +01:00
Jonathan Naylor 4f3aa8b7e1 Merge pull request #304 from dg0tm/M17_AX25_FM
Fixing Arduino UUID support
2020-11-28 12:13:35 +00:00
Christoph Kottke a35b8f929a Fixing Arduino UUID support 2020-11-28 08:51:58 +01:00
Jonathan Naylor 6d0335b357 Update for latest M17 specification. 2020-11-26 10:03:54 +00:00
Jonathan Naylor 54f4dcabf0 Increase serial speed to 460800. 2020-11-24 16:22:14 +00:00
Jonathan Naylor 19e2ccf150 Bump the version date. 2020-11-20 10:36:45 +00:00
Jonathan Naylor 0c4f49fa68 Add FM LED pin definition for the Repeater Builder V4 board. 2020-11-20 10:35:19 +00:00
Jonathan Naylor 98ebefe84b Update module pointers. 2020-11-20 10:31:11 +00:00
Jonathan Naylor 029e7eef4a Fix bugs. 2020-11-18 20:35:07 +00:00
Jonathan Naylor ca4fff2ba6 Remove unused I2C code and fix buffer handling bugs. 2020-11-17 10:36:00 +00:00
Jonathan Naylor 23ba73cabd Disable I2C in M17_AX25_FM. 2020-11-13 15:22:35 +00:00
Jonathan Naylor 519af80ac4 Add the beginnings of I2C support. 2020-11-13 15:20:54 +00:00
Jonathan Naylor c5b542f438 Allow serial data to be sent back to the host. 2020-11-13 12:09:10 +00:00
Jonathan Naylor 3503e0cc2a Merge branch 'master' into M17_AX25_FM 2020-11-12 09:15:40 +00:00
Jonathan Naylor 955578789d Make the M17 receiver less sensitive to noise. 2020-11-11 18:30:49 +00:00
Andy CA6JAU 061e10e395 Fixing deploy-pi and deploy-pi-f7 (M0VSE advice) 2020-11-11 15:23:14 -03:00
Jonathan Naylor fa9040fdf0 Fix compile issue for the serial repeater. 2020-11-11 17:14:05 +00:00
Jonathan Naylor 8240225371 Set the Config.h defaults correctly for the ZUM v0.9 board. 2020-11-11 17:11:22 +00:00
Jonathan Naylor f2c7c19444 Strip the version out of SerialPort.cpp 2020-11-09 17:29:55 +00:00
Jonathan Naylor 2e5f174cdd Add the modem capabilities data to the version message. 2020-11-09 16:22:44 +00:00
Jonathan Naylor d144ce6f1c Small changes to the serial protocol. 2020-11-09 14:23:43 +00:00
Jonathan Naylor 31744a237a Use the D-Star correlator receiver. 2020-11-09 11:50:02 +00:00
Jonathan Naylor 46c0958704 Add the boxcar filter as an option for NXDN. 2020-11-09 11:25:03 +00:00
Jonathan Naylor 99d2a0d822 Add UDID support. 2020-11-09 10:23:57 +00:00
Jonathan Naylor 81518bf74c Make AX.25, DMR, P25, NXDN and FM selectable at compile time. 2020-11-08 22:23:27 +00:00
Jonathan Naylor dd5a465a39 Make D-Star, System Fusion, M17, and POCSAG optional. 2020-11-08 21:28:26 +00:00
Jonathan Naylor a345586ee9 Update the protocol version. 2020-11-06 15:14:02 +00:00
Jonathan Naylor 55c89a4413 Merge branch 'AX25_FM' into M17_AX25_FM 2020-11-06 15:06:00 +00:00
Jonathan Naylor 60f87072ba Rescale the TX filter for M17. 2020-10-15 09:40:35 +01:00
Jonathan Naylor f2d2033733 Add the sync and RRC 0.5 data and code. 2020-10-14 13:29:23 +01:00
Jonathan Naylor 0334b5a791 Handle the M17 mode LED pins(-ish) 2020-10-14 11:55:31 +01:00
Jonathan Naylor a62fd814ae Begin M17 support. 2020-10-14 10:52:30 +01:00
126 changed files with 4076 additions and 2546 deletions
-3
View File
@@ -4,6 +4,3 @@
[submodule "STM32F7XX_Lib"]
path = STM32F7XX_Lib
url = https://github.com/juribeparada/STM32F7XX_Lib.git
[submodule "STM32F10X_Lib"]
path = STM32F10X_Lib
url = https://github.com/shawnchain/STM32F10X_Lib.git
+29 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2023 by Jonathan Naylor G4KLX
* Copyright 2015-2019 Mobilinkd LLC <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,9 @@
*/
#include "Config.h"
#if defined(MODE_AX25)
#include "Globals.h"
#include "AX25Demodulator.h"
#include "AX25Defines.h"
@@ -82,7 +85,9 @@ m_hdlcOnes(0U),
m_hdlcFlag(false),
m_hdlcBuffer(0U),
m_hdlcBits(0U),
m_hdlcState(AX25_IDLE)
m_hdlcState(AX25_IDLE),
m_rssiAccum(0U),
m_rssiCount(0U)
{
m_delayLine = new bool[DELAY_LEN];
@@ -98,7 +103,7 @@ m_hdlcState(AX25_IDLE)
m_iirHistory[i] = 0.0F;
}
bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame)
bool CAX25Demodulator::process(q15_t* samples, const uint16_t* rssi, uint8_t length, CAX25Frame& frame)
{
bool result = false;
@@ -116,6 +121,9 @@ bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame
::arm_fir_fast_q15(&m_lpfFilter, buffer, fc, RX_BLOCK_SIZE);
for (uint8_t i = 0; i < length; i++) {
m_rssiAccum += rssi[i];
m_rssiCount++;
bool bit = fc[i] >= 0;
bool sample = PLL(bit);
@@ -263,6 +271,8 @@ bool CAX25Demodulator::HDLC(bool b)
// Start of frame data.
m_hdlcState = AX25_RECEIVE;
m_frame.append(m_hdlcBuffer);
m_rssiAccum = 0U;
m_rssiCount = 0U;
m_hdlcBits = 0U;
}
break;
@@ -312,3 +322,19 @@ float32_t CAX25Demodulator::iir(float32_t input)
return result;
}
uint16_t CAX25Demodulator::getRSSI()
{
if (m_rssiCount > 0U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
m_rssiAccum = 0U;
m_rssiCount = 0U;
return rssi;
}
return 0U;
}
#endif
+12 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2023 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_AX25)
#if !defined(AX25Demodulator_H)
#define AX25Demodulator_H
#include "Config.h"
#include "AX25Frame.h"
#include "AX25Twist.h"
@@ -34,12 +36,14 @@ class CAX25Demodulator {
public:
CAX25Demodulator(int8_t n);
bool process(q15_t* samples, uint8_t length, CAX25Frame& frame);
bool process(q15_t* samples, const uint16_t* rssi, uint8_t length, CAX25Frame& frame);
void setTwist(int8_t n);
bool isDCD();
uint16_t getRSSI();
private:
CAX25Frame m_frame;
CAX25Twist m_twist;
@@ -61,6 +65,8 @@ private:
uint16_t m_hdlcBuffer;
uint16_t m_hdlcBits;
AX25_STATE m_hdlcState;
uint32_t m_rssiAccum;
uint16_t m_rssiCount;
bool delay(bool b);
bool NRZI(bool b);
@@ -71,3 +77,5 @@ private:
#endif
#endif
+5
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_AX25)
#include "Globals.h"
#include "AX25Frame.h"
@@ -120,3 +123,5 @@ void CAX25Frame::addCRC()
m_data[m_length++] = crc8[1U];
}
#endif
+6 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_AX25)
#if !defined(AX25Frame_H)
#define AX25Frame_H
#include "Config.h"
const uint16_t AX25_MAX_PACKET_LEN = 300U;
class CAX25Frame {
@@ -41,3 +43,5 @@ public:
#endif
#endif
+35 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2023 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_AX25)
#include "Globals.h"
#include "AX25RX.h"
@@ -83,7 +86,7 @@ m_c(0xF6U)
initRand();
}
void CAX25RX::samples(q15_t* samples, uint8_t length)
void CAX25RX::samples(q15_t* samples, const uint16_t* rssi, uint8_t length)
{
q15_t output[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE);
@@ -92,32 +95,56 @@ void CAX25RX::samples(q15_t* samples, uint8_t length)
CAX25Frame frame;
bool ret = m_demod1.process(output, length, frame);
bool ret = m_demod1.process(output, rssi, length, frame);
if (ret) {
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
m_lastFCS = frame.m_fcs;
m_count = 0U;
#if defined(SEND_RSSI_DATA)
uint16_t rssi = m_demod1.getRSSI();
if (rssi > 0U)
serial.writeAX25DataEx(rssi, frame.m_data, frame.m_length - 2U);
else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#endif
}
DEBUG1("Decoder 1 reported");
}
ret = m_demod2.process(output, length, frame);
ret = m_demod2.process(output, rssi, length, frame);
if (ret) {
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
m_lastFCS = frame.m_fcs;
m_count = 0U;
#if defined(SEND_RSSI_DATA)
uint16_t rssi = m_demod2.getRSSI();
if (rssi > 0U)
serial.writeAX25DataEx(rssi, frame.m_data, frame.m_length - 2U);
else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#endif
}
DEBUG1("Decoder 2 reported");
}
ret = m_demod3.process(output, length, frame);
ret = m_demod3.process(output, rssi, length, frame);
if (ret) {
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
m_lastFCS = frame.m_fcs;
m_count = 0U;
#if defined(SEND_RSSI_DATA)
uint16_t rssi = m_demod3.getRSSI();
if (rssi > 0U)
serial.writeAX25DataEx(rssi, frame.m_data, frame.m_length - 2U);
else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#else
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
#endif
}
DEBUG1("Decoder 3 reported");
}
@@ -203,3 +230,6 @@ uint8_t CAX25RX::rand()
return uint8_t(m_c); //low order bits of other variables
}
#endif
+8 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2023 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,18 +16,20 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_AX25)
#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 samples(q15_t* samples, const uint16_t* rssi, uint8_t length);
void setParams(int8_t twist, uint8_t slotTime, uint8_t pPersist);
@@ -57,3 +59,5 @@ private:
#endif
#endif
+6 -1
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_AX25)
#include "Globals.h"
#include "AX25TX.h"
@@ -157,7 +160,7 @@ void CAX25TX::writeBit(bool b)
m_tablePtr += 11U;
}
buffer[i] = value;
buffer[i] = value >> 1;
if (m_tablePtr >= AUDIO_TABLE_LEN)
m_tablePtr -= AUDIO_TABLE_LEN;
@@ -184,3 +187,5 @@ bool CAX25TX::NRZI(bool b)
return m_nrzi;
}
#endif
+6 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_AX25)
#if !defined(AX25TX_H)
#define AX25TX_H
#include "Config.h"
class CAX25TX {
public:
CAX25TX();
@@ -47,3 +49,5 @@ private:
#endif
#endif
+5
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_AX25)
#include "Globals.h"
#include "AX25Twist.h"
@@ -309,3 +312,5 @@ void CAX25Twist::setTwist(int8_t n)
m_filter.pCoeffs = coeffs[twist];
}
#endif
+6 -3
View File
@@ -16,11 +16,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(AX25Twist_H)
#define AX25Twist_H
#include "Config.h"
#if defined(MODE_AX25)
#if !defined(AX25Twist_H)
#define AX25Twist_H
class CAX25Twist {
public:
@@ -37,3 +38,5 @@ private:
#endif
#endif
+5
View File
@@ -18,6 +18,9 @@
*/
#include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h"
#include "CalDMR.h"
@@ -221,3 +224,5 @@ uint8_t CCalDMR::write(const uint8_t* data, uint16_t length)
return 0U;
}
#endif
+6 -1
View File
@@ -17,10 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(CALDMR_H)
#define CALDMR_H
#include "Config.h"
#include "DMRDefines.h"
enum DMRCAL1K {
@@ -53,3 +56,5 @@ private:
#endif
#endif
+7 -2
View File
@@ -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
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_DSTAR)
#include "Globals.h"
#include "CalDStarRX.h"
#include "Utils.h"
@@ -24,7 +27,7 @@
const unsigned int BUFFER_LENGTH = 200U;
const uint32_t PLLMAX = 0x10000U;
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_BIT_LENGTH;
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_SYMBOL_LENGTH;
const uint32_t INC = PLLINC / 32U;
// D-Star bit order version of 0x55 0x2D 0x16
@@ -126,3 +129,5 @@ void CCalDStarRX::process(q15_t value)
}
}
#endif
+7 -2
View File
@@ -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
* it under the terms of the GNU General Public License as published by
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DSTAR)
#if !defined(CALDSTARRX_H)
#define CALDSTARRX_H
#include "Config.h"
#include "DStarDefines.h"
class CCalDStarRX {
@@ -40,3 +43,5 @@ private:
#endif
#endif
+5
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_DSTAR)
#include "Globals.h"
#include "CalDStarTX.h"
@@ -181,3 +184,5 @@ uint8_t CCalDStarTX::write(const uint8_t* data, uint16_t length)
return 0U;
}
#endif
+6 -1
View File
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DSTAR)
#if !defined(CALDSTARTX_H)
#define CALDSTARTX_H
#include "Config.h"
#include "DStarDefines.h"
class CCalDStarTX {
@@ -37,3 +40,5 @@ private:
#endif
#endif
+6
View File
@@ -19,6 +19,9 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#include "Globals.h"
#include "CalFM.h"
@@ -125,3 +128,6 @@ uint8_t CCalFM::write(const uint8_t* data, uint16_t length)
return 0U;
}
#endif
+6 -2
View File
@@ -18,11 +18,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(CALFM_H)
#define CALFM_H
#include "Config.h"
class CCalFM {
public:
CCalFM();
@@ -49,3 +51,5 @@ private:
#endif
#endif
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2009-2015,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_M17)
#include "Globals.h"
#include "CalM17.h"
#include "M17Defines.h"
const uint8_t PREAMBLE[] = {0x00U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U,
0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U, 0x77U};
CCalM17::CCalM17() :
m_transmit(false)
{
}
void CCalM17::process()
{
m17TX.process();
if (!m_transmit)
return;
uint16_t space = m17TX.getSpace();
if (space < 2U)
return;
m17TX.writeData(PREAMBLE, M17_FRAME_LENGTH_BYTES + 1U);
}
uint8_t CCalM17::write(const uint8_t* data, uint16_t length)
{
if (length != 1U)
return 4U;
m_transmit = data[0U] == 1U;
return 0U;
}
#endif
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2009-2015,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_M17)
#if !defined(CALM17_H)
#define CALM17_H
class CCalM17 {
public:
CCalM17();
void process();
uint8_t write(const uint8_t* data, uint16_t length);
private:
bool m_transmit;
};
#endif
#endif
+5
View File
@@ -18,6 +18,9 @@
*/
#include "Config.h"
#if defined(MODE_NXDN)
#include "Globals.h"
#include "CalNXDN.h"
@@ -93,3 +96,5 @@ uint8_t CCalNXDN::write(const uint8_t* data, uint16_t length)
return 0U;
}
#endif
+6 -2
View File
@@ -17,11 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_NXDN)
#if !defined(CALNXDN_H)
#define CALNXDN_H
#include "Config.h"
enum NXDNCAL1K {
NXDNCAL1K_IDLE,
NXDNCAL1K_TX
@@ -43,3 +45,5 @@ private:
#endif
#endif
+5
View File
@@ -18,6 +18,9 @@
*/
#include "Config.h"
#if defined(MODE_P25)
#include "Globals.h"
#include "CalP25.h"
@@ -96,3 +99,5 @@ uint8_t CCalP25::write(const uint8_t* data, uint16_t length)
return 0U;
}
#endif
+6 -1
View File
@@ -17,10 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_P25)
#if !defined(CALP25_H)
#define CALP25_H
#include "Config.h"
#include "P25Defines.h"
enum P25CAL1K {
@@ -44,3 +47,5 @@ private:
#endif
#endif
+6 -1
View File
@@ -18,10 +18,12 @@
*/
#include "Config.h"
#if defined(MODE_POCSAG)
#include "Globals.h"
#include "CalPOCSAG.h"
CCalPOCSAG::CCalPOCSAG() :
m_state(POCSAGCAL_IDLE)
{
@@ -48,3 +50,6 @@ uint8_t CCalPOCSAG::write(const uint8_t* data, uint16_t length)
return 0U;
}
#endif
+7 -2
View File
@@ -17,11 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_POCSAG)
#if !defined(CALPOCSAG_H)
#define CALPOCSAG_H
#include "Config.h"
enum POCSAGCAL {
POCSAGCAL_IDLE,
POCSAGCAL_TX
@@ -40,3 +42,6 @@ private:
};
#endif
#endif
+49 -16
View File
@@ -19,6 +19,37 @@
#if !defined(CONFIG_H)
#define CONFIG_H
// Allow for the selection of which modes to compile into the firmware. This is particularly useful for processors
// which have limited code space and processing power.
// Enable D-Star support.
#define MODE_DSTAR
// Enable DMR support.
#define MODE_DMR
// Enable System Fusion support.
#define MODE_YSF
// Enable P25 phase 1 support.
#define MODE_P25
// Enable NXDN support, the boxcar filter sometimes improves the performance of NXDN receive on some systems.
#define MODE_NXDN
#define USE_NXDN_BOXCAR
// Enable M17 support.
#define MODE_M17
// Enable POCSAG support.
#define MODE_POCSAG
// Enable FM support.
#define MODE_FM
// Enable AX.25 support, this is only enabled if FM is also enabled.
#define MODE_AX25
// Allow for the use of high quality external clock oscillators
// The number is the frequency of the oscillator in Hertz.
//
@@ -35,13 +66,11 @@
// For 19.2 MHz
// #define EXTERNAL_OSC 19200000
// Use a higher baudrate for host communication. Required for FM network !
#define SERIAL_SPEED 115200 //suitable for most older boards (Arduino, Due STM32F1_POG etc). External FM will NOT work with this !
// #define SERIAL_SPEED 230400 // Only works on newer board M4, M7, Teensy. External FM might work with this
// #define SERIAL_SPEED 460800 // Only works on newer board M4, M7, Teensy. External FM should work with this
// Allow the use of the COS line to lockout the modem
// #define USE_COS_AS_LOCKOUT
// Select a baud rate for host communication. The faster speeds are needed for external FM to work.
// #define SERIAL_SPEED 115200 // Suitable for most older boards (Arduino Due, etc). External FM will NOT work with this!
// #define SERIAL_SPEED 230400 // Only works on newer boards like fast M4, M7, Teensy 3.x. External FM might work with this
#define SERIAL_SPEED 460800 // Only works on newer boards like fast M4, M7, Teensy 3.x. External FM should work with this
//#define SERIAL_SPEED 500000 // Used with newer boards and Armbian on AllWinner SOCs (H2, H3) that do not support 460800
// Use pins to output the current mode via LEDs
#define MODE_LEDS
@@ -49,13 +78,8 @@
// For the original Arduino Due pin layout
// #define ARDUINO_DUE_PAPA
#if defined(STM32F1)
// For the SQ6POG board
#define STM32F1_POG
#else
// For the ZUM V1.0 and V1.0.1 boards pin layout
#define ARDUINO_DUE_ZUM_V10
#endif
// #define ARDUINO_DUE_ZUM_V10
// For the SP8NTH board
// #define ARDUINO_DUE_NTH
@@ -71,10 +95,16 @@
// #define VK6MST_TEENSY_PI3_SHIELD_I2C
// Pass RSSI information to the host
// #define SEND_RSSI_DATA
#define SEND_RSSI_DATA
// Use the modem as a serial repeater for Nextion displays
// #define SERIAL_REPEATER
#define SERIAL_REPEATER
// Set the baud rate of the modem serial repeater for Nextion displays
#define SERIAL_REPEATER_BAUD_RATE 9600
// Use the modem as an I2C repeater for OLED displays
// #define I2C_REPEATER
// To reduce CPU load, you can remove the DC blocker by commenting out the next line
#define USE_DCBLOCKER
@@ -86,8 +116,11 @@
// Use the YSF and P25 LEDs for NXDN
// #define USE_ALTERNATE_NXDN_LEDS
// Use the D-Star and P25 LEDs for M17
#define USE_ALTERNATE_M17_LEDS
// Use the D-Star and DMR LEDs for POCSAG
// #define USE_ALTERNATE_POCSAG_LEDS
#define USE_ALTERNATE_POCSAG_LEDS
// Use the D-Star and YSF LEDs for FM
#define USE_ALTERNATE_FM_LEDS
+7 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h"
#include "DMRDMORX.h"
#include "DMRSlotType.h"
@@ -423,3 +426,6 @@ void CDMRDMORX::writeRSSIData(uint8_t* frame)
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif
}
#endif
+8 -2
View File
@@ -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
* it under the terms of the GNU General Public License as published by
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRDMORX_H)
#define DMRDMORX_H
#include "Config.h"
#include "DMRDefines.h"
const uint16_t DMO_BUFFER_LENGTH_SAMPLES = 1440U; // 60ms at 24 kHz
@@ -67,3 +70,6 @@ private:
};
#endif
#endif
+5
View File
@@ -19,6 +19,9 @@
*/
#include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h"
#include "DMRSlotType.h"
@@ -161,3 +164,5 @@ void CDMRDMOTX::setTXDelay(uint8_t delay)
m_txDelay = 1200U;
}
#endif
+6 -1
View File
@@ -17,10 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRDMOTX_H)
#define DMRDMOTX_H
#include "Config.h"
#include "DMRDefines.h"
#include "RingBuffer.h"
@@ -51,3 +54,5 @@ private:
#endif
#endif
+7 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h"
#include "DMRIdleRX.h"
#include "DMRSlotType.h"
@@ -209,3 +212,6 @@ void CDMRIdleRX::setColorCode(uint8_t colorCode)
{
m_colorCode = colorCode;
}
#endif
+7 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRIDLERX_H)
#define DMRIDLERX_H
#include "Config.h"
#include "DMRDefines.h"
class CDMRIdleRX {
@@ -49,3 +52,5 @@ private:
#endif
#endif
+6 -1
View File
@@ -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
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h"
#include "DMRRX.h"
@@ -68,3 +71,5 @@ void CDMRRX::reset()
m_slot2RX.reset();
}
#endif
+7 -2
View File
@@ -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
* it under the terms of the GNU General Public License as published by
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRRX_H)
#define DMRRX_H
#include "Config.h"
#include "DMRSlotRX.h"
class CDMRRX {
@@ -40,3 +43,5 @@ private:
#endif
#endif
+7 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h"
#include "DMRSlotRX.h"
#include "DMRSlotType.h"
@@ -400,3 +403,6 @@ void CDMRSlotRX::writeRSSIData(uint8_t* frame)
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
#endif
}
#endif
+8 -2
View File
@@ -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
* it under the terms of the GNU General Public License as published by
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRSLOTRX_H)
#define DMRSLOTRX_H
#include "Config.h"
#include "DMRDefines.h"
enum DMRRX_STATE {
@@ -70,3 +73,6 @@ private:
};
#endif
#endif
+6 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h"
#include "DMRSlotType.h"
@@ -285,3 +288,5 @@ void CDMRSlotType::encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) c
frame[20U] = (frame[20U] & 0x03U) | ((slotType[1U] << 6) & 0xC0U) | ((slotType[2U] >> 2) & 0x3CU);
}
#endif
+7 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,6 +16,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRSLOTTYPE_H)
#define DMRSLOTTYPE_H
@@ -35,3 +39,5 @@ private:
#endif
#endif
+6
View File
@@ -19,6 +19,9 @@
*/
#include "Config.h"
#if defined(MODE_DMR)
#include "Globals.h"
#include "DMRSlotType.h"
@@ -414,3 +417,6 @@ uint32_t CDMRTX::getFrameCount()
{
return m_frameCount;
}
#endif
+6 -1
View File
@@ -17,10 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DMR)
#if !defined(DMRTX_H)
#define DMRTX_H
#include "Config.h"
#include "DMRDefines.h"
#include "RingBuffer.h"
@@ -83,3 +86,5 @@ private:
#endif
#endif
+37 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2015,2017,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,30 +19,50 @@
#if !defined(DSTARDEFINES_H)
#define DSTARDEFINES_H
const unsigned int DSTAR_RADIO_BIT_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int DSTAR_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
const unsigned int DSTAR_HEADER_LENGTH_BITS = DSTAR_HEADER_LENGTH_BYTES * 8U;
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U;
const unsigned int DSTAR_FEC_SECTION_LENGTH_BITS = 660U;
const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U;
const unsigned int DSTAR_FEC_SECTION_LENGTH_SYMBOLS = 660U;
const unsigned int DSTAR_FEC_SECTION_LENGTH_SAMPLES = DSTAR_FEC_SECTION_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U;
const unsigned int DSTAR_DATA_LENGTH_BITS = DSTAR_DATA_LENGTH_BYTES * 8U;
const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U;
const unsigned int DSTAR_DATA_LENGTH_SYMBOLS = DSTAR_DATA_LENGTH_BYTES * 8U;
const unsigned int DSTAR_DATA_LENGTH_SAMPLES = DSTAR_DATA_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
const uint8_t DSTAR_EOT_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const unsigned int DSTAR_EOT_LENGTH_BYTES = 6U;
const unsigned int DSTAR_EOT_LENGTH_BITS = DSTAR_EOT_LENGTH_BYTES * 8U;
const unsigned int DSTAR_END_SYNC_LENGTH_BYTES = 6U;
const unsigned int DSTAR_END_SYNC_LENGTH_BITS = DSTAR_END_SYNC_LENGTH_BYTES * 8U;
const uint8_t DSTAR_DATA_SYNC_LENGTH_BYTES = 3U;
const uint8_t DSTAR_DATA_SYNC_LENGTH_BITS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U;
const unsigned int DSTAR_FRAME_SYNC_LENGTH_BYTES = 3U;
const unsigned int DSTAR_FRAME_SYNC_LENGTH_SYMBOLS = DSTAR_FRAME_SYNC_LENGTH_BYTES * 8U;
const unsigned int DSTAR_FRAME_SYNC_LENGTH_SAMPLES = DSTAR_FRAME_SYNC_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16};
const unsigned int DSTAR_DATA_SYNC_LENGTH_BYTES = 3U;
const unsigned int DSTAR_DATA_SYNC_LENGTH_SYMBOLS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U;
const unsigned int DSTAR_DATA_SYNC_LENGTH_SAMPLES = DSTAR_DATA_SYNC_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U;
const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U;
const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16};
const uint8_t DSTAR_SCRAMBLER_BYTES[] = {0x70U, 0x4FU, 0x93U};
// D-Star bit order version of 0x55 0x6E 0x0A
const uint32_t DSTAR_FRAME_SYNC_DATA = 0x00557650U;
const uint32_t DSTAR_FRAME_SYNC_MASK = 0x00FFFFFFU;
const bool DSTAR_FRAME_SYNC_SYMBOLS[] = {false, true, false, true, false, true, false, true, false, true, true, true, false, true, true, false, false, true, false, true, false, false, false, false};
// D-Star bit order version of 0x55 0x2D 0x16
const uint32_t DSTAR_DATA_SYNC_DATA = 0x00AAB468U;
const uint32_t DSTAR_DATA_SYNC_MASK = 0x00FFFFFFU;
const bool DSTAR_DATA_SYNC_SYMBOLS[] = {true, false, true, false, true, false, true, false, true, false, true, true, false, true, false, false, false, true, true, false, true, false, false, false};
// D-Star bit order version of 0x55 0x55 0xC8 0x7A
const uint32_t DSTAR_END_SYNC_DATA = 0xAAAA135EU;
const uint32_t DSTAR_END_SYNC_MASK = 0xFFFFFFFFU;
const uint8_t DSTAR_END_SYNC_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U;
const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U;
const uint8_t DSTAR_SCRAMBLER_BYTES[] = {0x70U, 0x4FU, 0x93U};
#endif
+249 -142
View File
@@ -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
*
* This program is free software; you can redistribute it and/or modify
@@ -18,31 +18,28 @@
*/
#include "Config.h"
#if defined(MODE_DSTAR)
#include "Globals.h"
#include "DStarRX.h"
#include "Utils.h"
const unsigned int BUFFER_LENGTH = 200U;
const uint32_t PLLMAX = 0x10000U;
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_BIT_LENGTH;
const uint32_t INC = PLLINC / 32U;
const unsigned int MAX_SYNC_BITS = 100U * DSTAR_DATA_LENGTH_BITS;
const unsigned int MAX_FRAMES = 150U;
// D-Star bit order version of 0x55 0x55 0x6E 0x0A
const uint32_t FRAME_SYNC_DATA = 0x00557650U;
const uint32_t FRAME_SYNC_MASK = 0x00FFFFFFU;
const uint64_t FRAME_SYNC_DATA = 0x0000000000557650U;
const uint64_t FRAME_SYNC_MASK = 0x0000000000FFFFFFU;
const uint8_t FRAME_SYNC_ERRS = 2U;
// D-Star bit order version of 0x55 0x2D 0x16
const uint32_t DATA_SYNC_DATA = 0x00AAB468U;
const uint32_t DATA_SYNC_MASK = 0x00FFFFFFU;
const uint64_t DATA_SYNC_DATA = 0x0000000000AAB468U;
const uint64_t DATA_SYNC_MASK = 0x0000000000FFFFFFU;
const uint8_t DATA_SYNC_ERRS = 2U;
// D-Star bit order version of 0x55 0x55 0xC8 0x7A
const uint32_t END_SYNC_DATA = 0xAAAA135EU;
const uint32_t END_SYNC_MASK = 0xFFFFFFFFU;
const uint64_t END_SYNC_DATA = 0x0000AAAAAAAA135EU;
const uint64_t END_SYNC_MASK = 0x0000FFFFFFFFFFFFU;
const uint8_t END_SYNC_ERRS = 1U;
const uint8_t BIT_MASK_TABLE0[] = {0x7FU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0xFEU};
@@ -237,14 +234,24 @@ const uint16_t CCITT_TABLE[] = {
0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U,
0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U};
const uint16_t NOENDPTR = 9999U;
CDStarRX::CDStarRX() :
m_pll(0U),
m_prev(false),
m_rxState(DSRXS_NONE),
m_patternBuffer(0x00U),
m_rxBuffer(),
m_rxBufferBits(0U),
m_dataBits(0U),
m_bitBuffer(),
m_headerBuffer(),
m_dataBuffer(),
m_bitPtr(0U),
m_headerPtr(0U),
m_dataPtr(0U),
m_startPtr(NOENDPTR),
m_syncPtr(NOENDPTR),
m_minSyncPtr(NOENDPTR),
m_maxSyncPtr(NOENDPTR),
m_maxFrameCorr(0),
m_maxDataCorr(0),
m_frameCount(0U),
m_countdown(0U),
m_mar(0U),
m_pathMetric(),
m_pathMemory0(),
@@ -259,14 +266,20 @@ m_rssiCount(0U)
void CDStarRX::reset()
{
m_pll = 0U;
m_prev = false;
m_rxState = DSRXS_NONE;
m_patternBuffer = 0x00U;
m_rxBufferBits = 0U;
m_dataBits = 0U;
m_rssiAccum = 0U;
m_rssiCount = 0U;
m_rxState = DSRXS_NONE;
m_headerPtr = 0U;
m_dataPtr = 0U;
m_bitPtr = 0U;
m_maxFrameCorr = 0;
m_maxDataCorr = 0;
m_startPtr = NOENDPTR;
m_syncPtr = NOENDPTR;
m_minSyncPtr = NOENDPTR;
m_maxSyncPtr = NOENDPTR;
m_frameCount = 0U;
m_countdown = 0U;
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t length)
@@ -275,125 +288,117 @@ void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t lengt
m_rssiAccum += rssi[i];
m_rssiCount++;
bool bit = samples[i] < 0;
q15_t sample = samples[i];
if (bit != m_prev) {
if (m_pll < (PLLMAX / 2U))
m_pll += INC;
else
m_pll -= INC;
m_bitBuffer[m_bitPtr] <<= 1;
if (sample < 0)
m_bitBuffer[m_bitPtr] |= 0x01U;
m_dataBuffer[m_dataPtr] = sample;
switch (m_rxState) {
case DSRXS_HEADER:
processHeader(sample);
break;
case DSRXS_DATA:
processData();
break;
default:
processNone(sample);
break;
}
m_prev = bit;
m_dataPtr++;
if (m_dataPtr >= DSTAR_DATA_LENGTH_SAMPLES)
m_dataPtr = 0U;
m_pll += PLLINC;
if (m_pll >= PLLMAX) {
m_pll -= PLLMAX;
switch (m_rxState) {
case DSRXS_NONE:
processNone(bit);
break;
case DSRXS_HEADER:
processHeader(bit);
break;
case DSRXS_DATA:
processData(bit);
break;
default:
break;
}
}
m_bitPtr++;
if (m_bitPtr >= DSTAR_RADIO_SYMBOL_LENGTH)
m_bitPtr = 0U;
}
}
void CDStarRX::processNone(bool bit)
void CDStarRX::processNone(q15_t sample)
{
m_patternBuffer <<= 1;
if (bit)
m_patternBuffer |= 0x01U;
// Fuzzy matching of the frame sync sequence
if (countBits32((m_patternBuffer & FRAME_SYNC_MASK) ^ FRAME_SYNC_DATA) <= FRAME_SYNC_ERRS) {
DEBUG1("DStarRX: found frame sync in None");
bool ret = correlateFrameSync();
if (ret) {
m_countdown = 5U;
::memset(m_rxBuffer, 0x00U, DSTAR_FEC_SECTION_LENGTH_BYTES);
m_rxBufferBits = 0U;
m_headerBuffer[m_headerPtr] = sample;
m_headerPtr++;
m_rssiAccum = 0U;
m_rssiCount = 0U;
m_rxState = DSRXS_HEADER;
return;
}
// Exact matching of the data sync bit sequence
if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) == 0U) {
// Fuzzy matching of the data sync bit sequence
ret = correlateDataSync();
if (ret) {
DEBUG1("DStarRX: found data sync in None");
io.setDecode(true);
io.setADCDetection(true);
// Suppress RSSI on the dummy sync message
m_rssiAccum = 0U;
m_rssiCount = 0U;
::memcpy(m_rxBuffer, DSTAR_DATA_SYNC_BYTES, DSTAR_DATA_LENGTH_BYTES);
writeRSSIData(m_rxBuffer);
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
m_rxBufferBits = 0U;
m_dataBits = MAX_SYNC_BITS;
m_rxState = DSRXS_DATA;
return;
m_rxState = DSRXS_DATA;
}
}
void CDStarRX::processHeader(bool bit)
void CDStarRX::processHeader(q15_t sample)
{
m_patternBuffer <<= 1;
if (bit)
m_patternBuffer |= 0x01U;
if (m_countdown > 0U) {
correlateFrameSync();
m_countdown--;
}
WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit);
m_rxBufferBits++;
m_headerBuffer[m_headerPtr] = sample;
m_headerPtr++;
// A full FEC header
if (m_rxBufferBits == DSTAR_FEC_SECTION_LENGTH_BITS) {
// Process the scrambling, interleaving and FEC, then return if the chcksum was correct
unsigned char header[DSTAR_HEADER_LENGTH_BYTES];
bool ok = rxHeader(m_rxBuffer, header);
if (ok) {
if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH)) {
uint8_t buffer[DSTAR_FEC_SECTION_LENGTH_BYTES];
samplesToBits(m_headerBuffer, DSTAR_RADIO_SYMBOL_LENGTH, DSTAR_FEC_SECTION_LENGTH_SYMBOLS, buffer, DSTAR_FEC_SECTION_LENGTH_SAMPLES);
// Process the scrambling, interleaving and FEC, then return true if the chcksum was correct
uint8_t header[DSTAR_HEADER_LENGTH_BYTES];
bool ok = rxHeader(buffer, header);
if (!ok) {
// The checksum failed, return to looking for syncs
m_rxState = DSRXS_NONE;
m_maxFrameCorr = 0;
m_maxDataCorr = 0;
} else {
io.setDecode(true);
io.setADCDetection(true);
writeRSSIHeader(header);
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
m_rxBufferBits = 0U;
m_rxState = DSRXS_DATA;
m_dataBits = MAX_SYNC_BITS;
} else {
// The checksum failed, return to looking for syncs
m_rxState = DSRXS_NONE;
}
}
// Ready to start the first data section
if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + 2U * DSTAR_RADIO_SYMBOL_LENGTH)) {
m_frameCount = 0U;
m_dataPtr = 0U;
m_startPtr = 476U;
m_syncPtr = 471U;
m_maxSyncPtr = 472U;
m_minSyncPtr = 470U;
DEBUG5("DStarRX: calc start/sync/max/min", m_startPtr, m_syncPtr, m_maxSyncPtr, m_minSyncPtr);
m_rxState = DSRXS_DATA;
}
}
void CDStarRX::processData(bool bit)
void CDStarRX::processData()
{
m_patternBuffer <<= 1;
if (bit)
m_patternBuffer |= 0x01U;
WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit);
m_rxBufferBits++;
// Fuzzy matching of the end frame sequences
if (countBits32((m_patternBuffer & END_SYNC_MASK) ^ END_SYNC_DATA) <= END_SYNC_ERRS) {
if (countBits64((m_bitBuffer[m_bitPtr] & DSTAR_END_SYNC_MASK) ^ DSTAR_END_SYNC_DATA) <= END_SYNC_ERRS) {
DEBUG1("DStarRX: Found end sync in Data");
io.setDecode(false);
@@ -401,35 +406,24 @@ void CDStarRX::processData(bool bit)
serial.writeDStarEOT();
m_maxFrameCorr = 0;
m_maxDataCorr = 0;
m_rxState = DSRXS_NONE;
return;
}
// Fuzzy matching of the data sync bit sequence
bool syncSeen = false;
if (m_rxBufferBits >= (DSTAR_DATA_LENGTH_BITS - 3U)) {
if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) <= DATA_SYNC_ERRS) {
m_rxBufferBits = DSTAR_DATA_LENGTH_BITS;
m_dataBits = MAX_SYNC_BITS;
syncSeen = true;
}
if (m_minSyncPtr < m_maxSyncPtr) {
if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr)
correlateDataSync();
} else {
if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr)
correlateDataSync();
}
// Check to see if the sync is arriving late
if (m_rxBufferBits == DSTAR_DATA_LENGTH_BITS && !syncSeen) {
for (uint8_t i = 1U; i <= 3U; i++) {
uint32_t syncMask = DATA_SYNC_MASK >> i;
uint32_t syncData = DATA_SYNC_DATA >> i;
if (countBits32((m_patternBuffer & syncMask) ^ syncData) <= DATA_SYNC_ERRS) {
m_rxBufferBits -= i;
break;
}
}
}
m_dataBits--;
if (m_dataBits == 0U) {
// We've not seen a data sync for too long, signal RXLOST and change to RX_NONE
if (m_frameCount >= MAX_FRAMES) {
DEBUG1("DStarRX: data sync timed out, lost lock");
io.setDecode(false);
@@ -437,24 +431,35 @@ void CDStarRX::processData(bool bit)
serial.writeDStarLost();
m_maxFrameCorr = 0;
m_maxDataCorr = 0;
m_rxState = DSRXS_NONE;
return;
}
// Send a data frame to the host if the required number of bits have been received, or if a data sync has been seen
if (m_rxBufferBits == DSTAR_DATA_LENGTH_BITS) {
if (syncSeen) {
m_rxBuffer[9U] = DSTAR_DATA_SYNC_BYTES[9U];
m_rxBuffer[10U] = DSTAR_DATA_SYNC_BYTES[10U];
m_rxBuffer[11U] = DSTAR_DATA_SYNC_BYTES[11U];
writeRSSIData(m_rxBuffer);
} else {
serial.writeDStarData(m_rxBuffer, DSTAR_DATA_LENGTH_BYTES);
}
// Send a data frame to the host if the required number of bits have been received
if (m_dataPtr == m_maxSyncPtr) {
uint8_t buffer[DSTAR_DATA_LENGTH_BYTES + 2U];
samplesToBits(m_dataBuffer, m_startPtr, DSTAR_DATA_LENGTH_SYMBOLS, buffer, DSTAR_DATA_LENGTH_SAMPLES);
// Start the next frame
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
m_rxBufferBits = 0U;
if ((m_frameCount % 21U) == 0U) {
if (m_frameCount == 0U) {
buffer[9U] = DSTAR_DATA_SYNC_BYTES[9U];
buffer[10U] = DSTAR_DATA_SYNC_BYTES[10U];
buffer[11U] = DSTAR_DATA_SYNC_BYTES[11U];
DEBUG5("DStarRX: found start/sync/max/min", m_startPtr, m_syncPtr, m_maxSyncPtr, m_minSyncPtr);
}
writeRSSIData(buffer);
} else {
serial.writeDStarData(buffer, DSTAR_DATA_LENGTH_BYTES);
}
m_frameCount++;
m_maxFrameCorr = 0;
m_maxDataCorr = 0;
}
}
@@ -500,6 +505,105 @@ void CDStarRX::writeRSSIData(unsigned char* data)
m_rssiCount = 0U;
}
bool CDStarRX::correlateFrameSync()
{
if (countBits64((m_bitBuffer[m_bitPtr] & DSTAR_FRAME_SYNC_MASK) ^ DSTAR_FRAME_SYNC_DATA) <= FRAME_SYNC_ERRS) {
uint16_t ptr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_FRAME_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH;
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
q31_t corr = 0;
for (uint8_t i = 0U; i < DSTAR_FRAME_SYNC_LENGTH_SYMBOLS; i++) {
q15_t val = m_dataBuffer[ptr];
if (DSTAR_FRAME_SYNC_SYMBOLS[i])
corr -= val;
else
corr += val;
ptr += DSTAR_RADIO_SYMBOL_LENGTH;
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
}
if (corr > m_maxFrameCorr) {
m_maxFrameCorr = corr;
m_headerPtr = 0U;
return true;
}
}
return false;
}
bool CDStarRX::correlateDataSync()
{
uint8_t maxErrs = 0U;
if (m_rxState == DSRXS_DATA)
maxErrs = DATA_SYNC_ERRS;
if (countBits64((m_bitBuffer[m_bitPtr] & DSTAR_DATA_SYNC_MASK) ^ DSTAR_DATA_SYNC_DATA) <= maxErrs) {
uint16_t ptr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_DATA_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH;
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
q31_t corr = 0;
for (uint8_t i = 0U; i < DSTAR_DATA_SYNC_LENGTH_SYMBOLS; i++) {
q15_t val = m_dataBuffer[ptr];
if (DSTAR_DATA_SYNC_SYMBOLS[i])
corr -= val;
else
corr += val;
ptr += DSTAR_RADIO_SYMBOL_LENGTH;
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
}
if (corr > m_maxDataCorr) {
m_maxDataCorr = corr;
m_frameCount = 0U;
m_syncPtr = m_dataPtr;
m_startPtr = m_dataPtr + DSTAR_RADIO_SYMBOL_LENGTH;
if (m_startPtr >= DSTAR_DATA_LENGTH_SAMPLES)
m_startPtr -= DSTAR_DATA_LENGTH_SAMPLES;
m_maxSyncPtr = m_syncPtr + 1U;
if (m_maxSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES)
m_maxSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES;
m_minSyncPtr = m_syncPtr + DSTAR_DATA_LENGTH_SAMPLES - 1U;
if (m_minSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES)
m_minSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES;
return true;
}
}
return false;
}
void CDStarRX::samplesToBits(const q15_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit)
{
for (uint16_t i = 0U; i < count; i++) {
q15_t sample = inBuffer[start];
if (sample < 0)
WRITE_BIT2(outBuffer, i, true);
else
WRITE_BIT2(outBuffer, i, false);
start += DSTAR_RADIO_SYMBOL_LENGTH;
if (start >= limit)
start -= limit;
}
}
bool CDStarRX::rxHeader(uint8_t* in, uint8_t* out)
{
int i;
@@ -715,3 +819,6 @@ bool CDStarRX::checksum(const uint8_t* header) const
return crc8[0U] == header[DSTAR_HEADER_LENGTH_BYTES - 2U] && crc8[1U] == header[DSTAR_HEADER_LENGTH_BYTES - 1U];
}
#endif
+27 -11
View File
@@ -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
* it under the terms of the GNU General Public License as published by
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DSTAR)
#if !defined(DSTARRX_H)
#define DSTARRX_H
#include "Config.h"
#include "DStarDefines.h"
enum DSRX_STATE {
@@ -37,13 +40,21 @@ public:
void reset();
private:
uint32_t m_pll;
bool m_prev;
DSRX_STATE m_rxState;
uint32_t m_patternBuffer;
uint8_t m_rxBuffer[100U];
unsigned int m_rxBufferBits;
unsigned int m_dataBits;
uint64_t m_bitBuffer[DSTAR_RADIO_SYMBOL_LENGTH];
q15_t m_headerBuffer[DSTAR_FEC_SECTION_LENGTH_SAMPLES + 2U * DSTAR_RADIO_SYMBOL_LENGTH];
q15_t m_dataBuffer[DSTAR_DATA_LENGTH_SAMPLES];
uint16_t m_bitPtr;
uint16_t m_headerPtr;
uint16_t m_dataPtr;
uint16_t m_startPtr;
uint16_t m_syncPtr;
uint16_t m_minSyncPtr;
uint16_t m_maxSyncPtr;
q31_t m_maxFrameCorr;
q31_t m_maxDataCorr;
uint16_t m_frameCount;
uint8_t m_countdown;
unsigned int m_mar;
int m_pathMetric[4U];
unsigned int m_pathMemory0[42U];
@@ -54,9 +65,12 @@ private:
uint32_t m_rssiAccum;
uint16_t m_rssiCount;
void processNone(bool bit);
void processHeader(bool bit);
void processData(bool bit);
void processNone(q15_t sample);
void processHeader(q15_t sample);
void processData();
bool correlateFrameSync();
bool correlateDataSync();
void samplesToBits(const q15_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit);
void writeRSSIHeader(unsigned char* header);
void writeRSSIData(unsigned char* data);
bool rxHeader(uint8_t* in, uint8_t* out);
@@ -68,3 +82,5 @@ private:
#endif
#endif
+13 -8
View File
@@ -18,6 +18,9 @@
*/
#include "Config.h"
#if defined(MODE_DSTAR)
#include "Globals.h"
#include "DStarTX.h"
@@ -198,7 +201,7 @@ m_txDelay(60U) // 100ms
{
::memset(m_modState, 0x00U, 20U * sizeof(q15_t));
m_modFilter.L = DSTAR_RADIO_BIT_LENGTH;
m_modFilter.L = DSTAR_RADIO_SYMBOL_LENGTH;
m_modFilter.phaseLength = GAUSSIAN_0_35_FILTER_PHASE_LEN;
m_modFilter.pCoeffs = GAUSSIAN_0_35_FILTER;
m_modFilter.pState = m_modState;
@@ -216,8 +219,8 @@ void CDStarTX::process()
for (uint16_t i = 0U; i < m_txDelay; i++)
m_poBuffer[m_poLen++] = BIT_SYNC;
} else {
uint8_t dummy;
// Pop the type byte off
uint8_t dummy;
m_buffer.get(dummy);
uint8_t header[DSTAR_HEADER_LENGTH_BYTES];
@@ -255,8 +258,8 @@ void CDStarTX::process()
m_buffer.get(dummy);
for (uint8_t j = 0U; j < 3U; j++) {
for (uint8_t i = 0U; i < DSTAR_EOT_LENGTH_BYTES; i++)
m_poBuffer[m_poLen++] = DSTAR_EOT_BYTES[i];
for (uint8_t i = 0U; i < DSTAR_END_SYNC_LENGTH_BYTES; i++)
m_poBuffer[m_poLen++] = DSTAR_END_SYNC_BYTES[i];
}
m_poPtr = 0U;
@@ -265,11 +268,11 @@ void CDStarTX::process()
if (m_poLen > 0U) {
uint16_t space = io.getSpace();
while (space > (8U * DSTAR_RADIO_BIT_LENGTH)) {
while (space > (8U * DSTAR_RADIO_SYMBOL_LENGTH)) {
uint8_t c = m_poBuffer[m_poPtr++];
writeByte(c);
space -= 8U * DSTAR_RADIO_BIT_LENGTH;
space -= 8U * DSTAR_RADIO_SYMBOL_LENGTH;
if (m_poPtr >= m_poLen) {
m_poPtr = 0U;
@@ -415,7 +418,7 @@ void CDStarTX::txHeader(const uint8_t* in, uint8_t* out) const
void CDStarTX::writeByte(uint8_t c)
{
q15_t inBuffer[8U];
q15_t outBuffer[DSTAR_RADIO_BIT_LENGTH * 8U];
q15_t outBuffer[DSTAR_RADIO_SYMBOL_LENGTH * 8U];
uint8_t mask = 0x01U;
@@ -430,7 +433,7 @@ void CDStarTX::writeByte(uint8_t c)
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 8U);
io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U);
io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_SYMBOL_LENGTH * 8U);
}
void CDStarTX::setTXDelay(uint8_t delay)
@@ -446,3 +449,5 @@ uint8_t CDStarTX::getSpace() const
return m_buffer.getSpace() / (DSTAR_DATA_LENGTH_BYTES + 1U);
}
#endif
+6 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_DSTAR)
#if !defined(DSTARTX_H)
#define DSTARTX_H
#include "Config.h"
#include "RingBuffer.h"
class CDStarTX {
@@ -52,3 +54,5 @@ private:
#endif
#endif
+2 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#define DEBUG3(a,b,c) serial.writeDebug((a),(b),(c))
#define DEBUG4(a,b,c,d) serial.writeDebug((a),(b),(c),(d))
#define DEBUG5(a,b,c,d,e) serial.writeDebug((a),(b),(c),(d),(e))
#define DEBUG_DUMP(a,b) serial.writeDebugDump((a),(b))
#endif
+296 -40
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2021,2023 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
@@ -17,21 +17,30 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#include "Globals.h"
#include "FM.h"
const uint16_t FM_TX_BLOCK_SIZE = 100U;
const uint16_t FM_SERIAL_BLOCK_SIZE = 84U;//this is the number of sample pairs to send over serial. One sample pair is 3bytes.
const uint16_t FM_SERIAL_BLOCK_SIZE = 80U;//this is the number of sample pairs to send over serial. One sample pair is 3bytes.
//three times this value shall never exceed 252
const uint16_t FM_SERIAL_BLOCK_SIZE_BYTES = FM_SERIAL_BLOCK_SIZE * 3U;
/*
* 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
*/
const uint8_t FS_LISTENING = 0U;
const uint8_t FS_KERCHUNK_RF = 1U;
const uint8_t FS_RELAYING_RF = 2U;
const uint8_t FS_RELAYING_WAIT_RF = 3U;
const uint8_t FS_TIMEOUT_RF = 4U;
const uint8_t FS_TIMEOUT_WAIT_RF = 5U;
const uint8_t FS_KERCHUNK_EXT = 6U;
const uint8_t FS_RELAYING_EXT = 7U;
const uint8_t FS_RELAYING_WAIT_EXT = 8U;
const uint8_t FS_TIMEOUT_EXT = 9U;
const uint8_t FS_TIMEOUT_WAIT_EXT = 10U;
const uint8_t FS_HANG = 11U;
CFM::CFM() :
m_callsign(),
@@ -52,7 +61,6 @@ m_kerchunkTimer(),
m_ackMinTimer(),
m_ackDelayTimer(),
m_hangTimer(),
m_statusTimer(),
m_reverseTimer(),
m_needReverse(false),
m_filterStage1( 724, 1448, 724, 32768, -37895, 21352),//3rd order Cheby Filter 300 to 2700Hz, 0.2dB passband ripple, sampling rate 24kHz
@@ -60,6 +68,7 @@ m_filterStage2(32768, 0,-32768, 32768, -50339, 19052),
m_filterStage3(32768, -65536, 32768, 32768, -64075, 31460),
m_blanking(),
m_accessMode(1U),
m_linkMode(false),
m_cosInvert(false),
m_noiseSquelch(false),
m_rfAudioBoost(1U),
@@ -69,15 +78,26 @@ m_extEnabled(false),
m_rxLevel(1),
m_inputRFRB(2401U), // 100ms of audio + 1 sample
m_outputRFRB(2400U), // 100ms of audio
m_inputExtRB()
m_inputExtRB(),
m_rfSignal(false),
m_extSignal(false),
m_rssiAccum(0U),
m_rssiCount(0U)
{
m_statusTimer.setTimeout(1U, 0U);
m_reverseTimer.setTimeout(0U, 150U);
insertDelay(100U);
}
void CFM::samples(bool cos, q15_t* samples, uint8_t length)
void CFM::samples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length)
{
if (m_linkMode)
linkSamples(cos, samples, length);
else
repeaterSamples(cos, samples, rssi, length);
}
void CFM::repeaterSamples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length)
{
if (m_cosInvert)
cos = !cos;
@@ -86,6 +106,11 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
uint8_t i = 0U;
for (; i < length; i++) {
if (m_state == FS_RELAYING_RF) {
m_rssiAccum += rssi[i];
m_rssiCount++;
}
// ARMv7-M has hardware integer division
q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel);
@@ -216,6 +241,108 @@ void CFM::samples(bool cos, q15_t* samples, uint8_t length)
}
}
void CFM::linkSamples(bool cos, q15_t* samples, uint8_t length)
{
if (m_cosInvert)
cos = !cos;
clock(length);
uint8_t i = 0U;
for (; i < length; i++) {
// ARMv7-M has hardware integer division
q15_t currentRFSample = q15_t((q31_t(samples[i]) << 8) / m_rxLevel);
if (m_noiseSquelch)
cos = m_squelch.process(currentRFSample);
q15_t currentExtSample;
bool inputExt = m_inputExtRB.getSample(currentExtSample);//always consume the external input data so it does not overflow
inputExt = inputExt && m_extEnabled;
switch (m_accessMode) {
case 0U:
if (!inputExt && !cos && m_modemState != STATE_FM)
continue;
else
stateMachine(cos, inputExt);
break;
case 1U: {
bool ctcss = m_ctcssRX.process(currentRFSample);
// Delay the audio by 100ms to better match the CTCSS detector output
m_inputRFRB.put(currentRFSample);
m_inputRFRB.get(currentRFSample);
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
// No CTCSS detected, just carry on
continue;
} else if ((inputExt || ctcss) && m_modemState != STATE_FM) {
// We had CTCSS or external input
stateMachine(ctcss, inputExt);
if (m_state == FS_LISTENING)
continue;
} else {
stateMachine(ctcss, inputExt);
}
}
break;
case 2U: {
bool ctcss = m_ctcssRX.process(currentRFSample);
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
// No CTCSS detected, just carry on
continue;
} else if ((inputExt || (ctcss && cos)) && m_modemState != STATE_FM) {
// We had CTCSS or external input
stateMachine(ctcss && cos, inputExt);
if (m_state == FS_LISTENING)
continue;
} else {
stateMachine(ctcss && cos, inputExt);
}
}
break;
default: {
bool ctcss = m_ctcssRX.process(currentRFSample);
if (!inputExt && !ctcss && m_modemState != STATE_FM) {
// No CTCSS detected, just carry on
continue;
} else if ((inputExt || (ctcss && cos)) && m_modemState != STATE_FM) {
// We had CTCSS or external input
stateMachine(ctcss && cos, inputExt);
if (m_state == FS_LISTENING)
continue;
} else {
stateMachine(cos, inputExt);
}
}
break;
}
if (m_modemState != STATE_FM)
continue;
if (m_rfSignal && m_extEnabled) {
q15_t currentSample = m_blanking.process(currentRFSample);
m_downSampler.addSample(currentSample);
}
if (!m_extSignal)
continue;
q15_t currentSample = currentExtSample * m_extAudioBoost;
currentSample = m_filterStage3.filter(m_filterStage2.filter(m_filterStage1.filter(currentSample)));
currentSample += m_ctcssTX.getAudio(m_reverseTimer.isRunning());
m_outputRFRB.put(currentSample);
}
}
void CFM::process()
{
uint16_t space = io.getSpace();
@@ -268,7 +395,6 @@ void CFM::reset()
m_ackMinTimer.stop();
m_ackDelayTimer.stop();
m_hangTimer.stop();
m_statusTimer.stop();
m_reverseTimer.stop();
m_ctcssRX.reset();
@@ -284,6 +410,8 @@ void CFM::reset()
m_squelch.reset();
m_needReverse = false;
m_rfSignal = false;
m_extSignal = false;
}
uint8_t CFM::setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch)
@@ -314,9 +442,10 @@ uint8_t CFM::setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_
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, uint8_t accessMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel)
uint8_t CFM::setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool linkMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel)
{
m_accessMode = accessMode;
m_linkMode = linkMode;
m_cosInvert = cosInvert;
m_noiseSquelch = noiseSquelch;
@@ -353,10 +482,14 @@ uint8_t CFM::setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t
void CFM::stateMachine(bool validRFSignal, bool validExtSignal)
{
if (m_duplex)
duplexStateMachine(validRFSignal, validExtSignal);
else
simplexStateMachine(validRFSignal, validExtSignal);
if (m_linkMode) {
linkStateMachine(validRFSignal, validExtSignal);
} else {
if (m_duplex)
duplexStateMachine(validRFSignal, validExtSignal);
else
simplexStateMachine(validRFSignal, validExtSignal);
}
}
void CFM::simplexStateMachine(bool validRFSignal, bool validExtSignal)
@@ -467,13 +600,7 @@ void CFM::clock(uint8_t length)
m_ackMinTimer.clock(length);
m_ackDelayTimer.clock(length);
m_hangTimer.clock(length);
m_statusTimer.clock(length);
m_reverseTimer.clock(length);
if (m_statusTimer.isRunning() && m_statusTimer.hasExpired()) {
serial.writeFMStatus(m_state);
m_statusTimer.start();
}
}
void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
@@ -482,12 +609,19 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
if (m_kerchunkTimer.getTimeout() > 0U) {
DEBUG1("State to KERCHUNK_RF");
m_state = FS_KERCHUNK_RF;
serial.writeFMStatus(m_state);
m_kerchunkTimer.start();
if (m_callsignAtStart && !m_callsignAtLatch)
sendCallsign();
} else {
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
m_rssiAccum = 0U;
m_rssiCount = 0U;
if (m_callsignAtStart)
sendCallsign();
}
@@ -502,20 +636,21 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
io.setDecode(true);
io.setADCDetection(true);
m_statusTimer.start();
serial.writeFMStatus(m_state);
}
} else if (validExtSignal) {
if (m_kerchunkTimer.getTimeout() > 0U) {
DEBUG1("State to KERCHUNK_EXT");
m_state = FS_KERCHUNK_EXT;
serial.writeFMStatus(m_state);
m_kerchunkTimer.start();
if (m_callsignAtStart && !m_callsignAtLatch)
sendCallsign();
} else {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
if (m_callsignAtStart)
sendCallsign();
}
@@ -527,9 +662,6 @@ void CFM::listeningStateDuplex(bool validRFSignal, bool validExtSignal)
m_callsignTimer.start();
m_reverseTimer.stop();
m_statusTimer.start();
serial.writeFMStatus(m_state);
}
}
}
@@ -539,26 +671,22 @@ void CFM::listeningStateSimplex(bool validRFSignal, bool validExtSignal)
if (validRFSignal) {
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
io.setDecode(true);
io.setADCDetection(true);
m_timeoutTimer.start();
m_reverseTimer.stop();
m_statusTimer.start();
serial.writeFMStatus(m_state);
} else if (validExtSignal) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
insertSilence(50U);
m_timeoutTimer.start();
m_reverseTimer.stop();
m_statusTimer.start();
serial.writeFMStatus(m_state);
}
}
@@ -568,6 +696,11 @@ void CFM::kerchunkRFStateDuplex(bool validSignal)
if (m_kerchunkTimer.hasExpired()) {
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
m_rssiAccum = 0U;
m_rssiCount = 0U;
m_kerchunkTimer.stop();
if (m_callsignAtStart && m_callsignAtLatch) {
sendCallsign();
@@ -580,11 +713,12 @@ void CFM::kerchunkRFStateDuplex(bool validSignal)
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_kerchunkTimer.stop();
m_timeoutTimer.stop();
m_ackMinTimer.stop();
m_callsignTimer.stop();
m_statusTimer.stop();
m_needReverse = true;
if (m_extEnabled)
serial.writeFMEOT();
@@ -594,9 +728,21 @@ void CFM::kerchunkRFStateDuplex(bool validSignal)
void CFM::relayingRFStateDuplex(bool validSignal)
{
if (validSignal) {
#if defined(SEND_RSSI_DATA)
if (m_rssiCount >= 24000U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
serial.writeFMRSSI(rssi);
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
#endif
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
DEBUG1("State to TIMEOUT_RF");
m_state = FS_TIMEOUT_RF;
serial.writeFMStatus(m_state);
m_ackMinTimer.stop();
m_timeoutTimer.stop();
m_timeoutTone.start();
@@ -610,6 +756,8 @@ void CFM::relayingRFStateDuplex(bool validSignal)
DEBUG1("State to RELAYING_WAIT_RF");
m_state = FS_RELAYING_WAIT_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
if (m_extEnabled)
@@ -628,6 +776,7 @@ void CFM::relayingRFStateSimplex(bool validSignal)
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
DEBUG1("State to TIMEOUT_RF");
m_state = FS_TIMEOUT_RF;
serial.writeFMStatus(m_state);
m_timeoutTimer.stop();
@@ -640,6 +789,8 @@ void CFM::relayingRFStateSimplex(bool validSignal)
DEBUG1("State to RELAYING_WAIT_RF");
m_state = FS_RELAYING_WAIT_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
if (m_extEnabled)
@@ -655,11 +806,17 @@ void CFM::relayingRFWaitStateDuplex(bool validSignal)
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
m_rssiAccum = 0U;
m_rssiCount = 0U;
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to HANG");
m_state = FS_HANG;
serial.writeFMStatus(m_state);
if (m_ackMinTimer.isRunning()) {
if (m_ackMinTimer.hasExpired()) {
@@ -693,11 +850,15 @@ void CFM::relayingRFWaitStateSimplex(bool validSignal)
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
m_timeoutTimer.stop();
}
@@ -710,6 +871,8 @@ void CFM::kerchunkExtStateDuplex(bool validSignal)
if (m_kerchunkTimer.hasExpired()) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
m_kerchunkTimer.stop();
if (m_callsignAtStart && m_callsignAtLatch) {
sendCallsign();
@@ -719,11 +882,12 @@ void CFM::kerchunkExtStateDuplex(bool validSignal)
} else {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_kerchunkTimer.stop();
m_timeoutTimer.stop();
m_ackMinTimer.stop();
m_callsignTimer.stop();
m_statusTimer.stop();
m_needReverse = true;
}
}
@@ -734,6 +898,8 @@ void CFM::relayingExtStateDuplex(bool validSignal)
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
DEBUG1("State to TIMEOUT_EXT");
m_state = FS_TIMEOUT_EXT;
serial.writeFMStatus(m_state);
m_ackMinTimer.stop();
m_timeoutTimer.stop();
m_timeoutTone.start();
@@ -741,6 +907,7 @@ void CFM::relayingExtStateDuplex(bool validSignal)
} else {
DEBUG1("State to RELAYING_WAIT_EXT");
m_state = FS_RELAYING_WAIT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
}
@@ -756,12 +923,14 @@ void CFM::relayingExtStateSimplex(bool validSignal)
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
DEBUG1("State to TIMEOUT_EXT");
m_state = FS_TIMEOUT_EXT;
serial.writeFMStatus(m_state);
m_timeoutTimer.stop();
}
} else {
DEBUG1("State to RELAYING_WAIT_EXT");
m_state = FS_RELAYING_WAIT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
}
}
@@ -771,11 +940,13 @@ void CFM::relayingExtWaitStateDuplex(bool validSignal)
if (validSignal) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to HANG");
m_state = FS_HANG;
serial.writeFMStatus(m_state);
if (m_ackMinTimer.isRunning()) {
if (m_ackMinTimer.hasExpired()) {
@@ -806,11 +977,14 @@ void CFM::relayingExtWaitStateSimplex(bool validSignal)
if (validSignal) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
m_timeoutTimer.stop();
m_needReverse = true;
@@ -826,6 +1000,11 @@ void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal)
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
m_rssiAccum = 0U;
m_rssiCount = 0U;
DEBUG1("Stop ack");
m_rfAck.stop();
m_extAck.stop();
@@ -833,6 +1012,8 @@ void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal)
} else if (validExtSignal) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
DEBUG1("Stop ack");
m_rfAck.stop();
m_extAck.stop();
@@ -841,8 +1022,9 @@ void CFM::hangStateDuplex(bool validRFSignal, bool validExtSignal)
if (m_hangTimer.isRunning() && m_hangTimer.hasExpired()) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_hangTimer.stop();
m_statusTimer.stop();
if (m_callsignAtEnd)
sendCallsign();
@@ -866,6 +1048,7 @@ void CFM::timeoutRFStateDuplex(bool validSignal)
DEBUG1("State to TIMEOUT_WAIT_RF");
m_state = FS_TIMEOUT_WAIT_RF;
serial.writeFMStatus(m_state);
if (m_callsignAtEnd)
sendCallsign();
@@ -887,6 +1070,7 @@ void CFM::timeoutRFStateSimplex(bool validSignal)
DEBUG1("State to TIMEOUT_WAIT_RF");
m_state = FS_TIMEOUT_WAIT_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
}
@@ -900,11 +1084,14 @@ void CFM::timeoutRFWaitStateDuplex(bool validSignal)
DEBUG1("State to TIMEOUT_RF");
m_state = FS_TIMEOUT_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to HANG");
m_state = FS_HANG;
serial.writeFMStatus(m_state);
m_timeoutTone.stop();
DEBUG1("Send RF ack");
m_rfAck.start();
@@ -929,11 +1116,14 @@ void CFM::timeoutRFWaitStateSimplex(bool validSignal)
DEBUG1("State to TIMEOUT_RF");
m_state = FS_TIMEOUT_RF;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
m_timeoutTimer.stop();
}
@@ -945,6 +1135,7 @@ void CFM::timeoutExtStateDuplex(bool validSignal)
if (!validSignal) {
DEBUG1("State to TIMEOUT_WAIT_EXT");
m_state = FS_TIMEOUT_WAIT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
}
@@ -959,6 +1150,7 @@ void CFM::timeoutExtStateSimplex(bool validSignal)
if (!validSignal) {
DEBUG1("State to TIMEOUT_WAIT_EXT");
m_state = FS_TIMEOUT_WAIT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.start();
}
}
@@ -968,11 +1160,14 @@ void CFM::timeoutExtWaitStateDuplex(bool validSignal)
if (validSignal) {
DEBUG1("State to TIMEOUT_EXT");
m_state = FS_TIMEOUT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to HANG");
m_state = FS_HANG;
serial.writeFMStatus(m_state);
m_timeoutTone.stop();
DEBUG1("Send Ext ack");
m_extAck.start();
@@ -994,11 +1189,14 @@ void CFM::timeoutExtWaitStateSimplex(bool validSignal)
if (validSignal) {
DEBUG1("State to TIMEOUT_EXT");
m_state = FS_TIMEOUT_EXT;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
} else {
if (m_ackDelayTimer.isRunning() && m_ackDelayTimer.hasExpired()) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
m_ackDelayTimer.stop();
m_timeoutTimer.stop();
m_needReverse = true;
@@ -1006,6 +1204,61 @@ void CFM::timeoutExtWaitStateSimplex(bool validSignal)
}
}
void CFM::linkStateMachine(bool validRFSignal, bool validExtSignal)
{
if (validRFSignal && !m_rfSignal) {
io.setDecode(true);
io.setADCDetection(true);
if (!m_extSignal) {
DEBUG1("State to RELAYING_RF");
m_state = FS_RELAYING_RF;
serial.writeFMStatus(m_state);
}
m_rfSignal = true;
}
if (validExtSignal && !m_extSignal) {
if (!m_rfSignal) {
DEBUG1("State to RELAYING_EXT");
m_state = FS_RELAYING_EXT;
serial.writeFMStatus(m_state);
}
insertSilence(50U);
m_extSignal = true;
}
if (!validRFSignal && m_rfSignal) {
io.setDecode(false);
io.setADCDetection(false);
if (!m_extSignal) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
}
m_rfSignal = false;
if (m_extEnabled)
serial.writeFMEOT();
}
if (!validExtSignal && m_extSignal) {
if (!m_rfSignal) {
DEBUG1("State to LISTENING");
m_state = FS_LISTENING;
serial.writeFMStatus(m_state);
}
m_needReverse = true;
m_extSignal = false;
}
}
void CFM::sendCallsign()
{
if (m_holdoffTimer.isRunning()) {
@@ -1054,3 +1307,6 @@ void CFM::insertSilence(uint16_t ms)
for (uint32_t i = 0U; i < nSamples; i++)
m_outputRFRB.put(0);
}
#endif
+21 -22
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 by Jonathan Naylor G4KLX
* Copyright (C) 2020,2021,2023 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
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FM_H)
#define FM_H
#include "Config.h"
#include "FMBlanking.h"
#include "FMCTCSSRX.h"
#include "FMCTCSSTX.h"
@@ -33,27 +35,12 @@
#include "FMUpSampler.h"
#include "FMNoiseSquelch.h"
enum FM_STATE {
FS_LISTENING,
FS_KERCHUNK_RF,
FS_RELAYING_RF,
FS_RELAYING_WAIT_RF,
FS_TIMEOUT_RF,
FS_TIMEOUT_WAIT_RF,
FS_KERCHUNK_EXT,
FS_RELAYING_EXT,
FS_RELAYING_WAIT_EXT,
FS_TIMEOUT_EXT,
FS_TIMEOUT_WAIT_EXT,
FS_HANG
};
class CFM {
public:
CFM();
void samples(bool cos, q15_t* samples, uint8_t length);
void samples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length);
void process();
@@ -61,7 +48,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 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, uint8_t accessMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel);
uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool linkMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel);
uint8_t setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t frequency, uint8_t level);
uint8_t getSpace() const;
@@ -76,7 +63,7 @@ private:
CFMCTCSSTX m_ctcssTX;
CFMNoiseSquelch m_squelch;
CFMTimeout m_timeoutTone;
FM_STATE m_state;
uint8_t m_state;
bool m_callsignAtStart;
bool m_callsignAtEnd;
bool m_callsignAtLatch;
@@ -87,7 +74,6 @@ private:
CFMTimer m_ackMinTimer;
CFMTimer m_ackDelayTimer;
CFMTimer m_hangTimer;
CFMTimer m_statusTimer;
CFMTimer m_reverseTimer;
bool m_needReverse;
CFMDirectFormI m_filterStage1;
@@ -95,6 +81,7 @@ private:
CFMDirectFormI m_filterStage3;
CFMBlanking m_blanking;
uint8_t m_accessMode;
bool m_linkMode;
bool m_cosInvert;
bool m_noiseSquelch;
q15_t m_rfAudioBoost;
@@ -105,9 +92,16 @@ private:
CRingBuffer<q15_t> m_inputRFRB;
CRingBuffer<q15_t> m_outputRFRB;
CFMUpSampler m_inputExtRB;
bool m_rfSignal;
bool m_extSignal;
uint32_t m_rssiAccum;
uint16_t m_rssiCount;
void stateMachine(bool validRFSignal, bool validExtSignal);
void repeaterSamples(bool cos, q15_t* samples, const uint16_t* rssi, uint8_t length);
void linkSamples(bool cos, q15_t* samples, uint8_t length);
void duplexStateMachine(bool validRFSignal, bool validExtSignal);
void listeningStateDuplex(bool validRFSignal, bool validExtSignal);
void kerchunkRFStateDuplex(bool validSignal);
@@ -133,6 +127,8 @@ private:
void timeoutExtStateSimplex(bool validSignal);
void timeoutExtWaitStateSimplex(bool validSignal);
void linkStateMachine(bool validRFSignal, bool validExtSignal);
void clock(uint8_t length);
void sendCallsign();
@@ -143,3 +139,6 @@ private:
};
#endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#include "Globals.h"
#include "FMBlanking.h"
@@ -80,3 +83,6 @@ q15_t CFMBlanking::process(q15_t sample)
return sample;
}
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMBlanking_H)
#define FMBlanking_H
#include "Config.h"
class CFMBlanking {
public:
CFMBlanking();
@@ -39,3 +41,6 @@ private:
};
#endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#include "Globals.h"
#include "FMCTCSSRX.h"
@@ -173,3 +176,6 @@ void CFMCTCSSRX::reset()
m_state = false;
m_count = 0U;
}
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMCTCSSRX_H)
#define FMCTCSSRX_H
#include "Config.h"
class CFMCTCSSRX {
public:
CFMCTCSSRX();
@@ -42,3 +44,6 @@ private:
};
#endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#include "Globals.h"
#include "FMCTCSSTX.h"
@@ -126,3 +129,6 @@ q15_t CFMCTCSSTX::getAudio(bool reverse)
else
return sample;
}
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMCTCSSTX_H)
#define FMCTCSSTX_H
#include "Config.h"
class CFMCTCSSTX {
public:
CFMCTCSSTX();
@@ -36,3 +38,6 @@ private:
};
#endif
#endif
+14 -12
View File
@@ -29,6 +29,10 @@ THE SOFTWARE.
// based on https://raw.githubusercontent.com/berndporr/iir_fixed_point/master/DirectFormI.h
#include "Config.h"
#if defined(MODE_FM)
#include <cstdint>
#ifndef DIRECTFORMI_H_
@@ -38,8 +42,7 @@ class CFMDirectFormI
public:
// convenience function which takes the a0 argument but ignores it!
CFMDirectFormI(const q31_t b0, const q31_t b1, const q31_t b2,
const q31_t, const q31_t a1, const q31_t a2)
CFMDirectFormI(const q31_t b0, const q31_t b1, const q31_t b2, const q31_t, const q31_t a1, const q31_t a2)
{
// FIR coefficients
c_b0 = b0;
@@ -53,21 +56,21 @@ public:
CFMDirectFormI(const CFMDirectFormI &my)
{
// delay line
// delay line
m_x2 = my.m_x2; // x[n-2]
m_y2 = my.m_y2; // y[n-2]
m_x1 = my.m_x1; // x[n-1]
m_y1 = my.m_y1; // y[n-1]
// coefficients
// coefficients
c_b0 = my.c_b0;
c_b1 = my.c_b1;
c_b2 = my.c_b2; // FIR
c_a1 = my.c_a1;
c_a2 = my.c_a2; // IIR
}
}
void reset ()
void reset()
{
m_x1 = 0;
m_x2 = 0;
@@ -79,11 +82,7 @@ public:
inline q15_t filter(const q15_t in)
{
// calculate the output
register q31_t out_upscaled = c_b0 * in
+ c_b1 * m_x1
+ c_b2 * m_x2
- c_a1 * m_y1
- c_a2 * m_y2;
q31_t out_upscaled = c_b0 * in + c_b1 * m_x1 + c_b2 * m_x2 - c_a1 * m_y1 - c_a2 * m_y2;
q15_t out = __SSAT(out_upscaled >> 15, 15);
@@ -108,4 +107,7 @@ private:
q31_t c_a1,c_a2; // IIR
};
#endif /* DIRECTFORMI_H */
#endif /* DIRECTFORMI_H */
#endif
+6
View File
@@ -18,6 +18,9 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#include "FMDownSampler.h"
CFMDownSampler::CFMDownSampler(uint16_t length) :
@@ -72,3 +75,6 @@ void CFMDownSampler::reset()
{
m_sampleIndex = 0U;
}
#endif
+6 -1
View File
@@ -17,10 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMDOWNSAMPLER_H)
#define FMDOWNSAMPLER_H
#include "Config.h"
#include "RingBuffer.h"
#include "FMSamplePairPack.h"
@@ -45,3 +48,5 @@ private:
#endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#include "Globals.h"
#include "FMKeyer.h"
@@ -214,3 +217,6 @@ bool CFMKeyer::isRunning() const
{
return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U;
}
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMKeyer_H)
#define FMKeyer_H
#include "Config.h"
class CFMKeyer {
public:
CFMKeyer();
@@ -52,3 +54,6 @@ private:
};
#endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#include "Globals.h"
#include "FMNoiseSquelch.h"
@@ -125,3 +128,6 @@ void CFMNoiseSquelch::reset()
m_state = false;
m_count = 0U;
}
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMNOISESQUELCH_H)
#define FMNOISESQUELCH_H
#include "Config.h"
class CFMNoiseSquelch {
public:
CFMNoiseSquelch();
@@ -43,3 +45,6 @@ private:
};
#endif
#endif
+8 -1
View File
@@ -17,6 +17,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(TSAMPLEPACK_H)
#define TSAMPLEPACK_H
@@ -26,4 +30,7 @@ struct TSamplePairPack {
uint8_t byte2;
};
#endif
#endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#include "Globals.h"
#include "FMTimeout.h"
@@ -72,3 +75,6 @@ void CFMTimeout::stop()
{
m_running = false;
}
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMTimeout_H)
#define FMTimeout_H
#include "Config.h"
class CFMTimeout {
public:
CFMTimeout();
@@ -40,3 +42,6 @@ private:
};
#endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#include "Globals.h"
#include "FMTimer.h"
@@ -68,3 +71,6 @@ bool CFMTimer::hasExpired() const
return false;
}
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMTimer_H)
#define FMTimer_H
#include "Config.h"
class CFMTimer {
public:
CFMTimer();
@@ -45,3 +47,6 @@ private:
};
#endif
#endif
+8 -1
View File
@@ -17,6 +17,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_FM)
#include "FMUpSampler.h"
const uint32_t FM_UPSAMPLE_MASK = 0x00000FFFU;
@@ -94,4 +98,7 @@ uint16_t CFMUpSampler::getSpace() const
{
//return available space in bytes
return m_samples.getSpace() * sizeof(TSamplePairPack);
}
}
#endif
+8 -2
View File
@@ -18,10 +18,13 @@
*/
#include "Config.h"
#if defined(MODE_FM)
#if !defined(FMUPSAMPLER_H)
#define FMUPSAMPLER_H
#include "Config.h"
#include "RingBuffer.h"
#include "FMSamplePairPack.h"
@@ -45,4 +48,7 @@ private:
bool m_running;
};
#endif
#endif
#endif
+48 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,15 +23,12 @@
#include "stm32f4xx.h"
#elif defined(STM32F7XX)
#include "stm32f7xx.h"
#elif defined(STM32F105xC)
#include "stm32f1xx.h"
#include "STM32Utils.h"
#else
#include <Arduino.h>
#undef PI //Undefine PI to get rid of annoying warning as it is also defined in arm_math.h.
#endif
#if defined(__SAM3X8E__) || defined(STM32F105xC)
#if defined(__SAM3X8E__)
#define ARM_MATH_CM3
#elif defined(STM32F7XX)
#define ARM_MATH_CM7
@@ -51,6 +48,7 @@ enum MMDVM_STATE {
STATE_P25 = 4,
STATE_NXDN = 5,
STATE_POCSAG = 6,
STATE_M17 = 7,
STATE_FM = 10,
STATE_AX25 = 11,
@@ -71,7 +69,8 @@ enum MMDVM_STATE {
STATE_FMCAL15K = 104,
STATE_FMCAL20K = 105,
STATE_FMCAL25K = 106,
STATE_FMCAL30K = 107
STATE_FMCAL30K = 107,
STATE_M17CAL = 108
};
#include "SerialPort.h"
@@ -86,6 +85,8 @@ enum MMDVM_STATE {
#include "YSFTX.h"
#include "P25RX.h"
#include "P25TX.h"
#include "M17RX.h"
#include "M17TX.h"
#include "NXDNRX.h"
#include "NXDNTX.h"
#include "POCSAGTX.h"
@@ -100,6 +101,7 @@ enum MMDVM_STATE {
#include "CWIdTX.h"
#include "AX25RX.h"
#include "AX25TX.h"
#include "CalM17.h"
#include "Debug.h"
#include "IO.h"
#include "FM.h"
@@ -113,7 +115,7 @@ const uint16_t RX_BLOCK_SIZE = 2U;
const uint16_t TX_RINGBUFFER_SIZE = 500U;
const uint16_t RX_RINGBUFFER_SIZE = 600U;
#if defined(STM32F105xC) || defined(__MK20DX256__)
#if defined(__MK20DX256__)
const uint16_t TX_BUFFER_LEN = 2000U;
#else
const uint16_t TX_BUFFER_LEN = 4000U;
@@ -127,6 +129,7 @@ extern bool m_ysfEnable;
extern bool m_p25Enable;
extern bool m_nxdnEnable;
extern bool m_pocsagEnable;
extern bool m_m17Enable;
extern bool m_fmEnable;
extern bool m_ax25Enable;
@@ -138,9 +141,15 @@ extern bool m_dcd;
extern CSerialPort serial;
extern CIO io;
#if defined(MODE_DSTAR)
extern CDStarRX dstarRX;
extern CDStarTX dstarTX;
extern CCalDStarRX calDStarRX;
extern CCalDStarTX calDStarTX;
#endif
#if defined(MODE_DMR)
extern CDMRIdleRX dmrIdleRX;
extern CDMRRX dmrRX;
extern CDMRTX dmrTX;
@@ -148,29 +157,51 @@ extern CDMRTX dmrTX;
extern CDMRDMORX dmrDMORX;
extern CDMRDMOTX dmrDMOTX;
extern CCalDMR calDMR;
#endif
#if defined(MODE_YSF)
extern CYSFRX ysfRX;
extern CYSFTX ysfTX;
#endif
#if defined(MODE_P25)
extern CP25RX p25RX;
extern CP25TX p25TX;
extern CCalP25 calP25;
#endif
#if defined(MODE_NXDN)
extern CNXDNRX nxdnRX;
extern CNXDNTX nxdnTX;
extern CPOCSAGTX pocsagTX;
extern CCalNXDN calNXDN;
#endif
extern CFM fm;
#if defined(MODE_POCSAG)
extern CPOCSAGTX pocsagTX;
extern CCalPOCSAG calPOCSAG;
#endif
#if defined(MODE_M17)
extern CM17RX m17RX;
extern CM17TX m17TX;
extern CCalM17 calM17;
#endif
#if defined(MODE_FM)
extern CFM fm;
extern CCalFM calFM;
#endif
#if defined(MODE_AX25)
extern CAX25RX ax25RX;
extern CAX25TX ax25TX;
#endif
extern CCalDStarRX calDStarRX;
extern CCalDStarTX calDStarTX;
extern CCalDMR calDMR;
extern CCalFM calFM;
extern CCalP25 calP25;
extern CCalNXDN calNXDN;
extern CCalPOCSAG calPOCSAG;
extern CCalRSSI calRSSI;
extern CCalRSSI calRSSI;
extern CCWIdTX cwIdTX;
+267 -66
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2018,2020,2021,2023 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML
*
@@ -22,16 +22,34 @@
#include "Globals.h"
#include "IO.h"
#if defined(USE_DCBLOCKER)
// Generated using [b, a] = butter(1, 0.001) in MATLAB
static q31_t DC_FILTER[] = {3367972, 0, 3367972, 0, 2140747704, 0}; // {b0, 0, b1, b2, -a1, -a2}
const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage
#endif
#if defined(MODE_DMR) || defined(MODE_YSF)
// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995,
11237, 14331, 15464, 14331, 11237, 6995, 2667, -770, -2706, -3040, -2144, -675, 683, 1450, 1472, 909, 112,
-553, -847, -731, -340, 104, 401, 0};
const uint16_t RRC_0_2_FILTER_LEN = 42U;
#endif
#if defined(MODE_M17)
// Generated using rcosdesign(0.5, 8, 5, 'sqrt') in MATLAB
static q15_t RRC_0_5_FILTER[] = {-147, -88, 72, 220, 223, 46, -197, -285, -79, 334, 623, 390, -498, -1691, -2363, -1556, 1284, 5872, 11033,
15109, 16656, 15109, 11033, 5872, 1284, -1556, -2363, -1691, -498, 390, 623, 334, -79, -285, -197, 46, 223,
220, 72, -88, -147, 0};
const uint16_t RRC_0_5_FILTER_LEN = 42U;
#endif
#if defined(MODE_NXDN)
#if defined(USE_NXDN_BOXCAR)
// One symbol boxcar filter
static q15_t BOXCAR10_FILTER[] = {6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000};
const uint16_t BOXCAR10_FILTER_LEN = 10U;
#else
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
static q15_t NXDN_0_2_FILTER[] = {284, 198, 73, -78, -240, -393, -517, -590, -599, -533, -391, -181, 79, 364, 643, 880, 1041, 1097, 1026, 819,
483, 39, -477, -1016, -1516, -1915, -2150, -2164, -1914, -1375, -545, 557, 1886, 3376, 4946, 6502, 7946, 9184,
@@ -43,14 +61,20 @@ const uint16_t NXDN_0_2_FILTER_LEN = 82U;
static q15_t NXDN_ISINC_FILTER[] = {790, -1085, -1073, -553, 747, 2341, 3156, 2152, -893, -4915, -7834, -7536, -3102, 4441, 12354, 17394, 17394,
12354, 4441, -3102, -7536, -7834, -4915, -893, 2152, 3156, 2341, 747, -553, -1073, -1085, 790};
const uint16_t NXDN_ISINC_FILTER_LEN = 32U;
#endif
#endif
#if defined(MODE_DSTAR)
// Generated using gaussfir(0.5, 4, 5) in MATLAB
static q15_t GAUSSIAN_0_5_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0};
const uint16_t GAUSSIAN_0_5_FILTER_LEN = 12U;
#endif
#if defined(MODE_P25)
// One symbol boxcar filter
static q15_t BOXCAR_FILTER[] = {12000, 12000, 12000, 12000, 12000, 0};
const uint16_t BOXCAR_FILTER_LEN = 6U;
static q15_t BOXCAR5_FILTER[] = {12000, 12000, 12000, 12000, 12000, 0};
const uint16_t BOXCAR5_FILTER_LEN = 6U;
#endif
const uint16_t DC_OFFSET = 2048U;
@@ -59,18 +83,41 @@ m_started(false),
m_rxBuffer(RX_RINGBUFFER_SIZE),
m_txBuffer(TX_RINGBUFFER_SIZE),
m_rssiBuffer(RX_RINGBUFFER_SIZE),
#if defined(USE_DCBLOCKER)
m_dcFilter(),
m_dcState(),
m_rrcFilter(),
#endif
#if defined(MODE_DSTAR)
m_gaussianFilter(),
m_boxcarFilter(),
m_gaussianState(),
#endif
#if defined(MODE_DMR)
m_rrc02Filter1(),
m_rrc02State1(),
#endif
#if defined(MODE_YSF)
m_rrc02Filter2(),
m_rrc02State2(),
#endif
#if defined(MODE_P25)
m_boxcar5Filter(),
m_boxcar5State(),
#endif
#if defined(MODE_NXDN)
#if defined(USE_NXDN_BOXCAR)
m_boxcar10Filter(),
m_boxcar10State(),
#else
m_nxdnFilter(),
m_nxdnISincFilter(),
m_rrcState(),
m_gaussianState(),
m_boxcarState(),
m_nxdnState(),
m_nxdnISincState(),
#endif
#endif
#if defined(MODE_M17)
m_rrc05Filter(),
m_rrc05State(),
#endif
m_pttInvert(false),
m_rxLevel(128 * 128),
m_cwIdTXLevel(128 * 128),
@@ -79,6 +126,7 @@ m_dmrTXLevel(128 * 128),
m_ysfTXLevel(128 * 128),
m_p25TXLevel(128 * 128),
m_nxdnTXLevel(128 * 128),
m_m17TXLevel(128 * 128),
m_pocsagTXLevel(128 * 128),
m_fmTXLevel(128 * 128),
m_ax25TXLevel(128 * 128),
@@ -93,30 +141,52 @@ m_dacOverflow(0U),
m_watchdog(0U),
m_lockout(false)
{
::memset(m_rrcState, 0x00U, 70U * sizeof(q15_t));
::memset(m_gaussianState, 0x00U, 40U * sizeof(q15_t));
::memset(m_boxcarState, 0x00U, 30U * sizeof(q15_t));
::memset(m_nxdnState, 0x00U, 110U * sizeof(q15_t));
::memset(m_nxdnISincState, 0x00U, 60U * sizeof(q15_t));
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
#if defined(USE_DCBLOCKER)
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
m_dcFilter.numStages = DC_FILTER_STAGES;
m_dcFilter.pState = m_dcState;
m_dcFilter.pCoeffs = DC_FILTER;
m_dcFilter.postShift = 0;
#endif
m_rrcFilter.numTaps = RRC_0_2_FILTER_LEN;
m_rrcFilter.pState = m_rrcState;
m_rrcFilter.pCoeffs = RRC_0_2_FILTER;
#if defined(MODE_DSTAR)
::memset(m_gaussianState, 0x00U, 40U * sizeof(q15_t));
m_gaussianFilter.numTaps = GAUSSIAN_0_5_FILTER_LEN;
m_gaussianFilter.pState = m_gaussianState;
m_gaussianFilter.pCoeffs = GAUSSIAN_0_5_FILTER;
#endif
#if defined(MODE_DMR)
::memset(m_rrc02State1, 0x00U, 70U * sizeof(q15_t));
m_rrc02Filter1.numTaps = RRC_0_2_FILTER_LEN;
m_rrc02Filter1.pState = m_rrc02State1;
m_rrc02Filter1.pCoeffs = RRC_0_2_FILTER;
#endif
#if defined(MODE_YSF)
::memset(m_rrc02State2, 0x00U, 70U * sizeof(q15_t));
m_rrc02Filter2.numTaps = RRC_0_2_FILTER_LEN;
m_rrc02Filter2.pState = m_rrc02State2;
m_rrc02Filter2.pCoeffs = RRC_0_2_FILTER;
#endif
#if defined(MODE_P25)
::memset(m_boxcar5State, 0x00U, 30U * sizeof(q15_t));
m_boxcar5Filter.numTaps = BOXCAR5_FILTER_LEN;
m_boxcar5Filter.pState = m_boxcar5State;
m_boxcar5Filter.pCoeffs = BOXCAR5_FILTER;
#endif
#if defined(MODE_NXDN)
#if defined(USE_NXDN_BOXCAR)
::memset(m_boxcar10State, 0x00U, 40U * sizeof(q15_t));
m_boxcar10Filter.numTaps = BOXCAR10_FILTER_LEN;
m_boxcar10Filter.pState = m_boxcar10State;
m_boxcar10Filter.pCoeffs = BOXCAR10_FILTER;
#else
::memset(m_nxdnState, 0x00U, 110U * sizeof(q15_t));
::memset(m_nxdnISincState, 0x00U, 60U * sizeof(q15_t));
m_boxcarFilter.numTaps = BOXCAR_FILTER_LEN;
m_boxcarFilter.pState = m_boxcarState;
m_boxcarFilter.pCoeffs = BOXCAR_FILTER;
m_nxdnFilter.numTaps = NXDN_0_2_FILTER_LEN;
m_nxdnFilter.pState = m_nxdnState;
m_nxdnFilter.pCoeffs = NXDN_0_2_FILTER;
@@ -124,6 +194,15 @@ m_lockout(false)
m_nxdnISincFilter.numTaps = NXDN_ISINC_FILTER_LEN;
m_nxdnISincFilter.pState = m_nxdnISincState;
m_nxdnISincFilter.pCoeffs = NXDN_ISINC_FILTER;
#endif
#endif
#if defined(MODE_M17)
::memset(m_rrc05State, 0x00U, 70U * sizeof(q15_t));
m_rrc05Filter.numTaps = RRC_0_5_FILTER_LEN;
m_rrc05Filter.pState = m_rrc05State;
m_rrc05Filter.pCoeffs = RRC_0_5_FILTER;
#endif
initInt();
@@ -148,6 +227,9 @@ void CIO::selfTest()
#if !defined(USE_ALTERNATE_NXDN_LEDS)
setNXDNInt(ledValue);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
setM17Int(ledValue);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
setPOCSAGInt(ledValue);
#endif
@@ -166,6 +248,9 @@ void CIO::selfTest()
#if !defined(USE_ALTERNATE_NXDN_LEDS)
setNXDNInt(false);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
setM17Int(false);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
setPOCSAGInt(false);
#endif
@@ -188,6 +273,11 @@ void CIO::selfTest()
setNXDNInt(true);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
delayInt(250);
setM17Int(true);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
delayInt(250);
setPOCSAGInt(true);
@@ -206,6 +296,11 @@ void CIO::selfTest()
setPOCSAGInt(false);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
delayInt(250);
setM17Int(false);
#endif
#if !defined(USE_ALTERNATE_NXDN_LEDS)
delayInt(250);
setNXDNInt(false);
@@ -243,9 +338,11 @@ void CIO::process()
if (m_started) {
// Two seconds timeout
if (m_watchdog >= 48000U) {
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_POCSAG) {
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_M17 || m_modemState == STATE_POCSAG) {
#if defined(MODE_DMR)
if (m_modemState == STATE_DMR && m_tx)
dmrTX.setStart(false);
#endif
setMode(STATE_IDLE);
}
@@ -323,6 +420,7 @@ void CIO::process()
#endif
if (m_modemState == STATE_IDLE) {
#if defined(MODE_DSTAR)
if (m_dstarEnable) {
q15_t GMSKVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
@@ -332,62 +430,102 @@ void CIO::process()
#endif
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
}
#endif
#if defined(MODE_P25)
if (m_p25Enable) {
q15_t P25Vals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, P25Vals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_boxcar5Filter, dcSamples, P25Vals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_boxcarFilter, samples, P25Vals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_boxcar5Filter, samples, P25Vals, RX_BLOCK_SIZE);
#endif
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
}
#endif
#if defined(MODE_NXDN)
if (m_nxdnEnable) {
q15_t NXDNVals[RX_BLOCK_SIZE];
#if defined(USE_NXDN_BOXCAR)
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_boxcar10Filter, dcSamples, NXDNVals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_boxcar10Filter, samples, NXDNVals, RX_BLOCK_SIZE);
#endif
#else
q15_t NXDNValsTmp[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_nxdnFilter, samples, NXDNValsTmp, RX_BLOCK_SIZE);
#endif
q15_t NXDNVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE);
#endif
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
}
#endif
if (m_dmrEnable || m_ysfEnable) {
q15_t RRCVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrcFilter, samples, RRCVals, RX_BLOCK_SIZE);
#if defined(MODE_DMR)
if (m_dmrEnable) {
q15_t DMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrc02Filter1, samples, DMRVals, RX_BLOCK_SIZE);
if (m_ysfEnable)
ysfRX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
if (m_dmrEnable) {
if (m_duplex)
dmrIdleRX.samples(RRCVals, RX_BLOCK_SIZE);
else
dmrDMORX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
}
if (m_duplex)
dmrIdleRX.samples(DMRVals, RX_BLOCK_SIZE);
else
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
}
#endif
#if defined(MODE_YSF)
if (m_ysfEnable) {
q15_t YSFVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_rrc02Filter2, dcSamples, YSFVals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_rrc02Filter2, samples, YSFVals, RX_BLOCK_SIZE);
#endif
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
}
#endif
#if defined(MODE_M17)
if (m_m17Enable) {
q15_t RRCVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_rrc05Filter, dcSamples, RRCVals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_rrc05Filter, samples, RRCVals, RX_BLOCK_SIZE);
#endif
m17RX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
}
#endif
#if defined(MODE_FM)
if (m_fmEnable) {
bool cos = getCOSInt();
#if defined(USE_DCBLOCKER)
fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
fm.samples(cos, dcSamples, rssi, RX_BLOCK_SIZE);
#else
fm.samples(cos, samples, RX_BLOCK_SIZE);
fm.samples(cos, samples, rssi, RX_BLOCK_SIZE);
#endif
}
#endif
#if defined(MODE_FM) && defined(MODE_AX25)
if (m_ax25Enable) {
#if defined(USE_DCBLOCKER)
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
ax25RX.samples(dcSamples, rssi, RX_BLOCK_SIZE);
#else
ax25RX.samples(samples, RX_BLOCK_SIZE);
ax25RX.samples(samples, rssi, RX_BLOCK_SIZE);
#endif
}
} else if (m_modemState == STATE_DSTAR) {
#endif
}
#if defined(MODE_DSTAR)
else if (m_modemState == STATE_DSTAR) {
if (m_dstarEnable) {
q15_t GMSKVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
@@ -397,10 +535,14 @@ void CIO::process()
#endif
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
}
} else if (m_modemState == STATE_DMR) {
}
#endif
#if defined(MODE_DMR)
else if (m_modemState == STATE_DMR) {
if (m_dmrEnable) {
q15_t DMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_rrcFilter, samples, DMRVals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_rrc02Filter1, samples, DMRVals, RX_BLOCK_SIZE);
if (m_duplex) {
// If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs
@@ -412,56 +554,106 @@ void CIO::process()
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
}
}
} else if (m_modemState == STATE_YSF) {
}
#endif
#if defined(MODE_YSF)
else if (m_modemState == STATE_YSF) {
if (m_ysfEnable) {
q15_t YSFVals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_rrcFilter, dcSamples, YSFVals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_rrc02Filter2, dcSamples, YSFVals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_rrcFilter, samples, YSFVals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_rrc02Filter2, samples, YSFVals, RX_BLOCK_SIZE);
#endif
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
}
} else if (m_modemState == STATE_P25) {
}
#endif
#if defined(MODE_P25)
else if (m_modemState == STATE_P25) {
if (m_p25Enable) {
q15_t P25Vals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, P25Vals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_boxcar5Filter, dcSamples, P25Vals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_boxcarFilter, samples, P25Vals, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_boxcar5Filter, samples, P25Vals, RX_BLOCK_SIZE);
#endif
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
}
} else if (m_modemState == STATE_NXDN) {
}
#endif
#if defined(MODE_NXDN)
else if (m_modemState == STATE_NXDN) {
if (m_nxdnEnable) {
q15_t NXDNVals[RX_BLOCK_SIZE];
#if defined(USE_NXDN_BOXCAR)
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_boxcar10Filter, dcSamples, NXDNVals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_boxcar10Filter, samples, NXDNVals, RX_BLOCK_SIZE);
#endif
#else
q15_t NXDNValsTmp[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_nxdnFilter, samples, NXDNValsTmp, RX_BLOCK_SIZE);
#endif
q15_t NXDNVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE);
#endif
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
}
} else if (m_modemState == STATE_FM) {
}
#endif
#if defined(MODE_M17)
else if (m_modemState == STATE_M17) {
if (m_m17Enable) {
q15_t M17Vals[RX_BLOCK_SIZE];
#if defined(USE_DCBLOCKER)
::arm_fir_fast_q15(&m_rrc05Filter, dcSamples, M17Vals, RX_BLOCK_SIZE);
#else
::arm_fir_fast_q15(&m_rrc05Filter, samples, M17Vals, RX_BLOCK_SIZE);
#endif
m17RX.samples(M17Vals, rssi, RX_BLOCK_SIZE);
}
}
#endif
#if defined(MODE_FM)
else if (m_modemState == STATE_FM) {
bool cos = getCOSInt();
#if defined(USE_DCBLOCKER)
fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
fm.samples(cos, dcSamples, rssi, RX_BLOCK_SIZE);
#if defined(MODE_AX25)
if (m_ax25Enable)
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
#else
fm.samples(cos, samples, RX_BLOCK_SIZE);
if (m_ax25Enable)
ax25RX.samples(samples, RX_BLOCK_SIZE);
ax25RX.samples(dcSamples, rssi, RX_BLOCK_SIZE);
#endif
} else if (m_modemState == STATE_DSTARCAL) {
#else
fm.samples(cos, samples, rssi, RX_BLOCK_SIZE);
#if defined(MODE_AX25)
if (m_ax25Enable)
ax25RX.samples(samples, rssi, RX_BLOCK_SIZE);
#endif
#endif
}
#endif
#if defined(MODE_DSTAR)
else if (m_modemState == STATE_DSTARCAL) {
q15_t GMSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
calDStarRX.samples(GMSKVals, RX_BLOCK_SIZE);
} else if (m_modemState == STATE_RSSICAL) {
}
#endif
else if (m_modemState == STATE_RSSICAL) {
calRSSI.samples(rssi, RX_BLOCK_SIZE);
}
}
@@ -499,6 +691,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
case STATE_NXDN:
txLevel = m_nxdnTXLevel;
break;
case STATE_M17:
txLevel = m_m17TXLevel;
break;
case STATE_POCSAG:
txLevel = m_pocsagTXLevel;
break;
@@ -559,8 +754,10 @@ void CIO::setMode(MMDVM_STATE state)
case STATE_YSF: setYSFInt(false); break;
case STATE_P25: setP25Int(false); break;
case STATE_NXDN: setNXDNInt(false); break;
case STATE_M17: setM17Int(false); break;
case STATE_POCSAG: setPOCSAGInt(false); break;
case STATE_FM: setFMInt(false); break;
default: break;
}
switch (state) {
@@ -569,15 +766,17 @@ void CIO::setMode(MMDVM_STATE state)
case STATE_YSF: setYSFInt(true); break;
case STATE_P25: setP25Int(true); break;
case STATE_NXDN: setNXDNInt(true); break;
case STATE_M17: setM17Int(true); break;
case STATE_POCSAG: setPOCSAGInt(true); break;
case STATE_FM: setFMInt(true); break;
default: break;
}
#endif
m_modemState = state;
}
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout)
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t m17TXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout)
{
m_pttInvert = pttInvert;
@@ -588,6 +787,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
m_ysfTXLevel = q15_t(ysfTXLevel * 128);
m_p25TXLevel = q15_t(p25TXLevel * 128);
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
m_m17TXLevel = q15_t(m17TXLevel * 128);
m_pocsagTXLevel = q15_t(pocsagTXLevel * 128);
m_fmTXLevel = q15_t(fmTXLevel * 128);
m_ax25TXLevel = q15_t(ax25TXLevel * 128);
@@ -606,6 +806,7 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
m_ysfTXLevel = -m_ysfTXLevel;
m_p25TXLevel = -m_p25TXLevel;
m_nxdnTXLevel = -m_nxdnTXLevel;
m_m17TXLevel = -m_m17TXLevel;
m_pocsagTXLevel = -m_pocsagTXLevel;
}
}
+41 -7
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -46,7 +46,7 @@ public:
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, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout);
void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t m17TXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout);
void getOverflow(bool& adcOverflow, bool& dacOverflow);
@@ -58,6 +58,10 @@ public:
void resetWatchdog();
uint32_t getWatchdog();
uint8_t getCPU() const;
void getUDID(uint8_t* buffer);
void selfTest();
private:
@@ -67,19 +71,47 @@ private:
CRingBuffer<TSample> m_txBuffer;
CRingBuffer<uint16_t> m_rssiBuffer;
#if defined(USE_DCBLOCKER)
arm_biquad_casd_df1_inst_q31 m_dcFilter;
q31_t m_dcState[4];
#endif
arm_fir_instance_q15 m_rrcFilter;
#if defined(MODE_DSTAR)
arm_fir_instance_q15 m_gaussianFilter;
arm_fir_instance_q15 m_boxcarFilter;
q15_t m_gaussianState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare
#endif
#if defined(MODE_DMR)
arm_fir_instance_q15 m_rrc02Filter1;
q15_t m_rrc02State1[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
#endif
#if defined(MODE_YSF)
arm_fir_instance_q15 m_rrc02Filter2;
q15_t m_rrc02State2[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
#endif
#if defined(MODE_P25)
arm_fir_instance_q15 m_boxcar5Filter;
q15_t m_boxcar5State[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
#endif
#if defined(MODE_NXDN)
#if defined(USE_NXDN_BOXCAR)
arm_fir_instance_q15 m_boxcar10Filter;
q15_t m_boxcar10State[40U]; // NoTaps + BlockSize - 1, 10 + 20 - 1 plus some spare
#else
arm_fir_instance_q15 m_nxdnFilter;
arm_fir_instance_q15 m_nxdnISincFilter;
q15_t m_rrcState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
q15_t m_gaussianState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare
q15_t m_boxcarState[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
q15_t m_nxdnState[110U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare
q15_t m_nxdnISincState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare
#endif
#endif
#if defined(MODE_M17)
arm_fir_instance_q15 m_rrc05Filter;
q15_t m_rrc05State[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
#endif
bool m_pttInvert;
q15_t m_rxLevel;
@@ -89,6 +121,7 @@ private:
q15_t m_ysfTXLevel;
q15_t m_p25TXLevel;
q15_t m_nxdnTXLevel;
q15_t m_m17TXLevel;
q15_t m_pocsagTXLevel;
q15_t m_fmTXLevel;
q15_t m_ax25TXLevel;
@@ -126,6 +159,7 @@ private:
void setP25Int(bool on);
void setNXDNInt(bool on);
void setPOCSAGInt(bool on);
void setM17Int(bool on);
void setFMInt(bool on);
void delayInt(unsigned int dly);
+42
View File
@@ -107,6 +107,9 @@ void CIO::initInt()
#if !defined(USE_ALTERNATE_NXDN_LEDS)
pinMode(PIN_NXDN, OUTPUT);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
pinMode(PIN_M17, OUTPUT);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
pinMode(PIN_POCSAG, OUTPUT);
#endif
@@ -253,6 +256,16 @@ void CIO::setNXDNInt(bool on)
#endif
}
void CIO::setM17Int(bool on)
{
#if defined(USE_ALTERNATE_M17_LEDS)
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
digitalWrite(PIN_P25, on ? HIGH : LOW);
#else
digitalWrite(PIN_M17, on ? HIGH : LOW);
#endif
}
void CIO::setPOCSAGInt(bool on)
{
#if defined(USE_ALTERNATE_POCSAG_LEDS)
@@ -278,4 +291,33 @@ void CIO::delayInt(unsigned int dly)
delay(dly);
}
uint8_t CIO::getCPU() const
{
return 0U;
}
// Code taken from https://github.com/emagii/at91sam3s/blob/master/examples/eefc_uniqueid/main.c
void CIO::getUDID(uint8_t* buffer)
{
uint32_t status;
EFC1->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
do {
status = EFC1->EEFC_FSR;
} while ( (status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY );
for (uint8_t i = 0; i < 16; i+=4) {
buffer[i + 0] = *(uint32_t *)(IFLASH1_ADDR + i) >> 24;
buffer[i + 1] = *(uint32_t *)(IFLASH1_ADDR + i) >> 16;
buffer[i + 2] = *(uint32_t *)(IFLASH1_ADDR + i) >> 8;
buffer[i + 3] = *(uint32_t *)(IFLASH1_ADDR + i) >> 0;
}
EFC1->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
do {
status = EFC1->EEFC_FSR;
} while ( (status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY );
}
#endif
+6
View File
@@ -59,9 +59,15 @@
#elif defined(STM32F4_DVM)
#include "pins/pins_f4_stm32dvm_v3.h"
#elif defined(STM32F7_DVM)
#include "pins/pins_f7_stm32dvm_v5.h"
#elif defined(DRCC_DVM_NQF)
#include "pins/pins_f4_drcc_nqf.h"
#elif defined(DRCC_DVM_HHP446)
#include "pins/pins_f4_drcc_hhp446.h"
#elif defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
#include "pins/pins_f4_stm32eda.h"
+62 -2
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018,2020,2023 by Jonathan Naylor G4KLX
* Copyright (C) 2019,2020 by BG5HHP
*
* This program is free software; you can redistribute it and/or modify
@@ -106,6 +106,14 @@ void CIO::initInt()
GPIO_Init(PORT_NXDN, &GPIO_InitStruct);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
// M17 pin
RCC_AHB1PeriphClockCmd(RCC_Per_M17, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_M17;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_M17, &GPIO_InitStruct);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
// POCSAG pin
RCC_AHB1PeriphClockCmd(RCC_Per_POCSAG, ENABLE);
@@ -157,6 +165,14 @@ void CIO::initInt()
GPIO_Init(PORT_MNXDN, &GPIO_InitStruct);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
// M17 mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MM17, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MM17;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MM17, &GPIO_InitStruct);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
// POCSAG mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MPOCSAG, ENABLE);
@@ -349,10 +365,16 @@ void CIO::interrupt()
#endif
}
// trigger next ADC1
// Trigger next ADC1
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
ADC_SoftwareStartConv(ADC1);
#if defined(SEND_RSSI_DATA)
// Trigger next ADC2
ADC_ClearFlag(ADC2, ADC_FLAG_EOC);
ADC_SoftwareStartConv(ADC2);
#endif
m_rxBuffer.put(sample);
m_rssiBuffer.put(rawRSSI);
@@ -440,6 +462,27 @@ void CIO::setNXDNInt(bool on)
#endif
}
void CIO::setM17Int(bool on)
{
#if defined(MODE_LEDS)
#if defined(USE_ALTERNATE_M17_LEDS)
GPIO_WriteBit(PORT_DSTAR, PIN_DSTAR, on ? Bit_SET : Bit_RESET);
GPIO_WriteBit(PORT_P25, PIN_P25, on ? Bit_SET : Bit_RESET);
#else
GPIO_WriteBit(PORT_M17, PIN_M17, on ? Bit_SET : Bit_RESET);
#endif
#endif
#if defined(MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && (defined(STM32F4_NUCLEO) || defined(STM32F722_RPT_HAT))
#if defined(USE_ALTERNATE_M17_LEDS)
GPIO_WriteBit(PORT_MDSTAR, PIN_MDSTAR, on ? Bit_SET : Bit_RESET);
GPIO_WriteBit(PORT_MP25, PIN_MP25, on ? Bit_SET : Bit_RESET);
#else
GPIO_WriteBit(PORT_MM17, PIN_MM17, on ? Bit_SET : Bit_RESET);
#endif
#endif
}
void CIO::setPOCSAGInt(bool on)
{
#if defined(MODE_LEDS)
@@ -508,4 +551,21 @@ void CIO::delayInt(unsigned int dly)
}
}
uint8_t CIO::getCPU() const
{
return 2U;
}
void CIO::getUDID(uint8_t* buffer)
{
#if defined(STM32F4XX)
::memcpy(buffer, (void *)0x1FFF7A10, 12U);
#elif defined(STM32F722xx)
::memcpy(buffer, (void *)0x1FF07A10, 12U);
#elif defined(STM32F767xx)
::memcpy(buffer, (void *)0x1FF0F420, 12U);
#endif
}
#endif
-475
View File
@@ -1,475 +0,0 @@
/*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
* Copyright (C) 2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Wojciech Krutnik N0CALL
*
* 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 "IO.h"
#if defined(STM32F1)
#if defined(STM32F1_POG)
/*
Pin definitions for STM32F1 POG Board:
PTT PB12 output
COSLED PB5 output
LED PB4 output
COS PB13 input/PD
DSTAR PB7 output
DMR PB6 output
YSF PB8 output
P25 PB9 output
NXDN PB10 output
POCSAG PB11 output
RX PB0 analog input (ADC1_8)
RSSI PB1 analog input (ADC2_9)
TX PA4 analog output (DAC_OUT1)
EXT_CLK PA15 input (AF: TIM2_CH1_ETR)
USART1_TXD PA9 output (AF)
USART1_RXD PA10 input (AF)
*/
#define PIN_PTT 12
#define PORT_PTT GPIOB
#define BB_PTT *((bitband_t)BITBAND_PERIPH(&PORT_PTT->ODR, PIN_PTT))
#define PIN_COSLED 5
#define PORT_COSLED GPIOB
#define BB_COSLED *((bitband_t)BITBAND_PERIPH(&PORT_COSLED->ODR, PIN_COSLED))
#define PIN_LED 4
#define PORT_LED GPIOB
#define BB_LED *((bitband_t)BITBAND_PERIPH(&PORT_LED->ODR, PIN_LED))
#define PIN_COS 13
#define PORT_COS GPIOB
#define BB_COS *((bitband_t)BITBAND_PERIPH(&PORT_COS->IDR, PIN_COS))
#define PIN_DSTAR 7
#define PORT_DSTAR GPIOB
#define BB_DSTAR *((bitband_t)BITBAND_PERIPH(&PORT_DSTAR->ODR, PIN_DSTAR))
#define PIN_DMR 6
#define PORT_DMR GPIOB
#define BB_DMR *((bitband_t)BITBAND_PERIPH(&PORT_DMR->ODR, PIN_DMR))
#define PIN_YSF 8
#define PORT_YSF GPIOB
#define BB_YSF *((bitband_t)BITBAND_PERIPH(&PORT_YSF->ODR, PIN_YSF))
#define PIN_P25 9
#define PORT_P25 GPIOB
#define BB_P25 *((bitband_t)BITBAND_PERIPH(&PORT_P25->ODR, PIN_P25))
#define PIN_NXDN 10
#define PORT_NXDN GPIOB
#define BB_NXDN *((bitband_t)BITBAND_PERIPH(&PORT_NXDN->ODR, PIN_NXDN))
#define PIN_POCSAG 11
#define PORT_POCSAG GPIOB
#define BB_POCSAG *((bitband_t)BITBAND_PERIPH(&PORT_POCSAG->ODR, PIN_POCSAG))
#define PIN_RX 0
#define PIN_RX_ADC_CH 8
#define PORT_RX GPIOB
#define PIN_RSSI 1
#define PIN_RSSI_ADC_CH 9
#define PORT_RSSI GPIOB
#define PIN_TX 4
#define PIN_TX_DAC_CH 1
#define PORT_TX GPIOA
#define PIN_EXT_CLK 15
#define SRC_EXT_CLK 15
#define PORT_EXT_CLK GPIOA
#define PIN_USART1_TXD 9
#define PORT_USART1_TXD GPIOA
#define PIN_USART1_RXD 10
#define PORT_USART1_RXD GPIOA
#else // defined(STM32F1_POG)
#error "Either STM32F1_POG, or sth need to be defined"
#endif // defined(STM32F1_POG)
const uint16_t DC_OFFSET = 2048U;
// Sampling frequency
#define SAMP_FREQ 24000
extern "C" {
void TIM2_IRQHandler() {
if ((TIM2->SR & TIM_SR_UIF) == TIM_SR_UIF) {
TIM2->SR = ~TIM_SR_UIF; // clear UI flag
io.interrupt();
}
}
}
void delay(uint32_t cnt)
{
while(cnt--)
asm("nop");
}
// source: http://www.freddiechopin.info/
void GPIOConfigPin(GPIO_TypeDef *port_ptr, uint32_t pin, uint32_t mode_cnf_value)
{
volatile uint32_t *cr_ptr;
uint32_t cr_value;
cr_ptr = &port_ptr->CRL; // configuration of pins [0,7] is in CRL
if (pin >= 8) // is pin in [8; 15]?
{ // configuration of pins [8,15] is in CRH
cr_ptr++; // advance to next struct element CRL -> CRH
pin -= 8; // crop the pin number
}
cr_value = *cr_ptr; // localize the CRL / CRH value
cr_value &= ~(0xF << (pin * 4)); // clear the MODE and CNF fields (now that pin is an analog input)
cr_value |= (mode_cnf_value << (pin * 4)); // save new MODE and CNF value for desired pin
*cr_ptr = cr_value; // save localized value to CRL / CRL
}
#if defined(STM32F1_POG)
void FancyLEDEffect()
{
bitband_t foo[] = {&BB_LED, &BB_COSLED, &BB_PTT, &BB_DMR, &BB_DSTAR, &BB_YSF, &BB_P25};
for(int i=0; i<7; i++){
*foo[i] = 0x01;
}
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1);
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
delay(SystemCoreClock/1000*100);
for(int i=0; i<7; i++){
*foo[i] = 0x00;
}
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
delay(SystemCoreClock/1000*20);
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
delay(SystemCoreClock/1000*10);
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
*foo[0] = 0x01;
for(int i=1; i<7; i++){
delay(SystemCoreClock/1000*10);
*foo[i-1] = 0x00;
*foo[i] = 0x01;
}
for(int i=5; i>=0; i--){
delay(SystemCoreClock/1000*10);
*foo[i+1] = 0x00;
*foo[i] = 0x01;
}
delay(SystemCoreClock/1000*10);
*foo[5+1-6] = 0x00;
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x00;
delay(SystemCoreClock/1000*10);
*((bitband_t)BITBAND_PERIPH(&PORT_USART1_TXD->ODR, PIN_USART1_TXD)) = 0x01;
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1|GPIO_CRL_CNF0_1);
delay(SystemCoreClock/1000*50);
}
#endif
static inline void GPIOInit()
{
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN
| RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN
| RCC_APB2ENR_AFIOEN; // enable all GPIOs
// set all ports to input with pull-down
GPIOA->CRL = 0x88888888;
GPIOA->CRH = 0x88888888;
GPIOA->ODR = 0;
GPIOB->CRL = 0x88888888;
GPIOB->CRH = 0x88888888;
GPIOB->ODR = 0;
GPIOC->CRL = 0x88888888;
GPIOC->CRH = 0x88888888;
GPIOC->ODR = 0;
GPIOD->CRL = 0x88888888;
GPIOD->CRH = 0x88888888;
GPIOD->ODR = 0;
// configure ports
GPIOConfigPin(PORT_PTT, PIN_PTT, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_COSLED, PIN_COSLED, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_LED, PIN_LED, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_COS, PIN_COS, GPIO_CRL_CNF0_1);
GPIOConfigPin(PORT_DSTAR, PIN_DSTAR, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_DMR, PIN_DMR, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_YSF, PIN_YSF, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_P25, PIN_P25, GPIO_CRL_MODE0_1);
#if !defined(USE_ALTERNATE_NXDN_LEDS)
GPIOConfigPin(PORT_NXDN, PIN_NXDN, GPIO_CRL_MODE0_1);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
GPIOConfigPin(PORT_POCSAG, PIN_POCSAG, GPIO_CRL_MODE0_1);
#endif
GPIOConfigPin(PORT_RX, PIN_RX, 0);
#if defined(SEND_RSSI_DATA)
GPIOConfigPin(PORT_RSSI, PIN_RSSI, 0);
#endif
GPIOConfigPin(PORT_TX, PIN_TX, 0);
#if defined(EXTERNAL_OSC)
#if defined(STM32F1_POG)
GPIOConfigPin(PORT_EXT_CLK, PIN_EXT_CLK, GPIO_CRL_CNF0_0);
AFIO->MAPR = (AFIO->MAPR & ~AFIO_MAPR_TIM2_REMAP) | AFIO_MAPR_TIM2_REMAP_0;
#endif
#endif
GPIOConfigPin(PORT_USART1_TXD, PIN_USART1_TXD, GPIO_CRL_MODE0_1|GPIO_CRL_CNF0_1);
GPIOConfigPin(PORT_USART1_RXD, PIN_USART1_RXD, GPIO_CRL_CNF0_0);
AFIO->MAPR = (AFIO->MAPR & ~AFIO_MAPR_SWJ_CFG) | AFIO_MAPR_SWJ_CFG_1;
}
static inline void ADCInit()
{
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_ADCPRE_Msk)
| RCC_CFGR_ADCPRE_DIV6; // ADC clock divided by 6 (72MHz/6 = 12MHz)
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
#if defined(SEND_RSSI_DATA)
RCC->APB2ENR |= RCC_APB2ENR_ADC2EN;
#endif
// Init ADCs in dual mode (RSSI)
#if defined(SEND_RSSI_DATA)
ADC1->CR1 = ADC_CR1_DUALMOD_1|ADC_CR1_DUALMOD_2; // Regular simultaneous mode
#endif
// Set sampling time to 7.5 cycles
if (PIN_RX_ADC_CH < 10) {
ADC1->SMPR2 = ADC_SMPR2_SMP0_0 << (3*PIN_RX_ADC_CH);
} else {
ADC1->SMPR1 = ADC_SMPR1_SMP10_0 << (3*PIN_RX_ADC_CH);
}
#if defined(SEND_RSSI_DATA)
if (PIN_RSSI_ADC_CH < 10) {
ADC2->SMPR2 = ADC_SMPR2_SMP0_0 << (3*PIN_RSSI_ADC_CH);
} else {
ADC2->SMPR1 = ADC_SMPR1_SMP10_0 << (3*PIN_RSSI_ADC_CH);
}
#endif
// Set conversion channel (single conversion)
ADC1->SQR3 = PIN_RX_ADC_CH;
#if defined(SEND_RSSI_DATA)
ADC2->SQR3 = PIN_RSSI_ADC_CH;
#endif
// Enable ADC
ADC1->CR2 |= ADC_CR2_ADON;
#if defined(SEND_RSSI_DATA)
// Enable ADC2
ADC2->CR2 |= ADC_CR2_ADON;
#endif
// Start calibration
delay(6*2);
ADC1->CR2 |= ADC_CR2_CAL;
while((ADC1->CR2 & ADC_CR2_CAL) == ADC_CR2_CAL)
;
#if defined(SEND_RSSI_DATA)
ADC2->CR2 |= ADC_CR2_CAL;
while((ADC2->CR2 & ADC_CR2_CAL) == ADC_CR2_CAL)
;
#endif
// Trigger first conversion
ADC1->CR2 |= ADC_CR2_ADON;
#if defined(SEND_RSSI_DATA)
ADC2->CR2 |= ADC_CR2_ADON;
#endif
}
static inline void DACInit()
{
RCC->APB1ENR |= RCC_APB1ENR_DACEN;
DAC->CR = DAC_CR_EN1;
}
static inline void TimerInit()
{
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
#if defined(EXTERNAL_OSC)
// Enable external clock, prescaler /4
TIM2->SMCR = TIM_SMCR_ECE | TIM_SMCR_ETPS_1;
#endif
// TIM2 output frequency
TIM2->PSC = 0;
#if defined(EXTERNAL_OSC)
// TimerCount = ExternalOsc
// /4 (external clock prescaler)
// /SAMP_FREQ
TIM2->ARR = (uint16_t) ((EXTERNAL_OSC/(4*SAMP_FREQ)) - 1);
#else
TIM2->ARR = (uint16_t) ((SystemCoreClock/(SAMP_FREQ)) - 1);
#endif
// Enable TIse 1%-tolerance comM2 interrupt
TIM2->DIER = TIM_DIER_UIE;
NVIC_EnableIRQ(TIM2_IRQn);
// Enable TIM2
TIM2->CR1 |= TIM_CR1_CEN;
}
void CIO::initInt()
{
GPIOInit();
ADCInit();
DACInit();
#if defined(STM32F1_POG)
FancyLEDEffect();
#endif
}
void CIO::startInt()
{
TimerInit();
BB_COSLED = 0;
BB_LED = 1;
}
void CIO::interrupt()
{
TSample sample = {DC_OFFSET, MARK_NONE};
#if defined(SEND_RSSI_DATA)
uint16_t rawRSSI = 0U;
#endif
bitband_t eoc = (bitband_t)BITBAND_PERIPH(&ADC1->SR, ADC_SR_EOS_Pos);
bitband_t adon = (bitband_t)BITBAND_PERIPH(&ADC1->CR2, ADC_CR2_ADON_Pos);
#if defined(SEND_RSSI_DATA)
bitband_t rssi_adon = (bitband_t)BITBAND_PERIPH(&ADC2->CR2, ADC_CR2_ADON_Pos);
#endif
if (*eoc) {
// trigger next conversion
*adon = 1;
#if defined(SEND_RSSI_DATA)
*rssi_adon = 1;
#endif
m_txBuffer.get(sample);
DAC->DHR12R1 = sample.sample; // Send the value to the DAC
// Read value from ADC1 and ADC2
sample.sample = ADC1->DR; // read conversion result; EOC is cleared by this read
m_rxBuffer.put(sample);
#if defined(SEND_RSSI_DATA)
rawRSSI = ADC2->DR;
m_rssiBuffer.put(rawRSSI);
#endif
m_watchdog++;
}
}
bool CIO::getCOSInt()
{
return BB_COS;
}
void CIO::setLEDInt(bool on)
{
BB_LED = !!on;
}
void CIO::setPTTInt(bool on)
{
BB_PTT = !!on;
}
void CIO::setCOSInt(bool on)
{
BB_COSLED = !!on;
}
void CIO::setDStarInt(bool on)
{
BB_DSTAR = !!on;
}
void CIO::setDMRInt(bool on)
{
BB_DMR = !!on;
}
void CIO::setYSFInt(bool on)
{
BB_YSF = !!on;
}
void CIO::setP25Int(bool on)
{
BB_P25 = !!on;
}
void CIO::setNXDNInt(bool on)
{
#if defined(USE_ALTERNATE_NXDN_LEDS)
BB_YSF = !!on;
BB_P25 = !!on;
#else
BB_NXDN = !!on;
#endif
}
void CIO::setPOCSAGInt(bool on)
{
#if defined(USE_ALTERNATE_POCSAG_LEDS)
BB_DSTAR = !!on;
BB_DMR = !!on;
#else
BB_POCSAG = !!on;
#endif
}
void CIO::setFMInt(bool on)
{
#if defined(USE_ALTERNATE_FM_LEDS)
BB_DSTAR = !!on;
BB_YSF = !!on;
#endif
}
void CIO::delayInt(unsigned int dly)
{
delay(dly);
}
#endif
+24
View File
@@ -75,6 +75,9 @@ void CIO::initInt()
#if !defined(USE_ALTERNATE_NXDN_LEDS)
pinMode(PIN_NXDN, OUTPUT);
#endif
#if !defined(USE_ALTERNATE_M17_LEDS)
pinMode(PIN_M17, OUTPUT);
#endif
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
pinMode(PIN_POCSAG, OUTPUT);
#endif
@@ -237,6 +240,16 @@ void CIO::setNXDNInt(bool on)
#endif
}
void CIO::setM17Int(bool on)
{
#if defined(USE_ALTERNATE_M17_LEDS)
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
digitalWrite(PIN_P25, on ? HIGH : LOW);
#else
digitalWrite(PIN_M17, on ? HIGH : LOW);
#endif
}
void CIO::setPOCSAGInt(bool on)
{
#if defined(USE_ALTERNATE_POCSAG_LEDS)
@@ -262,4 +275,15 @@ void CIO::delayInt(unsigned int dly)
delay(dly);
}
uint8_t CIO::getCPU() const
{
return 1U;
}
void CIO::getUDID(uint8_t* buffer)
{
::memcpy(buffer, (void *)0x4058, 16U);
}
#endif
+67
View File
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(M17DEFINES_H)
#define M17DEFINES_H
const unsigned int M17_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int M17_FRAME_LENGTH_BITS = 384U;
const unsigned int M17_FRAME_LENGTH_BYTES = M17_FRAME_LENGTH_BITS / 8U;
const unsigned int M17_FRAME_LENGTH_SYMBOLS = M17_FRAME_LENGTH_BITS / 2U;
const unsigned int M17_FRAME_LENGTH_SAMPLES = M17_FRAME_LENGTH_SYMBOLS * M17_RADIO_SYMBOL_LENGTH;
const unsigned int M17_SYNC_LENGTH_BITS = 16U;
const unsigned int M17_SYNC_LENGTH_BYTES = M17_SYNC_LENGTH_BITS / 8U;
const unsigned int M17_SYNC_LENGTH_SYMBOLS = M17_SYNC_LENGTH_BITS / 2U;
const unsigned int M17_SYNC_LENGTH_SAMPLES = M17_SYNC_LENGTH_SYMBOLS * M17_RADIO_SYMBOL_LENGTH;
const uint8_t M17_LINK_SETUP_SYNC_BYTES[] = {0x55U, 0xF7U};
const uint8_t M17_STREAM_SYNC_BYTES[] = {0xFFU, 0x5DU};
const uint8_t M17_EOF_SYNC_BYTES[] = {0x55U, 0x5DU};
const uint16_t M17_LINK_SETUP_SYNC_BITS = 0x55F7U;
const uint16_t M17_STREAM_SYNC_BITS = 0xFF5DU;
const uint16_t M17_EOF_SYNC_BITS = 0x555DU;
// 5 5 F 7
// 01 01 01 01 11 11 01 11
// +3 +3 +3 +3 -3 -3 +3 -3
const int8_t M17_LINK_SETUP_SYNC_SYMBOLS_VALUES[] = {+3, +3, +3, +3, -3, -3, +3, -3};
const uint8_t M17_LINK_SETUP_SYNC_SYMBOLS = 0xF2U;
// F F 5 D
// 11 11 11 11 01 01 11 01
// -3 -3 -3 -3 +3 +3 -3 +3
const int8_t M17_STREAM_SYNC_SYMBOLS_VALUES[] = {-3, -3, -3, -3, +3, +3, -3, +3};
const uint8_t M17_STREAM_SYNC_SYMBOLS = 0x0DU;
// 5 5 5 D
// 01 01 01 01 01 01 11 01
// +3 +3 +3 +3 +3 +3 -3 +3
const int8_t M17_EOF_SYNC_SYMBOLS_VALUES[] = {+3, +3, +3, +3, +3, +3, -3, +3};
const uint8_t M17_EOF_SYNC_SYMBOLS = 0xFDU;
#endif
+485
View File
@@ -0,0 +1,485 @@
/*
* Copyright (C) 2009-2017,2020,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_M17)
#include "Globals.h"
#include "M17RX.h"
#include "Utils.h"
const q15_t SCALING_FACTOR = 18750; // Q15(0.55)
const uint8_t MAX_SYNC_BIT_START_ERRS = 0U;
const uint8_t MAX_SYNC_BIT_RUN_ERRS = 2U;
const uint8_t MAX_SYNC_SYMBOL_START_ERRS = 0U;
const uint8_t MAX_SYNC_SYMBOL_RUN_ERRS = 1U;
const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
const uint8_t NOAVEPTR = 99U;
const uint16_t NOENDPTR = 9999U;
const unsigned int MAX_SYNC_FRAMES = 3U + 1U;
CM17RX::CM17RX() :
m_state(M17RXS_NONE),
m_bitBuffer(),
m_buffer(),
m_bitPtr(0U),
m_dataPtr(0U),
m_startPtr(NOENDPTR),
m_endPtr(NOENDPTR),
m_syncPtr(NOENDPTR),
m_minSyncPtr(NOENDPTR),
m_maxSyncPtr(NOENDPTR),
m_maxCorr(0),
m_lostCount(0U),
m_countdown(0U),
m_nextState(M17RXS_NONE),
m_centre(),
m_centreVal(0),
m_threshold(),
m_thresholdVal(0),
m_averagePtr(NOAVEPTR),
m_rssiAccum(0U),
m_rssiCount(0U)
{
}
void CM17RX::reset()
{
m_state = M17RXS_NONE;
m_dataPtr = 0U;
m_bitPtr = 0U;
m_maxCorr = 0;
m_averagePtr = NOAVEPTR;
m_startPtr = NOENDPTR;
m_endPtr = NOENDPTR;
m_syncPtr = NOENDPTR;
m_minSyncPtr = NOENDPTR;
m_maxSyncPtr = NOENDPTR;
m_centreVal = 0;
m_thresholdVal = 0;
m_lostCount = 0U;
m_countdown = 0U;
m_nextState = M17RXS_NONE;
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
void CM17RX::samples(const q15_t* samples, uint16_t* rssi, uint8_t length)
{
for (uint8_t i = 0U; i < length; i++) {
q15_t sample = samples[i];
m_rssiAccum += rssi[i];
m_rssiCount++;
m_bitBuffer[m_bitPtr] <<= 1;
if (sample < 0)
m_bitBuffer[m_bitPtr] |= 0x01U;
m_buffer[m_dataPtr] = sample;
switch (m_state) {
case M17RXS_LINK_SETUP:
case M17RXS_STREAM:
processData(sample);
break;
default:
processNone(sample);
break;
}
m_dataPtr++;
if (m_dataPtr >= M17_FRAME_LENGTH_SAMPLES)
m_dataPtr = 0U;
m_bitPtr++;
if (m_bitPtr >= M17_RADIO_SYMBOL_LENGTH)
m_bitPtr = 0U;
}
}
void CM17RX::processNone(q15_t sample)
{
bool ret1 = correlateSync(M17_LINK_SETUP_SYNC_SYMBOLS, M17_LINK_SETUP_SYNC_SYMBOLS_VALUES, M17_LINK_SETUP_SYNC_BYTES, MAX_SYNC_SYMBOL_START_ERRS, MAX_SYNC_BIT_START_ERRS);
bool ret2 = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_START_ERRS, MAX_SYNC_BIT_START_ERRS);
if (ret1 || ret2) {
// On the first sync, start the countdown to the state change
if (m_countdown == 0U) {
m_rssiAccum = 0U;
m_rssiCount = 0U;
io.setDecode(true);
io.setADCDetection(true);
m_averagePtr = NOAVEPTR;
m_countdown = 5U;
if (ret1) m_nextState = M17RXS_LINK_SETUP;
if (ret2) m_nextState = M17RXS_STREAM;
}
}
if (m_countdown > 0U)
m_countdown--;
if (m_countdown == 1U) {
m_minSyncPtr = m_syncPtr + M17_FRAME_LENGTH_SAMPLES - 1U;
if (m_minSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
m_minSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
m_maxSyncPtr = m_syncPtr + 1U;
if (m_maxSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
m_maxSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
m_state = m_nextState;
m_countdown = 0U;
m_nextState = M17RXS_NONE;
}
}
void CM17RX::processData(q15_t sample)
{
bool eof = false;
if (m_minSyncPtr < m_maxSyncPtr) {
if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr) {
bool ret = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
eof = correlateSync(M17_EOF_SYNC_SYMBOLS, M17_EOF_SYNC_SYMBOLS_VALUES, M17_EOF_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
if (ret) m_state = M17RXS_STREAM;
}
} else {
if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr) {
bool ret = correlateSync(M17_STREAM_SYNC_SYMBOLS, M17_STREAM_SYNC_SYMBOLS_VALUES, M17_STREAM_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
eof = correlateSync(M17_EOF_SYNC_SYMBOLS, M17_EOF_SYNC_SYMBOLS_VALUES, M17_EOF_SYNC_BYTES, MAX_SYNC_SYMBOL_RUN_ERRS, MAX_SYNC_BIT_RUN_ERRS);
if (ret) m_state = M17RXS_STREAM;
}
}
if (eof) {
DEBUG4("M17RX: eof sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
io.setDecode(false);
io.setADCDetection(false);
serial.writeM17EOT();
m_state = M17RXS_NONE;
m_endPtr = NOENDPTR;
m_averagePtr = NOAVEPTR;
m_countdown = 0U;
m_nextState = M17RXS_NONE;
m_maxCorr = 0;
}
if (m_dataPtr == m_endPtr) {
// Only update the centre and threshold if they are from a good sync
if (m_lostCount == MAX_SYNC_FRAMES) {
m_minSyncPtr = m_syncPtr + M17_FRAME_LENGTH_SAMPLES - 1U;
if (m_minSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
m_minSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
m_maxSyncPtr = m_syncPtr + 1U;
if (m_maxSyncPtr >= M17_FRAME_LENGTH_SAMPLES)
m_maxSyncPtr -= M17_FRAME_LENGTH_SAMPLES;
}
calculateLevels(m_startPtr, M17_FRAME_LENGTH_SYMBOLS);
switch (m_state) {
case M17RXS_LINK_SETUP:
DEBUG4("M17RX: link setup sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
break;
case M17RXS_STREAM:
DEBUG4("M17RX: stream sync found pos/centre/threshold", m_syncPtr, m_centreVal, m_thresholdVal);
break;
default:
break;
}
uint8_t frame[M17_FRAME_LENGTH_BYTES + 3U];
samplesToBits(m_startPtr, M17_FRAME_LENGTH_SYMBOLS, frame, 8U, m_centreVal, m_thresholdVal);
// We've not seen a stream sync for too long, signal RXLOST and change to RX_NONE
m_lostCount--;
if (m_lostCount == 0U) {
DEBUG1("M17RX: sync timed out, lost lock");
io.setDecode(false);
io.setADCDetection(false);
serial.writeM17Lost();
m_state = M17RXS_NONE;
m_endPtr = NOENDPTR;
m_averagePtr = NOAVEPTR;
m_countdown = 0U;
m_nextState = M17RXS_NONE;
m_maxCorr = 0;
} else {
frame[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U;
switch (m_state) {
case M17RXS_LINK_SETUP:
writeRSSILinkSetup(frame);
break;
case M17RXS_STREAM:
writeRSSIStream(frame);
break;
default:
break;
}
m_maxCorr = 0;
m_nextState = M17RXS_NONE;
}
}
}
bool CM17RX::correlateSync(uint8_t syncSymbols, const int8_t* syncSymbolValues, const uint8_t* syncBytes, uint8_t maxSymbolErrs, uint8_t maxBitErrs)
{
if (countBits8(m_bitBuffer[m_bitPtr] ^ syncSymbols) <= maxSymbolErrs) {
uint16_t ptr = m_dataPtr + M17_FRAME_LENGTH_SAMPLES - M17_SYNC_LENGTH_SAMPLES + M17_RADIO_SYMBOL_LENGTH;
if (ptr >= M17_FRAME_LENGTH_SAMPLES)
ptr -= M17_FRAME_LENGTH_SAMPLES;
q31_t corr = 0;
q15_t min = 16000;
q15_t max = -16000;
for (uint8_t i = 0U; i < M17_SYNC_LENGTH_SYMBOLS; i++) {
q15_t val = m_buffer[ptr];
if (val > max)
max = val;
if (val < min)
min = val;
switch (syncSymbolValues[i]) {
case +3:
corr -= (val + val + val);
break;
case +1:
corr -= val;
break;
case -1:
corr += val;
break;
default: // -3
corr += (val + val + val);
break;
}
ptr += M17_RADIO_SYMBOL_LENGTH;
if (ptr >= M17_FRAME_LENGTH_SAMPLES)
ptr -= M17_FRAME_LENGTH_SAMPLES;
}
if (corr > m_maxCorr) {
if (m_averagePtr == NOAVEPTR) {
m_centreVal = (max + min) >> 1;
q31_t v1 = (max - m_centreVal) * SCALING_FACTOR;
m_thresholdVal = q15_t(v1 >> 15);
}
uint16_t startPtr = m_dataPtr + M17_FRAME_LENGTH_SAMPLES - M17_SYNC_LENGTH_SAMPLES + M17_RADIO_SYMBOL_LENGTH;
if (startPtr >= M17_FRAME_LENGTH_SAMPLES)
startPtr -= M17_FRAME_LENGTH_SAMPLES;
uint8_t sync[M17_SYNC_LENGTH_BYTES];
samplesToBits(startPtr, M17_SYNC_LENGTH_SYMBOLS, sync, 0U, m_centreVal, m_thresholdVal);
uint8_t errs = 0U;
for (uint8_t i = 0U; i < M17_SYNC_LENGTH_BYTES; i++)
errs += countBits8(sync[i] ^ syncBytes[i]);
if (errs <= maxBitErrs) {
m_maxCorr = corr;
m_lostCount = MAX_SYNC_FRAMES;
m_syncPtr = m_dataPtr;
m_startPtr = startPtr;
m_endPtr = m_dataPtr + M17_FRAME_LENGTH_SAMPLES - M17_SYNC_LENGTH_SAMPLES - 1U;
if (m_endPtr >= M17_FRAME_LENGTH_SAMPLES)
m_endPtr -= M17_FRAME_LENGTH_SAMPLES;
return true;
}
}
}
return false;
}
void CM17RX::calculateLevels(uint16_t start, uint16_t count)
{
q15_t maxPos = -16000;
q15_t minPos = 16000;
q15_t maxNeg = 16000;
q15_t minNeg = -16000;
for (uint16_t i = 0U; i < count; i++) {
q15_t sample = m_buffer[start];
if (sample > 0) {
if (sample > maxPos)
maxPos = sample;
if (sample < minPos)
minPos = sample;
} else {
if (sample < maxNeg)
maxNeg = sample;
if (sample > minNeg)
minNeg = sample;
}
start += M17_RADIO_SYMBOL_LENGTH;
if (start >= M17_FRAME_LENGTH_SAMPLES)
start -= M17_FRAME_LENGTH_SAMPLES;
}
q15_t posThresh = (maxPos + minPos) >> 1;
q15_t negThresh = (maxNeg + minNeg) >> 1;
q15_t centre = (posThresh + negThresh) >> 1;
q15_t threshold = posThresh - centre;
DEBUG5("M17RX: pos/neg/centre/threshold", posThresh, negThresh, centre, threshold);
if (m_averagePtr == NOAVEPTR) {
for (uint8_t i = 0U; i < 16U; i++) {
m_centre[i] = centre;
m_threshold[i] = threshold;
}
m_averagePtr = 0U;
} else {
m_centre[m_averagePtr] = centre;
m_threshold[m_averagePtr] = threshold;
m_averagePtr++;
if (m_averagePtr >= 16U)
m_averagePtr = 0U;
}
m_centreVal = 0;
m_thresholdVal = 0;
for (uint8_t i = 0U; i < 16U; i++) {
m_centreVal += m_centre[i];
m_thresholdVal += m_threshold[i];
}
m_centreVal >>= 4;
m_thresholdVal >>= 4;
}
void CM17RX::samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold)
{
for (uint16_t i = 0U; i < count; i++) {
q15_t sample = m_buffer[start] - centre;
if (sample < -threshold) {
WRITE_BIT1(buffer, offset, false);
offset++;
WRITE_BIT1(buffer, offset, true);
offset++;
} else if (sample < 0) {
WRITE_BIT1(buffer, offset, false);
offset++;
WRITE_BIT1(buffer, offset, false);
offset++;
} else if (sample < threshold) {
WRITE_BIT1(buffer, offset, true);
offset++;
WRITE_BIT1(buffer, offset, false);
offset++;
} else {
WRITE_BIT1(buffer, offset, true);
offset++;
WRITE_BIT1(buffer, offset, true);
offset++;
}
start += M17_RADIO_SYMBOL_LENGTH;
if (start >= M17_FRAME_LENGTH_SAMPLES)
start -= M17_FRAME_LENGTH_SAMPLES;
}
}
void CM17RX::writeRSSILinkSetup(uint8_t* data)
{
#if defined(SEND_RSSI_DATA)
if (m_rssiCount > 0U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
data[49U] = (rssi >> 8) & 0xFFU;
data[50U] = (rssi >> 0) & 0xFFU;
serial.writeM17LinkSetup(data, M17_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeM17LinkSetup(data, M17_FRAME_LENGTH_BYTES + 1U);
}
#else
serial.writeM17LinkSetup(data, M17_FRAME_LENGTH_BYTES + 1U);
#endif
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
void CM17RX::writeRSSIStream(uint8_t* data)
{
#if defined(SEND_RSSI_DATA)
if (m_rssiCount > 0U) {
uint16_t rssi = m_rssiAccum / m_rssiCount;
data[49U] = (rssi >> 8) & 0xFFU;
data[50U] = (rssi >> 0) & 0xFFU;
serial.writeM17Stream(data, M17_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeM17Stream(data, M17_FRAME_LENGTH_BYTES + 1U);
}
#else
serial.writeM17Stream(data, M17_FRAME_LENGTH_BYTES + 1U);
#endif
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
#endif
+77
View File
@@ -0,0 +1,77 @@
/*
* Copyright (C) 2015,2016,2017,2020,2021 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_M17)
#if !defined(M17RX_H)
#define M17RX_H
#include "M17Defines.h"
enum M17RX_STATE {
M17RXS_NONE,
M17RXS_LINK_SETUP,
M17RXS_STREAM
};
class CM17RX {
public:
CM17RX();
void samples(const q15_t* samples, uint16_t* rssi, uint8_t length);
void reset();
private:
M17RX_STATE m_state;
uint8_t m_bitBuffer[M17_RADIO_SYMBOL_LENGTH];
q15_t m_buffer[M17_FRAME_LENGTH_SAMPLES];
uint16_t m_bitPtr;
uint16_t m_dataPtr;
uint16_t m_startPtr;
uint16_t m_endPtr;
uint16_t m_syncPtr;
uint16_t m_minSyncPtr;
uint16_t m_maxSyncPtr;
q31_t m_maxCorr;
uint16_t m_lostCount;
uint8_t m_countdown;
M17RX_STATE m_nextState;
q15_t m_centre[16U];
q15_t m_centreVal;
q15_t m_threshold[16U];
q15_t m_thresholdVal;
uint8_t m_averagePtr;
uint32_t m_rssiAccum;
uint16_t m_rssiCount;
void processNone(q15_t sample);
void processData(q15_t sample);
bool correlateSync(uint8_t syncSymbols, const int8_t* syncSymbolValues, const uint8_t* syncBytes, uint8_t maxSymbolErrs, uint8_t maxBitErrs);
void calculateLevels(uint16_t start, uint16_t count);
void samplesToBits(uint16_t start, uint16_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
void writeRSSILinkSetup(uint8_t* data);
void writeRSSIStream(uint8_t* data);
};
#endif
#endif
+190
View File
@@ -0,0 +1,190 @@
/*
* Copyright (C) 2009-2018,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_M17)
#include "Globals.h"
#include "M17TX.h"
#include "M17Defines.h"
// Generated using rcosdesign(0.5, 8, 5, 'sqrt') in MATLAB
static q15_t RRC_0_5_FILTER[] = {0, 0, 0, 0, -290, -174, 142, 432, 438, 90, -387, -561, -155, 658, 1225, 767,
-980, -3326, -4648, -3062, 2527, 11552, 21705, 29724, 32767, 29724, 21705,
11552, 2527, -3062, -4648, -3326, -980, 767, 1225, 658, -155, -561, -387, 90,
438, 432, 142, -174, -290}; // numTaps = 45, L = 5
const uint16_t RRC_0_5_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
const q15_t M17_LEVELA = 1481;
const q15_t M17_LEVELB = 494;
const q15_t M17_LEVELC = -494;
const q15_t M17_LEVELD = -1481;
const uint8_t M17_START_SYNC = 0x77U;
const uint8_t M17_END_SYNC = 0xFFU;
const uint8_t M17_HANG = 0x00U;
CM17TX::CM17TX() :
m_buffer(TX_BUFFER_LEN),
m_modFilter(),
m_modState(),
m_poBuffer(),
m_poLen(0U),
m_poPtr(0U),
m_txDelay(240U), // 200ms
m_txHang(4800U), // 4s
m_txCount(0U)
{
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
m_modFilter.L = M17_RADIO_SYMBOL_LENGTH;
m_modFilter.phaseLength = RRC_0_5_FILTER_PHASE_LEN;
m_modFilter.pCoeffs = RRC_0_5_FILTER;
m_modFilter.pState = m_modState;
}
void CM17TX::process()
{
// If we have M17 data to transmit, do so.
if (m_poLen == 0U && m_buffer.getData() > 0U) {
if (!m_tx) {
for (uint16_t i = 0U; i < m_txDelay; i++)
m_poBuffer[m_poLen++] = M17_START_SYNC;
} else {
for (uint8_t i = 0U; i < M17_FRAME_LENGTH_BYTES; i++) {
uint8_t c = 0U;
m_buffer.get(c);
m_poBuffer[m_poLen++] = c;
}
}
m_poPtr = 0U;
}
if (m_poLen > 0U) {
// Transmit M17 data.
uint16_t space = io.getSpace();
while (space > (4U * M17_RADIO_SYMBOL_LENGTH)) {
uint8_t c = m_poBuffer[m_poPtr++];
writeByte(c);
// Reduce space and reset the hang timer.
space -= 4U * M17_RADIO_SYMBOL_LENGTH;
if (m_duplex)
m_txCount = m_txHang;
if (m_poPtr >= m_poLen) {
m_poPtr = 0U;
m_poLen = 0U;
return;
}
}
} else if (m_txCount > 0U) {
// Transmit silence until the hang timer has expired.
uint16_t space = io.getSpace();
while (space > (4U * M17_RADIO_SYMBOL_LENGTH)) {
writeSilence();
space -= 4U * M17_RADIO_SYMBOL_LENGTH;
m_txCount--;
if (m_txCount == 0U)
return;
}
}
}
uint8_t CM17TX::writeData(const uint8_t* data, uint8_t length)
{
if (length != (M17_FRAME_LENGTH_BYTES + 1U))
return 4U;
uint16_t space = m_buffer.getSpace();
if (space < M17_FRAME_LENGTH_BYTES)
return 5U;
for (uint8_t i = 0U; i < M17_FRAME_LENGTH_BYTES; i++)
m_buffer.put(data[i + 1U]);
return 0U;
}
void CM17TX::writeByte(uint8_t c)
{
q15_t inBuffer[4U];
q15_t outBuffer[M17_RADIO_SYMBOL_LENGTH * 4U];
const uint8_t MASK = 0xC0U;
for (uint8_t i = 0U; i < 4U; i++, c <<= 2) {
switch (c & MASK) {
case 0xC0U:
inBuffer[i] = M17_LEVELA;
break;
case 0x80U:
inBuffer[i] = M17_LEVELB;
break;
case 0x00U:
inBuffer[i] = M17_LEVELC;
break;
default:
inBuffer[i] = M17_LEVELD;
break;
}
}
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U);
io.write(STATE_M17, outBuffer, M17_RADIO_SYMBOL_LENGTH * 4U);
}
void CM17TX::writeSilence()
{
q15_t inBuffer[4U] = {0, 0, 0, 0};
q15_t outBuffer[M17_RADIO_SYMBOL_LENGTH * 4U];
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U);
io.write(STATE_M17, outBuffer, M17_RADIO_SYMBOL_LENGTH * 4U);
}
void CM17TX::setTXDelay(uint8_t delay)
{
m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay
if (m_txDelay > 1200U)
m_txDelay = 1200U;
}
uint8_t CM17TX::getSpace() const
{
return m_buffer.getSpace() / M17_FRAME_LENGTH_BYTES;
}
void CM17TX::setParams(uint8_t txHang)
{
m_txHang = txHang * 1200U;
}
#endif
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_M17)
#if !defined(M17TX_H)
#define M17TX_H
#include "RingBuffer.h"
class CM17TX {
public:
CM17TX();
uint8_t writeData(const uint8_t* data, uint8_t length);
void process();
void setTXDelay(uint8_t delay);
uint8_t getSpace() const;
void setParams(uint8_t txHang);
private:
CRingBuffer<uint8_t> m_buffer;
arm_fir_interpolate_instance_q15 m_modFilter;
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
uint8_t m_poBuffer[1200U];
uint16_t m_poLen;
uint16_t m_poPtr;
uint16_t m_txDelay;
uint32_t m_txHang;
uint32_t m_txCount;
void writeByte(uint8_t c);
void writeSilence();
};
#endif
#endif
+102 -35
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Mathis Schmieder DB9MAT
* Copyright (C) 2016 by Colin Durbridge G4EML
*
@@ -18,7 +18,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if defined(STM32F4XX) || defined(STM32F7XX) || defined(STM32F105xC)
#if defined(STM32F4XX) || defined(STM32F7XX)
#include "Config.h"
#include "Globals.h"
@@ -31,6 +31,7 @@ bool m_dmrEnable = true;
bool m_ysfEnable = true;
bool m_p25Enable = true;
bool m_nxdnEnable = true;
bool m_m17Enable = true;
bool m_pocsagEnable = true;
bool m_fmEnable = true;
bool m_ax25Enable = true;
@@ -40,39 +41,67 @@ bool m_duplex = true;
bool m_tx = false;
bool m_dcd = false;
CDStarRX dstarRX;
CDStarTX dstarTX;
CDMRIdleRX dmrIdleRX;
CDMRRX dmrRX;
CDMRTX dmrTX;
CDMRDMORX dmrDMORX;
CDMRDMOTX dmrDMOTX;
CYSFRX ysfRX;
CYSFTX ysfTX;
CP25RX p25RX;
CP25TX p25TX;
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CPOCSAGTX pocsagTX;
CFM fm;
CAX25RX ax25RX;
CAX25TX ax25TX;
#if defined(MODE_DSTAR)
CDStarRX dstarRX;
CDStarTX dstarTX;
CCalDStarRX calDStarRX;
CCalDStarTX calDStarTX;
CCalDMR calDMR;
CCalP25 calP25;
CCalNXDN calNXDN;
CCalFM calFM;
CCalPOCSAG calPOCSAG;
CCalRSSI calRSSI;
#endif
#if defined(MODE_DMR)
CDMRIdleRX dmrIdleRX;
CDMRRX dmrRX;
CDMRTX dmrTX;
CDMRDMORX dmrDMORX;
CDMRDMOTX dmrDMOTX;
CCalDMR calDMR;
#endif
#if defined(MODE_YSF)
CYSFRX ysfRX;
CYSFTX ysfTX;
#endif
#if defined(MODE_P25)
CP25RX p25RX;
CP25TX p25TX;
CCalP25 calP25;
#endif
#if defined(MODE_NXDN)
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalNXDN calNXDN;
#endif
#if defined(MODE_M17)
CM17RX m17RX;
CM17TX m17TX;
CCalM17 calM17;
#endif
#if defined(MODE_POCSAG)
CPOCSAGTX pocsagTX;
CCalPOCSAG calPOCSAG;
#endif
#if defined(MODE_FM)
CFM fm;
CCalFM calFM;
#endif
#if defined(MODE_AX25)
CAX25RX ax25RX;
CAX25TX ax25TX;
#endif
CCalRSSI calRSSI;
CCWIdTX cwIdTX;
@@ -91,51 +120,89 @@ void loop()
io.process();
// The following is for transmitting
#if defined(MODE_DSTAR)
if (m_dstarEnable && m_modemState == STATE_DSTAR)
dstarTX.process();
#endif
#if defined(MODE_DMR)
if (m_dmrEnable && m_modemState == STATE_DMR) {
if (m_duplex)
dmrTX.process();
else
dmrDMOTX.process();
}
#endif
#if defined(MODE_YSF)
if (m_ysfEnable && m_modemState == STATE_YSF)
ysfTX.process();
#endif
#if defined(MODE_P25)
if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process();
#endif
#if defined(MODE_NXDN)
if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process();
#endif
#if defined(MODE_M17)
if (m_m17Enable && m_modemState == STATE_M17)
m17TX.process();
#endif
#if defined(MODE_POCSAG)
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
pocsagTX.process();
#endif
#if defined(MODE_AX25)
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM))
ax25TX.process();
#endif
#if defined(MODE_FM)
if (m_fmEnable && m_modemState == STATE_FM)
fm.process();
#endif
#if defined(MODE_DSTAR)
if (m_modemState == STATE_DSTARCAL)
calDStarTX.process();
#endif
#if defined(MODE_DMR)
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
calDMR.process();
#endif
#if defined(MODE_FM)
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
calFM.process();
#endif
#if defined(MODE_P25)
if (m_modemState == STATE_P25CAL1K)
calP25.process();
#endif
#if defined(MODE_NXDN)
if (m_modemState == STATE_NXDNCAL1K)
calNXDN.process();
#endif
#if defined(MODE_M17)
if (m_modemState == STATE_M17CAL)
calM17.process();
#endif
#if defined(MODE_POCSAG)
if (m_modemState == STATE_POCSAGCAL)
calPOCSAG.process();
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K ||m_modemState == STATE_FMCAL30K)
calFM.process();
#endif
if (m_modemState == STATE_IDLE)
cwIdTX.process();
+99 -31
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2018,2020,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,7 @@ bool m_dmrEnable = true;
bool m_ysfEnable = true;
bool m_p25Enable = true;
bool m_nxdnEnable = true;
bool m_m17Enable = true;
bool m_pocsagEnable = true;
bool m_fmEnable = true;
bool m_ax25Enable = true;
@@ -37,39 +38,67 @@ bool m_duplex = true;
bool m_tx = false;
bool m_dcd = false;
CDStarRX dstarRX;
CDStarTX dstarTX;
CDMRIdleRX dmrIdleRX;
CDMRRX dmrRX;
CDMRTX dmrTX;
CDMRDMORX dmrDMORX;
CDMRDMOTX dmrDMOTX;
CYSFRX ysfRX;
CYSFTX ysfTX;
CP25RX p25RX;
CP25TX p25TX;
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CPOCSAGTX pocsagTX;
CFM fm;
CAX25RX ax25RX;
CAX25TX ax25TX;
#if defined(MODE_DSTAR)
CDStarRX dstarRX;
CDStarTX dstarTX;
CCalDStarRX calDStarRX;
CCalDStarTX calDStarTX;
CCalDMR calDMR;
CCalFM calFM;
CCalP25 calP25;
CCalNXDN calNXDN;
CCalPOCSAG calPOCSAG;
CCalRSSI calRSSI;
#endif
#if defined(MODE_DMR)
CDMRIdleRX dmrIdleRX;
CDMRRX dmrRX;
CDMRTX dmrTX;
CDMRDMORX dmrDMORX;
CDMRDMOTX dmrDMOTX;
CCalDMR calDMR;
#endif
#if defined(MODE_YSF)
CYSFRX ysfRX;
CYSFTX ysfTX;
#endif
#if defined(MODE_P25)
CP25RX p25RX;
CP25TX p25TX;
CCalP25 calP25;
#endif
#if defined(MODE_NXDN)
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalNXDN calNXDN;
#endif
#if defined(MODE_M17)
CM17RX m17RX;
CM17TX m17TX;
CCalM17 calM17;
#endif
#if defined(MODE_POCSAG)
CPOCSAGTX pocsagTX;
CCalPOCSAG calPOCSAG;
#endif
#if defined(MODE_FM)
CFM fm;
CCalFM calFM;
#endif
#if defined(MODE_AX25)
CAX25RX ax25RX;
CAX25TX ax25TX;
#endif
CCalRSSI calRSSI;
CCWIdTX cwIdTX;
@@ -88,52 +117,91 @@ void loop()
io.process();
// The following is for transmitting
#if defined(MODE_DSTAR)
if (m_dstarEnable && m_modemState == STATE_DSTAR)
dstarTX.process();
#endif
#if defined(MODE_DMR)
if (m_dmrEnable && m_modemState == STATE_DMR) {
if (m_duplex)
dmrTX.process();
else
dmrDMOTX.process();
}
#endif
#if defined(MODE_YSF)
if (m_ysfEnable && m_modemState == STATE_YSF)
ysfTX.process();
#endif
#if defined(MODE_P25)
if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process();
#endif
#if defined(MODE_NXDN)
if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process();
#endif
#if defined(MODE_M17)
if (m_m17Enable && m_modemState == STATE_M17)
m17TX.process();
#endif
#if defined(MODE_POCSAG)
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
pocsagTX.process();
#endif
#if defined(MODE_AX25)
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM))
ax25TX.process();
#endif
#if defined(MODE_FM)
if (m_fmEnable && m_modemState == STATE_FM)
fm.process();
#endif
#if defined(MODE_DSTAR)
if (m_modemState == STATE_DSTARCAL)
calDStarTX.process();
#endif
#if defined(MODE_DMR)
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
calDMR.process();
#endif
#if defined(MODE_FM)
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
calFM.process();
#endif
#if defined(MODE_P25)
if (m_modemState == STATE_P25CAL1K)
calP25.process();
#endif
#if defined(MODE_NXDN)
if (m_modemState == STATE_NXDNCAL1K)
calNXDN.process();
#endif
#if defined(MODE_M17)
if (m_modemState == STATE_M17CAL)
calM17.process();
#endif
#if defined(MODE_POCSAG)
if (m_modemState == STATE_POCSAGCAL)
calPOCSAG.process();
#endif
if (m_modemState == STATE_IDLE)
cwIdTX.process();
}
Binary file not shown.
+21 -9
View File
@@ -133,8 +133,10 @@ DEFS_PI_F722=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_PI -DHSE_VAL
DEFS_F7M=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_F7M -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# MMDVM_RPT_Hat F0DEI, DB9MAT, DF2ET board:
DEFS_RPT_HAT=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_RPT_HAT -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# STM32F4 DVM board:
# RB STM32F4_DVM board:
DEFS_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# RB STM32F7 DVM board:
DEFS_DVM722=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F7_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# MMDVM_RPT_Hat BG4TGO, BG5HHP board:
DEFS_RPT_HAT_TGO=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_RPT_HAT_TGO -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
# DRCC_DVM BG7NQF board:
@@ -222,17 +224,29 @@ f767: LDFLAGS+=$(LDFLAGS_F767)
f767: release_f7
dvm: GitVersion.h
dvm: CFLAGS+=$(CFLAGS_F4) $(DEFS_DVM)
dvm: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DVM)
dvm: CFLAGS+=$(CFLAGS_F4) $(DEFS_DVM) -DDRCC_DVM_446
dvm: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DVM) -DDRCC_DVM_446
dvm: LDFLAGS+=$(LDFLAGS_F4)
dvm: release_f4
dvm722: GitVersion.h
dvm722: CFLAGS+=$(CFLAGS_F7) $(DEFS_DVM722) -DDRCC_DVM_722
dvm722: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_DVM722) -DDRCC_DVM_722
dvm722: LDFLAGS+=$(LDFLAGS_F722)
dvm722: release_f7
drcc_nqf: GitVersion.h
drcc_nqf: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
drcc_nqf: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
drcc_nqf: LDFLAGS+=$(LDFLAGS_F4)
drcc_nqf: release_f4
hhp446: GitVersion.h
hhp446: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_HHP446
hhp446: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_HHP446
hhp446: LDFLAGS+=$(LDFLAGS_F4)
hhp446: release_f4
eda405: GitVersion.h
eda405: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_405)
eda405: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_405)
@@ -354,14 +368,12 @@ endif
deploy-pi:
ifneq ($(wildcard /usr/local/bin/stm32flash),)
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
-/usr/local/bin/stm32ld /dev/ttyAMA0 57600 bin/$(BINBIN_F4)
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R -c /dev/ttyAMA0
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R /dev/ttyAMA0
endif
ifneq ($(wildcard /usr/bin/stm32flash),)
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
-/usr/bin/stm32ld /dev/ttyAMA0 57600 bin/$(BINBIN_F4)
/usr/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R -c /dev/ttyAMA0
/usr/bin/stm32flash -v -w bin/$(BINBIN_F4) -g 0x0 -R /dev/ttyAMA0
endif
deploy-f4m: deploy-pi
@@ -372,11 +384,11 @@ deploy-eda446: deploy-pi
deploy-pi-f7:
ifneq ($(wildcard /usr/local/bin/stm32flash),)
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R -c /dev/ttyAMA0
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R /dev/ttyAMA0
else ifneq ($(wildcard /usr/bin/stm32flash),)
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
/usr/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R -c /dev/ttyAMA0
/usr/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R /dev/ttyAMA0
endif
deploy-f7m: deploy-pi-f7
-165
View File
@@ -1,165 +0,0 @@
# The name for the project
TARGET:=mmdvm
# The CPU architecture (will be used for -mcpu)
MCPU:=cortex-m3
MCU:=STM32F105xC
# The source files of the project
CSRC:=
CXXSRC:=$(wildcard *.cpp)
# Include directory for the system include files and system source file
SYSDIR:=system_stm32f1xx
SYSSRC:=$(SYSDIR)/system_stm32f1xx.c
# Other include directories
INCDIR:=
# Definitions
CDEFS:=
CXXDEFS:=
# The name of the startup file which matches to the architecture (MCPU)
STARTUP:=$(SYSDIR)/startup_stm32f105xc.S
STARTUP_DEFS=
# Include directory for CMSIS
CMSISDIR:=STM32F10X_Lib/CMSIS
# Libraries
LIBDIR:=
LIBS:=-larm_cortexM3l_math
# Name of the linker script
LDSCRIPT:=$(SYSDIR)/gcc.ld
# Target objects and binaries directory
OBJDIR:=obj
BINDIR:=bin
# Port definition for programming via bootloader (using stm32flash)
BL_PORT:=ttyUSB0
# Internal Variables
ELF:=$(BINDIR)/$(TARGET).elf
HEX:=$(BINDIR)/$(TARGET).hex
DIS:=$(BINDIR)/$(TARGET).dis
MAP:=$(BINDIR)/$(TARGET).map
OBJ:=$(CSRC:%.c=$(OBJDIR)/%.o) $(CXXSRC:%.cpp=$(OBJDIR)/%.o)
OBJ+=$(SYSSRC:$(SYSDIR)/%.c=$(OBJDIR)/%.o) $(STARTUP:$(SYSDIR)/%.S=$(OBJDIR)/%.o)
# Replace standard build tools by arm tools
CC:=arm-none-eabi-gcc
CXX:=arm-none-eabi-g++
AS:=arm-none-eabi-gcc
LD:=arm-none-eabi-g++
OBJCOPY:=arm-none-eabi-objcopy
OBJDUMP:=arm-none-eabi-objdump
SIZE:=arm-none-eabi-size
# Common flags
COMMON_FLAGS =-mthumb -mlittle-endian -mcpu=$(MCPU)
COMMON_FLAGS+= -Wall
COMMON_FLAGS+= -I. -I$(CMSISDIR)/Include -I$(CMSISDIR)/Device/ST/STM32F1xx/Include -I$(SYSDIR)
COMMON_FLAGS+= $(addprefix -I,$(INCDIR))
COMMON_FLAGS+= -D$(MCU) -DMADEBYMAKEFILE -DSTM32F1
COMMON_FLAGS+= -Os -flto -ffunction-sections -fdata-sections
COMMON_FLAGS+= -g
# Assembler flags
ASFLAGS:=$(COMMON_FLAGS)
# C flags
CFLAGS:=$(COMMON_FLAGS) $(addprefix -D,$(CDEFS))
CFLAGS+= -std=gnu11 -nostdlib
# CXX flags
CXXFLAGS:=$(COMMON_FLAGS) $(addprefix -D,$(CXXDEFS))
CXXFLAGS+= -nostdlib -fno-exceptions -fno-rtti
# LD flags
LDFLAGS:=$(COMMON_FLAGS) -Wl,--gc-sections -Wl,-Map=$(MAP) -Wl,--no-wchar-size-warning
LDFLAGS+= --specs=nosys.specs --specs=nano.specs
LDFLAGS+= -L$(CMSISDIR)/Lib/GCC/ $(addprefix -L,$(LIBDIR))
LDLIBS:=-T$(LDSCRIPT) $(LIBS)
# Dependecies
DEPENDS:=$(CSRC:%.c=$(OBJDIR)/%.d) $(CXXSRC:%.cpp=$(OBJDIR)/%.d)
# Additional Suffixes
.SUFFIXES: .elf .hex
# Targets
.PHONY: all
all: GitVersion.h $(DIS) $(HEX)
$(SIZE) $(ELF)
.PHONY: program
program: $(HEX) $(ELF)
openocd -f openocd.cfg \
-c "program $(HEX) verify reset exit"
$(SIZE) $(ELF)
.PHONY: program_bl
program_bl: $(HEX) $(ELF)
stm32flash -w $(HEX) -v /dev/$(BL_PORT)
$(SIZE) $(ELF)
.PHONY: run
run: $(HEX) $(ELF)
openocd -f openocd.cfg \
-c "init" -c "reset" -c "exit"
.PHONY: debug
debug: $(ELF)
./debug.sh $(ELF)
.PHONY: clean
clean:
$(RM) $(OBJ) $(HEX) $(ELF) $(DIS) $(MAP) $(DEPENDS) GitVersion.h
# implicit rules
.elf.hex:
$(OBJCOPY) -O ihex $< $@
$(OBJDIR)/%.o: %.c
$(CC) -MMD $(CFLAGS) -c $< -o $@
$(OBJDIR)/%.o: %.cpp
$(CXX) -MMD $(CXXFLAGS) -c $< -o $@
$(OBJDIR)/%.o: $(SYSDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR)/%.o: $(SYSDIR)/%.S
$(AS) $(ASFLAGS) -c $< -o $@
# explicit rules
$(OBJDIR):
mkdir -p $(OBJDIR)
$(BINDIR):
mkdir -p $(BINDIR)
$(ELF): $(OBJDIR) $(BINDIR) $(OBJ)
$(LD) $(OBJ) $(LDFLAGS) $(LDLIBS) -o $@
$(DIS): $(ELF)
$(OBJDUMP) -S $< > $@
# include dependecies
-include $(DEPENDS)
# Export the current git version if the index file exists, else 000...
GitVersion.h:
ifdef SYSTEMROOT
echo #define GITVERSION "0000000" > $@
else ifdef SystemRoot
echo #define GITVERSION "0000000" > $@
else
ifneq ("$(wildcard .git/index)","")
echo "#define GITVERSION \"$(shell git rev-parse --short HEAD)\"" > $@
else
echo "#define GITVERSION \"0000000\"" > $@
endif
endif
+6 -1
View File
@@ -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
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_NXDN)
#include "Globals.h"
#include "NXDNRX.h"
#include "Utils.h"
@@ -403,3 +406,5 @@ void CNXDNRX::writeRSSIData(uint8_t* data)
m_rssiCount = 0U;
}
#endif
+7 -2
View File
@@ -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
* it under the terms of the GNU General Public License as published by
@@ -16,10 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_NXDN)
#if !defined(NXDNRX_H)
#define NXDNRX_H
#include "Config.h"
#include "NXDNDefines.h"
enum NXDNRX_STATE {
@@ -67,3 +70,5 @@ private:
#endif
#endif
+7 -1
View File
@@ -18,6 +18,9 @@
*/
#include "Config.h"
#if defined(MODE_NXDN)
#include "Globals.h"
#include "NXDNTX.h"
@@ -172,7 +175,7 @@ void CNXDNTX::writeByte(uint8_t c)
void CNXDNTX::writeSilence()
{
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
q15_t inBuffer[4U] = {0, 0, 0, 0};
q15_t intBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
q15_t outBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
@@ -200,3 +203,6 @@ void CNXDNTX::setParams(uint8_t txHang)
{
m_txHang = txHang * 600U;
}
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_NXDN)
#if !defined(NXDNTX_H)
#define NXDNTX_H
#include "Config.h"
#include "RingBuffer.h"
class CNXDNTX {
@@ -55,3 +57,6 @@ private:
};
#endif
#endif
+7 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,9 @@
*/
#include "Config.h"
#if defined(MODE_P25)
#include "Globals.h"
#include "P25RX.h"
#include "Utils.h"
@@ -535,3 +538,6 @@ void CP25RX::writeRSSILdu(uint8_t* ldu)
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
#endif
+8 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Bryan Biedenkapp <gatekeep@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,10 +17,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_P25)
#if !defined(P25RX_H)
#define P25RX_H
#include "Config.h"
#include "P25Defines.h"
enum P25RX_STATE {
@@ -72,3 +75,6 @@ private:
};
#endif
#endif
+7 -1
View File
@@ -18,6 +18,9 @@
*/
#include "Config.h"
#if defined(MODE_P25)
#include "Globals.h"
#include "P25TX.h"
@@ -170,7 +173,7 @@ void CP25TX::writeByte(uint8_t c)
void CP25TX::writeSilence()
{
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
q15_t inBuffer[4U] = {0, 0, 0, 0};
q15_t intBuffer[P25_RADIO_SYMBOL_LENGTH * 4U];
q15_t outBuffer[P25_RADIO_SYMBOL_LENGTH * 4U];
@@ -198,3 +201,6 @@ void CP25TX::setParams(uint8_t txHang)
{
m_txHang = txHang * 1200U;
}
#endif
+7 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_P25)
#if !defined(P25TX_H)
#define P25TX_H
#include "Config.h"
#include "RingBuffer.h"
class CP25TX {
@@ -55,3 +57,6 @@ private:
};
#endif
#endif
+6
View File
@@ -17,6 +17,9 @@
*/
#include "Config.h"
#if defined(MODE_POCSAG)
#include "Globals.h"
#include "POCSAGTX.h"
@@ -147,3 +150,6 @@ uint8_t CPOCSAGTX::getSpace() const
{
return m_buffer.getSpace() / POCSAG_FRAME_LENGTH_BYTES;
}
#endif
+6 -2
View File
@@ -16,11 +16,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#if defined(MODE_POCSAG)
#if !defined(POCSAGTX_H)
#define POCSAGTX_H
#include "Config.h"
#include "RingBuffer.h"
class CPOCSAGTX {
@@ -51,3 +53,5 @@ private:
#endif
#endif
+32 -14
View File
@@ -1,17 +1,35 @@
This is the source code of the MMDVM firmware that supports D-Star, DMR,
System Fusion, P25, NXDN, POCSAG, and FM modes.
This is the source code of the MMDVM firmware that supports D-Star, DMR, System Fusion, P25, NXDN, M17, POCSAG, AX.25, 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, 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.
It runs on the Arduino Due, the ST-Micro STM32F4xxx and STM32F7xxx processors, as well as the Teensy 3.5/3.6. What these platforms have in common is the use of an ARM Cortex-M3, M4, or M7 processors with a minimum clock speed greater of 80 MHz, and access to at least one analogue to digital converter, one digital to analogue converter, as well as a number of GPIO pins.
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.
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 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 primarily intended for amateur and educational use.
Portions of the ARM support code include the following copyright:
Copyright (c) 2011 - 2013 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-47
View File
@@ -1,47 +0,0 @@
/*
* Copyright (C) 2017 Wojciech Krutnik N0CALL
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
* FIFO ring buffer
* source:
* http://stackoverflow.com/questions/6822548/correct-way-of-implementing-a-uart-receive-buffer-in-a-small-arm-microcontroller
* (modified)
*
*/
#if !defined(RINGBUFF_H)
#define RINGBUFF_H
#define RINGBUFF_SIZE(ringBuff) (ringBuff.size) /* serial buffer in bytes (power 2) */
#define RINGBUFF_MASK(ringBuff) (ringBuff.size-1U) /* buffer size mask */
/* Buffer read / write macros */
#define RINGBUFF_RESET(ringBuff) (ringBuff).rdIdx = ringBuff.wrIdx = 0
#define RINGBUFF_WRITE(ringBuff, dataIn) (ringBuff).data[RINGBUFF_MASK(ringBuff) & ringBuff.wrIdx++] = (dataIn)
#define RINGBUFF_READ(ringBuff) ((ringBuff).data[RINGBUFF_MASK(ringBuff) & ((ringBuff).rdIdx++)])
#define RINGBUFF_EMPTY(ringBuff) ((ringBuff).rdIdx == (ringBuff).wrIdx)
#define RINGBUFF_FULL(ringBuff) ((RINGBUFF_MASK(ringBuff) & ringFifo.rdIdx) == (RINGBUFF_MASK(ringBuff) & ringFifo.wrIdx))
#define RINGBUFF_COUNT(ringBuff) (RINGBUFF_MASK(ringBuff) & ((ringBuff).wrIdx - (ringBuff).rdIdx))
/* Buffer type */
#define DECLARE_RINGBUFFER_TYPE(name, _size) \
typedef struct{ \
uint32_t size; \
uint32_t wrIdx; \
uint32_t rdIdx; \
uint8_t data[_size]; \
}name##_t
#endif

Some files were not shown because too many files have changed in this diff Show More