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