// ====================================================================== // \title SequenceFileLoader.cpp // \author bocchino // \brief cpp file for SequenceFileLoader component implementation class // // \copyright // Copyright (C) 2009-2016 California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // // ====================================================================== #include #include #include #include // TKC - don't know why it's undefined in VxWorks #ifdef TGT_OS_TYPE_VXWORKS #define M_PI (22.0 / 7.0) #endif namespace Ref { // ---------------------------------------------------------------------- // Construction, initialization, and destruction // ---------------------------------------------------------------------- SignalGen ::SignalGen(const char* name) : SignalGenComponentBase(name), sampleFrequency(25), signalFrequency(1), signalAmplitude(0.0f), signalPhase(0.0f), ticks(0), sigType(SignalType::SINE), sigHistory(), sigPairHistory(), running(false), skipOne(false), m_dpInProgress(false), m_numDps(0), m_currDp(0), m_dpPriority(0) {} SignalGen ::~SignalGen() {} // ---------------------------------------------------------------------- // Handler implementations // ---------------------------------------------------------------------- F32 SignalGen::generateSample(U32 ticks) { F32 val = 0.0f; if (this->skipOne) { return val; } // Samples per period F32 samplesPerPeriod = static_cast(this->sampleFrequency) / static_cast(this->signalFrequency); U32 halfSamplesPerPeriod = samplesPerPeriod / 2; /* Signals courtesy of the open source Aquila DSP Library */ switch (this->sigType.e) { case SignalType::TRIANGLE: { F32 m = this->signalAmplitude / static_cast(halfSamplesPerPeriod); val = m * static_cast(ticks % halfSamplesPerPeriod); break; } case SignalType::SINE: { F32 normalizedFrequency = 1.0f / samplesPerPeriod; val = this->signalAmplitude * std::sin((2.0 * M_PI * normalizedFrequency * static_cast(ticks)) + (this->signalPhase * 2.0 * M_PI)); break; } case SignalType::SQUARE: { val = this->signalAmplitude * ((ticks % static_cast(samplesPerPeriod) < halfSamplesPerPeriod) ? 1.0f : -1.0f); break; } case SignalType::NOISE: { val = this->signalAmplitude * (std::rand() / static_cast(RAND_MAX)); break; } default: FW_ASSERT(0); // Should never happen } return val; } void SignalGen::schedIn_handler(FwIndexType portNum, /*!< The port number*/ U32 context /*!< The call order*/ ) { F32 value = 0.0f; // This is a queued component, so it must intentionally run the dispatch of commands and queue processing on this // synchronous scheduled call this->doDispatch(); // This short-circuits when the signal generator is not running if (not this->running) { return; } // Allows for skipping a single reading of the signal if (not this->skipOne) { value = this->generateSample(this->ticks); } this->skipOne = false; // Build our new types SignalPair pair = SignalPair(this->ticks, value); // Shift and assign our array types for (U32 i = 1; i < this->sigHistory.SIZE; i++) { this->sigHistory[i - 1] = this->sigHistory[i]; this->sigPairHistory[i - 1] = this->sigPairHistory[i]; } this->sigHistory[this->sigHistory.SIZE - 1] = value; this->sigPairHistory[this->sigPairHistory.SIZE - 1] = pair; // Composite structure SignalInfo sigInfo(this->sigType, this->sigHistory, this->sigPairHistory); // Write all signals this->tlmWrite_Type(this->sigType); this->tlmWrite_Output(value); this->tlmWrite_PairOutput(pair); this->tlmWrite_History(this->sigHistory); this->tlmWrite_PairHistory(this->sigPairHistory); this->tlmWrite_Info(sigInfo); // if a Data product is being generated, store a record if (this->m_dpInProgress) { Fw::SerializeStatus stat = this->m_dpContainer.serializeRecord_DataRecord(sigInfo); this->m_currDp++; this->m_dpBytes += SignalInfo::SERIALIZED_SIZE; // check for full data product if (Fw::SerializeStatus::FW_SERIALIZE_NO_ROOM_LEFT == stat) { this->log_WARNING_LO_DpRecordFull(this->m_currDp, this->m_dpBytes); this->cleanupAndSendDp(); } else if (this->m_currDp == this->m_numDps) { // if we reached the target number of DPs this->log_ACTIVITY_LO_DpComplete(this->m_numDps, this->m_dpBytes); this->cleanupAndSendDp(); } this->tlmWrite_DpBytes(this->m_dpBytes); this->tlmWrite_DpRecords(this->m_currDp); } this->ticks += 1; } void SignalGen::Settings_cmdHandler(FwOpcodeType opCode, /*!< The opcode*/ U32 cmdSeq, /*!< The command sequence number*/ U32 Frequency, F32 Amplitude, F32 Phase, Ref::SignalType SigType) { this->signalFrequency = Frequency; this->signalAmplitude = Amplitude; this->signalPhase = Phase; this->sigType = SigType; // When the settings change, reset the history values for (U32 i = 0; i < SignalSet::SIZE; i++) { this->sigHistory[i] = 0.0f; } for (U32 i = 0; i < SignalPairSet::SIZE; i++) { this->sigPairHistory[i].set_time(0.0f); this->sigPairHistory[i].set_value(0.0f); } this->log_ACTIVITY_LO_SettingsChanged(this->signalFrequency, this->signalAmplitude, this->signalPhase, this->sigType); this->tlmWrite_Type(SigType); this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } void SignalGen::Toggle_cmdHandler(FwOpcodeType opCode, /*!< The opcode*/ U32 cmdSeq /*!< The command sequence number*/ ) { this->running = !this->running; this->ticks = 0; this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } void SignalGen::Skip_cmdHandler(FwOpcodeType opCode, /*!< The opcode*/ U32 cmdSeq /*!< The command sequence number*/ ) { this->skipOne = true; this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } void SignalGen::Dp_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, Ref::SignalGen_DpReqType reqType, U32 records, U32 priority) { // at least one record if (0 == records) { this->log_WARNING_HI_InSufficientDpRecords(); this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR); return; } // make sure DPs are available if (not this->isConnected_productGetOut_OutputPort(0)) { this->log_WARNING_HI_DpsNotConnected(); this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); return; } // get DP buffer. Use sync or async request depending on // requested type FwSizeType dpSize = records * (SignalInfo::SERIALIZED_SIZE + sizeof(FwDpIdType)); this->m_numDps = records; this->m_currDp = 0; this->m_dpPriority = static_cast(priority); this->log_ACTIVITY_LO_DpMemRequested(dpSize); if (Ref::SignalGen_DpReqType::IMMEDIATE == reqType) { Fw::Success stat = this->dpGet_DataContainer(dpSize, this->m_dpContainer); // make sure we got the memory we wanted if (Fw::Success::FAILURE == stat) { this->log_WARNING_HI_DpMemoryFail(); this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); } else { this->m_dpInProgress = true; this->log_ACTIVITY_LO_DpStarted(records); this->log_ACTIVITY_LO_DpMemReceived(this->m_dpContainer.getBuffer().getSize()); this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); // override priority with requested priority this->m_dpContainer.setPriority(this->m_dpPriority); } } else if (Ref::SignalGen_DpReqType::ASYNC == reqType) { this->dpRequest_DataContainer(dpSize); this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } else { // should never get here FW_ASSERT(0, reqType.e); } } void SignalGen::cleanupAndSendDp() { this->dpSend(this->m_dpContainer); this->m_dpInProgress = false; this->m_dpBytes = 0; this->m_numDps = 0; this->m_currDp = 0; } // ---------------------------------------------------------------------- // Handler implementations for data products // ---------------------------------------------------------------------- void SignalGen ::dpRecv_DataContainer_handler(DpContainer& container, Fw::Success::T status) { // Make sure we got the buffer we wanted or quit if (Fw::Success::SUCCESS == status) { this->m_dpContainer = container; this->m_dpInProgress = true; // set previously requested priority this->m_dpContainer.setPriority(this->m_dpPriority); this->log_ACTIVITY_LO_DpStarted(this->m_numDps); } else { this->log_WARNING_HI_DpMemoryFail(); // cleanup this->m_dpInProgress = false; this->m_dpBytes = 0; this->m_numDps = 0; this->m_currDp = 0; } } } // namespace Ref