2016-01-14 18:45:04 +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 .
*/
2016-02-15 18:45:57 +00:00
# include "DMRSlotType.h"
# include "DMRShortLC.h"
2016-07-07 19:23:30 +00:00
# include "DMRTrellis.h"
2016-02-15 18:45:57 +00:00
# include "DMRFullLC.h"
2016-02-24 07:37:58 +00:00
# include "BPTC19696.h"
2016-01-14 18:45:04 +00:00
# include "DMRSlot.h"
2016-02-15 18:45:57 +00:00
# include "DMRCSBK.h"
2016-01-14 18:45:04 +00:00
# include "Utils.h"
2016-02-15 18:45:57 +00:00
# include "Sync.h"
2016-01-14 18:45:04 +00:00
# include "CRC.h"
# include "Log.h"
2016-07-10 10:47:23 +00:00
# include "DMRAccessControl.h"
2016-01-14 18:45:04 +00:00
# include <cassert>
# include <ctime>
2016-04-06 16:24:14 +00:00
# include <algorithm>
2016-01-14 18:45:04 +00:00
2016-04-04 16:40:05 +00:00
unsigned int CDMRSlot : : m_id = 0U ;
2016-02-15 18:45:57 +00:00
unsigned int CDMRSlot : : m_colorCode = 0U ;
2016-04-04 16:40:05 +00:00
bool CDMRSlot : : m_selfOnly = false ;
2016-04-04 18:03:38 +00:00
std : : vector < unsigned int > CDMRSlot : : m_prefixes ;
2016-04-06 17:46:05 +00:00
std : : vector < unsigned int > CDMRSlot : : m_blackList ;
2016-07-10 20:37:11 +00:00
2016-02-15 18:45:57 +00:00
CModem * CDMRSlot : : m_modem = NULL ;
CDMRIPSC * CDMRSlot : : m_network = NULL ;
2016-05-09 17:14:27 +00:00
CDisplay * CDMRSlot : : m_display = NULL ;
2016-02-15 18:45:57 +00:00
bool CDMRSlot : : m_duplex = true ;
2016-04-12 17:26:13 +00:00
CDMRLookup * CDMRSlot : : m_lookup = NULL ;
2016-06-16 20:40:05 +00:00
unsigned int CDMRSlot : : m_hangCount = 3U * 17U ;
2016-01-14 18:45:04 +00:00
2016-08-08 20:26:18 +00:00
int CDMRSlot : : m_rssiMultiplier = 0 ;
int CDMRSlot : : m_rssiOffset = 0 ;
2016-02-15 18:45:57 +00:00
unsigned char * CDMRSlot : : m_idle = NULL ;
2016-01-14 18:45:04 +00:00
2016-02-15 18:45:57 +00:00
FLCO CDMRSlot : : m_flco1 ;
unsigned char CDMRSlot : : m_id1 = 0U ;
bool CDMRSlot : : m_voice1 = true ;
FLCO CDMRSlot : : m_flco2 ;
unsigned char CDMRSlot : : m_id2 = 0U ;
bool CDMRSlot : : m_voice2 = true ;
2016-01-14 18:45:04 +00:00
// #define DUMP_DMR
CDMRSlot : : CDMRSlot ( unsigned int slotNo , unsigned int timeout ) :
m_slotNo ( slotNo ) ,
2016-05-10 17:54:35 +00:00
m_queue ( 5000U , " DMR Slot " ) ,
2016-02-25 19:54:18 +00:00
m_rfState ( RS_RF_LISTENING ) ,
m_netState ( RS_NET_IDLE ) ,
2016-02-28 17:18:13 +00:00
m_rfEmbeddedLC ( ) ,
2016-02-29 07:27:10 +00:00
m_netEmbeddedLC ( ) ,
2016-02-25 19:54:18 +00:00
m_rfLC ( NULL ) ,
m_netLC ( NULL ) ,
2016-02-28 18:22:17 +00:00
m_rfDataHeader ( ) ,
m_netDataHeader ( ) ,
2016-02-28 17:40:15 +00:00
m_rfSeqNo ( 0U ) ,
2016-02-28 17:18:13 +00:00
m_netSeqNo ( 0U ) ,
m_rfN ( 0U ) ,
m_netN ( 0U ) ,
2016-01-21 18:38:45 +00:00
m_networkWatchdog ( 1000U , 0U , 1500U ) ,
2016-02-25 19:54:18 +00:00
m_rfTimeoutTimer ( 1000U , timeout ) ,
m_netTimeoutTimer ( 1000U , timeout ) ,
2016-08-09 06:35:31 +00:00
m_packetTimer ( 1000U , 0U , 400U ) ,
2016-03-14 20:55:15 +00:00
m_interval ( ) ,
2016-01-19 19:34:49 +00:00
m_elapsed ( ) ,
2016-02-25 19:54:18 +00:00
m_rfFrames ( 0U ) ,
m_netFrames ( 0U ) ,
m_netLost ( 0U ) ,
2016-01-19 20:13:20 +00:00
m_fec ( ) ,
2016-07-21 16:46:37 +00:00
m_rfBits ( 1U ) ,
m_netBits ( 1U ) ,
2016-02-25 19:54:18 +00:00
m_rfErrs ( 0U ) ,
m_netErrs ( 0U ) ,
2016-01-25 21:56:57 +00:00
m_lastFrame ( NULL ) ,
2016-07-21 17:09:29 +00:00
m_lastFrameValid ( false ) ,
2016-01-25 21:56:57 +00:00
m_lastEMB ( ) ,
2016-08-08 20:26:18 +00:00
m_rssi ( 0 ) ,
2016-01-14 18:45:04 +00:00
m_fp ( NULL )
{
2016-01-25 21:56:57 +00:00
m_lastFrame = new unsigned char [ DMR_FRAME_LENGTH_BYTES + 2U ] ;
2016-03-14 20:55:15 +00:00
m_interval . start ( ) ;
2016-01-14 18:45:04 +00:00
}
CDMRSlot : : ~ CDMRSlot ( )
{
2016-01-25 21:56:57 +00:00
delete [ ] m_lastFrame ;
2016-01-14 18:45:04 +00:00
}
2016-08-08 20:26:18 +00:00
void CDMRSlot : : writeModem ( unsigned char * data , unsigned int len )
2016-01-14 18:45:04 +00:00
{
2016-03-07 20:21:55 +00:00
assert ( data ! = NULL ) ;
2016-02-25 19:54:18 +00:00
if ( data [ 0U ] = = TAG_LOST & & m_rfState = = RS_RF_AUDIO ) {
LogMessage ( " DMR Slot %u, RF transmission lost, %.1f seconds, BER: %.1f%% " , m_slotNo , float ( m_rfFrames ) / 16.667F , float ( m_rfErrs * 100U ) / float ( m_rfBits ) ) ;
writeEndRF ( true ) ;
2016-01-20 07:12:28 +00:00
return ;
}
2016-02-25 19:54:18 +00:00
if ( data [ 0U ] = = TAG_LOST & & m_rfState = = RS_RF_DATA ) {
LogMessage ( " DMR Slot %u, RF transmission lost " , m_slotNo ) ;
writeEndRF ( ) ;
2016-01-14 18:45:04 +00:00
return ;
}
2016-02-02 18:17:36 +00:00
if ( data [ 0U ] = = TAG_LOST ) {
2016-02-25 19:54:18 +00:00
m_rfState = RS_RF_LISTENING ;
2016-01-14 18:45:04 +00:00
return ;
}
2016-08-08 20:26:18 +00:00
// Have we got RSSI bytes on the end?
2016-08-09 05:24:13 +00:00
if ( len = = ( DMR_FRAME_LENGTH_BYTES + 4U ) & & m_rssiMultiplier ! = 0 ) {
2016-08-08 20:26:18 +00:00
uint16_t rssi = 0U ;
2016-08-09 05:24:13 +00:00
rssi | = ( data [ 35U ] < < 8 ) & 0xFF00U ;
rssi | = ( data [ 36U ] < < 0 ) & 0x00FFU ;
2016-08-08 20:26:18 +00:00
m_rssi = ( rssi - m_rssiOffset ) / m_rssiMultiplier ;
2016-08-09 05:46:04 +00:00
LogDebug ( " DMR Slot %u, raw RSSI: %u, reported RSSI: %d dBm " , m_slotNo , rssi , m_rssi ) ;
2016-08-08 20:26:18 +00:00
}
2016-01-14 18:45:04 +00:00
bool dataSync = ( data [ 1U ] & DMR_SYNC_DATA ) = = DMR_SYNC_DATA ;
bool audioSync = ( data [ 1U ] & DMR_SYNC_AUDIO ) = = DMR_SYNC_AUDIO ;
if ( dataSync ) {
2016-02-15 18:45:57 +00:00
CDMRSlotType slotType ;
2016-01-14 18:45:04 +00:00
slotType . putData ( data + 2U ) ;
2016-01-19 17:43:33 +00:00
unsigned char dataType = slotType . getDataType ( ) ;
2016-01-14 18:45:04 +00:00
if ( dataType = = DT_VOICE_LC_HEADER ) {
2016-02-25 19:54:18 +00:00
if ( m_rfState = = RS_RF_AUDIO )
2016-01-18 18:36:14 +00:00
return ;
2016-01-14 18:45:04 +00:00
2016-02-15 18:45:57 +00:00
CDMRFullLC fullLC ;
2016-04-04 16:40:05 +00:00
CDMRLC * lc = fullLC . decode ( data + 2U , DT_VOICE_LC_HEADER ) ;
2016-04-28 08:58:45 +00:00
if ( lc = = NULL )
2016-01-18 18:36:14 +00:00
return ;
2016-01-14 18:45:04 +00:00
2016-06-16 20:40:05 +00:00
unsigned int id = lc - > getSrcId ( ) ;
unsigned int did = lc - > getDstId ( ) ;
2016-07-21 16:46:37 +00:00
if ( ! DMRAccessControl : : validateAccess ( id , did , m_slotNo , false ) ) {
2016-07-10 17:35:23 +00:00
delete lc ;
return ;
2016-06-07 14:34:16 +00:00
}
2016-07-10 17:35:23 +00:00
2016-04-04 16:40:05 +00:00
m_rfLC = lc ;
2016-02-29 07:27:10 +00:00
// Store the LC for the embedded LC
m_rfEmbeddedLC . setData ( * m_rfLC ) ;
2016-02-22 18:12:24 +00:00
// Regenerate the LC data
2016-02-25 19:54:18 +00:00
fullLC . encode ( * m_rfLC , data + 2U , DT_VOICE_LC_HEADER ) ;
2016-02-22 18:12:24 +00:00
2016-01-18 18:36:14 +00:00
// Regenerate the Slot Type
slotType . getData ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-01-18 18:36:14 +00:00
// Convert the Data Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-01-18 18:36:14 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
m_rfTimeoutTimer . start ( ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
m_rfFrames = 0U ;
2016-02-28 17:40:15 +00:00
m_rfSeqNo = 0U ;
2016-02-25 19:54:18 +00:00
m_rfBits = 1U ;
m_rfErrs = 0U ;
2016-01-19 20:13:20 +00:00
2016-02-15 18:01:21 +00:00
if ( m_duplex ) {
2016-06-20 09:01:09 +00:00
m_queue . clear ( ) ;
m_modem - > writeDMRAbort ( m_slotNo ) ;
2016-03-29 17:06:17 +00:00
writeQueueRF ( data ) ;
writeQueueRF ( data ) ;
2016-05-03 20:18:44 +00:00
writeQueueRF ( data ) ;
2016-01-18 18:36:14 +00:00
}
2016-01-14 18:45:04 +00:00
2016-02-28 17:40:15 +00:00
writeNetworkRF ( data , DT_VOICE_LC_HEADER ) ;
2016-02-15 18:01:21 +00:00
2016-02-25 19:54:18 +00:00
m_rfState = RS_RF_AUDIO ;
2016-01-26 18:28:39 +00:00
2016-04-12 17:26:13 +00:00
std : : string src = m_lookup - > find ( id ) ;
2016-04-15 13:24:57 +00:00
std : : string dst = m_lookup - > find ( m_rfLC - > getDstId ( ) ) ;
2016-04-12 17:26:13 +00:00
2016-02-25 19:54:18 +00:00
if ( m_netState = = RS_NET_IDLE ) {
setShortLC ( m_slotNo , m_rfLC - > getDstId ( ) , m_rfLC - > getFLCO ( ) , true ) ;
2016-04-21 12:01:53 +00:00
m_display - > writeDMR ( m_slotNo , src , m_rfLC - > getFLCO ( ) = = FLCO_GROUP , dst , " R " ) ;
2016-02-25 19:54:18 +00:00
}
2016-01-18 18:36:14 +00:00
2016-04-15 13:24:57 +00:00
LogMessage ( " DMR Slot %u, received RF voice header from %s to %s%s " , m_slotNo , src . c_str ( ) , m_rfLC - > getFLCO ( ) = = FLCO_GROUP ? " TG " : " " , dst . c_str ( ) ) ;
2016-01-14 18:45:04 +00:00
} else if ( dataType = = DT_VOICE_PI_HEADER ) {
2016-02-25 19:54:18 +00:00
if ( m_rfState ! = RS_RF_AUDIO )
2016-01-18 18:36:14 +00:00
return ;
2016-01-14 18:45:04 +00:00
2016-01-18 18:36:14 +00:00
// Regenerate the Slot Type
slotType . getData ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-01-18 18:36:14 +00:00
// Convert the Data Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:59:09 +00:00
// Regenerate the payload
CBPTC19696 bptc ;
unsigned char payload [ 12U ] ;
bptc . decode ( data + 2U , payload ) ;
bptc . encode ( payload , data + 2U ) ;
2016-01-18 18:36:14 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-01-14 18:45:04 +00:00
2016-02-15 18:01:21 +00:00
if ( m_duplex )
2016-02-25 19:54:18 +00:00
writeQueueRF ( data ) ;
2016-02-15 18:01:21 +00:00
2016-02-25 19:54:18 +00:00
writeNetworkRF ( data , DT_VOICE_PI_HEADER ) ;
2016-01-18 18:36:14 +00:00
} else if ( dataType = = DT_TERMINATOR_WITH_LC ) {
2016-02-25 19:54:18 +00:00
if ( m_rfState ! = RS_RF_AUDIO )
2016-01-18 18:36:14 +00:00
return ;
2016-01-14 18:45:04 +00:00
2016-02-22 18:12:24 +00:00
// Regenerate the LC data
CDMRFullLC fullLC ;
2016-02-25 19:54:18 +00:00
fullLC . encode ( * m_rfLC , data + 2U , DT_TERMINATOR_WITH_LC ) ;
2016-02-22 18:12:24 +00:00
2016-01-18 18:36:14 +00:00
// Regenerate the Slot Type
slotType . getData ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-01-18 18:36:14 +00:00
// Set the Data Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-18 18:36:14 +00:00
data [ 0U ] = TAG_EOT ;
data [ 1U ] = 0x00U ;
2016-01-14 18:45:04 +00:00
2016-03-29 17:06:17 +00:00
writeNetworkRF ( data , DT_TERMINATOR_WITH_LC ) ;
writeNetworkRF ( data , DT_TERMINATOR_WITH_LC ) ;
2016-01-14 18:45:04 +00:00
2016-02-15 18:01:21 +00:00
if ( m_duplex ) {
2016-06-16 20:40:05 +00:00
for ( unsigned int i = 0U ; i < m_hangCount ; i + + )
writeQueueRF ( data ) ;
2016-02-15 18:01:21 +00:00
}
2016-01-21 18:38:45 +00:00
2016-02-25 19:54:18 +00:00
LogMessage ( " DMR Slot %u, received RF end of voice transmission, %.1f seconds, BER: %.1f%% " , m_slotNo , float ( m_rfFrames ) / 16.667F , float ( m_rfErrs * 100U ) / float ( m_rfBits ) ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
writeEndRF ( ) ;
2016-01-18 18:36:14 +00:00
} else if ( dataType = = DT_DATA_HEADER ) {
2016-04-26 17:22:47 +00:00
if ( m_rfState = = RS_RF_DATA )
return ;
2016-02-22 18:12:24 +00:00
CDMRDataHeader dataHeader ;
bool valid = dataHeader . put ( data + 2U ) ;
2016-04-28 08:58:45 +00:00
if ( ! valid )
2016-02-18 21:56:26 +00:00
return ;
2016-01-26 18:06:31 +00:00
2016-04-04 16:40:05 +00:00
bool gi = dataHeader . getGI ( ) ;
unsigned int srcId = dataHeader . getSrcId ( ) ;
unsigned int dstId = dataHeader . getDstId ( ) ;
2016-07-21 16:46:37 +00:00
if ( ! DMRAccessControl : : validateAccess ( srcId , dstId , m_slotNo , false ) )
2016-07-10 17:35:23 +00:00
return ;
2016-04-04 16:40:05 +00:00
2016-03-15 22:46:36 +00:00
m_rfFrames = dataHeader . getBlocks ( ) ;
2016-02-28 18:22:17 +00:00
m_rfDataHeader = dataHeader ;
2016-02-28 17:40:15 +00:00
m_rfSeqNo = 0U ;
2016-01-26 18:06:31 +00:00
2016-02-25 19:54:18 +00:00
m_rfLC = new CDMRLC ( gi ? FLCO_GROUP : FLCO_USER_USER , srcId , dstId ) ;
2016-01-26 18:06:31 +00:00
2016-02-22 18:12:24 +00:00
// Regenerate the data header
2016-03-14 17:33:05 +00:00
dataHeader . get ( data + 2U ) ;
2016-02-22 18:12:24 +00:00
2016-01-18 18:36:14 +00:00
// Regenerate the Slot Type
slotType . getData ( data + 2U ) ;
// Convert the Data Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-18 18:36:14 +00:00
2016-04-26 17:22:47 +00:00
data [ 0U ] = m_rfFrames = = 0U ? TAG_EOT : TAG_DATA ;
2016-01-18 18:36:14 +00:00
data [ 1U ] = 0x00U ;
2016-03-11 06:50:06 +00:00
if ( m_duplex )
writeQueueRF ( data ) ;
2016-01-14 18:45:04 +00:00
2016-02-28 17:40:15 +00:00
writeNetworkRF ( data , DT_DATA_HEADER ) ;
2016-01-18 18:36:14 +00:00
2016-02-25 19:54:18 +00:00
m_rfState = RS_RF_DATA ;
2016-01-26 18:06:31 +00:00
2016-04-12 17:26:13 +00:00
std : : string src = m_lookup - > find ( srcId ) ;
2016-04-15 13:24:57 +00:00
std : : string dst = m_lookup - > find ( dstId ) ;
2016-04-12 17:26:13 +00:00
2016-02-25 19:54:18 +00:00
if ( m_netState = = RS_NET_IDLE ) {
setShortLC ( m_slotNo , dstId , gi ? FLCO_GROUP : FLCO_USER_USER , false ) ;
2016-04-21 12:01:53 +00:00
m_display - > writeDMR ( m_slotNo , src , gi , dst , " R " ) ;
2016-02-25 19:54:18 +00:00
}
2016-01-18 18:36:14 +00:00
2016-04-15 13:24:57 +00:00
LogMessage ( " DMR Slot %u, received RF data header from %s to %s%s, %u blocks " , m_slotNo , src . c_str ( ) , gi ? " TG " : " " , dst . c_str ( ) , m_rfFrames ) ;
2016-04-26 17:22:47 +00:00
if ( m_rfFrames = = 0U )
endOfRFData ( ) ;
2016-01-25 21:56:57 +00:00
} else if ( dataType = = DT_CSBK ) {
2016-02-22 18:12:24 +00:00
CDMRCSBK csbk ;
bool valid = csbk . put ( data + 2U ) ;
2016-04-28 08:58:45 +00:00
if ( ! valid )
2016-02-18 21:56:26 +00:00
return ;
2016-01-25 21:56:57 +00:00
CSBKO csbko = csbk . getCSBKO ( ) ;
2016-03-14 17:33:05 +00:00
if ( csbko = = CSBKO_BSDWNACT )
2016-01-25 21:56:57 +00:00
return ;
2016-03-14 21:22:09 +00:00
bool gi = csbk . getGI ( ) ;
unsigned int srcId = csbk . getSrcId ( ) ;
unsigned int dstId = csbk . getDstId ( ) ;
2016-07-21 16:46:37 +00:00
if ( ! DMRAccessControl : : validateAccess ( srcId , dstId , m_slotNo , false ) )
2016-07-10 17:35:23 +00:00
return ;
2016-04-04 16:40:05 +00:00
2016-03-14 17:33:05 +00:00
// Regenerate the CSBK data
csbk . get ( data + 2U ) ;
2016-02-22 18:12:24 +00:00
2016-03-14 17:33:05 +00:00
// Regenerate the Slot Type
slotType . getData ( data + 2U ) ;
2016-01-26 18:06:31 +00:00
2016-03-14 17:33:05 +00:00
// Convert the Data Sync to be from the BS
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-25 21:56:57 +00:00
2016-03-14 17:33:05 +00:00
m_rfSeqNo = 0U ;
2016-02-28 17:40:15 +00:00
2016-03-14 17:33:05 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-01-25 21:56:57 +00:00
2016-03-14 17:33:05 +00:00
if ( m_duplex )
writeQueueRF ( data ) ;
2016-02-15 18:01:21 +00:00
2016-03-14 21:22:09 +00:00
writeNetworkRF ( data , DT_CSBK , gi ? FLCO_GROUP : FLCO_USER_USER , srcId , dstId ) ;
2016-01-25 22:36:16 +00:00
2016-04-28 09:32:11 +00:00
std : : string src = m_lookup - > find ( srcId ) ;
std : : string dst = m_lookup - > find ( dstId ) ;
2016-03-14 17:33:05 +00:00
switch ( csbko ) {
case CSBKO_UUVREQ :
2016-04-28 09:32:11 +00:00
LogMessage ( " DMR Slot %u, received RF Unit to Unit Voice Service Request CSBK from %s to %s%s " , m_slotNo , src . c_str ( ) , gi ? " TG " : " " , dst . c_str ( ) ) ;
2016-03-14 17:33:05 +00:00
break ;
case CSBKO_UUANSRSP :
2016-04-28 09:32:11 +00:00
LogMessage ( " DMR Slot %u, received RF Unit to Unit Voice Service Answer Response CSBK from %s to %s%s " , m_slotNo , src . c_str ( ) , gi ? " TG " : " " , dst . c_str ( ) ) ;
2016-03-14 17:33:05 +00:00
break ;
case CSBKO_NACKRSP :
2016-04-28 09:32:11 +00:00
LogMessage ( " DMR Slot %u, received RF Negative Acknowledgment Response CSBK from %s to %s%s " , m_slotNo , src . c_str ( ) , gi ? " TG " : " " , dst . c_str ( ) ) ;
2016-03-14 17:33:05 +00:00
break ;
case CSBKO_PRECCSBK :
2016-04-28 09:32:11 +00:00
LogMessage ( " DMR Slot %u, received RF Preamble CSBK from %s to %s%s " , m_slotNo , src . c_str ( ) , gi ? " TG " : " " , dst . c_str ( ) ) ;
2016-01-25 21:56:57 +00:00
break ;
default :
2016-01-25 22:36:16 +00:00
LogWarning ( " DMR Slot %u, unhandled RF CSBK type - 0x%02X " , m_slotNo , csbko ) ;
2016-01-25 21:56:57 +00:00
break ;
}
2016-01-26 18:06:31 +00:00
} else if ( dataType = = DT_RATE_12_DATA | | dataType = = DT_RATE_34_DATA | | dataType = = DT_RATE_1_DATA ) {
2016-03-14 21:22:09 +00:00
if ( m_rfState ! = RS_RF_DATA | | m_rfFrames = = 0U )
2016-01-26 18:06:31 +00:00
return ;
2016-04-19 18:46:16 +00:00
// Regenerate the rate 1/2 payload
2016-03-10 17:18:40 +00:00
if ( dataType = = DT_RATE_12_DATA ) {
CBPTC19696 bptc ;
unsigned char payload [ 12U ] ;
bptc . decode ( data + 2U , payload ) ;
bptc . encode ( payload , data + 2U ) ;
2016-07-07 13:05:38 +00:00
} else if ( dataType = = DT_RATE_34_DATA ) {
2016-07-07 19:23:30 +00:00
CDMRTrellis trellis ;
unsigned char payload [ 18U ] ;
2016-07-14 17:58:03 +00:00
bool ret = trellis . decode ( data + 2U , payload ) ;
2016-08-08 17:05:14 +00:00
if ( ret ) {
2016-07-14 17:58:03 +00:00
trellis . encode ( payload , data + 2U ) ;
2016-08-08 17:05:14 +00:00
} else {
LogDebug ( " DMR Slot %u, unfixable rate 3/4 data " , m_slotNo ) ;
CUtils : : dump ( 1U , " Data " , data + 2U , DMR_FRAME_LENGTH_BYTES ) ;
}
2016-03-10 17:18:40 +00:00
}
2016-01-14 18:45:04 +00:00
// Regenerate the Slot Type
slotType . getData ( data + 2U ) ;
// Convert the Data Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
m_rfFrames - - ;
2016-01-26 18:06:31 +00:00
2016-02-25 19:54:18 +00:00
data [ 0U ] = m_rfFrames = = 0U ? TAG_EOT : TAG_DATA ;
2016-01-14 18:45:04 +00:00
data [ 1U ] = 0x00U ;
2016-02-15 18:01:21 +00:00
if ( m_duplex )
2016-02-25 19:54:18 +00:00
writeQueueRF ( data ) ;
2016-02-15 18:01:21 +00:00
2016-02-25 19:54:18 +00:00
writeNetworkRF ( data , dataType ) ;
2016-01-26 18:06:31 +00:00
2016-04-26 17:22:47 +00:00
if ( m_rfFrames = = 0U )
endOfRFData ( ) ;
2016-01-14 18:45:04 +00:00
}
} else if ( audioSync ) {
2016-02-25 19:54:18 +00:00
if ( m_rfState = = RS_RF_AUDIO ) {
2016-01-14 18:45:04 +00:00
// Convert the Audio Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRAudioSync ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-03-23 17:30:06 +00:00
unsigned int errors = 0U ;
2016-02-25 19:54:18 +00:00
unsigned char fid = m_rfLC - > getFID ( ) ;
2016-02-18 18:18:37 +00:00
if ( fid = = FID_ETSI | | fid = = FID_DMRA ) {
2016-03-23 17:30:06 +00:00
errors = m_fec . regenerateDMR ( data + 2U ) ;
2016-06-01 08:43:39 +00:00
LogDebug ( " DMR Slot %u, audio sequence no. 0, errs: %u/141 " , m_slotNo , errors ) ;
2016-02-25 19:54:18 +00:00
m_rfErrs + = errors ;
2016-02-18 18:18:37 +00:00
}
2016-02-25 19:54:18 +00:00
m_rfBits + = 141U ;
2016-01-14 18:45:04 +00:00
2016-04-26 18:10:45 +00:00
m_rfFrames + + ;
2016-01-14 18:45:04 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-01-18 18:36:14 +00:00
2016-02-15 18:01:21 +00:00
if ( m_duplex )
2016-02-25 19:54:18 +00:00
writeQueueRF ( data ) ;
2016-02-15 18:01:21 +00:00
2016-03-23 17:30:06 +00:00
writeNetworkRF ( data , DT_VOICE_SYNC , errors ) ;
2016-02-25 19:54:18 +00:00
} else if ( m_rfState = = RS_RF_LISTENING ) {
m_rfState = RS_RF_LATE_ENTRY ;
2016-01-14 18:45:04 +00:00
}
} else {
2016-02-29 06:41:19 +00:00
if ( m_rfState = = RS_RF_AUDIO ) {
2016-02-29 06:51:34 +00:00
m_rfN = data [ 1U ] & 0x0FU ;
2016-02-29 07:27:10 +00:00
// Regenerate the embedded LC
unsigned char lcss = m_rfEmbeddedLC . getData ( data + 2U , m_rfN ) ;
2016-02-23 21:01:14 +00:00
CDMREMB emb ;
emb . putData ( data + 2U ) ;
2016-01-19 17:43:33 +00:00
2016-01-14 18:45:04 +00:00
// Regenerate the EMB
emb . setColorCode ( m_colorCode ) ;
2016-02-29 07:27:10 +00:00
emb . setLCSS ( lcss ) ;
2016-01-14 18:45:04 +00:00
emb . getData ( data + 2U ) ;
2016-03-23 17:30:06 +00:00
unsigned int errors = 0U ;
2016-02-25 19:54:18 +00:00
unsigned char fid = m_rfLC - > getFID ( ) ;
2016-02-18 18:18:37 +00:00
if ( fid = = FID_ETSI | | fid = = FID_DMRA ) {
2016-03-23 17:30:06 +00:00
errors = m_fec . regenerateDMR ( data + 2U ) ;
2016-06-01 08:43:39 +00:00
LogDebug ( " DMR Slot %u, audio sequence no. %u, errs: %u/141 " , m_slotNo , m_rfN , errors ) ;
2016-02-25 19:54:18 +00:00
m_rfErrs + = errors ;
2016-02-18 18:18:37 +00:00
}
2016-02-25 19:54:18 +00:00
m_rfBits + = 141U ;
2016-01-14 18:45:04 +00:00
2016-04-26 18:10:45 +00:00
m_rfFrames + + ;
2016-01-14 18:45:04 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-01-18 18:36:14 +00:00
2016-02-15 18:01:21 +00:00
if ( m_duplex )
2016-02-25 19:54:18 +00:00
writeQueueRF ( data ) ;
2016-02-15 18:01:21 +00:00
2016-03-23 17:30:06 +00:00
writeNetworkRF ( data , DT_VOICE , errors ) ;
2016-02-25 19:54:18 +00:00
} else if ( m_rfState = = RS_RF_LATE_ENTRY ) {
2016-02-23 21:01:14 +00:00
CDMREMB emb ;
emb . putData ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
// If we haven't received an LC yet, then be strict on the color code
unsigned char colorCode = emb . getColorCode ( ) ;
if ( colorCode ! = m_colorCode )
return ;
2016-04-04 16:40:05 +00:00
CDMRLC * lc = m_rfEmbeddedLC . addData ( data + 2U , emb . getLCSS ( ) ) ;
if ( lc ! = NULL ) {
2016-07-10 17:35:23 +00:00
unsigned int id = lc - > getSrcId ( ) ;
2016-06-16 20:40:05 +00:00
unsigned int did = lc - > getDstId ( ) ;
2016-07-10 17:35:23 +00:00
if ( ! DMRAccessControl : : validateAccess ( id , did , m_slotNo , false ) ) {
delete lc ;
return ;
2016-06-16 20:40:05 +00:00
}
2016-04-04 16:40:05 +00:00
m_rfLC = lc ;
2016-02-29 07:27:10 +00:00
// Store the LC for the embedded LC
m_rfEmbeddedLC . setData ( * m_rfLC ) ;
2016-01-14 18:45:04 +00:00
// Create a dummy start frame to replace the received frame
unsigned char start [ DMR_FRAME_LENGTH_BYTES + 2U ] ;
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-02-15 18:45:57 +00:00
CDMRFullLC fullLC ;
2016-02-25 19:54:18 +00:00
fullLC . encode ( * m_rfLC , start + 2U , DT_VOICE_LC_HEADER ) ;
2016-01-14 18:45:04 +00:00
2016-02-15 18:45:57 +00:00
CDMRSlotType slotType ;
2016-01-14 18:45:04 +00:00
slotType . setColorCode ( m_colorCode ) ;
slotType . setDataType ( DT_VOICE_LC_HEADER ) ;
slotType . getData ( start + 2U ) ;
start [ 0U ] = TAG_DATA ;
start [ 1U ] = 0x00U ;
2016-02-25 19:54:18 +00:00
m_rfTimeoutTimer . start ( ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
m_rfFrames = 0U ;
2016-02-28 17:40:15 +00:00
m_rfSeqNo = 0U ;
m_rfBits = 1U ;
m_rfErrs = 0U ;
2016-01-19 20:13:20 +00:00
2016-02-15 18:01:21 +00:00
if ( m_duplex ) {
2016-06-20 09:01:09 +00:00
m_queue . clear ( ) ;
m_modem - > writeDMRAbort ( m_slotNo ) ;
2016-03-29 17:06:17 +00:00
writeQueueRF ( start ) ;
writeQueueRF ( start ) ;
2016-05-03 20:18:44 +00:00
writeQueueRF ( start ) ;
2016-01-14 18:45:04 +00:00
}
2016-02-28 17:40:15 +00:00
writeNetworkRF ( start , DT_VOICE_LC_HEADER ) ;
2016-02-15 18:01:21 +00:00
2016-02-29 06:51:34 +00:00
m_rfN = data [ 1U ] & 0x0FU ;
2016-02-29 07:27:10 +00:00
// Regenerate the embedded LC
unsigned char lcss = m_rfEmbeddedLC . getData ( data + 2U , m_rfN ) ;
2016-01-19 17:43:33 +00:00
// Regenerate the EMB
2016-02-29 07:27:10 +00:00
emb . setLCSS ( lcss ) ;
2016-01-19 17:43:33 +00:00
emb . getData ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
// Send the original audio frame out
2016-03-23 17:30:06 +00:00
unsigned int errors = 0U ;
2016-02-25 19:54:18 +00:00
unsigned char fid = m_rfLC - > getFID ( ) ;
2016-02-18 18:18:37 +00:00
if ( fid = = FID_ETSI | | fid = = FID_DMRA ) {
2016-03-23 17:30:06 +00:00
errors = m_fec . regenerateDMR ( data + 2U ) ;
2016-06-01 08:43:39 +00:00
LogDebug ( " DMR Slot %u, audio sequence no. %u, errs: %u/141 " , m_slotNo , m_rfN , errors ) ;
2016-02-25 19:54:18 +00:00
m_rfErrs + = errors ;
2016-02-18 18:18:37 +00:00
}
2016-02-25 19:54:18 +00:00
m_rfBits + = 141U ;
2016-01-14 18:45:04 +00:00
2016-04-26 18:10:45 +00:00
m_rfFrames + + ;
2016-01-14 18:45:04 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-01-18 18:36:14 +00:00
2016-02-15 18:01:21 +00:00
if ( m_duplex )
2016-02-25 19:54:18 +00:00
writeQueueRF ( data ) ;
2016-01-14 18:45:04 +00:00
2016-03-23 17:30:06 +00:00
writeNetworkRF ( data , DT_VOICE , errors ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
m_rfState = RS_RF_AUDIO ;
2016-01-14 18:45:04 +00:00
2016-04-12 17:26:13 +00:00
std : : string src = m_lookup - > find ( m_rfLC - > getSrcId ( ) ) ;
2016-04-15 13:24:57 +00:00
std : : string dst = m_lookup - > find ( m_rfLC - > getDstId ( ) ) ;
2016-04-12 17:26:13 +00:00
2016-02-25 19:54:18 +00:00
if ( m_netState = = RS_NET_IDLE ) {
setShortLC ( m_slotNo , m_rfLC - > getDstId ( ) , m_rfLC - > getFLCO ( ) , true ) ;
2016-04-21 12:01:53 +00:00
m_display - > writeDMR ( m_slotNo , src , m_rfLC - > getFLCO ( ) = = FLCO_GROUP , dst , " R " ) ;
2016-02-25 19:54:18 +00:00
}
2016-01-14 18:45:04 +00:00
2016-04-15 13:24:57 +00:00
LogMessage ( " DMR Slot %u, received RF late entry from %s to %s%s " , m_slotNo , src . c_str ( ) , m_rfLC - > getFLCO ( ) = = FLCO_GROUP ? " TG " : " " , dst . c_str ( ) ) ;
2016-01-14 18:45:04 +00:00
}
}
}
}
unsigned int CDMRSlot : : readModem ( unsigned char * data )
{
2016-03-07 20:21:55 +00:00
assert ( data ! = NULL ) ;
2016-03-07 18:08:50 +00:00
if ( m_queue . isEmpty ( ) )
2016-01-14 18:45:04 +00:00
return 0U ;
unsigned char len = 0U ;
2016-03-07 18:08:50 +00:00
m_queue . getData ( & len , 1U ) ;
2016-01-14 18:45:04 +00:00
2016-03-07 18:08:50 +00:00
m_queue . getData ( data , len ) ;
2016-01-14 18:45:04 +00:00
return len ;
}
2016-04-26 17:22:47 +00:00
void CDMRSlot : : endOfRFData ( )
{
LogMessage ( " DMR Slot %u, ended RF data transmission " , m_slotNo ) ;
if ( m_duplex ) {
unsigned char bytes [ DMR_FRAME_LENGTH_BYTES + 2U ] ;
CSync : : addDMRDataSync ( bytes + 2U ) ;
CDMRSlotType slotType ;
slotType . setDataType ( DT_TERMINATOR_WITH_LC ) ;
slotType . setColorCode ( m_colorCode ) ;
slotType . getData ( bytes + 2U ) ;
m_rfDataHeader . getTerminator ( bytes + 2U ) ;
2016-05-03 20:18:44 +00:00
bytes [ 0U ] = TAG_EOT ;
2016-04-26 17:22:47 +00:00
bytes [ 1U ] = 0x00U ;
2016-05-03 20:18:44 +00:00
writeQueueRF ( bytes ) ;
writeQueueRF ( bytes ) ;
writeQueueRF ( bytes ) ;
2016-04-26 17:22:47 +00:00
}
writeEndRF ( ) ;
}
2016-02-25 19:54:18 +00:00
void CDMRSlot : : writeEndRF ( bool writeEnd )
2016-01-14 18:45:04 +00:00
{
2016-02-25 19:54:18 +00:00
m_rfState = RS_RF_LISTENING ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
if ( m_netState = = RS_NET_IDLE ) {
setShortLC ( m_slotNo , 0U ) ;
m_display - > clearDMR ( m_slotNo ) ;
}
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
m_rfTimeoutTimer . stop ( ) ;
2016-01-27 06:49:16 +00:00
2016-02-25 19:54:18 +00:00
m_rfFrames = 0U ;
m_rfErrs = 0U ;
2016-07-21 16:46:37 +00:00
m_rfBits = 1U ;
2016-01-27 06:49:16 +00:00
2016-02-07 20:12:24 +00:00
if ( writeEnd ) {
2016-02-25 19:54:18 +00:00
if ( m_netState = = RS_NET_IDLE & & m_duplex ) {
2016-02-15 18:01:21 +00:00
// Create a dummy start end frame
unsigned char data [ DMR_FRAME_LENGTH_BYTES + 2U ] ;
2016-02-07 20:12:24 +00:00
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-02-07 20:12:24 +00:00
2016-02-15 18:45:57 +00:00
CDMRFullLC fullLC ;
2016-02-25 19:54:18 +00:00
fullLC . encode ( * m_rfLC , data + 2U , DT_TERMINATOR_WITH_LC ) ;
2016-02-07 20:12:24 +00:00
2016-02-15 18:45:57 +00:00
CDMRSlotType slotType ;
2016-02-15 18:01:21 +00:00
slotType . setColorCode ( m_colorCode ) ;
slotType . setDataType ( DT_TERMINATOR_WITH_LC ) ;
slotType . getData ( data + 2U ) ;
2016-02-07 20:12:24 +00:00
2016-05-03 20:18:44 +00:00
data [ 0U ] = TAG_EOT ;
2016-02-15 18:01:21 +00:00
data [ 1U ] = 0x00U ;
2016-02-07 20:12:24 +00:00
2016-06-16 20:40:05 +00:00
for ( unsigned int i = 0U ; i < m_hangCount ; i + + )
writeQueueRF ( data ) ;
2016-02-15 18:01:21 +00:00
}
2016-02-07 20:12:24 +00:00
}
2016-02-25 19:54:18 +00:00
delete m_rfLC ;
m_rfLC = NULL ;
}
2016-04-26 17:22:47 +00:00
void CDMRSlot : : endOfNetData ( )
{
LogMessage ( " DMR Slot %u, ended network data transmission " , m_slotNo ) ;
if ( m_duplex ) {
unsigned char bytes [ DMR_FRAME_LENGTH_BYTES + 2U ] ;
CSync : : addDMRDataSync ( bytes + 2U ) ;
CDMRSlotType slotType ;
slotType . setDataType ( DT_TERMINATOR_WITH_LC ) ;
slotType . setColorCode ( m_colorCode ) ;
slotType . getData ( bytes + 2U ) ;
m_netDataHeader . getTerminator ( bytes + 2U ) ;
2016-05-03 20:18:44 +00:00
bytes [ 0U ] = TAG_EOT ;
2016-04-26 17:22:47 +00:00
bytes [ 1U ] = 0x00U ;
2016-05-03 20:18:44 +00:00
writeQueueNet ( bytes ) ;
writeQueueNet ( bytes ) ;
writeQueueNet ( bytes ) ;
2016-04-26 17:22:47 +00:00
}
writeEndNet ( ) ;
}
2016-02-25 19:54:18 +00:00
void CDMRSlot : : writeEndNet ( bool writeEnd )
{
m_netState = RS_NET_IDLE ;
setShortLC ( m_slotNo , 0U ) ;
m_display - > clearDMR ( m_slotNo ) ;
2016-07-21 17:09:29 +00:00
m_lastFrameValid = false ;
2016-02-25 19:54:18 +00:00
m_networkWatchdog . stop ( ) ;
m_netTimeoutTimer . stop ( ) ;
2016-07-15 05:32:56 +00:00
m_packetTimer . stop ( ) ;
2016-02-25 19:54:18 +00:00
m_netFrames = 0U ;
m_netLost = 0U ;
m_netErrs = 0U ;
2016-07-21 16:46:37 +00:00
m_netBits = 1U ;
2016-02-25 19:54:18 +00:00
if ( writeEnd ) {
// Create a dummy start end frame
unsigned char data [ DMR_FRAME_LENGTH_BYTES + 2U ] ;
CSync : : addDMRDataSync ( data + 2U ) ;
CDMRFullLC fullLC ;
fullLC . encode ( * m_netLC , data + 2U , DT_TERMINATOR_WITH_LC ) ;
CDMRSlotType slotType ;
slotType . setColorCode ( m_colorCode ) ;
slotType . setDataType ( DT_TERMINATOR_WITH_LC ) ;
slotType . getData ( data + 2U ) ;
2016-05-03 20:18:44 +00:00
data [ 0U ] = TAG_EOT ;
2016-02-25 19:54:18 +00:00
data [ 1U ] = 0x00U ;
2016-06-20 09:01:09 +00:00
if ( m_duplex ) {
for ( unsigned int i = 0U ; i < m_hangCount ; i + + )
writeQueueNet ( data ) ;
} else {
for ( unsigned int i = 0U ; i < 3U ; i + + )
writeQueueNet ( data ) ;
}
2016-02-25 19:54:18 +00:00
}
delete m_netLC ;
m_netLC = NULL ;
2016-01-19 17:43:33 +00:00
# if defined(DUMP_DMR)
closeFile ( ) ;
# endif
2016-01-14 18:45:04 +00:00
}
2016-06-16 20:40:05 +00:00
void CDMRSlot : : writeNetwork ( const CDMRData & dmrData )
2016-01-14 18:45:04 +00:00
{
2016-02-25 19:54:18 +00:00
if ( m_rfState ! = RS_RF_LISTENING & & m_netState = = RS_NET_IDLE )
2016-01-14 18:45:04 +00:00
return ;
m_networkWatchdog . start ( ) ;
unsigned char dataType = dmrData . getDataType ( ) ;
unsigned char data [ DMR_FRAME_LENGTH_BYTES + 2U ] ;
dmrData . getData ( data + 2U ) ;
if ( dataType = = DT_VOICE_LC_HEADER ) {
2016-08-09 06:28:10 +00:00
if ( m_netState = = RS_NET_AUDIO )
2016-01-18 18:36:14 +00:00
return ;
2016-01-14 18:45:04 +00:00
2016-02-15 18:45:57 +00:00
CDMRFullLC fullLC ;
2016-02-25 19:54:18 +00:00
m_netLC = fullLC . decode ( data + 2U , DT_VOICE_LC_HEADER ) ;
if ( m_netLC = = NULL ) {
2016-01-18 18:36:14 +00:00
LogMessage ( " DMR Slot %u, bad LC received from the network " , m_slotNo ) ;
return ;
}
2016-01-14 18:45:04 +00:00
2016-06-16 20:40:05 +00:00
unsigned int did = m_netLC - > getDstId ( ) ;
2016-07-10 17:35:23 +00:00
unsigned int id = m_netLC - > getSrcId ( ) ;
2016-07-21 16:46:37 +00:00
if ( ! DMRAccessControl : : validateAccess ( id , did , m_slotNo , true ) )
2016-07-10 17:35:23 +00:00
return ;
2016-06-09 18:33:00 +00:00
2016-02-29 07:27:10 +00:00
// Store the LC for the embedded LC
m_netEmbeddedLC . setData ( * m_netLC ) ;
2016-02-22 18:12:24 +00:00
// Regenerate the LC data
2016-02-25 19:54:18 +00:00
fullLC . encode ( * m_netLC , data + 2U , DT_VOICE_LC_HEADER ) ;
2016-06-16 20:40:05 +00:00
2016-01-18 18:36:14 +00:00
// Regenerate the Slot Type
2016-02-15 18:45:57 +00:00
CDMRSlotType slotType ;
2016-01-18 18:36:14 +00:00
slotType . setColorCode ( m_colorCode ) ;
slotType . setDataType ( DT_VOICE_LC_HEADER ) ;
slotType . getData ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-01-18 18:36:14 +00:00
// Convert the Data Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-01-18 18:36:14 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-01-14 18:45:04 +00:00
2016-07-21 17:09:29 +00:00
m_lastFrameValid = false ;
2016-02-25 19:54:18 +00:00
m_netTimeoutTimer . start ( ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
m_netFrames = 0U ;
m_netLost = 0U ;
2016-01-19 19:34:49 +00:00
2016-02-25 19:54:18 +00:00
m_netBits = 1U ;
m_netErrs = 0U ;
2016-01-20 07:12:28 +00:00
2016-06-20 09:01:09 +00:00
if ( m_duplex ) {
m_queue . clear ( ) ;
m_modem - > writeDMRAbort ( m_slotNo ) ;
}
2016-05-03 20:18:44 +00:00
writeQueueNet ( m_idle ) ;
writeQueueNet ( m_idle ) ;
writeQueueNet ( m_idle ) ;
writeQueueNet ( m_idle ) ;
2016-01-27 06:49:16 +00:00
2016-05-03 20:18:44 +00:00
writeQueueNet ( data ) ;
2016-03-29 17:06:17 +00:00
writeQueueNet ( data ) ;
writeQueueNet ( data ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
m_netState = RS_NET_AUDIO ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
setShortLC ( m_slotNo , m_netLC - > getDstId ( ) , m_netLC - > getFLCO ( ) , true ) ;
2016-01-18 18:36:14 +00:00
2016-04-12 17:26:13 +00:00
std : : string src = m_lookup - > find ( m_netLC - > getSrcId ( ) ) ;
2016-04-15 13:24:57 +00:00
std : : string dst = m_lookup - > find ( m_netLC - > getDstId ( ) ) ;
2016-04-12 17:26:13 +00:00
2016-04-21 14:21:39 +00:00
m_display - > writeDMR ( m_slotNo , src , m_netLC - > getFLCO ( ) = = FLCO_GROUP , dst , " N " ) ;
2016-01-14 18:45:04 +00:00
# if defined(DUMP_DMR)
2016-01-18 18:36:14 +00:00
openFile ( ) ;
writeFile ( data ) ;
2016-01-14 18:45:04 +00:00
# endif
2016-04-15 13:24:57 +00:00
LogMessage ( " DMR Slot %u, received network voice header from %s to %s%s " , m_slotNo , src . c_str ( ) , m_netLC - > getFLCO ( ) = = FLCO_GROUP ? " TG " : " " , dst . c_str ( ) ) ;
2016-01-14 18:45:04 +00:00
} else if ( dataType = = DT_VOICE_PI_HEADER ) {
2016-02-25 19:54:18 +00:00
if ( m_netState ! = RS_NET_AUDIO )
2016-01-14 18:45:04 +00:00
return ;
2016-06-17 06:05:37 +00:00
unsigned int did = m_netLC - > getDstId ( ) ;
2016-07-10 17:35:23 +00:00
unsigned int id = m_netLC - > getSrcId ( ) ;
2016-07-21 16:46:37 +00:00
if ( ! DMRAccessControl : : validateAccess ( id , did , m_slotNo , true ) )
2016-07-10 17:35:23 +00:00
return ;
2016-06-17 06:05:37 +00:00
2016-01-14 18:45:04 +00:00
// Regenerate the Slot Type
2016-02-15 18:45:57 +00:00
CDMRSlotType slotType ;
2016-01-14 18:45:04 +00:00
slotType . setColorCode ( m_colorCode ) ;
slotType . setDataType ( DT_VOICE_PI_HEADER ) ;
slotType . getData ( data + 2U ) ;
// Convert the Data Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:59:09 +00:00
// Regenerate the payload
CBPTC19696 bptc ;
unsigned char payload [ 12U ] ;
bptc . decode ( data + 2U , payload ) ;
bptc . encode ( payload , data + 2U ) ;
2016-01-14 18:45:04 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-06-16 20:40:05 +00:00
2016-02-25 19:54:18 +00:00
writeQueueNet ( data ) ;
2016-01-14 18:45:04 +00:00
# if defined(DUMP_DMR)
writeFile ( data ) ;
# endif
} else if ( dataType = = DT_TERMINATOR_WITH_LC ) {
2016-02-25 19:54:18 +00:00
if ( m_netState ! = RS_NET_AUDIO )
2016-01-14 18:45:04 +00:00
return ;
2016-06-16 20:40:05 +00:00
unsigned int did = m_netLC - > getDstId ( ) ;
2016-07-10 17:35:23 +00:00
unsigned int id = m_netLC - > getSrcId ( ) ;
2016-07-21 16:46:37 +00:00
if ( ! DMRAccessControl : : validateAccess ( id , did , m_slotNo , true ) )
2016-07-10 17:35:23 +00:00
return ;
2016-06-17 06:05:37 +00:00
// Regenerate the LC data
CDMRFullLC fullLC ;
fullLC . encode ( * m_netLC , data + 2U , DT_TERMINATOR_WITH_LC ) ;
2016-01-14 18:45:04 +00:00
// Regenerate the Slot Type
2016-02-15 18:45:57 +00:00
CDMRSlotType slotType ;
2016-01-14 18:45:04 +00:00
slotType . setColorCode ( m_colorCode ) ;
slotType . setDataType ( DT_TERMINATOR_WITH_LC ) ;
slotType . getData ( data + 2U ) ;
// Convert the Data Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
data [ 0U ] = TAG_EOT ;
data [ 1U ] = 0x00U ;
2016-06-20 09:01:09 +00:00
if ( m_duplex ) {
for ( unsigned int i = 0U ; i < m_hangCount ; i + + )
writeQueueNet ( data ) ;
} else {
for ( unsigned int i = 0U ; i < 3U ; i + + )
writeQueueNet ( data ) ;
}
2016-01-21 18:38:45 +00:00
2016-01-14 18:45:04 +00:00
# if defined(DUMP_DMR)
writeFile ( data ) ;
closeFile ( ) ;
# endif
2016-01-19 19:34:49 +00:00
// We've received the voice header and terminator haven't we?
2016-02-25 19:54:18 +00:00
m_netFrames + = 2U ;
LogMessage ( " DMR Slot %u, received network end of voice transmission, %.1f seconds, %u%% packet loss, BER: %.1f%% " , m_slotNo , float ( m_netFrames ) / 16.667F , ( m_netLost * 100U ) / m_netFrames , float ( m_netErrs * 100U ) / float ( m_netBits ) ) ;
2016-04-26 18:10:45 +00:00
writeEndNet ( ) ;
2016-01-18 18:36:14 +00:00
} else if ( dataType = = DT_DATA_HEADER ) {
2016-04-26 17:22:47 +00:00
if ( m_netState = = RS_NET_DATA )
return ;
2016-02-22 18:12:24 +00:00
CDMRDataHeader dataHeader ;
bool valid = dataHeader . put ( data + 2U ) ;
if ( ! valid ) {
2016-03-14 21:22:09 +00:00
LogMessage ( " DMR Slot %u, unable to decode the network data header " , m_slotNo ) ;
2016-02-18 21:56:26 +00:00
return ;
}
2016-01-26 18:06:31 +00:00
2016-02-28 18:22:17 +00:00
m_netDataHeader = dataHeader ;
2016-01-26 18:06:31 +00:00
bool gi = dataHeader . getGI ( ) ;
unsigned int srcId = dataHeader . getSrcId ( ) ;
unsigned int dstId = dataHeader . getDstId ( ) ;
2016-07-21 16:46:37 +00:00
if ( ! DMRAccessControl : : validateAccess ( srcId , dstId , m_slotNo , true ) )
2016-07-10 17:35:23 +00:00
return ;
2016-06-17 06:05:37 +00:00
m_netFrames = dataHeader . getBlocks ( ) ;
2016-02-22 18:12:24 +00:00
// Regenerate the data header
2016-03-14 17:33:05 +00:00
dataHeader . get ( data + 2U ) ;
2016-02-22 18:12:24 +00:00
2016-01-18 18:36:14 +00:00
// Regenerate the Slot Type
2016-02-15 18:45:57 +00:00
CDMRSlotType slotType ;
2016-01-18 18:36:14 +00:00
slotType . setColorCode ( m_colorCode ) ;
slotType . setDataType ( DT_DATA_HEADER ) ;
slotType . getData ( data + 2U ) ;
// Convert the Data Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-18 18:36:14 +00:00
2016-04-26 17:22:47 +00:00
data [ 0U ] = m_netFrames = = 0U ? TAG_EOT : TAG_DATA ;
2016-01-18 18:36:14 +00:00
data [ 1U ] = 0x00U ;
2016-01-19 19:34:49 +00:00
// Put a small delay into starting transmission
2016-02-25 19:54:18 +00:00
writeQueueNet ( m_idle ) ;
writeQueueNet ( m_idle ) ;
2016-06-09 18:33:00 +00:00
2016-03-11 06:50:06 +00:00
writeQueueNet ( data ) ;
2016-01-18 18:36:14 +00:00
2016-02-25 19:54:18 +00:00
m_netState = RS_NET_DATA ;
2016-01-19 19:34:49 +00:00
2016-04-19 18:46:16 +00:00
setShortLC ( m_slotNo , dstId , gi ? FLCO_GROUP : FLCO_USER_USER , false ) ;
2016-01-18 18:36:14 +00:00
2016-04-19 18:46:16 +00:00
std : : string src = m_lookup - > find ( srcId ) ;
std : : string dst = m_lookup - > find ( dstId ) ;
2016-04-12 17:26:13 +00:00
2016-04-21 14:21:39 +00:00
m_display - > writeDMR ( m_slotNo , src , gi , dst , " N " ) ;
2016-01-18 18:36:14 +00:00
2016-04-15 13:24:57 +00:00
LogMessage ( " DMR Slot %u, received network data header from %s to %s%s, %u blocks " , m_slotNo , src . c_str ( ) , gi ? " TG " : " " , dst . c_str ( ) , m_netFrames ) ;
2016-04-26 17:22:47 +00:00
if ( m_netFrames = = 0U )
endOfNetData ( ) ;
2016-01-14 18:45:04 +00:00
} else if ( dataType = = DT_VOICE_SYNC ) {
2016-02-25 19:54:18 +00:00
if ( m_netState = = RS_NET_IDLE ) {
m_netLC = new CDMRLC ( dmrData . getFLCO ( ) , dmrData . getSrcId ( ) , dmrData . getDstId ( ) ) ;
2016-06-16 20:40:05 +00:00
2016-06-17 06:05:37 +00:00
unsigned int did = dmrData . getDstId ( ) ;
2016-07-10 17:35:23 +00:00
unsigned int id = dmrData . getSrcId ( ) ;
2016-07-21 16:46:37 +00:00
if ( ! DMRAccessControl : : validateAccess ( id , did , m_slotNo , true ) )
2016-07-10 17:35:23 +00:00
return ;
2016-07-21 17:09:29 +00:00
m_lastFrameValid = false ;
2016-02-25 19:54:18 +00:00
m_netTimeoutTimer . start ( ) ;
2016-01-14 18:45:04 +00:00
2016-06-20 09:01:09 +00:00
if ( m_duplex ) {
m_queue . clear ( ) ;
m_modem - > writeDMRAbort ( m_slotNo ) ;
}
2016-05-03 20:18:44 +00:00
writeQueueNet ( m_idle ) ;
writeQueueNet ( m_idle ) ;
writeQueueNet ( m_idle ) ;
writeQueueNet ( m_idle ) ;
// Create a dummy start frame
unsigned char start [ DMR_FRAME_LENGTH_BYTES + 2U ] ;
CSync : : addDMRDataSync ( start + 2U ) ;
CDMRFullLC fullLC ;
fullLC . encode ( * m_netLC , start + 2U , DT_VOICE_LC_HEADER ) ;
CDMRSlotType slotType ;
slotType . setColorCode ( m_colorCode ) ;
slotType . setDataType ( DT_VOICE_LC_HEADER ) ;
slotType . getData ( start + 2U ) ;
start [ 0U ] = TAG_DATA ;
start [ 1U ] = 0x00U ;
writeQueueRF ( start ) ;
writeQueueRF ( start ) ;
writeQueueRF ( start ) ;
2016-01-21 21:08:10 +00:00
2016-01-22 06:43:08 +00:00
# if defined(DUMP_DMR)
openFile ( ) ;
# endif
2016-02-25 19:54:18 +00:00
m_netFrames = 0U ;
m_netLost = 0U ;
m_netBits = 1U ;
m_netErrs = 0U ;
2016-01-21 21:08:10 +00:00
2016-02-25 19:54:18 +00:00
m_netState = RS_NET_AUDIO ;
2016-01-21 21:08:10 +00:00
2016-02-25 19:54:18 +00:00
setShortLC ( m_slotNo , m_netLC - > getDstId ( ) , m_netLC - > getFLCO ( ) , true ) ;
2016-06-09 18:33:00 +00:00
2016-04-12 17:26:13 +00:00
std : : string src = m_lookup - > find ( m_netLC - > getSrcId ( ) ) ;
2016-04-15 13:24:57 +00:00
std : : string dst = m_lookup - > find ( m_netLC - > getDstId ( ) ) ;
2016-04-12 17:26:13 +00:00
2016-04-21 14:21:39 +00:00
m_display - > writeDMR ( m_slotNo , src , m_netLC - > getFLCO ( ) = = FLCO_GROUP , dst , " N " ) ;
2016-01-22 06:43:08 +00:00
2016-04-15 13:24:57 +00:00
LogMessage ( " DMR Slot %u, received network late entry from %s to %s%s " , m_slotNo , src . c_str ( ) , m_netLC - > getFLCO ( ) = = FLCO_GROUP ? " TG " : " " , dst . c_str ( ) ) ;
2016-01-19 19:34:49 +00:00
}
2016-02-25 19:54:18 +00:00
if ( m_netState = = RS_NET_AUDIO ) {
2016-08-09 07:06:59 +00:00
LogDebug ( " DMR Slot %u, seq no: %u " , m_slotNo , dmrData . getSeqNo ( ) ) ;
2016-02-25 19:54:18 +00:00
unsigned char fid = m_netLC - > getFID ( ) ;
2016-06-01 08:43:39 +00:00
if ( fid = = FID_ETSI | | fid = = FID_DMRA )
m_netErrs + = m_fec . regenerateDMR ( data + 2U ) ;
2016-02-25 19:54:18 +00:00
m_netBits + = 141U ;
2016-01-25 21:56:57 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-01-22 06:43:08 +00:00
// Convert the Audio Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRAudioSync ( data + 2U ) ;
2016-01-22 06:43:08 +00:00
2016-08-09 06:28:10 +00:00
// Initialise the lost packet data
if ( ! m_lastFrameValid ) {
: : memcpy ( m_lastFrame , data , DMR_FRAME_LENGTH_BYTES + 2U ) ;
m_lastFrameValid = true ;
m_netSeqNo = dmrData . getSeqNo ( ) ;
m_netN = dmrData . getN ( ) ;
m_elapsed . start ( ) ;
m_netLost = 0U ;
} else {
bool ret = insertSilence ( data , dmrData . getSeqNo ( ) ) ;
if ( ! ret )
return ;
}
2016-07-21 16:46:37 +00:00
2016-02-25 19:54:18 +00:00
writeQueueNet ( data ) ;
2016-01-21 21:08:10 +00:00
2016-07-15 05:32:56 +00:00
m_packetTimer . start ( ) ;
2016-02-25 19:54:18 +00:00
m_netFrames + + ;
2016-01-19 19:34:49 +00:00
2016-01-21 21:08:10 +00:00
// Save details in case we need to infill data
2016-02-28 17:18:13 +00:00
m_netSeqNo = dmrData . getSeqNo ( ) ;
m_netN = dmrData . getN ( ) ;
2016-01-19 19:34:49 +00:00
2016-01-14 18:45:04 +00:00
# if defined(DUMP_DMR)
2016-01-21 21:08:10 +00:00
writeFile ( data ) ;
2016-01-14 18:45:04 +00:00
# endif
2016-01-22 06:43:08 +00:00
}
} else if ( dataType = = DT_VOICE ) {
2016-02-25 19:54:18 +00:00
if ( m_netState ! = RS_NET_AUDIO )
2016-01-22 06:43:08 +00:00
return ;
2016-06-16 20:40:05 +00:00
unsigned int did = m_netLC - > getDstId ( ) ;
2016-07-10 17:35:23 +00:00
unsigned int id = m_netLC - > getSrcId ( ) ;
2016-07-21 16:46:37 +00:00
if ( ! DMRAccessControl : : validateAccess ( id , did , m_slotNo , true ) )
2016-07-10 17:35:23 +00:00
return ;
2016-08-09 07:06:59 +00:00
LogDebug ( " DMR Slot %u, seq no: %u " , m_slotNo , dmrData . getSeqNo ( ) ) ;
2016-02-25 19:54:18 +00:00
unsigned char fid = m_netLC - > getFID ( ) ;
2016-06-01 08:43:39 +00:00
if ( fid = = FID_ETSI | | fid = = FID_DMRA )
m_netErrs + = m_fec . regenerateDMR ( data + 2U ) ;
2016-02-25 19:54:18 +00:00
m_netBits + = 141U ;
2016-01-25 21:56:57 +00:00
2016-02-29 07:27:10 +00:00
// Regenerate the embedded LC
unsigned char lcss = m_netEmbeddedLC . getData ( data + 2U , dmrData . getN ( ) ) ;
2016-01-25 21:56:57 +00:00
// Change the color code in the EMB
m_lastEMB . putData ( data + 2U ) ;
m_lastEMB . setColorCode ( m_colorCode ) ;
2016-02-29 07:27:10 +00:00
m_lastEMB . setLCSS ( lcss ) ;
2016-01-25 21:56:57 +00:00
m_lastEMB . getData ( data + 2U ) ;
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-08-09 06:28:10 +00:00
// Initialise the lost packet data
if ( ! m_lastFrameValid ) {
: : memcpy ( m_lastFrame , data , DMR_FRAME_LENGTH_BYTES + 2U ) ;
m_lastFrameValid = true ;
m_netSeqNo = dmrData . getSeqNo ( ) ;
m_netN = dmrData . getN ( ) ;
m_elapsed . start ( ) ;
m_netLost = 0U ;
} else {
bool ret = insertSilence ( data , dmrData . getSeqNo ( ) ) ;
if ( ! ret )
return ;
}
2016-01-21 21:08:10 +00:00
2016-02-25 19:54:18 +00:00
writeQueueNet ( data ) ;
2016-01-21 21:08:10 +00:00
2016-07-15 05:32:56 +00:00
m_packetTimer . start ( ) ;
2016-02-25 19:54:18 +00:00
m_netFrames + + ;
2016-01-21 21:08:10 +00:00
2016-01-22 06:43:08 +00:00
// Save details in case we need to infill data
2016-02-28 17:18:13 +00:00
m_netSeqNo = dmrData . getSeqNo ( ) ;
m_netN = dmrData . getN ( ) ;
2016-01-21 21:08:10 +00:00
# if defined(DUMP_DMR)
2016-01-22 06:43:08 +00:00
writeFile ( data ) ;
2016-01-21 21:08:10 +00:00
# endif
2016-01-26 18:06:31 +00:00
} else if ( dataType = = DT_CSBK ) {
2016-02-22 18:12:24 +00:00
CDMRCSBK csbk ;
bool valid = csbk . put ( data + 2U ) ;
if ( ! valid ) {
2016-03-14 21:22:09 +00:00
LogMessage ( " DMR Slot %u, unable to decode the network CSBK " , m_slotNo ) ;
2016-02-18 21:56:26 +00:00
return ;
}
2016-01-26 18:06:31 +00:00
CSBKO csbko = csbk . getCSBKO ( ) ;
2016-03-14 17:33:05 +00:00
if ( csbko = = CSBKO_BSDWNACT )
2016-01-26 18:06:31 +00:00
return ;
2016-03-14 21:22:09 +00:00
bool gi = csbk . getGI ( ) ;
unsigned int srcId = csbk . getSrcId ( ) ;
unsigned int dstId = csbk . getDstId ( ) ;
2016-07-21 16:46:37 +00:00
if ( ! DMRAccessControl : : validateAccess ( srcId , dstId , m_slotNo , true ) )
2016-07-10 17:35:23 +00:00
return ;
2016-03-14 17:33:05 +00:00
// Regenerate the CSBK data
csbk . get ( data + 2U ) ;
2016-02-22 18:12:24 +00:00
2016-03-14 17:33:05 +00:00
// Regenerate the Slot Type
CDMRSlotType slotType ;
slotType . putData ( data + 2U ) ;
slotType . setColorCode ( m_colorCode ) ;
slotType . getData ( data + 2U ) ;
2016-01-26 18:06:31 +00:00
2016-03-14 17:33:05 +00:00
// Convert the Data Sync to be from the BS
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-26 18:06:31 +00:00
2016-03-14 17:33:05 +00:00
data [ 0U ] = TAG_DATA ;
data [ 1U ] = 0x00U ;
2016-01-26 18:06:31 +00:00
2016-03-14 17:33:05 +00:00
writeQueueNet ( data ) ;
2016-01-26 18:06:31 +00:00
# if defined(DUMP_DMR)
2016-03-14 17:33:05 +00:00
openFile ( ) ;
writeFile ( data ) ;
closeFile ( ) ;
2016-01-26 18:06:31 +00:00
# endif
2016-04-28 09:32:11 +00:00
std : : string src = m_lookup - > find ( srcId ) ;
std : : string dst = m_lookup - > find ( dstId ) ;
2016-03-14 17:33:05 +00:00
switch ( csbko ) {
case CSBKO_UUVREQ :
2016-04-28 09:32:11 +00:00
LogMessage ( " DMR Slot %u, received network Unit to Unit Voice Service Request CSBK from %s to %s%s " , m_slotNo , src . c_str ( ) , gi ? " TG " : " " , dst . c_str ( ) ) ;
2016-03-14 17:33:05 +00:00
break ;
case CSBKO_UUANSRSP :
2016-04-28 09:32:11 +00:00
LogMessage ( " DMR Slot %u, received network Unit to Unit Voice Service Answer Response CSBK from %s to %s%s " , m_slotNo , src . c_str ( ) , gi ? " TG " : " " , dst . c_str ( ) ) ;
2016-03-14 17:33:05 +00:00
break ;
case CSBKO_NACKRSP :
2016-04-28 09:32:11 +00:00
LogMessage ( " DMR Slot %u, received network Negative Acknowledgment Response CSBK from %s to %s%s " , m_slotNo , src . c_str ( ) , gi ? " TG " : " " , dst . c_str ( ) ) ;
2016-03-14 17:33:05 +00:00
break ;
case CSBKO_PRECCSBK :
2016-04-28 09:32:11 +00:00
LogMessage ( " DMR Slot %u, received network Preamble CSBK from %s to %s%s " , m_slotNo , src . c_str ( ) , gi ? " TG " : " " , dst . c_str ( ) ) ;
2016-03-14 17:33:05 +00:00
break ;
2016-01-26 18:06:31 +00:00
default :
LogWarning ( " DMR Slot %u, unhandled network CSBK type - 0x%02X " , m_slotNo , csbko ) ;
break ;
}
} else if ( dataType = = DT_RATE_12_DATA | | dataType = = DT_RATE_34_DATA | | dataType = = DT_RATE_1_DATA ) {
2016-03-14 21:22:09 +00:00
if ( m_netState ! = RS_NET_DATA | | m_netFrames = = 0U )
2016-01-26 18:06:31 +00:00
return ;
2016-04-19 18:46:16 +00:00
// Regenerate the rate 1/2 payload
2016-03-10 17:18:40 +00:00
if ( dataType = = DT_RATE_12_DATA ) {
CBPTC19696 bptc ;
unsigned char payload [ 12U ] ;
bptc . decode ( data + 2U , payload ) ;
bptc . encode ( payload , data + 2U ) ;
2016-07-07 13:05:38 +00:00
} else if ( dataType = = DT_RATE_34_DATA ) {
2016-07-07 19:23:30 +00:00
CDMRTrellis trellis ;
unsigned char payload [ 18U ] ;
2016-07-14 17:58:03 +00:00
bool ret = trellis . decode ( data + 2U , payload ) ;
if ( ret )
trellis . encode ( payload , data + 2U ) ;
2016-03-10 17:18:40 +00:00
}
2016-01-26 18:06:31 +00:00
// Regenerate the Slot Type
2016-02-15 18:45:57 +00:00
CDMRSlotType slotType ;
2016-01-14 18:45:04 +00:00
slotType . putData ( data + 2U ) ;
slotType . setColorCode ( m_colorCode ) ;
slotType . getData ( data + 2U ) ;
// Convert the Data Sync to be from the BS
2016-02-15 18:45:57 +00:00
CSync : : addDMRDataSync ( data + 2U ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
m_netFrames - - ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
data [ 0U ] = m_netFrames = = 0U ? TAG_EOT : TAG_DATA ;
2016-01-26 18:06:31 +00:00
data [ 1U ] = 0x00U ;
2016-01-14 18:45:04 +00:00
# if defined(DUMP_DMR)
writeFile ( data ) ;
# endif
2016-02-25 19:54:18 +00:00
writeQueueNet ( data ) ;
2016-01-26 18:06:31 +00:00
2016-04-26 17:22:47 +00:00
if ( m_netFrames = = 0U )
endOfNetData ( ) ;
2016-01-26 18:06:31 +00:00
} else {
// Unhandled data type
LogWarning ( " DMR Slot %u, unhandled network data type - 0x%02X " , m_slotNo , dataType ) ;
2016-01-14 18:45:04 +00:00
}
}
2016-03-14 20:55:15 +00:00
void CDMRSlot : : clock ( )
2016-01-14 18:45:04 +00:00
{
2016-03-14 20:55:15 +00:00
unsigned int ms = m_interval . elapsed ( ) ;
m_interval . start ( ) ;
2016-02-25 19:54:18 +00:00
m_rfTimeoutTimer . clock ( ms ) ;
m_netTimeoutTimer . clock ( ms ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
if ( m_netState = = RS_NET_AUDIO | | m_netState = = RS_NET_DATA ) {
2016-01-14 18:45:04 +00:00
m_networkWatchdog . clock ( ms ) ;
if ( m_networkWatchdog . hasExpired ( ) ) {
2016-02-25 19:54:18 +00:00
if ( m_netState = = RS_NET_AUDIO ) {
2016-01-21 18:38:45 +00:00
// We've received the voice header haven't we?
2016-02-25 19:54:18 +00:00
m_netFrames + = 1U ;
LogMessage ( " DMR Slot %u, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %.1f%% " , m_slotNo , float ( m_netFrames ) / 16.667F , ( m_netLost * 100U ) / m_netFrames , float ( m_netErrs * 100U ) / float ( m_netBits ) ) ;
writeEndNet ( true ) ;
2016-01-21 21:08:10 +00:00
# if defined(DUMP_DMR)
closeFile ( ) ;
# endif
2016-01-22 06:43:08 +00:00
} else {
2016-01-20 07:12:28 +00:00
LogMessage ( " DMR Slot %u, network watchdog has expired " , m_slotNo ) ;
2016-02-25 19:54:18 +00:00
writeEndNet ( ) ;
2016-01-14 18:45:04 +00:00
# if defined(DUMP_DMR)
2016-01-21 21:08:10 +00:00
closeFile ( ) ;
2016-01-14 18:45:04 +00:00
# endif
2016-01-21 21:08:10 +00:00
}
2016-01-14 18:45:04 +00:00
}
}
2016-01-19 19:34:49 +00:00
2016-02-25 19:54:18 +00:00
if ( m_netState = = RS_NET_AUDIO ) {
2016-07-15 05:32:56 +00:00
m_packetTimer . clock ( ms ) ;
if ( m_packetTimer . isRunning ( ) & & m_packetTimer . hasExpired ( ) ) {
unsigned int elapsed = m_elapsed . elapsed ( ) ;
unsigned int frames = elapsed / DMR_SLOT_TIME ;
if ( frames > m_netFrames ) {
unsigned int count = frames - m_netFrames ;
if ( count > 3U ) {
2016-08-09 06:35:31 +00:00
LogDebug ( " DMR Slot %u, lost audio for 400ms filling in, elapsed: %ums, expected: %u, received: %u " , m_slotNo , elapsed , frames , m_netFrames ) ;
2016-07-15 05:32:56 +00:00
insertSilence ( count - 1U ) ;
}
2016-01-19 19:34:49 +00:00
}
2016-07-15 05:32:56 +00:00
m_packetTimer . start ( ) ;
2016-01-19 19:34:49 +00:00
}
}
2016-01-14 18:45:04 +00:00
}
2016-02-25 19:54:18 +00:00
void CDMRSlot : : writeQueueRF ( const unsigned char * data )
2016-01-14 18:45:04 +00:00
{
2016-03-07 20:21:55 +00:00
assert ( data ! = NULL ) ;
2016-02-25 19:54:18 +00:00
if ( m_netState ! = RS_NET_IDLE )
return ;
2016-01-14 18:45:04 +00:00
unsigned char len = DMR_FRAME_LENGTH_BYTES + 2U ;
2016-03-07 18:08:50 +00:00
unsigned int space = m_queue . freeSpace ( ) ;
if ( space < ( len + 1U ) ) {
LogError ( " DMR Slot %u, overflow in the DMR slot RF queue " , m_slotNo ) ;
return ;
}
m_queue . addData ( & len , 1U ) ;
2016-01-14 18:45:04 +00:00
// If the timeout has expired, replace the audio with idles to keep the slot busy
2016-02-25 19:54:18 +00:00
if ( m_rfTimeoutTimer . isRunning ( ) & & m_rfTimeoutTimer . hasExpired ( ) )
2016-03-07 18:08:50 +00:00
m_queue . addData ( m_idle , len ) ;
2016-01-14 18:45:04 +00:00
else
2016-03-07 18:08:50 +00:00
m_queue . addData ( data , len ) ;
2016-01-14 18:45:04 +00:00
}
2016-03-23 17:30:06 +00:00
void CDMRSlot : : writeNetworkRF ( const unsigned char * data , unsigned char dataType , FLCO flco , unsigned int srcId , unsigned int dstId , unsigned char errors )
2016-01-14 18:45:04 +00:00
{
2016-01-25 21:56:57 +00:00
assert ( data ! = NULL ) ;
2016-01-14 18:45:04 +00:00
2016-02-25 19:54:18 +00:00
if ( m_netState ! = RS_NET_IDLE )
return ;
2016-01-14 18:45:04 +00:00
if ( m_network = = NULL )
return ;
// Don't send to the network if the timeout has expired
2016-02-25 19:54:18 +00:00
if ( m_rfTimeoutTimer . isRunning ( ) & & m_rfTimeoutTimer . hasExpired ( ) )
2016-01-14 18:45:04 +00:00
return ;
CDMRData dmrData ;
dmrData . setSlotNo ( m_slotNo ) ;
dmrData . setDataType ( dataType ) ;
2016-01-25 21:56:57 +00:00
dmrData . setSrcId ( srcId ) ;
dmrData . setDstId ( dstId ) ;
dmrData . setFLCO ( flco ) ;
2016-02-28 17:40:15 +00:00
dmrData . setN ( m_rfN ) ;
dmrData . setSeqNo ( m_rfSeqNo ) ;
2016-03-23 17:30:06 +00:00
dmrData . setBER ( errors ) ;
2016-08-08 20:26:18 +00:00
dmrData . setRSSI ( m_rssi ) ;
2016-01-14 18:45:04 +00:00
2016-02-28 17:40:15 +00:00
m_rfSeqNo + + ;
2016-01-14 18:45:04 +00:00
dmrData . setData ( data + 2U ) ;
m_network - > write ( dmrData ) ;
}
2016-03-23 17:30:06 +00:00
void CDMRSlot : : writeNetworkRF ( const unsigned char * data , unsigned char dataType , unsigned char errors )
2016-01-25 21:56:57 +00:00
{
assert ( data ! = NULL ) ;
2016-02-25 19:54:18 +00:00
assert ( m_rfLC ! = NULL ) ;
2016-03-23 17:30:06 +00:00
writeNetworkRF ( data , dataType , m_rfLC - > getFLCO ( ) , m_rfLC - > getSrcId ( ) , m_rfLC - > getDstId ( ) , errors ) ;
2016-02-25 19:54:18 +00:00
}
2016-01-25 21:56:57 +00:00
2016-02-25 19:54:18 +00:00
void CDMRSlot : : writeQueueNet ( const unsigned char * data )
{
2016-03-07 20:21:55 +00:00
assert ( data ! = NULL ) ;
2016-02-25 19:54:18 +00:00
unsigned char len = DMR_FRAME_LENGTH_BYTES + 2U ;
2016-03-07 18:08:50 +00:00
unsigned int space = m_queue . freeSpace ( ) ;
if ( space < ( len + 1U ) ) {
LogError ( " DMR Slot %u, overflow in the DMR slot RF queue " , m_slotNo ) ;
return ;
}
m_queue . addData ( & len , 1U ) ;
2016-02-25 19:54:18 +00:00
// If the timeout has expired, replace the audio with idles to keep the slot busy
if ( m_netTimeoutTimer . isRunning ( ) & & m_netTimeoutTimer . hasExpired ( ) )
2016-03-07 18:08:50 +00:00
m_queue . addData ( m_idle , len ) ;
2016-02-25 19:54:18 +00:00
else
2016-03-07 18:08:50 +00:00
m_queue . addData ( data , len ) ;
2016-01-25 21:56:57 +00:00
}
2016-08-08 20:26:18 +00:00
void CDMRSlot : : init ( unsigned int id , unsigned int colorCode , unsigned int callHang , bool selfOnly , const std : : vector < unsigned int > & prefixes , const std : : vector < unsigned int > & SrcIdBlacklist , const std : : vector < unsigned int > & DstIdBlacklistSlot1RF , const std : : vector < unsigned int > & DstIdWhitelistSlot1RF , const std : : vector < unsigned int > & DstIdBlacklistSlot2RF , const std : : vector < unsigned int > & DstIdWhitelistSlot2RF , const std : : vector < unsigned int > & DstIdBlacklistSlot1NET , const std : : vector < unsigned int > & DstIdWhitelistSlot1NET , const std : : vector < unsigned int > & DstIdBlacklistSlot2NET , const std : : vector < unsigned int > & DstIdWhitelistSlot2NET , CModem * modem , CDMRIPSC * network , CDisplay * display , bool duplex , CDMRLookup * lookup , int rssiMultiplier , int rssiOffset )
2016-01-14 18:45:04 +00:00
{
2016-04-04 16:40:05 +00:00
assert ( id ! = 0U ) ;
2016-01-14 18:45:04 +00:00
assert ( modem ! = NULL ) ;
assert ( display ! = NULL ) ;
2016-04-12 17:26:13 +00:00
assert ( lookup ! = NULL ) ;
2016-01-14 18:45:04 +00:00
2016-04-04 16:40:05 +00:00
m_id = id ;
2016-01-14 18:45:04 +00:00
m_colorCode = colorCode ;
2016-04-04 16:40:05 +00:00
m_selfOnly = selfOnly ;
2016-04-04 18:03:38 +00:00
m_prefixes = prefixes ;
2016-07-10 15:46:02 +00:00
// m_blackList = blackList;
2016-01-14 18:45:04 +00:00
m_modem = modem ;
m_network = network ;
m_display = display ;
2016-02-15 18:01:21 +00:00
m_duplex = duplex ;
2016-04-12 17:26:13 +00:00
m_lookup = lookup ;
2016-08-08 20:26:18 +00:00
m_hangCount = callHang * 17U ;
m_rssiMultiplier = rssiMultiplier ;
m_rssiOffset = rssiOffset ;
2016-01-14 18:45:04 +00:00
2016-01-21 18:38:45 +00:00
m_idle = new unsigned char [ DMR_FRAME_LENGTH_BYTES + 2U ] ;
2016-01-14 18:45:04 +00:00
2016-01-25 21:56:57 +00:00
: : memcpy ( m_idle , DMR_IDLE_DATA , DMR_FRAME_LENGTH_BYTES + 2U ) ;
2016-01-21 18:38:45 +00:00
// Generate the Slot Type for the Idle frame
2016-02-15 18:45:57 +00:00
CDMRSlotType slotType ;
2016-01-14 18:45:04 +00:00
slotType . setColorCode ( colorCode ) ;
slotType . setDataType ( DT_IDLE ) ;
slotType . getData ( m_idle + 2U ) ;
2016-07-10 10:47:23 +00:00
//Load black and white lists to DMRAccessControl
2016-07-10 20:37:11 +00:00
DMRAccessControl : : init ( DstIdBlacklistSlot1RF , DstIdWhitelistSlot1RF , DstIdBlacklistSlot2RF , DstIdWhitelistSlot2RF , DstIdBlacklistSlot1NET , DstIdWhitelistSlot1NET , DstIdBlacklistSlot2NET , DstIdWhitelistSlot2NET , SrcIdBlacklist , m_selfOnly , m_prefixes , m_id ) ;
2016-04-04 18:03:38 +00:00
}
2016-06-07 14:34:16 +00:00
2016-01-26 18:28:39 +00:00
void CDMRSlot : : setShortLC ( unsigned int slotNo , unsigned int id , FLCO flco , bool voice )
2016-01-14 18:45:04 +00:00
{
assert ( m_modem ! = NULL ) ;
switch ( slotNo ) {
case 1U :
2016-01-26 18:28:39 +00:00
m_id1 = 0U ;
m_flco1 = flco ;
m_voice1 = voice ;
2016-01-14 18:45:04 +00:00
if ( id ! = 0U ) {
unsigned char buffer [ 3U ] ;
buffer [ 0U ] = ( id < < 16 ) & 0xFFU ;
buffer [ 1U ] = ( id < < 8 ) & 0xFFU ;
buffer [ 2U ] = ( id < < 0 ) & 0xFFU ;
m_id1 = CCRC : : crc8 ( buffer , 3U ) ;
}
break ;
case 2U :
2016-01-26 18:28:39 +00:00
m_id2 = 0U ;
m_flco2 = flco ;
m_voice2 = voice ;
2016-01-14 18:45:04 +00:00
if ( id ! = 0U ) {
unsigned char buffer [ 3U ] ;
buffer [ 0U ] = ( id < < 16 ) & 0xFFU ;
buffer [ 1U ] = ( id < < 8 ) & 0xFFU ;
buffer [ 2U ] = ( id < < 0 ) & 0xFFU ;
m_id2 = CCRC : : crc8 ( buffer , 3U ) ;
}
break ;
default :
LogError ( " Invalid slot number passed to setShortLC - %u " , slotNo ) ;
return ;
}
2016-06-20 17:33:04 +00:00
// If we have no activity to report, let the modem send the null Short LC when it's ready
if ( m_id1 = = 0U & & m_id2 = = 0U )
return ;
2016-01-14 18:45:04 +00:00
unsigned char lc [ 5U ] ;
lc [ 0U ] = 0x01U ;
lc [ 1U ] = 0x00U ;
lc [ 2U ] = 0x00U ;
lc [ 3U ] = 0x00U ;
if ( m_id1 ! = 0U ) {
lc [ 2U ] = m_id1 ;
2016-01-26 18:28:39 +00:00
if ( m_voice1 ) {
if ( m_flco1 = = FLCO_GROUP )
lc [ 1U ] | = 0x80U ;
else
lc [ 1U ] | = 0x90U ;
} else {
if ( m_flco1 = = FLCO_GROUP )
lc [ 1U ] | = 0xB0U ;
else
lc [ 1U ] | = 0xA0U ;
}
2016-01-14 18:45:04 +00:00
}
if ( m_id2 ! = 0U ) {
lc [ 3U ] = m_id2 ;
2016-01-26 18:28:39 +00:00
if ( m_voice2 ) {
if ( m_flco2 = = FLCO_GROUP )
lc [ 1U ] | = 0x08U ;
else
lc [ 1U ] | = 0x09U ;
} else {
if ( m_flco2 = = FLCO_GROUP )
lc [ 1U ] | = 0x0BU ;
else
lc [ 1U ] | = 0x0AU ;
}
2016-01-14 18:45:04 +00:00
}
lc [ 4U ] = CCRC : : crc8 ( lc , 4U ) ;
unsigned char sLC [ 9U ] ;
2016-02-15 18:45:57 +00:00
CDMRShortLC shortLC ;
2016-01-14 18:45:04 +00:00
shortLC . encode ( lc , sLC ) ;
m_modem - > writeDMRShortLC ( sLC ) ;
}
bool CDMRSlot : : openFile ( )
{
if ( m_fp ! = NULL )
return true ;
time_t t ;
: : time ( & t ) ;
struct tm * tm = : : localtime ( & t ) ;
char name [ 100U ] ;
: : sprintf ( name , " DMR_%u_%04d%02d%02d_%02d%02d%02d.ambe " , m_slotNo , 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 ( " DMR " , 1U , 3U , m_fp ) ;
return true ;
}
bool CDMRSlot : : writeFile ( const unsigned char * data )
{
if ( m_fp = = NULL )
return false ;
: : fwrite ( data , 1U , DMR_FRAME_LENGTH_BYTES + 2U , m_fp ) ;
return true ;
}
void CDMRSlot : : closeFile ( )
{
if ( m_fp ! = NULL ) {
: : fclose ( m_fp ) ;
m_fp = NULL ;
}
}
2016-01-19 19:34:49 +00:00
2016-07-21 16:46:37 +00:00
bool CDMRSlot : : insertSilence ( const unsigned char * data , unsigned char seqNo )
2016-01-22 06:43:08 +00:00
{
2016-01-25 21:56:57 +00:00
assert ( data ! = NULL ) ;
// Check to see if we have any spaces to fill?
2016-02-28 17:18:13 +00:00
unsigned char seq = m_netSeqNo + 1U ;
2016-01-25 21:56:57 +00:00
if ( seq = = seqNo ) {
// Just copy the data, nothing else to do here
: : memcpy ( m_lastFrame , data , DMR_FRAME_LENGTH_BYTES + 2U ) ;
2016-07-21 17:09:29 +00:00
m_lastFrameValid = true ;
2016-07-21 16:46:37 +00:00
return true ;
2016-01-25 21:56:57 +00:00
}
2016-02-28 17:18:13 +00:00
unsigned int oldSeqNo = m_netSeqNo + 1U ;
2016-01-25 21:56:57 +00:00
unsigned int newSeqNo = seqNo ;
2016-01-22 06:43:08 +00:00
unsigned int count ;
if ( newSeqNo > oldSeqNo )
count = newSeqNo - oldSeqNo ;
else
count = ( 256U + newSeqNo ) - oldSeqNo ;
2016-07-21 16:46:37 +00:00
if ( count > = 10U )
return false ;
insertSilence ( count ) ;
2016-01-22 06:43:08 +00:00
2016-01-25 21:56:57 +00:00
: : memcpy ( m_lastFrame , data , DMR_FRAME_LENGTH_BYTES + 2U ) ;
2016-07-21 17:09:29 +00:00
m_lastFrameValid = true ;
2016-07-21 16:46:37 +00:00
return true ;
2016-01-22 06:43:08 +00:00
}
2016-01-25 21:56:57 +00:00
void CDMRSlot : : insertSilence ( unsigned int count )
2016-01-19 19:34:49 +00:00
{
2016-01-28 06:50:54 +00:00
unsigned char data [ DMR_FRAME_LENGTH_BYTES + 2U ] ;
2016-07-21 17:09:29 +00:00
if ( m_lastFrameValid ) {
: : memcpy ( data , m_lastFrame , 2U ) ; // The control data
: : memcpy ( data + 2U , m_lastFrame + 24U + 2U , 9U ) ; // Copy the last audio block to the first
: : memcpy ( data + 24U + 2U , data + 2U , 9U ) ; // Copy the last audio block to the last
: : memcpy ( data + 9U + 2U , data + 2U , 5U ) ; // Copy the last audio block to the middle (1/2)
: : memcpy ( data + 19U + 2U , data + 4U + 2U , 5U ) ; // Copy the last audio block to the middle (2/2)
} else {
// Not sure what to do if this isn't AMBE audio
: : memcpy ( data , DMR_SILENCE_DATA , DMR_FRAME_LENGTH_BYTES + 2U ) ;
}
2016-01-28 06:50:54 +00:00
2016-02-28 17:18:13 +00:00
unsigned char n = ( m_netN + 1U ) % 6U ;
unsigned char seqNo = m_netSeqNo + 1U ;
2016-01-19 19:34:49 +00:00
2016-03-03 09:18:52 +00:00
unsigned char fid = m_netLC - > getFID ( ) ;
2016-01-25 21:56:57 +00:00
for ( unsigned int i = 0U ; i < count ; i + + ) {
2016-03-03 09:18:52 +00:00
// Only use our silence frame if its AMBE audio data
if ( fid = = FID_ETSI | | fid = = FID_DMRA ) {
if ( i > 0U )
: : memcpy ( data , DMR_SILENCE_DATA , DMR_FRAME_LENGTH_BYTES + 2U ) ;
}
2016-01-21 18:38:45 +00:00
2016-01-19 19:34:49 +00:00
if ( n = = 0U ) {
2016-02-15 18:45:57 +00:00
CSync : : addDMRAudioSync ( data + 2U ) ;
2016-01-25 21:56:57 +00:00
} else {
2016-03-01 19:04:04 +00:00
unsigned char lcss = m_netEmbeddedLC . getData ( data + 2U , n ) ;
2016-01-26 18:28:39 +00:00
2016-03-01 19:04:04 +00:00
m_lastEMB . setColorCode ( m_colorCode ) ;
m_lastEMB . setLCSS ( lcss ) ;
2016-01-25 21:56:57 +00:00
m_lastEMB . getData ( data + 2U ) ;
2016-01-19 19:34:49 +00:00
}
2016-02-25 19:54:18 +00:00
writeQueueNet ( data ) ;
2016-01-19 19:34:49 +00:00
2016-02-28 17:18:13 +00:00
m_netSeqNo = seqNo ;
m_netN = n ;
2016-01-19 19:34:49 +00:00
2016-02-25 19:54:18 +00:00
m_netFrames + + ;
m_netLost + + ;
2016-01-19 19:34:49 +00:00
seqNo + + ;
n = ( n + 1U ) % 6U ;
}
}