fprime/Ref/Top/RefTopology.cpp
Thomas Boyer-Chammard d0246f148b
Add Framer FPP interface, implement FprimeFramer and adapt ComQueue (#3486)
* Initial FprimeFramer and FprimePacketizer

* Code clarity + set up UTs

* Rework ComQueue and ComStub to use DataWithContext

* Add packets to RefPackets.fppi

* Fix ComQueue tests

* Add hotfix to FileDownlink instead of ComQueue

* Fix cancelPacket as well

* Fix ComQueue UTs by removing hotfix

* Refactor DataWithContext to use an FPP object for context instead of Fw.Buffer

* Touch up testing

* Add docs

* more docs

* More docs

* Rework buffer deallocation pattern to pass-through ComQueue

* Update ComStub UTs

* Restore original FileDownlink.cpp

* Formatting tweak

* Update deprecated getSerializeRepr() calls

* deserialization methods

* Fix spelling

* add cast for safety

* CMakefile change

* Bump ComQueue depth

* Update RPI deployment with new Downlink stack

* Rename comQueueIn port to comPktQueueIn

* Fix comQueueIn to comPktQueueIn change

* Remove legacy Svc.Framer

* Fix CMake UTs

* Fix RPI topology config

* Fix FprimeProtocol.fpp module

* Fix namespacing

* Use const reference for FrameContext port

* Review comments EXCEPT port passback refactor

* Rework ComStub with new ByteStream

* New ByteStream - ComInterface model

* Rework TcpClient / TcpServer with new bytestream

* Adapt UDP component for new ByteStream

* Adapt FrameAccumulator for new ByteStream

* Adapt FprimeFramer for new ByteStream

* Update Ref topology with new ByteStream model

* Remove all legacy deallocates from Drivers; reintroduce DEPRECATED model types

* Fix spelling and include error

* More spelling....

* RPI and RpiDemo fixes

* Fix conversion warning on RPI

* static_cast for short int on RPI

* Standardize port names

* Remove legacy Drv types and merge RECV/SEND enum type, delete StreamCrossover

* Update SDDs

* Update SDDs

* Fix ComInterface <-> Framer interfaction, clarify comments and fix annotations

* Switch ComStub from ASSERT to log failure and return buffer

* Add history size check + clarify test handler overrides

* Fix RPI topology to wire comStub on Uplink

* Rename comm to comDriver in RPI topology

* Update communication adapter interface docs
2025-04-29 16:40:36 -07:00

218 lines
8.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ======================================================================
// \title Topology.cpp
// \author mstarch
// \brief cpp file containing the topology instantiation code
//
// \copyright
// Copyright 2009-2022, by the California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged.
// ======================================================================
// Provides access to autocoded functions
#include <Ref/Top/RefTopologyAc.hpp>
// Necessary project-specified types
#include <Fw/Types/MallocAllocator.hpp>
#include <Os/Console.hpp>
#include <Svc/FrameAccumulator/FrameDetector/FprimeFrameDetector.hpp>
#include <Ref/Top/Ports_ComPacketQueueEnumAc.hpp>
// Used for 1Hz synthetic cycling
#include <Os/Mutex.hpp>
// Allows easy reference to objects in FPP/autocoder required namespaces
using namespace Ref;
// Instantiate a system logger that will handle Fw::Logger::log calls
Os::Console logger;
// The reference topology uses a malloc-based allocator for components that need to allocate memory during the
// initialization phase.
Fw::MallocAllocator mallocator;
// The reference topology uses the F´ packet protocol when communicating with the ground and therefore uses the F´
// framing and deframing implementations.
Svc::FrameDetectors::FprimeFrameDetector frameDetector;
// The reference topology divides the incoming clock signal (1Hz) into sub-signals: 1Hz, 1/2Hz, and 1/4Hz and
// zero offset for all the dividers
Svc::RateGroupDriver::DividerSet rateGroupDivisorsSet{{{1, 0}, {2, 0}, {4, 0}}};
// Rate groups may supply a context token to each of the attached children whose purpose is set by the project. The
// reference topology sets each token to zero as these contexts are unused in this project.
U32 rateGroup1Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
U32 rateGroup2Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
U32 rateGroup3Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
Svc::ComQueue::QueueConfigurationTable configurationTable;
// A number of constants are needed for construction of the topology. These are specified here.
enum TopologyConstants {
CMD_SEQ_BUFFER_SIZE = 5 * 1024,
FILE_DOWNLINK_TIMEOUT = 1000,
FILE_DOWNLINK_COOLDOWN = 1000,
FILE_DOWNLINK_CYCLE_TIME = 1000,
FILE_DOWNLINK_FILE_QUEUE_DEPTH = 10,
HEALTH_WATCHDOG_CODE = 0x123,
COMM_PRIORITY = 100,
// Buffer manager for Uplink/Downlink
COMMS_BUFFER_MANAGER_STORE_SIZE = 2048,
COMMS_BUFFER_MANAGER_STORE_COUNT = 20,
COMMS_BUFFER_MANAGER_FILE_STORE_SIZE = 3000,
COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE = 30,
COMMS_BUFFER_MANAGER_ID = 200,
// Buffer manager for Data Products
DP_BUFFER_MANAGER_STORE_SIZE = 10000,
DP_BUFFER_MANAGER_STORE_COUNT = 10,
DP_BUFFER_MANAGER_ID = 300,
};
/**
* \brief configure/setup components in project-specific way
*
* This is a *helper* function which configures/sets up each component requiring project specific input. This includes
* allocating resources, passing-in arguments, etc. This function may be inlined into the topology setup function if
* desired, but is extracted here for clarity.
*/
void configureTopology() {
// Command sequencer needs to allocate memory to hold contents of command sequences
cmdSeq.allocateBuffer(0, mallocator, CMD_SEQ_BUFFER_SIZE);
// Rate group driver needs a divisor list
rateGroupDriverComp.configure(rateGroupDivisorsSet);
// Rate groups require context arrays. Empty for Reference example.
rateGroup1Comp.configure(rateGroup1Context, FW_NUM_ARRAY_ELEMENTS(rateGroup1Context));
rateGroup2Comp.configure(rateGroup2Context, FW_NUM_ARRAY_ELEMENTS(rateGroup2Context));
rateGroup3Comp.configure(rateGroup3Context, FW_NUM_ARRAY_ELEMENTS(rateGroup3Context));
// File downlink requires some project-derived properties.
fileDownlink.configure(FILE_DOWNLINK_TIMEOUT, FILE_DOWNLINK_COOLDOWN, FILE_DOWNLINK_CYCLE_TIME,
FILE_DOWNLINK_FILE_QUEUE_DEPTH);
// Parameter database is configured with a database file name, and that file must be initially read.
prmDb.configure("PrmDb.dat");
prmDb.readParamFile();
// Health is supplied a set of ping entires.
health.setPingEntries(ConfigObjects::Ref_health::pingEntries,
FW_NUM_ARRAY_ELEMENTS(ConfigObjects::Ref_health::pingEntries), HEALTH_WATCHDOG_CODE);
// Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets.
Svc::BufferManager::BufferBins commsBuffMgrBins;
memset(&commsBuffMgrBins, 0, sizeof(commsBuffMgrBins));
commsBuffMgrBins.bins[0].bufferSize = COMMS_BUFFER_MANAGER_STORE_SIZE;
commsBuffMgrBins.bins[0].numBuffers = COMMS_BUFFER_MANAGER_STORE_COUNT;
commsBuffMgrBins.bins[1].bufferSize = COMMS_BUFFER_MANAGER_FILE_STORE_SIZE;
commsBuffMgrBins.bins[1].numBuffers = COMMS_BUFFER_MANAGER_FILE_QUEUE_SIZE;
commsBufferManager.setup(COMMS_BUFFER_MANAGER_ID, 0, mallocator, commsBuffMgrBins);
Svc::BufferManager::BufferBins dpBuffMgrBins;
memset(&dpBuffMgrBins, 0, sizeof(dpBuffMgrBins));
dpBuffMgrBins.bins[0].bufferSize = DP_BUFFER_MANAGER_STORE_SIZE;
dpBuffMgrBins.bins[0].numBuffers = DP_BUFFER_MANAGER_STORE_COUNT;
dpBufferManager.setup(DP_BUFFER_MANAGER_ID, 0, mallocator, dpBuffMgrBins);
frameAccumulator.configure(frameDetector, 1, mallocator, 2048);
Fw::FileNameString dpDir("./DpCat");
Fw::FileNameString dpState("./DpCat/DpState.dat");
// create the DP directory if it doesn't exist
Os::FileSystem::createDirectory(dpDir.toChar());
dpCat.configure(&dpDir,1,dpState,0,mallocator);
dpWriter.configure(dpDir);
// ComQueue configuration
// Events (highest-priority)
configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].depth = 100;
configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].priority = 0;
// Telemetry
configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].depth = 500;
configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].priority = 2;
// File Downlink (first entry after the ComPacket queues = NUM_CONSTANTS)
configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].depth = 100;
configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].priority = 1;
// Allocation identifier is 0 as the MallocAllocator discards it
comQueue.configure(configurationTable, 0, mallocator);
// Note: Uncomment when using Svc:TlmPacketizer
// tlmSend.setPacketList(Ref::Ref_RefPacketsTlmPackets::packetList, Ref::Ref_RefPacketsTlmPackets::omittedChannels, 1);
}
// Public functions for use in main program are namespaced with deployment name Ref
namespace Ref {
void setupTopology(const TopologyState& state) {
// Autocoded initialization. Function provided by autocoder.
initComponents(state);
// Autocoded id setup. Function provided by autocoder.
setBaseIds();
// Autocoded connection wiring. Function provided by autocoder.
connectComponents();
// Autocoded command registration. Function provided by autocoder.
regCommands();
// Autocoded configuration. Function provided by autocoder.
configComponents(state);
if (state.hostname != nullptr && state.port != 0) {
comDriver.configure(state.hostname, state.port);
}
// Project-specific component configuration. Function provided above. May be inlined, if desired.
configureTopology();
// Autocoded parameter loading. Function provided by autocoder.
loadParameters();
// Autocoded task kick-off (active components). Function provided by autocoder.
startTasks(state);
// Startup TLM and Config verbosity for Versions
version.config(true);
// Initialize socket client communication if and only if there is a valid specification
if (state.hostname != nullptr && state.port != 0) {
Os::TaskString name("ReceiveTask");
// Uplink is configured for receive so a socket task is started
comDriver.start(name, COMM_PRIORITY, Default::STACK_SIZE);
}
}
// Variables used for cycle simulation
Os::Mutex cycleLock;
volatile bool cycleFlag = true;
void startSimulatedCycle(Fw::TimeInterval interval) {
cycleLock.lock();
bool cycling = cycleFlag;
cycleLock.unLock();
// Main loop
while (cycling) {
Ref::blockDrv.callIsr();
Os::Task::delay(interval);
cycleLock.lock();
cycling = cycleFlag;
cycleLock.unLock();
}
}
void stopSimulatedCycle() {
cycleLock.lock();
cycleFlag = false;
cycleLock.unLock();
}
void teardownTopology(const TopologyState& state) {
// Autocoded (active component) task clean-up. Functions provided by topology autocoder.
stopTasks(state);
freeThreads(state);
// Other task clean-up.
comDriver.stop();
(void)comDriver.join();
// Resource deallocation
cmdSeq.deallocateBuffer(mallocator);
commsBufferManager.cleanup();
frameAccumulator.cleanup();
}
} // namespace Ref