TITLE: Antidote Developer’s Guide
TYPE: Developer’s Guide
TITLE
|
IDENTIFICATION
|
|
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
|
0.5
|
Dependencies and Embedded Linux sections have been added
|
Marcos Pereira
|
29/11/2010
|
0.6
|
Added comments in Embedded Linux sections
|
Elvis Pfutzenreuter
|
10/12/2010
|
0.7
|
Added linking section
|
Elvis Pfutzenreuter
|
13/12/2010
|
0.8
|
Review of linking section
|
Marcos Pereira
|
14/12/2010
|
0.9
|
Updated device measurement D-Bus interface
|
Elvis Pfutzenreuter
|
14/12/2010
|
1.0
|
Updated to Signove’s template
|
Marcos Pereira
|
17/12/2010
|
1.0
|
Review
|
Aldenor Martins
|
23/03/2011
|
1.0
|
Library name
|
Elvis Pfutzenreuter
|
20/04/2011
|
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.
1.Document Control 4
References 4
Documentation Conventions 4
Abbreviations 4
Introduction 5
High-level architecture 5
Dependencies 5
Components 6
MDER encoding/decoding and utility functions 6
APDU parser 7
DIM – Domain Information model 7
Specializations 8
Data codecs 8
Communication and state machine 9
Transport plug-ins 9
IEEE manager 10
Applications 11
IEEE manager 11
D-Bus service 11
Anatomy of an IEEE application 13
Enabling IEEE 11073-20601 based applications on embedded linux platform 19
Platforms without D-Bus or BlueZ 19
Appendix A: partial D-Bus health service API description 20
Linking against THE IEEE static library 22
Document Control References
Ref id
|
Document / Source
|
State
|
Author
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Objects (components, classes, interfaces) in diagrams follow these color conventions:
Style
|
Purpose
|
Bold
|
Objects defined in the scope of this document
|
Italic
|
Methods defined in the scope of this document
|
Courrier
|
Code snipets
|
Code snippets use Courier New font and they are surrounded by a box.
Abbreviations
Abbreviation
|
Description
|
API
|
Application Programming Interface.
|
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.
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).
Dependencies
Antidote depends on certain applications and libraries to work:
-
BlueZ (With HDP support)
-
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)
Components
This section describes each building block within the stack.
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,
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.
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.
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.
-
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
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.
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.
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 loop-agnostic, 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.
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.
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 plug-in is written under the assumption that a Glib event loop will exist at runtime.
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.
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.
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.
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.
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.
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 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.
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;
}
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.
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.
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");
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;
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 plug-in and IEEE stack.
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.
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 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.
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)
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)
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()
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).
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 of
Share with your friends: |