Skip to content

Commit

Permalink
Data product framework support (#2485)
Browse files Browse the repository at this point in the history
* Pull in framework changes from data-products

* Pull in framework changes from data-products

* Pull in updates from data-products branch

* Update fpp version

* Fix spelling

* Update spell check

* Add log archiving to FppTest CI

* Update fpp version

* Revise DpContainer

Remove unused code

* Revise data products design

* Revise Fw/Dp

Fix mistake in built-in Python autocoder types

* Revise dp container members

Add _m prefix

* Update fpp version

* Update fpp version

* Update fpp version

* Revise DpContainer and unit tests

Don't fail an assertion on bad serial input

* Pull in changes from data-products branch

* Revise DpContainer

Revise handling of serialize status

---------

Co-authored-by: thomas-bc <thomas.boyerchammard@gmail.com>
  • Loading branch information
bocchino and thomas-bc authored Feb 16, 2024
1 parent 75b30ad commit c6f8e7b
Show file tree
Hide file tree
Showing 47 changed files with 3,377 additions and 26 deletions.
5 changes: 5 additions & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ dawbarton
DDDTHH
ddl
ddmm
dealloc
Debian
deconstructor
Deerin
Expand Down Expand Up @@ -265,6 +266,8 @@ doxyrules
doxysearch
Doxywizard
dpi
DPMANAGER
DPWRITER
DRAINBUFFERS
drv
dsdl
Expand All @@ -285,6 +288,7 @@ EGB
EHAs
elist
ELOG
Elts
emoji
endcode
endcond
Expand Down Expand Up @@ -389,6 +393,7 @@ getquaternion
gettime
gettimeofday
getty
getu
ghprb
gitmodules
gmock
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/fpp-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,10 @@ jobs:
run: |
fprime-util check
shell: bash
- name: "Archive Logs"
uses: actions/upload-artifact@v3
if: always()
with:
name: FppTest-Logs
path: ./FppTest/build-fprime-automatic-native-ut/Testing/Temporary/*.log
retention-days: 5
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ def _get_args_sum_string(self, obj):
"bool",
"FwBuffSizeType",
"FwChanIdType",
"FwDpIdType",
"FwDpPriorityType",
"FwEnumStoreType",
"FwEventIdType",
"FwIndexType",
Expand Down
2 changes: 2 additions & 0 deletions Autocoders/Python/src/fprime_ac/utils/TypesList.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
port_types_list = [
"FwBuffSizeType",
"FwChanIdType",
"FwDpIdType",
"FwDpPriorityType",
"FwEnumStoreType",
"FwEventIdType",
"FwIndexType",
Expand Down
15 changes: 7 additions & 8 deletions FppTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,16 @@ project(FppTest C CXX)
include("${CMAKE_CURRENT_LIST_DIR}/../cmake/FPrime.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/../cmake/FPrime-Code.cmake")

if (BUILD_TESTING AND NOT __FPRIME_NO_UT_GEN__)
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/enum/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/array/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/struct/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/component/")
endif()

add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/array/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/component/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/dp/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/enum/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/struct/")
set(SOURCE_FILES "source.cpp")
set(MOD_DEPS
${PROJECT_NAME}/enum
${PROJECT_NAME}/array
${PROJECT_NAME}/dp
${PROJECT_NAME}/enum
${PROJECT_NAME}/struct
${PROJECT_NAME}/component/empty
${PROJECT_NAME}/component/active
Expand Down
15 changes: 15 additions & 0 deletions FppTest/dp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
set(SOURCE_FILES
"${CMAKE_CURRENT_LIST_DIR}/DpTest.cpp"
"${CMAKE_CURRENT_LIST_DIR}/DpTest.fpp"
)

register_fprime_module()

set(UT_SOURCE_FILES
"${CMAKE_CURRENT_LIST_DIR}/DpTest.fpp"
"${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp"
"${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp"
"${CMAKE_CURRENT_LIST_DIR}/test/ut/TesterHelpers.cpp"
)
set(UT_MOD_DEPS STest)
register_fprime_ut()
188 changes: 188 additions & 0 deletions FppTest/dp/DpTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// ======================================================================
// \title DpTest.cpp
// \author bocchino
// \brief cpp file for DpTest component implementation class
// ======================================================================

#include <cstdio>

#include "FppTest/dp/DpTest.hpp"
#include "Fw/Types/Assert.hpp"

namespace FppTest {

// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------

DpTest ::DpTest(const char* const compName,
U32 u32RecordData,
U16 dataRecordData,
const U8ArrayRecordData& u8ArrayRecordData,
const U32ArrayRecordData& u32ArrayRecordData,
const DataArrayRecordData& dataArrayRecordData)
: DpTestComponentBase(compName),
u32RecordData(u32RecordData),
dataRecordData(dataRecordData),
u8ArrayRecordData(u8ArrayRecordData),
u32ArrayRecordData(u32ArrayRecordData),
dataArrayRecordData(dataArrayRecordData),
sendTime(Fw::ZERO_TIME) {}

void DpTest ::init(const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance) {
DpTestComponentBase::init(queueDepth, instance);
}

DpTest ::~DpTest() {}

// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------

void DpTest::schedIn_handler(const NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context) {
// Request a buffer for Container 1
this->dpRequest_Container1(CONTAINER_1_DATA_SIZE);
// Request a buffer for Container 2
this->dpRequest_Container2(CONTAINER_2_DATA_SIZE);
// Request a buffer for Container 3
this->dpRequest_Container3(CONTAINER_3_DATA_SIZE);
// Request a buffer for Container 4
this->dpRequest_Container4(CONTAINER_4_DATA_SIZE);
// Request a buffer for Container 5
this->dpRequest_Container5(CONTAINER_5_DATA_SIZE);
// Get a buffer for Container 1
{
DpContainer container;
Fw::Success status = this->dpGet_Container1(CONTAINER_1_DATA_SIZE, container);
FW_ASSERT(status == Fw::Success::SUCCESS, status);
// Check the container
this->checkContainer(container, ContainerId::Container1, CONTAINER_1_PACKET_SIZE);
}
// Get a buffer for Container 2
{
DpContainer container;
Fw::Success status = this->dpGet_Container2(CONTAINER_2_DATA_SIZE, container);
FW_ASSERT(status == Fw::Success::SUCCESS);
// Check the container
this->checkContainer(container, ContainerId::Container2, CONTAINER_2_PACKET_SIZE);
}
// Get a buffer for Container 3
{
DpContainer container;
Fw::Success status = this->dpGet_Container3(CONTAINER_3_DATA_SIZE, container);
// This one should fail
FW_ASSERT(status == Fw::Success::FAILURE);
}
// Get a buffer for Container 4
{
DpContainer container;
Fw::Success status = this->dpGet_Container4(CONTAINER_4_DATA_SIZE, container);
FW_ASSERT(status == Fw::Success::SUCCESS);
// Check the container
this->checkContainer(container, ContainerId::Container4, CONTAINER_4_PACKET_SIZE);
}
// Get a buffer for Container 5
{
DpContainer container;
Fw::Success status = this->dpGet_Container5(CONTAINER_5_DATA_SIZE, container);
FW_ASSERT(status == Fw::Success::SUCCESS);
// Check the container
this->checkContainer(container, ContainerId::Container5, CONTAINER_5_PACKET_SIZE);
}
}

// ----------------------------------------------------------------------
// Data product handler implementations
// ----------------------------------------------------------------------

void DpTest ::dpRecv_Container1_handler(DpContainer& container, Fw::Success::T status) {
if (status == Fw::Success::SUCCESS) {
auto serializeStatus = Fw::FW_SERIALIZE_OK;
for (FwSizeType i = 0; i < CONTAINER_1_DATA_SIZE; ++i) {
serializeStatus = container.serializeRecord_U32Record(this->u32RecordData);
if (serializeStatus == Fw::FW_SERIALIZE_NO_ROOM_LEFT) {
break;
}
FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, status);
}
// Use the time stamp from the time get port
this->dpSend(container);
}
}

void DpTest ::dpRecv_Container2_handler(DpContainer& container, Fw::Success::T status) {
if (status == Fw::Success::SUCCESS) {
const DpTest_Data dataRecord(this->dataRecordData);
auto serializeStatus = Fw::FW_SERIALIZE_OK;
for (FwSizeType i = 0; i < CONTAINER_2_DATA_SIZE; ++i) {
serializeStatus = container.serializeRecord_DataRecord(dataRecord);
if (serializeStatus == Fw::FW_SERIALIZE_NO_ROOM_LEFT) {
break;
}
FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, status);
}
// Provide an explicit time stamp
this->dpSend(container, this->sendTime);
}
}

void DpTest ::dpRecv_Container3_handler(DpContainer& container, Fw::Success::T status) {
if (status == Fw::Success::SUCCESS) {
auto serializeStatus = Fw::FW_SERIALIZE_OK;
for (FwSizeType i = 0; i < CONTAINER_3_DATA_SIZE; ++i) {
serializeStatus =
container.serializeRecord_U8ArrayRecord(this->u8ArrayRecordData.data(), this->u8ArrayRecordData.size());
if (serializeStatus == Fw::FW_SERIALIZE_NO_ROOM_LEFT) {
break;
}
FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, status);
}
// Use the time stamp from the time get port
this->dpSend(container);
}
}

void DpTest ::dpRecv_Container4_handler(DpContainer& container, Fw::Success::T status) {
if (status == Fw::Success::SUCCESS) {
auto serializeStatus = Fw::FW_SERIALIZE_OK;
for (FwSizeType i = 0; i < CONTAINER_4_DATA_SIZE; ++i) {
serializeStatus = container.serializeRecord_U32ArrayRecord(this->u32ArrayRecordData.data(),
this->u32ArrayRecordData.size());
if (serializeStatus == Fw::FW_SERIALIZE_NO_ROOM_LEFT) {
break;
}
FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, status);
}
// Use the time stamp from the time get port
this->dpSend(container);
}
}

void DpTest ::dpRecv_Container5_handler(DpContainer& container, Fw::Success::T status) {
if (status == Fw::Success::SUCCESS) {
auto serializeStatus = Fw::FW_SERIALIZE_OK;
for (FwSizeType i = 0; i < CONTAINER_5_DATA_SIZE; ++i) {
serializeStatus = container.serializeRecord_DataArrayRecord(this->dataArrayRecordData.data(),
this->dataArrayRecordData.size());
if (serializeStatus == Fw::FW_SERIALIZE_NO_ROOM_LEFT) {
break;
}
FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, status);
}
// Use the time stamp from the time get port
this->dpSend(container);
}
}

// ----------------------------------------------------------------------
// Private helper functions
// ----------------------------------------------------------------------

void DpTest::checkContainer(const DpContainer& container, FwDpIdType localId, FwSizeType size) const {
FW_ASSERT(container.getBaseId() == this->getIdBase(), container.getBaseId(), this->getIdBase());
FW_ASSERT(container.getId() == container.getBaseId() + localId, container.getId(), container.getBaseId(),
ContainerId::Container1);
FW_ASSERT(container.getBuffer().getSize() == size, container.getBuffer().getSize(), size);
}

} // end namespace FppTest
82 changes: 82 additions & 0 deletions FppTest/dp/DpTest.fpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
module FppTest {

@ A component for testing data product code gen
active component DpTest {

# ----------------------------------------------------------------------
# Types
# ----------------------------------------------------------------------

@ Data for a DataRecord
struct Data {
@ A U16 field
u16Field: U16
}

# ----------------------------------------------------------------------
# Special ports
# ----------------------------------------------------------------------

@ Data product get port
product get port productGetOut

@ Data product request port
product request port productRequestOut

@ Data product receive port
async product recv port productRecvIn

@ Data product send port
product send port productSendOut

@ Time get port
time get port timeGetOut

# ----------------------------------------------------------------------
# General ports
# ----------------------------------------------------------------------

@ A schedIn port to run the data product generation
async input port schedIn: Svc.Sched

# ----------------------------------------------------------------------
# Records
# ----------------------------------------------------------------------

@ Record 1
product record U32Record: U32 id 100

@ Record 2
product record DataRecord: Data id 200

@ Record 3
product record U8ArrayRecord: U8 array id 300

@ Record 4
product record U32ArrayRecord: U32 array id 400

@ Record 5
product record DataArrayRecord: Data array id 500

# ----------------------------------------------------------------------
# Containers
# ----------------------------------------------------------------------

@ Container 1
product container Container1 id 100 default priority 10

@ Container 2
product container Container2 id 200 default priority 20

@ Container 3
product container Container3 id 300 default priority 30

@ Container 4
product container Container4 id 400 default priority 40

@ Container 5
product container Container5 id 500 default priority 50

}

}
Loading

0 comments on commit c6f8e7b

Please sign in to comment.