From 587fe63a47c2e21ec99b7faa808f189e19af3555 Mon Sep 17 00:00:00 2001 From: Andy CA6JAU Date: Wed, 1 Feb 2017 01:33:31 -0300 Subject: [PATCH] First commit --- ADF7021.cpp | 254 +++++++++++++ ADF7021.h | 38 ++ BitRB.cpp | 104 ++++++ BitRB.h | 55 +++ Config.h | 29 ++ DMRDMORX.cpp | 255 +++++++++++++ DMRDMORX.h | 61 ++++ DMRDMOTX.cpp | 114 ++++++ DMRDMOTX.h | 51 +++ DMRDefines.h | 91 +++++ DMRSlotType.cpp | 286 +++++++++++++++ DMRSlotType.h | 37 ++ DStarDefines.h | 45 +++ DStarRX.cpp | 640 +++++++++++++++++++++++++++++++++ DStarRX.h | 62 ++++ DStarTX.cpp | 437 +++++++++++++++++++++++ DStarTX.h | 51 +++ Debug.h | 45 +++ Globals.h | 78 ++++ IO.cpp | 161 +++++++++ IO.h | 85 +++++ IOArduino.cpp | 178 +++++++++ IOSTM.cpp | 294 +++++++++++++++ LICENCE | 340 ++++++++++++++++++ MMDVM_HS.cpp | 87 +++++ MMDVM_HS.ino | 72 ++++ Makefile | 157 ++++++++ P25Defines.h | 58 +++ P25RX.cpp | 143 ++++++++ P25RX.h | 52 +++ P25TX.cpp | 122 +++++++ P25TX.h | 49 +++ SerialArduino.cpp | 95 +++++ SerialPort.cpp | 892 ++++++++++++++++++++++++++++++++++++++++++++++ SerialPort.h | 77 ++++ SerialRB.cpp | 101 ++++++ SerialRB.h | 58 +++ SerialSTM.cpp | 513 ++++++++++++++++++++++++++ Utils.cpp | 59 +++ Utils.h | 36 ++ YSFDefines.h | 46 +++ YSFRX.cpp | 127 +++++++ YSFRX.h | 51 +++ YSFTX.cpp | 121 +++++++ YSFTX.h | 49 +++ stm32f10x_link.ld | 137 +++++++ 46 files changed, 6893 insertions(+) create mode 100644 ADF7021.cpp create mode 100644 ADF7021.h create mode 100644 BitRB.cpp create mode 100644 BitRB.h create mode 100644 Config.h create mode 100644 DMRDMORX.cpp create mode 100644 DMRDMORX.h create mode 100644 DMRDMOTX.cpp create mode 100644 DMRDMOTX.h create mode 100644 DMRDefines.h create mode 100644 DMRSlotType.cpp create mode 100644 DMRSlotType.h create mode 100644 DStarDefines.h create mode 100644 DStarRX.cpp create mode 100644 DStarRX.h create mode 100644 DStarTX.cpp create mode 100644 DStarTX.h create mode 100644 Debug.h create mode 100644 Globals.h create mode 100644 IO.cpp create mode 100644 IO.h create mode 100644 IOArduino.cpp create mode 100644 IOSTM.cpp create mode 100644 LICENCE create mode 100644 MMDVM_HS.cpp create mode 100644 MMDVM_HS.ino create mode 100644 Makefile create mode 100644 P25Defines.h create mode 100644 P25RX.cpp create mode 100644 P25RX.h create mode 100644 P25TX.cpp create mode 100644 P25TX.h create mode 100755 SerialArduino.cpp create mode 100644 SerialPort.cpp create mode 100644 SerialPort.h create mode 100644 SerialRB.cpp create mode 100644 SerialRB.h create mode 100644 SerialSTM.cpp create mode 100644 Utils.cpp create mode 100644 Utils.h create mode 100644 YSFDefines.h create mode 100644 YSFRX.cpp create mode 100644 YSFRX.h create mode 100644 YSFTX.cpp create mode 100644 YSFTX.h create mode 100644 stm32f10x_link.ld diff --git a/ADF7021.cpp b/ADF7021.cpp new file mode 100644 index 0000000..05da485 --- /dev/null +++ b/ADF7021.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2016 by Jim McLaughlin KI6ZUM + * Copyright (C) 2016, 2017 by Andy Uribe CA6JAU + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" + +#if defined(ADF7021) + +#include "Globals.h" +#include "IO.h" +#include "ADF7021.h" +#include + +volatile uint32_t AD7021_control_byte; +volatile int AD7021_counter; + +void dlybit(void) +{ + volatile unsigned int delay; + for(delay = 0;delay<5;delay++); +} + +void Send_AD7021_control() +{ + for(AD7021_counter = 31; AD7021_counter >= 0; AD7021_counter--) { + if(bitRead(AD7021_control_byte, AD7021_counter) == HIGH) + io.SDATA_pin(HIGH); + else + io.SDATA_pin(LOW); + + io.SCLK_pin(HIGH); + dlybit(); + io.SCLK_pin(LOW); + dlybit(); + } + + io.SLE_pin(HIGH); + dlybit(); + io.SLE_pin(LOW); + io.SDATA_pin(LOW); +} + +void Send_REG0_RX() +{ + uint32_t ADF7021_RX_REG0; + float divider; + uint8_t N_divider; + uint16_t F_divider; + + divider = (m_frequency_rx - 100000) / (ADF7021_PFD / 2.0); + + N_divider = floor(divider); + divider = (divider - N_divider) * 32768; + F_divider = floor(divider + 0.5); + + ADF7021_RX_REG0 = (uint32_t)0b0000; + ADF7021_RX_REG0 |= (uint32_t)0b01011 << 27; // mux regulator/uart enabled/receive + ADF7021_RX_REG0 |= (uint32_t)N_divider << 19; //frequency; + ADF7021_RX_REG0 |= (uint32_t)F_divider << 4; //frequency; + + AD7021_control_byte = ADF7021_RX_REG0; + Send_AD7021_control(); +} + +void Send_REG0_TX() +{ + uint32_t ADF7021_TX_REG0; + float divider; + uint8_t N_divider; + uint16_t F_divider; + + divider = m_frequency_tx / (ADF7021_PFD / 2.0); + + N_divider = floor(divider); + divider = (divider - N_divider) * 32768; + F_divider = floor(divider + 0.5); + + ADF7021_TX_REG0 = (uint32_t)0b0000; // register 0 + ADF7021_TX_REG0 |= (uint32_t)0b01010 << 27; // mux regulator/uart enabled/transmit + ADF7021_TX_REG0 |= (uint32_t)N_divider << 19; //frequency; + ADF7021_TX_REG0 |= (uint32_t)F_divider << 4; //frequency; + + AD7021_control_byte = ADF7021_TX_REG0; + Send_AD7021_control(); +} + +void CIO::ifConf() +{ + uint32_t ADF7021_REG2 = 0; + uint32_t ADF7021_REG3 = 0; + uint32_t ADF7021_REG4 = 0; + uint32_t ADF7021_REG13 = 0; + + if (m_dstarEnable) { + // Dev: 1200 Hz, symb rate = 4800 + + ADF7021_REG3 = 0x2A4C4193; + ADF7021_REG4 = 0x00A82A94; + ADF7021_REG13 = 0x0000000D; + + ADF7021_REG2 = (uint32_t)0b00 << 28; // clock normal + ADF7021_REG2 |= (uint32_t)0b000101010 << 19; // deviation + ADF7021_REG2 |= (uint32_t)0b001 << 4; // modulation (GMSK) + } + else if (m_dmrEnable) { + // Dev: +1 symb 648 Hz, symb rate = 4800 + + ADF7021_REG3 = 0x2A4C80D3; + + // K=32 + ADF7021_REG4 = (uint32_t)0b0100 << 0; // register 4 + ADF7021_REG4 |= (uint32_t)0b011 << 4; // mode, 4FSK + ADF7021_REG4 |= (uint32_t)0b0 << 7; + ADF7021_REG4 |= (uint32_t)0b11 << 8; + ADF7021_REG4 |= (uint32_t)393U << 10; // Disc BW + ADF7021_REG4 |= (uint32_t)65U << 20; // Post dem BW + ADF7021_REG4 |= (uint32_t)0b10 << 30; // IF filter + + ADF7021_REG13 = 0x0000033D; + + ADF7021_REG2 = (uint32_t)0b10 << 28; // invert data + ADF7021_REG2 |= (uint32_t)24U << 19; // deviation + ADF7021_REG2 |= (uint32_t)0b111 << 4; // modulation (4FSK) + } + else if (m_ysfEnable) { + // Dev: +1 symb 900 Hz, symb rate = 4800 + + ADF7021_REG3 = 0x2A4C80D3; + + // K=28 + ADF7021_REG4 = (uint32_t)0b0100 << 0; // register 4 + ADF7021_REG4 |= (uint32_t)0b011 << 4; // mode, 4FSK + ADF7021_REG4 |= (uint32_t)0b0 << 7; + ADF7021_REG4 |= (uint32_t)0b11 << 8; + ADF7021_REG4 |= (uint32_t)344U << 10; // Disc BW + ADF7021_REG4 |= (uint32_t)65U << 20; // Post dem BW + ADF7021_REG4 |= (uint32_t)0b10 << 30; // IF filter + + ADF7021_REG13 = 0x000003BD; + + ADF7021_REG2 = (uint32_t)0b10 << 28; // invert data + ADF7021_REG2 |= (uint32_t)32U << 19; // deviation + ADF7021_REG2 |= (uint32_t)0b111 << 4; // modulation (4FSK) + } + else if (m_p25Enable) { + // Dev: +1 symb 600 Hz, symb rate = 4800 + + ADF7021_REG3 = 0x2A4C80D3; + + // K=32 + ADF7021_REG4 = (uint32_t)0b0100 << 0; // register 4 + ADF7021_REG4 |= (uint32_t)0b011 << 4; // mode, 4FSK + ADF7021_REG4 |= (uint32_t)0b0 << 7; + ADF7021_REG4 |= (uint32_t)0b11 << 8; + ADF7021_REG4 |= (uint32_t)393U << 10; // Disc BW + ADF7021_REG4 |= (uint32_t)65U << 20; // Post dem BW + ADF7021_REG4 |= (uint32_t)0b10 << 30; // IF filter + + ADF7021_REG13 = 0x000002DD; + + ADF7021_REG2 = (uint32_t)0b10 << 28; // invert data + ADF7021_REG2 |= (uint32_t)22U << 19; // deviation + ADF7021_REG2 |= (uint32_t)0b111 << 4; // modulation (4FSK) + } + + // VCO/OSCILLATOR (REG1) + if( (m_frequency_tx >= VHF_MIN) && (m_frequency_tx < VHF_MAX) ) + AD7021_control_byte = 0x021F5041; // VHF, external VCO + else if( (m_frequency_tx >= UHF_MIN)&&(m_frequency_tx < UHF_MAX) ) + AD7021_control_byte = 0x00575041; // UHF, internal VCO + + Send_AD7021_control(); + + // TX/RX CLOCK (3) + AD7021_control_byte = ADF7021_REG3; + Send_AD7021_control(); + + // DEMOD (4) + AD7021_control_byte = ADF7021_REG4; + Send_AD7021_control(); + + // IF FILTER (5) + AD7021_control_byte = 0x000024F5; + Send_AD7021_control(); + + // MODULATION (2) + ADF7021_REG2 |= (uint32_t)0b0010; // register 2 + ADF7021_REG2 |= (uint32_t)m_power << 13; // power level + ADF7021_REG2 |= (uint32_t)0b110001 << 7; // PA + AD7021_control_byte = ADF7021_REG2; + Send_AD7021_control(); + + // TEST MODE (disabled) (15) + AD7021_control_byte = 0x000E000F; + Send_AD7021_control(); + + // IF FINE CAL (fine cal, defaults) (6) + AD7021_control_byte = 0x05080B16; + Send_AD7021_control(); + + // AGC (auto, defaults) (9) + AD7021_control_byte = 0x000231E9; // auto + Send_AD7021_control(); + + // AFC (off, defaults) (10) + AD7021_control_byte = 0x3296472A; // off + Send_AD7021_control(); + + // SYNC WORD DET (11) + AD7021_control_byte = 0x0000003B; + Send_AD7021_control(); + + // SWD/THRESHOLD (12) + AD7021_control_byte = 0x0000010C; + Send_AD7021_control(); + + // 3FSK/4FSK DEMOD (13) + AD7021_control_byte = ADF7021_REG13; + Send_AD7021_control(); +} + +//====================================================================================================================== +void CIO::setTX() +{ + PTT_pin(HIGH); + LED_pin(LOW); + Send_REG0_TX(); +} + +//====================================================================================================================== +void CIO::setRX() +{ + PTT_pin(LOW); + LED_pin(HIGH); + delay_rx(); + Send_REG0_RX(); +} + +#endif diff --git a/ADF7021.h b/ADF7021.h new file mode 100644 index 0000000..477f6bf --- /dev/null +++ b/ADF7021.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 by Jim McLaughlin KI6ZUM + * Copyright (C) 2016, 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. + */ + +#if !defined(ADF7021_H) +#define ADF7021_H + +#include "Config.h" + +#if defined(ADF7021) + +#define ADF7021_PFD 3686400.0 + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) + +void dlybit(void); +void Send_AD7021_control(void); +void Send_REG0_RX(void); +void Send_REG0_TX(void); + +#endif + +#endif \ No newline at end of file diff --git a/BitRB.cpp b/BitRB.cpp new file mode 100644 index 0000000..8faee51 --- /dev/null +++ b/BitRB.cpp @@ -0,0 +1,104 @@ +/* +TX fifo control - Copyright (C) KI6ZUM 2015 +Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. +*/ + +#include "BitRB.h" + +CBitRB::CBitRB(uint16_t length) : +m_length(length), +m_bits(NULL), +m_head(0U), +m_tail(0U), +m_full(false), +m_overflow(false) +{ + m_bits = new uint8_t[length]; +} + +uint16_t CBitRB::getSpace() const +{ + uint16_t n = 0U; + + if (m_tail == m_head) + n = m_full ? 0U : m_length; + else if (m_tail < m_head) + n = m_length - m_head + m_tail; + else + n = m_tail - m_head; + + if (n > m_length) + n = 0U; + + return n; +} + +uint16_t CBitRB::getData() const +{ + if (m_tail == m_head) + return m_full ? m_length : 0U; + else if (m_tail < m_head) + return m_head - m_tail; + else + return m_length - m_tail + m_head; +} + +bool CBitRB::put(uint8_t bit) +{ + if (m_full) { + m_overflow = true; + return false; + } + + m_bits[m_head] = bit; + + m_head++; + if (m_head >= m_length) + m_head = 0U; + + if (m_head == m_tail) + m_full = true; + + return true; +} + +bool CBitRB::get(uint8_t& bit) +{ + if (m_head == m_tail && !m_full) + return false; + + bit = m_bits[m_tail]; + + m_full = false; + + m_tail++; + if (m_tail >= m_length) + m_tail = 0U; + + return true; +} + +bool CBitRB::hasOverflowed() +{ + bool overflow = m_overflow; + + m_overflow = false; + + return overflow; +} + diff --git a/BitRB.h b/BitRB.h new file mode 100644 index 0000000..0a9c952 --- /dev/null +++ b/BitRB.h @@ -0,0 +1,55 @@ +/* +Serial fifo control - Copyright (C) KI6ZUM 2015 +Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. +*/ + +#if !defined(BITRB_H) +#define BITRB_H + +#if defined(STM32F10X_MD) +#include "stm32f10x.h" +#include +#else +#include +#endif + +class CBitRB { +public: + CBitRB(uint16_t length); + + uint16_t getSpace() const; + + uint16_t getData() const; + + bool put(uint8_t bit); + + bool get(uint8_t& bit); + + bool hasOverflowed(); + +private: + uint16_t m_length; + volatile uint8_t* m_bits; + volatile uint16_t m_head; + volatile uint16_t m_tail; + volatile bool m_full; + bool m_overflow; +}; + +#endif + diff --git a/Config.h b/Config.h new file mode 100644 index 0000000..dd726db --- /dev/null +++ b/Config.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#if !defined(CONFIG_H) +#define CONFIG_H + +#define ADF7021 + +//#define STM32_USART1_HOST +#define STM32_USB_HOST + +//#define SERIAL_REPEATER + +#endif diff --git a/DMRDMORX.cpp b/DMRDMORX.cpp new file mode 100644 index 0000000..abbec8c --- /dev/null +++ b/DMRDMORX.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2009-2016 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. + */ + +#define WANT_DEBUG + +#include "Config.h" +#include "Globals.h" +#include "DMRDMORX.h" +#include "DMRSlotType.h" +#include "Utils.h" + +const uint8_t MAX_SYNC_BYTES_ERRS = 3U; + +const uint8_t MAX_SYNC_LOST_FRAMES = 13U; + +const uint16_t NOENDPTR = 9999U; + +const uint8_t CONTROL_NONE = 0x00U; +const uint8_t CONTROL_VOICE = 0x20U; +const uint8_t CONTROL_DATA = 0x40U; + +CDMRDMORX::CDMRDMORX() : +m_patternBuffer(0x00U), +m_dataPtr(0U), +m_syncPtr(0U), +m_startPtr(0U), +m_endPtr(NOENDPTR), +m_control(CONTROL_NONE), +m_syncCount(0U), +m_colorCode(0U), +m_state(DMORXS_NONE), +m_n(0U), +m_type(0U) +{ +} + +void CDMRDMORX::reset() +{ + m_syncPtr = 0U; + m_control = CONTROL_NONE; + m_syncCount = 0U; + m_state = DMORXS_NONE; + m_startPtr = 0U; + m_endPtr = NOENDPTR; +} + +void CDMRDMORX::databit(bool bit) +{ + m_buffer[m_dataPtr] = bit; + + m_patternBuffer <<= 1; + if (bit) + m_patternBuffer |= 0x01U; + + if (m_state == DMORXS_NONE) { + correlateSync(); + } else { + + uint16_t min = m_syncPtr + DMO_BUFFER_LENGTH_BITS - 2; + uint16_t max = m_syncPtr + 2; + + if (min >= DMO_BUFFER_LENGTH_BITS) + min -= DMO_BUFFER_LENGTH_BITS; + if (max >= DMO_BUFFER_LENGTH_BITS) + max -= DMO_BUFFER_LENGTH_BITS; + + if (min < max) { + if (m_dataPtr >= min && m_dataPtr <= max) + correlateSync(); + } else { + if (m_dataPtr >= min || m_dataPtr <= max) + correlateSync(); + } + } + + if (m_dataPtr == m_endPtr) { + frame[0U] = m_control; + + bitsToBytes(m_startPtr, DMR_FRAME_LENGTH_BYTES, frame + 1U); + + if (m_control == CONTROL_DATA) { + // Data sync + uint8_t colorCode; + uint8_t dataType; + CDMRSlotType slotType; + slotType.decode(frame + 1U, colorCode, dataType); + + if (colorCode == m_colorCode) { + m_syncCount = 0U; + m_n = 0U; + + frame[0U] |= dataType; + + switch (dataType) { + case DT_DATA_HEADER: + DEBUG2("DMRDMORX: data header found pos", m_syncPtr); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_state = DMORXS_DATA; + m_type = 0x00U; + break; + case DT_RATE_12_DATA: + case DT_RATE_34_DATA: + case DT_RATE_1_DATA: + if (m_state == DMORXS_DATA) { + DEBUG2("DMRDMORX: data payload found pos", m_syncPtr); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_type = dataType; + } + break; + case DT_VOICE_LC_HEADER: + DEBUG2("DMRDMORX: voice header found pos", m_syncPtr); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + m_state = DMORXS_VOICE; + break; + case DT_VOICE_PI_HEADER: + if (m_state == DMORXS_VOICE) { + DEBUG2("DMRDMORX: voice pi header found pos", m_syncPtr); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + } + m_state = DMORXS_VOICE; + break; + case DT_TERMINATOR_WITH_LC: + if (m_state == DMORXS_VOICE) { + DEBUG2("DMRDMORX: voice terminator found pos", m_syncPtr); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + reset(); + } + break; + default: // DT_CSBK + DEBUG2("DMRDMORX: csbk found pos", m_syncPtr); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + reset(); + break; + } + } + } else if (m_control == CONTROL_VOICE) { + // Voice sync + DEBUG2("DMRDMORX: voice sync found pos", m_syncPtr); + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + + m_state = DMORXS_VOICE; + m_syncCount = 0U; + m_n = 0U; + } else { + if (m_state != DMORXS_NONE) { + m_syncCount++; + if (m_syncCount >= MAX_SYNC_LOST_FRAMES) { + serial.writeDMRLost(true); + reset(); + } + } + + if (m_state == DMORXS_VOICE) { + if (m_n >= 5U) { + frame[0U] = CONTROL_VOICE; + m_n = 0U; + } else { + frame[0U] = ++m_n; + } + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + } else if (m_state == DMORXS_DATA) { + if (m_type != 0x00U) { + frame[0U] = CONTROL_DATA | m_type; + serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); + } + } + } + + // End of this slot, reset some items for the next slot. + m_control = CONTROL_NONE; + } + + m_dataPtr++; + + if (m_dataPtr >= DMO_BUFFER_LENGTH_BITS) + m_dataPtr = 0U; + + io.setDecode(m_state != DMORXS_NONE); +} + +void CDMRDMORX::correlateSync() +{ + if ( (countBits64((m_patternBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_DATA_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) || \ + (countBits64((m_patternBuffer & DMR_SYNC_BITS_MASK) ^ DMR_S2_DATA_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) ) { + + m_control = CONTROL_DATA; + m_syncPtr = m_dataPtr; + + m_startPtr = m_dataPtr + DMO_BUFFER_LENGTH_BITS - DMR_SLOT_TYPE_LENGTH_BITS / 2U - DMR_INFO_LENGTH_BITS / 2U - DMR_SYNC_LENGTH_BITS + 1; + if (m_startPtr >= DMO_BUFFER_LENGTH_BITS) + m_startPtr -= DMO_BUFFER_LENGTH_BITS; + + m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_BITS / 2U + DMR_INFO_LENGTH_BITS / 2U; + if (m_endPtr >= DMO_BUFFER_LENGTH_BITS) + m_endPtr -= DMO_BUFFER_LENGTH_BITS; + + //DEBUG4("SYNC MS Data found pos/start/end:", m_dataPtr, m_startPtr, m_endPtr); + } else if ( (countBits64((m_patternBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_VOICE_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) || \ + (countBits64((m_patternBuffer & DMR_SYNC_BITS_MASK) ^ DMR_S2_VOICE_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) ) { + + m_control = CONTROL_VOICE; + m_syncPtr = m_dataPtr; + + m_startPtr = m_dataPtr + DMO_BUFFER_LENGTH_BITS - DMR_SLOT_TYPE_LENGTH_BITS / 2U - DMR_INFO_LENGTH_BITS / 2U - DMR_SYNC_LENGTH_BITS + 1; + if (m_startPtr >= DMO_BUFFER_LENGTH_BITS) + m_startPtr -= DMO_BUFFER_LENGTH_BITS; + + m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_BITS / 2U + DMR_INFO_LENGTH_BITS / 2U; + if (m_endPtr >= DMO_BUFFER_LENGTH_BITS) + m_endPtr -= DMO_BUFFER_LENGTH_BITS; + + //DEBUG4("SYNC MS Voice found pos/start/end: ", m_dataPtr, m_startPtr, m_endPtr); + } +} + +void CDMRDMORX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer) +{ + for (uint8_t i = 0U; i < count; i++) { + + buffer[i] = 0U; + buffer[i] |= ((m_buffer[start + 0U] & 0x01) << 7); + buffer[i] |= ((m_buffer[start + 1U] & 0x01) << 6); + buffer[i] |= ((m_buffer[start + 2U] & 0x01) << 5); + buffer[i] |= ((m_buffer[start + 3U] & 0x01) << 4); + buffer[i] |= ((m_buffer[start + 4U] & 0x01) << 3); + buffer[i] |= ((m_buffer[start + 5U] & 0x01) << 2); + buffer[i] |= ((m_buffer[start + 6U] & 0x01) << 1); + buffer[i] |= ((m_buffer[start + 7U] & 0x01) << 0); + + start += 8U; + + if (start >= DMO_BUFFER_LENGTH_BITS) + start -= DMO_BUFFER_LENGTH_BITS; + } +} + +void CDMRDMORX::setColorCode(uint8_t colorCode) +{ + m_colorCode = colorCode; +} diff --git a/DMRDMORX.h b/DMRDMORX.h new file mode 100644 index 0000000..8afcb91 --- /dev/null +++ b/DMRDMORX.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015,2016 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(DMRDMORX_H) +#define DMRDMORX_H + +#include "DMRDefines.h" + +const uint16_t DMO_BUFFER_LENGTH_BITS = 576U; + +enum DMORX_STATE { + DMORXS_NONE, + DMORXS_VOICE, + DMORXS_DATA +}; + +class CDMRDMORX { +public: + CDMRDMORX(); + + void databit(bool bit); + void setColorCode(uint8_t colorCode); + + void reset(); + +private: + uint64_t m_patternBuffer; + uint8_t m_buffer[DMO_BUFFER_LENGTH_BITS]; + uint8_t frame[DMR_FRAME_LENGTH_BYTES + 3U]; + uint16_t m_dataPtr; + uint16_t m_syncPtr; + uint16_t m_startPtr; + uint16_t m_endPtr; + uint8_t m_control; + uint8_t m_syncCount; + uint8_t m_colorCode; + DMORX_STATE m_state; + uint8_t m_n; + uint8_t m_type; + + void correlateSync(); + void bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer); + +}; + +#endif diff --git a/DMRDMOTX.cpp b/DMRDMOTX.cpp new file mode 100644 index 0000000..093b660 --- /dev/null +++ b/DMRDMOTX.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2009-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2016 by Colin Durbridge G4EML + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +// #define WANT_DEBUG + +#include "Config.h" +#include "Globals.h" + +CDMRDMOTX::CDMRDMOTX() : +m_fifo(), +m_poBuffer(), +m_poLen(0U), +m_poPtr(0U), +m_txDelay(240U), // 200ms +m_count(0U) +{ +} + +void CDMRDMOTX::process() +{ + if (m_poLen == 0U && m_fifo.getData() > 0U) { + if (!m_tx) { + m_delay = true; + m_poLen = m_txDelay; + } else { + m_delay = false; + for (unsigned int i = 0U; i < 72U; i++) + m_poBuffer[m_poLen++] = 0x00U; + + for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) + m_poBuffer[i] = m_fifo.get(); + } + + m_poPtr = 0U; + } + + if (m_poLen > 0U) { + uint16_t space = io.getSpace(); + + while (space > 8U) { + if (m_delay) { + m_poPtr++; + writeByte(0U); + } else + writeByte(m_poBuffer[m_poPtr++]); + + space -= 8U; + + if (m_poPtr >= m_poLen) { + m_poPtr = 0U; + m_poLen = 0U; + m_delay = false; + return; + } + } + } + +} + +uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint8_t length) +{ + if (length != (DMR_FRAME_LENGTH_BYTES + 1U)) + return 4U; + + uint16_t space = m_fifo.getSpace(); + if (space < DMR_FRAME_LENGTH_BYTES) + return 5U; + + for (uint8_t i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) + m_fifo.put(data[i + 1U]); + + return 0U; +} + +void CDMRDMOTX::writeByte(uint8_t c) +{ + uint8_t bit; + uint8_t mask = 0x80U; + + for (uint8_t i = 0U; i < 8U; i++, c <<= 1) { + if ((c & mask) == mask) + bit = 1U; + else + bit = 0U; + + io.write(&bit, 1); + } +} + +uint16_t CDMRDMOTX::getSpace() const +{ + return m_fifo.getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U); +} + +void CDMRDMOTX::setTXDelay(uint8_t delay) +{ + m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay +} diff --git a/DMRDMOTX.h b/DMRDMOTX.h new file mode 100644 index 0000000..84234af --- /dev/null +++ b/DMRDMOTX.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2016 by Colin Durbridge G4EML + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if !defined(DMRDMOTX_H) +#define DMRDMOTX_H + +#include "DMRDefines.h" + +#include "SerialRB.h" + +class CDMRDMOTX { +public: + CDMRDMOTX(); + + uint8_t writeData(const uint8_t* data, uint8_t length); + + void process(); + + void setTXDelay(uint8_t delay); + + uint16_t getSpace() const; + +private: + CSerialRB m_fifo; + uint8_t m_poBuffer[80U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; + uint32_t m_count; + bool m_delay; + + void writeByte(uint8_t c); +}; + +#endif diff --git a/DMRDefines.h b/DMRDefines.h new file mode 100644 index 0000000..b027d48 --- /dev/null +++ b/DMRDefines.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009-2016 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(DMRDEFINES_H) +#define DMRDEFINES_H + +const unsigned int DMR_FRAME_LENGTH_BYTES = 33U; +const unsigned int DMR_FRAME_LENGTH_BITS = DMR_FRAME_LENGTH_BYTES * 8U; +const unsigned int DMR_FRAME_LENGTH_SYMBOLS = DMR_FRAME_LENGTH_BYTES * 4U; + +const unsigned int DMR_SYNC_LENGTH_BYTES = 6U; +const unsigned int DMR_SYNC_LENGTH_BITS = DMR_SYNC_LENGTH_BYTES * 8U; +const unsigned int DMR_SYNC_LENGTH_SYMBOLS = DMR_SYNC_LENGTH_BYTES * 4U; + +const unsigned int DMR_EMB_LENGTH_BITS = 16U; +const unsigned int DMR_EMB_LENGTH_SYMBOLS = 8U; + +const unsigned int DMR_EMBSIG_LENGTH_BITS = 32U; +const unsigned int DMR_EMBSIG_LENGTH_SYMBOLS = 16U; + +const unsigned int DMR_SLOT_TYPE_LENGTH_BITS = 20U; +const unsigned int DMR_SLOT_TYPE_LENGTH_SYMBOLS = 10U; + +const unsigned int DMR_INFO_LENGTH_BITS = 196U; +const unsigned int DMR_INFO_LENGTH_SYMBOLS = 98U; + +const unsigned int DMR_AUDIO_LENGTH_BITS = 216U; +const unsigned int DMR_AUDIO_LENGTH_SYMBOLS = 108U; + +const unsigned int DMR_CACH_LENGTH_BYTES = 3U; +const unsigned int DMR_CACH_LENGTH_BITS = DMR_CACH_LENGTH_BYTES * 8U; +const unsigned int DMR_CACH_LENGTH_SYMBOLS = DMR_CACH_LENGTH_BYTES * 4U; + +const uint8_t DMR_SYNC_BYTES_LENGTH = 7U; +const uint8_t DMR_MS_DATA_SYNC_BYTES[] = {0x0DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x70U}; +const uint8_t DMR_MS_VOICE_SYNC_BYTES[] = {0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U}; +const uint8_t DMR_BS_DATA_SYNC_BYTES[] = {0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U}; +const uint8_t DMR_BS_VOICE_SYNC_BYTES[] = {0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U}; +const uint8_t DMR_S1_DATA_SYNC_BYTES[] = {0x0FU, 0x7FU, 0xDDU, 0x5DU, 0xDFU, 0xD5U, 0x50U}; +const uint8_t DMR_S1_VOICE_SYNC_BYTES[] = {0x05U, 0xD5U, 0x77U, 0xF7U, 0x75U, 0x7FU, 0xF0U}; +const uint8_t DMR_S2_DATA_SYNC_BYTES[] = {0x0DU, 0x75U, 0x57U, 0xF5U, 0xFFU, 0x7FU, 0x50U}; +const uint8_t DMR_S2_VOICE_SYNC_BYTES[] = {0x07U, 0xDFU, 0xFDU, 0x5FU, 0x55U, 0xD5U, 0xF0U}; +const uint8_t DMR_SYNC_BYTES_MASK[] = {0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U}; + +const uint64_t DMR_MS_DATA_SYNC_BITS = 0x0000D5D7F77FD757U; +const uint64_t DMR_MS_VOICE_SYNC_BITS = 0x00007F7D5DD57DFDU; +const uint64_t DMR_BS_DATA_SYNC_BITS = 0x0000DFF57D75DF5DU; +const uint64_t DMR_BS_VOICE_SYNC_BITS = 0x0000755FD7DF75F7U; +const uint64_t DMR_S1_DATA_SYNC_BITS = 0x0000F7FDD5DDFD55U; +const uint64_t DMR_S1_VOICE_SYNC_BITS = 0x00005D577F7757FFU; +const uint64_t DMR_S2_DATA_SYNC_BITS = 0x0000D7557F5FF7F5U; +const uint64_t DMR_S2_VOICE_SYNC_BITS = 0x00007DFFD5F55D5FU; +const uint64_t DMR_SYNC_BITS_MASK = 0x0000FFFFFFFFFFFFU; + +const uint32_t DMR_MS_DATA_SYNC_SYMBOLS = 0x0076286EU; +const uint32_t DMR_MS_VOICE_SYNC_SYMBOLS = 0x0089D791U; +const uint32_t DMR_BS_DATA_SYNC_SYMBOLS = 0x00439B4DU; +const uint32_t DMR_BS_VOICE_SYNC_SYMBOLS = 0x00BC64B2U; +const uint32_t DMR_S1_DATA_SYNC_SYMBOLS = 0x0021751FU; +const uint32_t DMR_S1_VOICE_SYNC_SYMBOLS = 0x00DE8AE0U; +const uint32_t DMR_S2_DATA_SYNC_SYMBOLS = 0x006F8C23U; +const uint32_t DMR_S2_VOICE_SYNC_SYMBOLS = 0x009073DCU; +const uint32_t DMR_SYNC_SYMBOLS_MASK = 0x00FFFFFFU; + +const uint8_t DT_VOICE_PI_HEADER = 0U; +const uint8_t DT_VOICE_LC_HEADER = 1U; +const uint8_t DT_TERMINATOR_WITH_LC = 2U; +const uint8_t DT_CSBK = 3U; +const uint8_t DT_DATA_HEADER = 6U; +const uint8_t DT_RATE_12_DATA = 7U; +const uint8_t DT_RATE_34_DATA = 8U; +const uint8_t DT_IDLE = 9U; +const uint8_t DT_RATE_1_DATA = 10U; + +#endif + diff --git a/DMRSlotType.cpp b/DMRSlotType.cpp new file mode 100644 index 0000000..941deef --- /dev/null +++ b/DMRSlotType.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2015 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 "Globals.h" +#include "DMRSlotType.h" + +const uint16_t ENCODING_TABLE_2087[] = + {0x0000U, 0xB08EU, 0xE093U, 0x501DU, 0x70A9U, 0xC027U, 0x903AU, 0x20B4U, 0x60DCU, 0xD052U, 0x804FU, 0x30C1U, + 0x1075U, 0xA0FBU, 0xF0E6U, 0x4068U, 0x7036U, 0xC0B8U, 0x90A5U, 0x202BU, 0x009FU, 0xB011U, 0xE00CU, 0x5082U, + 0x10EAU, 0xA064U, 0xF079U, 0x40F7U, 0x6043U, 0xD0CDU, 0x80D0U, 0x305EU, 0xD06CU, 0x60E2U, 0x30FFU, 0x8071U, + 0xA0C5U, 0x104BU, 0x4056U, 0xF0D8U, 0xB0B0U, 0x003EU, 0x5023U, 0xE0ADU, 0xC019U, 0x7097U, 0x208AU, 0x9004U, + 0xA05AU, 0x10D4U, 0x40C9U, 0xF047U, 0xD0F3U, 0x607DU, 0x3060U, 0x80EEU, 0xC086U, 0x7008U, 0x2015U, 0x909BU, + 0xB02FU, 0x00A1U, 0x50BCU, 0xE032U, 0x90D9U, 0x2057U, 0x704AU, 0xC0C4U, 0xE070U, 0x50FEU, 0x00E3U, 0xB06DU, + 0xF005U, 0x408BU, 0x1096U, 0xA018U, 0x80ACU, 0x3022U, 0x603FU, 0xD0B1U, 0xE0EFU, 0x5061U, 0x007CU, 0xB0F2U, + 0x9046U, 0x20C8U, 0x70D5U, 0xC05BU, 0x8033U, 0x30BDU, 0x60A0U, 0xD02EU, 0xF09AU, 0x4014U, 0x1009U, 0xA087U, + 0x40B5U, 0xF03BU, 0xA026U, 0x10A8U, 0x301CU, 0x8092U, 0xD08FU, 0x6001U, 0x2069U, 0x90E7U, 0xC0FAU, 0x7074U, + 0x50C0U, 0xE04EU, 0xB053U, 0x00DDU, 0x3083U, 0x800DU, 0xD010U, 0x609EU, 0x402AU, 0xF0A4U, 0xA0B9U, 0x1037U, + 0x505FU, 0xE0D1U, 0xB0CCU, 0x0042U, 0x20F6U, 0x9078U, 0xC065U, 0x70EBU, 0xA03DU, 0x10B3U, 0x40AEU, 0xF020U, + 0xD094U, 0x601AU, 0x3007U, 0x8089U, 0xC0E1U, 0x706FU, 0x2072U, 0x90FCU, 0xB048U, 0x00C6U, 0x50DBU, 0xE055U, + 0xD00BU, 0x6085U, 0x3098U, 0x8016U, 0xA0A2U, 0x102CU, 0x4031U, 0xF0BFU, 0xB0D7U, 0x0059U, 0x5044U, 0xE0CAU, + 0xC07EU, 0x70F0U, 0x20EDU, 0x9063U, 0x7051U, 0xC0DFU, 0x90C2U, 0x204CU, 0x00F8U, 0xB076U, 0xE06BU, 0x50E5U, + 0x108DU, 0xA003U, 0xF01EU, 0x4090U, 0x6024U, 0xD0AAU, 0x80B7U, 0x3039U, 0x0067U, 0xB0E9U, 0xE0F4U, 0x507AU, + 0x70CEU, 0xC040U, 0x905DU, 0x20D3U, 0x60BBU, 0xD035U, 0x8028U, 0x30A6U, 0x1012U, 0xA09CU, 0xF081U, 0x400FU, + 0x30E4U, 0x806AU, 0xD077U, 0x60F9U, 0x404DU, 0xF0C3U, 0xA0DEU, 0x1050U, 0x5038U, 0xE0B6U, 0xB0ABU, 0x0025U, + 0x2091U, 0x901FU, 0xC002U, 0x708CU, 0x40D2U, 0xF05CU, 0xA041U, 0x10CFU, 0x307BU, 0x80F5U, 0xD0E8U, 0x6066U, + 0x200EU, 0x9080U, 0xC09DU, 0x7013U, 0x50A7U, 0xE029U, 0xB034U, 0x00BAU, 0xE088U, 0x5006U, 0x001BU, 0xB095U, + 0x9021U, 0x20AFU, 0x70B2U, 0xC03CU, 0x8054U, 0x30DAU, 0x60C7U, 0xD049U, 0xF0FDU, 0x4073U, 0x106EU, 0xA0E0U, + 0x90BEU, 0x2030U, 0x702DU, 0xC0A3U, 0xE017U, 0x5099U, 0x0084U, 0xB00AU, 0xF062U, 0x40ECU, 0x10F1U, 0xA07FU, + 0x80CBU, 0x3045U, 0x6058U, 0xD0D6U}; + +const uint32_t DECODING_TABLE_1987[] = + {0x00000U, 0x00001U, 0x00002U, 0x00003U, 0x00004U, 0x00005U, 0x00006U, 0x00007U, 0x00008U, 0x00009U, 0x0000AU, 0x0000BU, 0x0000CU, + 0x0000DU, 0x0000EU, 0x24020U, 0x00010U, 0x00011U, 0x00012U, 0x00013U, 0x00014U, 0x00015U, 0x00016U, 0x00017U, 0x00018U, 0x00019U, + 0x0001AU, 0x0001BU, 0x0001CU, 0x0001DU, 0x48040U, 0x01480U, 0x00020U, 0x00021U, 0x00022U, 0x00023U, 0x00024U, 0x00025U, 0x00026U, + 0x24008U, 0x00028U, 0x00029U, 0x0002AU, 0x24004U, 0x0002CU, 0x24002U, 0x24001U, 0x24000U, 0x00030U, 0x00031U, 0x00032U, 0x08180U, + 0x00034U, 0x00C40U, 0x00036U, 0x00C42U, 0x00038U, 0x43000U, 0x0003AU, 0x43002U, 0x02902U, 0x24012U, 0x02900U, 0x24010U, 0x00040U, + 0x00041U, 0x00042U, 0x00043U, 0x00044U, 0x00045U, 0x00046U, 0x00047U, 0x00048U, 0x00049U, 0x0004AU, 0x02500U, 0x0004CU, 0x0004DU, + 0x48010U, 0x48011U, 0x00050U, 0x00051U, 0x00052U, 0x21200U, 0x00054U, 0x00C20U, 0x48008U, 0x48009U, 0x00058U, 0x00059U, 0x48004U, + 0x48005U, 0x48002U, 0x48003U, 0x48000U, 0x48001U, 0x00060U, 0x00061U, 0x00062U, 0x00063U, 0x00064U, 0x00C10U, 0x10300U, 0x0B000U, + 0x00068U, 0x00069U, 0x01880U, 0x01881U, 0x40181U, 0x40180U, 0x24041U, 0x24040U, 0x00070U, 0x00C04U, 0x00072U, 0x00C06U, 0x00C01U, + 0x00C00U, 0x00C03U, 0x00C02U, 0x05204U, 0x00C0CU, 0x48024U, 0x48025U, 0x05200U, 0x00C08U, 0x48020U, 0x48021U, 0x00080U, 0x00081U, + 0x00082U, 0x00083U, 0x00084U, 0x00085U, 0x00086U, 0x00087U, 0x00088U, 0x00089U, 0x0008AU, 0x50200U, 0x0008CU, 0x0A800U, 0x01411U, + 0x01410U, 0x00090U, 0x00091U, 0x00092U, 0x08120U, 0x00094U, 0x00095U, 0x04A00U, 0x01408U, 0x00098U, 0x00099U, 0x01405U, 0x01404U, + 0x01403U, 0x01402U, 0x01401U, 0x01400U, 0x000A0U, 0x000A1U, 0x000A2U, 0x08110U, 0x000A4U, 0x000A5U, 0x42400U, 0x42401U, 0x000A8U, + 0x000A9U, 0x01840U, 0x01841U, 0x40141U, 0x40140U, 0x24081U, 0x24080U, 0x000B0U, 0x08102U, 0x08101U, 0x08100U, 0x000B4U, 0x08106U, + 0x08105U, 0x08104U, 0x20A01U, 0x20A00U, 0x08109U, 0x08108U, 0x01423U, 0x01422U, 0x01421U, 0x01420U, 0x000C0U, 0x000C1U, 0x000C2U, + 0x000C3U, 0x000C4U, 0x000C5U, 0x000C6U, 0x000C7U, 0x000C8U, 0x000C9U, 0x01820U, 0x01821U, 0x20600U, 0x40120U, 0x16000U, 0x16001U, + 0x000D0U, 0x000D1U, 0x42801U, 0x42800U, 0x03100U, 0x18200U, 0x03102U, 0x18202U, 0x000D8U, 0x000D9U, 0x48084U, 0x01444U, 0x48082U, + 0x01442U, 0x48080U, 0x01440U, 0x000E0U, 0x32000U, 0x01808U, 0x04600U, 0x40109U, 0x40108U, 0x0180CU, 0x4010AU, 0x01802U, 0x40104U, + 0x01800U, 0x01801U, 0x40101U, 0x40100U, 0x01804U, 0x40102U, 0x0A408U, 0x08142U, 0x08141U, 0x08140U, 0x00C81U, 0x00C80U, 0x00C83U, + 0x00C82U, 0x0A400U, 0x0A401U, 0x01810U, 0x01811U, 0x40111U, 0x40110U, 0x01814U, 0x40112U, 0x00100U, 0x00101U, 0x00102U, 0x00103U, + 0x00104U, 0x00105U, 0x00106U, 0x41800U, 0x00108U, 0x00109U, 0x0010AU, 0x02440U, 0x0010CU, 0x0010DU, 0x0010EU, 0x02444U, 0x00110U, + 0x00111U, 0x00112U, 0x080A0U, 0x00114U, 0x00115U, 0x00116U, 0x080A4U, 0x00118U, 0x00119U, 0x15000U, 0x15001U, 0x02822U, 0x02823U, + 0x02820U, 0x02821U, 0x00120U, 0x00121U, 0x00122U, 0x08090U, 0x00124U, 0x00125U, 0x10240U, 0x10241U, 0x00128U, 0x00129U, 0x0012AU, + 0x24104U, 0x09400U, 0x400C0U, 0x02810U, 0x24100U, 0x00130U, 0x08082U, 0x08081U, 0x08080U, 0x31001U, 0x31000U, 0x02808U, 0x08084U, + 0x02806U, 0x0808AU, 0x02804U, 0x08088U, 0x02802U, 0x02803U, 0x02800U, 0x02801U, 0x00140U, 0x00141U, 0x00142U, 0x02408U, 0x00144U, + 0x00145U, 0x10220U, 0x10221U, 0x00148U, 0x02402U, 0x02401U, 0x02400U, 0x400A1U, 0x400A0U, 0x02405U, 0x02404U, 0x00150U, 0x00151U, + 0x00152U, 0x02418U, 0x03080U, 0x03081U, 0x03082U, 0x03083U, 0x09801U, 0x09800U, 0x02411U, 0x02410U, 0x48102U, 0x09804U, 0x48100U, + 0x48101U, 0x00160U, 0x00161U, 0x10204U, 0x10205U, 0x10202U, 0x40088U, 0x10200U, 0x10201U, 0x40085U, 0x40084U, 0x02421U, 0x02420U, + 0x40081U, 0x40080U, 0x10208U, 0x40082U, 0x41402U, 0x080C2U, 0x41400U, 0x080C0U, 0x00D01U, 0x00D00U, 0x10210U, 0x10211U, 0x40095U, + 0x40094U, 0x02844U, 0x080C8U, 0x40091U, 0x40090U, 0x02840U, 0x02841U, 0x00180U, 0x00181U, 0x00182U, 0x08030U, 0x00184U, 0x14400U, + 0x22201U, 0x22200U, 0x00188U, 0x00189U, 0x0018AU, 0x08038U, 0x40061U, 0x40060U, 0x40063U, 0x40062U, 0x00190U, 0x08022U, 0x08021U, + 0x08020U, 0x03040U, 0x03041U, 0x08025U, 0x08024U, 0x40C00U, 0x40C01U, 0x08029U, 0x08028U, 0x2C000U, 0x2C001U, 0x01501U, 0x01500U, + 0x001A0U, 0x08012U, 0x08011U, 0x08010U, 0x40049U, 0x40048U, 0x08015U, 0x08014U, 0x06200U, 0x40044U, 0x30400U, 0x08018U, 0x40041U, + 0x40040U, 0x40043U, 0x40042U, 0x08003U, 0x08002U, 0x08001U, 0x08000U, 0x08007U, 0x08006U, 0x08005U, 0x08004U, 0x0800BU, 0x0800AU, + 0x08009U, 0x08008U, 0x40051U, 0x40050U, 0x02880U, 0x0800CU, 0x001C0U, 0x001C1U, 0x64000U, 0x64001U, 0x03010U, 0x40028U, 0x08C00U, + 0x08C01U, 0x40025U, 0x40024U, 0x02481U, 0x02480U, 0x40021U, 0x40020U, 0x40023U, 0x40022U, 0x03004U, 0x03005U, 0x08061U, 0x08060U, + 0x03000U, 0x03001U, 0x03002U, 0x03003U, 0x0300CU, 0x40034U, 0x30805U, 0x30804U, 0x03008U, 0x40030U, 0x30801U, 0x30800U, 0x4000DU, + 0x4000CU, 0x08051U, 0x08050U, 0x40009U, 0x40008U, 0x10280U, 0x4000AU, 0x40005U, 0x40004U, 0x01900U, 0x40006U, 0x40001U, 0x40000U, + 0x40003U, 0x40002U, 0x14800U, 0x08042U, 0x08041U, 0x08040U, 0x03020U, 0x40018U, 0x08045U, 0x08044U, 0x40015U, 0x40014U, 0x08049U, + 0x08048U, 0x40011U, 0x40010U, 0x40013U, 0x40012U, 0x00200U, 0x00201U, 0x00202U, 0x00203U, 0x00204U, 0x00205U, 0x00206U, 0x00207U, + 0x00208U, 0x00209U, 0x0020AU, 0x50080U, 0x0020CU, 0x0020DU, 0x0020EU, 0x50084U, 0x00210U, 0x00211U, 0x00212U, 0x21040U, 0x00214U, + 0x00215U, 0x04880U, 0x04881U, 0x00218U, 0x00219U, 0x0E001U, 0x0E000U, 0x0021CU, 0x0021DU, 0x04888U, 0x0E004U, 0x00220U, 0x00221U, + 0x00222U, 0x00223U, 0x00224U, 0x00225U, 0x10140U, 0x10141U, 0x00228U, 0x00229U, 0x0022AU, 0x24204U, 0x12401U, 0x12400U, 0x24201U, + 0x24200U, 0x00230U, 0x00231U, 0x00232U, 0x21060U, 0x2A000U, 0x2A001U, 0x2A002U, 0x2A003U, 0x20881U, 0x20880U, 0x20883U, 0x20882U, + 0x05040U, 0x05041U, 0x05042U, 0x24210U, 0x00240U, 0x00241U, 0x00242U, 0x21010U, 0x00244U, 0x46000U, 0x10120U, 0x10121U, 0x00248U, + 0x00249U, 0x0024AU, 0x21018U, 0x20480U, 0x20481U, 0x20482U, 0x20483U, 0x00250U, 0x21002U, 0x21001U, 0x21000U, 0x18081U, 0x18080U, + 0x21005U, 0x21004U, 0x12800U, 0x12801U, 0x21009U, 0x21008U, 0x05020U, 0x05021U, 0x48200U, 0x48201U, 0x00260U, 0x00261U, 0x10104U, + 0x04480U, 0x10102U, 0x10103U, 0x10100U, 0x10101U, 0x62002U, 0x62003U, 0x62000U, 0x62001U, 0x05010U, 0x05011U, 0x10108U, 0x10109U, + 0x0500CU, 0x21022U, 0x21021U, 0x21020U, 0x05008U, 0x00E00U, 0x10110U, 0x10111U, 0x05004U, 0x05005U, 0x05006U, 0x21028U, 0x05000U, + 0x05001U, 0x05002U, 0x05003U, 0x00280U, 0x00281U, 0x00282U, 0x50008U, 0x00284U, 0x00285U, 0x04810U, 0x22100U, 0x00288U, 0x50002U, + 0x50001U, 0x50000U, 0x20440U, 0x20441U, 0x50005U, 0x50004U, 0x00290U, 0x00291U, 0x04804U, 0x04805U, 0x04802U, 0x18040U, 0x04800U, + 0x04801U, 0x20821U, 0x20820U, 0x50011U, 0x50010U, 0x0480AU, 0x01602U, 0x04808U, 0x01600U, 0x002A0U, 0x002A1U, 0x04441U, 0x04440U, + 0x002A4U, 0x002A5U, 0x04830U, 0x04444U, 0x06100U, 0x20810U, 0x50021U, 0x50020U, 0x06104U, 0x20814U, 0x50025U, 0x50024U, 0x20809U, + 0x20808U, 0x13000U, 0x08300U, 0x04822U, 0x2080CU, 0x04820U, 0x04821U, 0x20801U, 0x20800U, 0x20803U, 0x20802U, 0x20805U, 0x20804U, + 0x04828U, 0x20806U, 0x002C0U, 0x002C1U, 0x04421U, 0x04420U, 0x20408U, 0x18010U, 0x2040AU, 0x18012U, 0x20404U, 0x20405U, 0x50041U, + 0x50040U, 0x20400U, 0x20401U, 0x20402U, 0x20403U, 0x18005U, 0x18004U, 0x21081U, 0x21080U, 0x18001U, 0x18000U, 0x04840U, 0x18002U, + 0x20414U, 0x1800CU, 0x21089U, 0x21088U, 0x20410U, 0x18008U, 0x20412U, 0x1800AU, 0x04403U, 0x04402U, 0x04401U, 0x04400U, 0x10182U, + 0x04406U, 0x10180U, 0x04404U, 0x01A02U, 0x0440AU, 0x01A00U, 0x04408U, 0x20420U, 0x40300U, 0x20422U, 0x40302U, 0x04413U, 0x04412U, + 0x04411U, 0x04410U, 0x18021U, 0x18020U, 0x10190U, 0x18022U, 0x20841U, 0x20840U, 0x01A10U, 0x20842U, 0x05080U, 0x05081U, 0x05082U, + 0x05083U, 0x00300U, 0x00301U, 0x00302U, 0x00303U, 0x00304U, 0x00305U, 0x10060U, 0x22080U, 0x00308U, 0x00309U, 0x28800U, 0x28801U, + 0x44402U, 0x44403U, 0x44400U, 0x44401U, 0x00310U, 0x00311U, 0x10C01U, 0x10C00U, 0x00314U, 0x00315U, 0x10070U, 0x10C04U, 0x00318U, + 0x00319U, 0x28810U, 0x10C08U, 0x44412U, 0x00000U, 0x44410U, 0x44411U, 0x00320U, 0x60400U, 0x10044U, 0x10045U, 0x10042U, 0x0C800U, + 0x10040U, 0x10041U, 0x06080U, 0x06081U, 0x06082U, 0x06083U, 0x1004AU, 0x0C808U, 0x10048U, 0x10049U, 0x58008U, 0x08282U, 0x08281U, + 0x08280U, 0x10052U, 0x0C810U, 0x10050U, 0x10051U, 0x58000U, 0x58001U, 0x58002U, 0x08288U, 0x02A02U, 0x02A03U, 0x02A00U, 0x02A01U, + 0x00340U, 0x00341U, 0x10024U, 0x10025U, 0x10022U, 0x10023U, 0x10020U, 0x10021U, 0x34001U, 0x34000U, 0x02601U, 0x02600U, 0x1002AU, + 0x34004U, 0x10028U, 0x10029U, 0x0C400U, 0x0C401U, 0x21101U, 0x21100U, 0x60800U, 0x60801U, 0x10030U, 0x10031U, 0x0C408U, 0x34010U, + 0x21109U, 0x21108U, 0x60808U, 0x60809U, 0x10038U, 0x28420U, 0x10006U, 0x10007U, 0x10004U, 0x10005U, 0x10002U, 0x10003U, 0x10000U, + 0x10001U, 0x1000EU, 0x40284U, 0x1000CU, 0x1000DU, 0x1000AU, 0x40280U, 0x10008U, 0x10009U, 0x10016U, 0x10017U, 0x10014U, 0x10015U, + 0x10012U, 0x10013U, 0x10010U, 0x10011U, 0x05104U, 0x44802U, 0x44801U, 0x44800U, 0x05100U, 0x05101U, 0x10018U, 0x28400U, 0x00380U, + 0x00381U, 0x22005U, 0x22004U, 0x22003U, 0x22002U, 0x22001U, 0x22000U, 0x06020U, 0x06021U, 0x50101U, 0x50100U, 0x11800U, 0x11801U, + 0x22009U, 0x22008U, 0x45001U, 0x45000U, 0x08221U, 0x08220U, 0x04902U, 0x22012U, 0x04900U, 0x22010U, 0x06030U, 0x45008U, 0x08229U, + 0x08228U, 0x11810U, 0x11811U, 0x04908U, 0x22018U, 0x06008U, 0x06009U, 0x08211U, 0x08210U, 0x100C2U, 0x22022U, 0x100C0U, 0x22020U, + 0x06000U, 0x06001U, 0x06002U, 0x06003U, 0x06004U, 0x40240U, 0x06006U, 0x40242U, 0x08203U, 0x08202U, 0x08201U, 0x08200U, 0x08207U, + 0x08206U, 0x08205U, 0x08204U, 0x06010U, 0x20900U, 0x08209U, 0x08208U, 0x61002U, 0x20904U, 0x61000U, 0x61001U, 0x29020U, 0x29021U, + 0x100A4U, 0x22044U, 0x100A2U, 0x22042U, 0x100A0U, 0x22040U, 0x20504U, 0x40224U, 0x0D005U, 0x0D004U, 0x20500U, 0x40220U, 0x0D001U, + 0x0D000U, 0x03204U, 0x18104U, 0x08261U, 0x08260U, 0x03200U, 0x18100U, 0x03202U, 0x18102U, 0x11421U, 0x11420U, 0x00000U, 0x11422U, + 0x03208U, 0x18108U, 0x0D011U, 0x0D010U, 0x29000U, 0x29001U, 0x10084U, 0x04500U, 0x10082U, 0x40208U, 0x10080U, 0x10081U, 0x06040U, + 0x40204U, 0x06042U, 0x40206U, 0x40201U, 0x40200U, 0x10088U, 0x40202U, 0x29010U, 0x08242U, 0x08241U, 0x08240U, 0x10092U, 0x40218U, + 0x10090U, 0x10091U, 0x11401U, 0x11400U, 0x11403U, 0x11402U, 0x40211U, 0x40210U, 0x10098U, 0x40212U, 0x00400U, 0x00401U, 0x00402U, + 0x00403U, 0x00404U, 0x00405U, 0x00406U, 0x00407U, 0x00408U, 0x00409U, 0x0040AU, 0x02140U, 0x0040CU, 0x0040DU, 0x01091U, 0x01090U, + 0x00410U, 0x00411U, 0x00412U, 0x00413U, 0x00414U, 0x00860U, 0x01089U, 0x01088U, 0x00418U, 0x38000U, 0x01085U, 0x01084U, 0x01083U, + 0x01082U, 0x01081U, 0x01080U, 0x00420U, 0x00421U, 0x00422U, 0x00423U, 0x00424U, 0x00850U, 0x42080U, 0x42081U, 0x00428U, 0x00429U, + 0x48801U, 0x48800U, 0x09100U, 0x12200U, 0x24401U, 0x24400U, 0x00430U, 0x00844U, 0x00432U, 0x00846U, 0x00841U, 0x00840U, 0x1C000U, + 0x00842U, 0x00438U, 0x0084CU, 0x010A5U, 0x010A4U, 0x00849U, 0x00848U, 0x010A1U, 0x010A0U, 0x00440U, 0x00441U, 0x00442U, 0x02108U, + 0x00444U, 0x00830U, 0x70001U, 0x70000U, 0x00448U, 0x02102U, 0x02101U, 0x02100U, 0x20280U, 0x20281U, 0x02105U, 0x02104U, 0x00450U, + 0x00824U, 0x00452U, 0x00826U, 0x00821U, 0x00820U, 0x00823U, 0x00822U, 0x24802U, 0x02112U, 0x24800U, 0x02110U, 0x00829U, 0x00828U, + 0x48400U, 0x010C0U, 0x00460U, 0x00814U, 0x04281U, 0x04280U, 0x00811U, 0x00810U, 0x00813U, 0x00812U, 0x54000U, 0x54001U, 0x02121U, + 0x02120U, 0x00819U, 0x00818U, 0x0081BU, 0x0081AU, 0x00805U, 0x00804U, 0x41100U, 0x00806U, 0x00801U, 0x00800U, 0x00803U, 0x00802U, + 0x0A080U, 0x0080CU, 0x0A082U, 0x0080EU, 0x00809U, 0x00808U, 0x0080BU, 0x0080AU, 0x00480U, 0x00481U, 0x00482U, 0x00483U, 0x00484U, + 0x14100U, 0x42020U, 0x01018U, 0x00488U, 0x00489U, 0x01015U, 0x01014U, 0x20240U, 0x01012U, 0x01011U, 0x01010U, 0x00490U, 0x00491U, + 0x0100DU, 0x0100CU, 0x0100BU, 0x0100AU, 0x01009U, 0x01008U, 0x40900U, 0x01006U, 0x01005U, 0x01004U, 0x01003U, 0x01002U, 0x01001U, + 0x01000U, 0x004A0U, 0x004A1U, 0x42004U, 0x04240U, 0x42002U, 0x42003U, 0x42000U, 0x42001U, 0x30102U, 0x30103U, 0x30100U, 0x30101U, + 0x4200AU, 0x01032U, 0x42008U, 0x01030U, 0x25000U, 0x25001U, 0x08501U, 0x08500U, 0x008C1U, 0x008C0U, 0x42010U, 0x01028U, 0x0A040U, + 0x0A041U, 0x01025U, 0x01024U, 0x01023U, 0x01022U, 0x01021U, 0x01020U, 0x004C0U, 0x49000U, 0x04221U, 0x04220U, 0x20208U, 0x20209U, + 0x08900U, 0x08901U, 0x20204U, 0x20205U, 0x02181U, 0x02180U, 0x20200U, 0x20201U, 0x20202U, 0x01050U, 0x0A028U, 0x008A4U, 0x0104DU, + 0x0104CU, 0x008A1U, 0x008A0U, 0x01049U, 0x01048U, 0x0A020U, 0x0A021U, 0x01045U, 0x01044U, 0x20210U, 0x01042U, 0x01041U, 0x01040U, + 0x04203U, 0x04202U, 0x04201U, 0x04200U, 0x00891U, 0x00890U, 0x42040U, 0x04204U, 0x0A010U, 0x0A011U, 0x01C00U, 0x04208U, 0x20220U, + 0x40500U, 0x20222U, 0x40502U, 0x0A008U, 0x00884U, 0x04211U, 0x04210U, 0x00881U, 0x00880U, 0x00883U, 0x00882U, 0x0A000U, 0x0A001U, + 0x0A002U, 0x0A003U, 0x0A004U, 0x00888U, 0x01061U, 0x01060U, 0x00500U, 0x00501U, 0x00502U, 0x02048U, 0x00504U, 0x14080U, 0x00506U, + 0x14082U, 0x00508U, 0x02042U, 0x02041U, 0x02040U, 0x09020U, 0x09021U, 0x44200U, 0x02044U, 0x00510U, 0x00511U, 0x10A01U, 0x10A00U, + 0x4A001U, 0x4A000U, 0x4A003U, 0x4A002U, 0x40880U, 0x40881U, 0x02051U, 0x02050U, 0x40884U, 0x01182U, 0x01181U, 0x01180U, 0x00520U, + 0x60200U, 0x00522U, 0x60202U, 0x09008U, 0x09009U, 0x0900AU, 0x0900BU, 0x09004U, 0x09005U, 0x30080U, 0x02060U, 0x09000U, 0x09001U, + 0x09002U, 0x09003U, 0x41042U, 0x08482U, 0x41040U, 0x08480U, 0x00941U, 0x00940U, 0x41044U, 0x00942U, 0x09014U, 0x09015U, 0x02C04U, + 0x08488U, 0x09010U, 0x09011U, 0x02C00U, 0x02C01U, 0x00540U, 0x0200AU, 0x02009U, 0x02008U, 0x08882U, 0x0200EU, 0x08880U, 0x0200CU, + 0x02003U, 0x02002U, 0x02001U, 0x02000U, 0x02007U, 0x02006U, 0x02005U, 0x02004U, 0x0C200U, 0x0C201U, 0x41020U, 0x02018U, 0x00921U, + 0x00920U, 0x41024U, 0x00922U, 0x02013U, 0x02012U, 0x02011U, 0x02010U, 0x02017U, 0x02016U, 0x02015U, 0x02014U, 0x41012U, 0x0202AU, + 0x41010U, 0x02028U, 0x26000U, 0x00910U, 0x10600U, 0x10601U, 0x02023U, 0x02022U, 0x02021U, 0x02020U, 0x09040U, 0x40480U, 0x02025U, + 0x02024U, 0x41002U, 0x00904U, 0x41000U, 0x41001U, 0x00901U, 0x00900U, 0x41004U, 0x00902U, 0x4100AU, 0x02032U, 0x41008U, 0x02030U, + 0x00909U, 0x00908U, 0x28201U, 0x28200U, 0x00580U, 0x14004U, 0x00582U, 0x14006U, 0x14001U, 0x14000U, 0x08840U, 0x14002U, 0x40810U, + 0x40811U, 0x30020U, 0x020C0U, 0x14009U, 0x14008U, 0x01111U, 0x01110U, 0x40808U, 0x40809U, 0x08421U, 0x08420U, 0x14011U, 0x14010U, + 0x01109U, 0x01108U, 0x40800U, 0x40801U, 0x40802U, 0x01104U, 0x40804U, 0x01102U, 0x01101U, 0x01100U, 0x03801U, 0x03800U, 0x30008U, + 0x08410U, 0x14021U, 0x14020U, 0x42100U, 0x42101U, 0x30002U, 0x30003U, 0x30000U, 0x30001U, 0x09080U, 0x40440U, 0x30004U, 0x30005U, + 0x08403U, 0x08402U, 0x08401U, 0x08400U, 0x08407U, 0x08406U, 0x08405U, 0x08404U, 0x40820U, 0x40821U, 0x30010U, 0x08408U, 0x40824U, + 0x01122U, 0x01121U, 0x01120U, 0x08806U, 0x0208AU, 0x08804U, 0x02088U, 0x08802U, 0x14040U, 0x08800U, 0x08801U, 0x02083U, 0x02082U, + 0x02081U, 0x02080U, 0x20300U, 0x40420U, 0x08808U, 0x02084U, 0x03404U, 0x03405U, 0x08814U, 0x02098U, 0x03400U, 0x03401U, 0x08810U, + 0x08811U, 0x40840U, 0x40841U, 0x02091U, 0x02090U, 0x40844U, 0x01142U, 0x01141U, 0x01140U, 0x04303U, 0x04302U, 0x04301U, 0x04300U, + 0x40409U, 0x40408U, 0x08820U, 0x08821U, 0x40405U, 0x40404U, 0x30040U, 0x020A0U, 0x40401U, 0x40400U, 0x40403U, 0x40402U, 0x41082U, + 0x08442U, 0x41080U, 0x08440U, 0x00981U, 0x00980U, 0x41084U, 0x00982U, 0x0A100U, 0x11200U, 0x0A102U, 0x11202U, 0x40411U, 0x40410U, + 0x40413U, 0x40412U, 0x00600U, 0x00601U, 0x00602U, 0x00603U, 0x00604U, 0x00605U, 0x00606U, 0x00607U, 0x00608U, 0x05800U, 0x0060AU, + 0x05802U, 0x200C0U, 0x12020U, 0x44100U, 0x44101U, 0x00610U, 0x00611U, 0x10901U, 0x10900U, 0x51000U, 0x51001U, 0x51002U, 0x10904U, + 0x00618U, 0x05810U, 0x01285U, 0x01284U, 0x51008U, 0x01282U, 0x01281U, 0x01280U, 0x00620U, 0x60100U, 0x040C1U, 0x040C0U, 0x12009U, + 0x12008U, 0x21800U, 0x21801U, 0x12005U, 0x12004U, 0x12007U, 0x12006U, 0x12001U, 0x12000U, 0x12003U, 0x12002U, 0x00630U, 0x00A44U, + 0x040D1U, 0x040D0U, 0x00A41U, 0x00A40U, 0x21810U, 0x00A42U, 0x12015U, 0x12014U, 0x00000U, 0x12016U, 0x12011U, 0x12010U, 0x12013U, + 0x12012U, 0x00640U, 0x00641U, 0x040A1U, 0x040A0U, 0x20088U, 0x20089U, 0x2008AU, 0x040A4U, 0x20084U, 0x20085U, 0x19000U, 0x02300U, + 0x20080U, 0x20081U, 0x20082U, 0x20083U, 0x0C100U, 0x0C101U, 0x21401U, 0x21400U, 0x00A21U, 0x00A20U, 0x00A23U, 0x00A22U, 0x20094U, + 0x20095U, 0x19010U, 0x21408U, 0x20090U, 0x20091U, 0x20092U, 0x28120U, 0x04083U, 0x04082U, 0x04081U, 0x04080U, 0x00A11U, 0x00A10U, + 0x10500U, 0x04084U, 0x200A4U, 0x0408AU, 0x04089U, 0x04088U, 0x200A0U, 0x12040U, 0x200A2U, 0x12042U, 0x00A05U, 0x00A04U, 0x04091U, + 0x04090U, 0x00A01U, 0x00A00U, 0x00A03U, 0x00A02U, 0x05404U, 0x00A0CU, 0x28105U, 0x28104U, 0x05400U, 0x00A08U, 0x28101U, 0x28100U, + 0x00680U, 0x00681U, 0x04061U, 0x04060U, 0x20048U, 0x20049U, 0x2004AU, 0x04064U, 0x20044U, 0x20045U, 0x50401U, 0x50400U, 0x20040U, + 0x20041U, 0x20042U, 0x01210U, 0x68002U, 0x68003U, 0x68000U, 0x68001U, 0x04C02U, 0x0120AU, 0x04C00U, 0x01208U, 0x20054U, 0x01206U, + 0x01205U, 0x01204U, 0x20050U, 0x01202U, 0x01201U, 0x01200U, 0x18800U, 0x04042U, 0x04041U, 0x04040U, 0x42202U, 0x04046U, 0x42200U, + 0x04044U, 0x20064U, 0x0404AU, 0x04049U, 0x04048U, 0x20060U, 0x12080U, 0x20062U, 0x12082U, 0x18810U, 0x04052U, 0x04051U, 0x04050U, + 0x4C009U, 0x4C008U, 0x42210U, 0x04054U, 0x20C01U, 0x20C00U, 0x20C03U, 0x20C02U, 0x4C001U, 0x4C000U, 0x01221U, 0x01220U, 0x2000CU, + 0x04022U, 0x04021U, 0x04020U, 0x20008U, 0x20009U, 0x2000AU, 0x04024U, 0x20004U, 0x20005U, 0x20006U, 0x04028U, 0x20000U, 0x20001U, + 0x20002U, 0x20003U, 0x2001CU, 0x04032U, 0x04031U, 0x04030U, 0x20018U, 0x18400U, 0x2001AU, 0x18402U, 0x20014U, 0x20015U, 0x20016U, + 0x01244U, 0x20010U, 0x20011U, 0x20012U, 0x01240U, 0x04003U, 0x04002U, 0x04001U, 0x04000U, 0x20028U, 0x04006U, 0x04005U, 0x04004U, + 0x20024U, 0x0400AU, 0x04009U, 0x04008U, 0x20020U, 0x20021U, 0x20022U, 0x0400CU, 0x04013U, 0x04012U, 0x04011U, 0x04010U, 0x00A81U, + 0x00A80U, 0x04015U, 0x04014U, 0x0A200U, 0x11100U, 0x04019U, 0x04018U, 0x20030U, 0x20031U, 0x50800U, 0x50801U, 0x00700U, 0x60020U, + 0x10811U, 0x10810U, 0x4400AU, 0x60024U, 0x44008U, 0x44009U, 0x44006U, 0x02242U, 0x44004U, 0x02240U, 0x44002U, 0x44003U, 0x44000U, + 0x44001U, 0x0C040U, 0x10802U, 0x10801U, 0x10800U, 0x0C044U, 0x10806U, 0x10805U, 0x10804U, 0x23000U, 0x23001U, 0x10809U, 0x10808U, + 0x44012U, 0x44013U, 0x44010U, 0x44011U, 0x60001U, 0x60000U, 0x60003U, 0x60002U, 0x60005U, 0x60004U, 0x10440U, 0x10441U, 0x60009U, + 0x60008U, 0x44024U, 0x6000AU, 0x09200U, 0x12100U, 0x44020U, 0x44021U, 0x60011U, 0x60010U, 0x10821U, 0x10820U, 0x07003U, 0x07002U, + 0x07001U, 0x07000U, 0x23020U, 0x60018U, 0x28045U, 0x28044U, 0x09210U, 0x28042U, 0x28041U, 0x28040U, 0x0C010U, 0x0C011U, 0x02209U, + 0x02208U, 0x10422U, 0x10423U, 0x10420U, 0x10421U, 0x02203U, 0x02202U, 0x02201U, 0x02200U, 0x20180U, 0x20181U, 0x44040U, 0x02204U, + 0x0C000U, 0x0C001U, 0x0C002U, 0x10840U, 0x0C004U, 0x0C005U, 0x0C006U, 0x10844U, 0x0C008U, 0x0C009U, 0x02211U, 0x02210U, 0x0C00CU, + 0x28022U, 0x28021U, 0x28020U, 0x60041U, 0x60040U, 0x10404U, 0x04180U, 0x10402U, 0x10403U, 0x10400U, 0x10401U, 0x02223U, 0x02222U, + 0x02221U, 0x02220U, 0x1040AU, 0x28012U, 0x10408U, 0x28010U, 0x0C020U, 0x0C021U, 0x41200U, 0x41201U, 0x00B01U, 0x00B00U, 0x10410U, + 0x28008U, 0x11081U, 0x11080U, 0x28005U, 0x28004U, 0x28003U, 0x28002U, 0x28001U, 0x28000U, 0x52040U, 0x14204U, 0x22405U, 0x22404U, + 0x14201U, 0x14200U, 0x22401U, 0x22400U, 0x20144U, 0x20145U, 0x44084U, 0x022C0U, 0x20140U, 0x20141U, 0x44080U, 0x44081U, 0x40A08U, + 0x10882U, 0x10881U, 0x10880U, 0x14211U, 0x14210U, 0x1A008U, 0x10884U, 0x40A00U, 0x40A01U, 0x40A02U, 0x01304U, 0x1A002U, 0x01302U, + 0x1A000U, 0x01300U, 0x60081U, 0x60080U, 0x04141U, 0x04140U, 0x60085U, 0x60084U, 0x104C0U, 0x04144U, 0x06400U, 0x06401U, 0x30200U, + 0x30201U, 0x06404U, 0x40640U, 0x30204U, 0x30205U, 0x08603U, 0x08602U, 0x08601U, 0x08600U, 0x00000U, 0x08606U, 0x08605U, 0x08604U, + 0x11041U, 0x11040U, 0x30210U, 0x11042U, 0x11045U, 0x11044U, 0x1A020U, 0x01320U, 0x52000U, 0x52001U, 0x04121U, 0x04120U, 0x20108U, + 0x20109U, 0x08A00U, 0x08A01U, 0x20104U, 0x20105U, 0x02281U, 0x02280U, 0x20100U, 0x20101U, 0x20102U, 0x20103U, 0x0C080U, 0x0C081U, + 0x0C082U, 0x04130U, 0x0C084U, 0x06808U, 0x08A10U, 0x08A11U, 0x11021U, 0x11020U, 0x11023U, 0x11022U, 0x20110U, 0x06800U, 0x20112U, + 0x06802U, 0x04103U, 0x04102U, 0x04101U, 0x04100U, 0x10482U, 0x04106U, 0x10480U, 0x04104U, 0x11011U, 0x11010U, 0x04109U, 0x04108U, + 0x20120U, 0x40600U, 0x20122U, 0x40602U, 0x11009U, 0x11008U, 0x22800U, 0x04110U, 0x1100DU, 0x1100CU, 0x22804U, 0x04114U, 0x11001U, + 0x11000U, 0x11003U, 0x11002U, 0x11005U, 0x11004U, 0x28081U, 0x28080U}; + +#define X18 0x00040000 /* vector representation of X^{18} */ +#define X11 0x00000800 /* vector representation of X^{11} */ +#define MASK8 0xfffff800 /* auxiliary vector for testing */ +#define GENPOL 0x00000c75 /* generator polinomial, g(x) */ + +CDMRSlotType::CDMRSlotType() +{ +} + +uint32_t CDMRSlotType::getSyndrome1987(uint32_t pattern) const +/* + * Compute the syndrome corresponding to the given pattern, i.e., the + * remainder after dividing the pattern (when considering it as the vector + * representation of a polynomial) by the generator polynomial, GENPOL. + * In the program this pattern has several meanings: (1) pattern = infomation + * bits, when constructing the encoding table; (2) pattern = error pattern, + * when constructing the decoding table; and (3) pattern = received vector, to + * obtain its syndrome in decoding. + */ +{ + unsigned int aux = X18; + + if (pattern >= X11) { + while (pattern & MASK8) { + while (!(aux & pattern)) + aux = aux >> 1; + + pattern ^= (aux / X11) * GENPOL; + } + } + + return pattern; +} + +uint8_t CDMRSlotType::decode2087(const uint8_t* data) const +{ + uint32_t code = (data[0U] << 11) + (data[1U] << 3) + (data[2U] >> 5); + uint32_t syndrome = getSyndrome1987(code); + uint32_t error_pattern = DECODING_TABLE_1987[syndrome]; + + if (error_pattern != 0x00U) + code ^= error_pattern; + + return code >> 11; +} + +void CDMRSlotType::decode(const uint8_t* frame, uint8_t& colorCode, uint8_t& dataType) const +{ + uint8_t slotType[3U]; + slotType[0U] = (frame[12U] << 2) & 0xFCU; + slotType[0U] |= (frame[13U] >> 6) & 0x03U; + + slotType[1U] = (frame[13U] << 2) & 0xC0U; + slotType[1U] |= (frame[19U] << 2) & 0x3CU; + slotType[1U] |= (frame[20U] >> 6) & 0x03U; + + slotType[2U] = (frame[20U] << 2) & 0xF0U; + + uint8_t code = decode2087(slotType); + + colorCode = (code >> 4) & 0x0FU; + dataType = (code >> 0) & 0x0FU; +} + +void CDMRSlotType::encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) const +{ + uint8_t slotType[3U]; + slotType[0U] = (colorCode << 4) & 0xF0U; + slotType[0U] |= (dataType << 0) & 0x0FU; + + uint16_t cksum = ENCODING_TABLE_2087[slotType[0U]]; + + slotType[1U] = (cksum >> 0) & 0xFFU; + slotType[2U] = (cksum >> 8) & 0xFFU; + + frame[12U] = (frame[12U] & 0xC0U) | ((slotType[0U] >> 2) & 0x3FU); + frame[13U] = (frame[13U] & 0x0FU) | ((slotType[0U] << 6) & 0xC0U) | ((slotType[1U] >> 2) & 0x30U); + frame[19U] = (frame[19U] & 0xF0U) | ((slotType[1U] >> 2) & 0x0FU); + frame[20U] = (frame[20U] & 0x03U) | ((slotType[1U] << 6) & 0xC0U) | ((slotType[2U] >> 2) & 0x3CU); +} + diff --git a/DMRSlotType.h b/DMRSlotType.h new file mode 100644 index 0000000..0052467 --- /dev/null +++ b/DMRSlotType.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 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(DMRSLOTTYPE_H) +#define DMRSLOTTYPE_H + +class CDMRSlotType { +public: + CDMRSlotType(); + + void decode(const uint8_t* frame, uint8_t& colorCode, uint8_t& dataType) const; + + void encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) const; + +private: + + uint8_t decode2087(const uint8_t* data) const; + uint32_t getSyndrome1987(uint32_t pattern) const; +}; + +#endif + diff --git a/DStarDefines.h b/DStarDefines.h new file mode 100644 index 0000000..a5f0e6f --- /dev/null +++ b/DStarDefines.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009-2015 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(DSTARDEFINES_H) +#define DSTARDEFINES_H + +const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U; +const unsigned int DSTAR_HEADER_LENGTH_BITS = DSTAR_HEADER_LENGTH_BYTES * 8U; + +const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U; +const unsigned int DSTAR_FEC_SECTION_LENGTH_BITS = 660U; + +const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U; +const unsigned int DSTAR_DATA_LENGTH_BITS = DSTAR_DATA_LENGTH_BYTES * 8U; + +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 uint8_t DSTAR_DATA_SYNC_LENGTH_BYTES = 3U; +const uint8_t DSTAR_DATA_SYNC_LENGTH_BITS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U; + +const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16}; + +const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U; +const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U; + +const uint8_t DSTAR_SCRAMBLER_BYTES[] = {0x70U, 0x4FU, 0x93U}; + +#endif diff --git a/DStarRX.cpp b/DStarRX.cpp new file mode 100644 index 0000000..56ca601 --- /dev/null +++ b/DStarRX.cpp @@ -0,0 +1,640 @@ +/* + * Copyright (C) 2009-2016 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. + */ + +//#define WANT_DEBUG + +#include "Config.h" +#include "Globals.h" +#include "DStarRX.h" +#include "Utils.h" + +const unsigned int MAX_SYNC_BITS = 50U * DSTAR_DATA_LENGTH_BITS; + +const unsigned int SYNC_POS = 21U * DSTAR_DATA_LENGTH_BITS; +const unsigned int SYNC_SCAN_START = SYNC_POS - 3U; +const unsigned int SYNC_SCAN_END = SYNC_POS + 3U; + +// 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; + +// D-Star bit order version of 0x55 0x2D 0x16 +const uint32_t DATA_SYNC_DATA = 0x00AAB468U; +const uint32_t DATA_SYNC_MASK = 0x00FFFFFFU; +const uint8_t DATA_SYNC_ERRS = 2U; + +// D-Star bit order version of 0x55 0x55 0xC8 0x7A +const uint32_t END_SYNC_DATA = 0xAAAA135EU; +const uint32_t END_SYNC_MASK = 0xFFFFFFFFU; +const uint8_t END_SYNC_ERRS = 3U; + +const uint8_t BIT_MASK_TABLE0[] = {0x7FU, 0xBFU, 0xDFU, 0xEFU, 0xF7U, 0xFBU, 0xFDU, 0xFEU}; +const uint8_t BIT_MASK_TABLE1[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; +const uint8_t BIT_MASK_TABLE2[] = {0xFEU, 0xFDU, 0xFBU, 0xF7U, 0xEFU, 0xDFU, 0xBFU, 0x7FU}; +const uint8_t BIT_MASK_TABLE3[] = {0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U}; + +#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE1[(i)&7]) : (p[(i)>>3] & BIT_MASK_TABLE0[(i)&7]) +#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE1[(i)&7]) + +#define WRITE_BIT2(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE3[(i)&7]) : (p[(i)>>3] & BIT_MASK_TABLE2[(i)&7]) +#define READ_BIT2(p,i) (p[(i)>>3] & BIT_MASK_TABLE3[(i)&7]) + +const uint8_t INTERLEAVE_TABLE_RX[] = { + 0x00U, 0x00U, 0x03U, 0x00U, 0x06U, 0x00U, 0x09U, 0x00U, 0x0CU, 0x00U, + 0x0FU, 0x00U, 0x12U, 0x00U, 0x15U, 0x00U, 0x18U, 0x00U, 0x1BU, 0x00U, + 0x1EU, 0x00U, 0x21U, 0x00U, 0x24U, 0x00U, 0x27U, 0x00U, 0x2AU, 0x00U, + 0x2DU, 0x00U, 0x30U, 0x00U, 0x33U, 0x00U, 0x36U, 0x00U, 0x39U, 0x00U, + 0x3CU, 0x00U, 0x3FU, 0x00U, 0x42U, 0x00U, 0x45U, 0x00U, 0x48U, 0x00U, + 0x4BU, 0x00U, 0x4EU, 0x00U, 0x51U, 0x00U, 0x00U, 0x01U, 0x03U, 0x01U, + 0x06U, 0x01U, 0x09U, 0x01U, 0x0CU, 0x01U, 0x0FU, 0x01U, 0x12U, 0x01U, + 0x15U, 0x01U, 0x18U, 0x01U, 0x1BU, 0x01U, 0x1EU, 0x01U, 0x21U, 0x01U, + 0x24U, 0x01U, 0x27U, 0x01U, 0x2AU, 0x01U, 0x2DU, 0x01U, 0x30U, 0x01U, + 0x33U, 0x01U, 0x36U, 0x01U, 0x39U, 0x01U, 0x3CU, 0x01U, 0x3FU, 0x01U, + 0x42U, 0x01U, 0x45U, 0x01U, 0x48U, 0x01U, 0x4BU, 0x01U, 0x4EU, 0x01U, + 0x51U, 0x01U, 0x00U, 0x02U, 0x03U, 0x02U, 0x06U, 0x02U, 0x09U, 0x02U, + 0x0CU, 0x02U, 0x0FU, 0x02U, 0x12U, 0x02U, 0x15U, 0x02U, 0x18U, 0x02U, + 0x1BU, 0x02U, 0x1EU, 0x02U, 0x21U, 0x02U, 0x24U, 0x02U, 0x27U, 0x02U, + 0x2AU, 0x02U, 0x2DU, 0x02U, 0x30U, 0x02U, 0x33U, 0x02U, 0x36U, 0x02U, + 0x39U, 0x02U, 0x3CU, 0x02U, 0x3FU, 0x02U, 0x42U, 0x02U, 0x45U, 0x02U, + 0x48U, 0x02U, 0x4BU, 0x02U, 0x4EU, 0x02U, 0x51U, 0x02U, 0x00U, 0x03U, + 0x03U, 0x03U, 0x06U, 0x03U, 0x09U, 0x03U, 0x0CU, 0x03U, 0x0FU, 0x03U, + 0x12U, 0x03U, 0x15U, 0x03U, 0x18U, 0x03U, 0x1BU, 0x03U, 0x1EU, 0x03U, + 0x21U, 0x03U, 0x24U, 0x03U, 0x27U, 0x03U, 0x2AU, 0x03U, 0x2DU, 0x03U, + 0x30U, 0x03U, 0x33U, 0x03U, 0x36U, 0x03U, 0x39U, 0x03U, 0x3CU, 0x03U, + 0x3FU, 0x03U, 0x42U, 0x03U, 0x45U, 0x03U, 0x48U, 0x03U, 0x4BU, 0x03U, + 0x4EU, 0x03U, 0x51U, 0x03U, 0x00U, 0x04U, 0x03U, 0x04U, 0x06U, 0x04U, + 0x09U, 0x04U, 0x0CU, 0x04U, 0x0FU, 0x04U, 0x12U, 0x04U, 0x15U, 0x04U, + 0x18U, 0x04U, 0x1BU, 0x04U, 0x1EU, 0x04U, 0x21U, 0x04U, 0x24U, 0x04U, + 0x27U, 0x04U, 0x2AU, 0x04U, 0x2DU, 0x04U, 0x30U, 0x04U, 0x33U, 0x04U, + 0x36U, 0x04U, 0x39U, 0x04U, 0x3CU, 0x04U, 0x3FU, 0x04U, 0x42U, 0x04U, + 0x45U, 0x04U, 0x48U, 0x04U, 0x4BU, 0x04U, 0x4EU, 0x04U, 0x51U, 0x04U, + 0x00U, 0x05U, 0x03U, 0x05U, 0x06U, 0x05U, 0x09U, 0x05U, 0x0CU, 0x05U, + 0x0FU, 0x05U, 0x12U, 0x05U, 0x15U, 0x05U, 0x18U, 0x05U, 0x1BU, 0x05U, + 0x1EU, 0x05U, 0x21U, 0x05U, 0x24U, 0x05U, 0x27U, 0x05U, 0x2AU, 0x05U, + 0x2DU, 0x05U, 0x30U, 0x05U, 0x33U, 0x05U, 0x36U, 0x05U, 0x39U, 0x05U, + 0x3CU, 0x05U, 0x3FU, 0x05U, 0x42U, 0x05U, 0x45U, 0x05U, 0x48U, 0x05U, + 0x4BU, 0x05U, 0x4EU, 0x05U, 0x51U, 0x05U, 0x00U, 0x06U, 0x03U, 0x06U, + 0x06U, 0x06U, 0x09U, 0x06U, 0x0CU, 0x06U, 0x0FU, 0x06U, 0x12U, 0x06U, + 0x15U, 0x06U, 0x18U, 0x06U, 0x1BU, 0x06U, 0x1EU, 0x06U, 0x21U, 0x06U, + 0x24U, 0x06U, 0x27U, 0x06U, 0x2AU, 0x06U, 0x2DU, 0x06U, 0x30U, 0x06U, + 0x33U, 0x06U, 0x36U, 0x06U, 0x39U, 0x06U, 0x3CU, 0x06U, 0x3FU, 0x06U, + 0x42U, 0x06U, 0x45U, 0x06U, 0x48U, 0x06U, 0x4BU, 0x06U, 0x4EU, 0x06U, + 0x51U, 0x06U, 0x00U, 0x07U, 0x03U, 0x07U, 0x06U, 0x07U, 0x09U, 0x07U, + 0x0CU, 0x07U, 0x0FU, 0x07U, 0x12U, 0x07U, 0x15U, 0x07U, 0x18U, 0x07U, + 0x1BU, 0x07U, 0x1EU, 0x07U, 0x21U, 0x07U, 0x24U, 0x07U, 0x27U, 0x07U, + 0x2AU, 0x07U, 0x2DU, 0x07U, 0x30U, 0x07U, 0x33U, 0x07U, 0x36U, 0x07U, + 0x39U, 0x07U, 0x3CU, 0x07U, 0x3FU, 0x07U, 0x42U, 0x07U, 0x45U, 0x07U, + 0x48U, 0x07U, 0x4BU, 0x07U, 0x4EU, 0x07U, 0x51U, 0x07U, 0x01U, 0x00U, + 0x04U, 0x00U, 0x07U, 0x00U, 0x0AU, 0x00U, 0x0DU, 0x00U, 0x10U, 0x00U, + 0x13U, 0x00U, 0x16U, 0x00U, 0x19U, 0x00U, 0x1CU, 0x00U, 0x1FU, 0x00U, + 0x22U, 0x00U, 0x25U, 0x00U, 0x28U, 0x00U, 0x2BU, 0x00U, 0x2EU, 0x00U, + 0x31U, 0x00U, 0x34U, 0x00U, 0x37U, 0x00U, 0x3AU, 0x00U, 0x3DU, 0x00U, + 0x40U, 0x00U, 0x43U, 0x00U, 0x46U, 0x00U, 0x49U, 0x00U, 0x4CU, 0x00U, + 0x4FU, 0x00U, 0x52U, 0x00U, 0x01U, 0x01U, 0x04U, 0x01U, 0x07U, 0x01U, + 0x0AU, 0x01U, 0x0DU, 0x01U, 0x10U, 0x01U, 0x13U, 0x01U, 0x16U, 0x01U, + 0x19U, 0x01U, 0x1CU, 0x01U, 0x1FU, 0x01U, 0x22U, 0x01U, 0x25U, 0x01U, + 0x28U, 0x01U, 0x2BU, 0x01U, 0x2EU, 0x01U, 0x31U, 0x01U, 0x34U, 0x01U, + 0x37U, 0x01U, 0x3AU, 0x01U, 0x3DU, 0x01U, 0x40U, 0x01U, 0x43U, 0x01U, + 0x46U, 0x01U, 0x49U, 0x01U, 0x4CU, 0x01U, 0x4FU, 0x01U, 0x52U, 0x01U, + 0x01U, 0x02U, 0x04U, 0x02U, 0x07U, 0x02U, 0x0AU, 0x02U, 0x0DU, 0x02U, + 0x10U, 0x02U, 0x13U, 0x02U, 0x16U, 0x02U, 0x19U, 0x02U, 0x1CU, 0x02U, + 0x1FU, 0x02U, 0x22U, 0x02U, 0x25U, 0x02U, 0x28U, 0x02U, 0x2BU, 0x02U, + 0x2EU, 0x02U, 0x31U, 0x02U, 0x34U, 0x02U, 0x37U, 0x02U, 0x3AU, 0x02U, + 0x3DU, 0x02U, 0x40U, 0x02U, 0x43U, 0x02U, 0x46U, 0x02U, 0x49U, 0x02U, + 0x4CU, 0x02U, 0x4FU, 0x02U, 0x52U, 0x02U, 0x01U, 0x03U, 0x04U, 0x03U, + 0x07U, 0x03U, 0x0AU, 0x03U, 0x0DU, 0x03U, 0x10U, 0x03U, 0x13U, 0x03U, + 0x16U, 0x03U, 0x19U, 0x03U, 0x1CU, 0x03U, 0x1FU, 0x03U, 0x22U, 0x03U, + 0x25U, 0x03U, 0x28U, 0x03U, 0x2BU, 0x03U, 0x2EU, 0x03U, 0x31U, 0x03U, + 0x34U, 0x03U, 0x37U, 0x03U, 0x3AU, 0x03U, 0x3DU, 0x03U, 0x40U, 0x03U, + 0x43U, 0x03U, 0x46U, 0x03U, 0x49U, 0x03U, 0x4CU, 0x03U, 0x4FU, 0x03U, + 0x52U, 0x03U, 0x01U, 0x04U, 0x04U, 0x04U, 0x07U, 0x04U, 0x0AU, 0x04U, + 0x0DU, 0x04U, 0x10U, 0x04U, 0x13U, 0x04U, 0x16U, 0x04U, 0x19U, 0x04U, + 0x1CU, 0x04U, 0x1FU, 0x04U, 0x22U, 0x04U, 0x25U, 0x04U, 0x28U, 0x04U, + 0x2BU, 0x04U, 0x2EU, 0x04U, 0x31U, 0x04U, 0x34U, 0x04U, 0x37U, 0x04U, + 0x3AU, 0x04U, 0x3DU, 0x04U, 0x40U, 0x04U, 0x43U, 0x04U, 0x46U, 0x04U, + 0x49U, 0x04U, 0x4CU, 0x04U, 0x4FU, 0x04U, 0x01U, 0x05U, 0x04U, 0x05U, + 0x07U, 0x05U, 0x0AU, 0x05U, 0x0DU, 0x05U, 0x10U, 0x05U, 0x13U, 0x05U, + 0x16U, 0x05U, 0x19U, 0x05U, 0x1CU, 0x05U, 0x1FU, 0x05U, 0x22U, 0x05U, + 0x25U, 0x05U, 0x28U, 0x05U, 0x2BU, 0x05U, 0x2EU, 0x05U, 0x31U, 0x05U, + 0x34U, 0x05U, 0x37U, 0x05U, 0x3AU, 0x05U, 0x3DU, 0x05U, 0x40U, 0x05U, + 0x43U, 0x05U, 0x46U, 0x05U, 0x49U, 0x05U, 0x4CU, 0x05U, 0x4FU, 0x05U, + 0x01U, 0x06U, 0x04U, 0x06U, 0x07U, 0x06U, 0x0AU, 0x06U, 0x0DU, 0x06U, + 0x10U, 0x06U, 0x13U, 0x06U, 0x16U, 0x06U, 0x19U, 0x06U, 0x1CU, 0x06U, + 0x1FU, 0x06U, 0x22U, 0x06U, 0x25U, 0x06U, 0x28U, 0x06U, 0x2BU, 0x06U, + 0x2EU, 0x06U, 0x31U, 0x06U, 0x34U, 0x06U, 0x37U, 0x06U, 0x3AU, 0x06U, + 0x3DU, 0x06U, 0x40U, 0x06U, 0x43U, 0x06U, 0x46U, 0x06U, 0x49U, 0x06U, + 0x4CU, 0x06U, 0x4FU, 0x06U, 0x01U, 0x07U, 0x04U, 0x07U, 0x07U, 0x07U, + 0x0AU, 0x07U, 0x0DU, 0x07U, 0x10U, 0x07U, 0x13U, 0x07U, 0x16U, 0x07U, + 0x19U, 0x07U, 0x1CU, 0x07U, 0x1FU, 0x07U, 0x22U, 0x07U, 0x25U, 0x07U, + 0x28U, 0x07U, 0x2BU, 0x07U, 0x2EU, 0x07U, 0x31U, 0x07U, 0x34U, 0x07U, + 0x37U, 0x07U, 0x3AU, 0x07U, 0x3DU, 0x07U, 0x40U, 0x07U, 0x43U, 0x07U, + 0x46U, 0x07U, 0x49U, 0x07U, 0x4CU, 0x07U, 0x4FU, 0x07U, 0x02U, 0x00U, + 0x05U, 0x00U, 0x08U, 0x00U, 0x0BU, 0x00U, 0x0EU, 0x00U, 0x11U, 0x00U, + 0x14U, 0x00U, 0x17U, 0x00U, 0x1AU, 0x00U, 0x1DU, 0x00U, 0x20U, 0x00U, + 0x23U, 0x00U, 0x26U, 0x00U, 0x29U, 0x00U, 0x2CU, 0x00U, 0x2FU, 0x00U, + 0x32U, 0x00U, 0x35U, 0x00U, 0x38U, 0x00U, 0x3BU, 0x00U, 0x3EU, 0x00U, + 0x41U, 0x00U, 0x44U, 0x00U, 0x47U, 0x00U, 0x4AU, 0x00U, 0x4DU, 0x00U, + 0x50U, 0x00U, 0x02U, 0x01U, 0x05U, 0x01U, 0x08U, 0x01U, 0x0BU, 0x01U, + 0x0EU, 0x01U, 0x11U, 0x01U, 0x14U, 0x01U, 0x17U, 0x01U, 0x1AU, 0x01U, + 0x1DU, 0x01U, 0x20U, 0x01U, 0x23U, 0x01U, 0x26U, 0x01U, 0x29U, 0x01U, + 0x2CU, 0x01U, 0x2FU, 0x01U, 0x32U, 0x01U, 0x35U, 0x01U, 0x38U, 0x01U, + 0x3BU, 0x01U, 0x3EU, 0x01U, 0x41U, 0x01U, 0x44U, 0x01U, 0x47U, 0x01U, + 0x4AU, 0x01U, 0x4DU, 0x01U, 0x50U, 0x01U, 0x02U, 0x02U, 0x05U, 0x02U, + 0x08U, 0x02U, 0x0BU, 0x02U, 0x0EU, 0x02U, 0x11U, 0x02U, 0x14U, 0x02U, + 0x17U, 0x02U, 0x1AU, 0x02U, 0x1DU, 0x02U, 0x20U, 0x02U, 0x23U, 0x02U, + 0x26U, 0x02U, 0x29U, 0x02U, 0x2CU, 0x02U, 0x2FU, 0x02U, 0x32U, 0x02U, + 0x35U, 0x02U, 0x38U, 0x02U, 0x3BU, 0x02U, 0x3EU, 0x02U, 0x41U, 0x02U, + 0x44U, 0x02U, 0x47U, 0x02U, 0x4AU, 0x02U, 0x4DU, 0x02U, 0x50U, 0x02U, + 0x02U, 0x03U, 0x05U, 0x03U, 0x08U, 0x03U, 0x0BU, 0x03U, 0x0EU, 0x03U, + 0x11U, 0x03U, 0x14U, 0x03U, 0x17U, 0x03U, 0x1AU, 0x03U, 0x1DU, 0x03U, + 0x20U, 0x03U, 0x23U, 0x03U, 0x26U, 0x03U, 0x29U, 0x03U, 0x2CU, 0x03U, + 0x2FU, 0x03U, 0x32U, 0x03U, 0x35U, 0x03U, 0x38U, 0x03U, 0x3BU, 0x03U, + 0x3EU, 0x03U, 0x41U, 0x03U, 0x44U, 0x03U, 0x47U, 0x03U, 0x4AU, 0x03U, + 0x4DU, 0x03U, 0x50U, 0x03U, 0x02U, 0x04U, 0x05U, 0x04U, 0x08U, 0x04U, + 0x0BU, 0x04U, 0x0EU, 0x04U, 0x11U, 0x04U, 0x14U, 0x04U, 0x17U, 0x04U, + 0x1AU, 0x04U, 0x1DU, 0x04U, 0x20U, 0x04U, 0x23U, 0x04U, 0x26U, 0x04U, + 0x29U, 0x04U, 0x2CU, 0x04U, 0x2FU, 0x04U, 0x32U, 0x04U, 0x35U, 0x04U, + 0x38U, 0x04U, 0x3BU, 0x04U, 0x3EU, 0x04U, 0x41U, 0x04U, 0x44U, 0x04U, + 0x47U, 0x04U, 0x4AU, 0x04U, 0x4DU, 0x04U, 0x50U, 0x04U, 0x02U, 0x05U, + 0x05U, 0x05U, 0x08U, 0x05U, 0x0BU, 0x05U, 0x0EU, 0x05U, 0x11U, 0x05U, + 0x14U, 0x05U, 0x17U, 0x05U, 0x1AU, 0x05U, 0x1DU, 0x05U, 0x20U, 0x05U, + 0x23U, 0x05U, 0x26U, 0x05U, 0x29U, 0x05U, 0x2CU, 0x05U, 0x2FU, 0x05U, + 0x32U, 0x05U, 0x35U, 0x05U, 0x38U, 0x05U, 0x3BU, 0x05U, 0x3EU, 0x05U, + 0x41U, 0x05U, 0x44U, 0x05U, 0x47U, 0x05U, 0x4AU, 0x05U, 0x4DU, 0x05U, + 0x50U, 0x05U, 0x02U, 0x06U, 0x05U, 0x06U, 0x08U, 0x06U, 0x0BU, 0x06U, + 0x0EU, 0x06U, 0x11U, 0x06U, 0x14U, 0x06U, 0x17U, 0x06U, 0x1AU, 0x06U, + 0x1DU, 0x06U, 0x20U, 0x06U, 0x23U, 0x06U, 0x26U, 0x06U, 0x29U, 0x06U, + 0x2CU, 0x06U, 0x2FU, 0x06U, 0x32U, 0x06U, 0x35U, 0x06U, 0x38U, 0x06U, + 0x3BU, 0x06U, 0x3EU, 0x06U, 0x41U, 0x06U, 0x44U, 0x06U, 0x47U, 0x06U, + 0x4AU, 0x06U, 0x4DU, 0x06U, 0x50U, 0x06U, 0x02U, 0x07U, 0x05U, 0x07U, + 0x08U, 0x07U, 0x0BU, 0x07U, 0x0EU, 0x07U, 0x11U, 0x07U, 0x14U, 0x07U, + 0x17U, 0x07U, 0x1AU, 0x07U, 0x1DU, 0x07U, 0x20U, 0x07U, 0x23U, 0x07U, + 0x26U, 0x07U, 0x29U, 0x07U, 0x2CU, 0x07U, 0x2FU, 0x07U, 0x32U, 0x07U, + 0x35U, 0x07U, 0x38U, 0x07U, 0x3BU, 0x07U, 0x3EU, 0x07U, 0x41U, 0x07U, + 0x44U, 0x07U, 0x47U, 0x07U, 0x4AU, 0x07U, 0x4DU, 0x07U, 0x50U, 0x07U, +}; + +const uint8_t SCRAMBLE_TABLE_RX[] = { + 0x70U, 0x4FU, 0x93U, 0x40U, 0x64U, 0x74U, 0x6DU, 0x30U, 0x2BU, 0xE7U, + 0x2DU, 0x54U, 0x5FU, 0x8AU, 0x1DU, 0x7FU, 0xB8U, 0xA7U, 0x49U, 0x20U, + 0x32U, 0xBAU, 0x36U, 0x98U, 0x95U, 0xF3U, 0x16U, 0xAAU, 0x2FU, 0xC5U, + 0x8EU, 0x3FU, 0xDCU, 0xD3U, 0x24U, 0x10U, 0x19U, 0x5DU, 0x1BU, 0xCCU, + 0xCAU, 0x79U, 0x0BU, 0xD5U, 0x97U, 0x62U, 0xC7U, 0x1FU, 0xEEU, 0x69U, + 0x12U, 0x88U, 0x8CU, 0xAEU, 0x0DU, 0x66U, 0xE5U, 0xBCU, 0x85U, 0xEAU, + 0x4BU, 0xB1U, 0xE3U, 0x0FU, 0xF7U, 0x34U, 0x09U, 0x44U, 0x46U, 0xD7U, + 0x06U, 0xB3U, 0x72U, 0xDEU, 0x42U, 0xF5U, 0xA5U, 0xD8U, 0xF1U, 0x87U, + 0x7BU, 0x9AU, 0x04U, 0x22U, 0xA3U, 0x6BU, 0x83U, 0x59U, 0x39U, 0x6FU, + 0x00U}; + +const uint16_t CCITT_TABLE[] = { + 0x0000U, 0x1189U, 0x2312U, 0x329bU, 0x4624U, 0x57adU, 0x6536U, 0x74bfU, + 0x8c48U, 0x9dc1U, 0xaf5aU, 0xbed3U, 0xca6cU, 0xdbe5U, 0xe97eU, 0xf8f7U, + 0x1081U, 0x0108U, 0x3393U, 0x221aU, 0x56a5U, 0x472cU, 0x75b7U, 0x643eU, + 0x9cc9U, 0x8d40U, 0xbfdbU, 0xae52U, 0xdaedU, 0xcb64U, 0xf9ffU, 0xe876U, + 0x2102U, 0x308bU, 0x0210U, 0x1399U, 0x6726U, 0x76afU, 0x4434U, 0x55bdU, + 0xad4aU, 0xbcc3U, 0x8e58U, 0x9fd1U, 0xeb6eU, 0xfae7U, 0xc87cU, 0xd9f5U, + 0x3183U, 0x200aU, 0x1291U, 0x0318U, 0x77a7U, 0x662eU, 0x54b5U, 0x453cU, + 0xbdcbU, 0xac42U, 0x9ed9U, 0x8f50U, 0xfbefU, 0xea66U, 0xd8fdU, 0xc974U, + 0x4204U, 0x538dU, 0x6116U, 0x709fU, 0x0420U, 0x15a9U, 0x2732U, 0x36bbU, + 0xce4cU, 0xdfc5U, 0xed5eU, 0xfcd7U, 0x8868U, 0x99e1U, 0xab7aU, 0xbaf3U, + 0x5285U, 0x430cU, 0x7197U, 0x601eU, 0x14a1U, 0x0528U, 0x37b3U, 0x263aU, + 0xdecdU, 0xcf44U, 0xfddfU, 0xec56U, 0x98e9U, 0x8960U, 0xbbfbU, 0xaa72U, + 0x6306U, 0x728fU, 0x4014U, 0x519dU, 0x2522U, 0x34abU, 0x0630U, 0x17b9U, + 0xef4eU, 0xfec7U, 0xcc5cU, 0xddd5U, 0xa96aU, 0xb8e3U, 0x8a78U, 0x9bf1U, + 0x7387U, 0x620eU, 0x5095U, 0x411cU, 0x35a3U, 0x242aU, 0x16b1U, 0x0738U, + 0xffcfU, 0xee46U, 0xdcddU, 0xcd54U, 0xb9ebU, 0xa862U, 0x9af9U, 0x8b70U, + 0x8408U, 0x9581U, 0xa71aU, 0xb693U, 0xc22cU, 0xd3a5U, 0xe13eU, 0xf0b7U, + 0x0840U, 0x19c9U, 0x2b52U, 0x3adbU, 0x4e64U, 0x5fedU, 0x6d76U, 0x7cffU, + 0x9489U, 0x8500U, 0xb79bU, 0xa612U, 0xd2adU, 0xc324U, 0xf1bfU, 0xe036U, + 0x18c1U, 0x0948U, 0x3bd3U, 0x2a5aU, 0x5ee5U, 0x4f6cU, 0x7df7U, 0x6c7eU, + 0xa50aU, 0xb483U, 0x8618U, 0x9791U, 0xe32eU, 0xf2a7U, 0xc03cU, 0xd1b5U, + 0x2942U, 0x38cbU, 0x0a50U, 0x1bd9U, 0x6f66U, 0x7eefU, 0x4c74U, 0x5dfdU, + 0xb58bU, 0xa402U, 0x9699U, 0x8710U, 0xf3afU, 0xe226U, 0xd0bdU, 0xc134U, + 0x39c3U, 0x284aU, 0x1ad1U, 0x0b58U, 0x7fe7U, 0x6e6eU, 0x5cf5U, 0x4d7cU, + 0xc60cU, 0xd785U, 0xe51eU, 0xf497U, 0x8028U, 0x91a1U, 0xa33aU, 0xb2b3U, + 0x4a44U, 0x5bcdU, 0x6956U, 0x78dfU, 0x0c60U, 0x1de9U, 0x2f72U, 0x3efbU, + 0xd68dU, 0xc704U, 0xf59fU, 0xe416U, 0x90a9U, 0x8120U, 0xb3bbU, 0xa232U, + 0x5ac5U, 0x4b4cU, 0x79d7U, 0x685eU, 0x1ce1U, 0x0d68U, 0x3ff3U, 0x2e7aU, + 0xe70eU, 0xf687U, 0xc41cU, 0xd595U, 0xa12aU, 0xb0a3U, 0x8238U, 0x93b1U, + 0x6b46U, 0x7acfU, 0x4854U, 0x59ddU, 0x2d62U, 0x3cebU, 0x0e70U, 0x1ff9U, + 0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U, + 0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U}; + +CDStarRX::CDStarRX() : +m_rxState(DSRXS_NONE), +m_patternBuffer(0x00U), +m_rxBuffer(), +m_rxBufferBits(0U), +m_dataBits(0U), +m_mar(0U), +m_pathMetric(), +m_pathMemory0(), +m_pathMemory1(), +m_pathMemory2(), +m_pathMemory3(), +m_fecOutput() +{ +} + +void CDStarRX::reset() +{ + m_rxState = DSRXS_NONE; + m_patternBuffer = 0x00U; + m_rxBufferBits = 0U; + m_dataBits = 0U; +} + +void CDStarRX::databit(bool bit) +{ + switch (m_rxState) { + case DSRXS_NONE: + processNone(bit); + break; + case DSRXS_HEADER: + processHeader(bit); + break; + case DSRXS_DATA: + processData(bit); + break; + default: + break; + } +} + +void CDStarRX::processNone(bool bit) +{ + 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; + + m_rxState = DSRXS_HEADER; + return; + } + + // Exact matching of the data sync bit sequence + if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) == 0U) { + DEBUG1("DStarRX: found data sync in None"); + + io.setDecode(true); + + serial.writeDStarData(DSTAR_DATA_SYNC_BYTES, DSTAR_DATA_LENGTH_BYTES); + + ::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U); + m_rxBufferBits = 0U; + + m_dataBits = 0U; + m_rxState = DSRXS_DATA; + return; + } +} + +void CDStarRX::processHeader(bool bit) +{ + m_patternBuffer <<= 1; + if (bit) + m_patternBuffer |= 0x01U; + + WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit); + m_rxBufferBits++; + + // 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) { + io.setDecode(true); + + serial.writeDStarHeader(header, DSTAR_HEADER_LENGTH_BYTES); + + ::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U); + m_rxBufferBits = 0U; + + m_rxState = DSRXS_DATA; + m_dataBits = SYNC_POS - DSTAR_DATA_LENGTH_BITS + 1U; + } else { + // The checksum failed, return to looking for syncs + m_rxState = DSRXS_NONE; + } + } +} + +void CDStarRX::processData(bool bit) +{ + 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) { + DEBUG1("DStarRX: Found end sync in Data"); + io.setDecode(false); + + serial.writeDStarEOT(); + + m_rxState = DSRXS_NONE; + return; + } + + // Fuzzy matching of the data sync bit sequence + bool syncSeen = false; + if (m_dataBits >= SYNC_SCAN_START && m_dataBits <= (SYNC_POS + 1U)) { + if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) <= DATA_SYNC_ERRS) { +#if defined(WANT_DEBUG) + if (m_dataBits < SYNC_POS) + DEBUG2("DStarRX: found data sync in Data, early", SYNC_POS - m_dataBits); + else + DEBUG1("DStarRX: found data sync in Data"); +#endif + m_rxBufferBits = DSTAR_DATA_LENGTH_BITS; + m_dataBits = 0U; + syncSeen = true; + } + } + + // Check to see if the sync is arriving late + if (m_dataBits == SYNC_POS) { + 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) { + DEBUG2("DStarRX: found data sync in Data, late", i); + m_rxBufferBits -= i; + m_dataBits -= i; + break; + } + } + } + + m_dataBits++; + + // We've not seen a data sync for too long, signal RXLOST and change to RX_NONE + if (m_dataBits >= MAX_SYNC_BITS) { + DEBUG1("DStarRX: data sync timed out, lost lock"); + io.setDecode(false); + + serial.writeDStarLost(); + + 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]; + } + io.setDecode(true); + + serial.writeDStarData(m_rxBuffer, DSTAR_DATA_LENGTH_BYTES); + + // Start the next frame + ::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U); + m_rxBufferBits = 0U; + } +} + +bool CDStarRX::rxHeader(uint8_t* in, uint8_t* out) +{ + int i; + + // Descramble the header + for (i = 0; i < int(DSTAR_FEC_SECTION_LENGTH_BYTES); i++) + in[i] ^= SCRAMBLE_TABLE_RX[i]; + + unsigned char intermediate[84U]; + for (i = 0; i < 84; i++) + intermediate[i] = 0x00U; + + // Deinterleave the header + i = 0; + while (i < 660) { + unsigned char d = in[i / 8]; + + if (d & 0x01U) + intermediate[INTERLEAVE_TABLE_RX[i * 2U]] |= (0x80U >> INTERLEAVE_TABLE_RX[i * 2U + 1U]); + i++; + + if (d & 0x02U) + intermediate[INTERLEAVE_TABLE_RX[i * 2U]] |= (0x80U >> INTERLEAVE_TABLE_RX[i * 2U + 1U]); + i++; + + if (d & 0x04U) + intermediate[INTERLEAVE_TABLE_RX[i * 2U]] |= (0x80U >> INTERLEAVE_TABLE_RX[i * 2U + 1U]); + i++; + + if (d & 0x08U) + intermediate[INTERLEAVE_TABLE_RX[i * 2U]] |= (0x80U >> INTERLEAVE_TABLE_RX[i * 2U + 1U]); + i++; + + if (i < 660) { + if (d & 0x10U) + intermediate[INTERLEAVE_TABLE_RX[i * 2U]] |= (0x80U >> INTERLEAVE_TABLE_RX[i * 2U + 1U]); + i++; + + if (d & 0x20U) + intermediate[INTERLEAVE_TABLE_RX[i * 2U]] |= (0x80U >> INTERLEAVE_TABLE_RX[i * 2U + 1U]); + i++; + + if (d & 0x40U) + intermediate[INTERLEAVE_TABLE_RX[i * 2U]] |= (0x80U >> INTERLEAVE_TABLE_RX[i * 2U + 1U]); + i++; + + if (d & 0x80U) + intermediate[INTERLEAVE_TABLE_RX[i * 2U]] |= (0x80U >> INTERLEAVE_TABLE_RX[i * 2U + 1U]); + i++; + } + } + + for (i = 0; i < 4; i++) + m_pathMetric[i] = 0; + + int decodeData[2U]; + + m_mar = 0U; + for (i = 0; i < 660; i += 2) { + if (intermediate[i >> 3] & (0x80U >> (i & 7))) + decodeData[1U] = 1U; + else + decodeData[1U] = 0U; + + if (intermediate[i >> 3] & (0x40U >> (i & 7))) + decodeData[0U] = 1U; + else + decodeData[0U] = 0U; + + viterbiDecode(decodeData); + } + + traceBack(); + + for (i = 0; i < int(DSTAR_HEADER_LENGTH_BYTES); i++) + out[i] = 0x00U; + + unsigned int j = 0; + for (i = 329; i >= 0; i--) { + if (READ_BIT1(m_fecOutput, i)) + out[j >> 3] |= (0x01U << (j & 7)); + + j++; + } + + return checksum(out); +} + +void CDStarRX::acs(int* metric) +{ + int tempMetric[4U]; + + unsigned int j = m_mar >> 3; + unsigned int k = m_mar & 7; + + // Pres. state = S0, Prev. state = S0 & S2 + int m1 = metric[0U] + m_pathMetric[0U]; + int m2 = metric[4U] + m_pathMetric[2U]; + tempMetric[0U] = m1 < m2 ? m1 : m2; + if (m1 < m2) + m_pathMemory0[j] &= BIT_MASK_TABLE0[k]; + else + m_pathMemory0[j] |= BIT_MASK_TABLE1[k]; + + // Pres. state = S1, Prev. state = S0 & S2 + m1 = metric[1U] + m_pathMetric[0U]; + m2 = metric[5U] + m_pathMetric[2U]; + tempMetric[1U] = m1 < m2 ? m1 : m2; + if (m1 < m2) + m_pathMemory1[j] &= BIT_MASK_TABLE0[k]; + else + m_pathMemory1[j] |= BIT_MASK_TABLE1[k]; + + // Pres. state = S2, Prev. state = S2 & S3 + m1 = metric[2U] + m_pathMetric[1U]; + m2 = metric[6U] + m_pathMetric[3U]; + tempMetric[2U] = m1 < m2 ? m1 : m2; + if (m1 < m2) + m_pathMemory2[j] &= BIT_MASK_TABLE0[k]; + else + m_pathMemory2[j] |= BIT_MASK_TABLE1[k]; + + // Pres. state = S3, Prev. state = S1 & S3 + m1 = metric[3U] + m_pathMetric[1U]; + m2 = metric[7U] + m_pathMetric[3U]; + tempMetric[3U] = m1 < m2 ? m1 : m2; + if (m1 < m2) + m_pathMemory3[j] &= BIT_MASK_TABLE0[k]; + else + m_pathMemory3[j] |= BIT_MASK_TABLE1[k]; + + for (unsigned int i = 0U; i < 4U; i++) + m_pathMetric[i] = tempMetric[i]; + + m_mar++; +} + +void CDStarRX::viterbiDecode(int* data) +{ + int metric[8U]; + + metric[0] = (data[1] ^ 0) + (data[0] ^ 0); + metric[1] = (data[1] ^ 1) + (data[0] ^ 1); + metric[2] = (data[1] ^ 1) + (data[0] ^ 0); + metric[3] = (data[1] ^ 0) + (data[0] ^ 1); + metric[4] = (data[1] ^ 1) + (data[0] ^ 1); + metric[5] = (data[1] ^ 0) + (data[0] ^ 0); + metric[6] = (data[1] ^ 0) + (data[0] ^ 1); + metric[7] = (data[1] ^ 1) + (data[0] ^ 0); + + acs(metric); +} + +void CDStarRX::traceBack() +{ + // Start from the S0, t=31 + unsigned int j = 0U; + unsigned int k = 0U; + for (int i = 329; i >= 0; i--) { + switch (j) { + case 0U: // if state = S0 + if (!READ_BIT1(m_pathMemory0, i)) + j = 0U; + else + j = 2U; + WRITE_BIT1(m_fecOutput, k, false); + k++; + break; + + + case 1U: // if state = S1 + if (!READ_BIT1(m_pathMemory1, i)) + j = 0U; + else + j = 2U; + WRITE_BIT1(m_fecOutput, k, true); + k++; + break; + + case 2U: // if state = S1 + if (!READ_BIT1(m_pathMemory2, i)) + j = 1U; + else + j = 3U; + WRITE_BIT1(m_fecOutput, k, false); + k++; + break; + + case 3U: // if state = S1 + if (!READ_BIT1(m_pathMemory3, i)) + j = 1U; + else + j = 3U; + WRITE_BIT1(m_fecOutput, k, true); + k++; + break; + } + } +} + +bool CDStarRX::checksum(const uint8_t* header) const +{ + union { + uint16_t crc16; + uint8_t crc8[2U]; + }; + + crc16 = 0xFFFFU; + for (uint8_t i = 0U; i < (DSTAR_HEADER_LENGTH_BYTES - 2U); i++) + crc16 = uint16_t(crc8[1U]) ^ CCITT_TABLE[crc8[0U] ^ header[i]]; + + crc16 = ~crc16; + + return crc8[0U] == header[DSTAR_HEADER_LENGTH_BYTES - 2U] && crc8[1U] == header[DSTAR_HEADER_LENGTH_BYTES - 1U]; +} + diff --git a/DStarRX.h b/DStarRX.h new file mode 100644 index 0000000..2490c37 --- /dev/null +++ b/DStarRX.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015,2016 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(DSTARRX_H) +#define DSTARRX_H + +#include "DStarDefines.h" + +enum DSRX_STATE { + DSRXS_NONE, + DSRXS_HEADER, + DSRXS_DATA +}; + +class CDStarRX { +public: + CDStarRX(); + + void databit(bool bit); + + void reset(); + +private: + DSRX_STATE m_rxState; + uint32_t m_patternBuffer; + uint8_t m_rxBuffer[100U]; + unsigned int m_rxBufferBits; + unsigned int m_dataBits; + unsigned int m_mar; + int m_pathMetric[4U]; + unsigned int m_pathMemory0[42U]; + unsigned int m_pathMemory1[42U]; + unsigned int m_pathMemory2[42U]; + unsigned int m_pathMemory3[42U]; + uint8_t m_fecOutput[42U]; + + void processNone(bool bit); + void processHeader(bool bit); + void processData(bool bit); + bool rxHeader(uint8_t* in, uint8_t* out); + void acs(int* metric); + void viterbiDecode(int* data); + void traceBack(); + bool checksum(const uint8_t* header) const; +}; + +#endif diff --git a/DStarTX.cpp b/DStarTX.cpp new file mode 100644 index 0000000..d4fda70 --- /dev/null +++ b/DStarTX.cpp @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2009-2016 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. + */ + +#define WANT_DEBUG + +#include "Config.h" +#include "Globals.h" +#include "DStarTX.h" + +#include "DStarDefines.h" + +const uint8_t BIT_SYNC = 0xAAU; + +const uint8_t FRAME_SYNC[] = {0xEAU, 0xA6U, 0x00U}; + +const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; + +const uint8_t INTERLEAVE_TABLE_TX[] = { + 0x00U, 0x04U, 0x04U, 0x00U, 0x07U, 0x04U, 0x0BU, 0x00U, 0x0EU, 0x04U, + 0x12U, 0x00U, 0x15U, 0x04U, 0x19U, 0x00U, 0x1CU, 0x04U, 0x20U, 0x00U, + 0x23U, 0x04U, 0x27U, 0x00U, 0x2AU, 0x04U, 0x2DU, 0x07U, 0x31U, 0x02U, + 0x34U, 0x05U, 0x38U, 0x00U, 0x3BU, 0x03U, 0x3EU, 0x06U, 0x42U, 0x01U, + 0x45U, 0x04U, 0x48U, 0x07U, 0x4CU, 0x02U, 0x4FU, 0x05U, 0x00U, 0x05U, + 0x04U, 0x01U, 0x07U, 0x05U, 0x0BU, 0x01U, 0x0EU, 0x05U, 0x12U, 0x01U, + 0x15U, 0x05U, 0x19U, 0x01U, 0x1CU, 0x05U, 0x20U, 0x01U, 0x23U, 0x05U, + 0x27U, 0x01U, 0x2AU, 0x05U, 0x2EU, 0x00U, 0x31U, 0x03U, 0x34U, 0x06U, + 0x38U, 0x01U, 0x3BU, 0x04U, 0x3EU, 0x07U, 0x42U, 0x02U, 0x45U, 0x05U, + 0x49U, 0x00U, 0x4CU, 0x03U, 0x4FU, 0x06U, 0x00U, 0x06U, 0x04U, 0x02U, + 0x07U, 0x06U, 0x0BU, 0x02U, 0x0EU, 0x06U, 0x12U, 0x02U, 0x15U, 0x06U, + 0x19U, 0x02U, 0x1CU, 0x06U, 0x20U, 0x02U, 0x23U, 0x06U, 0x27U, 0x02U, + 0x2AU, 0x06U, 0x2EU, 0x01U, 0x31U, 0x04U, 0x34U, 0x07U, 0x38U, 0x02U, + 0x3BU, 0x05U, 0x3FU, 0x00U, 0x42U, 0x03U, 0x45U, 0x06U, 0x49U, 0x01U, + 0x4CU, 0x04U, 0x4FU, 0x07U, 0x00U, 0x07U, 0x04U, 0x03U, 0x07U, 0x07U, + 0x0BU, 0x03U, 0x0EU, 0x07U, 0x12U, 0x03U, 0x15U, 0x07U, 0x19U, 0x03U, + 0x1CU, 0x07U, 0x20U, 0x03U, 0x23U, 0x07U, 0x27U, 0x03U, 0x2AU, 0x07U, + 0x2EU, 0x02U, 0x31U, 0x05U, 0x35U, 0x00U, 0x38U, 0x03U, 0x3BU, 0x06U, + 0x3FU, 0x01U, 0x42U, 0x04U, 0x45U, 0x07U, 0x49U, 0x02U, 0x4CU, 0x05U, + 0x50U, 0x00U, 0x01U, 0x00U, 0x04U, 0x04U, 0x08U, 0x00U, 0x0BU, 0x04U, + 0x0FU, 0x00U, 0x12U, 0x04U, 0x16U, 0x00U, 0x19U, 0x04U, 0x1DU, 0x00U, + 0x20U, 0x04U, 0x24U, 0x00U, 0x27U, 0x04U, 0x2BU, 0x00U, 0x2EU, 0x03U, + 0x31U, 0x06U, 0x35U, 0x01U, 0x38U, 0x04U, 0x3BU, 0x07U, 0x3FU, 0x02U, + 0x42U, 0x05U, 0x46U, 0x00U, 0x49U, 0x03U, 0x4CU, 0x06U, 0x50U, 0x01U, + 0x01U, 0x01U, 0x04U, 0x05U, 0x08U, 0x01U, 0x0BU, 0x05U, 0x0FU, 0x01U, + 0x12U, 0x05U, 0x16U, 0x01U, 0x19U, 0x05U, 0x1DU, 0x01U, 0x20U, 0x05U, + 0x24U, 0x01U, 0x27U, 0x05U, 0x2BU, 0x01U, 0x2EU, 0x04U, 0x31U, 0x07U, + 0x35U, 0x02U, 0x38U, 0x05U, 0x3CU, 0x00U, 0x3FU, 0x03U, 0x42U, 0x06U, + 0x46U, 0x01U, 0x49U, 0x04U, 0x4CU, 0x07U, 0x50U, 0x02U, 0x01U, 0x02U, + 0x04U, 0x06U, 0x08U, 0x02U, 0x0BU, 0x06U, 0x0FU, 0x02U, 0x12U, 0x06U, + 0x16U, 0x02U, 0x19U, 0x06U, 0x1DU, 0x02U, 0x20U, 0x06U, 0x24U, 0x02U, + 0x27U, 0x06U, 0x2BU, 0x02U, 0x2EU, 0x05U, 0x32U, 0x00U, 0x35U, 0x03U, + 0x38U, 0x06U, 0x3CU, 0x01U, 0x3FU, 0x04U, 0x42U, 0x07U, 0x46U, 0x02U, + 0x49U, 0x05U, 0x4DU, 0x00U, 0x50U, 0x03U, 0x01U, 0x03U, 0x04U, 0x07U, + 0x08U, 0x03U, 0x0BU, 0x07U, 0x0FU, 0x03U, 0x12U, 0x07U, 0x16U, 0x03U, + 0x19U, 0x07U, 0x1DU, 0x03U, 0x20U, 0x07U, 0x24U, 0x03U, 0x27U, 0x07U, + 0x2BU, 0x03U, 0x2EU, 0x06U, 0x32U, 0x01U, 0x35U, 0x04U, 0x38U, 0x07U, + 0x3CU, 0x02U, 0x3FU, 0x05U, 0x43U, 0x00U, 0x46U, 0x03U, 0x49U, 0x06U, + 0x4DU, 0x01U, 0x50U, 0x04U, 0x01U, 0x04U, 0x05U, 0x00U, 0x08U, 0x04U, + 0x0CU, 0x00U, 0x0FU, 0x04U, 0x13U, 0x00U, 0x16U, 0x04U, 0x1AU, 0x00U, + 0x1DU, 0x04U, 0x21U, 0x00U, 0x24U, 0x04U, 0x28U, 0x00U, 0x2BU, 0x04U, + 0x2EU, 0x07U, 0x32U, 0x02U, 0x35U, 0x05U, 0x39U, 0x00U, 0x3CU, 0x03U, + 0x3FU, 0x06U, 0x43U, 0x01U, 0x46U, 0x04U, 0x49U, 0x07U, 0x4DU, 0x02U, + 0x50U, 0x05U, 0x01U, 0x05U, 0x05U, 0x01U, 0x08U, 0x05U, 0x0CU, 0x01U, + 0x0FU, 0x05U, 0x13U, 0x01U, 0x16U, 0x05U, 0x1AU, 0x01U, 0x1DU, 0x05U, + 0x21U, 0x01U, 0x24U, 0x05U, 0x28U, 0x01U, 0x2BU, 0x05U, 0x2FU, 0x00U, + 0x32U, 0x03U, 0x35U, 0x06U, 0x39U, 0x01U, 0x3CU, 0x04U, 0x3FU, 0x07U, + 0x43U, 0x02U, 0x46U, 0x05U, 0x4AU, 0x00U, 0x4DU, 0x03U, 0x50U, 0x06U, + 0x01U, 0x06U, 0x05U, 0x02U, 0x08U, 0x06U, 0x0CU, 0x02U, 0x0FU, 0x06U, + 0x13U, 0x02U, 0x16U, 0x06U, 0x1AU, 0x02U, 0x1DU, 0x06U, 0x21U, 0x02U, + 0x24U, 0x06U, 0x28U, 0x02U, 0x2BU, 0x06U, 0x2FU, 0x01U, 0x32U, 0x04U, + 0x35U, 0x07U, 0x39U, 0x02U, 0x3CU, 0x05U, 0x40U, 0x00U, 0x43U, 0x03U, + 0x46U, 0x06U, 0x4AU, 0x01U, 0x4DU, 0x04U, 0x50U, 0x07U, 0x01U, 0x07U, + 0x05U, 0x03U, 0x08U, 0x07U, 0x0CU, 0x03U, 0x0FU, 0x07U, 0x13U, 0x03U, + 0x16U, 0x07U, 0x1AU, 0x03U, 0x1DU, 0x07U, 0x21U, 0x03U, 0x24U, 0x07U, + 0x28U, 0x03U, 0x2BU, 0x07U, 0x2FU, 0x02U, 0x32U, 0x05U, 0x36U, 0x00U, + 0x39U, 0x03U, 0x3CU, 0x06U, 0x40U, 0x01U, 0x43U, 0x04U, 0x46U, 0x07U, + 0x4AU, 0x02U, 0x4DU, 0x05U, 0x51U, 0x00U, 0x02U, 0x00U, 0x05U, 0x04U, + 0x09U, 0x00U, 0x0CU, 0x04U, 0x10U, 0x00U, 0x13U, 0x04U, 0x17U, 0x00U, + 0x1AU, 0x04U, 0x1EU, 0x00U, 0x21U, 0x04U, 0x25U, 0x00U, 0x28U, 0x04U, + 0x2CU, 0x00U, 0x2FU, 0x03U, 0x32U, 0x06U, 0x36U, 0x01U, 0x39U, 0x04U, + 0x3CU, 0x07U, 0x40U, 0x02U, 0x43U, 0x05U, 0x47U, 0x00U, 0x4AU, 0x03U, + 0x4DU, 0x06U, 0x51U, 0x01U, 0x02U, 0x01U, 0x05U, 0x05U, 0x09U, 0x01U, + 0x0CU, 0x05U, 0x10U, 0x01U, 0x13U, 0x05U, 0x17U, 0x01U, 0x1AU, 0x05U, + 0x1EU, 0x01U, 0x21U, 0x05U, 0x25U, 0x01U, 0x28U, 0x05U, 0x2CU, 0x01U, + 0x2FU, 0x04U, 0x32U, 0x07U, 0x36U, 0x02U, 0x39U, 0x05U, 0x3DU, 0x00U, + 0x40U, 0x03U, 0x43U, 0x06U, 0x47U, 0x01U, 0x4AU, 0x04U, 0x4DU, 0x07U, + 0x51U, 0x02U, 0x02U, 0x02U, 0x05U, 0x06U, 0x09U, 0x02U, 0x0CU, 0x06U, + 0x10U, 0x02U, 0x13U, 0x06U, 0x17U, 0x02U, 0x1AU, 0x06U, 0x1EU, 0x02U, + 0x21U, 0x06U, 0x25U, 0x02U, 0x28U, 0x06U, 0x2CU, 0x02U, 0x2FU, 0x05U, + 0x33U, 0x00U, 0x36U, 0x03U, 0x39U, 0x06U, 0x3DU, 0x01U, 0x40U, 0x04U, + 0x43U, 0x07U, 0x47U, 0x02U, 0x4AU, 0x05U, 0x4EU, 0x00U, 0x51U, 0x03U, + 0x02U, 0x03U, 0x05U, 0x07U, 0x09U, 0x03U, 0x0CU, 0x07U, 0x10U, 0x03U, + 0x13U, 0x07U, 0x17U, 0x03U, 0x1AU, 0x07U, 0x1EU, 0x03U, 0x21U, 0x07U, + 0x25U, 0x03U, 0x28U, 0x07U, 0x2CU, 0x03U, 0x2FU, 0x06U, 0x33U, 0x01U, + 0x36U, 0x04U, 0x39U, 0x07U, 0x3DU, 0x02U, 0x40U, 0x05U, 0x44U, 0x00U, + 0x47U, 0x03U, 0x4AU, 0x06U, 0x4EU, 0x01U, 0x51U, 0x04U, 0x02U, 0x04U, + 0x06U, 0x00U, 0x09U, 0x04U, 0x0DU, 0x00U, 0x10U, 0x04U, 0x14U, 0x00U, + 0x17U, 0x04U, 0x1BU, 0x00U, 0x1EU, 0x04U, 0x22U, 0x00U, 0x25U, 0x04U, + 0x29U, 0x00U, 0x2CU, 0x04U, 0x2FU, 0x07U, 0x33U, 0x02U, 0x36U, 0x05U, + 0x3AU, 0x00U, 0x3DU, 0x03U, 0x40U, 0x06U, 0x44U, 0x01U, 0x47U, 0x04U, + 0x4AU, 0x07U, 0x4EU, 0x02U, 0x51U, 0x05U, 0x02U, 0x05U, 0x06U, 0x01U, + 0x09U, 0x05U, 0x0DU, 0x01U, 0x10U, 0x05U, 0x14U, 0x01U, 0x17U, 0x05U, + 0x1BU, 0x01U, 0x1EU, 0x05U, 0x22U, 0x01U, 0x25U, 0x05U, 0x29U, 0x01U, + 0x2CU, 0x05U, 0x30U, 0x00U, 0x33U, 0x03U, 0x36U, 0x06U, 0x3AU, 0x01U, + 0x3DU, 0x04U, 0x40U, 0x07U, 0x44U, 0x02U, 0x47U, 0x05U, 0x4BU, 0x00U, + 0x4EU, 0x03U, 0x51U, 0x06U, 0x02U, 0x06U, 0x06U, 0x02U, 0x09U, 0x06U, + 0x0DU, 0x02U, 0x10U, 0x06U, 0x14U, 0x02U, 0x17U, 0x06U, 0x1BU, 0x02U, + 0x1EU, 0x06U, 0x22U, 0x02U, 0x25U, 0x06U, 0x29U, 0x02U, 0x2CU, 0x06U, + 0x30U, 0x01U, 0x33U, 0x04U, 0x36U, 0x07U, 0x3AU, 0x02U, 0x3DU, 0x05U, + 0x41U, 0x00U, 0x44U, 0x03U, 0x47U, 0x06U, 0x4BU, 0x01U, 0x4EU, 0x04U, + 0x51U, 0x07U, 0x02U, 0x07U, 0x06U, 0x03U, 0x09U, 0x07U, 0x0DU, 0x03U, + 0x10U, 0x07U, 0x14U, 0x03U, 0x17U, 0x07U, 0x1BU, 0x03U, 0x1EU, 0x07U, + 0x22U, 0x03U, 0x25U, 0x07U, 0x29U, 0x03U, 0x2CU, 0x07U, 0x30U, 0x02U, + 0x33U, 0x05U, 0x37U, 0x00U, 0x3AU, 0x03U, 0x3DU, 0x06U, 0x41U, 0x01U, + 0x44U, 0x04U, 0x47U, 0x07U, 0x4BU, 0x02U, 0x4EU, 0x05U, 0x52U, 0x00U, + 0x03U, 0x00U, 0x06U, 0x04U, 0x0AU, 0x00U, 0x0DU, 0x04U, 0x11U, 0x00U, + 0x14U, 0x04U, 0x18U, 0x00U, 0x1BU, 0x04U, 0x1FU, 0x00U, 0x22U, 0x04U, + 0x26U, 0x00U, 0x29U, 0x04U, 0x2DU, 0x00U, 0x30U, 0x03U, 0x33U, 0x06U, + 0x37U, 0x01U, 0x3AU, 0x04U, 0x3DU, 0x07U, 0x41U, 0x02U, 0x44U, 0x05U, + 0x48U, 0x00U, 0x4BU, 0x03U, 0x4EU, 0x06U, 0x52U, 0x01U, 0x03U, 0x01U, + 0x06U, 0x05U, 0x0AU, 0x01U, 0x0DU, 0x05U, 0x11U, 0x01U, 0x14U, 0x05U, + 0x18U, 0x01U, 0x1BU, 0x05U, 0x1FU, 0x01U, 0x22U, 0x05U, 0x26U, 0x01U, + 0x29U, 0x05U, 0x2DU, 0x01U, 0x30U, 0x04U, 0x33U, 0x07U, 0x37U, 0x02U, + 0x3AU, 0x05U, 0x3EU, 0x00U, 0x41U, 0x03U, 0x44U, 0x06U, 0x48U, 0x01U, + 0x4BU, 0x04U, 0x4EU, 0x07U, 0x52U, 0x02U, 0x03U, 0x02U, 0x06U, 0x06U, + 0x0AU, 0x02U, 0x0DU, 0x06U, 0x11U, 0x02U, 0x14U, 0x06U, 0x18U, 0x02U, + 0x1BU, 0x06U, 0x1FU, 0x02U, 0x22U, 0x06U, 0x26U, 0x02U, 0x29U, 0x06U, + 0x2DU, 0x02U, 0x30U, 0x05U, 0x34U, 0x00U, 0x37U, 0x03U, 0x3AU, 0x06U, + 0x3EU, 0x01U, 0x41U, 0x04U, 0x44U, 0x07U, 0x48U, 0x02U, 0x4BU, 0x05U, + 0x4FU, 0x00U, 0x52U, 0x03U, 0x03U, 0x03U, 0x06U, 0x07U, 0x0AU, 0x03U, + 0x0DU, 0x07U, 0x11U, 0x03U, 0x14U, 0x07U, 0x18U, 0x03U, 0x1BU, 0x07U, + 0x1FU, 0x03U, 0x22U, 0x07U, 0x26U, 0x03U, 0x29U, 0x07U, 0x2DU, 0x03U, + 0x30U, 0x06U, 0x34U, 0x01U, 0x37U, 0x04U, 0x3AU, 0x07U, 0x3EU, 0x02U, + 0x41U, 0x05U, 0x45U, 0x00U, 0x48U, 0x03U, 0x4BU, 0x06U, 0x4FU, 0x01U, + 0x52U, 0x04U, 0x03U, 0x04U, 0x07U, 0x00U, 0x0AU, 0x04U, 0x0EU, 0x00U, + 0x11U, 0x04U, 0x15U, 0x00U, 0x18U, 0x04U, 0x1CU, 0x00U, 0x1FU, 0x04U, + 0x23U, 0x00U, 0x26U, 0x04U, 0x2AU, 0x00U, 0x2DU, 0x04U, 0x30U, 0x07U, + 0x34U, 0x02U, 0x37U, 0x05U, 0x3BU, 0x00U, 0x3EU, 0x03U, 0x41U, 0x06U, + 0x45U, 0x01U, 0x48U, 0x04U, 0x4BU, 0x07U, 0x4FU, 0x02U, 0x52U, 0x05U, + 0x03U, 0x05U, 0x07U, 0x01U, 0x0AU, 0x05U, 0x0EU, 0x01U, 0x11U, 0x05U, + 0x15U, 0x01U, 0x18U, 0x05U, 0x1CU, 0x01U, 0x1FU, 0x05U, 0x23U, 0x01U, + 0x26U, 0x05U, 0x2AU, 0x01U, 0x2DU, 0x05U, 0x31U, 0x00U, 0x34U, 0x03U, + 0x37U, 0x06U, 0x3BU, 0x01U, 0x3EU, 0x04U, 0x41U, 0x07U, 0x45U, 0x02U, + 0x48U, 0x05U, 0x4CU, 0x00U, 0x4FU, 0x03U, 0x52U, 0x06U, 0x03U, 0x06U, + 0x07U, 0x02U, 0x0AU, 0x06U, 0x0EU, 0x02U, 0x11U, 0x06U, 0x15U, 0x02U, + 0x18U, 0x06U, 0x1CU, 0x02U, 0x1FU, 0x06U, 0x23U, 0x02U, 0x26U, 0x06U, + 0x2AU, 0x02U, 0x2DU, 0x06U, 0x31U, 0x01U, 0x34U, 0x04U, 0x37U, 0x07U, + 0x3BU, 0x02U, 0x3EU, 0x05U, 0x42U, 0x00U, 0x45U, 0x03U, 0x48U, 0x06U, + 0x4CU, 0x01U, 0x4FU, 0x04U, 0x52U, 0x07U, 0x03U, 0x07U, 0x07U, 0x03U, + 0x0AU, 0x07U, 0x0EU, 0x03U, 0x11U, 0x07U, 0x15U, 0x03U, 0x18U, 0x07U, + 0x1CU, 0x03U, 0x1FU, 0x07U, 0x23U, 0x03U, 0x26U, 0x07U, 0x2AU, 0x03U +}; + +const uint8_t SCRAMBLE_TABLE_TX[] = { + 0x00U, 0xF7U, 0x34U, 0x09U, 0x44U, 0x46U, 0xD7U, 0x06U, 0xB3U, 0x72U, + 0xDEU, 0x42U, 0xF5U, 0xA5U, 0xD8U, 0xF1U, 0x87U, 0x7BU, 0x9AU, 0x04U, + 0x22U, 0xA3U, 0x6BU, 0x83U, 0x59U, 0x39U, 0x6FU, 0xA1U, 0xFAU, 0x52U, + 0xECU, 0xF8U, 0xC3U, 0x3DU, 0x4DU, 0x02U, 0x91U, 0xD1U, 0xB5U, 0xC1U, + 0xACU, 0x9CU, 0xB7U, 0x50U, 0x7DU, 0x29U, 0x76U, 0xFCU, 0xE1U, 0x9EU, + 0x26U, 0x81U, 0xC8U, 0xE8U, 0xDAU, 0x60U, 0x56U, 0xCEU, 0x5BU, 0xA8U, + 0xBEU, 0x14U, 0x3BU, 0xFEU, 0x70U, 0x4FU, 0x93U, 0x40U, 0x64U, 0x74U, + 0x6DU, 0x30U, 0x2BU, 0xE7U, 0x2DU, 0x54U, 0x5FU, 0x8AU, 0x1DU, 0x7FU, + 0xB8U, 0xA7U, 0x49U, 0x20U, 0x32U, 0xBAU, 0x36U, 0x98U, 0x95U, 0xF3U, + 0x06U}; + +const uint8_t DSTAR_HEADER = 0x00U; +const uint8_t DSTAR_DATA = 0x01U; +const uint8_t DSTAR_EOT = 0x02U; + +CDStarTX::CDStarTX() : +m_buffer(), +m_poBuffer(), +m_poLen(0U), +m_poPtr(0U), +m_txDelay(60U), // 100ms +m_count(0U) +{ + +} + +void CDStarTX::process() +{ + if (m_buffer.getData() == 0U && m_poLen == 0U) + return; + + uint8_t type = m_buffer.peek(); + + if (type == DSTAR_HEADER && m_poLen == 0U) { + if (!m_tx) { + m_delay = true; + m_count = 0U; + m_poLen = m_txDelay; + } else { + m_delay = false; + // Pop the type byte off + m_buffer.get(); + + uint8_t header[DSTAR_HEADER_LENGTH_BYTES]; + for (uint8_t i = 0U; i < DSTAR_HEADER_LENGTH_BYTES; i++) + header[i] = m_buffer.get(); + + uint8_t buffer[86U]; + txHeader(header, buffer + 2U); + + buffer[0U] = FRAME_SYNC[0U]; + buffer[1U] = FRAME_SYNC[1U]; + buffer[2U] |= FRAME_SYNC[2U]; + + for (uint8_t i = 0U; i < 85U; i++) + m_poBuffer[m_poLen++] = buffer[i]; + } + + m_poPtr = 0U; + } + + if (type == DSTAR_DATA && m_poLen == 0U) { + m_delay = false; + if (!m_tx) + m_count = 0U; + + // Pop the type byte off + m_buffer.get(); + + for (uint8_t i = 0U; i < DSTAR_DATA_LENGTH_BYTES; i++) + m_poBuffer[m_poLen++] = m_buffer.get(); + + m_poPtr = 0U; + } + + if (type == DSTAR_EOT && m_poLen == 0U) { + m_delay = false; + // Pop the type byte off + 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]; + } + + m_poPtr = 0U; + } + + if (m_poLen > 0U) { + uint16_t space = io.getSpace(); + + while (space > 8U) { + if (m_delay) { + m_poPtr++; + writeByte(BIT_SYNC); + } + else + writeByte(m_poBuffer[m_poPtr++]); + + space -= 8U; + + if (m_poPtr >= m_poLen) { + m_poPtr = 0U; + m_poLen = 0U; + m_delay = false; + return; + } + } + } +} + +uint8_t CDStarTX::writeHeader(const uint8_t* header, uint8_t length) +{ + if (length != DSTAR_HEADER_LENGTH_BYTES) + return 4U; + + uint16_t space = m_buffer.getSpace(); + if (space < (DSTAR_HEADER_LENGTH_BYTES + 1U)) { + DEBUG2("DStarTX: header space available", space); + return 5U; + } + + m_buffer.put(DSTAR_HEADER); + + for (uint8_t i = 0U; i < DSTAR_HEADER_LENGTH_BYTES; i++) + m_buffer.put(header[i]); + + return 0U; +} + +uint8_t CDStarTX::writeData(const uint8_t* data, uint8_t length) +{ + if (length != DSTAR_DATA_LENGTH_BYTES) + return 4U; + + uint16_t space = m_buffer.getSpace(); + if (space < (DSTAR_DATA_LENGTH_BYTES + 1U)) { + DEBUG2("DStarTX: data space available", space); + return 5U; + } + + m_buffer.put(DSTAR_DATA); + + for (uint8_t i = 0U; i < DSTAR_DATA_LENGTH_BYTES; i++) + m_buffer.put(data[i]); + + return 0U; +} + +uint8_t CDStarTX::writeEOT() +{ + uint16_t space = m_buffer.getSpace(); + if (space < 1U) { + DEBUG2("DStarTX: EOT space available", space); + return 5U; + } + + m_buffer.put(DSTAR_EOT); + + return 0U; +} + +void CDStarTX::txHeader(const uint8_t* in, uint8_t* out) const +{ + uint8_t intermediate[84U]; + uint32_t i; + + for (i = 0U; i < 83U; i++) { + intermediate[i] = 0x00U; + out[i] = 0x00U; + } + + // Convolve the header + uint8_t d, d1 = 0U, d2 = 0U, g0, g1; + uint32_t k = 0U; + for (i = 0U; i < 42U; i++) { + for (uint8_t j = 0U; j < 8U; j++) { + uint8_t mask = (0x01U << j); + d = 0U; + + if (in[i] & mask) + d = 1U; + + g0 = (d + d2) & 1; + g1 = (d + d1 + d2) & 1; + d2 = d1; + d1 = d; + + if (g1) + intermediate[k >> 3] |= BIT_MASK_TABLE[k & 7]; + k++; + + if (g0) + intermediate[k >> 3] |= BIT_MASK_TABLE[k & 7]; + k++; + } + } + + // Interleave the header + i = 0U; + while (i < 660U) { + unsigned char d = intermediate[i >> 3]; + + if (d & 0x80U) + out[INTERLEAVE_TABLE_TX[i * 2U]] |= (0x01U << INTERLEAVE_TABLE_TX[i * 2U + 1U]); + i++; + + if (d & 0x40U) + out[INTERLEAVE_TABLE_TX[i * 2U]] |= (0x01U << INTERLEAVE_TABLE_TX[i * 2U + 1U]); + i++; + + if (d & 0x20U) + out[INTERLEAVE_TABLE_TX[i * 2U]] |= (0x01U << INTERLEAVE_TABLE_TX[i * 2U + 1U]); + i++; + + if (d & 0x10U) + out[INTERLEAVE_TABLE_TX[i * 2U]] |= (0x01U << INTERLEAVE_TABLE_TX[i * 2U + 1U]); + i++; + + if (i < 660U) { + if (d & 0x08U) + out[INTERLEAVE_TABLE_TX[i * 2U]] |= (0x01U << INTERLEAVE_TABLE_TX[i * 2U + 1U]); + i++; + + if (d & 0x04U) + out[INTERLEAVE_TABLE_TX[i * 2U]] |= (0x01U << INTERLEAVE_TABLE_TX[i * 2U + 1U]); + i++; + + if (d & 0x02U) + out[INTERLEAVE_TABLE_TX[i * 2U]] |= (0x01U << INTERLEAVE_TABLE_TX[i * 2U + 1U]); + i++; + + if (d & 0x01U) + out[INTERLEAVE_TABLE_TX[i * 2U]] |= (0x01U << INTERLEAVE_TABLE_TX[i * 2U + 1U]); + i++; + } + } + + // Scramble the header + for (i = 0U; i < 83U; i++) + out[i] ^= SCRAMBLE_TABLE_TX[i]; +} + +void CDStarTX::writeByte(uint8_t c) +{ + uint8_t bit; + uint8_t mask = 0x01U; + + for (uint8_t i = 0U; i < 8U; i++) { + if ((c & mask) == mask) + bit = 1U; + else + bit = 0U; + + io.write(&bit, 1); + mask <<= 1; + } + +} + +void CDStarTX::setTXDelay(uint8_t delay) +{ + m_txDelay = 150U + uint16_t(delay) * 6U; // 250ms + tx delay +} + +uint16_t CDStarTX::getSpace() const +{ + return m_buffer.getSpace() / (DSTAR_DATA_LENGTH_BYTES + 1U); +} diff --git a/DStarTX.h b/DStarTX.h new file mode 100644 index 0000000..5f3957f --- /dev/null +++ b/DStarTX.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015,2016 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(DSTARTX_H) +#define DSTARTX_H + +#include "SerialRB.h" + +class CDStarTX { +public: + CDStarTX(); + + uint8_t writeHeader(const uint8_t* header, uint8_t length); + uint8_t writeData(const uint8_t* data, uint8_t length); + uint8_t writeEOT(); + + void process(); + + void setTXDelay(uint8_t delay); + + uint16_t getSpace() const; + +private: + CSerialRB m_buffer; + uint8_t m_poBuffer[90U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; // In bytes + uint32_t m_count; + bool m_delay; + + void txHeader(const uint8_t* in, uint8_t* out) const; + void writeByte(uint8_t c); +}; + +#endif diff --git a/Debug.h b/Debug.h new file mode 100644 index 0000000..c056d6c --- /dev/null +++ b/Debug.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015,2016 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(DEBUG_H) +#define DEBUG_H + +#if defined(WANT_DEBUG) + +#include "Globals.h" + +#define DEBUG1(a) serial.writeDebug((a)) +#define DEBUG2(a,b) serial.writeDebug((a),(b)) +#define DEBUG3(a,b,c) serial.writeDebug((a),(b),(c)) +#define DEBUG4(a,b,c,d) serial.writeDebug((a),(b),(c),(d)) +#define DEBUG5(a,b,c,d,e) serial.writeDebug((a),(b),(c),(d),(e)) +#define ASSERT(a) serial.writeAssert((a),#a,__FILE__,__LINE__) + +#else + +#define DEBUG1(a) +#define DEBUG2(a,b) +#define DEBUG3(a,b,c) +#define DEBUG4(a,b,c,d) +#define DEBUG5(a,b,c,d,e) +#define ASSERT(a) + +#endif + +#endif + diff --git a/Globals.h b/Globals.h new file mode 100644 index 0000000..1e01060 --- /dev/null +++ b/Globals.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015,2016 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(GLOBALS_H) +#define GLOBALS_H + +#if defined(STM32F10X_MD) +#include +#include "string.h" +#else +#include +#endif + +enum MMDVM_STATE { + STATE_IDLE = 0, + STATE_DSTAR = 1, + STATE_DMR = 2, + STATE_YSF = 3, + STATE_P25 = 4 +}; + +#include "IO.h" +#include "SerialPort.h" +#include "DMRDMORX.h" +#include "DMRDMOTX.h" +#include "DStarRX.h" +#include "DStarTX.h" +#include "YSFRX.h" +#include "YSFTX.h" +#include "P25RX.h" +#include "P25TX.h" +#include "Debug.h" + +const uint16_t TX_RINGBUFFER_SIZE = 100U; +const uint16_t RX_RINGBUFFER_SIZE = 120U; + +extern MMDVM_STATE m_modemState; + +extern bool m_dstarEnable; +extern bool m_dmrEnable; +extern bool m_ysfEnable; +extern bool m_p25Enable; + +extern bool m_tx; +extern bool m_dcd; + +extern CIO io; +extern CSerialPort serial; + +extern CDStarRX dstarRX; +extern CDStarTX dstarTX; + +extern CDMRDMORX dmrDMORX; +extern CDMRDMOTX dmrDMOTX; + +extern CYSFRX ysfRX; +extern CYSFTX ysfTX; + +extern CP25RX p25RX; +extern CP25TX p25TX; + +#endif + diff --git a/IO.cpp b/IO.cpp new file mode 100644 index 0000000..79541ff --- /dev/null +++ b/IO.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2015, 2016 by Jonathan Naylor G4KLX + * Copyright (C) 2016, 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 "IO.h" + +#if defined(ADF7021) +#include "ADF7021.h" +#endif + +uint32_t m_frequency_rx; +uint32_t m_frequency_tx; +uint8_t m_power; + +CIO::CIO(): +m_started(false), +m_rxBuffer(RX_RINGBUFFER_SIZE), +m_txBuffer(TX_RINGBUFFER_SIZE) +{ + Init(); + + LED_pin(HIGH); + PTT_pin(LOW); + DSTAR_pin(LOW); + DMR_pin(LOW); + YSF_pin(LOW); + P25_pin(LOW); + COS_pin(LOW); + DEB_pin(LOW); + + TXD_pin(LOW); + SCLK_pin(LOW); + SDATA_pin(LOW); + SLE_pin(LOW); +} + +void CIO::process() +{ + uint8_t bit; + + // Switch off the transmitter if needed + if (m_txBuffer.getData() == 0U && m_tx) { + m_tx = false; + setRX(); + } + + if (m_rxBuffer.getData() >= 1U) { + m_rxBuffer.get(bit); + + if(m_dstarEnable) + dstarRX.databit(bit); + else if(m_dmrEnable) + dmrDMORX.databit(bit); + else if(m_ysfEnable) + ysfRX.databit(bit); + else if(m_p25Enable) + p25RX.databit(bit); + } +} + +void CIO::interrupt() +{ + uint8_t bit = 0; + + if(m_tx) { + m_txBuffer.get(bit); + + if(bit) + TXD_pin(HIGH); + else + TXD_pin(LOW); + + } else { + if(RXD_pin()) + bit = 1; + else + bit = 0; + + m_rxBuffer.put(bit); + } + +} + +void CIO::write(uint8_t* data, uint16_t length) +{ + if (!m_started) + return; + + for (uint16_t i = 0U; i < length; i++) + m_txBuffer.put(data[i]); + + // Switch the transmitter on if needed + if (!m_tx) { + setTX(); + m_tx = true; + } + +} + +uint16_t CIO::getSpace() const +{ + return m_txBuffer.getSpace(); +} + +bool CIO::hasTXOverflow() +{ + return m_txBuffer.hasOverflowed(); +} + +bool CIO::hasRXOverflow() +{ + return m_rxBuffer.hasOverflowed(); +} + +uint8_t CIO::setFreq(uint32_t frequency_rx, uint32_t frequency_tx) +{ + // power level + m_power = 0x20; + + if( !( ((frequency_rx >= VHF_MIN)&&(frequency_rx < VHF_MAX)) || ((frequency_tx >= VHF_MIN)&&(frequency_tx < VHF_MAX)) || \ + ((frequency_rx >= UHF_MIN)&&(frequency_rx < UHF_MAX)) || ((frequency_tx >= UHF_MIN)&&(frequency_tx < UHF_MAX)) ) ) + return 4U; + + m_frequency_rx = frequency_rx; + m_frequency_tx = frequency_tx; + + return 0U; +} + +void CIO::setMode() +{ + DSTAR_pin(m_modemState == STATE_DSTAR); + DMR_pin(m_modemState == STATE_DMR); + YSF_pin(m_modemState == STATE_YSF); + P25_pin(m_modemState == STATE_P25); +} + +void CIO::setDecode(bool dcd) +{ + if (dcd != m_dcd) + COS_pin(dcd ? true : false); + + m_dcd = dcd; +} diff --git a/IO.h b/IO.h new file mode 100644 index 0000000..797da19 --- /dev/null +++ b/IO.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015, 2016 by Jonathan Naylor G4KLX + * Copyright (C) 2016, 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. + */ + +#if !defined(CIO_H) +#define CIO_H + +#include "Globals.h" +#include "BitRB.h" + +#define LOW 0 +#define HIGH 1 + +#define VHF_MIN 144000000 +#define VHF_MAX 148000000 +#define UHF_MIN 430000000 +#define UHF_MAX 450000000 + +extern uint32_t m_frequency_rx; +extern uint32_t m_frequency_tx; +extern uint8_t m_power; + +class CIO { + +public: + CIO(); + + // Platform API + void Init(void); + void SCLK_pin(bool on); + void SDATA_pin(bool on); + void SLE_pin(bool on); + bool RXD_pin(); + void TXD_pin(bool on); + void PTT_pin(bool on); + void LED_pin(bool on); + void DEB_pin(bool on); + void DSTAR_pin(bool on); + void DMR_pin(bool on); + void YSF_pin(bool on); + void P25_pin(bool on); + void COS_pin(bool on); + void interrupt(void); + + // IO API + void write(uint8_t* data, uint16_t length); + uint16_t getSpace() const; + void process(); + bool hasTXOverflow(); + bool hasRXOverflow(); + uint8_t setFreq(uint32_t frequency_rx, uint32_t frequency_tx); + void setMode(); + void setDecode(bool dcd); + + // RF interface API + void setTX(); + void setRX(); + void ifConf(); + void ifInit(); + +private: + bool m_started; + CBitRB m_rxBuffer; + CBitRB m_txBuffer; + + void delay_rx(void); + +}; + +#endif diff --git a/IOArduino.cpp b/IOArduino.cpp new file mode 100644 index 0000000..bce310f --- /dev/null +++ b/IOArduino.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2015, 2016 by Jonathan Naylor G4KLX + * Copyright (C) 2016, 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 "IO.h" + +#if defined(ARDUINO) + +#if defined (__STM32F1__) + +// STM32F1 pin definitions, using STM32duino +#define PIN_SCLK PB5 +#define PIN_SREAD PB7 +#define PIN_SDATA PB6 +#define PIN_SLE PB8 +#define PIN_RXD PB4 +#define PIN_TXD PB3 +#define PIN_TXRX_CLK PA15 +#define PIN_LED PC13 +#define PIN_DEB PB9 +#define PIN_DSTAR_LED PB12 +#define PIN_DMR_LED PB13 +#define PIN_YSF_LED PB1 +#define PIN_P25_LED PB0 +#define PIN_PTT_LED PB14 +#define PIN_COS_LED PB15 + +#else + +// Arduino pin definitions (Due and Zero) +#define PIN_SCLK 3 +#define PIN_SDATA 4 // 2 in Arduino Zero Pro +#define PIN_SREAD 5 +#define PIN_SLE 6 +#define PIN_RXD 7 +#define PIN_TXD 8 +#define PIN_TXRX_CLK 2 // 4 in Arduino Zero Pro +#define PIN_LED 13 +#define PIN_DEB 11 +#define PIN_DSTAR_LED 14 +#define PIN_DMR_LED 15 +#define PIN_YSF_LED 16 +#define PIN_P25_LED 17 +#define PIN_PTT_LED 9 +#define PIN_COS_LED 10 + +#endif + +extern "C" { + void EXT_IRQHandler(void) { + io.interrupt(); + } +} + +void CIO::delay_rx() { + delayMicroseconds(1); +} + +void CIO::Init() +{ +#if defined (__STM32F1__) + afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY); +#endif + + pinMode(PIN_SCLK, OUTPUT); + pinMode(PIN_SDATA, OUTPUT); + pinMode(PIN_SLE, OUTPUT); + pinMode(PIN_RXD, INPUT); + pinMode(PIN_TXD, OUTPUT); + pinMode(PIN_TXRX_CLK, INPUT); + pinMode(PIN_LED, OUTPUT); + pinMode(PIN_DEB, OUTPUT); + pinMode(PIN_DSTAR_LED, OUTPUT); + pinMode(PIN_DMR_LED, OUTPUT); + pinMode(PIN_YSF_LED, OUTPUT); + pinMode(PIN_P25_LED, OUTPUT); + pinMode(PIN_PTT_LED, OUTPUT); + pinMode(PIN_COS_LED, OUTPUT); +} + +void CIO::ifInit() +{ + m_started = true; + +#if defined (__STM32F1__) + attachInterrupt(PIN_TXRX_CLK, EXT_IRQHandler, RISING); +#else + attachInterrupt(digitalPinToInterrupt(PIN_TXRX_CLK), EXT_IRQHandler, RISING); +#endif + + ifConf(); + delay_rx();; + setRX(); +} + +void CIO::SCLK_pin(bool on) +{ + digitalWrite(PIN_SCLK, on ? HIGH : LOW); +} + +void CIO::SDATA_pin(bool on) +{ + digitalWrite(PIN_SDATA, on ? HIGH : LOW); +} + +void CIO::SLE_pin(bool on) +{ + digitalWrite(PIN_SLE, on ? HIGH : LOW); +} + +bool CIO::RXD_pin() +{ + return digitalRead(PIN_RXD) == HIGH; +} + +void CIO::TXD_pin(bool on) +{ + digitalWrite(PIN_TXD, on ? HIGH : LOW); +} + +void CIO::LED_pin(bool on) +{ + digitalWrite(PIN_LED, on ? HIGH : LOW); +} + +void CIO::DEB_pin(bool on) +{ + digitalWrite(PIN_DEB, on ? HIGH : LOW); +} + +void CIO::DSTAR_pin(bool on) +{ + digitalWrite(PIN_DSTAR_LED, on ? HIGH : LOW); +} + +void CIO::DMR_pin(bool on) +{ + digitalWrite(PIN_DMR_LED, on ? HIGH : LOW); +} + +void CIO::YSF_pin(bool on) +{ + digitalWrite(PIN_YSF_LED, on ? HIGH : LOW); +} + +void CIO::P25_pin(bool on) +{ + digitalWrite(PIN_P25_LED, on ? HIGH : LOW); +} + +void CIO::PTT_pin(bool on) +{ + digitalWrite(PIN_PTT_LED, on ? HIGH : LOW); +} + +void CIO::COS_pin(bool on) +{ + digitalWrite(PIN_COS_LED, on ? HIGH : LOW); +} + +#endif diff --git a/IOSTM.cpp b/IOSTM.cpp new file mode 100644 index 0000000..515f4cf --- /dev/null +++ b/IOSTM.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2016 by Jim McLaughlin KI6ZUM + * Copyright (C) 2016, 2017 by Andy Uribe CA6JAU + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" + +#if defined(STM32F10X_MD) + +#include "Globals.h" +#include "IO.h" + +#define PIN_SCLK GPIO_Pin_5 +#define PORT_SCLK GPIOB + +#define PIN_SREAD GPIO_Pin_7 +#define PORT_SREAD GPIOB + +#define PIN_SDATA GPIO_Pin_6 +#define PORT_SDATA GPIOB + +#define PIN_SLE GPIO_Pin_8 +#define PORT_SLE GPIOB + +#define PIN_RXD GPIO_Pin_4 +#define PORT_RXD GPIOB + +#define PIN_TXD GPIO_Pin_3 +#define PORT_TXD GPIOB + +#define PIN_TXRX_CLK GPIO_Pin_15 +#define PORT_TXRX_CLK GPIOA +#define PIN_TXRX_CLK_INT GPIO_PinSource15 +#define PORT_TXRX_CLK_INT GPIO_PortSourceGPIOA + +#define PIN_LED GPIO_Pin_13 +#define PORT_LED GPIOC + +#define PIN_DEB GPIO_Pin_9 +#define PORT_DEB GPIOB + +#define PIN_DSTAR_LED GPIO_Pin_12 +#define PORT_DSTAR_LED GPIOB + +#define PIN_DMR_LED GPIO_Pin_13 +#define PORT_DMR_LED GPIOB + +#define PIN_YSF_LED GPIO_Pin_1 +#define PORT_YSF_LED GPIOB + +#define PIN_P25_LED GPIO_Pin_0 +#define PORT_P25_LED GPIOB + +#define PIN_PTT_LED GPIO_Pin_14 +#define PORT_PTT_LED GPIOB + +#define PIN_COS_LED GPIO_Pin_15 +#define PORT_COS_LED GPIOB + +extern "C" { + void EXTI15_10_IRQHandler(void) { + if(EXTI_GetITStatus(EXTI_Line15)!=RESET) { + io.interrupt(); + EXTI_ClearITPendingBit(EXTI_Line15); + } + } +} + +void CIO::delay_rx() { + volatile unsigned int delay; + for(delay = 0;delay<512;delay++); +} + +void CIO::Init() +{ + // USB Conf IO: + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); + GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); + + RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5); + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE); + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); + + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_StructInit(&GPIO_InitStruct); + + // Pin PA12 = LOW, USB Reset in generic boards + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(GPIOA, &GPIO_InitStruct); + GPIO_WriteBit(GPIOA, GPIO_Pin_12, Bit_RESET); + + volatile unsigned int delay; + for(delay = 0;delay<512;delay++); + + GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_Init(GPIOA, &GPIO_InitStruct); + + // Pin SCLK + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_SCLK; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_SCLK, &GPIO_InitStruct); + + // Pin SDATA + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_SDATA; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_SDATA, &GPIO_InitStruct); + + // Pin SLE + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_SLE; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_SLE, &GPIO_InitStruct); + + // Pin RXD + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_RXD; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_Init(PORT_RXD, &GPIO_InitStruct); + + // Pin TXD + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_TXD; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_TXD, &GPIO_InitStruct); + + // Pin TXRX_CLK + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_TXRX_CLK; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_Init(PORT_TXRX_CLK, &GPIO_InitStruct); + + // Pin LED + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_LED; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_LED, &GPIO_InitStruct); + + // Pin Debug + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_DEB; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_DEB, &GPIO_InitStruct); + + // D-Star LED + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_DSTAR_LED; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_DSTAR_LED, &GPIO_InitStruct); + + // DMR LED + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_DMR_LED; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_DMR_LED, &GPIO_InitStruct); + + // YSF LED + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_YSF_LED; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_YSF_LED, &GPIO_InitStruct); + + // P25 LED + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_P25_LED; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_P25_LED, &GPIO_InitStruct); + + // PTT LED + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_PTT_LED; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_PTT_LED, &GPIO_InitStruct); + + // COS LED + GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStruct.GPIO_Pin = PIN_COS_LED; + GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(PORT_COS_LED, &GPIO_InitStruct); +} + +void CIO::ifInit() +{ + EXTI_InitTypeDef EXTI_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + m_started = true; + + // Connect EXTI15 Line + GPIO_EXTILineConfig(PORT_TXRX_CLK_INT, PIN_TXRX_CLK_INT); + + // Configure EXTI15 line + EXTI_InitStructure.EXTI_Line = EXTI_Line15; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); + + // Enable and set EXTI15 Interrupt + NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + ifConf(); + delay_rx();; + setRX(); +} + +void CIO::SCLK_pin(bool on) +{ + GPIO_WriteBit(PORT_SCLK, PIN_SCLK, on ? Bit_SET : Bit_RESET); +} + +void CIO::SDATA_pin(bool on) +{ + GPIO_WriteBit(PORT_SDATA, PIN_SDATA, on ? Bit_SET : Bit_RESET); +} + +void CIO::SLE_pin(bool on) +{ + GPIO_WriteBit(PORT_SLE, PIN_SLE, on ? Bit_SET : Bit_RESET); +} + +bool CIO::RXD_pin() +{ + return GPIO_ReadInputDataBit(PORT_RXD, PIN_RXD) == Bit_SET; +} + +void CIO::TXD_pin(bool on) +{ + GPIO_WriteBit(PORT_TXD, PIN_TXD, on ? Bit_SET : Bit_RESET); +} + +void CIO::LED_pin(bool on) +{ + GPIO_WriteBit(PORT_LED, PIN_LED, on ? Bit_SET : Bit_RESET); +} + +void CIO::DEB_pin(bool on) +{ + GPIO_WriteBit(PORT_DEB, PIN_DEB, on ? Bit_SET : Bit_RESET); +} + +void CIO::DSTAR_pin(bool on) +{ + GPIO_WriteBit(PORT_DSTAR_LED, PIN_DSTAR_LED, on ? Bit_SET : Bit_RESET); +} + +void CIO::DMR_pin(bool on) +{ + GPIO_WriteBit(PORT_DMR_LED, PIN_DMR_LED, on ? Bit_SET : Bit_RESET); +} + +void CIO::YSF_pin(bool on) +{ + GPIO_WriteBit(PORT_YSF_LED, PIN_YSF_LED, on ? Bit_SET : Bit_RESET); +} + +void CIO::P25_pin(bool on) +{ + GPIO_WriteBit(PORT_P25_LED, PIN_P25_LED, on ? Bit_SET : Bit_RESET); +} + +void CIO::PTT_pin(bool on) +{ + GPIO_WriteBit(PORT_PTT_LED, PIN_PTT_LED, on ? Bit_SET : Bit_RESET); +} + +void CIO::COS_pin(bool on) +{ + GPIO_WriteBit(PORT_COS_LED, PIN_COS_LED, on ? Bit_SET : Bit_RESET); +} + +#endif diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..3912109 --- /dev/null +++ b/LICENCE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/MMDVM_HS.cpp b/MMDVM_HS.cpp new file mode 100644 index 0000000..ccf2fef --- /dev/null +++ b/MMDVM_HS.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2016 by Mathis Schmieder DB9MAT + * Copyright (C) 2016 by Colin Durbridge G4EML + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" + +#if defined(STM32F10X_MD) + +#include "Globals.h" + +// Global variables +MMDVM_STATE m_modemState = STATE_IDLE; + +bool m_dstarEnable = true; +bool m_dmrEnable = true; +bool m_ysfEnable = true; +bool m_p25Enable = true; + +bool m_tx = false; +bool m_dcd = false; + +CDStarRX dstarRX; +CDStarTX dstarTX; + +CDMRDMORX dmrDMORX; +CDMRDMOTX dmrDMOTX; + +CYSFRX ysfRX; +CYSFTX ysfTX; + +CP25RX p25RX; +CP25TX p25TX; + +CSerialPort serial; +CIO io; + +void setup() +{ + serial.start(); +} + +void loop() +{ + io.process(); + + serial.process(); + + // The following is for transmitting + if (m_dstarEnable && m_modemState == STATE_DSTAR) + dstarTX.process(); + + if (m_dmrEnable && m_modemState == STATE_DMR) + dmrDMOTX.process(); + + if (m_ysfEnable && m_modemState == STATE_YSF) + ysfTX.process(); + + if (m_p25Enable && m_modemState == STATE_P25) + p25TX.process(); + +} + +int main() +{ + setup(); + + for (;;) + loop(); +} + +#endif diff --git a/MMDVM_HS.ino b/MMDVM_HS.ino new file mode 100644 index 0000000..74214ff --- /dev/null +++ b/MMDVM_HS.ino @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2016 by Colin Durbridge G4EML + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" +#include "Globals.h" + +// Global variables +MMDVM_STATE m_modemState = STATE_IDLE; + +bool m_dstarEnable = true; +bool m_dmrEnable = true; +bool m_ysfEnable = true; +bool m_p25Enable = true; + +bool m_tx = false; +bool m_dcd = false; + +CDStarRX dstarRX; +CDStarTX dstarTX; + +CDMRDMORX dmrDMORX; +CDMRDMOTX dmrDMOTX; + +CYSFRX ysfRX; +CYSFTX ysfTX; + +CP25RX p25RX; +CP25TX p25TX; + +CSerialPort serial; +CIO io; + +void setup() +{ + serial.start(); +} + +void loop() +{ + serial.process(); + io.process(); + + // The following is for transmitting + if (m_dstarEnable && m_modemState == STATE_DSTAR) + dstarTX.process(); + + if (m_dmrEnable && m_modemState == STATE_DMR) + dmrDMOTX.process(); + + if (m_ysfEnable && m_modemState == STATE_YSF) + ysfTX.process(); + + if (m_p25Enable && m_modemState == STATE_P25) + p25TX.process(); + +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0578674 --- /dev/null +++ b/Makefile @@ -0,0 +1,157 @@ +# Copyright (C) 2016 by Andy Uribe CA6JAU +# Copyright (C) 2016 by Jim McLaughlin KI6ZUM + +# 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. + +# GNU ARM Embedded Toolchain +CC=arm-none-eabi-gcc +CXX=arm-none-eabi-g++ +LD=arm-none-eabi-ld +AR=arm-none-eabi-ar +AS=arm-none-eabi-as +CP=arm-none-eabi-objcopy +OD=arm-none-eabi-objdump +NM=arm-none-eabi-nm +SIZE=arm-none-eabi-size +A2L=arm-none-eabi-addr2line + +# Directory Structure +BINDIR=bin + +# Find source files +# "SystemRoot" is only defined in Windows +ifdef SYSTEMROOT + ASOURCES=$(shell dir /S /B *.s) + CSOURCES=$(shell dir /S /B *.c) + CXXSOURCES=$(shell dir /S /B *.cpp) + CLEANCMD=del /S *.o *.hex *.bin *.elf + MDBIN=md $@ +else ifdef SystemRoot + ASOURCES=$(shell dir /S /B *.s) + CSOURCES=$(shell dir /S /B *.c) + CXXSOURCES=$(shell dir /S /B *.cpp) + CLEANCMD=del /S *.o *.hex *.bin *.elf + MDBIN=md $@ +else + ASOURCES=$(shell find . -name '*.s') + CSOURCES=$(shell find . -name '*.c') + CXXSOURCES=$(shell find . -name '*.cpp') + CLEANCMD=rm -f $(OBJECTS) $(BINDIR)/$(BINELF) $(BINDIR)/$(BINHEX) $(BINDIR)/$(BINBIN) + MDBIN=mkdir $@ +endif + +# Default reference oscillator frequencies +ifndef $(OSC) + OSC=8000000 +endif + +# Find header directories +INC= . STM32F10X_Lib/CMSIS/ STM32F10X_Lib/Device/ STM32F10X_Lib/STM32F10x_StdPeriph_Driver/inc/ STM32F10X_Lib/usb/inc/ +INCLUDES=$(INC:%=-I%) + +# Find libraries +INCLUDES_LIBS= +LINK_LIBS= + +# Create object list +OBJECTS=$(ASOURCES:%.s=%.o) +OBJECTS+=$(CSOURCES:%.c=%.o) +OBJECTS+=$(CXXSOURCES:%.cpp=%.o) + +# Define output files ELF & IHEX +BINELF=outp.elf +BINHEX=outp.hex +BINBIN=outp.bin + +# MCU FLAGS +MCFLAGS=-mcpu=cortex-m3 -mthumb -Wall + +# COMPILE FLAGS +DEFS_HS=-DUSE_STDPERIPH_DRIVER -DSTM32F10X_MD -DHSE_VALUE=$(OSC) + +CFLAGS=-c $(MCFLAGS) $(INCLUDES) +CXXFLAGS=-c $(MCFLAGS) $(INCLUDES) + +# LINKER FLAGS +LDSCRIPT=stm32f10x_link.ld +LDFLAGS =-T $(LDSCRIPT) $(MCFLAGS) --specs=nosys.specs $(INCLUDES_LIBS) $(LINK_LIBS) + +# Build Rules +.PHONY: all release hs debug clean + +all: hs + +hs: CFLAGS+=$(DEFS_HS) -Os -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS +hs: CXXFLAGS+=$(DEFS_HS) -Os -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -DCUSTOM_NEW -DNO_EXCEPTIONS +hs: LDFLAGS+=-Os --specs=nano.specs +hs: release + +debug: CFLAGS+=-g +debug: CXXFLAGS+=-g +debug: LDFLAGS+=-g +debug: release + +release: $(BINDIR) +release: $(BINDIR)/$(BINHEX) +release: $(BINDIR)/$(BINBIN) + +$(BINDIR): + $(MDBIN) + +$(BINDIR)/$(BINHEX): $(BINDIR)/$(BINELF) + $(CP) -O ihex $< $@ + @echo "Objcopy from ELF to IHEX complete!\n" + +$(BINDIR)/$(BINBIN): $(BINDIR)/$(BINELF) + $(CP) -O binary $< $@ + @echo "Objcopy from ELF to BINARY complete!\n" + +$(BINDIR)/$(BINELF): $(OBJECTS) + $(CXX) $(OBJECTS) $(LDFLAGS) -o $@ + @echo "Linking complete!\n" + $(SIZE) $(BINDIR)/$(BINELF) + +%.o: %.cpp + $(CXX) $(CXXFLAGS) $< -o $@ + @echo "Compiled "$<"!\n" + +%.o: %.c + $(CC) $(CFLAGS) $< -o $@ + @echo "Compiled "$<"!\n" + +%.o: %.s + $(CC) $(CFLAGS) $< -o $@ + @echo "Assambled "$<"!\n" + +clean: + $(CLEANCMD) + +stlink: +ifneq ($(wildcard /usr/bin/openocd),) + /usr/bin/openocd -f /usr/share/openocd/scripts/interface/stlink-v2-1.cfg -f /usr/share/openocd/scripts/target/stm32f1x.cfg -c "program bin/$(BINELF) verify reset exit" +endif + +ifneq ($(wildcard /usr/local/bin/openocd),) + /usr/local/bin/openocd -f /usr/local/share/openocd/scripts/interface/stlink-v2-1.cfg -f /usr/local/share/openocd/scripts/target/stm32f1x.cfg -c "program bin/$(BINELF) verify reset exit" +endif + +ifneq ($(wildcard /opt/openocd/bin/openocd),) + /opt/openocd/bin/openocd -f /opt/openocd/scripts/interface/stlink-v2-1.cfg -f /opt/openocd/share/openocd/scripts/target/stm32f1x.cfg -c "program bin/$(BINELF) verify reset exit" +endif + +serial: +ifneq ($(wildcard /usr/local/bin/stm32flash),) + /usr/local/bin/stm32flash -w bin/$(BINBIN) -g 0x0 $(devser) +endif diff --git a/P25Defines.h b/P25Defines.h new file mode 100644 index 0000000..408ff5f --- /dev/null +++ b/P25Defines.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 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(P25DEFINES_H) +#define P25DEFINES_H + +const unsigned int P25_HDR_FRAME_LENGTH_BYTES = 99U; +const unsigned int P25_HDR_FRAME_LENGTH_BITS = P25_HDR_FRAME_LENGTH_BYTES * 8U; +const unsigned int P25_HDR_FRAME_LENGTH_SYMBOLS = P25_HDR_FRAME_LENGTH_BYTES * 4U; + +const unsigned int P25_LDU_FRAME_LENGTH_BYTES = 216U; +const unsigned int P25_LDU_FRAME_LENGTH_BITS = P25_LDU_FRAME_LENGTH_BYTES * 8U; +const unsigned int P25_LDU_FRAME_LENGTH_SYMBOLS = P25_LDU_FRAME_LENGTH_BYTES * 4U; + +const unsigned int P25_TERMLC_FRAME_LENGTH_BYTES = 54U; +const unsigned int P25_TERMLC_FRAME_LENGTH_BITS = P25_TERMLC_FRAME_LENGTH_BYTES * 8U; +const unsigned int P25_TERMLC_FRAME_LENGTH_SYMBOLS = P25_TERMLC_FRAME_LENGTH_BYTES * 4U; + +const unsigned int P25_TERM_FRAME_LENGTH_BYTES = 18U; +const unsigned int P25_TERM_FRAME_LENGTH_BITS = P25_TERM_FRAME_LENGTH_BYTES * 8U; +const unsigned int P25_TERM_FRAME_LENGTH_SYMBOLS = P25_TERM_FRAME_LENGTH_BYTES * 4U; + +const unsigned int P25_SYNC_LENGTH_BYTES = 6U; +const unsigned int P25_SYNC_LENGTH_BITS = P25_SYNC_LENGTH_BYTES * 8U; +const unsigned int P25_SYNC_LENGTH_SYMBOLS = P25_SYNC_LENGTH_BYTES * 4U; + +const unsigned int P25_NID_LENGTH_BITS = 64U; +const unsigned int P25_NID_LENGTH_SYMBOLS = 32U; + +const uint8_t P25_SYNC_BYTES[] = {0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU}; +const uint8_t P25_SYNC_BYTES_LENGTH = 6U; + +const uint64_t P25_SYNC_BITS = 0x00005575F5FF77FFU; +const uint64_t P25_SYNC_BITS_MASK = 0x0000FFFFFFFFFFFFU; + +// 5 5 7 5 F 5 F F 7 7 F F +// 01 01 01 01 01 11 01 01 11 11 01 01 11 11 11 11 01 11 01 11 11 11 11 11 +// +3 +3 +3 +3 +3 -3 +3 +3 -3 -3 +3 +3 -3 -3 -3 -3 +3 -3 +3 -3 -3 -3 -3 -3 + +const uint32_t P25_SYNC_SYMBOLS = 0x00FB30A0U; +const uint32_t P25_SYNC_SYMBOLS_MASK = 0x00FFFFFFU; + +#endif diff --git a/P25RX.cpp b/P25RX.cpp new file mode 100644 index 0000000..0739b61 --- /dev/null +++ b/P25RX.cpp @@ -0,0 +1,143 @@ +/* + * 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 + * 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. + */ + +// #define WANT_DEBUG + +#include "Config.h" +#include "Globals.h" +#include "P25RX.h" +#include "Utils.h" + +const uint8_t SYNC_BIT_START_ERRS = 2U; +const uint8_t SYNC_BIT_RUN_ERRS = 4U; + +const unsigned int MAX_SYNC_FRAMES = 3U + 1U; + +const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; + +#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) + +CP25RX::CP25RX() : +m_prev(false), +m_state(P25RXS_NONE), +m_bitBuffer(0x00U), +m_outBuffer(), +m_buffer(NULL), +m_bufferPtr(0U), +m_lostCount(0U) +{ + m_buffer = m_outBuffer + 1U; +} + +void CP25RX::reset() +{ + m_prev = false; + m_state = P25RXS_NONE; + m_bitBuffer = 0x00U; + m_bufferPtr = 0U; + m_lostCount = 0U; +} + +void CP25RX::databit(bool bit) +{ + if (m_state == P25RXS_NONE) + processNone(bit); + else + processData(bit); +} + +void CP25RX::processNone(bool bit) +{ + m_bitBuffer <<= 1; + if (bit) + m_bitBuffer |= 0x01U; + + // Fuzzy matching of the data sync bit sequence + if (countBits64((m_bitBuffer & P25_SYNC_BITS_MASK) ^ P25_SYNC_BITS) <= SYNC_BIT_START_ERRS) { + DEBUG1("P25RX: sync found in None"); + for (uint8_t i = 0U; i < P25_SYNC_LENGTH_BYTES; i++) + m_buffer[i] = P25_SYNC_BYTES[i]; + + m_lostCount = MAX_SYNC_FRAMES; + m_bufferPtr = P25_SYNC_LENGTH_BITS; + m_state = P25RXS_DATA; + + io.setDecode(true); + } +} + +void CP25RX::processData(bool bit) +{ + m_bitBuffer <<= 1; + if (bit) + m_bitBuffer |= 0x01U; + + WRITE_BIT1(m_buffer, m_bufferPtr, bit); + m_bufferPtr++; + + // Search for an early sync to indicate an LDU following a header + if (m_bufferPtr >= (P25_HDR_FRAME_LENGTH_BITS + P25_SYNC_LENGTH_BITS - 1U) && m_bufferPtr <= (P25_HDR_FRAME_LENGTH_BITS + P25_SYNC_LENGTH_BITS + 1U)) { + // Fuzzy matching of the data sync bit sequence + if (countBits64((m_bitBuffer & P25_SYNC_BITS_MASK) ^ P25_SYNC_BITS) <= SYNC_BIT_RUN_ERRS) { + DEBUG2("P25RX: found LDU sync in Data, pos", m_bufferPtr - P25_SYNC_LENGTH_BITS); + + m_outBuffer[0U] = 0x01U; + serial.writeP25Hdr(m_outBuffer, P25_HDR_FRAME_LENGTH_BYTES + 1U); + + // Restore the sync that's now in the wrong place + for (uint8_t i = 0U; i < P25_SYNC_LENGTH_BYTES; i++) + m_buffer[i] = P25_SYNC_BYTES[i]; + + m_lostCount = MAX_SYNC_FRAMES; + m_bufferPtr = P25_SYNC_LENGTH_BITS; + } + } + + // Only search for a sync in the right place +-2 symbols + if (m_bufferPtr >= (P25_SYNC_LENGTH_BITS - 2U) && m_bufferPtr <= (P25_SYNC_LENGTH_BITS + 2U)) { + // Fuzzy matching of the data sync bit sequence + if (countBits64((m_bitBuffer & P25_SYNC_BITS_MASK) ^ P25_SYNC_BITS) <= SYNC_BIT_RUN_ERRS) { + DEBUG2("P25RX: found sync in Data, pos", m_bufferPtr - P25_SYNC_LENGTH_BITS); + m_lostCount = MAX_SYNC_FRAMES; + m_bufferPtr = P25_SYNC_LENGTH_BITS; + } + } + + // Send a data frame to the host if the required number of bits have been received + if (m_bufferPtr == P25_LDU_FRAME_LENGTH_BITS) { + // We've not seen a data sync for too long, signal RXLOST and change to RX_NONE + m_lostCount--; + if (m_lostCount == 0U) { + DEBUG1("P25RX: sync timed out, lost lock"); + io.setDecode(false); + + serial.writeP25Lost(); + + m_state = P25RXS_NONE; + } else { + m_outBuffer[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U; + + serial.writeP25Ldu(m_outBuffer, P25_LDU_FRAME_LENGTH_BYTES + 1U); + + // Start the next frame + ::memset(m_outBuffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 3U); + m_bufferPtr = 0U; + } + } +} + diff --git a/P25RX.h b/P25RX.h new file mode 100644 index 0000000..514ad95 --- /dev/null +++ b/P25RX.h @@ -0,0 +1,52 @@ +/* + * 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 + * 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(P25RX_H) +#define P25RX_H + +#include "P25Defines.h" + +enum P25RX_STATE { + P25RXS_NONE, + P25RXS_DATA +}; + +class CP25RX { +public: + CP25RX(); + + void databit(bool bit); + + void reset(); + +private: + bool m_prev; + P25RX_STATE m_state; + uint64_t m_bitBuffer; + uint8_t m_outBuffer[P25_LDU_FRAME_LENGTH_BYTES + 3U]; + uint8_t* m_buffer; + uint16_t m_bufferPtr; + uint16_t m_lostCount; + + void processNone(bool bit); + void processData(bool bit); + +}; + +#endif + diff --git a/P25TX.cpp b/P25TX.cpp new file mode 100644 index 0000000..781c207 --- /dev/null +++ b/P25TX.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2016 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. + */ + +// #define WANT_DEBUG + +#include "Config.h" +#include "Globals.h" +#include "P25TX.h" + +#include "P25Defines.h" + +const uint8_t P25_START_SYNC = 0x77U; + +CP25TX::CP25TX() : +m_buffer(1500U), +m_poBuffer(), +m_poLen(0U), +m_poPtr(0U), +m_txDelay(240U), // 200ms +m_count(0U) +{ +} + +void CP25TX::process() +{ + if (m_buffer.getData() == 0U && m_poLen == 0U) + return; + + if (m_poLen == 0U) { + if (!m_tx) { + m_delay = true; + m_count = 0U; + m_poLen = m_txDelay; + } else { + uint8_t length = m_buffer.get(); + m_delay = false; + for (uint8_t i = 0U; i < length; i++) { + m_poBuffer[m_poLen++] = m_buffer.get(); + } + } + + m_poPtr = 0U; + } + + if (m_poLen > 0U) { + uint16_t space = io.getSpace(); + + while (space > 8U) { + if (m_delay) { + m_poPtr++; + writeByte(P25_START_SYNC); + } else + writeByte(m_poBuffer[m_poPtr++]); + + space -= 8U; + + if (m_poPtr >= m_poLen) { + m_poPtr = 0U; + m_poLen = 0U; + m_delay = false; + return; + } + } + } +} + +uint8_t CP25TX::writeData(const uint8_t* data, uint8_t length) +{ + if (length < (P25_TERM_FRAME_LENGTH_BYTES + 1U)) + return 4U; + + uint16_t space = m_buffer.getSpace(); + if (space < length) + return 5U; + + m_buffer.put(length - 1U); + + for (uint8_t i = 0U; i < (length - 1U); i++) + m_buffer.put(data[i + 1U]); + + return 0U; +} + +void CP25TX::writeByte(uint8_t c) +{ + uint8_t bit; + uint8_t mask = 0x80U; + + for (uint8_t i = 0U; i < 8U; i++, c <<= 1) { + if ((c & mask) == mask) + bit = 1U; + else + bit = 0U; + + io.write(&bit, 1); + } +} + +void CP25TX::setTXDelay(uint8_t delay) +{ + m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay +} + +uint16_t CP25TX::getSpace() const +{ + return m_buffer.getSpace() / P25_LDU_FRAME_LENGTH_BYTES; +} diff --git a/P25TX.h b/P25TX.h new file mode 100644 index 0000000..1f239ce --- /dev/null +++ b/P25TX.h @@ -0,0 +1,49 @@ +/* + * 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 + * 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(P25TX_H) +#define P25TX_H + +#include "SerialRB.h" + +class CP25TX { +public: + CP25TX(); + + uint8_t writeData(const uint8_t* data, uint8_t length); + + void process(); + + void setTXDelay(uint8_t delay); + + uint16_t getSpace() const; + +private: + CSerialRB m_buffer; + uint8_t m_poBuffer[250U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; + uint32_t m_count; + bool m_delay; + + void writeByte(uint8_t c); +}; + +#endif + diff --git a/SerialArduino.cpp b/SerialArduino.cpp new file mode 100755 index 0000000..f3334f2 --- /dev/null +++ b/SerialArduino.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 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 "SerialPort.h" + +#if defined(ARDUINO) + +void CSerialPort::beginInt(uint8_t n, int speed) +{ + switch (n) { + case 1U: + Serial.begin(speed); + break; +/* case 2U: + Serial2.begin(speed); + break; + case 3U: + Serial3.begin(speed); + break;*/ + default: + break; + } +} + +int CSerialPort::availableInt(uint8_t n) +{ + switch (n) { + case 1U: + return Serial.available(); +/* case 2U: + return Serial2.available(); + case 3U: + return Serial3.available();*/ + default: + return false; + } +} + +uint8_t CSerialPort::readInt(uint8_t n) +{ + switch (n) { + case 1U: + return Serial.read(); +/* case 2U: + return Serial2.read(); + case 3U: + return Serial3.read();*/ + default: + return 0U; + } +} + +void CSerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush) +{ + switch (n) { + case 1U: + Serial.write(data, length); + if (flush) + Serial.flush(); + break; +/* case 2U: + Serial2.write(data, length); + if (flush) + Serial2.flush(); + break; + case 3U: + Serial3.write(data, length); + if (flush) + Serial3.flush(); + break;*/ + default: + break; + } +} + +#endif + diff --git a/SerialPort.cpp b/SerialPort.cpp new file mode 100644 index 0000000..65b2e07 --- /dev/null +++ b/SerialPort.cpp @@ -0,0 +1,892 @@ +/* + * Copyright (C) 2013,2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2016 by Colin Durbridge G4EML + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +// #define WANT_DEBUG + +#include "Config.h" +#include "Globals.h" + +#include "SerialPort.h" + +const uint8_t MMDVM_FRAME_START = 0xE0U; + +const uint8_t MMDVM_GET_VERSION = 0x00U; +const uint8_t MMDVM_GET_STATUS = 0x01U; +const uint8_t MMDVM_SET_CONFIG = 0x02U; +const uint8_t MMDVM_SET_MODE = 0x03U; +const uint8_t MMDVM_SET_FREQ = 0x04U; + +const uint8_t MMDVM_CAL_DATA = 0x08U; + +const uint8_t MMDVM_SEND_CWID = 0x0AU; + +const uint8_t MMDVM_DSTAR_HEADER = 0x10U; +const uint8_t MMDVM_DSTAR_DATA = 0x11U; +const uint8_t MMDVM_DSTAR_LOST = 0x12U; +const uint8_t MMDVM_DSTAR_EOT = 0x13U; + +const uint8_t MMDVM_DMR_DATA1 = 0x18U; +const uint8_t MMDVM_DMR_LOST1 = 0x19U; +const uint8_t MMDVM_DMR_DATA2 = 0x1AU; +const uint8_t MMDVM_DMR_LOST2 = 0x1BU; +const uint8_t MMDVM_DMR_SHORTLC = 0x1CU; +const uint8_t MMDVM_DMR_START = 0x1DU; +const uint8_t MMDVM_DMR_ABORT = 0x1EU; + +const uint8_t MMDVM_YSF_DATA = 0x20U; +const uint8_t MMDVM_YSF_LOST = 0x21U; + +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_ACK = 0x70U; +const uint8_t MMDVM_NAK = 0x7FU; + +const uint8_t MMDVM_SERIAL = 0x80U; + +const uint8_t MMDVM_DEBUG1 = 0xF1U; +const uint8_t MMDVM_DEBUG2 = 0xF2U; +const uint8_t MMDVM_DEBUG3 = 0xF3U; +const uint8_t MMDVM_DEBUG4 = 0xF4U; +const uint8_t MMDVM_DEBUG5 = 0xF5U; + +const uint8_t HARDWARE[] = "MMDVM 20161213-HS (D-Star/DMR/YSF/P25)"; + +const uint8_t PROTOCOL_VERSION = 1U; + + +CSerialPort::CSerialPort() : +m_buffer(), +m_ptr(0U), +m_len(0U) +{ +} + +void CSerialPort::sendACK() +{ + uint8_t reply[4U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 4U; + reply[2U] = MMDVM_ACK; + reply[3U] = m_buffer[2U]; + + writeInt(1U, reply, 4); +} + +void CSerialPort::sendNAK(uint8_t err) +{ + uint8_t reply[5U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 5U; + reply[2U] = MMDVM_NAK; + reply[3U] = m_buffer[2U]; + reply[4U] = err; + + writeInt(1U, reply, 5); +} + +void CSerialPort::getStatus() +{ + //io.resetWatchdog(); + + uint8_t reply[15U]; + + // Send all sorts of interesting internal values + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 11U; + reply[2U] = MMDVM_GET_STATUS; + + reply[3U] = 0x00U; + if (m_dstarEnable) + reply[3U] |= 0x01U; + if (m_dmrEnable) + reply[3U] |= 0x02U; + if (m_ysfEnable) + reply[3U] |= 0x04U; + if (m_p25Enable) + reply[3U] |= 0x08U; + + reply[4U] = uint8_t(m_modemState); + + reply[5U] = m_tx ? 0x01U : 0x00U; + + if (io.hasRXOverflow()) + reply[5U] |= 0x04U; + + if (io.hasTXOverflow()) + reply[5U] |= 0x08U; + + if (m_dstarEnable) + reply[6U] = dstarTX.getSpace(); + else + reply[6U] = 0U; + + if (m_dmrEnable) { + reply[7U] = 10U; + reply[8U] = dmrDMOTX.getSpace(); + } else { + reply[7U] = 0U; + reply[8U] = 0U; + } + + if (m_ysfEnable) + reply[9U] = ysfTX.getSpace(); + else + reply[9U] = 0U; + + if (m_p25Enable) + reply[10U] = p25TX.getSpace(); + else + reply[10U] = 0U; + + writeInt(1U, reply, 11); +} + +void CSerialPort::getVersion() +{ + uint8_t reply[100U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_GET_VERSION; + + reply[3U] = PROTOCOL_VERSION; + + uint8_t count = 4U; + for (uint8_t i = 0U; HARDWARE[i] != 0x00U; i++, count++) + reply[count] = HARDWARE[i]; + + reply[1U] = count; + + writeInt(1U, reply, count); +} + +uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length) +{ + if (length < 13U) + return 4U; + + bool dstarEnable = (data[1U] & 0x01U) == 0x01U; + bool dmrEnable = (data[1U] & 0x02U) == 0x02U; + bool ysfEnable = (data[1U] & 0x04U) == 0x04U; + bool p25Enable = (data[1U] & 0x08U) == 0x08U; + + uint8_t txDelay = data[2U]; + if (txDelay > 50U) + return 4U; + + MMDVM_STATE modemState = MMDVM_STATE(data[3U]); + + if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25) + return 4U; + if (modemState == STATE_DSTAR && !dstarEnable) + return 4U; + if (modemState == STATE_DMR && !dmrEnable) + return 4U; + if (modemState == STATE_YSF && !ysfEnable) + return 4U; + if (modemState == STATE_P25 && !p25Enable) + return 4U; + + uint8_t colorCode = data[6U]; + if (colorCode > 15U) + return 4U; + +// uint8_t dmrDelay = data[7U]; + + m_modemState = modemState; + + m_dstarEnable = dstarEnable; + m_dmrEnable = dmrEnable; + m_ysfEnable = ysfEnable; + m_p25Enable = p25Enable; + + dstarTX.setTXDelay(txDelay); + ysfTX.setTXDelay(txDelay); + p25TX.setTXDelay(txDelay); + dmrDMOTX.setTXDelay(txDelay); + + dmrDMORX.setColorCode(colorCode); + + io.ifInit(); + + return 0U; +} + +uint8_t CSerialPort::setMode(const uint8_t* data, uint8_t length) +{ + if (length < 1U) + return 4U; + + MMDVM_STATE modemState = MMDVM_STATE(data[0U]); + + if (modemState == m_modemState) + return 0U; + +if (modemState != STATE_IDLE && modemState != STATE_DSTAR && modemState != STATE_DMR && modemState != STATE_YSF && modemState != STATE_P25) + return 4U; + if (modemState == STATE_DSTAR && !m_dstarEnable) + return 4U; + if (modemState == STATE_DMR && !m_dmrEnable) + return 4U; + if (modemState == STATE_YSF && !m_ysfEnable) + return 4U; + if (modemState == STATE_P25 && !m_p25Enable) + return 4U; + + setMode(modemState); + + return 0U; +} + +uint8_t CSerialPort::setFreq(const uint8_t* data, uint8_t length) +{ + uint32_t freq_rx, freq_tx; + + if (length < 9U) + return 4U; + + freq_rx = data[1] * 1; + freq_rx += data[2] * 256; + freq_rx += data[3] * 65536; + freq_rx += data[4] * 16777216; + + freq_tx = data[5] * 1; + freq_tx += data[6] * 256; + freq_tx += data[7] * 65536; + freq_tx += data[8] * 16777216; + + return io.setFreq(freq_rx, freq_tx); +} + +void CSerialPort::setMode(MMDVM_STATE modemState) +{ + switch (modemState) { + case STATE_DMR: + DEBUG1("Mode set to DMR"); + dstarRX.reset(); + ysfRX.reset(); + p25RX.reset(); + break; + case STATE_DSTAR: + DEBUG1("Mode set to D-Star"); + dmrDMORX.reset(); + ysfRX.reset(); + p25RX.reset(); + break; + case STATE_YSF: + DEBUG1("Mode set to System Fusion"); + dmrDMORX.reset(); + dstarRX.reset(); + p25RX.reset(); + break; + case STATE_P25: + DEBUG1("Mode set to P25"); + dmrDMORX.reset(); + dstarRX.reset(); + ysfRX.reset(); + break; + default: + DEBUG1("Mode set to Idle"); + // STATE_IDLE + break; + } + + m_modemState = modemState; + + io.setMode(); +} + +void CSerialPort::start() +{ + beginInt(1U, 115200); + +#if defined(SERIAL_REPEATER) + beginInt(3U, 9600); +#endif +} + +void CSerialPort::process() +{ + while (availableInt(1U)) { + uint8_t c = readInt(1U); + + if (m_ptr == 0U) { + if (c == MMDVM_FRAME_START) { + // Handle the frame start correctly + m_buffer[0U] = c; + m_ptr = 1U; + m_len = 0U; + } + } else if (m_ptr == 1U) { + // Handle the frame length + m_len = m_buffer[m_ptr] = c; + m_ptr = 2U; + } else { + // Any other bytes are added to the buffer + m_buffer[m_ptr] = c; + m_ptr++; + + // The full packet has been received, process it + if (m_ptr == m_len) { + uint8_t err = 2U; + + switch (m_buffer[2U]) { + case MMDVM_GET_STATUS: + getStatus(); + break; + + case MMDVM_GET_VERSION: + getVersion(); + break; + + case MMDVM_SET_CONFIG: + err = setConfig(m_buffer + 3U, m_len - 3U); + if (err == 0U) + sendACK(); + else + sendNAK(err); + break; + + case MMDVM_SET_MODE: + err = setMode(m_buffer + 3U, m_len - 3U); + if (err == 0U) + sendACK(); + else + sendNAK(err); + break; + + case MMDVM_SET_FREQ: + err = setFreq(m_buffer + 3U, m_len - 3U); + if (err == 0U) + sendACK(); + else + sendNAK(err); + break; + + case MMDVM_CAL_DATA: + break; + + case MMDVM_SEND_CWID: + break; + + case MMDVM_DSTAR_HEADER: + if (m_dstarEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) + err = dstarTX.writeHeader(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_DSTAR); + } else { + DEBUG2("Received invalid D-Star header", err); + sendNAK(err); + } + break; + + case MMDVM_DSTAR_DATA: + if (m_dstarEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) + err = dstarTX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_DSTAR); + } else { + DEBUG2("Received invalid D-Star data", err); + sendNAK(err); + } + break; + + case MMDVM_DSTAR_EOT: + if (m_dstarEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR) + err = dstarTX.writeEOT(); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_DSTAR); + } else { + DEBUG2("Received invalid D-Star EOT", err); + sendNAK(err); + } + break; + + case MMDVM_DMR_DATA1: + break; + + case MMDVM_DMR_DATA2: + if (m_dmrEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_DMR) { + err = dmrDMOTX.writeData(m_buffer + 3U, m_len - 3U); + } + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_DMR); + } else { + DEBUG2("Received invalid DMR data", err); + sendNAK(err); + } + break; + + case MMDVM_DMR_START: + break; + + case MMDVM_DMR_SHORTLC: + break; + + case MMDVM_DMR_ABORT: + break; + + case MMDVM_YSF_DATA: + if (m_ysfEnable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_YSF) + err = ysfTX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_YSF); + } else { + DEBUG2("Received invalid System Fusion data", err); + sendNAK(err); + } + break; + + case MMDVM_P25_HDR: + if (m_p25Enable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_P25) + err = p25TX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_P25); + } else { + DEBUG2("Received invalid P25 header", err); + sendNAK(err); + } + break; + + case MMDVM_P25_LDU: + if (m_p25Enable) { + if (m_modemState == STATE_IDLE || m_modemState == STATE_P25) + err = p25TX.writeData(m_buffer + 3U, m_len - 3U); + } + if (err == 0U) { + if (m_modemState == STATE_IDLE) + setMode(STATE_P25); + } else { + DEBUG2("Received invalid P25 LDU", err); + sendNAK(err); + } + break; + +#if defined(SERIAL_REPEATER) + case MMDVM_SERIAL: + writeInt(3U, m_buffer + 3U, m_len - 3U); + break; +#endif + + default: + // Handle this, send a NAK back + sendNAK(1U); + break; + } + + m_ptr = 0U; + m_len = 0U; + } + } + } + +#if defined(SERIAL_REPEATER) + // Drain any incoming serial data + while (availableInt(3U)) + readInt(3U); +#endif +} + +void CSerialPort::writeDStarHeader(const uint8_t* header, uint8_t length) +{ + if (m_modemState != STATE_DSTAR && m_modemState != STATE_IDLE) + return; + + if (!m_dstarEnable) + return; + + uint8_t reply[50U]; + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_DSTAR_HEADER; + + uint8_t count = 3U; + for (uint8_t i = 0U; i < length; i++, count++) + reply[count] = header[i]; + + reply[1U] = count; + + writeInt(1U, reply, count); +} + +void CSerialPort::writeDStarData(const uint8_t* data, uint8_t length) +{ + if (m_modemState != STATE_DSTAR && m_modemState != STATE_IDLE) + return; + + if (!m_dstarEnable) + return; + + uint8_t reply[20U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_DSTAR_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::writeDStarLost() +{ + if (m_modemState != STATE_DSTAR && m_modemState != STATE_IDLE) + return; + + if (!m_dstarEnable) + return; + + uint8_t reply[3U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 3U; + reply[2U] = MMDVM_DSTAR_LOST; + + writeInt(1U, reply, 3); +} + +void CSerialPort::writeDStarEOT() +{ + if (m_modemState != STATE_DSTAR && m_modemState != STATE_IDLE) + return; + + if (!m_dstarEnable) + return; + + uint8_t reply[3U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 3U; + reply[2U] = MMDVM_DSTAR_EOT; + + writeInt(1U, reply, 3); +} + +void CSerialPort::writeDMRData(bool slot, const uint8_t* data, uint8_t length) +{ + if (m_modemState != STATE_DMR && m_modemState != STATE_IDLE) + return; + + if (!m_dmrEnable) + return; + + uint8_t reply[40U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = slot ? MMDVM_DMR_DATA2 : MMDVM_DMR_DATA1; + + 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::writeDMRLost(bool slot) +{ + if (m_modemState != STATE_DMR && m_modemState != STATE_IDLE) + return; + + if (!m_dmrEnable) + return; + + uint8_t reply[3U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 3U; + reply[2U] = slot ? MMDVM_DMR_LOST2 : MMDVM_DMR_LOST1; + + writeInt(1U, reply, 3); +} + +void CSerialPort::writeYSFData(const uint8_t* data, uint8_t length) +{ + if (m_modemState != STATE_YSF && m_modemState != STATE_IDLE) + return; + + if (!m_ysfEnable) + return; + + uint8_t reply[130U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_YSF_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::writeYSFLost() +{ + if (m_modemState != STATE_YSF && m_modemState != STATE_IDLE) + return; + + if (!m_ysfEnable) + return; + + uint8_t reply[3U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 3U; + reply[2U] = MMDVM_YSF_LOST; + + writeInt(1U, reply, 3); +} + +void CSerialPort::writeP25Hdr(const uint8_t* data, uint8_t length) +{ + if (m_modemState != STATE_P25 && m_modemState != STATE_IDLE) + return; + + if (!m_p25Enable) + return; + + uint8_t reply[120U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_P25_HDR; + + 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::writeP25Ldu(const uint8_t* data, uint8_t length) +{ + if (m_modemState != STATE_P25 && m_modemState != STATE_IDLE) + return; + + if (!m_p25Enable) + return; + + uint8_t reply[250U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_P25_LDU; + + 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::writeP25Lost() +{ + if (m_modemState != STATE_P25 && m_modemState != STATE_IDLE) + return; + + if (!m_p25Enable) + return; + + uint8_t reply[3U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 3U; + reply[2U] = MMDVM_P25_LOST; + + writeInt(1U, reply, 3); +} + +void CSerialPort::writeDebug(const char* text) +{ + uint8_t reply[130U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_DEBUG1; + + uint8_t count = 3U; + for (uint8_t i = 0U; text[i] != '\0'; i++, count++) + reply[count] = text[i]; + + reply[1U] = count; + + writeInt(1U, reply, count, true); +} + +void CSerialPort::writeDebug(const char* text, int16_t n1) +{ + uint8_t reply[130U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_DEBUG2; + + uint8_t count = 3U; + for (uint8_t i = 0U; text[i] != '\0'; i++, count++) + reply[count] = text[i]; + + reply[count++] = (n1 >> 8) & 0xFF; + reply[count++] = (n1 >> 0) & 0xFF; + + reply[1U] = count; + + writeInt(1U, reply, count, true); +} + +void CSerialPort::writeDebug(const char* text, int16_t n1, int16_t n2) +{ + uint8_t reply[130U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_DEBUG3; + + uint8_t count = 3U; + for (uint8_t i = 0U; text[i] != '\0'; i++, count++) + reply[count] = text[i]; + + reply[count++] = (n1 >> 8) & 0xFF; + reply[count++] = (n1 >> 0) & 0xFF; + + reply[count++] = (n2 >> 8) & 0xFF; + reply[count++] = (n2 >> 0) & 0xFF; + + reply[1U] = count; + + writeInt(1U, reply, count, true); +} + +void CSerialPort::writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3) +{ + uint8_t reply[130U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_DEBUG4; + + uint8_t count = 3U; + for (uint8_t i = 0U; text[i] != '\0'; i++, count++) + reply[count] = text[i]; + + reply[count++] = (n1 >> 8) & 0xFF; + reply[count++] = (n1 >> 0) & 0xFF; + + reply[count++] = (n2 >> 8) & 0xFF; + reply[count++] = (n2 >> 0) & 0xFF; + + reply[count++] = (n3 >> 8) & 0xFF; + reply[count++] = (n3 >> 0) & 0xFF; + + reply[1U] = count; + + writeInt(1U, reply, count, true); +} + +void CSerialPort::writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3, int16_t n4) +{ + uint8_t reply[130U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_DEBUG5; + + uint8_t count = 3U; + for (uint8_t i = 0U; text[i] != '\0'; i++, count++) + reply[count] = text[i]; + + reply[count++] = (n1 >> 8) & 0xFF; + reply[count++] = (n1 >> 0) & 0xFF; + + reply[count++] = (n2 >> 8) & 0xFF; + reply[count++] = (n2 >> 0) & 0xFF; + + reply[count++] = (n3 >> 8) & 0xFF; + reply[count++] = (n3 >> 0) & 0xFF; + + reply[count++] = (n4 >> 8) & 0xFF; + reply[count++] = (n4 >> 0) & 0xFF; + + reply[1U] = count; + + writeInt(1U, reply, count, true); +} + +void CSerialPort::writeAssert(bool cond, const char* text, const char* file, long line) +{ + if (cond) + return; + + uint8_t reply[200U]; + + reply[0U] = MMDVM_FRAME_START; + reply[1U] = 0U; + reply[2U] = MMDVM_DEBUG2; + + uint8_t count = 3U; + for (uint8_t i = 0U; text[i] != '\0'; i++, count++) + reply[count] = text[i]; + + reply[count++] = ' '; + + for (uint8_t i = 0U; file[i] != '\0'; i++, count++) + reply[count] = file[i]; + + reply[count++] = (line >> 8) & 0xFF; + reply[count++] = (line >> 0) & 0xFF; + + reply[1U] = count; + + writeInt(1U, reply, count, true); +} + diff --git a/SerialPort.h b/SerialPort.h new file mode 100644 index 0000000..233c44c --- /dev/null +++ b/SerialPort.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015,2016 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(SERIALPORT_H) +#define SERIALPORT_H + +#include "Globals.h" + +class CSerialPort { +public: + CSerialPort(); + + void start(); + + void process(); + + void writeDStarHeader(const uint8_t* header, uint8_t length); + void writeDStarData(const uint8_t* data, uint8_t length); + void writeDStarLost(); + void writeDStarEOT(); + + void writeDMRData(bool slot, const uint8_t* data, uint8_t length); + void writeDMRLost(bool slot); + + void writeYSFData(const uint8_t* data, uint8_t length); + void writeYSFLost(); + + void writeP25Hdr(const uint8_t* data, uint8_t length); + void writeP25Ldu(const uint8_t* data, uint8_t length); + void writeP25Lost(); + + void writeDebug(const char* text); + void writeDebug(const char* text, int16_t n1); + void writeDebug(const char* text, int16_t n1, int16_t n2); + void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3); + void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3, int16_t n4); + + void writeAssert(bool cond, const char* text, const char* file, long line); + +private: + uint8_t m_buffer[256U]; + uint8_t m_ptr; + uint8_t m_len; + + void sendACK(); + void sendNAK(uint8_t err); + void getStatus(); + void getVersion(); + uint8_t setConfig(const uint8_t* data, uint8_t length); + uint8_t setMode(const uint8_t* data, uint8_t length); + void setMode(MMDVM_STATE modemState); + uint8_t setFreq(const uint8_t* data, uint8_t length); + + // Hardware versions + void beginInt(uint8_t n, int speed); + int availableInt(uint8_t n); + uint8_t readInt(uint8_t n); + void writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush = false); +}; + +#endif + diff --git a/SerialRB.cpp b/SerialRB.cpp new file mode 100644 index 0000000..5f917d5 --- /dev/null +++ b/SerialRB.cpp @@ -0,0 +1,101 @@ +/* +Serial RB control - Copyright (C) KI6ZUM 2015 +Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. +*/ + +#include "SerialRB.h" + +CSerialRB::CSerialRB(uint16_t length) : +m_length(length), +m_buffer(NULL), +m_head(0U), +m_tail(0U), +m_full(false) +{ + m_buffer = new uint8_t[length]; +} + +void CSerialRB::reset() +{ + m_head = 0U; + m_tail = 0U; + m_full = false; +} + +uint16_t CSerialRB::getSpace() const +{ + uint16_t n = 0U; + + if (m_tail == m_head) + n = m_full ? 0U : m_length; + else if (m_tail < m_head) + n = m_length - m_head + m_tail; + else + n = m_tail - m_head; + + if (n > m_length) + n = 0U; + + return n; +} + +uint16_t CSerialRB::getData() const +{ + if (m_tail == m_head) + return m_full ? m_length : 0U; + else if (m_tail < m_head) + return m_head - m_tail; + else + return m_length - m_tail + m_head; +} + +bool CSerialRB::put(uint8_t c) +{ + if (m_full) + return false; + + m_buffer[m_head] = c; + + m_head++; + if (m_head >= m_length) + m_head = 0U; + + if (m_head == m_tail) + m_full = true; + + return true; +} + +uint8_t CSerialRB::peek() const +{ + return m_buffer[m_tail]; +} + +uint8_t CSerialRB::get() +{ + uint8_t value = m_buffer[m_tail]; + + m_full = false; + + m_tail++; + if (m_tail >= m_length) + m_tail = 0U; + + return value; +} + diff --git a/SerialRB.h b/SerialRB.h new file mode 100644 index 0000000..ae28935 --- /dev/null +++ b/SerialRB.h @@ -0,0 +1,58 @@ +/* +Serial fifo control - Copyright (C) KI6ZUM 2015 +Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. +*/ + +#if !defined(SERIALRB_H) +#define SERIALRB_H + +#if defined(STM32F10X_MD) +#include "stm32f10x.h" +#include +#else +#include +#endif + +const uint16_t SERIAL_RINGBUFFER_SIZE = 370U; + +class CSerialRB { +public: + CSerialRB(uint16_t length = SERIAL_RINGBUFFER_SIZE); + + uint16_t getSpace() const; + + uint16_t getData() const; + + void reset(); + + bool put(uint8_t c); + + uint8_t peek() const; + + uint8_t get(); + +private: + uint16_t m_length; + volatile uint8_t* m_buffer; + volatile uint16_t m_head; + volatile uint16_t m_tail; + volatile bool m_full; +}; + +#endif + diff --git a/SerialSTM.cpp b/SerialSTM.cpp new file mode 100644 index 0000000..2a54646 --- /dev/null +++ b/SerialSTM.cpp @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2016 by Jim McLaughlin KI6ZUM + * Copyright (C) 2016 by Andy Uribe CA6JAU + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "Config.h" + +#if defined(STM32F10X_MD) + +#include "Globals.h" +#include "SerialPort.h" + +#if defined(STM32_USB_HOST) +#include +#endif + +/* +Pin definitions: + +- Host communication: +USART1 - TXD PA9 - RXD PA10 +or +USB VCOM + +- Serial repeater +USART2 - TXD PA2 - RXD PA3 + +*/ + +#if defined(STM32_USART1_HOST) + +#define TX_SERIAL_FIFO_SIZE 256U +#define RX_SERIAL_FIFO_SIZE 256U + +extern "C" { + void USART1_IRQHandler(); +} + +/* ************* USART1 ***************** */ + +volatile uint32_t intcount1; +volatile uint8_t TXSerialfifo1[TX_SERIAL_FIFO_SIZE]; +volatile uint8_t RXSerialfifo1[RX_SERIAL_FIFO_SIZE]; +volatile uint16_t TXSerialfifohead1, TXSerialfifotail1; +volatile uint16_t RXSerialfifohead1, RXSerialfifotail1; + +// Init queues +void TXSerialfifoinit1() +{ + TXSerialfifohead1 = 0U; + TXSerialfifotail1 = 0U; +} + +void RXSerialfifoinit1() +{ + RXSerialfifohead1 = 0U; + RXSerialfifotail1 = 0U; +} + +// How full is queue +// TODO decide if how full or how empty is preferred info to return +uint16_t TXSerialfifolevel1() +{ + uint32_t tail = TXSerialfifotail1; + uint32_t head = TXSerialfifohead1; + + if (tail > head) + return TX_SERIAL_FIFO_SIZE + head - tail; + else + return head - tail; +} + +uint16_t RXSerialfifolevel1() +{ + uint32_t tail = RXSerialfifotail1; + uint32_t head = RXSerialfifohead1; + + if (tail > head) + return RX_SERIAL_FIFO_SIZE + head - tail; + else + return head - tail; +} + +// Flushes the transmit shift register +// warning: this call is blocking +void TXSerialFlush1() +{ + // wait until the TXE shows the shift register is empty + while (USART_GetITStatus(USART1, USART_FLAG_TXE)) + ; +} + +uint8_t TXSerialfifoput1(uint8_t next) +{ + if (TXSerialfifolevel1() < TX_SERIAL_FIFO_SIZE) { + TXSerialfifo1[TXSerialfifohead1] = next; + + TXSerialfifohead1++; + if (TXSerialfifohead1 >= TX_SERIAL_FIFO_SIZE) + TXSerialfifohead1 = 0U; + + // make sure transmit interrupts are enabled as long as there is data to send + USART_ITConfig(USART1, USART_IT_TXE, ENABLE); + return 1U; + } else { + return 0U; // signal an overflow occurred by returning a zero count + } +} + +void USART1_IRQHandler() +{ + uint8_t c; + + if (USART_GetITStatus(USART1, USART_IT_RXNE)) { + c = (uint8_t) USART_ReceiveData(USART1); + + if (RXSerialfifolevel1() < RX_SERIAL_FIFO_SIZE) { + RXSerialfifo1[RXSerialfifohead1] = c; + + RXSerialfifohead1++; + if (RXSerialfifohead1 >= RX_SERIAL_FIFO_SIZE) + RXSerialfifohead1 = 0U; + } else { + // TODO - do something if rx fifo is full? + } + + USART_ClearITPendingBit(USART1, USART_IT_RXNE); + intcount1++; + } + + if (USART_GetITStatus(USART1, USART_IT_TXE)) { + c = 0U; + + if (TXSerialfifohead1 != TXSerialfifotail1) { // if the fifo is not empty + c = TXSerialfifo1[TXSerialfifotail1]; + + TXSerialfifotail1++; + if (TXSerialfifotail1 >= TX_SERIAL_FIFO_SIZE) + TXSerialfifotail1 = 0U; + + USART_SendData(USART1, c); + } else { // if there's no more data to transmit then turn off TX interrupts + USART_ITConfig(USART1, USART_IT_TXE, DISABLE); + } + + USART_ClearITPendingBit(USART1, USART_IT_TXE); + } +} + +void InitUSART1(int speed) +{ + // USART1 - TXD PA9 - RXD PA10 + GPIO_InitTypeDef GPIO_InitStructure; + USART_InitTypeDef USART_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); + + // USART IRQ init + NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; + NVIC_Init(&NVIC_InitStructure); + + // Configure USART as alternate function + GPIO_StructInit(&GPIO_InitStructure); + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // Tx + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // Rx + GPIO_Init(GPIOA, &GPIO_InitStructure); + + // Configure USART baud rate + USART_StructInit(&USART_InitStructure); + USART_InitStructure.USART_BaudRate = speed; + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + USART_InitStructure.USART_StopBits = USART_StopBits_1; + USART_InitStructure.USART_Parity = USART_Parity_No; + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; + USART_Init(USART1, &USART_InitStructure); + + USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); + + USART_Cmd(USART1, ENABLE); + + // initialize the fifos + TXSerialfifoinit1(); + RXSerialfifoinit1(); +} + +uint8_t AvailUSART1(void) +{ + if (RXSerialfifolevel1() > 0U) + return 1U; + else + return 0U; +} + +uint8_t ReadUSART1(void) +{ + uint8_t data_c = RXSerialfifo1[RXSerialfifotail1]; + + RXSerialfifotail1++; + if (RXSerialfifotail1 >= RX_SERIAL_FIFO_SIZE) + RXSerialfifotail1 = 0U; + + return data_c; +} + +void WriteUSART1(const uint8_t* data, uint16_t length) +{ + for (uint16_t i = 0U; i < length; i++) + TXSerialfifoput1(data[i]); + + USART_ITConfig(USART1, USART_IT_TXE, ENABLE); +} + +#endif + +#if defined(SERIAL_REPEATER) +/* ************* USART2 ***************** */ + +volatile uint32_t intcount2; +volatile uint8_t TXSerialfifo2[TX_SERIAL_FIFO_SIZE]; +volatile uint8_t RXSerialfifo2[RX_SERIAL_FIFO_SIZE]; +volatile uint16_t TXSerialfifohead2, TXSerialfifotail2; +volatile uint16_t RXSerialfifohead2, RXSerialfifotail2; + +// Init queues +void TXSerialfifoinit2() +{ + TXSerialfifohead2 = 0U; + TXSerialfifotail2 = 0U; +} + +void RXSerialfifoinit2() +{ + RXSerialfifohead2 = 0U; + RXSerialfifotail2 = 0U; +} + +// How full is queue +// TODO decide if how full or how empty is preferred info to return +uint16_t TXSerialfifolevel2() +{ + uint32_t tail = TXSerialfifotail2; + uint32_t head = TXSerialfifohead2; + + if (tail > head) + return TX_SERIAL_FIFO_SIZE + head - tail; + else + return head - tail; +} + +uint16_t RXSerialfifolevel2() +{ + uint32_t tail = RXSerialfifotail2; + uint32_t head = RXSerialfifohead2; + + if (tail > head) + return RX_SERIAL_FIFO_SIZE + head - tail; + else + return head - tail; +} + +// Flushes the transmit shift register +// warning: this call is blocking +void TXSerialFlush2() +{ + // wait until the TXE shows the shift register is empty + while (USART_GetITStatus(USART2, USART_FLAG_TXE)) + ; +} + +uint8_t TXSerialfifoput2(uint8_t next) +{ + if (TXSerialfifolevel2() < TX_SERIAL_FIFO_SIZE) { + TXSerialfifo2[TXSerialfifohead2] = next; + + TXSerialfifohead2++; + if (TXSerialfifohead2 >= TX_SERIAL_FIFO_SIZE) + TXSerialfifohead2 = 0U; + + // make sure transmit interrupts are enabled as long as there is data to send + USART_ITConfig(USART2, USART_IT_TXE, ENABLE); + return 1U; + } else { + return 0U; // signal an overflow occurred by returning a zero count + } +} + +void USART2_IRQHandler() +{ + uint8_t c; + + if (USART_GetITStatus(USART2, USART_IT_RXNE)) { + c = (uint8_t) USART_ReceiveData(USART2); + + if (RXSerialfifolevel2() < RX_SERIAL_FIFO_SIZE) { + RXSerialfifo2[RXSerialfifohead2] = c; + + RXSerialfifohead2++; + if (RXSerialfifohead2 >= RX_SERIAL_FIFO_SIZE) + RXSerialfifohead2 = 0U; + } else { + // TODO - do something if rx fifo is full? + } + + USART_ClearITPendingBit(USART2, USART_IT_RXNE); + intcount2++; + } + + if (USART_GetITStatus(USART2, USART_IT_TXE)) { + c = 0U; + + if (TXSerialfifohead2 != TXSerialfifotail2) { // if the fifo is not empty + c = TXSerialfifo2[TXSerialfifotail2]; + + TXSerialfifotail2++; + if (TXSerialfifotail2 >= TX_SERIAL_FIFO_SIZE) + TXSerialfifotail2 = 0U; + + USART_SendData(USART2, c); + } else { // if there's no more data to transmit then turn off TX interrupts + USART_ITConfig(USART2, USART_IT_TXE, DISABLE); + } + + USART_ClearITPendingBit(USART2, USART_IT_TXE); + } +} + +void InitUSART2(int speed) +{ + + // USART2 - TXD PA2 - RXD PA3 + GPIO_InitTypeDef GPIO_InitStructure; + USART_InitTypeDef USART_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); + + // USART IRQ init + NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; + NVIC_Init(&NVIC_InitStructure); + + // Configure USART as alternate function + GPIO_StructInit(&GPIO_InitStructure); + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // Tx + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // Rx + GPIO_Init(GPIOA, &GPIO_InitStructure); + + // Configure USART baud rate + USART_StructInit(&USART_InitStructure); + USART_InitStructure.USART_BaudRate = speed; + USART_InitStructure.USART_WordLength = USART_WordLength_8b; + USART_InitStructure.USART_StopBits = USART_StopBits_1; + USART_InitStructure.USART_Parity = USART_Parity_No; + USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; + USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; + USART_Init(USART2, &USART_InitStructure); + + USART_Cmd(USART2, ENABLE); + + USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); + + // initialize the fifos + TXSerialfifoinit2(); + RXSerialfifoinit2(); +} + +uint8_t AvailUSART2(void) +{ + if (RXSerialfifolevel2() > 0U) + return 1U; + else + return 0U; +} + +uint8_t ReadUSART2(void) +{ + uint8_t data_c = RXSerialfifo2[RXSerialfifotail2]; + + RXSerialfifotail2++; + if (RXSerialfifotail2 >= RX_SERIAL_FIFO_SIZE) + RXSerialfifotail2 = 0U; + + return data_c; +} + +void WriteUSART2(const uint8_t* data, uint16_t length) +{ + for (uint16_t i = 0U; i < length; i++) + TXSerialfifoput2(data[i]); + + USART_ITConfig(USART2, USART_IT_TXE, ENABLE); +} + +#endif + +///////////////////////////////////////////////////////////////// + +void CSerialPort::beginInt(uint8_t n, int speed) +{ + switch (n) { + case 1U: + #if defined(STM32_USART1_HOST) + InitUSART1(speed); + #elif defined(STM32_USB_HOST) + usbserial.begin(); + #endif + break; + #if defined(SERIAL_REPEATER) + case 3U: + InitUSART2(speed); + break; + #endif + default: + break; + } +} + +int CSerialPort::availableInt(uint8_t n) +{ + switch (n) { + case 1U: + #if defined(STM32_USART1_HOST) + return AvailUSART1(); + #elif defined(STM32_USB_HOST) + return usbserial.available(); + #endif + #if defined(SERIAL_REPEATER) + case 3U: + return AvailUSART2(); + #endif + default: + return false; + } +} + +uint8_t CSerialPort::readInt(uint8_t n) +{ + switch (n) { + case 1U: + #if defined(STM32_USART1_HOST) + return ReadUSART1(); + #elif defined(STM32_USB_HOST) + return usbserial.read(); + #endif + #if defined(SERIAL_REPEATER) + case 3U: + return ReadUSART2(); + #endif + default: + return 0U; + } +} + +void CSerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush) +{ + switch (n) { + case 1U: + #if defined(STM32_USART1_HOST) + WriteUSART1(data, length); + if (flush) + TXSerialFlush1(); + #elif defined(STM32_USB_HOST) + usbserial.write(data, length); + if (flush) + usbserial.flush(); + break; + #endif + #if defined(SERIAL_REPEATER) + case 3U: + WriteUSART2(data, length); + if (flush) + TXSerialFlush2(); + break; + #endif + default: + break; + } +} + +#endif diff --git a/Utils.cpp b/Utils.cpp new file mode 100644 index 0000000..6a380f4 --- /dev/null +++ b/Utils.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 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 "Utils.h" + +const uint8_t BITS_TABLE[] = { +# define B2(n) n, n+1, n+1, n+2 +# define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2) +# define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2) + B6(0), B6(1), B6(1), B6(2) +}; + +uint8_t countBits8(uint8_t bits) +{ + return BITS_TABLE[bits]; +} + +uint8_t countBits32(uint32_t bits) +{ + uint8_t* p = (uint8_t*)&bits; + uint8_t n = 0U; + n += BITS_TABLE[p[0U]]; + n += BITS_TABLE[p[1U]]; + n += BITS_TABLE[p[2U]]; + n += BITS_TABLE[p[3U]]; + return n; +} + +uint8_t countBits64(uint64_t bits) +{ + uint8_t* p = (uint8_t*)&bits; + uint8_t n = 0U; + n += BITS_TABLE[p[0U]]; + n += BITS_TABLE[p[1U]]; + n += BITS_TABLE[p[2U]]; + n += BITS_TABLE[p[3U]]; + n += BITS_TABLE[p[4U]]; + n += BITS_TABLE[p[5U]]; + n += BITS_TABLE[p[6U]]; + n += BITS_TABLE[p[7U]]; + return n; +} + + diff --git a/Utils.h b/Utils.h new file mode 100644 index 0000000..e9098c9 --- /dev/null +++ b/Utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015,2016 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(UTILS_H) +#define UTILS_H + +#if defined(STM32F10X_MD) +#include "stm32f10x.h" +#include +#else +#include +#endif + +uint8_t countBits8(uint8_t bits); + +uint8_t countBits32(uint32_t bits); + +uint8_t countBits64(uint64_t bits); + +#endif + diff --git a/YSFDefines.h b/YSFDefines.h new file mode 100644 index 0000000..810ff39 --- /dev/null +++ b/YSFDefines.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009-2015 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(YSFDEFINES_H) +#define YSFDEFINES_H + +const unsigned int YSF_FRAME_LENGTH_BYTES = 120U; +const unsigned int YSF_FRAME_LENGTH_BITS = YSF_FRAME_LENGTH_BYTES * 8U; +const unsigned int YSF_FRAME_LENGTH_SYMBOLS = YSF_FRAME_LENGTH_BYTES * 4U; + +const unsigned int YSF_SYNC_LENGTH_BYTES = 5U; +const unsigned int YSF_SYNC_LENGTH_BITS = YSF_SYNC_LENGTH_BYTES * 8U; +const unsigned int YSF_SYNC_LENGTH_SYMBOLS = YSF_SYNC_LENGTH_BYTES * 4U; + +const unsigned int YSF_FICH_LENGTH_BITS = 200U; +const unsigned int YSF_FICH_LENGTH_SYMBOLS = 100U; + +const uint8_t YSF_SYNC_BYTES[] = {0xD4U, 0x71U, 0xC9U, 0x63U, 0x4DU}; +const uint8_t YSF_SYNC_BYTES_LENGTH = 5U; + +const uint64_t YSF_SYNC_BITS = 0x000000D471C9634DU; +const uint64_t YSF_SYNC_BITS_MASK = 0x000000FFFFFFFFFFU; + +// D 4 7 1 C 9 6 3 4 D +// 11 01 01 00 01 11 00 01 11 00 10 01 01 10 00 11 01 00 11 01 +// -3 +3 +3 +1 +3 -3 +1 +3 -3 +1 -1 +3 +3 -1 +3 -3 +3 +1 -3 +3 +const uint32_t YSF_SYNC_SYMBOLS = 0x0007B5ADU; +const uint32_t YSF_SYNC_SYMBOLS_MASK = 0x000FFFFFU; + +#endif + diff --git a/YSFRX.cpp b/YSFRX.cpp new file mode 100644 index 0000000..a3e9a46 --- /dev/null +++ b/YSFRX.cpp @@ -0,0 +1,127 @@ +/* + * 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 + * 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. + */ + +// #define WANT_DEBUG + +#include "Config.h" +#include "Globals.h" +#include "YSFRX.h" +#include "Utils.h" + +const uint8_t SYNC_BIT_START_ERRS = 2U; +const uint8_t SYNC_BIT_RUN_ERRS = 4U; + +const unsigned int MAX_SYNC_FRAMES = 4U + 1U; + +const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U}; + +#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) + +CYSFRX::CYSFRX() : +m_prev(false), +m_state(YSFRXS_NONE), +m_bitBuffer(0x00U), +m_outBuffer(), +m_buffer(NULL), +m_bufferPtr(0U), +m_lostCount(0U) +{ + m_buffer = m_outBuffer + 1U; +} + +void CYSFRX::reset() +{ + m_prev = false; + m_state = YSFRXS_NONE; + m_bitBuffer = 0x00U; + m_bufferPtr = 0U; + m_lostCount = 0U; +} + +void CYSFRX::databit(bool bit) +{ + if (m_state == YSFRXS_NONE) + processNone(bit); + else + processData(bit); +} + +void CYSFRX::processNone(bool bit) +{ + m_bitBuffer <<= 1; + if (bit) + m_bitBuffer |= 0x01U; + + // Fuzzy matching of the data sync bit sequence + if (countBits64((m_bitBuffer & YSF_SYNC_BITS_MASK) ^ YSF_SYNC_BITS) <= SYNC_BIT_START_ERRS) { + DEBUG1("YSFRX: sync found in None"); + for (uint8_t i = 0U; i < YSF_SYNC_LENGTH_BYTES; i++) + m_buffer[i] = YSF_SYNC_BYTES[i]; + + m_lostCount = MAX_SYNC_FRAMES; + m_bufferPtr = YSF_SYNC_LENGTH_BITS; + m_state = YSFRXS_DATA; + + io.setDecode(true); + + } + +} + +void CYSFRX::processData(bool bit) +{ + m_bitBuffer <<= 1; + if (bit) + m_bitBuffer |= 0x01U; + + WRITE_BIT1(m_buffer, m_bufferPtr, bit); + m_bufferPtr++; + + // Only search for a sync in the right place +-2 symbols + if (m_bufferPtr >= (YSF_SYNC_LENGTH_BITS - 2U) && m_bufferPtr <= (YSF_SYNC_LENGTH_BITS + 2U)) { + // Fuzzy matching of the data sync bit sequence + if (countBits64((m_bitBuffer & YSF_SYNC_BITS_MASK) ^ YSF_SYNC_BITS) <= SYNC_BIT_RUN_ERRS) { + DEBUG2("YSFRX: found sync in Data, pos", m_bufferPtr - YSF_SYNC_LENGTH_BITS); + m_lostCount = MAX_SYNC_FRAMES; + m_bufferPtr = YSF_SYNC_LENGTH_BITS; + } + } + + // Send a data frame to the host if the required number of bits have been received + if (m_bufferPtr == YSF_FRAME_LENGTH_BITS) { + // We've not seen a data sync for too long, signal RXLOST and change to RX_NONE + m_lostCount--; + if (m_lostCount == 0U) { + DEBUG1("YSFRX: sync timed out, lost lock"); + io.setDecode(false); + + serial.writeYSFLost(); + + m_state = YSFRXS_NONE; + } else { + m_outBuffer[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U; + + serial.writeYSFData(m_outBuffer, YSF_FRAME_LENGTH_BYTES + 1U); + + // Start the next frame + ::memset(m_outBuffer, 0x00U, YSF_FRAME_LENGTH_BYTES + 3U); + m_bufferPtr = 0U; + } + } +} + diff --git a/YSFRX.h b/YSFRX.h new file mode 100644 index 0000000..51c95fa --- /dev/null +++ b/YSFRX.h @@ -0,0 +1,51 @@ +/* + * 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 + * 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(YSFRX_H) +#define YSFRX_H + +#include "YSFDefines.h" + +enum YSFRX_STATE { + YSFRXS_NONE, + YSFRXS_DATA +}; + +class CYSFRX { +public: + CYSFRX(); + + void databit(bool bit); + + void reset(); + +private: + bool m_prev; + YSFRX_STATE m_state; + uint64_t m_bitBuffer; + uint8_t m_outBuffer[YSF_FRAME_LENGTH_BYTES + 3U]; + uint8_t* m_buffer; + uint16_t m_bufferPtr; + uint16_t m_lostCount; + + void processNone(bool bit); + void processData(bool bit); +}; + +#endif + diff --git a/YSFTX.cpp b/YSFTX.cpp new file mode 100644 index 0000000..8cbb58b --- /dev/null +++ b/YSFTX.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2009-2016 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. + */ + +// #define WANT_DEBUG + +#include "Config.h" +#include "Globals.h" +#include "YSFTX.h" + +#include "YSFDefines.h" + +const uint8_t YSF_START_SYNC = 0x77U; +const uint8_t YSF_END_SYNC = 0xFFU; + +CYSFTX::CYSFTX() : +m_buffer(1500U), +m_poBuffer(), +m_poLen(0U), +m_poPtr(0U), +m_txDelay(240U), // 200ms +m_count(0U) +{ +} + +void CYSFTX::process() +{ + if (m_buffer.getData() == 0U && m_poLen == 0U) + return; + + if (m_poLen == 0U) { + if (!m_tx) { + m_delay = true; + m_count = 0U; + m_poLen = m_txDelay; + } else { + m_delay = false; + for (uint8_t i = 0U; i < YSF_FRAME_LENGTH_BYTES; i++) + m_poBuffer[m_poLen++] = m_buffer.get(); + } + + m_poPtr = 0U; + } + + if (m_poLen > 0U) { + uint16_t space = io.getSpace(); + + while (space > 8U) { + if (m_delay) { + m_poPtr++; + writeByte(YSF_START_SYNC); + } + else + writeByte(m_poBuffer[m_poPtr++]); + + space -= 8U; + + if (m_poPtr >= m_poLen) { + m_poPtr = 0U; + m_poLen = 0U; + m_delay = false; + return; + } + } + } +} + +uint8_t CYSFTX::writeData(const uint8_t* data, uint8_t length) +{ + if (length != (YSF_FRAME_LENGTH_BYTES + 1U)) + return 4U; + + uint16_t space = m_buffer.getSpace(); + if (space < YSF_FRAME_LENGTH_BYTES) + return 5U; + + for (uint8_t i = 0U; i < YSF_FRAME_LENGTH_BYTES; i++) + m_buffer.put(data[i + 1U]); + + return 0U; +} + +void CYSFTX::writeByte(uint8_t c) +{ + uint8_t bit; + uint8_t mask = 0x80U; + + for (uint8_t i = 0U; i < 8U; i++, c <<= 1) { + if ((c & mask) == mask) + bit = 1U; + else + bit = 0U; + + io.write(&bit, 1); + } +} + +void CYSFTX::setTXDelay(uint8_t delay) +{ + m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay +} + +uint16_t CYSFTX::getSpace() const +{ + return m_buffer.getSpace() / YSF_FRAME_LENGTH_BYTES; +} + diff --git a/YSFTX.h b/YSFTX.h new file mode 100644 index 0000000..21bd1a6 --- /dev/null +++ b/YSFTX.h @@ -0,0 +1,49 @@ +/* + * 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 + * 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(YSFTX_H) +#define YSFTX_H + +#include "SerialRB.h" + +class CYSFTX { +public: + CYSFTX(); + + uint8_t writeData(const uint8_t* data, uint8_t length); + + void process(); + + void setTXDelay(uint8_t delay); + + uint16_t getSpace() const; + +private: + CSerialRB m_buffer; + uint8_t m_poBuffer[130U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint16_t m_txDelay; + uint32_t m_count; + bool m_delay; + + void writeByte(uint8_t c); +}; + +#endif + diff --git a/stm32f10x_link.ld b/stm32f10x_link.ld new file mode 100644 index 0000000..8dc7a21 --- /dev/null +++ b/stm32f10x_link.ld @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2016 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. + */ + +/* Required amount of heap and stack */ +_min_heap_size = 0x1000; +_min_stack_size = 0x0800; + +/* The entry point in the interrupt vector table */ +ENTRY(Reset_Handler) + +/* Memory areas */ +MEMORY +{ + ROM (rx) : ORIGIN = 0x08000000, LENGTH = 64K /* FLASH */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K /* Main RAM */ +} + +/* Stack start address (end of 20K RAM) */ +_estack = ORIGIN(RAM) + LENGTH(RAM); + +SECTIONS +{ + .text : + { + /* The interrupt vector table */ + . = ALIGN(4); + KEEP(*(.isr_vector .isr_vector.*)) + + /* The program code */ + . = ALIGN(4); + *(.text .text*) + *(.rodata .rodata*) + + /* ARM-Thumb code */ + *(.glue_7) *(.glue_7t) + + . = ALIGN(4); + KEEP(*(.init)) + KEEP(*(.fini)) + + /* EABI C++ global constructors support */ + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + /* EABI C++ global constructors support */ + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + + /* EABI C++ global constructors support */ + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + } > ROM + + /* ARM sections containing exception unwinding information */ + .ARM.extab : { + __extab_start = .; + *(.ARM.extab* .gnu.linkonce.armextab.*) + __extab_end = .; + } > ROM + + /* ARM index entries for section unwinding */ + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } > ROM + + /* Start address for the initialization values of the .data section */ + _sidata = .; + + /* The .data section (initialized data) */ + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = . ; /* Start address for the .data section */ + *(.data .data*) + + . = ALIGN(4); + _edata = . ; /* End address for the .data section */ + } > RAM + + /* The .bss section (uninitialized data) */ + .bss : + { + . = ALIGN(4); + _sbss = .; /* Start address for the .bss section */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = . ; /* End address for the .bss section */ + __bss_end__ = _ebss; + } > RAM + + /* Space for heap and stack */ + .heap_stack : + { + end = . ; /* 'end' symbol defines heap location */ + _end = end ; + . = . + _min_heap_size; /* Additional space for heap and stack */ + . = . + _min_stack_size; + } > RAM + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } +}