refactor Modem further to allow custom entry points for "user" handlers for modem open, close and clock (HostCal and Host use this); refactor "remote mode" in Host to use Modem custom entry points; correct some issues with the port of UARTPort from upstream (revert some changes back to pre-UARTPort from the old SerialController class); rework HostCal to use the new custom entry points; rework HostCal for better consistency and class use; correct and rename some misleading class variables and functions;

pull/1/head
Bryan Biedenkapp 5 years ago
parent 133ac37787
commit 266680f39b

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL * Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL
* *
* 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
@ -50,6 +50,7 @@ using namespace lookups;
#include <cstdio> #include <cstdio>
#include <cstdarg> #include <cstdarg>
#include <algorithm> #include <algorithm>
#include <functional>
#include <vector> #include <vector>
#if !defined(_WIN32) && !defined(_WIN64) #if !defined(_WIN32) && !defined(_WIN64)
@ -73,7 +74,8 @@ Host::Host(const std::string& confFile) :
m_modem(NULL), m_modem(NULL),
m_modemRemote(false), m_modemRemote(false),
m_network(NULL), m_network(NULL),
m_mode(STATE_IDLE), m_modemRemotePort(NULL),
m_state(STATE_IDLE),
m_modeTimer(1000U), m_modeTimer(1000U),
m_dmrTXTimer(1000U), m_dmrTXTimer(1000U),
m_cwIdTimer(1000U), m_cwIdTimer(1000U),
@ -210,15 +212,15 @@ int Host::run()
// main execution loop // main execution loop
while (!killed) { while (!killed) {
if (m_modem->hasLockout() && m_mode != HOST_STATE_LOCKOUT) if (m_modem->hasLockout() && m_state != HOST_STATE_LOCKOUT)
setMode(HOST_STATE_LOCKOUT); setState(HOST_STATE_LOCKOUT);
else if (!m_modem->hasLockout() && m_mode == HOST_STATE_LOCKOUT) else if (!m_modem->hasLockout() && m_state == HOST_STATE_LOCKOUT)
setMode(STATE_IDLE); setState(STATE_IDLE);
if (m_modem->hasError() && m_mode != HOST_STATE_ERROR) if (m_modem->hasError() && m_state != HOST_STATE_ERROR)
setMode(HOST_STATE_ERROR); setState(HOST_STATE_ERROR);
else if (!m_modem->hasError() && m_mode == HOST_STATE_ERROR) else if (!m_modem->hasError() && m_state == HOST_STATE_ERROR)
setMode(STATE_IDLE); setState(STATE_IDLE);
uint32_t ms = stopWatch.elapsed(); uint32_t ms = stopWatch.elapsed();
if (ms > 1U) if (ms > 1U)
@ -245,7 +247,7 @@ int Host::run()
Thread::sleep(1U); Thread::sleep(1U);
} }
setMode(HOST_STATE_QUIT); setState(HOST_STATE_QUIT);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -474,7 +476,7 @@ int Host::run()
} }
if (m_fixedMode && m_dmrEnabled && m_p25Enabled) { if (m_fixedMode && m_dmrEnabled && m_p25Enabled) {
::LogError(LOG_HOST, "Cannot have DMR enabled and P25 enabled when using fixed mode! Choose one protocol for fixed mode operation."); ::LogError(LOG_HOST, "Cannot have DMR enabled and P25 enabled when using fixed state! Choose one protocol for fixed state operation.");
g_killed = true; g_killed = true;
} }
@ -489,19 +491,19 @@ int Host::run()
} }
if (!g_killed) { if (!g_killed) {
// fixed more or P25 control channel will force a mode change // fixed more or P25 control channel will force a state change
if (m_fixedMode || m_p25CtrlChannel) { if (m_fixedMode || m_p25CtrlChannel) {
if (m_p25CtrlChannel) { if (m_p25CtrlChannel) {
m_fixedMode = true; m_fixedMode = true;
} }
if (dmr != NULL) if (dmr != NULL)
setMode(STATE_DMR); setState(STATE_DMR);
if (p25 != NULL) if (p25 != NULL)
setMode(STATE_P25); setState(STATE_P25);
} }
else { else {
setMode(STATE_IDLE); setState(STATE_IDLE);
} }
::LogInfoEx(LOG_HOST, "Host is performing late initialization and warmup"); ::LogInfoEx(LOG_HOST, "Host is performing late initialization and warmup");
@ -545,15 +547,15 @@ int Host::run()
// main execution loop // main execution loop
while (!killed) { while (!killed) {
if (m_modem->hasLockout() && m_mode != HOST_STATE_LOCKOUT) if (m_modem->hasLockout() && m_state != HOST_STATE_LOCKOUT)
setMode(HOST_STATE_LOCKOUT); setState(HOST_STATE_LOCKOUT);
else if (!m_modem->hasLockout() && m_mode == HOST_STATE_LOCKOUT) else if (!m_modem->hasLockout() && m_state == HOST_STATE_LOCKOUT)
setMode(STATE_IDLE); setState(STATE_IDLE);
if (m_modem->hasError() && m_mode != HOST_STATE_ERROR) if (m_modem->hasError() && m_state != HOST_STATE_ERROR)
setMode(HOST_STATE_ERROR); setState(HOST_STATE_ERROR);
else if (!m_modem->hasError() && m_mode == HOST_STATE_ERROR) else if (!m_modem->hasError() && m_state == HOST_STATE_ERROR)
setMode(STATE_IDLE); setState(STATE_IDLE);
uint32_t ms = stopWatch.elapsed(); uint32_t ms = stopWatch.elapsed();
if (ms > 1U) if (ms > 1U)
@ -574,13 +576,13 @@ int Host::run()
// write those frames to the DMR controller // write those frames to the DMR controller
len = m_modem->readDMRData1(data); len = m_modem->readDMRData1(data);
if (len > 0U) { if (len > 0U) {
if (m_mode == STATE_IDLE) { if (m_state == STATE_IDLE) {
// if the modem is in duplex -- process wakeup CSBKs // if the modem is in duplex -- process wakeup CSBKs
if (m_duplex) { if (m_duplex) {
bool ret = dmr->processWakeup(data); bool ret = dmr->processWakeup(data);
if (ret) { if (ret) {
m_modeTimer.setTimeout(m_rfModeHang); m_modeTimer.setTimeout(m_rfModeHang);
setMode(STATE_DMR); setState(STATE_DMR);
dmrBeaconDurationTimer.stop(); dmrBeaconDurationTimer.stop();
INTERRUPT_P25_CONTROL; INTERRUPT_P25_CONTROL;
@ -589,14 +591,14 @@ int Host::run()
else { else {
// in simplex directly process slot 1 frames // in simplex directly process slot 1 frames
m_modeTimer.setTimeout(m_rfModeHang); m_modeTimer.setTimeout(m_rfModeHang);
setMode(STATE_DMR); setState(STATE_DMR);
dmr->processFrame1(data, len); dmr->processFrame1(data, len);
dmrBeaconDurationTimer.stop(); dmrBeaconDurationTimer.stop();
p25CCDurationTimer.stop(); p25CCDurationTimer.stop();
} }
} }
else if (m_mode == STATE_DMR) { else if (m_state == STATE_DMR) {
// if the modem is in duplex, and hasn't started transmitting // if the modem is in duplex, and hasn't started transmitting
// process wakeup CSBKs // process wakeup CSBKs
if (m_duplex && !m_modem->hasTX()) { if (m_duplex && !m_modem->hasTX()) {
@ -619,8 +621,8 @@ int Host::run()
} }
} }
} }
else if (m_mode != HOST_STATE_LOCKOUT) { else if (m_state != HOST_STATE_LOCKOUT) {
LogWarning(LOG_HOST, "DMR modem data received, mode = %u", m_mode); LogWarning(LOG_HOST, "DMR modem data received, state = %u", m_state);
} }
} }
@ -628,13 +630,13 @@ int Host::run()
// write those frames to the DMR controller // write those frames to the DMR controller
len = m_modem->readDMRData2(data); len = m_modem->readDMRData2(data);
if (len > 0U) { if (len > 0U) {
if (m_mode == STATE_IDLE) { if (m_state == STATE_IDLE) {
// if the modem is in duplex -- process wakeup CSBKs // if the modem is in duplex -- process wakeup CSBKs
if (m_duplex) { if (m_duplex) {
bool ret = dmr->processWakeup(data); bool ret = dmr->processWakeup(data);
if (ret) { if (ret) {
m_modeTimer.setTimeout(m_rfModeHang); m_modeTimer.setTimeout(m_rfModeHang);
setMode(STATE_DMR); setState(STATE_DMR);
dmrBeaconDurationTimer.stop(); dmrBeaconDurationTimer.stop();
INTERRUPT_P25_CONTROL; INTERRUPT_P25_CONTROL;
@ -643,14 +645,14 @@ int Host::run()
else { else {
// in simplex -- directly process slot 2 frames // in simplex -- directly process slot 2 frames
m_modeTimer.setTimeout(m_rfModeHang); m_modeTimer.setTimeout(m_rfModeHang);
setMode(STATE_DMR); setState(STATE_DMR);
dmr->processFrame2(data, len); dmr->processFrame2(data, len);
dmrBeaconDurationTimer.stop(); dmrBeaconDurationTimer.stop();
INTERRUPT_P25_CONTROL; INTERRUPT_P25_CONTROL;
} }
} }
else if (m_mode == STATE_DMR) { else if (m_state == STATE_DMR) {
// if the modem is in duplex, and hasn't started transmitting // if the modem is in duplex, and hasn't started transmitting
// process wakeup CSBKs // process wakeup CSBKs
if (m_duplex && !m_modem->hasTX()) { if (m_duplex && !m_modem->hasTX()) {
@ -673,8 +675,8 @@ int Host::run()
} }
} }
} }
else if (m_mode != HOST_STATE_LOCKOUT) { else if (m_state != HOST_STATE_LOCKOUT) {
LogWarning(LOG_HOST, "DMR modem data received, mode = %u", m_mode); LogWarning(LOG_HOST, "DMR modem data received, state = %u", m_state);
} }
} }
} }
@ -685,11 +687,11 @@ int Host::run()
if (p25 != NULL) { if (p25 != NULL) {
len = m_modem->readP25Data(data); len = m_modem->readP25Data(data);
if (len > 0U) { if (len > 0U) {
if (m_mode == STATE_IDLE) { if (m_state == STATE_IDLE) {
bool ret = p25->processFrame(data, len); bool ret = p25->processFrame(data, len);
if (ret) { if (ret) {
m_modeTimer.setTimeout(m_rfModeHang); m_modeTimer.setTimeout(m_rfModeHang);
setMode(STATE_P25); setState(STATE_P25);
dmrBeaconDurationTimer.stop(); dmrBeaconDurationTimer.stop();
INTERRUPT_P25_CONTROL; INTERRUPT_P25_CONTROL;
@ -699,12 +701,12 @@ int Host::run()
if (ret) { if (ret) {
dmrBeaconDurationTimer.stop(); dmrBeaconDurationTimer.stop();
if (m_mode == STATE_IDLE) { if (m_state == STATE_IDLE) {
m_modeTimer.setTimeout(m_rfModeHang); m_modeTimer.setTimeout(m_rfModeHang);
setMode(STATE_P25); setState(STATE_P25);
} }
if (m_mode == STATE_P25) { if (m_state == STATE_P25) {
m_modeTimer.start(); m_modeTimer.start();
} }
@ -730,7 +732,7 @@ int Host::run()
} }
} }
} }
else if (m_mode == STATE_P25) { else if (m_state == STATE_P25) {
bool ret = p25->processFrame(data, len); bool ret = p25->processFrame(data, len);
if (ret) { if (ret) {
m_modeTimer.start(); m_modeTimer.start();
@ -739,19 +741,19 @@ int Host::run()
else { else {
ret = p25->writeEndRF(); ret = p25->writeEndRF();
if (ret) { if (ret) {
if (m_mode == STATE_IDLE) { if (m_state == STATE_IDLE) {
m_modeTimer.setTimeout(m_rfModeHang); m_modeTimer.setTimeout(m_rfModeHang);
setMode(STATE_P25); setState(STATE_P25);
} }
if (m_mode == STATE_P25) { if (m_state == STATE_P25) {
m_modeTimer.start(); m_modeTimer.start();
} }
} }
} }
} }
else if (m_mode != HOST_STATE_LOCKOUT) { else if (m_state != HOST_STATE_LOCKOUT) {
LogWarning(LOG_HOST, "P25 modem data received, mode = %u", m_mode); LogWarning(LOG_HOST, "P25 modem data received, state = %u", m_state);
} }
} }
} }
@ -762,12 +764,12 @@ int Host::run()
if (m_modeTimer.isRunning() && m_modeTimer.hasExpired()) { if (m_modeTimer.isRunning() && m_modeTimer.hasExpired()) {
if (!m_fixedMode) { if (!m_fixedMode) {
setMode(STATE_IDLE); setState(STATE_IDLE);
} else { } else {
if (dmr != NULL) if (dmr != NULL)
setMode(STATE_DMR); setState(STATE_DMR);
if (p25 != NULL) if (p25 != NULL)
setMode(STATE_P25); setState(STATE_P25);
} }
} }
@ -780,11 +782,11 @@ int Host::run()
if (ret) { if (ret) {
len = dmr->getFrame1(data); len = dmr->getFrame1(data);
if (len > 0U) { if (len > 0U) {
if (m_mode == STATE_IDLE) { if (m_state == STATE_IDLE) {
m_modeTimer.setTimeout(m_netModeHang); m_modeTimer.setTimeout(m_netModeHang);
setMode(STATE_DMR); setState(STATE_DMR);
} }
if (m_mode == STATE_DMR) { if (m_state == STATE_DMR) {
// if the modem is in duplex -- write DMR sync start // if the modem is in duplex -- write DMR sync start
if (m_duplex) { if (m_duplex) {
m_modem->writeDMRStart(true); m_modem->writeDMRStart(true);
@ -799,8 +801,8 @@ int Host::run()
} }
m_modeTimer.start(); m_modeTimer.start();
} }
else if (m_mode != HOST_STATE_LOCKOUT) { else if (m_state != HOST_STATE_LOCKOUT) {
LogWarning(LOG_HOST, "DMR data received, mode = %u", m_mode); LogWarning(LOG_HOST, "DMR data received, state = %u", m_state);
} }
} }
} }
@ -812,11 +814,11 @@ int Host::run()
if (ret) { if (ret) {
len = dmr->getFrame2(data); len = dmr->getFrame2(data);
if (len > 0U) { if (len > 0U) {
if (m_mode == STATE_IDLE) { if (m_state == STATE_IDLE) {
m_modeTimer.setTimeout(m_netModeHang); m_modeTimer.setTimeout(m_netModeHang);
setMode(STATE_DMR); setState(STATE_DMR);
} }
if (m_mode == STATE_DMR) { if (m_state == STATE_DMR) {
// if the modem is in duplex -- write DMR sync start // if the modem is in duplex -- write DMR sync start
if (m_duplex) { if (m_duplex) {
m_modem->writeDMRStart(true); m_modem->writeDMRStart(true);
@ -831,8 +833,8 @@ int Host::run()
} }
m_modeTimer.start(); m_modeTimer.start();
} }
else if (m_mode != HOST_STATE_LOCKOUT) { else if (m_state != HOST_STATE_LOCKOUT) {
LogWarning(LOG_HOST, "DMR data received, mode = %u", m_mode); LogWarning(LOG_HOST, "DMR data received, state = %u", m_state);
} }
} }
} }
@ -847,12 +849,12 @@ int Host::run()
if (ret) { if (ret) {
len = p25->getFrame(data); len = p25->getFrame(data);
if (len > 0U) { if (len > 0U) {
if (m_mode == STATE_IDLE) { if (m_state == STATE_IDLE) {
m_modeTimer.setTimeout(m_netModeHang); m_modeTimer.setTimeout(m_netModeHang);
setMode(STATE_P25); setState(STATE_P25);
} }
if (m_mode == STATE_P25) { if (m_state == STATE_P25) {
m_modem->writeP25Data(data, len); m_modem->writeP25Data(data, len);
dmrBeaconDurationTimer.stop(); dmrBeaconDurationTimer.stop();
@ -862,12 +864,12 @@ int Host::run()
m_modeTimer.start(); m_modeTimer.start();
} }
else if (m_mode != HOST_STATE_LOCKOUT) { else if (m_state != HOST_STATE_LOCKOUT) {
LogWarning(LOG_HOST, "P25 data received, mode = %u", m_mode); LogWarning(LOG_HOST, "P25 data received, state = %u", m_state);
} }
} }
else { else {
if (m_mode == STATE_IDLE || m_mode == STATE_P25) { if (m_state == STATE_IDLE || m_state == STATE_P25) {
// P25 control data, if control data is being transmitted // P25 control data, if control data is being transmitted
if (p25CCDurationTimer.isRunning() && !p25CCDurationTimer.hasExpired()) { if (p25CCDurationTimer.isRunning() && !p25CCDurationTimer.hasExpired()) {
p25->setCCRunning(true); p25->setCCRunning(true);
@ -877,12 +879,12 @@ int Host::run()
// P25 status data, tail on idle // P25 status data, tail on idle
ret = p25->writeEndRF(); ret = p25->writeEndRF();
if (ret) { if (ret) {
if (m_mode == STATE_IDLE) { if (m_state == STATE_IDLE) {
m_modeTimer.setTimeout(m_netModeHang); m_modeTimer.setTimeout(m_netModeHang);
setMode(STATE_P25); setState(STATE_P25);
} }
if (m_mode == STATE_P25) { if (m_state == STATE_P25) {
m_modeTimer.start(); m_modeTimer.start();
} }
} }
@ -943,14 +945,14 @@ int Host::run()
if (dmrBeaconDurationTimer.isRunning() || p25CCDurationTimer.isRunning()) { if (dmrBeaconDurationTimer.isRunning() || p25CCDurationTimer.isRunning()) {
LogDebug(LOG_HOST, "CW, beacon or CC timer running, ceasing"); LogDebug(LOG_HOST, "CW, beacon or CC timer running, ceasing");
setMode(STATE_IDLE); setState(STATE_IDLE);
dmrBeaconDurationTimer.stop(); dmrBeaconDurationTimer.stop();
p25CCDurationTimer.stop(); p25CCDurationTimer.stop();
//g_interruptP25Control = true; //g_interruptP25Control = true;
} }
if (m_mode == STATE_IDLE && !m_modem->hasTX()) { if (m_state == STATE_IDLE && !m_modem->hasTX()) {
hasCw = true; hasCw = true;
m_modem->sendCWId(m_cwCallsign); m_modem->sendCWId(m_cwCallsign);
@ -969,13 +971,13 @@ int Host::run()
dmrBeaconIntervalTimer.start(); dmrBeaconIntervalTimer.start();
} }
else { else {
if ((m_mode == STATE_IDLE || m_mode == STATE_DMR) && !m_modem->hasTX()) { if ((m_state == STATE_IDLE || m_state == STATE_DMR) && !m_modem->hasTX()) {
if (m_modeTimer.isRunning()) { if (m_modeTimer.isRunning()) {
m_modeTimer.stop(); m_modeTimer.stop();
} }
if (m_mode != STATE_DMR) if (m_state != STATE_DMR)
setMode(STATE_DMR); setState(STATE_DMR);
g_fireDMRBeacon = false; g_fireDMRBeacon = false;
LogDebug(LOG_HOST, "DMR, roaming beacon burst"); LogDebug(LOG_HOST, "DMR, roaming beacon burst");
@ -990,7 +992,7 @@ int Host::run()
if (dmrBeaconDurationTimer.isRunning() && dmrBeaconDurationTimer.hasExpired()) { if (dmrBeaconDurationTimer.isRunning() && dmrBeaconDurationTimer.hasExpired()) {
dmrBeaconDurationTimer.stop(); dmrBeaconDurationTimer.stop();
if (m_mode == STATE_DMR && !m_modeTimer.isRunning()) { if (m_state == STATE_DMR && !m_modeTimer.isRunning()) {
m_modeTimer.setTimeout(m_rfModeHang); m_modeTimer.setTimeout(m_rfModeHang);
m_modeTimer.start(); m_modeTimer.start();
} }
@ -1016,13 +1018,13 @@ int Host::run()
p25CCIntervalTimer.start(); p25CCIntervalTimer.start();
} }
else { else {
if ((m_mode == STATE_IDLE || m_mode == STATE_P25) && !m_modem->hasTX()) { if ((m_state == STATE_IDLE || m_state == STATE_P25) && !m_modem->hasTX()) {
if (m_modeTimer.isRunning()) { if (m_modeTimer.isRunning()) {
m_modeTimer.stop(); m_modeTimer.stop();
} }
if (m_mode != STATE_P25) if (m_state != STATE_P25)
setMode(STATE_P25); setState(STATE_P25);
if (g_interruptP25Control) { if (g_interruptP25Control) {
g_interruptP25Control = false; g_interruptP25Control = false;
@ -1060,7 +1062,7 @@ int Host::run()
p25->writeControlEndRF(); p25->writeControlEndRF();
p25->setCCRunning(false); p25->setCCRunning(false);
if (m_mode == STATE_P25 && !m_modeTimer.isRunning()) { if (m_state == STATE_P25 && !m_modeTimer.isRunning()) {
m_modeTimer.setTimeout(m_rfModeHang); m_modeTimer.setTimeout(m_rfModeHang);
m_modeTimer.start(); m_modeTimer.start();
} }
@ -1075,7 +1077,7 @@ int Host::run()
// simply use the P25 CC interval timer in a non-broadcast state to transmit adjacent site data over // simply use the P25 CC interval timer in a non-broadcast state to transmit adjacent site data over
// the network // the network
if (p25CCIntervalTimer.isRunning() && p25CCIntervalTimer.hasExpired()) { if (p25CCIntervalTimer.isRunning() && p25CCIntervalTimer.hasExpired()) {
if ((m_mode == STATE_IDLE || m_mode == STATE_P25) && !m_modem->hasTX()) { if ((m_state == STATE_IDLE || m_state == STATE_P25) && !m_modem->hasTX()) {
p25->writeAdjSSNetwork(); p25->writeAdjSSNetwork();
p25CCIntervalTimer.start(); p25CCIntervalTimer.start();
} }
@ -1110,7 +1112,7 @@ int Host::run()
Thread::sleep(1U); Thread::sleep(1U);
} }
setMode(HOST_STATE_QUIT); setState(HOST_STATE_QUIT);
if (dmr != NULL) { if (dmr != NULL) {
delete dmr; delete dmr;
@ -1428,11 +1430,10 @@ bool Host::createModem()
return false; return false;
} }
port::IModemPort* slavePort = NULL;
if (portType == UDP_PORT) { if (portType == UDP_PORT) {
std::transform(udpMode.begin(), udpMode.end(), udpMode.begin(), ::tolower); std::transform(udpMode.begin(), udpMode.end(), udpMode.begin(), ::tolower);
if (udpMode == UDP_MODE_MASTER) { if (udpMode == UDP_MODE_MASTER) {
slavePort = new port::UDPPort(udpAddress, udpPort); m_modemRemotePort = new port::UDPPort(udpAddress, udpPort);
m_modemRemote = true; m_modemRemote = true;
} }
else if (udpMode == UDP_MODE_PEER) { else if (udpMode == UDP_MODE_PEER) {
@ -1480,7 +1481,9 @@ bool Host::createModem()
m_modem->setP25NAC(m_p25NAC); m_modem->setP25NAC(m_p25NAC);
if (m_modemRemote) { if (m_modemRemote) {
m_modem->setSlavePort(slavePort); m_modem->setOpenHandler(MODEM_OC_PORT_HANDLER_BIND(Host::rmtPortModemOpen, this));
m_modem->setCloseHandler(MODEM_OC_PORT_HANDLER_BIND(Host::rmtPortModemClose, this));
m_modem->setResponseHandler(MODEM_RESP_HANDLER_BIND(Host::rmtPortModemHandler, this));
} }
bool ret = m_modem->open(); bool ret = m_modem->open();
@ -1586,21 +1589,111 @@ bool Host::createNetwork()
return true; return true;
} }
/// <summary>
///
/// </summary>
/// <param name="modem"></param>
bool Host::rmtPortModemOpen(Modem* modem)
{
assert(m_modemRemotePort != NULL);
bool ret = m_modemRemotePort->open();
if (!ret)
return false;
LogMessage(LOG_MODEM, "Modem Ready [Remote Mode]");
// handled modem open
return true;
}
/// <summary>
///
/// </summary>
/// <param name="modem"></param>
bool Host::rmtPortModemClose(Modem* modem)
{
assert(m_modemRemotePort != NULL);
m_modemRemotePort->close();
// handled modem close
return true;
}
/// <summary>
///
/// </summary>
/// <param name="modem"></param>
/// <param name="ms"></param>
/// <param name="rspType"></param>
/// <param name="rspDblLen"></param>
/// <param name="data"></param>
/// <param name="len"></param>
/// <returns></returns>
bool Host::rmtPortModemHandler(Modem* modem, uint32_t ms, modem::RESP_TYPE_DVM rspType, bool rspDblLen, const uint8_t* buffer, uint16_t len)
{
assert(m_modemRemotePort != NULL);
if (rspType == RTM_OK && len > 0U) {
if (modem->getTrace())
Utils::dump(1U, "TX Remote Data", buffer, len);
// send entire modem packet over the remote port
m_modemRemotePort->write(buffer, len);
// Only feed data to the modem if the playout timer has expired
modem->getPlayoutTimer().clock(ms);
if (!modem->getPlayoutTimer().hasExpired()) {
// handled modem response
return true;
}
}
// read any data from the remote port for the air interface
uint8_t data[BUFFER_LENGTH];
::memset(data, 0x00U, BUFFER_LENGTH);
uint32_t ret = m_modemRemotePort->read(data, BUFFER_LENGTH);
if (ret > 0) {
if (modem->getTrace())
Utils::dump(1U, "RX Remote Data", (uint8_t*)data, ret);
if (ret < 3U) {
LogError(LOG_MODEM, "Illegal length of remote data must be >3 bytes");
Utils::dump("Buffer dump", data, ret);
// handled modem response
return true;
}
uint8_t len = data[1U];
int ret = modem->write(data, len);
if (ret != int(len))
LogError(LOG_MODEM, "Error writing remote data");
}
modem->getPlayoutTimer().start();
// handled modem response
return true;
}
/// <summary> /// <summary>
/// Helper to set the host/modem running state. /// Helper to set the host/modem running state.
/// </summary> /// </summary>
/// <param name="mode">Mode enumeration to switch the host/modem state to.</param> /// <param name="state">Mode enumeration to switch the host/modem state to.</param>
void Host::setMode(uint8_t mode) void Host::setState(uint8_t state)
{ {
assert(m_modem != NULL); assert(m_modem != NULL);
//if (m_mode != mode) { //if (m_state != state) {
// LogDebug(LOG_HOST, "setMode, m_mode = %u, mode = %u", m_mode, mode); // LogDebug(LOG_HOST, "setState, m_state = %u, state = %u", m_state, state);
//} //}
switch (mode) { switch (state) {
case STATE_DMR: case STATE_DMR:
m_modem->setMode(STATE_DMR); m_modem->setState(STATE_DMR);
// if the modem is in duplex -- write DMR start sync // if the modem is in duplex -- write DMR start sync
if (m_duplex) { if (m_duplex) {
@ -1608,15 +1701,15 @@ void Host::setMode(uint8_t mode)
m_dmrTXTimer.start(); m_dmrTXTimer.start();
} }
m_mode = STATE_DMR; m_state = STATE_DMR;
m_modeTimer.start(); m_modeTimer.start();
//m_cwIdTimer.stop(); //m_cwIdTimer.stop();
createLockFile("DMR"); createLockFile("DMR");
break; break;
case STATE_P25: case STATE_P25:
m_modem->setMode(STATE_P25); m_modem->setState(STATE_P25);
m_mode = STATE_P25; m_state = STATE_P25;
m_modeTimer.start(); m_modeTimer.start();
//m_cwIdTimer.stop(); //m_cwIdTimer.stop();
createLockFile("P25"); createLockFile("P25");
@ -1627,13 +1720,13 @@ void Host::setMode(uint8_t mode)
if (m_network != NULL) if (m_network != NULL)
m_network->enable(false); m_network->enable(false);
if (m_mode == STATE_DMR && m_duplex && m_modem->hasTX()) { if (m_state == STATE_DMR && m_duplex && m_modem->hasTX()) {
m_modem->writeDMRStart(false); m_modem->writeDMRStart(false);
m_dmrTXTimer.stop(); m_dmrTXTimer.stop();
} }
m_modem->setMode(STATE_IDLE); m_modem->setState(STATE_IDLE);
m_mode = HOST_STATE_LOCKOUT; m_state = HOST_STATE_LOCKOUT;
m_modeTimer.stop(); m_modeTimer.stop();
//m_cwIdTimer.stop(); //m_cwIdTimer.stop();
removeLockFile(); removeLockFile();
@ -1644,12 +1737,12 @@ void Host::setMode(uint8_t mode)
if (m_network != NULL) if (m_network != NULL)
m_network->enable(false); m_network->enable(false);
if (m_mode == STATE_DMR && m_duplex && m_modem->hasTX()) { if (m_state == STATE_DMR && m_duplex && m_modem->hasTX()) {
m_modem->writeDMRStart(false); m_modem->writeDMRStart(false);
m_dmrTXTimer.stop(); m_dmrTXTimer.stop();
} }
m_mode = HOST_STATE_ERROR; m_state = HOST_STATE_ERROR;
m_modeTimer.stop(); m_modeTimer.stop();
m_cwIdTimer.stop(); m_cwIdTimer.stop();
removeLockFile(); removeLockFile();
@ -1659,14 +1752,14 @@ void Host::setMode(uint8_t mode)
if (m_network != NULL) if (m_network != NULL)
m_network->enable(true); m_network->enable(true);
if (m_mode == STATE_DMR && m_duplex && m_modem->hasTX()) { if (m_state == STATE_DMR && m_duplex && m_modem->hasTX()) {
m_modem->writeDMRStart(false); m_modem->writeDMRStart(false);
m_dmrTXTimer.stop(); m_dmrTXTimer.stop();
} }
m_modem->setMode(STATE_IDLE); m_modem->setState(STATE_IDLE);
if (m_mode == HOST_STATE_ERROR) { if (m_state == HOST_STATE_ERROR) {
m_modem->sendCWId(m_cwCallsign); m_modem->sendCWId(m_cwCallsign);
m_cwIdTimer.setTimeout(m_cwIdTime); m_cwIdTimer.setTimeout(m_cwIdTime);
@ -1676,7 +1769,7 @@ void Host::setMode(uint8_t mode)
removeLockFile(); removeLockFile();
m_modeTimer.stop(); m_modeTimer.stop();
if (m_mode == HOST_STATE_QUIT) { if (m_state == HOST_STATE_QUIT) {
if (m_modem != NULL) { if (m_modem != NULL) {
m_modem->close(); m_modem->close();
delete m_modem; delete m_modem;
@ -1702,7 +1795,7 @@ void Host::setMode(uint8_t mode)
} }
} }
else { else {
m_mode = STATE_IDLE; m_state = STATE_IDLE;
} }
break; break;
} }
@ -1711,7 +1804,7 @@ void Host::setMode(uint8_t mode)
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="mode"></param> /// <param name="state"></param>
void Host::createLockFile(const char* mode) const void Host::createLockFile(const char* mode) const
{ {
FILE* fp = ::fopen(g_lockFile.c_str(), "wt"); FILE* fp = ::fopen(g_lockFile.c_str(), "wt");

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL * Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL
* *
* 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
@ -71,7 +71,9 @@ private:
bool m_modemRemote; bool m_modemRemote;
network::Network* m_network; network::Network* m_network;
uint8_t m_mode; modem::port::IModemPort* m_modemRemotePort;
uint8_t m_state;
Timer m_modeTimer; Timer m_modeTimer;
Timer m_dmrTXTimer; Timer m_dmrTXTimer;
@ -133,8 +135,15 @@ private:
/// <summary>Initializes network connectivity.</summary> /// <summary>Initializes network connectivity.</summary>
bool createNetwork(); bool createNetwork();
/// <summary></summary>
bool rmtPortModemOpen(modem::Modem* modem);
/// <summary></summary>
bool rmtPortModemClose(modem::Modem* modem);
/// <summary></summary>
bool rmtPortModemHandler(modem::Modem* modem, uint32_t ms, modem::RESP_TYPE_DVM rspType, bool rspDblLen, const uint8_t* buffer, uint16_t len);
/// <summary>Helper to set the host/modem running state.</summary> /// <summary>Helper to set the host/modem running state.</summary>
void setMode(uint8_t mode); void setState(uint8_t mode);
/// <summary></summary> /// <summary></summary>
void createLockFile(const char* mode) const; void createLockFile(const char* mode) const;

@ -13,7 +13,7 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU * Copyright (C) 2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL * Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL
* *
* 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
@ -31,6 +31,7 @@
*/ */
#include "host/calibrate/HostCal.h" #include "host/calibrate/HostCal.h"
#include "dmr/DMRDefines.h" #include "dmr/DMRDefines.h"
#include "modem/port/UARTPort.h"
#include "p25/P25Defines.h" #include "p25/P25Defines.h"
#include "p25/data/DataHeader.h" #include "p25/data/DataHeader.h"
#include "p25/lc/LC.h" #include "p25/lc/LC.h"
@ -131,7 +132,7 @@ unsigned char LDU2_1K[] = {
HostCal::HostCal(const std::string& confFile) : HostCal::HostCal(const std::string& confFile) :
m_confFile(confFile), m_confFile(confFile),
m_conf(), m_conf(),
m_serial(NULL), m_modem(NULL),
m_console(), m_console(),
m_fec(), m_fec(),
m_transmit(false), m_transmit(false),
@ -174,7 +175,7 @@ HostCal::HostCal(const std::string& confFile) :
/// </summary> /// </summary>
HostCal::~HostCal() HostCal::~HostCal()
{ {
delete m_serial; delete m_modem;
} }
/// <summary> /// <summary>
@ -195,7 +196,16 @@ int HostCal::run()
return 1; return 1;
} }
yaml::Node modemConf = m_conf["system"]["modem"]; getHostVersion();
::LogInfo(">> Modem Calibration");
LogInfo("General Parameters");
yaml::Node systemConf = m_conf["system"];
std::string identity = systemConf["identity"].as<std::string>();
::LogInfo(" Identity: %s", identity.c_str());
yaml::Node modemConf = systemConf["modem"];
yaml::Node modemProtocol = modemConf["protocol"]; yaml::Node modemProtocol = modemConf["protocol"];
std::string portType = modemProtocol["type"].as<std::string>("null"); std::string portType = modemProtocol["type"].as<std::string>("null");
@ -204,6 +214,7 @@ int HostCal::run()
std::string uartPort = uartProtocol["port"].as<std::string>(); std::string uartPort = uartProtocol["port"].as<std::string>();
uint32_t uartSpeed = uartProtocol["speed"].as<uint32_t>(115200); uint32_t uartSpeed = uartProtocol["speed"].as<uint32_t>(115200);
port::IModemPort* modemPort = NULL;
std::transform(portType.begin(), portType.end(), portType.begin(), ::tolower); std::transform(portType.begin(), portType.end(), portType.begin(), ::tolower);
if (portType == NULL_PORT) { if (portType == NULL_PORT) {
::LogError(LOG_HOST, "Calibration mode is unsupported with the null modem!"); ::LogError(LOG_HOST, "Calibration mode is unsupported with the null modem!");
@ -246,7 +257,8 @@ int HostCal::run()
break; break;
} }
m_serial = new port::UARTPort(uartPort, serialSpeed, true); modemPort = new port::UARTPort(uartPort, serialSpeed, true);
LogInfo("Modem Parameters");
LogInfo(" UART Port: %s", uartPort.c_str()); LogInfo(" UART Port: %s", uartPort.c_str());
LogInfo(" UART Speed: %u", uartSpeed); LogInfo(" UART Speed: %u", uartSpeed);
} }
@ -255,32 +267,27 @@ int HostCal::run()
return 2; return 2;
} }
if (m_serial == NULL) { if (modemPort == NULL) {
::LogError(LOG_HOST, "Invalid modem port type, %s!", portType.c_str()); ::LogError(LOG_HOST, "Invalid modem port type, %s!", portType.c_str());
return 2; return 2;
} }
getHostVersion(); m_modem = new Modem(modemPort, false, false, false, false, true, false, 80, 7, 4, 10, false, false, false);
::LogInfo(">> Modem Calibration");
// open serial connection to modem DSP and initialize m_modem->setOpenHandler(MODEM_OC_PORT_HANDLER_BIND(HostCal::portModemOpen, this));
ret = m_serial->open(); m_modem->setCloseHandler(MODEM_OC_PORT_HANDLER_BIND(HostCal::portModemClose, this));
if (!ret) { m_modem->setResponseHandler(MODEM_RESP_HANDLER_BIND(HostCal::portModemHandler, this));
::LogError(LOG_CAL, "Failed to open serial device");
return 1;
}
ret = initModem(); // open modem and initialize
ret = m_modem->open();
if (!ret) { if (!ret) {
::LogError(LOG_CAL, "Modem is unresponsive"); ::LogError(LOG_CAL, "Failed to open modem");
m_serial->close();
return 1; return 1;
} }
// open terminal console // open terminal console
ret = m_console.open(); ret = m_console.open();
if (!ret) { if (!ret) {
m_serial->close();
return 1; return 1;
} }
@ -640,7 +647,7 @@ int HostCal::run()
getHostVersion(); getHostVersion();
break; break;
case 'v': case 'v':
getFirmwareVersion(); m_modem->getFirmwareVersion();
break; break;
case 'H': case 'H':
case 'h': case 'h':
@ -667,8 +674,7 @@ int HostCal::run()
break; break;
} }
uint8_t buffer[200U]; m_modem->clock(0U);
readModem(buffer, 200U);
timerClock(); timerClock();
sleep(5U); sleep(5U);
@ -677,7 +683,7 @@ int HostCal::run()
if (m_transmit) if (m_transmit)
setTransmit(); setTransmit();
m_serial->close(); m_modem->close();
m_console.close(); m_console.close();
return 0; return 0;
} }
@ -685,6 +691,155 @@ int HostCal::run()
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Private Class Members // Private Class Members
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <param name="modem"></param>
bool HostCal::portModemOpen(Modem* modem)
{
sleep(2000U);
bool ret = writeConfig();
if (!ret) {
ret = writeConfig();
if (!ret) {
LogError(LOG_MODEM, "Modem unresponsive to configuration set after 2 attempts. Stopping.");
m_modem->close();
return false;
}
}
LogMessage(LOG_MODEM, "Modem Ready [Calibration Mode]");
// handled modem open
return true;
}
/// <summary>
///
/// </summary>
/// <param name="modem"></param>
bool HostCal::portModemClose(Modem* modem)
{
// handled modem close
return true;
}
/// <summary>
///
/// </summary>
/// <param name="modem"></param>
/// <param name="ms"></param>
/// <param name="rspType"></param>
/// <param name="rspDblLen"></param>
/// <param name="data"></param>
/// <param name="len"></param>
/// <returns></returns>
bool HostCal::portModemHandler(Modem* modem, uint32_t ms, RESP_TYPE_DVM rspType, bool rspDblLen, const uint8_t* buffer, uint16_t len)
{
if (rspType == RTM_OK && len > 0) {
switch (buffer[2U]) {
case CMD_CAL_DATA:
{
bool inverted = (buffer[3U] == 0x80U);
short high = buffer[4U] << 8 | buffer[5U];
short low = buffer[6U] << 8 | buffer[7U];
short diff = high - low;
short centre = (high + low) / 2;
LogMessage(LOG_CAL, "Levels: inverted: %s, max: %d, min: %d, diff: %d, centre: %d", inverted ? "yes" : "no", high, low, diff, centre);
}
break;
case CMD_RSSI_DATA:
{
unsigned short max = buffer[3U] << 8 | buffer[4U];
unsigned short min = buffer[5U] << 8 | buffer[6U];
unsigned short ave = buffer[7U] << 8 | buffer[8U];
LogMessage(LOG_CAL, "RSSI: max: %u, min: %u, ave: %u", max, min, ave);
}
break;
case CMD_DMR_DATA1:
case CMD_DMR_DATA2:
processDMRBER(buffer + 4U, buffer[3]);
break;
case CMD_DMR_LOST1:
case CMD_DMR_LOST2:
{
LogMessage(LOG_CAL, "DMR Transmission lost, total frames: %d, bits: %d, uncorrectable frames: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", m_berFrames, m_berBits, m_berUncorrectable, m_berUndecodableLC, m_berErrs, float(m_berErrs * 100U) / float(m_berBits));
if (m_dmrEnabled) {
m_berBits = 0U;
m_berErrs = 0U;
m_berFrames = 0U;
m_berUndecodableLC = 0U;
m_berUncorrectable = 0U;
}
}
break;
case CMD_P25_DATA:
processP25BER(buffer + 3U);
break;
case CMD_P25_LOST:
{
LogMessage(LOG_CAL, "P25 Transmission lost, total frames: %d, bits: %d, uncorrectable frames: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", m_berFrames, m_berBits, m_berUncorrectable, m_berUndecodableLC, m_berErrs, float(m_berErrs * 100U) / float(m_berBits));
if (m_p25Enabled) {
m_berBits = 0U;
m_berErrs = 0U;
m_berFrames = 0U;
m_berUndecodableLC = 0U;
m_berUncorrectable = 0U;
}
}
break;
case CMD_GET_STATUS:
{
uint8_t modemState = buffer[4U];
bool tx = (buffer[5U] & 0x01U) == 0x01U;
bool adcOverflow = (buffer[5U] & 0x02U) == 0x02U;
bool rxOverflow = (buffer[5U] & 0x04U) == 0x04U;
bool txOverflow = (buffer[5U] & 0x08U) == 0x08U;
bool dacOverflow = (buffer[5U] & 0x20U) == 0x20U;
LogMessage(LOG_CAL, " - Diagnostic Values [Modem State: %u, Transmitting: %d, ADC Overflow: %d, Rx Overflow: %d, Tx Overflow: %d, DAC Overflow: %d]",
modemState, tx, adcOverflow, rxOverflow, txOverflow, dacOverflow);
}
break;
case CMD_GET_VERSION:
case CMD_ACK:
break;
case CMD_NAK:
LogWarning(LOG_MODEM, "NAK, command = 0x%02X, reason = %u", buffer[3U], buffer[4U]);
break;
case CMD_DEBUG1:
case CMD_DEBUG2:
case CMD_DEBUG3:
case CMD_DEBUG4:
case CMD_DEBUG5:
case CMD_DEBUG_DUMP:
m_modem->printDebug(buffer, len);
break;
default:
LogWarning(LOG_MODEM, "Unknown message, type = %02X", buffer[2U]);
Utils::dump("Buffer dump", buffer, len);
break;
}
}
// handled modem response
return true;
}
/// <summary> /// <summary>
/// Helper to print the calibration help to the console. /// Helper to print the calibration help to the console.
/// </summary> /// </summary>
@ -946,7 +1101,7 @@ bool HostCal::setTransmit()
buffer[2U] = CMD_CAL_DATA; buffer[2U] = CMD_CAL_DATA;
buffer[3U] = m_transmit ? 0x01U : 0x00U; buffer[3U] = m_transmit ? 0x01U : 0x00U;
int ret = m_serial->write(buffer, 4U); int ret = m_modem->write(buffer, 4U);
if (ret <= 0) if (ret <= 0)
return false; return false;
@ -957,174 +1112,11 @@ bool HostCal::setTransmit()
else else
LogMessage(LOG_CAL, " - Modem stop transmitting"); LogMessage(LOG_CAL, " - Modem stop transmitting");
ret = readModem(buffer, 50U); m_modem->clock(0U);
if (ret <= 0)
return false;
if (buffer[2U] == CMD_NAK) {
LogError(LOG_CAL, "Got a NAK from the modem");
return false;
}
if (buffer[2U] != CMD_ACK) {
Utils::dump("Invalid response", buffer, ret);
return false;
}
return true; return true;
} }
/// <summary>
/// Initializes the modem DSP.
/// </summary>
/// <returns>True, if modem DSP is initialized, otherwise false.</returns>
bool HostCal::initModem()
{
LogMessage(LOG_CAL, " - Initializing modem");
sleep(2000U);
if (!getFirmwareVersion())
return false;
bool ret = writeConfig();
if (!ret) {
ret = writeConfig();
if (!ret) {
LogError(LOG_CAL, "Modem unresponsive to configuration set after 2 attempts, calibration may fail.");
}
}
LogMessage(LOG_CAL, " - Modem Ready");
return true;
}
/// <summary>
/// Read data frames from the modem DSP.
/// </summary>
/// <param name="buffer"></param>
/// <param name="length"></param>
/// <returns>Zero if no data was read, otherwise returns length of data read.</returns>
int HostCal::readModem(uint8_t *buffer, uint32_t length)
{
int n = m_serial->read(buffer + 0U, 1U);
if (n <= 0)
return n;
if (buffer[0U] != DVM_FRAME_START)
return 0;
n = 0;
for (uint32_t i = 0U; i < 20U && n == 0; i++) {
n = m_serial->read(buffer + 1U, 1U);
if (n < 0)
return n;
if (n == 0)
sleep(10U);
}
if (n == 0)
return -1;
uint32_t len = buffer[1U];
uint32_t offset = 2U;
for (uint32_t i = 0U; i < 20U && offset < len; i++) {
n = m_serial->read(buffer + offset, len - offset);
if (n < 0)
return n;
if (n == 0)
sleep(10U);
if (n > 0)
offset += n;
}
if (len > 0) {
switch (buffer[2U]) {
case CMD_CAL_DATA:
{
bool inverted = (buffer[3U] == 0x80U);
short high = buffer[4U] << 8 | buffer[5U];
short low = buffer[6U] << 8 | buffer[7U];
short diff = high - low;
short centre = (high + low) / 2;
LogMessage(LOG_CAL, "Levels: inverted: %s, max: %d, min: %d, diff: %d, centre: %d", inverted ? "yes" : "no", high, low, diff, centre);
}
break;
case CMD_RSSI_DATA:
{
unsigned short max = buffer[3U] << 8 | buffer[4U];
unsigned short min = buffer[5U] << 8 | buffer[6U];
unsigned short ave = buffer[7U] << 8 | buffer[8U];
LogMessage(LOG_CAL, "RSSI: max: %u, min: %u, ave: %u", max, min, ave);
}
break;
case CMD_DMR_DATA1:
case CMD_DMR_DATA2:
processDMRBER(buffer + 4U, buffer[3]);
break;
case CMD_DMR_LOST1:
case CMD_DMR_LOST2:
{
LogMessage(LOG_CAL, "DMR Transmission lost, total frames: %d, bits: %d, uncorrectable frames: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", m_berFrames, m_berBits, m_berUncorrectable, m_berUndecodableLC, m_berErrs, float(m_berErrs * 100U) / float(m_berBits));
if (m_dmrEnabled) {
m_berBits = 0U;
m_berErrs = 0U;
m_berFrames = 0U;
m_berUndecodableLC = 0U;
m_berUncorrectable = 0U;
}
}
break;
case CMD_P25_DATA:
processP25BER(buffer + 3U);
break;
case CMD_P25_LOST:
{
LogMessage(LOG_CAL, "P25 Transmission lost, total frames: %d, bits: %d, uncorrectable frames: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", m_berFrames, m_berBits, m_berUncorrectable, m_berUndecodableLC, m_berErrs, float(m_berErrs * 100U) / float(m_berBits));
if (m_p25Enabled) {
m_berBits = 0U;
m_berErrs = 0U;
m_berFrames = 0U;
m_berUndecodableLC = 0U;
m_berUncorrectable = 0U;
}
}
break;
// These should not be received, but don't complain if we do
case CMD_GET_STATUS:
case CMD_GET_VERSION:
case CMD_ACK:
break;
case CMD_NAK:
LogWarning(LOG_MODEM, "NAK, command = 0x%02X, reason = %u", buffer[3U], buffer[4U]);
break;
case CMD_DEBUG1:
case CMD_DEBUG2:
case CMD_DEBUG3:
case CMD_DEBUG4:
case CMD_DEBUG5:
printDebug(buffer, len);
break;
default:
LogWarning(LOG_MODEM, "Unknown message, type = %02X", buffer[2U]);
Utils::dump("Buffer dump", buffer, len);
break;
}
}
return len;
}
/// <summary> /// <summary>
/// Process DMR Rx BER. /// Process DMR Rx BER.
/// </summary> /// </summary>
@ -1562,74 +1554,6 @@ void HostCal::processP251KBER(const uint8_t* buffer)
} }
} }
/// <summary>
/// Retrieve the modem DSP version.
/// </summary>
/// <returns>True, if firmware version was recieved, otherwise false.</returns>
bool HostCal::getFirmwareVersion()
{
uint8_t buffer[150U];
int ret = 0;
for (uint32_t i = 0U; i < 5U && ret <= 0; i++) {
buffer[0U] = DVM_FRAME_START;
buffer[1U] = 3U;
buffer[2U] = CMD_GET_VERSION;
ret = m_serial->write(buffer, 3U);
if (ret <= 0)
return false;
sleep(100U);
ret = readModem(buffer, 200U);
if (ret < 0)
return false;
if (ret == 0)
sleep(1000U);
}
if (ret <= 0) {
LogError(LOG_CAL, "Unable to read the firmware version after 6 attempts");
return false;
}
int length = ret;
if (buffer[2U] != CMD_GET_VERSION) {
Utils::dump("Invalid response", buffer, ret);
return false;
}
uint8_t protoVer = buffer[3U];
switch (protoVer) {
case PROTOCOL_VERSION:
LogInfoEx(LOG_MODEM, MODEM_VERSION_STR, length - 21U, buffer + 21U, protoVer);
switch (buffer[4U]) {
case 0U:
LogMessage(LOG_MODEM, "Atmel ARM, UDID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", buffer[5U], buffer[6U], buffer[7U], buffer[8U], buffer[9U], buffer[10U], buffer[11U], buffer[12U], buffer[13U], buffer[14U], buffer[15U], buffer[16U], buffer[17U], buffer[18U], buffer[19U], buffer[20U]);
break;
case 1U:
LogMessage(LOG_MODEM, "NXP ARM, UDID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", buffer[5U], buffer[6U], buffer[7U], buffer[8U], buffer[9U], buffer[10U], buffer[11U], buffer[12U], buffer[13U], buffer[14U], buffer[15U], buffer[16U], buffer[17U], buffer[18U], buffer[19U], buffer[20U]);
break;
case 2U:
LogMessage(LOG_MODEM, "ST-Micro ARM, UDID: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", buffer[5U], buffer[6U], buffer[7U], buffer[8U], buffer[9U], buffer[10U], buffer[11U], buffer[12U], buffer[13U], buffer[14U], buffer[15U], buffer[16U]);
break;
default:
LogMessage(LOG_MODEM, "Unknown CPU type: %u", buffer[4U]);
break;
}
return true;
default:
LogError(LOG_MODEM, MODEM_UNSUPPORTED_STR, protoVer);
return false;
}
return true;
}
/// <summary> /// <summary>
/// Write configuration to the modem DSP. /// Write configuration to the modem DSP.
/// </summary> /// </summary>
@ -1710,26 +1634,13 @@ bool HostCal::writeConfig(uint8_t modeOverride)
buffer[14U] = (uint8_t)m_p25CorrCount; buffer[14U] = (uint8_t)m_p25CorrCount;
int ret = m_serial->write(buffer, 17U); int ret = m_modem->write(buffer, 17U);
if (ret <= 0) if (ret <= 0)
return false; return false;
sleep(10U); sleep(10U);
ret = readModem(buffer, 50U); m_modem->clock(0U);
if (ret <= 0)
return false;
if (buffer[2U] == CMD_NAK) {
LogError(LOG_CAL, "Got a NAK from the modem");
return false;
}
if (buffer[2U] != CMD_ACK) {
Utils::dump("Invalid response", buffer, ret);
return false;
}
return true; return true;
} }
@ -1755,26 +1666,13 @@ bool HostCal::writeSymbolAdjust()
m_conf["system"]["modem"]["p25SymLvl1Adj"] = __INT_STR(m_p25SymLevel1Adj); m_conf["system"]["modem"]["p25SymLvl1Adj"] = __INT_STR(m_p25SymLevel1Adj);
buffer[6U] = (uint8_t)(m_p25SymLevel1Adj + 128); buffer[6U] = (uint8_t)(m_p25SymLevel1Adj + 128);
int ret = m_serial->write(buffer, 7U); int ret = m_modem->write(buffer, 7U);
if (ret <= 0) if (ret <= 0)
return false; return false;
sleep(10U); sleep(10U);
ret = readModem(buffer, 50U); m_modem->clock(0U);
if (ret <= 0)
return false;
if (buffer[2U] == CMD_NAK) {
LogError(LOG_CAL, "Got a NAK from the modem");
return false;
}
if (buffer[2U] != CMD_ACK) {
Utils::dump("Invalid response", buffer, ret);
return false;
}
return true; return true;
} }
@ -1851,70 +1749,13 @@ void HostCal::printStatus()
buffer[1U] = 4U; buffer[1U] = 4U;
buffer[2U] = CMD_GET_STATUS; buffer[2U] = CMD_GET_STATUS;
int ret = m_serial->write(buffer, 4U); int ret = m_modem->write(buffer, 4U);
if (ret <= 0) if (ret <= 0)
return; return;
sleep(25U); sleep(25U);
ret = readModem(buffer, 50U); m_modem->clock(0U);
if (ret <= 0)
return;
if (buffer[2U] == CMD_NAK) {
LogError(LOG_CAL, "Got a NAK from the modem");
return;
}
if (buffer[2U] != CMD_GET_STATUS) {
Utils::dump("Invalid response", buffer, ret);
return;
}
uint8_t modemState = buffer[4U];
bool tx = (buffer[5U] & 0x01U) == 0x01U;
bool adcOverflow = (buffer[5U] & 0x02U) == 0x02U;
bool rxOverflow = (buffer[5U] & 0x04U) == 0x04U;
bool txOverflow = (buffer[5U] & 0x08U) == 0x08U;
bool dacOverflow = (buffer[5U] & 0x20U) == 0x20U;
LogMessage(LOG_CAL, " - Diagnostic Values [Modem State: %u, Transmitting: %d, ADC Overflow: %d, Rx Overflow: %d, Tx Overflow: %d, DAC Overflow: %d]",
modemState, tx, adcOverflow, rxOverflow, txOverflow, dacOverflow);
}
/// <summary>
///
/// </summary>
/// <param name="buffer"></param>
/// <param name="length"></param>
void HostCal::printDebug(const uint8_t* buffer, uint32_t length)
{
if (buffer[2U] == CMD_DEBUG1) {
LogMessage(LOG_MODEM, "M: %.*s", length - 3U, buffer + 3U);
}
else if (buffer[2U] == CMD_DEBUG2) {
short val1 = (buffer[length - 2U] << 8) | buffer[length - 1U];
LogMessage(LOG_MODEM, "M: %.*s %X", length - 5U, buffer + 3U, val1);
}
else if (buffer[2U] == CMD_DEBUG3) {
short val1 = (buffer[length - 4U] << 8) | buffer[length - 3U];
short val2 = (buffer[length - 2U] << 8) | buffer[length - 1U];
LogMessage(LOG_MODEM, "M: %.*s %X %X", length - 7U, buffer + 3U, val1, val2);
}
else if (buffer[2U] == CMD_DEBUG4) {
short val1 = (buffer[length - 6U] << 8) | buffer[length - 5U];
short val2 = (buffer[length - 4U] << 8) | buffer[length - 3U];
short val3 = (buffer[length - 2U] << 8) | buffer[length - 1U];
LogMessage(LOG_MODEM, "M: %.*s %X %X %X", length - 9U, buffer + 3U, val1, val2, val3);
}
else if (buffer[2U] == CMD_DEBUG5) {
short val1 = (buffer[length - 8U] << 8) | buffer[length - 7U];
short val2 = (buffer[length - 6U] << 8) | buffer[length - 5U];
short val3 = (buffer[length - 4U] << 8) | buffer[length - 3U];
short val4 = (buffer[length - 2U] << 8) | buffer[length - 1U];
LogMessage(LOG_MODEM, "M: %.*s %X %X %X %X", length - 11U, buffer + 3U, val1, val2, val3, val4);
}
} }
/// <summary> /// <summary>

@ -13,7 +13,7 @@
/* /*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU * Copyright (C) 2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL * Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL
* *
* 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
@ -35,7 +35,6 @@
#include "Defines.h" #include "Defines.h"
#include "edac/AMBEFEC.h" #include "edac/AMBEFEC.h"
#include "modem/Modem.h" #include "modem/Modem.h"
#include "modem/port/UARTPort.h"
#include "host/calibrate/Console.h" #include "host/calibrate/Console.h"
#include "host/Host.h" #include "host/Host.h"
#include "yaml/Yaml.h" #include "yaml/Yaml.h"
@ -61,7 +60,7 @@ private:
const std::string& m_confFile; const std::string& m_confFile;
yaml::Node m_conf; yaml::Node m_conf;
modem::port::UARTPort* m_serial; modem::Modem* m_modem;
Console m_console; Console m_console;
edac::AMBEFEC m_fec; edac::AMBEFEC m_fec;
@ -108,6 +107,13 @@ private:
uint32_t m_timeout; uint32_t m_timeout;
uint32_t m_timer; uint32_t m_timer;
/// <summary></summary>
bool portModemOpen(modem::Modem* modem);
/// <summary></summary>
bool portModemClose(modem::Modem* modem);
/// <summary></summary>
bool portModemHandler(modem::Modem* modem, uint32_t ms, modem::RESP_TYPE_DVM rspType, bool rspDblLen, const uint8_t* buffer, uint16_t len);
/// <summary>Helper to print the calibration help to the console.</summary> /// <summary>Helper to print the calibration help to the console.</summary>
void displayHelp(); void displayHelp();
@ -131,10 +137,6 @@ private:
/// <summary>Helper to change the P25 Symbol Level 1 adjust.</summary> /// <summary>Helper to change the P25 Symbol Level 1 adjust.</summary>
bool setP25SymLevel1Adj(int incr); bool setP25SymLevel1Adj(int incr);
/// <summary>Initializes the modem DSP.</summary>
bool initModem();
/// <summary>Read data frames from the modem DSP.</summary>
int readModem(uint8_t* buffer, uint32_t length);
/// <summary>Process DMR Rx BER.</summary> /// <summary>Process DMR Rx BER.</summary>
void processDMRBER(const uint8_t* buffer, uint8_t seq); void processDMRBER(const uint8_t* buffer, uint8_t seq);
/// <summary>Process DMR Tx 1011hz BER.</summary> /// <summary>Process DMR Tx 1011hz BER.</summary>
@ -143,8 +145,7 @@ private:
void processP25BER(const uint8_t* buffer); void processP25BER(const uint8_t* buffer);
/// <summary>Process P25 Tx 1011hz BER.</summary> /// <summary>Process P25 Tx 1011hz BER.</summary>
void processP251KBER(const uint8_t* buffer); void processP251KBER(const uint8_t* buffer);
/// <summary>Retrieve the modem DSP version.</summary>
bool getFirmwareVersion();
/// <summary>Write configuration to the modem DSP.</summary> /// <summary>Write configuration to the modem DSP.</summary>
bool writeConfig(); bool writeConfig();
/// <summary>Write configuration to the modem DSP.</summary> /// <summary>Write configuration to the modem DSP.</summary>
@ -163,8 +164,6 @@ private:
/// <summary>Prints the current status of the calibration.</summary> /// <summary>Prints the current status of the calibration.</summary>
void printStatus(); void printStatus();
/// <summary></summary>
void printDebug(const uint8_t* buffer, uint32_t length);
/// <summary></summary> /// <summary></summary>
unsigned char countErrs(unsigned char a, unsigned char b); unsigned char countErrs(unsigned char a, unsigned char b);

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2011-2021 by Jonathan Naylor G4KLX * Copyright (C) 2011-2021 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL * Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL
* *
* 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
@ -51,6 +51,18 @@ using namespace modem;
#include <unistd.h> #include <unistd.h>
#endif #endif
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
enum RESP_STATE {
RESP_START,
RESP_LENGTH1,
RESP_LENGTH2,
RESP_TYPE,
RESP_DATA
};
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -74,7 +86,6 @@ using namespace modem;
Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker, Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker,
bool cosLockout, uint8_t fdmaPreamble, uint8_t dmrRxDelay, uint8_t p25CorrCount, uint8_t packetPlayoutTime, bool disableOFlowReset, bool trace, bool debug) : bool cosLockout, uint8_t fdmaPreamble, uint8_t dmrRxDelay, uint8_t p25CorrCount, uint8_t packetPlayoutTime, bool disableOFlowReset, bool trace, bool debug) :
m_port(port), m_port(port),
m_remotePort(NULL),
m_dmrColorCode(0U), m_dmrColorCode(0U),
m_p25NAC(0x293U), m_p25NAC(0x293U),
m_duplex(duplex), m_duplex(duplex),
@ -91,8 +102,6 @@ Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert,
m_dmrTXLevel(0U), m_dmrTXLevel(0U),
m_p25TXLevel(0U), m_p25TXLevel(0U),
m_disableOFlowReset(disableOFlowReset), m_disableOFlowReset(disableOFlowReset),
m_trace(trace),
m_debug(debug),
m_dmrEnabled(false), m_dmrEnabled(false),
m_p25Enabled(false), m_p25Enabled(false),
m_rxDCOffset(0), m_rxDCOffset(0),
@ -106,7 +115,11 @@ Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert,
m_modemState(STATE_IDLE), m_modemState(STATE_IDLE),
m_buffer(NULL), m_buffer(NULL),
m_length(0U), m_length(0U),
m_offset(0U), m_rspDoubleLength(false),
m_rspType(CMD_GET_STATUS),
m_openPortHandler(NULL),
m_closePortHandler(NULL),
m_rspHandler(NULL),
m_rxDMRData1(1000U, "Modem RX DMR1"), m_rxDMRData1(1000U, "Modem RX DMR1"),
m_rxDMRData2(1000U, "Modem RX DMR2"), m_rxDMRData2(1000U, "Modem RX DMR2"),
m_txDMRData1(1000U, "Modem TX DMR1"), m_txDMRData1(1000U, "Modem TX DMR1"),
@ -115,14 +128,16 @@ Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert,
m_txP25Data(1000U, "Modem TX P25"), m_txP25Data(1000U, "Modem TX P25"),
m_statusTimer(1000U, 0U, 250U), m_statusTimer(1000U, 0U, 250U),
m_inactivityTimer(1000U, 4U), m_inactivityTimer(1000U, 4U),
m_playoutTimer(1000U, 0U, packetPlayoutTime),
m_dmrSpace1(0U), m_dmrSpace1(0U),
m_dmrSpace2(0U), m_dmrSpace2(0U),
m_p25Space(0U), m_p25Space(0U),
m_tx(false), m_tx(false),
m_cd(false), m_cd(false),
m_lockout(false), m_lockout(false),
m_error(false) m_error(false),
m_trace(trace),
m_debug(debug),
m_playoutTimer(1000U, 0U, packetPlayoutTime)
{ {
assert(port != NULL); assert(port != NULL);
@ -135,11 +150,6 @@ Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert,
Modem::~Modem() Modem::~Modem()
{ {
delete m_port; delete m_port;
if (m_remotePort != NULL) {
delete m_remotePort;
}
delete[] m_buffer; delete[] m_buffer;
} }
@ -254,7 +264,7 @@ void Modem::setRXLevel(float rxLevel)
// Utils::dump(1U, "Written", buffer, 16U); // Utils::dump(1U, "Written", buffer, 16U);
int ret = m_port->write(buffer, 16U); int ret = write(buffer, 16U);
if (ret != 16) if (ret != 16)
return; return;
@ -281,13 +291,43 @@ void Modem::setRXLevel(float rxLevel)
} }
/// <summary> /// <summary>
/// Sets the slave port for remote operation. /// Sets a custom modem response handler.
/// </summary>
/// <remarks>
/// If the response handler returns true, processing will stop, otherwise it will continue.
/// </remarks>
/// <param name="handler"></param>
void Modem::setResponseHandler(std::function<MODEM_RESP_HANDLER> handler)
{
assert(handler != NULL);
m_rspHandler = handler;
}
/// <summary>
/// Sets a custom modem open port handler.
/// </summary> /// </summary>
void Modem::setSlavePort(port::IModemPort* slavePort) /// <remarks>
/// If the open handler is set, it is the responsibility of the handler to complete air interface
/// initialization (i.e. write configuration, etc).
/// </remarks>
/// <param name="handler"></param>
void Modem::setOpenHandler(std::function<MODEM_OC_PORT_HANDLER> handler)
{ {
assert(slavePort != NULL); assert(handler != NULL);
m_remotePort = slavePort; m_openPortHandler = handler;
}
/// <summary>
/// Sets a custom modem close port handler.
/// </summary>
/// <param name="handler"></param>
void Modem::setCloseHandler(std::function<MODEM_OC_PORT_HANDLER> handler)
{
assert(handler != NULL);
m_closePortHandler = handler;
} }
/// <summary> /// <summary>
@ -313,18 +353,13 @@ bool Modem::open()
m_inactivityTimer.stop(); m_inactivityTimer.stop();
} }
if (m_remotePort != NULL) { // do we have an open port handler?
ret = m_remotePort->open(); if (m_openPortHandler) {
ret = m_openPortHandler(this);
if (!ret) if (!ret)
return false; return false;
m_statusTimer.start();
m_error = false; m_error = false;
m_offset = 0U;
LogMessage(LOG_MODEM, "Modem Ready [Remote Mode]");
m_playoutTimer.start(); m_playoutTimer.start();
return true; return true;
@ -332,9 +367,12 @@ bool Modem::open()
ret = writeConfig(); ret = writeConfig();
if (!ret) { if (!ret) {
LogError(LOG_MODEM, "Modem is unresponsive"); ret = writeConfig();
m_port->close(); if (!ret) {
return false; LogError(LOG_MODEM, "Modem unresponsive to configuration set after 2 attempts. Stopping.");
m_port->close();
return false;
}
} }
writeSymbolAdjust(); writeSymbolAdjust();
@ -342,7 +380,6 @@ bool Modem::open()
m_statusTimer.start(); m_statusTimer.start();
m_error = false; m_error = false;
m_offset = 0U;
LogMessage(LOG_MODEM, "Modem Ready [Direct Mode]"); LogMessage(LOG_MODEM, "Modem Ready [Direct Mode]");
return true; return true;
@ -379,6 +416,15 @@ void Modem::clock(uint32_t ms)
bool forceModemReset = false; bool forceModemReset = false;
RESP_TYPE_DVM type = getResponse(); RESP_TYPE_DVM type = getResponse();
// do we have a custom response handler?
if (m_rspHandler != NULL) {
// execute custom response handler
if (m_rspHandler(this, ms, type, m_rspDoubleLength, m_buffer, m_length)) {
// all logic handled by handler -- return
return;
}
}
if (type == RTM_TIMEOUT) { if (type == RTM_TIMEOUT) {
// Nothing to do // Nothing to do
} }
@ -386,209 +432,225 @@ void Modem::clock(uint32_t ms)
// Nothing to do // Nothing to do
} }
else { else {
if (m_remotePort != NULL) { // type == RTM_OK
switch (m_buffer[2U]) {
/** Digital Mobile Radio */
case CMD_DMR_DATA1:
{
if (m_trace) if (m_trace)
Utils::dump(1U, "TX Remote Data", m_buffer, m_length); Utils::dump(1U, "RX DMR Data 1", m_buffer, m_length);
if (m_rspDoubleLength) {
LogError(LOG_MODEM, "CMD_DMR_DATA1 double length?; len = %u", m_length);
break;
}
uint8_t data = m_length - 2U;
m_rxDMRData1.addData(&data, 1U);
if (m_buffer[3U] == (dmr::DMR_SYNC_DATA | dmr::DT_TERMINATOR_WITH_LC))
data = TAG_EOT;
else
data = TAG_DATA;
m_rxDMRData1.addData(&data, 1U);
// send entire modem packet over the slave port m_rxDMRData1.addData(m_buffer + 3U, m_length - 3U);
m_remotePort->write(m_buffer, m_length);
} }
else { break;
// type == RTM_OK
switch (m_buffer[2U]) { case CMD_DMR_DATA2:
/** Digital Mobile Radio */ {
case CMD_DMR_DATA1: if (m_trace)
{ Utils::dump(1U, "RX DMR Data 2", m_buffer, m_length);
if (m_trace) if (m_rspDoubleLength) {
Utils::dump(1U, "RX DMR Data 1", m_buffer, m_length); LogError(LOG_MODEM, "CMD_DMR_DATA2 double length?; len = %u", m_length);
break;
uint8_t data = m_length - 2U;
m_rxDMRData1.addData(&data, 1U);
if (m_buffer[3U] == (dmr::DMR_SYNC_DATA | dmr::DT_TERMINATOR_WITH_LC))
data = TAG_EOT;
else
data = TAG_DATA;
m_rxDMRData1.addData(&data, 1U);
m_rxDMRData1.addData(m_buffer + 3U, m_length - 3U);
} }
break;
case CMD_DMR_DATA2: uint8_t data = m_length - 2U;
{ m_rxDMRData2.addData(&data, 1U);
if (m_trace)
Utils::dump(1U, "RX DMR Data 2", m_buffer, m_length);
uint8_t data = m_length - 2U; if (m_buffer[3U] == (dmr::DMR_SYNC_DATA | dmr::DT_TERMINATOR_WITH_LC))
m_rxDMRData2.addData(&data, 1U); data = TAG_EOT;
else
data = TAG_DATA;
m_rxDMRData2.addData(&data, 1U);
if (m_buffer[3U] == (dmr::DMR_SYNC_DATA | dmr::DT_TERMINATOR_WITH_LC)) m_rxDMRData2.addData(m_buffer + 3U, m_length - 3U);
data = TAG_EOT; }
else break;
data = TAG_DATA;
m_rxDMRData2.addData(&data, 1U);
m_rxDMRData2.addData(m_buffer + 3U, m_length - 3U); case CMD_DMR_LOST1:
{
if (m_trace)
Utils::dump(1U, "RX DMR Lost 1", m_buffer, m_length);
if (m_rspDoubleLength) {
LogError(LOG_MODEM, "CMD_DMR_LOST1 double length?; len = %u", m_length);
break;
} }
break;
case CMD_DMR_LOST1: uint8_t data = 1U;
{ m_rxDMRData1.addData(&data, 1U);
if (m_trace)
Utils::dump(1U, "RX DMR Lost 1", m_buffer, m_length);
uint8_t data = 1U; data = TAG_LOST;
m_rxDMRData1.addData(&data, 1U); m_rxDMRData1.addData(&data, 1U);
}
break;
data = TAG_LOST; case CMD_DMR_LOST2:
m_rxDMRData1.addData(&data, 1U); {
if (m_trace)
Utils::dump(1U, "RX DMR Lost 2", m_buffer, m_length);
if (m_rspDoubleLength) {
LogError(LOG_MODEM, "CMD_DMR_LOST2 double length?; len = %u", m_length);
break;
} }
break;
case CMD_DMR_LOST2: uint8_t data = 1U;
{ m_rxDMRData2.addData(&data, 1U);
if (m_trace)
Utils::dump(1U, "RX DMR Lost 2", m_buffer, m_length);
uint8_t data = 1U; data = TAG_LOST;
m_rxDMRData2.addData(&data, 1U); m_rxDMRData2.addData(&data, 1U);
}
break;
data = TAG_LOST; /** Project 25 */
m_rxDMRData2.addData(&data, 1U); case CMD_P25_DATA:
{
if (m_trace)
Utils::dump(1U, "RX P25 Data", m_buffer, m_length);
if (m_rspDoubleLength) {
LogError(LOG_MODEM, "CMD_P25_DATA double length?; len = %u", m_length);
break;
} }
break;
/** Project 25 */ uint8_t data = m_length - 2U;
case CMD_P25_DATA: m_rxP25Data.addData(&data, 1U);
{
if (m_trace)
Utils::dump(1U, "RX P25 Data", m_buffer, m_length);
uint8_t data = m_length - 2U; data = TAG_DATA;
m_rxP25Data.addData(&data, 1U); m_rxP25Data.addData(&data, 1U);
data = TAG_DATA; m_rxP25Data.addData(m_buffer + 3U, m_length - 3U);
m_rxP25Data.addData(&data, 1U); }
break;
m_rxP25Data.addData(m_buffer + 3U, m_length - 3U); case CMD_P25_LOST:
{
if (m_trace)
Utils::dump(1U, "RX P25 Lost", m_buffer, m_length);
if (m_rspDoubleLength) {
LogError(LOG_MODEM, "CMD_P25_LOST double length?; len = %u", m_length);
break;
} }
break;
case CMD_P25_LOST: uint8_t data = 1U;
{ m_rxP25Data.addData(&data, 1U);
if (m_trace)
Utils::dump(1U, "RX P25 Lost", m_buffer, m_length);
uint8_t data = 1U; data = TAG_LOST;
m_rxP25Data.addData(&data, 1U); m_rxP25Data.addData(&data, 1U);
}
data = TAG_LOST; break;
m_rxP25Data.addData(&data, 1U);
}
break;
/** General */ /** General */
case CMD_GET_STATUS: case CMD_GET_STATUS:
{ {
// if (m_trace) // if (m_trace)
// Utils::dump(1U, "Get Status", m_buffer, m_length); // Utils::dump(1U, "Get Status", m_buffer, m_length);
m_modemState = (DVM_STATE)m_buffer[4U]; m_modemState = (DVM_STATE)m_buffer[4U];
m_tx = (m_buffer[5U] & 0x01U) == 0x01U; m_tx = (m_buffer[5U] & 0x01U) == 0x01U;
bool adcOverflow = (m_buffer[5U] & 0x02U) == 0x02U; bool adcOverflow = (m_buffer[5U] & 0x02U) == 0x02U;
if (adcOverflow) { if (adcOverflow) {
//LogError(LOG_MODEM, "ADC levels have overflowed"); //LogError(LOG_MODEM, "ADC levels have overflowed");
m_adcOverFlowCount++; m_adcOverFlowCount++;
if (m_adcOverFlowCount >= MAX_ADC_OVERFLOW / 2U) { if (m_adcOverFlowCount >= MAX_ADC_OVERFLOW / 2U) {
LogWarning(LOG_MODEM, "ADC overflow count > %u!", MAX_ADC_OVERFLOW / 2U); LogWarning(LOG_MODEM, "ADC overflow count > %u!", MAX_ADC_OVERFLOW / 2U);
} }
if (!m_disableOFlowReset) { if (!m_disableOFlowReset) {
if (m_adcOverFlowCount > MAX_ADC_OVERFLOW) { if (m_adcOverFlowCount > MAX_ADC_OVERFLOW) {
LogError(LOG_MODEM, "ADC overflow count > %u, resetting modem", MAX_ADC_OVERFLOW); LogError(LOG_MODEM, "ADC overflow count > %u, resetting modem", MAX_ADC_OVERFLOW);
forceModemReset = true; forceModemReset = true;
}
}
else {
m_adcOverFlowCount = 0U;
} }
} }
else { else {
if (m_adcOverFlowCount != 0U) { m_adcOverFlowCount = 0U;
m_adcOverFlowCount--; }
} }
else {
if (m_adcOverFlowCount != 0U) {
m_adcOverFlowCount--;
} }
}
bool rxOverflow = (m_buffer[5U] & 0x04U) == 0x04U; bool rxOverflow = (m_buffer[5U] & 0x04U) == 0x04U;
if (rxOverflow) if (rxOverflow)
LogError(LOG_MODEM, "RX buffer has overflowed"); LogError(LOG_MODEM, "RX buffer has overflowed");
bool txOverflow = (m_buffer[5U] & 0x08U) == 0x08U; bool txOverflow = (m_buffer[5U] & 0x08U) == 0x08U;
if (txOverflow) if (txOverflow)
LogError(LOG_MODEM, "TX buffer has overflowed"); LogError(LOG_MODEM, "TX buffer has overflowed");
m_lockout = (m_buffer[5U] & 0x10U) == 0x10U; m_lockout = (m_buffer[5U] & 0x10U) == 0x10U;
bool dacOverflow = (m_buffer[5U] & 0x20U) == 0x20U; bool dacOverflow = (m_buffer[5U] & 0x20U) == 0x20U;
if (dacOverflow) { if (dacOverflow) {
//LogError(LOG_MODEM, "DAC levels have overflowed"); //LogError(LOG_MODEM, "DAC levels have overflowed");
m_dacOverFlowCount++; m_dacOverFlowCount++;
if (m_dacOverFlowCount > MAX_DAC_OVERFLOW / 2U) { if (m_dacOverFlowCount > MAX_DAC_OVERFLOW / 2U) {
LogWarning(LOG_MODEM, "DAC overflow count > %u!", MAX_DAC_OVERFLOW / 2U); LogWarning(LOG_MODEM, "DAC overflow count > %u!", MAX_DAC_OVERFLOW / 2U);
} }
if (!m_disableOFlowReset) { if (!m_disableOFlowReset) {
if (m_dacOverFlowCount > MAX_DAC_OVERFLOW) { if (m_dacOverFlowCount > MAX_DAC_OVERFLOW) {
LogError(LOG_MODEM, "DAC overflow count > %u, resetting modem", MAX_DAC_OVERFLOW); LogError(LOG_MODEM, "DAC overflow count > %u, resetting modem", MAX_DAC_OVERFLOW);
forceModemReset = true; forceModemReset = true;
}
}
else {
m_dacOverFlowCount = 0U;
} }
} }
else { else {
if (m_dacOverFlowCount != 0U) { m_dacOverFlowCount = 0U;
m_dacOverFlowCount--; }
} }
else {
if (m_dacOverFlowCount != 0U) {
m_dacOverFlowCount--;
} }
}
m_cd = (m_buffer[5U] & 0x40U) == 0x40U; m_cd = (m_buffer[5U] & 0x40U) == 0x40U;
m_dmrSpace1 = m_buffer[7U]; m_dmrSpace1 = m_buffer[7U];
m_dmrSpace2 = m_buffer[8U]; m_dmrSpace2 = m_buffer[8U];
m_p25Space = m_buffer[10U]; m_p25Space = m_buffer[10U];
m_inactivityTimer.start(); m_inactivityTimer.start();
} }
break; break;
case CMD_GET_VERSION: case CMD_GET_VERSION:
case CMD_ACK: case CMD_ACK:
break; break;
case CMD_NAK: case CMD_NAK:
LogWarning(LOG_MODEM, "NAK, command = 0x%02X, reason = %u", m_buffer[3U], m_buffer[4U]); LogWarning(LOG_MODEM, "NAK, command = 0x%02X, reason = %u", m_buffer[3U], m_buffer[4U]);
break; break;
case CMD_DEBUG1: case CMD_DEBUG1:
case CMD_DEBUG2: case CMD_DEBUG2:
case CMD_DEBUG3: case CMD_DEBUG3:
case CMD_DEBUG4: case CMD_DEBUG4:
case CMD_DEBUG5: case CMD_DEBUG5:
printDebug(); case CMD_DEBUG_DUMP:
break; printDebug(m_buffer, m_length);
break;
default: default:
LogWarning(LOG_MODEM, "Unknown message, type = %02X", m_buffer[2U]); LogWarning(LOG_MODEM, "Unknown message, type = %02X", m_buffer[2U]);
Utils::dump("Buffer dump", m_buffer, m_length); Utils::dump("Buffer dump", m_buffer, m_length);
break; break;
}
} }
} }
@ -611,33 +673,6 @@ void Modem::clock(uint32_t ms)
if (!m_playoutTimer.hasExpired()) if (!m_playoutTimer.hasExpired())
return; return;
// read any data from the slave port for the air interface
if (m_remotePort != NULL) {
uint8_t buffer[BUFFER_LENGTH];
::memset(buffer, 0x00U, BUFFER_LENGTH);
uint32_t ret = m_remotePort->read(buffer, BUFFER_LENGTH);
if (ret > 0) {
if (m_trace)
Utils::dump(1U, "RX Remote Data", (uint8_t*)buffer, ret);
if (ret < 3U) {
LogError(LOG_MODEM, "Illegal length of remote data must be >3 bytes");
Utils::dump("Buffer dump", buffer, ret);
return;
}
uint8_t len = buffer[1U];
int ret = m_port->write(buffer, len);
if (ret != int(len))
LogError(LOG_MODEM, "Error writing remote data data");
}
m_playoutTimer.start();
return;
}
// write DMR slot 1 data to air interface // write DMR slot 1 data to air interface
if (m_dmrSpace1 > 1U && !m_txDMRData1.isEmpty()) { if (m_dmrSpace1 > 1U && !m_txDMRData1.isEmpty()) {
uint8_t len = 0U; uint8_t len = 0U;
@ -647,7 +682,7 @@ void Modem::clock(uint32_t ms)
if (m_trace) if (m_trace)
Utils::dump(1U, "TX DMR Data 1", m_buffer, len); Utils::dump(1U, "TX DMR Data 1", m_buffer, len);
int ret = m_port->write(m_buffer, len); int ret = write(m_buffer, len);
if (ret != int(len)) if (ret != int(len))
LogError(LOG_MODEM, "Error writing DMR slot 1 data"); LogError(LOG_MODEM, "Error writing DMR slot 1 data");
@ -665,7 +700,7 @@ void Modem::clock(uint32_t ms)
if (m_trace) if (m_trace)
Utils::dump(1U, "TX DMR Data 2", m_buffer, len); Utils::dump(1U, "TX DMR Data 2", m_buffer, len);
int ret = m_port->write(m_buffer, len); int ret = write(m_buffer, len);
if (ret != int(len)) if (ret != int(len))
LogError(LOG_MODEM, "Error writing DMR slot 2 data"); LogError(LOG_MODEM, "Error writing DMR slot 2 data");
@ -684,7 +719,7 @@ void Modem::clock(uint32_t ms)
Utils::dump(1U, "TX P25 Data", m_buffer, len); Utils::dump(1U, "TX P25 Data", m_buffer, len);
} }
int ret = m_port->write(m_buffer, len); int ret = write(m_buffer, len);
if (ret != int(len)) if (ret != int(len))
LogError(LOG_MODEM, "Error writing P25 data"); LogError(LOG_MODEM, "Error writing P25 data");
@ -702,8 +737,9 @@ void Modem::close()
LogDebug(LOG_MODEM, "Closing the modem"); LogDebug(LOG_MODEM, "Closing the modem");
m_port->close(); m_port->close();
if (m_remotePort != NULL) { // do we have a close port handler?
m_remotePort->close(); if (m_closePortHandler != NULL) {
m_closePortHandler(this);
} }
} }
@ -866,7 +902,7 @@ void Modem::clearP25Data()
// Utils::dump(1U, "Written", buffer, 3U); // Utils::dump(1U, "Written", buffer, 3U);
m_port->write(buffer, 3U); write(buffer, 3U);
} }
} }
@ -1050,7 +1086,7 @@ bool Modem::writeDMRStart(bool tx)
// Utils::dump(1U, "Written", buffer, 4U); // Utils::dump(1U, "Written", buffer, 4U);
return m_port->write(buffer, 4U) == 4; return write(buffer, 4U) == 4;
} }
/// <summary> /// <summary>
@ -1079,7 +1115,7 @@ bool Modem::writeDMRShortLC(const uint8_t* lc)
// Utils::dump(1U, "Written", buffer, 12U); // Utils::dump(1U, "Written", buffer, 12U);
return m_port->write(buffer, 12U) == 12; return write(buffer, 12U) == 12;
} }
/// <summary> /// <summary>
@ -1103,15 +1139,35 @@ bool Modem::writeDMRAbort(uint32_t slotNo)
// Utils::dump(1U, "Written", buffer, 4U); // Utils::dump(1U, "Written", buffer, 4U);
return m_port->write(buffer, 4U) == 4; return write(buffer, 4U) == 4;
} }
/// <summary> /// <summary>
/// Sets the current operating mode for the air interface modem. /// Writes raw data to the air interface modem.
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <returns></returns>
int Modem::write(const uint8_t* data, uint32_t length)
{
return m_port->write(data, length);
}
/// <summary>
/// Gets the current operating state for the air interface modem.
/// </summary>
/// <returns></returns>
DVM_STATE Modem::getState() const
{
return m_modemState;
}
/// <summary>
/// Sets the current operating state for the air interface modem.
/// </summary> /// </summary>
/// <param name="state"></param> /// <param name="state"></param>
/// <returns></returns> /// <returns></returns>
bool Modem::setMode(DVM_STATE state) bool Modem::setState(DVM_STATE state)
{ {
uint8_t buffer[4U]; uint8_t buffer[4U];
@ -1122,7 +1178,7 @@ bool Modem::setMode(DVM_STATE state)
// Utils::dump(1U, "Written", buffer, 4U); // Utils::dump(1U, "Written", buffer, 4U);
return m_port->write(buffer, 4U) == 4; return write(buffer, 4U) == 4;
} }
/// <summary> /// <summary>
@ -1151,7 +1207,7 @@ bool Modem::sendCWId(const std::string& callsign)
Utils::dump(1U, "CW ID Data", buffer, length + 3U); Utils::dump(1U, "CW ID Data", buffer, length + 3U);
} }
return m_port->write(buffer, length + 3U) == int(length + 3U); return write(buffer, length + 3U) == int(length + 3U);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -1174,7 +1230,7 @@ bool Modem::getFirmwareVersion()
// Utils::dump(1U, "F/W Ver Written", buffer, 3U); // Utils::dump(1U, "F/W Ver Written", buffer, 3U);
int ret = m_port->write(buffer, 3U); int ret = write(buffer, 3U);
if (ret != 3) if (ret != 3)
return false; return false;
@ -1235,7 +1291,7 @@ bool Modem::getStatus()
// Utils::dump(1U, "Written", buffer, 3U); // Utils::dump(1U, "Written", buffer, 3U);
return m_port->write(buffer, 3U) == 3; return write(buffer, 3U) == 3;
} }
/// <summary> /// <summary>
@ -1303,7 +1359,7 @@ bool Modem::writeConfig()
// Utils::dump(1U, "Written", buffer, 17U); // Utils::dump(1U, "Written", buffer, 17U);
int ret = m_port->write(buffer, 17U); int ret = write(buffer, 17U);
if (ret != 17) if (ret != 17)
return false; return false;
@ -1352,7 +1408,7 @@ bool Modem::writeSymbolAdjust()
buffer[5U] = (uint8_t)(m_p25SymLevel3Adj + 128); buffer[5U] = (uint8_t)(m_p25SymLevel3Adj + 128);
buffer[6U] = (uint8_t)(m_p25SymLevel1Adj + 128); buffer[6U] = (uint8_t)(m_p25SymLevel1Adj + 128);
int ret = m_port->write(buffer, 7U); int ret = write(buffer, 7U);
if (ret <= 0) if (ret <= 0)
return false; return false;
@ -1386,32 +1442,56 @@ bool Modem::writeSymbolAdjust()
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
void Modem::printDebug() /// <param name="buffer"></param>
/// <param name="len"></param>
void Modem::printDebug(const uint8_t* buffer, uint16_t len)
{ {
if (m_buffer[2U] == CMD_DEBUG1) { if (m_rspDoubleLength && buffer[3U] == CMD_DEBUG_DUMP) {
LogDebug(LOG_MODEM, "M: %.*s", m_length - 3U, m_buffer + 3U); uint8_t data[512U];
::memset(data, 0x00U, 512U);
::memcpy(data, buffer, len);
Utils::dump(1U, "Modem Debug Dump", data, len);
return;
}
else {
if (m_rspDoubleLength) {
LogError(LOG_MODEM, "Invalid debug data received from the modem, len = %u", len);
return;
}
}
if (buffer[2U] == CMD_DEBUG1) {
LogDebug(LOG_MODEM, "M: %.*s", len - 3U, buffer + 3U);
} }
else if (m_buffer[2U] == CMD_DEBUG2) { else if (buffer[2U] == CMD_DEBUG2) {
short val1 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; short val1 = (buffer[len - 2U] << 8) | buffer[len - 1U];
LogDebug(LOG_MODEM, "M: %.*s %X", m_length - 5U, m_buffer + 3U, val1); LogDebug(LOG_MODEM, "M: %.*s %X", len - 5U, buffer + 3U, val1);
} }
else if (m_buffer[2U] == CMD_DEBUG3) { else if (buffer[2U] == CMD_DEBUG3) {
short val1 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; short val1 = (buffer[len - 4U] << 8) | buffer[len - 3U];
short val2 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; short val2 = (buffer[len - 2U] << 8) | buffer[len - 1U];
LogDebug(LOG_MODEM, "M: %.*s %X %X", m_length - 7U, m_buffer + 3U, val1, val2); LogDebug(LOG_MODEM, "M: %.*s %X %X", len - 7U, buffer + 3U, val1, val2);
} }
else if (m_buffer[2U] == CMD_DEBUG4) { else if (buffer[2U] == CMD_DEBUG4) {
short val1 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; short val1 = (buffer[len - 6U] << 8) | buffer[len - 5U];
short val2 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; short val2 = (buffer[len - 4U] << 8) | buffer[len - 3U];
short val3 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; short val3 = (buffer[len - 2U] << 8) | buffer[len - 1U];
LogDebug(LOG_MODEM, "M: %.*s %X %X %X", m_length - 9U, m_buffer + 3U, val1, val2, val3); LogDebug(LOG_MODEM, "M: %.*s %X %X %X", len - 9U, buffer + 3U, val1, val2, val3);
} }
else if (m_buffer[2U] == CMD_DEBUG5) { else if (buffer[2U] == CMD_DEBUG5) {
short val1 = (m_buffer[m_length - 8U] << 8) | m_buffer[m_length - 7U]; short val1 = (buffer[len - 8U] << 8) | buffer[len - 7U];
short val2 = (m_buffer[m_length - 6U] << 8) | m_buffer[m_length - 5U]; short val2 = (buffer[len - 6U] << 8) | buffer[len - 5U];
short val3 = (m_buffer[m_length - 4U] << 8) | m_buffer[m_length - 3U]; short val3 = (buffer[len - 4U] << 8) | buffer[len - 3U];
short val4 = (m_buffer[m_length - 2U] << 8) | m_buffer[m_length - 1U]; short val4 = (buffer[len - 2U] << 8) | buffer[len - 1U];
LogDebug(LOG_MODEM, "M: %.*s %X %X %X %X", m_length - 11U, m_buffer + 3U, val1, val2, val3, val4); LogDebug(LOG_MODEM, "M: %.*s %X %X %X %X", len - 11U, buffer + 3U, val1, val2, val3, val4);
}
else if (buffer[2U] == CMD_DEBUG_DUMP) {
uint8_t data[255U];
::memset(data, 0x00U, 255U);
::memcpy(data, buffer, len);
Utils::dump(1U, "Modem Debug Dump", data, len);
} }
} }
@ -1421,111 +1501,118 @@ void Modem::printDebug()
/// <returns></returns> /// <returns></returns>
RESP_TYPE_DVM Modem::getResponse() RESP_TYPE_DVM Modem::getResponse()
{ {
if (m_offset == 0U) { RESP_STATE state = RESP_START;
// Get the start of the frame or nothing at all uint16_t offset = 0U;
m_rspDoubleLength = false;
// get the start of the frame or nothing at all
if (state == RESP_START) {
int ret = m_port->read(m_buffer + 0U, 1U); int ret = m_port->read(m_buffer + 0U, 1U);
if (ret < 0) { if (ret < 0) {
LogError(LOG_MODEM, "Error reading from the modem, ret = %d", ret); LogError(LOG_MODEM, "Error reading from the modem, ret = %d", ret);
return RTM_ERROR; return RTM_ERROR;
} }
// LogDebug(LOG_MODEM, "ret = %d", ret);
// Utils::dump(1U, "Response 0", m_buffer, 1U);
if (ret == 0) if (ret == 0)
return RTM_TIMEOUT; return RTM_TIMEOUT;
if (m_buffer[0U] != DVM_FRAME_START) if (m_buffer[0U] != DVM_FRAME_START)
return RTM_TIMEOUT; return RTM_TIMEOUT;
m_offset = 1U; // LogDebug(LOG_MODEM, "getResponse(), RESP_START");
state = RESP_LENGTH1;
} }
if (m_offset == 1U) { // get the length of the frame, 1/2
// Get the length of the frame if (state == RESP_LENGTH1) {
int ret = m_port->read(m_buffer + 1U, 1U); int ret = m_port->read(m_buffer + 1U, 1U);
if (ret < 0) { if (ret < 0) {
LogError(LOG_MODEM, "Error reading from the modem, ret = %d", ret); LogError(LOG_MODEM, "Error reading from the modem, ret = %d", ret);
m_offset = 0U;
return RTM_ERROR; return RTM_ERROR;
} }
// LogDebug(LOG_MODEM, "ret = %d", ret);
// Utils::dump(1U, "Response 1", m_buffer + 1U, 1U);
if (ret == 0) if (ret == 0)
return RTM_TIMEOUT; return RTM_TIMEOUT;
if (m_buffer[1U] >= 250U) { if (m_buffer[1U] >= 250U) {
LogError(LOG_MODEM, "Invalid length received from the modem, len = %u", m_buffer[1U]); LogError(LOG_MODEM, "Invalid length received from the modem, len = %u", m_buffer[1U]);
m_offset = 0U;
return RTM_ERROR; return RTM_ERROR;
} }
m_length = m_buffer[1U]; m_length = m_buffer[1U];
m_offset = 2U;
if (m_length == 0U)
state = RESP_LENGTH2;
else
state = RESP_TYPE;
// LogDebug(LOG_MODEM, "getResponse(), RESP_LENGTH1, len = %u", m_length);
m_rspDoubleLength = false;
offset = 2U;
} }
if (m_offset == 2U) { // get the length of the frame, 2/2
// Get the frame type if (state == RESP_LENGTH2) {
int ret = m_port->read(m_buffer + 2U, 1U); int ret = m_port->read(m_buffer + 2U, 1U);
if (ret < 0) { if (ret < 0) {
LogError(LOG_MODEM, "Error reading from the modem, ret = %d", ret); LogError(LOG_MODEM, "Error reading from the modem, ret = %d", ret);
m_offset = 0U;
return RTM_ERROR; return RTM_ERROR;
} }
// LogDebug(LOG_MODEM, "ret = %d", ret);
// Utils::dump(1U, "Response 2", m_buffer + 2U, 1U);
if (ret == 0) if (ret == 0)
return RTM_TIMEOUT; return RTM_TIMEOUT;
m_offset = 3U; m_length = m_buffer[2U] + 255U;
state = RESP_TYPE;
// LogDebug(LOG_MODEM, "getResponse(), RESP_LENGTH2, len = %u", m_length);
m_rspDoubleLength = true;
offset = 3U;
} }
if (m_offset >= 3U) { // get the frame type
// Use later two byte length field if (state == RESP_TYPE) {
if (m_length == 0U) { int ret = m_port->read(m_buffer + offset, 1U);
int ret = m_port->read(m_buffer + 3U, 2U); if (ret < 0) {
if (ret < 0) { LogError(LOG_MODEM, "Error reading from the modem, ret = %d", ret);
LogError(LOG_MODEM, "Error reading from the modem, ret = %d", ret); return RTM_ERROR;
m_offset = 0U; }
return RTM_ERROR;
}
// LogDebug(LOG_MODEM, "ret = %d", ret); if (ret == 0)
// Utils::dump(1U, "Response 3", m_buffer + 3U, 2U); return RTM_TIMEOUT;
if (ret == 0) m_rspType = (DVM_COMMANDS)m_buffer[offset];
return RTM_TIMEOUT;
m_length = (m_buffer[3U] << 8) | m_buffer[4U]; // LogDebug(LOG_MODEM, "getResponse(), RESP_TYPE, len = %u, type = %u", m_length, m_rspType);
m_offset = 5U;
} state = RESP_DATA;
offset++;
}
// get the frame data
if (state == RESP_DATA) {
// LogDebug(LOG_MODEM, "getResponse(), RESP_DATA, len = %u, type = %u", m_length, m_rspType);
while (m_offset < m_length) { while (offset < m_length) {
int ret = m_port->read(m_buffer + m_offset, m_length - m_offset); int ret = m_port->read(m_buffer + offset, m_length - offset);
if (ret < 0) { if (ret < 0) {
LogError(LOG_MODEM, "Error reading from the modem, ret = %d", ret); LogError(LOG_MODEM, "Error reading from the modem, ret = %d", ret);
m_offset = 0U;
return RTM_ERROR; return RTM_ERROR;
} }
// LogDebug(LOG_MODEM, "ret = %d", ret);
// Utils::dump(1U, "Response 4", m_buffer + m_offset, m_length - m_offset);
if (ret == 0) if (ret == 0)
return RTM_TIMEOUT; return RTM_TIMEOUT;
if (ret > 0) if (ret > 0)
m_offset += ret; offset += ret;
} }
}
m_offset = 0U; // Utils::dump(1U, "Modem getResponse()", m_buffer, m_length);
}
// Utils::dump(1U, "Received", m_buffer, m_length);
return RTM_OK; return RTM_OK;
} }

@ -12,7 +12,7 @@
// //
/* /*
* Copyright (C) 2011-2021 by Jonathan Naylor G4KLX * Copyright (C) 2011-2021 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2018 by Bryan Biedenkapp N2PLL * Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL
* *
* 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
@ -37,13 +37,25 @@
#include "Timer.h" #include "Timer.h"
#include <string> #include <string>
#include <functional>
#define MODEM_VERSION_STR "%.*s, Modem protocol: %u" #define MODEM_VERSION_STR "%.*s, Modem protocol: %u"
#define MODEM_UNSUPPORTED_STR "Modem protocol: %u, unsupported! Stopping." #define MODEM_UNSUPPORTED_STR "Modem protocol: %u, unsupported! Stopping."
#define NULL_MODEM "null" #define NULL_MODEM "null"
#define MODEM_OC_PORT_HANDLER bool(modem::Modem* modem)
#define MODEM_OC_PORT_HANDLER_BIND(funcAddr, classInstance) std::bind(&funcAddr, classInstance, std::placeholders::_1)
#define MODEM_RESP_HANDLER bool(modem::Modem* modem, uint32_t ms, modem::RESP_TYPE_DVM rspType, bool rspDblLen, const uint8_t* buffer, uint16_t len)
#define MODEM_RESP_HANDLER_BIND(funcAddr, classInstance) std::bind(&funcAddr, classInstance, std::placeholders::_1, std::placeholders::_2, \
std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6)
const uint8_t PROTOCOL_VERSION = 2U; const uint8_t PROTOCOL_VERSION = 2U;
// ---------------------------------------------------------------------------
// Class Prototypes
// ---------------------------------------------------------------------------
class HOST_SW_API HostCal;
namespace modem namespace modem
{ {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -124,6 +136,7 @@ namespace modem
CMD_DEBUG3 = 0xF3U, CMD_DEBUG3 = 0xF3U,
CMD_DEBUG4 = 0xF4U, CMD_DEBUG4 = 0xF4U,
CMD_DEBUG5 = 0xF5U, CMD_DEBUG5 = 0xF5U,
CMD_DEBUG_DUMP = 0xFAU,
}; };
enum CMD_REASON_CODE { enum CMD_REASON_CODE {
@ -185,8 +198,16 @@ namespace modem
void setP25NAC(uint32_t nac); void setP25NAC(uint32_t nac);
/// <summary>Sets the RF receive deviation levels.</summary> /// <summary>Sets the RF receive deviation levels.</summary>
void setRXLevel(float rxLevel); void setRXLevel(float rxLevel);
/// <summary>Sets the slave port for remote operation.</summary>
void setSlavePort(port::IModemPort* slavePort); /// <summary>Sets a custom modem response handler.</summary>
/// <remarks>If the response handler returns true, processing will stop, otherwise it will continue.</remarks>
void setResponseHandler(std::function<MODEM_RESP_HANDLER> handler);
/// <summary>Sets a custom modem open port handler.</summary>
/// <remarks>If the open handler is set, it is the responsibility of the handler to complete air interface
/// initialization (i.e. write configuration, etc).</remarks>
void setOpenHandler(std::function<MODEM_OC_PORT_HANDLER> handler);
/// <summary>Sets a custom modem close port handler.</summary>
void setCloseHandler(std::function<MODEM_OC_PORT_HANDLER> handler);
/// <summary>Opens connection to the air interface modem.</summary> /// <summary>Opens connection to the air interface modem.</summary>
bool open(); bool open();
@ -249,17 +270,21 @@ namespace modem
/// <summary>Writes a DMR abort message for the given slot to the air interface modem.</summary> /// <summary>Writes a DMR abort message for the given slot to the air interface modem.</summary>
bool writeDMRAbort(uint32_t slotNo); bool writeDMRAbort(uint32_t slotNo);
/// <summary>Gets the current operating mode for the air interface modem.</summary> /// <summary>Writes raw data to the air interface modem.</summary>
DVM_STATE getMode() const; int write(const uint8_t* data, uint32_t length);
/// <summary>Sets the current operating mode for the air interface modem.</summary>
bool setMode(DVM_STATE state); /// <summary>Gets the current operating state for the air interface modem.</summary>
DVM_STATE getState() const;
/// <summary>Sets the current operating state for the air interface modem.</summary>
bool setState(DVM_STATE state);
/// <summary>Transmits the given string as CW morse.</summary> /// <summary>Transmits the given string as CW morse.</summary>
bool sendCWId(const std::string& callsign); bool sendCWId(const std::string& callsign);
private: private:
friend class ::HostCal;
port::IModemPort* m_port; port::IModemPort* m_port;
port::IModemPort* m_remotePort;
uint32_t m_dmrColorCode; uint32_t m_dmrColorCode;
uint32_t m_p25NAC; uint32_t m_p25NAC;
@ -283,8 +308,6 @@ namespace modem
float m_p25TXLevel; float m_p25TXLevel;
bool m_disableOFlowReset; bool m_disableOFlowReset;
bool m_trace;
bool m_debug;
bool m_dmrEnabled; bool m_dmrEnabled;
bool m_p25Enabled; bool m_p25Enabled;
@ -302,8 +325,13 @@ namespace modem
DVM_STATE m_modemState; DVM_STATE m_modemState;
uint8_t* m_buffer; uint8_t* m_buffer;
uint32_t m_length; uint16_t m_length;
uint32_t m_offset; bool m_rspDoubleLength;
DVM_COMMANDS m_rspType;
std::function<MODEM_OC_PORT_HANDLER> m_openPortHandler;
std::function<MODEM_OC_PORT_HANDLER> m_closePortHandler;
std::function<MODEM_RESP_HANDLER> m_rspHandler;
RingBuffer<uint8_t> m_rxDMRData1; RingBuffer<uint8_t> m_rxDMRData1;
RingBuffer<uint8_t> m_rxDMRData2; RingBuffer<uint8_t> m_rxDMRData2;
@ -314,7 +342,6 @@ namespace modem
Timer m_statusTimer; Timer m_statusTimer;
Timer m_inactivityTimer; Timer m_inactivityTimer;
Timer m_playoutTimer;
uint32_t m_dmrSpace1; uint32_t m_dmrSpace1;
uint32_t m_dmrSpace2; uint32_t m_dmrSpace2;
@ -335,10 +362,19 @@ namespace modem
bool writeSymbolAdjust(); bool writeSymbolAdjust();
/// <summary></summary> /// <summary></summary>
void printDebug(); void printDebug(const uint8_t* buffer, uint16_t len);
/// <summary></summary> /// <summary></summary>
RESP_TYPE_DVM getResponse(); RESP_TYPE_DVM getResponse();
public:
/// <summary>Flag indicating if modem trace is enabled.</summary>
__READONLY_PROPERTY(bool, trace, Trace);
/// <summary>Flag indicating if modem debugging is enabled.</summary>
__READONLY_PROPERTY(bool, debug, Debug);
/// <summary></summary>
__READONLY_PROPERTY(Timer, playoutTimer, PlayoutTimer);
}; };
} // namespace modem } // namespace modem

@ -65,6 +65,7 @@ using namespace modem::port;
/// <param name="speed">Serial port speed.</param> /// <param name="speed">Serial port speed.</param>
/// <param name="assertRTS"></param> /// <param name="assertRTS"></param>
UARTPort::UARTPort(const std::string& device, SERIAL_SPEED speed, bool assertRTS) : UARTPort::UARTPort(const std::string& device, SERIAL_SPEED speed, bool assertRTS) :
m_isOpen(false),
m_device(device), m_device(device),
m_speed(speed), m_speed(speed),
m_assertRTS(assertRTS), m_assertRTS(assertRTS),
@ -87,6 +88,9 @@ UARTPort::~UARTPort()
/// <returns>True, if connection is opened, otherwise false.</returns> /// <returns>True, if connection is opened, otherwise false.</returns>
bool UARTPort::open() bool UARTPort::open()
{ {
if (m_isOpen)
return true;
assert(m_handle == INVALID_HANDLE_VALUE); assert(m_handle == INVALID_HANDLE_VALUE);
DWORD errCode; DWORD errCode;
@ -163,6 +167,7 @@ bool UARTPort::open()
::ClearCommError(m_handle, &errCode, NULL); ::ClearCommError(m_handle, &errCode, NULL);
m_isOpen = true;
return true; return true;
} }
@ -231,6 +236,9 @@ int UARTPort::write(const uint8_t* buffer, uint32_t length)
/// </summary> /// </summary>
void UARTPort::close() void UARTPort::close()
{ {
if (!m_isOpen)
return;
assert(m_handle != INVALID_HANDLE_VALUE); assert(m_handle != INVALID_HANDLE_VALUE);
::CloseHandle(m_handle); ::CloseHandle(m_handle);
@ -246,6 +254,7 @@ void UARTPort::close()
/// <param name="speed">Serial port speed.</param> /// <param name="speed">Serial port speed.</param>
/// <param name="assertRTS"></param> /// <param name="assertRTS"></param>
UARTPort::UARTPort(const std::string& device, SERIAL_SPEED speed, bool assertRTS) : UARTPort::UARTPort(const std::string& device, SERIAL_SPEED speed, bool assertRTS) :
m_isOpen(false),
m_device(device), m_device(device),
m_speed(speed), m_speed(speed),
m_assertRTS(assertRTS), m_assertRTS(assertRTS),
@ -267,6 +276,9 @@ UARTPort::~UARTPort()
/// <returns>True, if connection is opened, otherwise false.</returns> /// <returns>True, if connection is opened, otherwise false.</returns>
bool UARTPort::open() bool UARTPort::open()
{ {
if (m_isOpen)
return true;
assert(m_fd == -1); assert(m_fd == -1);
#if defined(__APPLE__) #if defined(__APPLE__)
@ -279,9 +291,106 @@ bool UARTPort::open()
return false; return false;
} }
if (::isatty(m_fd)) if (::isatty(m_fd) == 0) {
return setRaw(); LogError(LOG_HOST, "%s is not a TTY device", m_device.c_str());
::close(m_fd);
return false;
}
termios termios;
if (::tcgetattr(m_fd, &termios) < 0) {
::LogError(LOG_HOST, "Cannot get the attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
termios.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK);
termios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL);
termios.c_iflag &= ~(IXON | IXOFF | IXANY);
termios.c_oflag &= ~(OPOST);
termios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS);
termios.c_cflag |= (CS8 | CLOCAL | CREAD);
termios.c_lflag &= ~(ISIG | ICANON | IEXTEN);
termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
#if defined(__APPLE__)
termios.c_cc[VMIN] = 1;
termios.c_cc[VTIME] = 1;
#else
termios.c_cc[VMIN] = 0;
termios.c_cc[VTIME] = 10;
#endif
switch (m_speed) {
case SERIAL_1200:
::cfsetospeed(&termios, B1200);
::cfsetispeed(&termios, B1200);
break;
case SERIAL_2400:
::cfsetospeed(&termios, B2400);
::cfsetispeed(&termios, B2400);
break;
case SERIAL_4800:
::cfsetospeed(&termios, B4800);
::cfsetispeed(&termios, B4800);
break;
case SERIAL_9600:
::cfsetospeed(&termios, B9600);
::cfsetispeed(&termios, B9600);
break;
case SERIAL_19200:
::cfsetospeed(&termios, B19200);
::cfsetispeed(&termios, B19200);
break;
case SERIAL_38400:
::cfsetospeed(&termios, B38400);
::cfsetispeed(&termios, B38400);
break;
case SERIAL_115200:
::cfsetospeed(&termios, B115200);
::cfsetispeed(&termios, B115200);
break;
case SERIAL_230400:
::cfsetospeed(&termios, B230400);
::cfsetispeed(&termios, B230400);
break;
case SERIAL_460800:
::cfsetospeed(&termios, B460800);
::cfsetispeed(&termios, B460800);
break;
default:
::LogError(LOG_HOST, "Unsupported serial port speed - %u", m_speed);
::close(m_fd);
return false;
}
if (::tcsetattr(m_fd, TCSANOW, &termios) < 0) {
::LogError(LOG_HOST, "Cannot set the attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
if (m_assertRTS) {
uint32_t y;
if (::ioctl(m_fd, TIOCMGET, &y) < 0) {
::LogError(LOG_HOST, "Cannot get the control attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
y |= TIOCM_RTS;
if (::ioctl(m_fd, TIOCMSET, &y) < 0) {
::LogError(LOG_HOST, "Cannot set the control attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
}
#if defined(__APPLE__)
setNonblock(false);
#endif
m_isOpen = true;
return true; return true;
} }
@ -378,6 +487,9 @@ int UARTPort::write(const uint8_t* buffer, uint32_t length)
/// </summary> /// </summary>
void UARTPort::close() void UARTPort::close()
{ {
if (!m_isOpen)
return;
assert(m_fd != -1); assert(m_fd != -1);
::close(m_fd); ::close(m_fd);
@ -408,20 +520,6 @@ int UARTPort::setNonblock(bool nonblock)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
/// <summary>
/// Initializes a new instance of the UARTPort class.
/// </summary>
/// <param name="speed">Serial port speed.</param>
/// <param name="assertRTS"></param>
UARTPort::UARTPort(SERIAL_SPEED speed, bool assertRTS) :
m_device(),
m_speed(speed),
m_assertRTS(assertRTS),
m_handle(INVALID_HANDLE_VALUE)
{
/* stub */
}
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@ -462,20 +560,6 @@ int UARTPort::readNonblock(uint8_t* buffer, uint32_t length)
#else #else
/// <summary>
/// Initializes a new instance of the UARTPort class.
/// </summary>
/// <param name="speed">Serial port speed.</param>
/// <param name="assertRTS"></param>
UARTPort::UARTPort(SERIAL_SPEED speed, bool assertRTS) :
m_device(),
m_speed(speed),
m_assertRTS(assertRTS),
m_fd(-1)
{
/* stub */
}
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@ -500,106 +584,4 @@ bool UARTPort::canWrite()
return true; return true;
#endif #endif
} }
/// <summary>
///
/// </summary>
/// <returns></returns>
bool UARTPort::setRaw()
{
termios termios;
if (::tcgetattr(m_fd, &termios) < 0) {
::LogError(LOG_HOST, "Cannot get the attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
termios.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK);
termios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL);
termios.c_iflag &= ~(IXON | IXOFF | IXANY);
termios.c_oflag &= ~(OPOST);
termios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS);
termios.c_cflag |= (CS8 | CLOCAL | CREAD);
termios.c_lflag &= ~(ISIG | ICANON | IEXTEN);
termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
#if defined(__APPLE__)
termios.c_cc[VMIN] = 1;
termios.c_cc[VTIME] = 1;
#else
termios.c_cc[VMIN] = 0;
termios.c_cc[VTIME] = 10;
#endif
switch (m_speed) {
case SERIAL_1200:
::cfsetospeed(&termios, B1200);
::cfsetispeed(&termios, B1200);
break;
case SERIAL_2400:
::cfsetospeed(&termios, B2400);
::cfsetispeed(&termios, B2400);
break;
case SERIAL_4800:
::cfsetospeed(&termios, B4800);
::cfsetispeed(&termios, B4800);
break;
case SERIAL_9600:
::cfsetospeed(&termios, B9600);
::cfsetispeed(&termios, B9600);
break;
case SERIAL_19200:
::cfsetospeed(&termios, B19200);
::cfsetispeed(&termios, B19200);
break;
case SERIAL_38400:
::cfsetospeed(&termios, B38400);
::cfsetispeed(&termios, B38400);
break;
case SERIAL_115200:
::cfsetospeed(&termios, B115200);
::cfsetispeed(&termios, B115200);
break;
case SERIAL_230400:
::cfsetospeed(&termios, B230400);
::cfsetispeed(&termios, B230400);
break;
case SERIAL_460800:
::cfsetospeed(&termios, B460800);
::cfsetispeed(&termios, B460800);
break;
default:
::LogError(LOG_HOST, "Unsupported serial port speed - %u", m_speed);
::close(m_fd);
return false;
}
if (::tcsetattr(m_fd, TCSANOW, &termios) < 0) {
::LogError(LOG_HOST, "Cannot set the attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
if (m_assertRTS) {
uint32_t y;
if (::ioctl(m_fd, TIOCMGET, &y) < 0) {
::LogError(LOG_HOST, "Cannot get the control attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
y |= TIOCM_RTS;
if (::ioctl(m_fd, TIOCMSET, &y) < 0) {
::LogError(LOG_HOST, "Cannot set the control attributes for %s", m_device.c_str());
::close(m_fd);
return false;
}
}
#if defined(__APPLE__)
setNonblock(false);
#endif
return true;
}
#endif #endif

@ -94,8 +94,7 @@ namespace modem
#endif #endif
protected: protected:
/// <summary>Initializes a new instance of the UARTPort class.</summary> bool m_isOpen;
UARTPort(SERIAL_SPEED speed, bool assertRTS = false);
std::string m_device; std::string m_device;
SERIAL_SPEED m_speed; SERIAL_SPEED m_speed;
@ -112,8 +111,6 @@ namespace modem
#else #else
/// <summary></summary> /// <summary></summary>
bool canWrite(); bool canWrite();
/// <summary></summary>
bool setRaw();
#endif #endif
}; // class HOST_SW_API UARTPort : public ISerialPort, public IModemPort }; // class HOST_SW_API UARTPort : public ISerialPort, public IModemPort
} // namespace port } // namespace port

@ -230,19 +230,19 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25)
// Command is in the form of: "mode <mode>" // Command is in the form of: "mode <mode>"
if (mode == RCD_MODE_OPT_IDLE) { if (mode == RCD_MODE_OPT_IDLE) {
host->m_fixedMode = false; host->m_fixedMode = false;
host->setMode(STATE_IDLE); host->setState(STATE_IDLE);
LogInfoEx(LOG_RCON, "Dynamic mode, mode %u", host->m_mode); LogInfoEx(LOG_RCON, "Dynamic mode, mode %u", host->m_state);
} }
else if (mode == RCD_MODE_OPT_LCKOUT) { else if (mode == RCD_MODE_OPT_LCKOUT) {
host->m_fixedMode = false; host->m_fixedMode = false;
host->setMode(HOST_STATE_LOCKOUT); host->setState(HOST_STATE_LOCKOUT);
LogInfoEx(LOG_RCON, "Lockout mode, mode %u", host->m_mode); LogInfoEx(LOG_RCON, "Lockout mode, mode %u", host->m_state);
} }
else if (mode == RCD_MODE_OPT_FDMR) { else if (mode == RCD_MODE_OPT_FDMR) {
if (dmr != NULL) { if (dmr != NULL) {
host->m_fixedMode = true; host->m_fixedMode = true;
host->setMode(STATE_DMR); host->setState(STATE_DMR);
LogInfoEx(LOG_RCON, "Fixed mode, mode %u", host->m_mode); LogInfoEx(LOG_RCON, "Fixed mode, mode %u", host->m_state);
} }
else { else {
LogError(LOG_RCON, CMD_FAILED_STR "DMR mode is not enabled!"); LogError(LOG_RCON, CMD_FAILED_STR "DMR mode is not enabled!");
@ -251,8 +251,8 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25)
else if (mode == RCD_MODE_OPT_FP25) { else if (mode == RCD_MODE_OPT_FP25) {
if (p25 != NULL) { if (p25 != NULL) {
host->m_fixedMode = true; host->m_fixedMode = true;
host->setMode(STATE_P25); host->setState(STATE_P25);
LogInfoEx(LOG_RCON, "Fixed mode, mode %u", host->m_mode); LogInfoEx(LOG_RCON, "Fixed mode, mode %u", host->m_state);
} }
else { else {
LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!"); LogError(LOG_RCON, CMD_FAILED_STR "P25 mode is not enabled!");
@ -262,7 +262,7 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25)
else if (rcom == RCD_KILL_CMD) { else if (rcom == RCD_KILL_CMD) {
// Command is in the form of: "kill" // Command is in the form of: "kill"
g_killed = true; g_killed = true;
host->setMode(HOST_STATE_QUIT); host->setState(HOST_STATE_QUIT);
} }
else if (rcom == RCD_RID_WLIST_CMD && argCnt >= 1U) { else if (rcom == RCD_RID_WLIST_CMD && argCnt >= 1U) {
// Command is in the form of: "rid-whitelist <RID>" // Command is in the form of: "rid-whitelist <RID>"

Loading…
Cancel
Save

Powered by TurnKey Linux.