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 ( * ) + } +}