Antidote_IEEE_11073-20601_Library_Developers_Guide

advertisement
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
TITLE
IDENTIFICATION
<PARTNERSHIP>
Antidote Developer’s Guide
--------------------------------
---------------------
DOCUMENT HISTORY
VERSION
COMMENTS
REALIZED BY
DATE
0.1
Initial draft – putting all
sections together
Elvis Pfutzenreuter
22/11/2010
0.2
Review
Mateus Lima
24/11/2010
0.3
Review
Elvis Pfutzenreuter
26/11/2010
0.4
Final version
Raul Herbster
29/11/2010
Marcos Pereira
29/11/2010
Elvis Pfutzenreuter
10/12/2010
0.5
0.6
Dependencies and
Embedded Linux sections
have been added
Added comments in
Embedded Linux sections
0.7
Added linking section
Elvis Pfutzenreuter
13/12/2010
0.8
Review of linking section
Marcos Pereira
14/12/2010
Elvis Pfutzenreuter
14/12/2010
Marcos Pereira
17/12/2010
0.9
1.0
Updated device
measurement D-Bus
interface
Updated to Signove’s
template
1.0
Review
Aldenor Martins
23/03/2011
1.0
Library name
Elvis Pfutzenreuter
20/04/2011
Page 1 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
Summary
This document describes Antidote, the IEEE 11073-20601 implementation, which is an
API defined to help developers to create applications for medical devices.
The information in this document is aimed mainly for software developers of project.
Page 2 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
1.
Document Control .............................................................................. 4
1.1
References .................................................................................. 4
1.2
Documentation Conventions ............................................................. 4
1.3
Abbreviations ............................................................................... 4
2.
Introduction ..................................................................................... 5
3.
High-level architecture ....................................................................... 5
3.1
4.
Dependencies ............................................................................... 5
Components ..................................................................................... 6
4.1
MDER encoding/decoding and utility functions ....................................... 6
4.2
APDU parser ................................................................................. 7
4.3
DIM – Domain Information model ........................................................ 7
4.4
Specializations.............................................................................. 8
4.5
Data codecs ................................................................................. 9
4.6
Communication and state machine ..................................................... 9
4.7
Transport plug-ins ......................................................................... 9
4.8
IEEE manager ............................................................................. 10
4.9
Applications ............................................................................... 11
4.10
IEEE manager ............................................................................ 11
4.11
D-Bus service ............................................................................ 11
5.
Anatomy of an IEEE application ........................................................... 13
6.
Enabling IEEE 11073-20601 based applications on embedded linux platform ..... 19
6.1
Platforms without D-Bus or BlueZ ..................................................... 19
7.
Appendix A: partial D-Bus health service API description ............................ 20
8.
Linking against THE IEEE static library ................................................... 22
Page 3 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
1. Document Control
1.1 References
Ref id
Document / Source
State
Author
1.2 Documentation Conventions
Objects (components, classes, interfaces) in diagrams follow these color conventions:
Style
Bold
Italic
Courrier
Purpose
Objects defined in the scope of this document
Methods defined in the scope of this document
Code snipets
Code snippets use Courier New font and they are surrounded by a box.
1.3 Abbreviations
Abbreviation
API
Description
Application Programming Interface.
Page 4 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
2. Introduction
This is a developer's guide for Antidote, the Signove IEEE 11073-20601 stack library.
This library should be used by applications that want to communicate with health and
fitness devices.
The document aims to introduce the developer to the software, including architecture
and internal building blocks, and ease the learning curve of APIs.
A real, working application is included in library itself, and it is dissected in this
document, which yields a prompt reference to the developer that is writing his first
health application with this stack.
It is assumed that the reader knows the IEEE 11073 standard and is familiarized with
health devices in general. The text contains opportune clarifications to aid readers
that are beginning to work with these matters, but it is not an introductory text to
them.
3. High-level architecture
Antidote IEEE 11073 stack (therefore called “stack”) was developed under key
architectural decisions:

Avoid dependencies from external libraries. This means easy porting to
different Linux distributions, or even different operating systems.

Not tied to any particular event loop framework e.g. GLib or Qt or threads.
Again, this aims to easy porting and easy adaptation to external software
parts (having in mind that every Linux/Unix UI framework implements its
event loop in a particular way).

Transport plug-in architecture, which allows connection with virtually any
transport protocol, be it Bluetooth, pipes, sockets etc.

Generation of static libraries, which are embedded into application binary.
Applications may link to the main library (which includes the full stack) or any
number of components that it actually employs (each component compiles
into a separate static library).
3.1 Dependencies
Antidote depends on certain applications and libraries to work:

BlueZ (With HDP support)
Page 5 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide




Kernel 2.6.36 (Some ERTM bugs were fixed in this version). There are
community-maintained packages of 2.6.36 for Ubuntu and possibly for other
distributions as well. Otherwise, compiling the stock 2.6.36 source is also ok.
D-Bus 1.4 (This version adds file descriptor passing support)
D-Bus Glib
Glib 2.0
4. Components
This section describes each building block within the stack.
Platform
dependencies
Application
Data
codecs
IEEE manager
Stock
transport
plug-ins
Device
specializations
Communication
state machine
Transport
plug-in
Interface
DIM
APDU
parser
MDER
IEEE 11073 library
Components
PHD
ASN.1
4.1 MDER encoding/decoding and utility functions
IEEE 11073 protocol specification is written using the ASN.1 language. Actual encoding
of an ASN.1 message to a stream of bytes is dictated by a set of rules, like BER, XER
or MDER. In case of health devices,
Page 6 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
MDER is the common-denominator rule, that every health agent and manager is
expected to implement. MDER is optimized in some ways, in order to accommodate
low-end devices
MDER supports a subset of ASN.1 primitive types. Medical messages are ultimately
limited to those primitive types. Of course, compound types like PHD types may use
any composition of the primitive types supported by MDER.
Apart from MDER, the IEEE stack needs a number of utility functions like date
manipulation, safe string buffer handling and so on. These things were implemented
here in order to avoid depending on external libraries for such tasks (and thus
avoiding gratuitous portability problems).
Source code of this block can be found at src/util, and its static library is
src/util/libutil.a.
Another folder of interest is src/asn1/, which contains include files for the PHD types.
PHD types are compound types of primitive ASN.1 types (int, float string etc.), and
are used throughout the stack.
4.2 APDU parser
APDU (Application Protocol Data Unit) is the equivalent of a network or Bluetooth
data packet. Each APDU that arrives must be decoded under MDER rules, but with
safety precautions against damaged or malformed data.
Source code of this block can be found at src/communication/parser, and its library is
src/communication/parser/libparser.a.
4.3 DIM – Domain Information model
DIM is an object-oriented representation of medical data.
Each DIM class contains a well-defined set of PHD type variables, and may inherit
from another DIM class. For example, the Numeric class inherits from Metric, which
inherits from DIM. So, each PHD attribute found in Metric is also found in Numeric,
but the opposite is not true.
A Numeric instance with value 70 could mean anything. But every Metric instance
contains a type identifier, which ties the value to a particular unit -- for example,
beats per minute. The complete meaning of object becomes “70 beats per minute”,
which has a self-sufficient meaning.
Other concepts of IEEE stack implemented in this block are:

The Scanner class, which is a way to send a collection of measures in a single
APDU.
Page 7 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide

PM-Store, which is a method of agent off-line data collection and eventual
retrieving by the manager.
Source code of this block can be found at src/dim, and its static library is
src/dim/libdim
4.4 Specializations
When an IEEE agent device associates with the manager, it sends its configuration. It
is an integer value that defines how measured data events will be formatted.
For example, the configuration ID of 0x0190 identifies an oximeter. It is a standard
configuration (that a manager should already know) and implies that measurement
events will always send two values:| oxygen saturation and pulse rate.
If the configuration ID is unknown by the manager, or it is extended (meaning: not
standard), the agent will send a configuration APDU after association step is
complete. This allows the manager to discover the configuration dynamically, and
interpret measurement event data.
An IEEE specialization defines standard configurations. For example,
src/specializations/pulse_oximeter.h defines configurations 0x0190 and 0x0191. If
some oximeter presents an unknown configuration like 0x0192, the IEEE stack will still
be able to interpret the measurement data, but an additional configuration APDU
exchange is required. Standard configurations exist to reduce the APDU exchange
during session establishment, which also helps to save energy.
A specialization may also extend the collection of DIM types.. For example, the same
source adds a type for beats-per-minute. It does not add a type for oxygen saturation
because the saturation unit (percent) is already present on base DIM.
Sources for this block are at src/specializations, and its library is
src/specializations/libspecializations.a. Specializations are added dynamically by
src/manager.c. This means that, in theory, more specializations could be dynamically
loaded and added afterwards, even though the current version of stack uses static
linking.
The IEEE manager caches configurations in the local filesystem. Even if there is no
specialization implemented, the device needs to send configuration only once, at the
very first association. Future associations from any device that implements the same
configuration will skip this phase and save energy.
Extended configurations are cached as well. The only difference is that extended
configuration namespace is device-specific.
Page 8 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
4.5 Data codecs
It is expected that most applications will not like to deal directly with IEEE stack
structures. This way, handling XML or JSON strings, that represent DIM objects, would
be more convenient.
In order to fill this need, the stack supplies a number of data codecs. They can be
found at src/api, and its static library is src/api/libapi.a.
Note that these codecs are never used by IEEE stack itself. They are meant to be used
by the application, as will be shown later in this document.
Besides that, note that codecs work at PHD level, not at DIM level. That is, a DIM
object will be presented as a hierarchical collection of PHD and ASN.1 types, not as
an object.
4.6 Communication and state machine
The communication block is the “glue” that makes all previous components work
together, making a true IEEE stack. It takes care of:

IEEE state machine for each session;

IEEE protocol timeouts;

Dealing with transport connections;

Notifying applications about data of interest (e.g. agent connected,
measurement received).
This component is the “nearest” to the application's event loop. Since it is event loopagnostic, the timeout primitives must be supplied by application via external
functions, and transport protocol is supplied via plug-ins, which will be shown in next
topic.
Communication source codes may be found at src/communication, and its library is
src/communication/libcomm.a.
4.7 Transport plug-ins
As stated before, this stack is platform-agnostic and transport-agnostic, but at some
point the stack needs to interface with transport layer details. This interface is
supplied by a transport plug-in, which is implemented and/or chosen by the
application.
Page 9 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
When the communication is started, a structure comprised of a few function pointers
must be supplied by application. Those functions implement initiation, transport
primitives (creation, sending, receiving and closing).
The application may implement those functions in any way it wants. Requirements
are very few: send and receive functions should not block, and it must support
multiple initiation/shutdown, in case IEEE stack is shutdown and restarted.
Each transport session is identified by a handle, which is a simple 64-bit integer. It is
plug-in's (and therefore application's) responsibility to attribute an unique ID to each
transport connection. If the transport supports reconnection (like HDP does), the ID
should be re-used upon reconnection, which allows the IEEE state machine to resume
communication instead of beginning from scratch.
When the communication layer needs to send data, it just calls the plug-in write
function, passing the handle and the APDU buffer. The application just needs to
relate the handle ID with actual transport connection and send the data (or schedule
for later dispatch).
The application may use threads to deal with transport connections. A common
technique is to dedicate one thread per connection; in that case, IEEE stack would
run in multiple, possibly simultaneous, contexts. The stack is thread-safe and supports
this case. The only caveat is callback to application whilst in communication thread's
context; an UI application would not be allowed to update the UI immediately upon
callback, handling it in main thread instead. All thread-aware frameworks (like Qt,
Glib) have techniques to solve this issue.
In the other hand, no application is forced to use threads. The IEEE stack does not
create threads internally.
For convenience and auto-testing, some plug-ins are already implemented. They can
be found at src/communications/plugin folder. Most plug-ins are in
src/communications/plugin/libcommplugin.a library.
The src/communications/plugin/bluez/libbluezplugin.a is a BlueZ HDP plug-in. It is
specifically used by the included D-Bus health service.
IMPORTANT: while the rest of IEEE stack is platform-agnostic, each one of the
supplied transport plug-ins is platform-dependent. For example, the BlueZ HDP plugin is written under the assumption that a Glib event loop will exist at runtime.
4.8 IEEE manager
The IEEE manager is the top-level component of IEEE stack. IEEE counterparts are
either agents or managers. Currently, this stack implements the manager only.
Page 10 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
The src/manager.c source code implements the IEEE manager. It depends (directly or
indirectly) on all other components, save by data codecs.
The whole stack, including the manager, is contained in a single static library:
src/libantidote.a.
4.9 Applications
Antidote source tree contains not only the stack itself, but also two complete and
functional applications that make use of stack and accept connections from actual
IEEE agents.
These applications serve specific purposes, as will be explained below, but they are
also very valuable examples of how to actually use the stack. A developer wanting to
link the stack with its own application just needs to follow the footsteps.
4.10 IEEE manager
It is mostly used as auto-testing tool, and gives option of using BlueZ (MCAP), TCP/IP
or FIFO transport plug-ins, at command-line. TCP/IP connection allows, for example,
connection with Continua testing suite or Continua Enabled Source Code Library
(CESL).
Executable is at src/ieee_manager.
4.11 D-Bus service
The src/healthd is a true D-Bus service which exports an easy-to-use D-Bus health API.
It is written using Glib framework.
Executable is src/healthd, and a simple script that uses/tests the API is
src/test_healthd.py. A more palatable example can be found at
doc/examples/simple_example.py.
This service makes use of recent BlueZ HDP API (which is D-Bus, too). It needs a
recent BlueZ version (minimum 4.77 was the first to ship with HDP, 4.79 or later is
recommended). Since BlueZ HDP API uses file descriptor passing, D-Bus 1.4.0 or later
is required.
Page 11 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
Health D-Bus service
D-Bus Glib
bindings
BlueZ HDP
transport plug-in
IEEE 11073
library
GLib
BlueZ
version >= 4.77
D-Bus
Version >= 1.40
BlueZ dependency upon
recent versions of kernel
and D-Bus are due to the
HDP profile
Linux kernel
version >= 2.6.36
This service is offered because writing transport plug-ins for IEEE stack is not a trivial
task, not because of IEEE stack itself, but because asynchronous communication is
itself difficult. An application may use this D-Bus service instead of linking with IEEE
stack directly, not having to deal with transport layer at all.
This service was written with Linux in mind, with presence of D-Bus service; but it is
perfectly possible to port the service to another architecture and to use another IPC
mechanism to exchange data. Having the transport handling outside UI application
would still be very convenient.
More elaborate D-Bus types were carefully avoided. While it is very easy to send and
receive e.g. arrays and dictionaries over D-Bus in Python language, it is very
inconvenient to do the same things in statically-typed languages.
With this in mind, structured messages like DIM objects, which seem to lend
themselves to recursive D-Bus arrays and dictionaries, are encoded as XML and sent
over plain D-Bus strings instead.
D-Bus was chosen because it is well-supported in intended targets (Linux, Meego or
Android) and most programming languages and UI frameworks have good D-Bus
Page 12 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
support, which means immediate access to the API regardless of how the application
is developed.
Details of D-Bus API are laid out at Appendix A.
5. Anatomy of an IEEE application
In this session, the Health D-Bus service (healthd) is analyzed. Source code is
src/managerdbus.c.
The objective of this section is to show how an application must interact with IEEE
stack to make end-to-end communication possible. Only relevant code is visited; in
terms of line count, most of managerdbus.c is devoted to D-Bus service exporting,
which is not relevant in this case.
#include “manager.h”
#include "src/api/xml_encoder.h"
#include "src/communication/plugin/bluez/plugin_bluez.h"
We will be an IEEE manager; we will use XML codec to translate data from DIM
objects, and we will employ the BlueZ HDP plug-in.
static void timer_reset_timeout(Context *ctx)
{
if (ctx->timeout_action.id) {
g_source_remove(ctx->timeout_action.id);
}
}
static gboolean timer_alarm(gpointer data)
{
void (*f)() = data;
f();
return FALSE;
}
static int timer_count_timeout(Context *ctx)
{
ctx->timeout_action.id = g_timeout_add(ctx->timeout_action.timeout
* 1000, timer_alarm, ctx->timeout_action.func);
return ctx->timeout_action.id;
Page 13 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
}
These functions implement timeout scheduling and triggering, in terms of Glib
framework. Note that timeout_action is expressed in full seconds (as are all IEEE
protocol timeouts) and it is multiplied by one thousand to meet Glib API that uses
miliseconds.
We also employ user_data pointer, pervasive to Glib, to call back IEEE stack when
timeout is triggered.
Note that functions are static; they do not need to be public. Their pointers will be
passed to IEEE stack at main().
void new_data_received(Context *ctx, DataList *list)
{
DEBUG("Medical Device System Data");
char *data = xml_encode_data_list(list);
if (data) {
call_agent_measurementdata(ctx->id, data);
free(data);
}
}
void device_associated(Context *ctx, DataList *list)
{
DEBUG("Device associated");
char *data = xml_encode_data_list(list);
if (data) {
call_agent_associated(ctx->id, data);
free(data);
}
}
void device_disassociated(Context *ctx)
{
DEBUG("Device unassociated");
call_agent_disassociated(ctx->id);
}
These functions are called back by IEEE stack when a new measurement data is
available, a device has associated, and a device has disassociated, respectively.
The call_agent_* functions (not shown in this document) just forward the message to
interested parties, via D-Bus.
Page 14 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
These functions could be static as well; main() will participate their pointers to the
plug-in (in this application; other apps could just use public functions).
void network_app_has_recv(guint64 handle)
{
communication_read_input_stream(context_get((ContextId)handle));
}
This is a callback needed by BlueZ HDP plug-in. Therefore it is an interface defined
between application and plug-in, completely outside IEEE stack. The function name
could be any other.
When data arrives, application notifies the IEEE stack by calling
communication_read_input_stream(). Upon this call, the stack will ask the plug-in for
data.
Normally, at this stage, data has already been read from transport, and it is waiting in
some kind of buffer. The handle identifies which channel has incoming data.
As stated before, the 64-bit handle that identifies the channel is determined by the
transport plug-in. It is plug-in's responsibility to ensure that this handle is unique and
has 1:1 relationship with a channel (and there may be several channels with the same
device, so device MAC address would not make a good handle in this case).
Since the field of a 64-bit handle is virtually infinite, the plug-in implementation may
well choose not to recycle handles.
void device_connected(guint64 handle, const char* device)
{
call_agent_connected(handle, device);
communication_transport_connect_indication(handle);
}
void device_disconnected(guint64 handle, const char* device)
{
call_agent_disconnected(handle, device);
communication_transport_disconnect_indication(handle);
}
Agent device connection and disconnection are out-of-band events, they don't map to
a given APDU. So, the plug-in needs a callback to notify such events, so IEEE stack
knows that a connection exists before the indication APDU arrives.
Page 15 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
In BSD/Sockets API, a recv() that returns zero means that connection has closed.
Sending a zero-length APDU to IEEE stack is not understood as connection closure.
That's why a specific disconnection callback is needed.
If the particular transport handled by the plug-in follows that BSD/Sockets rule, it is
plugin's responsibility to call (for example) device_disconnected or
network_app_has_recv, depending on recv() return.
Moreover, in the case of BlueZ HDP, socket-level disconnection does not mean actual
channel closure. Only the HDP channel deletion, or failure to acquire a channel file
descriptor, provoke a call to device_disconnected(), because the channel is truly
really gone.
These functions are public because the BlueZ HDP plug-in calls them by name, not via
pointer. As happened with network_app_has_recv(), this is an implementation issue;
IEEE stack does not impose their current names.
gboolean device_reqmeasurement(Device *obj, GError** err)
{
DEBUG("device_reqmeasurement");
manager_request_measurement_data_transmission(obj->handle, NULL);
return TRUE;
}
gboolean device_reqactivationscanner(Device *obj, gint handle, GError** err)
{
DEBUG("device_reqactivationscanner");
manager_set_operational_state_of_the_scanner(obj->handle, (HANDLE)
handle, os_enabled, NULL);
return TRUE;
}
gboolean device_reqdeactivationscanner(Device *obj, gint handle, GError** err)
{
DEBUG("device_reqdeactivationscanner");
manager_set_operational_state_of_the_scanner(obj->handle, (HANDLE)
handle, os_disabled, NULL);
return TRUE;
}
gboolean device_releaseassoc(Device *obj, GError** err)
{
DEBUG("device_releaseassoc");
manager_request_association_release(obj->handle);
return TRUE;
}
gboolean device_abortassoc(Device *obj, GError** err)
{
DEBUG("device_abortassoc");
Page 16 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
manager_request_association_release(obj->handle);
return TRUE;
}
gboolean device_get_segminfo(Device *obj, GError** err)
{
DEBUG("device_get_segminfo");
manager_request_get_segment_info(obj->handle, NULL);
return TRUE;
}
gboolean device_get_segmdata(Device *obj, GError** err)
{
DEBUG("device_getsegmdata");
manager_request_get_segment_data(obj->handle, NULL);
return TRUE;
}
gboolean device_clearsegmdata(Device *obj, GError** err)
{
DEBUG("device_clearsegmdata");
manager_request_clear_segments(obj->handle, NULL);
return TRUE;
}
These functions are not IEEE-related callbacks; they are called whenever the health
service client requests something. They just forward the given request to IEEE stack,
which in turn creates an APDU and sends it to the agent device.
The “Device” pointer is not an IEEE stack typedef; it is a GObject. This channels
representation was chosen in this particular application because it allows easy
exporting through D-Bus when using Glib. Other platforms/frameworks would do this
in a completely different way, and IEEE stack does not care about this.
int main()
{
...
CommunicationPlugin plugin = communication_plugin();
/* Configure communications plugin */
plugin_bluez_setup(&plugin);
plugin.timer_count_timeout = timer_count_timeout;
plugin.timer_reset_timeout = timer_reset_timeout;
manager_init(plugin);
ManagerListener listener = MANAGER_LISTENER_EMPTY;
listener.measurement_data_updated = &new_data_received;
Page 17 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
listener.device_available = &device_associated;
listener.device_unavailable = &device_disassociated;
manager_add_listener(listener);
manager_start();
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_ref(mainloop);
g_main_loop_run(mainloop);
DEBUG("Main loop stopped");
manager_finalize();
app_clean_up();
dbus_shutdown();
return 0;
}
This is the application's main() function. Here, we instantiate the communication
plug-in and the IEEE manager. All callback functions that we had defined before are
participated either to IEEE stack or BlueZ HDP plugin.
The CommunicationPlugin is an IEEE stack typedef, because it uses the plug-in to
carry out communication, but contents are completely defined by application (or by
the plug-in). As an illustration, follows a small section of plug-in code:
// implemented in top-level application
void network_app_has_recv(guint64 handle);
void device_connected(guint64, const char*);
void device_disconnected(guint64, const char*);
void plugin_bluez_setup(CommunicationPlugin *plugin)
{
plugin->network_init = init;
plugin->network_get_apdu_stream = get_apdu;
plugin->network_send_apdu_stream = send_apdu_stream;
plugin->network_finalize = finalize;
}
Note that BlueZ plug-in fills the CommunicationPlugin structure with its own
functions, which may well be static. The IEEE stack will call those functions when it
needs some plug-in service.
In the other hand, BlueZ plug-in never calls IEEE stack functions directly. It calls
application-defined public functions (network_app_has_recv() et al.) which in turn
forward the even to the IEEE stack. This is a way to minimize coupling between plugin and IEEE stack.
Page 18 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
6. Enabling IEEE 11073-20601 based applications on
embedded linux platform
There are several Linux-based embedded platforms. The choice for a particular
distribution and components depends on the requirements and limitations/features of
the target platform. Tests were performed on a BeagleBoard in order to evaluate the
usage of IEEE 11073 protocol implementation on an Embedded Linux platform.
The Beagleboard is an ARM based platform with an OMAP3530 Cortex-A8 720 MHz
processor and 256 MB of RAM memory. There are several possibilities for the
operating system in this platform, and for tests the Angstrom 2008 distribution was
adopted. There is a requirement for 4688 KB of memory available in order to run IEEE
11073 health based applications on this platform.
The Angstrom distribution was deployed using the current OpenEmbedded
implementation, with minor modifications to include the IEEE 11073 protocol
implementation. In addition, the distribution was modified to use the 1.4.0 Dbus
version, Bluez 4.80 implementation with health plugin enabled, and the Linux kernel
2.6.36.
6.1 Platforms without D-Bus or BlueZ
The health service discussed in topics 4.1.1 and 4.1.2 assumed a Linux environment
with D-Bus IPC service, with BlueZ as Bluetooth stack.
It is possible that a given Linux-based platform chooses not to use one of the
components, or both of them. BlueZ implies D-Bus (because most BlueZ APIs are
supplied via D-Bus), so the main outstanding case is using a different Bluetooth stack,
with two sub-cases: with and without D-Bus.
The IEEE 11073 stack is easily adaptable to a different Bluetooth stack. It is a matter
of writing a proper transport plug-in that uses whatever API the BT stack offers to get
access to HDP services.
Naturally, the Bluetooth stack in question must offer support to ERTM, MCAP and HDP,
or have those modules implemented. The exact details of how to implement MCAP
and/or HDP on an incomplete Bluetooth stack (e.g. develop it inside or outside the
transport plug-in?) are beyond the scope of this document.
In case the platform offers D-Bus, the health service architecture described in 4.1.1
and 4.1.2 may be kept as it is, without changes in healthd code.
In case D-Bus is not present, there are two options: link the IEEE stack directly to the
application (eliminating the need of IPC between health service and health
Page 19 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
application), or keep the service (desirable if there is more than one health
application in the system) and replacing D-Bus with another IPC mechanism.
Replacing D-Bus is perfectly possible but it would take a fair amount of work. Before
resorting to pipes or sockets, it is advisable to look for another high-level IPC
mechanism that platform may have adopted.
7. Appendix A: partial D-Bus health service API description
Service: com.signove.health
Path: /com/signove/health
Interface: com.signove.health.manager
Methods:
void ConfigurePassive(object agent, int data_types[])
Starts the health service.
The agent is a client-side D-Bus object that will receive IEEE events, by having
its methods called back.
The data_types parameter is an array of integers that configure which HDP
data types should be accepted. The values can be found in HDP specification.
For example, 0x1004 hex is the oximeter, and this is the value that should be
passed in this API, if oximeters are to be supported.
HDP data types map 1:n to IEEE standard configurations. For example, this
IEEE stack implements two standard configurations for oximeter: 0x0190 and
0x0191. But those values are not of interest in this API.
Current IEEE stack implement specializations that correspond to the following
HDP data types: 0x1004, 0x1007, 0x1029, 0x100f.
Follows the agent interface that service expects the agent to implement.
Path: any
Interface: com.signove.health.manager
Methods:
void Connected(object device, string address)
Page 20 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
Called back when a channel connects. The first parameter is an
opaque device path. The second parameters is a more meaningful device
identification (in case of Bluetooth HDP devices, it is the MAC address).
The received device object implements at least the interface
com.signove.health.device.
The name of first parameter (device) is a bit misleading because, if an agent
device establishes two separate data channels with manager, there will be
two different “device” objects. So, the object path actually maps 1:1 to
channels and 1:n to device addresses. (In practice, most device objects are
expected to use a single channel and extended configurations to send
multiple-specialization data.)
It is guaranteed that a new channel path will always be first sent via
Connected() before it appears in Associated() or via any other agent call, so a
channel can always be mapped to a MAC address by the application.
void Associated(object device, string xmldata)
Called back when a device (actually a channel) goes into “associated” state.
The first parameter is the opaque device path. The application may relate it
to the actual MAC address by keeping a map and update it upon Connected()
and Disconnected() agent calls.
The second parameter contains a XML representation of data sent by agent in
association APDU.
void MeasurementData(object device, string data)
Called back when a measurement data event arrived. The second parameter
is the XML representation of DIM objects.
void DeviceAttributes(object device, string data)
Called back when attributes have been fetched from device. This is the
asynchronous response to an earlier call to device.RequestDeviceAttributes()
(interface com.signove.health.device).
void Disassociated(object device)
Device (actually, a channel) entered into disassociated state.
This normally means that device path will cease to exist, but it might happen
that a new association happens over preexisting channel, so the application
must wait for Disconnected() to release all channel information.
void Disconnected(object device)
Page 21 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
Device (channel) disconnected.
At this point, the device path ceases to exist and may be “forgotten” by the
application, as well as any associated information. A new connection coming
from the same device is guaranteed to have a different path.
The device objects export an interface, too, for device- or channel-specific
activities.
Path: any
Interface: com.signove.health.device
Methods:
void Connect()
void Disconnect()
void RequestDeviceAttributes()
Requests device attributes. The call returns immediately, and the actual
result of this request will be returned asynchronously via agent.
void RequestActivationScanner(int handle)
void RequestDeactivationScanner(int handle)
void RequestMeasurementDataTransmission()
void ReleaseAssociation()
void GetSegmentInfo()
void GetSegmentData()
void ClearSegmentData()
8. Linking against THE IEEE static library
This section describes how to link a given application against the IEEE static library in
a GNU/Linux environment.
First, the library must be installed, either by downloading and installing the
development package, or by installing it from source (configure && make && make
install).
Page 22 of 23
TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
Since this library uses pkg-tools, it is very easy to add it to an application that
employs automake/autoconf as build system.
At configure.in file, the following line is added:
PKG_CHECK_MODULES(IEEE11073, antidote)
At Makefile.am file, the compilation and link flags are added, like the example below:
someapp_CFLAGS = @LIB1_CFLAGS@ @LIB2_CFLAGS@ @IEEE11073_CFLAGS@
someapp_LDADD = \
@LIB1_LIBS@ \
@LIB2_LIBS@ \
@IEEE11073_LIBS@
“Lib1” and “Lib2” are other hypothetical dependencies of the application.
If the application does not use autoconf/automake, the compiler/linker flags and
include paths must be configured manually. Since each environment may present
different configurations, the best bet is to read the pkgconfig file
(/usr/lib/pkgconfig/antidote.pc or /usr/local/lib/pkgconfig/antidote.pc) in order to
get the appropriate configurations.
Page 23 of 23
Download