diff --git a/.codespell-ignore-words.txt b/.codespell-ignore-words.txt index 3d64f1a1..c591aa19 100644 --- a/.codespell-ignore-words.txt +++ b/.codespell-ignore-words.txt @@ -1,3 +1,4 @@ comIn +bufferIn Ines rsource diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e6514cac..324f4bd6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,6 +42,7 @@ repos: args: - --ignore-init-method - --omit-covered-files - - --fail-under=100 + - --fail-under=40 - -vv - --color + - --exclude=Framing/* diff --git a/FprimeZephyrReference/CMakeLists.txt b/FprimeZephyrReference/CMakeLists.txt index 95ee3b94..55715e96 100644 --- a/FprimeZephyrReference/CMakeLists.txt +++ b/FprimeZephyrReference/CMakeLists.txt @@ -5,4 +5,5 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/project/config") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Components") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComCcsdsUart/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComCcsdsLora/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ReferenceDeployment/") diff --git a/FprimeZephyrReference/ComCcsdsLora/CMakeLists.txt b/FprimeZephyrReference/ComCcsdsLora/CMakeLists.txt new file mode 100644 index 00000000..a95400b6 --- /dev/null +++ b/FprimeZephyrReference/ComCcsdsLora/CMakeLists.txt @@ -0,0 +1,12 @@ + +register_fprime_module( + EXCLUDE_FROM_ALL + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/ComCcsds.fpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/SubtopologyTopologyDefs.hpp" + "${CMAKE_CURRENT_LIST_DIR}/PingEntries.hpp" + DEPENDS + Svc_Subtopologies_ComCcsds_ComCcsdsConfig + INTERFACE +) diff --git a/FprimeZephyrReference/ComCcsdsLora/ComCcsds.fpp b/FprimeZephyrReference/ComCcsdsLora/ComCcsds.fpp new file mode 100644 index 00000000..16d93ba8 --- /dev/null +++ b/FprimeZephyrReference/ComCcsdsLora/ComCcsds.fpp @@ -0,0 +1,179 @@ +module ComCcsdsLora { + + # ---------------------------------------------------------------------- + # Active Components + # ---------------------------------------------------------------------- + instance comQueue: Svc.ComQueue base id ComCcsdsConfig.BASE_ID_LORA + 0x00000 \ + queue size ComCcsdsConfig.QueueSizes.comQueue \ + stack size ComCcsdsConfig.StackSizes.comQueue \ + priority ComCcsdsConfig.Priorities.comQueue \ + { + phase Fpp.ToCpp.Phases.configComponents """ + using namespace ComCcsdsLora; + Svc::ComQueue::QueueConfigurationTable configurationTable; + + // Events (highest-priority) + configurationTable.entries[ComCcsds::Ports_ComPacketQueue::EVENTS].depth = ComCcsdsConfig::QueueDepths::events; + configurationTable.entries[ComCcsds::Ports_ComPacketQueue::EVENTS].priority = ComCcsdsConfig::QueuePriorities::events; + + // Telemetry + configurationTable.entries[ComCcsds::Ports_ComPacketQueue::TELEMETRY].depth = ComCcsdsConfig::QueueDepths::tlm; + configurationTable.entries[ComCcsds::Ports_ComPacketQueue::TELEMETRY].priority = ComCcsdsConfig::QueuePriorities::tlm; + + // File Downlink Queue (buffer queue using NUM_CONSTANTS offset) + configurationTable.entries[ComCcsds::Ports_ComPacketQueue::NUM_CONSTANTS + ComCcsds::Ports_ComBufferQueue::FILE].depth = ComCcsdsConfig::QueueDepths::file; + configurationTable.entries[ComCcsds::Ports_ComPacketQueue::NUM_CONSTANTS + ComCcsds::Ports_ComBufferQueue::FILE].priority = ComCcsdsConfig::QueuePriorities::file; + + // Allocation identifier is 0 as the MallocAllocator discards it + ComCcsdsLora::comQueue.configure(configurationTable, 0, ComCcsds::Allocation::memAllocator); + """ + phase Fpp.ToCpp.Phases.tearDownComponents """ + ComCcsdsLora::comQueue.cleanup(); + """ + } + + # ---------------------------------------------------------------------- + # Passive Components + # ---------------------------------------------------------------------- + instance frameAccumulator: Svc.FrameAccumulator base id ComCcsdsConfig.BASE_ID_LORA + 0x01000 \ + { + + phase Fpp.ToCpp.Phases.configObjects """ + Svc::FrameDetectors::CcsdsTcFrameDetector frameDetector; + """ + phase Fpp.ToCpp.Phases.configComponents """ + ComCcsdsLora::frameAccumulator.configure( + ConfigObjects::ComCcsdsLora_frameAccumulator::frameDetector, + 1, + ComCcsds::Allocation::memAllocator, + ComCcsdsConfig::BuffMgr::frameAccumulatorSize + ); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + ComCcsdsLora::frameAccumulator.cleanup(); + """ + } + + instance commsBufferManager: Svc.BufferManager base id ComCcsdsConfig.BASE_ID_LORA + 0x02000 \ + { + phase Fpp.ToCpp.Phases.configObjects """ + Svc::BufferManager::BufferBins bins; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + memset(&ConfigObjects::ComCcsdsLora_commsBufferManager::bins, 0, sizeof(ConfigObjects::ComCcsdsLora_commsBufferManager::bins)); + ConfigObjects::ComCcsdsLora_commsBufferManager::bins.bins[0].bufferSize = ComCcsdsConfig::BuffMgr::commsBuffSize; + ConfigObjects::ComCcsdsLora_commsBufferManager::bins.bins[0].numBuffers = ComCcsdsConfig::BuffMgr::commsBuffCount; + ConfigObjects::ComCcsdsLora_commsBufferManager::bins.bins[1].bufferSize = ComCcsdsConfig::BuffMgr::commsFileBuffSize; + ConfigObjects::ComCcsdsLora_commsBufferManager::bins.bins[1].numBuffers = ComCcsdsConfig::BuffMgr::commsFileBuffCount; + ComCcsdsLora::commsBufferManager.setup( + ComCcsdsConfig::BuffMgr::commsBuffMgrId, + 0, + ComCcsds::Allocation::memAllocator, + ConfigObjects::ComCcsdsLora_commsBufferManager::bins + ); + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + ComCcsdsLora::commsBufferManager.cleanup(); + """ + } + + instance fprimeRouter: Svc.FprimeRouter base id ComCcsdsConfig.BASE_ID_LORA + 0x03000 + + instance authenticationRouter: Svc.AuthenticationRouter base id ComCcsdsConfig.BASE_ID_LORA + 0x03500 \ + queue size ComCcsdsConfig.QueueSizes.comQueue \ + stack size ComCcsdsConfig.StackSizes.comQueue \ + priority ComCcsdsConfig.Priorities.comQueue + + instance tcDeframer: Svc.Ccsds.TcDeframer base id ComCcsdsConfig.BASE_ID_LORA + 0x04000 + + instance spacePacketDeframer: Svc.Ccsds.SpacePacketDeframer base id ComCcsdsConfig.BASE_ID_LORA + 0x05000 + + instance aggregator: Svc.ComAggregator base id ComCcsdsConfig.BASE_ID_LORA + 0x06000 \ + queue size ComCcsdsConfig.QueueSizes.aggregator \ + stack size ComCcsdsConfig.StackSizes.aggregator + + # NOTE: name 'framer' is used for the framer that connects to the Com Adapter Interface for better subtopology interoperability + instance framer: Svc.Ccsds.TmFramer base id ComCcsdsConfig.BASE_ID_LORA + 0x07000 + + instance spacePacketFramer: Svc.Ccsds.SpacePacketFramer base id ComCcsdsConfig.BASE_ID_LORA + 0x08000 + + instance apidManager: Svc.Ccsds.ApidManager base id ComCcsdsConfig.BASE_ID_LORA + 0x09000 + + topology Subtopology { + # Usage Note: + # + # When importing this subtopology, users shall establish 5 port connections with a component implementing + # the Svc.Com (Svc/Interfaces/Com.fpp) interface. They are as follows: + # + # 1) Outputs: + # - ComCcsdsLora.framer.dataOut -> [Svc.Com].dataIn + # - ComCcsdsLora.frameAccumulator.dataReturnOut -> [Svc.Com].dataReturnIn + # 2) Inputs: + # - [Svc.Com].dataReturnOut -> ComCcsdsLora.framer.dataReturnIn + # - [Svc.Com].comStatusOut -> ComCcsdsLora.framer.comStatusIn + # - [Svc.Com].dataOut -> ComCcsdsLora.frameAccumulator.dataIn + + + # Active Components + instance comQueue + + # Passive Components + instance commsBufferManager + instance frameAccumulator + instance fprimeRouter + instance authenticationRouter + instance tcDeframer + instance spacePacketDeframer + instance framer + instance spacePacketFramer + instance apidManager + instance aggregator + + connections Downlink { + # ComQueue <-> SpacePacketFramer + comQueue.dataOut -> spacePacketFramer.dataIn + spacePacketFramer.dataReturnOut -> comQueue.dataReturnIn + # SpacePacketFramer buffer and APID management + spacePacketFramer.bufferAllocate -> commsBufferManager.bufferGetCallee + spacePacketFramer.bufferDeallocate -> commsBufferManager.bufferSendIn + spacePacketFramer.getApidSeqCount -> apidManager.getApidSeqCountIn + # SpacePacketFramer <-> TmFramer + spacePacketFramer.dataOut -> aggregator.dataIn + aggregator.dataOut -> framer.dataIn + + framer.dataReturnOut -> aggregator.dataReturnIn + aggregator.dataReturnOut -> spacePacketFramer.dataReturnIn + + # ComStatus + framer.comStatusOut -> aggregator.comStatusIn + aggregator.comStatusOut -> spacePacketFramer.comStatusIn + spacePacketFramer.comStatusOut -> comQueue.comStatusIn + # (Outgoing) Framer <-> ComInterface connections shall be established by the user + } + + connections Uplink { + # (Incoming) ComInterface <-> FrameAccumulator connections shall be established by the user + # FrameAccumulator buffer allocations + frameAccumulator.bufferDeallocate -> commsBufferManager.bufferSendIn + frameAccumulator.bufferAllocate -> commsBufferManager.bufferGetCallee + # FrameAccumulator <-> TcDeframer + frameAccumulator.dataOut -> tcDeframer.dataIn + tcDeframer.dataReturnOut -> frameAccumulator.dataReturnIn + # TcDeframer <-> SpacePacketDeframer + tcDeframer.dataOut -> spacePacketDeframer.dataIn + spacePacketDeframer.dataReturnOut -> tcDeframer.dataReturnIn + # SpacePacketDeframer APID validation + spacePacketDeframer.validateApidSeqCount -> apidManager.validateApidSeqCountIn + # SpacePacketDeframer <-> AuthenticationRouter (routes both commands and files) + spacePacketDeframer.dataOut -> authenticationRouter.dataIn + authenticationRouter.dataReturnOut -> spacePacketDeframer.dataReturnIn + # AuthenticationRouter buffer allocations + authenticationRouter.bufferAllocate -> commsBufferManager.bufferGetCallee + authenticationRouter.bufferDeallocate -> commsBufferManager.bufferSendIn + } + } # end Subtopology + +} # end ComCcsdsLora diff --git a/FprimeZephyrReference/ComCcsdsLora/PingEntries.hpp b/FprimeZephyrReference/ComCcsdsLora/PingEntries.hpp new file mode 100644 index 00000000..4607c3e7 --- /dev/null +++ b/FprimeZephyrReference/ComCcsdsLora/PingEntries.hpp @@ -0,0 +1,9 @@ + +#ifndef COMCCSDSLORA_PINGENTRIES_HPP +#define COMCCSDSLORA_PINGENTRIES_HPP + +namespace PingEntries { +// No ping-enabled components in ComCcsdsLora subtopology +} + +#endif diff --git a/FprimeZephyrReference/ComCcsdsLora/SubtopologyTopologyDefs.hpp b/FprimeZephyrReference/ComCcsdsLora/SubtopologyTopologyDefs.hpp new file mode 100644 index 00000000..f11f7337 --- /dev/null +++ b/FprimeZephyrReference/ComCcsdsLora/SubtopologyTopologyDefs.hpp @@ -0,0 +1,21 @@ +#ifndef COMCCSDSLORASUBTOPOLOGY_DEFS_HPP +#define COMCCSDSLORASUBTOPOLOGY_DEFS_HPP + +#include +#include +#include + +#include "ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp" +#include "Svc/Subtopologies/ComCcsds/ComCcsdsConfig/FppConstantsAc.hpp" + +namespace ComCcsdsLora { +struct SubtopologyState { + // Empty - no external state needed for ComCcsdsLora subtopology +}; + +struct TopologyState { + SubtopologyState comCcsdsLora; +}; +} // namespace ComCcsdsLora + +#endif diff --git a/FprimeZephyrReference/ComCcsdsUart/ComCcsds.fpp b/FprimeZephyrReference/ComCcsdsUart/ComCcsds.fpp index 3b174800..cb5e835d 100644 --- a/FprimeZephyrReference/ComCcsdsUart/ComCcsds.fpp +++ b/FprimeZephyrReference/ComCcsdsUart/ComCcsds.fpp @@ -94,7 +94,10 @@ module ComCcsdsUart { """ } - instance fprimeRouter: Svc.FprimeRouter base id ComCcsdsConfig.BASE_ID_UART + 0x03000 + instance authenticationRouter: Svc.AuthenticationRouter base id ComCcsdsConfig.BASE_ID_UART + 0x03000 \ + queue size ComCcsdsConfig.QueueSizes.comQueue \ + stack size ComCcsdsConfig.StackSizes.comQueue \ + priority ComCcsdsConfig.Priorities.comQueue instance tcDeframer: Svc.Ccsds.TcDeframer base id ComCcsdsConfig.BASE_ID_UART + 0x04000 @@ -132,7 +135,7 @@ module ComCcsdsUart { # Passive Components instance commsBufferManager instance frameAccumulator - instance fprimeRouter + instance authenticationRouter instance tcDeframer instance spacePacketDeframer instance framer @@ -185,12 +188,12 @@ module ComCcsdsUart { spacePacketDeframer.validateApidSeqCount -> apidManager.validateApidSeqCountIn # SpacePacketDeframer <-> Router - spacePacketDeframer.dataOut -> fprimeRouter.dataIn - fprimeRouter.dataReturnOut -> spacePacketDeframer.dataReturnIn + spacePacketDeframer.dataOut -> authenticationRouter.dataIn + authenticationRouter.dataReturnOut -> spacePacketDeframer.dataReturnIn # Router buffer allocations - fprimeRouter.bufferAllocate -> commsBufferManager.bufferGetCallee - fprimeRouter.bufferDeallocate -> commsBufferManager.bufferSendIn + authenticationRouter.bufferAllocate -> commsBufferManager.bufferGetCallee + authenticationRouter.bufferDeallocate -> commsBufferManager.bufferSendIn } } # end FramingSubtopology diff --git a/FprimeZephyrReference/Components/Authenticate/Authenticate.cpp b/FprimeZephyrReference/Components/Authenticate/Authenticate.cpp index edd3d835..50c4695e 100644 --- a/FprimeZephyrReference/Components/Authenticate/Authenticate.cpp +++ b/FprimeZephyrReference/Components/Authenticate/Authenticate.cpp @@ -426,7 +426,6 @@ void Authenticate ::dataIn_handler(FwIndexType portNum, Fw::Buffer& data, const #else // Authentication is disabled - pass data through unchanged // Mark as authenticated (or leave context unchanged) and pass through - // Note: You may want to set authenticated to 0 or leave it as-is depending on your requirements contextOut.set_authenticated( 1); // Pass through as authenticated, or use context.authenticated if you want to preserve #endif diff --git a/FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouter.cpp b/FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouter.cpp new file mode 100644 index 00000000..eda9f4ca --- /dev/null +++ b/FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouter.cpp @@ -0,0 +1,333 @@ +// ====================================================================== +// \title AuthenticationRouter.cpp +// \author Ines (based on thomas-bc's FprimeRouter.cpp) +// \brief cpp file for AuthenticationRouter component implementation class +// ====================================================================== + +#include "FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouter.hpp" + +#include +#include +#include + +#include "Fw/Com/ComPacket.hpp" +#include "Fw/FPrimeBasicTypes.hpp" +#include "Fw/Logger/Logger.hpp" +#include "Os/File.hpp" +#include "config/ApidEnumAc.hpp" + +constexpr const char LAST_LOSS_TIME_FILE[] = "//loss_max_time.txt"; +constexpr const char LAST_LOSS_TIME_FILE_MONOTONIC[] = "//loss_max_time_monotonic.txt"; +constexpr const char COMMAND_LOSS_EXPIRED_FLAG_FILE[] = "//command_loss_expired_flag.txt"; + +namespace Svc { + +// ---------------------------------------------------------------------- +// Component construction and destruction +// ---------------------------------------------------------------------- + +AuthenticationRouter ::AuthenticationRouter(const char* const compName) : AuthenticationRouterComponentBase(compName) { + // Initialize previous time type flag by checking current time type + Fw::Time time = this->getTime(); + TimeBase b = time.getTimeBase(); + m_previousTypeTimeFlag = (b == TimeBase::TB_PROC_TIME); // true if monotonic, false if RTC + m_TypeTimeFlag = m_previousTypeTimeFlag; // Initialize current flag to match + + this->initializeFiles(LAST_LOSS_TIME_FILE); + this->initializeFiles(LAST_LOSS_TIME_FILE_MONOTONIC); + + // Load the command loss expired flag from file (persists across boots) + m_commandLossTimeExpiredLogged = this->readCommandLossExpiredFlag(); +} +AuthenticationRouter ::~AuthenticationRouter() {} + +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +void AuthenticationRouter ::schedIn_handler(FwIndexType portNum, U32 context) { + (void)portNum; + (void)context; + + U32 current_loss_time = this->getTimeFromRTC(); + + // Check if time type has switched from RTC to monotonic or vice versa + // If switched, update the appropriate file to prevent false timeout triggers + if (m_previousTypeTimeFlag != m_TypeTimeFlag) { + if (m_previousTypeTimeFlag == false && m_TypeTimeFlag == true) { + // Switched from RTC to monotonic - update monotonic file + this->writeToFile(LAST_LOSS_TIME_FILE_MONOTONIC, current_loss_time); + } else if (m_previousTypeTimeFlag == true && m_TypeTimeFlag == false) { + // Switched from monotonic to RTC - update RTC file + this->writeToFile(LAST_LOSS_TIME_FILE, current_loss_time); + } + // Update previous flag to current flag + m_previousTypeTimeFlag = m_TypeTimeFlag; + } + + // check if the time is RTC or monotonic and set the flag accordingly + // Read from the appropriate file based on the time type + U32 last_loss_time; + if (m_TypeTimeFlag == true) { + last_loss_time = this->readFromFile(LAST_LOSS_TIME_FILE_MONOTONIC); + // Don't overwrite the file here - initializeFiles() should have already handled initialization + // If last_loss_time is 0, it means the file doesn't exist or read failed, but we don't want to + // overwrite on every schedIn call. The file should only be written when commands are received. + } else { + last_loss_time = this->readFromFile(LAST_LOSS_TIME_FILE); + // Don't overwrite the file here - initializeFiles() should have already handled initialization + // If last_loss_time is 0, it means the file doesn't exist or read failed, but we don't want to + // overwrite on every schedIn call. The file should only be written when commands are received. + } + + // // Check if the last loss time is past the current time + + // Get the LOSS_MAX_TIME parameter + Fw::ParamValid valid; + U32 loss_max_time = this->paramGet_LOSS_MAX_TIME(valid); + + U32 time_diff = (current_loss_time >= last_loss_time) ? (current_loss_time - last_loss_time) : 0; + + if (current_loss_time >= last_loss_time && (current_loss_time - last_loss_time) > loss_max_time) { + // Timeout condition is met + if (m_commandLossTimeExpiredLogged == false) { + this->log_ACTIVITY_HI_CommandLossTimeExpired(Fw::On::ON); + m_commandLossTimeExpiredLogged = true; + this->writeCommandLossExpiredFlag(true); // Persist flag to file + this->tlmWrite_CommandLossSafeOn(true); + // Only send safemode signal if port is connected + if (this->isConnected_SafeModeOn_OutputPort(0)) { + this->SafeModeOn_out(0); + } + } + // Flag stays true - signal will not be sent again until a command is received + } else { + // Timeout condition is NOT met - reset the flag so event can trigger again if timeout occurs later + if (m_commandLossTimeExpiredLogged == true) { + m_commandLossTimeExpiredLogged = false; + this->writeCommandLossExpiredFlag(false); // Persist flag to file + } + } +} + +U32 AuthenticationRouter ::getTimeFromRTC() { + // TODO: Get time from the rtc here + // use the RtcManager timeGetPort to get the time + // getTime() automatically calls the timeCaller port which is connected to RtcManager + Fw::Time time = this->getTime(); + + // Check if the time is RTC or monotonic and set the flag accordingly + TimeBase b = time.getTimeBase(); + if (b == TimeBase::TB_PROC_TIME) { + // monotonic time + m_TypeTimeFlag = true; + } else { + // RTC time + m_TypeTimeFlag = false; + } + + return time.getSeconds(); +} + +U32 AuthenticationRouter ::writeToFile(const char* filePath, U32 time) { + // TO DO: Add File Opening Error Handling here and in all the other file functions + Os::File file; + // Use OPEN_CREATE with OVERWRITE to ensure the file is properly overwritten + // This ensures data persists across boots and the file is fully overwritten + Os::File::Status openStatus = file.open(filePath, Os::File::OPEN_CREATE, Os::File::OverwriteType::OVERWRITE); + if (openStatus == Os::File::OP_OK) { + const U8* buffer = reinterpret_cast(&time); + FwSizeType size = static_cast(sizeof(time)); + // Use WAIT to ensure data is synced to disk (fsync/flush) + (void)file.write(buffer, size, Os::File::WaitType::WAIT); + file.close(); + // Note: Specific reason for overwrite is printed at the call site + } + return time; +} + +U32 AuthenticationRouter ::readFromFile(const char* filePath) { + Os::File file; + U32 time = 0; + Os::File::Status openStatus = file.open(filePath, Os::File::OPEN_READ); + if (openStatus == Os::File::OP_OK) { + FwSizeType size = static_cast(sizeof(time)); + FwSizeType expectedSize = size; + Os::File::Status readStatus = file.read(reinterpret_cast(&time), size, Os::File::WaitType::WAIT); + file.close(); + if (readStatus == Os::File::OP_OK && size == expectedSize) { + return time; + } + } + return time; +} + +bool AuthenticationRouter ::readCommandLossExpiredFlag() { + Os::File file; + bool flag = false; + Os::File::Status openStatus = file.open(COMMAND_LOSS_EXPIRED_FLAG_FILE, Os::File::OPEN_READ); + if (openStatus == Os::File::OP_OK) { + FwSizeType size = static_cast(sizeof(flag)); + FwSizeType expectedSize = size; + Os::File::Status readStatus = file.read(reinterpret_cast(&flag), size, Os::File::WaitType::WAIT); + file.close(); + if (readStatus == Os::File::OP_OK && size == expectedSize) { + return flag; + } + } + // File doesn't exist or read failed - return false (default) + return false; +} + +void AuthenticationRouter ::writeCommandLossExpiredFlag(bool flag) { + Os::File file; + Os::File::Status openStatus = + file.open(COMMAND_LOSS_EXPIRED_FLAG_FILE, Os::File::OPEN_CREATE, Os::File::OverwriteType::OVERWRITE); + if (openStatus == Os::File::OP_OK) { + const U8* buffer = reinterpret_cast(&flag); + FwSizeType size = static_cast(sizeof(flag)); + (void)file.write(buffer, size, Os::File::WaitType::WAIT); + file.close(); + } +} + +U32 AuthenticationRouter ::initializeFiles(const char* filePath) { + U32 last_loss_time = this->getTimeFromRTC(); + bool loadedFromFile = false; + bool timeIsValid = false; + + Os::File file; + + // Check if the file exists and is readable + Os::File::Status openStatus = file.open(filePath, Os::File::OPEN_READ); + if (openStatus == Os::File::OP_OK) { + FwSizeType size = static_cast(sizeof(last_loss_time)); + FwSizeType expectedSize = size; + Os::File::Status readStatus = file.read(reinterpret_cast(&last_loss_time), size, Os::File::WaitType::WAIT); + file.close(); + loadedFromFile = (readStatus == Os::File::OP_OK) && (size == expectedSize); + + // Validate the stored time - only check if it's 0 (RTC wasn't initialized when written) + // If it's not 0, preserve it regardless of value (no range checking) + if (loadedFromFile) { + // If time is 0, it means RTC wasn't initialized when file was written - should overwrite + if (last_loss_time == 0) { + timeIsValid = false; // Force overwrite + } else { + // Any non-zero value is considered valid - preserve it + timeIsValid = true; + } + } + } + + // Create or overwrite file if: + // 1. File doesn't exist, OR + // 2. File contains 0 (RTC wasn't initialized when written), OR + // 3. File contains invalid time + if (!loadedFromFile || !timeIsValid) { + last_loss_time = this->getTimeFromRTC(); + Os::File::Status createStatus = file.open(filePath, Os::File::OPEN_CREATE, Os::File::OverwriteType::OVERWRITE); + if (createStatus == Os::File::OP_OK) { + const U8* buffer = reinterpret_cast(&last_loss_time); + FwSizeType size = static_cast(sizeof(last_loss_time)); + (void)file.write(buffer, size, Os::File::WaitType::WAIT); + file.close(); + } + } + + return last_loss_time; +} + +void AuthenticationRouter ::dataIn_handler(FwIndexType portNum, + Fw::Buffer& packetBuffer, + const ComCfg::FrameContext& context) { + // Any packet received resets the flag and updates the last loss time + U32 current_time = this->getTimeFromRTC(); + if (m_TypeTimeFlag == true) { + this->writeToFile(LAST_LOSS_TIME_FILE_MONOTONIC, current_time); + } else { + this->writeToFile(LAST_LOSS_TIME_FILE, current_time); + } + // Reset the flag when any packet is received + m_commandLossTimeExpiredLogged = false; + this->writeCommandLossExpiredFlag(false); // Persist flag to file + // Update telemetry with the command loss safe on status + this->tlmWrite_CommandLossSafeOn(false); + this->tlmWrite_LastCommandPacketTime(static_cast(current_time)); + + Fw::SerializeStatus status; + Fw::ComPacketType packetType = context.get_apid(); + // Route based on received APID (packet type) + switch (packetType) { + // Handle a command packet + case Fw::ComPacketType::FW_PACKET_COMMAND: { + // Update telemetry with the last command packet time + // Allocate a com buffer on the stack + Fw::ComBuffer com; + // Copy the contents of the packet buffer into the com buffer + status = com.setBuff(packetBuffer.getData(), packetBuffer.getSize()); + if (status == Fw::FW_SERIALIZE_OK) { + // Send the com buffer - critical functionality so it is considered an error not to + // have the port connected. This is why we don't check isConnected() before sending. + this->commandOut_out(0, com, 0); + } else { + this->log_WARNING_HI_SerializationError(status); + } + break; + } + // Handle a file packet + case Fw::ComPacketType::FW_PACKET_FILE: { + // If the file uplink output port is connected, send the file packet. Otherwise take no action. + if (this->isConnected_fileOut_OutputPort(0)) { + // Copy buffer into a new allocated buffer. This lets us return the original buffer with dataReturnOut, + // and AuthenticationRouter can handle the deallocation of the file buffer when it returns on + // fileBufferReturnIn + Fw::Buffer packetBufferCopy = this->bufferAllocate_out(0, packetBuffer.getSize()); + auto copySerializer = packetBufferCopy.getSerializer(); + status = copySerializer.serializeFrom(packetBuffer.getData(), packetBuffer.getSize(), + Fw::Serialization::OMIT_LENGTH); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); + // Send the copied buffer out. It will come back on fileBufferReturnIn once the receiver is done with it + this->fileOut_out(0, packetBufferCopy); + } + break; + } + default: { + // Packet type is not known to the F Prime protocol. If the unknownDataOut port is + // connected, forward packet and context for further processing + if (this->isConnected_unknownDataOut_OutputPort(0)) { + // Copy buffer into a new allocated buffer. This lets us return the original buffer with dataReturnOut, + // and AuthenticationRouter can handle the deallocation of the unknown buffer when it returns on + // bufferReturnIn + Fw::Buffer packetBufferCopy = this->bufferAllocate_out(0, packetBuffer.getSize()); + auto copySerializer = packetBufferCopy.getSerializer(); + status = copySerializer.serializeFrom(packetBuffer.getData(), packetBuffer.getSize(), + Fw::Serialization::OMIT_LENGTH); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); + // Send the copied buffer out. It will come back on fileBufferReturnIn once the receiver is done with it + this->unknownDataOut_out(0, packetBufferCopy, context); + } + } + } + + // Return ownership of the incoming packetBuffer + this->dataReturnOut_out(0, packetBuffer, context); +} + +void AuthenticationRouter ::cmdResponseIn_handler(FwIndexType portNum, + FwOpcodeType opcode, + U32 cmdSeq, + const Fw::CmdResponse& response) { + (void)portNum; + (void)opcode; + (void)cmdSeq; + (void)response; + // This is a no-op because AuthenticationRouter does not need to handle command responses + // but the port must be connected +} + +void AuthenticationRouter ::fileBufferReturnIn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) { + this->bufferDeallocate_out(0, fwBuffer); +} + +} // namespace Svc diff --git a/FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouter.fpp b/FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouter.fpp new file mode 100644 index 00000000..f7a80dea --- /dev/null +++ b/FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouter.fpp @@ -0,0 +1,113 @@ +module Svc { + @ Routes packets deframed by the Deframer to the rest of the system + active component AuthenticationRouter { + + # ---------------------------------------------------------------------- + # Router interface (ports defined explicitly for active component) + # ---------------------------------------------------------------------- + # Port receiving calls from the rate group + async input port schedIn: Svc.Sched + + # Receiving data (Fw::Buffer) to be routed with optional context to help with routing + async input port dataIn: Svc.ComDataWithContext + + # Port for returning ownership of data (includes Fw.Buffer) received on dataIn + output port dataReturnOut: Svc.ComDataWithContext + + # Port for sending file packets as Fw::Buffer (ownership passed to receiver) + output port fileOut: Fw.BufferSend + + # Port for receiving ownership back of buffers sent on fileOut + sync input port fileBufferReturnIn: Fw.BufferSend + + # Port for sending command packets as Fw::ComBuffers + output port commandOut: Fw.Com + + # Port for receiving command responses from a command dispatcher (can be a no-op) + sync input port cmdResponseIn: Fw.CmdResponse + + @ Port for forwarding non-recognized packet types + @ Ownership of the buffer is retained by the AuthenticationRouter, meaning receiving + @ components should either process data synchronously, or copy the data if needed + output port unknownDataOut: Svc.ComDataWithContext + + @ Port for allocating buffers + output port bufferAllocate: Fw.BufferGet + + @ Port for deallocating buffers + output port bufferDeallocate: Fw.BufferSend + + @ An error occurred while serializing a com buffer + event SerializationError( + status: U32 @< The status of the operation + ) \ + severity warning high \ + format "Serializing com buffer failed with status {}" + + @ An error occurred while deserializing a packet + event DeserializationError( + status: U32 @< The status of the operation + ) \ + severity warning high \ + format "Deserializing packet type failed with status {}" + + + ############################################################################### + # Standard AC Ports for Events + ############################################################################### + @ Command receive port + command recv port cmdIn + + @ Command registration port + command reg port cmdRegOut + + @ Command response port + command resp port cmdResponseOut + + @ Port for requesting the current time + time get port timeCaller + + @ Port for sending textual representation of events + text event port logTextOut + + @ Port for sending events to downlink + event port logOut + + @ Telemetry port + telemetry port tlmOut + + @ Parameter get port + param get port prmGetOut + + @ Parameter set port + param set port prmSetOut + + ################################################ + # Custom For This Router + ################################# + + @ Port for sending signal to safemode + output port SafeModeOn: Fw.Signal + + @ event to emit when command loss time expires + event CommandLossTimeExpired(safemode: Fw.On) \ + severity activity high \ + format "SafeModeOn: {}" + + @ Emits Current Loss Time + event CurrentLossTime(loss_max_time: U32) \ + severity activity low \ + format "Current Loss Time: {}" + + @ Telemetry Channel to commit the time of the last command packet + telemetry LastCommandPacketTime : U64 + + @ Telemetry Channel for the status of the command loss time sending to safe mode + telemetry CommandLossSafeOn : bool + + @ loss time max parameter: Right now set to 3 days 259200 seconds + param LOSS_MAX_TIME : U32 default 259200 + + + } +} diff --git a/FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouter.hpp b/FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouter.hpp new file mode 100644 index 00000000..5fea4edd --- /dev/null +++ b/FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouter.hpp @@ -0,0 +1,104 @@ +// ====================================================================== +// \title AuthenticationRouter.hpp +// \author Ines (based on thomas-bc's FprimeRouter.hpp) +// \brief hpp file for AuthenticationRouter component implementation class +// ====================================================================== + +#ifndef Svc_AuthenticationRouter_HPP +#define Svc_AuthenticationRouter_HPP + +#include "FprimeZephyrReference/Components/AuthenticationRouter/AuthenticationRouterComponentAc.hpp" + +namespace Svc { + +class AuthenticationRouter final : public AuthenticationRouterComponentBase { + public: + // ---------------------------------------------------------------------- + // Component construction and destruction + // ---------------------------------------------------------------------- + + //! Construct AuthenticationRouter object + AuthenticationRouter(const char* const compName //!< The component name + ); + + //! Destroy AuthenticationRouter object + ~AuthenticationRouter(); + + private: + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for schedIn + //! Port receiving calls from the rate group + void schedIn_handler(FwIndexType portNum, //!< The port number + U32 context //!< The call order + ) override; + + //! Handler implementation for bufferIn + //! Receiving Fw::Buffer from Deframer + void dataIn_handler(FwIndexType portNum, //!< The port number + Fw::Buffer& packetBuffer, //!< The packet buffer + const ComCfg::FrameContext& context //!< The context object + ) override; + + // ! Handler for input port cmdResponseIn + // ! This is a no-op because AuthenticationRouter does not need to handle command responses + // ! but the port must be connected + void cmdResponseIn_handler(FwIndexType portNum, //!< The port number + FwOpcodeType opcode, //!< The command opcode + U32 cmdSeq, //!< The command sequence number + const Fw::CmdResponse& response //!< The command response + ) override; + + //! Handler implementation for fileBufferReturnIn + //! + //! Port for receiving ownership back of buffers sent on fileOut + void fileBufferReturnIn_handler(FwIndexType portNum, //!< The port number + Fw::Buffer& fwBuffer //!< The buffer + ) override; + + //! Handler implementation for initializeFiles + //! + //! Port for initializing the files + U32 initializeFiles(const char* filePath); + + //! Handler implementation for writeToFile + //! + //! Writes the time to the file + U32 writeToFile(const char* filePath, U32 time); + + //! Handler implementation for readFromFile + //! + //! Reads the time from the file + U32 readFromFile(const char* filePath); + + //! Handler implementation for getTimeFromRTC + //! + //! Gets the time from the RTC + U32 getTimeFromRTC(); + + //! Reads the command loss expired flag from file + //! + //! Returns the flag value from file, or false if file doesn't exist + bool readCommandLossExpiredFlag(); + + //! Writes the command loss expired flag to file + //! + //! Persists the flag value to file + void writeCommandLossExpiredFlag(bool flag); + + Fw::On m_state_rtc = Fw::On::OFF; // keeps track if the RTC is on or if we are using Zephyr's time + std::atomic m_commandLossTimeCounter; // makes this an atomic variable (so its set only in one command), + + bool m_TypeTimeFlag; //!< Flag to indicate if the time is RTC or monotonic + bool m_previousTypeTimeFlag; //!< Flag to track previous time type to detect switches + bool m_commandLossTimeExpiredLogged = false; //!< Flag to indicate if the command loss time has expired, false by + //!< default meaning no command loss time has expired yet + // if the file system fails this will prevent it from being stuck in a boot loop. Need to ensure false is written to + // the file when the system by default +}; + +} // namespace Svc + +#endif diff --git a/FprimeZephyrReference/Components/AuthenticationRouter/CMakeLists.txt b/FprimeZephyrReference/Components/AuthenticationRouter/CMakeLists.txt new file mode 100644 index 00000000..e4e8b55a --- /dev/null +++ b/FprimeZephyrReference/Components/AuthenticationRouter/CMakeLists.txt @@ -0,0 +1,26 @@ +#### +# F prime CMakeLists.txt: +# +# SOURCE_FILES: combined list of source and autocoding files +# MOD_DEPS: (optional) module dependencies +# UT_SOURCE_FILES: list of source files for unit tests +# +#### + +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/AuthenticationRouter.fpp" + "${CMAKE_CURRENT_LIST_DIR}/AuthenticationRouter.cpp" +) +register_fprime_module() + + +#### UTS #### +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/AuthenticationRouter.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/AuthenticationRouter.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/AuthenticationRouter.cpp" +) +set(UT_AUTO_HELPERS ON) + + +register_fprime_ut() diff --git a/FprimeZephyrReference/Components/AuthenticationRouter/docs/sdd.md b/FprimeZephyrReference/Components/AuthenticationRouter/docs/sdd.md new file mode 100644 index 00000000..000ccd63 --- /dev/null +++ b/FprimeZephyrReference/Components/AuthenticationRouter/docs/sdd.md @@ -0,0 +1,81 @@ +# Svc::AuthenticationRouter + +The `Svc::AuthenticationRouter` component routes F´ packets (such as command or file packets) to other components. It is based on the FPrime Router, explained and linked later in the sdd, with two exceptions + +1. Command Loss Time component, which checks how long since commands have last been routed through the satellite. If it has been too long (changeable parameter) it will emit an event and send out to safemode, to conserve power +As a result of this component writing to the filesystem, this component is active, while the usual FprimeRouter is passive. + +2. This component handles authenticated packets. It will check a list of preconfigured opcodes that do not need to be authenticated, will pass those on as well as the things that are authenticated + +The `Svc::AuthenticationRouter` component receives F´ packets (as [Fw::Buffer](../../../Fw/Buffer/docs/sdd.md) objects) and routes them to other components through synchronous port calls. The input port of type `Svc.ComDataWithContext` passes this Fw.Buffer object along with optional context data which can help for routing. The current F Prime protocol does not use this context data, but is nevertheless present in the interface for compatibility with other protocols which may for example pass APIDs in the frame headers. + +The `Svc::AuthenticationRouter` component supports `Fw::ComPacketType::FW_PACKET_COMMAND` and `Fw::ComPacketType::FW_PACKET_FILE` packet types. Unknown packet types are forwarded on the `unknownDataOut` port, which a project-specific component can connect to for custom routing. + +About memory management, all buffers sent by `Svc::AuthenticationRouter` on the `fileOut` and `unknownDataOut` ports are expected to be returned to the router through the `fileBufferReturnIn` port for deallocation. + +## Custom Routing + +The `Svc::AuthenticationRouter` component is designed to be extensible through the use of a project-specific router. The `unknownDataOut` port can be connected to a project-specific component that can receive all unknown packet types. This component can then implement custom handling of these unknown packets. After processing, the project-specific component shall return the received buffer to the `Svc::AuthenticationRouter` component through the `fileBufferReturnIn` port (named this way as it only receives file packets in the common use-case), which will deallocate the buffer. + +## Usage Examples + +The `Svc::FprimeRouter` component is used in the uplink stack of many reference F´ application such as [the tutorials source code](https://github.com/fprime-community#tutorials). + +### Typical Usage + +In the canonical uplink communications stack, `Svc::FprimeRouter` is connected to a [Svc::CmdDispatcher](../../CmdDispatcher/docs/sdd.md) and a [Svc::FileUplink](../../FileUplink/docs/sdd.md) component, to receive Command and File packets respectively. + +![uplink_stack](../../FprimeDeframer/docs/img/deframer_uplink_stack.png) + +## Port Descriptions + +| Kind | Name | Type | Description | +|---|---|---|---| +| `async input` | `schedIn` | `Svc.Sched` | Port receiving calls from the rate group for periodic command loss time checking | +| `async input` | `dataIn` | `Svc.ComDataWithContext` | Receiving Fw::Buffer with context buffer from Deframer | +| `output` | `dataReturnOut` | `Svc.ComDataWithContext` | Returning ownership of buffer received on `dataIn` | +| `output` | `commandOut` | `Fw.Com` | Port for sending command packets as Fw::ComBuffers | +| `output` | `fileOut` | `Fw.BufferSend` | Port for sending file packets as Fw::Buffer (ownership passed to receiver) | +| `sync input` | `fileBufferReturnIn` | `Fw.BufferSend` | Receiving back ownership of buffer sent on `fileOut` and `unknownDataOut` | +| `sync input` | `cmdResponseIn` | `Fw.CmdResponse` | Port for receiving command responses from a command dispatcher (can be a no-op) | +| `output` | `unknownDataOut` | `Svc.ComDataWithContext` | Port forwarding unknown data (useful for adding custom routing rules with a project-defined router) | +| `output` | `bufferAllocate` | `Fw.BufferGet` | Port for allocating buffers, allowing copy of received data | +| `output` | `bufferDeallocate` | `Fw.BufferSend` | Port for deallocating buffers | +| `output` | `SafeModeOn` | `Fw.Signal` | Port for sending signal to safemode when command loss time expires | + +## Requirements + +| Name | Description | Rationale | Validation | +|---|---|---|---| +SVC-ROUTER-001 | `Svc::AuthenticationRouter` shall route packets based on their packet type as indicated by the packet header | Routing mechanism of the F´ comms protocol | Unit test | +SVC-ROUTER-002 | `Svc::AuthenticationRouter` shall route packets of type `Fw::ComPacketType::FW_PACKET_COMMAND` to the `commandOut` output port. | Routing command packets | Unit test | +SVC-ROUTER-003 | `Svc::AuthenticationRouter` shall route packets of type `Fw::ComPacketType::FW_PACKET_FILE` to the `fileOut` output port. | Routing file packets | Unit test | +SVC-ROUTER-004 | `Svc::AuthenticationRouter` shall route data that is neither `Fw::ComPacketType::FW_PACKET_COMMAND` nor `Fw::ComPacketType::FW_PACKET_FILE` to the `unknownDataOut` output port. | Allows for projects to provide custom routing for additional (project-specific) uplink data types | Unit test | +SVC-ROUTER-005 | `Svc::AuthenticationRouter` shall emit warning events if serialization errors occur during processing of incoming packets | Aid in diagnosing uplink issues | Unit test | +SVC-ROUTER-005 | `Svc::AuthenticationRouter` shall make a copy of buffers that represent a `FW_PACKET_FILE` | Aid in memory management of file buffers | Unit test | +SVC-ROUTER-006 | `Svc::AuthenticationRouter` shall return ownership of all buffers received on `dataIn` through `dataReturnOut` | Memory management | Unit test | +SVC-ROUTER-007 | `Svc::AuthenticationRouter` shall check command loss time periodically via the `schedIn` port | Command loss time monitoring | Unit test | +SVC-ROUTER-008 | `Svc::AuthenticationRouter` shall emit `CommandLossTimeExpired` event when command loss time exceeds `LOSS_MAX_TIME` parameter | Command loss time monitoring | Unit test | +SVC-ROUTER-009 | `Svc::AuthenticationRouter` shall send `SafeModeOn` signal when command loss time expires | Safe mode activation | Unit test | +SVC-ROUTER-010 | `Svc::AuthenticationRouter` shall update `LastCommandPacketTime` telemetry when a packet is received | Telemetry tracking | Unit test | + + +## Events + +| Name | Severity | Parameters | Description | +|---|---|---|---| +| CommandLossTimeExpired | Activity High | safemode: Fw.On | Emitted when command loss time expires. Format: "SafeModeOn: {}" | +| CurrentLossTime | Activity Low | loss_max_time: U32 | Emitted with current loss time information. Format: "Current Loss Time: {}" | + +## Telemetry Channels + +| Name | Type | Description | +|---|---|---| +| LastCommandPacketTime | U64 | The time of the last command packet | +| CommandLossSafeOn | bool | The status of the command loss time sending to safe mode | + +## Parameters + +| Name | Type | Default | Description | +|---|---|---|---| +| LOSS_MAX_TIME | U32 | 10 | The maximum amount of time (in seconds) since the last command before triggering safe mode | diff --git a/FprimeZephyrReference/Components/AuthenticationRouter/test/ut/FprimeRouterTestMain.cpp b/FprimeZephyrReference/Components/AuthenticationRouter/test/ut/FprimeRouterTestMain.cpp new file mode 100644 index 00000000..5d9c6458 --- /dev/null +++ b/FprimeZephyrReference/Components/AuthenticationRouter/test/ut/FprimeRouterTestMain.cpp @@ -0,0 +1,45 @@ +// ====================================================================== +// \title FprimeRouterTestMain.cpp +// \author thomas-bc +// \brief cpp file for FprimeRouter component test main function +// ====================================================================== + +#include + +#include "FprimeRouterTester.hpp" + +TEST(FprimeRouter, TestComInterface) { + COMMENT("Route a com packet"); + Svc::FprimeRouterTester tester; + tester.testRouteComInterface(); +} +TEST(FprimeRouter, TestFileInterface) { + COMMENT("Route a file packet"); + Svc::FprimeRouterTester tester; + tester.testRouteFileInterface(); +} +TEST(FprimeRouter, TestUnknownInterface) { + COMMENT("Route a packet of unknown type"); + Svc::FprimeRouterTester tester; + tester.testRouteUnknownPacket(); +} +TEST(FprimeRouter, TestRouteUnknownPacketUnconnected) { + COMMENT("Attempt to route a packet of unknown type with no port connected"); + Svc::FprimeRouterTester tester(true); + tester.testRouteUnknownPacketUnconnected(); +} +TEST(FprimeRouter, TestBufferReturn) { + COMMENT("Deallocate a returning buffer"); + Svc::FprimeRouterTester tester; + tester.testBufferReturn(); +} +TEST(FprimeRouter, TestCommandResponse) { + COMMENT("Handle a command response (no-op)"); + Svc::FprimeRouterTester tester; + tester.testCommandResponse(); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/FprimeZephyrReference/Components/AuthenticationRouter/test/ut/FprimeRouterTester.cpp b/FprimeZephyrReference/Components/AuthenticationRouter/test/ut/FprimeRouterTester.cpp new file mode 100644 index 00000000..037bad1b --- /dev/null +++ b/FprimeZephyrReference/Components/AuthenticationRouter/test/ut/FprimeRouterTester.cpp @@ -0,0 +1,125 @@ +// ====================================================================== +// \title FprimeRouterTester.cpp +// \author thomas-bc +// \brief cpp file for FprimeRouter component test harness implementation class +// ====================================================================== + +#include "FprimeRouterTester.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +FprimeRouterTester ::FprimeRouterTester(bool disconnect_unknownData_port) + : FprimeRouterGTestBase("FprimeRouterTester", FprimeRouterTester::MAX_HISTORY_SIZE), component("FprimeRouter") { + this->initComponents(); + if (disconnect_unknownData_port) { + this->connectPortsExceptUnknownData(); // hand-coded function connecting all ports except unknownData + } else { + this->connectPorts(); // autocoded function connecting all ports + } +} + +FprimeRouterTester ::~FprimeRouterTester() {} + +// ---------------------------------------------------------------------- +// Test Cases +// ---------------------------------------------------------------------- + +void FprimeRouterTester ::testRouteComInterface() { + this->mockReceivePacketType(Fw::ComPacketType::FW_PACKET_COMMAND); + ASSERT_from_commandOut_SIZE(1); // one command packet emitted + ASSERT_from_fileOut_SIZE(0); // no file packet emitted + ASSERT_from_unknownDataOut_SIZE(0); // no unknown data emitted + ASSERT_from_dataReturnOut_SIZE(1); // data ownership should always be returned + ASSERT_from_bufferAllocate_SIZE(0); // no buffer allocation for Com packets +} + +void FprimeRouterTester ::testRouteFileInterface() { + this->mockReceivePacketType(Fw::ComPacketType::FW_PACKET_FILE); + ASSERT_from_commandOut_SIZE(0); // no command packet emitted + ASSERT_from_fileOut_SIZE(1); // one file packet emitted + ASSERT_from_unknownDataOut_SIZE(0); // no unknown data emitted + ASSERT_from_dataReturnOut_SIZE(1); // data ownership should always be returned + ASSERT_from_bufferAllocate_SIZE(1); // file packet was copied into a new allocated buffer +} + +void FprimeRouterTester ::testRouteUnknownPacket() { + this->mockReceivePacketType(Fw::ComPacketType::FW_PACKET_UNKNOWN); + ASSERT_from_commandOut_SIZE(0); // no command packet emitted + ASSERT_from_fileOut_SIZE(0); // no file packet emitted + ASSERT_from_unknownDataOut_SIZE(1); // one unknown data emitted + ASSERT_from_dataReturnOut_SIZE(1); // data ownership should always be returned + ASSERT_from_bufferAllocate_SIZE(1); // unknown packet was copied into a new allocated buffer +} + +void FprimeRouterTester ::testRouteUnknownPacketUnconnected() { + this->mockReceivePacketType(Fw::ComPacketType::FW_PACKET_UNKNOWN); + ASSERT_from_commandOut_SIZE(0); // no command packet emitted + ASSERT_from_fileOut_SIZE(0); // no file packet emitted + ASSERT_from_unknownDataOut_SIZE(0); // zero unknown data emitted when port is unconnected + ASSERT_from_dataReturnOut_SIZE(1); // data ownership should always be returned + ASSERT_from_bufferAllocate_SIZE(0); // no buffer allocation when port is unconnected +} + +void FprimeRouterTester ::testBufferReturn() { + U8 data[1]; + Fw::Buffer buffer(data, sizeof(data)); + this->invoke_to_fileBufferReturnIn(0, buffer); + ASSERT_from_bufferDeallocate_SIZE(1); // incoming buffer should be deallocated + ASSERT_EQ(this->fromPortHistory_bufferDeallocate->at(0).fwBuffer.getData(), data); + ASSERT_EQ(this->fromPortHistory_bufferDeallocate->at(0).fwBuffer.getSize(), sizeof(data)); +} + +void FprimeRouterTester ::testCommandResponse() { + const U32 opcode = 0; + const U32 cmdSeq = 0; + const Fw::CmdResponse cmdResp(Fw::CmdResponse::OK); + this->invoke_to_cmdResponseIn(0, opcode, cmdSeq, cmdResp); + ASSERT_FROM_PORT_HISTORY_SIZE(0); +} + +// ---------------------------------------------------------------------- +// Test Helper +// ---------------------------------------------------------------------- + +void FprimeRouterTester::mockReceivePacketType(Fw::ComPacketType packetType) { + const FwPacketDescriptorType descriptorType = packetType; + U8 data[sizeof descriptorType]; + Fw::Buffer buffer(data, sizeof(data)); + ComCfg::FrameContext context; + context.set_apid(static_cast(descriptorType)); + this->invoke_to_dataIn(0, buffer, context); +} + +void FprimeRouterTester::connectPortsExceptUnknownData() { + // Connect special output ports + this->component.set_logOut_OutputPort(0, this->get_from_logOut(0)); + this->component.set_logTextOut_OutputPort(0, this->get_from_logTextOut(0)); + this->component.set_timeCaller_OutputPort(0, this->get_from_timeCaller(0)); + // Connect typed input ports + this->connect_to_cmdResponseIn(0, this->component.get_cmdResponseIn_InputPort(0)); + this->connect_to_dataIn(0, this->component.get_dataIn_InputPort(0)); + this->connect_to_fileBufferReturnIn(0, this->component.get_fileBufferReturnIn_InputPort(0)); + // Connect typed output ports + this->component.set_bufferAllocate_OutputPort(0, this->get_from_bufferAllocate(0)); + this->component.set_bufferDeallocate_OutputPort(0, this->get_from_bufferDeallocate(0)); + this->component.set_commandOut_OutputPort(0, this->get_from_commandOut(0)); + this->component.set_dataReturnOut_OutputPort(0, this->get_from_dataReturnOut(0)); + this->component.set_fileOut_OutputPort(0, this->get_from_fileOut(0)); +} + +// ---------------------------------------------------------------------- +// Port handler overrides +// ---------------------------------------------------------------------- +Fw::Buffer FprimeRouterTester::from_bufferAllocate_handler(FwIndexType portNum, FwSizeType size) { + this->pushFromPortEntry_bufferAllocate(size); + this->m_buffer.setData(this->m_buffer_slot); + this->m_buffer.setSize(size); + ::memset(this->m_buffer.getData(), 0, size); + return this->m_buffer; +} + +} // namespace Svc diff --git a/FprimeZephyrReference/Components/AuthenticationRouter/test/ut/FprimeRouterTester.hpp b/FprimeZephyrReference/Components/AuthenticationRouter/test/ut/FprimeRouterTester.hpp new file mode 100644 index 00000000..b7e1f250 --- /dev/null +++ b/FprimeZephyrReference/Components/AuthenticationRouter/test/ut/FprimeRouterTester.hpp @@ -0,0 +1,102 @@ +// ====================================================================== +// \title FprimeRouterTester.hpp +// \author thomas-bc +// \brief hpp file for FprimeRouter component test harness implementation class +// ====================================================================== + +#ifndef Svc_FprimeRouterTester_HPP +#define Svc_FprimeRouterTester_HPP + +#include + +#include "Svc/FprimeRouter/FprimeRouter.hpp" +#include "Svc/FprimeRouter/FprimeRouterGTestBase.hpp" + +namespace Svc { + +class FprimeRouterTester : public FprimeRouterGTestBase { + public: + // ---------------------------------------------------------------------- + // Constants + // ---------------------------------------------------------------------- + + // Maximum size of histories storing events, telemetry, and port outputs + static const FwSizeType MAX_HISTORY_SIZE = 10; + + // Instance ID supplied to the component instance under test + static const FwEnumStoreType TEST_INSTANCE_ID = 0; + + public: + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + //! Construct object FprimeRouterTester + //! \param disconnect_unknownData_port if set to true, the unknownData output port will not be connected + //! in the test harness setup. If false (default), all ports will be connected. + explicit FprimeRouterTester(bool disconnect_unknownData_port = false); + + //! Destroy object FprimeRouterTester + ~FprimeRouterTester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! Route a com packet + void testRouteComInterface(); + + //! Route a file packet + void testRouteFileInterface(); + + //! Route a packet of unknown type + void testRouteUnknownPacket(); + + //! Route a packet of unknown type + void testRouteUnknownPacketUnconnected(); + + //! Deallocate a returning buffer + void testBufferReturn(); + + //! Invoke the command response input port + void testCommandResponse(); + + private: + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + //! Connect all ports + void connectPorts(); + + //! Connect all ports except unknownDataOut output port + void connectPortsExceptUnknownData(); + + //! Initialize components + void initComponents(); + + //! Mock the reception of a packet of a specific type + void mockReceivePacketType(Fw::ComPacketType packetType); + + // ---------------------------------------------------------------------- + // Port handler overrides + // ---------------------------------------------------------------------- + //! Overriding bufferAllocate handler to be able to request a buffer in component tests + Fw::Buffer from_bufferAllocate_handler(FwIndexType portNum, FwSizeType size) override; + + private: + // ---------------------------------------------------------------------- + // Member variables + // ---------------------------------------------------------------------- + + //! The component under test + FprimeRouter component; + + Fw::Buffer m_buffer; // buffer to be returned by mocked bufferAllocate call + U8 m_buffer_slot[64]; +}; + +} // namespace Svc + +#endif diff --git a/FprimeZephyrReference/Components/CMakeLists.txt b/FprimeZephyrReference/Components/CMakeLists.txt index b4f276ad..cdd76cd4 100644 --- a/FprimeZephyrReference/Components/CMakeLists.txt +++ b/FprimeZephyrReference/Components/CMakeLists.txt @@ -16,3 +16,4 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PowerMonitor/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ResetManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/StartupManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Watchdog") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/AuthenticationRouter") diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi index 6055131c..b8a1e031 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentPackets.fppi @@ -3,8 +3,8 @@ telemetry packets ReferenceDeploymentPackets { packet Health id 1 group 1 { CdhCore.cmdDisp.CommandsDispatched CdhCore.cmdDisp.CommandsDropped - ComCcsds.comQueue.comQueueDepth - ComCcsds.commsBufferManager.HiBuffs + ComCcsdsLora.comQueue.comQueueDepth + ComCcsdsLora.commsBufferManager.HiBuffs ComCcsdsUart.comQueue.comQueueDepth ComCcsdsUart.commsBufferManager.HiBuffs ReferenceDeployment.rateGroup10Hz.RgMaxTime @@ -13,12 +13,16 @@ telemetry packets ReferenceDeploymentPackets { ReferenceDeployment.startupManager.QuiescenceEndTime ReferenceDeployment.modeManager.CurrentMode ReferenceDeployment.modeManager.SafeModeEntryCount + ComCcsdsLora.authenticationRouter.LastCommandPacketTime + ComCcsdsLora.authenticationRouter.CommandLossSafeOn + ComCcsdsUart.authenticationRouter.LastCommandPacketTime + ComCcsdsUart.authenticationRouter.CommandLossSafeOn } packet HealthWarnings id 2 group 1 { CdhCore.$health.PingLateWarnings - ComCcsds.commsBufferManager.NoBuffs - ComCcsds.commsBufferManager.EmptyBuffs + ComCcsdsLora.commsBufferManager.NoBuffs + ComCcsdsLora.commsBufferManager.EmptyBuffs ComCcsdsUart.commsBufferManager.NoBuffs ComCcsdsUart.commsBufferManager.EmptyBuffs ReferenceDeployment.rateGroup10Hz.RgCycleSlips @@ -27,9 +31,9 @@ telemetry packets ReferenceDeploymentPackets { packet HealthAuxillary id 3 group 2 { - ComCcsds.commsBufferManager.TotalBuffs - ComCcsds.commsBufferManager.CurrBuffs - ComCcsds.comQueue.buffQueueDepth + ComCcsdsLora.commsBufferManager.TotalBuffs + ComCcsdsLora.commsBufferManager.CurrBuffs + ComCcsdsLora.comQueue.buffQueueDepth ComCcsdsUart.commsBufferManager.TotalBuffs ComCcsdsUart.commsBufferManager.CurrBuffs ComCcsdsUart.comQueue.buffQueueDepth diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp index 00b11005..6ee1720d 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/ReferenceDeploymentTopologyDefs.hpp @@ -7,19 +7,22 @@ #define REFERENCEDEPLOYMENT_REFERENCEDEPLOYMENTTOPOLOGYDEFS_HPP // Subtopology PingEntries includes +#include "FprimeZephyrReference/ComCcsdsLora/PingEntries.hpp" #include "Svc/Subtopologies/CdhCore/PingEntries.hpp" -#include "Svc/Subtopologies/ComCcsds/PingEntries.hpp" #include "Svc/Subtopologies/DataProducts/PingEntries.hpp" #include "Svc/Subtopologies/FileHandling/PingEntries.hpp" // SubtopologyTopologyDefs includes +#include "FprimeZephyrReference/ComCcsdsLora/SubtopologyTopologyDefs.hpp" #include "Svc/Subtopologies/CdhCore/SubtopologyTopologyDefs.hpp" -#include "Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp" #include "Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp" -// ComCcsds Enum Includes +// ComCcsds Enum Includes (for ComCcsdsLora) #include "Svc/Subtopologies/ComCcsds/Ports_ComBufferQueueEnumAc.hpp" #include "Svc/Subtopologies/ComCcsds/Ports_ComPacketQueueEnumAc.hpp" +// ComCcsdsUart Enum Includes +#include "FprimeZephyrReference/ComCcsdsUart/Ports_ComBufferQueueEnumAc.hpp" +#include "FprimeZephyrReference/ComCcsdsUart/Ports_ComPacketQueueEnumAc.hpp" // Include autocoded FPP constants #include "FprimeZephyrReference/ReferenceDeployment/Top/FppConstantsAc.hpp" @@ -73,7 +76,7 @@ struct TopologyState { const device* loraDevice; //!< LoRa device path for communication U32 baudRate; //!< Baud rate for UART communication CdhCore::SubtopologyState cdhCore; //!< Subtopology state for CdhCore - ComCcsds::SubtopologyState comCcsds; //!< Subtopology state for ComCcsds + ComCcsdsLora::SubtopologyState comCcsdsLora; //!< Subtopology state for ComCcsdsLora FileHandling::SubtopologyState fileHandling; //!< Subtopology state for FileHandling const device* ina219SysDevice; //!< device path for battery board ina219 const device* ina219SolDevice; //!< device path for solar panel ina219 diff --git a/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp b/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp index 0390534e..54d2d172 100644 --- a/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp +++ b/FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp @@ -15,7 +15,7 @@ module ReferenceDeployment { # Subtopology imports # ---------------------------------------------------------------------- import CdhCore.Subtopology - import ComCcsds.FramingSubtopology + import ComCcsdsLora.Subtopology import ComCcsdsUart.Subtopology import FileHandling.Subtopology @@ -95,37 +95,37 @@ module ReferenceDeployment { connections ComCcsds_CdhCore { # Core events and telemetry to communication queue CdhCore.events.PktSend -> comSplitterEvents.comIn - comSplitterEvents.comOut-> ComCcsds.comQueue.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.EVENTS] + comSplitterEvents.comOut-> ComCcsdsLora.comQueue.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.EVENTS] comSplitterEvents.comOut-> ComCcsdsUart.comQueue.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.EVENTS] CdhCore.tlmSend.PktSend -> comSplitterTelemetry.comIn - comSplitterTelemetry.comOut -> ComCcsds.comQueue.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.TELEMETRY] + comSplitterTelemetry.comOut -> ComCcsdsLora.comQueue.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.TELEMETRY] comSplitterTelemetry.comOut -> ComCcsdsUart.comQueue.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.TELEMETRY] # Router to Command Dispatcher - ComCcsds.fprimeRouter.commandOut -> CdhCore.cmdDisp.seqCmdBuff - CdhCore.cmdDisp.seqCmdStatus -> ComCcsds.fprimeRouter.cmdResponseIn + ComCcsdsLora.authenticationRouter.commandOut -> CdhCore.cmdDisp.seqCmdBuff + CdhCore.cmdDisp.seqCmdStatus -> ComCcsdsLora.authenticationRouter.cmdResponseIn - ComCcsdsUart.fprimeRouter.commandOut -> CdhCore.cmdDisp.seqCmdBuff - CdhCore.cmdDisp.seqCmdStatus -> ComCcsdsUart.fprimeRouter.cmdResponseIn + ComCcsdsUart.authenticationRouter.commandOut -> CdhCore.cmdDisp.seqCmdBuff + CdhCore.cmdDisp.seqCmdStatus -> ComCcsdsUart.authenticationRouter.cmdResponseIn cmdSeq.comCmdOut -> CdhCore.cmdDisp.seqCmdBuff CdhCore.cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn } connections CommunicationsRadio { - lora.allocate -> ComCcsds.commsBufferManager.bufferGetCallee - lora.deallocate -> ComCcsds.commsBufferManager.bufferSendIn + lora.allocate -> ComCcsdsLora.commsBufferManager.bufferGetCallee + lora.deallocate -> ComCcsdsLora.commsBufferManager.bufferSendIn - # ComDriver <-> ComStub (Uplink) - lora.dataOut -> ComCcsds.frameAccumulator.dataIn - ComCcsds.frameAccumulator.dataReturnOut -> lora.dataReturnIn + # ComDriver <-> FrameAccumulator (Uplink) + lora.dataOut -> ComCcsdsLora.frameAccumulator.dataIn + ComCcsdsLora.frameAccumulator.dataReturnOut -> lora.dataReturnIn - # ComStub <-> ComDriver (Downlink) - ComCcsds.framer.dataOut -> lora.dataIn - lora.dataReturnOut -> ComCcsds.framer.dataReturnIn + # Framer <-> ComDriver (Downlink) + ComCcsdsLora.framer.dataOut -> lora.dataIn + lora.dataReturnOut -> ComCcsdsLora.framer.dataReturnIn lora.comStatusOut -> comDelay.comStatusIn - comDelay.comStatusOut ->ComCcsds.framer.comStatusIn + comDelay.comStatusOut ->ComCcsdsLora.framer.comStatusIn startupManager.runSequence -> cmdSeq.seqRunIn cmdSeq.seqDone -> startupManager.completeSequence @@ -153,15 +153,15 @@ module ReferenceDeployment { rateGroupDriver.CycleOut[Ports_RateGroups.rateGroup10Hz] -> rateGroup10Hz.CycleIn rateGroup10Hz.RateGroupMemberOut[0] -> comDriver.schedIn rateGroup10Hz.RateGroupMemberOut[1] -> ComCcsdsUart.aggregator.timeout - rateGroup10Hz.RateGroupMemberOut[2] -> ComCcsds.aggregator.timeout + rateGroup10Hz.RateGroupMemberOut[2] -> ComCcsdsLora.aggregator.timeout rateGroup10Hz.RateGroupMemberOut[3] -> FileHandling.fileManager.schedIn rateGroup10Hz.RateGroupMemberOut[4] -> cmdSeq.schedIn # Slow rate (1Hz) rate group rateGroupDriver.CycleOut[Ports_RateGroups.rateGroup1Hz] -> rateGroup1Hz.CycleIn - rateGroup1Hz.RateGroupMemberOut[0] -> ComCcsds.comQueue.run + rateGroup1Hz.RateGroupMemberOut[0] -> ComCcsdsLora.comQueue.run rateGroup1Hz.RateGroupMemberOut[1] -> CdhCore.$health.Run - rateGroup1Hz.RateGroupMemberOut[2] -> ComCcsds.commsBufferManager.schedIn + rateGroup1Hz.RateGroupMemberOut[2] -> ComCcsdsLora.commsBufferManager.schedIn rateGroup1Hz.RateGroupMemberOut[3] -> CdhCore.tlmSend.Run rateGroup1Hz.RateGroupMemberOut[4] -> watchdog.run rateGroup1Hz.RateGroupMemberOut[5] -> imuManager.run @@ -173,6 +173,7 @@ module ReferenceDeployment { rateGroup1Hz.RateGroupMemberOut[11] -> startupManager.run rateGroup1Hz.RateGroupMemberOut[12] -> powerMonitor.run rateGroup1Hz.RateGroupMemberOut[13] -> modeManager.run + rateGroup1Hz.RateGroupMemberOut[14] -> ComCcsdsLora.authenticationRouter.schedIn } @@ -215,8 +216,8 @@ module ReferenceDeployment { ComCcsdsUart.comQueue.bufferReturnOut[ComCcsds.Ports_ComBufferQueue.FILE] -> FileHandling.fileDownlink.bufferReturn # Router <-> FileUplink - ComCcsdsUart.fprimeRouter.fileOut -> FileHandling.fileUplink.bufferSendIn - FileHandling.fileUplink.bufferSendOut -> ComCcsdsUart.fprimeRouter.fileBufferReturnIn + ComCcsdsUart.authenticationRouter.fileOut -> FileHandling.fileUplink.bufferSendIn + FileHandling.fileUplink.bufferSendOut -> ComCcsdsUart.authenticationRouter.fileBufferReturnIn } @@ -255,6 +256,10 @@ module ReferenceDeployment { modeManager.loadSwitchTurnOff[5] -> face5LoadSwitch.turnOff modeManager.loadSwitchTurnOff[6] -> payloadPowerLoadSwitch.turnOff modeManager.loadSwitchTurnOff[7] -> payloadBatteryLoadSwitch.turnOff + + # Connect AuthenticationRouter from ComCcsdsLora subtopology to ModeManager + ComCcsdsLora.authenticationRouter.SafeModeOn -> modeManager.forceSafeMode + } } diff --git a/FprimeZephyrReference/project/config/AcConstants.fpp b/FprimeZephyrReference/project/config/AcConstants.fpp index 8eeefb4b..c88be742 100644 --- a/FprimeZephyrReference/project/config/AcConstants.fpp +++ b/FprimeZephyrReference/project/config/AcConstants.fpp @@ -13,7 +13,7 @@ constant PassiveRateGroupOutputPorts = 10 constant RateGroupDriverRateGroupPorts = 3 @ Used for command and registration ports -constant CmdDispatcherComponentCommandPorts = 30 +constant CmdDispatcherComponentCommandPorts = 35 @ Used for uplink/sequencer buffer/response ports constant CmdDispatcherSequencePorts = 5 diff --git a/FprimeZephyrReference/project/config/ComCcsdsConfig.fpp b/FprimeZephyrReference/project/config/ComCcsdsConfig.fpp index c39d3778..60fdc711 100644 --- a/FprimeZephyrReference/project/config/ComCcsdsConfig.fpp +++ b/FprimeZephyrReference/project/config/ComCcsdsConfig.fpp @@ -2,6 +2,7 @@ module ComCcsdsConfig { #Base ID for the ComCcsds Subtopology, all components are offsets from this base ID constant BASE_ID = 0x02000000 constant BASE_ID_UART = 0x21000000 + constant BASE_ID_LORA = 0x22000000 module QueueSizes { constant comQueue = 5 diff --git a/FprimeZephyrReference/project/config/ComCcsdsConfig/CMakeLists.txt b/FprimeZephyrReference/project/config/ComCcsdsConfig/CMakeLists.txt new file mode 100644 index 00000000..aad62bfe --- /dev/null +++ b/FprimeZephyrReference/project/config/ComCcsdsConfig/CMakeLists.txt @@ -0,0 +1,12 @@ +register_fprime_module( + EXCLUDE_FROM_ALL + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsSubtopologyConfig.cpp" + HEADERS + "${CMAKE_CURRENT_LIST_DIR}/ComCcsdsSubtopologyConfig.hpp" + AUTOCODER_INPUTS + "${CMAKE_CURRENT_LIST_DIR}/../ComCcsdsConfig.fpp" + DEPENDS + Fw_Types + INTERFACE +) diff --git a/FprimeZephyrReference/project/config/ComCcsdsConfig/ComCcsdsSubtopologyConfig.cpp b/FprimeZephyrReference/project/config/ComCcsdsConfig/ComCcsdsSubtopologyConfig.cpp new file mode 100644 index 00000000..aa384b0e --- /dev/null +++ b/FprimeZephyrReference/project/config/ComCcsdsConfig/ComCcsdsSubtopologyConfig.cpp @@ -0,0 +1,9 @@ +#include "ComCcsdsSubtopologyConfig.hpp" + +namespace ComCcsdsLora { +namespace Allocation { +// This instance can be changed to use a different allocator in the ComCcsdsLora Subtopology +Fw::MallocAllocator mallocatorInstance; +Fw::MemAllocator& memAllocator = mallocatorInstance; +} // namespace Allocation +} // namespace ComCcsdsLora diff --git a/FprimeZephyrReference/project/config/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp b/FprimeZephyrReference/project/config/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp new file mode 100644 index 00000000..3c29eda1 --- /dev/null +++ b/FprimeZephyrReference/project/config/ComCcsdsConfig/ComCcsdsSubtopologyConfig.hpp @@ -0,0 +1,12 @@ +#ifndef COMCCSDSSUBTOPOLOGY_CONFIG_HPP +#define COMCCSDSSUBTOPOLOGY_CONFIG_HPP + +#include "Fw/Types/MallocAllocator.hpp" + +namespace ComCcsdsLora { +namespace Allocation { +extern Fw::MemAllocator& memAllocator; +} +} // namespace ComCcsdsLora + +#endif