Implementation of the offsets in the RateGroupDriver (#2166)

* Implementation of the offsets

* Fix comment

* Fix spell error

* Changing configure interface by addind DividersSet

* Update RPI topology

* Removing numDivisors from call

* Removing memset clear as the constructor handles zeroed initialization

* Fixing ASSERT and removing m_numDivisors

* Renaming divisersSet to diviserSet

---------

Co-authored-by: Simone Morettini <simone.morettini@redwirespaceeurope.com>
Co-authored-by: Michael D Starch <Michael.D.Starch@jpl.nasa.gov>
This commit is contained in:
Simone Morettini 2023-10-27 00:09:47 +02:00 committed by GitHub
parent 9633049549
commit 36a07dd967
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 69 additions and 59 deletions

View File

@ -291,13 +291,12 @@ module RPI {
{
phase Fpp.ToCpp.Phases.configObjects """
NATIVE_INT_TYPE rgDivs[Svc::RateGroupDriver::DIVIDER_SIZE] = { 1, 10, 0 };
Svc::RateGroupDriver::DividerSet rgDivs{{{1, 0}, {10, 0}, {0, 0}}};
"""
phase Fpp.ToCpp.Phases.configComponents """
rateGroupDriverComp.configure(
ConfigObjects::rateGroupDriverComp::rgDivs,
FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroupDriverComp::rgDivs)
ConfigObjects::rateGroupDriverComp::rgDivs
);
"""
}

View File

@ -35,8 +35,9 @@ Fw::MallocAllocator mallocator;
Svc::FprimeFraming framing;
Svc::FprimeDeframing deframing;
// The reference topology divides the incoming clock signal (1Hz) into sub-signals: 1Hz, 1/2Hz, and 1/4Hz
NATIVE_INT_TYPE rateGroupDivisors[Svc::RateGroupDriver::DIVIDER_SIZE] = {1, 2, 4};
// 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.
@ -87,7 +88,7 @@ void configureTopology() {
cmdSeq.allocateBuffer(0, mallocator, CMD_SEQ_BUFFER_SIZE);
// Rate group driver needs a divisor list
rateGroupDriverComp.configure(rateGroupDivisors, FW_NUM_ARRAY_ELEMENTS(rateGroupDivisors));
rateGroupDriverComp.configure(rateGroupDivisorsSet);
// Rate groups require context arrays. Empty for Reference example.
rateGroup1Comp.configure(rateGroup1Context, FW_NUM_ARRAY_ELEMENTS(rateGroup1Context));

View File

@ -1,6 +1,9 @@
This component takes a primary clock tick in the system and divides it down to drive output ports.
Constructor arguments define the divisors for each port. The output ports are meant to be connected
to the input ports of rate groups to drive them at the correct rate.
This component takes a primary clock tick in the system and divides it down to drive output ports.
Constructor arguments define the divisors for each port.
The dividers argument define the divisors for each port as well as an offset to allow the triggering
for the rate group to be offset from each other.
The output ports are meant to be connected to the input ports of rate groups to drive them at the
correct rate.
RateGroupDriverComponentAi.xml - XML definition of rate group driver component
RateGroupDriverImpl.hpp(.cpp) - Implementation for rate group driver
RateGroupDriverImpl.hpp(.cpp) - Implementation for rate group driver

View File

@ -8,59 +8,52 @@ namespace Svc {
RateGroupDriver::RateGroupDriver(const char* compName) :
RateGroupDriverComponentBase(compName),
m_numDividers(0),m_ticks(0),m_rollover(1) {
m_ticks(0),m_rollover(1),m_configured(false) {
}
void RateGroupDriver::configure(NATIVE_INT_TYPE dividers[], NATIVE_INT_TYPE numDividers)
void RateGroupDriver::configure(const DividerSet& dividerSet)
{
// check arguments
FW_ASSERT(dividers);
FW_ASSERT(numDividers);
this->m_numDividers = numDividers;
FW_ASSERT(numDividers <= static_cast<NATIVE_INT_TYPE>(FW_NUM_ARRAY_ELEMENTS(this->m_dividers)),
numDividers,
static_cast<NATIVE_INT_TYPE>(FW_NUM_ARRAY_ELEMENTS(this->m_dividers)));
FW_ASSERT(dividerSet.dividers);
// verify port/table size matches
FW_ASSERT(FW_NUM_ARRAY_ELEMENTS(this->m_dividers) == this->getNum_CycleOut_OutputPorts(),
static_cast<NATIVE_INT_TYPE>(FW_NUM_ARRAY_ELEMENTS(this->m_dividers)),
this->getNum_CycleOut_OutputPorts());
// clear table
::memset(this->m_dividers,0,sizeof(this->m_dividers));
// copy provided array of dividers
for (NATIVE_INT_TYPE entry = 0; entry < numDividers; entry++) {
this->m_dividers[entry] = dividers[entry];
for (NATIVE_UINT_TYPE entry = 0; entry < RateGroupDriver::DIVIDER_SIZE; entry++) {
// A port with an offset equal or bigger than the divisor is not accepted because it would never be called
FW_ASSERT((dividerSet.dividers[entry].offset==0)||(dividerSet.dividers[entry].offset < dividerSet.dividers[entry].divisor),
dividerSet.dividers[entry].offset,
dividerSet.dividers[entry].divisor);
this->m_dividers[entry] = dividerSet.dividers[entry];
// rollover value should be product of all dividers to make sure integer rollover doesn't jump cycles
// only use non-zero dividers
if (dividers[entry] != 0) {
this->m_rollover *= dividers[entry];
if (dividerSet.dividers[entry].divisor != 0) {
this->m_rollover *= dividerSet.dividers[entry].divisor;
}
}
this->m_configured = true;
}
RateGroupDriver::~RateGroupDriver() {
}
void RateGroupDriver::init(NATIVE_INT_TYPE instanceId) {
RateGroupDriverComponentBase::init(instanceId);
}
void RateGroupDriver::CycleIn_handler(NATIVE_INT_TYPE portNum, Svc::TimerVal& cycleStart) {
// Make sure that the dividers have been configured:
// If this asserts, add the configure() call to initialization.
FW_ASSERT(this->m_numDividers);
FW_ASSERT(this->m_configured);
// Loop through each divider. For a given port, the port will be called when the divider value
// divides evenly into the number of ticks. For example, if the divider value for a port is 4,
// it would be called every fourth invocation of the CycleIn port.
for (NATIVE_INT_TYPE entry = 0; entry < this->m_numDividers; entry++) {
if (this->m_dividers[entry] != 0) {
for (NATIVE_UINT_TYPE entry = 0; entry < RateGroupDriver::DIVIDER_SIZE; entry++) {
if (this->m_dividers[entry].divisor != 0) {
if (this->isConnected_CycleOut_OutputPort(entry)) {
if ((this->m_ticks % this->m_dividers[entry]) == 0) {
if ((this->m_ticks % this->m_dividers[entry].divisor) == this->m_dividers[entry].offset) {
this->CycleOut_out(entry,cycleStart);
}
}

View File

@ -33,6 +33,31 @@ namespace Svc {
class RateGroupDriver : public RateGroupDriverComponentBase {
public:
//! Size of the divider table, provided as a constants to users passing the table in
static const NATIVE_UINT_TYPE DIVIDER_SIZE = NUM_CYCLEOUT_OUTPUT_PORTS;
//! \class Divider
//! \brief Struct describing a divider
struct Divider{
//! Initializes divisor and offset to 0 (unused)
Divider() : divisor(0), offset(0)
{}
//! Initializes divisor and offset to passed-in pair
Divider(NATIVE_INT_TYPE divisorIn, NATIVE_INT_TYPE offsetIn) :
divisor(divisorIn), offset(offsetIn)
{}
//! Divisor
NATIVE_INT_TYPE divisor;
//! Offset
NATIVE_INT_TYPE offset;
};
//! \class DividerSet
//! \brief Struct containing an array of dividers
struct DividerSet {
//! Dividers
Divider dividers[Svc::RateGroupDriver::DIVIDER_SIZE];
};
//! \brief RateGroupDriver constructor
//!
@ -43,17 +68,10 @@ namespace Svc {
//!
RateGroupDriver(const char* compName);
//! \brief RateGroupDriver initialization function
//!
//! The init() function initializes the autocoded base class
void init(NATIVE_INT_TYPE instanceId = 0);
//! \brief RateGroupDriver configuration function
//! \param dividers array of integers used to divide down input tick
//! \param numDividers size of dividers array
//! \param dividersSet set of dividers used to divide down input tick
void configure(NATIVE_INT_TYPE dividers[], NATIVE_INT_TYPE numDividers);
void configure(const DividerSet& dividersSet);
//! \brief RateGroupDriverImpl destructor
@ -66,18 +84,16 @@ namespace Svc {
void CycleIn_handler(NATIVE_INT_TYPE portNum, Svc::TimerVal& cycleStart);
//! divider array
NATIVE_INT_TYPE m_dividers[NUM_CYCLEOUT_OUTPUT_PORTS];
//! size of divider array
NATIVE_INT_TYPE m_numDividers;
Divider m_dividers[NUM_CYCLEOUT_OUTPUT_PORTS];
//! tick counter
NATIVE_INT_TYPE m_ticks;
//! rollover counter
NATIVE_INT_TYPE m_rollover;
public:
//! Size of the divider table, provided as a constants to users passing the table in
static const NATIVE_UINT_TYPE DIVIDER_SIZE = NUM_CYCLEOUT_OUTPUT_PORTS;
//! has the configure method been called
bool m_configured;
};
}

View File

@ -37,7 +37,7 @@ namespace Svc {
this->m_portCalls[portNum] = true;
}
void RateGroupDriverImplTester::runSchedNominal(NATIVE_INT_TYPE dividers[], NATIVE_INT_TYPE numDividers) {
void RateGroupDriverImplTester::runSchedNominal(Svc::RateGroupDriver::DividerSet dividersSet, NATIVE_INT_TYPE numDividers) {
TEST_CASE(106.1.1,"Nominal Execution");
COMMENT(
@ -48,7 +48,7 @@ namespace Svc {
NATIVE_INT_TYPE expected_rollover = 1;
for (NATIVE_INT_TYPE div = 0; div < numDividers; div++) {
expected_rollover *= dividers[div];
expected_rollover *= dividersSet.dividers[div].divisor;
}
ASSERT_EQ(expected_rollover,this->m_impl.m_rollover);
@ -65,7 +65,7 @@ namespace Svc {
ASSERT_EQ((cycle+1)%expected_rollover,this->m_impl.m_ticks);
// check for various intervals
for (NATIVE_INT_TYPE div = 0; div < numDividers; div++) {
if (cycle % dividers[div] == 0) {
if (cycle % dividersSet.dividers[div].divisor == dividersSet.dividers[div].offset) {
EXPECT_TRUE(this->m_portCalls[div]);
} else {
EXPECT_FALSE(this->m_portCalls[div]);

View File

@ -20,7 +20,7 @@ namespace Svc {
void init(NATIVE_INT_TYPE instance = 0);
void runSchedNominal(NATIVE_INT_TYPE dividers[], NATIVE_INT_TYPE numDividers);
void runSchedNominal(Svc::RateGroupDriver::DividerSet dividersSet, NATIVE_INT_TYPE numDividers);
private:

View File

@ -31,10 +31,10 @@ void connectPorts(Svc::RateGroupDriver& impl, Svc::RateGroupDriverImplTester& te
TEST(RateGroupDriverTest,NominalSchedule) {
NATIVE_INT_TYPE dividers[] = {1,2,3};
Svc::RateGroupDriver::DividerSet dividersSet{{{1, 0}, {2, 1}, {3, 0}}};
Svc::RateGroupDriver impl("RateGroupDriver");
impl.configure(dividers,FW_NUM_ARRAY_ELEMENTS(dividers));
impl.configure(dividersSet);
Svc::RateGroupDriverImplTester tester(impl);
@ -44,7 +44,7 @@ TEST(RateGroupDriverTest,NominalSchedule) {
// connect ports
connectPorts(impl,tester);
tester.runSchedNominal(dividers,FW_NUM_ARRAY_ELEMENTS(dividers));
tester.runSchedNominal(dividersSet,FW_NUM_ARRAY_ELEMENTS(dividersSet.dividers));
}
@ -53,5 +53,3 @@ int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}