F´ Flight Software - C/C++ Documentation  NASA-v2.1.0
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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] = 0;
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 = 0;
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 = 0;
154  TlmEntry* prevEntry = 0;
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 = 0;
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 = 0;
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 = 0;
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::COMMAND_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::COMMAND_VALIDATION_ERROR);
370  return;
371  }
372 
373  this->cmdResponse_out(opCode, cmdSeq, Fw::COMMAND_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
FwTlmPacketizeIdType
#define FwTlmPacketizeIdType
Packetized telemetry packet id.
Definition: FpConfig.hpp:78
Os::Mutex::lock
void lock(void)
lock the mutex
Definition: Mutex.cpp:12
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
Os::Mutex::unLock
void unLock(void)
unlock the mutex
Definition: Mutex.cpp:13
Fw::SerializeStatus
SerializeStatus
forward declaration for string
Definition: Serializable.hpp:14
Fw::TlmBuffer
Definition: TlmBuffer.hpp:21
FwChanIdType
#define FwChanIdType
Type representation for a channel id.
Definition: FpConfig.hpp:66
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
FwPacketDescriptorType
#define FwPacketDescriptorType
Type representation for a packet descriptor.
Definition: FpConfig.hpp:58
U8
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.hpp:76
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
Svc::TlmPacketizerChannelEntry::id
FwChanIdType id
Id of channel.
Definition: TlmPacketizerTypes.hpp:23
Svc::TlmPacketizerPacketList::numEntries
NATIVE_UINT_TYPE numEntries
Definition: TlmPacketizerTypes.hpp:36
Fw::FW_SERIALIZE_OK
@ FW_SERIALIZE_OK
Serialization/Deserialization operation was successful.
Definition: Serializable.hpp:15
Svc::TlmPacketizerPacket
Definition: TlmPacketizerTypes.hpp:27
Fw::Time::SERIALIZED_SIZE
@ SERIALIZED_SIZE
Definition: Time.hpp:14
Svc::TlmPacketizerPacket::numEntries
NATIVE_UINT_TYPE numEntries
number of channels in packet
Definition: TlmPacketizerTypes.hpp:31
Fw::TlmBuffer::getBuffAddr
U8 * getBuffAddr(void)
gets buffer address for data filling
Definition: TlmBuffer.cpp:36
Svc::TlmPacketizerChannelEntry::size
NATIVE_UINT_TYPE size
serialized size of channel in bytes
Definition: TlmPacketizerTypes.hpp:24
FwOpcodeType
#define FwOpcodeType
Type representation for a command opcode.
Definition: FpConfig.hpp:62
NATIVE_UINT_TYPE
unsigned int NATIVE_UINT_TYPE
native unsigned integer type declaration
Definition: BasicTypes.hpp:30
Svc::TlmPacketizerPacket::id
FwTlmPacketizeIdType id
packet ID
Definition: TlmPacketizerTypes.hpp:29
Svc::TlmPacketizerPacketList
Definition: TlmPacketizerTypes.hpp:34
FW_ASSERT
#define FW_ASSERT(...)
Definition: Assert.hpp:9
Fw::SerializeBufferBase::getBuffLength
NATIVE_UINT_TYPE getBuffLength() const
returns current buffer size
Definition: Serializable.cpp:587
Fw::ExternalSerializeBuffer
Definition: Serializable.hpp:156
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
Svc
Definition: ActiveRateGroupImplCfg.hpp:18
TlmPacketizer.hpp
Svc::TLMPACKETIZER_HASH_BUCKETS
static const NATIVE_UINT_TYPE TLMPACKETIZER_HASH_BUCKETS
Definition: TlmPacketizerComponentImplCfg.hpp:26
FW_COM_BUFFER_MAX_SIZE
#define FW_COM_BUFFER_MAX_SIZE
Max size of Fw::Com buffer.
Definition: FpConfig.hpp:224
Svc::TlmPacketizer::init
void init(const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance=0)
Definition: TlmPacketizer.cpp:59
BasicTypes.hpp
Declares ISF basic types.
Svc::PACKET_UPDATE_MODE
static const PacketUpdateMode PACKET_UPDATE_MODE
Definition: TlmPacketizerComponentImplCfg.hpp:37
NATIVE_INT_TYPE
int NATIVE_INT_TYPE
native integer type declaration
Definition: BasicTypes.hpp:29
Svc::TlmPacketizerPacket::level
NATIVE_UINT_TYPE level
packet level - used to select set of packets to send
Definition: TlmPacketizerTypes.hpp:30
ComPacket.hpp