diff --git a/.gitignore b/.gitignore index 2a5fb5771e4..4153d42d9e1 100644 --- a/.gitignore +++ b/.gitignore @@ -74,3 +74,6 @@ GTestBase.* /Fw/Python/src/fprime.egg-info /Gds/src/fprime_gds.egg-info **/DefaultDict/serializable/* + +# Clone CHESS-mission/pusopen as "Lib" in fprime root - Due to license restriction with PUSOpen +Lib # disable to allow VSCode to index Lib file \ No newline at end of file diff --git a/Drv/SocketIpDriver/SocketHelper.cpp b/Drv/SocketIpDriver/SocketHelper.cpp index 03697337344..bba58f317d6 100644 --- a/Drv/SocketIpDriver/SocketHelper.cpp +++ b/Drv/SocketIpDriver/SocketHelper.cpp @@ -29,7 +29,7 @@ #include #include #include -#elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN || TGT_OS_TYPE_FREERTOS_SIM +#elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN #include #include #include diff --git a/Drv/SocketIpDriver/SocketIpDriverComponentImpl.hpp b/Drv/SocketIpDriver/SocketIpDriverComponentImpl.hpp index fa54bf13625..60c10fdca4c 100644 --- a/Drv/SocketIpDriver/SocketIpDriverComponentImpl.hpp +++ b/Drv/SocketIpDriver/SocketIpDriverComponentImpl.hpp @@ -24,7 +24,7 @@ // Includes for the IP layer #ifdef TGT_OS_TYPE_VXWORKS #include -#elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN || TGT_OS_TYPE_FREERTOS_SIM +#elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN #include #else #error OS not supported for IP Socket Communications diff --git a/Fw/Com/ComBuffer.cpp b/Fw/Com/ComBuffer.cpp index 41d36c442a8..acd9a663bea 100644 --- a/Fw/Com/ComBuffer.cpp +++ b/Fw/Com/ComBuffer.cpp @@ -5,7 +5,7 @@ namespace Fw { ComBuffer::ComBuffer(const U8 *args, NATIVE_UINT_TYPE size) { SerializeStatus stat = SerializeBufferBase::setBuff(args,size); - FW_ASSERT(FW_SERIALIZE_OK == stat,static_cast(stat)); + FW_ASSERT(FW_SERIALIZE_OK == stat, static_cast(stat)); } ComBuffer::ComBuffer() { diff --git a/Fw/Types/Assert.cpp b/Fw/Types/Assert.cpp index 7b2e169120a..5a997954b8d 100644 --- a/Fw/Types/Assert.cpp +++ b/Fw/Types/Assert.cpp @@ -12,9 +12,9 @@ #else #if FW_ASSERT_LEVEL == FW_FILEID_ASSERT -#define fileIdFs "Assert file ID 0x%08X:%d " +#define fileIdFs "============= Assert file ID 0x%08X:%d =============" #else -#define fileIdFs "Assert file \"%s\":%d " +#define fileIdFs "============= Assert file \"%s\":%d =============" #endif namespace Fw { diff --git a/Gds/bin/helpers/run_tool.sh b/Gds/bin/helpers/run_tool.sh index e7b78e8cd81..45b34bfd019 100755 --- a/Gds/bin/helpers/run_tool.sh +++ b/Gds/bin/helpers/run_tool.sh @@ -34,4 +34,4 @@ export OUTPUT_DIR="`make -f ${BUILD_ROOT}/mk/makefiles/build_vars.mk BUILD=$NATI echo "OUTPUT_DIR: ${OUTPUT_DIR}" export PYTHONPATH="${BUILD_ROOT}/Fw/Python/src:${BUILD_ROOT}/Gds/src" -python -m fprime_gds.common.tools."${TOOL}" "$@" +python3 -m fprime_gds.common.tools."${TOOL}" "$@" diff --git a/Ref/PingReceiver/PingReceiverComponentImpl.cpp b/Ref/PingReceiver/PingReceiverComponentImpl.cpp index 8d6e5e68695..b7d46deb2ec 100644 --- a/Ref/PingReceiver/PingReceiverComponentImpl.cpp +++ b/Ref/PingReceiver/PingReceiverComponentImpl.cpp @@ -15,7 +15,6 @@ #include "Fw/Types/BasicTypes.hpp" namespace Ref { - // ---------------------------------------------------------------------- // Construction, initialization, and destruction // ---------------------------------------------------------------------- @@ -53,7 +52,7 @@ namespace Ref { U32 key ) { - //this->log_DIAGNOSTIC_PR_PingReceived(key); + this->log_DIAGNOSTIC_PR_PingReceived(key); this->tlmWrite_PR_NumPings(this->m_pingsRecvd++); if (not this->m_inhibitPings) { PingOut_out(0,key); diff --git a/Ref/PingReceiver/PingReceiverComponentImpl.hpp b/Ref/PingReceiver/PingReceiverComponentImpl.hpp index 053604ef8a1..458a7b25af0 100644 --- a/Ref/PingReceiver/PingReceiverComponentImpl.hpp +++ b/Ref/PingReceiver/PingReceiverComponentImpl.hpp @@ -64,8 +64,6 @@ namespace Ref { bool m_inhibitPings; U32 m_pingsRecvd; - - }; } // end namespace Ref diff --git a/Svc/ActiveLogger/ActiveLoggerComponentAi.xml b/Svc/ActiveLogger/ActiveLoggerComponentAi.xml index 729ab343b1d..a889671a664 100644 --- a/Svc/ActiveLogger/ActiveLoggerComponentAi.xml +++ b/Svc/ActiveLogger/ActiveLoggerComponentAi.xml @@ -18,7 +18,7 @@ Telemetry input port - + Telemetry output port diff --git a/Svc/ActiveLogger/ActiveLoggerImpl.cpp b/Svc/ActiveLogger/ActiveLoggerImpl.cpp index d32a242da0d..7dabc91fc18 100644 --- a/Svc/ActiveLogger/ActiveLoggerImpl.cpp +++ b/Svc/ActiveLogger/ActiveLoggerImpl.cpp @@ -64,6 +64,9 @@ namespace Svc { } void ActiveLoggerImpl::LogRecv_handler(NATIVE_INT_TYPE portNum, FwEventIdType id, Fw::Time &timeTag, Fw::LogSeverity severity, Fw::LogBuffer &args) { + // Filter event for demo + //if (id != 0x2a) + // return; // make sure ID is not zero. Zero is reserved for ID filter. FW_ASSERT(id != 0); @@ -187,15 +190,22 @@ namespace Svc { FW_ASSERT(0,static_cast(severity)); return; } - - if (this->isConnected_PktSend_OutputPort(0)) { - this->PktSend_out(0, this->m_comBuffer,0); - } - // redirect event through event output + // Send event to EventSequence if (this->isConnected_LogSend_OutputPort(0)) { this->LogSend_out(0, id, timeTag, static_cast(severity) , args); + } + +#ifdef _GDS + if (this->isConnected_PktSend_OutputPort(0)) { + this->PktSend_out(0, this->m_comBuffer,0); + } +#elif defined _PUS + // Send event to GroundInterface + if (this->isConnected_LogSend_OutputPort(1)) { + this->LogSend_out(1, id, timeTag, static_cast(severity) , args); } +#endif } void ActiveLoggerImpl::ALOG_SET_EVENT_REPORT_FILTER_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, InputFilterLevel FilterLevel, InputFilterEnabled FilterEnable) { diff --git a/Svc/ActiveLogger/docs/sdd.md b/Svc/ActiveLogger/docs/sdd.md index 8543d60bd61..269da319fd9 100644 --- a/Svc/ActiveLogger/docs/sdd.md +++ b/Svc/ActiveLogger/docs/sdd.md @@ -93,7 +93,7 @@ Document | Link -------- | ---- Design Checklist | [Link](Checklist_Design.xlsx) Code Checklist | [Link](Checklist_Code.xlsx) -Unit Test Checklist | [Link](Checklist_Unit_test.xlsx) +Unit Test Checklist | [Link](Checklist_Unit_Test.xls) ## 6. Unit Testing diff --git a/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp b/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp index db4f26c0109..e77c5eae92c 100644 --- a/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp +++ b/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp @@ -94,7 +94,7 @@ namespace Svc { stat = snprintf(textStr, FW_INTERNAL_INTERFACE_STRING_MAX_SIZE, - "EVENT: (%d) (%04d-%02d-%02dT%02d:%02d:%02d.%03u) %s: %s\n", + "EVENT: (0x%x) (%04d-%02d-%02dT%02d:%02d:%02d.%03u) %s: %s\n", id, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,tm.tm_sec,timeTag.getUSeconds(), severityString,text.toChar()); @@ -103,7 +103,7 @@ namespace Svc { stat = snprintf(textStr, FW_INTERNAL_INTERFACE_STRING_MAX_SIZE, - "EVENT: (%d) (%d:%d,%d) %s: %s\n", + "EVENT: (0x%x) (%d:%d,%d) %s: %s\n", id,timeTag.getTimeBase(),timeTag.getSeconds(),timeTag.getUSeconds(),severityString,text.toChar()); } diff --git a/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp b/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp index 1120d8a07f8..7611fa22d44 100644 --- a/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp +++ b/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp @@ -85,7 +85,7 @@ namespace Svc { arg1,arg2,arg3,arg4,arg5,arg6); } else { // Can't assert, what else can we do? Maybe somebody will see it. - Fw::Logger::logMsg("Svc::AssertFatalAdapter not registered!\n"); + Fw::Logger::logMsg("============= Svc::AssertFatalAdapter not registered! =============\n"); assert(0); } } diff --git a/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp b/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp index 0aaf2c26ff8..af4c55ce46f 100644 --- a/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp +++ b/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp @@ -25,8 +25,14 @@ namespace Svc { void FatalHandlerComponentImpl::FatalReceive_handler( const NATIVE_INT_TYPE portNum, FwEventIdType Id) { + + // @todo REMOVE FOR DEBUG PURPOSE + if(Id == 0x16a) { // HLTH_PING_LATE - when EPS not connected + return; + } + // for **nix, delay then exit with error code - Fw::Logger::logMsg("FATAL %d handled.\n",(U32)Id,0,0,0,0,0); + Fw::Logger::logMsg("============= FATAL event 0x%x handled ============= \n",(U32)Id,0,0,0,0,0); (void)Os::Task::delay(1000); Fw::Logger::logMsg("Exiting.\n",0,0,0,0,0,0); (void)raise( SIGSEGV ); diff --git a/Svc/GroundInterface/CMakeLists.txt b/Svc/GroundInterface/CMakeLists.txt index 458f0771541..61b6b0767e1 100644 --- a/Svc/GroundInterface/CMakeLists.txt +++ b/Svc/GroundInterface/CMakeLists.txt @@ -6,13 +6,23 @@ # # Note: using PROJECT_NAME as EXECUTABLE_NAME #### + +SET(PUSOPEN_PATH ${FPRIME_FRAMEWORK_PATH}/Lib) +SET(MDB_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../gs/mdb) + set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/GroundInterfaceComponentAi.xml" "${CMAKE_CURRENT_LIST_DIR}/GroundInterface.cpp" + "${MDB_PATH}/pusopen_onboard_mdb.c" # PUSOpen mission database ) set(MOD_DEPS "Utils/Types") register_fprime_module() +add_definitions(-D_LINUB1804_GCC750) +include_directories(${PUSOPEN_PATH}/Includes) +find_library(PUSOPEN pusopen ${PUSOPEN_PATH}/lib) +target_link_libraries(Svc_GroundInterface ${PUSOPEN}) + # Rules based unit testing set(UT_MOD_DEPS STest @@ -23,6 +33,8 @@ set(UT_SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/GroundInterfaceRules.cpp" + "${MDB_PATH}/pusopen_onboard_mdb.c" # PUSOpen mission database ) -# STest Includes for this UT +# Test Includes for this UT register_fprime_ut() + diff --git a/Svc/GroundInterface/GroundInterface.cpp b/Svc/GroundInterface/GroundInterface.cpp index c78c636954a..8f63622520a 100644 --- a/Svc/GroundInterface/GroundInterface.cpp +++ b/Svc/GroundInterface/GroundInterface.cpp @@ -2,205 +2,465 @@ // \title GroundInterface.cpp // \author lestarch // \brief cpp file for GroundInterface component implementation class +// +// Define _PUS or _GDS depending on GS/protocols needs. +// Currently set in App/CmakeLists.txt // ====================================================================== +#include + #include +#include +#include #include -#include "Fw/Types/BasicTypes.hpp" -#include +#include +#include +#include + +#ifdef _PUS +#include + +#include "pusopen.h" + +extern Svc::GroundInterfaceComponentImpl groundIf; +extern Os::Mutex PO_STACK_MUTEX; +#endif // defined _PUS + +#ifndef _GDS +#define _PUS // for VSCode synthax, will cause compiler warning for redefinition +#endif namespace Svc { - const U32 GroundInterfaceComponentImpl::MAX_DATA_SIZE = 2048; - const TOKEN_TYPE GroundInterfaceComponentImpl::START_WORD = static_cast(0xdeadbeef); - const U32 GroundInterfaceComponentImpl::END_WORD = static_cast(0xcafecafe); - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - GroundInterfaceComponentImpl :: - GroundInterfaceComponentImpl( - const char *const compName - ) : GroundInterfaceComponentBase(compName), - m_ext_buffer(m_buffer, GND_BUFFER_SIZE), - m_data_size(0), - m_in_ring(m_in_buffer, GND_BUFFER_SIZE) - { - - } - - void GroundInterfaceComponentImpl :: - init( - const NATIVE_INT_TYPE instance - ) - { +const U32 GroundInterfaceComponentImpl::MAX_DATA_SIZE = 2048; +const TOKEN_TYPE GroundInterfaceComponentImpl::START_WORD = static_cast(0xdeadbeef); +const U32 GroundInterfaceComponentImpl::END_WORD = static_cast(0xcafecafe); + +// ------------------------------------- --------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +GroundInterfaceComponentImpl :: +GroundInterfaceComponentImpl( + const char *const compName +) : GroundInterfaceComponentBase(compName), + m_ext_buffer(m_buffer, GND_BUFFER_SIZE), + m_data_size(0), + m_in_ring(m_in_buffer, GND_BUFFER_SIZE) { +} + +void GroundInterfaceComponentImpl::init(const NATIVE_INT_TYPE instance) { GroundInterfaceComponentBase::init(instance); - } +#ifdef _PUS + po_result_t res = PO_SUCCESS; - GroundInterfaceComponentImpl :: - ~GroundInterfaceComponentImpl(void) - { + res = po_initPus1(); // macro for pus1_reset(PO_DEF_PUS1) + res |= po_initPs(); // macro for ps_reset(PO_DEF_PS) + res |= po_initFess(); // macro for fess_reset(PO_DEF_FESS) - } + if (res != PO_SUCCESS) { + // PUSOpen initialisation error ! Critical error with FSW + FW_ASSERT(0); + } +#endif // defined _PUS +} - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- +GroundInterfaceComponentImpl::~GroundInterfaceComponentImpl(void) {} - void GroundInterfaceComponentImpl :: - downlinkPort_handler( - const NATIVE_INT_TYPE portNum, - Fw::ComBuffer &data, - U32 context - ) - { - FW_ASSERT(data.getBuffLength() <= MAX_DATA_SIZE); - frame_send(data.getBuffAddr(), data.getBuffLength()); - } - - void GroundInterfaceComponentImpl :: - fileDownlinkBufferSendIn_handler( +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +void GroundInterfaceComponentImpl::downlinkPort_handler( + const NATIVE_INT_TYPE portNum, + Fw::ComBuffer &data, + U32 context +) { +#ifdef _GDS + // Downlink TM disabled + FW_ASSERT(data.getBuffLength() <= MAX_DATA_SIZE); + frame_send(data.getBuffAddr(), data.getBuffLength()); +#endif // defined _GDS + +#ifdef _PUS + Fw::Buffer buffer; //!< Com buffer for sending event buffers + buffer.setData(data.getBuffAddr()); + buffer.setSize(data.getBuffCapacity()); + + write_out(0, buffer); +#endif + +} + +void GroundInterfaceComponentImpl::fileDownlinkBufferSendIn_handler( + const NATIVE_INT_TYPE portNum, + Fw::Buffer &fwBuffer +) { +#ifdef _GDS + FW_ASSERT(fwBuffer.getSize() <= MAX_DATA_SIZE); + frame_send(fwBuffer.getData(), fwBuffer.getSize(), Fw::ComPacket::FW_PACKET_FILE); + fileDownlinkBufferSendOut_out(0, fwBuffer); +#endif // defined _GDS +} + +void GroundInterfaceComponentImpl::readCallback_handler( + const NATIVE_INT_TYPE portNum, + Fw::Buffer &buffer +) { + if(isConnected_readPoll_OutputPort(0)) { + // User should chose to use callback or poll method for uplink data + FW_ASSERT(0); + } + +#ifdef _PUS + processPUS(buffer); +#elif defined _GDS + processBuffer(buffer); +#endif +} + +void GroundInterfaceComponentImpl::schedIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + NATIVE_UINT_TYPE context /*!< The call order*/ +) { + // TODO: replace with a call to a buffer manager + Fw::Buffer buffer = m_ext_buffer; + // Call read poll if it is hooked up + if (isConnected_readPoll_OutputPort(0)) { + readPoll_out(0, buffer); +#ifdef _PUS + processPUS(buffer); +#elif defined _GDS + processBuffer(buffer); +#endif + } +} + +void GroundInterfaceComponentImpl::hkReport_handler( const NATIVE_INT_TYPE portNum, - Fw::Buffer &fwBuffer - ) - { - FW_ASSERT(fwBuffer.getSize() <= MAX_DATA_SIZE); - frame_send(fwBuffer.getData(), fwBuffer.getSize(), Fw::ComPacket::FW_PACKET_FILE); - fileDownlinkBufferSendOut_out(0, fwBuffer); - } - - void GroundInterfaceComponentImpl :: - readCallback_handler( + FwChanIdType id, + Fw::Time &timeTag, + Fw::TlmBuffer &val +) { + // deprecated (defined by F') +} + +void GroundInterfaceComponentImpl::eventReport_handler( const NATIVE_INT_TYPE portNum, - Fw::Buffer &buffer - ) - { - processBuffer(buffer); - } - - void GroundInterfaceComponentImpl :: - schedIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - NATIVE_UINT_TYPE context /*!< The call order*/ - ) - { - // TODO: replace with a call to a buffer manager - Fw::Buffer buffer = m_ext_buffer; - // Call read poll if it is hooked up - if (isConnected_readPoll_OutputPort(0)) { - readPoll_out(0, buffer); - processBuffer(buffer); - } - } - - void GroundInterfaceComponentImpl::frame_send(U8 *data, TOKEN_TYPE size, TOKEN_TYPE packet_type) { - // TODO: replace with a call to a buffer manager - Fw::Buffer buffer = m_ext_buffer; - Fw::SerializeBufferBase& buffer_wrapper = buffer.getSerializeRepr(); - buffer_wrapper.resetSer(); - // True size is supplied size plus sizeof(TOKEN_TYPE) if a packet_type other than "UNKNOWN" was supplied. - // This is because if not UNKNOWN, the packet_type is serialized too. Otherwise it is assumed the PACKET_TYPE is - // already the first token in the UNKNOWN typed buffer. - U32 true_size = (packet_type != Fw::ComPacket::FW_PACKET_UNKNOWN) ? size + sizeof(TOKEN_TYPE) : size; - U32 total_size = sizeof(TOKEN_TYPE) + sizeof(TOKEN_TYPE) + true_size + sizeof(U32); - // Serialize data - FW_ASSERT(GND_BUFFER_SIZE >= total_size, GND_BUFFER_SIZE, total_size); - buffer_wrapper.serialize(START_WORD); - buffer_wrapper.serialize(static_cast(true_size)); - // Explicitly set the packet type, if it didn't come with the data already - if (packet_type != Fw::ComPacket::FW_PACKET_UNKNOWN) { - buffer_wrapper.serialize(packet_type); - } - buffer_wrapper.serialize(data, size, true); - buffer_wrapper.serialize(static_cast(END_WORD)); - - // Setup for sending by truncating unused data - buffer.setSize(buffer_wrapper.getBuffLength()); - FW_ASSERT(buffer.getSize() == total_size, buffer.getSize(), total_size); - write_out(0, buffer); - } - - void GroundInterfaceComponentImpl :: - routeComData() - { - // Read the packet type from the data buffer - U32 packet_type = Fw::ComPacket::FW_PACKET_UNKNOWN; - m_in_ring.peek(packet_type, HEADER_SIZE); - - // Process variable type - switch (packet_type) { - case Fw::ComPacket::FW_PACKET_COMMAND: { - Fw::ComBuffer com; - m_in_ring.peek(com.getBuffAddr(), m_data_size, HEADER_SIZE); - // Reset com buffer for sending out data - com.setBuffLen(m_data_size); - uplinkPort_out(0, com, 0); - break; - } - case Fw::ComPacket::FW_PACKET_FILE: { - // If file uplink is possible, handle files. Otherwise ignore. - if (isConnected_fileUplinkBufferGet_OutputPort(0) && - isConnected_fileDownlinkBufferSendOut_OutputPort(0)) { - Fw::Buffer buffer = fileUplinkBufferGet_out(0, m_data_size); - m_in_ring.peek(buffer.getData(), m_data_size - sizeof(packet_type), HEADER_SIZE + sizeof(packet_type)); - buffer.setSize(m_data_size - sizeof(packet_type)); - fileUplinkBufferSendOut_out(0, buffer); - } - break; - } - default: - return; - } - } - - void GroundInterfaceComponentImpl :: - processRing() - { - // Header items for the packet - TOKEN_TYPE start; - U32 checksum; //TODO: make this run a CRC32 - // Inner-loop, process ring buffer looking for at least the header - while (m_in_ring.get_remaining_size() >= HEADER_SIZE) { - m_data_size = 0; - // Peek into the header and read out values - Fw::SerializeStatus status = m_in_ring.peek(start, 0); - FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); - status = m_in_ring.peek(m_data_size, sizeof(TOKEN_TYPE)); - FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); - // Check the header for correctness - if (start != START_WORD || m_data_size >= MAX_DATA_SIZE) { - m_in_ring.rotate(1); - continue; - } - // Check for enough data to deserialize everything otherwise break and wait for more. - else if (m_in_ring.get_remaining_size() < (HEADER_SIZE + m_data_size + sizeof(END_WORD))) { - break; - } - // Continue with the data portion and checksum - m_in_ring.peek(checksum, HEADER_SIZE + m_data_size); - // Check checksum - if (checksum == END_WORD) { - routeComData(); - m_in_ring.rotate(HEADER_SIZE + m_data_size + sizeof(U32)); - } - // Failed checksum, keep looking for valid message - else { - m_in_ring.rotate(1); - } - } - } - - void GroundInterfaceComponentImpl :: - processBuffer(Fw::Buffer& buffer) - { - NATIVE_UINT_TYPE buffer_offset = 0; - while (buffer_offset < buffer.getSize()) { - NATIVE_UINT_TYPE ser_size = (buffer.getSize() >= m_in_ring.get_remaining_size(true)) ? - m_in_ring.get_remaining_size(true) : static_cast(buffer.getSize()); - m_in_ring.serialize(buffer.getData() + buffer_offset, ser_size); - buffer_offset = buffer_offset + ser_size; - processRing(); - } - } -} // end namespace Svc + FwEventIdType id, + Fw::Time &timeTag, + Fw::LogSeverity severity, + Fw::LogBuffer &args +) { +#ifdef _PUS + // F' variables + Fw::Buffer buffer; //!< buffer to send frame to SocketIpDriver + + Fw::LogPacket m_logPacket; //!< Packet buffer for assembling log packets + Fw::ComBuffer m_comBuffer; //!< Com buffer for sending event buffers + + // PUSOpen variables + U8 po_buf[4096]; // @todo use definition + U8 po_evtData = 0; + U16 po_len; + po_result_t po_res = PO_ERR; + pus5_evtId_t po_pus5_eventId = PUS5_EVT_HIGH; // default value + + // printf("[PUS5] Event received : %u (0x%02X)\n", id, id); + + /** + ---- PUS Service 5 severity level ---- + PUS5_EVT_INFO = Information event TM[5,1] + PUS5_EVT_LOW = Low severity anomaly TM[5,2] + PUS5_EVT_MEDIUM = Medium severity anomaly TM[5,3] + PUS5_EVT_HIGH = High severity anomaly TM[5,4] + + ---- F' Events severity level ---- + LOG_DIAGNOSTIC → PUS5_EVT_INFO + LOG_ACTIVITY_LO → PUS5_EVT_INFO + LOG_COMMAND → PUS5_EVT_INFO + LOG_ACTIVITY_HI → PUS5_EVT_LOW + LOG_WARNING_LO → PUS5_EVT_MEDIUM + LOG_ACTIVITY_HI → PUS5_EVT_HIGH + LOG_FATAL → PUS5_EVT_HIGH - internal handling in the future + **/ + switch(severity) { + case Fw::LOG_DIAGNOSTIC: + case Fw::LOG_ACTIVITY_LO: + case Fw::LOG_COMMAND: + po_pus5_eventId = PUS5_EVT_INFO; + break; + case Fw::LOG_ACTIVITY_HI: + po_pus5_eventId = PUS5_EVT_LOW; + break; + case Fw::LOG_WARNING_LO: + po_pus5_eventId = PUS5_EVT_MEDIUM; + break; + case Fw::LOG_WARNING_HI: + po_pus5_eventId = PUS5_EVT_HIGH; + break; + case Fw::LOG_FATAL: + po_pus5_eventId = PUS5_EVT_HIGH; + break; + default: + po_pus5_eventId = PUS5_EVT_HIGH; + } + + // Event arguments to serialize + m_logPacket.setId(id); + m_logPacket.setTimeTag(timeTag); + m_logPacket.setLogBuffer(args); + m_comBuffer.resetSer(); + Fw::SerializeStatus stat = m_logPacket.serialize(m_comBuffer); + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast(stat)); + //*/ + + PO_STACK_MUTEX.lock(); + + // Send TM[5,x] with F' event ID = x + po_res = po_pus5tm( + po_pus5_eventId, // event ID PUS[5, x] + m_comBuffer.getBuffAddr(), // event data + GS_APID); // destination APID (GS) + + if(po_res != PO_SUCCESS) { + printf("=== [PUS5] po_pus5tm po error: %u\n", po_res); + } + + while(1) { // @todo avoid endless loop + po_res = po_frame(po_buf, &po_len); + + if(po_res != PO_SUCCESS) { + if (po_res == PO_ERR_NODATA) { + break; + } else { + printf("=== [PUS] po_frame po error: %u\n", po_res); + } + break; + } + + if(po_len > 0) { + //printf("Send\n"); + buffer.setData(po_buf); + buffer.setSize(po_len); + write_out(0, buffer); + } + } + + PO_STACK_MUTEX.unLock(); + +#endif // defined _PUS +} + +void GroundInterfaceComponentImpl::processBuffer(Fw::Buffer& buffer) { + NATIVE_UINT_TYPE buffer_offset = 0; + + while (buffer_offset < buffer.getSize()) { + NATIVE_UINT_TYPE ser_size = (buffer.getSize() >= m_in_ring.get_remaining_size(true)) ? + m_in_ring.get_remaining_size(true) : static_cast(buffer.getSize()); + m_in_ring.serialize(buffer.getData() + buffer_offset, ser_size); + buffer_offset = buffer_offset + ser_size; + processRing(); + } +} + +void GroundInterfaceComponentImpl::routeComData() { + // Read the packet type from the data buffer + U32 packet_type = Fw::ComPacket::FW_PACKET_UNKNOWN; + m_in_ring.peek(packet_type, HEADER_SIZE); + + // Process variable type + switch (packet_type) { + case Fw::ComPacket::FW_PACKET_COMMAND: { + Fw::ComBuffer com; + m_in_ring.peek(com.getBuffAddr(), m_data_size, HEADER_SIZE); + // Reset com buffer for sending out data + com.setBuffLen(m_data_size); + uplinkPort_out(0, com, 0); // → send to CommandDispatcher + break; + } + case Fw::ComPacket::FW_PACKET_FILE: { + // If file uplink is possible, handle files. Otherwise ignore. + FW_ASSERT(0); + if (isConnected_fileUplinkBufferGet_OutputPort(0) && + isConnected_fileDownlinkBufferSendOut_OutputPort(0)) { + Fw::Buffer buffer = fileUplinkBufferGet_out(0, m_data_size); + m_in_ring.peek(buffer.getData(), m_data_size - sizeof(packet_type), HEADER_SIZE + sizeof(packet_type)); + buffer.setSize(m_data_size - sizeof(packet_type)); + fileUplinkBufferSendOut_out(0, buffer); + } + break; + } + default: + return; + } +} + +void GroundInterfaceComponentImpl::processRing() { + // Header items for the packet + TOKEN_TYPE start; + U32 checksum; //TODO: make this run a CRC32 + // Inner-loop, process ring buffer looking for at least the header + while (m_in_ring.get_remaining_size() >= HEADER_SIZE) { + m_data_size = 0; + // Peek into the header and read out values + Fw::SerializeStatus status = m_in_ring.peek(start, 0); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); + status = m_in_ring.peek(m_data_size, sizeof(TOKEN_TYPE)); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); + // Check the header for correctness + if (start != START_WORD || m_data_size >= MAX_DATA_SIZE) { + m_in_ring.rotate(1); + continue; + } + // Check for enough data to deserialize everything otherwise break and wait for more. + else if (m_in_ring.get_remaining_size() < (HEADER_SIZE + m_data_size + sizeof(END_WORD))) { + break; + } + // Continue with the data portion and checksum + m_in_ring.peek(checksum, HEADER_SIZE + m_data_size); + // Check checksum + if (checksum == END_WORD) { + routeComData(); + m_in_ring.rotate(HEADER_SIZE + m_data_size + sizeof(END_WORD)); + } + // Failed checksum, keep looking for valid message + else { + m_in_ring.rotate(1); + } + } + //*/ +} + +#ifdef _GDS +void GroundInterfaceComponentImpl::frame_send(U8 *data, TOKEN_TYPE size, TOKEN_TYPE packet_type) { + // TODO: replace with a call to a buffer manager + Fw::Buffer buffer = m_ext_buffer; + Fw::SerializeBufferBase& buffer_wrapper = buffer.getSerializeRepr(); + buffer_wrapper.resetSer(); + // True size is supplied size plus sizeof(TOKEN_TYPE) if a packet_type other than "UNKNOWN" was supplied. + // This is because if not UNKNOWN, the packet_type is serialized too. Otherwise it is assumed the PACKET_TYPE is + // already the first token in the UNKNOWN typed buffer. + U32 true_size = (packet_type != Fw::ComPacket::FW_PACKET_UNKNOWN) ? size + sizeof(TOKEN_TYPE) : size; + // Frame format : | START_WORD | data_size | data | END_WORD | + U32 total_size = sizeof(TOKEN_TYPE) + sizeof(TOKEN_TYPE) + true_size + sizeof(U32); + // Serialize data + FW_ASSERT(GND_BUFFER_SIZE >= total_size, GND_BUFFER_SIZE, total_size); + buffer_wrapper.serialize(START_WORD); + buffer_wrapper.serialize(static_cast(true_size)); + // Explicitly set the packet type, if it didn't come with the data already + if (packet_type != Fw::ComPacket::FW_PACKET_UNKNOWN) { + buffer_wrapper.serialize(packet_type); + } + buffer_wrapper.serialize(data, size, true); + buffer_wrapper.serialize(static_cast(END_WORD)); + + // Setup for sending by truncating unused data + buffer.setSize(buffer_wrapper.getBuffLength()); + FW_ASSERT(buffer.getSize() == total_size, buffer.getSize(), total_size); + write_out(0, buffer); +} +#endif // defined GDS + +#ifdef _PUS + +void GroundInterfaceComponentImpl::processPUS(Fw::Buffer& buffer) { + Fw::Buffer extBuff = m_ext_buffer; + //printf("[PUS] service pus received \n"); + //printf("[PUS] size data %u\n",buffer.getSize()); + // Transmission buffer + U8 buf[4096]; // @todo use definition + U16 len; + + PO_STACK_MUTEX.lock(); + + // Push received data byte-by-byte into PUSopen(R) stack + for(int i = 0; i < buffer.getSize(); i++) { + po_accept(buffer.getData()[i]); // todo propre reinterpret_cast + } + + // Unwrap TC[x,y] from received CCSDS packet + po_triggerPs(); + + // Forward TC[x,y] to PUS x + po_triggerPus1(); + + + // Retrieve potentially created TM[17,x] byte stream from PUSopen(R) stack and send it + po_frame(buf, &len); + + PO_STACK_MUTEX.unLock(); + + /*/ + printf("[PUS] size buf %u\n",len); + for(int i = 0;i 0) { + printf("[PUS] return data \n"); + extBuff.setSize(len); + extBuff.setData(buf); + write_out(0,extBuff); + } +} + + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* User-defined function triggered by PUS 8 provider. +* This function is defined in the Mission Database +* mdb_server.xml under . +*/ +po_result_t UserPus8Fn (uint8_t fid, uint8_t *data, uint16_t len) +{ + printf("[PUS8] User Function triggered with function ID = %u.\n",fid); + Fw::Buffer extBuff; + U8* dataExt = &data[1]; + extBuff.setSize(len-1); + extBuff.setData(dataExt); + groundIf.processBuffer(extBuff); + + return PO_SUCCESS; +} + + +/* -- Global functions -- */ +po_result_t subnet_request( + uint8_t * const data, + const uint16_t len, + const po_apid_t apid, + const uint16_t vcid) { + po_result_t res = PO_SUCCESS; /* Result of this function */ + + (void)apid; + (void)vcid; + + /* Forward requested data directly down to FESS */ + res = fessChannelAccess_request(PO_DEF_FESS, data, len); + + return res; +} + +po_result_t subnet_indication(uint8_t * const data, uint16_t *len) { + po_result_t res = PO_SUCCESS; /* Result of this function */ + uint8_t quality = 0U; + uint8_t sequence = 0U; + + /* Call FESS indication API to retrieve received data */ + res = fessChannelAccess_indication(PO_DEF_FESS, data, len, &quality, &sequence); + + return res; +} + +#ifdef __cplusplus +} +#endif + +#endif // defined _PUS + +} // end namespace Svc \ No newline at end of file diff --git a/Svc/GroundInterface/GroundInterface.hpp b/Svc/GroundInterface/GroundInterface.hpp index 12f78222922..29624fce3aa 100644 --- a/Svc/GroundInterface/GroundInterface.hpp +++ b/Svc/GroundInterface/GroundInterface.hpp @@ -3,11 +3,13 @@ // \author lestarch // \brief hpp file for GroundInterface component implementation class // ====================================================================== +#ifndef GroundInterface_HPP +#define GroundInterface_HPP + #include + #include "Svc/GroundInterface/GroundInterfaceComponentAc.hpp" #include "Utils/Types/CircularBuffer.hpp" -#ifndef GroundInterface_HPP -#define GroundInterface_HPP #define GND_BUFFER_SIZE 1024 #define TOKEN_TYPE U32 @@ -22,6 +24,7 @@ namespace Svc { static const U32 MAX_DATA_SIZE; static const TOKEN_TYPE START_WORD; static const U32 END_WORD; + void processBuffer(Fw::Buffer& data /*!< Data to process */); // ---------------------------------------------------------------------- // Construction, initialization, and destruction // ---------------------------------------------------------------------- @@ -56,6 +59,25 @@ namespace Svc { U32 context /*!< Call context value; meaning chosen by user*/ ); + //! Handler implementation for eventReport + //! + void eventReport_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwEventIdType id, /*!< Log ID*/ + Fw::Time &timeTag, /*!< Time Tag*/ + Fw::LogSeverity severity, /*!< The severity argument*/ + Fw::LogBuffer &args /*!< Buffer containing serialized log entry*/ + ); + + //! Handler implementation for hkReport + //! + void hkReport_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwChanIdType id, /*!< Telemetry Channel ID*/ + Fw::Time &timeTag, /*!< Time Tag*/ + Fw::TlmBuffer &val /*!< Buffer containing serialized telemetry value*/ + ); + //! Handler implementation for fileDownlinkBufferSendIn //! void fileDownlinkBufferSendIn_handler( @@ -76,6 +98,14 @@ namespace Svc { const NATIVE_INT_TYPE portNum, /*!< The port number*/ NATIVE_UINT_TYPE context /*!< The call order*/ ); + + //! Processes the out-going data into coms order + void routeComData(); + + //! Process all the data in the ring + void processRing(); + +#ifdef _GDS //! Frame and send some data //! void frame_send( @@ -83,19 +113,17 @@ namespace Svc { TOKEN_TYPE size, /*!< Size of data in typed format */ TOKEN_TYPE packet_type = Fw::ComPacket::FW_PACKET_UNKNOWN /*!< Packet type override for anoymous data i.e. file downlink */ ); +#endif // defined _GDS - //! Processes the out-going data into coms order - void routeComData(); - - //! Process all the data in the ring - void processRing(); - +#ifdef _PUS //! Process a data buffer containing a read from the serial port - void processBuffer(Fw::Buffer& data /*!< Data to process */); + void processPUS(Fw::Buffer& data /*!< Data to process */); +#endif // defined _PUS // Basic data movement variables Fw::Buffer m_ext_buffer; U8 m_buffer[GND_BUFFER_SIZE]; + // Input variables TOKEN_TYPE m_data_size; //!< Data size expected in incoming data U8 m_in_buffer[GND_BUFFER_SIZE]; diff --git a/Svc/GroundInterface/GroundInterfaceCfg.hpp b/Svc/GroundInterface/GroundInterfaceCfg.hpp new file mode 100644 index 00000000000..a4c7e59eb65 --- /dev/null +++ b/Svc/GroundInterface/GroundInterfaceCfg.hpp @@ -0,0 +1,14 @@ +// ====================================================================== +// \title GroundInterfaceCfg.hpp +// \author jonathanmichel +// \brief hpp file for GroundInterface component configuration +// ====================================================================== + +#ifndef SVC_GROUNDINTERFACECGF_HPP +#define SVC_GROUNDINTERFACECGF_HPP + +enum GroundIntefaceCfg { + GS_APID = 3U, // Ground segement APID +}; + +#endif //SVC_GROUNDINTERFACECGF_HPP diff --git a/Svc/GroundInterface/GroundInterfaceComponentAi.xml b/Svc/GroundInterface/GroundInterfaceComponentAi.xml index f09375c5c17..0bcdc15ae1e 100644 --- a/Svc/GroundInterface/GroundInterfaceComponentAi.xml +++ b/Svc/GroundInterface/GroundInterfaceComponentAi.xml @@ -9,11 +9,24 @@ Fw/Time/TimePortAi.xml Fw/Buffer/BufferGetPortAi.xml Svc/Sched/SchedPortAi.xml + Fw/Tlm/TlmPortAi.xml Svc/GroundInterface/Events.xml - + + + + + + Event input port + + + + + + Housekeeping input port + diff --git a/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp b/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp index 5fbc041dada..50634aa5723 100644 --- a/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp +++ b/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp @@ -43,7 +43,7 @@ namespace Svc { severityString = "SEVERITY ERROR"; break; } - Fw::Logger::logMsg("EVENT: (%d) (%d:%d,%d) %s: %s\n", + Fw::Logger::logMsg("EVENT: (0x%x) (%d:%d,%d) %s: %s\n", id, timeTag.getTimeBase(), timeTag.getSeconds(), timeTag.getUSeconds(), reinterpret_cast(severityString), reinterpret_cast(text.toChar())); } diff --git a/Svc/TlmChan/CMakeLists.txt b/Svc/TlmChan/CMakeLists.txt index 171181dd181..504906ae15e 100644 --- a/Svc/TlmChan/CMakeLists.txt +++ b/Svc/TlmChan/CMakeLists.txt @@ -6,22 +6,30 @@ # # Note: using PROJECT_NAME as EXECUTABLE_NAME #### +SET(PUSOPEN_PATH ${FPRIME_FRAMEWORK_PATH}/Lib) +SET(MDB_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../gs/mdb) + set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/TlmChanComponentAi.xml" "${CMAKE_CURRENT_LIST_DIR}/TlmChanImpl.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TlmChanImplGet.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TlmChanImplRecv.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TlmChanImplTask.cpp" + "${MDB_PATH}/pusopen_onboard_mdb.c" # PUSOpen mission database ) register_fprime_module() +add_definitions(-D_LINUB1804_GCC750) +include_directories(${MDB_PATH}) # hk_param.h +include_directories(${PUSOPEN_PATH}/Includes) +find_library(PUSOPEN pusopen ${PUSOPEN_PATH}/lib) +target_link_libraries(Svc_TlmChan ${PUSOPEN}) + ### UTs ### set(UT_SOURCE_FILES "${FPRIME_FRAMEWORK_PATH}/Svc/TlmChan/TlmChanComponentAi.xml" "${CMAKE_CURRENT_LIST_DIR}/test/ut/TlmChanTester.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/TlmChanImplTester.cpp" + "${MDB_PATH}/pusopen_onboard_mdb.c" # PUSOpen mission database ) register_fprime_ut() diff --git a/Svc/TlmChan/TlmChanComponentAi.xml b/Svc/TlmChan/TlmChanComponentAi.xml index 4619238bdc4..aac5e5350c1 100644 --- a/Svc/TlmChan/TlmChanComponentAi.xml +++ b/Svc/TlmChan/TlmChanComponentAi.xml @@ -18,6 +18,11 @@ Telemetry input port + + + Telemetry output port + + Run port for starting packet send cycle diff --git a/Svc/TlmChan/TlmChanImpl.cpp b/Svc/TlmChan/TlmChanImpl.cpp index a3b1ea9689e..6f30417bac1 100644 --- a/Svc/TlmChan/TlmChanImpl.cpp +++ b/Svc/TlmChan/TlmChanImpl.cpp @@ -10,17 +10,37 @@ *

*/ #include -#include #include #include #include +#include +#include +#include "hk_param.h" +#include #include +#ifndef _GDS // for VS synthax highlighting +//#define _PUS // will cause compiler warning for redifinition +#endif + +#ifdef _PUS +#include + +#include "pusopen.h" + +extern Os::Mutex PO_STACK_MUTEX; + +extern s_PARAM PARAM; + +#endif // defined _PUS + namespace Svc { TlmChanImpl::TlmChanImpl(const char* name) : TlmChanComponentBase(name) - { + { + U16 i = 0; + // clear data this->m_activeBuffer = 0; // clear slot pointers @@ -28,6 +48,7 @@ namespace Svc { this->m_tlmEntries[0].slots[entry] = 0; this->m_tlmEntries[1].slots[entry] = 0; } + // clear buckets for (NATIVE_UINT_TYPE entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { this->m_tlmEntries[0].buckets[entry].used = false; @@ -41,15 +62,24 @@ namespace Svc { this->m_tlmEntries[1].buckets[entry].next = 0; this->m_tlmEntries[1].buckets[entry].id = 0; } + // clear free index this->m_tlmEntries[0].free = 0; this->m_tlmEntries[1].free = 0; - +#ifdef _PUS + // Set global PUS variable with default value + // @todo - Find a clean way to deal with PARAM struct - Dirty code :o + // Works only with U32 parameters list !! + for(i = 0; i < PO_PARAM_SIZE; i++) { + U32* ptr = reinterpret_cast(&PARAM); + ptr = ptr + i; + *ptr = (U32)0; + } +#endif } - TlmChanImpl::~TlmChanImpl() { - } + TlmChanImpl::~TlmChanImpl() {} void TlmChanImpl::init( NATIVE_INT_TYPE queueDepth, /*!< The queue depth*/ @@ -65,11 +95,171 @@ namespace Svc { void TlmChanImpl::pingIn_handler( const NATIVE_INT_TYPE portNum, U32 key - ) - { + ) { // return key this->pingOut_out(0,key); } + void TlmChanImpl::Run_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context) { + // Only write packets if connected + if (not this->isConnected_PktSend_OutputPort(0)) { + return; + } + +#ifdef _GDS + + // lock mutex long enough to modify active telemetry buffer + // so the data can be read without worrying about updates + this->lock(); + this->m_activeBuffer = 1 - this->m_activeBuffer; // activeBuffer is 0 or 1 + // set activeBuffer to not updated + for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { + this->m_tlmEntries[this->m_activeBuffer].buckets[entry].updated = false; + } + this->unLock(); + + // go through each entry and send a packet if it has been updated + for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { + TlmEntry* p_entry = &this->m_tlmEntries[1-this->m_activeBuffer].buckets[entry]; + if ((p_entry->updated) && (p_entry->used)) { + this->m_tlmPacket.setId(p_entry->id); + this->m_tlmPacket.setTimeTag(p_entry->lastUpdate); + this->m_tlmPacket.setTlmBuffer(p_entry->buffer); + this->m_comBuffer.resetSer(); + Fw::SerializeStatus stat = this->m_tlmPacket.serialize(this->m_comBuffer); + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast(stat)); + p_entry->updated = false; + + this->PktSend_out(0,this->m_comBuffer,0); + } + } + +#elif defined _PUS + // F' variables + U32 tlmVal; + + + // PUSOpen variables + U8 po_buf[4096]; // @todo use definition + U16 po_len; + po_result_t po_res = PO_ERR; + + PO_STACK_MUTEX.lock(); + + // Trigger PUS service 3 to check is report + // has to generated + po_triggerPus3(); + + po_res = po_frame(po_buf, &po_len); + + PO_STACK_MUTEX.unLock(); + + if(po_len > 0) { + // @todo Remove - Temporary + if(po_len > FW_COM_BUFFER_MAX_SIZE) { + printf("=== [PUS3] TLM - To long frame (%u) - Not send\n", po_len); + return; + } + FW_ASSERT(po_len <= FW_COM_BUFFER_MAX_SIZE); + printf("TLM: Send report (%u)\n", po_len); + Fw::ComBuffer m_comBuffer(po_buf, po_len); //!< Com buffer for sending event buffers + this->PktSend_out(0,m_comBuffer,0); + } +#endif + } + + void TlmChanImpl::TlmRecv_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time &timeTag, Fw::TlmBuffer &val) { + // Compute index for entry + NATIVE_UINT_TYPE index = this->doHash(id); + TlmEntry* entryToUse = 0; + TlmEntry* prevEntry = 0; + + // Search to see if channel has already been stored or a bucket needs to be added + if (this->m_tlmEntries[this->m_activeBuffer].slots[index]) { + entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; + for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + if (entryToUse) { + if (entryToUse->id == id) { // found the matching entry + break; + } else { // try next entry + prevEntry = entryToUse; + entryToUse = entryToUse->next; + } + } else { + // Make sure that we haven't run out of buckets + FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS); + // add new bucket from free list + entryToUse = &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++]; + prevEntry->next = entryToUse; + // clear next pointer + entryToUse->next = 0; + break; + } + } + } else { + // Make sure that we haven't run out of buckets + FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS); + // create new entry at slot head + this->m_tlmEntries[this->m_activeBuffer].slots[index] = &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++]; + entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; + entryToUse->next = 0; + } + + // copy into entry + FW_ASSERT(entryToUse); + entryToUse->used = true; + entryToUse->id = id; + entryToUse->updated = true; + entryToUse->lastUpdate = timeTag; + entryToUse->buffer = val; + +#ifdef _PUS + // List ids used in report #1 for PUS3 service + U32 used_hk[] = {0x29, 0x79, 0x7a, 0x169, 0x1E1, 0x42f, 0x430, 0x431}; + + // Check received TM and update global variable for PUSOpen lib if + // id is used in report + // @todo - Find a clean way to deal with hk_param - Dirty code :o + // Works only with U32 parameters list !! + U16 i; + for(i = 0; i < PO_PARAM_SIZE; i++) { + if (used_hk[i] == id) { + U32 value; + val.deserialize(value); + U32* ptr = reinterpret_cast(&PARAM); + ptr = ptr + i; + *ptr = value; + // printf("Tlm %u val %u\n", id, value); + } + } +#endif // defined _PUS + + } + + void TlmChanImpl::TlmGet_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time &timeTag, Fw::TlmBuffer &val) { + // Compute index for entry + NATIVE_UINT_TYPE index = this->doHash(id); + // Search to see if channel has been stored + TlmEntry *entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; + for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + if (entryToUse) { // If bucket exists, check id + if (entryToUse->id == id) { + break; + } else { // otherwise go to next bucket + entryToUse = entryToUse->next; + } + } else { // no buckets left to search + break; + } + } + + if (entryToUse) { + val = entryToUse->buffer; + timeTag = entryToUse->lastUpdate; + } else { // requested entry may not be written yet; empty buffer + val.resetSer(); + } + + } } diff --git a/Svc/TlmChan/TlmChanImpl.hpp b/Svc/TlmChan/TlmChanImpl.hpp index 3a7f801cb9e..8cfc1ee79a3 100644 --- a/Svc/TlmChan/TlmChanImpl.hpp +++ b/Svc/TlmChan/TlmChanImpl.hpp @@ -19,7 +19,6 @@ #include namespace Svc { - class TlmChanImpl: public TlmChanComponentBase { public: friend class TlmChanImplTester; @@ -30,12 +29,10 @@ namespace Svc { NATIVE_INT_TYPE instance /*!< The instance number*/ ); PROTECTED: - // can be overridden for alternate algorithms virtual NATIVE_UINT_TYPE doHash(FwChanIdType id); PRIVATE: - // Port functions void TlmRecv_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time &timeTag, Fw::TlmBuffer &val); void TlmGet_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time &timeTag, Fw::TlmBuffer &val); @@ -47,6 +44,16 @@ namespace Svc { U32 key /*!< Value to return to pinger*/ ); + U32 m_activeBuffer; // !< which buffer is active for storing telemetry + // can be 1 or 2 and will define m_tlmEntries[index] + + // work variables + Fw::ComBuffer m_comBuffer; + Fw::TlmPacket m_tlmPacket; + + U32 defaultTlmValue; + + public: typedef struct tlmEntry { FwChanIdType id; //!< telemetry id stored in slot bool updated; //!< set whenever a value has been written. Used to skip if writing out values for downlinking @@ -62,15 +69,7 @@ namespace Svc { TlmEntry buckets[TLMCHAN_HASH_BUCKETS]; //!< set of buckets used in hash table NATIVE_INT_TYPE free; //!< next free bucket } m_tlmEntries[2]; - - U32 m_activeBuffer; // !< which buffer is active for storing telemetry - - // work variables - Fw::ComBuffer m_comBuffer; - Fw::TlmPacket m_tlmPacket; - }; - } #endif /* TELEMCHANIMPL_HPP_ */ diff --git a/Utils/Types/CircularBuffer.hpp b/Utils/Types/CircularBuffer.hpp index ecfc6b3a45b..0070129079b 100644 --- a/Utils/Types/CircularBuffer.hpp +++ b/Utils/Types/CircularBuffer.hpp @@ -18,7 +18,7 @@ #ifndef TYPES_CIRCULAR_BUFFER_HPP #define TYPES_CIRCULAR_BUFFER_HPP -//#define CIRCULAR_DEBUG +// #define CIRCULAR_DEBUG // An assertion to guarantee the self-consistency of a head/tail pointer w.r.t. the store and size #define ASSERT_CONSISTENT(store, size, X) \ @@ -51,7 +51,7 @@ class CircularBuffer { /** * Deserialize data into the given variable without moving the head pointer - * \param U8& value: value to fill + * \param char& value: value to fill */ Fw::SerializeStatus peek(char& value, NATIVE_UINT_TYPE offset = 0); /** diff --git a/config/ActiveLoggerImplCfg.hpp b/config/ActiveLoggerImplCfg.hpp index 5a94cd30d44..19fb277e49a 100644 --- a/config/ActiveLoggerImplCfg.hpp +++ b/config/ActiveLoggerImplCfg.hpp @@ -18,14 +18,14 @@ enum { INPUT_COMMAND_DEFAULT = true, //!< COMMAND events are filtered at input INPUT_ACTIVITY_HI_DEFAULT = true, //!< ACTIVITY HI events are filtered at input INPUT_ACTIVITY_LO_DEFAULT = true, //!< ACTIVITY LO events are filtered at input - INPUT_DIAGNOSTIC_DEFAULT = false, //!< DIAGNOSTIC events are filtered at input + INPUT_DIAGNOSTIC_DEFAULT = true, //!< DIAGNOSTIC events are filtered at input SEND_WARNING_HI_DEFAULT = true, //!< WARNING HI events are filtered at output SEND_WARNING_LO_DEFAULT = true, //!< WARNING LO events are filtered at output SEND_COMMAND_DEFAULT = true, //!< COMMAND events are filtered at output SEND_ACTIVITY_HI_DEFAULT = true, //!< ACTIVITY HO events are filtered at output SEND_ACTIVITY_LO_DEFAULT = true, //!< ACTIVITY LO events are filtered at output - SEND_DIAGNOSTIC_DEFAULT = false //!< DIAGNOSTIC events are filtered at output + SEND_DIAGNOSTIC_DEFAULT = true //!< DIAGNOSTIC events are filtered at output }; // set event history circular buffer sizes diff --git a/config/SocketIpDriverCfg.hpp b/config/SocketIpDriverCfg.hpp index 512da740c53..c18fa28af6f 100644 --- a/config/SocketIpDriverCfg.hpp +++ b/config/SocketIpDriverCfg.hpp @@ -18,12 +18,17 @@ enum SocketIpCfg { SOCKET_TIMEOUT_SECONDS = 1, // Seconds component of timeout SOCKET_TIMEOUT_MICROSECONDS = 0, // Milliseconds component of timeout - SOCKET_SEND_UDP = 1, // 0 - Send down using TCP, 1 - Send down using UDP + #if defined _PUS + SOCKET_SEND_UDP = 0, + MAX_RECV_BUFFER_SIZE = 1, // Maximum and allocation size of the send buffer. TODO: use buffer manager + #elif defined _GDS + SOCKET_SEND_UDP = 1, + MAX_RECV_BUFFER_SIZE = 2048, // Maximum and allocation size of the send buffer. TODO: use buffer manager + #endif // 0 - Send down using TCP, 1 - Send down using UDP SOCKET_SEND_FLAGS = 0, // send, sendto FLAGS argument SOCKET_RECV_FLAGS = 0, // recv FLAGS argument RECONNECT_AUTOMATICALLY = 1, // Attempt to reconnect when a socket closes - MAX_SEND_ITERATIONS = 0xFFFF, // Maximum send iterations - MAX_RECV_BUFFER_SIZE = 2048, // Maximum and allocation size of the send buffer. TODO: use buffer manager + MAX_SEND_ITERATIONS = 0xFFFF, // Maximum send iterations PRE_CONNECTION_RETRY_INTERVAL_MS = 1000, // Interval between connection retries before main recv thread starts MAX_HOSTNAME_SIZE = 256 // Maximum stored hostname }; diff --git a/config/TlmChanImplCfg.hpp b/config/TlmChanImplCfg.hpp index b62009b013a..4fe369add5d 100644 --- a/config/TlmChanImplCfg.hpp +++ b/config/TlmChanImplCfg.hpp @@ -17,7 +17,7 @@ // The parameters below provide for tuning of the hash function used to -// write and read entries in the database. The has function is very simple; +// write and read entries in the database. The hash function is very simple; // It first takes the telemetry ID and does a modulo computation with // TLMCHAN_HASH_MOD_VALUE. It then does a second modulo with the number // of slots to make sure the value lands in the provided slots.