44from threading import Event
55from .cbindings import *
66
7+ import copy
78import errno
89import json
910import os
10- import platform
1111import requests
12+ import sys
1213import time
1314import uuid
1415
16+ if sys .version_info [0 ] == 2 :
17+ range = xrange
18+
1519so_path = os .path .join (os .path .dirname (__file__ ), 'libmetawear.so' )
1620libmetawear = CDLL (so_path )
1721init_libmetawear (libmetawear )
@@ -67,6 +71,8 @@ def parse_value(p_data):
6771 return cast (p_data .contents .value , POINTER (Quaternion )).contents
6872 elif (p_data .contents .type_id == DataTypeId .CORRECTED_CARTESIAN_FLOAT ):
6973 return cast (p_data .contents .value , POINTER (CorrectedCartesianFloat )).contents
74+ elif (p_data .contents .type_id == DataTypeId .OVERFLOW_STATE ):
75+ return cast (p_data .contents .value , POINTER (OverflowState )).contents
7076 else :
7177 raise RuntimeError ('Unrecognized data type id: ' + str (p_data .contents .type_id ))
7278
@@ -87,6 +93,10 @@ def on_notification(self, handle, data):
8793class MetaWear (object ):
8894 _METABOOT_SERVICE = uuid .UUID ("00001530-1212-efde-1523-785feabcd123" )
8995
96+ @staticmethod
97+ def _convert (value ):
98+ return value if sys .version_info [0 ] == 2 else value .encode ('utf8' )
99+
90100 def __init__ (self , address , ** kwargs ):
91101 """
92102 Creates a MetaWear object
@@ -96,8 +106,7 @@ def __init__(self, address, **kwargs):
96106 device - Optional : hci device to use, defaults to 'hci0'
97107 deserialize - Optional : Deserialize the cached C++ SDK state if available, defaults to true
98108 """
99- self .hw = None
100- self .model = None
109+ self .info = {}
101110
102111 self .address = address
103112 self .cache = kwargs ['cache_path' ] if ('cache_path' in kwargs ) else ".metawear"
@@ -153,10 +162,22 @@ def connect(self, **kwargs):
153162 for c in self .gatt .discover_characteristics ():
154163 self .characteristics [c ['uuid' ]] = c ['value_handle' ]
155164
165+ if ('hardware' not in self .info ):
166+ self .info ['hardware' ] = self .gatt .read_by_uuid ("00002a27-0000-1000-8000-00805f9b34fb" )[0 ]
167+
168+ if ('manufacturer' not in self .info ):
169+ self .info ['manufacturer' ] = self .gatt .read_by_uuid ("00002a29-0000-1000-8000-00805f9b34fb" )[0 ]
170+
171+ if ('serial' not in self .info ):
172+ self .info ['serial' ] = self .gatt .read_by_uuid ("00002a25-0000-1000-8000-00805f9b34fb" )[0 ]
173+
174+ if ('model' not in self .info ):
175+ self .info ['model' ] = self .gatt .read_by_uuid ("00002a24-0000-1000-8000-00805f9b34fb" )[0 ]
176+
156177 if not self .in_metaboot_mode :
157178 init_event = Event ()
158179 def init_handler (device , status ):
159- self .init_status = status ;
180+ self .init_status = status
160181 init_event .set ()
161182
162183 init_handler_fn = FnVoid_VoidP_Int (init_handler )
@@ -169,10 +190,19 @@ def init_handler(device, status):
169190
170191 if 'serialize' not in kwargs or kwargs ['serialize' ]:
171192 self .serialize ()
193+ else :
194+ self .info ['firmware' ] = self .gatt .read_by_uuid ("00002a26-0000-1000-8000-00805f9b34fb" )[0 ]
172195
173196 def _read_gatt_char (self , caller , ptr_gattchar , handler ):
174- value = self .gatt .read_by_uuid (_gattchar_to_string (ptr_gattchar .contents ))[0 ]
175- value = value if platform .python_version_tuple ()[0 ] == '2' else value .encode ('utf8' )
197+ uuid = _gattchar_to_string (ptr_gattchar .contents )
198+ raw = self .gatt .read_by_uuid (uuid )[0 ]
199+
200+ if (('model' not in self .info ) and uuid == "00002a24-0000-1000-8000-00805f9b34fb" ):
201+ self .info ['model' ] = raw
202+ elif (uuid == "00002a26-0000-1000-8000-00805f9b34fb" ):
203+ self .info ['firmware' ] = raw
204+
205+ value = MetaWear ._convert (raw )
176206 buffer = create_string_buffer (value , len (value ))
177207 handler (caller , cast (buffer , POINTER (c_ubyte )), len (buffer .raw ))
178208
@@ -206,55 +236,70 @@ def _download_firmware(self, version=None):
206236 with open (info1 , "rb" ) as f :
207237 info1_content = json .load (f )
208238
209- if (self .hw == None ):
210- self .hw = self .gatt .read_by_uuid ("00002a27-0000-1000-8000-00805f9b34fb" )[0 ]
211-
212- if (self .model == None ):
213- self .model = self .gatt .read_by_uuid ("00002a24-0000-1000-8000-00805f9b34fb" )[0 ]
214-
215239 if version is None :
216240 versions = []
217- for k in info1_content [self .hw ] [self .model ]["vanilla" ].keys ():
241+ for k in info1_content [self .info [ 'hardware' ]] [self .info [ ' model' ] ]["vanilla" ].keys ():
218242 versions .append (LooseVersion (k ))
219243 versions .sort ()
220244 target = str (versions [- 1 ])
221245 else :
222- if version not in info1_content [self .hw ] [self .model ]["vanilla" ]:
246+ if version not in info1_content [self .info [ 'hardware' ]] [self .info [ ' model' ] ]["vanilla" ]:
223247 raise ValueError ("Firmware '%s' not available for this board" % (version ))
224248 target = version
225249
226- filename = info1_content [self .hw ] [self .model ]["vanilla" ][target ]["filename" ]
227- local_path = os .path .join (firmware_root , self .hw , self .model , "vanilla" , target , filename )
250+ filename = info1_content [self .info [ 'hardware' ]] [self .info [ ' model' ] ]["vanilla" ][target ]["filename" ]
251+ local_path = os .path .join (firmware_root , self .info [ 'hardware' ] , self .info [ ' model' ] , "vanilla" , target , filename )
228252
229253 if not os .path .isfile (local_path ):
230- url = "https://releases.mbientlab.com/metawear/{}/{}/{}/{}/{}" .format (self .hw , self .model , "vanilla" , target , filename )
254+ url = "https://releases.mbientlab.com/metawear/{}/{}/{}/{}/{}" .format (
255+ self .info ['hardware' ], self .info ['model' ], "vanilla" , target , filename
256+ )
231257 _download_file (url , local_path )
232258 return local_path
233259
234260 def serialize (self ):
235261 """
236262 Serialize and cache the SDK state
237263 """
238- path = os .path .join (self .cache , '%s.bin' % (self .address .replace (':' ,'' )))
264+ mac_str = self .address .replace (':' ,'' )
265+ path = os .path .join (self .cache , '%s.json' % (mac_str ))
239266
240- size = c_uint (0 )
241- state = cast (libmetawear .mbl_mw_metawearboard_serialize (self .board , byref (size )), POINTER (c_ubyte * size .value ))
242- with open (path , "wb" ) as f :
243- f .write (state .contents )
267+ state = { "info" : copy .deepcopy (self .info ) }
244268
245- libmetawear .mbl_mw_memory_free (state )
269+ size = c_uint (0 )
270+ cpp_state = cast (libmetawear .mbl_mw_metawearboard_serialize (self .board , byref (size )), POINTER (c_ubyte * size .value ))
271+ state ["cpp_state" ] = [cpp_state .contents [i ] for i in range (0 , size .value )]
272+ libmetawear .mbl_mw_memory_free (cpp_state )
246273
274+ with open (path , "w" ) as f :
275+ f .write (json .dumps (state , indent = 2 ))
276+
247277 def deserialize (self ):
248278 """
249279 Deserialize the cached SDK state
250280 """
251- path = os .path .join (self .cache , '%s.bin' % (self .address .replace (':' ,'' )))
281+ mac_str = self .address .replace (':' ,'' )
282+
283+ # See if old serialized state exists, if it does, read that then remove it
284+ path = os .path .join (self .cache , '%s.bin' % (mac_str ))
252285 if os .path .isfile (path ):
253286 with (open (path , "rb" )) as f :
254287 content = f .read ()
255288 raw = (c_ubyte * len (content )).from_buffer_copy (content )
256289 libmetawear .mbl_mw_metawearboard_deserialize (self .board , raw , len (content ))
290+
291+ os .remove (path )
292+ return True
293+
294+ path = os .path .join (self .cache , '%s.json' % (mac_str ))
295+ if os .path .isfile (path ):
296+ with (open (path , "r" )) as f :
297+ content = json .loads (f .read ())
298+ self .info = content ["info" ]
299+ raw = (c_ubyte * len (content )).from_buffer_copy (bytearray (content ["cpp_state" ]))
300+ libmetawear .mbl_mw_metawearboard_deserialize (self .board , raw , len (content ))
257301 return True
302+
258303 return False
259304
260305 def update_firmware_async (self , handler , ** kwargs ):
0 commit comments