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>
15 #include <cstring>
16 
17 namespace Svc {
18 
19 const TlmPacketizer_TelemetrySendPortMap TlmPacketizer::TELEMETRY_SEND_PORT_MAP = {};
20 
21 static_assert(Svc::TelemetrySection::NUM_SECTIONS >= 1, "At least one telemetry section is required");
22 
23 // ----------------------------------------------------------------------
24 // Construction, initialization, and destruction
25 // ----------------------------------------------------------------------
26 
27 TlmPacketizer ::TlmPacketizer(const char* const compName)
28  : TlmPacketizerComponentBase(compName), m_numPackets(0), m_configured(false), m_numChannels(0) {
29  // Register self as parameter delegate
30  this->registerExternalParameters(this);
31  // clear missing tlm channel check
32  for (FwChanIdType entry = 0; entry < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; entry++) {
33  this->m_missTlmCheck[entry].checked = false;
34  this->m_missTlmCheck[entry].id = 0;
35  }
36 
37  // clear packet buffers
38  for (FwChanIdType buffer = 0; buffer < MAX_PACKETIZER_PACKETS; buffer++) {
39  this->m_fillBuffers[buffer].updated = false;
40  }
41 
43  "NUM_CONFIGURABLE_TLMPACKETIZER_GROUPS MUST BE MAX_CONFIGURABLE_TLMPACKETIZER_GROUP + 1");
44 }
45 
47 
49  const Svc::TlmPacketizerPacket& ignoreList,
50  const FwChanIdType startLevel) {
51  // Ignore list may be nullptr as long as numEntries is 0. Providing an ignore list with numEntries 0 disables
52  // functionality for two reasons:
53  // 1. There are no ignored channels as configured by FPP.
54  // 2. Ignore functionality is intentionally disabled by project where nullptr was intentionally supplied.
55  FW_ASSERT(ignoreList.list || ignoreList.numEntries == 0);
56  FW_ASSERT(packetList.numEntries <= MAX_PACKETIZER_PACKETS, static_cast<FwAssertArgType>(packetList.numEntries));
57 
58  // Reset key data members incase of reentrant calls
59  this->m_numChannels = 0;
60  this->m_channelIndices.clear();
61  this->m_configured = false;
62 
63  // validate packet sizes against maximum com buffer size and populate hash
64  // table
65  FwChanIdType maxLevel = 0;
66  for (FwChanIdType pktEntry = 0; pktEntry < packetList.numEntries; pktEntry++) {
67  // Initial size is packetized telemetry descriptor + size of time tag + sizeof packet ID
68  FwSizeType packetLen =
70  FW_ASSERT(packetList.list[pktEntry]->list != nullptr, static_cast<FwAssertArgType>(pktEntry));
71  // add up entries for each defined packet
72  for (FwChanIdType tlmEntry = 0; tlmEntry < packetList.list[pktEntry]->numEntries; tlmEntry++) {
73  FwChanIdType id = packetList.list[pktEntry]->list[tlmEntry].id;
74  const FwSizeType channelSize = packetList.list[pktEntry]->list[tlmEntry].size;
75  FwSizeType entryIndex = 0;
76  if (this->m_channelIndices.find(id, entryIndex) != Fw::Success::SUCCESS) {
77  // New channel - allocate a slot and initialize offsets to -1 (not in any packet)
78  entryIndex = this->m_numChannels++;
79  this->m_channels[entryIndex].id = id;
80  this->m_channels[entryIndex].hasValue = false;
81  this->m_channels[entryIndex].channelSize = channelSize;
82  for (FwChanIdType pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) {
83  this->m_channels[entryIndex].packetOffset[pktOffsetEntry] = -1;
84  }
85  const Fw::Success insertStatus = this->m_channelIndices.insert(id, entryIndex);
86  FW_ASSERT(insertStatus == Fw::Success::SUCCESS, static_cast<FwAssertArgType>(insertStatus));
87  } else {
88  // Existing channel - a channel ID may repeat across packets, but its definition (size) must match.
89  // A conflicting size would corrupt the packet offsets computed from the earlier definition and
90  // overflow the fill buffer during TlmRecv/TlmGet copies, so reject the misconfiguration here.
91  FW_ASSERT(this->m_channels[entryIndex].channelSize == channelSize, static_cast<FwAssertArgType>(id),
92  static_cast<FwAssertArgType>(channelSize),
93  static_cast<FwAssertArgType>(this->m_channels[entryIndex].channelSize));
94  }
95  // not ignored channel - update entry in place via reference
96  TlmEntry& entry = this->m_channels[entryIndex];
97  entry.ignored = false;
98  entry.channelSize = channelSize;
99  // the offset into the buffer will be the current packet length
100  // the offset must fit within FwSignedSizeType to allow for negative values
101  FW_ASSERT(packetLen <= static_cast<FwSizeType>(std::numeric_limits<FwSignedSizeType>::max()),
102  static_cast<FwAssertArgType>(packetLen));
103  entry.packetOffset[pktEntry] = static_cast<FwSignedSizeType>(packetLen);
104 
105  packetLen += entry.channelSize;
106 
107  } // end channel in packet
108  FW_ASSERT(packetLen <= FW_COM_BUFFER_MAX_SIZE, static_cast<FwAssertArgType>(packetLen),
109  static_cast<FwAssertArgType>(pktEntry));
110  // clear contents
111  (void)memset(this->m_fillBuffers[pktEntry].buffer.getBuffAddr(), 0, static_cast<size_t>(packetLen));
112  // serialize packet descriptor and packet ID now since it will always be the same
113  Fw::SerializeStatus stat = this->m_fillBuffers[pktEntry].buffer.serializeFrom(
114  static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_PACKETIZED_TLM));
115  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
116  stat = this->m_fillBuffers[pktEntry].buffer.serializeFrom(packetList.list[pktEntry]->id);
117  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
118  // set packet buffer length
119  stat = this->m_fillBuffers[pktEntry].buffer.setBuffLen(packetLen);
120  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
121  // save ID
122  this->m_fillBuffers[pktEntry].id = packetList.list[pktEntry]->id;
123  // save level
124  this->m_fillBuffers[pktEntry].level = packetList.list[pktEntry]->level;
125  // store max level
126  if (packetList.list[pktEntry]->level > maxLevel) {
127  maxLevel = packetList.list[pktEntry]->level;
128  }
129 
130  } // end packet list
131  FW_ASSERT(maxLevel <= MAX_CONFIGURABLE_TLMPACKETIZER_GROUP, static_cast<FwAssertArgType>(maxLevel));
132 
133  // This section adds entries in the map for channels that are intended to be ignored. When the user supplies
134  // a list with no length, this loop is skipped. To turn-off ignoring of channels, the user can provide a null
135  // list with 0 length.
136  for (FwChanIdType channelEntry = 0; channelEntry < ignoreList.numEntries; channelEntry++) {
137  FwChanIdType id = ignoreList.list[channelEntry].id;
138  FwSizeType entryIndex = 0;
139  if (this->m_channelIndices.find(id, entryIndex) != Fw::Success::SUCCESS) {
140  // New channel - allocate a slot and initialize offsets to -1 (not in any packet)
141  entryIndex = this->m_numChannels++;
142  this->m_channels[entryIndex].id = id;
143  this->m_channels[entryIndex].hasValue = false;
144  for (FwChanIdType pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) {
145  this->m_channels[entryIndex].packetOffset[pktOffsetEntry] = -1;
146  }
147  const Fw::Success insertStatus = this->m_channelIndices.insert(id, entryIndex);
148  FW_ASSERT(insertStatus == Fw::Success::SUCCESS, static_cast<FwAssertArgType>(insertStatus));
149  } else {
150  // Ensure it is a duplicate in the ignore list, not a duplicate of a valid channel
151  FW_ASSERT(this->m_channels[entryIndex].ignored, static_cast<FwAssertArgType>(id));
152  }
153  // is ignored channel - update entry in place via reference
154  TlmEntry& entry = this->m_channels[entryIndex];
155  entry.ignored = true;
156  entry.channelSize = ignoreList.list[channelEntry].size;
157  } // end ignore list
158 
159  // store number of packets
160  this->m_numPackets = packetList.numEntries;
161 
162  // indicate configured
163  this->m_configured = true;
164 }
165 
166 // ----------------------------------------------------------------------
167 // Handler implementations for user-defined typed input ports
168 // ----------------------------------------------------------------------
169 
170 void TlmPacketizer ::TlmRecv_handler(const FwIndexType portNum,
171  FwChanIdType id,
172  Fw::Time& timeTag,
173  Fw::TlmBuffer& val) {
174  FW_ASSERT(this->m_configured);
175  FwSizeType entryIndex = 0;
176 
177  // Search to see if the channel is being tracked
178  if (this->m_channelIndices.find(id, entryIndex) != Fw::Success::SUCCESS) {
179  // channel not part of a packet and not ignored
180  this->missingChannel(id);
181  return;
182  }
183 
184  TlmEntry& entry = this->m_channels[entryIndex];
185 
186  // check to see if the channel is ignored. If so, just return.
187  if (entry.ignored) {
188  return;
189  }
190 
191  // copy telemetry value into active buffers; hasValue written in-place via reference
192  entry.hasValue = true;
193  for (FwChanIdType pkt = 0; pkt < MAX_PACKETIZER_PACKETS; pkt++) {
194  // check if current packet has this channel
195  if (entry.packetOffset[pkt] != -1) {
196  // get destination address
197  this->m_lock.lock();
198  this->m_fillBuffers[pkt].updated = true;
199  this->m_fillBuffers[pkt].latestTime = timeTag;
200  U8* ptr = &this->m_fillBuffers[pkt].buffer.getBuffAddr()[entry.packetOffset[pkt]];
201  // validate before memcpy
202  FW_ASSERT(val.getSize() <= entry.channelSize, static_cast<FwAssertArgType>(val.getSize()),
203  static_cast<FwAssertArgType>(entry.channelSize));
204 
205  (void)memcpy(ptr, val.getBuffAddr(), static_cast<size_t>(val.getSize()));
206  this->m_lock.unLock();
207  }
208  }
209 }
210 
211 void TlmPacketizer ::configureSectionGroupRate_handler(FwIndexType portNum,
212  const Svc::TelemetrySection& section,
213  FwChanIdType tlmGroup,
214  const Svc::RateLogic& rateLogic,
215  U32 minDelta,
216  U32 maxDelta) {
217  this->configureSectionGroupRate(section, tlmGroup, rateLogic, minDelta, maxDelta);
218 }
219 
221 Fw::TlmValid TlmPacketizer ::TlmGet_handler(FwIndexType portNum,
222  FwChanIdType id,
223  Fw::Time& timeTag,
224  Fw::TlmBuffer& val
225 ) {
227  FW_ASSERT(this->m_configured);
228  FwSizeType entryIndex = 0;
229 
230  // Search to see if the channel is being tracked
231  if (this->m_channelIndices.find(id, entryIndex) != Fw::Success::SUCCESS) {
232  // channel not part of a packet and not ignored
233  this->missingChannel(id);
234  val.resetSer();
235  return Fw::TlmValid::INVALID;
236  }
237  const TlmEntry& entry = this->m_channels[entryIndex];
238 
239  // check to see if the channel is ignored. If so, just return, as
240  // we don't store the bytes of ignored channels
241  if (entry.ignored) {
242  val.resetSer();
243  return Fw::TlmValid::INVALID;
244  }
245 
246  if (!entry.hasValue) {
247  // haven't received a value yet for this entry.
248  val.resetSer();
249  return Fw::TlmValid::INVALID;
250  }
251 
252  // make sure we have enough space to store this entry in our buf
253  FW_ASSERT(entry.channelSize <= val.getCapacity(), static_cast<FwAssertArgType>(entry.channelSize),
254  static_cast<FwAssertArgType>(val.getCapacity()));
255 
256  // okay, we have the matching entry.
257  // go over each packet and find the first one which stores this channel
258 
259  for (FwChanIdType pkt = 0; pkt < MAX_PACKETIZER_PACKETS; pkt++) {
260  // check if current packet has this channel
261  if (entry.packetOffset[pkt] != -1) {
262  // okay, it has the channel. copy chan val into the tlm buf
263  this->m_lock.lock();
264  timeTag = this->m_fillBuffers[pkt].latestTime;
265  U8* ptr = &this->m_fillBuffers[pkt].buffer.getBuffAddr()[entry.packetOffset[pkt]];
266  (void)memcpy(val.getBuffAddr(), ptr, static_cast<size_t>(entry.channelSize));
267  // set buf len to the channelSize. keep in mind, this is the MAX serialized size of the channel.
268  // so we may actually be filling val with some junk after the value of the channel.
269  const Fw::SerializeStatus setStatus = val.setBuffLen(entry.channelSize);
270  FW_ASSERT(setStatus == Fw::SerializeStatus::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(setStatus));
271  this->m_lock.unLock();
272  return Fw::TlmValid::VALID;
273  }
274  }
275 
276  // did not find a packet which stores this channel.
277  // coding error, this was not an ignored channel so it must be in a packet somewhere
278  FW_ASSERT(false, static_cast<FwAssertArgType>(entry.id));
279  // TPP (tim paranoia principle)
280  val.resetSer();
281  return Fw::TlmValid::INVALID;
282 }
283 
284 void TlmPacketizer ::Run_handler(const FwIndexType portNum, U32 context) {
285  FW_ASSERT(this->m_configured);
286 
287  for (FwChanIdType pkt = 0; pkt < this->m_numPackets; pkt++) {
288  // Local flags to track which sections require a packet dispatch
289  bool sectionNeedsSend[TelemetrySection::NUM_SECTIONS] = {false};
290  bool anySectionNeedsSend = false;
291 
292  // Lock only to capture the update status and reset the fill buffer flag.
293  this->m_lock.lock();
294  bool isNewData = this->m_fillBuffers[pkt].updated;
295  FwChanIdType entryGroup = this->m_fillBuffers[pkt].level;
296  this->m_fillBuffers[pkt].updated = false;
297  this->m_lock.unLock();
298 
299  for (FwIndexType section = 0; section < TelemetrySection::NUM_SECTIONS; section++) {
300  PktSendCounters& pktEntryFlags = this->m_packetFlags[static_cast<FwSizeType>(section)][pkt];
301  TlmPacketizer_GroupConfig& entryGroupConfig =
302  this->m_groupConfigs[static_cast<FwSizeType>(section)][entryGroup];
303 
304  // Packet is updated and not REQUESTED (Keep REQUESTED marking to bypass disable checks)
305  if (isNewData && pktEntryFlags.updateFlag != UpdateFlag::REQUESTED) {
306  pktEntryFlags.updateFlag = UpdateFlag::NEW;
307  }
308 
309  /* Base conditions for sending
310  1. Output port is connected
311  2. The packet was requested (Override Checks).
312 
313  If the packet wasn't requested:
314  3. The Section and Group in Section is enabled OR the Group in Section is force enabled
315  4. The rate logic is not SILENCED.
316  5. The packet has data (marked updated in the past or new)
317  */
318  if (!this->isConnected_PktSend_OutputPort(this->sectionGroupToPort(section, entryGroup))) {
319  continue;
320  }
321 
322  if (pktEntryFlags.updateFlag == UpdateFlag::REQUESTED) {
323  sectionNeedsSend[section] = true;
324  } else {
325  if (not((entryGroupConfig.get_enabled() and
326  this->m_sectionEnabled[static_cast<FwSizeType>(section)] == Fw::Enabled::ENABLED) or
327  entryGroupConfig.get_forceEnabled() == Fw::Enabled::ENABLED)) {
328  continue;
329  }
330  if (entryGroupConfig.get_rateLogic() == Svc::RateLogic::SILENCED) {
331  continue;
332  }
333  if (pktEntryFlags.updateFlag == UpdateFlag::NEVER_UPDATED) {
334  continue; // Avoid No Data
335  }
336  }
337 
338  // Update Counter, prevent overflow.
339  if (pktEntryFlags.prevSentCounter < std::numeric_limits<U32>::max()) {
340  pktEntryFlags.prevSentCounter++;
341  }
342 
343  /*
344  1. Packet has been updated
345  2. Group Logic includes checking MIN
346  3. Packet sent counter at MIN
347  */
348  if (pktEntryFlags.updateFlag == UpdateFlag::NEW and
349  entryGroupConfig.get_rateLogic() != Svc::RateLogic::EVERY_MAX and
350  pktEntryFlags.prevSentCounter >= entryGroupConfig.get_min()) {
351  sectionNeedsSend[section] = true;
352  }
353 
354  /*
355  1. Group Logic includes checking MAX
356  2. Packet set counter is at MAX
357  */
358  if (entryGroupConfig.get_rateLogic() != Svc::RateLogic::ON_CHANGE_MIN and
359  pktEntryFlags.prevSentCounter >= entryGroupConfig.get_max()) {
360  sectionNeedsSend[section] = true;
361  }
362 
363  if (sectionNeedsSend[section]) {
364  anySectionNeedsSend = true;
365  }
366  }
367 
368  // Only perform the buffer copy if at least one section needs to send.
369  if (anySectionNeedsSend) {
370  this->m_lock.lock();
371  BufferEntry sendBuffer = this->m_fillBuffers[pkt];
372  this->m_lock.unLock();
373 
374  // serialize time into time offset in packet
376  &sendBuffer.buffer.getBuffAddr()[sizeof(FwPacketDescriptorType) + sizeof(FwTlmPacketizeIdType)],
378  (void)buff.serializeFrom(sendBuffer.latestTime);
379 
380  for (FwIndexType section = 0; section < TelemetrySection::NUM_SECTIONS; section++) {
381  if (sectionNeedsSend[section]) {
382  PktSendCounters& pktEntryFlags = this->m_packetFlags[section][pkt];
383  FwIndexType outIndex = this->sectionGroupToPort(section, entryGroup);
384 
385  this->PktSend_out(outIndex, sendBuffer.buffer, pktEntryFlags.prevSentCounter);
386 
387  pktEntryFlags.prevSentCounter = 0;
388  pktEntryFlags.updateFlag = UpdateFlag::PAST;
389  }
390  }
391  }
392  }
393 }
394 
395 void TlmPacketizer ::controlIn_handler(FwIndexType portNum,
396  const Svc::TelemetrySection& section,
397  const Fw::Enabled& enabled) {
398  // NUM_SECTIONS is an enum constant (not a standalone constant), so isValid() accepts it.
399  // The explicit bounds check prevents an out-of-bounds write to m_sectionEnabled.
400  if (section.isValid() && section < TelemetrySection::NUM_SECTIONS && enabled.isValid()) {
401  (void)(this->m_sectionEnabled[static_cast<FwSizeType>(section)] = enabled);
402  } else {
403  this->log_WARNING_LO_SectionUnconfigurable(section, enabled);
404  }
405 }
406 
407 void TlmPacketizer ::pingIn_handler(const FwIndexType portNum, U32 key) {
408  // return key
409  this->pingOut_out(0, key);
410 }
411 
412 // ----------------------------------------------------------------------
413 // Command handler implementations
414 // ----------------------------------------------------------------------
415 
416 void TlmPacketizer ::SET_LEVEL_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, FwChanIdType level) {
419  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
420  return;
421  }
422  for (FwIndexType section = 0; section < TelemetrySection::NUM_SECTIONS; section++) {
423  for (FwChanIdType group = 0; group < NUM_CONFIGURABLE_TLMPACKETIZER_GROUPS; group++) {
424  this->m_groupConfigs[static_cast<FwSizeType>(section)][group].set_enabled(
425  group <= level ? Fw::Enabled::ENABLED : Fw::Enabled::DISABLED);
426  }
427  }
428  this->tlmWrite_GroupConfigs(this->m_groupConfigs);
429  this->log_ACTIVITY_HI_LevelSet(level);
430  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
431 }
432 
433 void TlmPacketizer ::SEND_PKT_cmdHandler(const FwOpcodeType opCode,
434  const U32 cmdSeq,
435  const U32 id,
436  const Svc::TelemetrySection& section) {
437  FW_ASSERT(section.isValid());
438  if (section < 0 or section >= TelemetrySection::NUM_SECTIONS) {
439  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
440  return;
441  }
442  FwChanIdType pkt = 0;
443  for (pkt = 0; pkt < this->m_numPackets; pkt++) {
444  if (this->m_fillBuffers[pkt].id == id) {
445  this->m_lock.lock();
446  this->m_fillBuffers[pkt].updated = true;
447  this->m_fillBuffers[pkt].latestTime = this->getTime();
448  this->m_lock.unLock();
449 
450  this->m_packetFlags[section][pkt].updateFlag = UpdateFlag::REQUESTED;
451 
452  this->log_ACTIVITY_LO_PacketSent(id);
453  break;
454  }
455  }
456 
457  // couldn't find it
458  if (pkt == this->m_numPackets) {
460  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
461  return;
462  }
463 
464  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
465 }
466 
467 void TlmPacketizer ::ENABLE_SECTION_cmdHandler(FwOpcodeType opCode,
468  U32 cmdSeq,
469  const Svc::TelemetrySection& section,
470  const Fw::Enabled& enable) {
471  FW_ASSERT(section.isValid());
472  FW_ASSERT(enable.isValid());
473  if (section < 0 or section >= TelemetrySection::NUM_SECTIONS) {
474  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
475  return;
476  }
477  (void)(this->m_sectionEnabled[section] = enable);
478  this->tlmWrite_SectionEnabled(this->m_sectionEnabled);
479  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
480 }
481 
482 void TlmPacketizer ::ENABLE_GROUP_cmdHandler(FwOpcodeType opCode,
483  U32 cmdSeq,
484  const Svc::TelemetrySection& section,
485  FwChanIdType tlmGroup,
486  const Fw::Enabled& enable) {
487  FW_ASSERT(section.isValid());
488  FW_ASSERT(enable.isValid());
489  if (section < 0 or section >= TelemetrySection::NUM_SECTIONS or tlmGroup > MAX_CONFIGURABLE_TLMPACKETIZER_GROUP) {
490  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
491  return;
492  }
493  this->m_groupConfigs[section][tlmGroup].set_enabled(enable);
494  this->tlmWrite_GroupConfigs(this->m_groupConfigs);
495  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
496 }
497 
498 void TlmPacketizer ::FORCE_GROUP_cmdHandler(FwOpcodeType opCode,
499  U32 cmdSeq,
500  const Svc::TelemetrySection& section,
501  FwChanIdType tlmGroup,
502  const Fw::Enabled& enable) {
503  FW_ASSERT(section.isValid());
504  FW_ASSERT(enable.isValid());
505  if (section < 0 or section >= TelemetrySection::NUM_SECTIONS or tlmGroup > MAX_CONFIGURABLE_TLMPACKETIZER_GROUP) {
506  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
507  return;
508  }
509  this->m_groupConfigs[section][tlmGroup].set_forceEnabled(enable);
510  this->tlmWrite_GroupConfigs(this->m_groupConfigs);
511  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
512 }
513 
514 void TlmPacketizer ::CONFIGURE_GROUP_RATES_cmdHandler(FwOpcodeType opCode,
515  U32 cmdSeq,
516  const Svc::TelemetrySection& section,
517  FwChanIdType tlmGroup,
518  const Svc::RateLogic& rateLogic,
519  U32 minDelta,
520  U32 maxDelta) {
521  FW_ASSERT(section.isValid());
522  FW_ASSERT(rateLogic.isValid());
523  if (section < 0 or section >= TelemetrySection::NUM_SECTIONS or tlmGroup > MAX_CONFIGURABLE_TLMPACKETIZER_GROUP) {
524  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
525  return;
526  }
527  this->configureSectionGroupRate(section, tlmGroup, rateLogic, minDelta, maxDelta);
528  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
529 }
530 
531 void TlmPacketizer::configureSectionGroupRate(
532  const Svc::TelemetrySection& section,
533  FwChanIdType tlmGroup,
534  const Svc::RateLogic& rateLogic,
535  U32 minDelta,
536  U32 maxDelta
537 ) {
538  FW_ASSERT(section.isValid());
539  FW_ASSERT(rateLogic.isValid());
540  // These two asserts are an "if" statement in a command so they will no assert on bad user data
541  FW_ASSERT(section >= 0 and section < TelemetrySection::NUM_SECTIONS);
543 
544  TlmPacketizer_GroupConfig& groupConfig = this->m_groupConfigs[section][tlmGroup];
545  groupConfig.set_rateLogic(rateLogic);
546  groupConfig.set_min(minDelta);
547  groupConfig.set_max(maxDelta);
548  this->tlmWrite_GroupConfigs(this->m_groupConfigs);
549 }
550 
551 FwIndexType TlmPacketizer::sectionGroupToPort(const FwIndexType section, const FwSizeType group) {
552  // Confirm the indices will not overflow the size of the array
553  FW_ASSERT(group < TlmPacketizer_TelemetrySendSection::SIZE, static_cast<FwAssertArgType>(group));
554  FW_ASSERT(section < TlmPacketizer_TelemetrySendPortMap::SIZE, static_cast<FwAssertArgType>(section));
555 
556  const FwIndexType outIndex = TlmPacketizer::TELEMETRY_SEND_PORT_MAP[static_cast<FwSizeType>(section)][group];
557 
558  // Confirm the output port index is within the valid number of telemetry send ports
559  FW_ASSERT(outIndex < TELEMETRY_SEND_PORTS, static_cast<FwAssertArgType>(outIndex));
560  return outIndex;
561 }
562 
563 void TlmPacketizer::missingChannel(FwChanIdType id) {
564  // search to see if missing channel has already been sent
565  for (FwChanIdType slot = 0; slot < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; slot++) {
566  // if it's been checked, return
567  if (this->m_missTlmCheck[slot].checked and (this->m_missTlmCheck[slot].id == id)) {
568  return;
569  } else if (not this->m_missTlmCheck[slot].checked) {
570  this->m_missTlmCheck[slot].checked = true;
571  this->m_missTlmCheck[slot].id = id;
572  this->log_WARNING_LO_NoChan(id);
573  return;
574  }
575  }
576 }
577 
578 Fw::SerializeStatus TlmPacketizer::deserializeParam(const FwPrmIdType base_id,
579  const FwPrmIdType local_id,
580  const Fw::ParamValid prmStat,
581  Fw::SerialBufferBase& buff) {
582  if ((prmStat == Fw::ParamValid::VALID) || (prmStat == Fw::ParamValid::DEFAULT)) {
583  switch (local_id) {
585  return buff.deserializeTo(this->m_sectionEnabled);
587  return buff.deserializeTo(this->m_groupConfigs);
588  default:
589  FW_ASSERT(false, static_cast<FwAssertArgType>(local_id));
590  }
591  }
593 }
594 
595 Fw::SerializeStatus TlmPacketizer::serializeParam(const FwPrmIdType base_id,
596  const FwPrmIdType local_id,
597  Fw::SerialBufferBase& buff) const {
598  switch (local_id) {
600  return buff.serializeFrom(this->m_sectionEnabled);
602  return buff.serializeFrom(this->m_groupConfigs);
603  default:
604  FW_ASSERT(false, static_cast<FwAssertArgType>(local_id));
605  }
607 }
608 
609 } // end namespace Svc
bool isConnected_PktSend_OutputPort(FwIndexType portNum) const
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.
Representing success.
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.
void log_ACTIVITY_HI_LevelSet(FwChanIdType level) const
void log_ACTIVITY_LO_PacketSent(U32 packetId) const
Serializable::SizeType getSize() const override
Get current buffer size.
FwIdType FwPrmIdType
The type of a parameter identifier.
const TlmPacketizerPacket * list[MAX_PACKETIZER_PACKETS]
void log_WARNING_LO_NoChan(FwChanIdType Id) const
static const FwChanIdType MAX_PACKETIZER_PACKETS
Maximum number of packets that the packetizer can handle.
void unLock()
unlock the mutex and assert success
Definition: Mutex.cpp:41
bool isValid() const
Check raw enum value for validity.
PlatformSignedSizeType FwSignedSizeType
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
Send on updates after MIN ticks since last send.
virtual SerializeStatus serializeFrom(U8 val, Endianness mode=Endianness::BIG)=0
Serialize an 8-bit unsigned integer value.
Success find(const K &key, V &value) const override
Send every MAX ticks between sends.
const TlmPacketizerChannelEntry * list
pointer to a channel entry
void log_WARNING_LO_PacketNotFound(U32 packetId) const
static const FwChanIdType TLMPACKETIZER_MAX_MISSING_TLM_CHECK
Maximum number of missing channels to track and report.
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.
void registerExternalParameters(Fw::ParamExternalDelegate *paramExternalDelegatePtr)
Initialize the external parameter delegate.
virtual SerializeStatus deserializeTo(U8 &val, Endianness mode=Endianness::BIG)=0
Deserialize an 8-bit unsigned integer value.
FwChanIdType id
Id of channel.
FwChanIdType level
packet level - used to select set of packets to send
Data was the wrong format (e.g. wrong packet type)
void log_WARNING_LO_SectionUnconfigurable(const Svc::TelemetrySection &section, const Fw::Enabled &enable) const
Log event SectionUnconfigurable.
Enumeration for rate logic types for telemetry groups.
External serialize buffer with no copy semantics.
FwIdType FwChanIdType
The type of a telemetry channel identifier.
void resetSer() override
Reset serialization pointer to beginning of buffer.
Deserialized type ID didn&#39;t match.
Enabled and disabled states.
U16 FwTlmPacketizeIdType
The type of a telemetry packet identifier.
Command successfully executed.
void clear() override
Clear the map.
void setPacketList(const TlmPacketizerPacketList &packetList, const Svc::TlmPacketizerPacket &ignoreList, const FwChanIdType startLevel)
bool isValid() const
Check raw enum value for validity.
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:54
void PktSend_out(FwIndexType portNum, Fw::ComBuffer &data, U32 context) const
Invoke output port PktSend.
void log_WARNING_LO_MaxLevelExceed(FwChanIdType level, FwChanIdType max) const
PlatformIndexType FwIndexType
Command failed validation.
RateGroupDivider component implementation.
U8 * getBuffAddr() override
Get buffer address for data filling (non-const version)
Enum representing parameter validity.
SerializeStatus setBuffLen(Serializable::SizeType length) override
Set buffer length manually.
FwSizeType getCapacity() const override
Get buffer capacity.
FwChanIdType numEntries
number of channels in packet
void pingOut_out(FwIndexType portNum, U32 key) const
Invoke output port pingOut.
Success insert(const K &key, const V &value) override
#define FW_ASSERT(...)
Definition: Assert.hpp:14
Disabled state.
Success/Failure.
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.