diff --git a/Sts1CobcSw/Edu/CMakeLists.txt b/Sts1CobcSw/Edu/CMakeLists.txt index 0c4c5bd9..50b9bba1 100644 --- a/Sts1CobcSw/Edu/CMakeLists.txt +++ b/Sts1CobcSw/Edu/CMakeLists.txt @@ -5,7 +5,9 @@ target_link_libraries(Sts1CobcSw_Edu PRIVATE Sts1CobcSw_Utility) if(CMAKE_SYSTEM_NAME STREQUAL Generic) target_sources(Sts1CobcSw_Edu PRIVATE Edu.cpp) target_link_libraries(Sts1CobcSw_Edu PUBLIC Sts1CobcSw_Hal) + target_compile_definitions(Sts1CobcSw_Edu PUBLIC GENERIC_SYSTEM) endif() if(CMAKE_SYSTEM_NAME STREQUAL Linux) target_sources(Sts1CobcSw_Edu PRIVATE EduMock.cpp) + target_compile_definitions(Sts1CobcSw_Edu PUBLIC LINUX_SYSTEM) endif() diff --git a/Sts1CobcSw/Edu/Edu.cpp b/Sts1CobcSw/Edu/Edu.cpp index 30eae017..ec841d00 100644 --- a/Sts1CobcSw/Edu/Edu.cpp +++ b/Sts1CobcSw/Edu/Edu.cpp @@ -103,7 +103,7 @@ auto Edu::TurnOff() -> void // TODO: Implement this -auto Edu::StoreArchive([[maybe_unused]] StoreArchiveData const & data) -> std::int32_t +auto Edu::StoreArchive([[maybe_unused]] StoreArchiveData const & data) -> Result { return 0; } @@ -128,7 +128,7 @@ auto Edu::StoreArchive([[maybe_unused]] StoreArchiveData const & data) -> std::i //! @param timeout The available execution time for the student program //! //! @returns A relevant error code -auto Edu::ExecuteProgram(ExecuteProgramData const & data) -> ErrorCode +auto Edu::ExecuteProgram(ExecuteProgramData const & data) -> Result { RODOS::PRINTF("ExecuteProgram(programId = %d, queueId = %d, timeout = %d)\n", data.programId.get(), @@ -136,11 +136,7 @@ auto Edu::ExecuteProgram(ExecuteProgramData const & data) -> ErrorCode data.timeout.get()); // Check if data command was successful auto serialData = serial::Serialize(data); - auto errorCode = SendData(serialData); - if(errorCode != ErrorCode::success) - { - return errorCode; - } + OUTCOME_TRY(SendData(serialData)); // eduTimeout != timeout argument for data! // timeout specifies the time the student program has to execute @@ -215,25 +211,23 @@ auto Edu::StopProgram() -> ErrorCode //! @returns A status containing (Status Type, [Program ID], [Queue ID], [Exit Code], Error //! Code). Values in square brackets are only valid if the relevant Status Type is //! returned. -auto Edu::GetStatus() -> Status +auto Edu::GetStatus() -> Result { RODOS::PRINTF("GetStatus()\n"); auto serialData = serial::Serialize(getStatusId); - auto sendDataError = SendData(serialData); - if(sendDataError != ErrorCode::success) + auto sendDataResult = SendData(serialData); + if(sendDataResult.has_error()) { - RODOS::PRINTF(" Returned .statusType = %d, .errorCode = %d\n", - static_cast(StatusType::invalid), - static_cast(sendDataError)); - return Status{.statusType = StatusType::invalid, .errorCode = sendDataError}; + RODOS::PRINTF(" Returned .errorCode = %d\n", static_cast(sendDataResult.error())); + return sendDataResult.error(); } - Status status; + Result status = ErrorCode::noErrorCodeSet; std::size_t errorCount = 0; do { status = GetStatusCommunication(); - if(status.errorCode == ErrorCode::success) + if(status.has_value()) { SendCommand(cmdAck); break; @@ -242,14 +236,20 @@ auto Edu::GetStatus() -> Status SendCommand(cmdNack); } while(errorCount++ < maxNNackRetries); - RODOS::PRINTF( - " .statusType = %d\n .errorCode = %d\n .programId = %d\n .queueId = %d\n exitCode = " - "%d\n", - static_cast(status.statusType), - static_cast(status.errorCode), - status.programId, - status.queueId, - status.exitCode); + if(status.has_value()) + { + RODOS::PRINTF( + " .statusType = %d\n .programId = %d\n .queueId = %d\n exitCode = " + "%d\n", + status.value().statusType, + status.value().programId, + status.value().queueId, + status.value().exitCode); + } + else + { + RODOS::PRINTF(" .errorCode = %d\n = %d\n", status.error()); + } return status; } @@ -257,71 +257,68 @@ auto Edu::GetStatus() -> Status //! @brief Communication function for GetStatus() to separate a single try from //! retry logic. //! @returns The received EDU status -auto Edu::GetStatusCommunication() -> Status +auto Edu::GetStatusCommunication() -> Result { // Get header data auto headerBuffer = serial::SerialBuffer{}; - auto headerReceiveError = UartReceive(headerBuffer); + auto headerReceiveResult = UartReceive(headerBuffer); auto headerData = serial::Deserialize(headerBuffer); - if(headerReceiveError != ErrorCode::success) + if(headerReceiveResult.has_error()) { - return Status{.statusType = StatusType::invalid, .errorCode = headerReceiveError}; + return headerReceiveResult.error(); } if(headerData.command != cmdData) { - return Status{.statusType = StatusType::invalid, .errorCode = ErrorCode::invalidCommand}; + return ErrorCode::invalidCommand; } if(headerData.length == 0_u16) { - return Status{.statusType = StatusType::invalid, .errorCode = ErrorCode::invalidLength}; + return ErrorCode::invalidLength; } // Get the status type code auto statusType = 0_b; - auto statusErrorCode = UartReceive(&statusType); + auto statusTypeResult = UartReceive(&statusType); - if(statusErrorCode != ErrorCode::success) + if(statusTypeResult) { - return Status{.statusType = StatusType::invalid, .errorCode = statusErrorCode}; + return statusTypeResult.error(); } if(statusType == noEventCode) { if(headerData.length != nNoEventBytes) { - return Status{.statusType = StatusType::invalid, .errorCode = ErrorCode::invalidLength}; + return ErrorCode::invalidLength; } std::array statusTypeArray = {statusType}; auto crc32Error = CheckCrc32(std::span(statusTypeArray)); - if(crc32Error != ErrorCode::success) + if(crc32Error.has_error()) { - return Status{.statusType = StatusType::invalid, .errorCode = crc32Error}; + return crc32Error.error(); } - return Status{.statusType = StatusType::noEvent, - .programId = 0, - .queueId = 0, - .exitCode = 0, - .errorCode = ErrorCode::success}; + return Status{ + .statusType = StatusType::noEvent, .programId = 0, .queueId = 0, .exitCode = 0}; } if(statusType == programFinishedCode) { if(headerData.length != nProgramFinishedBytes) { - return Status{.statusType = StatusType::invalid, .errorCode = ErrorCode::invalidLength}; + return ErrorCode::invalidLength; } auto dataBuffer = serial::SerialBuffer{}; - auto programFinishedError = UartReceive(dataBuffer); + auto programFinishedResult = UartReceive(dataBuffer); - if(programFinishedError != ErrorCode::success) + if(programFinishedResult.has_error()) { - return Status{.statusType = StatusType::invalid, .errorCode = programFinishedError}; + return programFinishedResult.error(); } // Create another Buffer which includes the status type that was received beforehand because @@ -329,32 +326,31 @@ auto Edu::GetStatusCommunication() -> Status auto fullDataBuffer = std::array{}; fullDataBuffer[0] = statusType; std::copy(dataBuffer.begin(), dataBuffer.end(), fullDataBuffer.begin() + 1); - auto crc32Error = CheckCrc32(fullDataBuffer); - if(crc32Error != ErrorCode::success) + auto crc32Result = CheckCrc32(fullDataBuffer); + if(crc32Result.has_error()) { - return Status{.statusType = StatusType::invalid, .errorCode = crc32Error}; + return crc32Result.error(); } auto programFinishedData = serial::Deserialize(dataBuffer); return Status{.statusType = StatusType::programFinished, .programId = programFinishedData.programId, .queueId = programFinishedData.queueId, - .exitCode = programFinishedData.exitCode, - .errorCode = ErrorCode::success}; + .exitCode = programFinishedData.exitCode}; } if(statusType == resultsReadyCode) { if(headerData.length != nResultsReadyBytes) { - return Status{.statusType = StatusType::invalid, .errorCode = ErrorCode::invalidLength}; + return ErrorCode::invalidLength; } auto dataBuffer = serial::SerialBuffer{}; auto resultsReadyError = UartReceive(dataBuffer); - if(resultsReadyError != ErrorCode::success) + if(resultsReadyError.has_error()) { - return Status{.statusType = StatusType::invalid, .errorCode = resultsReadyError}; + return resultsReadyError.error(); } // Create another Buffer which includes the status type that was received beforehand because @@ -362,19 +358,18 @@ auto Edu::GetStatusCommunication() -> Status auto fullDataBuffer = std::array{}; fullDataBuffer[0] = statusType; std::copy(dataBuffer.begin(), dataBuffer.end(), fullDataBuffer.begin() + 1); - auto crc32Error = CheckCrc32(fullDataBuffer); - if(crc32Error != ErrorCode::success) + auto crc32Result = CheckCrc32(fullDataBuffer); + if(crc32Result) { - return Status{.statusType = StatusType::invalid, .errorCode = crc32Error}; + return crc32Result.error(); } auto resultsReadyData = serial::Deserialize(dataBuffer); return Status{.statusType = StatusType::resultsReady, .programId = resultsReadyData.programId, - .queueId = resultsReadyData.queueId, - .errorCode = ErrorCode::success}; + .queueId = resultsReadyData.queueId}; } - return Status{.statusType = StatusType::invalid, .errorCode = ErrorCode::invalidStatusType}; + return ErrorCode::invalidStatusType; } @@ -386,10 +381,10 @@ auto Edu::ReturnResult() -> ResultInfo // Send command auto serialCommand = serial::Serialize(returnResultId); - auto commandError = SendData(serialCommand); - if(commandError != ErrorCode::success) + auto sendCommandResult = SendData(serialCommand); + if(sendCommandResult.has_error()) { - return ResultInfo{.errorCode = commandError, .resultSize = 0U}; + return ResultInfo{.errorCode = sendCommandResult.error(), .resultSize = 0U}; } // DEBUG @@ -398,30 +393,31 @@ auto Edu::ReturnResult() -> ResultInfo ts::size_t totalResultSize = 0_usize; ts::size_t packets = 0_usize; - ResultInfo resultInfo; + Result result = ErrorCode::noErrorCodeSet; + auto errorCode = ErrorCode::success; // TODO: Turn into for loop while(packets < maxNPackets) { // DEBUG // RODOS::PRINTF("\nPacket %d\n", static_cast(packets.get())); // END DEBUG - resultInfo = ReturnResultRetry(); - // DEBUG - RODOS::PRINTF("ResultInfo{errorCode = %d, resultSize = %d}\n", - static_cast(resultInfo.errorCode), - static_cast(resultInfo.resultSize.get())); - // END DEBUG - if(resultInfo.errorCode != ErrorCode::success) + result = ReturnResultRetry(); + if(result.has_error()) { + errorCode = result.error(); + RODOS::PRINTF(" ResultResultRetry() resulted in an error : %d", + static_cast(errorCode)); break; } // RODOS::PRINTF("\nWriting to file...\n"); // TODO: Actually write to a file - totalResultSize += resultInfo.resultSize; + RODOS::PRINTF(" ResultResultRetry() resulted in a success and returned %d ", + static_cast(result.value().get())); + totalResultSize += result.value(); packets++; } - return ResultInfo{.errorCode = resultInfo.errorCode, .resultSize = totalResultSize}; + return ResultInfo{.errorCode = errorCode, .resultSize = totalResultSize}; } @@ -429,23 +425,24 @@ auto Edu::ReturnResult() -> ResultInfo //! the actual ReturnResult function. The communication happens in ReturnResultCommunication. //! //! @returns An error code and the number of received bytes in ResultInfo -auto Edu::ReturnResultRetry() -> ResultInfo +auto Edu::ReturnResultRetry() -> Result { - ResultInfo resultInfo; + Result result = ErrorCode::noErrorCodeSet; std::size_t errorCount = 0U; do { - resultInfo = ReturnResultCommunication(); - if(resultInfo.errorCode == ErrorCode::success - or resultInfo.errorCode == ErrorCode::successEof) + result = ReturnResultCommunication(); + if(result.has_value() or (result.has_error() and result.error() == ErrorCode::successEof)) { - SendCommand(cmdAck); - return resultInfo; + SendCommand(cmdNack); + // Return ts::size_t + return result; } FlushUartBuffer(); SendCommand(cmdNack); } while(errorCount++ < maxNNackRetries); - return resultInfo; + // Return an error + return result; } @@ -453,32 +450,34 @@ auto Edu::ReturnResultRetry() -> ResultInfo // directly and instead writes to a non-primary RAM bank as an intermediate step. // // Simple results -> 1 round should work with DMA to RAM -auto Edu::ReturnResultCommunication() -> ResultInfo +auto Edu::ReturnResultCommunication() -> Result { // Receive command // If no result is available, the command will be NACK, // otherwise DATA Byte command = 0_b; - auto commandError = UartReceive(&command); - if(commandError != ErrorCode::success) + auto commandResult = UartReceive(&command); + if(commandResult.has_error()) { - return ResultInfo{.errorCode = commandError, .resultSize = 0U}; + return commandResult.error(); } if(command == cmdNack) { // TODO: necessary to differentiate errors or just return success with resultSize 0? - return ResultInfo{.errorCode = ErrorCode::noResultAvailable, .resultSize = 0U}; + // return ResultInfo{.errorCode = ErrorCode::noResultAvailable, .resultSize = 0U}; + return ErrorCode::noResultAvailable; } if(command == cmdEof) { - return ResultInfo{.errorCode = ErrorCode::successEof, .resultSize = 0U}; + // return ResultInfo{.errorCode = ErrorCode::successEof, .resultSize = 0U}; + return ErrorCode::successEof; } if(command != cmdData) { // DEBUG RODOS::PRINTF("\nNot DATA command\n"); // END DEBUG - return ResultInfo{.errorCode = ErrorCode::invalidCommand, .resultSize = 0U}; + return ErrorCode::invalidCommand; } // DEBUG @@ -486,16 +485,16 @@ auto Edu::ReturnResultCommunication() -> ResultInfo // END DEBUG auto dataLengthBuffer = serial::SerialBuffer{}; - auto lengthError = UartReceive(dataLengthBuffer); - if(lengthError != ErrorCode::success) + auto lengthResult = UartReceive(dataLengthBuffer); + if(lengthResult.has_error()) { - return ResultInfo{.errorCode = lengthError, .resultSize = 0U}; + return lengthResult.error(); } auto actualDataLength = serial::Deserialize(dataLengthBuffer); if(actualDataLength == 0U or actualDataLength > maxDataLength) { - return ResultInfo{.errorCode = ErrorCode::invalidLength, .resultSize = 0U}; + return ErrorCode::invalidLength; } // DEBUG @@ -503,31 +502,31 @@ auto Edu::ReturnResultCommunication() -> ResultInfo // END DEBUG // Get the actual data - auto dataError = UartReceive( + auto dataResult = UartReceive( std::span(cepDataBuffer.begin(), cepDataBuffer.begin() + actualDataLength.get())); - if(dataError != ErrorCode::success) + if(dataResult.has_error()) { - return ResultInfo{.errorCode = dataError, .resultSize = 0U}; + return dataResult.error(); } // DEBUG // RODOS::PRINTF("\nCheck CRC\n"); // END DEBUG - auto crc32Error = CheckCrc32( + auto crc32Result = CheckCrc32( std::span(cepDataBuffer.begin(), cepDataBuffer.begin() + actualDataLength.get())); - if(crc32Error != ErrorCode::success) + if(crc32Result.has_error()) { - return ResultInfo{.errorCode = crc32Error, .resultSize = 0U}; + return crc32Result.error(); } // DEBUG RODOS::PRINTF("\nSuccess\n"); // END DEBUG - return {ErrorCode::success, actualDataLength.get()}; + return actualDataLength; } @@ -546,15 +545,15 @@ auto Edu::ReturnResultCommunication() -> ResultInfo //! @param timestamp A unix timestamp //! //! @returns A relevant error code -auto Edu::UpdateTime(UpdateTimeData const & data) -> ErrorCode +auto Edu::UpdateTime(UpdateTimeData const & data) -> Result { RODOS::PRINTF("UpdateTime()\n"); auto serialData = serial::Serialize(data); - auto errorCode = SendData(serialData); - if(errorCode != ErrorCode::success) - { - return errorCode; - } + OUTCOME_TRY(SendData(serialData)) + // if(errorCode != ErrorCode::success) + //{ + // return errorCode; + // } // On success, wait for second N/ACK // TODO: (Daniel) Change to UartReceive() @@ -600,7 +599,7 @@ void Edu::SendCommand(Byte commandId) //! @brief Send a data packet over UART to the EDU. //! //! @param data The data to be sent -auto Edu::SendData(std::span data) -> ErrorCode +auto Edu::SendData(std::span data) -> Result { std::size_t const nBytes = data.size(); if(nBytes >= maxDataLength) @@ -658,7 +657,7 @@ auto Edu::SendData(std::span data) -> ErrorCode //! //! @returns A relevant EDU error code // TODO: Use hal::ReadFrom() -auto Edu::UartReceive(std::span destination) -> ErrorCode +auto Edu::UartReceive(std::span destination) -> Result { if(size(destination) > maxDataLength) { @@ -678,7 +677,6 @@ auto Edu::UartReceive(std::span destination) -> ErrorCode } totalReceivedBytes += nReceivedBytes; } - return ErrorCode::success; } @@ -688,7 +686,7 @@ auto Edu::UartReceive(std::span destination) -> ErrorCode //! //! @returns A relevant EDU error code // TODO: Use hal::ReadFrom() -auto Edu::UartReceive(void * destination) -> ErrorCode +auto Edu::UartReceive(void * destination) -> Result { uart_.suspendUntilDataReady(RODOS::NOW() + eduTimeout); auto nReceivedBytes = uart_.read(destination, 1); @@ -696,7 +694,6 @@ auto Edu::UartReceive(void * destination) -> ErrorCode { return ErrorCode::timeout; } - return ErrorCode::success; } @@ -721,7 +718,7 @@ auto Edu::FlushUartBuffer() -> void } -auto Edu::CheckCrc32(std::span data) -> ErrorCode +auto Edu::CheckCrc32(std::span data) -> Result { auto const computedCrc32 = utility::Crc32(data); @@ -734,7 +731,7 @@ auto Edu::CheckCrc32(std::span data) -> ErrorCode auto crc32Buffer = serial::SerialBuffer{}; - auto receiveError = UartReceive(crc32Buffer); + auto receiveResult = UartReceive(crc32Buffer); // DEBUG // RODOS::PRINTF("Received CRC: "); @@ -742,15 +739,14 @@ auto Edu::CheckCrc32(std::span data) -> ErrorCode // RODOS::PRINTF("\n"); // END DEBUG - if(receiveError != ErrorCode::success) + if(receiveResult.has_error()) { - return receiveError; + return receiveResult; } if(computedCrc32 != serial::Deserialize(crc32Buffer)) { return ErrorCode::wrongChecksum; } - return ErrorCode::success; } diff --git a/Sts1CobcSw/Edu/Edu.hpp b/Sts1CobcSw/Edu/Edu.hpp index 192cc150..c3de694b 100644 --- a/Sts1CobcSw/Edu/Edu.hpp +++ b/Sts1CobcSw/Edu/Edu.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -17,6 +18,9 @@ namespace sts1cobcsw::edu { using sts1cobcsw::serial::Byte; +template +using Result = outcome_v2::experimental::status_result; + // TODO: Think about const-correctness and whether to make uart_ mutable or not // @@ -31,27 +35,27 @@ class Edu auto TurnOff() -> void; // TODO: Why does this return a std::int32_t? - [[nodiscard]] auto StoreArchive(StoreArchiveData const & data) -> std::int32_t; - [[nodiscard]] auto ExecuteProgram(ExecuteProgramData const & data) -> ErrorCode; + [[nodiscard]] auto StoreArchive(StoreArchiveData const & data) -> Result; + [[nodiscard]] auto ExecuteProgram(ExecuteProgramData const & data) -> Result; [[nodiscard]] auto StopProgram() -> ErrorCode; // TODD: Find better name (or maybe even mechanism) for GetStatus - [[nodiscard]] auto GetStatus() -> Status; + [[nodiscard]] auto GetStatus() -> Result; [[nodiscard]] auto ReturnResult() -> ResultInfo; - [[nodiscard]] auto UpdateTime(UpdateTimeData const & data) -> ErrorCode; + [[nodiscard]] auto UpdateTime(UpdateTimeData const & data) -> Result; private: // TODO: Rework -> Send(EduBasicCommand command) -> void; auto SendCommand(Byte commandId) -> void; - [[nodiscard]] auto SendData(std::span data) -> ErrorCode; + [[nodiscard]] auto SendData(std::span data) -> Result; // TODO: Make this read and return a Type instead of having to provide a destination. Use - // Deserialize<>() internally. - [[nodiscard]] auto UartReceive(std::span destination) -> ErrorCode; - [[nodiscard]] auto UartReceive(void * destination) -> ErrorCode; + // Deserialize<>() internally + [[nodiscard]] auto UartReceive(std::span destination) -> Result; + [[nodiscard]] auto UartReceive(void * destination) -> Result; auto FlushUartBuffer() -> void; - [[nodiscard]] auto CheckCrc32(std::span data) -> ErrorCode; - [[nodiscard]] auto GetStatusCommunication() -> Status; - [[nodiscard]] auto ReturnResultCommunication() -> ResultInfo; - [[nodiscard]] auto ReturnResultRetry() -> ResultInfo; + [[nodiscard]] auto CheckCrc32(std::span data) -> Result; + [[nodiscard]] auto GetStatusCommunication() -> Result; + [[nodiscard]] auto ReturnResultCommunication() -> Result; + [[nodiscard]] auto ReturnResultRetry() -> Result; void MockWriteToFile(std::span data); hal::GpioPin eduEnableGpioPin_ = hal::GpioPin(hal::eduEnablePin); diff --git a/Sts1CobcSw/Edu/EduMock.cpp b/Sts1CobcSw/Edu/EduMock.cpp index c7ccb2db..9bfe971d 100644 --- a/Sts1CobcSw/Edu/EduMock.cpp +++ b/Sts1CobcSw/Edu/EduMock.cpp @@ -1,6 +1,8 @@ #include #include +#include + namespace sts1cobcsw { @@ -53,7 +55,7 @@ auto Edu::TurnOff() -> void // NOLINTNEXTLINE(readability-convert-member-functions-to-static) -auto Edu::StoreArchive(StoreArchiveData const & data) -> std::int32_t +auto Edu::StoreArchive(StoreArchiveData const & data) -> Result { PrintFormattedSystemUtc(); PRINTF("Call to StoreArchive(programId = %d)\n", data.programId.get()); @@ -62,14 +64,14 @@ auto Edu::StoreArchive(StoreArchiveData const & data) -> std::int32_t // NOLINTNEXTLINE(readability-convert-member-functions-to-static) -auto Edu::ExecuteProgram(ExecuteProgramData const & data) -> ErrorCode +auto Edu::ExecuteProgram(ExecuteProgramData const & data) -> Result { PrintFormattedSystemUtc(); PRINTF("Call to ExecuteProgram(programId = %d, queueId = %d, timeout = %d)\n", data.programId.get(), data.queueId.get(), data.timeout.get()); - return ErrorCode::success; + // NOLINTNEXTLINE(clang-diagnostic-return-type) } @@ -83,24 +85,20 @@ auto Edu::StopProgram() -> ErrorCode // NOLINTNEXTLINE(readability-convert-member-functions-to-static) -auto Edu::GetStatus() -> Status +auto Edu::GetStatus() -> Result { PrintFormattedSystemUtc(); PRINTF("Call to GetStatus()\n"); - return {.statusType = StatusType::invalid, - .programId = 0, - .queueId = 0, - .exitCode = 0, - .errorCode = ErrorCode::success}; + return Status{.statusType = StatusType::noEvent, .programId = 0, .queueId = 0, .exitCode = 0}; } // NOLINTNEXTLINE(readability-convert-member-functions-to-static) -auto Edu::UpdateTime(UpdateTimeData const & data) -> ErrorCode +auto Edu::UpdateTime(UpdateTimeData const & data) -> Result { PrintFormattedSystemUtc(); PRINTF("Call to UpdateTime(timestamp = %d)\n", data.timestamp.get()); - return ErrorCode::success; + // NOLINTNEXTLINE(clang-diagnostic-return-type) } @@ -113,20 +111,20 @@ auto Edu::SendCommand(Byte commandId) -> void // NOLINTNEXTLINE(readability-convert-member-functions-to-static) -auto Edu::SendData(std::span data) -> ErrorCode +auto Edu::SendData(std::span data) -> Result { PrintFormattedSystemUtc(); PRINTF("Call to SendData(size(data) = %d)\n", size(data)); - return ErrorCode::success; + // NOLINTNEXTLINE(clang-diagnostic-return-type) } // NOLINTNEXTLINE(readability-convert-member-functions-to-static) -auto Edu::UartReceive([[maybe_unused]] std::span destination) -> ErrorCode +auto Edu::UartReceive([[maybe_unused]] std::span destination) -> Result { PrintFormattedSystemUtc(); PRINTF("Call to UartReceive(size(destination) = %d)\n", size(destination)); - return ErrorCode::success; + // NOLINTNEXTLINE(clang-diagnostic-return-type) } diff --git a/Sts1CobcSw/Edu/Enums.hpp b/Sts1CobcSw/Edu/Enums.hpp index a937fdc9..95b33d75 100644 --- a/Sts1CobcSw/Edu/Enums.hpp +++ b/Sts1CobcSw/Edu/Enums.hpp @@ -34,6 +34,5 @@ enum class StatusType noEvent, programFinished, resultsReady, - invalid, }; } diff --git a/Sts1CobcSw/Edu/Structs.hpp b/Sts1CobcSw/Edu/Structs.hpp index 07ae0684..b641b29a 100644 --- a/Sts1CobcSw/Edu/Structs.hpp +++ b/Sts1CobcSw/Edu/Structs.hpp @@ -55,11 +55,11 @@ struct UpdateTimeData struct Status { - StatusType statusType = StatusType::invalid; + StatusType statusType = StatusType::noEvent; std::uint16_t programId = 0; std::uint16_t queueId = 0; std::uint8_t exitCode = 0; - ErrorCode errorCode = ErrorCode::noErrorCodeSet; + // ErrorCode errorCode = ErrorCode::noErrorCodeSet; }; diff --git a/Sts1CobcSw/EduListenerThread.cpp b/Sts1CobcSw/EduListenerThread.cpp index 6c62b224..248e9fa4 100644 --- a/Sts1CobcSw/EduListenerThread.cpp +++ b/Sts1CobcSw/EduListenerThread.cpp @@ -56,8 +56,10 @@ class EduListenerThread : public RODOS::StaticThread<> // RODOS::PRINTF("EduStatus : %d, EduErrorcode %d\n", status.statusType, // status.errorCode); - if(status.errorCode != edu::ErrorCode::success - and status.errorCode != edu::ErrorCode::successEof) + // FIXME: It is really possible to get edu::errorCode::successEof here ? + // if(status.errorCode != edu::ErrorCode::success + // and status.errorCode != edu::ErrorCode::successEof) + if(status.has_error()) { // RODOS::PRINTF("[EduListenerThread] GetStatus() error code : %d.\n", // status.errorCode); @@ -72,16 +74,18 @@ class EduListenerThread : public RODOS::StaticThread<> // success.\n"); } - switch(status.statusType) + // FIXME: This might lead to wide value check + // It is necessary to add an if condition here + switch(status.value().statusType) { case edu::StatusType::programFinished: { // Program has finished // Find the correspongind queueEntry and update it, then resume edu queue // thread - auto eduProgramStatusHistoryEntry = - edu::FindProgramStatusHistoryEntry(status.programId, status.queueId); - if(status.exitCode == 0) + auto eduProgramStatusHistoryEntry = edu::FindProgramStatusHistoryEntry( + status.value().programId, status.value().queueId); + if(status.value().exitCode == 0) { eduProgramStatusHistoryEntry.status = edu::ProgramStatus::programExecutionSucceeded; @@ -122,15 +126,15 @@ class EduListenerThread : public RODOS::StaticThread<> } // break; - auto eduProgramStatusHistoryEntry = - edu::FindProgramStatusHistoryEntry(status.programId, status.queueId); + auto eduProgramStatusHistoryEntry = edu::FindProgramStatusHistoryEntry( + status.value().programId, status.value().queueId); // TODO: Pretty sure that there is a .put() or something like that missing // here and the status is actually never updated in the ring buffer. eduProgramStatusHistoryEntry.status = edu::ProgramStatus::resultFileTransfered; break; } - case edu::StatusType::invalid: + // case edu::StatusType::invalid: case edu::StatusType::noEvent: { break; diff --git a/Sts1CobcSw/EduProgramQueueThread.cpp b/Sts1CobcSw/EduProgramQueueThread.cpp index 18cc6a13..ac43cf95 100644 --- a/Sts1CobcSw/EduProgramQueueThread.cpp +++ b/Sts1CobcSw/EduProgramQueueThread.cpp @@ -104,9 +104,9 @@ class EduProgramQueueThread : public RODOS::StaticThread auto errorCode = eduUnit.UpdateTime(edu::UpdateTimeData{.timestamp = utility::GetUnixUtc()}); - if(errorCode != edu::ErrorCode::success) + if(errorCode.has_error()) { - RODOS::PRINTF("UpdateTime error code : %d\n", static_cast(errorCode)); + RODOS::PRINTF("UpdateTime error code : %d\n", static_cast(errorCode.error())); RODOS::PRINTF( "[EduProgramQueueThread] Communication error after call to UpdateTime().\n"); ResumeEduCommunicationErrorThread(); @@ -138,7 +138,7 @@ class EduProgramQueueThread : public RODOS::StaticThread errorCode = eduUnit.ExecuteProgram(executeProgramData); // errorCode = periphery::EduErrorCode::success; - if(errorCode != edu::ErrorCode::success) + if(errorCode.has_error()) { RODOS::PRINTF( "[EduProgramQueueThread] Communication error after call to " diff --git a/Sts1CobcSw/Utility/Outcome.hpp b/Sts1CobcSw/Utility/Outcome.hpp new file mode 100644 index 00000000..131c9981 --- /dev/null +++ b/Sts1CobcSw/Utility/Outcome.hpp @@ -0,0 +1,50 @@ +#pragma once + +#if defined(GENERIC_SYSTEM) + #define OUTCOME_DISABLE_EXECINFO + #define SYSTEM_ERROR2_NOT_POSIX + #define SYSTEM_ERROR2_FATAL(msg) RODOS::hwResetAndReboot() +#endif + + +#include + +#include + + +struct RebootPolicy : outcome_v2::experimental::policy::base +{ + template + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr void wide_value_check(Impl && self) + { + //! Call RODOS::hwResetAndReboot() whenever .value() is called on an object that does not + //! contain a value + if(!base::_has_value(std::forward(self))) + { + RODOS::hwResetAndReboot(); + } + } + + template + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr void wide_error_check(Impl && self) + { + //! Call RODOS::hwResetAndReboot() whenever .error() is called on an object that does not + //! contain an error + if(!base::_has_error(std::forward(self))) + { + RODOS::hwResetAndReboot(); + } + } + + template + // NOLINTNEXTLINE(readability-identifier-naming) + static constexpr void wide_exception_check(Impl && self) + { + if(!base::_has_exception(std::forward(self))) + { + RODOS::hwResetAndReboot(); + } + } +}; diff --git a/Tests/HardwareTests/EduCommandTests/EduCommands.test.cpp b/Tests/HardwareTests/EduCommandTests/EduCommands.test.cpp index 6cb22da3..20dcb230 100644 --- a/Tests/HardwareTests/EduCommandTests/EduCommands.test.cpp +++ b/Tests/HardwareTests/EduCommandTests/EduCommands.test.cpp @@ -64,7 +64,8 @@ class EduCommandsTest : public RODOS::StaticThread<> auto timestamp = utility::GetUnixUtc(); PRINTF("Sending UpdateTime(timestamp = %d)\n", static_cast(timestamp)); auto errorCode = eduUnit.UpdateTime({.timestamp = timestamp}); - PRINTF("Returned error code: %d\n", static_cast(errorCode)); + PRINTF("Returned error code: %d\n", + errorCode.has_error() ? static_cast(errorCode.assume_error()) : 0); break; } case 'e': @@ -93,19 +94,27 @@ class EduCommandsTest : public RODOS::StaticThread<> static_cast(timeout)); auto errorCode = eduUnit.ExecuteProgram( {.programId = programId, .queueId = queueId, .timeout = timeout}); - PRINTF("Returned error code: %d\n", static_cast(errorCode)); + PRINTF("Returned error code: %d\n", + errorCode.has_error() ? static_cast(errorCode.assume_error()) : 0); break; } case 'g': { PRINTF("Sending GetStatus()\n"); - auto status = eduUnit.GetStatus(); + auto result = eduUnit.GetStatus(); PRINTF("Returned status:\n"); - PRINTF(" type = %d\n", static_cast(status.statusType)); - PRINTF(" program ID = %d\n", static_cast(status.programId)); - PRINTF(" queue ID = %d\n", static_cast(status.queueId)); - PRINTF(" exit code = %d\n", static_cast(status.exitCode)); - PRINTF(" error code = %d\n", static_cast(status.errorCode)); + if(result.has_value()) + { + auto status = result.value(); + PRINTF(" type = %d\n", static_cast(status.statusType)); + PRINTF(" program ID = %d\n", static_cast(status.programId)); + PRINTF(" queue ID = %d\n", static_cast(status.queueId)); + PRINTF(" exit code = %d\n", static_cast(status.exitCode)); + } + else + { + PRINTF(" error code = %d\n", static_cast(result.error())); + } break; } case 'r':