FreeStyle Libre
Reverse engineered by Pascal Fribi, editing and expansion by Diego Elio Pettenò.
Important device notes
USB IDs
Device | Vendor ID | Product ID |
---|---|---|
FreeStyle Libre | 1a61 | 3650 |
Protocol
This device uses the shared HID protocol used by other
meters in the FreeStyle family. Text commands are sent by the original software
as message type 0x21
, with responses as 0x60
, but the device appears to
accept the commands as type 0x60
as well (compatible with other FreeStyle
devices).
Strings Handling
The official software has known UTF-8 handling bugs, but the device itself appears to display strings correctly if encoded in UTF-8.
Commands
The Libre supports a distinct set of commands from those described in the shared protocol. In particular, the following commands are not supported:
$serlnum?
— replaced by$sn?
.
A number of new text commands are added instead.
$dbrnum?
dbrnum-response = "DBRECORDS = " 1*DIGIT CRLF
The response includes the number of records in the database (history results.)
This number is permanent across factory resets.
$history?
The $history?
command returns all the automatic measurements taken by the
sensors. It does not include the immediate measurements on user request, nor
strip measurements (blood glucose and β-ketone).
The output follows the Multiple record command output format as described in the shared protocol documentation.
Record fields
record-id = 1*5DIGIT
unknown = "12"
month = 1*2DIGIT
day = 1*2DIGIT
year = 1*2DIGIT
hour = 1*2DIGIT
minute = 1*2DIGIT
second = 1*2DIGIT
unknown = "1"
unknown = "0"
unknown = "0"
unknown = "0"
-
unknown = "0" / "1"
This value appears to only be 1 for the first reading of the sensor (with sensor runtime reporting 15 minutes).
-
value = 1*DIGIT
sensor-runtime-minutes = 1*DIGIT
-
error-bitfield = 1*5DIGIT
This field needs to be interpreted as a bitfield (in decimal representation). Flag 0x8000 indicates an error (invalid reading). If the error flag is set, the remaining bits refer to more error details that are not clear.
$arresult?
The $arresult?
returns manual measurements taken by the user, either by
scanning the sensor or using a testing strip (for either blood sugar or β-ketone
measurement)
The output follows the Multiple record command output format as described in the shared protocol documentation.
Multiple record types have been identified; the second value in the record identifies the type; type 2 is a manual reading, record type 5 identifies a time change event.
Reading record fields
record-id = 1*5DIGIT
record-type = "2"
month = 1*2DIGIT
day = 1*2DIGIT
year = 1*2DIGIT
hour = 1*2DIGIT
minute = 1*2DIGIT
second = 1*2DIGIT
unknown = "1"
-
Identifies the type of reading in the record
reading-type = blood-glucose / blood-ketone / sensor-glucose blood-glucose = "0" blood-ketone = "1" sensor-glucose = "2"
-
unknown = "0"
-
unknown = "0" / "1"
This appears to be 1 when either an error is present, or when the read value is LO.
-
value = 1*DIGIT
When
reading-type
is eitherblood-glucose
orsensor-glucose
, this represent the blood sugar reading in mg/dL.When
reading-type
isblood-ketone
, this represent the β-ketone reading in mmol/l after applyvalue
/18. It seems that the value is reported in mg/dL and the conversion is using the wrong molar mass system for conversion. But based on actual measurements the results are correct this way. -
unknown = "0" / "1"
This appears to be 0 for values read from a blood strip, and 1 for values read from sensor. Appears redundant with the
reading-type
field. -
Corresponds to the arrow indicator in the UI.
direction-indicator = none / down-fast / down / steady / up / up-fast none = "0" down-fast = "1" down = "2" steady = "3" up = "4" up-fast = "5"
-
sports-flag = "0" / "1"
medication-flag = "0" / "1"
-
rapid-acting-insulin-flag = "0" / "1"
See field 44 for value†.
-
long-acting-insulin-flag = "0" / "1"
See field 24 for value.
-
custom-comments-bitfield = 1*DIGIT
Custom comments 1-6 flags. To be interpreted as a bitfield, LSB first.
-
unknown = "0"
unknown = "0"
unknown = "0" / "1" / "2" / "3" / "4" / "5"
- Value of long Acting insulin in 0.5 IE. If you want proper IE, divide by 2
unknown = "0" / "1"
-
food-flag = "0" / "1"
See field 27 for value.
-
food-carbs-grams = 1*DIGIT
unknown = "0"
-
error-bitfield = 1*5DIGIT
This field needs to be interpreted as a bitfield (in decimal representation). Flag 0x8000 indicates an error (invalid reading). If the error flag is set, the remaining bits refer to more error details that are not clear.
In the Event View on the device, these correspond to Err3 errors.
-
custom-comment-1 = DQUOTE *VCHAR DQUOTE
‡ custom-comment-2 = DQUOTE *VCHAR DQUOTE
‡custom-comment-3 = DQUOTE *VCHAR DQUOTE
‡custom-comment-4 = DQUOTE *VCHAR DQUOTE
‡custom-comment-5 = DQUOTE *VCHAR DQUOTE
‡custom-comment-6 = DQUOTE *VCHAR DQUOTE
‡unknown = "7"
†month = 1*2DIGIT
* †day = 1*2DIGIT
* †year = 1*2DIGIT
* †hour = 1*2DIGIT
* †minute = 1*2DIGIT
* †second = 1*2DIGIT
* †unknown = "1"
* †- Value of rapid acting insulin in 0.5 IE. If you want proper IE, divide by 2.
* These values are identical to values 3-9, regardless of what time the notes were added to the record. Which seems to make them entirely redundant.
† The number of columns in a record can be different. If a rapid acting insulin value has been set, then it is > 44, otherwise the record has only entries up to comment 6.
‡ Be aware that custom comments are shown in every record. The bitfield in field 19. shows which comments are actually set.
Time change record fields
record-id = 1*5DIGIT
record-type = "5"
new-month = 1*2DIGIT
new-day = 1*2DIGIT
new-year = 1*2DIGIT
new-hour = 1*2DIGIT
new-minute = 1*2DIGIT
new-second = 1*2DIGIT
unknown
old-month = 1*2DIGIT
old-day = 1*2DIGIT
old-year = 1*2DIGIT
old-hour = 1*2DIGIT
old-minute = 1*2DIGIT
old-second = 1*2DIGIT
unknown
unknown
unknown
unknown
unknown
$swreset
Restart the Libre device, not erasing any information.
swreset-cmd = "$swreset"
swreset-response = CRLF
$resetpatient
This command completely resets the FreeStyle Libre reader, bringing it effectively to factory reset.
CAUTION! This erases all information on the device, including currently-enabled sensors.
While not accessible via the protocol, a reset does not erases the "Event Log" as available on the device.
resetpatient-cmd = "$resetpatient"
resetpatient-response = *("Erasing Sector @ 0x" 6 HEXDIGIT CRLF)
Sound Settings
It's possible to query and set the notification and touch tone settings of FreeStyle Libre devices through two commands.
The commands have first been identified on FreeStyle Insulinx but are not tested on it.
notifications = notifications-enabled / notifications-disabled
notifications-enabled = "1"
notifications-disabled = "0"
vibrate = vibrate-enabled / vibrate-disabled
vibrate-enabled = "1"
vibrate-disabled = "0"
touch-tone = touch-tone-enabled / touch-tone-disabled
touch-tone-enabled = "1"
touch-tone-disabled = "0"
volume = volume-high / volume-low
volume-high = "1"
volume-low = "0"
ntsound-cmd = "$ntsound" ("?" / "," notifications "," vibrate)
ntsound-query-response = notifications "," vibrate CRLF
btsound-cmd = "$btsound" ("?" / "," touch-tone "," volume)
btsound-query-response = touch-tone "," volume
Reminders ($getrmndr
)
It's possible to read the reminders status for the reader device.
The commands have first been identified on FreeStyle Insulinx but are not tested on it.
get-reminder-command = "$getrmndr,0"
get-reminder-response = 12 (reminder-entry CRLF)
reminder-entry = reminder-repeat ","
reminder-action ","
( reminder-enabled / reminder-disabled ) ","
reminder-hour "," reminder-minute
reminder-repeat = reminder-off / reminder-daily / reminder-timer
reminer-off = "0"
reminder-once = "1"
reminder-daily = "2"
reminder-timer = "3"
reminder-action = reminder-glucose / reminder-insulin / reminder-alarm
reminder-glucose = "10"
reminder-insulin = "11"
reminder-alarm = "12"
reminder-enabled = "1"
reminder-disabled = "0"
reminder-hour = 1*2 DIGIT
reminder-minute = 1*2 DIGIT
Note that while other $getrmndr
arguments than 0 will be accepted by the
device, they return no data at all.
When the repeat is "off" (0
), all other fields are also 0
.
When the repeat is timer, the hour/minutes are the repeat time from the beginning of the reminder.
Native Glucose Units
The $uom?
command reports the native unit of measure of the device.
uom-cmd = "$uom?"
uom-msg = uom-mmoll / uom-mgdl CRLF
uom-mmol = "0"
uom-mgdl = "1"
Other Commands
The following commands are sent by various software used by the Libre, but their output is not obvious.
$brandname?
Appears to report the brand name of the device, possibly differing among marketing regions.
brandname-cmd = "$brandname?"
brandname-msg = "FreeStyle Libre" CRLF
$marketlev?
Unknown respoonse.
marketlev-cmd = "$marketlev?"
marketlev-msg = "1,0,0,0" CRLF
Language settings
The command $lang?
reports the currently configured language.
The command $lang,
allows changing the configured language (if available in
the firmware of the device.) Note that this allows to configure a language
that is not visible to set in the interface, though in that case the reader
will display the selected language as Español.
The command $langset?
reports the list of languages available to set through
the UI itself.
And similarly the $langset,
command allows to change the list of available
languages.
get-lang-cmd = "$lang?"
get-lang-msg = language-code CRLF
set-lang-cmd = "$lang," language-code
set-lang-msg = CRLF
get-configured-langs-cmd = "$langset?"
get-configured-langs-msg = language-code *("," language-code)
set-configured-langs-cmd = "$langset" 1*("," language-code)
set-configured-langs-msg = CRLF
language-code = pt-br / es-us / en-us / de / fr / it / en-gb / fr-ca /
zh / jp / nl / sv / es-es / no / dk / fi / el / pl /
pt-pt / ru / tr / ar / he
pt-br = "0"
es-us = "1"
en-us = "2"
de = "3"
fr = "4"
it = "5"
en-gb = "6"
fr-ca = "7"
zh = "8"
jp = "9"
nl = "10"
sv = "11"
es-es = "12"
no = "13"
dk = "14"
fi = "15"
el = "16"
pl = "17"
pt-pt = "18"
ru = "19"
tr = "20"
ar = "21"
he = "22"
$iobstatus?
Originally identified on FreeStyle Insulinx.
iobstatus-cmd = "$iobstatus?"
iobstatus-msg = "255,255" CRLF
$foodunits?
Originally identified on FreeStyle Insulinx.
foodunits-cmd = "$foodunits?"
foodunits-msg = "0" CRLF
$svgsdef?
Originally identified on FreeStyle Insulinx.
svgsdef-cmd = "$svgsdef?"
svgsdef-msg = "255" CRLF
$corsetup?
Originally identified on FreeStyle Insulinx.
corsetup-cmd = "$corsetup?"
corsetup-msg = "255" CRLF
$insdose?
Originally identified on FreeStyle Insulinx.
insdose-cmd = "$insdose?"
insdose-msg = "1" CRLF
$inscalsetup?
Originally identified on FreeStyle Insulinx.
inscalsetup-cmd = "$inscalsetup?"
inscalsetup-msg = "0,0" CRLF
$carbratio?
Originally identified on FreeStyle Insulinx.
carbratio-cmd = "$carbratio?"
carbratio-msg = "0,0" CRLF
"1,0" CRLF
"2,0" CRLF
"3,0" CRLF
"4,0" CRLF
"0" CRLF
$svgsratio?
Originally identified on FreeStyle Insulinx.
svgsratio-cmd = "$svgsratio?"
svgsratio-msg = "0,0" CRLF
"1,0" CRLF
"2,0" CRLF
"3,0" CRLF
"4,0" CRLF
"0" CRLF
$cttype?
Originally identified on FreeStyle Insulinx.
cttype-cmd = "$cttype?"
cttype-msg = "255" CRLF
$bgdrop?
Originally identified on FreeStyle Insulinx.
bgdrop-cmd = "$bgdrop?"
bgdrop-msg = "0,255" CRLF
"1,0" CRLF
"2,0" CRLF
"3,0" CRLF
"4,0" CRLF
"0" CRLF
$bgtrgt?
Originally identified on FreeStyle Insulinx.
bgtrgt-cmd = "$bgtrgt?"
bgtrgt-msg = "0,0" CRLF
"1,0" CRLF
"2,0" CRLF
"3,0" CRLF
"4,0" CRLF
"0" CRLF
$bgtgrng?
Originally identified on FreeStyle Insulinx.
bgtgrng-cmd = "$bgtgrng?"
bgtgrng-msg = "0,0,0" CRLF
"1,0,0" CRLF
"2,0,0" CRLF
"3,0,0" CRLF
"4,0,0" CRLF
"0" CRLF
$tagsenbl?
Originally identified on FreeStyle Insulinx.
tagsenbl-cmd = "$tagsenbl?"
tagsenbl-msg = CRLF
$patch?
Return information about the sensors (patches) that the device initialized.
The returned message is in a similar text format to "multi records" responses, but with a different structure.
patch-response = empty-log / patch-response-detailed
empty-log = "Log Empty" CRLF
csv-line = *( value "," ) value
value = 1*DIGIT
checksum = 8HEXDIGIT
patch-response-detailed = csv-line CRLF
"PID: " csv-line CRLF
"SW Versions: " csv-line CRLF
csv-line CRLF
"Event Log: " csv-line CRLF
csv-line CRLF
"AFE Cal Data: " csv-line CRLF
"Unused: " csv-line
"1," checksum
The <checksum>
field is calculated in the same way as multiple records
commands: by summing up the ASCII value of each of the bytes forming the
response set, up to and including the final newline before 1,
.