F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
SignalGen.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title SequenceFileLoader.cpp
3 // \author bocchino
4 // \brief cpp file for SequenceFileLoader component implementation class
5 //
6 // \copyright
7 // Copyright (C) 2009-2016 California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12 
13 #include <Fw/Types/Assert.hpp>
15 #include <cmath>
16 #include <cstdlib>
17 
18 // TKC - don't know why it's undefined in VxWorks
19 #ifdef TGT_OS_TYPE_VXWORKS
20 #define M_PI (22.0 / 7.0)
21 #endif
22 
23 namespace Ref {
24 
25 // ----------------------------------------------------------------------
26 // Construction, initialization, and destruction
27 // ----------------------------------------------------------------------
28 
29 SignalGen ::SignalGen(const char* name)
30  : SignalGenComponentBase(name),
31  sampleFrequency(25),
32  signalFrequency(1),
33  signalAmplitude(0.0f),
34  signalPhase(0.0f),
35  ticks(0),
36  sigType(SignalType::SINE),
37  sigHistory(),
38  sigPairHistory(),
39  running(false),
40  skipOne(false),
41  m_dpInProgress(false),
42  m_numDps(0),
43  m_currDp(0),
44  m_dpPriority(0) {}
45 
47 
48 // ----------------------------------------------------------------------
49 // Handler implementations
50 // ----------------------------------------------------------------------
51 
52 F32 SignalGen::generateSample(U32 ticks) {
53  F32 val = 0.0f;
54  if (this->skipOne) {
55  return val;
56  }
57  // Samples per period
58  F32 samplesPerPeriod = static_cast<F32>(this->sampleFrequency) / static_cast<F32>(this->signalFrequency);
59  U32 halfSamplesPerPeriod = samplesPerPeriod / 2;
60  /* Signals courtesy of the open source Aquila DSP Library */
61  switch (this->sigType.e) {
62  case SignalType::TRIANGLE: {
63  F32 m = this->signalAmplitude / static_cast<F32>(halfSamplesPerPeriod);
64  val = m * static_cast<F32>(ticks % halfSamplesPerPeriod);
65  break;
66  }
67  case SignalType::SINE: {
68  F32 normalizedFrequency = 1.0f / samplesPerPeriod;
69  val = this->signalAmplitude * std::sin((2.0 * M_PI * normalizedFrequency * static_cast<F32>(ticks)) +
70  (this->signalPhase * 2.0 * M_PI));
71  break;
72  }
73  case SignalType::SQUARE: {
74  val = this->signalAmplitude *
75  ((ticks % static_cast<U32>(samplesPerPeriod) < halfSamplesPerPeriod) ? 1.0f : -1.0f);
76  break;
77  }
78  case SignalType::NOISE: {
79  val = this->signalAmplitude * (std::rand() / static_cast<double>(RAND_MAX));
80  break;
81  }
82  default:
83  FW_ASSERT(0); // Should never happen
84  }
85  return val;
86 }
87 
88 void SignalGen::schedIn_handler(FwIndexType portNum,
89  U32 context
90 ) {
91  F32 value = 0.0f;
92  // This is a queued component, so it must intentionally run the dispatch of commands and queue processing on this
93  // synchronous scheduled call
94  this->doDispatch();
95 
96  // This short-circuits when the signal generator is not running
97  if (not this->running) {
98  return;
99  }
100  // Allows for skipping a single reading of the signal
101  if (not this->skipOne) {
102  value = this->generateSample(this->ticks);
103  }
104  this->skipOne = false;
105 
106  // Build our new types
107  SignalPair pair = SignalPair(this->ticks, value);
108 
109  // Shift and assign our array types
110  for (U32 i = 1; i < this->sigHistory.SIZE; i++) {
111  this->sigHistory[i - 1] = this->sigHistory[i];
112  this->sigPairHistory[i - 1] = this->sigPairHistory[i];
113  }
114  this->sigHistory[this->sigHistory.SIZE - 1] = value;
115  this->sigPairHistory[this->sigPairHistory.SIZE - 1] = pair;
116 
117  // Composite structure
118  SignalInfo sigInfo(this->sigType, this->sigHistory, this->sigPairHistory);
119 
120  // Write all signals
121  this->tlmWrite_Type(this->sigType);
122  this->tlmWrite_Output(value);
123  this->tlmWrite_PairOutput(pair);
124  this->tlmWrite_History(this->sigHistory);
125  this->tlmWrite_PairHistory(this->sigPairHistory);
126  this->tlmWrite_Info(sigInfo);
127 
128  // if a Data product is being generated, store a record
129  if (this->m_dpInProgress) {
130  Fw::SerializeStatus stat = this->m_dpContainer.serializeRecord_DataRecord(sigInfo);
131  this->m_currDp++;
132  this->m_dpBytes += SignalInfo::SERIALIZED_SIZE;
133  // check for full data product
135  this->log_WARNING_LO_DpRecordFull(this->m_currDp, this->m_dpBytes);
136  this->cleanupAndSendDp();
137  } else if (this->m_currDp == this->m_numDps) { // if we reached the target number of DPs
138  this->log_ACTIVITY_LO_DpComplete(this->m_numDps, this->m_dpBytes);
139  this->cleanupAndSendDp();
140  }
141 
142  this->tlmWrite_DpBytes(this->m_dpBytes);
143  this->tlmWrite_DpRecords(this->m_currDp);
144  }
145 
146  this->ticks += 1;
147 }
148 
149 void SignalGen::Settings_cmdHandler(FwOpcodeType opCode,
150  U32 cmdSeq,
151  U32 Frequency,
152  F32 Amplitude,
153  F32 Phase,
154  Ref::SignalType SigType) {
155  this->signalFrequency = Frequency;
156  this->signalAmplitude = Amplitude;
157  this->signalPhase = Phase;
158  this->sigType = SigType;
159 
160  // When the settings change, reset the history values
161  for (U32 i = 0; i < SignalSet::SIZE; i++) {
162  this->sigHistory[i] = 0.0f;
163  }
164  for (U32 i = 0; i < SignalPairSet::SIZE; i++) {
165  this->sigPairHistory[i].set_time(0.0f);
166  this->sigPairHistory[i].set_value(0.0f);
167  }
168  this->log_ACTIVITY_LO_SettingsChanged(this->signalFrequency, this->signalAmplitude, this->signalPhase,
169  this->sigType);
170  this->tlmWrite_Type(SigType);
171  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
172 }
173 
174 void SignalGen::Toggle_cmdHandler(FwOpcodeType opCode,
175  U32 cmdSeq
176 ) {
177  this->running = !this->running;
178  this->ticks = 0;
179  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
180 }
181 
182 void SignalGen::Skip_cmdHandler(FwOpcodeType opCode,
183  U32 cmdSeq
184 ) {
185  this->skipOne = true;
186  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
187 }
188 
189 void SignalGen::Dp_cmdHandler(FwOpcodeType opCode,
190  U32 cmdSeq,
191  Ref::SignalGen_DpReqType reqType,
192  U32 records,
193  U32 priority) {
194  // at least one record
195  if (0 == records) {
196  this->log_WARNING_HI_InSufficientDpRecords();
197  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
198  return;
199  }
200 
201  // make sure DPs are available
202  if (not this->isConnected_productGetOut_OutputPort(0)) {
203  this->log_WARNING_HI_DpsNotConnected();
204  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
205  return;
206  }
207 
208  // get DP buffer. Use sync or async request depending on
209  // requested type
210  FwSizeType dpSize = records * (SignalInfo::SERIALIZED_SIZE + sizeof(FwDpIdType));
211  this->m_numDps = records;
212  this->m_currDp = 0;
213  this->m_dpPriority = static_cast<FwDpPriorityType>(priority);
214  this->log_ACTIVITY_LO_DpMemRequested(dpSize);
215  if (Ref::SignalGen_DpReqType::IMMEDIATE == reqType) {
216  Fw::Success stat = this->dpGet_DataContainer(dpSize, this->m_dpContainer);
217  // make sure we got the memory we wanted
218  if (Fw::Success::FAILURE == stat) {
219  this->log_WARNING_HI_DpMemoryFail();
220  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
221  } else {
222  this->m_dpInProgress = true;
223  this->log_ACTIVITY_LO_DpStarted(records);
224  this->log_ACTIVITY_LO_DpMemReceived(this->m_dpContainer.getBuffer().getSize());
225  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
226  // override priority with requested priority
227  this->m_dpContainer.setPriority(this->m_dpPriority);
228  }
229  } else if (Ref::SignalGen_DpReqType::ASYNC == reqType) {
230  this->dpRequest_DataContainer(dpSize);
231  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
232  } else {
233  // should never get here
234  FW_ASSERT(0, reqType.e);
235  }
236 }
237 
238 void SignalGen::cleanupAndSendDp() {
239  this->dpSend(this->m_dpContainer);
240  this->m_dpInProgress = false;
241  this->m_dpBytes = 0;
242  this->m_numDps = 0;
243  this->m_currDp = 0;
244 }
245 
246 // ----------------------------------------------------------------------
247 // Handler implementations for data products
248 // ----------------------------------------------------------------------
249 
250 void SignalGen ::dpRecv_DataContainer_handler(DpContainer& container, Fw::Success::T status) {
251  // Make sure we got the buffer we wanted or quit
252  if (Fw::Success::SUCCESS == status) {
253  this->m_dpContainer = container;
254  this->m_dpInProgress = true;
255  // set previously requested priority
256  this->m_dpContainer.setPriority(this->m_dpPriority);
257  this->log_ACTIVITY_LO_DpStarted(this->m_numDps);
258  } else {
259  this->log_WARNING_HI_DpMemoryFail();
260  // cleanup
261  this->m_dpInProgress = false;
262  this->m_dpBytes = 0;
263  this->m_numDps = 0;
264  this->m_currDp = 0;
265  }
266 }
267 
268 } // namespace Ref
FwIdType FwOpcodeType
The type of a command opcode.
Representing success.
PlatformSizeType FwSizeType
U32 FwDpPriorityType
The type of a data product priority.
No room left in the buffer to serialize data.
SerializeStatus
forward declaration for string
float F32
32-bit floating point
Definition: BasicTypes.h:84
T
The raw enum type.
Representing failure.
Command successfully executed.
Command had execution error.
FwIdType FwDpIdType
The type of a data product identifier.
PlatformIndexType FwIndexType
Command failed validation.
~SignalGen()
Destroy a SignalGen.
Definition: SignalGen.cpp:46
SignalGen(const char *compName)
Construct a SignalGen.
Definition: SignalGen.cpp:29
#define FW_ASSERT(...)
Definition: Assert.hpp:14
Success/Failure.