Adding CW ID support based on original Jonathan G4KLX CW ID

This commit is contained in:
Andy CA6JAU 2017-12-27 13:35:29 -03:00
parent 90a6759baa
commit 8b1042e2b1
8 changed files with 298 additions and 9 deletions

View file

@ -180,7 +180,8 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset)
uint32_t ADF7021_REG13 = 0; uint32_t ADF7021_REG13 = 0;
uint32_t AFC_OFFSET = 0; uint32_t AFC_OFFSET = 0;
m_modemState_prev = modemState; if(modemState != STATE_CWID)
m_modemState_prev = modemState;
// Toggle CE pin for ADF7021 reset // Toggle CE pin for ADF7021 reset
if(reset) { if(reset) {
@ -222,6 +223,7 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset)
AFC_OFFSET = 0; AFC_OFFSET = 0;
break; break;
case STATE_DMR: case STATE_DMR:
case STATE_CWID:
AFC_OFFSET = AFC_OFFSET_DMR; AFC_OFFSET = AFC_OFFSET_DMR;
break; break;
case STATE_YSF: case STATE_YSF:
@ -279,6 +281,30 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset)
#endif #endif
switch (modemState) { switch (modemState) {
case STATE_CWID:
// CW ID base configuration: DMR
// Dev: +1 symb (variable), symb rate = 4800
ADF7021_REG3 = ADF7021_REG3_DMR;
ADF7021_REG10 = ADF7021_REG10_DMR;
// 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) ADF7021_DISC_BW_DMR << 10; // Disc BW
ADF7021_REG4 |= (uint32_t) ADF7021_POST_BW_DMR << 20; // Post dem BW
ADF7021_REG4 |= (uint32_t) 0b10 << 30; // IF filter (25 kHz)
ADF7021_REG13 = (uint32_t) 0b1101 << 0; // register 13
ADF7021_REG13 |= (uint32_t) ADF7021_SLICER_TH_DMR << 4; // slicer threshold
ADF7021_REG2 = (uint32_t) 0b10 << 28; // invert data (and RC alpha = 0.5)
ADF7021_REG2 |= (uint32_t) (m_cwIdTXLevel / div2) << 19; // deviation
ADF7021_REG2 |= (uint32_t) 0b111 << 4; // modulation (RC 4FSK)
break;
case STATE_DSTAR: case STATE_DSTAR:
// Dev: 1200 Hz, symb rate = 4800 // Dev: 1200 Hz, symb rate = 4800
@ -461,7 +487,7 @@ void CIO::ifConf(MMDVM_STATE modemState, bool reset)
Send_AD7021_control(); Send_AD7021_control();
#if defined(DUPLEX) #if defined(DUPLEX)
if(m_duplex) if(m_duplex && (modemState != STATE_CWID))
ifConf2(modemState); ifConf2(modemState);
#endif #endif
} }

174
CWIdTX.cpp Normal file
View file

@ -0,0 +1,174 @@
/*
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2017 by Andy Uribe CA6JAU
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#include "Globals.h"
#include "CWIdTX.h"
// 4FSK symbol sequence (800 Hz "tone" at 4800 baud): +1 +3 +1 -1 -3 -1
// Bit sequence: 00 01 00 10 11 10
uint8_t TONE[] = {0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0};
uint8_t SILENCE[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const uint8_t CYCLE_LENGTH = 12U;
const uint8_t DOT_LENGTH = 40U;
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},
{'-', 0xEAAE0000U, 18U},
{'=', 0xEAB80000U, 16U},
{' ', 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) {
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, 300U * 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 >= 295U) {
m_poLen = 0U;
return 4U;
}
}
break;
}
}
}
// An empty message
if (m_poLen == 8U) {
m_poLen = 0U;
return 4U;
}
m_poLen += 5U;
DEBUG2("Message created with length", m_poLen);
return 0U;
}
void CCWIdTX::reset()
{
m_poLen = 0U;
m_poPtr = 0U;
m_n = 0U;
}

44
CWIdTX.h Normal file
View file

@ -0,0 +1,44 @@
/*
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML
* 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(CWIDTX_H)
#define CWIDTX_H
#include "Config.h"
class CCWIdTX {
public:
CCWIdTX();
void process();
uint8_t write(const uint8_t* data, uint8_t length);
void reset();
private:
uint8_t m_poBuffer[300U];
uint16_t m_poLen;
uint16_t m_poPtr;
uint8_t m_n;
};
#endif

View file

@ -32,7 +32,10 @@ enum MMDVM_STATE {
STATE_DSTAR = 1, STATE_DSTAR = 1,
STATE_DMR = 2, STATE_DMR = 2,
STATE_YSF = 3, STATE_YSF = 3,
STATE_P25 = 4 STATE_P25 = 4,
// Dummy states start at 90
STATE_CWID = 97
}; };
const uint8_t MARK_SLOT1 = 0x08U; const uint8_t MARK_SLOT1 = 0x08U;
@ -59,6 +62,7 @@ const uint8_t MARK_NONE = 0x00U;
#include "YSFTX.h" #include "YSFTX.h"
#include "P25RX.h" #include "P25RX.h"
#include "P25TX.h" #include "P25TX.h"
#include "CWIdTX.h"
#include "Debug.h" #include "Debug.h"
#include "Utils.h" #include "Utils.h"
@ -68,6 +72,9 @@ const uint16_t RX_RINGBUFFER_SIZE = 1024U;
extern MMDVM_STATE m_modemState; extern MMDVM_STATE m_modemState;
extern MMDVM_STATE m_modemState_prev; extern MMDVM_STATE m_modemState_prev;
extern bool m_cwid_state;
extern uint8_t m_cwIdTXLevel;
extern uint32_t m_modeTimerCnt; extern uint32_t m_modeTimerCnt;
extern bool m_dstarEnable; extern bool m_dstarEnable;
@ -103,5 +110,7 @@ extern CYSFTX ysfTX;
extern CP25RX p25RX; extern CP25RX p25RX;
extern CP25TX p25TX; extern CP25TX p25TX;
extern CCWIdTX cwIdTX;
#endif #endif

10
IO.cpp
View file

@ -127,8 +127,14 @@ void CIO::process()
} }
// Switch off the transmitter if needed // Switch off the transmitter if needed
if (m_txBuffer.getData() == 0U && m_tx) if (m_txBuffer.getData() == 0U && m_tx) {
if(m_cwid_state) { // check for CW ID end of transmission
m_cwid_state = false;
// Restoring previous mode
io.ifConf(m_modemState_prev, true);
}
setRX(false); setRX(false);
}
if(m_modemState_prev == STATE_DSTAR) if(m_modemState_prev == STATE_DSTAR)
scantime = SCAN_TIME; scantime = SCAN_TIME;
@ -143,7 +149,7 @@ void CIO::process()
if(m_modeTimerCnt >= scantime) { if(m_modeTimerCnt >= scantime) {
m_modeTimerCnt = 0; m_modeTimerCnt = 0;
if( (m_modemState == STATE_IDLE) && (m_scanPauseCnt == 0) && m_scanEnable) { if( (m_modemState == STATE_IDLE) && (m_scanPauseCnt == 0) && m_scanEnable && !m_cwid_state) {
m_scanPos = (m_scanPos + 1) % m_TotalModes; m_scanPos = (m_scanPos + 1) % m_TotalModes;
#if !defined(QUIET_MODE_LEDS) #if !defined(QUIET_MODE_LEDS)
setMode(m_Modes[m_scanPos]); setMode(m_Modes[m_scanPos]);

View file

@ -2,7 +2,7 @@
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Mathis Schmieder DB9MAT * Copyright (C) 2016 by Mathis Schmieder DB9MAT
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU * Copyright (C) 2016,2017 by Andy Uribe CA6JAU
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -29,6 +29,9 @@
MMDVM_STATE m_modemState = STATE_IDLE; MMDVM_STATE m_modemState = STATE_IDLE;
MMDVM_STATE m_modemState_prev = STATE_IDLE; MMDVM_STATE m_modemState_prev = STATE_IDLE;
bool m_cwid_state = false;
uint8_t m_cwIdTXLevel = 30;
uint32_t m_modeTimerCnt; uint32_t m_modeTimerCnt;
bool m_dstarEnable = true; bool m_dstarEnable = true;
@ -61,6 +64,8 @@ CYSFTX ysfTX;
CP25RX p25RX; CP25RX p25RX;
CP25TX p25TX; CP25TX p25TX;
CCWIdTX cwIdTX;
CSerialPort serial; CSerialPort serial;
CIO io; CIO io;
@ -96,6 +101,8 @@ void loop()
if (m_p25Enable && m_modemState == STATE_P25) if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process(); p25TX.process();
if (m_modemState == STATE_IDLE)
cwIdTX.process();
} }
int main() int main()

View file

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU * Copyright (C) 2016,2017 by Andy Uribe CA6JAU
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -25,6 +25,9 @@
MMDVM_STATE m_modemState = STATE_IDLE; MMDVM_STATE m_modemState = STATE_IDLE;
MMDVM_STATE m_modemState_prev = STATE_IDLE; MMDVM_STATE m_modemState_prev = STATE_IDLE;
bool m_cwid_state = false;
uint8_t m_cwIdTXLevel = 30;
uint32_t m_modeTimerCnt; uint32_t m_modeTimerCnt;
bool m_dstarEnable = true; bool m_dstarEnable = true;
@ -57,6 +60,8 @@ CYSFTX ysfTX;
CP25RX p25RX; CP25RX p25RX;
CP25TX p25TX; CP25TX p25TX;
CCWIdTX cwIdTX;
CSerialPort serial; CSerialPort serial;
CIO io; CIO io;
@ -91,4 +96,6 @@ void loop()
if (m_p25Enable && m_modemState == STATE_P25) if (m_p25Enable && m_modemState == STATE_P25)
p25TX.process(); p25TX.process();
if (m_modemState == STATE_IDLE)
cwIdTX.process();
} }

View file

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2013,2015,2016 by Jonathan Naylor G4KLX * Copyright (C) 2013,2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016 by Colin Durbridge G4EML * Copyright (C) 2016 by Colin Durbridge G4EML
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU * Copyright (C) 2016,2017 by Andy Uribe CA6JAU
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -227,6 +227,8 @@ uint8_t CSerialPort::setConfig(const uint8_t* data, uint8_t length)
uint8_t dmrDelay = data[7U]; uint8_t dmrDelay = data[7U];
#endif #endif
m_cwIdTXLevel = data[5U]>>2;
m_modemState = modemState; m_modemState = modemState;
m_dstarEnable = dstarEnable; m_dstarEnable = dstarEnable;
@ -321,6 +323,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dstarRX.reset(); dstarRX.reset();
ysfRX.reset(); ysfRX.reset();
p25RX.reset(); p25RX.reset();
cwIdTX.reset();
break; break;
case STATE_DSTAR: case STATE_DSTAR:
DEBUG1("Mode set to D-Star"); DEBUG1("Mode set to D-Star");
@ -331,6 +334,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dmrDMORX.reset(); dmrDMORX.reset();
ysfRX.reset(); ysfRX.reset();
p25RX.reset(); p25RX.reset();
cwIdTX.reset();
break; break;
case STATE_YSF: case STATE_YSF:
DEBUG1("Mode set to System Fusion"); DEBUG1("Mode set to System Fusion");
@ -341,6 +345,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dmrDMORX.reset(); dmrDMORX.reset();
dstarRX.reset(); dstarRX.reset();
p25RX.reset(); p25RX.reset();
cwIdTX.reset();
break; break;
case STATE_P25: case STATE_P25:
DEBUG1("Mode set to P25"); DEBUG1("Mode set to P25");
@ -351,6 +356,7 @@ void CSerialPort::setMode(MMDVM_STATE modemState)
dmrDMORX.reset(); dmrDMORX.reset();
dstarRX.reset(); dstarRX.reset();
ysfRX.reset(); ysfRX.reset();
cwIdTX.reset();
break; break;
default: default:
DEBUG1("Mode set to Idle"); DEBUG1("Mode set to Idle");
@ -443,6 +449,16 @@ void CSerialPort::process()
break; break;
case MMDVM_SEND_CWID: case MMDVM_SEND_CWID:
err = 5U;
if (m_modemState == STATE_IDLE) {
m_cwid_state = true;
io.ifConf(STATE_CWID, true);
err = cwIdTX.write(m_buffer + 3U, m_len - 3U);
}
if (err != 0U) {
DEBUG2("Invalid CW Id data", err);
sendNAK(err);
}
break; break;
case MMDVM_DSTAR_HEADER: case MMDVM_DSTAR_HEADER: