mirror of
https://github.com/fairwaves/UHD-Fairwaves.git
synced 2025-11-02 13:03:13 +00:00
Merge branch 'status_monitor'
Implements a TCP server inside UHD which gives access to a device's property tree through a JSON API.
This commit is contained in:
@@ -39,6 +39,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
########################################################################
|
||||
list(APPEND UMTRX_SOURCES
|
||||
umtrx_impl.cpp
|
||||
umtrx_monitor.cpp
|
||||
umtrx_io_impl.cpp
|
||||
umtrx_find.cpp
|
||||
umtrx_iface.cpp
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/math/special_functions/round.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <utility>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
@@ -154,11 +155,13 @@ public:
|
||||
|
||||
uhd::sensor_value_t get_rx_pll_locked()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
return uhd::sensor_value_t("LO", lms.get_rx_pll_locked(), "locked", "unlocked");
|
||||
}
|
||||
|
||||
uhd::sensor_value_t get_tx_pll_locked()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
return uhd::sensor_value_t("LO", lms.get_tx_pll_locked(), "locked", "unlocked");
|
||||
}
|
||||
|
||||
@@ -214,17 +217,20 @@ public:
|
||||
|
||||
uint8_t get_tx_vga1dc_i_int(void)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
return lms.get_tx_vga1dc_i_int();
|
||||
}
|
||||
|
||||
uint8_t get_tx_vga1dc_q_int(void)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
return lms.get_tx_vga1dc_i_int();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
double set_freq(dboard_iface::unit_t unit, double f) {
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
if (verbosity>0) printf("lms6002d_ctrl_impl::set_freq(%f)\n", f);
|
||||
unsigned ref_freq = _clock_rate;
|
||||
double actual_freq = 0;
|
||||
@@ -254,6 +260,7 @@ protected:
|
||||
}
|
||||
|
||||
bool set_enabled(dboard_iface::unit_t unit, bool en) {
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
if (verbosity>0) printf("lms6002d_ctrl_impl::set_enabled(%d)\n", en);
|
||||
if (unit==dboard_iface::UNIT_RX) {
|
||||
if (en)
|
||||
@@ -271,6 +278,7 @@ protected:
|
||||
}
|
||||
|
||||
double set_rx_gain(double gain, const std::string &name) {
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
if (verbosity>0) printf("lms6002d_ctrl_impl::set_rx_gain(%f, %s)\n", gain, name.c_str());
|
||||
assert_has(lms_rx_gain_ranges.keys(), name, "LMS6002D rx gain name");
|
||||
if(name == "VGA1"){
|
||||
@@ -284,6 +292,7 @@ protected:
|
||||
}
|
||||
|
||||
void set_rx_ant(const std::string &ant) {
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
if (verbosity>0) printf("lms6002d_ctrl_impl::set_rx_ant(%s)\n", ant.c_str());
|
||||
//validate input
|
||||
assert_has(lms_rx_antennas, ant, "LMS6002D rx antenna name");
|
||||
@@ -317,6 +326,7 @@ protected:
|
||||
}
|
||||
|
||||
double set_rx_bandwidth(double bandwidth) {
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
if (verbosity>0) printf("lms6002d_ctrl_impl::set_rx_bandwidth(%f)\n", bandwidth);
|
||||
// Get the closest available bandwidth
|
||||
bandwidth = lms_bandwidth_range.clip(bandwidth);
|
||||
@@ -328,6 +338,7 @@ protected:
|
||||
}
|
||||
|
||||
double set_tx_gain(double gain, const std::string &name) {
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_gain(%f, %s)\n", gain, name.c_str());
|
||||
//validate input
|
||||
assert_has(lms_tx_gain_ranges.keys(), name, "LMS6002D tx gain name");
|
||||
@@ -349,6 +360,7 @@ protected:
|
||||
}
|
||||
|
||||
void set_tx_ant(const std::string &ant) {
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_ant(%s)\n", ant.c_str());
|
||||
//validate input
|
||||
assert_has(lms_tx_antennas, ant, "LMS6002D tx antenna ant");
|
||||
@@ -368,6 +380,7 @@ protected:
|
||||
}
|
||||
|
||||
double set_tx_bandwidth(double bandwidth) {
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_bandwidth(%f)\n", bandwidth);
|
||||
// Get the closest available bandwidth
|
||||
bandwidth = lms_bandwidth_range.clip(bandwidth);
|
||||
@@ -379,12 +392,14 @@ protected:
|
||||
}
|
||||
|
||||
uint8_t _set_tx_vga1dc_i_int(uint8_t offset) {
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_vga1dc_i_int(%d)\n", offset);
|
||||
lms.set_tx_vga1dc_i_int(offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
uint8_t _set_tx_vga1dc_q_int(uint8_t offset) {
|
||||
boost::recursive_mutex::scoped_lock l(_mutex);
|
||||
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_vga1dc_q_int(%d)\n", offset);
|
||||
lms.set_tx_vga1dc_q_int(offset);
|
||||
return offset;
|
||||
@@ -402,6 +417,8 @@ private:
|
||||
const int _lms_spi_number;
|
||||
const int _adf4350_spi_number;
|
||||
const double _clock_rate;
|
||||
|
||||
boost::recursive_mutex _mutex;
|
||||
};
|
||||
|
||||
lms6002d_ctrl::sptr lms6002d_ctrl::make(uhd::spi_iface::sptr spiface, const int lms_spi_number, const int adf4350_spi_number, const double clock_rate)
|
||||
|
||||
@@ -690,10 +690,15 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
|
||||
|
||||
_tree->access<std::string>(mb_path / "clock_source" / "value").set("internal");
|
||||
_tree->access<std::string>(mb_path / "time_source" / "value").set("none");
|
||||
|
||||
//create status monitor and client handler
|
||||
this->status_monitor_start(device_addr);
|
||||
}
|
||||
|
||||
umtrx_impl::~umtrx_impl(void)
|
||||
{
|
||||
this->status_monitor_stop();
|
||||
|
||||
BOOST_FOREACH(const std::string &fe_name, _lms_ctrl.keys())
|
||||
{
|
||||
lms6002d_ctrl::sptr ctrl = _lms_ctrl[fe_name];
|
||||
@@ -718,6 +723,7 @@ int umtrx_impl::volt_to_dcdc_r(double v)
|
||||
|
||||
void umtrx_impl::set_pa_dcdc_r(uint8_t val)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
|
||||
// AD5245 control
|
||||
if (_hw_rev >= UMTRX_VER_2_3_1)
|
||||
{
|
||||
@@ -775,6 +781,7 @@ double umtrx_impl::set_tx_power(double power, const std::string &which)
|
||||
|
||||
double umtrx_impl::set_pa_power(double power, const std::string &which)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
|
||||
// TODO:: Use DCDC bypass for maximum output power
|
||||
// TODO:: Limit output power for UmSITE-TM3
|
||||
|
||||
@@ -802,6 +809,7 @@ double umtrx_impl::set_pa_power(double power, const std::string &which)
|
||||
|
||||
void umtrx_impl::set_mb_eeprom(const uhd::i2c_iface::sptr &iface, const uhd::usrp::mboard_eeprom_t &eeprom)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
|
||||
store_umtrx_eeprom(eeprom, *iface);
|
||||
}
|
||||
|
||||
@@ -866,6 +874,7 @@ uint8_t umtrx_impl::dc_offset_double2int(double corr)
|
||||
|
||||
uhd::sensor_value_t umtrx_impl::read_temp_c(const std::string &which)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
|
||||
double temp = (which == "A") ? _temp_side_a.get_temp() :
|
||||
_temp_side_b.get_temp();
|
||||
return uhd::sensor_value_t("Temp"+which, temp, "C");
|
||||
@@ -873,6 +882,7 @@ uhd::sensor_value_t umtrx_impl::read_temp_c(const std::string &which)
|
||||
|
||||
uhd::sensor_value_t umtrx_impl::read_pa_v(const std::string &which)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
|
||||
unsigned i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (which == power_sensors[i])
|
||||
@@ -888,6 +898,7 @@ uhd::sensor_value_t umtrx_impl::read_pa_v(const std::string &which)
|
||||
|
||||
uhd::sensor_value_t umtrx_impl::read_dc_v(const std::string &which)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
|
||||
unsigned i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (which == dc_sensors[i])
|
||||
@@ -1051,4 +1062,3 @@ const char* umtrx_impl::get_hw_rev() const
|
||||
default: return "[unknown]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
#include <uhd/transport/udp_simple.hpp>
|
||||
#include <uhd/transport/udp_zero_copy.hpp>
|
||||
#include <uhd/transport/bounded_buffer.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <uhd/types/ranges.hpp>
|
||||
#include <uhd/exception.hpp>
|
||||
#include <uhd/utils/static.hpp>
|
||||
@@ -58,6 +60,7 @@
|
||||
#include <boost/weak_ptr.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <uhd/utils/tasks.hpp>
|
||||
|
||||
|
||||
// Halfthe size of USRP2 SRAM, because we split the same SRAM into buffers for two Tx channels instead of one.
|
||||
@@ -200,6 +203,21 @@ private:
|
||||
uhd::sensor_value_t read_temp_c(const std::string &which);
|
||||
uhd::sensor_value_t read_pa_v(const std::string &which);
|
||||
uhd::sensor_value_t read_dc_v(const std::string &which);
|
||||
boost::recursive_mutex _i2c_mutex;
|
||||
|
||||
//status monitoring
|
||||
void status_monitor_start(const uhd::device_addr_t &device_addr);
|
||||
void status_monitor_stop(void);
|
||||
uhd::task::sptr _status_monitor_task;
|
||||
void status_monitor_handler(void);
|
||||
|
||||
//tcp query server
|
||||
uhd::task::sptr _server_query_task;
|
||||
void server_query_handler(void);
|
||||
boost::asio::io_service _server_query_io_service;
|
||||
boost::shared_ptr<boost::asio::ip::tcp::acceptor> _server_query_tcp_acceptor;
|
||||
void client_query_handle(boost::shared_ptr<boost::asio::ip::tcp::socket>);
|
||||
void client_query_handle1(const boost::property_tree::ptree &request, boost::property_tree::ptree &response);
|
||||
|
||||
//streaming
|
||||
std::vector<boost::weak_ptr<uhd::rx_streamer> > _rx_streamers;
|
||||
|
||||
246
host/umtrx_monitor.cpp
Normal file
246
host/umtrx_monitor.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
//
|
||||
// Copyright 2015-2015 Fairwaves LLC
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#include "umtrx_impl.hpp"
|
||||
#include <uhd/utils/msg.hpp>
|
||||
#include <uhd/types/sensors.hpp>
|
||||
#include <uhd/types/ranges.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
using namespace uhd;
|
||||
using namespace uhd::usrp;
|
||||
namespace asio = boost::asio;
|
||||
|
||||
/*!
|
||||
* Querying sensors using the status monitor server.
|
||||
* Requests are encoded in JSON and end in a newline.
|
||||
* Responses are encoded in JSON and end in a newline.
|
||||
*
|
||||
* Start UmTRX driver with status_port set in args
|
||||
* ./some_application --args="status_port=12345"
|
||||
*
|
||||
* import json
|
||||
* import socket
|
||||
* s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
* s.connect(("localhost", 12345))
|
||||
* f = s.makefile() #gives us readline()
|
||||
*
|
||||
* #list branches in the property tree
|
||||
* s.send(json.dumps(dict(action='LIST', path='/mboards/0/sensors'))+'\n')
|
||||
* print json.loads(f.readline())
|
||||
* {u'result': [u'tempA']}
|
||||
*
|
||||
* #check if the specified path exists
|
||||
* s.send(json.dumps(dict(action='HAS', path='/mboards/0/sensors/tempA'))+'\n')
|
||||
* print json.loads(f.readline())
|
||||
* {u'result': u'true'}
|
||||
*
|
||||
* #get the value of a tree entry, types can be BOOL, INT, DOUBLE, SENSOR, RANGE
|
||||
* s.send(json.dumps(dict(action='GET', path='/mboards/0/sensors/tempA', type='SENSOR'))+'\n')
|
||||
* print json.loads(f.readline())
|
||||
* {u'result': {u'unit': u'C', u'name': u'TempA', u'value': u'61.625000'}}
|
||||
*
|
||||
* #set the value of a tree entry, types can be BOOL, INT, DOUBLE
|
||||
* s.send(json.dumps(dict(action='SET', path='/mboards/0/dboards/A/rx_frontends/0/freq/value', type='DOUBLE', value=1e9))+'\n')
|
||||
* print json.loads(f.readline())
|
||||
* {} #empty response means no error
|
||||
*/
|
||||
|
||||
void umtrx_impl::status_monitor_start(const uhd::device_addr_t &device_addr)
|
||||
{
|
||||
if (device_addr.has_key("status_port"))
|
||||
{
|
||||
UHD_MSG(status) << "Creating TCP monitor on port " << device_addr.get("status_port") << std::endl;
|
||||
_server_query_tcp_acceptor.reset(new asio::ip::tcp::acceptor(
|
||||
_server_query_io_service, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), device_addr.cast<int>("status_port", 0))));
|
||||
_server_query_task = task::make(boost::bind(&umtrx_impl::server_query_handler, this));
|
||||
}
|
||||
_status_monitor_task = task::make(boost::bind(&umtrx_impl::status_monitor_handler, this));
|
||||
}
|
||||
|
||||
void umtrx_impl::status_monitor_stop(void)
|
||||
{
|
||||
_status_monitor_task.reset();
|
||||
_server_query_task.reset();
|
||||
}
|
||||
|
||||
static bool wait_read_sockfd(const int sockfd, const size_t timeoutMs)
|
||||
{
|
||||
//setup timeval for timeout
|
||||
timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = timeoutMs*1000;
|
||||
|
||||
//setup rset for timeout
|
||||
fd_set rset;
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(sockfd, &rset);
|
||||
|
||||
//call select with timeout on receive socket
|
||||
return ::select(sockfd+1, &rset, NULL, NULL, &tv) > 0;
|
||||
}
|
||||
|
||||
void umtrx_impl::status_monitor_handler(void)
|
||||
{
|
||||
//TODO read the sensors and react...
|
||||
//read_dc_v, etc...
|
||||
//UHD_MSG(status) << this->read_temp_c("A").to_pp_string() << std::endl;
|
||||
|
||||
//TODO shutdown frontend when temp > thresh
|
||||
//ctrl->set_rx_enabled(false);
|
||||
//ctrl->set_tx_enabled(false);
|
||||
|
||||
//this sleep defines the polling time between status checks
|
||||
//when the handler completes, it will be called again asap
|
||||
//if the task is canceled, this sleep in interrupted for exit
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(1500));
|
||||
}
|
||||
|
||||
void umtrx_impl::server_query_handler(void)
|
||||
{
|
||||
//accept the client socket (timeout is 100 ms, task is called again)
|
||||
if (not wait_read_sockfd(_server_query_tcp_acceptor->native(), 100)) return;
|
||||
boost::shared_ptr<asio::ip::tcp::socket> socket(new asio::ip::tcp::socket(_server_query_io_service));
|
||||
_server_query_tcp_acceptor->accept(*socket);
|
||||
|
||||
//create a new thread to handle the client
|
||||
boost::thread handler(boost::bind(&umtrx_impl::client_query_handle, this, socket));
|
||||
handler.detach();
|
||||
}
|
||||
|
||||
void umtrx_impl::client_query_handle(boost::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||
{
|
||||
while (not boost::this_thread::interruption_requested())
|
||||
{
|
||||
boost::property_tree::ptree request, response;
|
||||
|
||||
//receive the request in JSON markup
|
||||
boost::asio::streambuf requestBuff;
|
||||
try
|
||||
{
|
||||
boost::asio::read_until(*socket, requestBuff, "\n");
|
||||
std::istream is(&requestBuff);
|
||||
boost::property_tree::read_json(is, request);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
if (requestBuff.size() == 0) return; //client ended
|
||||
response.put("error", "request parser error: " + std::string(ex.what()));
|
||||
}
|
||||
|
||||
//handle the request
|
||||
try
|
||||
{
|
||||
this->client_query_handle1(request, response);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
response.put("error", "failed to handle request: " + std::string(ex.what()));
|
||||
}
|
||||
|
||||
//send the response
|
||||
boost::asio::streambuf responseBuff;
|
||||
std::ostream os(&responseBuff);
|
||||
try
|
||||
{
|
||||
boost::property_tree::write_json(os, response, false/*not pretty required*/);
|
||||
boost::asio::write(*socket, responseBuff);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UHD_MSG(error) << "client_query_handle send response failed, exit client thread: " << ex.what() << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void umtrx_impl::client_query_handle1(const boost::property_tree::ptree &request, boost::property_tree::ptree &response)
|
||||
{
|
||||
const std::string action = request.get("action", "");
|
||||
const std::string path = request.get("path", "");
|
||||
if (response.count("error") != 0)
|
||||
{
|
||||
//already in error
|
||||
}
|
||||
else if (path.empty())
|
||||
{
|
||||
response.put("error", "path field not specified");
|
||||
}
|
||||
else if (action.empty())
|
||||
{
|
||||
response.put("error", "action field not specified: GET, SET, HAS, LIST");
|
||||
}
|
||||
else if (action == "GET")
|
||||
{
|
||||
const std::string type = request.get("type", "");
|
||||
if (type.empty()) response.put("error", "type field not specified: BOOL, INT, DOUBLE, SENSOR, RANGE");
|
||||
else if (type == "BOOL") response.put("result", _tree->access<bool>(path).get());
|
||||
else if (type == "INT") response.put("result", _tree->access<int>(path).get());
|
||||
else if (type == "DOUBLE") response.put("result", _tree->access<double>(path).get());
|
||||
else if (type == "SENSOR")
|
||||
{
|
||||
boost::property_tree::ptree result;
|
||||
const sensor_value_t sensor = _tree->access<sensor_value_t>(path).get();
|
||||
result.put("name", sensor.name);
|
||||
result.put("value", sensor.value);
|
||||
result.put("unit", sensor.unit);
|
||||
response.add_child("result", result);
|
||||
}
|
||||
else if (type == "RANGE")
|
||||
{
|
||||
boost::property_tree::ptree result;
|
||||
BOOST_FOREACH(const range_t &range, _tree->access<meta_range_t>(path).get())
|
||||
{
|
||||
boost::property_tree::ptree rangeData;
|
||||
rangeData.put("start", range.start());
|
||||
rangeData.put("stop", range.stop());
|
||||
rangeData.put("step", range.step());
|
||||
result.push_back(std::make_pair("", rangeData));
|
||||
}
|
||||
response.add_child("result", result);
|
||||
}
|
||||
else response.put("error", "unknown type: " + type);
|
||||
}
|
||||
else if (action == "SET")
|
||||
{
|
||||
const std::string type = request.get("type", "");
|
||||
if (type.empty()) response.put("error", "type field not specified: BOOL, INT, DOUBLE");
|
||||
else if (type == "BOOL") _tree->access<bool>(path).set(request.get<bool>("value"));
|
||||
else if (type == "INT") _tree->access<int>(path).set(request.get<bool>("value"));
|
||||
else if (type == "DOUBLE") _tree->access<double>(path).set(request.get<bool>("value"));
|
||||
else response.put("error", "unknown type: " + type);
|
||||
}
|
||||
else if (action == "HAS")
|
||||
{
|
||||
response.put("result", _tree->exists(path));
|
||||
}
|
||||
else if (action == "LIST")
|
||||
{
|
||||
boost::property_tree::ptree result;
|
||||
BOOST_FOREACH(const std::string &branchName, _tree->list(path))
|
||||
{
|
||||
boost::property_tree::ptree branchData;
|
||||
branchData.put("", branchName);
|
||||
result.push_back(std::make_pair("", branchData));
|
||||
}
|
||||
response.add_child("result", result);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.put("error", "unknown action: " + action);
|
||||
}
|
||||
}
|
||||
112
host/utils/umtrx_property_tree.py
Normal file
112
host/utils/umtrx_property_tree.py
Normal file
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##########################
|
||||
### Property tree API
|
||||
##########################
|
||||
|
||||
import socket
|
||||
import json
|
||||
|
||||
class umtrx_property_tree:
|
||||
|
||||
def connect(self, host="localhost", port=12345):
|
||||
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.s.connect((host, port))
|
||||
self.f = self.s.makefile()
|
||||
|
||||
def close(self):
|
||||
self.s.close()
|
||||
|
||||
#
|
||||
# Helper methods
|
||||
#
|
||||
|
||||
def _send_request(self, action, path, value_type=None, value=None):
|
||||
d = dict(action=action, path=path)
|
||||
if value_type is not None: d['type'] = value_type
|
||||
if value is not None: d['value'] = value
|
||||
return self.s.send(json.dumps(d)+'\n')
|
||||
|
||||
def _recv_response(self):
|
||||
resp = self.f.readline().strip()
|
||||
if len(resp)>0:
|
||||
return json.loads(resp)
|
||||
else:
|
||||
return None
|
||||
|
||||
#
|
||||
# Getters (raw)
|
||||
#
|
||||
|
||||
def query_bool_raw(self, path):
|
||||
self._send_request('GET', path, value_type='BOOL')
|
||||
return self._recv_response()
|
||||
|
||||
def query_int_raw(self, path):
|
||||
self._send_request('GET', path, value_type='INT')
|
||||
return self._recv_response()
|
||||
|
||||
def query_double_raw(self, path):
|
||||
self._send_request('GET', path, value_type='DOUBLE')
|
||||
return self._recv_response()
|
||||
|
||||
def query_sensor_raw(self, sensor_path):
|
||||
self._send_request('GET', sensor_path, value_type='SENSOR')
|
||||
return self._recv_response()
|
||||
|
||||
def query_range_raw(self, path):
|
||||
self._send_request('GET', path, value_type='RANGE')
|
||||
return self._recv_response()
|
||||
|
||||
#
|
||||
# Getters (value)
|
||||
#
|
||||
|
||||
def query_bool_value(self, path):
|
||||
res = self.query_bool_raw(sensor_path)
|
||||
return res['result']['value']
|
||||
|
||||
def query_int_value(self, path):
|
||||
res = self.query_int_raw(sensor_path)
|
||||
return res['result']['value']
|
||||
|
||||
def query_double_value(self, path):
|
||||
res = self.query_double_raw(sensor_path)
|
||||
return res['result']['value']
|
||||
|
||||
def query_sensor_value(self, sensor_path):
|
||||
res = self.query_sensor_raw(sensor_path)
|
||||
return res['result']['value']
|
||||
|
||||
def query_range_value(self, path):
|
||||
res = self.query_range_raw(sensor_path)
|
||||
return res['result']['value']
|
||||
|
||||
#
|
||||
# Setters
|
||||
#
|
||||
|
||||
def set_bool(self, path, val):
|
||||
self._send_request('SET', path, value_type='BOOL', value=val)
|
||||
return self._recv_response()
|
||||
|
||||
def set_int(self, path, val):
|
||||
self._send_request('SET', path, value_type='INT', value=val)
|
||||
return self._recv_response()
|
||||
|
||||
def set_double(self, path, val):
|
||||
self._send_request('SET', path, value_type='DOUBLE', value=val)
|
||||
return self._recv_response()
|
||||
|
||||
#
|
||||
# Check path presence and list paths
|
||||
#
|
||||
|
||||
def has_path_raw(self, path):
|
||||
self._send_request('HAS', path)
|
||||
return self._recv_response()
|
||||
|
||||
def list_path_raw(self, path):
|
||||
self._send_request('LIST', path)
|
||||
return self._recv_response()
|
||||
54
host/utils/umtrx_query_sensors.py
Executable file
54
host/utils/umtrx_query_sensors.py
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##########################
|
||||
### VSWR calculations
|
||||
##########################
|
||||
|
||||
# Implemented as described at:
|
||||
# http://www.markimicrowave.com/assets/data/return%20loss%20to%20vswr.pdf
|
||||
|
||||
import math
|
||||
|
||||
TM10_VSWR_cal=0.3
|
||||
|
||||
def vswr_volts_to_db(VPF, VPR, calibration=0, coef=0.05):
|
||||
return (VPF-VPR-calibration)/coef
|
||||
|
||||
def db_to_vswr(db):
|
||||
gamma = math.pow(10, -db/20.0)
|
||||
return (1+gamma)/(1-gamma)
|
||||
|
||||
|
||||
##########################
|
||||
### Query sensors
|
||||
##########################
|
||||
|
||||
from umtrx_property_tree import umtrx_property_tree
|
||||
|
||||
s = umtrx_property_tree()
|
||||
s.connect()
|
||||
|
||||
sensors_path="/mboards/0/sensors"
|
||||
res = s.list_path_raw(sensors_path)
|
||||
sensors_list = res.get('result', [])
|
||||
|
||||
for sensor in sensors_list:
|
||||
print s.query_sensor_raw(sensors_path+"/"+sensor)
|
||||
|
||||
#vswr_calibration = TM10_VSWR_cal
|
||||
vswr_calibration = 0
|
||||
for num in [1, 2]:
|
||||
vpr_name = 'voltagePR'+str(num)
|
||||
vpf_name = 'voltagePF'+str(num)
|
||||
if vpr_name in sensors_list and vpf_name in sensors_list:
|
||||
vpr = float(s.query_sensor_value(sensors_path+'/'+vpr_name))
|
||||
vpf = float(s.query_sensor_value(sensors_path+'/'+vpf_name))
|
||||
vswr_db = vswr_volts_to_db(vpf, vpr, vswr_calibration)
|
||||
if vswr_db == 0.0:
|
||||
vswr = float("inf")
|
||||
else:
|
||||
vswr = db_to_vswr(vswr_db)
|
||||
print "Channel %d VSWR = %.2f = %.1f dB" % (num, vswr, vswr_db)
|
||||
|
||||
s.close()
|
||||
Reference in New Issue
Block a user