F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
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>
15 #include <Svc/TlmChan/TlmChan.hpp>
16 
17 namespace Svc {
18 
19 TlmChan::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 
49 void TlmChan::pingIn_handler(const NATIVE_INT_TYPE portNum, U32 key) {
50  // return key
51  this->pingOut_out(0, key);
52 }
53 
54 void 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 
81 void 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 
131 void 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
Definition: Time.hpp:9
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.