diff --git a/.codespellrc b/.codespellrc index f8b4cc8b..15e1566d 100644 --- a/.codespellrc +++ b/.codespellrc @@ -2,6 +2,6 @@ builtin = clear,rare,en-GB_to_en-US,names,informal,code check-filenames = check-hidden = -ignore-words-list = weill,sinc,mut,numer,uint,stdio,ws -skip = */.git,*/build,*/prefix,./scripts/all_plugins,./libs +ignore-words-list = weill,sinc,mut,numer,uint,stdio,ws,indx +skip = */.git,*/build,*/prefix,./scripts/all_plugins,./libs,.venv quiet-level = 2 diff --git a/docs/Doxyfile b/docs/Doxyfile index 0659c10b..e0316a80 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -559,7 +559,7 @@ INTERNAL_DOCS = NO # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows -# (including Cygwin) ands Mac users are advised to set this option to NO. +# (including Cygwin) and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = NO diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index d1314280..c123e67e 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -559,7 +559,7 @@ INTERNAL_DOCS = NO # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows -# (including Cygwin) ands Mac users are advised to set this option to NO. +# (including Cygwin) and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = NO diff --git a/src/io.cpp b/src/io.cpp index a7d37159..2489d70e 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -35,7 +35,7 @@ IO::Block::Block(std::string blockname, port.value = 0.0; port.buff_value = 0.0; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index) - ports[channel.flags].push_back(port); + ports.at(channel.flags).push_back(port); port = {}; } } @@ -43,44 +43,44 @@ IO::Block::Block(std::string blockname, size_t IO::Block::getCount(IO::flags_t type) const { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index) - return this->ports[type].size(); + return this->ports.at(type).size(); } std::string IO::Block::getChannelName(IO::flags_t type, size_t index) const { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index) - return this->ports[type][index].channel_info.name; + return this->ports.at(type).at(index).channel_info.name; } std::string IO::Block::getChannelDescription(IO::flags_t type, size_t index) const { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index) - return this->ports[type][index].channel_info.description; + return this->ports.at(type).at(index).channel_info.description; } void IO::Block::writeinput(size_t index, const double& data) { - this->ports[IO::INPUT][index].buff_value += data; + this->ports.at(IO::INPUT).at(index).buff_value += data; } double& IO::Block::readinput(size_t index) { // We must reset input values to zero so that the next cycle doesn't use these // values - this->ports[IO::INPUT][index].value = - this->ports[IO::INPUT][index].buff_value; - this->ports[IO::INPUT][index].buff_value = 0.0; - return this->ports[IO::INPUT][index].value; + this->ports.at(IO::INPUT).at(index).value = + this->ports.at(IO::INPUT).at(index).buff_value; + this->ports.at(IO::INPUT).at(index).buff_value = 0.0; + return this->ports.at(IO::INPUT).at(index).value; } void IO::Block::writeoutput(size_t index, const double& data) { - this->ports[IO::OUTPUT][index].value = data; + this->ports.at(IO::OUTPUT).at(index).value = data; } const double& IO::Block::readPort(IO::flags_t direction, size_t index) { - return this->ports[direction][index].value; + return this->ports.at(direction).at(index).value; } // NOLINTEND(cppcoreguidelines-pro-bounds-constant-array-index) diff --git a/src/main_window.cpp b/src/main_window.cpp index 293db33d..389538f0 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -61,11 +61,11 @@ // deserialize it back when loading settings. struct plugin_connection { - quint64 src_id; - quint64 src_direction; - quint64 src_port; - quint64 dest_id; - quint64 dest_port; + qint32 src_id; + qint32 src_direction; + qint32 src_port; + qint32 dest_id; + qint32 dest_port; }; QDataStream& operator<<(QDataStream& out, const plugin_connection& conn) @@ -534,7 +534,7 @@ void MainWindow::saveDAQSettings(QSettings& userprefs) } void MainWindow::loadDAQSettings( - QSettings& userprefs, std::unordered_map block_cache) + QSettings& userprefs, std::unordered_map& block_cache) { userprefs.beginGroup("DAQs"); Event::Object get_devices_event(Event::Type::DAQ_DEVICE_QUERY_EVENT); @@ -652,7 +652,7 @@ void MainWindow::loadDAQSettings( } userprefs.endGroup(); // Digital Output userprefs.endGroup(); // Device name - block_cache[device_id.toUInt()] = tmp_device; + block_cache[device_id.toInt()] = tmp_device; } userprefs.endGroup(); // DAQ } @@ -664,9 +664,18 @@ void MainWindow::saveWidgetSettings(QSettings& userprefs) this->event_manager->postEvent(&loaded_plugins_query); const auto plugin_list = std::any_cast>( loaded_plugins_query.getParam("plugins")); - int widget_count = 0; + int non_component_plugin_id = -1; + int plugin_id = 0; for (const auto& entry : plugin_list) { - userprefs.beginGroup(QString::number(widget_count++)); + // We don't expect the number of blocks in the system to exceed the max + // positive value of int In 2025 you would run out of memory first before + // that happens. Additionally we are saving negative values to indicate to + // the workspace loading system that the negative valued plugins do not + // contain a component and therefore should be left out of the connection + // loading step. + plugin_id = entry->hasComponent() ? static_cast(entry->getID()) + : non_component_plugin_id--; + userprefs.beginGroup(QString::number(plugin_id)); userprefs.setValue("library", QString::fromStdString(entry->getLibrary())); userprefs.beginGroup("standardParams"); entry->saveParameterSettings(userprefs); @@ -680,7 +689,7 @@ void MainWindow::saveWidgetSettings(QSettings& userprefs) } void MainWindow::loadWidgetSettings( - QSettings& userprefs, std::unordered_map block_cache) + QSettings& userprefs, std::unordered_map& block_cache) { userprefs.beginGroup("Widgets"); QString plugin_name; @@ -698,7 +707,7 @@ void MainWindow::loadWidgetSettings( plugin_ptr->loadCustomParameterSettings(userprefs); userprefs.endGroup(); // customParams userprefs.endGroup(); // plugin_instance_id - block_cache[plugin_instance_id.toUInt()] = plugin_ptr->getBlock(); + block_cache[plugin_instance_id.toInt()] = plugin_ptr->getBlock(); } userprefs.endGroup(); // Widgets } @@ -722,11 +731,13 @@ void MainWindow::saveConnectionSettings(QSettings& userprefs) { continue; } - id_connection.src_id = conn.src->getID(); - id_connection.src_direction = conn.src_port_type; - id_connection.src_port = conn.src_port; - id_connection.dest_id = conn.dest->getID(); - id_connection.dest_port = conn.dest_port; + // We need to match the block id with the id already stored in the + // settings file when saveWidgets was called. + id_connection.src_id = static_cast(conn.src->getID()); + id_connection.src_direction = static_cast(conn.src_port_type); + id_connection.src_port = static_cast(conn.src_port); + id_connection.dest_id = static_cast(conn.dest->getID()); + id_connection.dest_port = static_cast(conn.dest_port); userprefs.setValue(QString::number(connection_count++), QVariant::fromValue(id_connection)); } @@ -734,7 +745,7 @@ void MainWindow::saveConnectionSettings(QSettings& userprefs) } void MainWindow::loadConnectionSettings( - QSettings& userprefs, std::unordered_map block_cache) + QSettings& userprefs, std::unordered_map& block_cache) { ///////////////////// Load connections ///////////////////////// RT::block_connection_t connection; @@ -754,9 +765,9 @@ void MainWindow::loadConnectionSettings( connection.src = block_cache[id_connection.src_id]; connection.src_port_type = static_cast(id_connection.src_direction); - connection.src_port = id_connection.src_port; + connection.src_port = static_cast(id_connection.src_port); connection.dest = block_cache[id_connection.dest_id]; - connection.dest_port = id_connection.dest_port; + connection.dest_port = static_cast(id_connection.dest_port); connection_events.emplace_back(Event::Type::IO_LINK_INSERT_EVENT); connection_events.back().setParam("connection", std::any(connection)); } @@ -785,7 +796,7 @@ void MainWindow::loadSettings() mdiArea->closeAllSubWindows(); const auto workspace_filename = userprefs.value(profile).toString(); QSettings workspaceprefs(workspace_filename, QSettings::IniFormat); - std::unordered_map blocks; + std::unordered_map blocks; this->loadPeriodSettings(workspaceprefs); this->loadDAQSettings(workspaceprefs, blocks); @@ -837,6 +848,8 @@ void MainWindow::saveSettings() this->saveWidgetSettings(workspaceprefs); + this->saveConnectionSettings(workspaceprefs); + userprefs.endGroup(); // Workspaces } diff --git a/src/main_window.hpp b/src/main_window.hpp index fc3fff5f..16ccd3ce 100644 --- a/src/main_window.hpp +++ b/src/main_window.hpp @@ -23,6 +23,7 @@ #include #include +#include #include "event.hpp" @@ -177,14 +178,14 @@ private slots: inline void savePeriodSettings(QSettings& userprefs); inline void loadPeriodSettings(QSettings& userprefs); inline void saveDAQSettings(QSettings& userprefs); - inline void loadDAQSettings( - QSettings& userprefs, std::unordered_map block_cache); + inline void loadDAQSettings(QSettings& userprefs, + std::unordered_map& block_cache); inline void saveWidgetSettings(QSettings& userprefs); inline void loadWidgetSettings( - QSettings& userprefs, std::unordered_map block_cache); + QSettings& userprefs, std::unordered_map& block_cache); inline void saveConnectionSettings(QSettings& userprefs); inline void loadConnectionSettings( - QSettings& userprefs, std::unordered_map block_cache); + QSettings& userprefs, std::unordered_map& block_cache); Event::Manager* event_manager; QMdiArea* mdiArea = nullptr; QList subWindows; diff --git a/src/nidaq_driver.cpp b/src/nidaq_driver.cpp index 6fd544b6..d138642f 100644 --- a/src/nidaq_driver.cpp +++ b/src/nidaq_driver.cpp @@ -184,6 +184,27 @@ inline void printError(int32_t status) ERROR_MSG("Message : {}", std::string(err_buff.data())); } +inline void printExtendedError(int32_t status) +{ + if (status == 0) { + return; + } + ERROR_MSG("NIDAQ ERROR : code {}", status); + const int32_t error_size = DAQmxGetExtendedErrorInfo(nullptr, 0); + if (error_size < 0) { + ERROR_MSG("Unable to get code message"); + return; + } + std::vector err_buff(static_cast(error_size)); + const int32_t errcode = DAQmxGetExtendedErrorInfo( + err_buff.data(), static_cast(error_size)); + if (errcode < 0) { + ERROR_MSG("Unable to parse message"); + return; + } + ERROR_MSG("Message : {}", std::string(err_buff.data())); +} + inline std::string physical_card_name(const std::string& device_name) { std::array buffer {}; @@ -218,6 +239,8 @@ struct physical_channel_t int32_t physical_channel_t::addToTask(TaskHandle task_handle) const { int32_t err = 0; + int32_t shunt_resistance_location = 0; + int32_t shunt_resisntance_value = 0; const std::string units = DAQ::get_default_units().at(units_index); auto [min, max] = DAQ::get_default_ranges().at(range_index); switch (type) { @@ -232,20 +255,22 @@ int32_t physical_channel_t::addToTask(TaskHandle task_handle) const DAQmx_Val_Volts, nullptr); } else if (units == "amps") { + DAQmxGetAICurrentShuntLoc( + task_handle, name.c_str(), &shunt_resistance_location); err = DAQmxCreateAICurrentChan(task_handle, name.c_str(), nullptr, - reference, - min, - max, + DAQmx_Val_Diff, + min / 1000.0, + max / 1000.0, DAQmx_Val_Amps, - DAQmx_Val_Default, - 0, + shunt_resistance_location, + 249.0, nullptr); } else { ERROR_MSG("NIDAQ : Virtual Channel Creation : Unknown units {}", units); } - printError(err); + printExtendedError(err); break; case DAQ::ChannelType::AO: if (units == "volts") { @@ -267,17 +292,17 @@ int32_t physical_channel_t::addToTask(TaskHandle task_handle) const } else { ERROR_MSG("NIDAQ : Virtual Channel Creation : Unknown units {}", units); } - printError(err); + printExtendedError(err); break; case DAQ::ChannelType::DI: err = DAQmxCreateDIChan( task_handle, name.c_str(), nullptr, DAQmx_Val_ChanPerLine); - printError(err); + printExtendedError(err); break; case DAQ::ChannelType::DO: err = DAQmxCreateDOChan( task_handle, name.c_str(), nullptr, DAQmx_Val_ChanPerLine); - printError(err); + printExtendedError(err); break; default: ERROR_MSG("NIDAQ_DRIVER : Channel Type Unknown"); @@ -516,7 +541,7 @@ int Device::setChannelActive(DAQ::ChannelType::type_t type, DAQmxClearTask(task); err = DAQmxCreateTask(DAQ::ChannelType::type2string(type).c_str(), &task); if (err != 0) { - printError(err); + printExtendedError(err); for (auto& channel : physical_channels_registry.at(type)) { channel.active = false; } @@ -554,9 +579,9 @@ int Device::setChannelActive(DAQ::ChannelType::type_t type, } } if (DAQmxGetTaskChannels(task, nullptr, 0) > 0) { - printError(DAQmxSetSampTimingType(task, DAQmx_Val_OnDemand)); - printError(DAQmxTaskControl(task, DAQmx_Val_Task_Commit)); - printError(DAQmxStartTask(task)); + printExtendedError(DAQmxSetSampTimingType(task, DAQmx_Val_OnDemand)); + printExtendedError(DAQmxTaskControl(task, DAQmx_Val_Task_Commit)); + printExtendedError(DAQmxStartTask(task)); } return err; } @@ -993,6 +1018,9 @@ void Driver::loadDevices() printError(device_names_buffer_size); return; } + if (device_names_buffer_size == 0) { + return; + } const std::string alpha = "abcdefghijklmnopqrstuvwxyz"; std::vector buffer(static_cast(device_names_buffer_size)); DAQmxGetSysDevNames(buffer.data(), static_cast(buffer.size())); diff --git a/src/rtos.hpp b/src/rtos.hpp index bbce0416..c2d45cdc 100644 --- a/src/rtos.hpp +++ b/src/rtos.hpp @@ -82,7 +82,7 @@ int setPeriod(Task* task, int64_t period); * real-time loop. Available inside execute(). * * \returns Period of the realtime thread the calling function is - * runninng from, -1 otherwise. + * running from, -1 otherwise. * * \sa RT::OS::sleepTimestep */ diff --git a/src/widgets.cpp b/src/widgets.cpp index e9f9fe63..4c5b3c5a 100644 --- a/src/widgets.cpp +++ b/src/widgets.cpp @@ -304,7 +304,7 @@ void Widgets::Panel::updatePauseButton() return; } const bool paused = state == RT::State::PAUSE; - pauseButton->setChecked(paused); + pauseButton->setDown(paused); } void Widgets::Panel::update_state(RT::State::state_t flag) diff --git a/src/widgets.hpp b/src/widgets.hpp index 9e5e8e4f..6f055cc6 100644 --- a/src/widgets.hpp +++ b/src/widgets.hpp @@ -719,6 +719,7 @@ class Plugin : public Event::Handler * \return IO::Block pointer to the internal structure */ IO::Block* getBlock() { return plugin_component.get(); } + const IO::Block* getBlock() const { return plugin_component.get(); } protected: Widgets::Component* getComponent(); diff --git a/src/workspace.cpp b/src/workspace.cpp index b551d65d..097c6b5d 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -75,6 +75,17 @@ Workspace::Manager::Manager(Event::Manager* ev_manager) ERROR_MSG("Unable to load GSC aio168 rtxi driver"); } } +#ifdef DEBUG_DRIVERS + const std::string fake_driver_name = "librtxifakedriver.so"; + if (bin_dir.exists(QString::fromStdString(fake_driver_name))) { + try { + this->registerDriver(bin_dir.path().toStdString() + std::string("/") + + fake_driver_name); + } catch (std::runtime_error& excepttion) { + ERROR_MSG("Unable to load fake rtxi driver"); + } + } +#endif } Workspace::Manager::~Manager()