From f7ffa8f4fa9b7cd8f3900cc208e55e7f7e514802 Mon Sep 17 00:00:00 2001 From: "Querejeta Lomas, Leire" <leire.querejeta@tecnalia.com> Date: Tue, 30 Aug 2022 09:42:34 +0200 Subject: [PATCH] Subir nuevo archivo --- src/api/class/include/class/class_core.hpp | 772 +++++++++++++++++++++ 1 file changed, 772 insertions(+) create mode 100644 src/api/class/include/class/class_core.hpp diff --git a/src/api/class/include/class/class_core.hpp b/src/api/class/include/class/class_core.hpp new file mode 100644 index 0000000..75d6b0f --- /dev/null +++ b/src/api/class/include/class/class_core.hpp @@ -0,0 +1,772 @@ +/** + * @file class_core.hpp + * @author Alfonso Dominguez <alfonso.dominguez@tecnalia.com> and Leire Querejeta Lomas <leire.querejeta@tecnalia.com> + * @date 2020 + * + * Copyright 2020 Tecnalia Research & Innovation. + * Distributed under the GNU GPL v3. + * For full terms see https://www.gnu.org/licenses/gpl.txt + * + * @brief Interface to the funccionalities of Class + */ + +#ifndef CLASS_CORE_HPP +#define CLASS_CORE_HPP + +#include <vector> +#include <string> +#include <memory> +#include <thread> +#include <mutex> +#include <cmath> +#include <iostream> +#include <fstream> + +#include <boost/circular_buffer.hpp> + +#include <communication/udp_server.hpp> +#include <communication/udp_client.hpp> +#include <logger/logger.hpp> +#include <class/class_structures.hpp> +#include <class/class_error.hpp> +#include <class/class_cb.hpp> +#include <filter/butterworth.hpp> + +#include <Python.h> + +/** + * @brief Core class + */ +class ClassCore:public UdpServerListener +{ +public: + //! Allowed values + + int BUZZER_MAX_VALUE = 500; + int BUZZER_MIN_VALUE = 25; + int FREQ_MAX_VALUE = 2000; + int FREQ_MIN_VALUE = 0; + int HV_MAX_VALUE = 200; + int HV_MIN_VALUE = 120; + int INTERVAL_MAX_VALUE = 1000; + int INTERVAL_MIN_VALUE = 250; + + //! Structure for electrode + struct Elec + { + int id; + int pads_number; + }; + + //! Structure for virtual electrode + struct Velec + { + int id; + std::string name; + bool selected; + }; + + //! basic constructor + ClassCore(); + //! basic destructor + ~ClassCore(); + + /*! + \brief Stops acquisition + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error acqOff(); + + /*! + \brief Starts acquisition + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error acqOn(); + + /*! + \brief Stops impedance acquisition + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error acqImpedanceOff(); + + /*! + \brief Starts impedance acquisition + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error acqImpedanceOn(); + + /*! + \brief Stops acquisition stream + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error acqStreamOff(); + + /*! + \brief Starts acquisition stream + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error acqStreamOn(); + + /*! + \brief Sets the config for impedance acquisition + \param positive Indicates whther is positive (true) or negative (false) + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error acqImpedanceConfig(const bool& positive); + + /*! + \brief Sets the polarity for impedance acquisition + \param unipolar Indicates whther is unipolar (true) or bipolar (false). + \return Integer indicating the success of the setting process (0-success, <0 error) + */ + ClassError::Error acqImpedancePolarity(const bool& unipolar); + + /*! + \brief Sets class acq input to normal (bio signal captured from channels) + \return Integer indicating the success of the setting process (0-success, <0 error) + */ + ClassError::Error acqInputNormal(); + + /*! + \brief Sets class acq input to test. The class will provide a quadratic signal. It is useful for testing and not getting saturated signal all the time. + \return Integer indicating the success of the setting process (0-success, <0 error) + */ + ClassError::Error acqInputTest(); + + /*! + \brief Sends the request for battery level + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error batteryLevel(); + + /*! + \brief Sets the duration of the buffer (ms*frequency//1000.0) + \param ms Time in ms + \return Integer indicating the success of the setting process (0-success, <0 error) + */ + ClassError::Error bufferDuration(const double& ms); + + /*! + \brief Sets buzzer on + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error buzzerPlay(); + + /*! + \brief Sends the request for buzzer + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error buzzerStatus(); + + /*! + \brief Sets ms of buzzer song + \param tempo time in ms + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error buzzerTempo(const std::string& tempo); + + /*! + \brief Connect to the CLASS server + \param server_ip IP of the CLASS server + \param server_port of the CLASS server + \param local_ip IP in which the instance is listening for messages coming from CLASS server + \param local_port Port in which the instance is listening for messages coming from CLASS server + \return Integer indicating the success of the connection (0-success, <0 error) + */ + ClassError::Error connect(const std::string & server_ip, const int & server_port, const std::string & local_ip, const int & local_port); + + /*! + \brief Sends the request for device name + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error deviceName(); + + /*! + \brief Sets name of device + \param devicename Name of the device + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error devName(const std::string& devicename); + + /*! + \brief Disconnect from the CLASS server + \return Integer indicating the success of the disconnection (0-success, <0 error) + */ + ClassError::Error disconnect(); + + /*! + \brief Sets electrode pads number + \param id Electrode number/ID + \param pads_number Number of pads of the electrode + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error elecPads(const int& id, const int& pads_number); + + /*! + \brief Sends the request for firmware version + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error firmwareVersion(); + + /*! + \brief Sends the request for frequency + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error frequencyStatus(); + + /*! + \brief Sets the config for impedance acquisition + \param acq_frames Vector to fill with acqusition frames + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error getAcqFrames(std::vector<AcqFrame>& acq_frames); + + /*! + \brief Sends the request for hardware version + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error hardwareVersion(); + + /*! + \brief Sets high voltage to off + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error hvOff(); + + /*! + \brief Sets high voltage to on + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error hvOn(); + + /*! + \brief Sends the request for high voltage status + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error hvStatus(); + + /*! + \brief Sets high voltage value + \param hvvalue value of high voltage + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error hvValue(const std::string& hvvalue); + + /*! + \brief Sets the order of the filter used for impedance calculation + \param order Filter order (>0) + \return Integer indicating the success of the setting process (0-success, <0 error) + */ + ClassError::Error impedanceFilterOrder(const int& order); + + /*! + \brief Init communication + \param init_mode Initialization mode + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error initCommunication(const std::string& init_mode); + + /*! + \brief Sends the request for interval status + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error intervalStatus(); + + /*! + \brief Sets stimulation inter pulses interval + \param interval value of stimulation inter pulses + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error intervalValue(const std::string& interval); + + /*! + \brief Sets logevents to off + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error logeventsOff(); + + /*! + \brief Sets logevents to on + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error logeventsOn(); + + /*! + \brief Sends the request for logevents + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error logeventsStatus(); + + /*! + \brief Sets pattern + \param number pattern number + \param pat vector of patterns + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error pattern(const int& number, const std::vector<Pattern>& pat); + + /*! + \brief Clear pattern + \param id pattern to delete + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error patternClear(const int& id); + + /*! + \brief Sends the request for pattern + \param number pattern + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error patternStatus(const int& number); + + /*! + \brief Sends the request for pattern + \param number pattern + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error velecStatus(const int& number); + + /*! + \brief Sets rtc date + \param rtcdate mm/dd/yyyy format + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error rtcDate(const std::string& rtcdate); + + /*! + \brief Sends the request for rtc + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error rtcStatus(); + + /*! + \brief Sets rtc time + \param rtctime hh:mm:ss format + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error rtcTime(const std::string& rtctime); + + /*! + \brief Sends the request for sd function + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error sdfunctionStatus(); + + /*! + \brief Sets name of sdcard folder where the pattern are saved + \param sdfunctionname name of the folder + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error sdFunctionName(const std::string& sdfunctionname); + + /*! + \brief Sets name of sdcard folder where the folder containing the patterns is saved + \param sduname name of the folder + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error sdUName(const std::string& sduname); + + /*! + \brief Sends the request for sd user name + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error sdunameStatus(); + + /*! + \brief Sends custom command to CLASS device + \param cmd Command + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error sendCustomCmd(const std::string& cmd); + + /*! + \brief Sets class acq configuration + \param frequency Frequency of acquisition + \param channel_numbers Channel numbers + \param gain Gain of the acquisition + \param input Acq input type, normal or test + \return Integer indicating the success of the setting process (0-success, <0 error) + */ + ClassError::Error setAcqConfig(const double& frequency, const std::vector<int>& channel_numbers, const double& gain, const std::string& input); + + /*! + \brief Sets the callback + \param callback Callback + \param language Language which has defined the callback + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error setCallback(ClassCallback* callback, std::string language); + + /*! + \brief Turn off + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error shutdown(); + + /*! + \brief Sets frequency of the stimulation + \param frequency Frequency of the stimulation + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error stimFreq(const double& frequency); + + /*! + \brief Stops stimulation + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error stimOff(); + + /*! + \brief Starts stimulation + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error stimOn(); + + /*! + \brief Starts stimulation of the virtual electrode which name is passed as parameter + \param name Name of the virtual electrode + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error stimVelec(const std::string& name); + + /*! + \brief Sends the request for tic + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error tic(); + + /*! + \brief Handles the reception of an UDP msg from the CLASS server + \param msg Msg + \param ip IP the message comes from + */ + void udpMsgReceived(std::string msg, std::string client_ip); + + /*! + \brief Sets virtual electrode + \param number Virtual electrode number/ID + \param name Name of the virtual electrode + \param electrode_id Electrode ID/number + \param cathodes List of integers with the IDs of the pads acting as cathodes + \param anodes List of integers with the IDs of the pads acting as cathodes + \param amp List of doubles with the amplitude (in mA) associated to each of the cathodes. Must have the same length as cathodes + \param width List of integers with the pulse width (in uS) associated to each of the cathodes. Must have the same length as cathodes + \param selected Defines if the velec is selected (‘true’ value) or deselected (‘false’ value). Only selected velecs will be executed with a “stim on” command + \param sync Defines if the velec is synchronous (‘rtue’ value) or asynchronous (‘false’ value). + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error velec(const int& id, const std::string& name, const int& electrode_id, const std::vector<int>& cathodes, const std::vector<int>& anodes, const std::vector<double>& amp, const std::vector<int>& width, const bool& selected, const bool& sync); + + /*! + \brief Sets whether the virtual electrode is selected or not + \param id Virtual electrode number/ID + \param selected Defines if the velec is selected (‘true’ value) or deselected (‘false’ value). Only selected velecs will be executed with a “stim on” command. + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error velecSelected(const int& id, const bool& selected); + + /*! + \brief Sets whether the virtual electrodes are selected or not + \param id Vector with virtual electrode number/ID. + \param selected Vector of bool values indicating whether the virtual electrode is selected + \return Integer indicating the success of the process (0-success, <0 error) + */ + ClassError::Error velecsSelected(const std::vector<int>& id, const std::vector<bool>& selected); + +private: + /*! + \brief Sends msg through serial + \param msg Msg to send. + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error sendMsg(std::string msg); + + /*! + \brief Sends msgs through serial + \param msgs Vector with msgs to send. + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error sendMsgs(std::vector<std::string> msgs); + + /*! + \brief Updates buffer capacity based on acq rate and seconds + \param seconds Buffer duration. + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error setBufferCapacity(const double& seconds); + + /*! + \brief Configures the filter for impedance + \param order Order of the filter + \param low_freq Lower frequency of the band + \param up_freq Upper freqeuncy of the band + \param acq_freq Sampling rate + \return Integer indicating the success of the starting process (0-success, <0 error) + */ + ClassError::Error configureFilter(int order, double low_freq, double up_freq, double acq_freq); + + /*! + \brief Sets the number of digits after decimal + \param value Value + \param digits_after_decimal Number of desired digits after decimal + \return Pair with the new_value and a bool indicating whether the operation has enough precision + */ + std::pair< double, bool > trunc_n( double value, std::size_t digits_after_decimal); + + /*! + \brief Increases lock error number + */ + void increaseLockError(); + + //! UDP server where it listens for command coming form the CLASS server + UDPServer *udp_server_; + //! UDP client which sends messages to CLASS server + UDPClient *udp_client_; + + //! indicates the IP where the CLASS server is listening + std::string server_ip_; + //! indicates the port where the CLASS server is listening + int server_port_; + //! indicates the local IP where the instance is listening for messages coming from CLASS server + std::string local_ip_; + //! indicates the local port where the instance is listening for messages coming from CLASS server + int local_port_; + + //! defined electrodes + std::vector<Elec> electrodes_; + + //! defined virual electrodes + std::vector<Velec> virtual_electrodes_; + + //! indicates whether it is acquiring frames + bool is_acquiring_frames_; + //! is_acquiring_frames mutex + std::mutex is_acquiring_frames_mutex_; + //! number of channels + int channels_number_; + //! frequency of the acquisition + double acq_frequency_; + //! acquisition time (determinates buffer maximum size) + double acq_seconds_; + //! acquisition time + int acq_buffer_capacity_; + //! acquisition buffer + boost::circular_buffer<AcqFrame> acq_buffer_; + //! acquisition buffer mutex + std::mutex acq_buffer_mutex_; + + //! indicates whether it is acquiring impedances + bool is_acquiring_impedances_; + //! is_acquiring_frames mutex + std::mutex is_acquiring_impedances_mutex_; + //! acquisition time + int acq_impedances_buffer_capacity_; + //! acquisition buffer + boost::circular_buffer<AcqFrame> acq_impedances_buffer_; + //! acquisition buffer mutex + std::mutex acq_impedances_buffer_mutex_; + + //! butterworth filters, one per channel + Butterworth **butterworth_; + //! order of the filter + int filter_order_; + + //! thread for waiting messages + std::thread *waiting_thread_; + //! function for waiting messages + void waitingThreadFunction_(); + //! Indicates whether to wait for special messages + bool waiting_; + //! Mutex for waiting + std::mutex waiting_mutex_; + + //! indicates whether it is waiting for tic + bool tic_received_; + //! indicates whether tic has been received + bool is_waiting_tic_; + //! mutex for tic + std::mutex tic_mutex_; + + //! indicates whether it is waiting for firmware + bool firmware_received_; + //! indicates whether firmware has been received + bool is_waiting_firmware_; + //! mutex for firmware + std::mutex firmware_mutex_; + + //! indicates whether it is waiting for device name + bool device_received_; + //! indicates whether device name has been received + bool is_waiting_device_; + //! mutex for firmware + std::mutex device_mutex_; + + //! indicates whether it is waiting for hardware + bool hardware_received_; + //! indicates whether hardware has been received + bool is_waiting_hardware_; + //! mutex for hardware + std::mutex hardware_mutex_; + + //! indicates whether it is waiting for battery + bool battery_received_; + //! indicates whether battery has been received + bool is_waiting_battery_; + //! mutex for battery + std::mutex battery_mutex_; + + //! indicates whether it is waiting for logevents + bool logevents_received_; + //! indicates whether logevents has been received + bool is_waiting_logevents_; + //! mutex for logevents + std::mutex logevents_mutex_; + + //! indicates whether it is waiting for high voltage status + bool hvstatus_received_; + //! indicates whether high voltage status has been received + bool is_waiting_hvstatus_; + //! mutex for high voltage status + std::mutex hvstatus_mutex_; + + //! indicates whether it is waiting for interval status + bool intervalstatus_received_; + //! indicates whether interval status has been received + bool is_waiting_intervalstatus_; + //! mutex for interval status + std::mutex intervalstatus_mutex_; + + //! indicates whether it is waiting for rtc status + bool rtcstatus_received_; + //! indicates whether rtc status has been received + bool is_waiting_rtcstatus_; + //! mutex for rtc status + std::mutex rtcstatus_mutex_; + + //! indicates whether it is waiting for buzzer status + bool buzzerstatus_received_; + //! indicates whether buzzer status has been received + bool is_waiting_buzzerstatus_; + //! mutex for buzzer status + std::mutex buzzerstatus_mutex_; + + //! indicates whether it is waiting for frequency status + bool frequencystatus_received_; + //! indicates whether frequency status has been received + bool is_waiting_frequencystatus_; + //! mutex for frequency status + std::mutex frequencystatus_mutex_; + + //! indicates whether it is waiting for sdfunction + bool sdfunction_received_; + //! indicates whether sdfunction has been received + bool is_waiting_sdfunction_; + //! mutex for sdfunction + std::mutex sdfunction_mutex_; + + //! indicates whether it is waiting for sduname + bool sduname_received_; + //! indicates whether sduname has been received + bool is_waiting_sduname_; + //! mutex for sduname + std::mutex sduname_mutex_; + + //! indicates whether it is waiting for pattern + bool patternstatus_received_; + //! indicates whether pattern has been received + bool is_waiting_patternstatus_; + //! mutex for logevents + std::mutex patternstatus_mutex_; + + //! indicates whether it is waiting for velecstatus + bool velecstatus_received_; + //! indicates whether velecstatus has been received + bool is_waiting_velecstatus_; + //! mutex for velecstatus + std::mutex velecstatus_mutex_; + + //! battery level + double battery_; + // tic text + std::string tic_; + // firmware text + std::string firmware_; + // hardware text + std::string hardware_; + // device text + std::string device_; + // logevents text + std::string logevents_; + // high voltage status text + std::string hvstatus_; + // interval status text + std::string intervalstatus_; + // rtc status text + std::string rtcstatus_; + // buzzer status text + std::string buzzerstatus_; + // frequency status text + std::string frequencystatus_; + // sdfunction status text + std::string sdfunctionstatus_; + // sduname status text + std::string sdunamestatus_; + // pattern status text + std::string patternstatus_; + // velecstatus text + std::string velecstatus_; + + //! mutex for lock errors + std::mutex lock_error_mutex_; + //! number of lock errors + int lock_error_number_; + //! max number of lock errors before launching error + int lock_error_number_max_; + //! thread for lock errors + std::thread *lock_error_thread_; + //! function for lock error + void lockErrorThreadFunction_(); + //! Indicates whether to wait for special messages + bool error_waiting_; + + //! callback for battery, turn_off, etc. + ClassCallback* class_cb_; + //! Language which has defined the callback + std::string language_; + + //! acq gainb + double gain_; + + //! log function + #define log_stream_(x) log_(std::stringstream() << x); + #define log_warn_stream_(x) log_warn_(std::stringstream() << x); + #define log_error_stream_(x) log_err_(std::stringstream() << x); + void log_(const std::string &text); + void log_(const std::stringstream &text); + void log_(std::ostream & text); + void log_err_(const std::string &text); + void log_err_(std::ostream & text); + void log_warn_(const std::string &text); + void log_warn_(std::ostream & text); +}; + +/** + * @brief Class for locking when accesing callback in Python + */ +class PyThreadStateLock +{ +public: + PyThreadStateLock(void) + { + state = PyGILState_Ensure( ); + } + + ~PyThreadStateLock(void) + { + PyGILState_Release( state ); + } +private: + PyGILState_STATE state; +}; + +#endif // CLASS_CORE_HPP -- GitLab