Abstract
This documentation is intended to help designing applications for the Velobox' vmkstationd3
that include communication with Velometrik's controller for pressure mats.
Introduction
The bluetooth communication between the Velometrik controller and an application API
of the Velobox runs through several layers:
- The BlueZ Bluetooth protocol stack for Linux
- The Bluetooth Low Energy platform Agnostic Klient "Bleak" library for Python
- The Bluetooth Agent of the vmkstationd3 of the Velobox
(a Python script named btagent.py)
- A TCL Interface to btagent.py.
(A kernel module, named ::kernel::BTSattel for saddle pressure mats)
- The Application module that defines the applications API
For program design it is useful to know some internals starting from the bluetooth agent upwards.
The bluetooth agent
The bluetooth agent arranges the bluetooth communication between Velometrik's controller
and the vmkstationd3 daemon of the Velobox.
After invocation the agent expects commands from stdin that control what happens.
Responses go in JSON format to stdout.
Pressure values go as comma seperated (ASCII) integer values
(one line per pressure image) to stdout too.
The data delivered can be grouped as follows:
- Line starts with '[' and ends with ']':
JSON array with controllers found
- Line starts with '{' and ends with '}':
Message object with the key "btevent" whose value determines what other keys can
be expected
- Line starts with '0' through '9':
Pressure values
Commands
The bluetooth agent has two nested command loops, an inner and an outer command loop.
The inner loop has a very limited command set and runs while data will be transferred.
(outer command loop)
- scan
Scan for bluetooth devices named "SmartCov*".
The result is a JSON-array with the devices found.
Each object has the keys "name" (bluetooth device name),
"address" (bluetooth mac address), "paired" (True or False) and "connected" (True or False).
- status
Result of the last scan.
- notify <device-name>
Start reading data from (Start connection to) <device-name>.
<device-name> must have been found by a previous scan.
If the device isn't paired yet it will be paired before.
- set nonulls {on|off}
Switch suppression of NULL pressure images (images without any pressure).
The initial setting (default) is off
unless btagent was started with the Option '-n'.
- stop
Dummy command.
If in the inner loop the connection ends unexpectedly,
btagent continues waiting for a command to exit this loop.
So when trying to connect again
a 'stop' to the inner loop must be sent before.
Having this dummy command in the outer loop too the client doesn't have to care about
unexpected disconnection.
He can simply send a 'stop' before every try to connect.
- version
Query bluetooth agents version.
- quit
Exit bluetooth agent.1)
(inner command loop)
- stop
Stop reading data (stop connection) and exit to outer command loop.
- quit
Stop reading data (stop connection) and exit bluetooth agent.1)
1)Bluetooth agent will exit on receipt of EOF (Ctrl-D) on stdin too.
Message objects
Every JSON message object has a key named "btevent".
Depending on that key's value there may be more keys for the details.
| btevent | class (error) | |
| disconnected | | Regular disconnect |
| error | disconnected | Unexpected disconnect |
| | fail | Pair failed |
| | | Start notify failed |
| | | Device not found |
| | comm | Stop notify failed |
| | client | Invalid command |
| | internal | Unexpected error, outer loop restarted |
| debug | | Debug message |
The TCL bluetooth interface
On startup of the vmkstationd3 loading the kernel module ::kernel::BTSattel this
module starts the bluetooth agent. It hides the communication details by offering
interface procedure calls.
To get informations about the connection status and to get the pressure pressure
data the application regsisters a connection change handler and a data handler rsp.
Commands (TCL-procedures)
- ::kernel::BTSattel::tryConnect [<device-name>]
Try to connect to the only controller available
or to the controller with <device-name>.
- ::kernel::BTSattel::disconnect
Stop the current connection.
- ::kernel::BTSattel::agentVersion
Query the blutooth agents version.
Callbacks for connection changes
To register a callback for connection changes call
::kernel::BTSattel::addConnectionHandler <handler-proc-name>
(Working with namespaces it's a good idea
to set the complete namespace path for <handler-proc-name>.)
The connection handler must handle a JSON object string with the key "btevent".
Depending on that key's value there may be more keys fore the details.
In addition to the message object passed from the bluetooth agent the TCL interface
sends the following btevents:
| btevent | detail-key | class (error) | value |
| status | devices | | Array of device objects
(Keys see btagent command scan) |
| error | class | | The error class |
| | | fail | Expected device not found |
| | | | No device found |
| | | client | disconnect while trying connect (ignored) |
| | msg | | The error message |
| ambiguity | devices | | Array with all device names |
| data | | | Data are available |
To remove a callback for connection changes use
::kernel::BTSattel::removeConnectionHandler <handler-proc-name>
Callbacks for pressure data
To register a callback for pressure data call
::kernel::BTSattel::addDataHandler <handler-proc-name>
(Working with namespaces it's a good idea
to set the complete namespace path for <handler-proc-name>.)
The data handler must accept the three arguments "values" (list of pressure values), "n_cols" (number of columns) and "n_rows" (number of rows).
To remove a callback for pressure data use
::kernel::BTSattel::removeDataHandler <handler-proc-name>
Hints for application design