0
Under review

Reading a DeviceIdentity that has a blank model field

Bradford Needham 10 years ago in OpenICE updated by Jeff Plourde 10 years ago 6
I'm writing an OpenICE app designed to report the on/off state of various Devices. So far I've successfully modified Hello OpenICE code to Subscribe to HeartBeat and DeviceIdentity Topics. The HeartBeat data seems to arrive fine, but the DeviceIdentity data has problems.

In the received DeviceIdentity, the model name is blank, rather than being something like "Pulse Ox (simulated)". I've seen some symptoms that suggest that the model string gets filled in later, but I'm not certain of that.

I wanted to double-check with you that I'm using the correct pattern to read the DeviceIdentity data: I substituted class names in Hello OpenICE code based on some guesswork, so something may be incorrect. Based on the symptom I'm wondering whether I'm not properly telling DDS that I want to read the data contents. I haven't found an example of reading DeviceIdentity in the mdpnp git.

Here is the relevant code (adapted from HelloICE.java) - I apologize for the formatting. Note that on reception of a Pulse Ox (simulated) DeviceIdentity, the model field is blank.

Thanks for your help,
Brad
---------------------------------

public void on_data_available(DataReader reader) {
ice.DeviceIdentitySeq deviceIdentitySeq = new ice.DeviceIdentitySeq();
SampleInfoSeq infoSeq = new SampleInfoSeq();
DeviceIdentityDataReader diReader = (DeviceIdentityDataReader) reader;
try {
diReader.read(deviceIdentitySeq, infoSeq, ResourceLimitsQosPolicy.LENGTH_UNLIMITED, SampleStateKind.NOT_READ_SAMPLE_STATE, ViewStateKind.ANY_VIEW_STATE, InstanceStateKind.ALIVE_INSTANCE_STATE);
/*
* Bug: the model number info seems blank. Example output:
* 2015-09-24 13:50:11 DEBUG IceQos:50 - Loaded default ice_library QoS
* 2015-09-24 13:51:30 ERROR DeviceIdentityListener:75 - Empty model in received DeviceIdentity
* 2015-09-24 13:51:30 INFO HelloIce:75 - ON: manuf: , model: , serial:
* 2015-09-24 13:51:47 INFO HelloIce:75 - OFF: manuf: , model: , serial:
*/
Date now = new Date();
for(int i = 0; i < infoSeq.size(); i++) {
SampleInfo si = (SampleInfo) infoSeq.get(i);
ice.DeviceIdentity data = (ice.DeviceIdentity) deviceIdentitySeq.get(i);
if(si.valid_data) {
if (data.model.length() == 0) {
logger.error("Empty model in received DeviceIdentity");
}

tracker.sawIdentity(data, now);
}

}
} catch (RETCODE_NO_DATA noData) {
// No Data was available to the read call
} finally {
// the objects provided by "read" are owned by the reader and we must return them
// so the reader can control their lifecycle
diReader.return_loan(deviceIdentitySeq, infoSeq);
}

}



OpenICE
More details: I suspect it's manifested as a timing related issue, because the frequency of the symptom changes when I add or remove slf4j logging in other Subscriptions. Also, at home today the bug happens nearly all the time; even if I close both my app and the OpenICE supervisor and restart both. It also happens if I remove the tracker.sawIdentity() call above, so it doesn't seem related to what tracker.sawIdentity() does (which is to do a deep copy of the DeviceIdentity object).

To reproduce, I start my code, then start OpenICE Supervisor on the same PC, then use the Supervisor to create a simulated Pulse Oximeter. The code I show above receives the Pulse Oximeter's DeviceIdentity, but often (not always) that DeviceIdentity has a blank (0 length; not null) model String rather than a string like "Pulse Ox (Simulated)".
P.S, I'm using OpenICE library 0.6.3 (via Gradle), java version "1.8.0_45", Java(TM) SE Runtime Environment (build 1.8.0_45-b33, 64-bit Eclipse Mars on a 64-bit Windows 8 Pro system with Intel Core i5-4300U CPU @ 1.90GHz 2.49GHz and 4GB ram. So it's all 64bit x86.
FOUND THE PROBLEM. Reading through the mdpnp git repo, I find that when a (simulated at least) device is Constructed, it writes a blank DeviceIdentity followed by the filled in DeviceIdentity. Internal timing of DDS can cause one to arrive before the other sometimes.

The workaround is to ignore received DeviceIdentity objects whose .model field is blank (not null; length == 0).

The bug is that the AbstractSimulatedConnectedDevice constructor calls writeDeviceIdentity() before the subclass has a chance to fill in that DeviceIdentity. Then the subclass constructor, for example SimPulseOximeter(), eventually gets control, fills in the fields of the DeviceIdentity, then (appropriately) calls writeDeviceIdentity().

Naively, it looks like the fix would be to remove the call to writeDeviceIdentity() from the constructor for AbstractSimulatedConnectedDevice. That's assuming that all of its subclasses' constructors call writeDeviceIdentity once they've filled in the DeviceIdentity fields.
Under review
Hey Brad,

This is fantastic work! Thank you for taking the time to track down the solution. Is there a way we can share this fix or workaround with others? You mentioned that your code is adapted from HelloICE.java, can we alter that to avoid this?

Thanks,
Jeff
After digging into detection of device on/off state a bit more, I think we still don't know how to properly infer/calculate whether a given Medical Device (not just its Device Adapter) is on or off. The Topics HeartBeat, DeviceIdentity, and DeviceConnectivity seem closely related to it, but not the whole answer. I've posted a question about it in another thread.

On a more practical note: HelloICE.java doesn't have the problem, because it doesn't Subscribe to the DeviceIdentity Topic. I think the right thing would be to write an app that detects what devices are on or off. ...but as I mentioned here, I'm not sure we really know how to do that yet.
I'll look forward to reading the other post but I'm curious how one could detect the power state of a device reliably short of monitoring electrical current? The DeviceConnectivity samples will indicate whether a connection has been established/detected on the port but you're absolutely right that it's not necessarily indicative of the power state of the remote device. A powered down device will never establish a connection or transmit data and therefore remain in the "Connecting" state. A powered up device would, if its interface is functioning correctly, progress to the Connected state on the DeviceConnectivity topic. If an interface shuts down (maybe because the device powered down or maybe just because the interface stopped functioning) a timeout will occur reverting the DeviceConnectivity state back to Connecting.

It's also intentional that DeviceIdentity fields are often populated progressively. For instance for some device 'driver' software the Manufacturer is known initially (because the driver itself is manufacturer-specific) but the Model will be received later in the course of communication with the device. Similarly the serial number may subsequently be populated as communication with the device progresses. Also some devices never emit some of the data (especially something like serial number) so it's impossible to "hold up" publication until the entire DeviceIdentity object can be filled out. While some day manufacturers may agree to a small subset of these fields being mandatory there will always be optional fields. For instance the latest revision to the Device resource in HL7 FHIR also specifies 0..1 cardinality for descriptive fields.

Without sounding like a buzzword machine a more reactive approach to handling these data might serve better. For instance in the OpenICE UIs many DDS topics are peered to JavaFX collections of enriched JavaFX objects. Transforming from a paradigm of "handling events" to one of "binding data". The ultimate flexibility of this approach is exemplified in the existing code by the VitalModelImpl where basic data properties received from DDS are combined into ever more complex dynamic (reactive) properties which are easily bound to the UI declaratively. I hope that future iterations of the DDS infrastructure allow this to occur more natively. The classes currently generated by IDL are not even valid java beans much less reactive objects and I hope that can change in the future.