F´ Flight Software - C/C++ Documentation NASA-v1.6.0
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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.