First go at System Fusion networking.

This commit is contained in:
Jonathan Naylor
2016-05-16 21:57:32 +01:00
parent 1d5ed691c4
commit 9ed2c00b0c
25 changed files with 571 additions and 171 deletions

View File

@@ -24,16 +24,21 @@
// #define DUMP_YSF
CYSFControl::CYSFControl(const std::string& callsign, CDisplay* display, unsigned int timeout, bool duplex) :
CYSFControl::CYSFControl(const std::string& callsign, CYSFNetwork* network, CDisplay* display, unsigned int timeout, bool duplex) :
m_network(network),
m_display(display),
m_duplex(duplex),
m_queue(5000U, "YSF Control"),
m_state(RS_RF_LISTENING),
m_timeoutTimer(1000U, timeout),
m_interval(),
m_frames(0U),
m_errs(0U),
m_bits(0U),
m_rfState(RS_RF_LISTENING),
m_netState(RS_NET_IDLE),
m_rfTimeoutTimer(1000U, timeout),
m_netTimeoutTimer(1000U, timeout),
m_networkWatchdog(1000U, 0U, 1500U),
m_holdoffTimer(1000U, 0U, 500U),
m_rfFrames(0U),
m_netFrames(0U),
m_rfErrs(0U),
m_rfBits(0U),
m_source(NULL),
m_dest(NULL),
m_payload(),
@@ -43,8 +48,6 @@ m_fp(NULL)
m_payload.setUplink(callsign);
m_payload.setDownlink(callsign);
m_interval.start();
}
CYSFControl::~CYSFControl()
@@ -57,11 +60,9 @@ bool CYSFControl::writeModem(unsigned char *data)
unsigned char type = data[0U];
if (type == TAG_LOST && m_state == RS_RF_AUDIO) {
LogMessage("YSF, transmission lost, %.1f seconds, BER: %.1f%%", float(m_frames) / 10.0F, float(m_errs * 100U) / float(m_bits));
// if (m_parrot != NULL)
// m_parrot->end();
writeEndOfTransmission();
if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) {
LogMessage("YSF, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits));
writeEndRF();
return false;
}
@@ -71,51 +72,45 @@ bool CYSFControl::writeModem(unsigned char *data)
CYSFFICH fich;
bool valid = fich.decode(data + 2U);
if (valid && m_state == RS_RF_LISTENING) {
if (valid && m_rfState == RS_RF_LISTENING) {
unsigned char fi = fich.getFI();
if (fi == YSF_FI_TERMINATOR)
return false;
m_frames = 0U;
m_errs = 0U;
m_bits = 1U;
m_timeoutTimer.start();
m_rfFrames = 0U;
m_rfErrs = 0U;
m_rfBits = 1U;
m_rfTimeoutTimer.start();
m_holdoffTimer.stop();
m_payload.reset();
m_state = RS_RF_AUDIO;
m_rfState = RS_RF_AUDIO;
#if defined(DUMP_YSF)
openFile();
#endif
}
if (m_state != RS_RF_AUDIO)
if (m_rfState != RS_RF_AUDIO)
return false;
unsigned char fi = fich.getFI();
if (valid && fi == YSF_FI_HEADER) {
CSync::addYSFSync(data + 2U);
m_frames++;
m_rfFrames++;
valid = m_payload.processHeaderData(data + 2U);
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeNetwork(data);
if (m_duplex) {
fich.setMR(YSF_MR_BUSY);
fich.encode(data + 2U);
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeQueue(data);
writeQueueRF(data);
}
// if (m_parrot != NULL) {
// fich.setMR(YSF_MR_NOT_BUSY);
// fich.encode(data + 2U);
//
// data[0U] = TAG_DATA;
// data[1U] = 0x00U;
// writeParrot(data);
// }
if (valid)
m_source = m_payload.getSource();
@@ -131,45 +126,43 @@ bool CYSFControl::writeModem(unsigned char *data)
writeFile(data + 2U);
#endif
if (m_source != NULL && m_dest != NULL)
LogMessage("YSF, received header from %10.10s to %10.10s", m_source, m_dest);
else if (m_source == NULL && m_dest != NULL)
LogMessage("YSF, received header from ?????????? to %10.10s", m_dest);
else if (m_source != NULL && m_dest == NULL)
LogMessage("YSF, received header from %10.10s to ??????????", m_source);
else
LogMessage("YSF, received header from ?????????? to ??????????");
if (m_source != NULL && m_dest != NULL) {
m_display->writeFusion((char*)m_source, (char*)m_dest, "R");
LogMessage("YSF, received RF header from %10.10s to %10.10s", m_source, m_dest);
} else if (m_source == NULL && m_dest != NULL) {
m_display->writeFusion("??????????", (char*)m_dest, "R");
LogMessage("YSF, received RF header from ?????????? to %10.10s", m_dest);
} else if (m_source != NULL && m_dest == NULL) {
m_display->writeFusion((char*)m_source, "??????????", "R");
LogMessage("YSF, received RF header from %10.10s to ??????????", m_source);
} else {
m_display->writeFusion("??????????", "??????????", "R");
LogMessage("YSF, received RF header from ?????????? to ??????????");
}
} else if (valid && fi == YSF_FI_TERMINATOR) {
CSync::addYSFSync(data + 2U);
m_frames++;
m_rfFrames++;
m_payload.processHeaderData(data + 2U);
data[0U] = TAG_EOT;
data[1U] = 0x00U;
writeNetwork(data);
if (m_duplex) {
fich.setMR(YSF_MR_BUSY);
fich.encode(data + 2U);
data[0U] = TAG_EOT;
data[1U] = 0x00U;
writeQueue(data);
writeQueueRF(data);
}
// if (m_parrot != NULL) {
// fich.setMR(YSF_MR_NOT_BUSY);
// fich.encode(data + 2U);
//
// data[0U] = TAG_EOT;
// data[1U] = 0x00U;
// writeParrot(data);
// }
#if defined(DUMP_YSF)
writeFile(data + 2U);
#endif
LogMessage("YSF, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_frames) / 10.0F, float(m_errs * 100U) / float(m_bits));
writeEndOfTransmission();
LogMessage("YSF, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits));
writeEndRF();
return false;
} else if (valid) {
@@ -179,19 +172,19 @@ bool CYSFControl::writeModem(unsigned char *data)
unsigned char ft = fich.getFT();
unsigned char dt = fich.getDT();
m_frames++;
m_rfFrames++;
switch (dt) {
case YSF_DT_VD_MODE1:
valid = m_payload.processVDMode1Data(data + 2U, fn);
m_errs += m_payload.processVDMode1Audio(data + 2U);
m_bits += 235U;
m_rfErrs += m_payload.processVDMode1Audio(data + 2U);
m_rfBits += 235U;
break;
case YSF_DT_VD_MODE2:
valid = m_payload.processVDMode2Data(data + 2U, fn);
m_errs += m_payload.processVDMode2Audio(data + 2U);
m_bits += 135U;
m_rfErrs += m_payload.processVDMode2Audio(data + 2U);
m_rfBits += 135U;
break;
case YSF_DT_DATA_FR_MODE:
@@ -201,8 +194,8 @@ bool CYSFControl::writeModem(unsigned char *data)
case YSF_DT_VOICE_FR_MODE:
if (fn != 0U || ft != 1U) {
// The first packet after the header is odd, don't try and regenerate it
m_errs += m_payload.processVoiceFRModeAudio(data + 2U);
m_bits += 720U;
m_rfErrs += m_payload.processVoiceFRModeAudio(data + 2U);
m_rfBits += 720U;
}
valid = false;
break;
@@ -233,56 +226,45 @@ bool CYSFControl::writeModem(unsigned char *data)
if (change) {
if (m_source != NULL && m_dest != NULL) {
m_display->writeFusion((char*)m_source, (char*)m_dest);
LogMessage("YSF, received transmission from %10.10s to %10.10s", m_source, m_dest);
m_display->writeFusion((char*)m_source, (char*)m_dest, "R");
LogMessage("YSF, received RF data from %10.10s to %10.10s", m_source, m_dest);
}
if (m_source != NULL && m_dest == NULL) {
m_display->writeFusion((char*)m_source, "??????????");
LogMessage("YSF, received transmission from %10.10s to ??????????", m_source);
m_display->writeFusion((char*)m_source, "??????????", "R");
LogMessage("YSF, received RF data from %10.10s to ??????????", m_source);
}
if (m_source == NULL && m_dest != NULL) {
m_display->writeFusion("??????????", (char*)m_dest);
LogMessage("YSF, received transmission from ?????????? to %10.10s", m_dest);
m_display->writeFusion("??????????", (char*)m_dest, "R");
LogMessage("YSF, received RF data from ?????????? to %10.10s", m_dest);
}
}
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeNetwork(data);
if (m_duplex) {
fich.setMR(YSF_MR_BUSY);
fich.encode(data + 2U);
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeQueue(data);
writeQueueRF(data);
}
// if (m_parrot != NULL) {
// fich.setMR(YSF_MR_NOT_BUSY);
// fich.encode(data + 2U);
//
// data[0U] = TAG_DATA;
// data[1U] = 0x00U;
// writeParrot(data);
// }
#if defined(DUMP_YSF)
writeFile(data + 2U);
#endif
} else {
CSync::addYSFSync(data + 2U);
m_frames++;
m_rfFrames++;
if (m_duplex) {
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeQueue(data);
}
data[0U] = TAG_DATA;
data[1U] = 0x00U;
// if (m_parrot != NULL) {
// data[0U] = TAG_DATA;
// data[1U] = 0x00U;
// writeParrot(data);
// }
writeNetwork(data);
if (m_duplex)
writeQueueRF(data);
#if defined(DUMP_YSF)
writeFile(data + 2U);
@@ -299,6 +281,10 @@ unsigned int CYSFControl::readModem(unsigned char* data)
if (m_queue.isEmpty())
return 0U;
// Don't relay data until the timer has stopped.
if (m_holdoffTimer.isRunning())
return 0U;
unsigned char len = 0U;
m_queue.getData(&len, 1U);
@@ -307,51 +293,103 @@ unsigned int CYSFControl::readModem(unsigned char* data)
return len;
}
void CYSFControl::writeEndOfTransmission()
void CYSFControl::writeEndRF()
{
m_state = RS_RF_LISTENING;
m_rfState = RS_RF_LISTENING;
m_timeoutTimer.stop();
if (m_netState == RS_NET_IDLE) {
m_payload.reset();
m_payload.reset();
m_display->clearFusion();
m_display->clearFusion();
if (m_network != NULL)
m_network->reset();
// These variables are free'd by YSFPayload
m_source = NULL;
m_dest = NULL;
// These variables are free'd by YSFPayload
m_source = NULL;
m_dest = NULL;
} else {
m_rfTimeoutTimer.stop();
}
#if defined(DUMP_YSF)
closeFile();
#endif
}
void CYSFControl::clock()
void CYSFControl::writeEndNet()
{
unsigned int ms = m_interval.elapsed();
m_interval.start();
m_netState = RS_NET_IDLE;
m_timeoutTimer.clock(ms);
m_netTimeoutTimer.stop();
m_networkWatchdog.stop();
// if (m_parrot != NULL) {
// m_parrot->clock(ms);
//
// unsigned int space = m_queue.freeSpace();
// bool hasData = m_parrot->hasData();
//
// if (space > (YSF_FRAME_LENGTH_BYTES + 2U) && hasData) {
// unsigned char data[YSF_FRAME_LENGTH_BYTES + 2U];
// m_parrot->read(data);
// writeQueue(data);
// }
// }
m_display->clearFusion();
if (m_network != NULL)
m_network->reset();
}
void CYSFControl::writeQueue(const unsigned char *data)
void CYSFControl::writeNetwork()
{
unsigned char data[200U];
unsigned int length = m_network->read(data);
if (length == 0U)
return;
if (m_rfState != RS_RF_LISTENING && m_netState == RS_NET_IDLE)
return;
m_networkWatchdog.start();
if (!m_netTimeoutTimer.isRunning()) {
m_display->writeFusion("??????????", "??????????", "N");
LogMessage("YSF, received network data from ?????????? to ??????????");
m_netTimeoutTimer.start();
m_netState = RS_NET_AUDIO;
m_netFrames = 0U;
}
m_netFrames++;
writeQueueNet(data);
if (data[0U] == TAG_EOT) {
LogMessage("YSF, received network end of transmission, %.1f seconds", float(m_netFrames) / 10.0F);
writeEndNet();
}
}
void CYSFControl::clock(unsigned int ms)
{
if (m_network != NULL)
writeNetwork();
m_holdoffTimer.clock(ms);
if (m_holdoffTimer.isRunning() && m_holdoffTimer.hasExpired())
m_holdoffTimer.stop();
m_rfTimeoutTimer.clock(ms);
m_netTimeoutTimer.clock(ms);
if (m_netState == RS_NET_AUDIO) {
m_networkWatchdog.clock(ms);
if (m_networkWatchdog.hasExpired()) {
LogMessage("YSF, network watchdog has expired, %.1f seconds", float(m_netFrames) / 10.0F);
writeEndNet();
}
}
}
void CYSFControl::writeQueueRF(const unsigned char *data)
{
assert(data != NULL);
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired())
if (m_netState != RS_NET_IDLE)
return;
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
return;
unsigned char len = YSF_FRAME_LENGTH_BYTES + 2U;
@@ -367,18 +405,38 @@ void CYSFControl::writeQueue(const unsigned char *data)
m_queue.addData(data, len);
}
// void CYSFControl::writeParrot(const unsigned char *data)
// {
// assert(data != NULL);
//
// if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired())
// return;
//
// m_parrot->write(data);
//
// if (data[0U] == TAG_EOT)
// m_parrot->end();
// }
void CYSFControl::writeQueueNet(const unsigned char *data)
{
assert(data != NULL);
if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired())
return;
unsigned char len = YSF_FRAME_LENGTH_BYTES + 2U;
unsigned int space = m_queue.freeSpace();
if (space < (len + 1U)) {
LogError("YSF, overflow in the System Fusion RF queue");
return;
}
m_queue.addData(&len, 1U);
m_queue.addData(data, len);
}
void CYSFControl::writeNetwork(const unsigned char *data)
{
assert(data != NULL);
if (m_network == NULL)
return;
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
return;
m_network->write(m_source, m_dest, data + 2U, data[0U] == TAG_EOT);
}
bool CYSFControl::openFile()
{