From 0648d9f1a73a2589ff1d38436a40a975a5ab4586 Mon Sep 17 00:00:00 2001 From: "Querejeta Lomas, Leire" <leire.querejeta@tecnalia.com> Date: Tue, 30 Aug 2022 09:43:19 +0200 Subject: [PATCH] Subir nuevo archivo --- src/api/class/src/class_core.cpp | 2434 ++++++++++++++++++++++++++++++ 1 file changed, 2434 insertions(+) create mode 100644 src/api/class/src/class_core.cpp diff --git a/src/api/class/src/class_core.cpp b/src/api/class/src/class_core.cpp new file mode 100644 index 0000000..c4b0aae --- /dev/null +++ b/src/api/class/src/class_core.cpp @@ -0,0 +1,2434 @@ +/** + * @file ClassCore.cpp + * @author Alfonso Domminguez <alfonso.dominguez@tecnalia.com> and Leire Querejeta Lomas <leire.querejeta@tecnalia.com> + * @date 2020 + * + * Copyright 2' Tecnalia Research & Innovation. + * Distributed under the GNU GPL v3. + * For full terms see https://www.gnu.org/licenses/gpl.txt + * + * @brief Interface to the funcionalities of Class. + */ + +#include <class/class_core.hpp> +#include <iostream> +#include <numeric> +#include <chrono> +#include <thread> +#include <regex> +#include <math.h> +#include <bitset> +#include "../../commands.h" + +const double ACQ_SECONDS_DEFAULT = 2.0; +const int FILTER_ORDER_DEFAULT = 2; +const int MSG_MAX_LENGTH = 1024; + +ClassCore::ClassCore() +{ + + udp_server_ = nullptr; + udp_client_ = nullptr; + butterworth_ = nullptr; + + channels_number_ = 0; + gain_ = 0.0; + acq_seconds_ = ACQ_SECONDS_DEFAULT; + acq_buffer_capacity_ = 0; + is_acquiring_frames_ = false; + filter_order_ = FILTER_ORDER_DEFAULT; + + waiting_ = false; + + is_waiting_battery_ = false; + battery_received_ = false; + battery_ = 0.0; + tic_ = ""; + firmware_ = ""; + hardware_ = ""; + device_ = ""; + logevents_ = ""; + hvstatus_ = ""; + intervalstatus_ = ""; + rtcstatus_ = ""; + buzzerstatus_ = ""; + frequencystatus_ = ""; + sdfunctionstatus_ = ""; + sdunamestatus_ = ""; + patternstatus_ = ""; + velecstatus_ = ""; + + lock_error_number_ = 0; + lock_error_number_max_ = 10; + + language_ = ""; + class_cb_ = nullptr; + waiting_thread_ = new std::thread(&ClassCore::waitingThreadFunction_, this); + + lock_error_thread_ = new std::thread(&ClassCore::lockErrorThreadFunction_, this); + // myfile_.open ("msgs.txt"); +} + +ClassCore::~ClassCore() +{ + if (udp_server_ != nullptr) + { + delete udp_server_; + } + + if (udp_client_ != nullptr) + { + delete udp_client_; + } + + if (butterworth_ != nullptr) + { + for (int i = 0; i < channels_number_; ++i) + { + delete butterworth_[i]; + } + delete[] butterworth_; + } + + waiting_mutex_.lock(); + waiting_ = false; + waiting_mutex_.unlock(); + + lock_error_mutex_.lock(); + error_waiting_ = false; + lock_error_mutex_.unlock(); + // myfile_.close(); +} + +ClassError::Error ClassCore::connect(const std::string &server_ip, const int &server_port, const std::string &local_ip, const int &local_port) +{ + if (udp_server_ != nullptr) + { + log_("[connect] There is already a local UDP server listening for messages coming from CLASS server"); + } + else + { + log_stream_("[connect] Starting local server on port " << local_port); + udp_server_ = new UDPServer(local_port); + local_port_ = local_port; + udp_server_->startListening(); + udp_server_->addListener((UdpServerListener *)this); + log_stream_("[connect] Waiting for CLASS server messages on local port " << local_port); + } + + std::string server_port_str; + std::stringstream ss; + ss << server_port; + server_port_str = ss.str(); + log_stream_("[connect] Creating a client which connects to CLASS server (IP " << server_ip << ":" << server_port_str << ")"); + udp_client_ = new UDPClient(server_ip, server_port_str, -1); + + ss.str(std::string()); + ss << "connect " << local_port_; + std::string msg = ss.str(); + + return sendMsg(msg); +} + +ClassError::Error ClassCore::disconnect() +{ + std::stringstream ss; + ss << "disconnect " << local_port_; + std::string msg = ss.str(); + + int response = sendMsg(msg); + if (response != 0) + { + return ClassError::ERROR_SENDING_MSG; + } + + log_("[disconnect] Stopping local UPD server..."); + if (udp_server_ != nullptr) + { + udp_server_->removeListener((UdpServerListener *)this); + udp_server_->stopListening(); + } + log_("[disconnect] Local UDP server stopped"); + + return ClassError::CLASS_NO_ERROR; +} + +ClassError::Error ClassCore::setAcqConfig(const double &frequency, const std::vector<int> &channel_numbers, const double &gain, const std::string &input) +{ + // log_stream_("[setAcqConfig]"); + gain_ = gain; + + if (butterworth_ != nullptr) + { + for (int i = 0; i < channels_number_; ++i) + { + if (butterworth_[i] != nullptr) + { + delete butterworth_[i]; + } + } + delete[] butterworth_; + } + + channels_number_ = channel_numbers.size(); + log_stream_("[setAcqConfig] Number of channels: " << channels_number_); + + int channels_int = 0; + + for (int i = 0; i < channel_numbers.size(); i++) + { + if (channel_numbers[i] < 1 || channel_numbers[i] > 16) + { + log_error_stream_("[setAcqConfig] Channel " << i << "has the id " << channel_numbers[i] << " which is not in the interval >=1 and <=16"); + return ClassError::ERROR_NOT_VALID_CHANNEL_ID; + } + channels_int += (int)(pow(2, channel_numbers[i] - 1)); + } + + std::stringstream stream; + stream << "0x" + << std::setfill('0') << std::setw(2) // 2 digits hex 0xAA (4 digits does not work) + << std::hex << channels_int; + std::string channels_hex_str(stream.str()); + log_stream_("[setAcqConfig] channels hex: " << channels_hex_str); + + acq_frequency_ = frequency; + + log_("[setAcqConfig] setBufferCapacity"); + setBufferCapacity(acq_seconds_); + + log_("[setAcqConfig] configureFilter"); + configureFilter(filter_order_, 30.2, 32.2, acq_frequency_); + + return sendMsg(commands::ClassCommands::CMD_CONFIGACQ + std::to_string(frequency) + commands::ClassCommands::CMD_CONFIGACQ_PARAM1 +channels_hex_str + commands::ClassCommands::CMD_CONFIGACQ_PARAM2 + std::to_string(gain) + commands::ClassCommands::CMD_CONFIGACQ_PARAM3 + input + commands::ClassCommands::CMD_AUX); +} + +ClassError::Error ClassCore::setBufferCapacity(const double &seconds) +{ + acq_seconds_ = seconds; + if (acq_buffer_mutex_.try_lock()) + { + acq_buffer_.clear(); + acq_buffer_capacity_ = (int)(acq_frequency_ * acq_seconds_); + acq_buffer_.set_capacity(acq_buffer_capacity_); + acq_buffer_mutex_.unlock(); + } + else + { + log_warn_stream_("[setBufferCapacity] lock not acquired"); + increaseLockError(); + } + + return ClassError::CLASS_NO_ERROR; +} + +ClassError::Error ClassCore::configureFilter(int order, double low_freq, double up_freq, double acq_freq) +{ + filter_order_ = order; + double low = low_freq / (acq_freq / 2.0); + double up = up_freq / (acq_freq / 2.0); + + if (butterworth_ != nullptr) + { + for (int i = 0; i < channels_number_; ++i) + { + delete butterworth_[i]; + } + delete[] butterworth_; + } + + butterworth_ = new Butterworth *[channels_number_]; + for (int i = 0; i < channels_number_; ++i) + { + butterworth_[i] = new Butterworth(); + butterworth_[i]->configure(order, low, up); + } + + return ClassError::CLASS_NO_ERROR; +} + +ClassError::Error ClassCore::acqOn() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_BUFFERFLUSH); + if (response != ClassError::CLASS_NO_ERROR) + { + return ClassError::ERROR_SENDING_MSG; + } + + if (acq_buffer_mutex_.try_lock()) + { + acq_buffer_.clear(); + acq_buffer_mutex_.unlock(); + } + else + { + log_warn_stream_("[acqOn] lock not acquired"); + increaseLockError(); + } + + is_acquiring_frames_mutex_.lock(); + is_acquiring_frames_ = true; + is_acquiring_frames_mutex_.unlock(); + + return sendMsg(commands::ClassCommands::CMD_ONACQ); +} + +ClassError::Error ClassCore::acqOff() +{ + is_acquiring_frames_mutex_.lock(); + is_acquiring_frames_ = false; + is_acquiring_frames_mutex_.unlock(); + + return sendMsg(commands::ClassCommands::CMD_OFFACQ); +} + +ClassError::Error ClassCore::acqImpedanceOn() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_BUFFERFLUSH); + if (response != ClassError::CLASS_NO_ERROR) + { + return ClassError::ERROR_SENDING_MSG; + } + + if (acq_buffer_mutex_.try_lock()) + { + acq_buffer_.clear(); + acq_buffer_mutex_.unlock(); + } + else + { + log_warn_stream_("[acqImpedanceOn] lock not acquired"); + increaseLockError(); + } + + is_acquiring_impedances_mutex_.lock(); + is_acquiring_impedances_ = true; + is_acquiring_impedances_mutex_.unlock(); + + std::vector<std::string> msg_list; + msg_list.push_back(commands::ClassCommands::CMD_ONIMPEDANCEACQ); + msg_list.push_back(commands::ClassCommands::CMD_ONACQ); + + return sendMsgs(msg_list); +} + +ClassError::Error ClassCore::acqImpedanceOff() +{ + is_acquiring_impedances_mutex_.lock(); + is_acquiring_impedances_ = false; + is_acquiring_impedances_mutex_.unlock(); + + std::vector<std::string> msg_list; + msg_list.push_back(commands::ClassCommands::CMD_OFFIMPEDANCEACQ); + msg_list.push_back(commands::ClassCommands::CMD_OFFACQ); + + return sendMsgs(msg_list); +} + +ClassError::Error ClassCore::acqStreamOn() +{ + return sendMsg(commands::ClassCommands::CMD_STREAMONACQ); +} + +ClassError::Error ClassCore::acqStreamOff() +{ + return sendMsg(commands::ClassCommands::CMD_STREAMOFFACQ); +} + +ClassError::Error ClassCore::acqInputNormal() +{ + return sendMsg(commands::ClassCommands::CMD_NORMALACQ); +} + +ClassError::Error ClassCore::acqInputTest() +{ + return sendMsg(commands::ClassCommands::CMD_TESTACQ); +} + +ClassError::Error ClassCore::stimOn() +{ + return sendMsg(commands::ClassCommands::CMD_ONSTIM); +} + +ClassError::Error ClassCore::stimOff() +{ + return sendMsg(commands::ClassCommands::CMD_OFFSTIM); +} + +ClassError::Error ClassCore::elecPads(const int &id, const int &pads_number) +{ + // chek whether the electrode exists. If so, update, if not insert + int electrode_index = -1; + for (unsigned int i = 0; i < electrodes_.size(); i++) + { + Elec elec = electrodes_[i]; + if (elec.id == id) + { + electrode_index = i; + break; + } + } + + if (electrode_index >= 0) + { + electrodes_[electrode_index].pads_number = pads_number; + } + else + { + Elec elec; + elec.id = id; + elec.pads_number = pads_number; + + electrodes_.push_back(elec); + } + + return sendMsg(commands::ClassCommands::CMD_CONFIGELEC + std::to_string(id) + commands::ClassCommands::CMD_CONFIGACQ_PARAM1 + std::to_string(pads_number) + commands::ClassCommands::CMD_AUX); +} + +ClassError::Error ClassCore::stimFreq(const double &frequency) +{ + if(frequency < FREQ_MIN_VALUE || frequency > FREQ_MAX_VALUE) + { + return ClassError::ERROR_NOT_VALID_VALUE; + } + else + { + return sendMsg(commands::ClassCommands::CMD_SETFREQ + std::to_string(frequency) + commands::ClassCommands::CMD_AUX); + } +} + +ClassError::Error ClassCore::devName(const std::string& devicename) +{ + return sendMsg(commands::ClassCommands::CMD_SETDEVICENAME + devicename + commands::ClassCommands::CMD_AUX); +} + +ClassError::Error ClassCore::hvValue(const std::string& hvvalue) +{ + if(std::stoi(hvvalue) < HV_MIN_VALUE || std::stoi(hvvalue) > HV_MAX_VALUE) + { + return ClassError::ERROR_NOT_VALID_VALUE; + } + else + { + return sendMsg(commands::ClassCommands::CMD_SETHV + hvvalue + commands::ClassCommands::CMD_AUX); + } +} + +ClassError::Error ClassCore::hvOn() +{ + return sendMsg(commands::ClassCommands::CMD_ONHV); +} + +ClassError::Error ClassCore::hvOff() +{ + return sendMsg(commands::ClassCommands::CMD_OFFHV); +} + +ClassError::Error ClassCore::logeventsOn() +{ + return sendMsg(commands::ClassCommands::CMD_ONLOGEVENTS); +} + +ClassError::Error ClassCore::logeventsOff() +{ + return sendMsg(commands::ClassCommands::CMD_OFFLOGEVENTS); +} + +ClassError::Error ClassCore::intervalValue(const std::string& interval) +{ + if(std::stoi(interval) < INTERVAL_MIN_VALUE || std::stoi(interval) > INTERVAL_MAX_VALUE) + { + return ClassError::ERROR_NOT_VALID_VALUE; + } + else + { + return sendMsg(commands::ClassCommands::CMD_SETINTERVAL + interval + commands::ClassCommands::CMD_AUX); + } +} + +ClassError::Error ClassCore::buzzerTempo(const std::string& tempo) +{ + if(std::stoi(tempo) < BUZZER_MIN_VALUE || std::stoi(tempo) > BUZZER_MAX_VALUE) + { + return ClassError::ERROR_NOT_VALID_VALUE; + } + else + { + return sendMsg(commands::ClassCommands::CMD_SETBUZZER + tempo + commands::ClassCommands::CMD_AUX); + } +} + +ClassError::Error ClassCore::buzzerPlay() +{ + return sendMsg(commands::ClassCommands::CMD_PLAYBUZZER); +} + +ClassError::Error ClassCore::rtcDate(const std::string& rtcDate) +{ + return sendMsg(commands::ClassCommands::CMD_SETRTCDATE + rtcDate + commands::ClassCommands::CMD_AUX); +} + +ClassError::Error ClassCore::rtcTime(const std::string& rtcTime) +{ + return sendMsg(commands::ClassCommands::CMD_SETRTCTIME + rtcTime + commands::ClassCommands::CMD_AUX); +} + +ClassError::Error ClassCore::shutdown() +{ + return sendMsg(commands::ClassCommands::CMD_SWITCHOFF); +} + +ClassError::Error ClassCore::sdFunctionName(const std::string& sdfunctionname) +{ + return sendMsg(commands::ClassCommands::CMD_SETSDFUNCTION + sdfunctionname + commands::ClassCommands::CMD_AUX); +} + +ClassError::Error ClassCore::sdUName(const std::string& sduname) +{ + return sendMsg(commands::ClassCommands::CMD_SETSDNAME + sduname + commands::ClassCommands::CMD_AUX); +} + +ClassError::Error ClassCore::pattern(const int &id, const std::vector<Pattern> &pat) +{ + sendMsg(commands::ClassCommands::CMD_CONFIGPATTERN + std::to_string(id) + commands::ClassCommands::CMD_CONFIGACQ_PARAM1 + commands::ClassCommands::CMD_AUX); + + std::this_thread::sleep_for(std::chrono::milliseconds(300)); + for(int i = 0; i < pat.size() ; i++) + { + + sendMsg(commands::ClassCommands::CMD_CONFIGPATTERN + std::to_string(id) + commands::ClassCommands::CMD_CONFIGPATTERN_PARAM2 + pat[i].amp + " " + pat[i].pw + " " + pat[i].r + " " + std::to_string(pat[i].ampval) + " " + std::to_string(pat[i].pwval) + " " + std::to_string(pat[i].time) + commands::ClassCommands::CMD_AUX); + std::this_thread::sleep_for(std::chrono::milliseconds(300)); + } + + return sendMsg(commands::ClassCommands::CMD_CONFIGPATTERN + std::to_string(id) + commands::ClassCommands::CMD_CONFIGACQ_PARAM3 + commands::ClassCommands::CMD_AUX); + +} + +ClassError::Error ClassCore::patternClear(const int& id) +{ + return sendMsg(commands::ClassCommands::CMD_CONFIGPATTERN + std::to_string(id) + commands::ClassCommands::CMD_CONFIGACQ_PARAM1 + commands::ClassCommands::CMD_AUX); +} + +ClassError::Error ClassCore::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> &, const std::vector<int> &width, const bool &selected, const bool &sync) +{ + // check whether there is an electrode in the list with id=electrode_id + int electrode_index = -1; + for (unsigned int i = 0; i < electrodes_.size(); i++) + { + Elec elec = electrodes_[i]; + if (elec.id == electrode_id) + { + electrode_index = i; + break; + } + } + + if (electrode_index < 0) + { + log_warn_stream_("[velec] No electrode with id: " << electrode_id << " configured from this client."); + } + + // check whether there is an virtual_electrode in the list with id=id + int virtual_electrode_index = -1; + for (unsigned int i = 0; i < virtual_electrodes_.size(); i++) + { + Velec elec = virtual_electrodes_[i]; + if (elec.id == id) + { + virtual_electrode_index = i; + break; + } + } + + if (virtual_electrode_index < 0) + { + // new velec + Velec elec; + elec.id = id; + elec.selected = selected; + elec.name = name; + + virtual_electrodes_.push_back(elec); + } + else + { + // update velec + virtual_electrodes_[electrode_index].selected = selected; + virtual_electrodes_[electrode_index].name = name; + } + + if (cathodes.size() == 0) + { + log_err_("[virtualElectrode] Cathode vector is empty"); + return ClassError::ERROR_EMPTY_CATHODE; + } + + if (anodes.size() == 0) + { + log_err_("[virtualElectrode] Anode vector is empty"); + return ClassError::ERROR_EMPTY_ANODE; + } + + // check whether the length of cathodes, amp and width are the same + if (cathodes.size() != amp.size() || cathodes.size() != width.size()) + { + log_err_("[virtualElectrode] Cathode, amp and width vector sizes are different"); + return ClassError::ERROR_CATHODE_AMP_DIFFERENT_SIZE; + } + + std::stringstream ss; + ss << "velec " << id << " *name " << name << " *elec " << electrode_id << " *pads "; + //commands::ClassCommands::CMD_CONFIGVELEC + id + commands::ClassCommands::CMD_CONFIGVELEC_PARAM1 + name + commands::ClassCommands::CMD_CONFIGVELEC_PARAM2 + electrode_id + commands::ClassCommands::CMD_CONFIGVELEC_PARAM3 + for (unsigned int i = 0; i < cathodes.size(); i++) + { + ss << cathodes[i] << "=C" + << ","; + } + for (unsigned int i = 0; i < anodes.size(); i++) + { + ss << anodes[i] << "=A" + << ","; + } + + ss << " *amp "; + for (unsigned int i = 0; i < amp.size(); i++) + { + ss << cathodes[i] << "=" << amp[i] << ","; + } + ss << " *width "; + for (unsigned int i = 0; i < width.size(); i++) + { + ss << cathodes[i] << "=" << width[i] << ","; + } + ss << " *selected "; + if (selected) + { + ss << "1"; + } + else + { + ss << "0"; + } + ss << " *sync "; + if (sync) + { + ss << "1"; + } + else + { + ss << "0"; + } + ss << "\r\n"; + std::string msg = ss.str(); + + return sendMsg(msg); +} + +ClassError::Error ClassCore::velecSelected(const int &id, const bool &selected) +{ + int virtual_electrode_index = -1; + for (unsigned int i = 0; i < virtual_electrodes_.size(); i++) + { + Velec elec = virtual_electrodes_[i]; + if (elec.id == id) + { + virtual_electrode_index = i; + break; + } + } + + if (virtual_electrode_index < 0) + { + log_warn_stream_("[velecSelected] No virtual electrode with id: " << id << " configured from this client."); + } + + if(selected) + { + return sendMsg(commands::ClassCommands::CMD_CONFIGVELEC + std::to_string(id) + commands::ClassCommands::CMD_VELEC_SELECTED + commands::ClassCommands::CMD_AUX); + } + else + { + return sendMsg(commands::ClassCommands::CMD_CONFIGVELEC + std::to_string(id) + commands::ClassCommands::CMD_VELEC_NOTSELECTED + commands::ClassCommands::CMD_AUX); + } +} + +ClassError::Error ClassCore::velecsSelected(const std::vector<int> &id, const std::vector<bool> &selected) +{ + if (id.size() != selected.size()) + { + return ClassError::ERROR_DIF_VECTOR_SIZE; + } + + std::vector<std::string> msg_list; + + for (int velecIndex = 0; velecIndex < id.size(); velecIndex++) + { + int virtual_electrode_index = -1; + for (unsigned int i = 0; i < virtual_electrodes_.size(); i++) + { + Velec elec = virtual_electrodes_[i]; + if (elec.id == id[velecIndex]) + { + virtual_electrode_index = i; + break; + } + } + + if (virtual_electrode_index < 0) + { + log_warn_stream_("[velecsSelected] No virtual electrode with id: " << id[velecIndex] << "configured from this client."); + } + + std::stringstream ss; + ss << "velec " << id[velecIndex]; + ss << " *selected "; + if (selected[velecIndex]) + { + //commands::ClassCommands::CMD_CONFIGVELEC + id + commands::ClassCommands::CMD_VELEC_SELECTED + commands::ClassCommands::CMD_AUX + ss << "1"; + } + else + { + //commands::ClassCommands::CMD_CONFIGVELEC + id + commands::ClassCommands::CMD_VELEC_NOTSELECTED + commands::ClassCommands::CMD_AUX + ss << "0"; + } + ss << "\r\n"; + std::string msg = ss.str(); + msg_list.push_back(msg); + } + return sendMsgs(msg_list); +} + +ClassError::Error ClassCore::stimVelec(const std::string &name) +{ + int virtual_electrode_index = -1; + for (unsigned int i = 0; i < virtual_electrodes_.size(); i++) + { + Velec elec = virtual_electrodes_[i]; + if (elec.name == name) + { + virtual_electrode_index = i; + break; + } + } + + if (virtual_electrode_index < 0) + { + log_warn_stream_("[velecSelected] No virtual electrode with name: " << name << " condifgured from this client."); + } + + std::stringstream ss; + ss << "stim " << name << "\r\n"; + std::string msg = ss.str(); + + return sendMsg(msg); +} + +ClassError::Error ClassCore::acqImpedanceConfig(const bool &positive) +{ + std::stringstream ss; + ss << "acq impedance_config *channels "; + if (positive) + { + ss << "positives"; + } + else + { + ss << "negatives"; + } + ss << "\r\n"; + std::string msg = ss.str(); + + return sendMsg(msg); +} + +ClassError::Error ClassCore::acqImpedancePolarity(const bool &unipolar) +{ + std::stringstream ss; + ss << "acq config type "; + if (unipolar) + { + ss << "unipolar"; + } + else + { + ss << "bipolar"; + } + ss << "\r\n"; + std::string msg = ss.str(); + + return sendMsg(msg); +} + +ClassError::Error ClassCore::initCommunication(const std::string &init_mode) +{ + return sendMsg(commands::ClassCommands::CMD_INIT + init_mode + commands::ClassCommands::CMD_AUX); +} + +ClassError::Error ClassCore::getAcqFrames(std::vector<AcqFrame> &acq_frames) +{ + bool is_acquiring_frames = false; + is_acquiring_frames_mutex_.lock(); + is_acquiring_frames = is_acquiring_frames_; + is_acquiring_frames_mutex_.unlock(); + + bool is_acquiring_impedances = false; + is_acquiring_impedances_mutex_.lock(); + is_acquiring_impedances = is_acquiring_impedances_; + is_acquiring_impedances_mutex_.unlock(); + + if (!is_acquiring_frames && !is_acquiring_impedances) + { + log_stream_("[getAcqFrames] The device is not acquiring frames"); + return ClassError::ERROR_DEVICE_NOT_ACQUIRING; + } + + acq_frames.clear(); + if (acq_buffer_mutex_.try_lock()) + { + for (int i = 0; i < acq_buffer_.size(); i++) + { + acq_frames.push_back(acq_buffer_[i]); + } + acq_buffer_mutex_.unlock(); + } + else + { + log_warn_stream_("[getAcqFrames] lock not acquired"); + increaseLockError(); + } + + return ClassError::CLASS_NO_ERROR; +} + +ClassError::Error ClassCore::sendMsg(std::string msg) +{ + log_stream_("[sendMsg] Msg:" << msg); + if (udp_client_ == nullptr) + { + return ClassError::ERROR_UDP_CLIENT_NULL; + } + udp_client_->send(msg); + + // log_stream_("[sendMsg] Msg sent"); + + return ClassError::CLASS_NO_ERROR; +} + +ClassError::Error ClassCore::sendMsgs(std::vector<std::string> msgs) +{ + // wrap msgs in a string until MSG_MAX_LENGTH + std::string string_with_msgs_prev = ""; + std::stringstream ss; + int msg_index = 0; + while (msg_index < msgs.size()) + { + ss << msgs[msg_index]; + std::string string_with_msgs = ss.str(); + + if (string_with_msgs.length() > MSG_MAX_LENGTH) + { + // clear stringstream + ss.str(std::string()); + // send prev and do not increase index + ClassError::Error response = sendMsg(string_with_msgs_prev); + if (response != ClassError::CLASS_NO_ERROR) + { + return response; + } + + string_with_msgs_prev = ""; + } + else + { + // continue concatenating + msg_index += 1; + string_with_msgs_prev = string_with_msgs; + } + } + + if (string_with_msgs_prev.length() != 0) + { + ClassError::Error response = sendMsg(string_with_msgs_prev); + if (response != ClassError::CLASS_NO_ERROR) + { + return response; + } + } + + return ClassError::CLASS_NO_ERROR; +} + +void ClassCore::udpMsgReceived(std::string msg, std::string ip) +{ + // processing depends on the status + //log_stream_("[udpMsgReceived] Msg received from CLASS server: " << msg << ". Msg length: " << msg.length()); + + tic_ = ""; + firmware_ = ""; + device_ = ""; + logevents_ = ""; + + + std::string temphvstatus; + if (!hvstatus_.empty()){ + temphvstatus = hvstatus_; + } else { + temphvstatus = ""; + } + hvstatus_ = ""; + + intervalstatus_ = ""; + rtcstatus_ = ""; + buzzerstatus_ = ""; + frequencystatus_ = ""; + sdfunctionstatus_ = ""; + sdunamestatus_ = ""; + patternstatus_ = ""; + hardware_ = ""; + velecstatus_ = ""; + + std::string battery_capacity_str = "battery *capacity="; + std::size_t found = msg.find(battery_capacity_str); + + if (msg.find("tic ") != std::string::npos) + { + tic_ = msg; + + double is_waiting_tic = false; + if (tic_mutex_.try_lock()) + { + is_waiting_tic = is_waiting_tic_; + tic_mutex_.unlock(); + } + + if (is_waiting_tic) + { + if (tic_mutex_.try_lock()) + { + tic_ = msg; + tic_received_ = true; + tic_mutex_.unlock(); + } + } + } + else if (msg.find("firmware") != std::string::npos) + { + // firmware_ = msg; + double is_waiting_firmware = false; + if (firmware_mutex_.try_lock()) + { + is_waiting_firmware = is_waiting_firmware_; + firmware_mutex_.unlock(); + } + + if (is_waiting_firmware) + { + if (firmware_mutex_.try_lock()) + { + firmware_ = msg; + firmware_received_ = true; + firmware_mutex_.unlock(); + } + } + } + else if (msg.find("velec ") != std::string::npos) + { + double is_waiting_velecstatus = false; + if (velecstatus_mutex_.try_lock()) + { + is_waiting_velecstatus = is_waiting_velecstatus_; + velecstatus_mutex_.unlock(); + } + if (is_waiting_velecstatus) + { + if (velecstatus_mutex_.try_lock()) + { + velecstatus_ = msg; + velecstatus_received_ = true; + velecstatus_mutex_.unlock(); + } + } + } + else if (msg.find("device") != std::string::npos) + { + double is_waiting_device = false; + if (device_mutex_.try_lock()) + { + is_waiting_device = is_waiting_device_; + device_mutex_.unlock(); + } + + if (is_waiting_device) + { + if (device_mutex_.try_lock()) + { + device_ = msg; + device_received_ = true; + device_mutex_.unlock(); + } + } + } + else if (msg.find("hardware ") != std::string::npos) + { + //hardware_ = msg; + double is_waiting_hardware = false; + if (hardware_mutex_.try_lock()) + { + is_waiting_hardware = is_waiting_hardware_; + hardware_mutex_.unlock(); + } + + if (is_waiting_hardware) + { + if (hardware_mutex_.try_lock()) + { + hardware_ = msg; + hardware_received_ = true; + hardware_mutex_.unlock(); + } + } + } + else if (msg.find("logevents ") != std::string::npos) + { + double is_waiting_logevents = false; + if (logevents_mutex_.try_lock()) + { + is_waiting_logevents = is_waiting_logevents_; + logevents_mutex_.unlock(); + } + if (is_waiting_logevents) + { + if (logevents_mutex_.try_lock()) + { + logevents_ = msg; + logevents_received_ = true; + logevents_mutex_.unlock(); + } + } + } + else if (msg.find("hv ") != std::string::npos) + { + double is_waiting_hvstatus = false; + if (hvstatus_mutex_.try_lock()) + { + is_waiting_hvstatus = is_waiting_hvstatus_; + hvstatus_mutex_.unlock(); + } + if (is_waiting_hvstatus) + { + if (hvstatus_mutex_.try_lock()) + { + hvstatus_ = temphvstatus + msg; + hvstatus_received_ = true; + hvstatus_mutex_.unlock(); + } + } + } + else if (msg.find("interval ") != std::string::npos) + { + double is_waiting_intervalstatus = false; + if (intervalstatus_mutex_.try_lock()) + { + is_waiting_intervalstatus = is_waiting_intervalstatus_; + intervalstatus_mutex_.unlock(); + } + if (is_waiting_intervalstatus) + { + if (intervalstatus_mutex_.try_lock()) + { + intervalstatus_ = msg; + intervalstatus_received_ = true; + intervalstatus_mutex_.unlock(); + } + } + } + else if (msg.find("rtc ") != std::string::npos) + { + double is_waiting_rtcstatus = false; + if (rtcstatus_mutex_.try_lock()) + { + is_waiting_rtcstatus = is_waiting_rtcstatus_; + rtcstatus_mutex_.unlock(); + } + if (is_waiting_rtcstatus) + { + if (rtcstatus_mutex_.try_lock()) + { + rtcstatus_ = msg; + rtcstatus_received_ = true; + rtcstatus_mutex_.unlock(); + } + } + } + else if (msg.find("buzzer ") != std::string::npos) + { + double is_waiting_buzzerstatus = false; + if (buzzerstatus_mutex_.try_lock()) + { + is_waiting_buzzerstatus = is_waiting_buzzerstatus_; + buzzerstatus_mutex_.unlock(); + } + if (is_waiting_buzzerstatus) + { + if (buzzerstatus_mutex_.try_lock()) + { + buzzerstatus_ = msg; + buzzerstatus_received_ = true; + buzzerstatus_mutex_.unlock(); + } + } + } + else if (msg.find("freq ") != std::string::npos) + { + double is_waiting_frequencystatus = false; + if (frequencystatus_mutex_.try_lock()) + { + is_waiting_frequencystatus = is_waiting_frequencystatus_; + frequencystatus_mutex_.unlock(); + } + if (is_waiting_frequencystatus) + { + if (frequencystatus_mutex_.try_lock()) + { + frequencystatus_ = msg; + frequencystatus_received_ = true; + frequencystatus_mutex_.unlock(); + } + } + } + else if (msg.find("function ") != std::string::npos) + { + double is_waiting_sdfunction = false; + if (sdfunction_mutex_.try_lock()) + { + is_waiting_sdfunction = is_waiting_sdfunction_; + sdfunction_mutex_.unlock(); + } + if (is_waiting_sdfunction) + { + if (sdfunction_mutex_.try_lock()) + { + sdfunctionstatus_ = msg; + sdfunction_received_ = true; + sdfunction_mutex_.unlock(); + } + } + } + else if (msg.find("uname ") != std::string::npos) + { + double is_waiting_sduname = false; + if (sduname_mutex_.try_lock()) + { + is_waiting_sduname = is_waiting_sduname_; + sduname_mutex_.unlock(); + } + if (is_waiting_sduname) + { + if (sduname_mutex_.try_lock()) + { + sdunamestatus_ = msg; + sduname_received_ = true; + sduname_mutex_.unlock(); + } + } + } + else if (msg.find("pattern ") != std::string::npos) + { + double is_waiting_patternstatus = false; + if (patternstatus_mutex_.try_lock()) + { + is_waiting_patternstatus = is_waiting_patternstatus_; + patternstatus_mutex_.unlock(); + } + if (is_waiting_patternstatus) + { + if (patternstatus_mutex_.try_lock()) + { + patternstatus_ = msg; + patternstatus_received_ = true; + patternstatus_mutex_.unlock(); + } + } + } + else if (msg.find("battery *capacity=") != std::string::npos) + { + // log_stream_("[udpMsgReceived] battery msg received:" << msg); + double is_waiting_battery = false; + if (battery_mutex_.try_lock()) + { + is_waiting_battery = is_waiting_battery_; + battery_mutex_.unlock(); + } + + if (is_waiting_battery) + { + // log_stream_("[udpMsgReceived] extract battery level"); + // extract battery level + double battery; + + std::size_t found_space = msg.find(" ", found + battery_capacity_str.length()); + if (found_space != std::string::npos) + { + std::string battery_str = msg.substr(found + battery_capacity_str.length(), found_space - (found + battery_capacity_str.length())); + + // log_stream_("[udpMsgReceived] battery str: " << battery_str); + + try + { + battery = std::stod(battery_str); + // log_stream_("[udpMsgReceived] battery: " << battery); + if (battery_mutex_.try_lock()) + { + battery_ = battery; + battery_received_ = true; + battery_mutex_.unlock(); + } + } + catch (std::exception ex) + { + log_error_stream_("[udpMsgReceived] battery. cannot convert to double: " << battery_str); + return; + } + } + } + } + else if (msg.find("turnning off") != std::string::npos) + { + log_stream_("[udpMsgReceived] turn off received:" << msg); + + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->turnOffHandle(); + } + else + { + class_cb_->turnOffHandle(); + } + } + } + else + { + bool is_acquiring_frames = false; + is_acquiring_frames_mutex_.lock(); + is_acquiring_frames = is_acquiring_frames_; + is_acquiring_frames_mutex_.unlock(); + + bool is_acquiring_impedances = false; + is_acquiring_impedances_mutex_.lock(); + is_acquiring_impedances = is_acquiring_impedances_; + is_acquiring_impedances_mutex_.unlock(); + + if (is_acquiring_frames || is_acquiring_impedances) + { + // myfile_ << msg; + int expected_bytes = 3 + 1 + 2 + channels_number_ * (1 + 3); + if (msg.length() != expected_bytes) + { + // log_warn_stream_("[udpMsgReceived] The message , which length is " << msg.length() << ", does not have the expected length " << expected_bytes << ". Msg:" << msg); + return; + } + + std::string timestamp_bin = msg.substr(0, 6); + + if (timestamp_bin.substr(3, 1) != ".") + { + // log_warn_stream_("[udpMsgReceived] Timestamp part does not have a point: " << msg); + return; + } + + AcqFrame frame; + + try + { + std::string timestamp_ms_bin = timestamp_bin.substr(0, 3); + int timestamp_ms = ((unsigned char)(timestamp_ms_bin.at(0)) << 16) + ((unsigned char)(timestamp_ms_bin.at(1)) << 8) + (unsigned char)(timestamp_ms_bin.at(2)); + + std::string timestamp_us_bin = timestamp_bin.substr(4, 2); + int timestamp_us = ((unsigned char)(timestamp_us_bin.at(0)) << 8) + (unsigned char)(timestamp_us_bin.at(1)); + + std::stringstream timestamp_stream; + timestamp_stream << timestamp_ms << "." << timestamp_us; + std::string timestamp_str(timestamp_stream.str()); + + frame.timestamp = std::stod(timestamp_str); + + int starting_index = 7; + for (int i = 0; i < channels_number_; i++) + { + std::string data_bin_str = msg.substr(starting_index, 3); + int data_bin = ((unsigned char)(data_bin_str.at(0)) << 16) + ((unsigned char)(data_bin_str.at(1)) << 8) + (unsigned char)(data_bin_str.at(2)); + + // get value of bit 24 + int bit_number = 23; + int mask = 1 << bit_number; + int masked_n = data_bin & mask; + int bit_value = masked_n >> bit_number; + + int data; + if (bit_value == 1) + { + int data_bin_xor = data_bin ^ int(pow(2, bit_number + 1) - 1); // bit xor + data = (data_bin_xor + 1) * -1; + } + else + { + data = data_bin; + } + + double chDataV = (data * 2 * 2.048) / (gain_ * pow(2.0, 24.0)); + double chDataUV = round(chDataV * 1000000); + + if (is_acquiring_frames) + { + // log_stream_("[udpMsgReceived] Value " << i << ": " << chDataUV); + // truncate + const auto result = trunc_n(chDataUV, 4); + frame.values.push_back(result.first); + } + else + { + // log_stream_("[udpMsgReceived] Value before filtering " << i << ": " << chDataUV); + if (butterworth_ == nullptr) + { + return; + } + double chDataUV_filtered; + butterworth_[i]->update(chDataUV, chDataUV_filtered); + double chDataNV_filtered = chDataUV_filtered * 1000.0; + // log_stream_("[udpMsgReceived] Value after filtering " << i << ": " << chDataNV_filtered); + double currentNA = 6; + // CHECK: it is a value per channel or unique value? do we have to take into account previous values? + double impedance = (chDataNV_filtered / currentNA) - 4700; + // log_stream_("[udpMsgReceived] Impedance " << i << ": " << impedance); + + // truncate + const auto result = trunc_n(impedance, 4); + frame.values.push_back(result.first); + } + starting_index += (3 + 1); // 3bytes of channel info + 1byte of space + } + } + catch (std::exception ex) + { + // log_error_stream_("[udpMsgReceived] error converting to double some of the values: " << msg); + return; + } + + if (is_acquiring_frames || is_acquiring_impedances) + { + if (acq_buffer_mutex_.try_lock()) + { + acq_buffer_.push_back(frame); + acq_buffer_mutex_.unlock(); + } + else + { + log_warn_stream_("[udpMsgReceived] lock not acquired"); + increaseLockError(); + } + } + else + { + acq_impedances_buffer_mutex_.lock(); + acq_impedances_buffer_.push_back(frame); + acq_impedances_buffer_mutex_.unlock(); + } + } + } +} + +ClassError::Error ClassCore::impedanceFilterOrder(const int &order) +{ + if (order == filter_order_) + { + return ClassError::CLASS_NO_ERROR; + } + + if (order <= 0) + { + return ClassError::ERROR_NOT_VALID_ORDER; + } + + return configureFilter(order, 30.2, 32.2, acq_frequency_); +} + +ClassError::Error ClassCore::bufferDuration(const double &ms) +{ + if (ms <= 0) + { + return ClassError::ERROR_NOT_VALID_MS; + } + + return setBufferCapacity(ms / 1000.0); +} + +ClassError::Error ClassCore::batteryLevel() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETBATTERY); + + if (battery_mutex_.try_lock()) + { + is_waiting_battery_ = true; + battery_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::firmwareVersion() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETFW); + + if (firmware_mutex_.try_lock()) + { + is_waiting_firmware_ = true; + firmware_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::deviceName() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETDEVICENAME); + if (device_mutex_.try_lock()) + { + is_waiting_device_ = true; + device_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::logeventsStatus() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETLOGEVENTS); + + if (logevents_mutex_.try_lock()) + { + is_waiting_logevents_ = true; + logevents_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::velecStatus(const int &number) +{ + std::stringstream ss; + ss << "velec " << number << " ?\r\n"; + std::string msg = ss.str(); + + ClassError::Error response = sendMsg(msg); + + if (velecstatus_mutex_.try_lock()) + { + is_waiting_velecstatus_ = true; + velecstatus_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::patternStatus(const int &number) +{ + std::stringstream ss; + ss << "pattern " << number << " ?\r\n"; + std::string msg = ss.str(); + + ClassError::Error response = sendMsg(msg); + + if (patternstatus_mutex_.try_lock()) + { + is_waiting_patternstatus_ = true; + patternstatus_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::hvStatus() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETHV); + + if (hvstatus_mutex_.try_lock()) + { + is_waiting_hvstatus_ = true; + hvstatus_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::intervalStatus() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETINTERVAL); + + if (intervalstatus_mutex_.try_lock()) + { + is_waiting_intervalstatus_ = true; + intervalstatus_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::rtcStatus() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETRTC); + + if (rtcstatus_mutex_.try_lock()) + { + is_waiting_rtcstatus_ = true; + rtcstatus_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::buzzerStatus() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETBUZZER); + + if (buzzerstatus_mutex_.try_lock()) + { + is_waiting_buzzerstatus_ = true; + buzzerstatus_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::frequencyStatus() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETFRQUENCY); + + if (frequencystatus_mutex_.try_lock()) + { + is_waiting_frequencystatus_ = true; + frequencystatus_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::sdfunctionStatus() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETSDFUNCTION); + + if (sdfunction_mutex_.try_lock()) + { + is_waiting_sdfunction_ = true; + sdfunction_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::sdunameStatus() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETSDNAME); + + if (sduname_mutex_.try_lock()) + { + is_waiting_sduname_ = true; + sduname_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::hardwareVersion() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETHW); + + if (hardware_mutex_.try_lock()) + { + is_waiting_hardware_ = true; + hardware_mutex_.unlock(); + } + + return response; +} + +ClassError::Error ClassCore::tic() +{ + ClassError::Error response = sendMsg(commands::ClassCommands::CMD_GETTIC); + + if (tic_mutex_.try_lock()) + { + is_waiting_tic_ = true; + tic_mutex_.unlock(); + } + + return response; +} + +void ClassCore::waitingThreadFunction_() +{ + waiting_ = true; + + bool waiting = true; + + log_stream_("[waitingThreadFunction_] Thread for waiting for callback messages started"); + + do + { + bool is_waiting_tic = false; + bool tic_received = false; + + bool is_waiting_firmware = false; + bool firmware_received = false; + + bool is_waiting_hardware = false; + bool hardware_received = false; + + bool is_waiting_battery = false; + bool battery_received = false; + + bool is_waiting_device = false; + bool device_received = false; + + bool is_waiting_logevents = false; + bool logevents_received = false; + + bool is_waiting_hvstatus = false; + bool hvstatus_received = false; + + bool is_waiting_intervalstatus = false; + bool intervalstatus_received = false; + + bool is_waiting_rtcstatus = false; + bool rtcstatus_received = false; + + bool is_waiting_buzzerstatus = false; + bool buzzerstatus_received = false; + + bool is_waiting_frequencystatus = false; + bool frequencystatus_received = false; + + bool is_waiting_sdfunctionstatus = false; + bool sdfunctionstatus_received = false; + + bool is_waiting_sdunamestatus = false; + bool sdunamestatus_received = false; + + bool is_waiting_patternstatus = false; + bool patternstatus_received = false; + + bool is_waiting_velecstatus = false; + bool velecstatus_received = false; + + double battery = 0; + + std::string tic = ""; + std::string firmware = ""; + std::string hardware = ""; + std::string device = ""; + std::string logevents = ""; + std::string hvstatus = ""; + std::string intervalstatus = ""; + std::string rtcstatus = ""; + std::string buzzerstatus = ""; + std::string frequencystatus = ""; + std::string sdfunctionstatus = ""; + std::string sdunamestatus = ""; + std::string patternstatus = ""; + std::string velecstatus = ""; + + // FIRMWARE + // if (firmware_ != "") + // { + // firmware = firmware_; + // class_cb_->firmwareHandle(firmware); + // } + + if (firmware_mutex_.try_lock()) + { + is_waiting_firmware = is_waiting_firmware_; + firmware_received = firmware_received_; + firmware = firmware_; + firmware_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] firmware lock not acquired"); + } + + if (is_waiting_firmware && firmware_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->firmwareHandle(firmware); + } + else + { + class_cb_->firmwareHandle(firmware); + } + if (firmware_mutex_.try_lock()) + { + firmware_received_ = false; + is_waiting_firmware_ = false; + firmware_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + // END OF FIRMWARE +if (velecstatus_mutex_.try_lock()) + { + is_waiting_velecstatus = is_waiting_velecstatus_; + velecstatus_received = velecstatus_received_; + velecstatus = velecstatus_; + velecstatus_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] velecstatus lock not acquired"); + } + + if (is_waiting_velecstatus && velecstatus_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->velecstatusHandle(velecstatus); + } + else + { + class_cb_->velecstatusHandle(velecstatus); + } + if (velecstatus_mutex_.try_lock()) + { + velecstatus_received_ = false; + is_waiting_velecstatus_ = false; + velecstatus_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + // END OF VELECSTATUS + if (device_mutex_.try_lock()) + { + is_waiting_device = is_waiting_device_; + device_received = device_received_; + device = device_; + device_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] device lock not acquired"); + } + + if (is_waiting_device && device_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->deviceNameHandle(device); + } + else + { + class_cb_->deviceNameHandle(device); + } + if (device_mutex_.try_lock()) + { + device_received_ = false; + is_waiting_device_ = false; + device_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + + //END of device name + if (logevents_mutex_.try_lock()) + { + is_waiting_logevents = is_waiting_logevents_; + logevents_received = logevents_received_; + logevents = logevents_; + logevents_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] logevents lock not acquired"); + } + + if (is_waiting_logevents && logevents_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->logeventsHandle(logevents); + } + else + { + class_cb_->logeventsHandle(logevents); + } + if (logevents_mutex_.try_lock()) + { + logevents_received_ = false; + is_waiting_logevents_ = false; + logevents_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + //END of logevents + if (patternstatus_mutex_.try_lock()) + { + is_waiting_patternstatus = is_waiting_patternstatus_; + patternstatus_received = patternstatus_received_; + patternstatus = patternstatus_; + patternstatus_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] patternstatus lock not acquired"); + } + + if (is_waiting_patternstatus && patternstatus_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->patternHandle(patternstatus); + } + else + { + class_cb_->patternHandle(patternstatus); + } + if (patternstatus_mutex_.try_lock()) + { + patternstatus_received_ = false; + is_waiting_patternstatus_ = false; + patternstatus_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + //END of pattern status + if (hvstatus_mutex_.try_lock()) + { + is_waiting_hvstatus = is_waiting_hvstatus_; + hvstatus_received = hvstatus_received_; + hvstatus = hvstatus_; + hvstatus_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] hvstatus lock not acquired"); + } + + if (is_waiting_hvstatus && hvstatus_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->hvHandle(hvstatus); + } + else + { + class_cb_->hvHandle(hvstatus); + } + if (hvstatus_mutex_.try_lock()) + { + hvstatus_received_ = false; + is_waiting_hvstatus_ = false; + hvstatus_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + //END of hvstatus + + if (intervalstatus_mutex_.try_lock()) + { + is_waiting_intervalstatus = is_waiting_intervalstatus_; + intervalstatus_received = intervalstatus_received_; + intervalstatus = intervalstatus_; + intervalstatus_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] intervalstatus lock not acquired"); + } + + if (is_waiting_intervalstatus && intervalstatus_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->intervalHandle(intervalstatus); + } + else + { + class_cb_->intervalHandle(intervalstatus); + } + if (intervalstatus_mutex_.try_lock()) + { + intervalstatus_received_ = false; + is_waiting_intervalstatus_ = false; + intervalstatus_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + //END of intervalstatus + + if (rtcstatus_mutex_.try_lock()) + { + is_waiting_rtcstatus = is_waiting_rtcstatus_; + rtcstatus_received = rtcstatus_received_; + rtcstatus = rtcstatus_; + rtcstatus_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] rtcstatus lock not acquired"); + } + + if (is_waiting_rtcstatus && rtcstatus_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->rtcHandle(rtcstatus); + } + else + { + class_cb_->rtcHandle(rtcstatus); + } + if (rtcstatus_mutex_.try_lock()) + { + rtcstatus_received_ = false; + is_waiting_rtcstatus_ = false; + rtcstatus_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + //END of rtc + + if (buzzerstatus_mutex_.try_lock()) + { + is_waiting_buzzerstatus = is_waiting_buzzerstatus_; + buzzerstatus_received = buzzerstatus_received_; + buzzerstatus = buzzerstatus_; + buzzerstatus_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] buzzer lock not acquired"); + } + + if (is_waiting_buzzerstatus && buzzerstatus_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->buzzerHandle(buzzerstatus); + } + else + { + class_cb_->buzzerHandle(buzzerstatus); + } + if (buzzerstatus_mutex_.try_lock()) + { + buzzerstatus_received_ = false; + is_waiting_buzzerstatus_ = false; + buzzerstatus_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + //END of buzzer + if (frequencystatus_mutex_.try_lock()) + { + is_waiting_frequencystatus = is_waiting_frequencystatus_; + frequencystatus_received = frequencystatus_received_; + frequencystatus = frequencystatus_; + frequencystatus_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] frequency lock not acquired"); + } + + if (is_waiting_frequencystatus && frequencystatus_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->frequencyHandle(frequencystatus); + } + else + { + class_cb_->frequencyHandle(frequencystatus); + } + if (frequencystatus_mutex_.try_lock()) + { + frequencystatus_received_ = false; + is_waiting_frequencystatus_ = false; + frequencystatus_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + //END of frequency + + if (sdfunction_mutex_.try_lock()) + { + is_waiting_sdfunctionstatus = is_waiting_sdfunction_; + sdfunctionstatus_received = sdfunction_received_; + sdfunctionstatus = sdfunctionstatus_; + sdfunction_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] sdfunction lock not acquired"); + } + + if (is_waiting_sdfunctionstatus && sdfunctionstatus_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->sdfunctionHandle(sdfunctionstatus); + } + else + { + class_cb_->sdfunctionHandle(sdfunctionstatus); + } + if (sdfunction_mutex_.try_lock()) + { + sdfunction_received_ = false; + is_waiting_sdfunction_ = false; + sdfunction_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + //END of sdfunction + + if (sduname_mutex_.try_lock()) + { + is_waiting_sdunamestatus = is_waiting_sduname_; + sdunamestatus_received = sduname_received_; + sdunamestatus = sdunamestatus_; + sduname_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] sduname lock not acquired"); + } + + if (is_waiting_sdunamestatus && sdunamestatus_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->sdunameHandle(sdunamestatus); + } + else + { + class_cb_->sdunameHandle(sdunamestatus); + } + if (sduname_mutex_.try_lock()) + { + sduname_received_ = false; + is_waiting_sduname_ = false; + sduname_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + //END of sduname + + // HARDWARE + // if (hardware_ != "") + // { + // hardware = hardware_; + // class_cb_->hardwareHandle(hardware); + // } + + if (hardware_mutex_.try_lock()) + { + is_waiting_hardware = is_waiting_hardware_; + hardware_received = hardware_received_; + hardware = hardware_; + hardware_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] hardware lock not acquired"); + } + + if (is_waiting_hardware && hardware_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->hardwareHandle(hardware); + } + else + { + class_cb_->hardwareHandle(hardware); + } + if (hardware_mutex_.try_lock()) + { + hardware_received_ = false; + is_waiting_hardware_ = false; + hardware_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + + // END OF HARDWARE + + // TIC + // if (tic_ != "") + // { + // tic = tic_; + // class_cb_->ticHandle(tic); + // } + if (tic_mutex_.try_lock()) + { + is_waiting_tic = is_waiting_tic_; + tic_received = tic_received_; + tic = tic_; + tic_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] tic lock not acquired"); + } + + if (is_waiting_tic && tic_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->ticHandle(tic); + } + else + { + class_cb_->ticHandle(tic); + } + if (tic_mutex_.try_lock()) + { + tic_received_ = false; + is_waiting_tic_ = false; + tic_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + // END OF TIC + + // BATTERY + if (battery_mutex_.try_lock()) + { + is_waiting_battery = is_waiting_battery_; + battery_received = battery_received_; + battery = battery_; + battery_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] battery lock not acquired"); + } + + if (is_waiting_battery && battery_received) + { + if (class_cb_ != nullptr) + { + if (language_ == "python") + { + class PyThreadStateLock PyThreadLock; // fix segmentation fault + class_cb_->batteryHandle(battery); + } + else + { + class_cb_->batteryHandle(battery); + } + if (battery_mutex_.try_lock()) + { + battery_received_ = false; + is_waiting_battery_ = false; + battery_mutex_.unlock(); + } + } + else + { + log_error_stream_("[waitingThreadFunction_] callback is null"); + } + } + // END OF BATTERY + + std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 0.5 secs + + if (waiting_mutex_.try_lock()) + { + waiting = waiting_; + waiting_mutex_.unlock(); + } + else + { + log_warn_stream_("[waitingThreadFunction_] waiting lock not acquired"); + } + } while (waiting); +} + +void ClassCore::lockErrorThreadFunction_() +{ + error_waiting_ = true; + + bool error_waiting = true; + + log_stream_("[lockErrorThreadFunction_] Thread for taking into account lock errors started"); + + do + { + int lock_error_number = 0; + + if (lock_error_mutex_.try_lock()) + { + lock_error_number = lock_error_number_; + lock_error_mutex_.unlock(); + } + else + { + log_warn_stream_("[lockErrorThreadFunction_] error lock not acquired"); + } + + if (lock_error_number >= lock_error_number_max_) + { + log_error_stream_("[lockErrorThreadFunction_] Number of errors when getting lock has overcome the limit. Check processes in your computer."); + } + + if (lock_error_mutex_.try_lock()) + { + lock_error_number_ = 0; + lock_error_mutex_.unlock(); + } + else + { + log_warn_stream_("[lockErrorThreadFunction_] error lock not acquired"); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 1secs + + if (lock_error_mutex_.try_lock()) + { + error_waiting = error_waiting_; + lock_error_mutex_.unlock(); + } + else + { + log_warn_stream_("[lockErrorThreadFunction_] error lock not acquired"); + } + } while (error_waiting); +} + +ClassError::Error ClassCore::setCallback(ClassCallback *callback, std::string language) +{ + if (class_cb_ != nullptr) + { + delete class_cb_; + class_cb_ = nullptr; + } + + if (callback) + { + class_cb_ = callback; + } + else + { + return ClassError::ERROR_CB_NULL; + } + + language_ = language; + + return ClassError::CLASS_NO_ERROR; +} + +std::pair<double, bool> ClassCore::trunc_n(double value, std::size_t digits_after_decimal = 0) +{ + static constexpr std::intmax_t maxv = std::numeric_limits<std::intmax_t>::max(); + static constexpr std::intmax_t minv = std::numeric_limits<std::intmax_t>::min(); + + unsigned long long multiplier = 1; + for (std::size_t i = 0; i < digits_after_decimal; ++i) + multiplier *= 10; + + const auto scaled_value = value * multiplier; + + const bool did_trunc = scaled_value != scaled_value + 0.5 && scaled_value != scaled_value - 0.5; + + if (scaled_value >= minv && scaled_value <= maxv) + return {double(std::intmax_t(scaled_value)) / multiplier, did_trunc}; + else + return {std::trunc(scaled_value) / multiplier, did_trunc}; +} + +void ClassCore::increaseLockError() +{ + lock_error_mutex_.lock(); + lock_error_number_ += 1; + lock_error_mutex_.unlock(); +} +ClassError::Error ClassCore::sendCustomCmd(const std::string &cmd) +{ + return sendMsg(cmd); +} + +/*LOGGING functions*/ + +void ClassCore::log_(const std::string &text) +{ + LOG_INFO << "[ClassCore]: " << text; +} + +void ClassCore::log_(std::ostream &text) +{ + LOG_INFO << "[ClassCore]: " << text.rdbuf(); +} + +void ClassCore::log_(const std::stringstream &text) +{ + LOG_INFO << "[ClassCore]: " << text.str(); +} + +// see http://www.cplusplus.com/forum/unices/36461/ +// see https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute + +#ifdef __unix__ +const std::string bold_red("\033[1;31m"); +const std::string bold_yellow("\033[1;33m"); +const std::string reset("\033[0m"); +#endif + +void ClassCore::log_err_(const std::string &text) +{ +#ifdef __unix__ + LOG_ERROR << bold_red << "[ClassCore]: " << text << reset; +#elif defined(_WIN32) || defined(WIN32) + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(hConsole, 12); + LOG_ERROR << "[ClassCore]: " << text; + SetConsoleTextAttribute(hConsole, 7); +#endif +} + +void ClassCore::log_err_(std::ostream &text) +{ +#ifdef __unix__ + LOG_ERROR << bold_red << "[ClassCore]: " << text.rdbuf() << reset; +#elif defined(_WIN32) || defined(WIN32) + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(hConsole, 12); + LOG_ERROR << "[ClassCore]: " << text.rdbuf(); + SetConsoleTextAttribute(hConsole, 7); +#endif +} + +void ClassCore::log_warn_(const std::string &text) +{ +#ifdef __unix__ + LOG_WARNING << bold_yellow << "[ClassCore]: " << text << reset; +#elif defined(_WIN32) || defined(WIN32) + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(hConsole, 14); + LOG_WARNING << "[ClassCore]: " << text; + SetConsoleTextAttribute(hConsole, 7); +#endif +} + +void ClassCore::log_warn_(std::ostream &text) +{ +#ifdef __unix__ + LOG_WARNING << bold_yellow << "[ClassCore]: " << text.rdbuf() << reset; +#elif defined(_WIN32) || defined(WIN32) + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleTextAttribute(hConsole, 14); + LOG_WARNING << "[ClassCore]: " << text.rdbuf(); + SetConsoleTextAttribute(hConsole, 7); +#endif +} -- GitLab