Abbott Shared HID protocol
Multiple Abbott devices of the FreeStyle family share a common communication protocol based on USB HID. These devices all provide a direct USB connector and require no special cable nor driver to speak with a PC.
While most of the commands are not compatible between each other, the devices do share a basic framing protocol and basic text command format.
Credit for the reverse engineering go to Xavier Claessens for OpenGlucose.
Communication Protocol
These devices appears on the USB bus as a HID device. The communication between the software and the device happens through HID Set Report/Get Report interfaces, in a way that is compatible with the Linux hidraw interface.
In particular the packets are sent on the Control endpoint, as Class
Interface messages (bRequestType = 0x21, bRequest = 0x09, wValue = 0x0200,
wIndex = 0x0000
), and received on the interrupt endpoint (0x81
). Report
numbers are not used.
The "reports" are not following the HID standard. They are of a fixed 64-bytes size, even if most of the commands themselves are shorter. Replies can span multiple inbound reports.
message = message-type message-length 62OCTET
message-type = OCTET ; this will more properly defined later.
message-length = %x00-3E
The message-type
is not fully understood, and its valid values differ
between different devices, so please reference the specific device document.
The message-length
represent the number of significant bytes in the message
excluding type and length.
Some devices (notably the Libre 2 reader) encrypt the message following
message-type
, and as such don't have a valid message-length
value.
Binary Messages
Abbott's original software sends a number of pre-initialization commands to identify the model and software version of the device, and choose the appropriate protocol implementation. These are all binary (i.e. non-text) commands. The names are arbitrary to provide a mnemonic reference.
INIT (0x01
)
init = %x01 %x00
init-reply = %x71 %x01 %x01
This is the same exact request/reply pair in all the currently observed devices. Most devices will respond to text commands following this initialization.
0x04
x04-command = %x04 %x00
x04-command-reply = %x34 %x01 OCTET
The octet returned by this command appears not to be constant per device, according to Xavier's notes and experimentation. It is not constant across devices. No meaning is known for this.
QUERY SERIAL (0x05
)
init-query-serial = %x05 %x00
init-query-serial-reply = %x06 %x0e
( serial-number / no-serial-number ) %x00
serial-number = 7( ALPHA / DIGIT ) "-" 5( ALPHA / DIGIT )
no-serial-number = "00000000 (No SerialNum)"
Note: the serial number definition is common to most Abbott device, except newer devices have a longer, and non-compatible serial number format. It is possible that the Abbott software can determine the driver to use based on this serial number.
QUERY SWVER (0x15
)
init-query-swver = %x15 %x00
init-query-swver-reply = %x35 message-length software-version %x00
software-version = VCHAR *( VCHAR / SP )
The software version definition is effectively free-form. Some newer models appear to include a date.
Error Conditions
UNKNOWN COMMAND
Whenever an invalid (unknown) message type is sent to a device, it will respond with the following message:
error-reply = %x30 %x01 %x85
Synchronization packets
Some devices send what appears like a "synchronization packet" every few reports read, that is so defined:
synchronization-packet = %x22 %x01 OCTET
The frequency of these packets appears to depend on the device (some devices appear to send it exactly every three reports sent), and so does the content of the packet.
Text commands
Most of the devices using this HID-based protocol can be sent commands that receive ASCII text responses. These responses can span multiple frames, allowing the single response to cross the 62-bytes length limit.
Each text response, once reconstructed, complies to the following specs:
response = message "CKSM:" checksum CRLF
"CMD" SP command-status CRLF
checksum = 8HEXDIG
message = *( VCHAR / SP / CRLF )
command-status ("OK" / "Fail!")
The <checksum>
is calculated by summing up the ASCII value of each of the
bytes forming the message, including the final newline that usually terminates
the message.
Since no message is present in case of message failure, the checksum is null and
is represented by the string 00000000
.
Multiple records commands
Different commands can return a list of records. While their meaning depends on the issued command, the reported format fits the same syntax:
multi-records = empty-log / log
empty-log = "Log Empty" CRLF
log = *( record CRLF )
record-count "," checksum
record = *( value "," ) value
value = *VCHAR
record-count = 1*DIGIT
checksum = 8HEXDIGIT
The <record-count>
field will contain the number of records that were
returned; the <checksum>
field is calculated the same way as the overall
command one by summing up the ASCII value of each of the bytes forming the
record set, up to and including the final newline, and excluding the record
count.
Common commands
There are a number of commands that appear shared across FreeStyle devices, and are thus documented here to avoid duplication.
As devices may not support all these common commands, please refer to the detailed protocol definition to note inconsistencies.
The majority of these commands are getters and setters of variables, some free-form and some structured. The generic syntax for these commands is:
command = "$" variable-name ( "?" / "," variable-value )
variable-name = 1*VCHAR
variable-value = *( VCHAR / SP )
Some variable (such as the software version and serial number) are read-only. Those commands are documented with their full value, including the terminating question mark.
$swver?
swver-response = 1* ( VCHAR / SP ) CRLF
Returns the software version of the device. The returned value is free-form, as it changes among devices.
$serlnum?
serlnum-response = 1* ( ALPHA / DIGIT ) CRLF
Returns the serial number of the device. The serial number format appears to be different from previous Abbott devices and as such is to be considered free-form.
Please note that this command may provide a serial number even for devices that
respond with <no-serial-num>
during initialization.
$date
date-cmd = "$date" ("?" / "," date-value)
date-query-response = date-value CRLF
date-value = ( month "," day "," year )
month = 1*3DIGIT
day = 1*3DIGIT
year 1*3DIGIT
Fetch or set the current date as seen by the device. If a date value is passed following the command, it'll be interpreted as a set-date.
If the device does not have a valid date settings (e.g. the real time clock lost its power), the value 255 is reported for all fields.
Note the year value is defined at most with two digits, the value 2000 needs to be added (or subtracted) to match the current year.
In case of successful setting of date, the command is confirmed with no further
information; in case of error, the <message>
field will report the encountered
error.
$time
time-cmd = "$time" ("?" / "," time-value)
time-query-response = time-value CRLF
time-value = hour "," minute
hour = 1*3DIGIT
minute = 1*3DIGIT
Fetch or set the current time as seen by the device.
If the device does not have a valid time settings (e.g. the real time clock lost its power), the value 255 is reported for all fields.
In case of successful setting of date, the command is confirmed with no further
information; in case of error, the <message>
field will report the encountered
error.
$ptname
ptname-cmd = "$ptname" ("?" / "," patient-name)
ptname-query-response = patient-name CRLF
patient-name-setting = 1*VCHAR
patient-name-response = *VCHAR
Returns the patient name as configured in the device.
Note that while an empty response is valid, an empty value when setting the variable is not always accepted. The behaviour depends meter by meter.
$ptid
ptid-cmd = "$ptname" ("?" / "," patient-id)
ptid-query-response = patient-id CRLF
patient-id-setting = 1*VCHAR
patient-id-response = *VCHAR
Returns the patient ID as configured in the device.
Note that while an empty response is valid, an empty value when setting the variable is not accepted.