Skip to content
UPetersen edited this page Nov 10, 2018 · 16 revisions

Welcome to the LibreMonitor wiki!

The Freestyle Libre sensor uses a TI RF430TAL152H chip, see Vandevenne. Some of its data can be read via NFC (ISO 15693). The following text describes some of the data content.

FRAM

The Freestyle Libre sensor's TI RF430TAL152H has 244 blocks of 8 bytes each of FRAM that can be read via nfc using a normal read blocks command. The FRAM is ordered into sections that comprise several blocks. Each section is secured by a arc 16 in the first two bytes. We will go through the FRAM on a section per section basis.

Sensor State Section (Header)

The first section consists of three blocks of data.

  block no |      FRAM bytes
 dec | hex | 00 01 02 03 04 05 06 07
-----+-----+------------------------
 000 |  00 | FD 61 18 19 01 00 00 00
 001 |  01 | 00 00 00 00 00 00 00 00  
 002 |  02 | 00 00 00 00 00 00 00 00

The first two bytes FD61 are the crc for this section. See this swift code or this or this c code for crc calculation implementations. There is also a swift playground you can use to toy around with the crc calculations. Byte 0x04 denotes the current state of the sensor. The following states have been observed:

0x01 ... sensor not yet started
0x02 ... sensor in warm up phase
0x03 ... sensor ready and working (up to 14 days and twelve hours)
0x04 ... sensor expired (for the following twelve hours, FRAM data section content does not change any more)
0x05 ... sensor shutdown
0x06 ... sensor failure

The meaning of all other bytes within this section is not yet understood.

Data Section (Body)

The data section contains the glucose data and some more yet unknown data. It ranges from block 3 (0x03) to block 39 (0x27) and is secured by a crc in the first to bytes, i.e. B229 in this case.

  block no |      FRAM bytes
 dec | hex | 00 01 02 03 04 05 06 07
-----+-----+------------------------
 003 |  03 | B2 29 02 00 83 B4 80 E6
 004 |  04 | 98 80 F0 8D 80 42 99 80
 005 |  05 | 00 00 00 00 00 00 00 00
 006 |  06 | 00 00 00 00 00 00 00 00
 007 |  07 | 00 00 00 00 00 00 00 00
 008 |  08 | 00 00 00 00 00 00 00 00
 009 |  09 | 00 00 00 00 00 00 00 00
 010 |  0A | 00 00 00 00 00 00 00 00
 011 |  0B | 00 00 00 00 00 00 00 00
 012 |  0C | 00 00 00 00 00 00 00 00
 013 |  0D | 00 00 00 00 00 00 00 00
 014 |  0E | 00 00 00 00 00 00 00 00
 015 |  0F | 00 00 00 00 00 00 00 00
 016 |  10 | 00 00 00 00 00 00 00 00
 017 |  11 | 00 00 00 00 00 00 00 00
 018 |  12 | 00 00 00 00 00 00 00 00
 019 |  13 | 00 00 00 00 00 00 00 00
 020 |  14 | 00 00 00 00 00 00 00 00
 021 |  15 | 00 00 00 00 00 00 00 00
 022 |  16 | 00 00 00 00 00 00 00 00
 023 |  17 | 00 00 00 00 00 00 00 00
 024 |  18 | 00 00 00 00 00 00 00 00
 025 |  19 | 00 00 00 00 00 00 00 00
 026 |  1A | 00 00 00 00 00 00 00 00
 027 |  1B | 00 00 00 00 00 00 00 00
 028 |  1C | 00 00 00 00 00 00 00 00
 029 |  1D | 00 00 00 00 00 00 00 00
 030 |  1E | 00 00 00 00 00 00 00 00
 031 |  1F | 00 00 00 00 00 00 00 00
 032 |  20 | 00 00 00 00 00 00 00 00
 033 |  21 | 00 00 00 00 00 00 00 00
 034 |  22 | 00 00 00 00 00 00 00 00
 035 |  23 | 00 00 00 00 00 00 00 00
 036 |  24 | 00 00 00 00 00 00 00 00
 037 |  25 | 00 00 00 00 00 00 00 00
 038 |  26 | 00 00 00 00 00 00 00 00
 039 |  27 | 00 00 00 00 02 00 00 00

The 02 in byte 2 is a pointer to the next block of 6 bytes with trend information and the 00 in byte 3 is a pointer to the next block of 6 bytes of history values to be written. Each of the data blocks consists of 6 bytes of data. There are

  • 16 trend data blocks for
    • the current value and
    • fifteen values for the last fifteen minutes and
  • 32 history data blocks for the last 8 hours, all fifteen minutes apart.

The trend data blocks are stored from byte 4 in block 3 to byte 3 in block 15 (0x0F) and the history data blocks are stored from byte 4 in block 15 (0x0F) to byte 3 in block 39 (0x27).

Furthermore there is a counter that counts up every minute in the two bytes 4 and 5 in block 39 (0x27). In this case after two minutes the counter is 02 00 which is 0x0002 (bytes have to be swapped).

Footer Section

The next section from byte 40 (0x28) to byte 42 (0x2B) has yet unknown content. It also has a crc in the first two bytes which is 58C7 in this case.

  block no |      FRAM bytes
 dec | hex | 00 01 02 03 04 05 06 07
-----+-----+------------------------
 040 |  28 | 58 C7 00 01 15 04 96 50
 041 |  29 | 14 07 96 80 5A 00 ED A6
 042 |  2A | 12 13 1B C8 04 99 28 66

Remaining Sections

The remaining blocks have unknown content that might be code or data. Playing around a little bit with the crc algorithm one finds that there is a crc in the first two bytes of block 43 (0x2B), 9E 42 in this case, that secures the bytes from block 43 (0x2B) to block 237 (0xED).

  block no |      FRAM bytes
 dec | hex | 00 01 02 03 04 05 06 07
-----+-----+------------------------
  43 |  2B | 9E 42 21 83 F2 90 07 00 
  44 |  2C | 06 08 02 24 0C 43 17 3C 
  45 |  2D | C2 43 08 08 B2 40 DF 00 
  46 |  2E | 08 08 D2 42 A2 F9 08 08 
  47 |  2F | D2 42 A3 F9 08 08 0C 41 

             ...

 235 |  EB | AB AB 2C 5A A4 00 CA FB 
 236 |  EC | A3 00 56 5A A2 00 BA F9 
 237 |  ED | A1 00 24 57 A0 00 AB AB 

Unfortunately I could not find a crc for the rest of data from block 238 (0xEE) to block 243 (0xF3).

  block no |      FRAM bytes
 dec | hex | 00 01 02 03 04 05 06 07
-----+-----+------------------------
 238 |  EE | 00 00 00 00 FF FF FF FF 
 239 |  EF | 20 00 71 62 00 00 00 00 
 240 |  F0 | 00 00 00 00 00 00 00 00 
 241 |  F1 | 00 00 AE 5C 00 00 A8 57 
 242 |  F2 | 00 00 28 4E 68 45 00 00 
 243 |  F3 | DC 5F AE 5A 7A 5A DA 50 

Serial Number

The serial number of a Freestyle Libre sensor can be derived from its uid one gets with a NFC reading. The numbers an letters of the serial number are coded in a compressed scheme that uses only 32 numbers and letters, by omitting the letters B, I, O and S. This information is stored in consecutive units of five bits (decimal 0 to 31). The encding thus is as follows:

 index: 0 1 2 3 4 5 6 7 8 9 10     11 12 13 14 15 16     17 18 19 20 21     22 23 24      25 26 27 28 29 30 31
 char:  0 1 2 3 4 5 6 7 8 9 A  (B) C  D  E  F  G  H  (I) J  K  L  M  N  (O) P  Q  R  (S)  T  U  V  W  X  Y  Z

Example:

Uid is E0 07 A0 00 00 25 90 5E, and the corresponding serial number is "0M00009DHCR". The first two bytes of the uid are standard bytes containing the manufacturer code, where 0x07 denotes "Texas Instruments Tag-it™" according to wikipedia, and are omitted in the further calculation.

  E0 07 A0 00 00 25 90 5E
  \   / \              /
   -+-   -----+--------
    |         |
    |         +-- This part encodes the Freestyle Libre serial number
    +-- Standard first two bytes, where 0x07 is the code for "Texas Instruments Tag-it™"

To retrieve the serial number convert the part without E0 07, i.e. A0 00 00 25 90 5E to binary representation:

  A    0     0    0     0    0     2    5     9    0     5    E
  1010 0000  0000 0000  0000 0000  0010 0101  1001 0000  0101 1110

Add two binary zeros at the end and then split this binary array in units of five bits length from the beginning. Calculate the corresponding decimal integer for each five bits unit and retreive the corresponding char from the table above:

+--  1010 0000  0000 0000  0000 0000  0010 0101  1001 0000  0101 1110   + 00
|
+->  10100 00000 00000 00000 00000 01001 01100 10000 01011 11000
       |     |     |     |     |     |     |     |     |     |
       |     |     |     |     |     |     |     |     |     +- = 24 -> "R"
       |     |     |     |     |     |     |     |     +------- = 11 -> "C"
       |     |     |     |     |     |     |     +------------- = 16 -> "H"
       |     |     |     |     |     |     +------------------- = 12 -> "D"
       |     |     |     |     |     +------------------------- =  9 -> "9"
       |     |     |     |     +------------------------------- =  0 -> "0"
       |     |     |     +------------------------------------- =  0 -> "0"
       |     |     +------------------------------------------- =  0 -> "0"
       |     +------------------------------------------------- =  0 -> "0"
       +------------------------------------------------------- = 20 -> "M"

Finally prepend "0" at the beginning an thus receive "0M00009DHCR" as the Freestyle Libre serial number in this example.

References

  1. Pierre Vandevenne was the first to investigate the Freestyle Libre data and did ground breaking work. See e.g. this blog post as a starting point and also read his follow ups.
  2. Marcel Klug made (besides providing the community with Liapp) a nice picture that also explains the FRAM content.
  3. Courtesy to Marek Macner, @keencave.