bptc_196_96_data_bits_t *dmrpacket_csbk_construct(dmrpacket_csbk_t *csbk) { static bptc_196_96_data_bits_t data_bits; uint8_t data_bytes[sizeof(bptc_196_96_data_bits_t)/8] = {0,}; uint16_t calculated_crc = 0; uint8_t i; data_bytes[0] = (csbk->last_block & 0x01) << 7; switch (csbk->csbko) { case DMRPACKET_CSBKO_BS_OUTBOUND_ACTIVATION: data_bytes[0] |= 0b111000; break; case DMRPACKET_CSBKO_UNIT_TO_UNIT_VOICE_SERVICE_REQUEST: data_bytes[0] |= 0b000100; data_bytes[2] = csbk->data.unit_to_unit_voice_service_request.service_options; break; case DMRPACKET_CSBKO_UNIT_TO_UNIT_VOICE_SERVICE_ANSWER_RESPONSE: data_bytes[0] |= 0b00000101; data_bytes[2] = csbk->data.unit_to_unit_voice_service_answer_response.service_options; data_bytes[3] = csbk->data.unit_to_unit_voice_service_answer_response.answer_response; break; case DMRPACKET_CSBKO_NEGATIVE_ACKNOWLEDGE_RESPONSE: data_bytes[0] |= 0b00100110; data_bytes[2] = 0b10000000 | (csbk->data.negative_acknowledge_response.source_type & 0x01) << 6 | (csbk->data.negative_acknowledge_response.service_type & 0b00111111); data_bytes[3] = csbk->data.negative_acknowledge_response.reason_code; break; case DMRPACKET_CSBKO_PREAMBLE: data_bytes[0] |= 0b00111101; data_bytes[2] = (csbk->data.preamble.data_follows & 0x01) << 7 | (csbk->data.preamble.dst_is_group & 0x01) << 6; data_bytes[3] = csbk->data.preamble.csbk_blocks_to_follow; break; default: return NULL; } data_bytes[4] = (csbk->dst_id & 0xff0000) >> 16; data_bytes[5] = (csbk->dst_id & 0x00ff00) >> 8; data_bytes[6] = (csbk->dst_id & 0x0000ff); data_bytes[7] = (csbk->src_id & 0xff0000) >> 16; data_bytes[8] = (csbk->src_id & 0x00ff00) >> 8; data_bytes[9] = (csbk->src_id & 0x0000ff); for (i = 0; i < 10; i++) crc_calc_crc16_ccitt(&calculated_crc, data_bytes[i]); crc_calc_crc16_ccitt_finish(&calculated_crc); // Inverting according to the inversion polynomial. calculated_crc = ~calculated_crc; // Applying CRC mask, see DMR AI spec. page 143. calculated_crc ^= 0xa5a5; data_bytes[10] = (calculated_crc & 0xff00) >> 8; data_bytes[11] = calculated_crc & 0xff; base_bytestobits(data_bytes, sizeof(data_bytes), data_bits.bits, sizeof(bptc_196_96_data_bits_t)); return &data_bits; }
// Swaps given payload bytes and then converts them to an uint8_t array of bits. dmrpacket_payload_bits_t *ipscpacket_convertpayloadtobits(uint8_t *ipscpacket_payload) { static dmrpacket_payload_bits_t payload_bits; uint8_t swapped_bytes[IPSCPACKET_PAYLOAD_SIZE] = {0,}; uint8_t i; if (ipscpacket_payload == NULL) return NULL; // Swapping the bytes. for (i = 0; i < IPSCPACKET_PAYLOAD_SIZE-1; i += 2) { swapped_bytes[i] = *(ipscpacket_payload + i + 1); swapped_bytes[i+1] = *(ipscpacket_payload + i); } base_bytestobits(swapped_bytes, IPSCPACKET_PAYLOAD_SIZE-1, payload_bits.bits, sizeof(payload_bits.bits)); return &payload_bits; }
void repeaters_play_ambe_data(dmrpacket_payload_voice_bytes_t *voice_bytes, repeater_t *repeater, dmr_timeslot_t ts, dmr_call_type_t calltype, dmr_id_t dstid, dmr_id_t srcid) { dmrpacket_payload_voice_bits_t voice_bits; if (repeater == NULL || voice_bytes == NULL) return; base_bytestobits(voice_bytes->bytes, sizeof(dmrpacket_payload_voice_bytes_t), voice_bits.raw.bits, sizeof(dmrpacket_payload_voice_bits_t)); switch (repeater->slot[ts].ipsc_tx_voice_frame_num) { case 0: repeaters_add_to_ipsc_packet_buffer(repeater, ts, ipscpacket_construct_raw_packet(&repeater->ipaddr, ipscpacket_construct_raw_payload(repeater->slot[ts].ipsc_tx_seqnum++, ts, IPSCPACKET_SLOT_TYPE_VOICE_DATA_A, calltype, dstid, srcid, ipscpacket_construct_payload_voice_frame(IPSCPACKET_SLOT_TYPE_VOICE_DATA_A, &voice_bits, &repeater->slot[ts].ipsc_tx_emb_sig_lc_vbptc_storage))), 0); break; case 1: repeaters_add_to_ipsc_packet_buffer(repeater, ts, ipscpacket_construct_raw_packet(&repeater->ipaddr, ipscpacket_construct_raw_payload(repeater->slot[ts].ipsc_tx_seqnum++, ts, IPSCPACKET_SLOT_TYPE_VOICE_DATA_B, calltype, dstid, srcid, ipscpacket_construct_payload_voice_frame(IPSCPACKET_SLOT_TYPE_VOICE_DATA_B, &voice_bits, &repeater->slot[ts].ipsc_tx_emb_sig_lc_vbptc_storage))), 0); break; case 2: repeaters_add_to_ipsc_packet_buffer(repeater, ts, ipscpacket_construct_raw_packet(&repeater->ipaddr, ipscpacket_construct_raw_payload(repeater->slot[ts].ipsc_tx_seqnum++, ts, IPSCPACKET_SLOT_TYPE_VOICE_DATA_C, calltype, dstid, srcid, ipscpacket_construct_payload_voice_frame(IPSCPACKET_SLOT_TYPE_VOICE_DATA_C, &voice_bits, &repeater->slot[ts].ipsc_tx_emb_sig_lc_vbptc_storage))), 0); break; case 3: repeaters_add_to_ipsc_packet_buffer(repeater, ts, ipscpacket_construct_raw_packet(&repeater->ipaddr, ipscpacket_construct_raw_payload(repeater->slot[ts].ipsc_tx_seqnum++, ts, IPSCPACKET_SLOT_TYPE_VOICE_DATA_D, calltype, dstid, srcid, ipscpacket_construct_payload_voice_frame(IPSCPACKET_SLOT_TYPE_VOICE_DATA_D, &voice_bits, &repeater->slot[ts].ipsc_tx_emb_sig_lc_vbptc_storage))), 0); break; case 4: repeaters_add_to_ipsc_packet_buffer(repeater, ts, ipscpacket_construct_raw_packet(&repeater->ipaddr, ipscpacket_construct_raw_payload(repeater->slot[ts].ipsc_tx_seqnum++, ts, IPSCPACKET_SLOT_TYPE_VOICE_DATA_E, calltype, dstid, srcid, ipscpacket_construct_payload_voice_frame(IPSCPACKET_SLOT_TYPE_VOICE_DATA_E, &voice_bits, &repeater->slot[ts].ipsc_tx_emb_sig_lc_vbptc_storage))), 0); break; case 5: repeaters_add_to_ipsc_packet_buffer(repeater, ts, ipscpacket_construct_raw_packet(&repeater->ipaddr, ipscpacket_construct_raw_payload(repeater->slot[ts].ipsc_tx_seqnum++, ts, IPSCPACKET_SLOT_TYPE_VOICE_DATA_F, calltype, dstid, srcid, ipscpacket_construct_payload_voice_frame(IPSCPACKET_SLOT_TYPE_VOICE_DATA_F, &voice_bits, &repeater->slot[ts].ipsc_tx_emb_sig_lc_vbptc_storage))), 0); break; default: break; } repeater->slot[ts].ipsc_tx_voice_frame_num++; if (repeater->slot[ts].ipsc_tx_voice_frame_num > 5) repeater->slot[ts].ipsc_tx_voice_frame_num = 0; }