17 const std::string& delim)
23 size_t pos_end = buffer.find(delim, pos_start);
24 if (pos_end == std::string::npos) {
28 std::vector<std::string> split_tokens;
29 const size_t delim_len = delim.size();
31 token = buffer.substr(pos_start, pos_end - pos_start);
32 pos_start = pos_end + delim_len;
33 split_tokens.push_back(token);
34 pos_end = buffer.find(delim, pos_start);
35 if (pos_end == std::string::npos) {
39 token = buffer.substr(pos_start, buffer.size() - pos_start);
40 split_tokens.push_back(token);
47 int32_t (*func)(
const char*,
char*, uint32_t) =
nullptr;
50 func = &DAQmxGetDevAOPhysicalChans;
53 func = &DAQmxGetDevAIPhysicalChans;
56 func = &DAQmxGetDevDOLines;
59 func = &DAQmxGetDevDILines;
64 std::string channel_names;
65 const int32_t buff_size = func(device.c_str(),
nullptr, 0);
69 channel_names.resize(
static_cast<size_t>(buff_size));
70 func(device.c_str(), channel_names.data(),
static_cast<uint32_t
>(buff_size));
79 ERROR_MSG(
"NIDAQ ERROR : code {}", status);
80 const int32_t error_size = DAQmxGetErrorString(status,
nullptr, 0);
85 std::string err_str(
static_cast<size_t>(error_size),
'\0');
86 const int32_t errcode = DAQmxGetErrorString(
87 status, err_str.data(),
static_cast<uint32_t
>(error_size));
97 const int32_t err = DAQmxGetDevProductType(device_name.c_str(),
nullptr, 0);
98 std::string result(
static_cast<size_t>(err),
'\0');
99 DAQmxGetDevProductType(
100 device_name.c_str(), result.data(),
static_cast<uint32_t
>(result.size()));
109 :
name(std::move(chan_name))
114 int32_t
addToTask(TaskHandle task_handle)
const;
134 if (units ==
"volts") {
135 err = DAQmxCreateAIVoltageChan(task_handle,
143 }
else if (units ==
"amps") {
144 err = DAQmxCreateAICurrentChan(task_handle,
155 ERROR_MSG(
"NIDAQ : Virtual Channel Creation : Unknown units {}", units);
160 if (units ==
"volts") {
161 err = DAQmxCreateAOVoltageChan(task_handle,
168 }
else if (units ==
"amps") {
169 err = DAQmxCreateAOCurrentChan(task_handle,
177 ERROR_MSG(
"NIDAQ : Virtual Channel Creation : Unknown units {}", units);
182 err = DAQmxCreateDIChan(
183 task_handle,
name.c_str(),
nullptr, DAQmx_Val_ChanPerLine);
187 err = DAQmxCreateDOChan(
188 task_handle,
name.c_str(),
nullptr, DAQmx_Val_ChanPerLine);
192 ERROR_MSG(
"NIDAQ_DRIVER : Channel Type Unknown");
207 Device(
const std::string& dev_name,
208 const std::vector<IO::channel_t>& channels,
209 std::string internal_name);
252 double offset) final;
264 size_t downsample) final;
284 std::array<TaskHandle,
DAQ::ChannelType::
UNKNOWN> task_list {};
287 std::string internal_dev_name;
288 std::array<std::vector<physical_channel_t>, 4> physical_channels_registry;
291 std::tuple<std::vector<double>,
293 std::vector<uint8_t>,
294 std::vector<uint8_t>>
308 std::vector<Device> nidaq_devices;
312 const std::vector<IO::channel_t>& channels,
313 std::string internal_name)
315 , internal_dev_name(std::move(internal_name))
317 size_t inputs_count = 0;
318 size_t outputs_count = 0;
319 std::string task_name;
323 if (DAQmxCreateTask(task_name.c_str(), &task_list.at(type)) < 0) {
324 ERROR_MSG(
"NIDAQ::Device : Unable to create {} task for device {}",
331 DAQmxCfgInputBuffer(task_list.at(type), 1);
332 DAQmxSetReadOverWrite(task_list.at(type),
333 DAQmx_Val_OverwriteUnreadSamps);
337 DAQmxCfgOutputBuffer(task_list.at(type), 1);
344 std::vector<std::string> chan_names;
345 for (
size_t type = 0; type < physical_channels_registry.size(); type++) {
348 for (
const auto& chan_name : chan_names) {
349 physical_channels_registry.at(type).emplace_back(
352 type % 2 == 0 ? inputs_count : outputs_count);
353 type % 2 == 0 ? inputs_count++ : outputs_count++;
356 std::get<DAQ::ChannelType::AI>(buffer_arrays)
358 std::get<DAQ::ChannelType::AO>(buffer_arrays)
360 std::get<DAQ::ChannelType::DI>(buffer_arrays)
362 std::get<DAQ::ChannelType::DO>(buffer_arrays)
365 for (
auto& task : task_list) {
366 DAQmxSetSampTimingType(task, DAQmx_Val_OnDemand);
367 DAQmxTaskControl(task, DAQmx_Val_Task_Commit);
368 DAQmxStartTask(task);
375 for (
const auto& task : task_list) {
377 DAQmxClearTask(task);
383 return physical_channels_registry.at(type).size();
389 return physical_channels_registry.at(type).at(index).active;
402 if (physical_channels_registry.at(type).at(index).active == state) {
405 DAQmxStopTask(task_list.at(type));
407 err = physical_channels_registry.at(type).at(index).addToTask(
409 physical_channels_registry.at(type).at(index).active = err == 0;
411 physical_channels_registry.at(type).at(index).active =
false;
412 DAQmxClearTask(task_list.at(type));
414 &task_list.at(type));
418 DAQmxCfgInputBuffer(task_list.at(type), 1);
419 DAQmxSetReadOverWrite(task_list.at(type),
420 DAQmx_Val_OverwriteUnreadSamps);
424 DAQmxCfgOutputBuffer(task_list.at(type), 1);
430 for (
auto& channel : physical_channels_registry.at(type)) {
431 channel.active =
false;
433 active_channels.at(type).clear();
436 for (
const auto& channel : physical_channels_registry.at(type)) {
437 if (!channel.active) {
440 err = channel.addToTask(task_list.at(type));
447 active_channels.at(type).clear();
448 for (
auto& channel : physical_channels_registry.at(type)) {
449 if (channel.active) {
450 active_channels.at(type).push_back(&channel);
453 printError(DAQmxSetSampTimingType(task_list.at(type), DAQmx_Val_OnDemand));
454 printError(DAQmxTaskControl(task_list.at(type), DAQmx_Val_Task_Commit));
455 printError(DAQmxStartTask(task_list.at(type)));
462 return default_ranges.size();
472 return default_units.size();
488 const std::string formatting =
"{:.1f}";
489 auto [min, max] = default_ranges.at(
490 physical_channels_registry.at(type).at(index).range_index);
491 return fmt::format(formatting, min) + std::string(
" to ")
492 + fmt::format(formatting, max);
502 const int32_t ref = physical_channels_registry.at(type).at(index).reference;
512 refstr =
"Differential";
514 case DAQmx_Val_PseudoDiff:
531 return default_units.at(
532 physical_channels_registry.at(type).at(index).units_index);
541 return physical_channels_registry.at(type).at(index).gain;
550 return physical_channels_registry.at(type).at(index).offset;
559 return physical_channels_registry.at(type).at(index).range_index;
568 return static_cast<size_t>(
569 physical_channels_registry.at(type).at(index).reference);
578 return physical_channels_registry.at(type).at(index).units_index;
587 return physical_channels_registry.at(type).at(index).units_index;
597 physical_channels_registry.at(type).at(index).gain = gain;
608 physical_channels_registry.at(type).at(index).range_index = range;
619 physical_channels_registry.at(type).at(index).offset = offset;
630 physical_channels_registry.at(type).at(index).range_index = reference;
641 physical_channels_registry.at(type).at(index).units_index = units;
700 int samples_read = 0;
701 size_t value_index = 0;
705 DAQmx_Val_WaitInfinitely,
706 DAQmx_Val_GroupByScanNumber,
707 std::get<DAQ::ChannelType::AI>(buffer_arrays).data(),
708 std::get<DAQ::ChannelType::AI>(buffer_arrays).size(),
714 std::get<DAQ::ChannelType::AI>(buffer_arrays).at(value_index));
720 int32_t num_bytes_per_sample = 0;
724 DAQmx_Val_WaitInfinitely,
725 DAQmx_Val_GroupByScanNumber,
726 std::get<DAQ::ChannelType::DI>(buffer_arrays).data(),
727 std::get<DAQ::ChannelType::DI>(buffer_arrays).size(),
729 &num_bytes_per_sample,
734 std::get<DAQ::ChannelType::DI>(buffer_arrays).at(value_index));
742 size_t samples_to_write = 0;
743 int samples_written = 0;
746 std::get<DAQ::ChannelType::AO>(buffer_arrays).at(samples_to_write) =
753 DAQmx_Val_WaitInfinitely,
754 DAQmx_Val_GroupByScanNumber,
755 std::get<DAQ::ChannelType::AO>(buffer_arrays).data(),
759 samples_to_write = 0;
761 bool digital_value_changed =
false;
762 uint8_t old_value = 0;
763 uint8_t new_value = 0;
766 std::get<DAQ::ChannelType::DO>(buffer_arrays).at(samples_to_write);
767 new_value =
static_cast<uint8_t
>(
readinput(chan->id));
768 if (old_value != new_value) {
769 digital_value_changed =
true;
771 std::get<DAQ::ChannelType::DO>(buffer_arrays).at(samples_to_write) =
775 if (digital_value_changed) {
776 DAQmxWriteDigitalLines(
780 DAQmx_Val_WaitInfinitely,
781 DAQmx_Val_GroupByScanNumber,
782 std::get<DAQ::ChannelType::DO>(buffer_arrays).data(),
797 const int32_t device_names_buffer_size = DAQmxGetSysDevNames(
nullptr, 0);
798 if (device_names_buffer_size < 0) {
802 const std::string alpha =
"abcdefghijklmnopqrstuvwxyz";
803 std::string string_buffer(
static_cast<size_t>(device_names_buffer_size),
805 DAQmxGetSysDevNames(string_buffer.data(),
806 static_cast<uint32_t
>(string_buffer.size()));
807 const std::vector<std::string> device_names =
809 std::vector<IO::channel_t> channels;
810 std::vector<std::string> split_channel_names;
812 std::string physical_daq_name;
813 std::string description;
815 for (
const auto& internal_dev_name : device_names) {
816 for (
size_t query_indx = 0; query_indx < 4; query_indx++) {
820 for (
const auto& chan_name : split_channel_names) {
821 description = std::string(query_indx < 2 ?
"Analog" :
"Digital");
823 description += std::string(query_indx % 2 == 0 ?
"Output" :
"Input");
825 pos = chan_name.find_last_of(alpha) + 1;
826 channel_id = std::stoi(chan_name.substr(pos, chan_name.size() - pos));
827 description += std::to_string(channel_id);
828 channels.push_back({chan_name,
833 this->nidaq_devices.emplace_back(
834 physical_daq_name, channels, internal_dev_name);
842 std::vector<DAQ::Device*> devices;
843 devices.reserve(this->nidaq_devices.size());
844 for (
auto& device : nidaq_devices) {
845 devices.push_back(&device);
852 Driver* instance =
nullptr;
857 if (instance ==
nullptr) {
DAQ::index_t getAnalogOffsetUnits(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
int setAnalogRange(DAQ::ChannelType::type_t type, DAQ::index_t index, DAQ::index_t range) final
Device(const Device &)=default
Device & operator=(const Device &)=delete
DAQ::index_t getAnalogUnits(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
double getAnalogGain(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
std::string getAnalogUnitsString(DAQ::ChannelType::type_t type, DAQ::index_t index, DAQ::index_t units) const final
size_t getChannelCount(DAQ::ChannelType::type_t type) const final
bool getAnalogCalibrationActive(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
size_t getAnalogDownsample(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
int setAnalogCalibrationActive(DAQ::ChannelType::type_t type, DAQ::index_t index, bool state) final
bool getAnalogCalibrationState(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
int setAnalogZeroOffset(DAQ::ChannelType::type_t type, DAQ::index_t index, double offset) final
size_t getAnalogReferenceCount(DAQ::index_t index) const final
double getAnalogCalibrationValue(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
int setChannelActive(DAQ::ChannelType::type_t type, DAQ::index_t index, bool state) final
int setDigitalDirection(DAQ::index_t index, DAQ::direction_t direction) final
int setAnalogDownsample(DAQ::ChannelType::type_t type, DAQ::index_t index, size_t downsample) final
int setAnalogGain(DAQ::ChannelType::type_t type, DAQ::index_t index, double gain) final
int setAnalogCounter(DAQ::ChannelType::type_t type, DAQ::index_t index) final
std::string getAnalogReferenceString(DAQ::ChannelType::type_t type, DAQ::index_t index, DAQ::index_t reference) const final
Device & operator=(Device &&)=delete
int setAnalogCalibrationValue(DAQ::ChannelType::type_t type, DAQ::index_t index, double value) final
int setAnalogReference(DAQ::ChannelType::type_t type, DAQ::index_t index, DAQ::index_t reference) final
double getAnalogZeroOffset(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
size_t getAnalogRangeCount(DAQ::index_t index) const final
size_t getAnalogUnitsCount(DAQ::index_t index) const final
DAQ::index_t getAnalogReference(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
bool getChannelActive(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
int setAnalogUnits(DAQ::ChannelType::type_t type, DAQ::index_t index, DAQ::index_t units) final
DAQ::index_t getAnalogRange(DAQ::ChannelType::type_t type, DAQ::index_t index) const final
std::string getAnalogRangeString(DAQ::ChannelType::type_t type, DAQ::index_t index, DAQ::index_t range) const final
int setAnalogOffsetUnits(DAQ::ChannelType::type_t type, DAQ::index_t index, DAQ::index_t units) final
void unloadDevices() final
std::vector< DAQ::Device * > getDevices() final
static DAQ::Driver * getInstance()
double & readinput(size_t index)
void writeoutput(size_t index, const double &data)
void ERROR_MSG(const std::string &errmsg, Args... args)
std::string type2string(type_t type)
std::array< std::string, 2 > get_default_units()
std::array< analog_range_t, 7 > get_default_ranges()
void printError(int32_t status)
const std::string_view DEFAULT_DRIVER_NAME
DAQ::Driver * getRTXIDAQDriver()
void deleteRTXIDAQDriver()
std::string physical_card_name(const std::string &device_name)
std::vector< std::string > split_string(const std::string &buffer, const std::string &delim)
std::vector< std::string > physical_channel_names(const std::string &device, DAQ::ChannelType::type_t chan_type)
int32_t addToTask(TaskHandle task_handle) const
DAQ::ChannelType::type_t type
physical_channel_t(std::string chan_name, DAQ::ChannelType::type_t chan_type, size_t chan_id)