From cdf53cc9ad635468e22b3babf7766b140de160ca Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Thu, 10 Mar 2022 00:05:46 -0500 Subject: [PATCH] initial commit for using flash storage on the modem as a backup for critical tuning data (this is incomplete, it will READ/WRITE/ERASE data, but won't parse it yet...); --- host/calibrate/HostCal.cpp | 229 ++++++++++++++++++++++++++++++++++++- host/calibrate/HostCal.h | 10 ++ modem/Modem.cpp | 91 ++++++++++++++- modem/Modem.h | 18 +++ 4 files changed, 342 insertions(+), 6 deletions(-) diff --git a/host/calibrate/HostCal.cpp b/host/calibrate/HostCal.cpp index 4036369b..49f9efe6 100644 --- a/host/calibrate/HostCal.cpp +++ b/host/calibrate/HostCal.cpp @@ -36,6 +36,7 @@ #include "p25/data/DataHeader.h" #include "p25/lc/LC.h" #include "p25/P25Utils.h" +#include "edac/CRC.h" #include "HostMain.h" #include "Log.h" #include "Utils.h" @@ -174,6 +175,7 @@ HostCal::HostCal(const std::string& confFile) : m_berUncorrectable(0U), m_timeout(300U), m_timer(0U), + m_updateConfigFromModem(false), m_hasFetchedStatus(false) { /* stub */ @@ -414,6 +416,8 @@ int HostCal::run() return 1; } + readFlash(); + writeConfig(); writeRFParams(); @@ -445,7 +449,7 @@ int HostCal::run() while (!end) { int c = m_console.getChar(); switch (c) { - /** Level Adjustment Commands */ + /** Level Adjustment Commands */ case 'I': { if (!m_isHotspot) { @@ -613,7 +617,13 @@ int HostCal::run() } break; - /** Engineering Commands */ + /** Engineering Commands */ + case 'E': + eraseFlash(); + break; + case 'e': + readFlash(); + break; case '-': if (!m_isHotspot) setDMRSymLevel3Adj(-1); @@ -755,7 +765,7 @@ int HostCal::run() } break; - /** Mode Commands */ + /** Mode Commands */ case 'Z': { m_mode = STATE_DMR_CAL; @@ -936,8 +946,15 @@ int HostCal::run() { yaml::Serialize(m_conf, m_confFile.c_str(), yaml::SerializeConfig(4, 64, false, false)); LogMessage(LOG_CAL, " - Saved configuration to %s", m_confFile.c_str()); + if (writeFlash()) { + LogMessage(LOG_CAL, " - Wrote configuration area on modem"); + } } break; + case 'U': + m_updateConfigFromModem = true; + readFlash(); + break; case 'Q': case 'q': m_mode = STATE_IDLE; @@ -1109,12 +1126,52 @@ bool HostCal::portModemHandler(Modem* modem, uint32_t ms, RESP_TYPE_DVM rspType, } break; + case CMD_FLSH_READ: + { + uint8_t len = buffer[1U]; + if (m_debug) { + Utils::dump(1U, "Modem Flash Contents", buffer, len); + } + if (len == 249U) { + bool ret = edac::CRC::checkCCITT162(buffer + 3U, DVM_CONF_AREA_LEN); + if (!ret) { + LogWarning(LOG_CAL, "HostCal::portModemHandler(), clearing modem configuration area; first setup?"); + eraseFlash(); + } + else { + bool isErased = (buffer[DVM_CONF_AREA_LEN] & 0x80U) == 0x80U; + uint8_t confAreaVersion = buffer[DVM_CONF_AREA_LEN] & 0x7FU; + + if (!isErased) { + if (confAreaVersion != DVM_CONF_AREA_VER) { + LogError(LOG_MODEM, "HostCal::portModemHandler(), invalid version for configuration area, %02X != %02X", DVM_CONF_AREA_VER, confAreaVersion); + } + else { + processFlashConfig(buffer + 3U); + + // reset update config flag if its set + if (m_updateConfigFromModem) { + m_updateConfigFromModem = false; + } + } + } + else { + LogWarning(LOG_MODEM, "HostCal::portModemHandler(), modem configuration area was erased and does not contain active configuration!"); + } + } + } + else { + LogWarning(LOG_MODEM, "Incorrect length for configuration area! Ignoring."); + } + } + break; + case CMD_GET_VERSION: case CMD_ACK: break; case CMD_NAK: - LogWarning(LOG_MODEM, "NAK, command = 0x%02X, reason = %u", buffer[3U], buffer[4U]); + LogWarning(LOG_CAL, "NAK, command = 0x%02X, reason = %u", buffer[3U], buffer[4U]); break; case CMD_DEBUG1: @@ -1127,7 +1184,7 @@ bool HostCal::portModemHandler(Modem* modem, uint32_t ms, RESP_TYPE_DVM rspType, break; default: - LogWarning(LOG_MODEM, "Unknown message, type = %02X", buffer[2U]); + LogWarning(LOG_CAL, "Unknown message, type = %02X", buffer[2U]); Utils::dump("Buffer dump", buffer, len); break; } @@ -1149,6 +1206,9 @@ void HostCal::displayHelp() LogMessage(LOG_CAL, " v Display version of firmware"); LogMessage(LOG_CAL, " H/h Display help"); LogMessage(LOG_CAL, " S/s Save calibration settings to configuration file"); + if (!m_modem->m_flashDisabled) { + LogMessage(LOG_CAL, " U Read modem configuration area and reset local configuration"); + } LogMessage(LOG_CAL, " Q/q Quit"); LogMessage(LOG_CAL, "Level Adjustment Commands:"); if (!m_isHotspot) { @@ -1199,6 +1259,10 @@ void HostCal::displayHelp() LogMessage(LOG_CAL, " 4 Set P25 Post Demod Bandwidth Offset"); LogMessage(LOG_CAL, " 5 Set ADF7021 Rx Auto. Gain Mode"); } + if (!m_modem->m_flashDisabled) { + LogMessage(LOG_CAL, " E Erase modem configuration area"); + LogMessage(LOG_CAL, " e Read modem configuration area"); + } } /// @@ -2064,6 +2128,161 @@ void HostCal::sleep(uint32_t ms) #endif } +/// +/// Read the configuration area on the air interface modem. +/// +bool HostCal::readFlash() +{ + if (m_modem->m_flashDisabled) { + return false; + } + + uint8_t buffer[3U]; + ::memset(buffer, 0x00U, 3U); + + buffer[0U] = DVM_FRAME_START; + buffer[1U] = 3U; + buffer[2U] = CMD_FLSH_READ; + + int ret = m_modem->write(buffer, 3U); + if (ret <= 0) + return false; + + sleep(1000U); + + m_modem->clock(0U); + return true; +} + +/// +/// Process the configuration data from the air interface modem. +/// +/// +void HostCal::processFlashConfig(const uint8_t *buffer) +{ + if (m_updateConfigFromModem) { + LogMessage(LOG_CAL, " - Restoring local configuration from configuration area on modem"); + + // TODO TODO TODO + } +} + +/// +/// Erase the configuration area on the air interface modem. +/// +bool HostCal::eraseFlash() +{ + if (m_modem->m_flashDisabled) { + return false; + } + + uint8_t buffer[249U]; + ::memset(buffer, 0x00U, 249U); + + buffer[0U] = DVM_FRAME_START; + buffer[1U] = 249U; + buffer[2U] = CMD_FLSH_WRITE; + + // configuration version + buffer[DVM_CONF_AREA_LEN] = DVM_CONF_AREA_VER & 0x7FU; + buffer[DVM_CONF_AREA_LEN] |= 0x80U; // flag erased + edac::CRC::addCCITT162(buffer + 3U, DVM_CONF_AREA_LEN); + + int ret = m_modem->write(buffer, 249U); + if (ret <= 0) + return false; + + sleep(1000U); + + m_updateConfigFromModem = false; + LogMessage(LOG_CAL, " - Erased configuration area on modem"); + + m_modem->clock(0U); + return true; +} + +/// +/// Write the configuration area on the air interface modem. +/// +bool HostCal::writeFlash() +{ + if (m_modem->m_flashDisabled) { + return false; + } + + uint8_t buffer[249U]; + ::memset(buffer, 0x00U, 249U); + + buffer[0U] = DVM_FRAME_START; + buffer[1U] = 249U; + buffer[2U] = CMD_FLSH_WRITE; + + // general config + buffer[3U] = 0x00U; + if (m_rxInvert) + buffer[3U] |= 0x01U; + if (m_txInvert) + buffer[3U] |= 0x02U; + if (m_pttInvert) + buffer[3U] |= 0x04U; + + buffer[4U] = 0x00U; + if (m_dcBlocker) + buffer[4U] |= 0x01U; + + if (m_dmrEnabled) + buffer[4U] |= 0x02U; + if (m_p25Enabled) + buffer[4U] |= 0x08U; + + buffer[5U] = m_fdmaPreamble; + + buffer[7U] = (uint8_t)(m_rxLevel * 2.55F + 0.5F); + buffer[8U] = (uint8_t)(m_txLevel * 2.55F + 0.5F); + + buffer[10U] = m_dmrRxDelay; + buffer[11U] = (uint8_t)m_p25CorrCount; + + buffer[13U] = (uint8_t)(m_txLevel * 2.55F + 0.5F); + buffer[15U] = (uint8_t)(m_txLevel * 2.55F + 0.5F); + + buffer[16U] = (uint8_t)(m_txDCOffset + 128); + buffer[17U] = (uint8_t)(m_rxDCOffset + 128); + + // RF parameters + buffer[20U] = (uint8_t)(m_dmrDiscBWAdj + 128); + buffer[21U] = (uint8_t)(m_p25DiscBWAdj + 128); + buffer[22U] = (uint8_t)(m_dmrPostBWAdj + 128); + buffer[23U] = (uint8_t)(m_p25PostBWAdj + 128); + + buffer[24U] = (uint8_t)m_adfGainMode; + + buffer[25U] = (uint8_t)(m_txTuning + 128); + buffer[26U] = (uint8_t)(m_rxTuning + 128); + + // symbol adjust + buffer[30U] = (uint8_t)(m_dmrSymLevel3Adj + 128); + buffer[31U] = (uint8_t)(m_dmrSymLevel1Adj + 128); + + buffer[32U] = (uint8_t)(m_p25SymLevel3Adj + 128); + buffer[33U] = (uint8_t)(m_p25SymLevel1Adj + 128); + + // configuration version + buffer[DVM_CONF_AREA_LEN] = DVM_CONF_AREA_VER; + edac::CRC::addCCITT162(buffer + 3U, DVM_CONF_AREA_LEN); + + int ret = m_modem->write(buffer, 249U); + if (ret <= 0) + return false; + + sleep(1000U); + + m_updateConfigFromModem = false; + + m_modem->clock(0U); + return true; +} + /// /// Helper to clock the calibration BER timer. /// diff --git a/host/calibrate/HostCal.h b/host/calibrate/HostCal.h index 04e5d69e..83df0d9f 100644 --- a/host/calibrate/HostCal.h +++ b/host/calibrate/HostCal.h @@ -129,6 +129,7 @@ private: uint32_t m_timeout; uint32_t m_timer; + bool m_updateConfigFromModem; bool m_hasFetchedStatus; /// Modem port open callback. @@ -181,6 +182,15 @@ private: /// Helper to sleep the calibration thread. void sleep(uint32_t ms); + /// Read the configuration area on the air interface modem. + bool readFlash(); + /// Process the configuration data from the air interface modem. + void processFlashConfig(const uint8_t *buffer); + /// Erase the configuration area on the air interface modem. + bool eraseFlash(); + /// Write the configuration area on the air interface modem. + bool writeFlash(); + /// Helper to clock the calibration BER timer. void timerClock(); /// Helper to start the calibration BER timer. diff --git a/modem/Modem.cpp b/modem/Modem.cpp index 31e23585..038ded3f 100644 --- a/modem/Modem.cpp +++ b/modem/Modem.cpp @@ -33,6 +33,7 @@ #include "dmr/DMRDefines.h" #include "p25/P25Defines.h" #include "modem/Modem.h" +#include "edac/CRC.h" #include "Log.h" #include "Thread.h" #include "Utils.h" @@ -135,6 +136,7 @@ Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert, m_cd(false), m_lockout(false), m_error(false), + m_flashDisabled(false), m_trace(trace), m_debug(debug), m_playoutTimer(1000U, 0U, packetPlayoutTime) @@ -381,6 +383,12 @@ bool Modem::open() m_rspOffset = 0U; m_rspState = RESP_START; + ret = readFlash(); + if (!ret) { + LogError(LOG_MODEM, "Unable to read configuration on modem flash device! Using local configuration."); + m_flashDisabled = true; + } + // do we have an open port handler? if (m_openPortHandler) { ret = m_openPortHandler(this); @@ -1553,6 +1561,87 @@ bool Modem::writeRFParams() return true; } +/// +/// Retrieve the data from the configuration area on the air interface modem. +/// +/// +bool Modem::readFlash() +{ + Thread::sleep(2000U); // 2s + + for (uint32_t i = 0U; i < 6U; i++) { + uint8_t buffer[3U]; + + buffer[0U] = DVM_FRAME_START; + buffer[1U] = 3U; + buffer[2U] = CMD_FLSH_READ; + + int ret = write(buffer, 3U); + if (ret != 3) + return false; + + for (uint32_t count = 0U; count < MAX_RESPONSES; count++) { + Thread::sleep(10U); + RESP_TYPE_DVM resp = getResponse(); + + if (resp == RTM_OK && m_buffer[2U] == CMD_NAK) { + LogWarning(LOG_MODEM, "Modem::readFlash(), old modem that doesn't support flash commands?"); + return false; + } + + if (resp == RTM_OK && m_buffer[2U] == CMD_FLSH_READ) { + uint8_t len = m_buffer[1U]; + if (m_debug) { + Utils::dump(1U, "Modem Flash Contents", m_buffer, len); + } + + if (len == 249U) { + bool ret = edac::CRC::checkCCITT162(m_buffer + 3U, DVM_CONF_AREA_LEN); + if (!ret) { + LogError(LOG_MODEM, "Modem::readFlash(), failed CRC CCITT-162 check"); + } + else { + bool isErased = (m_buffer[DVM_CONF_AREA_LEN] & 0x80U) == 0x80U; + uint8_t confAreaVersion = m_buffer[DVM_CONF_AREA_LEN] & 0x7FU; + + if (!isErased) { + if (confAreaVersion != DVM_CONF_AREA_VER) { + LogError(LOG_MODEM, "Modem::readFlash(), invalid version for configuration area, %02X != %02X", DVM_CONF_AREA_VER, confAreaVersion); + } + else { + processFlashConfig(m_buffer + 3U); + } + } + else { + LogWarning(LOG_MODEM, "Modem::readFlash(), modem configuration area was erased and does not contain active configuration!"); + } + } + } + else { + LogWarning(LOG_MODEM, "Incorrect length for configuration area! Ignoring."); + } + + return true; + } + } + + Thread::sleep(1500U); + } + + LogError(LOG_MODEM, "Unable to read the configuration flash after 6 attempts"); + + return false; +} + +/// +/// Process the configuration data from the air interface modem. +/// +/// +void Modem::processFlashConfig(const uint8_t *buffer) +{ + // TODO TODO TODO +} + /// /// Print debug air interface messages to the host log. /// @@ -1634,7 +1723,7 @@ RESP_TYPE_DVM Modem::getResponse() } if (m_buffer[0U] != DVM_FRAME_START) { - LogDebug(LOG_MODEM, "getResponse(), first byte not a frame start"); + LogDebug(LOG_MODEM, "getResponse(), first byte not a frame start; byte = %02X", m_buffer[0U]); return RTM_TIMEOUT; } diff --git a/modem/Modem.h b/modem/Modem.h index f6a46434..9c4253a8 100644 --- a/modem/Modem.h +++ b/modem/Modem.h @@ -123,6 +123,9 @@ namespace modem CMD_ACK = 0x70U, CMD_NAK = 0x7FU, + CMD_FLSH_READ = 0xE0U, + CMD_FLSH_WRITE = 0xE1U, + CMD_DEBUG1 = 0xF1U, CMD_DEBUG2 = 0xF2U, CMD_DEBUG3 = 0xF3U, @@ -149,6 +152,11 @@ namespace modem RSN_INVALID_P25_CORR_COUNT = 16U, + RSN_NO_INTERNAL_FLASH = 20U, + RSN_FAILED_ERASE_FLASH = 21U, + RSN_FAILED_WRITE_FLASH = 22U, + RSN_FLASH_WRITE_TOO_BIG = 23U, + RSN_HS_NO_DUAL_MODE = 32U, RSN_DMR_DISABLED = 63U, @@ -172,6 +180,9 @@ namespace modem const uint8_t DVM_FRAME_START = 0xFEU; + const uint8_t DVM_CONF_AREA_VER = 0x01U; + const uint8_t DVM_CONF_AREA_LEN = 246U; + const uint8_t MAX_FDMA_PREAMBLE = 255U; const uint32_t MAX_RESPONSES = 30U; @@ -382,6 +393,8 @@ namespace modem bool m_lockout; bool m_error; + bool m_flashDisabled; + /// Retrieve the air interface modem version. bool getFirmwareVersion(); /// Retrieve the current status from the air interface modem. @@ -393,6 +406,11 @@ namespace modem /// Write RF parameters to the air interface modem. bool writeRFParams(); + /// Retrieve the data from the configuration area on the air interface modem. + bool readFlash(); + /// Process the configuration data from the air interface modem. + void processFlashConfig(const uint8_t *buffer); + /// Print debug air interface messages to the host log. void printDebug(const uint8_t* buffer, uint16_t len);