.. highlight:: python Logger ====== The MetaWear board can log sensor data and store it in the internal memory of the device using ``loggers`` to be retrieved at a later time. Loggers record data from a data signal and are represented by the `MblMwDataLogger `_ struct. Create an ``MblMwDataLogger`` object by calling `mbl_mw_datasignal_log `_ with the data signal you want to log. If successful, the callback function will be executed with a `MblMwDataLogger `_ pointer and if creating the logger failed, a ``null`` pointer will be returned. :: signal = libmetawear.mbl_mw_acc_get_acceleration_data_signal(d.board) logger = create_voidp(lambda fn: libmetawear.mbl_mw_datasignal_log(signal, None, fn), resource = "acc_logger") :: def logger_ready(self, context, pointer): self.logger = pointer logger_created_fn= FnVoid_VoidP_VoidP(logger_ready) libmetawear.mbl_mw_datasignal_log(signal, None, logger_created_fn) MblMwDataLogger objects only interact with the specific data signal, they do not control the logging features. Logging control functions are detailed in the :doc:`logging` section. ID -- MblMwDataLogger objects are identified by a numerical id. This id can be used to keep track of loggers when there is considerable time between the start of a log and the download of a log. It is also useful to get the state of the device (i.e is my device still downloading?). You can retrieve the id by calling `mbl_mw_logger_get_id `_. The id is used to retrieve existing loggers from the API with the `mbl_mw_logger_lookup_id `_ function. :: sensor_data_handler= FnVoid_VoidP_DataP(sensorDataHandler) logger = libmetawear.mbl_mw_logger_lookup_id(board, 0) libmetawear.mbl_mw_logger_subscribe(logger, None, sensor_data_handler) Handling Data ------------- Like a data signal, you can subscribe to an MblMwDataLogger to process the downloaded data. Call `mbl_mw_logger_subscribe `_ to attach a callback function to the MblMwDataLogger which handles all received data. There is a helper function from the SDK CPP called sensorDataHandler() which you can use (found in `common.py `_). :: def sensorDataHandler(self, context, data): // See full definition in common.py if (data.contents.type_id == DataTypeId.UINT32): data_ptr= cast(data.contents.value, POINTER(c_uint)) self.data_uint32= c_uint() self.data_uint32.value= data_ptr.contents.value self.data = self.data_uint32 elif (data.contents.type_id == DataTypeId.INT32 or data.contents.type_id == DataTypeId.SENSOR_ORIENTATION): data_ptr= cast(data.contents.value, POINTER(c_int)) self.data_int32= c_int() self.data_int32.value= data_ptr.contents.value self.data = self.data_int32 elif (data.contents.type_id == DataTypeId.FLOAT): data_ptr= cast(data.contents.value, POINTER(c_float)) self.data_float= c_float() self.data_float.value= data_ptr.contents.value self.data = self.data_float elif (data.contents.type_id == DataTypeId.CARTESIAN_FLOAT): data_ptr= cast(data.contents.value, POINTER(CartesianFloat)) self.data_cartesian_float= copy.deepcopy(data_ptr.contents) self.data = self.data_cartesian_float elif (data.contents.type_id == DataTypeId.QUATERNION): data_ptr= cast(data.contents.value, POINTER(Quaternion)) self.data= copy.deepcopy(data_ptr.contents) else: raise RuntimeError('Unrecognized data type id: ' + str(data.contents.type_id)) There is also a helper function called `parse_value `_ which will handle the data types for you as part of the MetaWear class: :: callback = FnVoid_VoidP_DataP(lambda ctx, p: print("{epoch: %d, value: %s}" % (p.contents.epoch, parse_value(p)))) libmetawear.mbl_mw_logger_subscribe(logger, None, callback) :: def parse_value(pointer, **kwargs): """ Helper function to extract the value from a Data object. If you are storing the values to be used at a later time, call copy.deepcopy preserve the value. You do not need to do this if the underlying type is a native type or a byte array @params: pointer - Required : Pointer to a Data object n_elem - Optional : Nummber of elements in the value array if the type_id attribute is DataTypeId.DATA_ARRAY """ if (pointer.contents.type_id in _value_parsers): return _value_parsers[pointer.contents.type_id](pointer) elif (pointer.contents.type_id == DataTypeId.SENSOR_ORIENTATION): return _value_parsers[DataTypeId.INT32](pointer) elif (pointer.contents.type_id == DataTypeId.BYTE_ARRAY): array_ptr= cast(pointer.contents.value, POINTER(c_ubyte * pointer.contents.length)) return [array_ptr.contents[i] for i in range(0, pointer.contents.length)] elif (pointer.contents.type_id == DataTypeId.DATA_ARRAY): if 'n_elem' in kwargs: values = cast(pointer.contents.value, POINTER(POINTER(Data) * kwargs['n_elem'])) return [parse_value(values.contents[i]) for i in range(0, kwargs['n_elem'])] else: raise RuntimeError("Missing optional parameter 'n_elem' for parsing DataTypeId.DATA_ARRAY value") else: raise RuntimeError('Unrecognized data type id: ' + str(pointer.contents.type_id)) Removal ------- When you no longer want to log the values from a data signal, call `mbl_mw_logger_remove `_ to remove the logger. :: mbl_mw_logger_remove(logger)