32
32
from time import sleep , monotonic , monotonic_ns
33
33
from micropython import const
34
34
35
+ # TODO: Remove on release
36
+ from .debug import channels , reports
37
+
35
38
# TODO: shorten names
36
39
# Channel 0: the SHTP command channel
37
40
_BNO_CHANNEL_SHTP_COMMAND = const (0 )
74
77
_BNO_REPORT_ROTATION_VECTOR = const (0x05 )
75
78
_BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR = const (0x09 )
76
79
_BNO_REPORT_STEP_COUNTER = const (0x11 )
80
+ _BNO_REPORT_SHAKE_DETECTOR = const (0x19 )
81
+
77
82
78
83
_DEFAULT_REPORT_INTERVAL = const (50000 ) # in microseconds = 50ms
79
84
_QUAT_READ_TIMEOUT = 0.500 # timeout in seconds
114
119
_BNO_REPORT_ROTATION_VECTOR : (_Q_POINT_14_SCALAR , 4 , 14 ,),
115
120
_BNO_REPORT_GEOMAGNETIC_ROTATION_VECTOR : (_Q_POINT_12_SCALAR , 4 , 14 ),
116
121
_BNO_REPORT_STEP_COUNTER : (1 , 1 , 12 ),
122
+ _BNO_REPORT_SHAKE_DETECTOR : (1 , 1 , 6 ),
117
123
}
118
124
119
125
DATA_BUFFER_SIZE = const (512 ) # data buffer size. obviously eats ram
@@ -168,7 +174,12 @@ def _parse_sensor_report_data(report_bytes):
168
174
# 10 Reserved
169
175
# 11 Reserved
170
176
def _parse_step_couter_report (report_bytes ):
171
- return unpack_from ("<h" , report_bytes , offset = 8 )[0 ]
177
+ return unpack_from ("<H" , report_bytes , offset = 8 )[0 ]
178
+
179
+
180
+ def _parse_shake_report (report_bytes ):
181
+ shake_bitfield = unpack_from ("<H" , report_bytes , offset = 4 )[0 ]
182
+ return (shake_bitfield & 0x111 ) > 0
172
183
173
184
174
185
def parse_sensor_id (buffer ):
@@ -222,7 +233,6 @@ def __init__(self, packet_bytes):
222
233
self .data = packet_bytes [_BNO_HEADER_LEN :data_end_index ]
223
234
224
235
def __str__ (self ):
225
- from .debug import channels , reports # pylint:disable=import-outside-toplevel
226
236
227
237
length = self .header .packet_byte_count
228
238
outstr = "\n \t \t ********** Packet *************\n "
@@ -252,11 +262,20 @@ def __str__(self):
252
262
and len (self .data ) >= 6
253
263
and self .data [5 ] in reports
254
264
):
255
- outstr += "DBG::\t \t \t Sensor Report Type: %s(%d )\n " % (
265
+ outstr += "DBG::\t \t \t Sensor Report Type: %s(%s )\n " % (
256
266
reports [self .data [5 ]],
257
- self .data [5 ],
267
+ hex ( self .data [5 ]) ,
258
268
)
259
269
270
+ if (
271
+ self .report_id == 0xFC
272
+ and len (self .data ) >= 6
273
+ and self .data [1 ] in reports
274
+ ):
275
+ outstr += "DBG::\t \t \t Enabled Feature: %s(%s)\n " % (
276
+ reports [self .data [1 ]],
277
+ hex (self .data [5 ]),
278
+ )
260
279
outstr += "DBG::\t \t Sequence number: %s\n " % self .header .sequence_number
261
280
outstr += "\n "
262
281
outstr += "DBG::\t \t Data:"
@@ -383,6 +402,20 @@ def gyro(self):
383
402
self ._process_available_packets ()
384
403
return self ._readings [_BNO_REPORT_GYROSCOPE ]
385
404
405
+ @property
406
+ def shake (self ):
407
+ """True if a shake was detected on any axis since the last time it was checked
408
+
409
+ This property has a "latching" behavior where once a shake is detected, it will stay in a
410
+ "shaken" state until the value is read. This prevents missing shake events but means that
411
+ this property is not guaranteed to reflect the shake state at the moment it is read
412
+ """
413
+ self ._process_available_packets ()
414
+ shake_detected = self ._readings [_BNO_REPORT_SHAKE_DETECTOR ]
415
+ # clear on read
416
+ if shake_detected :
417
+ self ._readings [_BNO_REPORT_SHAKE_DETECTOR ] = False
418
+
386
419
# # decorator?
387
420
def _process_available_packets (self ):
388
421
processed_count = 0
@@ -459,9 +492,27 @@ def _handle_control_report(self, report_id, report_bytes):
459
492
460
493
def _process_report (self , report_id , report_bytes ):
461
494
if report_id < 0xF0 :
495
+ self ._dbg ("\t Processing report:" , reports [report_id ])
496
+ if self ._debug :
497
+ outstr = ""
498
+ for idx , packet_byte in enumerate (report_bytes ):
499
+ packet_index = idx
500
+ if (packet_index % 4 ) == 0 :
501
+ outstr += "\n DBG::\t \t [0x{:02X}] " .format (packet_index )
502
+ outstr += "0x{:02X} " .format (packet_byte )
503
+ print (outstr )
504
+ self ._dbg ("" )
505
+
462
506
if report_id == _BNO_REPORT_STEP_COUNTER :
463
507
self ._readings [report_id ] = _parse_step_couter_report (report_bytes )
464
508
return
509
+ if report_id == _BNO_REPORT_SHAKE_DETECTOR :
510
+ shake_detected = _parse_shake_report (report_bytes )
511
+ # shake not previously detected - auto cleared by 'shake' property
512
+ if not self ._readings [_BNO_REPORT_SHAKE_DETECTOR ]:
513
+ self ._readings [_BNO_REPORT_SHAKE_DETECTOR ] = shake_detected
514
+ return
515
+
465
516
sensor_data = _parse_sensor_report_data (report_bytes )
466
517
# TODO: FIXME; Sensor reports are batched in a LIFO which means that multiple reports
467
518
# for the same type will end with the oldest/last being kept and the other
@@ -472,12 +523,14 @@ def _process_report(self, report_id, report_bytes):
472
523
473
524
# TODO: Make this a Packet creation
474
525
@staticmethod
475
- def _get_feature_enable_report (feature_id ):
526
+ def _get_feature_enable_report (
527
+ feature_id , report_interval = _DEFAULT_REPORT_INTERVAL
528
+ ):
476
529
# TODO !!! ALLOCATION !!!
477
530
set_feature_report = bytearray (17 )
478
531
set_feature_report [0 ] = _BNO_CMD_SET_FEATURE_COMMAND
479
532
set_feature_report [1 ] = feature_id
480
- pack_into ("<I" , set_feature_report , 5 , _DEFAULT_REPORT_INTERVAL )
533
+ pack_into ("<I" , set_feature_report , 5 , report_interval )
481
534
return set_feature_report
482
535
483
536
def _enable_feature (self , feature_id ):
0 commit comments