F´ Flight Software - C/C++ Documentation
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 return (id % TLMCHAN_HASH_MOD_VALUE) % TLMCHAN_NUM_TLM_HASH_SLOTS;
47}
48
49void TlmChan::pingIn_handler(const NATIVE_INT_TYPE portNum, U32 key) {
50 // return key
51 this->pingOut_out(0, key);
52}
53
54void TlmChan::TlmGet_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) {
55 // Compute index for entry
56
57 NATIVE_UINT_TYPE index = this->doHash(id);
58
59 // Search to see if channel has been stored
60 TlmEntry* entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index];
61 for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) {
62 if (entryToUse) { // If bucket exists, check id
63 if (entryToUse->id == id) {
64 break;
65 } else { // otherwise go to next bucket
66 entryToUse = entryToUse->next;
67 }
68 } else { // no buckets left to search
69 break;
70 }
71 }
72
73 if (entryToUse) {
74 val = entryToUse->buffer;
75 timeTag = entryToUse->lastUpdate;
76 } else { // requested entry may not be written yet; empty buffer
77 val.resetSer();
78 }
79}
80
81void TlmChan::TlmRecv_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) {
82 // Compute index for entry
83
84 NATIVE_UINT_TYPE index = this->doHash(id);
85 TlmEntry* entryToUse = nullptr;
86 TlmEntry* prevEntry = nullptr;
87
88 // Search to see if channel has already been stored or a bucket needs to be added
89 if (this->m_tlmEntries[this->m_activeBuffer].slots[index]) {
90 entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index];
91 for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) {
92 if (entryToUse) {
93 if (entryToUse->id == id) { // found the matching entry
94 break;
95 } else { // try next entry
96 prevEntry = entryToUse;
97 entryToUse = entryToUse->next;
98 }
99 } else {
100 // Make sure that we haven't run out of buckets
101 FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS);
102 // add new bucket from free list
103 entryToUse =
104 &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++];
105 FW_ASSERT(prevEntry);
106 prevEntry->next = entryToUse;
107 // clear next pointer
108 entryToUse->next = nullptr;
109 break;
110 }
111 }
112 } else {
113 // Make sure that we haven't run out of buckets
114 FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS);
115 // create new entry at slot head
116 this->m_tlmEntries[this->m_activeBuffer].slots[index] =
117 &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++];
118 entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index];
119 entryToUse->next = nullptr;
120 }
121
122 // copy into entry
123 FW_ASSERT(entryToUse);
124 entryToUse->used = true;
125 entryToUse->id = id;
126 entryToUse->updated = true;
127 entryToUse->lastUpdate = timeTag;
128 entryToUse->buffer = val;
129}
130
131void TlmChan::Run_handler(NATIVE_INT_TYPE portNum, U32 context) {
132 // Only write packets if connected
133 if (not this->isConnected_PktSend_OutputPort(0)) {
134 return;
135 }
136
137 // lock mutex long enough to modify active telemetry buffer
138 // so the data can be read without worrying about updates
139 this->lock();
140 this->m_activeBuffer = 1 - this->m_activeBuffer;
141 // set activeBuffer to not updated
142 for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) {
143 this->m_tlmEntries[this->m_activeBuffer].buckets[entry].updated = false;
144 }
145 this->unLock();
146
147 // go through each entry and send a packet if it has been updated
148 Fw::TlmPacket pkt;
149 pkt.resetPktSer();
150
151 for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) {
152 TlmEntry* p_entry = &this->m_tlmEntries[1 - this->m_activeBuffer].buckets[entry];
153 if ((p_entry->updated) && (p_entry->used)) {
154 Fw::SerializeStatus stat = pkt.addValue(p_entry->id, p_entry->lastUpdate, p_entry->buffer);
155
156 // check to see if this packet is full, if so, send it
157 if (Fw::FW_SERIALIZE_NO_ROOM_LEFT == stat) {
158 this->PktSend_out(0, pkt.getBuffer(), 0);
159 // reset packet for more entries
160 pkt.resetPktSer();
161 // add entry to new packet
162 stat = pkt.addValue(p_entry->id, p_entry->lastUpdate, p_entry->buffer);
163 // if this doesn't work, that means packet isn't big enough for
164 // even one channel, so assert
165 FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast<NATIVE_INT_TYPE>(stat));
166 } else if (Fw::FW_SERIALIZE_OK == stat) {
167 // if there was still room, do nothing move on to the next channel in the packet
168 } else // any other status is an assert, since it shouldn't happen
169 {
170 FW_ASSERT(0, static_cast<NATIVE_INT_TYPE>(stat));
171 }
172 // flag as updated
173 p_entry->updated = false;
174 } // end if entry was updated
175 } // end for each entry
176
177 // send remnant entries
178 if (pkt.getNumEntries() > 0) {
179 this->PktSend_out(0, pkt.getBuffer(), 0);
180 }
181} // end run handler
182
183} // namespace Svc
#define FW_ASSERT(...)
Definition Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition BasicTypes.h:55
PlatformUIntType NATIVE_UINT_TYPE
Definition BasicTypes.h:56
U32 FwChanIdType
Definition FpConfig.h:95
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
Auto-generated base for TlmChan component.
virtual void unLock()
Unlock the guarded mutex.
void PktSend_out(FwIndexType portNum, Fw::ComBuffer &data, U32 context)
Invoke output port PktSend.
bool isConnected_PktSend_OutputPort(FwIndexType portNum)
void pingOut_out(FwIndexType portNum, U32 key)
Invoke output port pingOut.
virtual void lock()
Lock the guarded mutex.
virtual NATIVE_UINT_TYPE doHash(FwChanIdType id)
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.