F´ Flight Software - C/C++ Documentation NASA-v1.6.0
A framework for building embedded system applications to NASA flight quality standards.
Loading...
Searching...
No Matches
TlmChan.cpp
Go to the documentation of this file.
1
12#include <FpConfig.hpp>
13#include <Fw/Com/ComBuffer.hpp>
14#include <Fw/Types/Assert.hpp>
16
17namespace Svc {
18
19TlmChan::TlmChan(const char* name) : TlmChanComponentBase(name), m_activeBuffer(0) {
20 // clear slot pointers
21 for (NATIVE_UINT_TYPE entry = 0; entry < TLMCHAN_NUM_TLM_HASH_SLOTS; entry++) {
22 this->m_tlmEntries[0].slots[entry] = nullptr;
23 this->m_tlmEntries[1].slots[entry] = nullptr;
24 }
25 // clear buckets
26 for (NATIVE_UINT_TYPE entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) {
27 this->m_tlmEntries[0].buckets[entry].used = false;
28 this->m_tlmEntries[0].buckets[entry].updated = false;
29 this->m_tlmEntries[0].buckets[entry].bucketNo = entry;
30 this->m_tlmEntries[0].buckets[entry].next = nullptr;
31 this->m_tlmEntries[0].buckets[entry].id = 0;
32 this->m_tlmEntries[1].buckets[entry].used = false;
33 this->m_tlmEntries[1].buckets[entry].updated = false;
34 this->m_tlmEntries[1].buckets[entry].bucketNo = entry;
35 this->m_tlmEntries[1].buckets[entry].next = nullptr;
36 this->m_tlmEntries[1].buckets[entry].id = 0;
37 }
38 // clear free index
39 this->m_tlmEntries[0].free = 0;
40 this->m_tlmEntries[1].free = 0;
41}
42
44
46 NATIVE_INT_TYPE instance
47) {
48 TlmChanComponentBase::init(queueDepth, instance);
49}
50
52 return (id % TLMCHAN_HASH_MOD_VALUE) % TLMCHAN_NUM_TLM_HASH_SLOTS;
53}
54
55void TlmChan::pingIn_handler(const NATIVE_INT_TYPE portNum, U32 key) {
56 // return key
57 this->pingOut_out(0, key);
58}
59
60void TlmChan::TlmGet_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) {
61 // Compute index for entry
62
63 NATIVE_UINT_TYPE index = this->doHash(id);
64
65 // Search to see if channel has been stored
66 TlmEntry* entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index];
67 for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) {
68 if (entryToUse) { // If bucket exists, check id
69 if (entryToUse->id == id) {
70 break;
71 } else { // otherwise go to next bucket
72 entryToUse = entryToUse->next;
73 }
74 } else { // no buckets left to search
75 break;
76 }
77 }
78
79 if (entryToUse) {
80 val = entryToUse->buffer;
81 timeTag = entryToUse->lastUpdate;
82 } else { // requested entry may not be written yet; empty buffer
83 val.resetSer();
84 }
85}
86
87void TlmChan::TlmRecv_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) {
88 // Compute index for entry
89
90 NATIVE_UINT_TYPE index = this->doHash(id);
91 TlmEntry* entryToUse = nullptr;
92 TlmEntry* prevEntry = nullptr;
93
94 // Search to see if channel has already been stored or a bucket needs to be added
95 if (this->m_tlmEntries[this->m_activeBuffer].slots[index]) {
96 entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index];
97 for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) {
98 if (entryToUse) {
99 if (entryToUse->id == id) { // found the matching entry
100 break;
101 } else { // try next entry
102 prevEntry = entryToUse;
103 entryToUse = entryToUse->next;
104 }
105 } else {
106 // Make sure that we haven't run out of buckets
107 FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS);
108 // add new bucket from free list
109 entryToUse =
110 &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++];
111 FW_ASSERT(prevEntry);
112 prevEntry->next = entryToUse;
113 // clear next pointer
114 entryToUse->next = nullptr;
115 break;
116 }
117 }
118 } else {
119 // Make sure that we haven't run out of buckets
120 FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS);
121 // create new entry at slot head
122 this->m_tlmEntries[this->m_activeBuffer].slots[index] =
123 &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++];
124 entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index];
125 entryToUse->next = nullptr;
126 }
127
128 // copy into entry
129 FW_ASSERT(entryToUse);
130 entryToUse->used = true;
131 entryToUse->id = id;
132 entryToUse->updated = true;
133 entryToUse->lastUpdate = timeTag;
134 entryToUse->buffer = val;
135}
136
137void TlmChan::Run_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context) {
138 // Only write packets if connected
139 if (not this->isConnected_PktSend_OutputPort(0)) {
140 return;
141 }
142
143 // lock mutex long enough to modify active telemetry buffer
144 // so the data can be read without worrying about updates
145 this->lock();
146 this->m_activeBuffer = 1 - this->m_activeBuffer;
147 // set activeBuffer to not updated
148 for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) {
149 this->m_tlmEntries[this->m_activeBuffer].buckets[entry].updated = false;
150 }
151 this->unLock();
152
153 // go through each entry and send a packet if it has been updated
154 Fw::TlmPacket pkt;
155 pkt.resetPktSer();
156
157 for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) {
158 TlmEntry* p_entry = &this->m_tlmEntries[1 - this->m_activeBuffer].buckets[entry];
159 if ((p_entry->updated) && (p_entry->used)) {
160 Fw::SerializeStatus stat = pkt.addValue(p_entry->id, p_entry->lastUpdate, p_entry->buffer);
161
162 // check to see if this packet is full, if so, send it
163 if (Fw::FW_SERIALIZE_NO_ROOM_LEFT == stat) {
164 this->PktSend_out(0, pkt.getBuffer(), 0);
165 // reset packet for more entries
166 pkt.resetPktSer();
167 // add entry to new packet
168 Fw::SerializeStatus stat = pkt.addValue(p_entry->id, p_entry->lastUpdate, p_entry->buffer);
169 // if this doesn't work, that means packet isn't big enough for
170 // even one channel, so assert
171 FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast<NATIVE_INT_TYPE>(stat));
172 } else if (Fw::FW_SERIALIZE_OK == stat) {
173 // if there was still room, do nothing move on to the next channel in the packet
174 } else // any other status is an assert, since it shouldn't happen
175 {
176 FW_ASSERT(0, static_cast<NATIVE_INT_TYPE>(stat));
177 }
178 // flag as updated
179 p_entry->updated = false;
180 } // end if entry was updated
181 } // end for each entry
182
183 // send remnant entries
184 if (pkt.getNumEntries() > 0) {
185 this->PktSend_out(0, pkt.getBuffer(), 0);
186 }
187} // end run handler
188
189} // namespace Svc
#define FW_ASSERT(...)
Definition Assert.hpp:7
PlatformIntType NATIVE_INT_TYPE
Definition BasicTypes.h:51
PlatformUIntType NATIVE_UINT_TYPE
Definition BasicTypes.h:52
U32 FwChanIdType
Definition FpConfig.h:59
C++-compatible configuration header for fprime configuration.
Component that stores telemetry channel values.
void resetSer()
reset to beginning of buffer to reuse for serialization
NATIVE_UINT_TYPE getNumEntries()
get the number of packets added via addValue()
Definition TlmPacket.cpp:52
SerializeStatus resetPktSer()
Reset serialization of values. This should be done when starting to accumulate a new set of values.
Definition TlmPacket.cpp:21
Fw::ComBuffer & getBuffer()
get buffer to send to the ground
Definition TlmPacket.cpp:56
SerializeStatus addValue(FwChanIdType id, Time &timeTag, TlmBuffer &buffer)
Add telemetry value to buffer.
Definition TlmPacket.cpp:64
virtual NATIVE_UINT_TYPE doHash(FwChanIdType id)
Definition TlmChan.cpp:51
void init(NATIVE_INT_TYPE queueDepth, NATIVE_INT_TYPE instance)
Definition TlmChan.cpp:45
virtual ~TlmChan()
Definition TlmChan.cpp:43
TlmChan(const char *compName)
Definition TlmChan.cpp:19
SerializeStatus
forward declaration for string
@ FW_SERIALIZE_OK
Serialization/Deserialization operation was successful.
@ FW_SERIALIZE_NO_ROOM_LEFT
No room left in the buffer to serialize data.