F´ Flight Software - C/C++ Documentation  NASA-v1.6.0
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 
12 #include <Fw/Types/BasicTypes.hpp>
13 #include <Fw/Com/ComPacket.hpp>
14 
15 namespace Svc {
16 
17  // ----------------------------------------------------------------------
18  // Construction, initialization, and destruction
19  // ----------------------------------------------------------------------
20 
23  const char *const compName
24  ) :
25  TlmPacketizerComponentBase(compName)
26  ,m_numPackets(0)
27  ,m_configured(false)
28  ,m_startLevel(0)
29  ,m_maxLevel(0)
30  {
31  // clear slot pointers
32  for (NATIVE_UINT_TYPE entry = 0; entry < TLMPACKETIZER_NUM_TLM_HASH_SLOTS; entry++) {
33  this->m_tlmEntries.slots[entry] = nullptr;
34  }
35  // clear buckets
36  for (NATIVE_UINT_TYPE entry = 0; entry < TLMPACKETIZER_HASH_BUCKETS; entry++) {
37  this->m_tlmEntries.buckets[entry].used = false;
38  this->m_tlmEntries.buckets[entry].bucketNo = entry;
39  this->m_tlmEntries.buckets[entry].next = nullptr;
40  this->m_tlmEntries.buckets[entry].id = 0;
41  }
42  // clear free index
43  this->m_tlmEntries.free = 0;
44  // clear missing tlm channel check
45  for (NATIVE_UINT_TYPE entry = 0; entry < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; entry++) {
46  this->m_missTlmCheck[entry].checked = false;
47  this->m_missTlmCheck[entry].id = 0;
48  }
49 
50  // clear packet buffers
51  for (NATIVE_UINT_TYPE buffer = 0; buffer < MAX_PACKETIZER_PACKETS; buffer++) {
52  this->m_fillBuffers[buffer].updated = false;
53  this->m_fillBuffers[buffer].requested = false;
54  this->m_sendBuffers[buffer].updated = false;
55  }
56  }
57 
58  void TlmPacketizer ::
60  const NATIVE_INT_TYPE queueDepth,
61  const NATIVE_INT_TYPE instance
62  )
63  {
64  TlmPacketizerComponentBase::init(queueDepth, instance);
65  }
66 
69  {
70 
71  }
72 
74  const TlmPacketizerPacketList& packetList,
75  const Svc::TlmPacketizerPacket& ignoreList,
76  const NATIVE_UINT_TYPE startLevel) {
77 
78  FW_ASSERT(packetList.list);
79  FW_ASSERT(ignoreList.list);
80  FW_ASSERT(packetList.numEntries <= MAX_PACKETIZER_PACKETS,packetList.numEntries);
81  // validate packet sizes against maximum com buffer size and populate hash
82  // table
83  for (NATIVE_UINT_TYPE pktEntry = 0; pktEntry < packetList.numEntries; pktEntry++) {
84  // Initial size is packetized telemetry descriptor + size of time tag + sizeof packet ID
86  FW_ASSERT(packetList.list[pktEntry]->list,pktEntry);
87  // add up entries for each defined packet
88  for (NATIVE_UINT_TYPE tlmEntry = 0; tlmEntry < packetList.list[pktEntry]->numEntries; tlmEntry++) {
89  // get hash value for id
90  FwChanIdType id = packetList.list[pktEntry]->list[tlmEntry].id;
91  TlmEntry *entryToUse = this->findBucket(id);
92  // copy into entry
93  FW_ASSERT(entryToUse);
94  entryToUse->used = true;
95  // not ignored channel
96  entryToUse->ignored = false;
97  entryToUse->id = id;
98  // the offset into the buffer will be the current packet length
99  entryToUse->packetOffset[pktEntry] = packetLen;
100 
101  packetLen += packetList.list[pktEntry]->list[tlmEntry].size;
102 
103  } // end channel in packet
104  FW_ASSERT(packetLen <= FW_COM_BUFFER_MAX_SIZE,packetLen,pktEntry);
105  // clear contents
106  memset(this->m_fillBuffers[pktEntry].buffer.getBuffAddr(),0,packetLen);
107  // serialize packet descriptor and packet ID now since it will always be the same
108  Fw::SerializeStatus stat = this->m_fillBuffers[pktEntry].buffer.serialize(static_cast<FwPacketDescriptorType>(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM));
109  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,stat);
110  stat = this->m_fillBuffers[pktEntry].buffer.serialize(packetList.list[pktEntry]->id);
111  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,stat);
112  // set packet buffer length
113  stat = this->m_fillBuffers[pktEntry].buffer.setBuffLen(packetLen);
114  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,stat);
115  // save ID
116  this->m_fillBuffers[pktEntry].id = packetList.list[pktEntry]->id;
117  // save level
118  this->m_fillBuffers[pktEntry].level = packetList.list[pktEntry]->level;
119  // store max level
120  if (packetList.list[pktEntry]->level > this->m_maxLevel) {
121  this->m_maxLevel = packetList.list[pktEntry]->level;
122  }
123  // save start level
124  this->m_startLevel = startLevel;
125 
126  } // end packet list
127 
128  // populate hash table with ignore list
129  for (NATIVE_UINT_TYPE channelEntry = 0; channelEntry < ignoreList.numEntries; channelEntry++) {
130  // get hash value for id
131  FwChanIdType id = ignoreList.list[channelEntry].id;
132 
133  TlmEntry *entryToUse = this->findBucket(id);
134 
135  // copy into entry
136  FW_ASSERT(entryToUse);
137  entryToUse->used = true;
138  // is ignored channel
139  entryToUse->ignored = true;
140  entryToUse->id = id;
141  } // end ignore list
142 
143  // store number of packets
144  this->m_numPackets = packetList.numEntries;
145 
146  // indicate configured
147  this->m_configured = true;
148  }
149 
150  TlmPacketizer::TlmEntry* TlmPacketizer::findBucket(FwChanIdType id) {
151  NATIVE_UINT_TYPE index = this->doHash(id);
153  TlmEntry* entryToUse = nullptr;
154  TlmEntry* prevEntry = nullptr;
155 
156  // Search to see if channel has already been stored or a bucket needs to be added
157  if (this->m_tlmEntries.slots[index]) {
158  entryToUse = this->m_tlmEntries.slots[index];
159  for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMPACKETIZER_HASH_BUCKETS; bucket++) {
160  if (entryToUse) {
161  if (entryToUse->id == id) { // found the matching entry
162  break;
163  } else { // try next entry
164  prevEntry = entryToUse;
165  entryToUse = entryToUse->next;
166  }
167  } else {
168  // Make sure that we haven't run out of buckets
169  FW_ASSERT(this->m_tlmEntries.free < TLMPACKETIZER_HASH_BUCKETS,this->m_tlmEntries.free);
170  // add new bucket from free list
171  entryToUse = &this->m_tlmEntries.buckets[this->m_tlmEntries.free++];
172  // Coverity warning about null dereference - see if it happens
173  FW_ASSERT(prevEntry);
174  prevEntry->next = entryToUse;
175  // clear next pointer
176  entryToUse->next = nullptr;
177  // set all packet offsets to -1 for new entry
178  for (NATIVE_UINT_TYPE pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) {
179  entryToUse->packetOffset[pktOffsetEntry] = -1;
180  }
181  break;
182  }
183  }
184  } else {
185  // Make sure that we haven't run out of buckets
186  FW_ASSERT(this->m_tlmEntries.free < TLMPACKETIZER_HASH_BUCKETS,this->m_tlmEntries.free);
187  // create new entry at slot head
188  this->m_tlmEntries.slots[index] = &this->m_tlmEntries.buckets[this->m_tlmEntries.free++];
189  entryToUse = this->m_tlmEntries.slots[index];
190  entryToUse->next = nullptr;
191  // set all packet offsets to -1 for new entry
192  for (NATIVE_UINT_TYPE pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) {
193  entryToUse->packetOffset[pktOffsetEntry] = -1;
194  }
195 
196  }
197 
198  return entryToUse;
199  }
200 
201 
202 
203  // ----------------------------------------------------------------------
204  // Handler implementations for user-defined typed input ports
205  // ----------------------------------------------------------------------
206 
207  void TlmPacketizer ::
208  TlmRecv_handler(
209  const NATIVE_INT_TYPE portNum,
210  FwChanIdType id,
211  Fw::Time &timeTag,
212  Fw::TlmBuffer &val
213  )
214  {
215  FW_ASSERT(this->m_configured);
216  // get hash value for id
217  NATIVE_UINT_TYPE index = this->doHash(id);
218  TlmEntry* entryToUse = nullptr;
219 
220  // Search to see if the channel is being sent
221  entryToUse = this->m_tlmEntries.slots[index];
222 
223  // if no entries at hash, channel not part of a packet or is not ignored
224  if (not entryToUse) {
225  this->missingChannel(id);
226  return;
227  }
228 
229  for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMPACKETIZER_HASH_BUCKETS; bucket++) {
230  if (entryToUse) {
231  if (entryToUse->id == id) { // found the matching entry
232  // check to see if the channel is ignored. If so, just return.
233  if (entryToUse->ignored) {
234  return;
235  }
236  break;
237  } else { // try next entry
238  entryToUse = entryToUse->next;
239  }
240  } else {
241  // telemetry channel not in any packets
242  this->missingChannel(id);
243  return;
244  }
245  }
246 
247  // copy telemetry value into active buffers
248  for (NATIVE_UINT_TYPE pkt = 0; pkt < MAX_PACKETIZER_PACKETS; pkt++) {
249  // check if current packet has this channel
250  if (entryToUse->packetOffset[pkt] != -1) {
251  // get destination address
252  // printf("PK %d CH: %d\n",this->m_fillBuffers[pkt].id,id);
253  this->m_lock.lock();
254  this->m_fillBuffers[pkt].updated = true;
255  this->m_fillBuffers[pkt].latestTime = timeTag;
256  U8* ptr = &this->m_fillBuffers[pkt].buffer.getBuffAddr()[entryToUse->packetOffset[pkt]];
257  memcpy(ptr,val.getBuffAddr(),val.getBuffLength());
258  this->m_lock.unLock();
259  }
260  }
261 
262  }
263 
264  void TlmPacketizer ::
265  Run_handler(
266  const NATIVE_INT_TYPE portNum,
267  NATIVE_UINT_TYPE context
268  )
269  {
270  FW_ASSERT(this->m_configured);
271 
272  // Only write packets if connected
273  if (not this->isConnected_PktSend_OutputPort(0)) {
274  return;
275  }
276 
277  // lock mutex long enough to modify active telemetry buffer
278  // so the data can be read without worrying about updates
279  this->m_lock.lock();
280  // copy buffers from fill side to send side
281  for (NATIVE_UINT_TYPE pkt = 0; pkt < this->m_numPackets; pkt++) {
282  if ((this->m_fillBuffers[pkt].updated) and
283  ((this->m_fillBuffers[pkt].level <= this->m_startLevel) or
284  (this->m_fillBuffers[pkt].requested))) {
285 
286  this->m_sendBuffers[pkt] = this->m_fillBuffers[pkt];
288  this->m_fillBuffers[pkt].updated = false;
289  }
290  this->m_fillBuffers[pkt].requested = false;
291  // PACKET_UPDATE_AFTER_FIRST_CHANGE will be this case - updated flag will not be cleared
292  } else if ((PACKET_UPDATE_ALWAYS == PACKET_UPDATE_MODE) and (this->m_fillBuffers[pkt].level <= this->m_startLevel)) {
293  this->m_sendBuffers[pkt] = this->m_fillBuffers[pkt];
294  this->m_sendBuffers[pkt].updated = true;
295  } else {
296  this->m_sendBuffers[pkt].updated = false;
297  }
298  }
299  this->m_lock.unLock();
300 
301  // push all updated packet buffers
302  for (NATIVE_UINT_TYPE pkt = 0; pkt < this->m_numPackets; pkt++) {
303  if (this->m_sendBuffers[pkt].updated) {
304  // serialize time into time offset in packet
305  Fw::ExternalSerializeBuffer buff(&this->m_sendBuffers[pkt].buffer.getBuffAddr()
307  Fw::SerializeStatus stat = buff.serialize(this->m_sendBuffers[pkt].latestTime);
308  FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat);
309  this->PktSend_out(0,this->m_sendBuffers[pkt].buffer,0);
310  }
311  }
312  }
313 
314  void TlmPacketizer ::
315  pingIn_handler(
316  const NATIVE_INT_TYPE portNum,
317  U32 key
318  )
319  {
320  // return key
321  this->pingOut_out(0,key);
322  }
323 
324  // ----------------------------------------------------------------------
325  // Command handler implementations
326  // ----------------------------------------------------------------------
327 
328  void TlmPacketizer ::
329  SET_LEVEL_cmdHandler(
330  const FwOpcodeType opCode,
331  const U32 cmdSeq,
332  U32 level
333  )
334  {
335  this->m_startLevel = level;
336  if (level > this->m_maxLevel) {
337  this->log_WARNING_LO_MaxLevelExceed(level,this->m_maxLevel);
338  }
339  this->tlmWrite_SendLevel(level);
340  this->log_ACTIVITY_HI_LevelSet(level);
341  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
342  }
343 
344  void TlmPacketizer ::
345  SEND_PKT_cmdHandler(
346  const FwOpcodeType opCode,
347  const U32 cmdSeq,
348  U32 id
349  )
350  {
351  NATIVE_UINT_TYPE pkt = 0;
352  for (pkt = 0; pkt < this->m_numPackets; pkt++) {
353  if (this->m_fillBuffers[pkt].id == id) {
354 
355  this->m_lock.lock();
356  this->m_fillBuffers[pkt].updated = true;
357  this->m_fillBuffers[pkt].latestTime = this->getTime();
358  this->m_fillBuffers[pkt].requested = true;
359  this->m_lock.unLock();
360 
361  this->log_ACTIVITY_LO_PacketSent(id);
362  break;
363  }
364  }
365 
366  // couldn't find it
367  if (pkt == this->m_numPackets) {
368  log_WARNING_LO_PacketNotFound(id);
369  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
370  return;
371  }
372 
373  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
374  }
375 
376 
377  NATIVE_UINT_TYPE TlmPacketizer::doHash(FwChanIdType id) {
379  }
380 
381  void TlmPacketizer::missingChannel(FwChanIdType id) {
382  // search to see if missing channel has already been sent
383  for (NATIVE_UINT_TYPE slot = 0; slot < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; slot++) {
384  // if it's been checked, return
385  if (this->m_missTlmCheck[slot].checked and (this->m_missTlmCheck[slot].id == id)) {
386  return;
387  } else if (not this->m_missTlmCheck[slot].checked) {
388  this->m_missTlmCheck[slot].checked = true;
389  this->m_missTlmCheck[slot].id = id;
390  this->log_WARNING_LO_NoChan(id);
391  return;
392  }
393  }
394 
395  }
396 
397 
398 } // end namespace Svc
Svc::TlmPacketizer::TlmPacketizer
TlmPacketizer(const char *const compName)
Definition: TlmPacketizer.cpp:22
Svc::PACKET_UPDATE_ALWAYS
@ PACKET_UPDATE_ALWAYS
Definition: TlmPacketizerComponentImplCfg.hpp:32
Svc::TLMPACKETIZER_MAX_MISSING_TLM_CHECK
static const NATIVE_UINT_TYPE TLMPACKETIZER_MAX_MISSING_TLM_CHECK
Definition: TlmPacketizerComponentImplCfg.hpp:28
Fw::Time
Definition: Time.hpp:10
Svc::MAX_PACKETIZER_PACKETS
static const NATIVE_UINT_TYPE MAX_PACKETIZER_PACKETS
Definition: TlmPacketizerComponentImplCfg.hpp:20
FwPacketDescriptorType
#define FwPacketDescriptorType
Type representation for a packet descriptor.
Definition: FpConfig.hpp:58
Fw::SerializeStatus
SerializeStatus
forward declaration for string
Definition: Serializable.hpp:14
Fw::TlmBuffer
Definition: TlmBuffer.hpp:21
Svc::TLMPACKETIZER_HASH_MOD_VALUE
static const NATIVE_UINT_TYPE TLMPACKETIZER_HASH_MOD_VALUE
Definition: TlmPacketizerComponentImplCfg.hpp:23
Svc::TlmPacketizerPacket::list
const TlmPacketizerChannelEntry * list
pointer to a channel entry
Definition: TlmPacketizerTypes.hpp:28
Fw::TlmBuffer::getBuffAddr
U8 * getBuffAddr()
gets buffer address for data filling
Definition: TlmBuffer.cpp:36
U8
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.hpp:73
NATIVE_UINT_TYPE
unsigned int NATIVE_UINT_TYPE
native unsigned integer type declaration
Definition: BasicTypes.hpp:28
Svc::PACKET_UPDATE_ON_CHANGE
@ PACKET_UPDATE_ON_CHANGE
Definition: TlmPacketizerComponentImplCfg.hpp:33
Svc::TLMPACKETIZER_NUM_TLM_HASH_SLOTS
static const NATIVE_UINT_TYPE TLMPACKETIZER_NUM_TLM_HASH_SLOTS
Definition: TlmPacketizerComponentImplCfg.hpp:21
FwTlmPacketizeIdType
#define FwTlmPacketizeIdType
Packetized telemetry packet id.
Definition: FpConfig.hpp:74
Svc::TlmPacketizerChannelEntry::id
FwChanIdType id
Id of channel.
Definition: TlmPacketizerTypes.hpp:23
Svc::TlmPacketizerPacketList::numEntries
NATIVE_UINT_TYPE numEntries
Definition: TlmPacketizerTypes.hpp:36
FwChanIdType
#define FwChanIdType
Type representation for a channel id.
Definition: FpConfig.hpp:66
Svc::TlmPacketizerPacket
Definition: TlmPacketizerTypes.hpp:27
NATIVE_INT_TYPE
int NATIVE_INT_TYPE
native integer type declaration
Definition: BasicTypes.hpp:27
Os::Mutex::lock
void lock()
lock the mutex
Definition: Mutex.cpp:12
Svc::TlmPacketizerPacket::numEntries
NATIVE_UINT_TYPE numEntries
number of channels in packet
Definition: TlmPacketizerTypes.hpp:31
Svc::TlmPacketizerChannelEntry::size
NATIVE_UINT_TYPE size
serialized size of channel in bytes
Definition: TlmPacketizerTypes.hpp:24
OK
@ OK
Definition: StandardTypes.hpp:15
Svc::TlmPacketizerPacket::id
FwTlmPacketizeIdType id
packet ID
Definition: TlmPacketizerTypes.hpp:29
Svc::TlmPacketizerPacketList
Definition: TlmPacketizerTypes.hpp:34
FwOpcodeType
#define FwOpcodeType
Type representation for a command opcode.
Definition: FpConfig.hpp:62
Fw::SerializeBufferBase::getBuffLength
NATIVE_UINT_TYPE getBuffLength() const
returns current buffer size
Definition: Serializable.cpp:594
Fw::ExternalSerializeBuffer
Definition: Serializable.hpp:153
FW_ASSERT
#define FW_ASSERT(...)
Definition: Assert.hpp:9
Svc::TlmPacketizer::setPacketList
void setPacketList(const TlmPacketizerPacketList &packetList, const Svc::TlmPacketizerPacket &ignoreList, const NATIVE_UINT_TYPE startLevel)
Definition: TlmPacketizer.cpp:73
Svc::TlmPacketizer::~TlmPacketizer
~TlmPacketizer(void)
Definition: TlmPacketizer.cpp:68
Fw::ComPacket::FW_PACKET_PACKETIZED_TLM
@ FW_PACKET_PACKETIZED_TLM
Definition: ComPacket.hpp:26
Svc::TlmPacketizerPacketList::list
const TlmPacketizerPacket * list[MAX_PACKETIZER_PACKETS]
Definition: TlmPacketizerTypes.hpp:35
FW_COM_BUFFER_MAX_SIZE
#define FW_COM_BUFFER_MAX_SIZE
Max size of Fw::Com buffer.
Definition: FpConfig.hpp:212
Svc
Definition: ActiveRateGroupCfg.hpp:18
TlmPacketizer.hpp
Svc::TLMPACKETIZER_HASH_BUCKETS
static const NATIVE_UINT_TYPE TLMPACKETIZER_HASH_BUCKETS
Definition: TlmPacketizerComponentImplCfg.hpp:26
Fw::Time::SERIALIZED_SIZE
@ SERIALIZED_SIZE
Definition: Time.hpp:14
Svc::TlmPacketizer::init
void init(const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance=0)
Definition: TlmPacketizer.cpp:59
Os::Mutex::unLock
void unLock()
unlock the mutex
Definition: Mutex.cpp:13
Svc::PACKET_UPDATE_MODE
static const PacketUpdateMode PACKET_UPDATE_MODE
Definition: TlmPacketizerComponentImplCfg.hpp:37
Svc::TlmPacketizerPacket::level
NATIVE_UINT_TYPE level
packet level - used to select set of packets to send
Definition: TlmPacketizerTypes.hpp:30
Fw::FW_SERIALIZE_OK
@ FW_SERIALIZE_OK
Serialization/Deserialization operation was successful.
Definition: Serializable.hpp:15
ComPacket.hpp