Electronics and Software
Engineering Innovation
BMeasure-lib  1.0.0
BMeasure-lib Documentation
Author
Dr Terry Barnaby
Version
1.0.0
Date
2020-02-09

Introduction

BMeasure-125i.png

The Beam BMeasure-125i unit is a flexible and powerful IoT system for data capture, data logging and control in the laboratory, industrial and remote sensing arenas. It is based around an 8 channel, fully differential, synchronous sampling, 24 bit ADC that can sample at speeds up to 128 ksps. Multiple units can be connected together to provide more synchronously sampled channels.

This reference information describes the data types and functions provided by the host API library allowing programs to be written to control the operation of a BMeasure unit and acquire the data from it. The API operates over a number of different physical interfaces including: USB 2.0, Ethernet, Wifi and RS485.

In addition there is a software manual providing an overview of using this API which should be read first. This document is available at:: https://portal.beam.ltd.uk/files/products/bmeasure-125i/doc/BMeasure-lib.pdf

Overview

The BMeasure API library, bmeasure-lib, is implemented in the C++ computer language. It has bindings layered on top of this for Python, with Matlab due to be supported soon. The API has an object orientated architecture. It has been designed as a general purpose API library for the Beam BMeasure-125i and future BMeasure products. Currently it has ports to Linux (Redhat7, Fedora29, Debian) and Microsoft Windows 7, 8 and 10.

The API provides the following functionality:

  • Find BMeasure units on the USB bus or local Ethernet and Wifi networks.
  • Connect to one or more BMeasure units.
  • Fetch information and configure the BMeasure units.
  • Start the BMeasure unit capturing and processing the sensor inputs.
  • Capture the data from all of the analogue and digital channels from one or a combined set of BMeasure units running in sync.
  • Access the data log files on the unit and download them to the host.
  • Configure the AWG to produce waveforms or set voltages on the analogue output channels.
  • Operate relays, read switches and other auxiliary operations.

The BMeasure API is implemented using the Beam BOAP (Beam Object Access protocol) communications system. It offers an BMeasureUnit API class to access an individual BMeasure unit in a relatively low level manner and an BMeasureUnits API class to access a set of BMeasure units synchronised together to operate as a single unit and with a queued data reception system..

The API supports threaded and non-threaded operation.

The referenve information provided describes the API from a C++ programming perspective. The Python and other language bindings are very similar the differences being noted under the particular language bindings section in the software manual..

API Usage

To use the API the core procedure is:

  1. Either find the available BMeasure units using: BMeasureApi::BMeasureUnit::findDevices() or use a BMeasure URL string..
  2. Choose to use the simple single unit interface BMeasureApi::BMeasureUnit or the BMeasureApi::BMeasureUnits classes.
  3. If using the simple single unit interface, connect to the unit using the BMeasureApi::BMeasureUnit::connect() function.
  4. If using the multiple unit interface, add the units using the BMeasureApi::BMeasureUnits::unitAdd() function and connect using the BMeasureApi::BMeasureUnits::unitsConnect() function.
  5. Use the interface to communicate to the unit.

See the examples below and the software manual for more details.

API Usage

There are some examples of client applications using the BMeasure API in the examples directory of the source code. Some simple client examples are listed below:

Simple example to access and read single sets of data samples in C++

/*******************************************************************************
* Example005-dataClient-single.cpp
* T.Barnaby, BEAM Ltd, 2019-10-09
*******************************************************************************
*/
#include <BMeasureUnit.h>
#include <unistd.h>
using namespace BMeasureApi;
// Function to read some data
BError test1(){
BError err;
BString device;
BMeasureUnit bmeasure;
Configuration config;
BUInt c;
printf("Start Processing Task\n");
bmeasure.start();
printf("Find BMeasure units\n");
if(err = BMeasureUnit::findDevicesUsb(devices)){
return err;
}
if(devices.number() == 0){
return err.set(1, "No USB BMeasure units found\n");
}
device = devices[0].device;
printf("Connect\n");
if(err = bmeasure.connect(device))
return err;
//printf("Exit\n"); return err;
printf("Get Info\n");
if(err = bmeasure.getInformation(info))
return err;
printf("NumChannels: %d\n", info.numChannels);
//printf("Exit\n"); return err;
printf("Configure measurement\n");
mc.triggerLevel = 0;
mc.triggerDelay = 0;
mc.sampleRate = 8000.0;
mc.measurePeriod = 0;
mc.numSamples0 = 1;
mc.numSamples1 = 0;
if(err = bmeasure.setMeasurementConfig(0, mc))
return err;
printf("Run single measurement\n");
if(err = bmeasure.measure(DataTypeFloat32, data))
return err;
printf("DataBlock: from: %d numChannels: %d numSamples: %d\n", data.source, data.numChannels, data.numSamples);
for(c = 0; c < data.numChannels; c++){
printf("%f ", data.data[c]);
}
printf("\n");
return err;
}
int main(){
BError err;
if(err = test1()){
printf("Error: %d %s\n", err.getErrorNo(), err.str());
return 1;
}
printf("Complete\n");
return 0;
}

Simple example to access and read single sets of data samples in Python

#!/usr/bin/python3
import sys
import time
import getopt
from threading import Thread
from bmeasure import *
# Function to read some data
def test1():
bmeasure = BMeasureUnit(True);
print("Find BMeasure units");
(err, devices) = BMeasureUnit.findDevicesUsb();
if(err):
return err;
if(devices.number() == 0):
return err.set(1, "No USB BMeasure units found\n");
print("Found", len(devices));
device = devices[0].device;
print("Start Processing Task");
bmeasure.start();
print("Connect to BMeasure");
err = bmeasure.connect(device);
if(err):
return err;
print("Get Info");
(err, info) = bmeasure.getInformation();
if(err):
return err;
print("NumChannels: ", info.numChannels);
print("Configure measurement");
mc = MeasurementConfig();
mc.measureMode = MeasureModeOneShot;
mc.triggerMode = TriggerModeOff;
mc.triggerConfig = TriggerConfigNone;
mc.triggerChannel = 0;
mc.triggerLevel = 0;
mc.triggerDelay = 0;
mc.sampleRate = 4000;
mc.numSamples0 = 1;
mc.numSamples1 = 0;
mc.measurePeriod = 0;
err = bmeasure.setMeasurementConfig(False, mc);
if(err):
return err;
print("Run single measurement");
(err, data) = bmeasure.measure();
if(err):
return err;
print("DataBlock: from: %d numChannels: %d numSamples: %d" % (data.source, data.numChannels, data.numSamples));
for c in range(0, data.numChannels):
print("Chan:", c, data.data[c]);
return err;
def main():
err = test1();
if(err):
print("Error:", err.getErrorNo(), err.getString());
return 1;
print("Complete");
return 0;
if __name__ == "__main__":
main();

Simple example to show operating the relays in Python

#!/usr/bin/python3
import sys
import time
import getopt
from threading import Thread
from bmeasure import *
# Function to set the relays on/off
def test1():
bmeasure = BMeasureUnit(True);
print("Find BMeasure units");
(err, devices) = BMeasureUnit.findDevicesUsb();
if(err):
return err;
if(devices.number() == 0):
return err.set(1, "No USB BMeasure units found\n");
print("Found", len(devices));
device = devices[0].device;
print("Start Communications Task");
bmeasure.start();
print("Connect");
err = bmeasure.connect(device);
if(err):
return err;
print("Get Info");
(err, info) = bmeasure.getInformation();
if(err):
return err;
print("NumChannels: ", info.numChannels);
# Toggle relay1
state = 0;
for i in range(0, 6):
if(state):
state = False;
else:
state = True;
print("Set relay 0: %d" % (state));
err = bmeasure.setRelay(0, state);
if(err):
return err;
time.sleep(1);
return err;
def main():
if(0):
err = find();
if(err):
print("Error:", err.getErrorNo(), err.getString());
return 1;
err = test1();
if(err):
print("Error:", err.getErrorNo(), err.getString());
return 1;
print("Complete");
return 0;
if __name__ == "__main__":
main();