Skip to content

Commit

Permalink
Implementation of the offsets in the RateGroupDriver (#2166)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: Michael D Starch <[email protected]>
  • Loading branch information
3 people authored Oct 26, 2023
1 parent 9633049 commit 36a07dd
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 59 deletions.
7 changes: 3 additions & 4 deletions RPI/Top/instances.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
"""
}
Expand Down
7 changes: 4 additions & 3 deletions Ref/Top/RefTopology.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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));
Expand Down
11 changes: 7 additions & 4 deletions Svc/RateGroupDriver/README
Original file line number Diff line number Diff line change
@@ -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
39 changes: 16 additions & 23 deletions Svc/RateGroupDriver/RateGroupDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
48 changes: 32 additions & 16 deletions Svc/RateGroupDriver/RateGroupDriver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
//!
Expand All @@ -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

Expand All @@ -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;
};

}
Expand Down
6 changes: 3 additions & 3 deletions Svc/RateGroupDriver/test/ut/RateGroupDriverImplTester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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);
Expand All @@ -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]);
Expand Down
2 changes: 1 addition & 1 deletion Svc/RateGroupDriver/test/ut/RateGroupDriverImplTester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
8 changes: 3 additions & 5 deletions Svc/RateGroupDriver/test/ut/RateGroupDriverTester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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));

}

Expand All @@ -53,5 +53,3 @@ int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}


0 comments on commit 36a07dd

Please sign in to comment.