diff --git a/linux/devices/ploc/PlocSupvHelper.cpp b/linux/devices/ploc/PlocSupvHelper.cpp index 9dd53535..51b6397e 100644 --- a/linux/devices/ploc/PlocSupvHelper.cpp +++ b/linux/devices/ploc/PlocSupvHelper.cpp @@ -90,107 +90,76 @@ ReturnValue_t PlocSupvHelper::initialize() { } ReturnValue_t PlocSupvHelper::performOperation(uint8_t operationCode) { - ReturnValue_t result; lock->lockMutex(); state = InternalState::IDLE; lock->unlockMutex(); + bool putTaskToSleep = false; while (true) { semaphore->acquire(); - int bytesRead = 0; while (true) { - bytesRead = read(serialPort, reinterpret_cast(recBuf.data()), - static_cast(recBuf.size())); - if (bytesRead == 0) { - { - MutexGuard mg(lock); - if (state == InternalState::FINISH) { - // Flush received and unread data - tcflush(serialPort, TCIOFLUSH); - state = InternalState::IDLE; - break; - } - } - } else if (bytesRead < 0) { - sif::warning << "ScexUartReader::performOperation: read call failed with error [" << errno - << ", " << strerror(errno) << "]" << std::endl; + putTaskToSleep = handleUartReception(); + if (putTaskToSleep) { break; - } else if (bytesRead >= static_cast(recBuf.size())) { - sif::error << "ScexUartReader::performOperation: Receive buffer too small for " << bytesRead - << " bytes" << std::endl; - } else if (bytesRead > 0) { - if (debugMode) { - sif::info << "Received " << bytesRead - << " bytes from the Solar Cell Experiment:" << std::endl; - } - recRingBuf.writeData(recBuf.data(), bytesRead); - // insert buffer into ring buffer here - // ReturnValue_t result = dleParser.passData(recBuf.data(), bytesRead); - // TODO: Parse ring buffer here } lock->lockMutex(); InternalState currentState = state; lock->unlockMutex(); switch (currentState) { case InternalState::IDLE: { + putTaskToSleep = true; break; } - case InternalState::UPDATE: { - result = executeUpdate(); - if (result == returnvalue::OK) { - triggerEvent(SUPV_UPDATE_SUCCESSFUL, result); - } else if (result == PROCESS_TERMINATED) { - // Event already triggered - } else { - triggerEvent(SUPV_UPDATE_FAILED, result); - } - MutexGuard mg(lock); + case InternalState::FINISH: { state = InternalState::IDLE; + putTaskToSleep = true; break; } - case InternalState::CHECK_MEMORY: { - executeFullCheckMemoryCommand(); - MutexGuard mg(lock); - state = InternalState::IDLE; + case InternalState::RUNNING: { + putTaskToSleep = handleRunningRequest(); break; } - case InternalState::CONTINUE_UPDATE: { - result = continueUpdate(); - if (result == returnvalue::OK) { - triggerEvent(SUPV_CONTINUE_UPDATE_SUCCESSFUL, result); - } else if (result == PROCESS_TERMINATED) { - // Event already triggered - } else { - triggerEvent(SUPV_CONTINUE_UPDATE_FAILED, result); - } - MutexGuard mg(lock); - state = InternalState::IDLE; - break; - } - case InternalState::REQUEST_EVENT_BUFFER: { - result = performEventBufferRequest(); - if (result == returnvalue::OK) { - triggerEvent(SUPV_EVENT_BUFFER_REQUEST_SUCCESSFUL, result); - } else if (result == PROCESS_TERMINATED) { - // Event already triggered - break; - } else { - triggerEvent(SUPV_EVENT_BUFFER_REQUEST_FAILED, result); - } - MutexGuard mg(lock); - state = InternalState::IDLE; - break; - } - case InternalState::HANDLER_DRIVEN: { - continue; - } - default: - sif::debug << "PlocSupvHelper::performOperation: Invalid state" << std::endl; - break; + } + if (putTaskToSleep) { + break; } } } } +bool PlocSupvHelper::handleUartReception() { + ReturnValue_t result = OK; + ssize_t bytesRead = read(serialPort, reinterpret_cast(recBuf.data()), + static_cast(recBuf.size())); + if (bytesRead == 0) { + { + MutexGuard mg(lock); + if (state == InternalState::FINISH) { + // Flush received and unread data + tcflush(serialPort, TCIOFLUSH); + state = InternalState::IDLE; + return true; + } + } + while (result != NO_PACKET_FOUND) { + result = tryHdlcParsing(); + } + } else if (bytesRead < 0) { + sif::warning << "PlocSupvHelper::performOperation: read call failed with error [" << errno + << ", " << strerror(errno) << "]" << std::endl; + return true; + } else if (bytesRead >= static_cast(recBuf.size())) { + sif::error << "PlocSupvHelper::performOperation: Receive buffer too small for " << bytesRead + << " bytes" << std::endl; + } else if (bytesRead > 0) { + if (debugMode) { + sif::info << "Received " << bytesRead << " bytes from the PLOC Supervisor:" << std::endl; + } + recRingBuf.writeData(recBuf.data(), bytesRead); + tryHdlcParsing(); + } + return false; +} + ReturnValue_t PlocSupvHelper::setComIF(UartComIF* uartComIF_) { if (uartComIF_ == nullptr) { sif::warning << "PlocSupvHelper::initialize: Provided invalid uart com if" << std::endl; @@ -253,7 +222,7 @@ ReturnValue_t PlocSupvHelper::performUpdate(const supv::UpdateParams& params) { update.packetNum = 1; update.deleteMemory = params.deleteMemory; update.sequenceCount = params.seqCount; - state = InternalState::UPDATE; + request = Request::UPDATE; uartComIF->flushUartTxAndRxBuf(comCookie); semaphore->release(); return result; @@ -272,14 +241,14 @@ ReturnValue_t PlocSupvHelper::performMemCheck(uint8_t memoryId, uint32_t startAd update.startAddress = startAddress; update.length = sizeToCheck; update.crcShouldBeChecked = checkCrc; - state = InternalState::CHECK_MEMORY; + request = Request::CHECK_MEMORY; uartComIF->flushUartTxAndRxBuf(comCookie); semaphore->release(); return returnvalue::OK; } void PlocSupvHelper::initiateUpdateContinuation() { - state = InternalState::CONTINUE_UPDATE; + request = Request::CONTINUE_UPDATE; semaphore->release(); } @@ -294,7 +263,7 @@ ReturnValue_t PlocSupvHelper::startEventBufferRequest(std::string path) { return PATH_NOT_EXISTS; } eventBufferReq.path = path; - state = InternalState::REQUEST_EVENT_BUFFER; + request = Request::REQUEST_EVENT_BUFFER; uartComIF->flushUartTxAndRxBuf(comCookie); semaphore->release(); return returnvalue::OK; @@ -917,7 +886,7 @@ ReturnValue_t PlocSupvHelper::sendMessage(CookieIF* cookie, const uint8_t* sendD if (result != OK) { std::cout << "PlocSupvHelper::sendMessage: Releasing semaphore failed" << std::endl; } - return returnvalue::OK; + return encodeAndSendPacket(sendData, sendLen); } ReturnValue_t PlocSupvHelper::getSendSuccess(CookieIF* cookie) { return returnvalue::OK; } @@ -926,6 +895,74 @@ ReturnValue_t PlocSupvHelper::requestReceiveMessage(CookieIF* cookie, size_t req return returnvalue::OK; } +bool PlocSupvHelper::handleRunningRequest() { + ReturnValue_t result = OK; + switch (request) { + case Request::UPDATE: { + result = executeUpdate(); + if (result == returnvalue::OK) { + triggerEvent(SUPV_UPDATE_SUCCESSFUL, result); + } else if (result == PROCESS_TERMINATED) { + // Event already triggered + } else { + triggerEvent(SUPV_UPDATE_FAILED, result); + } + MutexGuard mg(lock); + state = InternalState::IDLE; + return true; + } + case Request::CHECK_MEMORY: { + executeFullCheckMemoryCommand(); + MutexGuard mg(lock); + state = InternalState::IDLE; + return true; + } + case Request::CONTINUE_UPDATE: { + result = continueUpdate(); + if (result == returnvalue::OK) { + triggerEvent(SUPV_CONTINUE_UPDATE_SUCCESSFUL, result); + } else if (result == PROCESS_TERMINATED) { + // Event already triggered + } else { + triggerEvent(SUPV_CONTINUE_UPDATE_FAILED, result); + } + MutexGuard mg(lock); + state = InternalState::IDLE; + return true; + } + case Request::REQUEST_EVENT_BUFFER: { + result = performEventBufferRequest(); + if (result == returnvalue::OK) { + triggerEvent(SUPV_EVENT_BUFFER_REQUEST_SUCCESSFUL, result); + } else if (result == PROCESS_TERMINATED) { + // Event already triggered + break; + } else { + triggerEvent(SUPV_EVENT_BUFFER_REQUEST_FAILED, result); + } + MutexGuard mg(lock); + state = InternalState::IDLE; + return true; + } + case Request::HANDLER_DRIVEN: { + break; + } + } + return false; +} + +ReturnValue_t PlocSupvHelper::encodeAndSendPacket(const uint8_t* sendData, size_t sendLen) { + size_t encodedLen = 0; + hdlc_add_framing(sendData, sendLen, sendBuf.data(), &encodedLen); + size_t bytesWritten = write(serialPort, sendBuf.data(), encodedLen); + if (bytesWritten != encodedLen) { + sif::warning << "ScexUartReader::sendMessage: Sending ping command to solar experiment failed" + << std::endl; + return FAILED; + } + return returnvalue::OK; +} + ReturnValue_t PlocSupvHelper::readReceivedMessage(CookieIF* cookie, uint8_t** buffer, size_t* size) { MutexGuard mg(lock); @@ -937,11 +974,28 @@ ReturnValue_t PlocSupvHelper::readReceivedMessage(CookieIF* cookie, uint8_t** bu *buffer = ipcBuffer.data(); ReturnValue_t result = ipcRingBuf.readData(ipcBuffer.data(), *size, true); if (result != OK) { - sif::warning << "ScexUartReader::readReceivedMessage: Reading RingBuffer failed" << std::endl; + sif::warning << "PlocSupvHelper::readReceivedMessage: Reading RingBuffer failed" << std::endl; } return OK; } +ReturnValue_t PlocSupvHelper::tryHdlcParsing() { + size_t bytesRead = 0; + ReturnValue_t result = parseRecRingBufForHdlc(bytesRead); + if (result == returnvalue::OK) { + // Packet found, advance read pointer. + ipcRingBuf.writeData(decodedBuf.data(), bytesRead); + recRingBuf.deleteData(bytesRead); + } else if (result != NO_PACKET_FOUND) { + sif::warning << "ScexUartReader::performOperation: Possible packet loss" << std::endl; + // Markers found at wrong place + // which might be a hint for a possibly lost packet. + // Maybe trigger event? + recRingBuf.deleteData(bytesRead); + } + return result; +} + ReturnValue_t PlocSupvHelper::parseRecRingBufForHdlc(size_t& readSize) { size_t availableData = recRingBuf.getAvailableReadData(); if (availableData == 0) { diff --git a/linux/devices/ploc/PlocSupvHelper.h b/linux/devices/ploc/PlocSupvHelper.h index 2e6db05b..d2a3a3ec 100644 --- a/linux/devices/ploc/PlocSupvHelper.h +++ b/linux/devices/ploc/PlocSupvHelper.h @@ -227,6 +227,7 @@ class PlocSupvHelper : public DeviceCommunicationIF, SdCardManager* sdcMan = nullptr; #endif SimpleRingBuffer recRingBuf; + std::array sendBuf = {}; std::array recBuf = {}; std::array encodedBuf = {}; std::array decodedBuf = {}; @@ -254,8 +255,13 @@ class PlocSupvHelper : public DeviceCommunicationIF, // Remembers APID to know at which command a procedure failed uint16_t rememberApid = 0; + bool handleRunningRequest(); + bool handleUartReception(); + + ReturnValue_t encodeAndSendPacket(const uint8_t* sendData, size_t sendLen); void executeFullCheckMemoryCommand(); + ReturnValue_t tryHdlcParsing(); ReturnValue_t parseRecRingBufForHdlc(size_t& readSize); ReturnValue_t executeUpdate(); ReturnValue_t continueUpdate();