diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 007e860..e06f8a7 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -25,7 +25,7 @@ #include "DMRControl.h" #include "TFTSerial.h" #include "NullDisplay.h" -#include "YSFEcho.h" +#include "YSFControl.h" #include @@ -166,9 +166,18 @@ int CMMDVMHost::run() dmr = new CDMRControl(id, colorCode, timeout, m_modem, m_dmrNetwork, m_display, duplex); } - CYSFEcho* ysf = NULL; - if (m_ysfEnabled) - ysf = new CYSFEcho(2U, 10000U); + CYSFControl* ysf = NULL; + if (m_ysfEnabled) { + std::string callsign = m_conf.getCallsign(); + unsigned int timeout = m_conf.getTimeout(); + bool duplex = m_conf.getDuplex(); + + LogInfo("System Fusion Parameters"); + LogInfo(" Callsign: %s", callsign.c_str()); + LogInfo(" Timeout: %us", timeout); + + ysf = new CYSFControl(callsign, m_display, timeout, duplex); + } m_modeTimer.setTimeout(m_conf.getModeHang()); @@ -226,11 +235,11 @@ int CMMDVMHost::run() len = m_modem->readYSFData(data); if (ysf != NULL && len > 0U) { if (m_mode == MODE_IDLE) { - bool ret = ysf->writeData(data, len); + bool ret = ysf->writeModem(data); if (ret) setMode(MODE_YSF); } else if (m_mode == MODE_YSF) { - ysf->writeData(data, len); + ysf->writeModem(data); m_modeTimer.start(); } else { LogWarning("System Fusion modem data received when in mode %u", m_mode); @@ -294,7 +303,7 @@ int CMMDVMHost::run() if (ysf != NULL) { ret = m_modem->hasYSFSpace(); if (ret) { - len = ysf->readData(data); + len = ysf->readModem(data); if (len > 0U) { if (m_mode == MODE_IDLE) { setMode(MODE_YSF); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 0536a41..e296006 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -189,9 +189,9 @@ + - @@ -233,8 +233,8 @@ + - diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 4f018f7..14741f9 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -95,9 +95,6 @@ Header Files - - Header Files - Header Files @@ -152,6 +149,9 @@ Header Files + + Header Files + @@ -223,9 +223,6 @@ Source Files - - Source Files - Source Files @@ -277,5 +274,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index 6e1b4fd..38be0ab 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ LDFLAGS = -g OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLC.o DMRShortLC.o \ DMRSlot.o DMRSlotType.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o Golay24128.o Hamming.o Log.o MMDVMHost.o Modem.o NullDisplay.o \ - QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFConvolution.o YSFEcho.o YSFFICH.o + QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o all: MMDVMHost diff --git a/YSFControl.cpp b/YSFControl.cpp new file mode 100644 index 0000000..ce9b2f7 --- /dev/null +++ b/YSFControl.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "YSFControl.h" +#include "Utils.h" +#include "Sync.h" +#include "Log.h" + +#include +#include + +// #define DUMP_YSF + +CYSFControl::CYSFControl(const std::string& callsign, IDisplay* display, unsigned int timeout, bool duplex) : +m_display(display), +m_duplex(duplex), +m_queue(1000U, "YSF Control"), +m_state(RS_LISTENING), +m_timeoutTimer(1000U, timeout), +m_frames(0U), +m_fp(NULL) +{ + assert(display != NULL); +} + +CYSFControl::~CYSFControl() +{ +} + +bool CYSFControl::writeModem(unsigned char *data) +{ + unsigned char type = data[0U]; + + if (type == TAG_LOST && m_state == RS_RELAYING_RF_AUDIO) { + LogMessage("YSF, transmission lost, %.1f seconds", float(m_frames) / 10.0F); + writeEndOfTransmission(); + return false; + } + + if (type == TAG_LOST) + return false; + + bool valid = (data[1U] & YSF_CKSUM_OK) == YSF_CKSUM_OK; + unsigned char fi = data[1U] & YSF_FI_MASK; + unsigned char dt = data[1U] & YSF_DT_MASK; + + if (valid && m_state == RS_LISTENING) { + m_frames = 0U; + m_timeoutTimer.start(); + m_state = RS_RELAYING_RF_AUDIO; + LogMessage("YSF, received RF header"); + } + + if (fi == YSF_DT_TERMINATOR_CHANNEL) { + if (m_state == RS_RELAYING_RF_AUDIO) { + CSync::addYSFSync(data + 2U); + + m_frames++; + + if (m_duplex) { + data[0U] = TAG_DATA; + data[1U] = 0x00U; + writeQueue(data); + } + + LogMessage("YSF, received RF end of transmission, %.1f seconds", float(m_frames) / 10.0F); + + writeEndOfTransmission(); + } + + return false; + } else { + CSync::addYSFSync(data + 2U); + + m_frames++; + + if (m_duplex) { + data[0U] = TAG_DATA; + data[1U] = 0x00U; + writeQueue(data); + } + } + + return true; +} + +unsigned int CYSFControl::readModem(unsigned char* data) +{ + if (m_queue.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_queue.getData(&len, 1U); + + m_queue.getData(data, len); + + return len; +} + +void CYSFControl::writeEndOfTransmission() +{ + m_state = RS_LISTENING; + + m_timeoutTimer.stop(); + + m_display->clearFusion(); + +#if defined(DUMP_YSF) + closeFile(); +#endif +} + +void CYSFControl::clock(unsigned int ms) +{ + m_timeoutTimer.clock(ms); +} + +void CYSFControl::writeQueue(const unsigned char *data) +{ + assert(data != NULL); + + if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) + return; + + unsigned char len = YSF_FRAME_LENGTH_BYTES + 2U; + m_queue.addData(&len, 1U); + + m_queue.addData(data, len); +} + +bool CYSFControl::openFile() +{ + if (m_fp != NULL) + return true; + + time_t t; + ::time(&t); + + struct tm* tm = ::localtime(&t); + + char name[100U]; + ::sprintf(name, "YSF_%04d%02d%02d_%02d%02d%02d.ambe", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + + m_fp = ::fopen(name, "wb"); + if (m_fp == NULL) + return false; + + ::fwrite("YSF", 1U, 3U, m_fp); + + return true; +} + +bool CYSFControl::writeFile(const unsigned char* data) +{ + if (m_fp == NULL) + return false; + + ::fwrite(data, 1U, YSF_FRAME_LENGTH_BYTES, m_fp); + + return true; +} + +void CYSFControl::closeFile() +{ + if (m_fp != NULL) { + ::fclose(m_fp); + m_fp = NULL; + } +} diff --git a/YSFControl.h b/YSFControl.h new file mode 100644 index 0000000..2f838d7 --- /dev/null +++ b/YSFControl.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if !defined(YSFControl_H) +#define YSFControl_H + +#include "YSFDefines.h" +#include "RingBuffer.h" +#include "Display.h" +#include "Defines.h" +#include "Timer.h" +#include "Modem.h" + +#include + +class CYSFControl { +public: + CYSFControl(const std::string& callsign, IDisplay* display, unsigned int timeout, bool duplex); + ~CYSFControl(); + + bool writeModem(unsigned char* data); + + unsigned int readModem(unsigned char* data); + + void clock(unsigned int ms); + +private: + IDisplay* m_display; + bool m_duplex; + CRingBuffer m_queue; + RPT_STATE m_state; + CTimer m_timeoutTimer; + unsigned int m_frames; + FILE* m_fp; + + void writeQueue(const unsigned char* data); + + void writeEndOfTransmission(); + + bool openFile(); + bool writeFile(const unsigned char* data); + void closeFile(); +}; + +#endif diff --git a/YSFDefines.h b/YSFDefines.h index d1bed14..c9d4969 100644 --- a/YSFDefines.h +++ b/YSFDefines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +27,7 @@ const unsigned int YSF_SYNC_LENGTH_BYTES = 5U; const unsigned char YSF_FI_MASK = 0xC0U; const unsigned char YSF_DT_MASK = 0x30U; +const unsigned char YSF_DT_HEADER_CHANNEL = 0x00U; const unsigned char YSF_DT_TERMINATOR_CHANNEL = 0x80U; const unsigned char YSF_CKSUM_OK = 0x01U; diff --git a/YSFEcho.cpp b/YSFEcho.cpp deleted file mode 100644 index 858d699..0000000 --- a/YSFEcho.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2015 by Jonathan Naylor G4KLX - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "YSFEcho.h" - -#include "YSFDefines.h" - -CYSFEcho::CYSFEcho(unsigned int delay, unsigned int space) : -m_buffer(space, "YSF Echo"), -m_timer(1000U, delay) -{ -} - -CYSFEcho::~CYSFEcho() -{ -} - -unsigned int CYSFEcho::readData(unsigned char* data) -{ - if (!hasData()) - return 0U; - - unsigned char len; - m_buffer.getData(&len, 1U); - - m_buffer.getData(data, len); - - // If the FICH is valid, regenerate the sync - if ((data[1U] & 0x01U) == 0x01U) { - data[2U] = YSF_SYNC_BYTES[0U]; - data[3U] = YSF_SYNC_BYTES[1U]; - data[4U] = YSF_SYNC_BYTES[2U]; - data[5U] = YSF_SYNC_BYTES[3U]; - data[6U] = YSF_SYNC_BYTES[4U]; - } - - if (!hasData()) - m_timer.stop(); - - return len; -} - -bool CYSFEcho::writeData(const unsigned char* data, unsigned int length) -{ - bool ret = m_buffer.hasSpace(length + 1U); - if (!ret) - return false; - - unsigned char len = length; - m_buffer.addData(&len, 1U); - - m_buffer.addData(data, length); - - m_timer.start(); - - return true; -} - -bool CYSFEcho::hasData() -{ - if (m_timer.isRunning() && m_timer.hasExpired()) - return m_buffer.hasData(); - else - return false; -} - -void CYSFEcho::clock(unsigned int ms) -{ - m_timer.clock(ms); -} diff --git a/YSFEcho.h b/YSFEcho.h deleted file mode 100644 index 3218a6e..0000000 --- a/YSFEcho.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2015 by Jonathan Naylor G4KLX - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if !defined(YSFECHO_H) -#define YSFECHO_H - -#include "RingBuffer.h" -#include "Timer.h" - -class CYSFEcho { -public: - CYSFEcho(unsigned int delay, unsigned int space); - ~CYSFEcho(); - - unsigned int readData(unsigned char* data); - - bool writeData(const unsigned char* data, unsigned int length); - - bool hasData(); - - void clock(unsigned int ms); - -private: - CRingBuffer m_buffer; - CTimer m_timer; -}; - -#endif