2016-02-16 07:27:13 +00:00
/*
* 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"
2016-04-21 17:00:26 +00:00
# include "YSFFICH.h"
2016-02-16 07:27:13 +00:00
# include "Utils.h"
# include "Sync.h"
# include "Log.h"
2016-03-07 20:21:55 +00:00
# include <cstdio>
2016-02-16 07:27:13 +00:00
# include <cassert>
2016-04-21 17:00:26 +00:00
# include <cstring>
2016-02-16 07:27:13 +00:00
# include <ctime>
// #define DUMP_YSF
2016-05-16 20:57:32 +00:00
CYSFControl : : CYSFControl ( const std : : string & callsign , CYSFNetwork * network , CDisplay * display , unsigned int timeout , bool duplex ) :
m_network ( network ) ,
2016-02-16 07:27:13 +00:00
m_display ( display ) ,
m_duplex ( duplex ) ,
2016-05-10 17:54:35 +00:00
m_queue ( 5000U , " YSF Control " ) ,
2016-05-16 20:57:32 +00:00
m_rfState ( RS_RF_LISTENING ) ,
m_netState ( RS_NET_IDLE ) ,
m_rfTimeoutTimer ( 1000U , timeout ) ,
m_netTimeoutTimer ( 1000U , timeout ) ,
2016-07-12 17:20:48 +00:00
m_packetTimer ( 1000U , 0U , 200U ) ,
2016-05-16 20:57:32 +00:00
m_networkWatchdog ( 1000U , 0U , 1500U ) ,
2016-07-12 17:20:48 +00:00
m_elapsed ( ) ,
2016-05-16 20:57:32 +00:00
m_rfFrames ( 0U ) ,
m_netFrames ( 0U ) ,
2016-07-12 17:20:48 +00:00
m_netLost ( 0U ) ,
2016-05-16 20:57:32 +00:00
m_rfErrs ( 0U ) ,
2016-05-25 06:51:42 +00:00
m_rfBits ( 1U ) ,
m_netErrs ( 0U ) ,
m_netBits ( 1U ) ,
2016-05-19 18:08:48 +00:00
m_rfSource ( NULL ) ,
m_rfDest ( NULL ) ,
m_netSource ( NULL ) ,
m_netDest ( NULL ) ,
2016-07-12 17:20:48 +00:00
m_lastFrame ( NULL ) ,
2016-07-12 17:39:49 +00:00
m_lastMode ( YSF_DT_VOICE_FR_MODE ) ,
2016-07-12 17:20:48 +00:00
m_netN ( 0U ) ,
2016-05-23 20:45:52 +00:00
m_rfPayload ( ) ,
m_netPayload ( ) ,
2016-02-16 07:27:13 +00:00
m_fp ( NULL )
{
assert ( display ! = NULL ) ;
2016-02-22 21:13:48 +00:00
2016-05-23 20:45:52 +00:00
m_rfPayload . setUplink ( callsign ) ;
m_rfPayload . setDownlink ( callsign ) ;
m_netPayload . setDownlink ( callsign ) ;
2016-05-19 18:08:48 +00:00
m_netSource = new unsigned char [ YSF_CALLSIGN_LENGTH ] ;
m_netDest = new unsigned char [ YSF_CALLSIGN_LENGTH ] ;
2016-07-12 17:20:48 +00:00
m_lastFrame = new unsigned char [ YSF_FRAME_LENGTH_BYTES + 2U ] ;
2016-02-16 07:27:13 +00:00
}
CYSFControl : : ~ CYSFControl ( )
{
2016-05-19 18:08:48 +00:00
delete [ ] m_netSource ;
delete [ ] m_netDest ;
2016-07-12 17:20:48 +00:00
delete [ ] m_lastFrame ;
2016-02-16 07:27:13 +00:00
}
bool CYSFControl : : writeModem ( unsigned char * data )
{
2016-03-07 20:21:55 +00:00
assert ( data ! = NULL ) ;
2016-02-16 07:27:13 +00:00
unsigned char type = data [ 0U ] ;
2016-05-16 20:57:32 +00:00
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 ( ) ;
2016-02-16 07:27:13 +00:00
return false ;
}
if ( type = = TAG_LOST )
return false ;
2016-04-21 17:00:26 +00:00
CYSFFICH fich ;
bool valid = fich . decode ( data + 2U ) ;
2016-04-12 20:33:16 +00:00
2016-05-16 20:57:32 +00:00
if ( valid & & m_rfState = = RS_RF_LISTENING ) {
2016-04-21 17:00:26 +00:00
unsigned char fi = fich . getFI ( ) ;
2016-04-12 20:33:16 +00:00
if ( fi = = YSF_FI_TERMINATOR )
return false ;
2016-02-16 07:27:13 +00:00
2016-05-16 20:57:32 +00:00
m_rfFrames = 0U ;
m_rfErrs = 0U ;
m_rfBits = 1U ;
m_rfTimeoutTimer . start ( ) ;
2016-05-23 20:45:52 +00:00
m_rfPayload . reset ( ) ;
2016-05-16 20:57:32 +00:00
m_rfState = RS_RF_AUDIO ;
2016-02-16 17:37:12 +00:00
# if defined(DUMP_YSF)
openFile ( ) ;
# endif
2016-02-16 07:27:13 +00:00
}
2016-05-16 20:57:32 +00:00
if ( m_rfState ! = RS_RF_AUDIO )
2016-02-16 07:57:46 +00:00
return false ;
2016-02-16 07:27:13 +00:00
2016-04-21 17:00:26 +00:00
unsigned char fi = fich . getFI ( ) ;
if ( valid & & fi = = YSF_FI_HEADER ) {
2016-02-16 07:57:46 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2016-02-16 07:27:13 +00:00
2016-05-23 20:45:52 +00:00
// LogDebug("YSF, FICH: FI: %u, DT: %u, FN: %u, FT: %u", fich.getFI(), fich.getDT(), fich.getFN(), fich.getFT());
valid = m_rfPayload . processHeaderData ( data + 2U ) ;
2016-04-25 17:06:19 +00:00
2016-04-21 17:00:26 +00:00
if ( valid )
2016-05-23 20:45:52 +00:00
m_rfSource = m_rfPayload . getSource ( ) ;
2016-04-21 17:00:26 +00:00
2016-05-10 19:17:57 +00:00
unsigned char cm = fich . getCM ( ) ;
2016-04-21 17:00:26 +00:00
if ( cm = = YSF_CM_GROUP ) {
2016-05-19 18:08:48 +00:00
m_rfDest = ( unsigned char * ) " ALL " ;
2016-04-21 17:00:26 +00:00
} else {
if ( valid )
2016-05-23 20:45:52 +00:00
m_rfDest = m_rfPayload . getDest ( ) ;
2016-04-21 17:00:26 +00:00
}
2016-05-19 18:08:48 +00:00
if ( m_rfSource ! = NULL & & m_rfDest ! = NULL ) {
2016-05-20 05:15:42 +00:00
m_display - > writeFusion ( ( char * ) m_rfSource , ( char * ) m_rfDest , " R " , " " ) ;
2016-05-19 18:08:48 +00:00
LogMessage ( " YSF, received RF header from %10.10s to %10.10s " , m_rfSource , m_rfDest ) ;
} else if ( m_rfSource = = NULL & & m_rfDest ! = NULL ) {
2016-05-20 05:15:42 +00:00
m_display - > writeFusion ( " ?????????? " , ( char * ) m_rfDest , " R " , " " ) ;
2016-05-19 18:08:48 +00:00
LogMessage ( " YSF, received RF header from ?????????? to %10.10s " , m_rfDest ) ;
} else if ( m_rfSource ! = NULL & & m_rfDest = = NULL ) {
2016-05-20 05:15:42 +00:00
m_display - > writeFusion ( ( char * ) m_rfSource , " ?????????? " , " R " , " " ) ;
2016-05-19 18:08:48 +00:00
LogMessage ( " YSF, received RF header from %10.10s to ?????????? " , m_rfSource ) ;
} else {
2016-05-20 05:15:42 +00:00
m_display - > writeFusion ( " ?????????? " , " ?????????? " , " R " , " " ) ;
2016-05-19 18:08:48 +00:00
LogMessage ( " YSF, received RF header from ?????????? to ?????????? " ) ;
}
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-06-13 20:29:19 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
2016-05-19 18:08:48 +00:00
2016-04-21 17:00:26 +00:00
# if defined(DUMP_YSF)
writeFile ( data + 2U ) ;
# endif
2016-05-19 18:08:48 +00:00
if ( m_duplex ) {
fich . setMR ( YSF_MR_BUSY ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
2016-05-16 20:57:32 +00:00
}
2016-06-13 20:29:19 +00:00
m_rfFrames + + ;
2016-04-21 17:00:26 +00:00
} else if ( valid & & fi = = YSF_FI_TERMINATOR ) {
CSync : : addYSFSync ( data + 2U ) ;
2016-05-23 20:45:52 +00:00
// LogDebug("YSF, FICH: FI: %u, DT: %u, FN: %u, FT: %u", fich.getFI(), fich.getDT(), fich.getFN(), fich.getFT());
m_rfPayload . processHeaderData ( data + 2U ) ;
2016-04-25 17:06:19 +00:00
2016-05-16 20:57:32 +00:00
data [ 0U ] = TAG_EOT ;
data [ 1U ] = 0x00U ;
2016-06-13 20:29:19 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
2016-05-16 20:57:32 +00:00
2016-05-19 18:08:48 +00:00
# if defined(DUMP_YSF)
writeFile ( data + 2U ) ;
# endif
2016-02-16 07:57:46 +00:00
if ( m_duplex ) {
2016-04-21 17:00:26 +00:00
fich . setMR ( YSF_MR_BUSY ) ;
fich . encode ( data + 2U ) ;
2016-05-16 20:57:32 +00:00
writeQueueRF ( data ) ;
2016-02-16 07:27:13 +00:00
}
2016-06-13 20:29:19 +00:00
m_rfFrames + + ;
2016-05-16 20:57:32 +00:00
LogMessage ( " YSF, received RF end of transmission, %.1f seconds, BER: %.1f%% " , float ( m_rfFrames ) / 10.0F , float ( m_rfErrs * 100U ) / float ( m_rfBits ) ) ;
writeEndRF ( ) ;
2016-02-16 07:57:46 +00:00
2016-02-16 07:27:13 +00:00
return false ;
2016-04-21 17:00:26 +00:00
} else if ( valid ) {
2016-02-16 07:27:13 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2016-07-05 16:51:16 +00:00
unsigned char bn = fich . getBN ( ) ;
unsigned char bt = fich . getBT ( ) ;
2016-04-21 17:00:26 +00:00
unsigned char fn = fich . getFN ( ) ;
unsigned char ft = fich . getFT ( ) ;
unsigned char dt = fich . getDT ( ) ;
2016-04-20 06:29:09 +00:00
2016-05-23 20:45:52 +00:00
// LogDebug("YSF, FICH: FI: %u, DT: %u, FN: %u, FT: %u", fich.getFI(), fich.getDT(), fich.getFN(), fich.getFT());
2016-04-25 17:06:19 +00:00
switch ( dt ) {
2016-06-16 16:33:53 +00:00
case YSF_DT_VD_MODE1 : {
valid = m_rfPayload . processVDMode1Data ( data + 2U , fn ) ;
unsigned int errors = m_rfPayload . processVDMode1Audio ( data + 2U ) ;
m_rfErrs + = errors ;
m_rfBits + = 235U ;
LogDebug ( " YSF, V/D Mode 1, seq %u, AMBE FEC %u/235 (%.1f%%) " , m_rfFrames % 128 , errors , float ( errors ) / 2.35F ) ;
}
2016-04-25 17:06:19 +00:00
break ;
2016-06-16 16:33:53 +00:00
case YSF_DT_VD_MODE2 : {
valid = m_rfPayload . processVDMode2Data ( data + 2U , fn ) ;
unsigned int errors = m_rfPayload . processVDMode2Audio ( data + 2U ) ;
m_rfErrs + = errors ;
m_rfBits + = 135U ;
LogDebug ( " YSF, V/D Mode 2, seq %u, Repetition FEC %u/135 (%.1f%%) " , m_rfFrames % 128 , errors , float ( errors ) / 1.35F ) ;
}
2016-04-25 17:06:19 +00:00
break ;
case YSF_DT_DATA_FR_MODE :
2016-07-05 16:51:16 +00:00
LogDebug ( " YSF, RF data FICH B=%u/%u F=%u/%u " , bn , bt , fn , ft ) ;
2016-05-23 20:45:52 +00:00
valid = m_rfPayload . processDataFRModeData ( data + 2U , fn ) ;
2016-04-25 17:06:19 +00:00
break ;
2016-05-10 18:24:27 +00:00
case YSF_DT_VOICE_FR_MODE :
2016-04-25 19:10:03 +00:00
if ( fn ! = 0U | | ft ! = 1U ) {
2016-04-25 17:06:19 +00:00
// The first packet after the header is odd, don't try and regenerate it
2016-06-16 16:33:53 +00:00
unsigned int errors = m_rfPayload . processVoiceFRModeAudio ( data + 2U ) ;
m_rfErrs + = errors ;
2016-05-16 20:57:32 +00:00
m_rfBits + = 720U ;
2016-06-16 16:33:53 +00:00
LogDebug ( " YSF, V Mode 3, seq %u, AMBE FEC %u/720 (%.1f%%) " , m_rfFrames % 128 , errors , float ( errors ) / 7.2F ) ;
2016-04-25 17:06:19 +00:00
}
2016-04-26 05:24:48 +00:00
valid = false ;
2016-04-25 17:06:19 +00:00
break ;
2016-05-10 18:24:27 +00:00
default :
break ;
2016-04-25 17:06:19 +00:00
}
2016-04-21 17:00:26 +00:00
bool change = false ;
2016-02-29 22:43:26 +00:00
2016-05-19 18:08:48 +00:00
if ( m_rfDest = = NULL ) {
2016-05-10 19:17:57 +00:00
unsigned char cm = fich . getCM ( ) ;
2016-04-21 17:00:26 +00:00
if ( cm = = YSF_CM_GROUP ) {
2016-05-19 18:08:48 +00:00
m_rfDest = ( unsigned char * ) " ALL " ;
2016-04-21 17:00:26 +00:00
change = true ;
2016-04-25 19:10:03 +00:00
} else if ( valid ) {
2016-05-23 20:45:52 +00:00
m_rfDest = m_rfPayload . getDest ( ) ;
2016-05-19 18:08:48 +00:00
if ( m_rfDest ! = NULL )
2016-04-19 06:45:49 +00:00
change = true ;
2016-02-29 22:43:26 +00:00
}
2016-04-21 17:00:26 +00:00
}
2016-02-29 22:43:26 +00:00
2016-05-19 18:08:48 +00:00
if ( valid & & m_rfSource = = NULL ) {
2016-05-23 20:45:52 +00:00
m_rfSource = m_rfPayload . getSource ( ) ;
2016-05-19 18:08:48 +00:00
if ( m_rfSource ! = NULL )
2016-04-21 17:00:26 +00:00
change = true ;
}
2016-02-29 22:43:26 +00:00
2016-04-21 17:00:26 +00:00
if ( change ) {
2016-05-19 18:08:48 +00:00
if ( m_rfSource ! = NULL & & m_rfDest ! = NULL ) {
2016-05-20 05:15:42 +00:00
m_display - > writeFusion ( ( char * ) m_rfSource , ( char * ) m_rfDest , " R " , " " ) ;
2016-05-19 18:08:48 +00:00
LogMessage ( " YSF, received RF data from %10.10s to %10.10s " , m_rfSource , m_rfDest ) ;
2016-04-21 17:00:26 +00:00
}
2016-05-19 18:08:48 +00:00
if ( m_rfSource ! = NULL & & m_rfDest = = NULL ) {
2016-05-20 05:15:42 +00:00
m_display - > writeFusion ( ( char * ) m_rfSource , " ?????????? " , " R " , " " ) ;
2016-05-19 18:08:48 +00:00
LogMessage ( " YSF, received RF data from %10.10s to ?????????? " , m_rfSource ) ;
2016-04-21 17:00:26 +00:00
}
2016-05-19 18:08:48 +00:00
if ( m_rfSource = = NULL & & m_rfDest ! = NULL ) {
2016-05-20 05:15:42 +00:00
m_display - > writeFusion ( " ?????????? " , ( char * ) m_rfDest , " R " , " " ) ;
2016-05-19 18:08:48 +00:00
LogMessage ( " YSF, received RF data from ?????????? to %10.10s " , m_rfDest ) ;
2016-02-29 22:43:26 +00:00
}
2016-02-28 20:34:37 +00:00
}
2016-05-16 20:57:32 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-06-13 20:29:19 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
2016-05-16 20:57:32 +00:00
2016-02-16 07:27:13 +00:00
if ( m_duplex ) {
2016-04-21 17:00:26 +00:00
fich . setMR ( YSF_MR_BUSY ) ;
fich . encode ( data + 2U ) ;
2016-05-16 20:57:32 +00:00
writeQueueRF ( data ) ;
2016-02-16 07:27:13 +00:00
}
2016-02-16 17:37:12 +00:00
2016-04-21 17:00:26 +00:00
# if defined(DUMP_YSF)
writeFile ( data + 2U ) ;
# endif
2016-05-16 20:57:32 +00:00
m_rfFrames + + ;
2016-06-13 20:29:19 +00:00
} else {
CSync : : addYSFSync ( data + 2U ) ;
2016-04-21 17:00:26 +00:00
2016-05-16 20:57:32 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-06-13 20:29:19 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
2016-04-21 17:00:26 +00:00
2016-05-16 20:57:32 +00:00
if ( m_duplex )
writeQueueRF ( data ) ;
2016-04-21 17:00:26 +00:00
2016-02-16 17:37:12 +00:00
# if defined(DUMP_YSF)
writeFile ( data + 2U ) ;
# endif
2016-06-13 20:29:19 +00:00
m_rfFrames + + ;
2016-02-16 07:27:13 +00:00
}
return true ;
}
unsigned int CYSFControl : : readModem ( unsigned char * data )
{
2016-03-07 20:21:55 +00:00
assert ( data ! = NULL ) ;
2016-02-16 07:27:13 +00:00
if ( m_queue . isEmpty ( ) )
return 0U ;
unsigned char len = 0U ;
m_queue . getData ( & len , 1U ) ;
m_queue . getData ( data , len ) ;
return len ;
}
2016-05-16 20:57:32 +00:00
void CYSFControl : : writeEndRF ( )
2016-02-16 07:27:13 +00:00
{
2016-05-16 20:57:32 +00:00
m_rfState = RS_RF_LISTENING ;
2016-02-16 07:27:13 +00:00
2016-05-17 05:13:09 +00:00
m_rfTimeoutTimer . stop ( ) ;
2016-05-23 20:45:52 +00:00
m_rfPayload . reset ( ) ;
2016-05-17 05:13:09 +00:00
// These variables are free'd by YSFPayload
2016-05-19 18:08:48 +00:00
m_rfSource = NULL ;
m_rfDest = NULL ;
2016-02-16 07:27:13 +00:00
2016-05-17 05:13:09 +00:00
if ( m_netState = = RS_NET_IDLE ) {
2016-05-16 20:57:32 +00:00
m_display - > clearFusion ( ) ;
2016-02-29 22:43:26 +00:00
2016-05-16 20:57:32 +00:00
if ( m_network ! = NULL )
m_network - > reset ( ) ;
}
2016-02-29 22:43:26 +00:00
2016-02-16 07:27:13 +00:00
# if defined(DUMP_YSF)
closeFile ( ) ;
# endif
}
2016-05-16 20:57:32 +00:00
void CYSFControl : : writeEndNet ( )
{
m_netState = RS_NET_IDLE ;
m_netTimeoutTimer . stop ( ) ;
m_networkWatchdog . stop ( ) ;
2016-07-12 18:02:36 +00:00
m_packetTimer . stop ( ) ;
2016-05-16 20:57:32 +00:00
2016-05-23 20:45:52 +00:00
m_netPayload . reset ( ) ;
2016-05-16 20:57:32 +00:00
m_display - > clearFusion ( ) ;
if ( m_network ! = NULL )
m_network - > reset ( ) ;
}
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 ( ) ;
2016-06-09 18:51:23 +00:00
bool gateway = : : memcmp ( data + 4U , " GATEWAY " , YSF_CALLSIGN_LENGTH ) = = 0 ;
2016-07-12 18:02:36 +00:00
unsigned char n = ( data [ 34U ] & 0xFEU ) > > 1 ;
bool end = ( data [ 34U ] & 0x01U ) = = 0x01U ;
2016-05-16 20:57:32 +00:00
if ( ! m_netTimeoutTimer . isRunning ( ) ) {
2016-07-12 18:02:36 +00:00
if ( end )
return ;
2016-05-19 18:08:48 +00:00
if ( : : memcmp ( data + 14U , " " , YSF_CALLSIGN_LENGTH ) ! = 0 )
: : memcpy ( m_netSource , data + 14U , YSF_CALLSIGN_LENGTH ) ;
else
: : memcpy ( m_netSource , " ?????????? " , YSF_CALLSIGN_LENGTH ) ;
if ( : : memcmp ( data + 24U , " " , YSF_CALLSIGN_LENGTH ) ! = 0 )
: : memcpy ( m_netDest , data + 24U , YSF_CALLSIGN_LENGTH ) ;
else
: : memcpy ( m_netDest , " ?????????? " , YSF_CALLSIGN_LENGTH ) ;
2016-05-20 05:15:42 +00:00
m_display - > writeFusion ( ( char * ) m_netSource , ( char * ) m_netDest , " N " , ( char * ) ( data + 4U ) ) ;
2016-05-19 18:08:48 +00:00
LogMessage ( " YSF, received network data from %10.10s to %10.10s at %10.10s " , m_netSource , m_netDest , data + 4U ) ;
2016-05-16 20:57:32 +00:00
m_netTimeoutTimer . start ( ) ;
2016-05-23 20:45:52 +00:00
m_netPayload . reset ( ) ;
2016-07-12 17:20:48 +00:00
m_packetTimer . start ( ) ;
m_elapsed . start ( ) ;
2016-06-15 06:10:14 +00:00
m_netState = RS_NET_AUDIO ;
2016-05-16 20:57:32 +00:00
m_netFrames = 0U ;
2016-07-12 17:20:48 +00:00
m_netLost = 0U ;
2016-06-15 06:10:14 +00:00
m_netErrs = 0U ;
m_netBits = 1U ;
2016-07-12 17:20:48 +00:00
m_netN = 0U ;
2016-05-19 18:08:48 +00:00
} else {
2016-06-15 06:10:14 +00:00
// Check for duplicate frames, if we can
2016-07-12 18:02:36 +00:00
if ( m_netN = = n )
2016-06-15 06:10:14 +00:00
return ;
2016-05-19 18:08:48 +00:00
bool changed = false ;
if ( : : memcmp ( data + 14U , " " , YSF_CALLSIGN_LENGTH ) ! = 0 & & : : memcmp ( m_netSource , " ?????????? " , YSF_CALLSIGN_LENGTH ) = = 0 ) {
: : memcpy ( m_netSource , data + 14U , YSF_CALLSIGN_LENGTH ) ;
changed = true ;
}
if ( : : memcmp ( data + 24U , " " , YSF_CALLSIGN_LENGTH ) ! = 0 & & : : memcmp ( m_netDest , " ?????????? " , YSF_CALLSIGN_LENGTH ) = = 0 ) {
: : memcpy ( m_netDest , data + 24U , YSF_CALLSIGN_LENGTH ) ;
changed = true ;
}
if ( changed ) {
2016-05-20 05:15:42 +00:00
m_display - > writeFusion ( ( char * ) m_netSource , ( char * ) m_netDest , " N " , ( char * ) ( data + 4U ) ) ;
2016-05-21 12:09:34 +00:00
LogMessage ( " YSF, received network data from %10.10s to %10.10s at %10.10s " , m_netSource , m_netDest , data + 4U ) ;
2016-05-19 18:08:48 +00:00
}
2016-05-16 20:57:32 +00:00
}
2016-05-19 18:08:48 +00:00
data [ 33U ] = end ? TAG_EOT : TAG_DATA ;
data [ 34U ] = 0x00U ;
2016-07-12 17:20:48 +00:00
bool send = true ;
2016-05-17 05:30:59 +00:00
CYSFFICH fich ;
2016-05-19 18:08:48 +00:00
bool valid = fich . decode ( data + 35U ) ;
2016-05-17 05:30:59 +00:00
if ( valid ) {
2016-07-05 16:51:16 +00:00
unsigned char bn = fich . getBN ( ) ;
unsigned char bt = fich . getBT ( ) ;
2016-05-23 20:45:52 +00:00
unsigned char dt = fich . getDT ( ) ;
unsigned char fn = fich . getFN ( ) ;
2016-05-25 06:51:42 +00:00
unsigned char ft = fich . getFT ( ) ;
2016-07-05 16:51:16 +00:00
unsigned char fi = fich . getFI ( ) ;
2016-05-23 20:45:52 +00:00
2016-07-12 18:02:36 +00:00
fich . setVoIP ( true ) ;
fich . setMR ( YSF_MR_BUSY ) ;
fich . encode ( data + 35U ) ;
2016-07-12 17:39:49 +00:00
m_lastMode = dt ;
2016-05-23 20:45:52 +00:00
// Set the downlink callsign
switch ( fi ) {
case YSF_FI_HEADER :
case YSF_FI_TERMINATOR :
m_netPayload . processHeaderData ( data + 35U ) ;
break ;
case YSF_FI_COMMUNICATIONS :
switch ( dt ) {
2016-06-16 16:33:53 +00:00
case YSF_DT_VD_MODE1 : {
m_netPayload . processVDMode1Data ( data + 35U , fn , gateway ) ;
unsigned int errors = m_netPayload . processVDMode1Audio ( data + 35U ) ;
2016-07-12 17:20:48 +00:00
send = insertSilence ( data + 33U , n ) ;
if ( send ) {
m_netErrs + = errors ;
m_netBits + = 235U ;
LogDebug ( " YSF, V/D Mode 1, seq %u, AMBE FEC %u/235 (%.1f%%) " , n , errors , float ( errors ) / 2.35F ) ;
}
2016-06-16 16:33:53 +00:00
}
2016-05-23 20:45:52 +00:00
break ;
2016-06-16 16:33:53 +00:00
case YSF_DT_VD_MODE2 : {
m_netPayload . processVDMode2Data ( data + 35U , fn , gateway ) ;
unsigned int errors = m_netPayload . processVDMode2Audio ( data + 35U ) ;
2016-07-12 17:20:48 +00:00
send = insertSilence ( data + 33U , n ) ;
if ( send ) {
m_netErrs + = errors ;
m_netBits + = 135U ;
LogDebug ( " YSF, V/D Mode 2, seq %u, Repetition FEC %u/135 (%.1f%%) " , n , errors , float ( errors ) / 1.35F ) ;
}
2016-06-16 16:33:53 +00:00
}
2016-05-23 20:45:52 +00:00
break ;
case YSF_DT_DATA_FR_MODE :
2016-07-05 16:51:16 +00:00
LogDebug ( " YSF, Network data FICH B=%u/%u F=%u/%u " , bn , bt , fn , ft ) ;
2016-06-09 19:25:02 +00:00
m_netPayload . processDataFRModeData ( data + 35U , fn , gateway ) ;
2016-05-23 20:45:52 +00:00
break ;
case YSF_DT_VOICE_FR_MODE :
2016-05-25 06:51:42 +00:00
if ( fn ! = 0U | | ft ! = 1U ) {
// The first packet after the header is odd, don't try and regenerate it
2016-06-16 16:33:53 +00:00
unsigned int errors = m_netPayload . processVoiceFRModeAudio ( data + 35U ) ;
2016-07-12 17:20:48 +00:00
send = insertSilence ( data + 33U , n ) ;
if ( send ) {
m_netErrs + = errors ;
m_netBits + = 720U ;
LogDebug ( " YSF, V Mode 3, seq %u, AMBE FEC %u/720 (%.1f%%) " , n , errors , float ( errors ) / 7.2F ) ;
}
2016-05-25 06:51:42 +00:00
}
2016-05-23 20:45:52 +00:00
break ;
default :
break ;
}
break ;
default :
break ;
}
2016-07-12 17:20:48 +00:00
} else {
send = insertSilence ( data + 33U , n ) ;
2016-05-17 05:30:59 +00:00
}
2016-07-12 17:20:48 +00:00
if ( send ) {
writeQueueNet ( data + 33U ) ;
m_packetTimer . start ( ) ;
2016-07-12 18:02:36 +00:00
m_netFrames + + ;
2016-07-12 17:20:48 +00:00
m_netN = n ;
}
2016-05-16 20:57:32 +00:00
2016-05-19 18:08:48 +00:00
if ( end ) {
2016-07-12 17:20:48 +00:00
LogMessage ( " YSF, received network end of transmission, %.1f seconds, %u%% packet loss, BER: %.1f%% " , float ( m_netFrames ) / 10.0F , ( m_netLost * 100U ) / m_netFrames , float ( m_netErrs * 100U ) / float ( m_netBits ) ) ;
2016-05-16 20:57:32 +00:00
writeEndNet ( ) ;
}
}
void CYSFControl : : clock ( unsigned int ms )
2016-02-16 07:27:13 +00:00
{
2016-05-16 20:57:32 +00:00
if ( m_network ! = NULL )
writeNetwork ( ) ;
m_rfTimeoutTimer . clock ( ms ) ;
m_netTimeoutTimer . clock ( ms ) ;
if ( m_netState = = RS_NET_AUDIO ) {
m_networkWatchdog . clock ( ms ) ;
if ( m_networkWatchdog . hasExpired ( ) ) {
2016-07-12 17:20:48 +00:00
LogMessage ( " YSF, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %.1f%% " , float ( m_netFrames ) / 10.0F , ( m_netLost * 100U ) / m_netFrames , float ( m_netErrs * 100U ) / float ( m_netBits ) ) ;
2016-05-16 20:57:32 +00:00
writeEndNet ( ) ;
}
}
2016-07-12 17:20:48 +00:00
if ( m_netState = = RS_NET_AUDIO ) {
m_packetTimer . clock ( ms ) ;
if ( m_packetTimer . isRunning ( ) & & m_packetTimer . hasExpired ( ) ) {
unsigned int elapsed = m_elapsed . elapsed ( ) ;
unsigned int frames = elapsed / YSF_FRAME_TIME ;
if ( frames > m_netFrames ) {
unsigned int count = frames - m_netFrames ;
if ( count > 2U ) {
LogDebug ( " YSF, lost audio for 200ms filling in, elapsed: %ums, expected: %u, received: %u " , elapsed , frames , m_netFrames ) ;
insertSilence ( count - 1U ) ;
}
}
m_packetTimer . start ( ) ;
}
}
2016-02-16 07:27:13 +00:00
}
2016-05-16 20:57:32 +00:00
void CYSFControl : : writeQueueRF ( const unsigned char * data )
2016-02-16 07:27:13 +00:00
{
assert ( data ! = NULL ) ;
2016-05-16 20:57:32 +00:00
if ( m_netState ! = RS_NET_IDLE )
return ;
if ( m_rfTimeoutTimer . isRunning ( ) & & m_rfTimeoutTimer . hasExpired ( ) )
2016-02-16 07:27:13 +00:00
return ;
unsigned char len = YSF_FRAME_LENGTH_BYTES + 2U ;
2016-03-07 18:08:50 +00:00
unsigned int space = m_queue . freeSpace ( ) ;
if ( space < ( len + 1U ) ) {
LogError ( " YSF, overflow in the System Fusion RF queue " ) ;
return ;
}
2016-02-16 07:27:13 +00:00
m_queue . addData ( & len , 1U ) ;
m_queue . addData ( data , len ) ;
}
2016-05-16 20:57:32 +00:00
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 ) ;
}
2016-06-13 20:29:19 +00:00
void CYSFControl : : writeNetwork ( const unsigned char * data , unsigned int count )
2016-05-16 20:57:32 +00:00
{
assert ( data ! = NULL ) ;
if ( m_network = = NULL )
return ;
if ( m_rfTimeoutTimer . isRunning ( ) & & m_rfTimeoutTimer . hasExpired ( ) )
return ;
2016-06-13 20:29:19 +00:00
m_network - > write ( m_rfSource , m_rfDest , data + 2U , count , data [ 0U ] = = TAG_EOT ) ;
2016-05-16 20:57:32 +00:00
}
2016-02-22 21:13:48 +00:00
2016-02-16 07:27:13 +00:00
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 ;
}
}
2016-07-12 17:20:48 +00:00
bool CYSFControl : : insertSilence ( const unsigned char * data , unsigned char n )
{
assert ( data ! = NULL ) ;
// Check to see if we have any spaces to fill?
unsigned char newN = ( m_netN + 1U ) % 128U ;
if ( newN = = n ) {
// Just copy the data, nothing else to do here
: : memcpy ( m_lastFrame , data , YSF_FRAME_LENGTH_BYTES + 2U ) ;
return true ;
}
LogDebug ( " YSF, current=%u last=%u " , n , m_netN ) ;
unsigned int count ;
if ( n > newN )
count = n - newN ;
else
count = ( 128U + n ) - newN ;
if ( count > = 4U ) {
LogDebug ( " YSF, frame is out of range, count = %u " , count ) ;
return false ;
}
insertSilence ( count ) ;
: : memcpy ( m_lastFrame , data , YSF_FRAME_LENGTH_BYTES + 2U ) ;
return true ;
}
void CYSFControl : : insertSilence ( unsigned int count )
{
2016-07-12 17:39:49 +00:00
// We can't meaningfully create "silent" data
if ( m_lastMode = = YSF_DT_DATA_FR_MODE )
return ;
2016-07-12 17:20:48 +00:00
LogDebug ( " YSF, insert %u frames " , count ) ;
unsigned char n = ( m_netN + 1U ) % 128U ;
for ( unsigned int i = 0U ; i < count ; i + + ) {
writeQueueNet ( m_lastFrame ) ;
m_netN = n ;
m_netFrames + + ;
m_netLost + + ;
n = ( n + 1U ) % 128U ;
}
LogDebug ( " YSF, last=%u " , m_netN ) ;
}