def generate_voice_header(self, _rx_slot, _burst_type): src_id = struct.pack('>I', int_id(_rx_slot.src_id)) dst_id = struct.pack('>I', int_id(_rx_slot.dst_id)) headerType = ord(LC_GROUP_VOICE) if not _rx_slot.group: headerType = ord(LC_PRIVATE_VOICE) if _rx_slot.secure: headerType &= ~(1 << 7) featureSet = FID_ETSI svcOptions = 0x00 if _rx_slot.secure: featureSet = FID_DMRA svcOptions &= ~(1 << 6) header = struct.pack('B', headerType) + featureSet + struct.pack('B', svcOptions) + \ dst_id[1] + dst_id[2] + dst_id[3] + src_id[1] + src_id[2] + src_id[3] self.emb_lc = header fec = '' if _burst_type == BURST_DATA_TYPE['VOICE_HEADER']: fec = rs129.lc_header_encode(header) else: fec = rs129.lc_terminator_encode(header) ipsc_burst = self.generate_ipsc_burst(_rx_slot, _burst_type) burst_type = map(ord, _burst_type)[0] burst_type = burst_type + (_rx_slot.cc << 4) burst_type = struct.pack('>H', burst_type) rssi = struct.pack('>H', 0) # fake RSSI return ipsc_burst + header + fec + burst_type + rssi
def begin_call(self, _slot, _group_call, _src_id, _dst_id, _peer_id, _cc, _seq, _stream_id): group = '\x01' if (_group_call == False): group = '\x00' metadata = _src_id[0:3] + _peer_id[0:4] + _dst_id[0:3] + struct.pack( 'B', _slot) + struct.pack('B', _cc) + group # start transmission self.send_tlv(TAG_BEGIN_TX, metadata) self._logger.info( 'Voice Transmission Start; slot = {}, dstId = {}, srcId = {}'. format(_slot, int_id(_dst_id), int_id(_src_id))) _tx_slot = self.tx[_slot] _tx_slot.slot = _slot _tx_slot.src_id = _src_id _tx_slot.peer_id = _peer_id _tx_slot.dst_id = _dst_id _tx_slot.cc = _cc _tx_slot.stream_id = _stream_id _tx_slot.start_time = time() _tx_slot.frame_count = 0 _tx_slot.lostFrame = 0 _tx_slot.lastSeq = _seq
def pi_params(self, _slot, _dst_id, _alg_id, _key_id, _mi): metadata = _dst_id[0:3] + _alg_id + _key_id + _mi[0:4] + struct.pack( 'B', _slot) sleep(0.06) # start transmission self.send_tlv(TAG_PI_INFO, metadata) self._logger.info( 'PI parameters; slot = {}, dstId = {}, algId = {}, kId = {}'. format(_slot, int_id(_dst_id), int_id(_alg_id), int_id(_key_id))) _tx_slot = self.tx[_slot] _tx_slot.secure = True _tx_slot.alg_id = _alg_id _tx_slot.key_id = _key_id _tx_slot.mi = _mi
def send_system(self, _rx_slot, _frame): if hasattr(self._parent, '_peers'): _orig_flag = _frame[ 15] # Save off the flag since _frame is a reference for _peer in self._parent._peers: _peerDict = self._parent._peers[_peer] if _peerDict['TX_FREQ'] == _peerDict['RX_FREQ']: if (self._DMOStreamID == 0) or ( time() > self._DMOTimeout): # are we idle? self._DMOStreamID = _rx_slot.stream_id self._DMOTimeout = time() + 0.50 self._logger.info( '(%s) DMO Transition from idle to stream %d', self._system, int_id(_rx_slot.stream_id)) if _rx_slot.stream_id != self._DMOStreamID: # packet is from wrong stream? if (_frame[15] & 0x2F) == 0x21: # Call start? self._logger.info( '(%s) DMO Ignore traffic on stream %d', self._system, int_id(_rx_slot.stream_id)) continue if (_frame[15] & 0x2F) == 0x22: # call terminator flag? self._DMOStreamID = 0 # we are idle again self._logger.info('(%s) DMO End of call, back to IDLE', self._system) _frame[15] = ( _frame[15] & 0x7f) | 0x80 # force to slot 2 if client in DMO mode else: _frame[ 15] = _orig_flag # Use the origional flag value if not DMO _repeaterID = hex_str_4(int(_peerDict['PEER_ID'])) for _index in range( 0, 4 ): # Force the repeater ID to be the "destination" ID of the client (fne will not accept it otherwise) _frame[_index + 11] = _repeaterID[_index] self._parent.send_peer(_peer, _frame) self._DMOTimeout = time() + 0.50 else: self._parent.send_master(_frame)
def generate_ipsc_voice_header(self, _rx_slot): src_id = struct.pack('>I', int_id(_rx_slot.src_id)) dst_id = struct.pack('>I', int_id(_rx_slot.dst_id)) frameType = GROUP_VOICE if not _rx_slot.group: frameType = PVT_VOICE control = 0x00 if _rx_slot.slot == 1: control &= ~(1 << 5) elif _rx_slot.slot == 2: control |= 1 << 5 if _rx_slot.secure: control &= ~(1 << 7) control = chr(control) frame = frameType + struct.pack('>I', int_id(_rx_slot.peer_id)) + struct.pack("i", self.ipsc_seq)[0] + \ src_id[1] + src_id[2] + src_id[3] + dst_id[1] + dst_id[2] + dst_id[3] + \ CALL_PRIORITY_2 + struct.pack('>I', int_id(_rx_slot.stream_id)) + control return frame
def voice_call(self, _src_id, _dst_id, _group, _ts, _end, _peerId, _rtp, _data): _tx_slot = self.tlv_ipsc.tx[_ts] _payload_type = _data[30:31] _seq = int_id(_data[20:22]) _tx_slot.frame_count += 1 if _payload_type == BURST_DATA_TYPE['VOICE_HEADER']: _stream_id = int_id( _data[5:6]) # int8 looks like a sequence number for a packet if (_stream_id != _tx_slot.stream_id): self.tlv_ipsc.begin_call(_ts, _group, _src_id, _dst_id, _peerId, self.cc, _seq, _stream_id) _tx_slot.lastSeq = _seq if _payload_type == BURST_DATA_TYPE['PI_HEADER']: _stream_id = int_id( _data[5:6]) # int8 looks like a sequence number for a packet _alg_id = _data[38:39] _key_id = _data[40:41] _mi = _data[41:45] if (_stream_id == _tx_slot.stream_id): self.tlv_ipsc.pi_params(_ts, _dst_id, _alg_id, _key_id, _mi) if _payload_type == BURST_DATA_TYPE['VOICE_TERMINATOR']: self.tlv_ipsc.end_call(_tx_slot) if (_payload_type == BURST_DATA_TYPE['SLOT1_VOICE']) or ( _payload_type == BURST_DATA_TYPE['SLOT2_VOICE']): _ambe_frames = BitArray('0x' + ahex(_data[33:52])) _ambe_frame1 = _ambe_frames[0:49] _ambe_frame2 = _ambe_frames[50:99] _ambe_frame3 = _ambe_frames[100:149] self.tlv_ipsc.export_voice( _tx_slot, _seq, _ambe_frame1.tobytes() + _ambe_frame2.tobytes() + _ambe_frame3.tobytes())
def generate_pi_header(self, _rx_slot, _burst_type): _unk = '\x00' dst_id = struct.pack('>I', int_id(_rx_slot.dst_id)) featureSet = FID_DMRA header = struct.pack('B', _rx_slot.alg_id) + featureSet + struct.pack('B', _rx_slot.key_id) + \ mi[0] + mi[1] + mi[2] + mi[3] + dst_id[1] + dst_id[2] + dst_id[3] + _unk + _unk ipsc_burst = self.generate_ipsc_burst(_rx_slot, _burst_type) burst_type = map(ord, _burst_type)[0] burst_type = burst_type + (_rx_slot.cc << 4) burst_type = struct.pack('>H', burst_type) rssi = struct.pack('>H', 0) # fake RSSI return ipsc_burst + header + fec + burst_type + rssi
def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): dmrpkt = _data[20:53] _tx_slot = self.tlv_fne.tx[_slot] _seq = ord(_data[4]) _tx_slot.frame_count += 1 if (_stream_id != _tx_slot.stream_id): if _call_type == 'group': self.tlv_fne.begin_call(_slot, True, _rf_src, _dst_id, _peer_id, _tx_slot.cc, _seq, _stream_id) elif _call_type == 'unit': self.tlv_fne.begin_call(_slot, False, _rf_src, _dst_id, _peer_id, _tx_slot.cc, _seq, _stream_id) _tx_slot.lastSeq = _seq if (_frame_type == fne_const.FT_DATA_SYNC) and ( _dtype_vseq == fne_const.DT_VOICE_PI_HEADER): lcHeader = lc.decode_lc_header(dmrpkt) _alg_id = lcHeader['LC'][0] _key_id = lcHeader['LC'][2] _mi = lcHeader['LC'][3:7] self.tlv_fne.pi_params(_slot, _dst_id, _alg_id, _key_id, _mi) if (_frame_type == fne_const.FT_DATA_SYNC) and ( _dtype_vseq == fne_const.DT_TERMINATOR_WITH_LC) and ( _tx_slot.type != fne_const.DT_TERMINATOR_WITH_LC): self.tlv_fne.end_call(_tx_slot) if (int_id(_data[15]) & 0x20) == 0: _dmr_frame = BitArray('0x' + ahex(_data[20:])) _ambe = _dmr_frame[0:108] + _dmr_frame[156:264] self.tlv_fne.export_voice(_tx_slot, _seq, _ambe.tobytes()) else: _tx_slot.lastSeq = _seq
def import_datagramReceived(self, _data, (_host, _port)): #self._logger.debug('(%s) Network Received TLV (from %s:%s) -- %s', self._system, _host, _port, ahex(_data)) _slot = self._slot _rx_slot = self.rx[_slot] # Parse out the TLV t = _data[0] if (t): l = _data[1] if (l): v = _data[2:] if (v): t = ord(t) if (t == TAG_BEGIN_TX): if ord(l) > 1: _slot = int_id(v[10:11]) _rx_slot = self.rx[_slot] _rx_slot.slot = _slot _rx_slot.src_id = hex_str_3(int_id(v[0:3])) _rx_slot.peer_id = self._parent.get_peer_id( hex_str_4(int_id(v[3:7]))) _rx_slot.dst_id = hex_str_3(int_id(v[7:10])) _rx_slot.cc = int_id(v[11:12]) group = int_id(v[12]) if (group == 0): _rx_slot.group = False else: _rx_slot.group = True _rx_slot.stream_id = hex_str_4(randint(
def p25d_received(self, _peer_id, _rf_src, _dst_id, _call_type, _duid, _dtype_vseq, _stream_id, _data): pkt_time = time() p25pkt = _data[24:178] _slot = 1 # fake the slot data, P25 doesn't have this if _call_type == 'group': if (self.LAST_MODE != 'P25'): self._logger.info( '(%s) P25D: Previous call was not P25, mixed call modes! Dropping call data.', self._system) self.CALL_DATA = [] if (int_id(_rf_src) == 0): self._logger.warning( '(%s) P25D: Received call from SRC_ID %s? Dropping call data.', self._system, int_id(_rf_src)) self.CALL_DATA = [] self.LAST_MODE = 'P25' return self.LAST_MODE = 'P25' # Is this is a new call stream? if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']) and ( (_duid != fne_const.P25_DUID_TDU) and (_duid != fne_const.P25_DUID_TDULC)): self.STATUS['RX_START'] = pkt_time self._logger.info( '(%s) P25D: Traffic *CALL START * PEER %s SRC_ID %s TGID %s [STREAM ID %s]', self._system, int_id(_peer_id), int_id(_rf_src), int_id(_dst_id), int_id(_stream_id)) # Final actions - Is this a voice terminator? if ((_duid == fne_const.P25_DUID_TDU) or (_duid == fne_const.P25_DUID_TDULC)) and ( self.STATUS[_slot]['RX_TYPE'] != fne_const.DT_TERMINATOR_WITH_LC): call_duration = pkt_time - self.STATUS['RX_START'] self._logger.info( '(%s) P25D: Traffic *CALL END * PEER %s SRC_ID %s TGID %s DUR %s [STREAM ID %s]', self._system, int_id(_peer_id), int_id(_rf_src), int_id(_dst_id), call_duration, int_id(_stream_id)) self.CALL_DATA.append(_data) sleep(2) self._logger.info( '(%s) P25D: Playing back transmission from SRC_ID %s', self._system, int_id(_rf_src)) for _peer in self.CALL_DATA: self.send_peers(_peer) sleep(0.06) self.CALL_DATA = [] else: if not self.CALL_DATA: self._logger.info( '(%s) P25D: Receiving transmission to be played back from SRC_ID %s', self._system, int_id(_rf_src)) self.CALL_DATA.append(_data) # Mark status variables for use later self.STATUS[_slot]['RX_RFS'] = _rf_src self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq self.STATUS[_slot]['RX_TGID'] = _dst_id self.STATUS[_slot]['RX_TIME'] = pkt_time self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id
def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pkt_time = time() dmrpkt = _data[20:53] _bits = int_id(_data[15]) if _call_type == 'group': if (self.LAST_MODE != 'DMR'): self._logger.info( '(%s) DMRD: Previous call was not DMR, mixed call modes! Dropping call data.', self._system) self.CALL_DATA = [] if (int_id(_rf_src) == 0): self._logger.warning( '(%s) DMRD: Received call from SRC_ID %s? Dropping call data.', self._system, int_id(_rf_src)) self.CALL_DATA = [] self.LAST_MODE = 'P25' return self.LAST_MODE = 'DMR' # Is this is a new call stream? if (_stream_id != self.STATUS[_slot]['RX_STREAM_ID']): self.STATUS['RX_START'] = pkt_time self._logger.info( '(%s) DMRD: Traffic *CALL START * PEER %s SRC_ID %s TGID %s TS %s [STREAM ID %s]', self._system, int_id(_peer_id), int_id(_rf_src), int_id(_dst_id), _slot, int_id(_stream_id)) # Final actions - Is this a voice terminator? if (_frame_type == fne_const.FT_DATA_SYNC) and ( _dtype_vseq == fne_const.DT_TERMINATOR_WITH_LC) and ( self.STATUS[_slot]['RX_TYPE'] != fne_const.DT_TERMINATOR_WITH_LC): call_duration = pkt_time - self.STATUS['RX_START'] self._logger.info( '(%s) DMRD: Traffic *CALL END * PEER %s SRC_ID %s TGID %s TS %s DUR %s [STREAM ID %s]', self._system, int_id(_peer_id), int_id(_rf_src), int_id(_dst_id), _slot, call_duration, int_id(_stream_id)) self.CALL_DATA.append(_data) sleep(2) self._logger.info( '(%s) DMRD: Playing back transmission from SRC_ID %s', self._system, int_id(_rf_src)) for _peer in self.CALL_DATA: self.send_peers(_peer) sleep(0.06) self.CALL_DATA = [] else: if not self.CALL_DATA: self._logger.info( '(%s) DMRD: Receiving transmission to be played back from SRC_ID %s', self._system, int_id(_rf_src)) self.CALL_DATA.append(_data) # Mark status variables for use later self.STATUS[_slot]['RX_RFS'] = _rf_src self.STATUS[_slot]['RX_TYPE'] = _dtype_vseq self.STATUS[_slot]['RX_TGID'] = _dst_id self.STATUS[_slot]['RX_TIME'] = pkt_time self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id