From 06242bd5c9bfe0afb44a3c1c6482dc8c1599ea80 Mon Sep 17 00:00:00 2001 From: Bernardo Carvalho Date: Wed, 17 Apr 2024 18:17:21 +0100 Subject: [PATCH] New Datasource Signed-off-by: Bernardo Carvalho --- DataSources/AtcaIop/AtcaIopConfigEoWo.cpp | 411 ++++++++++++++++++++++ DataSources/AtcaIop/AtcaIopConfigEoWo.h | 247 +++++++++++++ 2 files changed, 658 insertions(+) create mode 100644 DataSources/AtcaIop/AtcaIopConfigEoWo.cpp create mode 100644 DataSources/AtcaIop/AtcaIopConfigEoWo.h diff --git a/DataSources/AtcaIop/AtcaIopConfigEoWo.cpp b/DataSources/AtcaIop/AtcaIopConfigEoWo.cpp new file mode 100644 index 0000000..ad8b940 --- /dev/null +++ b/DataSources/AtcaIop/AtcaIopConfigEoWo.cpp @@ -0,0 +1,411 @@ +/** + * @file AtcaIopConfigEoWo.cpp + * @brief Source file for class AtcaIopConfigEoWo + * @date 19/04/2024 + * @author Andre Neto / Bernardo Carvalho + * + * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and + * the Development of Fusion Energy ('Fusion for Energy'). + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence") + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl + * + * @warning Unless required by applicable law or agreed to in writing, + * software distributed under the Licence is distributed on an "AS IS" + * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence permissions and limitations under the Licence. + + * @details This source file contains the definition of all the methods for + * the class AtcaIopConfigEoWo (public, protected, and private). Be aware that some + * methods, such as those inline could be defined on the header file, instead. + * + */ + +#define DLL_API + +/*---------------------------------------------------------------------------*/ +/* Standard header includes */ +/*---------------------------------------------------------------------------*/ +#include + +#include // for close() +#include + +/*---------------------------------------------------------------------------*/ +/* Project header includes */ +/*---------------------------------------------------------------------------*/ +#include "AdvancedErrorManagement.h" +#include "MemoryMapSynchronisedOutputBroker.h" +#include "AtcaIopConfigEoWo.h" + +/*---------------------------------------------------------------------------*/ +/* Static definitions */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Method definitions */ +/*---------------------------------------------------------------------------*/ +namespace MARTe { + const float32 DAC_RANGE = 20.0; + const float32 ATCA_IOP_MAX_DAC_RANGE = 20.0; + AtcaIopConfigEoWo::AtcaIopConfigEoWo() : + DataSourceI(), + MessageI() { + boardFileDescriptor = -1; + //numberOfDACsEnabled = 0u; + //isMaster = 0u; + deviceName = ""; + boardId = 0u; + triggerSet = false; + uint32 n; + synchCounter = 0u; + + //channelsMemory = NULL_PTR(float32 *); + eoValues = NULL_PTR(int32 *); + woValues = NULL_PTR(float32 *); + + filter = ReferenceT(GlobalObjectsDatabase::Instance()->GetStandardHeap()); + filter->SetDestination(this); + ErrorManagement::ErrorType ret = MessageI::InstallMessageFilter(filter); + if (!ret.ErrorsCleared()) { + REPORT_ERROR(ErrorManagement::FatalError, "Failed to install message filters"); + } + } + + /*lint -e{1551} the destructor must guarantee that the Timer SingleThreadService is stopped.*/ + AtcaIopConfigEoWo::~AtcaIopConfigEoWo() { + if (boardFileDescriptor != -1) { + uint32 statusReg = 0; + //REPORT_ERROR(ErrorManagement::Information, " Close Device Status Reg %d, 0x%x", rc, statusReg); + close(boardFileDescriptor); + REPORT_ERROR(ErrorManagement::Information, "Close device %d OK. Status Reg 0x%x,", boardFileDescriptor, statusReg); + } + if (eoValues != NULL_PTR(int32 *)) { + delete[] eoValues; + } + if (woValues != NULL_PTR(float32 *)) { + delete[] woValues; + } + //if (channelsMemory != NULL_PTR(float32 *)) { + //delete[] channelsMemory; + //} + } + + bool AtcaIopConfigEoWo::AllocateMemory() { + return true; + } + + uint32 AtcaIopConfigEoWo::GetNumberOfMemoryBuffers() { + return 1u; + } + + /*lint -e{715} [MISRA C++ Rule 0-1-11], [MISRA C++ Rule 0-1-12]. Justification: The memory buffer is independent of the bufferIdx.*/ + bool AtcaIopConfigEoWo::GetSignalMemoryBuffer(const uint32 signalIdx, const uint32 bufferIdx, void*& signalAddress) { + //bool ok = (signalIdx < (ATCA_IOP_EOWO_N_SIGNALS)); + bool ok = true; + if (signalIdx == 0u) { + signalAddress = &eoValues[0]; + } + else if (signalIdx == 1u) { + signalAddress = woValues; //&counterAndTimer[1]; + } + else { + ok = false; + } + /* + bool ok = (signalIdx < (ATCA_IOP_MAX_DAC_CHANNELS)); + if (ok) { + if (channelsMemory != NULL_PTR(float32 *)) { + signalAddress = &(channelsMemory[signalIdx]); + } + } + */ + return ok; + } + + const char8* AtcaIopConfigEoWo::GetBrokerName(StructuredDataI& data, const SignalDirection direction) { + const char8 *brokerName = NULL_PTR(const char8 *); + if (direction == OutputSignals) { + uint32 trigger = 0u; + if (!data.Read("Trigger", trigger)) { + trigger = 0u; + } + + if (trigger == 1u) { + brokerName = "MemoryMapSynchronisedOutputBroker"; + triggerSet = true; + } + else { + brokerName = "MemoryMapOutputBroker"; + } + } + else { + REPORT_ERROR(ErrorManagement::ParametersError, "DataSource not compatible with InputSignals"); + } + return brokerName; + } + + bool AtcaIopConfigEoWo::GetInputBrokers(ReferenceContainer& inputBrokers, const char8* const functionName, void* const gamMemPtr) { + return false; + } + + bool AtcaIopConfigEoWo::GetOutputBrokers(ReferenceContainer& outputBrokers, const char8* const functionName, void* const gamMemPtr) { + //Check if there is a Trigger signal for this function. + uint32 functionIdx = 0u; + uint32 nOfFunctionSignals = 0u; + uint32 i; + bool triggerGAM = false; + bool ok = GetFunctionIndex(functionIdx, functionName); + + if (ok) { + ok = GetFunctionNumberOfSignals(OutputSignals, functionIdx, nOfFunctionSignals); + } + uint32 trigger = 0u; + for (i = 0u; (i < nOfFunctionSignals) && (ok) && (!triggerGAM); i++) { + ok = GetFunctionSignalTrigger(OutputSignals, functionIdx, i, trigger); + triggerGAM = (trigger == 1u); + } + if ((ok) && (triggerGAM)) { + ReferenceT broker("MemoryMapSynchronisedOutputBroker"); + ok = broker.IsValid(); + + if (ok) { + ok = broker->Init(OutputSignals, *this, functionName, gamMemPtr); + } + if (ok) { + ok = outputBrokers.Insert(broker); + } + //Must also add the signals which are not triggering but that belong to the same GAM... + if (ok) { + if (nOfFunctionSignals > 1u) { + ReferenceT brokerNotSync("MemoryMapOutputBroker"); + ok = brokerNotSync.IsValid(); + if (ok) { + ok = brokerNotSync->Init(OutputSignals, *this, functionName, gamMemPtr); + } + if (ok) { + ok = outputBrokers.Insert(brokerNotSync); + } + } + } + } + else { + ReferenceT brokerNotSync("MemoryMapOutputBroker"); + ok = brokerNotSync.IsValid(); + if (ok) { + ok = brokerNotSync->Init(OutputSignals, *this, functionName, gamMemPtr); + } + if (ok) { + ok = outputBrokers.Insert(brokerNotSync); + } + } + return ok; + } + + /*lint -e{715} [MISRA C++ Rule 0-1-11], [MISRA C++ Rule 0-1-12]. Justification: the counter and the timer are always reset irrespectively of the states being changed.*/ + bool AtcaIopConfigEoWo::PrepareNextState(const char8* const currentStateName, const char8* const nextStateName) { + REPORT_ERROR(ErrorManagement::Information, " EoWo currentStateName %s, nextStateName %s", currentStateName, nextStateName); + return true; + } + + bool AtcaIopConfigEoWo::Initialise(StructuredDataI& data) { + bool ok = DataSourceI::Initialise(data); + if (ok) { + ok = data.Read("DeviceName", deviceName); + if (!ok) { + REPORT_ERROR(ErrorManagement::ParametersError, "The DeviceName shall be specified"); + } + } + if (ok) { + ok = data.Read("BoardId", boardId); + if (!ok) { + REPORT_ERROR(ErrorManagement::ParametersError, "The BoardId shall be specified"); + } + } + + + //Get individual signal parameters + //uint32 i = 0u; + /* + if (ok) { + ok = data.MoveRelative("Signals"); + if (!ok) { + REPORT_ERROR(ErrorManagement::ParametersError, "Could not move to the Signals section"); + } + //Do not allow to add signals in run-time + if (ok) { + ok = signalsDatabase.MoveRelative("Signals"); + } + if (ok) { + ok = signalsDatabase.Write("Locked", 1u); + } + if (ok) { + ok = signalsDatabase.MoveToAncestor(1u); + } + while ((i < ATCA_IOP_MAX_DAC_CHANNELS) && (ok)) { + if (data.MoveRelative(data.GetChildName(i))) { + //uint32 channelId; + float32 range; + ok = data.Read("OutputRange", range); + if (ok) { + //if (data.Read("OutputRange", range)) { + ok = (range > 0.0) && (range <= ATCA_IOP_MAX_DAC_RANGE); + if (!ok) { + REPORT_ERROR(ErrorManagement::ParametersError, "Invalid OutputRange specified."); + } + if (ok) { + outputRange[i] = range; + REPORT_ERROR(ErrorManagement::Information, " Parameter DAC %d Output Range %f", i, range); + //dacEnabled[i] = true; + numberOfDACsEnabled++; + } + } + else { + REPORT_ERROR(ErrorManagement::ParametersError, "The OutputRange shall be specified."); + } + if (ok) { + ok = data.MoveToAncestor(1u); + } + i++; + } + else { + break; + } + } + } +// REPORT_ERROR(ErrorManagement::Information, "numberOfDACsEnabled %d", numberOfDACsEnabled); +// +*/ + + return ok; + } + + bool AtcaIopConfigEoWo::SetConfiguredDatabase(StructuredDataI& data) { + uint32 i; + bool ok = DataSourceI::SetConfiguredDatabase(data); + + if (ok) { + ok = triggerSet; + } + if (!ok) { + REPORT_ERROR(ErrorManagement::ParametersError, "At least one Trigger signal shall be set."); + } + + // Check the signal index + uint32 nOfSignals = GetNumberOfSignals(); + if (ok) { + ok = (nOfSignals > 0u); + if (!ok) { + REPORT_ERROR(ErrorManagement::ParametersError, "At least one signal shall be defined"); + } + } + if (ok) { + ok = (GetSignalType(0).type == SignedInteger); + if (!ok) { + REPORT_ERROR(ErrorManagement::ParametersError, "EO signal shall be of type SignedInteger"); + } + else { + //In member function ‘virtual bool MARTe::AtcaIopConfigEoWo::SetConfiguredDatabase(MARTe::StructuredDataI&)’: +//AtcaIopConfigEoWo.cpp:311:49: error: no match for ‘operator==’ (operand types are ‘MARTe::BitRange’ and ‘const MARTe::TypeDescriptor’) + ok = (GetSignalType(1) == Float32Bit); + if (!ok) { + REPORT_ERROR(ErrorManagement::ParametersError, "WO signal shall be of type Float32Bit"); + } + } + } + uint32 nOfFunctions = GetNumberOfFunctions(); + uint32 functionIdx; + /* + //Check that the number of samples for all the signals is one + for (functionIdx = 0u; (functionIdx < nOfFunctions) && (ok); functionIdx++) { + + for (i = 0u; (i < nOfSignals) && (ok); i++) { + uint32 nSamples = 0u; + ok = GetFunctionSignalSamples(OutputSignals, functionIdx, i, nSamples); + if (ok) { + ok = (nSamples == 1u); + } + if (!ok) { + REPORT_ERROR(ErrorManagement::ParametersError, "The number of samples shall be exactly one"); + } + } + } +*/ + StreamString fullDeviceName; + //Configure the board + if (ok) { + ok = fullDeviceName.Printf("%s_eo_%d", deviceName.Buffer(), boardId); + } + if (ok) { + ok = fullDeviceName.Seek(0LLU); + } + if (ok) { + boardFileDescriptor = open(fullDeviceName.Buffer(), O_RDWR); + ok = (boardFileDescriptor > -1); + if (!ok) { + REPORT_ERROR_PARAMETERS(ErrorManagement::ParametersError, "Could not open device %s", fullDeviceName); + } + else + REPORT_ERROR(ErrorManagement::Information, "Open device %s OK", fullDeviceName); + } + if (ok) { + //Allocate memory + //channelsMemory = new float32[ATCA_IOP_MAX_DAC_CHANNELS]; + eoValues = new int32[ATCA_IOP_MAX_ADC_CHANNELS]; + woValues = new float32[ATCA_IOP_MAX_ADC_CHANNELS]; + } + + return ok; + } + + + bool AtcaIopConfigEoWo::Synchronise() { + uint32 i; + int32 w; + bool ok = true; + if((synchCounter++)%4096 == 0) { + REPORT_ERROR(ErrorManagement::Information, " Synchronise"); + } + /* + if (channelsMemory != NULL_PTR(float32 *)) { + +// value = channelsMemory[0] / DAC_RANGE; + for (i = 0u; (i < 2u) && (ok); i++) { + //for (i = 0u; (i < numberOfDACsEnabled ) && (ok); i++) { + float32 value = channelsMemory[i] / outputRange[i]; + w = SetDacReg(i, value); + write(boardFileDescriptor, &w, 4); + // value = channelsMemory[1] / DAC_RANGE; + //value = channelsMemory[1] / DAC_RANGE * pow(2,17); + // w = SetDacReg(1, value); + //w = 0x000FFFFF & static_cast(value); + // write(boardFileDescriptor, &w, 4); + //REPORT_ERROR(ErrorManagement::Information, " Writing DAC 0 0x%x", w); + } + } + + w = dacValues[i]; + } + */ + return ok; + } + + int32 AtcaIopConfigEoWo::SetDacReg(uint32 channel, float32 val) const { + if (val > 1.0) + val = 1.0; + if (val < -1.0) + val = -1.0; + int32 dacReg = static_cast(val * pow(2,17)); + if (dacReg > 0x1FFFF) // 131071 + dacReg = 0x1FFFF; + if (dacReg < -131072) // -0x20000 + dacReg = -131072; + dacReg &= 0x0003FFFF; // keep 18 lsb + dacReg |= (0xF & channel) << 28; + return dacReg; + } + + CLASS_REGISTER(AtcaIopConfigEoWo, "1.0") + } + // vim: syntax=cpp ts=4 sw=4 sts=4 sr et diff --git a/DataSources/AtcaIop/AtcaIopConfigEoWo.h b/DataSources/AtcaIop/AtcaIopConfigEoWo.h new file mode 100644 index 0000000..6c04a30 --- /dev/null +++ b/DataSources/AtcaIop/AtcaIopConfigEoWo.h @@ -0,0 +1,247 @@ +/** + * @file AtcaIopConfigEoWo.h + * @brief Header file for class AtcaIopConfigEoWo + * @date 19/04/2024 + * @author Andre Neto / Bernardo Carvalho + * + * Based on Example: + * + * + * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and + * the Development of Fusion Energy ('Fusion for Energy'). + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved + * by the European Commission - subsequent versions of the EUPL (the "Licence") + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl + * + * @warning Unless required by applicable law or agreed to in writing, + * software distributed under the Licence is distributed on an "AS IS" + * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence permissions and limitations under the Licence. + + * @details This header file contains the declaration of the class AtcaIopConfigEoWo + * with all of its public, protected and private members. It may also include + * definitions for inline methods which need to be visible to the compiler. + */ + +#ifndef ATCA_IOP_DAC_H +#define ATCA_IOP_DAC_H + +/*---------------------------------------------------------------------------*/ +/* Standard header includes */ +/*-------DTYP--------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Project header includes */ +/*---------------------------------------------------------------------------*/ +#include "DataSourceI.h" +#include "EventSem.h" +#include "EmbeddedServiceMethodBinderI.h" +#include "SingleThreadService.h" +#include "MessageI.h" +#include "RegisteredMethodsMessageFilter.h" + +/*---------------------------------------------------------------------------*/ +/* Class declaration */ +/*---------------------------------------------------------------------------*/ +namespace MARTe { + + /** + * The number of signals + */ + + //const uint32 ATCA_IOP_N_DACs = 2u; + const uint32 ATCA_IOP_EOWO_N_SIGNALS = 2u; + //const uint32 ATCA_IOP_MAX_DAC_CHANNELS = 16u; + const uint32 ATCA_IOP_MAX_ADC_CHANNELS = 16u; + +/** + * @brief A DataSource which provides an analogue output interface to the ATCA IOP boards. + * @details The configuration syntax is (names are only given as an example): + * + *
+ * +AtcaIopConfigEoWo_2 = {
+ *     Class = AtcaIop::AtcaIopConfigEoWo
+ *     DeviceName = "/dev/atca_v6" //Mandatory
+ *     BoardId = 0 //Mandatory
+ *     Signals = {
+ *         EO = {
+ *             Type = int32 //Mandatory. Only type that is supported.
+ *         }
+ *         WO = {
+ *             Type = float32 //Mandatory. Only type that is supported.
+ *         }
+ *     }
+ * }
+ * 
+ * Note that at least one of the GAMs writing to this DataSource must have set one of the signals with Trigger=1 (which forces the writing of all the signals to the DAC). + */ + class AtcaIopConfigEoWo: public DataSourceI, public MessageI { + public: + CLASS_REGISTER_DECLARATION() + /** + * @brief Default constructor + * @post + * Counter = 0 + * Time = 0 + */ + AtcaIopConfigEoWo (); + + /** + * @brief Destructor. Stops the EmbeddedThread. + */ + virtual ~AtcaIopConfigEoWo(); + + /** + * @brief See DataSourceI::AllocateMemory. + * * @return true. + */ + virtual bool AllocateMemory(); + + /** + gg* @brief See DataSourceI::GetNumberOfMemoryBuffers. + * @return 1. + */ + virtual uint32 GetNumberOfMemoryBuffers(); + + /** + * @brief See DataSourceI::GetSignalMemoryBuffer. + */ + virtual bool GetSignalMemoryBuffer(const uint32 signalIdx, + const uint32 bufferIdx, + void *&signalAddress); + + + /** + * @brief See DataSourceI::GetNumberOfMemoryBuffers. + * @details Only OutputSignals are supported. + * @return MemoryMapSynchronisedOutputBroker if Trigger == 1 for any of the signals, MemoryMapOutputBroker otherwise. + */ + virtual const char8 *GetBrokerName(StructuredDataI &data, const SignalDirection direction); + + /** + * @brief See DataSourceI::GetInputBrokers. + * @return false. + */ + virtual bool GetInputBrokers(ReferenceContainer &inputBrokers, + const char8* const functionName, + void * const gamMemPtr); + + /** + * @brief See DataSourceI::GetOutputBrokers. + * @details If the functionName is one of the functions which requested a Trigger, + * it adds a MemoryMapSynchronisedOutputBroker instance to the outputBrokers, + * otherwise it adds a MemoryMapOutputBroker instance to the outputBrokers. + * @param[out] outputBrokers where the BrokerI instances have to be added to. + * @param[in] functionName name of the function being queried. + * @param[in] gamMemPtr the GAM memory where the signals will be read from. + * @return true if the outputBrokers can be successfully configured. + */ + virtual bool GetOutputBrokers(ReferenceContainer &outputBrokers, + const char8* const functionName, + void * const gamMemPtr); + + + /** + * @brief See StatefulI::PrepareNextState. + * @details NOOP. + * @return true. + */ + virtual bool PrepareNextState(const char8 * const currentStateName, + const char8 * const nextStateName); + + + /** + * @brief Loads and verifies the configuration parameters detailed in the class description. + * @return true if all the mandatory parameters are correctly specified and if the specified optional parameters have valid values. + uint32 synchCounter; + */ + + virtual bool Initialise(StructuredDataI & data); + + + /** + * @brief Final verification of all the parameters and setup of the board configuration. + * @details This method verifies that all the parameters (e.g. number of samples) requested by the GAMs interacting with this DataSource + * are valid and consistent with the board parameters set during the initialisation phase. + * In particular the following conditions shall be met: + * - At least one triggering signal was requested by a GAM (with the property Trigger = 1) + * - All the DAC channels have type float32. + uint32 synchCounter; + * - The number of samples of all the DAC channels is exactly one. + * @return true if all the parameters are valid and consistent with the board parameters and if the board can be successfully configured with + * these parameters. + */ + virtual bool SetConfiguredDatabase(StructuredDataI & data); + + + /** + * @details Writes the value of all the DAC channels to the board. + * @return true if the writing of all the channels is successful. + */ + virtual bool Synchronise(); + + + private: + /** + * The board device name + */ + StreamString deviceName; + /** + * The board identifier + */ + uint32 boardId; + + /** + * The board file descriptor + */ + int32 boardFileDescriptor; + + uint32 synchCounter; + /** + * DAC values + */ +// int32 dacValues[ATCA_IOP_N_DACs]; + + /** + * EO values Signal + */ + int32 *eoValues; + + /** + * WO valuesa Signal + */ + float32 *woValues; + + /** + * The signal memory + */ +// float32 *channelsMemory; + + /** + * The number of enabled DACs + */ + //uint32 numberOfDACsEnabled; + + /** + * Filter to receive the RPC which allows to change the... + */ + ReferenceT filter; + + /** + * True if at least one trigger was set. + */ + bool triggerSet; + + int32 SetDacReg(uint32 channel, float32 val) const; + + }; +} + +/*---------------------------------------------------------------------------*/ +/* Inline method definitions */ +/*---------------------------------------------------------------------------*/ + +#endif /* ATCA_IOP_DAC_H */ + +// vim: syntax=cpp ts=4 sw=4 sts=4 sr et