diff options
-rw-r--r-- | include/mts/MTS_IO_QuectelRadio.h | 2 | ||||
-rw-r--r-- | src/MTS_IO_QuectelRadio.cpp | 71 |
2 files changed, 49 insertions, 24 deletions
diff --git a/include/mts/MTS_IO_QuectelRadio.h b/include/mts/MTS_IO_QuectelRadio.h index 0f24db8..5199b40 100644 --- a/include/mts/MTS_IO_QuectelRadio.h +++ b/include/mts/MTS_IO_QuectelRadio.h @@ -73,7 +73,7 @@ namespace MTS { static const std::string VALUE_MTS_DELTA_NAME; static const std::string VALUE_MTS_DELTA_PATH; - CODE startFileUpload(const std::string& sTargetFilename, size_t nBytes); + CODE startFileUpload(const std::string& sTargetFilename, size_t nBytes, uint16_t uRxTimeout = 5, bool bAckEnabled = false); CODE abortFileUpload(); static inline void callNextStep(UpdateCb& stepCb, const char* csMessage); diff --git a/src/MTS_IO_QuectelRadio.cpp b/src/MTS_IO_QuectelRadio.cpp index 942c0f7..a41e6fc 100644 --- a/src/MTS_IO_QuectelRadio.cpp +++ b/src/MTS_IO_QuectelRadio.cpp @@ -871,6 +871,9 @@ ICellularRadio::CODE QuectelRadio::setCellularMode(CELLULAR_MODES networks) { } ICellularRadio::CODE QuectelRadio::uploadFile(int fd, const std::string& sTargetFilename, ICellularRadio::UpdateCb& stepCb) { + const uint16_t uFileTimeout = 2; // s + const int32_t iUploadResultTimeout = uFileTimeout * 2 * 1000; // ms + size_t dPayloadLength; size_t nChunks; CODE rc; @@ -888,7 +891,8 @@ ICellularRadio::CODE QuectelRadio::uploadFile(int fd, const std::string& sTarget printTrace("File size: %d bytes and %d chunks", dPayloadLength, nChunks); printTrace("Starting file upload..."); - rc = startFileUpload(sTargetFilename, dPayloadLength); + // Start file upload, set transmission timeouts and enable ACK mode + rc = startFileUpload(sTargetFilename, dPayloadLength, uFileTimeout, true); if (rc != SUCCESS) { return rc; } @@ -900,6 +904,20 @@ ICellularRadio::CODE QuectelRadio::uploadFile(int fd, const std::string& sTarget size_t nChunksPerCent = (nChunks / 100) + 1; size_t nFragmentLength = 0; std::array<char, FILE_CHUNK_SIZE> vBuffer; + std::string sResponse; + + // ACK waiter callback - wait for ACK and populate result code + IsNeedMoreData waitAck = [&rc](const std::string& iterationData, const std::string&/*allData*/)->bool { + if (iterationData.find('A') != std::string::npos) { + // No data needed + rc = SUCCESS; + return false; + } + + // We need more data + rc = NO_RESPONSE; + return true; + }; for (size_t iChunk = 1; iChunk < (nChunks + 1); iChunk++) { @@ -914,6 +932,14 @@ ICellularRadio::CODE QuectelRadio::uploadFile(int fd, const std::string& sTarget rc = sendData(vBuffer.data(), nFragmentLength); if (rc != SUCCESS) { + // failed to send data + break; + } + + // Wait for ACK for up to 1 second and populate rc variable + sResponse = waitResponse(waitAck, 1000); + if (rc != SUCCESS) { + // timeout or end of execution - check later break; } @@ -924,38 +950,28 @@ ICellularRadio::CODE QuectelRadio::uploadFile(int fd, const std::string& sTarget } - if (rc != SUCCESS) { - // cancel upload and terminate - callNextStep(stepCb, "FILE Error: Upload failed due to internal error"); - abortFileUpload(); - return rc; - } - printTrace("Waiting for acknoledge from the radio"); std::string sExpectedResult = "+QFUPL: "; sExpectedResult += MTS::Text::format(dPayloadLength); sExpectedResult += ","; sExpectedResult += MTS::Text::toLowerCase(MTS::Text::formatHex(dChecksum)); - // "send" empty string to read acknoledge string - std::string sResult = sendCommand("", DEFAULT_BAIL_STRINGS, 10000, 0x00); + // Wait for confirmation of successful upload completion + sResponse += waitResponse(DEFAULT_BAIL_STRINGS, iUploadResultTimeout); - if (sResult.find(sExpectedResult) != std::string::npos) { - printDebug("Radio returned: [%s]", sResult.c_str()); + if (sResponse.find(sExpectedResult) != std::string::npos) { + printDebug("Radio returned: [%s]", sResponse.c_str()); printTrace("Upload finished, checksum matched"); - } else { - printError("Upload failed: checksum mismatch. Expected: [%s], Actual: [%s]", sExpectedResult.c_str(), sResult.c_str()); - abortFileUpload(); - rc = FAILURE; - } - - if (rc == SUCCESS) { callNextStep(stepCb, "FILE Info: Upload finished successfully"); - } else { - callNextStep(stepCb, "FILE Error: Upload failed due to internal error"); + + return SUCCESS; } - return rc; + printError("Upload failed: checksum mismatch. Expected: [%s], Actual: [%s]", sExpectedResult.c_str(), sResponse.c_str()); + callNextStep(stepCb, "FILE Error: Upload failed due to internal error"); + + abortFileUpload(); + return FAILURE; } ICellularRadio::CODE QuectelRadio::removeFile(const std::string& sTargetFilename) { @@ -1159,15 +1175,24 @@ std::string QuectelRadio::getFumoEarlyErrorCode(const std::string& sRadioInput) return sResult; } -ICellularRadio::CODE QuectelRadio::startFileUpload(const std::string& sTargetFilename, size_t nBytes) { +ICellularRadio::CODE QuectelRadio::startFileUpload(const std::string& sTargetFilename, size_t nBytes, uint16_t uRxTimeout, bool bAckEnabled) { const std::vector<std::string> vBailStrings{ ICellularRadio::RSP_CONNECT, ICellularRadio::RSP_ERROR }; const int dTimeout = 1000; //ms std::string sCommand, sResult; + // Format: AT+QFUPL=<filename>[,<file_size>[,<timeout>[,<ackmode>]] + sCommand = "AT+QFUPL=\""; sCommand += sTargetFilename; sCommand += "\","; sCommand += MTS::Text::format(nBytes); + sCommand += ","; + sCommand += MTS::Text::format(uRxTimeout); + + if (bAckEnabled) { + // ACK mode enabled + sCommand += ",1"; + } sResult = sendCommand(sCommand, vBailStrings, dTimeout); if (sResult.find(ICellularRadio::RSP_CONNECT) == std::string::npos) { |