void CDMRTX::setColorCode(uint8_t colorCode) { ::memcpy(m_idle, IDLE_DATA, DMR_FRAME_LENGTH_BYTES); CDMRSlotType slotType; slotType.encode(colorCode, DT_IDLE, m_idle); }
void CDMRRX::processDataSync(const unsigned char* buffer) { CDMRSlotType slotType; slotType.putData(buffer); unsigned char type = slotType.getDataType(); unsigned char cc = slotType.getColorCode(); if (type == DT_IDLE) { unsigned int ber = idleBER(m_buffer); LogMessage("%u [Data Sync] [IDLE] CC=%u BER=%.1f%%", m_slotNo, cc, float(ber) / 1.96F); m_idleBits += 196U; m_idleErrs += ber; } else if (type == DT_VOICE_LC_HEADER) { CDMRFullLC fullLC; CDMRLC* lc = fullLC.decode(buffer, type); if (lc != NULL) { LogMessage("%u [Data Sync] [VOICE_LC_HEADER] CC=%u src=%u dest=%s%u", m_slotNo, cc, lc->getSrcId(), lc->getFLCO() == FLCO_GROUP ? "TG" : "", lc->getDstId()); delete lc; } else { LogMessage("%u [Data Sync] [VOICE_LC_HEADER] CC=%u <Invalid LC>", m_slotNo, cc); } } else if (type == DT_TERMINATOR_WITH_LC) { CDMRFullLC fullLC; CDMRLC* lc = fullLC.decode(buffer, type); if (lc != NULL) { LogMessage("%u [Data Sync] [DT_TERMINATOR_WITH_LC] CC=%u src=%u dest=%s%u", m_slotNo, cc, lc->getSrcId(), lc->getFLCO() == FLCO_GROUP ? "TG" : "", lc->getDstId()); delete lc; } else { LogMessage("%u [Data Sync] [DT_TERMINATOR_WITH_LC] CC=%u <Invalid LC>", m_slotNo, cc); } } else if (type == DT_VOICE_PI_HEADER) { LogMessage("%u [Data Sync] [VOICE_PI_HEADER] CC=%u", m_slotNo, cc); } else if (type == DT_DATA_HEADER) { CDMRDataHeader header; bool valid = header.put(buffer); if (valid) LogMessage("%u [Data Sync] [DATA_HEADER] CC=%u src=%u dest=%s%u", m_slotNo, cc, header.getSrcId(), header.getGI() ? "TG" : "", header.getDstId()); else LogMessage("%u [Data Sync] [DATA_HEADER] CC=%u invalid", m_slotNo, cc); } else if (type == DT_RATE_12_DATA) { LogMessage("%u [Data Sync] [RATE_1/2_DATA] CC=%u", m_slotNo, cc); } else if (type == DT_RATE_34_DATA) { LogMessage("%u [Data Sync] [RATE_3/4_DATA] CC=%u", m_slotNo, cc); } else if (type == DT_RATE_1_DATA) { LogMessage("%u [Data Sync] [RATE_1_DATA] CC=%u", m_slotNo, cc); } else if (type == DT_CSBK) { CDMRCSBK csbk; bool valid = csbk.put(buffer); if (valid) LogMessage("%u [Data Sync] [CSBK] CC=%u src=%u dest=%s%u", m_slotNo, cc, csbk.getSrcId(), csbk.getGI() ? "TG" : "", csbk.getDstId()); else LogMessage("%u [Data Sync] [CSBK] CC=%u invalid", m_slotNo, cc); } else { LogMessage("%u [Data Sync] [UNKNOWN] CC=%u type=%u", m_slotNo, cc, type); } }
bool CDMRSlotRX::processSample(q15_t sample) { m_delayPtr++; if (m_delayPtr < m_delay) return m_state != DMRRXS_NONE; if (m_state != DMRRXS_NONE) { if (m_dataPtr > m_startPtr && m_dataPtr < m_endPtr) io.setADCDetection(true); else io.setADCDetection(false); } else { io.setADCDetection(false); } // Ensure that the buffer doesn't overflow if (m_dataPtr > m_endPtr || m_dataPtr >= 900U) return m_state != DMRRXS_NONE; m_buffer[m_dataPtr] = sample; m_bitBuffer[m_bitPtr] <<= 1; if (sample < 0) m_bitBuffer[m_bitPtr] |= 0x01U; if (m_state == DMRRXS_NONE) { if (m_dataPtr >= SCAN_START && m_dataPtr <= SCAN_END) correlateSync(true); } else { uint16_t min = m_syncPtr - 1U; uint16_t max = m_syncPtr + 1U; if (m_dataPtr >= min && m_dataPtr <= max) correlateSync(false); } if (m_dataPtr == m_endPtr) { // Find the average centre and threshold values q15_t centre = (m_centre[0U] + m_centre[1U] + m_centre[2U] + m_centre[3U]) >> 2; q15_t threshold = (m_threshold[0U] + m_threshold[1U] + m_threshold[2U] + m_threshold[3U]) >> 2; uint8_t frame[DMR_FRAME_LENGTH_BYTES + 1U]; frame[0U] = m_control; uint16_t ptr = m_endPtr - DMR_FRAME_LENGTH_SAMPLES + DMR_RADIO_SYMBOL_LENGTH + 1U; samplesToBits(ptr, DMR_FRAME_LENGTH_SYMBOLS, frame, 8U, centre, threshold); if (m_control == CONTROL_DATA) { // Data sync uint8_t colorCode; uint8_t dataType; CDMRSlotType slotType; slotType.decode(frame + 1U, colorCode, dataType); if (colorCode == m_colorCode) { m_syncCount = 0U; m_n = 0U; frame[0U] |= dataType; switch (dataType) { case DT_DATA_HEADER: DEBUG5("DMRSlotRX: data header found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); m_state = DMRRXS_DATA; m_type = 0x00U; break; case DT_RATE_12_DATA: case DT_RATE_34_DATA: case DT_RATE_1_DATA: if (m_state == DMRRXS_DATA) { DEBUG5("DMRSlotRX: data payload found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); m_type = dataType; } break; case DT_VOICE_LC_HEADER: DEBUG5("DMRSlotRX: voice header found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); m_state = DMRRXS_VOICE; break; case DT_VOICE_PI_HEADER: if (m_state == DMRRXS_VOICE) { DEBUG5("DMRSlotRX: voice pi header found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); } m_state = DMRRXS_VOICE; break; case DT_TERMINATOR_WITH_LC: if (m_state == DMRRXS_VOICE) { DEBUG5("DMRSlotRX: voice terminator found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); m_state = DMRRXS_NONE; m_endPtr = NOENDPTR; } break; default: // DT_CSBK DEBUG5("DMRSlotRX: csbk found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); m_state = DMRRXS_NONE; m_endPtr = NOENDPTR; break; } } } else if (m_control == CONTROL_VOICE) { // Voice sync DEBUG5("DMRSlotRX: voice sync found slot/pos/centre/threshold", m_slot ? 2U : 1U, m_syncPtr, centre, threshold); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); m_state = DMRRXS_VOICE; m_syncCount = 0U; m_n = 0U; } else { if (m_state != DMRRXS_NONE) { m_syncCount++; if (m_syncCount >= MAX_SYNC_LOST_FRAMES) { serial.writeDMRLost(m_slot); m_state = DMRRXS_NONE; m_endPtr = NOENDPTR; } } if (m_state == DMRRXS_VOICE) { if (m_n >= 5U) { frame[0U] = CONTROL_VOICE; serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); m_n = 0U; } else { frame[0U] = ++m_n; serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); } } else if (m_state == DMRRXS_DATA) { if (m_type != 0x00U) { frame[0U] = CONTROL_DATA | m_type; serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); } } } }
bool CDMRDMORX::processSample(q15_t sample, uint16_t rssi) { m_buffer[m_dataPtr] = sample; m_rssi[m_dataPtr] = rssi; m_bitBuffer[m_bitPtr] <<= 1; if (sample < 0) m_bitBuffer[m_bitPtr] |= 0x01U; if (m_state == DMORXS_NONE) { correlateSync(true); } else { uint16_t min = m_syncPtr + DMO_BUFFER_LENGTH_SAMPLES - 1U; uint16_t max = m_syncPtr + 1U; if (min >= DMO_BUFFER_LENGTH_SAMPLES) min -= DMO_BUFFER_LENGTH_SAMPLES; if (max >= DMO_BUFFER_LENGTH_SAMPLES) max -= DMO_BUFFER_LENGTH_SAMPLES; if (min < max) { if (m_dataPtr >= min && m_dataPtr <= max) correlateSync(false); } else { if (m_dataPtr >= min || m_dataPtr <= max) correlateSync(false); } } if (m_dataPtr == m_endPtr) { // Find the average centre and threshold values q15_t centre = (m_centre[0U] + m_centre[1U] + m_centre[2U] + m_centre[3U]) >> 2; q15_t threshold = (m_threshold[0U] + m_threshold[1U] + m_threshold[2U] + m_threshold[3U]) >> 2; uint8_t frame[DMR_FRAME_LENGTH_BYTES + 3U]; frame[0U] = m_control; uint16_t ptr = m_endPtr + DMO_BUFFER_LENGTH_SAMPLES - DMR_FRAME_LENGTH_SAMPLES + DMR_RADIO_SYMBOL_LENGTH + 1U; if (ptr >= DMO_BUFFER_LENGTH_SAMPLES) ptr -= DMO_BUFFER_LENGTH_SAMPLES; samplesToBits(ptr, DMR_FRAME_LENGTH_SYMBOLS, frame, 8U, centre, threshold); if (m_control == CONTROL_DATA) { // Data sync uint8_t colorCode; uint8_t dataType; CDMRSlotType slotType; slotType.decode(frame + 1U, colorCode, dataType); if (colorCode == m_colorCode) { m_syncCount = 0U; m_n = 0U; frame[0U] |= dataType; switch (dataType) { case DT_DATA_HEADER: DEBUG4("DMRDMORX: data header found pos/centre/threshold", m_syncPtr, centre, threshold); writeRSSIData(frame); #if defined(DUMP_SAMPLES) writeSamples(ptr, frame[0U]); #endif m_state = DMORXS_DATA; m_type = 0x00U; break; case DT_RATE_12_DATA: case DT_RATE_34_DATA: case DT_RATE_1_DATA: if (m_state == DMORXS_DATA) { DEBUG4("DMRDMORX: data payload found pos/centre/threshold", m_syncPtr, centre, threshold); writeRSSIData(frame); #if defined(DUMP_SAMPLES) writeSamples(ptr, frame[0U]); #endif m_type = dataType; } break; case DT_VOICE_LC_HEADER: DEBUG4("DMRDMORX: voice header found pos/centre/threshold", m_syncPtr, centre, threshold); writeRSSIData(frame); #if defined(DUMP_SAMPLES) writeSamples(ptr, frame[0U]); #endif m_state = DMORXS_VOICE; break; case DT_VOICE_PI_HEADER: if (m_state == DMORXS_VOICE) { DEBUG4("DMRDMORX: voice pi header found pos/centre/threshold", m_syncPtr, centre, threshold); writeRSSIData(frame); #if defined(DUMP_SAMPLES) writeSamples(ptr, frame[0U]); #endif } m_state = DMORXS_VOICE; break; case DT_TERMINATOR_WITH_LC: if (m_state == DMORXS_VOICE) { DEBUG4("DMRDMORX: voice terminator found pos/centre/threshold", m_syncPtr, centre, threshold); writeRSSIData(frame); #if defined(DUMP_SAMPLES) writeSamples(ptr, frame[0U]); #endif reset(); } break; default: // DT_CSBK DEBUG4("DMRDMORX: csbk found pos/centre/threshold", m_syncPtr, centre, threshold); writeRSSIData(frame); #if defined(DUMP_SAMPLES) writeSamples(ptr, frame[0U]); #endif reset(); break; } } } else if (m_control == CONTROL_VOICE) { // Voice sync DEBUG4("DMRDMORX: voice sync found pos/centre/threshold", m_syncPtr, centre, threshold); writeRSSIData(frame); #if defined(DUMP_SAMPLES) writeSamples(ptr, frame[0U]); #endif m_state = DMORXS_VOICE; m_syncCount = 0U; m_n = 0U; } else { if (m_state != DMORXS_NONE) { m_syncCount++; if (m_syncCount >= MAX_SYNC_LOST_FRAMES) { serial.writeDMRLost(true); reset(); } } if (m_state == DMORXS_VOICE) { if (m_n >= 5U) { frame[0U] = CONTROL_VOICE; m_n = 0U; } else { frame[0U] = ++m_n; } serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U); #if defined(DUMP_SAMPLES) writeSamples(ptr, frame[0U]); #endif } else if (m_state == DMORXS_DATA) { if (m_type != 0x00U) { frame[0U] = CONTROL_DATA | m_type; writeRSSIData(frame); #if defined(DUMP_SAMPLES) writeSamples(ptr, frame[0U]); #endif } } } // End of this slot, reset some items for the next slot. m_maxCorr = 0; m_control = CONTROL_NONE; }
bool CDMRSlotRX::processSample(q15_t sample) { // Ensure that the buffer doesn't overflow if (m_dataPtr > m_endPtr || m_dataPtr >= 900U) return m_receiving; m_buffer[m_dataPtr] = sample; // The approximate position of the sync samples, XXX to be updated later // XXX change range when m_endPtr is set, make it tighter. if (m_dataPtr >= 160U && m_dataPtr <= 530U) correlateSync(sample); if (m_dataPtr == m_endPtr) { uint8_t frame[DMR_FRAME_LENGTH_BYTES + 1U]; frame[0U] = m_control; uint16_t ptr = m_endPtr - DMR_FRAME_LENGTH_SAMPLES + DMR_RADIO_SYMBOL_LENGTH + 1U; samplesToBits(ptr, DMR_FRAME_LENGTH_SYMBOLS, frame, 8U, m_centre, m_threshold); if (m_control == 0x40U) { // Data sync uint8_t colorCode; uint8_t dataType; CDMRSlotType slotType; slotType.decode(frame + 1U, colorCode, dataType); frame[0U] |= dataType; switch (dataType) { case DT_DATA_HEADER: case DT_VOICE_LC_HEADER: case DT_VOICE_PI_HEADER: DEBUG4("DMRSlotRX: header for slot/color code/data type", m_slot ? 2U : 1U, colorCode, dataType); m_receiving = true; m_syncCount = 0U; m_n = 0U; serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); break; case DT_TERMINATOR_WITH_LC: DEBUG3("DMRSlotRX: terminator for slot/color code", m_slot ? 2U : 1U, colorCode); m_receiving = false; m_endPtr = 999U; serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); break; default: DEBUG4("DMRSlotRX: data sync for slot/color code/data type", m_slot ? 2U : 1U, colorCode, dataType); m_receiving = false; serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); break; } } else if (m_control == 0x20U) { // Voice sync DEBUG2("DMRSlotRX: voice sync for slot", m_slot ? 2U : 1U); serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); m_receiving = true; m_syncCount = 0U; m_n = 0U; } else { // Voice data frame[0U] |= ++m_n; serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U); } } m_dataPtr++; return m_receiving; }