diff --git a/DMRDataHeader.cpp b/DMRDataHeader.cpp index ef0922d..d1864a5 100644 --- a/DMRDataHeader.cpp +++ b/DMRDataHeader.cpp @@ -29,6 +29,8 @@ #include #include +const unsigned char UDTF_NMEA = 0x05U; + CDMRDataHeader::CDMRDataHeader() : m_data(NULL), m_GI(false), @@ -78,13 +80,13 @@ bool CDMRDataHeader::put(const unsigned char* bytes) switch (dpf) { case DPF_UNCONFIRMED_DATA: - CUtils::dump(1U, "Unconfirmed Data Header", m_data, 12U); + CUtils::dump(1U, "DMR, Unconfirmed Data Header", m_data, 12U); m_F = (m_data[8U] & 0x80U) == 0x80U; m_blocks = m_data[8U] & 0x7FU; break; case DPF_CONFIRMED_DATA: - CUtils::dump(1U, "Confirmed Data Header", m_data, 12U); + CUtils::dump(1U, "DMR, Confirmed Data Header", m_data, 12U); m_F = (m_data[8U] & 0x80U) == 0x80U; m_blocks = m_data[8U] & 0x7FU; m_S = (m_data[9U] & 0x80U) == 0x80U; @@ -92,38 +94,46 @@ bool CDMRDataHeader::put(const unsigned char* bytes) break; case DPF_RESPONSE: - CUtils::dump(1U, "Response Data Header", m_data, 12U); + CUtils::dump(1U, "DMR, Response Data Header", m_data, 12U); m_blocks = m_data[8U] & 0x7FU; break; case DPF_PROPRIETARY: - CUtils::dump(1U, "Proprietary Data Header", m_data, 12U); + CUtils::dump(1U, "DMR, Proprietary Data Header", m_data, 12U); break; case DPF_DEFINED_RAW: - CUtils::dump(1U, "Raw or Status/Precoded Short Data Header", m_data, 12U); + CUtils::dump(1U, "DMR, Raw or Status/Precoded Short Data Header", m_data, 12U); m_blocks = (m_data[0U] & 0x30U) + (m_data[1U] & 0x0FU); m_F = (m_data[8U] & 0x01U) == 0x01U; m_S = (m_data[8U] & 0x02U) == 0x02U; break; case DPF_DEFINED_SHORT: - CUtils::dump(1U, "Defined Short Data Header", m_data, 12U); + CUtils::dump(1U, "DMR, Defined Short Data Header", m_data, 12U); m_blocks = (m_data[0U] & 0x30U) + (m_data[1U] & 0x0FU); m_F = (m_data[8U] & 0x01U) == 0x01U; m_S = (m_data[8U] & 0x02U) == 0x02U; break; case DPF_UDT: - CUtils::dump(1U, "Unified Data Transport Header", m_data, 12U); + CUtils::dump(1U, "DMR, Unified Data Transport Header", m_data, 12U); m_blocks = m_data[8U] & 0x03U; break; default: - CUtils::dump("Unknown Data Header", m_data, 12U); + CUtils::dump("DMR, Unknown Data Header", m_data, 12U); break; } + if (dpf == DPF_UDT && m_blocks == 0U) { + unsigned char format = m_data[1U] & 0x0FU; + if (format == UDTF_NMEA) { + LogDebug("DMR, fixing broken Tytera MD-390 GPS data block count"); + m_blocks = 3U; + } + } + return true; } diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index f902d2f..6bb182f 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -522,8 +522,16 @@ bool CDMRNetwork::writeConfig() char longitude[20U]; ::sprintf(longitude, "%09f", m_longitude); + unsigned int power = m_power; + if (power > 99U) + power = 99U; + + int height = m_height; + if (height > 999) + height = 999; + ::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%8.8s%9.9s%03d%-20.20s%-19.19s%c%-124.124s%-40.40s%-40.40s", m_callsign.c_str(), - m_rxFrequency, m_txFrequency, m_power, m_colorCode, latitude, longitude, m_height, m_location.c_str(), + m_rxFrequency, m_txFrequency, power, m_colorCode, latitude, longitude, height, m_location.c_str(), m_description.c_str(), slots, m_url.c_str(), m_version, software); return write((unsigned char*)buffer, 302U); diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index b2faa0d..6b495db 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1144,6 +1144,12 @@ void CMMDVMHost::createDisplay() m_display = new CNullDisplay; } + if (m_display == NULL) { + LogWarning("No valid display found, disabling"); + m_display = new CNullDisplay; + return; + } + bool ret = m_display->open(); if (!ret) { delete m_display; diff --git a/UMP/UMP.ino b/UMP/UMP.ino index 501737b..a0c99aa 100644 --- a/UMP/UMP.ino +++ b/UMP/UMP.ino @@ -16,20 +16,26 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#if !defined(__AVR_ATmega1280__) && !defined(__AVR_ATmega2560__) && !defined(__AVR_ATmega32U4__) && !defined(__SAM3X8E__) && !defined(__MK20DX256__) +#include +#endif + #if !defined(PIN_LED) #define PIN_LED 13 #endif #if defined(__MK20DX256__) -#define PIN_DSTAR 2 -#define PIN_DMR 3 -#define PIN_YSF 4 -#define PIN_P25 5 +#define PIN_DSTAR 3 +#define PIN_DMR 4 +#define PIN_YSF 5 +#define PIN_P25 6 #define PIN_TX 10 #define PIN_CD 11 #define PIN_LOCKOUT 12 + +#define FLASH_DELAY 200000U #else #define PIN_DSTAR 2 #define PIN_DMR 3 @@ -39,7 +45,13 @@ #define PIN_TX 6 #define PIN_CD 7 -#define PIN_LOCKOUT 8 +#define PIN_LOCKOUT 12 + +#define FLASH_DELAY 3200U +#endif + +#if !defined(__AVR_ATmega1280__) && !defined(__AVR_ATmega2560__) && !defined(__AVR_ATmega32U4__) && !defined(__SAM3X8E__) && !defined(__MK20DX256__) +AltSoftSerial mySerial; #endif // Use the LOCKOUT function on the UMP @@ -51,6 +63,8 @@ void setup() #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__SAM3X8E__) || defined(__MK20DX256__) Serial1.begin(9600); +#else + mySerial.begin(9600); #endif pinMode(PIN_LED, OUTPUT); @@ -132,11 +146,13 @@ void loop() case UMP_SET_CD: digitalWrite(PIN_CD, m_buffer[3U] == 0x01U ? HIGH : LOW); break; -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__SAM3X8E__) || defined(__MK20DX256__) case UMP_WRITE_SERIAL: +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__SAM3X8E__) || defined(__MK20DX256__) Serial1.write(m_buffer + 3U, m_length - 3U); - break; +#else + mySerial.write(m_buffer + 3U, m_length - 3U); #endif + break; default: break; } @@ -165,17 +181,20 @@ void loop() #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__SAM3X8E__) || defined(__MK20DX256__) while (Serial1.available()) Serial1.read(); +#else + while (mySerial.available()) + mySerial.read(); #endif m_count++; if (m_started) { - if (m_count > 3200U) { + if (m_count > FLASH_DELAY) { digitalWrite(PIN_LED, m_led ? LOW : HIGH); m_led = !m_led; m_count = 0U; } } else { - if (m_count > 32000U) { + if (m_count > (FLASH_DELAY * 3U)) { digitalWrite(PIN_LED, m_led ? LOW : HIGH); m_led = !m_led; m_count = 0U; diff --git a/Version.h b/Version.h index 865c176..3bce33e 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20161021"; +const char* VERSION = "20161124"; #endif diff --git a/YSFControl.cpp b/YSFControl.cpp index 5d23a69..c0a3ea7 100644 --- a/YSFControl.cpp +++ b/YSFControl.cpp @@ -254,7 +254,7 @@ bool CYSFControl::writeModem(unsigned char *data, unsigned int len) unsigned int errors = m_rfPayload.processVoiceFRModeAudio(data + 2U); m_rfErrs += errors; m_rfBits += 720U; - LogDebug("YSF, V Mode 3, seq %u, IMBE FEC %u/720 (%.1f%%)", m_rfFrames % 128, errors, float(errors) / 7.2F); + LogDebug("YSF, V Mode 3, seq %u, AMBE FEC %u/720 (%.1f%%)", m_rfFrames % 128, errors, float(errors) / 7.2F); } valid = false; break; @@ -525,7 +525,7 @@ void CYSFControl::writeNetwork() // if (send) { m_netErrs += errors; m_netBits += 720U; - LogDebug("YSF, V Mode 3, seq %u, IMBE FEC %u/720 (%.1f%%)", n, errors, float(errors) / 7.2F); + LogDebug("YSF, V Mode 3, seq %u, AMBE FEC %u/720 (%.1f%%)", n, errors, float(errors) / 7.2F); // } } break; diff --git a/YSFPayload.cpp b/YSFPayload.cpp index c74d7d6..253b35e 100644 --- a/YSFPayload.cpp +++ b/YSFPayload.cpp @@ -393,11 +393,51 @@ unsigned int CYSFPayload::processVDMode2Audio(unsigned char* data) data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES; unsigned int errors = 0U; - errors += processVDMode2AudioBlock(data + 5U); - errors += processVDMode2AudioBlock(data + 23U); - errors += processVDMode2AudioBlock(data + 41U); - errors += processVDMode2AudioBlock(data + 59U); - errors += processVDMode2AudioBlock(data + 77U); + unsigned int offset = 40U; // DCH(0) + + // We have a total of 5 VCH sections, iterate through each + for (unsigned int j = 0U; j < 5U; j++, offset += 144U) { + unsigned char vch[13U]; + + // Deinterleave + for (unsigned int i = 0U; i < 104U; i++) { + unsigned int n = INTERLEAVE_TABLE_26_4[i]; + bool s = READ_BIT1(data, offset + n) != 0x00U; + WRITE_BIT1(vch, i, s); + } + + // "Un-whiten" (descramble) + for (unsigned int i = 0U; i < 13U; i++) + vch[i] ^= WHITENING_DATA[i]; + + // errors += READ_BIT1(vch, 103); // Padding bit must be zero but apparently it is not... + + for (unsigned int i = 0U; i < 81U; i += 3) { + uint8_t vote = bool(READ_BIT1(vch, i)) + bool(READ_BIT1(vch, i + 1)) + bool(READ_BIT1(vch, i + 2)); + if (vote == 1 || vote == 2) { + bool decision = vote / 2; // exploit integer division: 1/2 == 0, 2/2 == 1. + WRITE_BIT1(vch, i, decision); + WRITE_BIT1(vch, i + 1, decision); + WRITE_BIT1(vch, i + 2, decision); + errors++; + } + } + + // Reconstruct only if we have bit errors. Technically we could even + // constrain it individually to the 5 VCH sections. + if (errors > 0U) { + // Scramble + for (unsigned int i = 0U; i < 13U; i++) + vch[i] ^= WHITENING_DATA[i]; + + // Interleave + for (unsigned int i = 0U; i < 104U; i++) { + unsigned int n = INTERLEAVE_TABLE_26_4[i]; + bool s = READ_BIT1(vch, i); + WRITE_BIT1(data, offset + n, s); + } + } + } // "errors" is the number of triplets that were recognized to be corrupted // and that were corrected. There are 27 of those per VCH and 5 VCH per CC, @@ -407,65 +447,6 @@ unsigned int CYSFPayload::processVDMode2Audio(unsigned char* data) return errors; } -unsigned int CYSFPayload::processVDMode2AudioBlock(unsigned char* data) -{ - assert(data != NULL); - - unsigned int errors = 0U; - unsigned char vch[13U]; - - // Deinterleave - for (unsigned int i = 0U; i < 104U; i++) { - unsigned int n = INTERLEAVE_TABLE_26_4[i]; - bool s = READ_BIT1(data, n); - WRITE_BIT1(vch, i, s); - } - - // "Un-whiten" (descramble) - for (unsigned int i = 0U; i < 13U; i++) - vch[i] ^= WHITENING_DATA[i]; - - for (unsigned int i = 0U; i < 81U; i += 3U) { - unsigned int n = i; - bool bit1 = READ_BIT1(vch, n); - n++; - bool bit2 = READ_BIT1(vch, n); - n++; - bool bit3 = READ_BIT1(vch, n); - - if ((bit1 && bit2 && !bit3) || (bit1 && !bit2 && bit3) || (!bit1 && bit2 && bit3)) { - unsigned int n = i; - WRITE_BIT1(vch, n, true); - n++; - WRITE_BIT1(vch, n, true); - n++; - WRITE_BIT1(vch, n, true); - errors++; - } else if ((!bit1 && !bit2 && bit3) || (!bit1 && bit2 && !bit3) || (bit1 && !bit2 && !bit3)) { - unsigned int n = i; - WRITE_BIT1(vch, n, false); - n++; - WRITE_BIT1(vch, n, false); - n++; - WRITE_BIT1(vch, n, false); - errors++; - } - } - - // Scramble - for (unsigned int i = 0U; i < 13U; i++) - vch[i] ^= WHITENING_DATA[i]; - - // Interleave - for (unsigned int i = 0U; i < 104U; i++) { - unsigned int n = INTERLEAVE_TABLE_26_4[i]; - bool s = READ_BIT1(vch, i); - WRITE_BIT1(data, n, s); - } - - return errors; -} - bool CYSFPayload::processVDMode2Data(unsigned char* data, unsigned char fn, bool gateway) { assert(data != NULL); diff --git a/YSFPayload.h b/YSFPayload.h index ba14889..8fc5061 100644 --- a/YSFPayload.h +++ b/YSFPayload.h @@ -54,8 +54,6 @@ private: unsigned char* m_source; unsigned char* m_dest; CAMBEFEC m_fec; - - unsigned int processVDMode2AudioBlock(unsigned char* data); }; #endif