BayLibre Power-Cape

This page contains basic documentation for the BayLibre Power-Cape software suite.

Please note, that the project itself is still work-in-progress and the software suite should be treated as a Proof-of-Concept.

Building

Power-Cape software suite has been written with Linux in mind and has not been tested on different systems yet. Besides glibc6 it's linked against the following external libraries: libwebsockets, libconfig, Qt5 and Qwt6 (the last two are required only for the Qt UI).

You can find the exact instructions on how to build provided programs in the README.building file in the project's main directory.

Running

Daemon

The main component of the software suite is the daemon which runs on the same platform on which the probes are installed and talks to the drivers via sysfs. It exports the data via websocket protocol so that it's suitable both for native UIs as well as for web-browsers.

The daemon can also receive data and instruct probes to cut or restore power to they connected devices.

After having built the daemon, the executable (together with libwebsocket and libconfig) should be installed on the measurement board. The whole /pages directory of the project should be copied to the board as well if you want to provide the Web UI.

The default path to the config file is /etc/pwcd/config.cfg. You can override this by passing the -c option to the daemon.

The default path to the web directory (where the contents of /pages are installed) is /var/pwcd/www. You can override this setting by passing the -w option to the daemon. The specified path has to be an absolute path for security reasons.

The daemon can be ordered to daemonize itself when passed the -d option.

Configuration

The daemon uses a simple structured configuration file as specified by libconfig. See this link for an example. In general please refer to libconfig documentation.

The basic structure of the configuration file is as follows:

  # Top level of the configuration.
  application:
  {
      # Array of capes.
      power_capes = (
      {
          # Name of the power cape.
          name = "example_cape_0";
          # Array of all the probes of the single cape.
          probes = (
          {
              # Name of the probe
              name = "probe_0";
              # Defines a path to the power-switch GPIO.
              # If not present, then the probe is not equipped
              # with a power-switch.
              power_switch = "/sys/class/gpio/gpio123";
              # Array of the measurements available for this probe.
              measurements = (
              {
                  # Arbitrary name of this measurement.
                  name = "Power";
                  # Type of the measurement - can be:
                  #     P - power,
                  #     C - current,
                  #     V - voltage,
                  #     T - temperature.
                  type = "P";
                  # Path to the sysfs file from which the values
                  # should be read.
                  path = "/sys/class/hwmon/hwmon0/power1_input";
                  # Units for the presentation layer. Can be:
                  #     W - Watt,
                  #     V - Volts,
                  #     A - Amper,
                  #     C - Celsius.
                  unit = "W";
              }, {
                  # Second example measurement.
                  name = "Voltage";
                  type = "V";
                  path = "/sys/class/hwmon/hwmon0/in1_input";
                  unit = "V";
              });
          }, {
              # Second example probe.
              name = "probe_1";
              measurements = (
              {
                  name = "Temperature";
                  type = "T";
                  path = "/sys/class/hwmon/hwmon1/temp1_input";
                  unit = "C";
              });
          });
      });
  }

Web UI

The Web UI is accessible via web browsers (by default on port 12351, but this can be overriden by -p option in the daemon). It's a simple page, which connects to the daemon via a websocket and starts to draw the plots as soon as it starts receiving the data from the server.

Each chart can be hidden and each separate plot curve can be disabled. Power-switch buttons are displayed for these probes which are equipped with one.

Qt UI

Building the Qt UI is described in detail in README.building.

Upon starting the program displays an empty chart and some text fields allowing to connect to the server at given address and port. Clicking the 'connect' button causes the program to connect to the server via websocket procotol. From this point it works exactly like the browser UI except that all the plots are displayed in a single chart.

Each probe can be hidden and restored with the checkboxes below and clicking separate measurements on the right can hide single plots as well. Power buttons are available for probes equipped with one.

There's a slider in the lower left corner of the UI which allows to dynamically change the width of the plot lines. It's useful when the plot lines are not distinct enough.

LCD display

The LCD display code is not finished as of yet.

Ncurses display

Idem.

Data exchange protocol

The protocol used now is not the final version. During the implementation several issues have been found and it will be redesigned. That's why it's not described here in detail.

For information on the websocket protocol please refer to RFC.

In general:

  • the server exposes two websocket subprotocols: http-only and power-measure-protocol,
  • the http-only protocol is there to serve the static Web UI data (html and javascript),
  • the power-measure-protocol exposes the actual measurement data,
  • upon connection via power-measure-protocol, the server sends a text packet containing the description of all the connected probes encoded in JSON (see below),
  • after that the client is expected to be able to understand subsequent binary frames containing the measurement data,
  • server sends a binary frame every decisecond, each frame contains hundred measurements for each probe, each measurement is 4 bytes long (bytes in network order), the measurements are in the same order as the probes described in the JSON message,
  • at any moment the client can send a power-switch frame containing two bytes the first one indicating the index of the probe and the second containing the desired power state (0 or 1).

As can be seen this protocol is not very flexible (adding extensions is impossible) and needs a rework.

JSON probe description

This is an example JSON message sent in the handshake:

  {
      "max_sps": 100,
      "probes": [
      {
          "name": "probe_0_0",
          "power_switch": "1",
          "measurements": [
          {
              "name": "Power",
              "unit": "A"
          }, {
              "name": "Voltage",
              "unit": "V"
          }, {
              "name": "Current",
              "unit": "W"
          }]
      }, {
          "name": "probe_0_1",
          "measurements": [
          {
              "name": "Temperature 1",
              "unit":"C"
          }, {
              "name": "Temperature 2",
              "unit": "C"
          }]
      }]
  }
  

The main difference from the config file structure is that we don't split the probes among capes. This information is irrelevant for the client.

Power probes software support

INA226 Power Monitor Linux driver features

The sensor chip used with the Power Probe is currently a ina226 Power Monitor from Texas Instruments. It is supported in the Linux kernel through two frameworks: hwmon (current use) and industrial-io (work in progress).

Hwmon is specialized in system status monitoring devices like temperature and voltage monitoring, and fan control. It is meant for low-speed measurement and controlling.

Typical client applications for hwmon are:

  • lmsensors utilities, like /usr/bin/sensor
  • the Sigrok library and Sigrok clients, like /usr/bin/sigrok-cli

Industrial IO is focused on industrial controlling and measuring, including high-speed data transfers, for instance from/to ADCs & DACs, accelerometers & gyroscopes etc… IIO allows for a streaming scheme, using software or hardware buffers, real-time capture triggers, events like value thresholds or timeouts. The Capture device may run a deamon (IIOD) , so that the processing or GUI front-end can be on a remote client, typically a PC.

Typical clients for IIO are:

  • the iio utilities, like /usr/bin/iio_readdev
  • libiio clients, like Analog Device iio-oscilloscope

HWMON driver

The kernel module source is located under driver/hwmon/ina2xx.c

Up to kernel 4.3: it performs a bulk-read of all 8 I2C registers, resulting in an acquisition time of mean 0.8ms x 8 = 6.4ms. The actual achievable sampling rate is roughly 1/6.4ms = 156 Hz. The driver will issue delayed values for read-rates faster than 156 Hz.

From kernel 4.4 and later on: the driver performs a more optimized read-out of selected values. Reading Power/VBus/Current will result in an acquisition time of mean 0.8ms x 3 = 2.4 ms, i.e. a sampling rate of 416 Hz (312Hz when monitoring VShunt as well). Reading a single value can be done at a rate of 1/0.8ms = 1250 Hz in theory, however, the driver will allow for capture rates up to 500Hz only (averaging value set to 1:1).

Industrial IO driver

Driver features and status

The device features as seen through the driver can be visualized with the iio_info tool.

IIO context has 1 devices:
	iio:device0: ina226
		5 channels found:
			voltage0:  (input)
			6 channel-specific attributes found:
				attr 0: scale value: 2.500000000
				attr 1: raw value: 799
				attr 2: integration_time value: 0.001100
				attr 3: index value: 0
				attr 4: en value: 1
				attr 5: type value: le:u16/16>>0
			voltage1:  (input)
			6 channel-specific attributes found:
				attr 0: integration_time value: 0.001100
				attr 1: raw value: 4149
				attr 2: scale value: 1.250000000
				attr 3: en value: 1
				attr 4: index value: 1
				attr 5: type value: le:u16/16>>0
			power2:  (input)
			5 channel-specific attributes found:
				attr 0: raw value: 42
				attr 1: scale value: 25.000000000
				attr 2: index value: 2
				attr 3: type value: le:u16/16>>0
				attr 4: en value: 1
			current3:  (input)
			5 channel-specific attributes found:
				attr 0: scale value: 1
				attr 1: raw value: 200
				attr 2: type value: le:u16/16>>0
				attr 3: index value: 3
				attr 4: en value: 1
			timestamp:  (input)
			3 channel-specific attributes found:
				attr 0: type value: le:s64/64>>0
				attr 1: index value: 4
				attr 2: en value: 1
		5 device-specific attributes found:
				attr 0: in_oversampling_ratio value: 4
				attr 1: in_shunt_resistor value: 10000
				attr 2: in_allow_async_readout value: 0
				attr 3: integration_time_available value: 0.000140 0.000204 0.000332 0.000588 0.001100 0.002116 0.004156 0.008244
				attr 4: in_sampling_frequency value: 114

This driver supports both

  • INDIO_DIRECT_MODE for direct read/write ops
  • INDIO_BUFFER_SOFTWARE streaming buffer

The client application can set an active_channel mask, this is used by the driver to optimize to type of i2c tranfers: bulk read is used when possible. The capture to a kfifo buffer is done by a kernel thread, that will compute the remaining time after the i2c transfer until the next due capture event, and do an active waiting. This insures near-to-realtime timestamps and a clean sampling clock for sampling periods longer than the i2c transaction time, like in the example below:

With Freq=454Hz, averaging is 4-times, the sampling period is 8.8ms, the i2c transfer for all four channels takes ~700us. The sampling is very regular.

Fast sampling mode

It is possible to sample faster, when less channels are wanted.

For instance, for one channel only (POWER) with Freq=850Hz, averaging is 1-times, the sampling period is 1176us, the i2c transfer for channel POWER takes ~450us. The sampling is very regular, but sampling clock jitter can be observed due to the i2c layer.

Building

The kernel module source is located under driver/iio/adc/ina2xx-adc.c

Patches: As of today it is not upstreamed, it must be retrieved from the baylibre git, using branch the acme-iio http://git.baylibre.com/pub/acme/linux/log/?h=acme-iio.

kernel config: this will reauire the following switches

CONFIG_IIO=y
CONFIG_INA2XX_ADC=m      (selects IIO_BUFFER)

Also, to generate the whole ACME software with IIO support, please refer to https://github.com/BayLibre/ACME

Testing

Insert driver with modprobe ina2xx-iio using the gpio extender and device-tree config as described in the acme wiki.

  • Manual testing

for debug purpose, you may setup the channels and buffer through sysfs:

echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage0_en
echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_voltage1_en
echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_current3_en
echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_power2_en
echo 1 > /sys/bus/iio/devices/iio:device0/scan_elements/in_timestamp_en

echo 2 >  /sys/bus/iio/devices/iio:device0/in_mean_raw
echo 100 > /sys/bus/iio/devices/iio:device0/buffer/length

Enable the buffer, and stream the data through the character device

echo 1 > /sys/bus/iio/devices/iio:device0/buffer/enable

dd if=/dev/iio\:device0 of=/root/result

echo 0 > /sys/bus/iio/devices/iio:device0/buffer/enable
  • Binary data format

Typically, the resulting data file will hold the four measurement channel values as int16 (4), and a int64 (1) timestamp.

  • Viewing for test purpose

Plotting with gnuplot can be done with

set term png
set output "iio-test.png"
plot "result" binary format="%4int16%int64" u 5:1 w l, \
 "result" binary format="%4int16%int64" u 5:2 w l, \
 "result" binary format="%4int16%int64" u 5:3 w l, \
 "result" binary format="%4int16%int64" u 5:4 w l
set term x11

Example of a USB remove/insert capture (units not shown).

  • Direct register access

The driver registers a debugfs direct register access interface, under /sys/kernel/debug/iio.

Known UI bugs and limitations

These are some of the known bugs, limitations and future features:

  • as mentioned before - the data exchange protocol has to be reworked,
  • the daemon architecture has to be redesigned,
  • the daemon uses a pipe & fork to split the logic into two processes, maybe we should use only one process with two threads, and use some lockless ring buffer for the data,
  • the C++ UI reimplement the protocol from the C daemon - the protocol handling should be put in a separate library against which we'll link the C daemon, the C++ UI and future LCD and Ncurses interfaces,
  • for now we don't support multiple clients - this is a crucial functionality,
  • the UIs should be redesigned, we should make them more eye-candy.
powercape/start.txt · Last modified: 2016/01/19 14:12 by mtitinger
Recent changes RSS feed Creative Commons License Donate Minima Template by Wikidesign Driven by DokuWiki