diff options
author | Ben West <bewest@gmail.com> | 2016-05-28 11:22:52 -0700 |
---|---|---|
committer | Ben West <bewest@gmail.com> | 2016-05-28 11:22:52 -0700 |
commit | cf10d70fe0c724286d6e84c869d63eefd077e331 (patch) | |
tree | 10c8bc446b74833076b213eabeed154486399ea0 | |
parent | ff9e632209317d1c16ceb3d78f77c244504be474 (diff) |
support fetching cal_set
Many thanks to @LorelaiL for putting up with some my remedial questions.
-rw-r--r-- | dexcom_reader/database_records.py | 90 | ||||
-rw-r--r-- | dexcom_reader/readdata.py | 4 |
2 files changed, 91 insertions, 3 deletions
diff --git a/dexcom_reader/database_records.py b/dexcom_reader/database_records.py index 8d471f4..6d5b37b 100644 --- a/dexcom_reader/database_records.py +++ b/dexcom_reader/database_records.py | |||
@@ -111,13 +111,99 @@ class InsertionRecord(GenericTimestampedRecord): | |||
111 | 111 | ||
112 | 112 | ||
113 | class Calibration(GenericTimestampedRecord): | 113 | class Calibration(GenericTimestampedRecord): |
114 | FORMAT = '<2Iddd3cdb' | ||
115 | # CAL_FORMAT = '<2Iddd3cdb' | ||
116 | FIELDS = [ 'slope', 'intercept', 'scale', 'decay', 'numsub', 'raw' ] | ||
114 | @property | 117 | @property |
115 | def raw(self): | 118 | def raw (self): |
116 | return binascii.hexlify(bytearray(self.data)) | 119 | return binascii.hexlify(self.raw_data) |
120 | @property | ||
121 | def slope (self): | ||
122 | return self.data[2] | ||
123 | @property | ||
124 | def intercept (self): | ||
125 | return self.data[3] | ||
126 | @property | ||
127 | def scale (self): | ||
128 | return self.data[4] | ||
129 | @property | ||
130 | def decay (self): | ||
131 | return self.data[8] | ||
132 | @property | ||
133 | def numsub (self): | ||
134 | return int(self.data[9]) | ||
117 | 135 | ||
118 | def __repr__(self): | 136 | def __repr__(self): |
119 | return '%s: CAL SET:%s' % (self.display_time, self.raw) | 137 | return '%s: CAL SET:%s' % (self.display_time, self.raw) |
120 | 138 | ||
139 | LEGACY_SIZE = 148 | ||
140 | REV_2_SIZE = 249 | ||
141 | @classmethod | ||
142 | def _ClassSize(cls): | ||
143 | |||
144 | return cls.REV_2_SIZE | ||
145 | |||
146 | @classmethod | ||
147 | def Create(cls, data, record_counter): | ||
148 | offset = record_counter * cls._ClassSize() | ||
149 | cal_size = struct.calcsize(cls.FORMAT) | ||
150 | raw_data = data[offset:offset + cls._ClassSize()] | ||
151 | |||
152 | cal_data = data[offset:offset + cal_size] | ||
153 | unpacked_data = cls._ClassFormat().unpack(cal_data) | ||
154 | return cls(unpacked_data, raw_data) | ||
155 | |||
156 | def __init__ (self, data, raw_data): | ||
157 | self.page_data = raw_data | ||
158 | self.raw_data = raw_data | ||
159 | self.data = data | ||
160 | subsize = struct.calcsize(SubCal.FORMAT) | ||
161 | offset = self.numsub * subsize | ||
162 | calsize = struct.calcsize(self.FORMAT) | ||
163 | caldata = raw_data[:calsize] | ||
164 | subdata = raw_data[calsize:calsize + offset] | ||
165 | crcdata = raw_data[calsize+offset:calsize+offset+2] | ||
166 | |||
167 | subcals = [ ] | ||
168 | for i in xrange(self.numsub): | ||
169 | offset = i * subsize | ||
170 | raw_sub = subdata[offset:offset+subsize] | ||
171 | sub = SubCal(raw_sub, self.data[1]) | ||
172 | subcals.append(sub) | ||
173 | |||
174 | self.subcals = subcals | ||
175 | |||
176 | self.check_crc() | ||
177 | def to_dict (self): | ||
178 | res = super(Calibration, self).to_dict( ) | ||
179 | res['subrecords'] = [ sub.to_dict( ) for sub in self.subcals ] | ||
180 | return res | ||
181 | @property | ||
182 | def crc(self): | ||
183 | return struct.unpack('H', self.raw_data[-2:])[0] | ||
184 | |||
185 | |||
186 | class SubCal (GenericTimestampedRecord): | ||
187 | FORMAT = '<IIIIc' | ||
188 | BASE_FIELDS = [ ] | ||
189 | FIELDS = [ 'entered', 'meter', 'sensor', 'applied', ] | ||
190 | def __init__ (self, raw_data, displayOffset=None): | ||
191 | self.raw_data = raw_data | ||
192 | self.data = self._ClassFormat().unpack(raw_data) | ||
193 | self.displayOffset = displayOffset | ||
194 | @property | ||
195 | def entered (self): | ||
196 | return util.ReceiverTimeToTime(self.data[0]) | ||
197 | @property | ||
198 | def meter (self): | ||
199 | return int(self.data[1]) | ||
200 | @property | ||
201 | def sensor (self): | ||
202 | return int(self.data[2]) | ||
203 | @property | ||
204 | def applied (self): | ||
205 | return util.ReceiverTimeToTime(self.data[3]) | ||
206 | |||
121 | class MeterRecord(GenericTimestampedRecord): | 207 | class MeterRecord(GenericTimestampedRecord): |
122 | FORMAT = '<2IHIH' | 208 | FORMAT = '<2IHIH' |
123 | FIELDS = ['meter_glucose', 'meter_time' ] | 209 | FIELDS = ['meter_glucose', 'meter_time' ] |
diff --git a/dexcom_reader/readdata.py b/dexcom_reader/readdata.py index cc02de3..5e91499 100644 --- a/dexcom_reader/readdata.py +++ b/dexcom_reader/readdata.py | |||
@@ -251,7 +251,7 @@ class Dexcom(object): | |||
251 | assert ord(packet.command) == 1 | 251 | assert ord(packet.command) == 1 |
252 | # first index (uint), numrec (uint), record_type (byte), revision (byte), | 252 | # first index (uint), numrec (uint), record_type (byte), revision (byte), |
253 | # page# (uint), r1 (uint), r2 (uint), r3 (uint), ushort (Crc) | 253 | # page# (uint), r1 (uint), r2 (uint), r3 (uint), ushort (Crc) |
254 | header_format = '<2I2c4IH' | 254 | header_format = '<2IcB4IH' |
255 | header_data_len = struct.calcsize(header_format) | 255 | header_data_len = struct.calcsize(header_format) |
256 | header = struct.unpack_from(header_format, packet.data) | 256 | header = struct.unpack_from(header_format, packet.data) |
257 | header_crc = crc16.crc16(packet.data[:header_data_len-2]) | 257 | header_crc = crc16.crc16(packet.data[:header_data_len-2]) |
@@ -268,9 +268,11 @@ class Dexcom(object): | |||
268 | 268 | ||
269 | def ParsePage(self, header, data): | 269 | def ParsePage(self, header, data): |
270 | record_type = constants.RECORD_TYPES[ord(header[2])] | 270 | record_type = constants.RECORD_TYPES[ord(header[2])] |
271 | revision = int(header[3]) | ||
271 | generic_parser_map = { | 272 | generic_parser_map = { |
272 | 'USER_EVENT_DATA': database_records.EventRecord, | 273 | 'USER_EVENT_DATA': database_records.EventRecord, |
273 | 'METER_DATA': database_records.MeterRecord, | 274 | 'METER_DATA': database_records.MeterRecord, |
275 | 'CAL_SET': database_records.Calibration, | ||
274 | 'INSERTION_TIME': database_records.InsertionRecord, | 276 | 'INSERTION_TIME': database_records.InsertionRecord, |
275 | 'EGV_DATA': database_records.EGVRecord, | 277 | 'EGV_DATA': database_records.EGVRecord, |
276 | 'SENSOR_DATA': database_records.SensorRecord, | 278 | 'SENSOR_DATA': database_records.SensorRecord, |