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