diff --git a/lib/drivers/abbott/abbottFreeStyleLibre.js b/lib/drivers/abbott/abbottFreeStyleLibre.js index f58ee702dd..f1fbedac2b 100644 --- a/lib/drivers/abbott/abbottFreeStyleLibre.js +++ b/lib/drivers/abbott/abbottFreeStyleLibre.js @@ -92,7 +92,7 @@ export default function (config) { progress(0); const getterFunctions = [ - cb => { protocol.setCompression(0, cb); }, + cb => { protocol.setCompression(1, cb); }, cb => { protocol.getDbSchema(cb); }, cb => { protocol.getCfgSchema(cb); }, cb => { protocol.getDateTime(cb); }, diff --git a/lib/drivers/abbott/freeStyleLibreConstants.js b/lib/drivers/abbott/freeStyleLibreConstants.js index e376711ce8..eea5a658c5 100644 --- a/lib/drivers/abbott/freeStyleLibreConstants.js +++ b/lib/drivers/abbott/freeStyleLibreConstants.js @@ -15,6 +15,7 @@ export const COMMAND = { export const OP_CODE = { GET_DATABASE: 0x31, GET_DB_SCHEMA: 0x34, + COMPRESSED_DATABASE: 0x35, GET_DATE_TIME: 0x41, GET_CFG_DATA: 0x51, GET_CFG_SCHEMA: 0x54, @@ -425,6 +426,11 @@ export const RESULT_VALUE_TYPE = { SCAN: 2 }; +export const COMPRESSION_TYPE = { + UNCOMPRESSED: 0xfd, + ZERO_COMPRESSED: 0xff +} + export const CRC32_TABLE = [ 0x00000000, 0x04c11db7, diff --git a/lib/drivers/abbott/freeStyleLibreData.js b/lib/drivers/abbott/freeStyleLibreData.js index 772ad87096..f1620ef727 100644 --- a/lib/drivers/abbott/freeStyleLibreData.js +++ b/lib/drivers/abbott/freeStyleLibreData.js @@ -26,7 +26,14 @@ import sundial from 'sundial'; import TZOUtil from '../../TimezoneOffsetUtil'; -import {OP_CODE, ERROR_DESCRIPTION, DB_RECORD_TYPE, CFG_TABLE_ID, RESULT_VALUE_TYPE} from './freeStyleLibreConstants'; +import { + OP_CODE, + ERROR_DESCRIPTION, + DB_RECORD_TYPE, + CFG_TABLE_ID, + RESULT_VALUE_TYPE, + COMPRESSION_TYPE +} from './freeStyleLibreConstants'; const FORMAT = { ERROR: 'bb', @@ -43,6 +50,7 @@ const OP_CODE_PROCESSING_ORDER = [ //OP_CODE.GET_DB_SCHEMA, // not used for now OP_CODE.GET_DATE_TIME, OP_CODE.GET_CFG_DATA, + OP_CODE.COMPRESSED_DATABASE, OP_CODE.GET_DATABASE ]; @@ -54,6 +62,7 @@ export class FreeStyleLibreData { this.opCodeHandlers = {}; this.opCodeHandlers[OP_CODE.GET_DATE_TIME] = this.handleDateTime.bind(this); this.opCodeHandlers[OP_CODE.GET_DB_SCHEMA] = this.handleDatabaseSchema.bind(this); + this.opCodeHandlers[OP_CODE.COMPRESSED_DATABASE] = this.handleCompressedDatabase.bind(this); this.opCodeHandlers[OP_CODE.GET_DATABASE] = this.handleDatabase.bind(this); this.opCodeHandlers[OP_CODE.GET_CFG_SCHEMA] = this.handleConfigSchema.bind(this); this.opCodeHandlers[OP_CODE.GET_CFG_DATA] = this.handleConfigData.bind(this); @@ -226,6 +235,54 @@ export class FreeStyleLibreData { } } + handleCompressedDatabase(aapPacket) { + let decompressedBuffer = new Buffer(1); + let compressedOffset = 0; + + // copy table ID + decompressedBuffer[0] = aapPacket.data[compressedOffset]; + compressedOffset++; + + while (compressedOffset < aapPacket.dataLength) { + const blockType = aapPacket.data[compressedOffset]; + compressedOffset++; + + // parse 24 bit little endian block length + let blockLength = aapPacket.data[compressedOffset] + | (aapPacket.data[compressedOffset + 1] << 8) + | (aapPacket.data[compressedOffset + 2] << 16); + compressedOffset += 3; + + blockLength *= 4; // convert number of uint32 values to number of uint8 values + + if (blockType === COMPRESSION_TYPE.UNCOMPRESSED) { + + decompressedBuffer = Buffer.concat( + [decompressedBuffer, aapPacket.data.slice(compressedOffset, compressedOffset + blockLength)]); + compressedOffset += blockLength; + + } else if (blockType === COMPRESSION_TYPE.ZERO_COMPRESSED) { + + decompressedBuffer = Buffer.concat([decompressedBuffer, Buffer.alloc(blockLength)]); + compressedOffset += blockLength; + + } else { + debug('handleCompressedDatabase: failed to decompress!'); + return; + } + } + + // build decompressed AAP packet to process + const decompressedAapPacket = { + packetLength: aapPacket.packetLength - aapPacket.dataLength + aapPacket.data.length, + data: decompressedBuffer, + dataLength: aapPacket.data.length, + opCode: OP_CODE.GET_DATABASE + }; + + this.handleDatabase(decompressedAapPacket); + } + handleDatabase(aapPacket) { if (aapPacket.dataLength === 0) { return;