F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
TlmPacketizer.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title TlmPacketizerImpl.cpp
3 // \author tcanham
4 // \brief cpp file for TlmPacketizer component implementation class
5 //
6 // \copyright
7 // Copyright 2009-2015, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 
11 #include <Fw/Com/ComPacket.hpp>
12 #include <Fw/FPrimeBasicTypes.hpp>
14 #include <cstring>
15 
16 namespace Svc {
17 
18 const TlmPacketizer_TelemetrySendPortMap TlmPacketizer::TELEMETRY_SEND_PORT_MAP = {};
19 
20 static_assert(Svc::TelemetrySection::NUM_SECTIONS >= 1, "At least one telemetry section is required");
21 
22 // ----------------------------------------------------------------------
23 // Construction, initialization, and destruction
24 // ----------------------------------------------------------------------
25 
26 TlmPacketizer ::TlmPacketizer(const char* const compName)
27  : TlmPacketizerComponentBase(compName), m_numPackets(0), m_configured(false) {
28  // clear slot pointers
29  for (FwChanIdType entry = 0; entry < TLMPACKETIZER_NUM_TLM_HASH_SLOTS; entry++) {
30  this->m_tlmEntries.slots[entry] = nullptr;
31  }
32  // clear buckets
33  for (FwChanIdType entry = 0; entry < TLMPACKETIZER_HASH_BUCKETS; entry++) {
34  this->m_tlmEntries.buckets[entry].used = false;
35  this->m_tlmEntries.buckets[entry].bucketNo = entry;
36  this->m_tlmEntries.buckets[entry].next = nullptr;
37  this->m_tlmEntries.buckets[entry].id = 0;
38  }
39  // clear free index
40  this->m_tlmEntries.free = 0;
41  // clear missing tlm channel check
42  for (FwChanIdType entry = 0; entry < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; entry++) {
43  this->m_missTlmCheck[entry].checked = false;
44  this->m_missTlmCheck[entry].id = 0;
45  }
46 
47  // clear packet buffers
48  for (FwChanIdType buffer = 0; buffer < MAX_PACKETIZER_PACKETS; buffer++) {
49  this->m_fillBuffers[buffer].updated = false;
50  this->m_sendBuffers[buffer].updated = false;
51  }
52 
53  // enable sections
54  for (FwIndexType section = 0; section < TelemetrySection::NUM_SECTIONS; section++) {
55  (void)(this->m_sectionEnabled[static_cast<FwSizeType>(section)] = Fw::Enabled::ENABLED);
56  }
57 
59  "NUM_CONFIGURABLE_TLMPACKETIZER_GROUPS MUST BE MAX_CONFIGURABLE_TLMPACKETIZER_GROUP + 1");
60 }
61 
63 
65  const Svc::TlmPacketizerPacket& ignoreList,
66  const FwChanIdType startLevel,
67  const TlmPacketizer_GroupConfig& defaultGroupConfig) {
68  FW_ASSERT(packetList.list);
69  FW_ASSERT(ignoreList.list);
70  FW_ASSERT(packetList.numEntries <= MAX_PACKETIZER_PACKETS, static_cast<FwAssertArgType>(packetList.numEntries));
71  // validate packet sizes against maximum com buffer size and populate hash
72  // table
73  FwChanIdType maxLevel = 0;
74  for (FwChanIdType pktEntry = 0; pktEntry < packetList.numEntries; pktEntry++) {
75  // Initial size is packetized telemetry descriptor + size of time tag + sizeof packet ID
76  FwSizeType packetLen =
78  FW_ASSERT(packetList.list[pktEntry]->list, static_cast<FwAssertArgType>(pktEntry));
79  // add up entries for each defined packet
80  for (FwChanIdType tlmEntry = 0; tlmEntry < packetList.list[pktEntry]->numEntries; tlmEntry++) {
81  // get hash value for id
82  FwChanIdType id = packetList.list[pktEntry]->list[tlmEntry].id;
83  TlmEntry* entryToUse = this->findBucket(id);
84  // copy into entry
85  FW_ASSERT(entryToUse);
86  entryToUse->used = true;
87  // not ignored channel
88  entryToUse->ignored = false;
89  entryToUse->id = id;
90  entryToUse->hasValue = false;
91  entryToUse->channelSize = packetList.list[pktEntry]->list[tlmEntry].size;
92  // the offset into the buffer will be the current packet length
93  // the offset must fit within FwSignedSizeType to allow for negative values
94  FW_ASSERT(packetLen <= static_cast<FwSizeType>(std::numeric_limits<FwSignedSizeType>::max()),
95  static_cast<FwAssertArgType>(packetLen));
96  entryToUse->packetOffset[pktEntry] = static_cast<FwSignedSizeType>(packetLen);
97 
98  packetLen += entryToUse->channelSize;
99 
100  } // end channel in packet
101  FW_ASSERT(packetLen <= FW_COM_BUFFER_MAX_SIZE, static_cast<FwAssertArgType>(packetLen),
102  static_cast<FwAssertArgType>(pktEntry));
103  // clear contents
104  memset(this->m_fillBuffers[pktEntry].buffer.getBuffAddr(), 0, static_cast<size_t>(packetLen));
105  // serialize packet descriptor and packet ID now since it will always be the same
106  Fw::SerializeStatus stat = this->m_fillBuffers[pktEntry].buffer.serializeFrom(
107  static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_PACKETIZED_TLM));
108  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
109  stat = this->m_fillBuffers[pktEntry].buffer.serializeFrom(packetList.list[pktEntry]->id);
110  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
111  // set packet buffer length
112  stat = this->m_fillBuffers[pktEntry].buffer.setBuffLen(packetLen);
113  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
114  // save ID
115  this->m_fillBuffers[pktEntry].id = packetList.list[pktEntry]->id;
116  // save level
117  this->m_fillBuffers[pktEntry].level = packetList.list[pktEntry]->level;
118  // store max level
119  if (packetList.list[pktEntry]->level > maxLevel) {
120  maxLevel = packetList.list[pktEntry]->level;
121  }
122 
123  } // end packet list
124  FW_ASSERT(maxLevel <= MAX_CONFIGURABLE_TLMPACKETIZER_GROUP, static_cast<FwAssertArgType>(maxLevel));
125 
126  // Enable and set group configurations
127  for (FwIndexType section = 0; section < TelemetrySection::NUM_SECTIONS; section++) {
128  for (FwChanIdType group = 0; group < NUM_CONFIGURABLE_TLMPACKETIZER_GROUPS; group++) {
129  Fw::Enabled groupEnabled = group <= startLevel ? Fw::Enabled::ENABLED : Fw::Enabled::DISABLED;
130  this->m_groupConfigs[static_cast<FwSizeType>(section)][group] = defaultGroupConfig;
131  this->m_groupConfigs[static_cast<FwSizeType>(section)][group].set_enabled(groupEnabled);
132  }
133  }
134 
135  // populate hash table with ignore list
136  for (FwChanIdType channelEntry = 0; channelEntry < ignoreList.numEntries; channelEntry++) {
137  // get hash value for id
138  FwChanIdType id = ignoreList.list[channelEntry].id;
139 
140  TlmEntry* entryToUse = this->findBucket(id);
141 
142  // copy into entry
143  FW_ASSERT(entryToUse);
144  entryToUse->used = true;
145  // is ignored channel
146  entryToUse->ignored = true;
147  entryToUse->id = id;
148  entryToUse->hasValue = false;
149  entryToUse->channelSize = ignoreList.list[channelEntry].size;
150  } // end ignore list
151 
152  // store number of packets
153  this->m_numPackets = packetList.numEntries;
154 
155  // indicate configured
156  this->m_configured = true;
157 }
158 
159 TlmPacketizer::TlmEntry* TlmPacketizer::findBucket(FwChanIdType id) {
160  FwChanIdType index = this->doHash(id);
162  TlmEntry* entryToUse = nullptr;
163  TlmEntry* prevEntry = nullptr;
164 
165  // Search to see if channel has already been stored or a bucket needs to be added
166  if (this->m_tlmEntries.slots[index]) {
167  entryToUse = this->m_tlmEntries.slots[index];
168  for (FwChanIdType bucket = 0; bucket < TLMPACKETIZER_HASH_BUCKETS; bucket++) {
169  if (entryToUse) {
170  if (entryToUse->id == id) { // found the matching entry
171  break;
172  } else { // try next entry
173  prevEntry = entryToUse;
174  entryToUse = entryToUse->next;
175  }
176  } else {
177  // Make sure that we haven't run out of buckets
178  FW_ASSERT(this->m_tlmEntries.free < TLMPACKETIZER_HASH_BUCKETS,
179  static_cast<FwAssertArgType>(this->m_tlmEntries.free));
180  // add new bucket from free list
181  entryToUse = &this->m_tlmEntries.buckets[this->m_tlmEntries.free++];
182  // Coverity warning about null dereference - see if it happens
183  FW_ASSERT(prevEntry);
184  prevEntry->next = entryToUse;
185  // clear next pointer
186  entryToUse->next = nullptr;
187  // set all packet offsets to -1 for new entry
188  for (FwChanIdType pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) {
189  entryToUse->packetOffset[pktOffsetEntry] = -1;
190  }
191  break;
192  }
193  }
194  } else {
195  // Make sure that we haven't run out of buckets
196  FW_ASSERT(this->m_tlmEntries.free < TLMPACKETIZER_HASH_BUCKETS,
197  static_cast<FwAssertArgType>(this->m_tlmEntries.free));
198  // create new entry at slot head
199  this->m_tlmEntries.slots[index] = &this->m_tlmEntries.buckets[this->m_tlmEntries.free++];
200  entryToUse = this->m_tlmEntries.slots[index];
201  entryToUse->next = nullptr;
202  // set all packet offsets to -1 for new entry
203  for (FwChanIdType pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) {
204  entryToUse->packetOffset[pktOffsetEntry] = -1;
205  }
206  }
207 
208  return entryToUse;
209 }
210 
211 // ----------------------------------------------------------------------
212 // Handler implementations for user-defined typed input ports
213 // ----------------------------------------------------------------------
214 
215 void TlmPacketizer ::TlmRecv_handler(const FwIndexType portNum,
216  FwChanIdType id,
217  Fw::Time& timeTag,
218  Fw::TlmBuffer& val) {
219  FW_ASSERT(this->m_configured);
220  // get hash value for id
221  FwChanIdType index = this->doHash(id);
222  TlmEntry* entryToUse = nullptr;
223 
224  // Search to see if the channel is being sent
225  entryToUse = this->m_tlmEntries.slots[index];
226 
227  // if no entries at hash, channel not part of a packet or is not ignored
228  if (not entryToUse) {
229  this->missingChannel(id);
230  return;
231  }
232 
233  for (FwChanIdType bucket = 0; bucket < TLMPACKETIZER_HASH_BUCKETS; bucket++) {
234  if (entryToUse) {
235  if (entryToUse->id == id) { // found the matching entry
236  // check to see if the channel is ignored. If so, just return.
237  if (entryToUse->ignored) {
238  return;
239  }
240  break;
241  } else { // try next entry
242  entryToUse = entryToUse->next;
243  }
244  } else {
245  // telemetry channel not in any packets
246  this->missingChannel(id);
247  return;
248  }
249  }
250 
251  // copy telemetry value into active buffers
252  for (FwChanIdType pkt = 0; pkt < MAX_PACKETIZER_PACKETS; pkt++) {
253  // check if current packet has this channel
254  if (entryToUse->packetOffset[pkt] != -1) {
255  // get destination address
256  this->m_lock.lock();
257  this->m_fillBuffers[pkt].updated = true;
258  this->m_fillBuffers[pkt].latestTime = timeTag;
259  U8* ptr = &this->m_fillBuffers[pkt].buffer.getBuffAddr()[entryToUse->packetOffset[pkt]];
260  (void)memcpy(ptr, val.getBuffAddr(), static_cast<size_t>(val.getSize()));
261  // record that this chan has a value. could do this outside of the loop only once
262  // but then we'd need to grab the lock again.
263  entryToUse->hasValue = true;
264  this->m_lock.unLock();
265  }
266  }
267 }
268 
269 void TlmPacketizer ::configureSectionGroupRate_handler(FwIndexType portNum,
270  const Svc::TelemetrySection& section,
271  FwChanIdType tlmGroup,
272  const Svc::RateLogic& rateLogic,
273  U32 minDelta,
274  U32 maxDelta) {
275  this->configureSectionGroupRate(section, tlmGroup, rateLogic, minDelta, maxDelta);
276 }
277 
279 Fw::TlmValid TlmPacketizer ::TlmGet_handler(FwIndexType portNum,
280  FwChanIdType id,
281  Fw::Time& timeTag,
282  Fw::TlmBuffer& val
283 ) {
285  FW_ASSERT(this->m_configured);
286  // get hash value for id
287  FwChanIdType index = this->doHash(id);
288  TlmEntry* entryToUse = nullptr;
289 
290  // Search to see if the channel is being sent
291  entryToUse = this->m_tlmEntries.slots[index];
292 
293  // if no entries at hash, channel not part of a packet or is not ignored
294  if (not entryToUse) {
295  this->missingChannel(id);
296  val.resetSer();
297  return Fw::TlmValid::INVALID;
298  }
299 
300  for (FwChanIdType bucket = 0; bucket < TLMPACKETIZER_HASH_BUCKETS; bucket++) {
301  if (entryToUse) {
302  if (entryToUse->id == id) { // found the matching entry
303  // check to see if the channel is ignored. If so, just return, as
304  // we don't store the bytes of ignored channels
305  if (entryToUse->ignored) {
306  val.resetSer();
307  return Fw::TlmValid::INVALID;
308  }
309  break;
310  } else { // try next entry
311  entryToUse = entryToUse->next;
312  }
313  } else {
314  // telemetry channel not in any packets
315  this->missingChannel(id);
316  val.resetSer();
317  return Fw::TlmValid::INVALID;
318  }
319  }
320 
321  if (!entryToUse->hasValue) {
322  // haven't received a value yet for this entry.
323  val.resetSer();
324  return Fw::TlmValid::INVALID;
325  }
326 
327  // make sure we have enough space to store this entry in our buf
328  FW_ASSERT(entryToUse->channelSize <= val.getCapacity(), static_cast<FwAssertArgType>(entryToUse->channelSize),
329  static_cast<FwAssertArgType>(val.getCapacity()));
330 
331  // okay, we have the matching entry.
332  // go over each packet and find the first one which stores this channel
333 
334  for (FwChanIdType pkt = 0; pkt < MAX_PACKETIZER_PACKETS; pkt++) {
335  // check if current packet has this channel
336  if (entryToUse->packetOffset[pkt] != -1) {
337  // okay, it has the channel. copy chan val into the tlm buf
338  this->m_lock.lock();
339  timeTag = this->m_fillBuffers[pkt].latestTime;
340  U8* ptr = &this->m_fillBuffers[pkt].buffer.getBuffAddr()[entryToUse->packetOffset[pkt]];
341  (void)memcpy(val.getBuffAddr(), ptr, static_cast<size_t>(entryToUse->channelSize));
342  // set buf len to the channelSize. keep in mind, this is the MAX serialized size of the channel.
343  // so we may actually be filling val with some junk after the value of the channel.
344  FW_ASSERT(val.setBuffLen(entryToUse->channelSize) == Fw::SerializeStatus::FW_SERIALIZE_OK);
345  this->m_lock.unLock();
346  return Fw::TlmValid::VALID;
347  }
348  }
349 
350  // did not find a packet which stores this channel.
351  // coding error, this was not an ignored channel so it must be in a packet somewhere
352  FW_ASSERT(0, static_cast<FwAssertArgType>(entryToUse->id));
353  // TPP (tim paranoia principle)
354  val.resetSer();
355  return Fw::TlmValid::INVALID;
356 }
357 
358 void TlmPacketizer ::Run_handler(const FwIndexType portNum, U32 context) {
359  FW_ASSERT(this->m_configured);
360 
361  // lock mutex long enough to copy fill buffers to send buffers
362  // so the data can be read without worrying about updates
363  this->m_lock.lock();
364  // copy buffers from fill side to send side
365  for (FwChanIdType pkt = 0; pkt < this->m_numPackets; pkt++) {
366  if (this->m_fillBuffers[pkt].updated == true) {
367  (void)(this->m_sendBuffers[pkt] = this->m_fillBuffers[pkt]);
368  }
369  this->m_fillBuffers[pkt].updated = false;
370  }
371  this->m_lock.unLock();
372 
373  // push all updated packet buffers
374  for (FwChanIdType pkt = 0; pkt < this->m_numPackets; pkt++) {
375  FwChanIdType entryGroup = this->m_sendBuffers[pkt].level;
376 
377  // Iterate through output sections
378  for (FwIndexType section = 0; section < TelemetrySection::NUM_SECTIONS; section++) {
379  // Packet is updated and not REQUESTED (Keep REQUESTED marking to bypass disable checks)
380  if (this->m_sendBuffers[pkt].updated and
381  this->m_packetFlags[section][pkt].updateFlag != UpdateFlag::REQUESTED) {
382  this->m_packetFlags[section][pkt].updateFlag = UpdateFlag::NEW;
383  }
384 
385  bool sendOutFlag = false;
386  const FwIndexType outIndex = this->sectionGroupToPort(section, entryGroup);
387 
388  PktSendCounters& pktEntryFlags = this->m_packetFlags[static_cast<FwSizeType>(section)][pkt];
389  TlmPacketizer_GroupConfig& entryGroupConfig =
390  this->m_groupConfigs[static_cast<FwSizeType>(section)][entryGroup];
391 
392  /* Base conditions for sending
393  1. Output port is connected
394  2. The packet was requested (Override Checks).
395 
396  If the packet wasn't requested:
397  3. The Section and Group in Section is enabled OR the Group in Section is force enabled
398  4. The rate logic is not SILENCED.
399  5. The packet has data (marked updated in the past or new)
400  */
401  if (not this->isConnected_PktSend_OutputPort(outIndex)) {
402  continue;
403  }
404  if (pktEntryFlags.updateFlag == UpdateFlag::REQUESTED) {
405  sendOutFlag = true;
406  } else {
407  if (not((entryGroupConfig.get_enabled() and
408  this->m_sectionEnabled[static_cast<FwSizeType>(section)] == Fw::Enabled::ENABLED) or
409  entryGroupConfig.get_forceEnabled() == Fw::Enabled::ENABLED)) {
410  continue;
411  }
412  if (entryGroupConfig.get_rateLogic() == Svc::RateLogic::SILENCED) {
413  continue;
414  }
415  if (pktEntryFlags.updateFlag == UpdateFlag::NEVER_UPDATED) {
416  continue; // Avoid No Data
417  }
418  }
419 
420  // Update Counter, prevent overflow.
421  if (pktEntryFlags.prevSentCounter < std::numeric_limits<U32>::max()) {
422  pktEntryFlags.prevSentCounter++;
423  }
424 
425  /*
426  1. Packet has been updated
427  2. Group Logic includes checking MIN
428  3. Packet sent counter at MIN
429  */
430  if (pktEntryFlags.updateFlag == UpdateFlag::NEW and
431  entryGroupConfig.get_rateLogic() != Svc::RateLogic::EVERY_MAX and
432  pktEntryFlags.prevSentCounter >= entryGroupConfig.get_min()) {
433  sendOutFlag = true;
434  }
435 
436  /*
437  1. Group Logic includes checking MAX
438  2. Packet set counter is at MAX
439  */
440  if (entryGroupConfig.get_rateLogic() != Svc::RateLogic::ON_CHANGE_MIN and
441  pktEntryFlags.prevSentCounter >= entryGroupConfig.get_max()) {
442  sendOutFlag = true;
443  }
444 
445  // Send under the following conditions:
446  // 1. Packet received updates and it has been past delta min counts since last packet (min enabled)
447  // 2. Packet has passed delta max counts since last packet (max enabled)
448  // With the above, the group must be either enabled or force enabled.
449  // 3. If the packet was requested.
450  if (sendOutFlag) {
451  // serialize time into time offset in packet
453  &this->m_sendBuffers[pkt]
454  .buffer.getBuffAddr()[sizeof(FwPacketDescriptorType) + sizeof(FwTlmPacketizeIdType)],
456  Fw::SerializeStatus stat = buff.serializeFrom(this->m_sendBuffers[pkt].latestTime);
457  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
458  this->PktSend_out(outIndex, this->m_sendBuffers[pkt].buffer, pktEntryFlags.prevSentCounter);
459  pktEntryFlags.prevSentCounter = 0;
460  pktEntryFlags.updateFlag = UpdateFlag::PAST;
461  }
462  }
463  this->m_sendBuffers[pkt].updated = false;
464  }
465 }
466 
467 void TlmPacketizer ::controlIn_handler(FwIndexType portNum,
468  const Svc::TelemetrySection& section,
469  const Fw::Enabled& enabled) {
470  FW_ASSERT(section.isValid());
471  FW_ASSERT(enabled.isValid());
472  if (0 <= section && section < TelemetrySection::NUM_SECTIONS) {
473  (void)(this->m_sectionEnabled[static_cast<FwSizeType>(section)] = enabled);
474  } else {
475  this->log_WARNING_LO_SectionUnconfigurable(section, enabled);
476  }
477 }
478 
479 void TlmPacketizer ::pingIn_handler(const FwIndexType portNum, U32 key) {
480  // return key
481  this->pingOut_out(0, key);
482 }
483 
484 // ----------------------------------------------------------------------
485 // Command handler implementations
486 // ----------------------------------------------------------------------
487 
488 void TlmPacketizer ::SET_LEVEL_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, FwChanIdType level) {
491  }
492  for (FwIndexType section = 0; section < TelemetrySection::NUM_SECTIONS; section++) {
493  for (FwChanIdType group = 0; group < NUM_CONFIGURABLE_TLMPACKETIZER_GROUPS; group++) {
494  this->m_groupConfigs[static_cast<FwSizeType>(section)][group].set_enabled(
495  group <= level ? Fw::Enabled::ENABLED : Fw::Enabled::DISABLED);
496  }
497  }
498  this->tlmWrite_GroupConfigs(this->m_groupConfigs);
499  this->log_ACTIVITY_HI_LevelSet(level);
500  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
501 }
502 
503 void TlmPacketizer ::SEND_PKT_cmdHandler(const FwOpcodeType opCode,
504  const U32 cmdSeq,
505  const U32 id,
506  const Svc::TelemetrySection section) {
507  FW_ASSERT(section.isValid());
508  FwChanIdType pkt = 0;
509  for (pkt = 0; pkt < this->m_numPackets; pkt++) {
510  if (this->m_fillBuffers[pkt].id == id) {
511  this->m_lock.lock();
512  this->m_fillBuffers[pkt].updated = true;
513  this->m_fillBuffers[pkt].latestTime = this->getTime();
514  this->m_lock.unLock();
515 
516  this->m_packetFlags[section][pkt].updateFlag = UpdateFlag::REQUESTED;
517 
518  this->log_ACTIVITY_LO_PacketSent(id);
519  break;
520  }
521  }
522 
523  // couldn't find it
524  if (pkt == this->m_numPackets) {
526  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
527  return;
528  }
529 
530  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
531 }
532 
533 void TlmPacketizer ::ENABLE_SECTION_cmdHandler(FwOpcodeType opCode,
534  U32 cmdSeq,
535  Svc::TelemetrySection section,
536  Fw::Enabled enable) {
537  FW_ASSERT(section.isValid());
538  FW_ASSERT(enable.isValid());
539  if (section < 0 or section >= TelemetrySection::NUM_SECTIONS) {
540  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
541  return;
542  }
543  (void)(this->m_sectionEnabled[section] = enable);
544  this->tlmWrite_SectionEnabled(this->m_sectionEnabled);
545  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
546 }
547 
548 void TlmPacketizer ::ENABLE_GROUP_cmdHandler(FwOpcodeType opCode,
549  U32 cmdSeq,
550  Svc::TelemetrySection section,
551  FwChanIdType tlmGroup,
552  Fw::Enabled enable) {
553  FW_ASSERT(section.isValid());
554  FW_ASSERT(enable.isValid());
555  if ((0 <= section and section >= TelemetrySection::NUM_SECTIONS) or
557  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
558  return;
559  }
560  this->m_groupConfigs[section][tlmGroup].set_enabled(enable);
561  this->tlmWrite_GroupConfigs(this->m_groupConfigs);
562  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
563 }
564 
565 void TlmPacketizer ::FORCE_GROUP_cmdHandler(FwOpcodeType opCode,
566  U32 cmdSeq,
567  Svc::TelemetrySection section,
568  FwChanIdType tlmGroup,
569  Fw::Enabled enable) {
570  FW_ASSERT(section.isValid());
571  FW_ASSERT(enable.isValid());
572  if (section < 0 or section >= TelemetrySection::NUM_SECTIONS or tlmGroup > MAX_CONFIGURABLE_TLMPACKETIZER_GROUP) {
573  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
574  return;
575  }
576  this->m_groupConfigs[section][tlmGroup].set_forceEnabled(enable);
577  this->tlmWrite_GroupConfigs(this->m_groupConfigs);
578  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
579 }
580 
581 void TlmPacketizer ::CONFIGURE_GROUP_RATES_cmdHandler(FwOpcodeType opCode,
582  U32 cmdSeq,
583  Svc::TelemetrySection section,
584  FwChanIdType tlmGroup,
585  Svc::RateLogic rateLogic,
586  U32 minDelta,
587  U32 maxDelta) {
588  FW_ASSERT(section.isValid());
589  FW_ASSERT(rateLogic.isValid());
590  if (section < 0 or section >= TelemetrySection::NUM_SECTIONS or tlmGroup > MAX_CONFIGURABLE_TLMPACKETIZER_GROUP) {
591  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
592  return;
593  }
594  this->configureSectionGroupRate(section, tlmGroup, rateLogic, minDelta, maxDelta);
595  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
596 }
597 
598 void TlmPacketizer::configureSectionGroupRate(
599  const Svc::TelemetrySection& section,
600  FwChanIdType tlmGroup,
601  const Svc::RateLogic& rateLogic,
602  U32 minDelta,
603  U32 maxDelta
604 ) {
605  FW_ASSERT(section.isValid());
606  FW_ASSERT(rateLogic.isValid());
607  // These two asserts are an "if" statement in a command so they will no assert on bad user data
608  FW_ASSERT(section >= 0 and section < TelemetrySection::NUM_SECTIONS);
610 
611  TlmPacketizer_GroupConfig& groupConfig = this->m_groupConfigs[section][tlmGroup];
612  groupConfig.set_rateLogic(rateLogic);
613  groupConfig.set_min(minDelta);
614  groupConfig.set_max(maxDelta);
615  this->tlmWrite_GroupConfigs(this->m_groupConfigs);
616 }
617 
618 FwIndexType TlmPacketizer::sectionGroupToPort(const FwIndexType section, const FwSizeType group) {
619  // Confirm the indices will not overflow the size of the array
620  FW_ASSERT(group < TlmPacketizer_TelemetrySendSection::SIZE, static_cast<FwAssertArgType>(group));
621  FW_ASSERT(section < TlmPacketizer_TelemetrySendPortMap::SIZE, static_cast<FwAssertArgType>(section));
622 
623  const FwIndexType outIndex = TlmPacketizer::TELEMETRY_SEND_PORT_MAP[static_cast<FwSizeType>(section)][group];
624 
625  // Confirm the output port index is within the valid number of telemetry send ports
626  FW_ASSERT(outIndex < TELEMETRY_SEND_PORTS, static_cast<FwAssertArgType>(outIndex));
627  return outIndex;
628 }
629 
630 FwChanIdType TlmPacketizer::doHash(FwChanIdType id) {
632 }
633 
634 void TlmPacketizer::missingChannel(FwChanIdType id) {
635  // search to see if missing channel has already been sent
636  for (FwChanIdType slot = 0; slot < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; slot++) {
637  // if it's been checked, return
638  if (this->m_missTlmCheck[slot].checked and (this->m_missTlmCheck[slot].id == id)) {
639  return;
640  } else if (not this->m_missTlmCheck[slot].checked) {
641  this->m_missTlmCheck[slot].checked = true;
642  this->m_missTlmCheck[slot].id = id;
643  this->log_WARNING_LO_NoChan(id);
644  return;
645  }
646  }
647 }
648 
649 } // end namespace Svc
Serialization/Deserialization operation was successful.
bool isValid() const
Check raw enum value for validity.
U16 FwPacketDescriptorType
The width of packet descriptors when they are serialized by the framework.
TlmPacketizer(const char *const compName)
REQUIRED: Counter, leave as last element.
FwIdType FwOpcodeType
The type of a command opcode.
SerializeStatus serializeFrom(U8 val, Endianness mode=Endianness::BIG) override
Serialize an 8-bit unsigned integer value.
void setPacketList(const TlmPacketizerPacketList &packetList, const Svc::TlmPacketizerPacket &ignoreList, const FwChanIdType startLevel, const TlmPacketizer_GroupConfig &defaultGroupConfig=TlmPacketizer_GroupConfig{})
FwSizeType size
serialized size of channel in bytes
PlatformSizeType FwSizeType
FwTlmPacketizeIdType id
packet ID
void tlmWrite_GroupConfigs(const Svc::TlmPacketizer_SectionConfigs &arg, Fw::Time _tlmTime=Fw::Time()) const
Enabled state.
static const FwChanIdType TLMPACKETIZER_HASH_BUCKETS
Serializable::SizeType getSize() const override
Get current buffer size.
const TlmPacketizerPacket * list[MAX_PACKETIZER_PACKETS]
void log_WARNING_LO_NoChan(FwChanIdType Id) const
static const FwChanIdType MAX_PACKETIZER_PACKETS
void unLock()
unlock the mutex and assert success
Definition: Mutex.cpp:41
bool isValid() const
Check raw enum value for validity.
PlatformSignedSizeType FwSignedSizeType
void PktSend_out(FwIndexType portNum, Fw::ComBuffer &data, U32 context)
Invoke output port PktSend.
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
static const FwChanIdType TLMPACKETIZER_NUM_TLM_HASH_SLOTS
Send on updates after MIN ticks since last send.
Send every MAX ticks between sends.
const TlmPacketizerChannelEntry * list
pointer to a channel entry
static const FwChanIdType TLMPACKETIZER_MAX_MISSING_TLM_CHECK
void tlmWrite_SectionEnabled(const Svc::TlmPacketizer_SectionEnabled &arg, Fw::Time _tlmTime=Fw::Time()) const
Write telemetry channel SectionEnabled.
SerializeStatus
forward declaration for string
No logic applied. Does not send group and freezes counter.
FwChanIdType id
Id of channel.
FwChanIdType level
packet level - used to select set of packets to send
Enumeration for rate logic types for telemetry groups.
External serialize buffer with no copy semantics.
FwIdType FwChanIdType
The type of a telemetry channel identifier.
static const FwChanIdType TLMPACKETIZER_HASH_MOD_VALUE
U8 * getBuffAddr()
Get buffer address for data filling (non-const version)
Definition: TlmBuffer.cpp:42
void resetSer() override
Reset serialization pointer to beginning of buffer.
Enabled and disabled states.
U16 FwTlmPacketizeIdType
The type of a telemetry packet identifier.
Command successfully executed.
bool isValid() const
Check raw enum value for validity.
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:53
void log_WARNING_LO_SectionUnconfigurable(Svc::TelemetrySection section, Fw::Enabled enable) const
Log event SectionUnconfigurable.
void log_WARNING_LO_MaxLevelExceed(FwChanIdType level, FwChanIdType max) const
PlatformIndexType FwIndexType
FwSizeType getCapacity() const
Get buffer capacity.
Definition: TlmBuffer.cpp:30
void log_ACTIVITY_HI_LevelSet(FwChanIdType id) const
Command failed validation.
RateGroupDivider component implementation.
bool isConnected_PktSend_OutputPort(FwIndexType portNum)
SerializeStatus setBuffLen(Serializable::SizeType length) override
Set buffer length manually.
FwChanIdType numEntries
number of channels in packet
#define FW_ASSERT(...)
Definition: Assert.hpp:14
Disabled state.
void pingOut_out(FwIndexType portNum, U32 key)
Invoke output port pingOut.
PlatformAssertArgType FwAssertArgType
The type of arguments to assert functions.
void lock()
lock the mutex and assert success
Definition: Mutex.cpp:34
Auto-generated base for TlmPacketizer component.