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)