diff --git a/CWIdTX.cpp b/CWIdTX.cpp new file mode 100644 index 0000000..a5433ee --- /dev/null +++ b/CWIdTX.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2009-2015 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 "CWIdTX.h" + +q15_t TONE[] = { + 0, 2588, 5000, 7071, 8660, 9659, 10000, 9659, 8660, 7071, 5000, 2588, 0, -2588, -5000, -7071, -8660, -9659, -10000, -9659, -8660, -7071, -5000, -2588}; + +q15_t SILENCE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +const uint8_t CYCLE_LENGTH = 24U; + +const uint8_t DOT_LENGTH = 80U; + +const struct { + uint8_t c; + uint32_t pattern; + uint8_t length; +} SYMBOL_LIST[] = { + {'A', 0xB8000000U, 8U}, + {'B', 0xEA800000U, 12U}, + {'C', 0xEBA00000U, 14U}, + {'D', 0xEA000000U, 10U}, + {'E', 0x80000000U, 4U}, + {'F', 0xAE800000U, 12U}, + {'G', 0xEE800000U, 12U}, + {'H', 0xAA000000U, 10U}, + {'I', 0xA0000000U, 6U}, + {'J', 0xBBB80000U, 16U}, + {'K', 0xEB800000U, 12U}, + {'L', 0xBA800000U, 12U}, + {'M', 0xEE000000U, 10U}, + {'N', 0xE8000000U, 8U}, + {'O', 0xEEE00000U, 14U}, + {'P', 0xBBA00000U, 14U}, + {'Q', 0xEEB80000U, 16U}, + {'R', 0xBA000000U, 10U}, + {'S', 0xA8000000U, 8U}, + {'T', 0xE0000000U, 6U}, + {'U', 0xAE000000U, 10U}, + {'V', 0xAB800000U, 12U}, + {'W', 0xBB800000U, 12U}, + {'X', 0xEAE00000U, 14U}, + {'Y', 0xEBB80000U, 16U}, + {'Z', 0xEEA00000U, 14U}, + {'1', 0xBBBB8000U, 20U}, + {'2', 0xAEEE0000U, 18U}, + {'3', 0xABB80000U, 16U}, + {'4', 0xAAE00000U, 14U}, + {'5', 0xAA800000U, 12U}, + {'6', 0xEAA00000U, 14U}, + {'7', 0xEEA80000U, 16U}, + {'8', 0xEEEA0000U, 18U}, + {'9', 0xEEEE8000U, 20U}, + {'0', 0xEEEEE000U, 22U}, + {'/', 0xEAE80000U, 16U}, + {'?', 0xAEEA0000U, 18U}, + {',', 0xEEAEE000U, 22U}, + {' ', 0x00000000U, 4U}, + {0U, 0x00000000U, 0U} +}; + +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]) +#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +CCWIdTX::CCWIdTX() : +m_poBuffer(), +m_poLen(0U), +m_poPtr(0U), +m_n(0U) +{ +} + +void CCWIdTX::process() +{ + if (m_poLen == 0U) + return; + + uint16_t space = io.getSpace(); + + while (space > CYCLE_LENGTH && space < 1000U) { + bool b = READ_BIT1(m_poBuffer, m_poPtr); + if (b) + io.write(TONE, CYCLE_LENGTH); + else + io.write(SILENCE, CYCLE_LENGTH); + + space -= CYCLE_LENGTH; + + m_n++; + if (m_n >= DOT_LENGTH) { + m_poPtr++; + m_n = 0U; + } + + if (m_poPtr >= m_poLen) { + m_poPtr = 0U; + m_poLen = 0U; + return; + } + } +} + +uint8_t CCWIdTX::write(const uint8_t* data, uint8_t length) +{ + ::memset(m_poBuffer, 0x00U, 1000U * sizeof(uint8_t)); + + m_poLen = 8U; + m_poPtr = 0U; + m_n = 0U; + + for (uint8_t i = 0U; i < length; i++) { + for (uint8_t j = 0U; SYMBOL_LIST[j].c != 0U; j++) { + if (SYMBOL_LIST[j].c == data[i]) { + uint32_t MASK = 0x80000000U; + for (uint8_t k = 0U; k < SYMBOL_LIST[j].length; k++, m_poLen++, MASK >>= 1) { + bool b = (SYMBOL_LIST[j].pattern & MASK) == MASK; + WRITE_BIT1(m_poBuffer, m_poLen, b); + + if (m_poLen >= 1000U) { + m_poLen = 0U; + return 4U; + } + } + + break; + } + } + } + + if (m_poLen == 8U) + m_poLen = 0U; + else + m_poLen += 5U; + + DEBUG2("Message created with length", m_poLen); + + return 0U; +} + diff --git a/CWIdTX.h b/CWIdTX.h new file mode 100644 index 0000000..4722dfa --- /dev/null +++ b/CWIdTX.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2009-2015 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(CWIDTX_H) +#define CWIDTX_H + +#include "Config.h" + +class CCWIdTX { +public: + CCWIdTX(); + + void process(); + + uint8_t write(const uint8_t* data, uint8_t length); + +private: + uint8_t m_poBuffer[1000U]; + uint16_t m_poLen; + uint16_t m_poPtr; + uint8_t m_n; +}; + +#endif + diff --git a/Globals.h b/Globals.h index 0e7116f..9199e60 100644 --- a/Globals.h +++ b/Globals.h @@ -54,6 +54,7 @@ enum MMDVM_STATE { #include "CalDStarRX.h" #include "CalDStarTX.h" #include "CalDMR.h" +#include "CWIdTX.h" #include "Debug.h" #include "IO.h" @@ -91,5 +92,7 @@ extern CCalDStarRX calDStarRX; extern CCalDStarTX calDStarTX; extern CCalDMR calDMR; +extern CCWIdTX cwIdTX; + #endif diff --git a/MMDVM.cpp b/MMDVM.cpp index 1f14e88..432678b 100644 --- a/MMDVM.cpp +++ b/MMDVM.cpp @@ -49,6 +49,8 @@ CCalDStarRX calDStarRX; CCalDStarTX calDStarTX; CCalDMR calDMR; +CCWIdTX cwIdTX; + CSerialPort serial; CIO io; @@ -78,6 +80,9 @@ void loop() if (m_modemState == STATE_DMRCAL) calDMR.process(); + + if (m_modemState == STATE_IDLE) + cwIdTX.process(); } int main() diff --git a/MMDVM.ino b/MMDVM.ino index f84c25f..ef84aa0 100644 --- a/MMDVM.ino +++ b/MMDVM.ino @@ -46,6 +46,8 @@ CCalDStarRX calDStarRX; CCalDStarTX calDStarTX; CCalDMR calDMR; +CCWIdTX cwIdTX; + CSerialPort serial; CIO io; @@ -75,5 +77,8 @@ void loop() if (m_modemState == STATE_DMRCAL) calDMR.process(); + + if (m_modemState == STATE_IDLE) + cwIdTX.process(); } diff --git a/SerialPort.cpp b/SerialPort.cpp index 612fdd7..3ea8515 100644 --- a/SerialPort.cpp +++ b/SerialPort.cpp @@ -34,6 +34,8 @@ 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; @@ -395,6 +397,15 @@ void CSerialPort::process() } break; + case MMDVM_SEND_CWID: + if (m_modemState == STATE_IDLE) + err = cwIdTX.write(m_buffer + 3U, m_len - 3U); + if (err != 0U) { + DEBUG2("Invalid CW Id data", err); + sendNAK(err); + } + break; + case MMDVM_DSTAR_HEADER: if (m_dstarEnable) { if (m_modemState == STATE_IDLE || m_modemState == STATE_DSTAR)