-
Notifications
You must be signed in to change notification settings - Fork 18
TlmArchive #464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
hrfarmer
wants to merge
44
commits into
main
Choose a base branch
from
tlm-archive
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
TlmArchive #464
Changes from all commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
598d901
initial commit
hrfarmer 5f38c96
logs
hrfarmer a3080a9
file downilnk test
hrfarmer bd45c99
Merge branch 'main' into tlm-archive
hrfarmer ad90a15
fix packet
hrfarmer c9d5171
test update
hrfarmer d7e0a49
higher tlm delay pleaes don't die
hrfarmer 5d66a29
decrease downlink delay during test
hrfarmer f132ee3
file count and pruning
hrfarmer c1a8448
Merge branch 'main' into tlm-archive
hrfarmer 3746d9d
add configurable timeout to send and assert
hrfarmer 6f262e6
Merge branch 'tlm-archive' of https://github.com/open-source-space-fo…
hrfarmer a80e238
nuke everything
hrfarmer 6b82a52
coderabbit recommendations
hrfarmer 139991e
Merge branch 'main' into tlm-archive
hrfarmer d8b3c1a
add archive write events
hrfarmer 6218823
stop attempting directory creation once successful
hrfarmer 4e6d07e
add filesystem failure limit
hrfarmer b4e359c
add max file size limit to component
hrfarmer fc06f35
ensure state changes are scoped with mutex
hrfarmer 44a37e4
only send one event when starting telemetry archival
hrfarmer c5b3349
updates
hrfarmer 46a5269
check file size only once
hrfarmer 46d00ca
update events
hrfarmer 44be94f
update sdd
hrfarmer 29ec02d
Merge branch 'main' into tlm-archive
hrfarmer aff88a5
ensure file is created before checking size
hrfarmer 2571b1a
get rid of size remaining check
hrfarmer 2e04e37
use atomics for telemetry archive state
hrfarmer 1e4dfe0
switch to using a csv format
hrfarmer b2ef327
bump max size to 25000
hrfarmer 3a72539
delete random test
hrfarmer 4100a6c
queue and filter updates
hrfarmer 2eb632b
increase size
hrfarmer 8165f28
remove queue empty event
hrfarmer eabfedf
add parameters for file size limit and error limit
hrfarmer 7739320
ensure file limit event is fired and queue is cleared on fileSize limit
hrfarmer 7e79bdd
Merge branch 'main' into tlm-archive
hrfarmer c1aecfa
bump command table size
hrfarmer 06bba3b
wait 30 seconds to start writing to disk
hrfarmer 5dbd15e
i am a stupid man
hrfarmer 4ccceba
test codex recommendation for radio test setup
hrfarmer f2a1a9d
Revert "test codex recommendation for radio test setup"
hrfarmer 21309ec
test i guess
hrfarmer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
PROVESFlightControllerReference/Components/TlmArchive/CMakeLists.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| register_fprime_library( | ||
| AUTOCODER_INPUTS | ||
| "${CMAKE_CURRENT_LIST_DIR}/TlmArchive.fpp" | ||
| SOURCES | ||
| "${CMAKE_CURRENT_LIST_DIR}/TlmArchive.cpp" | ||
| ) |
226 changes: 226 additions & 0 deletions
226
PROVESFlightControllerReference/Components/TlmArchive/TlmArchive.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,226 @@ | ||
| // ====================================================================== | ||
| // \title TlmArchive.cpp | ||
| // \author aychar | ||
| // \brief cpp file for TlmArchive component implementation class | ||
| // ====================================================================== | ||
|
|
||
| #include "PROVESFlightControllerReference/Components/TlmArchive/TlmArchive.hpp" | ||
|
|
||
| #include <cstdio> | ||
| #include <cstring> | ||
|
|
||
| #include "Fw/Com/ComPacket.hpp" | ||
| #include "Os/File.hpp" | ||
| #include "Os/FileSystem.hpp" | ||
| #include "Os/Models/FileStatusEnumAc.hpp" | ||
|
|
||
| namespace Components { | ||
|
|
||
| namespace { | ||
|
|
||
| constexpr const char* TLM_DIRECTORY = "//tlm"; | ||
| constexpr const char* PRE_DEPLOYMENT_TLM_PATH = "//tlm/pre_deployment.csv"; | ||
| constexpr char CSV_HEADER[] = "format_version,packet_size_bytes,packet_hex\n"; | ||
| constexpr char HEX_DIGITS[] = "0123456789ABCDEF"; | ||
| constexpr FwSizeType CSV_RECORD_BUFFER_SIZE = (FW_COM_BUFFER_MAX_SIZE * 2) + sizeof(CSV_HEADER) + 32; | ||
|
|
||
| // Only packetized telemetry IDs in this list are stored in the archive. | ||
| constexpr FwTlmPacketizeIdType STORED_PACKET_IDS[] = { | ||
| 1, // Beacon | ||
| 7, // Imu | ||
| }; | ||
|
|
||
| bool shouldStorePacket(const Fw::ComBuffer& data) { | ||
| Fw::ComBuffer packet = data; | ||
| FwPacketDescriptorType descriptor = 0; | ||
| FwTlmPacketizeIdType packetId = 0; | ||
|
|
||
| if ((packet.deserializeTo(descriptor) != Fw::FW_SERIALIZE_OK) || | ||
| (descriptor != static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_PACKETIZED_TLM)) || | ||
| (packet.deserializeTo(packetId) != Fw::FW_SERIALIZE_OK)) { | ||
| return false; | ||
| } | ||
|
|
||
| for (const FwTlmPacketizeIdType storedPacketId : STORED_PACKET_IDS) { | ||
| if (packetId == storedPacketId) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| TlmArchive ::TlmArchive(const char* const compName) : TlmArchiveComponentBase(compName) {} | ||
|
|
||
| TlmArchive ::~TlmArchive() {} | ||
|
|
||
| void TlmArchive::clearPacketQueue() { | ||
| Os::ScopeLock lock(this->m_queueMutex); | ||
| this->m_queueHead = 0; | ||
| this->m_queueTail = 0; | ||
| this->m_queueSize = 0; | ||
| } | ||
|
|
||
| void TlmArchive::comIn_handler(FwIndexType portNum, Fw::ComBuffer& data, U32 context) { | ||
| (void)portNum; | ||
| (void)context; | ||
|
|
||
| Fw::ParamValid maxFailuresValid; | ||
| const U32 maxFailures = this->paramGet_MAX_FAILURES(maxFailuresValid); | ||
| FW_ASSERT(maxFailuresValid == Fw::ParamValid::VALID || maxFailuresValid == Fw::ParamValid::DEFAULT); | ||
|
|
||
| Fw::ParamValid maxFileSizeValid; | ||
| const U32 maxFileSize = this->paramGet_MAX_FILE_SIZE(maxFileSizeValid); | ||
| FW_ASSERT(maxFileSizeValid == Fw::ParamValid::VALID || maxFileSizeValid == Fw::ParamValid::DEFAULT); | ||
|
|
||
| if (this->m_failures.load() >= maxFailures) { | ||
| this->log_WARNING_HI_FailureLimitReached(maxFailures); | ||
| return; | ||
| } else if (this->m_fileSize.load() >= maxFileSize) { | ||
| this->clearPacketQueue(); | ||
| this->log_WARNING_LO_SizeLimitReached(maxFileSize); | ||
| return; | ||
| } else if (this->m_antennasDeployed.load()) { | ||
| this->log_WARNING_LO_AntennasDeployed(); | ||
| return; | ||
| } | ||
|
|
||
| if (!shouldStorePacket(data)) { | ||
| return; | ||
| } | ||
|
|
||
| bool queueFull = false; | ||
| { | ||
| Os::ScopeLock lock(this->m_queueMutex); | ||
|
ineskhou marked this conversation as resolved.
|
||
| if (this->m_queueSize >= PACKET_QUEUE_CAPACITY) { | ||
| queueFull = true; | ||
| } else { | ||
| this->m_packetQueue[this->m_queueTail] = data; | ||
| this->m_queueTail = (this->m_queueTail + 1) % PACKET_QUEUE_CAPACITY; | ||
| this->m_queueSize++; | ||
| } | ||
| } | ||
|
|
||
| if (queueFull) { | ||
| this->log_WARNING_HI_QueueFull(PACKET_QUEUE_CAPACITY); | ||
| } else { | ||
| this->log_WARNING_HI_QueueFull_ThrottleClear(); | ||
| } | ||
| } | ||
|
|
||
| void TlmArchive::run_handler(FwIndexType portNum, U32 context) { | ||
| (void)portNum; | ||
| (void)context; | ||
|
|
||
| // Don't write for the first 30s of boot to attempt to mitigate | ||
| // any conflicts with other filesystem writes/actions | ||
| if (this->m_ticks <= 30) { | ||
| this->m_ticks++; | ||
| return; | ||
| } | ||
|
|
||
| Fw::ComBuffer packet; | ||
| { | ||
| Os::ScopeLock lock(this->m_queueMutex); | ||
| if (this->m_queueSize == 0) { | ||
| return; | ||
| } | ||
| packet = this->m_packetQueue[this->m_queueHead]; | ||
| this->m_queueHead = (this->m_queueHead + 1) % PACKET_QUEUE_CAPACITY; | ||
| this->m_queueSize--; | ||
| } | ||
|
|
||
| if (!this->m_antennasDeployed.load()) { | ||
| this->m_antennasDeployed.store(this->deploymentStateGet_out(0)); | ||
| } | ||
|
|
||
| if (this->m_antennasDeployed.load()) { | ||
| return; | ||
| } | ||
|
|
||
| if (!this->m_directoryInitialized) { | ||
| if (Os::FileSystem::createDirectory(TLM_DIRECTORY, false) != Os::FileSystem::OP_OK) { | ||
| this->log_WARNING_HI_FileError(Fw::LogStringArg("create_directory")); | ||
| this->m_failures.fetch_add(1); | ||
| return; | ||
| } | ||
| if (Os::FileSystem::touch(PRE_DEPLOYMENT_TLM_PATH) != Os::FileSystem::OP_OK) { | ||
| this->log_WARNING_HI_FileError(Fw::LogStringArg("create_file")); | ||
| this->m_failures.fetch_add(1); | ||
| return; | ||
| } | ||
| this->m_directoryInitialized = true; | ||
| } | ||
|
|
||
| const FwSizeType packetSize = packet.getSize(); | ||
| FwSizeType currentSize = this->m_fileSize.load(); | ||
| Fw::ParamValid maxFileSizeValid; | ||
| const U32 maxFileSize = this->paramGet_MAX_FILE_SIZE(maxFileSizeValid); | ||
| FW_ASSERT(maxFileSizeValid == Fw::ParamValid::VALID || maxFileSizeValid == Fw::ParamValid::DEFAULT); | ||
| if (!this->m_fileSizeInitialized) { | ||
| const Os::FileSystem::Status sizeStatus = Os::FileSystem::getFileSize(PRE_DEPLOYMENT_TLM_PATH, currentSize); | ||
| if (sizeStatus != Os::FileSystem::OP_OK) { | ||
| this->log_WARNING_HI_FileError(Fw::LogStringArg("get_file_size")); | ||
| this->m_failures.fetch_add(1); | ||
| return; | ||
| } | ||
| this->m_fileSize.store(static_cast<U32>(currentSize)); | ||
| this->m_fileSizeInitialized = true; | ||
| } | ||
|
|
||
| char csvRecord[CSV_RECORD_BUFFER_SIZE]; | ||
| FwSizeType recordSize = 0; | ||
| if (currentSize == 0) { | ||
| static_assert(sizeof(CSV_HEADER) > 1, "CSV header must not be empty"); | ||
| (void)std::memcpy(csvRecord, CSV_HEADER, sizeof(CSV_HEADER) - 1); | ||
| recordSize = sizeof(CSV_HEADER) - 1; | ||
| } | ||
|
|
||
| const int prefixSize = std::snprintf(&csvRecord[recordSize], sizeof(csvRecord) - recordSize, "1,%llu,", | ||
| static_cast<unsigned long long>(packetSize)); | ||
| if ((prefixSize < 0) || (static_cast<FwSizeType>(prefixSize) >= (sizeof(csvRecord) - recordSize))) { | ||
| this->log_WARNING_HI_FileError(Fw::LogStringArg("format_record")); | ||
| this->m_failures.fetch_add(1); | ||
| return; | ||
| } | ||
| recordSize += static_cast<FwSizeType>(prefixSize); | ||
|
|
||
| const U8* const packetBytes = packet.getBuffAddr(); | ||
| for (FwSizeType index = 0; index < packetSize; index++) { | ||
| csvRecord[recordSize++] = HEX_DIGITS[(packetBytes[index] >> 4) & 0x0F]; | ||
| csvRecord[recordSize++] = HEX_DIGITS[packetBytes[index] & 0x0F]; | ||
| } | ||
| csvRecord[recordSize++] = '\n'; | ||
|
|
||
| if (currentSize > maxFileSize) { | ||
| this->clearPacketQueue(); | ||
| this->log_WARNING_LO_SizeLimitReached(maxFileSize); | ||
| return; | ||
| } | ||
|
|
||
| this->log_ACTIVITY_LO_WriteStart(); | ||
| Os::File file; | ||
| const Os::File::Status openStatus = file.open(PRE_DEPLOYMENT_TLM_PATH, Os::File::OPEN_APPEND); | ||
| if (openStatus != Os::File::OP_OK) { | ||
| this->log_WARNING_HI_FileError(Fw::LogStringArg("open_append")); | ||
| this->m_failures.fetch_add(1); | ||
| return; | ||
| } | ||
|
|
||
| FwSizeType writtenSize = recordSize; | ||
| const Os::File::Status writeStatus = | ||
| file.write(reinterpret_cast<const U8*>(csvRecord), writtenSize, Os::File::WaitType::WAIT); | ||
| if ((writeStatus != Os::File::OP_OK) || (writtenSize != recordSize)) { | ||
| this->log_WARNING_HI_WriteError(Os::FileStatus(static_cast<Os::FileStatus::T>(writeStatus)), recordSize, | ||
| writtenSize); | ||
| this->m_failures.fetch_add(1); | ||
| file.close(); | ||
| return; | ||
| } | ||
| file.close(); | ||
|
|
||
| this->m_fileSize.fetch_add(static_cast<U32>(writtenSize)); | ||
| } | ||
|
|
||
| } // namespace Components | ||
78 changes: 78 additions & 0 deletions
78
PROVESFlightControllerReference/Components/TlmArchive/TlmArchive.fpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| module Components { | ||
| @ Stores telemetry generated before antenna deployment | ||
| passive component TlmArchive { | ||
| @ Telemetry packet to enqueue for deferred archival | ||
| sync input port comIn: Fw.Com | ||
|
|
||
| @ Drains one queued telemetry packet and performs filesystem work | ||
| sync input port run: Svc.Sched | ||
|
|
||
| @ Port for checking whether antenna deployment has completed | ||
| output port deploymentStateGet: Components.GetDeploymentState | ||
|
|
||
| @ Maximum archive size in bytes | ||
| param MAX_FILE_SIZE: U32 default 50000 id 0 | ||
|
|
||
| @ Number of counted filesystem failures that disables archiving | ||
| param MAX_FAILURES: U32 default 3 id 1 | ||
|
|
||
| @ Report when file write has started | ||
| event WriteStart severity activity low format "Beginning telemetry archival to pre_deployment.csv" throttle 1 | ||
|
|
||
| @ Reports that a packet could not be enqueued because the queue is full | ||
| event QueueFull( | ||
| capacity: FwSizeType @< Maximum number of queued telemetry packets | ||
| ) severity warning high format "Telemetry archive packet queue is full at {} packets" throttle 1 | ||
|
|
||
| @ Reports archive initialization, size, and open failures | ||
| event FileError( | ||
| operation: string @< Filesystem operation that failed | ||
| ) severity warning high \ | ||
| format "Pre-deployment telemetry archive operation failed: {}" | ||
|
|
||
| @ Reports failed and incomplete archive writes | ||
| event WriteError( | ||
| status: Os.FileStatus @< File write status | ||
| requested: FwSizeType @< Requested byte count | ||
| written: FwSizeType @< Reported byte count | ||
| ) severity warning high \ | ||
| format "Pre-deployment telemetry archive write failed: status {}, requested {}, wrote {}" | ||
|
|
||
| @ Reports when telemetry archiving is disabled due to hitting the failure limit | ||
| event FailureLimitReached( | ||
| count: U32 | ||
| ) severity warning high format "{} filesystem failures counted; disabling further telemetry writes." throttle 1 | ||
|
|
||
| @ Reports when telemetry archiving is disabled due to antennas being deployed | ||
| event AntennasDeployed() severity warning low format "Antennas deployed; disabling further telemetry writes." throttle 1 | ||
|
|
||
| @ Reports when telemetry archiving is disabled due to pre_deployment.csv hitting the size limit | ||
| event SizeLimitReached( | ||
| maxSize: U32 | ||
| ) severity warning low format "pre_deployment.csv file size limit of {}b reached; disabling further telemetry writes." throttle 1 | ||
|
|
||
| @ Port for requesting the current time | ||
| time get port timeCaller | ||
|
|
||
| @ Port for sending command registrations | ||
| command reg port cmdRegOut | ||
|
|
||
| @ Port for receiving commands | ||
| command recv port cmdIn | ||
|
|
||
| @ Port for sending command responses | ||
| command resp port cmdResponseOut | ||
|
|
||
| @ Port for sending textual representation of events | ||
| text event port logTextOut | ||
|
|
||
| @ Port for sending events to downlink | ||
| event port logOut | ||
|
|
||
| @ Port for getting parameter values | ||
| param get port prmGetOut | ||
|
|
||
| @ Port for setting parameter values | ||
| param set port prmSetOut | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Keep failed deployments marked as not deployed.
finishDeployment()writestruefor bothDEPLOY_RESULT_SUCCESSandDEPLOY_RESULT_FAILED(Lines 226-231). After retries are exhausted, this handler reports deployed, soTlmArchivestops archiving and futureDEPLOYcommands are rejected.Proposed fix
🤖 Prompt for AI Agents