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