Compare commits

..
Author SHA1 Message Date
Jonathan Naylor c2ba5ab273 Merge branch 'boxcar_dstar_correlator' into boxcar_dstar_correlator_48k 2018-01-11 07:29:33 +00:00
Jonathan Naylor 6098ac3e6d Merge branch 'boxcar' into boxcar_dstar_correlator 2018-01-11 07:29:04 +00:00
Jonathan Naylor c1f12705a9 Merge branch 'master' into boxcar 2018-01-11 07:28:42 +00:00
Jonathan Naylor 84ad5c47fc Merge branch 'boxcar_dstar_correlator' into boxcar_dstar_correlator_48k 2018-01-08 18:24:46 +00:00
Jonathan Naylor 373e1893bc Merge branch 'dstar_correlator' into boxcar_dstar_correlator 2018-01-08 18:24:16 +00:00
Jonathan Naylor aa52b03bc2 Merge branch 'master' into dstar_correlator 2018-01-08 18:23:55 +00:00
Jonathan Naylor 6192a88b98 Merge branch 'master' into boxcar 2018-01-08 18:23:07 +00:00
Jonathan Naylor a784ffeddf Merge branch 'boxcar_dstar_correlator' into boxcar_dstar_correlator_48k 2018-01-01 13:37:21 +00:00
Jonathan Naylor 017df518a6 Merge branch 'dstar_correlator' into boxcar_dstar_correlator 2018-01-01 13:36:34 +00:00
Jonathan Naylor cf849ccf65 Merge branch 'master' into dstar_correlator 2018-01-01 13:36:03 +00:00
Jonathan Naylor 8651e3a77b Merge branch 'master' into boxcar 2018-01-01 13:35:27 +00:00
Jonathan Naylor 6ae65ababa Merge branch 'boxcar_dstar_correlator' into boxcar_dstar_correlator_48k 2017-12-16 21:06:31 +00:00
Jonathan Naylor 83dd360062 Merge pull request #128 from F4FXL/dstar_correlator
Fixes erroneous end sync seen on station having QSB
2017-12-16 21:03:53 +00:00
Jonathan Naylor d298a5bde5 Merge pull request #129 from F4FXL/boxcar_dstar_correlator
Fixes erroneous end sync on stations having QSB
2017-12-16 21:03:38 +00:00
F4FXL 925263a216 Fixes erroneous end sync on stations having QSB 2017-12-16 09:04:31 +01:00
F4FXL 551aa3bb20 Fixes erroneous end of frame seen on station having QSB 2017-12-16 09:02:15 +01:00
Jonathan Naylor 151d068b80 Merge branch 'boxcar_dstar_correlator' into boxcar_dstar_correlator_48k 2017-11-06 09:34:22 +00:00
Jonathan Naylor c62a686d30 Merge branch 'master' into boxcar_dstar_correlator 2017-11-06 09:33:59 +00:00
Jonathan Naylor cb78220156 Merge branch 'master' into dstar_correlator 2017-11-06 09:33:44 +00:00
Jonathan Naylor cb00f4aba7 Merge branch 'master' into boxcar 2017-11-06 09:33:22 +00:00
Jonathan Naylor f7caeea07e Merge branch 'boxcar_dstar_correlator' into boxcar_dstar_correlator_48k 2017-10-30 14:07:29 +00:00
Jonathan Naylor 750ac02b7e Merge branch 'boxcar' into boxcar_dstar_correlator 2017-10-30 14:07:07 +00:00
Jonathan Naylor 22297c613c Merge branch 'master' into dstar_correlator 2017-10-30 14:06:42 +00:00
Jonathan Naylor 91a87f4581 Merge branch 'master' into boxcar 2017-10-30 14:06:06 +00:00
Jonathan Naylor 417555e515 Merge branch 'boxcar_dstar_correlator' into boxcar_dstar_correlator_48k 2017-10-28 12:47:15 +01:00
Jonathan Naylor 4ccc004de3 Merge branch 'master' into boxcar_dstar_correlator 2017-10-28 12:46:40 +01:00
Jonathan Naylor bf1de4f307 Merge branch 'master' into boxcar 2017-10-28 12:46:19 +01:00
Jonathan Naylor 24741a11c6 Merge branch 'master' into dstar_correlator 2017-10-28 12:45:40 +01:00
Jonathan Naylor bca8514060 Update the TODO list, it's now empty. 2017-10-24 22:11:52 +01:00
Jonathan Naylor a7aade4d81 Merge pull request #123 from juribeparada/boxcar_dstar_correlator_48k
More changes for 48 kHz
2017-10-16 09:23:47 +01:00
Andy CA6JAU 942b9365a6 Better way for sampling frequency calculation for MMDVM-Pi 2017-10-15 17:23:21 -03:00
Andy CA6JAU 4ac7d63af9 Adding 48 kHz in description (but shorting string) 2017-10-15 13:30:12 -03:00
Andy CA6JAU c911ec771c Merge branch 'boxcar_dstar_correlator_48k' of https://github.com/g4klx/MMDVM into boxcar_dstar_correlator_48k 2017-10-15 12:27:16 -03:00
Andy CA6JAU b1dceec444 Updating serial port watchdog for 48 kHz 2017-10-15 12:16:19 -03:00
Andy CA6JAU 6192d75c4a Removing 48 kHz string in description 2017-10-15 11:27:45 -03:00
Jonathan Naylor b2567f09dc Merge branch 'boxcar_dstar_correlator' into boxcar_dstar_correlator_48k 2017-10-15 13:22:12 +01:00
Jonathan Naylor 293a5b6912 Merge branch 'master' into dstar_correlator 2017-10-15 13:21:50 +01:00
Jonathan Naylor 442627dc35 Merge branch 'master' into boxcar_dstar_correlator 2017-10-15 13:21:16 +01:00
Jonathan Naylor 5f8a323dde Merge branch 'master' into boxcar 2017-10-15 13:20:52 +01:00
Andy CA6JAU b0f8cb8908 Fix D-Star for 48 kHz 2017-10-14 23:28:25 -03:00
Andy CA6JAU 2f766ffeea Increase DMR rssi buffer size 2017-10-14 21:17:55 -03:00
Andy CA6JAU 7ea9e692bb Merge branch 'boxcar_dstar_correlator_48k' of https://github.com/g4klx/MMDVM into boxcar_dstar_correlator_48k 2017-10-14 19:34:10 -03:00
Andy CA6JAU 7f251e1380 Additional changes for 48 kHz 2017-10-14 19:33:41 -03:00
Jonathan Naylor 30212eebad Merge pull request #121 from juribeparada/boxcar_dstar_correlator_48k
TX filter coefficients for 48 kHz
2017-10-14 20:54:01 +01:00
Andy CA6JAU 551eac3140 TX filter coefficients for 48 kHz 2017-10-14 12:18:43 -03:00
Jonathan Naylor e469294348 Change the hardware sample rate and ring buffer sizes. 2017-10-12 13:22:41 +01:00
Jonathan Naylor 4a8d2d5cd1 Begin conversion to 48 kHz sample rate. 2017-10-12 12:38:32 +01:00
Jonathan Naylor 11809a6baf Merge branch 'master' into boxcar_dstar_correlator 2017-10-02 16:35:46 +01:00
Jonathan Naylor 7e8d018242 Merge branch 'master' into dstar_correlator 2017-10-02 16:35:30 +01:00
Jonathan Naylor 436ca1d851 Merge branch 'master' into boxcar 2017-10-02 16:35:14 +01:00
Jonathan Naylor 1162354c43 Merge branch 'boxcar' into boxcar_dstar_correlator 2017-09-27 09:22:20 +01:00
Jonathan Naylor 3b84cf85c3 Merge branch 'master' into dstar_correlator 2017-09-27 09:21:56 +01:00
Jonathan Naylor ec34eb4a64 Merge branch 'master' into boxcar 2017-09-27 09:21:33 +01:00
Jonathan Naylor 9a5f932e6a Merge branch 'master' into boxcar_dstar_correlator 2017-09-10 14:41:12 +01:00
Jonathan Naylor ef8f5bb80b Merge branch 'master' into dstar_correlator 2017-09-10 14:40:40 +01:00
Jonathan Naylor b76e95b540 Merge branch 'master' into boxcar 2017-09-10 14:39:51 +01:00
Jonathan Naylor 0231ce38d5 Merge branch 'master' into boxcar_dstar_correlator 2017-09-07 09:03:48 +01:00
Jonathan Naylor 037810b23b Merge branch 'master' into dstar_correlator 2017-09-07 09:03:34 +01:00
Jonathan Naylor b017e75787 Merge branch 'master' into boxcar 2017-09-07 09:03:17 +01:00
Jonathan Naylor 8ff924e376 Merge branch 'master' into boxcar_dstar_correlator 2017-08-31 08:39:53 +01:00
Jonathan Naylor f7de632cd5 Merge branch 'master' into dstar_correlator 2017-08-31 08:39:36 +01:00
Jonathan Naylor 6221386873 Merge branch 'master' into boxcar 2017-08-31 08:39:15 +01:00
Jonathan Naylor cc3c676082 Merge branch 'master' into boxcar_dstar_correlator 2017-08-30 09:18:31 +01:00
Jonathan Naylor a554a86202 Merge branch 'master' into dstar_correlator 2017-08-30 09:18:11 +01:00
Jonathan Naylor 3c1b41c03f Merge branch 'master' into boxcar 2017-08-30 09:17:50 +01:00
Jonathan Naylor 4eda2b61f5 Merge pull request #109 from juribeparada/dstar_correlator
Adding support for STM32F767 dstar_correlator branch
2017-08-29 09:17:09 +01:00
Jonathan Naylor f06bd5125b Merge branch 'dstar_correlator' into dstar_correlator 2017-08-29 09:17:01 +01:00
Jonathan Naylor 84df334f52 Merge pull request #110 from juribeparada/boxcar_dstar_correlator
Adding support for STM32F767 boxcar_dstar_correlator branch
2017-08-29 09:15:45 +01:00
Jonathan Naylor b88a3d02bf Merge branch 'boxcar' into boxcar_dstar_correlator 2017-08-29 08:55:12 +01:00
Jonathan Naylor a0afe0e54f Merge branch 'master' into dstar_correlator 2017-08-29 08:50:44 +01:00
Jonathan Naylor 7e85a64a41 Remove compiler warning. 2017-08-29 08:37:48 +01:00
Jonathan Naylor c820b22524 Merge pull request #108 from juribeparada/boxcar
Adding support for STM32F767 boxcar branch
2017-08-29 07:24:25 +01:00
Andy CA6JAU 7fae32042f Fix typo 2017-08-28 23:07:30 -03:00
Andy CA6JAU edbf2b3ec0 Fix typo 2017-08-28 23:02:28 -03:00
Andy CA6JAU ac31999d9d Adding support for STM32F767 boxcar_dstar_correlator branch 2017-08-28 22:59:37 -03:00
Andy CA6JAU 2833ed2d2e Adding support for STM32F767 dstar_correlator branch 2017-08-28 22:42:26 -03:00
Andy CA6JAU ebd86df3ef Fix Config.h 2017-08-28 21:25:40 -03:00
Andy CA6JAU 918403c399 Adding support for STM32F767 boxcar branch 2017-08-28 21:18:06 -03:00
Andy CA6JAU 7c243af5da Merge branch 'boxcar' of https://github.com/g4klx/MMDVM into boxcar 2017-08-28 20:54:31 -03:00
Jonathan Naylor 2b502848c1 Adding watchdog to host serial port. 2017-08-20 16:07:28 +01:00
Jonathan Naylor d91a155084 Add watchdog to host serial port. 2017-08-20 15:59:48 +01:00
Jonathan Naylor 7bb042a6ca Adding watchdog to the host serial port. 2017-08-20 15:52:52 +01:00
Jonathan Naylor 14ce682210 Add optional TX DC offset. 2017-08-20 12:23:51 +01:00
Jonathan Naylor dc9d83f9f0 Add optional TX DC offset. 2017-08-20 12:19:04 +01:00
Jonathan Naylor fbd9c4d18b Add an optional TX DC offset. 2017-08-20 12:14:58 +01:00
Jonathan Naylor 76312c7bb9 Re-add the const qualifiers. 2017-08-18 11:04:06 +01:00
Jonathan Naylor 2a5690fd4d Re-add the const qualifiers. 2017-08-18 11:02:33 +01:00
Jonathan Naylor 58966406da Re-add the const qualifiers. 2017-08-18 11:00:25 +01:00
Jonathan Naylor 161736925e Optimise the DC offset processing. 2017-08-18 10:55:32 +01:00
Jonathan Naylor 9398d03e0b Optimised the DC offset processing. 2017-08-18 10:48:23 +01:00
Jonathan Naylor e707391a5e Optimise the DC offset removal. 2017-08-18 10:40:34 +01:00
Andy CA6JAU cff5a58bc7 Merge branch 'boxcar' of https://github.com/g4klx/MMDVM into boxcar 2017-08-13 17:19:50 -03:00
Jonathan Naylor 51577efd79 Merge branch 'master' into boxcar 2017-08-13 18:51:41 +01:00
Jonathan Naylor 064de9fef7 Merge branch 'dstar_correlator' into boxcar_dstar_correlator 2017-08-13 18:41:41 +01:00
Jonathan Naylor c43616f3c5 Enhancements suggested by IZ1MLT. 2017-08-13 18:40:05 +01:00
Jonathan Naylor e6adc0a296 Forgot the Q31 to Q15 conversion. 2017-08-02 20:38:46 +01:00
Jonathan Naylor 13f340917e Merge branch 'boxcar' into boxcar_dstar_correlator 2017-08-02 20:36:57 +01:00
Jonathan Naylor f195fd6f66 Merge branch 'master' into dstar_correlator 2017-08-02 19:39:15 +01:00
Jonathan Naylor 469be87dc3 Merge branch 'master' into boxcar 2017-07-31 21:58:16 +01:00
Jonathan Naylor 7f8a0a71f5 Merge branch 'boxcar' into boxcar_dstar_correlator 2017-07-20 21:44:39 +01:00
Jonathan Naylor 16a43db79a Further optimisation of the calculated values. 2017-07-17 21:26:39 +01:00
Jonathan Naylor a033b2db7b Adjust values slightly. 2017-07-17 21:16:24 +01:00
Jonathan Naylor 88ab312da0 Merge branch 'master' into dstar_correlator 2017-07-16 19:22:56 +01:00
Jonathan Naylor 8ce38eec9a Merge branch 'master' into boxcar 2017-07-16 19:01:54 +01:00
Jonathan Naylor 49383ca921 Get the RSSI working properly and simplify calculations. 2017-07-16 18:46:09 +01:00
Jonathan Naylor ed07175437 Tweak the settings. 2017-07-11 21:10:03 +01:00
Jonathan Naylor c8208ab1df Added extra debugging and updated position calculations. 2017-07-10 19:58:50 +01:00
Jonathan Naylor 68f0fa8132 Merge branch 'master' into boxcar 2017-07-10 19:45:47 +01:00
Andy CA6JAU 954131f73c Merge branch 'boxcar' of https://github.com/g4klx/MMDVM into boxcar 2017-07-06 19:55:34 -04:00
Andy CA6JAU 06ec4b79a5 Merge remote-tracking branch 'g4klx/master' into boxcar 2017-07-06 19:55:01 -04:00
Jonathan Naylor 90797696dd First compileable version, but untested. 2017-07-06 20:28:20 +01:00
Jonathan Naylor de0aed2d2b Increase amplitude of the boxcar filter. 2017-07-06 20:09:57 +01:00
Jonathan Naylor 4b253f888d Increase the boxcar level. 2017-07-03 20:29:52 +01:00
Jonathan Naylor c22f360ed1 More changes to the D-Star RX. 2017-07-03 20:26:24 +01:00
Jonathan Naylor 5d74c2f7bf First changes for correlation of D-Star. 2017-07-02 17:57:17 +01:00
Jonathan Naylor 316085f2a6 Try the boxcar filter on all modes. 2017-07-02 17:08:45 +01:00
40 changed files with 493 additions and 1657 deletions
+4 -4
View File
@@ -22,12 +22,12 @@
#include "CWIdTX.h"
q15_t TONE[] = {
0, 518, 1000, 1414, 1732, 1932, 2000, 1932, 1732, 1414, 1000, 518, 0, -518, -1000, -1414, -1732, -1932, -2000, -1932, -1732, -1414, -1000, -518};
0, 261, 518, 765, 1000, 1218, 1414, 1587, 1732, 1848, 1932, 1983, 2000, 1983, 1932, 1848, 1732, 1587, 1414, 1218, 1000, 765, 518, 261, 0, -261, -518, -765, -1000, -1218, -1414,
-1587, -1732, -1848, -1932, -1983, -2000, -1983, -1932, -1848, -1732, -1587, -1414, -1218, -1000, -765, -518, -261};
q15_t SILENCE[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const uint8_t CYCLE_LENGTH = 24U;
const uint8_t CYCLE_LENGTH = 48U;
const uint8_t DOT_LENGTH = 50U;
+4 -73
View File
@@ -21,37 +21,25 @@
#include "Globals.h"
#include "CalDMR.h"
// Voice LC BS Header, CC: 1, srcID: 1, dstID: TG9
// Voice LC Header, CC: 1, srcID: 1, dstID: TG9
const uint8_t VH_1K[] = {0x00U,
0x00U, 0x20U, 0x08U, 0x08U, 0x02U, 0x38U, 0x15U, 0x00U, 0x2CU, 0xA0U, 0x14U,
0x60U, 0x84U, 0x6DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xDEU, 0x30U, 0x30U,
0x01U, 0x10U, 0x01U, 0x40U, 0x03U, 0xC0U, 0x13U, 0xC1U, 0x1EU, 0x80U, 0x6FU};
// Voice Term BS with LC, CC: 1, srcID: 1, dstID: TG9
// Voice Term with LC, CC: 1, srcID: 1, dstID: TG9
const uint8_t VT_1K[] = {0x00U,
0x00U, 0x4FU, 0x08U, 0xDCU, 0x02U, 0x88U, 0x15U, 0x78U, 0x2CU, 0xD0U, 0x14U,
0xC0U, 0x84U, 0xADU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD9U, 0x65U, 0x24U,
0x02U, 0x28U, 0x06U, 0x20U, 0x0FU, 0x80U, 0x1BU, 0xC1U, 0x07U, 0x80U, 0x5CU};
// Voice LC MS Header, CC: 1, srcID: 1, dstID: TG9
const uint8_t VH_DMO1K[] = {0x00U,
0x00U, 0x20U, 0x08U, 0x08U, 0x02U, 0x38U, 0x15U, 0x00U, 0x2CU, 0xA0U, 0x14U,
0x60U, 0x84U, 0x6DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x7EU, 0x30U, 0x30U,
0x01U, 0x10U, 0x01U, 0x40U, 0x03U, 0xC0U, 0x13U, 0xC1U, 0x1EU, 0x80U, 0x6FU};
// Voice Term MS with LC, CC: 1, srcID: 1, dstID: TG9
const uint8_t VT_DMO1K[] = {0x00U,
0x00U, 0x4FU, 0x08U, 0xDCU, 0x02U, 0x88U, 0x15U, 0x78U, 0x2CU, 0xD0U, 0x14U,
0xC0U, 0x84U, 0xADU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x79U, 0x65U, 0x24U,
0x02U, 0x28U, 0x06U, 0x20U, 0x0FU, 0x80U, 0x1BU, 0xC1U, 0x07U, 0x80U, 0x5CU};
// Voice coding data + FEC, 1031 Hz Test Pattern
const uint8_t VOICE_1K[] = {0x00U,
0xCEU, 0xA8U, 0xFEU, 0x83U, 0xACU, 0xC4U, 0x58U, 0x20U, 0x0AU, 0xCEU, 0xA8U,
0xFEU, 0x83U, 0xA0U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x0CU, 0xC4U, 0x58U,
0x20U, 0x0AU, 0xCEU, 0xA8U, 0xFEU, 0x83U, 0xACU, 0xC4U, 0x58U, 0x20U, 0x0AU};
// Embedded LC BS: CC: 1, srcID: 1, dstID: TG9
// Embedded LC: CC: 1, srcID: 1, dstID: TG9
const uint8_t SYNCEMB_1K[6][7] = {
{0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U}, // BS VOICE SYNC (audio seq 0)
{0x01U, 0x30U, 0x00U, 0x00U, 0x90U, 0x09U, 0x10U}, // EMB + Embedded LC1 (audio seq 1)
@@ -60,15 +48,6 @@ const uint8_t SYNCEMB_1K[6][7] = {
{0x01U, 0x50U, 0xA1U, 0x71U, 0xD1U, 0x70U, 0x70U}, // EMB + Embedded LC4 (audio seq 4)
{0x01U, 0x10U, 0x00U, 0x00U, 0x00U, 0x0EU, 0x20U}}; // EMB (audio seq 5)
// Embedded LC MS: CC: 1, srcID: 1, dstID: TG9
const uint8_t SYNCEMB_DMO1K[6][7] = {
{0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U}, // MS VOICE SYNC (audio seq 0)
{0x01U, 0x30U, 0x00U, 0x00U, 0x90U, 0x09U, 0x10U}, // EMB + Embedded LC1 (audio seq 1)
{0x01U, 0x70U, 0x00U, 0x90U, 0x00U, 0x07U, 0x40U}, // EMB + Embedded LC2 (audio seq 2)
{0x01U, 0x70U, 0x00U, 0x31U, 0x40U, 0x07U, 0x40U}, // EMB + Embedded LC3 (audio seq 3)
{0x01U, 0x50U, 0xA1U, 0x71U, 0xD1U, 0x70U, 0x70U}, // EMB + Embedded LC4 (audio seq 4)
{0x01U, 0x10U, 0x00U, 0x00U, 0x00U, 0x0EU, 0x20U}}; // EMB (audio seq 5)
// Short LC:
// TS1: dstID: 0, ACTIVITY_NONE
// TS2: dstID: TG9, ACTIVITY_VOICE
@@ -99,9 +78,6 @@ void CCalDMR::process()
case STATE_DMRCAL1K:
dmr1kcal();
break;
case STATE_DMRDMO1K:
dmrdmo1k();
break;
default:
break;
}
@@ -118,17 +94,6 @@ void CCalDMR::createData1k(uint8_t n)
m_dmr1k[20U] |= SYNCEMB_1K[n][6] & 0xF0U;
}
void CCalDMR::createDataDMO1k(uint8_t n)
{
for(uint8_t i = 0; i < 5U; i++)
m_dmr1k[i + 15U] = SYNCEMB_DMO1K[n][i + 1U];
m_dmr1k[14U] &= 0xF0U;
m_dmr1k[20U] &= 0x0FU;
m_dmr1k[14U] |= SYNCEMB_DMO1K[n][0] & 0x0FU;
m_dmr1k[20U] |= SYNCEMB_DMO1K[n][6] & 0xF0U;
}
void CCalDMR::dmr1kcal()
{
dmrTX.process();
@@ -174,40 +139,6 @@ void CCalDMR::dmr1kcal()
}
}
void CCalDMR::dmrdmo1k()
{
dmrDMOTX.process();
uint16_t space = dmrDMOTX.getSpace();
if (space < 1U)
return;
switch (m_state) {
case DMRCAL1K_VH:
dmrDMOTX.writeData(VH_DMO1K, DMR_FRAME_LENGTH_BYTES + 1U);
m_state = DMRCAL1K_VOICE;
break;
case DMRCAL1K_VOICE:
createDataDMO1k(m_audioSeq);
dmrDMOTX.writeData(m_dmr1k, DMR_FRAME_LENGTH_BYTES + 1U);
if(m_audioSeq == 5U) {
m_audioSeq = 0U;
if(!m_transmit)
m_state = DMRCAL1K_VT;
} else
m_audioSeq++;
break;
case DMRCAL1K_VT:
dmrDMOTX.writeData(VT_DMO1K, DMR_FRAME_LENGTH_BYTES + 1U);
m_state = DMRCAL1K_IDLE;
break;
default:
m_state = DMRCAL1K_IDLE;
m_audioSeq = 0U;
break;
}
}
uint8_t CCalDMR::write(const uint8_t* data, uint8_t length)
{
if (length != 1U)
@@ -215,7 +146,7 @@ uint8_t CCalDMR::write(const uint8_t* data, uint8_t length)
m_transmit = data[0U] == 1U;
if(m_transmit && m_state == DMRCAL1K_IDLE && (m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K))
if(m_transmit && m_state == DMRCAL1K_IDLE && m_modemState == STATE_DMRCAL1K)
m_state = DMRCAL1K_VH;
return 0U;
-2
View File
@@ -37,9 +37,7 @@ public:
void process();
void dmr1kcal();
void dmrdmo1k();
void createData1k(uint8_t n);
void createDataDMO1k(uint8_t n);
uint8_t write(const uint8_t* data, uint8_t length);
+1 -1
View File
@@ -24,7 +24,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
-94
View File
@@ -1,94 +0,0 @@
/*
* Copyright (C) 2018 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"
#include "Globals.h"
#include "CalNXDN.h"
// NXDN 1031 Hz Test Pattern, RAN: 1, Unit ID: 1, Dst Group ID: 1, Outbound Direction
const uint8_t NXDN_CAL1K[4][49] = {
{0x00U,
0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x7CU, 0xFAU, 0x0AU, 0x6EU, 0x8AU, 0x23U, 0x56U, 0xE8U,
0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U,
0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U,
0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U,
0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U},
{0x00U,
0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x7CU, 0x6DU, 0xBBU, 0x0EU, 0xB3U, 0xA4U, 0x26U, 0xA8U,
0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U,
0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U,
0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U,
0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U},
{0x00U,
0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x76U, 0x3AU, 0x1BU, 0x4AU, 0x81U, 0xA8U, 0xE2U, 0x80U,
0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U,
0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U,
0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U,
0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U},
{0x00U,
0xCDU, 0xF5U, 0x9DU, 0x5DU, 0x74U, 0x28U, 0x83U, 0x02U, 0xB0U, 0x2DU, 0x07U, 0xE2U,
0x4CU, 0xAAU, 0xDEU, 0x8BU, 0x26U, 0xE4U, 0xF2U, 0x82U, 0x88U,
0xC6U, 0x8AU, 0x74U, 0x29U, 0xA4U, 0xECU, 0xD0U, 0x08U, 0x22U,
0xCEU, 0xA2U, 0xFCU, 0x01U, 0x8CU, 0xECU, 0xDAU, 0x0AU, 0xA0U,
0xEEU, 0x8AU, 0x7EU, 0x2BU, 0x26U, 0xCCU, 0xF8U, 0x8AU, 0x08U}};
CCalNXDN::CCalNXDN() :
m_transmit(false),
m_state(NXDNCAL1K_IDLE),
m_audioSeq(0U)
{
}
void CCalNXDN::process()
{
nxdnTX.process();
uint16_t space = nxdnTX.getSpace();
if (space < 1U)
return;
switch (m_state) {
case NXDNCAL1K_TX:
nxdnTX.writeData(NXDN_CAL1K[m_audioSeq], NXDN_FRAME_LENGTH_BYTES + 1U);
m_audioSeq = (m_audioSeq + 1U) % 4U;
if(!m_transmit)
m_state = NXDNCAL1K_IDLE;
break;
default:
m_state = NXDNCAL1K_IDLE;
m_audioSeq = 0U;
break;
}
}
uint8_t CCalNXDN::write(const uint8_t* data, uint8_t length)
{
if (length != 1U)
return 4U;
m_transmit = data[0U] == 1U;
if(m_transmit && m_state == NXDNCAL1K_IDLE)
m_state = NXDNCAL1K_TX;
return 0U;
}
-44
View File
@@ -1,44 +0,0 @@
/*
* Copyright (C) 2018 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.
*/
#if !defined(CALNXDN_H)
#define CALNXDN_H
#include "Config.h"
enum NXDNCAL1K {
NXDNCAL1K_IDLE,
NXDNCAL1K_TX
};
class CCalNXDN {
public:
CCalNXDN();
void process();
uint8_t write(const uint8_t* data, uint8_t length);
private:
bool m_transmit;
NXDNCAL1K m_state;
uint8_t m_audioSeq;
};
#endif
+1 -1
View File
@@ -22,7 +22,7 @@
#include "Config.h"
#include "DMRDefines.h"
const uint16_t DMO_BUFFER_LENGTH_SAMPLES = 1440U; // 60ms at 24 kHz
const uint16_t DMO_BUFFER_LENGTH_SAMPLES = 2880U; // 60ms at 48 kHz
enum DMORX_STATE {
DMORXS_NONE,
+10 -4
View File
@@ -22,10 +22,16 @@
#include "Globals.h"
#include "DMRSlotType.h"
// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 850, 219, -720, -1548, -1795, -1172, 237, 1927, 3120, 3073, 1447, -1431, -4544, -6442,
-5735, -1633, 5651, 14822, 23810, 30367, 32767, 30367, 23810, 14822, 5651, -1633, -5735, -6442,
-4544, -1431, 1447, 3073, 3120, 1927, 237, -1172, -1795, -1548, -720, 219, 850}; // numTaps = 45, L = 5
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 850, 592, 219, -234, -720, -1179,
-1548, -1769, -1795, -1597, -1172, -544, 237, 1092, 1927, 2637,
3120, 3286, 3073, 2454, 1447, 116, -1431, -3043, -4544, -5739,
-6442, -6483, -5735, -4121, -1633, 1669, 5651, 10118, 14822,
19484, 23810, 27520, 30367, 32156, 32767, 32156, 30367, 27520,
23810, 19484, 14822, 10118, 5651, 1669, -1633, -4121, -5735,
-6483, -6442, -5739, -4544, -3043, -1431, 116, 1447, 2454,
3073, 3286, 3120, 2637, 1927, 1092, 237, -544, -1172, -1597,
-1795, -1769, -1548, -1179, -720, -234, 219, 592, 850}; // numTaps = 90, L = 10
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
const q15_t DMR_LEVELA = 1362;
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2017 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,7 +19,7 @@
#if !defined(DMRDEFINES_H)
#define DMRDEFINES_H
const unsigned int DMR_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int DMR_RADIO_SYMBOL_LENGTH = 10U; // At 48 kHz sample rate
const unsigned int DMR_FRAME_LENGTH_BYTES = 33U;
const unsigned int DMR_FRAME_LENGTH_BITS = DMR_FRAME_LENGTH_BYTES * 8U;
+3 -3
View File
@@ -22,8 +22,8 @@
#include "DMRSlotType.h"
#include "Utils.h"
const uint16_t SCAN_START = 400U;
const uint16_t SCAN_END = 490U;
const uint16_t SCAN_START = 790U;
const uint16_t SCAN_END = 920U;
const q15_t SCALING_FACTOR = 19505; // Q15(0.60)
@@ -97,7 +97,7 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi)
return m_state != DMRRXS_NONE;
// Ensure that the buffer doesn't overflow
if (m_dataPtr > m_endPtr || m_dataPtr >= 900U)
if (m_dataPtr > m_endPtr || m_dataPtr >= 1900U)
return m_state != DMRRXS_NONE;
m_buffer[m_dataPtr] = sample;
+2 -2
View File
@@ -44,7 +44,7 @@ public:
private:
bool m_slot;
uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH];
q15_t m_buffer[900U];
q15_t m_buffer[1900U];
uint16_t m_bitPtr;
uint16_t m_dataPtr;
uint16_t m_syncPtr;
@@ -62,7 +62,7 @@ private:
DMRRX_STATE m_state;
uint8_t m_n;
uint8_t m_type;
uint16_t m_rssi[900U];
uint16_t m_rssi[1900U];
void correlateSync(bool first);
void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
Executable → Regular
+11 -16
View File
@@ -22,10 +22,16 @@
#include "Globals.h"
#include "DMRSlotType.h"
// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 850, 219, -720, -1548, -1795, -1172, 237, 1927, 3120, 3073, 1447, -1431, -4544, -6442,
-5735, -1633, 5651, 14822, 23810, 30367, 32767, 30367, 23810, 14822, 5651, -1633, -5735, -6442,
-4544, -1431, 1447, 3073, 3120, 1927, 237, -1172, -1795, -1548, -720, 219, 850}; // numTaps = 45, L = 5
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 850, 592, 219, -234, -720, -1179,
-1548, -1769, -1795, -1597, -1172, -544, 237, 1092, 1927, 2637,
3120, 3286, 3073, 2454, 1447, 116, -1431, -3043, -4544, -5739,
-6442, -6483, -5735, -4121, -1633, 1669, 5651, 10118, 14822,
19484, 23810, 27520, 30367, 32156, 32767, 32156, 30367, 27520,
23810, 19484, 14822, 10118, 5651, 1669, -1633, -4121, -5735,
-6483, -6442, -5739, -4544, -3043, -1431, 116, 1447, 2454,
3073, 3286, 3120, 2637, 1927, 1092, 237, -544, -1172, -1597,
-1795, -1769, -1548, -1179, -720, -234, 219, 592, 850}; // numTaps = 90, L = 10
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
const q15_t DMR_LEVELA = 1362;
@@ -54,7 +60,6 @@ const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
const uint32_t STARTUP_COUNT = 20U;
const uint32_t ABORT_COUNT = 6U;
CDMRTX::CDMRTX() :
m_fifo(),
@@ -70,7 +75,6 @@ m_poBuffer(),
m_poLen(0U),
m_poPtr(0U),
m_frameCount(0U),
m_abortCount(),
m_abort()
{
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
@@ -85,9 +89,6 @@ m_abort()
m_abort[0U] = false;
m_abort[1U] = false;
m_abortCount[0U] = 0U;
m_abortCount[1U] = 0U;
}
void CDMRTX::process()
@@ -215,12 +216,10 @@ uint8_t CDMRTX::writeAbort(const uint8_t* data, uint8_t length)
switch (data[0U]) {
case 1U:
m_abortCount[0U] = 0U;
m_abort[0U] = true;
return 0U;
case 2U:
m_abortCount[1U] = 0U;
m_abort[1U] = true;
return 0U;
@@ -234,8 +233,6 @@ void CDMRTX::setStart(bool start)
m_state = start ? DMRTXSTATE_SLOT1 : DMRTXSTATE_IDLE;
m_frameCount = 0U;
m_abortCount[0U] = 0U;
m_abortCount[1U] = 0U;
m_abort[0U] = false;
m_abort[1U] = false;
@@ -291,7 +288,7 @@ uint8_t CDMRTX::getSpace2() const
void CDMRTX::createData(uint8_t slotIndex)
{
if (m_fifo[slotIndex].getData() >= DMR_FRAME_LENGTH_BYTES && m_frameCount >= STARTUP_COUNT && m_abortCount[slotIndex] >= ABORT_COUNT) {
if (m_fifo[slotIndex].getData() > 0U && m_frameCount >= STARTUP_COUNT) {
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
m_poBuffer[i] = m_fifo[slotIndex].get();
m_markBuffer[i] = MARK_NONE;
@@ -344,8 +341,6 @@ void CDMRTX::createCal()
void CDMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex)
{
m_frameCount++;
m_abortCount[0U]++;
m_abortCount[1U]++;
if (m_cachPtr >= 12U)
m_cachPtr = 0U;
Executable → Regular
-1
View File
@@ -72,7 +72,6 @@ private:
uint16_t m_poLen;
uint16_t m_poPtr;
uint32_t m_frameCount;
uint32_t m_abortCount[2U];
bool m_abort[2U];
void createData(uint8_t slotIndex);
+37 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2015,2017 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 = 10U; // At 48 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
+238 -137
View File
@@ -22,18 +22,12 @@
#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 uint8_t FRAME_SYNC_ERRS = 2U;
const uint8_t FRAME_SYNC_ERRS = 1U;
// D-Star bit order version of 0x55 0x2D 0x16
const uint32_t DATA_SYNC_DATA = 0x00AAB468U;
@@ -237,14 +231,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 +263,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 +285,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");
::memset(m_rxBuffer, 0x00U, DSTAR_FEC_SECTION_LENGTH_BYTES);
m_rxBufferBits = 0U;
bool ret = correlateFrameSync();
if (ret) {
m_countdown = 5U;
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 = 952U;
m_syncPtr = 942U;
m_maxSyncPtr = 944U;
m_minSyncPtr = 940U;
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 (countBits32((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 +403,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 +428,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 +502,105 @@ void CDStarRX::writeRSSIData(unsigned char* data)
m_rssiCount = 0U;
}
bool CDStarRX::correlateFrameSync()
{
if (countBits32((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 (countBits32((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;
+20 -9
View File
@@ -37,13 +37,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;
uint32_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 +62,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);
+12 -10
View File
@@ -27,8 +27,10 @@ const uint8_t BIT_SYNC = 0xAAU;
const uint8_t FRAME_SYNC[] = {0xEAU, 0xA6U, 0x00U};
// Generated using gaussfir(0.35, 1, 5) in MATLAB
static q15_t GAUSSIAN_0_35_FILTER[] = {0, 0, 0, 0, 1001, 3514, 9333, 18751, 28499, 32767, 28499, 18751, 9333, 3514, 1001}; // numTaps = 15, L = 5
// Generated using gaussfir(0.35, 1, 10) in MATLAB
static q15_t GAUSSIAN_0_35_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1001, 1942, 3514, 5930,
9333, 13699, 18751, 23938, 28499, 31644, 32767, 31644,
28499, 23938, 18751, 13699, 9333, 5930, 3514, 1942, 1001}; // numTaps = 30, L = 10
const uint16_t GAUSSIAN_0_35_FILTER_PHASE_LEN = 3U; // phaseLength = numTaps/L
const q15_t DSTAR_LEVEL0 = -841;
@@ -196,9 +198,9 @@ m_poLen(0U),
m_poPtr(0U),
m_txDelay(60U) // 100ms
{
::memset(m_modState, 0x00U, 20U * sizeof(q15_t));
::memset(m_modState, 0x00U, 15U * 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;
@@ -252,8 +254,8 @@ void CDStarTX::process()
m_buffer.get();
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;
@@ -262,11 +264,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;
@@ -412,7 +414,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;
@@ -427,7 +429,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)
+1 -1
View File
@@ -40,7 +40,7 @@ public:
private:
CSerialRB m_buffer;
arm_fir_interpolate_instance_q15 m_modFilter;
q15_t m_modState[20U]; // blockSize + phaseLength - 1, 8 + 9 - 1 plus some spare
q15_t m_modState[15U]; // blockSize + phaseLength - 1, 8 + 3 - 1 plus some spare
uint8_t m_poBuffer[600U];
uint16_t m_poLen;
uint16_t m_poPtr;
+3 -14
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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
@@ -48,11 +48,8 @@ enum MMDVM_STATE {
STATE_DMR = 2,
STATE_YSF = 3,
STATE_P25 = 4,
STATE_NXDN = 5,
// Dummy states start at 90
STATE_NXDNCAL1K = 91,
STATE_DMRDMO1K = 92,
STATE_P25CAL1K = 93,
STATE_DMRCAL1K = 94,
STATE_LFCAL = 95,
@@ -74,13 +71,10 @@ enum MMDVM_STATE {
#include "YSFTX.h"
#include "P25RX.h"
#include "P25TX.h"
#include "NXDNRX.h"
#include "NXDNTX.h"
#include "CalDStarRX.h"
#include "CalDStarTX.h"
#include "CalDMR.h"
#include "CalP25.h"
#include "CalNXDN.h"
#include "CalRSSI.h"
#include "CWIdTX.h"
#include "Debug.h"
@@ -92,8 +86,8 @@ const uint8_t MARK_NONE = 0x00U;
const uint16_t RX_BLOCK_SIZE = 2U;
const uint16_t TX_RINGBUFFER_SIZE = 500U;
const uint16_t RX_RINGBUFFER_SIZE = 600U;
const uint16_t TX_RINGBUFFER_SIZE = 1000U;
const uint16_t RX_RINGBUFFER_SIZE = 1200U;
extern MMDVM_STATE m_modemState;
@@ -101,7 +95,6 @@ extern bool m_dstarEnable;
extern bool m_dmrEnable;
extern bool m_ysfEnable;
extern bool m_p25Enable;
extern bool m_nxdnEnable;
extern bool m_duplex;
@@ -127,14 +120,10 @@ extern CYSFTX ysfTX;
extern CP25RX p25RX;
extern CP25TX p25TX;
extern CNXDNRX nxdnRX;
extern CNXDNTX nxdnTX;
extern CCalDStarRX calDStarRX;
extern CCalDStarTX calDStarTX;
extern CCalDMR calDMR;
extern CCalP25 calP25;
extern CCalNXDN calNXDN;
extern CCalRSSI calRSSI;
extern CCWIdTX cwIdTX;
+38 -175
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML
*
@@ -23,34 +23,12 @@
#include "IO.h"
// Generated using [b, a] = butter(1, 0.001) in MATLAB
static q31_t DC_FILTER[] = {3367972, 0, 3367972, 0, 2140747704, 0}; // {b0, 0, b1, b2, -a1, -a2}
static q31_t DC_FILTER[] = {1685306, 0, 1685306, 0, 2144113034, 0}; // {b0, 0, b1, b2, -a1, -a2}
const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage
// 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;
// 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,
10134, 10731, 10935, 10731, 10134, 9184, 7946, 6502, 4946, 3376, 1886, 557, -545, -1375, -1914, -2164, -2150,
-1915, -1516, -1016, -477, 39, 483, 819, 1026, 1097, 1041, 880, 643, 364, 79, -181, -391, -533, -599, -590,
-517, -393, -240, -78, 73, 198, 284, 0};
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;
// 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;
// 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 BOXCAR_FILTER[] = {6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 0, 0};
const uint16_t BOXCAR_FILTER_LEN = 12U;
const uint16_t DC_OFFSET = 2048U;
@@ -61,18 +39,8 @@ m_txBuffer(TX_RINGBUFFER_SIZE),
m_rssiBuffer(RX_RINGBUFFER_SIZE),
m_dcFilter(),
m_dcState(),
m_dmrFilter(),
m_gaussianFilter(),
m_boxcarFilter(),
m_nxdnFilter(),
m_nxdnISincFilter(),
m_ysfFilter(),
m_dmrState(),
m_gaussianState(),
m_boxcarState(),
m_nxdnState(),
m_nxdnISincState(),
m_ysfState(),
m_pttInvert(false),
m_rxLevel(128 * 128),
m_cwIdTXLevel(128 * 128),
@@ -80,7 +48,6 @@ m_dstarTXLevel(128 * 128),
m_dmrTXLevel(128 * 128),
m_ysfTXLevel(128 * 128),
m_p25TXLevel(128 * 128),
m_nxdnTXLevel(128 * 128),
m_rxDCOffset(DC_OFFSET),
m_txDCOffset(DC_OFFSET),
m_ledCount(0U),
@@ -91,43 +58,18 @@ m_dacOverflow(0U),
m_watchdog(0U),
m_lockout(false)
{
::memset(m_dmrState, 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_ysfState, 0x00U, 70U * sizeof(q15_t));
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
::memset(m_boxcarState, 0x00U, 30U * sizeof(q15_t));
::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;
m_dmrFilter.numTaps = RRC_0_2_FILTER_LEN;
m_dmrFilter.pState = m_dmrState;
m_dmrFilter.pCoeffs = RRC_0_2_FILTER;
m_gaussianFilter.numTaps = GAUSSIAN_0_5_FILTER_LEN;
m_gaussianFilter.pState = m_gaussianState;
m_gaussianFilter.pCoeffs = GAUSSIAN_0_5_FILTER;
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;
m_nxdnISincFilter.numTaps = NXDN_ISINC_FILTER_LEN;
m_nxdnISincFilter.pState = m_nxdnISincState;
m_nxdnISincFilter.pCoeffs = NXDN_ISINC_FILTER;
m_ysfFilter.numTaps = RRC_0_2_FILTER_LEN;
m_ysfFilter.pState = m_ysfState;
m_ysfFilter.pCoeffs = RRC_0_2_FILTER;
initInt();
selfTest();
@@ -148,7 +90,6 @@ void CIO::selfTest()
setDMRInt(ledValue);
setYSFInt(ledValue);
setP25Int(ledValue);
setNXDNInt(ledValue);
#endif
delayInt(250);
}
@@ -158,7 +99,6 @@ void CIO::selfTest()
setDMRInt(false);
setYSFInt(false);
setP25Int(false);
setNXDNInt(false);
delayInt(250);
@@ -166,7 +106,6 @@ void CIO::selfTest()
setDMRInt(true);
setYSFInt(false);
setP25Int(false);
setNXDNInt(false);
delayInt(250);
@@ -174,7 +113,6 @@ void CIO::selfTest()
setDMRInt(true);
setYSFInt(true);
setP25Int(false);
setNXDNInt(false);
delayInt(250);
@@ -182,23 +120,6 @@ void CIO::selfTest()
setDMRInt(true);
setYSFInt(true);
setP25Int(true);
setNXDNInt(false);
delayInt(250);
setDStarInt(true);
setDMRInt(true);
setYSFInt(true);
setP25Int(true);
setNXDNInt(true);
delayInt(250);
setDStarInt(true);
setDMRInt(true);
setYSFInt(true);
setP25Int(true);
setNXDNInt(false);
delayInt(250);
@@ -206,7 +127,6 @@ void CIO::selfTest()
setDMRInt(true);
setYSFInt(true);
setP25Int(false);
setNXDNInt(false);
delayInt(250);
@@ -214,7 +134,6 @@ void CIO::selfTest()
setDMRInt(true);
setYSFInt(false);
setP25Int(false);
setNXDNInt(false);
delayInt(250);
@@ -222,7 +141,6 @@ void CIO::selfTest()
setDMRInt(false);
setYSFInt(false);
setP25Int(false);
setNXDNInt(false);
delayInt(250);
@@ -230,7 +148,6 @@ void CIO::selfTest()
setDMRInt(false);
setYSFInt(false);
setP25Int(false);
setNXDNInt(false);
#endif
}
@@ -251,8 +168,8 @@ void CIO::process()
m_ledCount++;
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) {
if (m_watchdog >= 96000U) {
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF) {
if (m_modemState == STATE_DMR && m_tx)
dmrTX.setStart(false);
m_modemState = STATE_IDLE;
@@ -262,13 +179,13 @@ void CIO::process()
m_watchdog = 0U;
}
if (m_ledCount >= 24000U) {
if (m_ledCount >= 48000U) {
m_ledCount = 0U;
m_ledValue = !m_ledValue;
setLEDInt(m_ledValue);
}
} else {
if (m_ledCount >= 240000U) {
if (m_ledCount >= 480000U) {
m_ledCount = 0U;
m_ledValue = !m_ledValue;
setLEDInt(m_ledValue);
@@ -308,12 +225,15 @@ void CIO::process()
if (m_lockout)
return;
q15_t vals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_boxcarFilter, samples, vals, RX_BLOCK_SIZE);
q31_t dcLevel = 0;
q31_t dcValues[RX_BLOCK_SIZE];
q31_t q31Samples[RX_BLOCK_SIZE];
q31_t q31Vals[RX_BLOCK_SIZE];
::arm_q15_to_q31(samples, q31Samples, RX_BLOCK_SIZE);
::arm_biquad_cascade_df1_q31(&m_dcFilter, q31Samples, dcValues, RX_BLOCK_SIZE);
::arm_q15_to_q31(vals, q31Vals, RX_BLOCK_SIZE);
::arm_biquad_cascade_df1_q31(&m_dcFilter, q31Vals, dcValues, RX_BLOCK_SIZE);
for (uint8_t i = 0U; i < RX_BLOCK_SIZE; i++)
dcLevel += dcValues[i];
@@ -321,100 +241,49 @@ void CIO::process()
q15_t offset = q15_t(__SSAT((dcLevel >> 16), 16));;
q15_t dcSamples[RX_BLOCK_SIZE];
q15_t dcVals[RX_BLOCK_SIZE];
for (uint8_t i = 0U; i < RX_BLOCK_SIZE; i++)
dcSamples[i] = samples[i] - offset;
dcVals[i] = vals[i] - offset;
if (m_modemState == STATE_IDLE) {
if (m_dstarEnable) {
q15_t GMSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_gaussianFilter, dcSamples, GMSKVals, RX_BLOCK_SIZE);
if (m_dstarEnable)
dstarRX.samples(dcVals, rssi, RX_BLOCK_SIZE);
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
}
if (m_p25Enable) {
q15_t P25Vals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, P25Vals, RX_BLOCK_SIZE);
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
}
if (m_nxdnEnable) {
q15_t NXDNVals[RX_BLOCK_SIZE];
q15_t NXDNValsTmp[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE);
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
}
if (m_ysfEnable) {
q15_t YSFVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_ysfFilter, dcSamples, YSFVals, RX_BLOCK_SIZE);
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
}
if (m_p25Enable)
p25RX.samples(dcVals, rssi, RX_BLOCK_SIZE);
if (m_dmrEnable) {
q15_t DMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_dmrFilter, samples, DMRVals, RX_BLOCK_SIZE);
if (m_duplex)
dmrIdleRX.samples(DMRVals, RX_BLOCK_SIZE);
dmrIdleRX.samples(vals, RX_BLOCK_SIZE);
else
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
dmrDMORX.samples(vals, rssi, RX_BLOCK_SIZE);
}
} else if (m_modemState == STATE_DSTAR) {
if (m_dstarEnable) {
q15_t GMSKVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_gaussianFilter, dcSamples, GMSKVals, RX_BLOCK_SIZE);
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
}
if (m_ysfEnable)
ysfRX.samples(dcVals, rssi, RX_BLOCK_SIZE);
} else if (m_modemState == STATE_DSTAR) {
if (m_dstarEnable)
dstarRX.samples(dcVals, rssi, RX_BLOCK_SIZE);
} else if (m_modemState == STATE_DMR) {
if (m_dmrEnable) {
q15_t DMRVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_dmrFilter, samples, DMRVals, RX_BLOCK_SIZE);
if (m_duplex) {
// If the transmitter isn't on, use the DMR idle RX to detect the wakeup CSBKs
if (m_tx)
dmrRX.samples(DMRVals, rssi, control, RX_BLOCK_SIZE);
dmrRX.samples(vals, rssi, control, RX_BLOCK_SIZE);
else
dmrIdleRX.samples(DMRVals, RX_BLOCK_SIZE);
dmrIdleRX.samples(vals, RX_BLOCK_SIZE);
} else {
dmrDMORX.samples(DMRVals, rssi, RX_BLOCK_SIZE);
dmrDMORX.samples(vals, rssi, RX_BLOCK_SIZE);
}
}
} else if (m_modemState == STATE_YSF) {
if (m_ysfEnable) {
q15_t YSFVals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_ysfFilter, dcSamples, YSFVals, RX_BLOCK_SIZE);
ysfRX.samples(YSFVals, rssi, RX_BLOCK_SIZE);
}
if (m_ysfEnable)
ysfRX.samples(dcVals, rssi, RX_BLOCK_SIZE);
} else if (m_modemState == STATE_P25) {
if (m_p25Enable) {
q15_t P25Vals[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, P25Vals, RX_BLOCK_SIZE);
p25RX.samples(P25Vals, rssi, RX_BLOCK_SIZE);
}
} else if (m_modemState == STATE_NXDN) {
if (m_nxdnEnable) {
q15_t NXDNVals[RX_BLOCK_SIZE];
q15_t NXDNValsTmp[RX_BLOCK_SIZE];
::arm_fir_fast_q15(&m_nxdnFilter, dcSamples, NXDNValsTmp, RX_BLOCK_SIZE);
::arm_fir_fast_q15(&m_nxdnISincFilter, NXDNValsTmp, NXDNVals, RX_BLOCK_SIZE);
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
}
if (m_p25Enable)
p25RX.samples(dcVals, rssi, RX_BLOCK_SIZE);
} 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);
calDStarRX.samples(vals, RX_BLOCK_SIZE);
} else if (m_modemState == STATE_RSSICAL) {
calRSSI.samples(rssi, RX_BLOCK_SIZE);
}
@@ -449,9 +318,6 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
case STATE_P25:
txLevel = m_p25TXLevel;
break;
case STATE_NXDN:
txLevel = m_nxdnTXLevel;
break;
default:
txLevel = m_cwIdTXLevel;
break;
@@ -498,11 +364,10 @@ void CIO::setMode()
setDMRInt(m_modemState == STATE_DMR);
setYSFInt(m_modemState == STATE_YSF);
setP25Int(m_modemState == STATE_P25);
setNXDNInt(m_modemState == STATE_NXDN);
#endif
}
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, int16_t txDCOffset, int16_t rxDCOffset)
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, int16_t txDCOffset, int16_t rxDCOffset)
{
m_pttInvert = pttInvert;
@@ -512,7 +377,6 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
m_dmrTXLevel = q15_t(dmrTXLevel * 128);
m_ysfTXLevel = q15_t(ysfTXLevel * 128);
m_p25TXLevel = q15_t(p25TXLevel * 128);
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
m_rxDCOffset = DC_OFFSET + rxDCOffset;
m_txDCOffset = DC_OFFSET + txDCOffset;
@@ -525,7 +389,6 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
m_dmrTXLevel = -m_dmrTXLevel;
m_ysfTXLevel = -m_ysfTXLevel;
m_p25TXLevel = -m_p25TXLevel;
m_nxdnTXLevel = -m_nxdnTXLevel;
}
}
+2 -14
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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
@@ -42,7 +42,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 nxdnLevel, int16_t txDCOffset, int16_t rxDCOffset);
void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, int16_t txDCOffset, int16_t rxDCOffset);
void getOverflow(bool& adcOverflow, bool& dacOverflow);
@@ -66,18 +66,8 @@ private:
arm_biquad_casd_df1_inst_q31 m_dcFilter;
q31_t m_dcState[4];
arm_fir_instance_q15 m_dmrFilter;
arm_fir_instance_q15 m_gaussianFilter;
arm_fir_instance_q15 m_boxcarFilter;
arm_fir_instance_q15 m_nxdnFilter;
arm_fir_instance_q15 m_nxdnISincFilter;
arm_fir_instance_q15 m_ysfFilter;
q15_t m_dmrState[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
q15_t m_ysfState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
bool m_pttInvert;
q15_t m_rxLevel;
@@ -86,7 +76,6 @@ private:
q15_t m_dmrTXLevel;
q15_t m_ysfTXLevel;
q15_t m_p25TXLevel;
q15_t m_nxdnTXLevel;
uint16_t m_rxDCOffset;
uint16_t m_txDCOffset;
@@ -117,7 +106,6 @@ private:
void setDMRInt(bool on);
void setYSFInt(bool on);
void setP25Int(bool on);
void setNXDNInt(bool on);
void delayInt(unsigned int dly);
};
+5 -15
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML
*
@@ -33,7 +33,6 @@
#define PIN_DMR 17
#define PIN_YSF 18
#define PIN_P25 19
#define PIN_NXDN 20
#define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7)
#define ADC_ISR_EOC_Chan ADC_ISR_EOC7
#define ADC_CDR_Chan 7
@@ -47,7 +46,6 @@
#define PIN_DMR 8
#define PIN_YSF 7
#define PIN_P25 6
#define PIN_NXDN 5
#define ADC_CHER_Chan (1<<13) // ADC on Due pin A11 - Due AD13 - (1 << 13)
#define ADC_ISR_EOC_Chan ADC_ISR_EOC13
#define ADC_CDR_Chan 13
@@ -63,7 +61,6 @@
#define PIN_DMR 8
#define PIN_YSF 7
#define PIN_P25 6
#define PIN_NXDN 5
#define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7)
#define ADC_ISR_EOC_Chan ADC_ISR_EOC7
#define ADC_CDR_Chan 7
@@ -98,7 +95,6 @@ void CIO::initInt()
pinMode(PIN_DMR, OUTPUT);
pinMode(PIN_YSF, OUTPUT);
pinMode(PIN_P25, OUTPUT);
pinMode(PIN_NXDN, OUTPUT);
#endif
}
@@ -144,11 +140,11 @@ void CIO::startInt()
TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_CLEAR |
TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_CLEAR;
#if defined(EXTERNAL_OSC)
t->TC_RC = EXTERNAL_OSC / 24000; // Counter resets on RC, so sets period in terms of the external clock
t->TC_RA = EXTERNAL_OSC / 48000; // Roughly square wave
t->TC_RC = EXTERNAL_OSC / 48000; // Counter resets on RC, so sets period in terms of the external clock
t->TC_RA = EXTERNAL_OSC / 96000; // Roughly square wave
#else
t->TC_RC = 1750; // Counter resets on RC, so sets period in terms of 42MHz internal clock
t->TC_RA = 880; // Roughly square wave
t->TC_RC = 875; // Counter resets on RC, so sets period in terms of 42MHz internal clock
t->TC_RA = 438; // Roughly square wave
#endif
t->TC_CMR = (t->TC_CMR & 0xFFF0FFFF) | TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET; // Set clear and set from RA and RC compares
t->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // re-enable local clocking and switch to hardware trigger source.
@@ -230,15 +226,9 @@ void CIO::setP25Int(bool on)
digitalWrite(PIN_P25, on ? HIGH : LOW);
}
void CIO::setNXDNInt(bool on)
{
digitalWrite(PIN_NXDN, on ? HIGH : LOW);
}
void CIO::delayInt(unsigned int dly)
{
delay(dly);
}
#endif
+4 -69
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 by Jonathan Naylor G4KLX
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
* Copyright (C) 2017 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
@@ -37,7 +37,6 @@ DSTAR PD12 output P1 Pin44
DMR PD13 output P1 Pin45
YSF PD14 output P1 Pin46
P25 PD11 output P1 Pin43
NXDN PD10 output P1 Pin42
RX PA0 analog input P1 Pin12
RSSI PA1 analog input P1 Pin11
@@ -66,10 +65,6 @@ EXT_CLK PA15 input P2 Pin40
#define PORT_P25 GPIOD
#define RCC_Per_P25 RCC_AHB1Periph_GPIOD
#define PIN_NXDN GPIO_Pin_10
#define PORT_NXDN GPIOD
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOD
#define PIN_DSTAR GPIO_Pin_12
#define PORT_DSTAR GPIOD
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOD
@@ -112,7 +107,6 @@ DSTAR PC7 output
DMR PC8 output
YSF PA8 output
P25 PC9 output
NXDN PB1 output
RX PA0 analog input
RSSI PA7 analog input
@@ -141,10 +135,6 @@ EXT_CLK PA15 input
#define PORT_P25 GPIOC
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC
#define PIN_NXDN GPIO_Pin_1
#define PORT_NXDN GPIOB
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOB
#define PIN_DSTAR GPIO_Pin_7
#define PORT_DSTAR GPIOC
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC
@@ -187,7 +177,6 @@ DSTAR PC7 output
DMR PC8 output
YSF PA8 output
P25 PC9 output
NXDN PB1 output
RX PA0 analog input
RSSI PA7 analog input
@@ -216,10 +205,6 @@ EXT_CLK PA15 input
#define PORT_P25 GPIOC
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC
#define PIN_NXDN GPIO_Pin_1
#define PORT_NXDN GPIOB
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOB
#define PIN_DSTAR GPIO_Pin_7
#define PORT_DSTAR GPIOC
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC
@@ -262,7 +247,6 @@ DSTAR PC7 output
DMR PC8 output
YSF PA8 output
P25 PC9 output
NXDN PB1 output
RX PA0 analog input
RSSI PA7 analog input
@@ -291,10 +275,6 @@ EXT_CLK PA15 input
#define PORT_P25 GPIOC
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC
#define PIN_NXDN GPIO_Pin_1
#define PORT_NXDN GPIOB
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOB
#define PIN_DSTAR GPIO_Pin_7
#define PORT_DSTAR GPIOC
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOC
@@ -339,13 +319,11 @@ DSTAR PB10 output CN10 Pin25
DMR PB4 output CN10 Pin27
YSF PB5 output CN10 Pin29
P25 PB3 output CN10 Pin31
NXDN PA10 output CN10 Pin33
MDSTAR PC4 output CN10 Pin34
MDMR PC5 output CN10 Pin6
MYSF PC2 output CN7 Pin35
MP25 PC3 output CN7 Pin37
MNXDN PC6 output CN10 Pin4
RX PA0 analog input CN7 Pin28
RSSI PA1 analog input CN7 Pin30
@@ -374,10 +352,6 @@ EXT_CLK PA15 input CN7 Pin17
#define PORT_P25 GPIOB
#define RCC_Per_P25 RCC_AHB1Periph_GPIOB
#define PIN_NXDN GPIO_Pin_10
#define PORT_NXDN GPIOA
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOA
#define PIN_DSTAR GPIO_Pin_10
#define PORT_DSTAR GPIOB
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOB
@@ -395,10 +369,6 @@ EXT_CLK PA15 input CN7 Pin17
#define PORT_MP25 GPIOC
#define RCC_Per_MP25 RCC_AHB1Periph_GPIOC
#define PIN_MNXDN GPIO_Pin_6
#define PORT_MNXDN GPIOC
#define RCC_Per_MNXDN RCC_AHB1Periph_GPIOC
#define PIN_MDSTAR GPIO_Pin_4
#define PORT_MDSTAR GPIOC
#define RCC_Per_MDSTAR RCC_AHB1Periph_GPIOC
@@ -442,7 +412,6 @@ DSTAR PA1 output CN8 Pin2
DMR PA4 output CN8 Pin3
YSF PB0 output CN8 Pin4
P25 PC1 output CN8 Pin5
NXDN PC0 output CN8 Pin6
RX PA0 analog input CN8 Pin1
RSSI PC0 analog input CN8 Pin6
@@ -471,10 +440,6 @@ EXT_CLK PB8 input CN5 Pin10
#define PORT_P25 GPIOC
#define RCC_Per_P25 RCC_AHB1Periph_GPIOC
#define PIN_NXDN GPIO_Pin_0
#define PORT_NXDN GPIOC
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOC
#define PIN_DSTAR GPIO_Pin_1
#define PORT_DSTAR GPIOA
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOA
@@ -521,13 +486,11 @@ DSTAR PB10 output CN12 Pin25
DMR PB4 output CN12 Pin27
YSF PB5 output CN12 Pin29
P25 PB3 output CN12 Pin31
NXDN PA10 output CN12 Pin33
MDSTAR PC4 output CN12 Pin34
MDMR PC5 output CN12 Pin6
MYSF PC2 output CN11 Pin35
MP25 PC3 output CN11 Pin37
MNXDN PC6 output CN12 Pin4
RX PA0 analog input CN11 Pin28
RSSI PA1 analog input CN11 Pin30
@@ -556,10 +519,6 @@ EXT_CLK PA15 input CN11 Pin17
#define PORT_P25 GPIOB
#define RCC_Per_P25 RCC_AHB1Periph_GPIOB
#define PIN_NXDN GPIO_Pin_10
#define PORT_NXDN GPIOA
#define RCC_Per_NXDN RCC_AHB1Periph_GPIOA
#define PIN_DSTAR GPIO_Pin_10
#define PORT_DSTAR GPIOB
#define RCC_Per_DSTAR RCC_AHB1Periph_GPIOB
@@ -577,10 +536,6 @@ EXT_CLK PA15 input CN11 Pin17
#define PORT_MP25 GPIOC
#define RCC_Per_MP25 RCC_AHB1Periph_GPIOC
#define PIN_MNXDN GPIO_Pin_6
#define PORT_MNXDN GPIOC
#define RCC_Per_MNXDN RCC_AHB1Periph_GPIOC
#define PIN_MDSTAR GPIO_Pin_4
#define PORT_MDSTAR GPIOC
#define RCC_Per_MDSTAR RCC_AHB1Periph_GPIOC
@@ -618,7 +573,7 @@ EXT_CLK PA15 input CN11 Pin17
const uint16_t DC_OFFSET = 2048U;
// Sampling frequency
#define SAMP_FREQ 24000
#define SAMP_FREQ 48000
extern "C" {
void TIM2_IRQHandler() {
@@ -685,12 +640,6 @@ void CIO::initInt()
GPIO_InitStruct.GPIO_Pin = PIN_P25;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_P25, &GPIO_InitStruct);
// NXDN pin
RCC_AHB1PeriphClockCmd(RCC_Per_NXDN, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_NXDN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_NXDN, &GPIO_InitStruct);
#endif
#if defined(STM32F4_NUCLEO_MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && defined(STM32F4_NUCLEO)
@@ -717,12 +666,6 @@ void CIO::initInt()
GPIO_InitStruct.GPIO_Pin = PIN_MP25;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MP25, &GPIO_InitStruct);
// NXDN mode pin
RCC_AHB1PeriphClockCmd(RCC_Per_MNXDN, ENABLE);
GPIO_InitStruct.GPIO_Pin = PIN_MNXDN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(PORT_MNXDN, &GPIO_InitStruct);
#endif
}
@@ -912,7 +855,7 @@ void CIO::interrupt()
bool CIO::getCOSInt()
{
return GPIO_ReadInputDataBit(PORT_COS, PIN_COS) == Bit_SET;
return GPIO_ReadOutputDataBit(PORT_COS, PIN_COS) == Bit_SET;
}
void CIO::setLEDInt(bool on)
@@ -962,14 +905,6 @@ void CIO::setP25Int(bool on)
#endif
}
void CIO::setNXDNInt(bool on)
{
GPIO_WriteBit(PORT_NXDN, PIN_NXDN, on ? Bit_SET : Bit_RESET);
#if defined(STM32F4_NUCLEO_MODE_PINS) && defined(STM32F4_NUCLEO_MORPHO_HEADER) && defined(STM32F4_NUCLEO)
GPIO_WriteBit(PORT_MNXDN, PIN_MNXDN, on ? Bit_SET : Bit_RESET);
#endif
}
// Simple delay function for STM32
// Example from: http://thehackerworkshop.com/?p=1209
void CIO::delayInt(unsigned int dly)
+2 -12
View File
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
* Copyright (C) 2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Wojciech Krutnik N0CALL
*
* This program is free software; you can redistribute it and/or modify
@@ -39,7 +39,6 @@ DSTAR PB7 output
DMR PB6 output
YSF PB8 output
P25 PB9 output
NXDN PB10 output
RX PB0 analog input (ADC1_8)
RSSI PB1 analog input (ADC2_9)
@@ -77,9 +76,6 @@ USART1_RXD PA10 input (AF)
#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_RX 0
#define PIN_RX_ADC_CH 8
@@ -107,7 +103,7 @@ USART1_RXD PA10 input (AF)
const uint16_t DC_OFFSET = 2048U;
// Sampling frequency
#define SAMP_FREQ 24000
#define SAMP_FREQ 48000
extern "C" {
void TIM2_IRQHandler() {
@@ -218,7 +214,6 @@ static inline void GPIOInit()
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);
GPIOConfigPin(PORT_NXDN, PIN_NXDN, GPIO_CRL_MODE0_1);
GPIOConfigPin(PORT_RX, PIN_RX, 0);
#if defined(SEND_RSSI_DATA)
@@ -429,11 +424,6 @@ void CIO::setP25Int(bool on)
BB_P25 = !!on;
}
void CIO::setNXDNInt(bool on)
{
BB_NXDN = !!on;
}
void CIO::delayInt(unsigned int dly)
{
delay(dly);
+5 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2016,2017 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
@@ -34,7 +34,6 @@
#define PIN_DMR 10
#define PIN_YSF 11
#define PIN_P25 12
#define PIN_NXDN 8
#define PIN_ADC 5 // A0, Pin 14
#define PIN_RSSI 4 // Teensy 3.5/3.6, A16, Pin 35. Teensy 3.1/3.2, A17, Pin 28
@@ -64,7 +63,6 @@ void CIO::initInt()
pinMode(PIN_DMR, OUTPUT);
pinMode(PIN_YSF, OUTPUT);
pinMode(PIN_P25, OUTPUT);
pinMode(PIN_NXDN, OUTPUT);
#endif
}
@@ -114,7 +112,7 @@ void CIO::startInt()
#endif
#if defined(EXTERNAL_OSC)
// Set ADC0 to trigger from the LPTMR at 24 kHz
// Set ADC0 to trigger from the LPTMR at 48 kHz
SIM_SOPT7 = SIM_SOPT7_ADC0ALTTRGEN | // Enable ADC0 alternate trigger
SIM_SOPT7_ADC0TRGSEL(14); // Trigger ADC0 by LPTMR0
@@ -123,14 +121,14 @@ void CIO::startInt()
SIM_SCGC5 |= SIM_SCGC5_LPTIMER; // Enable Low Power Timer Access
LPTMR0_CSR = 0; // Disable
LPTMR0_PSR = LPTMR_PSR_PBYP; // Bypass prescaler/filter
LPTMR0_CMR = (EXTERNAL_OSC / 24000) - 1; // Frequency divided by CMR + 1
LPTMR0_CMR = (EXTERNAL_OSC / 48000) - 1; // Frequency divided by CMR + 1
LPTMR0_CSR = LPTMR_CSR_TPS(2) | // Pin: 0=CMP0, 1=xtal, 2=pin13
LPTMR_CSR_TMS; // Mode Select, 0=timer, 1=counter
LPTMR0_CSR |= LPTMR_CSR_TEN; // Enable
#else
// Setup PDB for ADC0 at 24 kHz
// Setup PDB for ADC0 at 48 kHz
SIM_SCGC6 |= SIM_SCGC6_PDB; // Enable PDB clock
PDB0_MOD = (F_BUS / 24000) - 1; // Timer period - 1
PDB0_MOD = (F_BUS / 48000) - 1; // Timer period - 1
PDB0_IDLY = 0; // Interrupt delay
PDB0_CH0C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-trigger for ADC0
PDB0_SC = PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | // SW trigger, enable interrupts, continuous mode
@@ -212,11 +210,6 @@ void CIO::setP25Int(bool on)
digitalWrite(PIN_P25, on ? HIGH : LOW);
}
void CIO::setNXDNInt(bool on)
{
digitalWrite(PIN_NXDN, on ? HIGH : LOW);
}
void CIO::delayInt(unsigned int dly)
{
delay(dly);
+3 -13
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Mathis Schmieder DB9MAT
* Copyright (C) 2016 by Colin Durbridge G4EML
*
@@ -30,7 +30,6 @@ bool m_dstarEnable = true;
bool m_dmrEnable = true;
bool m_ysfEnable = true;
bool m_p25Enable = true;
bool m_nxdnEnable = true;
bool m_duplex = true;
@@ -53,14 +52,10 @@ CYSFTX ysfTX;
CP25RX p25RX;
CP25TX p25TX;
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalDStarRX calDStarRX;
CCalDStarTX calDStarTX;
CCalDMR calDMR;
CCalP25 calP25;
CCalNXDN calNXDN;
CCalRSSI calRSSI;
CCWIdTX cwIdTX;
@@ -96,21 +91,15 @@ void loop()
if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process();
if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process();
if (m_modemState == STATE_DSTARCAL)
calDStarTX.process();
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K)
calDMR.process();
if (m_modemState == STATE_P25CAL1K)
calP25.process();
if (m_modemState == STATE_NXDNCAL1K)
calNXDN.process();
if (m_modemState == STATE_IDLE)
cwIdTX.process();
}
@@ -124,3 +113,4 @@ int main()
}
#endif
+2 -13
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,6 @@ bool m_dstarEnable = true;
bool m_dmrEnable = true;
bool m_ysfEnable = true;
bool m_p25Enable = true;
bool m_nxdnEnable = true;
bool m_duplex = true;
@@ -50,14 +49,10 @@ CYSFTX ysfTX;
CP25RX p25RX;
CP25TX p25TX;
CNXDNRX nxdnRX;
CNXDNTX nxdnTX;
CCalDStarRX calDStarRX;
CCalDStarTX calDStarTX;
CCalDMR calDMR;
CCalP25 calP25;
CCalNXDN calNXDN;
CCalRSSI calRSSI;
CCWIdTX cwIdTX;
@@ -93,21 +88,15 @@ void loop()
if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process();
if (m_nxdnEnable && m_modemState == STATE_NXDN)
nxdnTX.process();
if (m_modemState == STATE_DSTARCAL)
calDStarTX.process();
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K)
calDMR.process();
if (m_modemState == STATE_P25CAL1K)
calP25.process();
if (m_modemState == STATE_NXDNCAL1K)
calNXDN.process();
if (m_modemState == STATE_IDLE)
cwIdTX.process();
}
-50
View File
@@ -1,50 +0,0 @@
/*
* Copyright (C) 2016,2017,2018 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(NXDNDEFINES_H)
#define NXDNDEFINES_H
const unsigned int NXDN_RADIO_SYMBOL_LENGTH = 10U; // At 24 kHz sample rate
const unsigned int NXDN_FRAME_LENGTH_BITS = 384U;
const unsigned int NXDN_FRAME_LENGTH_BYTES = NXDN_FRAME_LENGTH_BITS / 8U;
const unsigned int NXDN_FRAME_LENGTH_SYMBOLS = NXDN_FRAME_LENGTH_BITS / 2U;
const unsigned int NXDN_FRAME_LENGTH_SAMPLES = NXDN_FRAME_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH;
const unsigned int NXDN_FSW_LENGTH_BITS = 20U;
const unsigned int NXDN_FSW_LENGTH_SYMBOLS = NXDN_FSW_LENGTH_BITS / 2U;
const unsigned int NXDN_FSW_LENGTH_SAMPLES = NXDN_FSW_LENGTH_SYMBOLS * NXDN_RADIO_SYMBOL_LENGTH;
const uint8_t NXDN_FSW_BYTES[] = {0xCDU, 0xF5U, 0x90U};
const uint8_t NXDN_FSW_BYTES_MASK[] = {0xFFU, 0xFFU, 0xF0U};
const uint8_t NXDN_FSW_BYTES_LENGTH = 3U;
const uint32_t NXDN_FSW_BITS = 0x000CDF59U;
const uint32_t NXDN_FSW_BITS_MASK = 0x000FFFFFU;
// C D F 5 9
// 11 00 11 01 11 11 01 01 10 01
// -3 +1 -3 +3 -3 -3 +3 +3 -1 +3
const int8_t NXDN_FSW_SYMBOLS_VALUES[] = {-3, +1, -3, +3, -3, -3, +3, +3, -1, +3};
const uint16_t NXDN_FSW_SYMBOLS = 0x014DU;
const uint16_t NXDN_FSW_SYMBOLS_MASK = 0x03FFU;
#endif
-405
View File
@@ -1,405 +0,0 @@
/*
* Copyright (C) 2009-2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#include "Globals.h"
#include "NXDNRX.h"
#include "Utils.h"
const q15_t SCALING_FACTOR = 18750; // Q15(0.55)
const uint8_t MAX_FSW_BIT_START_ERRS = 1U;
const uint8_t MAX_FSW_BIT_RUN_ERRS = 3U;
const uint8_t MAX_FSW_SYMBOLS_ERRS = 2U;
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_FSW_FRAMES = 5U + 1U;
CNXDNRX::CNXDNRX() :
m_state(NXDNRXS_NONE),
m_bitBuffer(),
m_buffer(),
m_bitPtr(0U),
m_dataPtr(0U),
m_startPtr(NOENDPTR),
m_endPtr(NOENDPTR),
m_fswPtr(NOENDPTR),
m_minFSWPtr(NOENDPTR),
m_maxFSWPtr(NOENDPTR),
m_maxCorr(0),
m_lostCount(0U),
m_countdown(0U),
m_centre(),
m_centreVal(0),
m_threshold(),
m_thresholdVal(0),
m_averagePtr(NOAVEPTR),
m_rssiAccum(0U),
m_rssiCount(0U)
{
}
void CNXDNRX::reset()
{
m_state = NXDNRXS_NONE;
m_dataPtr = 0U;
m_bitPtr = 0U;
m_maxCorr = 0;
m_averagePtr = NOAVEPTR;
m_startPtr = NOENDPTR;
m_endPtr = NOENDPTR;
m_fswPtr = NOENDPTR;
m_minFSWPtr = NOENDPTR;
m_maxFSWPtr = NOENDPTR;
m_centreVal = 0;
m_thresholdVal = 0;
m_lostCount = 0U;
m_countdown = 0U;
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
void CNXDNRX::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 NXDNRXS_DATA:
processData(sample);
break;
default:
processNone(sample);
break;
}
m_dataPtr++;
if (m_dataPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_dataPtr = 0U;
m_bitPtr++;
if (m_bitPtr >= NXDN_RADIO_SYMBOL_LENGTH)
m_bitPtr = 0U;
}
}
void CNXDNRX::processNone(q15_t sample)
{
bool ret = correlateFSW();
if (ret) {
// 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 (m_countdown > 0U)
m_countdown--;
if (m_countdown == 1U) {
m_minFSWPtr = m_fswPtr + NXDN_FRAME_LENGTH_SAMPLES - 1U;
if (m_minFSWPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_minFSWPtr -= NXDN_FRAME_LENGTH_SAMPLES;
m_maxFSWPtr = m_fswPtr + 1U;
if (m_maxFSWPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_maxFSWPtr -= NXDN_FRAME_LENGTH_SAMPLES;
m_state = NXDNRXS_DATA;
m_countdown = 0U;
}
}
void CNXDNRX::processData(q15_t sample)
{
if (m_minFSWPtr < m_maxFSWPtr) {
if (m_dataPtr >= m_minFSWPtr && m_dataPtr <= m_maxFSWPtr)
correlateFSW();
} else {
if (m_dataPtr >= m_minFSWPtr || m_dataPtr <= m_maxFSWPtr)
correlateFSW();
}
if (m_dataPtr == m_endPtr) {
// Only update the centre and threshold if they are from a good sync
if (m_lostCount == MAX_FSW_FRAMES) {
m_minFSWPtr = m_fswPtr + NXDN_FRAME_LENGTH_SAMPLES - 1U;
if (m_minFSWPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_minFSWPtr -= NXDN_FRAME_LENGTH_SAMPLES;
m_maxFSWPtr = m_fswPtr + 1U;
if (m_maxFSWPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_maxFSWPtr -= NXDN_FRAME_LENGTH_SAMPLES;
}
calculateLevels(m_startPtr, NXDN_FRAME_LENGTH_SYMBOLS);
DEBUG4("NXDNRX: sync found pos/centre/threshold", m_fswPtr, m_centreVal, m_thresholdVal);
uint8_t frame[NXDN_FRAME_LENGTH_BYTES + 3U];
samplesToBits(m_startPtr, NXDN_FRAME_LENGTH_SYMBOLS, frame, 8U, m_centreVal, m_thresholdVal);
// We've not seen a data sync for too long, signal RXLOST and change to RX_NONE
m_lostCount--;
if (m_lostCount == 0U) {
DEBUG1("NXDNRX: sync timed out, lost lock");
io.setDecode(false);
io.setADCDetection(false);
serial.writeNXDNLost();
m_state = NXDNRXS_NONE;
m_endPtr = NOENDPTR;
m_averagePtr = NOAVEPTR;
m_countdown = 0U;
m_maxCorr = 0;
} else {
frame[0U] = m_lostCount == (MAX_FSW_FRAMES - 1U) ? 0x01U : 0x00U;
writeRSSIData(frame);
m_maxCorr = 0;
}
}
}
bool CNXDNRX::correlateFSW()
{
if (countBits32((m_bitBuffer[m_bitPtr] & NXDN_FSW_SYMBOLS_MASK) ^ NXDN_FSW_SYMBOLS) <= MAX_FSW_SYMBOLS_ERRS) {
uint16_t ptr = m_dataPtr + NXDN_FRAME_LENGTH_SAMPLES - NXDN_FSW_LENGTH_SAMPLES + NXDN_RADIO_SYMBOL_LENGTH;
if (ptr >= NXDN_FRAME_LENGTH_SAMPLES)
ptr -= NXDN_FRAME_LENGTH_SAMPLES;
q31_t corr = 0;
q15_t min = 16000;
q15_t max = -16000;
for (uint8_t i = 0U; i < NXDN_FSW_LENGTH_SYMBOLS; i++) {
q15_t val = m_buffer[ptr];
if (val > max)
max = val;
if (val < min)
min = val;
switch (NXDN_FSW_SYMBOLS_VALUES[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 += NXDN_RADIO_SYMBOL_LENGTH;
if (ptr >= NXDN_FRAME_LENGTH_SAMPLES)
ptr -= NXDN_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 + NXDN_FRAME_LENGTH_SAMPLES - NXDN_FSW_LENGTH_SAMPLES + NXDN_RADIO_SYMBOL_LENGTH;
if (startPtr >= NXDN_FRAME_LENGTH_SAMPLES)
startPtr -= NXDN_FRAME_LENGTH_SAMPLES;
uint8_t sync[NXDN_FSW_BYTES_LENGTH];
samplesToBits(startPtr, NXDN_FSW_LENGTH_SYMBOLS, sync, 0U, m_centreVal, m_thresholdVal);
uint8_t maxErrs;
if (m_state == NXDNRXS_NONE)
maxErrs = MAX_FSW_BIT_START_ERRS;
else
maxErrs = MAX_FSW_BIT_RUN_ERRS;
uint8_t errs = 0U;
for (uint8_t i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++)
errs += countBits8((sync[i] & NXDN_FSW_BYTES_MASK[i]) ^ NXDN_FSW_BYTES[i]);
if (errs <= maxErrs) {
m_maxCorr = corr;
m_lostCount = MAX_FSW_FRAMES;
m_fswPtr = m_dataPtr;
m_startPtr = startPtr;
m_endPtr = m_dataPtr + NXDN_FRAME_LENGTH_SAMPLES - NXDN_FSW_LENGTH_SAMPLES - 1U;
if (m_endPtr >= NXDN_FRAME_LENGTH_SAMPLES)
m_endPtr -= NXDN_FRAME_LENGTH_SAMPLES;
return true;
}
}
}
return false;
}
void CNXDNRX::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 += NXDN_RADIO_SYMBOL_LENGTH;
if (start >= NXDN_FRAME_LENGTH_SAMPLES)
start -= NXDN_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("NXDNRX: 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 CNXDNRX::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 += NXDN_RADIO_SYMBOL_LENGTH;
if (start >= NXDN_FRAME_LENGTH_SAMPLES)
start -= NXDN_FRAME_LENGTH_SAMPLES;
}
}
void CNXDNRX::writeRSSIData(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.writeNXDNData(data, NXDN_FRAME_LENGTH_BYTES + 3U);
} else {
serial.writeNXDNData(data, NXDN_FRAME_LENGTH_BYTES + 1U);
}
#else
serial.writeNXDNData(data, NXDN_FRAME_LENGTH_BYTES + 1U);
#endif
m_rssiAccum = 0U;
m_rssiCount = 0U;
}
-69
View File
@@ -1,69 +0,0 @@
/*
* Copyright (C) 2015,2016,2017,2018 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(NXDNRX_H)
#define NXDNRX_H
#include "Config.h"
#include "NXDNDefines.h"
enum NXDNRX_STATE {
NXDNRXS_NONE,
NXDNRXS_DATA
};
class CNXDNRX {
public:
CNXDNRX();
void samples(const q15_t* samples, uint16_t* rssi, uint8_t length);
void reset();
private:
NXDNRX_STATE m_state;
uint16_t m_bitBuffer[NXDN_RADIO_SYMBOL_LENGTH];
q15_t m_buffer[NXDN_FRAME_LENGTH_SAMPLES];
uint16_t m_bitPtr;
uint16_t m_dataPtr;
uint16_t m_startPtr;
uint16_t m_endPtr;
uint16_t m_fswPtr;
uint16_t m_minFSWPtr;
uint16_t m_maxFSWPtr;
q31_t m_maxCorr;
uint16_t m_lostCount;
uint8_t m_countdown;
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 correlateFSW();
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 writeRSSIData(uint8_t* data);
};
#endif
-170
View File
@@ -1,170 +0,0 @@
/*
* Copyright (C) 2009-2018 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"
#include "Globals.h"
#include "NXDNTX.h"
#include "NXDNDefines.h"
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 850, 592, 219, -234, -720, -1179, -1548, -1769, -1795, -1597, -1172,
-544, 237, 1092, 1927, 2637, 3120, 3286, 3073, 2454, 1447, 116, -1431, -3043, -4544, -5739, -6442,
-6483, -5735, -4121, -1633, 1669, 5651, 10118, 14822, 19484, 23810, 27520, 30367, 32156, 32767,
32156, 30367, 27520, 23810, 19484, 14822, 10118, 5651, 1669, -1633, -4121, -5735, -6483, -6442,
-5739, -4544, -3043, -1431, 116, 1447, 2454, 3073, 3286, 3120, 2637, 1927, 1092, 237, -544, -1172,
-1597, -1795, -1769, -1548, -1179, -720, -234, 219, 592, 850}; // numTaps = 90, L = 10
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
static q15_t NXDN_SINC_FILTER[] = {572, -1003, -253, 254, 740, 1290, 1902, 2527, 3090, 3517, 3747, 3747, 3517, 3090, 2527, 1902,
1290, 740, 254, -253, -1003, 572};
const uint16_t NXDN_SINC_FILTER_LEN = 22U;
const q15_t NXDN_LEVELA = 735;
const q15_t NXDN_LEVELB = 245;
const q15_t NXDN_LEVELC = -245;
const q15_t NXDN_LEVELD = -735;
const uint8_t NXDN_PREAMBLE[] = {0x57U, 0x75U, 0xFDU};
const uint8_t NXDN_SYNC = 0x5FU;
CNXDNTX::CNXDNTX() :
m_buffer(2000U),
m_modFilter(),
m_sincFilter(),
m_modState(),
m_sincState(),
m_poBuffer(),
m_poLen(0U),
m_poPtr(0U),
m_txDelay(240U) // 200ms
{
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
::memset(m_sincState, 0x00U, 70U * sizeof(q15_t));
m_modFilter.L = NXDN_RADIO_SYMBOL_LENGTH;
m_modFilter.phaseLength = RRC_0_2_FILTER_PHASE_LEN;
m_modFilter.pCoeffs = RRC_0_2_FILTER;
m_modFilter.pState = m_modState;
m_sincFilter.numTaps = NXDN_SINC_FILTER_LEN;
m_sincFilter.pState = m_sincState;
m_sincFilter.pCoeffs = NXDN_SINC_FILTER;
}
void CNXDNTX::process()
{
if (m_buffer.getData() == 0U && m_poLen == 0U)
return;
if (m_poLen == 0U) {
if (!m_tx) {
for (uint16_t i = 0U; i < m_txDelay; i++)
m_poBuffer[m_poLen++] = NXDN_SYNC;
m_poBuffer[m_poLen++] = NXDN_PREAMBLE[0U];
m_poBuffer[m_poLen++] = NXDN_PREAMBLE[1U];
m_poBuffer[m_poLen++] = NXDN_PREAMBLE[2U];
} else {
for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) {
uint8_t c = m_buffer.get();
m_poBuffer[m_poLen++] = c;
}
}
m_poPtr = 0U;
}
if (m_poLen > 0U) {
uint16_t space = io.getSpace();
while (space > (4U * NXDN_RADIO_SYMBOL_LENGTH)) {
uint8_t c = m_poBuffer[m_poPtr++];
writeByte(c);
space -= 4U * NXDN_RADIO_SYMBOL_LENGTH;
if (m_poPtr >= m_poLen) {
m_poPtr = 0U;
m_poLen = 0U;
return;
}
}
}
}
uint8_t CNXDNTX::writeData(const uint8_t* data, uint8_t length)
{
if (length != (NXDN_FRAME_LENGTH_BYTES + 1U))
return 4U;
uint16_t space = m_buffer.getSpace();
if (space < NXDN_FRAME_LENGTH_BYTES)
return 5U;
for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++)
m_buffer.put(data[i + 1U]);
return 0U;
}
void CNXDNTX::writeByte(uint8_t c)
{
q15_t inBuffer[4U];
q15_t intBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
q15_t outBuffer[NXDN_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] = NXDN_LEVELA;
break;
case 0x80U:
inBuffer[i] = NXDN_LEVELB;
break;
case 0x00U:
inBuffer[i] = NXDN_LEVELC;
break;
default:
inBuffer[i] = NXDN_LEVELD;
break;
}
}
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, intBuffer, 4U);
::arm_fir_fast_q15(&m_sincFilter, intBuffer, outBuffer, NXDN_RADIO_SYMBOL_LENGTH * 4U);
io.write(STATE_NXDN, outBuffer, NXDN_RADIO_SYMBOL_LENGTH * 4U);
}
void CNXDNTX::setTXDelay(uint8_t delay)
{
m_txDelay = 300U + uint16_t(delay) * 6U; // 500ms + tx delay
if (m_txDelay > 1200U)
m_txDelay = 1200U;
}
uint8_t CNXDNTX::getSpace() const
{
return m_buffer.getSpace() / NXDN_FRAME_LENGTH_BYTES;
}
-53
View File
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2015,2016,2017,2018 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(NXDNTX_H)
#define NXDNTX_H
#include "Config.h"
#include "SerialRB.h"
class CNXDNTX {
public:
CNXDNTX();
uint8_t writeData(const uint8_t* data, uint8_t length);
void process();
void setTXDelay(uint8_t delay);
uint8_t getSpace() const;
private:
CSerialRB m_buffer;
arm_fir_interpolate_instance_q15 m_modFilter;
arm_fir_instance_q15 m_sincFilter;
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
q15_t m_sincState[70U]; // NoTaps + BlockSize - 1, 22 + 40 - 1 plus some spare
uint8_t m_poBuffer[1200U];
uint16_t m_poLen;
uint16_t m_poPtr;
uint16_t m_txDelay;
void writeByte(uint8_t c);
};
#endif
+1 -1
View File
@@ -19,7 +19,7 @@
#if !defined(P25DEFINES_H)
#define P25DEFINES_H
const unsigned int P25_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int P25_RADIO_SYMBOL_LENGTH = 10U; // At 48 kHz sample rate
const unsigned int P25_HDR_FRAME_LENGTH_BYTES = 99U;
const unsigned int P25_HDR_FRAME_LENGTH_BITS = P25_HDR_FRAME_LENGTH_BYTES * 8U;
+16 -10
View File
@@ -23,17 +23,23 @@
#include "P25Defines.h"
// Generated using rcosdesign(0.2, 8, 5, 'normal') in MATLAB
// numTaps = 40, L = 5
static q15_t RC_0_2_FILTER[] = {-897, -1636, -1840, -1278, 0, 1613, 2936, 3310, 2315, 0, -3011, -5627, -6580, -4839,
0, 7482, 16311, 24651, 30607, 32767, 30607, 24651, 16311, 7482, 0, -4839, -6580, -5627,
-3011, 0, 2315, 3310, 2936, 1613, 0, -1278, -1840, -1636, -897, 0}; // numTaps = 40, L = 5
// Generated using rcosdesign(0.2, 8, 10, 'normal') in MATLAB
static q15_t RC_0_2_FILTER[] = {-444, -897, -1311, -1636, -1825, -1840, -1659, -1278, -712, 0,
800, 1613, 2354, 2936, 3277, 3310, 2994, 2315, 1296, 0, -1478,
-3011, -4448, -5627, -6386, -6580, -6090, -4839, -2800, 0, 3474,
7482, 11835, 16311, 20666, 24651, 28032, 30607, 32219, 32767,
32219, 30607, 28032, 24651, 20666, 16311, 11835, 7482, 3474, 0,
-2800, -4839, -6090, -6580, -6386, -5627, -4448, -3011, -1478,
0, 1296, 2315, 2994, 3310, 3277, 2936, 2354, 1613, 800, 0, -712,
-1278, -1659, -1840, -1825, -1636, -1311, -897, -444, 0}; // numTaps = 80, L = 10
const uint16_t RC_0_2_FILTER_PHASE_LEN = 8U; // phaseLength = numTaps/L
static q15_t LOWPASS_FILTER[] = {124, -188, -682, 1262, 556, -621, -1912, -911, 2058, 3855, 1234, -4592, -7692, -2799,
8556, 18133, 18133, 8556, -2799, -7692, -4592, 1234, 3855, 2058, -911, -1912, -621,
556, 1262, -682, -188, 124};
const uint16_t LOWPASS_FILTER_LEN = 32U;
// Generated in MATLAB using the following commands, and then normalised for unity gain
// shape2 = 'Inverse-sinc Lowpass';
// d2 = fdesign.interpolator(1, shape2);
// h2 = design(d2, 'SystemObject', true);
static q15_t LOWPASS_FILTER[] = {1294, -2251, 4312, -8402, 20999, 20999, -8402, 4312, -2251, 1294};
const uint16_t LOWPASS_FILTER_LEN = 10U;
const q15_t P25_LEVELA = 1260;
const q15_t P25_LEVELB = 420;
@@ -54,7 +60,7 @@ m_poPtr(0U),
m_txDelay(240U) // 200ms
{
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
::memset(m_lpState, 0x00U, 60U * sizeof(q15_t));
::memset(m_lpState, 0x00U, 70U * sizeof(q15_t));
m_modFilter.L = P25_RADIO_SYMBOL_LENGTH;
m_modFilter.phaseLength = RC_0_2_FILTER_PHASE_LEN;
+1 -1
View File
@@ -40,7 +40,7 @@ private:
arm_fir_interpolate_instance_q15 m_modFilter;
arm_fir_instance_q15 m_lpFilter;
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
q15_t m_lpState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare
q15_t m_lpState[70U]; // NoTaps + BlockSize - 1, 44 + 20 - 1 plus some spare
uint8_t m_poBuffer[1200U];
uint16_t m_poLen;
uint16_t m_poPtr;
+12 -130
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013,2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2013,2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* This program is free software; you can redistribute it and/or modify
@@ -60,9 +60,6 @@ const uint8_t MMDVM_P25_HDR = 0x30U;
const uint8_t MMDVM_P25_LDU = 0x31U;
const uint8_t MMDVM_P25_LOST = 0x32U;
const uint8_t MMDVM_NXDN_DATA = 0x40U;
const uint8_t MMDVM_NXDN_LOST = 0x41U;
const uint8_t MMDVM_ACK = 0x70U;
const uint8_t MMDVM_NAK = 0x7FU;
@@ -76,9 +73,9 @@ const uint8_t MMDVM_DEBUG5 = 0xF5U;
#if defined(EXTERNAL_OSC)
#define DESCRIPTION "MMDVM 20170501 TCXO (D-Star/DMR/System Fusion/P25/NXDN/RSSI/CW Id)"
#define DESCRIPTION "MMDVM 20170501 TCXO 48kHz (D-Star/DMR/YSF/P25/RSSI/CW Id)"
#else
#define DESCRIPTION "MMDVM 20170501 (D-Star/DMR/System Fusion/P25/NXDN/RSSI/CW Id)"
#define DESCRIPTION "MMDVM 20170501 48kHz (D-Star/DMR/YSF/P25/RSSI/CW Id)"
#endif
#if defined(GITVERSION)
@@ -146,8 +143,6 @@ void CSerialPort::getStatus()
reply[3U] |= 0x04U;
if (m_p25Enable)
reply[3U] |= 0x08U;
if (m_nxdnEnable)
reply[3U] |= 0x10U;
reply[4U] = uint8_t(m_modemState);
@@ -202,12 +197,7 @@ void CSerialPort::getStatus()
else
reply[10U] = 0U;
if (m_nxdnEnable)
reply[11U] = nxdnTX.getSpace();
else
reply[11U] = 0U;
writeInt(1U, reply, 12);
writeInt(1U, reply, 11);
}
void CSerialPort::getVersion()
@@ -231,7 +221,7 @@ void CSerialPort::getVersion()
uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
{
if (length < 16U)
if (length < 15U)
return 4U;
bool rxInvert = (data[0U] & 0x01U) == 0x01U;
@@ -246,7 +236,6 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
bool dmrEnable = (data[1U] & 0x02U) == 0x02U;
bool ysfEnable = (data[1U] & 0x04U) == 0x04U;
bool p25Enable = (data[1U] & 0x08U) == 0x08U;
bool nxdnEnable = (data[1U] & 0x10U) == 0x10U;
uint8_t txDelay = data[2U];
if (txDelay > 50U)
@@ -254,7 +243,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
MMDVM_STATE modemState = MMDVM_STATE(data[3U]);
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K)
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K)
return 4U;
if (modemState == STATE_DSTAR && !dstarEnable)
return 4U;
@@ -264,8 +253,6 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
return 4U;
if (modemState == STATE_P25 && !p25Enable)
return 4U;
if (modemState == STATE_NXDN && !nxdnEnable)
return 4U;
uint8_t rxLevel = data[4U];
@@ -284,22 +271,18 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
int16_t txDCOffset = int16_t(data[13U]) - 128;
int16_t rxDCOffset = int16_t(data[14U]) - 128;
uint8_t nxdnTXLevel = data[15U];
m_modemState = modemState;
m_dstarEnable = dstarEnable;
m_dmrEnable = dmrEnable;
m_ysfEnable = ysfEnable;
m_p25Enable = p25Enable;
m_nxdnEnable = nxdnEnable;
m_duplex = !simplex;
dstarTX.setTXDelay(txDelay);
ysfTX.setTXDelay(txDelay);
p25TX.setTXDelay(txDelay);
dmrDMOTX.setTXDelay(txDelay);
nxdnTX.setTXDelay(txDelay);
dmrTX.setColorCode(colorCode);
dmrRX.setColorCode(colorCode);
@@ -309,7 +292,7 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
ysfTX.setLoDev(ysfLoDev);
io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, nxdnTXLevel, txDCOffset, rxDCOffset);
io.setParameters(rxInvert, txInvert, pttInvert, rxLevel, cwIdTXLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel, txDCOffset, rxDCOffset);
io.start();
@@ -326,7 +309,7 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
if (modemState == m_modemState)
return 0U;
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_NXDN && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K && modemState != STATE_DMRDMO1K && modemState != STATE_NXDNCAL1K)
if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25 && modemState != STATE_DSTARCAL && modemState != STATE_DMRCAL && modemState != STATE_RSSICAL && modemState != STATE_LFCAL && modemState != STATE_DMRCAL1K && modemState != STATE_P25CAL1K)
return 4U;
if (modemState == STATE_DSTAR && !m_dstarEnable)
return 4U;
@@ -336,8 +319,6 @@ uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length)
return 4U;
if (modemState == STATE_P25 && !m_p25Enable)
return 4U;
if (modemState == STATE_NXDN && !m_nxdnEnable)
return 4U;
setMode(modemState);
@@ -352,7 +333,6 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_DSTAR:
@@ -362,7 +342,6 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dmrRX.reset();
ysfRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_YSF:
@@ -372,7 +351,6 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dmrRX.reset();
dstarRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_P25:
@@ -382,17 +360,6 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dmrRX.reset();
dstarRX.reset();
ysfRX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_NXDN:
DEBUG1("Mode set to NXDN");
dmrIdleRX.reset();
dmrDMORX.reset();
dmrRX.reset();
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
cwIdTX.reset();
break;
case STATE_DSTARCAL:
@@ -403,7 +370,6 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_DMRCAL:
@@ -414,7 +380,6 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_RSSICAL:
@@ -425,7 +390,6 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_LFCAL:
@@ -436,18 +400,16 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_DMRCAL1K:
DEBUG1("Mode set to DMR BS 1031 Hz Calibrate");
DEBUG1("Mode set to DMR 1031 Hz Calibrate");
dmrIdleRX.reset();
dmrDMORX.reset();
dmrRX.reset();
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_P25CAL1K:
@@ -458,29 +420,6 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_DMRDMO1K:
DEBUG1("Mode set to DMR MS 1031 Hz Calibrate");
dmrIdleRX.reset();
dmrDMORX.reset();
dmrRX.reset();
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
case STATE_NXDNCAL1K:
DEBUG1("Mode set to NXDN 1031 Hz Calibrate");
dmrIdleRX.reset();
dmrDMORX.reset();
dmrRX.reset();
dstarRX.reset();
ysfRX.reset();
p25RX.reset();
nxdnRX.reset();
cwIdTX.reset();
break;
default:
@@ -514,8 +453,7 @@ void CSerialPort::process()
m_buffer[0U] = c;
m_ptr = 1U;
m_len = 0U;
}
else {
} else {
m_ptr = 0U;
m_len = 0U;
}
@@ -564,12 +502,10 @@ void CSerialPort::process()
case MMDVM_CAL_DATA:
if (m_modemState == STATE_DSTARCAL)
err = calDStarTX.write(m_buffer + 3U, m_len - 3U);
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K)
err = calDMR.write(m_buffer + 3U, m_len - 3U);
if (m_modemState == STATE_P25CAL1K)
err = calP25.write(m_buffer + 3U, m_len - 3U);
if (m_modemState == STATE_NXDNCAL1K)
err = calNXDN.write(m_buffer + 3U, m_len - 3U);
if (err == 0U) {
sendACK();
} else {
@@ -745,20 +681,6 @@ void CSerialPort::process()
}
break;
case MMDVM_NXDN_DATA:
if (m_nxdnEnable) {
if (m_modemState == STATE_IDLE || m_modemState == STATE_NXDN)
err = nxdnTX.writeData(m_buffer + 3U, m_len - 3U);
}
if (err == 0U) {
if (m_modemState == STATE_IDLE)
setMode(STATE_NXDN);
} else {
DEBUG2("Received invalid NXDN data", err);
sendNAK(err);
}
break;
#if defined(SERIAL_REPEATER)
case MMDVM_SERIAL: {
for (uint8_t i = 3U; i < m_len; i++)
@@ -779,7 +701,7 @@ void CSerialPort::process()
}
}
if (io.getWatchdog() >= 48000U) {
if (io.getWatchdog() >= 96000U) {
m_ptr = 0U;
m_len = 0U;
}
@@ -1026,46 +948,6 @@ void CSerialPort::writeP25Lost()
writeInt(1U, reply, 3);
}
void CSerialPort::writeNXDNData(const uint8_t* data, uint8_t length)
{
if (m_modemState != STATE_NXDN && m_modemState != STATE_IDLE)
return;
if (!m_nxdnEnable)
return;
uint8_t reply[130U];
reply[0U] = MMDVM_FRAME_START;
reply[1U] = 0U;
reply[2U] = MMDVM_NXDN_DATA;
uint8_t count = 3U;
for (uint8_t i = 0U; i < length; i++, count++)
reply[count] = data[i];
reply[1U] = count;
writeInt(1U, reply, count);
}
void CSerialPort::writeNXDNLost()
{
if (m_modemState != STATE_NXDN && m_modemState != STATE_IDLE)
return;
if (!m_nxdnEnable)
return;
uint8_t reply[3U];
reply[0U] = MMDVM_FRAME_START;
reply[1U] = 3U;
reply[2U] = MMDVM_NXDN_LOST;
writeInt(1U, reply, 3);
}
void CSerialPort::writeCalData(const uint8_t* data, uint8_t length)
{
if (m_modemState != STATE_DSTARCAL)
+1 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2017 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
@@ -47,9 +47,6 @@ public:
void writeP25Ldu(const uint8_t* data, uint8_t length);
void writeP25Lost();
void writeNXDNData(const uint8_t* data, uint8_t length);
void writeNXDNLost();
void writeCalData(const uint8_t* data, uint8_t length);
void writeRSSIData(const uint8_t* data, uint8_t length);
@@ -83,4 +80,3 @@ private:
};
#endif
+41
View File
@@ -0,0 +1,41 @@
Jobs To Do
----------
Jobs Done
---------
1. Boxcar coefficients
2. Symbols lengths for:
D-Star
DMR
YSF
P25
3. Sample ring buffer sizing
RX
TX
4. Hardware sample rates:
Due
STM32
Teensy
5. DC Offset coefficients
6. TX Filters:
D-Star
DMR
YSF
P25
7. TX Filter workspaces and clearing:
D-Star
DMR
YSF
P25
8. CW Id sine wave, silence and construction
9. RX Filters
10. RX Filter workspaces and clearing:
D-Star
DMR
YSF
P25
11. TX symbols.
12. DC Offset workspace and clearing.
13. DMR magic numbers.
14. Watchdog values.
+1 -1
View File
@@ -19,7 +19,7 @@
#if !defined(YSFDEFINES_H)
#define YSFDEFINES_H
const unsigned int YSF_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
const unsigned int YSF_RADIO_SYMBOL_LENGTH = 10U; // At 48 kHz sample rate
const unsigned int YSF_FRAME_LENGTH_BYTES = 120U;
const unsigned int YSF_FRAME_LENGTH_BITS = YSF_FRAME_LENGTH_BYTES * 8U;
+10 -4
View File
@@ -23,10 +23,16 @@
#include "YSFDefines.h"
// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 850, 219, -720, -1548, -1795, -1172, 237, 1927, 3120, 3073, 1447, -1431, -4544, -6442,
-5735, -1633, 5651, 14822, 23810, 30367, 32767, 30367, 23810, 14822, 5651, -1633, -5735, -6442,
-4544, -1431, 1447, 3073, 3120, 1927, 237, -1172, -1795, -1548, -720, 219, 850}; // numTaps = 45, L = 5
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 850, 592, 219, -234, -720, -1179,
-1548, -1769, -1795, -1597, -1172, -544, 237, 1092, 1927, 2637,
3120, 3286, 3073, 2454, 1447, 116, -1431, -3043, -4544, -5739,
-6442, -6483, -5735, -4121, -1633, 1669, 5651, 10118, 14822,
19484, 23810, 27520, 30367, 32156, 32767, 32156, 30367, 27520,
23810, 19484, 14822, 10118, 5651, 1669, -1633, -4121, -5735,
-6483, -6442, -5739, -4544, -3043, -1431, 116, 1447, 2454,
3073, 3286, 3120, 2637, 1927, 1092, 237, -544, -1172, -1597,
-1795, -1769, -1548, -1179, -720, -234, 219, 592, 850}; // numTaps = 90, L = 10
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
const q15_t YSF_LEVELA_HI = 1893;