diff --git a/PlutoSDR_Settings.cpp b/PlutoSDR_Settings.cpp index 7a4da0e..c81d766 100644 --- a/PlutoSDR_Settings.cpp +++ b/PlutoSDR_Settings.cpp @@ -118,6 +118,172 @@ bool SoapyPlutoSDR::getFullDuplex( const int direction, const size_t channel ) c return(true); } + +/******************************************************************* + * Sensor API + ******************************************************************/ + +bool SoapyPlutoSDR::is_sensor_channel(struct iio_channel *chn) const +{ + return (!iio_channel_is_output(chn) && + (iio_channel_find_attr(chn, "raw") || + iio_channel_find_attr(chn, "input"))); +} + +double SoapyPlutoSDR::get_sensor_value(struct iio_channel *chn) const +{ + char *old_locale; + char buf[32]; + double val = 0.0; + + old_locale = strdup(setlocale(LC_NUMERIC, NULL)); + setlocale(LC_NUMERIC, "C"); + + if (iio_channel_find_attr(chn, "input")) { + if (iio_channel_attr_read(chn, "input", buf, sizeof(buf)) > 0) + val = strtod(buf, NULL); + } else { + if (iio_channel_attr_read(chn, "raw", buf, sizeof(buf)) > 0) + val = strtod(buf, NULL); + + if (iio_channel_find_attr(chn, "offset")) { + if (iio_channel_attr_read(chn, "offset", buf, sizeof(buf)) > 0) + val += strtod(buf, NULL); + } + + if (iio_channel_find_attr(chn, "scale")) { + if (iio_channel_attr_read(chn, "scale", buf, sizeof(buf)) > 0) + val *= strtod(buf, NULL); + } + } + + setlocale(LC_NUMERIC, old_locale); + free(old_locale); + + return val / 1000.0; +} + +const char *SoapyPlutoSDR::id_to_unit(const char *id) const +{ + static struct { + const char *id; + const char *unit; + } map[] = { + { "current", "A" }, + { "power", "W" }, + { "temp", "C" }, + { "voltage", "V" }, + { 0, }, + }; + + unsigned int i; + + for (i = 0; map[i].id; ++i) { + if (!strncmp(id, map[i].id, strlen(map[i].id))) + return map[i].unit; + } + + return ""; +} + +std::vector SoapyPlutoSDR::listSensors(void) const +{ + /* + iio:device2: xadc + 10 channels found: + temp0: (input) + voltage0: vccint (input) + voltage1: vccaux (input) + voltage2: vccbram (input) + voltage3: vccpint (input) + voltage4: vccpaux (input) + voltage5: vccoddr (input) + voltage6: vrefp (input) + voltage7: vrefn (input) + voltage8: (input) + iio:device0: adm1177 + 2 channels found: + current0: (input) + voltage0: (input) + iio:device1: ad9361-phy + 9 channels found: + temp0: (input) + voltage2: (input) + */ + std::vector sensors; + + sensors.push_back("xadc_temp0"); + sensors.push_back("xadc_voltage0"); + sensors.push_back("xadc_voltage1"); + sensors.push_back("xadc_voltage2"); + sensors.push_back("xadc_voltage3"); + sensors.push_back("xadc_voltage4"); + sensors.push_back("xadc_voltage5"); + sensors.push_back("xadc_voltage6"); + sensors.push_back("xadc_voltage7"); + sensors.push_back("xadc_voltage8"); + sensors.push_back("adm1177_current0"); + sensors.push_back("adm1177_voltage0"); + sensors.push_back("ad9361-phy_temp0"); + sensors.push_back("ad9361-phy_voltage2"); + + return sensors; +} + +SoapySDR::ArgInfo SoapyPlutoSDR::getSensorInfo(const std::string &key) const +{ + SoapySDR::ArgInfo info; + + std::size_t dash = key.find("_"); + if (dash < std::string::npos) + { + std::string deviceStr = key.substr(0, dash); + std::string channelStr = key.substr(dash + 1); + + iio_device *dev = iio_context_find_device(ctx, deviceStr.c_str()); + if (!dev) + return info; + iio_channel *chn = iio_device_find_channel(dev, channelStr.c_str(), false); + if (!chn) + return info; + + const char *name = iio_channel_get_name(chn); + info.key = key; + if (name) + info.name = name; + info.type = SoapySDR::ArgInfo::FLOAT; + info.value = "0.0"; + info.units = id_to_unit(channelStr.c_str()); + } + + return info; +} + +std::string SoapyPlutoSDR::readSensor(const std::string &key) const +{ + std::string sensorValue; + + std::size_t dash = key.find("_"); + if (dash < std::string::npos) + { + std::string deviceStr = key.substr(0, dash); + std::string channelStr = key.substr(dash + 1); + + iio_device *dev = iio_context_find_device(ctx, deviceStr.c_str()); + if (!dev) + return sensorValue; + iio_channel *chn = iio_device_find_channel(dev, channelStr.c_str(), false); + if (!chn) + return sensorValue; + + double value = get_sensor_value(chn); + sensorValue.assign(std::to_string(value)); + } + + return sensorValue; +} + + /******************************************************************* * Settings API ******************************************************************/ diff --git a/SoapyPlutoSDR.hpp b/SoapyPlutoSDR.hpp index 7f27b39..e412ad2 100644 --- a/SoapyPlutoSDR.hpp +++ b/SoapyPlutoSDR.hpp @@ -184,6 +184,17 @@ class SoapyPlutoSDR : public SoapySDR::Device{ ); + /******************************************************************* + * Sensor API + ******************************************************************/ + + std::vector listSensors(void) const; + + SoapySDR::ArgInfo getSensorInfo(const std::string &key) const; + + std::string readSensor(const std::string &key) const; + + /******************************************************************* * Settings API ******************************************************************/ @@ -292,6 +303,10 @@ class SoapyPlutoSDR : public SoapySDR::Device{ bool IsValidRxStreamHandle(SoapySDR::Stream* handle) const; bool IsValidTxStreamHandle(SoapySDR::Stream* handle); + bool is_sensor_channel(struct iio_channel *chn) const; + double get_sensor_value(struct iio_channel *chn) const; + const char *id_to_unit(const char *id) const; + iio_device *dev; iio_device *rx_dev; iio_device *tx_dev;