2016-02-16 07:27:13 +00:00
/*
2019-01-10 09:05:15 +00:00
* Copyright ( C ) 2015 - 2019 Jonathan Naylor , G4KLX
2016-02-16 07:27:13 +00:00
*
* 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"
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
2017-08-15 09:11:05 +00:00
CYSFControl : : CYSFControl ( const std : : string & callsign , bool selfOnly , CYSFNetwork * network , CDisplay * display , unsigned int timeout , bool duplex , bool lowDeviation , bool remoteGateway , CRSSIInterpolator * rssiMapper ) :
2016-09-22 21:38:59 +00:00
m_callsign ( NULL ) ,
2017-08-15 09:11:05 +00:00
m_selfCallsign ( NULL ) ,
m_selfOnly ( selfOnly ) ,
2016-05-16 20:57:32 +00:00
m_network ( network ) ,
2016-02-16 07:27:13 +00:00
m_display ( display ) ,
m_duplex ( duplex ) ,
2017-03-23 20:26:17 +00:00
m_lowDeviation ( lowDeviation ) ,
2016-09-26 17:07:06 +00:00
m_remoteGateway ( remoteGateway ) ,
2017-08-13 09:30:02 +00:00
m_sqlEnabled ( false ) ,
m_sqlValue ( 0U ) ,
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-15 05:32:56 +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 ) ,
2017-08-14 13:08:43 +00:00
m_lastFICH ( ) ,
2016-07-12 17:20:48 +00:00
m_netN ( 0U ) ,
2016-05-23 20:45:52 +00:00
m_rfPayload ( ) ,
m_netPayload ( ) ,
2017-01-05 19:15:10 +00:00
m_rssiMapper ( rssiMapper ) ,
m_rssi ( 0U ) ,
m_maxRSSI ( 0U ) ,
m_minRSSI ( 0U ) ,
m_aveRSSI ( 0U ) ,
m_rssiCount ( 0U ) ,
2019-01-19 17:15:24 +00:00
m_enabled ( true ) ,
2016-02-16 07:27:13 +00:00
m_fp ( NULL )
{
assert ( display ! = NULL ) ;
2017-01-05 19:15:10 +00:00
assert ( rssiMapper ! = 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
2016-09-22 21:38:59 +00:00
m_callsign = new unsigned char [ YSF_CALLSIGN_LENGTH ] ;
std : : string node = callsign ;
node . resize ( YSF_CALLSIGN_LENGTH , ' ' ) ;
for ( unsigned int i = 0U ; i < YSF_CALLSIGN_LENGTH ; i + + )
m_callsign [ i ] = node . at ( i ) ;
2017-08-15 09:11:05 +00:00
m_selfCallsign = new unsigned char [ YSF_CALLSIGN_LENGTH ] ;
: : memset ( m_selfCallsign , 0x00U , YSF_CALLSIGN_LENGTH ) ;
for ( unsigned int i = 0U ; i < callsign . length ( ) ; i + + )
m_selfCallsign [ i ] = callsign . at ( i ) ;
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-09-22 21:38:59 +00:00
delete [ ] m_callsign ;
2017-08-15 09:11:05 +00:00
delete [ ] m_selfCallsign ;
2016-02-16 07:27:13 +00:00
}
2017-08-13 09:30:02 +00:00
void CYSFControl : : setSQL ( bool on , unsigned char value )
{
m_sqlEnabled = on ;
m_sqlValue = value ;
}
2016-08-08 20:26:18 +00:00
bool CYSFControl : : writeModem ( unsigned char * data , unsigned int len )
2016-02-16 07:27:13 +00:00
{
2016-03-07 20:21:55 +00:00
assert ( data ! = NULL ) ;
2019-01-20 17:09:40 +00:00
if ( ! m_enabled )
return false ;
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 ) {
2017-01-07 12:25:03 +00:00
if ( m_rssi ! = 0U )
LogMessage ( " YSF, transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm " , float ( m_rfFrames ) / 10.0F , float ( m_rfErrs * 100U ) / float ( m_rfBits ) , m_minRSSI , m_maxRSSI , m_aveRSSI / m_rssiCount ) ;
else
LogMessage ( " YSF, transmission lost, %.1f seconds, BER: %.1f%% " , float ( m_rfFrames ) / 10.0F , float ( m_rfErrs * 100U ) / float ( m_rfBits ) ) ;
2016-05-16 20:57:32 +00:00
writeEndRF ( ) ;
2016-02-16 07:27:13 +00:00
return false ;
}
2018-01-09 07:41:04 +00:00
if ( type = = TAG_LOST & & m_rfState = = RS_RF_REJECTED ) {
m_rfPayload . reset ( ) ;
m_rfSource = NULL ;
m_rfDest = NULL ;
m_rfState = RS_RF_LISTENING ;
return false ;
}
2017-08-15 14:21:27 +00:00
if ( type = = TAG_LOST ) {
2017-08-19 11:08:28 +00:00
m_rfPayload . reset ( ) ;
2017-08-15 14:21:27 +00:00
m_rfState = RS_RF_LISTENING ;
2016-02-16 07:27:13 +00:00
return false ;
2017-08-15 14:21:27 +00:00
}
2016-02-16 07:27:13 +00:00
2017-01-05 19:15:10 +00:00
// Have we got RSSI bytes on the end?
if ( len = = ( YSF_FRAME_LENGTH_BYTES + 4U ) ) {
uint16_t raw = 0U ;
raw | = ( data [ 122U ] < < 8 ) & 0xFF00U ;
raw | = ( data [ 123U ] < < 0 ) & 0x00FFU ;
// Convert the raw RSSI to dBm
int rssi = m_rssiMapper - > interpolate ( raw ) ;
2018-03-06 20:12:29 +00:00
if ( rssi ! = 0 )
LogDebug ( " YSF, raw RSSI: %u, reported RSSI: %d dBm " , raw , rssi ) ;
2017-01-05 19:15:10 +00:00
// RSSI is always reported as positive
m_rssi = ( rssi > = 0 ) ? rssi : - rssi ;
if ( m_rssi > m_minRSSI )
m_minRSSI = m_rssi ;
if ( m_rssi < m_maxRSSI )
m_maxRSSI = m_rssi ;
m_aveRSSI + = m_rssi ;
m_rssiCount + + ;
}
2016-04-21 17:00:26 +00:00
CYSFFICH fich ;
bool valid = fich . decode ( data + 2U ) ;
2016-04-12 20:33:16 +00:00
2017-08-14 13:08:43 +00:00
if ( valid )
m_lastFICH = fich ;
2017-08-13 09:30:02 +00:00
2017-09-17 11:16:14 +00:00
// Validate the DSQ/DG-ID value if enabled
2017-08-14 13:08:43 +00:00
if ( m_sqlEnabled ) {
2017-09-17 11:16:14 +00:00
unsigned char cm = m_lastFICH . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 ) {
// Using the DG-ID value
unsigned char value = m_lastFICH . getSQ ( ) ;
if ( value ! = m_sqlValue )
return false ;
} else {
// Using the DSQ value
bool sql = m_lastFICH . getSQL ( ) ;
unsigned char value = m_lastFICH . getSQ ( ) ;
if ( ! sql | | value ! = m_sqlValue )
return false ;
}
2017-08-14 13:08:43 +00:00
}
2017-08-14 11:12:32 +00:00
2018-12-08 10:33:52 +00:00
# ifdef notdef
2017-08-14 13:08:43 +00:00
// Stop repeater packets coming through, unless we're acting as a remote gateway
if ( m_remoteGateway ) {
unsigned char mr = m_lastFICH . getMR ( ) ;
if ( mr ! = YSF_MR_BUSY )
return false ;
} else {
unsigned char mr = m_lastFICH . getMR ( ) ;
if ( mr = = YSF_MR_BUSY )
return false ;
}
2018-12-08 10:33:52 +00:00
# endif
2017-08-14 11:12:32 +00:00
2017-08-14 13:08:43 +00:00
unsigned char dt = m_lastFICH . getDT ( ) ;
bool ret = false ;
switch ( dt ) {
case YSF_DT_VOICE_FR_MODE :
ret = processVWData ( valid , data ) ;
break ;
case YSF_DT_VD_MODE1 :
case YSF_DT_VD_MODE2 :
ret = processDNData ( valid , data ) ;
break ;
case YSF_DT_DATA_FR_MODE :
ret = processFRData ( valid , data ) ;
break ;
default :
break ;
}
return ret ;
}
bool CYSFControl : : processVWData ( bool valid , unsigned char * data )
{
unsigned char fi = m_lastFICH . getFI ( ) ;
2017-08-14 16:34:04 +00:00
if ( valid & & fi = = YSF_FI_HEADER ) {
2017-08-19 11:08:28 +00:00
if ( m_rfState = = RS_RF_LISTENING ) {
bool valid = m_rfPayload . processHeaderData ( data + 2U ) ;
if ( ! valid )
return false ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_rfSource = m_rfPayload . getSource ( ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
if ( m_selfOnly ) {
bool ret = checkCallsign ( m_rfSource ) ;
if ( ! ret ) {
LogMessage ( " YSF, invalid access attempt from %10.10s " , m_rfSource ) ;
m_rfState = RS_RF_REJECTED ;
return false ;
}
2017-08-15 14:21:27 +00:00
}
2017-08-15 09:11:05 +00:00
2017-08-19 11:08:28 +00:00
unsigned char cm = m_lastFICH . getCM ( ) ;
2017-09-16 18:33:33 +00:00
if ( cm = = YSF_CM_GROUP1 | | cm = = YSF_CM_GROUP2 )
2017-08-19 11:08:28 +00:00
m_rfDest = ( unsigned char * ) " ALL " ;
else
m_rfDest = m_rfPayload . getDest ( ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_rfFrames = 0U ;
m_rfErrs = 0U ;
m_rfBits = 1U ;
m_rfTimeoutTimer . start ( ) ;
m_rfState = RS_RF_AUDIO ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_minRSSI = m_rssi ;
m_maxRSSI = m_rssi ;
m_aveRSSI = m_rssi ;
m_rssiCount = 1U ;
2016-02-16 17:37:12 +00:00
# if defined(DUMP_YSF)
2017-08-19 11:08:28 +00:00
openFile ( ) ;
2016-02-16 17:37:12 +00:00
# endif
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_display - > writeFusion ( ( char * ) m_rfSource , ( char * ) m_rfDest , " R " , " " ) ;
LogMessage ( " YSF, received RF header from %10.10s to %10.10s " , m_rfSource , m_rfDest ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
CYSFFICH fich = m_lastFICH ;
2018-02-27 18:34:32 +00:00
// Remove any DSQ/DG-ID information
2017-08-19 11:08:28 +00:00
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
2017-08-14 13:08:43 +00:00
# if defined(DUMP_YSF)
2017-08-19 11:08:28 +00:00
writeFile ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
# endif
2017-08-19 11:08:28 +00:00
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-19 11:08:28 +00:00
fich . setSQ ( m_sqlValue ) ;
2017-08-14 13:46:00 +00:00
2017-08-19 11:08:28 +00:00
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
}
m_rfFrames + + ;
2016-02-16 07:27:13 +00:00
2017-08-19 11:08:28 +00:00
m_display - > writeFusionRSSI ( m_rssi ) ;
2016-02-16 07:27:13 +00:00
2017-08-19 11:08:28 +00:00
return true ;
}
2017-08-14 16:34:04 +00:00
} else if ( valid & & fi = = YSF_FI_TERMINATOR ) {
2017-08-15 14:21:27 +00:00
if ( m_rfState = = RS_RF_REJECTED ) {
2018-01-09 07:41:04 +00:00
m_rfPayload . reset ( ) ;
m_rfSource = NULL ;
m_rfDest = NULL ;
m_rfState = RS_RF_LISTENING ;
2017-08-15 14:21:27 +00:00
} else if ( m_rfState = = RS_RF_AUDIO ) {
m_rfPayload . processHeaderData ( data + 2U ) ;
2016-09-26 17:07:06 +00:00
2017-08-15 14:21:27 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
CYSFFICH fich = m_lastFICH ;
2017-08-14 13:08:43 +00:00
2018-02-27 18:34:32 +00:00
// Remove any DSQ/DG-ID information
2017-08-15 14:21:27 +00:00
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
data [ 0U ] = TAG_EOT ;
data [ 1U ] = 0x00U ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
2017-08-14 13:08:43 +00:00
# if defined(DUMP_YSF)
2017-08-15 14:21:27 +00:00
writeFile ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
# endif
2017-08-15 14:21:27 +00:00
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-15 14:21:27 +00:00
fich . setSQ ( m_sqlValue ) ;
2017-08-14 13:46:00 +00:00
2017-08-15 14:21:27 +00:00
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
}
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
m_rfFrames + + ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
if ( m_rssi ! = 0U )
LogMessage ( " YSF, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm " , float ( m_rfFrames ) / 10.0F , float ( m_rfErrs * 100U ) / float ( m_rfBits ) , m_minRSSI , m_maxRSSI , m_aveRSSI / m_rssiCount ) ;
else
LogMessage ( " YSF, received RF end of transmission, %.1f seconds, BER: %.1f%% " , float ( m_rfFrames ) / 10.0F , float ( m_rfErrs * 100U ) / float ( m_rfBits ) ) ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
writeEndRF ( ) ;
}
2016-09-26 17:07:06 +00:00
} else {
2017-08-19 11:08:28 +00:00
if ( m_rfState = = RS_RF_AUDIO ) {
// If valid is false, update the m_lastFICH for this transmission
if ( ! valid ) {
// XXX Check these values
m_lastFICH . setFT ( 0U ) ;
m_lastFICH . setFN ( 0U ) ;
}
2016-02-16 07:27:13 +00:00
2017-08-19 11:08:28 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2016-05-23 20:45:52 +00:00
2017-08-19 11:08:28 +00:00
CYSFFICH fich = m_lastFICH ;
2016-04-25 17:06:19 +00:00
2017-08-19 11:08:28 +00:00
unsigned char fn = fich . getFN ( ) ;
unsigned char ft = fich . getFT ( ) ;
2016-04-21 17:00:26 +00:00
2017-08-19 11:08:28 +00:00
if ( fn ! = 0U | | ft ! = 1U ) {
// The first packet after the header is odd, don't try and regenerate it
unsigned int errors = m_rfPayload . processVoiceFRModeAudio ( data + 2U ) ;
m_rfErrs + = errors ;
m_rfBits + = 720U ;
m_display - > writeFusionBER ( float ( errors ) / 7.2F ) ;
LogDebug ( " YSF, V Mode 3, seq %u, AMBE FEC %u/720 (%.1f%%) " , m_rfFrames % 128 , errors , float ( errors ) / 7.2F ) ;
}
2016-04-21 17:00:26 +00:00
2018-02-27 18:34:32 +00:00
// Remove any DSQ/DG-ID information
2017-08-19 11:08:28 +00:00
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-19 11:08:28 +00:00
fich . setSQ ( m_sqlValue ) ;
2017-08-14 13:46:00 +00:00
2017-08-19 11:08:28 +00:00
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
}
2016-05-19 18:08:48 +00:00
2017-08-14 13:08:43 +00:00
# if defined(DUMP_YSF)
2017-08-19 11:08:28 +00:00
writeFile ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
# endif
2017-08-19 11:08:28 +00:00
m_rfFrames + + ;
m_display - > writeFusionRSSI ( m_rssi ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
return true ;
}
2017-08-14 13:08:43 +00:00
}
2017-08-19 11:08:28 +00:00
return false ;
2017-08-14 13:08:43 +00:00
}
bool CYSFControl : : processDNData ( bool valid , unsigned char * data )
{
unsigned char fi = m_lastFICH . getFI ( ) ;
2017-08-14 16:34:04 +00:00
if ( valid & & fi = = YSF_FI_HEADER ) {
2017-08-19 11:08:28 +00:00
if ( m_rfState = = RS_RF_LISTENING ) {
bool valid = m_rfPayload . processHeaderData ( data + 2U ) ;
if ( ! valid )
return false ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_rfSource = m_rfPayload . getSource ( ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
if ( m_selfOnly ) {
bool ret = checkCallsign ( m_rfSource ) ;
if ( ! ret ) {
LogMessage ( " YSF, invalid access attempt from %10.10s " , m_rfSource ) ;
m_rfState = RS_RF_REJECTED ;
return false ;
}
2017-08-15 14:21:27 +00:00
}
2017-08-15 09:11:05 +00:00
2017-08-19 11:08:28 +00:00
unsigned char cm = m_lastFICH . getCM ( ) ;
2017-09-16 18:33:33 +00:00
if ( cm = = YSF_CM_GROUP1 | | cm = = YSF_CM_GROUP2 )
2017-08-19 11:08:28 +00:00
m_rfDest = ( unsigned char * ) " ALL " ;
else
m_rfDest = m_rfPayload . getDest ( ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_rfFrames = 0U ;
m_rfErrs = 0U ;
m_rfBits = 1U ;
m_rfTimeoutTimer . start ( ) ;
m_rfState = RS_RF_AUDIO ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_minRSSI = m_rssi ;
m_maxRSSI = m_rssi ;
m_aveRSSI = m_rssi ;
m_rssiCount = 1U ;
2017-08-14 13:08:43 +00:00
# if defined(DUMP_YSF)
2017-08-19 11:08:28 +00:00
openFile ( ) ;
2017-08-14 13:08:43 +00:00
# endif
2017-08-19 11:08:28 +00:00
m_display - > writeFusion ( ( char * ) m_rfSource , ( char * ) m_rfDest , " R " , " " ) ;
LogMessage ( " YSF, received RF header from %10.10s to %10.10s " , m_rfSource , m_rfDest ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
CYSFFICH fich = m_lastFICH ;
2017-08-13 09:30:02 +00:00
2018-02-27 18:34:32 +00:00
// Remove any DSQ/DG-ID information
2017-08-19 11:08:28 +00:00
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( data + 2U ) ;
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-05-19 18:08:48 +00:00
2017-08-19 11:08:28 +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)
2017-08-19 11:08:28 +00:00
writeFile ( data + 2U ) ;
2016-04-21 17:00:26 +00:00
# endif
2017-08-19 11:08:28 +00:00
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-19 11:08:28 +00:00
fich . setSQ ( m_sqlValue ) ;
2017-08-14 13:46:00 +00:00
2017-08-19 11:08:28 +00:00
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
}
m_rfFrames + + ;
2016-06-13 20:29:19 +00:00
2017-08-19 11:08:28 +00:00
m_display - > writeFusionRSSI ( m_rssi ) ;
2017-01-05 19:44:52 +00:00
2017-08-19 11:08:28 +00:00
return true ;
}
2017-08-14 16:34:04 +00:00
} else if ( valid & & fi = = YSF_FI_TERMINATOR ) {
2017-08-15 14:21:27 +00:00
if ( m_rfState = = RS_RF_REJECTED ) {
2018-01-09 07:41:04 +00:00
m_rfPayload . reset ( ) ;
m_rfSource = NULL ;
m_rfDest = NULL ;
m_rfState = RS_RF_LISTENING ;
2017-08-15 14:21:27 +00:00
} else if ( m_rfState = = RS_RF_AUDIO ) {
m_rfPayload . processHeaderData ( data + 2U ) ;
2016-04-25 17:06:19 +00:00
2017-08-15 14:21:27 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
CYSFFICH fich = m_lastFICH ;
2017-08-14 13:08:43 +00:00
2018-02-27 18:34:32 +00:00
// Remove any DSQ/DG-ID information
2017-08-15 14:21:27 +00:00
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( data + 2U ) ;
2017-08-13 09:30:02 +00:00
2017-08-15 14:21:27 +00:00
data [ 0U ] = TAG_EOT ;
data [ 1U ] = 0x00U ;
2016-05-16 20:57:32 +00:00
2017-08-15 14:21:27 +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)
2017-08-15 14:21:27 +00:00
writeFile ( data + 2U ) ;
2016-05-19 18:08:48 +00:00
# endif
2017-08-15 14:21:27 +00:00
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-15 14:21:27 +00:00
fich . setSQ ( m_sqlValue ) ;
2017-08-14 13:46:00 +00:00
2017-08-15 14:21:27 +00:00
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
}
2016-02-16 07:27:13 +00:00
2017-08-15 14:21:27 +00:00
m_rfFrames + + ;
2016-06-13 20:29:19 +00:00
2017-08-15 14:21:27 +00:00
if ( m_rssi ! = 0U )
LogMessage ( " YSF, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm " , float ( m_rfFrames ) / 10.0F , float ( m_rfErrs * 100U ) / float ( m_rfBits ) , m_minRSSI , m_maxRSSI , m_aveRSSI / m_rssiCount ) ;
else
LogMessage ( " YSF, received RF end of transmission, %.1f seconds, BER: %.1f%% " , float ( m_rfFrames ) / 10.0F , float ( m_rfErrs * 100U ) / float ( m_rfBits ) ) ;
2017-01-07 12:25:03 +00:00
2017-08-15 14:21:27 +00:00
writeEndRF ( ) ;
}
2017-08-14 13:08:43 +00:00
} else {
if ( m_rfState = = RS_RF_AUDIO ) {
2017-08-14 16:34:04 +00:00
// If valid is false, update the m_lastFICH for this transmission
if ( ! valid ) {
unsigned char ft = m_lastFICH . getFT ( ) ;
unsigned char fn = m_lastFICH . getFN ( ) + 1U ;
if ( fn > ft )
fn = 0U ;
m_lastFICH . setFN ( fn ) ;
}
2016-02-16 07:27:13 +00:00
2017-08-14 13:08:43 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2016-04-20 06:29:09 +00:00
2017-08-14 13:08:43 +00:00
unsigned char fn = m_lastFICH . getFN ( ) ;
unsigned char dt = m_lastFICH . getDT ( ) ;
2016-05-23 20:45:52 +00:00
2017-08-14 13:08:43 +00:00
switch ( dt ) {
case YSF_DT_VD_MODE1 : {
m_rfPayload . processVDMode1Data ( data + 2U , fn ) ;
unsigned int errors = m_rfPayload . processVDMode1Audio ( data + 2U ) ;
m_rfErrs + = errors ;
m_rfBits + = 235U ;
m_display - > writeFusionBER ( float ( errors ) / 2.35F ) ;
LogDebug ( " YSF, V/D Mode 1, seq %u, AMBE FEC %u/235 (%.1f%%) " , m_rfFrames % 128 , errors , float ( errors ) / 2.35F ) ;
}
break ;
2016-04-25 17:06:19 +00:00
2017-08-14 13:08:43 +00:00
case YSF_DT_VD_MODE2 : {
m_rfPayload . processVDMode2Data ( data + 2U , fn ) ;
unsigned int errors = m_rfPayload . processVDMode2Audio ( data + 2U ) ;
m_rfErrs + = errors ;
2019-01-20 20:33:51 +00:00
m_rfBits + = 405U ;
m_display - > writeFusionBER ( float ( errors ) / 4.05F ) ;
LogDebug ( " YSF, V/D Mode 2, seq %u, Repetition FEC %u/405 (%.1f%%) " , m_rfFrames % 128 , errors , float ( errors ) / 4.05F ) ;
2017-08-14 13:08:43 +00:00
}
break ;
default :
break ;
2016-06-16 16:33:53 +00:00
}
2016-04-25 17:06:19 +00:00
2017-08-14 13:08:43 +00:00
CYSFFICH fich = m_lastFICH ;
2016-04-25 17:06:19 +00:00
2018-02-27 18:34:32 +00:00
// Remove any DSQ/DG-ID information
2017-08-14 13:08:43 +00:00
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( data + 2U ) ;
2016-05-10 18:24:27 +00:00
2017-08-14 13:08:43 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-04-25 17:06:19 +00:00
2017-08-14 13:08:43 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-14 13:46:00 +00:00
fich . setSQ ( m_sqlValue ) ;
2017-08-14 13:08:43 +00:00
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
2016-02-29 22:43:26 +00:00
}
2017-08-14 13:08:43 +00:00
# if defined(DUMP_YSF)
writeFile ( data + 2U ) ;
# endif
m_rfFrames + + ;
2016-02-29 22:43:26 +00:00
2017-08-14 13:08:43 +00:00
m_display - > writeFusionRSSI ( m_rssi ) ;
2017-08-19 11:08:28 +00:00
return true ;
} else if ( valid & & m_rfState = = RS_RF_LISTENING ) {
// Only use clean frames for late entry.
2017-08-14 13:08:43 +00:00
unsigned char fn = m_lastFICH . getFN ( ) ;
unsigned char dt = m_lastFICH . getDT ( ) ;
switch ( dt ) {
case YSF_DT_VD_MODE1 :
valid = m_rfPayload . processVDMode1Data ( data + 2U , fn ) ;
break ;
case YSF_DT_VD_MODE2 :
valid = m_rfPayload . processVDMode2Data ( data + 2U , fn ) ;
break ;
default :
2017-08-19 11:08:28 +00:00
valid = false ;
2017-08-14 13:08:43 +00:00
break ;
2016-04-21 17:00:26 +00:00
}
2017-08-14 13:08:43 +00:00
if ( ! valid )
return false ;
2017-08-19 11:08:28 +00:00
unsigned char cm = m_lastFICH . getCM ( ) ;
2017-09-16 18:33:33 +00:00
if ( cm = = YSF_CM_GROUP1 | | cm = = YSF_CM_GROUP2 )
2017-08-19 11:08:28 +00:00
m_rfDest = ( unsigned char * ) " ALL " ;
else
m_rfDest = m_rfPayload . getDest ( ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_rfSource = m_rfPayload . getSource ( ) ;
2017-08-14 13:08:43 +00:00
if ( m_rfSource = = NULL | | m_rfDest = = NULL )
return false ;
2017-08-15 09:11:05 +00:00
if ( m_selfOnly ) {
bool ret = checkCallsign ( m_rfSource ) ;
2017-08-15 14:21:27 +00:00
if ( ! ret ) {
LogMessage ( " YSF, invalid access attempt from %10.10s " , m_rfSource ) ;
m_rfState = RS_RF_REJECTED ;
2017-08-15 09:11:05 +00:00
return false ;
2017-08-15 14:21:27 +00:00
}
2017-08-15 09:11:05 +00:00
}
2017-08-14 13:08:43 +00:00
m_rfFrames = 0U ;
m_rfErrs = 0U ;
m_rfBits = 1U ;
m_rfTimeoutTimer . start ( ) ;
m_rfState = RS_RF_AUDIO ;
m_minRSSI = m_rssi ;
m_maxRSSI = m_rssi ;
m_aveRSSI = m_rssi ;
m_rssiCount = 1U ;
# if defined(DUMP_YSF)
openFile ( ) ;
# endif
2017-08-14 15:13:56 +00:00
// Build a new header and transmit it
unsigned char buffer [ YSF_FRAME_LENGTH_BYTES + 2U ] ;
CSync : : addYSFSync ( buffer + 2U ) ;
CYSFFICH fich = m_lastFICH ;
fich . setFI ( YSF_FI_HEADER ) ;
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( buffer + 2U ) ;
unsigned char csd1 [ 20U ] , csd2 [ 20U ] ;
2017-08-14 16:34:04 +00:00
memcpy ( csd1 + YSF_CALLSIGN_LENGTH , m_rfSource , YSF_CALLSIGN_LENGTH ) ;
memset ( csd2 , ' ' , YSF_CALLSIGN_LENGTH + YSF_CALLSIGN_LENGTH ) ;
2017-08-14 15:13:56 +00:00
2017-09-16 18:33:33 +00:00
if ( cm = = YSF_CM_GROUP1 | | cm = = YSF_CM_GROUP2 )
2017-08-14 16:34:04 +00:00
memset ( csd1 + 0U , ' * ' , YSF_CALLSIGN_LENGTH ) ;
2017-08-14 15:13:56 +00:00
else
2017-08-14 16:34:04 +00:00
memcpy ( csd1 + 0U , m_rfDest , YSF_CALLSIGN_LENGTH ) ;
2017-08-14 15:13:56 +00:00
CYSFPayload payload ;
payload . writeHeader ( buffer + 2U , csd1 , csd2 ) ;
buffer [ 0U ] = TAG_DATA ;
buffer [ 1U ] = 0x00U ;
writeNetwork ( buffer , m_rfFrames % 128U ) ;
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-14 15:13:56 +00:00
fich . setSQ ( m_sqlValue ) ;
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( buffer + 2U ) ;
writeQueueRF ( buffer ) ;
}
# if defined(DUMP_YSF)
writeFile ( buffer + 2U ) ;
# endif
2017-08-14 13:08:43 +00:00
m_display - > writeFusion ( ( char * ) m_rfSource , ( char * ) m_rfDest , " R " , " " ) ;
2017-08-15 11:48:48 +00:00
LogMessage ( " YSF, received RF late entry from %10.10s to %10.10s " , m_rfSource , m_rfDest ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2017-08-14 15:13:56 +00:00
fich = m_lastFICH ;
2017-08-14 13:08:43 +00:00
2018-02-27 18:34:32 +00:00
// Remove any DSQ/DG-ID information
2017-08-14 13:08:43 +00:00
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( data + 2U ) ;
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
writeNetwork ( data , m_rfFrames % 128U ) ;
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-14 13:46:00 +00:00
fich . setSQ ( m_sqlValue ) ;
2017-08-14 13:08:43 +00:00
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
2016-02-29 22:43:26 +00:00
}
2017-08-14 13:08:43 +00:00
# if defined(DUMP_YSF)
writeFile ( data + 2U ) ;
# endif
m_rfFrames + + ;
m_display - > writeFusionRSSI ( m_rssi ) ;
2017-08-19 11:08:28 +00:00
return true ;
2016-02-28 20:34:37 +00:00
}
2017-08-14 13:08:43 +00:00
}
2017-08-19 11:08:28 +00:00
return false ;
2017-08-14 13:08:43 +00:00
}
bool CYSFControl : : processFRData ( bool valid , unsigned char * data )
{
unsigned char fi = m_lastFICH . getFI ( ) ;
2017-08-14 16:34:04 +00:00
if ( valid & & fi = = YSF_FI_HEADER ) {
2017-08-19 11:08:28 +00:00
if ( m_rfState = = RS_RF_LISTENING ) {
valid = m_rfPayload . processHeaderData ( data + 2U ) ;
if ( ! valid )
return false ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_rfSource = m_rfPayload . getSource ( ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
if ( m_selfOnly ) {
bool ret = checkCallsign ( m_rfSource ) ;
if ( ! ret ) {
LogMessage ( " YSF, invalid access attempt from %10.10s " , m_rfSource ) ;
m_rfState = RS_RF_REJECTED ;
return false ;
}
2017-08-15 14:21:27 +00:00
}
2017-08-15 09:11:05 +00:00
2017-08-19 11:08:28 +00:00
unsigned char cm = m_lastFICH . getCM ( ) ;
2017-09-16 18:33:33 +00:00
if ( cm = = YSF_CM_GROUP1 | | cm = = YSF_CM_GROUP2 )
2017-08-19 11:08:28 +00:00
m_rfDest = ( unsigned char * ) " ALL " ;
else
m_rfDest = m_rfPayload . getDest ( ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_rfFrames = 0U ;
m_rfState = RS_RF_DATA ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_minRSSI = m_rssi ;
m_maxRSSI = m_rssi ;
m_aveRSSI = m_rssi ;
m_rssiCount = 1U ;
2017-08-14 13:08:43 +00:00
# if defined(DUMP_YSF)
2017-08-19 11:08:28 +00:00
openFile ( ) ;
2017-08-14 13:08:43 +00:00
# endif
2017-08-19 11:08:28 +00:00
m_display - > writeFusion ( ( char * ) m_rfSource , ( char * ) m_rfDest , " R " , " " ) ;
LogMessage ( " YSF, received RF header from %10.10s to %10.10s " , m_rfSource , m_rfDest ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2016-02-28 20:34:37 +00:00
2017-08-19 11:08:28 +00:00
CYSFFICH fich = m_lastFICH ;
2017-08-13 09:30:02 +00:00
2018-02-27 18:34:32 +00:00
// Remove any DSQ/DG-ID information
2017-08-19 11:08:28 +00:00
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( data + 2U ) ;
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-05-16 20:57:32 +00:00
2017-08-19 11:08:28 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
2016-05-16 20:57:32 +00:00
2017-08-14 13:08:43 +00:00
# if defined(DUMP_YSF)
2017-08-19 11:08:28 +00:00
writeFile ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
# endif
2017-08-19 11:08:28 +00:00
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-19 11:08:28 +00:00
fich . setSQ ( m_sqlValue ) ;
2017-08-14 13:46:00 +00:00
2017-08-19 11:08:28 +00:00
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
}
m_rfFrames + + ;
2016-02-16 17:37:12 +00:00
2017-08-19 11:08:28 +00:00
m_display - > writeFusionRSSI ( m_rssi ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
return true ;
}
2017-08-14 16:34:04 +00:00
} else if ( valid & & fi = = YSF_FI_TERMINATOR ) {
2017-08-15 14:21:27 +00:00
if ( m_rfState = = RS_RF_REJECTED ) {
2018-01-09 07:41:04 +00:00
m_rfPayload . reset ( ) ;
m_rfSource = NULL ;
m_rfDest = NULL ;
m_rfState = RS_RF_LISTENING ;
2017-08-15 14:21:27 +00:00
} else if ( m_rfState = = RS_RF_DATA ) {
m_rfPayload . processHeaderData ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
CYSFFICH fich = m_lastFICH ;
2017-08-14 13:08:43 +00:00
2018-02-27 18:34:32 +00:00
// Remove any DSQ/DG-ID information
2017-08-15 14:21:27 +00:00
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
data [ 0U ] = TAG_EOT ;
data [ 1U ] = 0x00U ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
2017-08-14 13:08:43 +00:00
2016-04-21 17:00:26 +00:00
# if defined(DUMP_YSF)
2017-08-15 14:21:27 +00:00
writeFile ( data + 2U ) ;
2016-04-21 17:00:26 +00:00
# endif
2017-08-15 14:21:27 +00:00
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-15 14:21:27 +00:00
fich . setSQ ( m_sqlValue ) ;
2017-08-14 13:46:00 +00:00
2017-08-15 14:21:27 +00:00
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
}
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
m_rfFrames + + ;
2017-01-05 19:44:52 +00:00
2017-08-15 14:21:27 +00:00
if ( m_rssi ! = 0U )
LogMessage ( " YSF, received RF end of transmission, %.1f seconds, RSSI: -%u/-%u/-%u dBm " , float ( m_rfFrames ) / 10.0F , m_minRSSI , m_maxRSSI , m_aveRSSI / m_rssiCount ) ;
else
LogMessage ( " YSF, received RF end of transmission, %.1f seconds " , float ( m_rfFrames ) / 10.0F ) ;
2017-08-14 13:08:43 +00:00
2017-08-15 14:21:27 +00:00
writeEndRF ( ) ;
}
2016-06-13 20:29:19 +00:00
} else {
2017-08-19 11:08:28 +00:00
if ( m_rfState = = RS_RF_DATA ) {
// If valid is false, update the m_lastFICH for this transmission
if ( ! valid ) {
unsigned char ft = m_lastFICH . getFT ( ) ;
unsigned char fn = m_lastFICH . getFN ( ) + 1U ;
2017-08-14 16:34:04 +00:00
2017-08-19 11:08:28 +00:00
if ( fn > ft )
fn = 0U ;
2017-08-14 16:34:04 +00:00
2017-08-19 11:08:28 +00:00
m_lastFICH . setFN ( fn ) ;
}
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
CSync : : addYSFSync ( data + 2U ) ;
2016-04-21 17:00:26 +00:00
2017-08-19 11:08:28 +00:00
unsigned char fn = m_lastFICH . getFN ( ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_rfPayload . processDataFRModeData ( data + 2U , fn ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
CYSFFICH fich = m_lastFICH ;
2017-08-14 13:08:43 +00:00
2018-02-27 18:34:32 +00:00
// Remove any DSQ/DG-ID information
2017-08-19 11:08:28 +00:00
fich . setSQL ( false ) ;
fich . setSQ ( 0U ) ;
fich . encode ( data + 2U ) ;
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-05-16 20:57:32 +00:00
2017-08-19 11:08:28 +00:00
writeNetwork ( data , m_rfFrames % 128U ) ;
2016-04-21 17:00:26 +00:00
2017-08-19 11:08:28 +00:00
if ( m_duplex ) {
2018-02-27 18:34:32 +00:00
// Add the DSQ/DG-ID information.
unsigned char cm = fich . getCM ( ) ;
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-19 11:08:28 +00:00
fich . setSQ ( m_sqlValue ) ;
2017-08-14 13:46:00 +00:00
2017-08-19 11:08:28 +00:00
fich . setMR ( m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY ) ;
fich . setDev ( m_lowDeviation ) ;
fich . encode ( data + 2U ) ;
writeQueueRF ( data ) ;
}
2016-04-21 17:00:26 +00:00
2016-02-16 17:37:12 +00:00
# if defined(DUMP_YSF)
2017-08-19 11:08:28 +00:00
writeFile ( data + 2U ) ;
2016-02-16 17:37:12 +00:00
# endif
2017-08-14 13:08:43 +00:00
2017-08-19 11:08:28 +00:00
m_rfFrames + + ;
2017-01-05 19:44:52 +00:00
2017-08-19 11:08:28 +00:00
m_display - > writeFusionRSSI ( m_rssi ) ;
return true ;
}
2016-02-16 07:27:13 +00:00
}
2017-08-19 11:08:28 +00:00
return false ;
2016-02-16 07:27:13 +00:00
}
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-15 05:32:56 +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 ;
2019-01-20 17:09:40 +00:00
if ( ! m_enabled )
return ;
2016-05-16 20:57:32 +00:00
if ( m_rfState ! = RS_RF_LISTENING & & m_netState = = RS_NET_IDLE )
return ;
m_networkWatchdog . start ( ) ;
2016-09-22 21:38:59 +00:00
bool gateway = : : memcmp ( data + 4U , m_callsign , YSF_CALLSIGN_LENGTH ) = = 0 ;
2016-06-09 18:51:23 +00:00
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 ;
2018-02-27 18:25:09 +00:00
: : memcpy ( m_netSource , data + 14U , YSF_CALLSIGN_LENGTH ) ;
: : memcpy ( m_netDest , data + 24U , YSF_CALLSIGN_LENGTH ) ;
2016-05-19 18:08:48 +00:00
2018-02-27 18:25:09 +00:00
if ( : : memcmp ( m_netSource , " " , 10U ) ! = 0 & & : : memcmp ( m_netDest , " " , 10U ) ! = 0 ) {
m_display - > writeFusion ( ( char * ) m_netSource , ( char * ) m_netDest , " N " , ( char * ) ( data + 4U ) ) ;
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
m_netTimeoutTimer . start ( ) ;
2016-05-23 20:45:52 +00:00
m_netPayload . reset ( ) ;
2016-07-15 05:32:56 +00:00
m_packetTimer . start ( ) ;
2016-07-12 17:20:48 +00:00
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-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-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-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 ( ) ;
2018-02-27 18:25:09 +00:00
unsigned char cm = fich . getCM ( ) ;
if ( : : memcmp ( m_netDest , " " , YSF_CALLSIGN_LENGTH ) = = 0 ) {
if ( cm = = YSF_CM_GROUP1 | | cm = = YSF_CM_GROUP2 )
: : memcpy ( m_netDest , " ALL " , YSF_CALLSIGN_LENGTH ) ;
}
2016-05-23 20:45:52 +00:00
2018-02-27 18:34:32 +00:00
// Add any DSQ/DG-ID information
if ( cm = = YSF_CM_GROUP2 )
fich . setSQL ( false ) ;
else
fich . setSQL ( m_sqlEnabled ) ;
2017-08-13 09:30:02 +00:00
fich . setSQ ( m_sqlValue ) ;
2018-02-27 18:34:32 +00:00
if ( m_remoteGateway ) {
fich . setVoIP ( false ) ;
2018-10-24 00:59:10 +00:00
fich . setMR ( YSF_MR_DIRECT ) ;
2018-02-27 18:34:32 +00:00
} else {
fich . setVoIP ( true ) ;
fich . setMR ( YSF_MR_BUSY ) ;
}
2017-03-23 20:26:17 +00:00
fich . setDev ( m_lowDeviation ) ;
2016-07-12 18:02:36 +00:00
fich . encode ( data + 35U ) ;
2016-05-23 20:45:52 +00:00
// Set the downlink callsign
switch ( fi ) {
2018-02-27 18:25:09 +00:00
case YSF_FI_HEADER : {
bool ok = m_netPayload . processHeaderData ( data + 35U ) ;
if ( ok )
processNetCallsigns ( data ) ;
2018-02-26 21:59:18 +00:00
}
break ;
2016-05-23 20:45:52 +00:00
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 : {
2018-02-27 18:25:09 +00:00
bool ok = m_netPayload . processVDMode1Data ( data + 35U , fn , gateway ) ;
if ( ok )
processNetCallsigns ( data ) ;
2016-06-16 16:33:53 +00:00
unsigned int errors = m_netPayload . processVDMode1Audio ( data + 35U ) ;
2017-08-14 13:08:43 +00:00
m_netErrs + = errors ;
m_netBits + = 235U ;
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 : {
2018-02-27 18:25:09 +00:00
bool ok = m_netPayload . processVDMode2Data ( data + 35U , fn , gateway ) ;
if ( ok )
processNetCallsigns ( data ) ;
2016-06-16 16:33:53 +00:00
unsigned int errors = m_netPayload . processVDMode2Audio ( data + 35U ) ;
2017-08-14 13:08:43 +00:00
m_netErrs + = errors ;
m_netBits + = 135U ;
2016-06-16 16:33:53 +00:00
}
2016-05-23 20:45:52 +00:00
break ;
case YSF_DT_DATA_FR_MODE :
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 ) ;
2017-08-14 13:08:43 +00:00
m_netErrs + = errors ;
m_netBits + = 720U ;
2016-05-25 06:51:42 +00:00
}
2016-05-23 20:45:52 +00:00
break ;
default :
break ;
}
break ;
default :
break ;
}
2016-05-17 05:30:59 +00:00
}
2017-08-13 09:30:02 +00:00
writeQueueNet ( data + 33U ) ;
m_packetTimer . start ( ) ;
m_netFrames + + ;
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-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 ;
}
}
2017-08-15 09:11:05 +00:00
bool CYSFControl : : checkCallsign ( const unsigned char * callsign ) const
{
return : : memcmp ( callsign , m_selfCallsign , : : strlen ( ( char * ) m_selfCallsign ) ) = = 0 ;
}
2018-02-27 18:25:09 +00:00
void CYSFControl : : processNetCallsigns ( const unsigned char * data )
{
assert ( data ! = NULL ) ;
if ( : : memcmp ( m_netSource , " " , 10U ) = = 0 | | : : memcmp ( m_netDest , " " , 10U ) = = 0 ) {
if ( : : memcmp ( m_netSource , " " , YSF_CALLSIGN_LENGTH ) = = 0 ) {
unsigned char * source = m_netPayload . getSource ( ) ;
if ( source ! = NULL )
: : memcpy ( m_netSource , source , YSF_CALLSIGN_LENGTH ) ;
}
if ( : : memcmp ( m_netDest , " " , YSF_CALLSIGN_LENGTH ) = = 0 ) {
unsigned char * dest = m_netPayload . getDest ( ) ;
if ( dest ! = NULL )
: : memcpy ( m_netDest , dest , YSF_CALLSIGN_LENGTH ) ;
}
if ( : : memcmp ( m_netSource , " " , 10U ) ! = 0 & & : : memcmp ( m_netDest , " " , 10U ) ! = 0 ) {
m_display - > writeFusion ( ( char * ) m_netSource , ( char * ) m_netDest , " N " , ( char * ) ( data + 4U ) ) ;
LogMessage ( " YSF, received network data from %10.10s to %10.10s at %10.10s " , m_netSource , m_netDest , data + 4U ) ;
}
}
}
2019-01-10 09:05:15 +00:00
bool CYSFControl : : isBusy ( ) const
{
return m_rfState ! = RS_RF_LISTENING | | m_netState ! = RS_NET_IDLE ;
}
2019-01-19 17:15:24 +00:00
void CYSFControl : : enable ( bool enabled )
{
if ( ! enabled & & m_enabled ) {
m_queue . clear ( ) ;
// Reset the RF section
m_rfState = RS_RF_LISTENING ;
m_rfTimeoutTimer . stop ( ) ;
m_rfPayload . reset ( ) ;
// These variables are free'd by YSFPayload
m_rfSource = NULL ;
m_rfDest = NULL ;
// Reset the networking section
m_netState = RS_NET_IDLE ;
m_netTimeoutTimer . stop ( ) ;
m_networkWatchdog . stop ( ) ;
m_packetTimer . stop ( ) ;
m_netPayload . reset ( ) ;
}
m_enabled = enabled ;
}