sensor-sdk 0.0.27__tar.gz → 0.0.33__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: sensor-sdk
3
- Version: 0.0.27
3
+ Version: 0.0.33
4
4
  Summary: Python sdk for Synchroni
5
5
  Home-page: https://github.com/oymotion/SynchroniSDKPython
6
6
  Author: Martin Ye
@@ -8,6 +8,18 @@ Author-email: yecq_82@hotmail.com
8
8
  Requires-Python: >=3.9.0
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE.txt
11
+ Requires-Dist: numpy
12
+ Requires-Dist: setuptools
13
+ Requires-Dist: bleak
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: home-page
19
+ Dynamic: license-file
20
+ Dynamic: requires-dist
21
+ Dynamic: requires-python
22
+ Dynamic: summary
11
23
 
12
24
  # sensor-sdk
13
25
 
@@ -375,10 +387,10 @@ result = sensorProfile.setParam("NTF_IMU", "ON")
375
387
  result = sensorProfile.setParam("NTF_BRTH", "ON")
376
388
  # set BRTH data to ON or OFF, result is "OK" if succeed
377
389
 
378
- result = sensorProfile.setParam("FILTER_50Hz", "ON")
390
+ result = sensorProfile.setParam("FILTER_50HZ", "ON")
379
391
  # set 50Hz notch filter to ON or OFF, result is "OK" if succeed
380
392
 
381
- result = sensorProfile.setParam("FILTER_60Hz", "ON")
393
+ result = sensorProfile.setParam("FILTER_60HZ", "ON")
382
394
  # set 60Hz notch filter to ON or OFF, result is "OK" if succeed
383
395
 
384
396
  result = sensorProfile.setParam("FILTER_HPF", "ON")
@@ -364,10 +364,10 @@ result = sensorProfile.setParam("NTF_IMU", "ON")
364
364
  result = sensorProfile.setParam("NTF_BRTH", "ON")
365
365
  # set BRTH data to ON or OFF, result is "OK" if succeed
366
366
 
367
- result = sensorProfile.setParam("FILTER_50Hz", "ON")
367
+ result = sensorProfile.setParam("FILTER_50HZ", "ON")
368
368
  # set 50Hz notch filter to ON or OFF, result is "OK" if succeed
369
369
 
370
- result = sensorProfile.setParam("FILTER_60Hz", "ON")
370
+ result = sensorProfile.setParam("FILTER_60HZ", "ON")
371
371
  # set 60Hz notch filter to ON or OFF, result is "OK" if succeed
372
372
 
373
373
  result = sensorProfile.setParam("FILTER_HPF", "ON")
@@ -3,6 +3,7 @@ import queue
3
3
  import struct
4
4
  from asyncio import Queue
5
5
  from contextlib import suppress
6
+ from datetime import datetime
6
7
  from dataclasses import dataclass
7
8
  from enum import IntEnum
8
9
  from typing import Optional, Dict, List
@@ -88,6 +89,7 @@ class Command(IntEnum):
88
89
  GET_EMG_RAWDATA_CONFIG = (0x46,)
89
90
 
90
91
  SET_DATA_NOTIF_SWITCH = (0x4F,)
92
+ SET_FUNCTION_SWITCH = (0x85,)
91
93
 
92
94
  CMD_GET_EEG_CONFIG = (0xA0,)
93
95
  CMD_SET_EEG_CONFIG = (0xA1,)
@@ -372,12 +374,21 @@ class Response:
372
374
 
373
375
 
374
376
  class GForce:
375
- def __init__(self, device: BLEDevice, cmd_char: str, data_char: str, isUniversalStream: bool):
377
+ def __init__(
378
+ self,
379
+ device: BLEDevice,
380
+ cmd_char: str,
381
+ data_char: str,
382
+ isUniversalStream: bool,
383
+ event_loop: asyncio.AbstractEventLoop,
384
+ gforce_event_loop: asyncio.AbstractEventLoop,
385
+ ):
376
386
  self.device_name = ""
377
387
  self.client = None
388
+ self.event_loop = event_loop
389
+ self.gforce_event_loop = gforce_event_loop
378
390
  self.cmd_char = cmd_char
379
391
  self.data_char = data_char
380
- self.current_request: Request = None
381
392
  self.responses: Dict[Command, Queue] = {}
382
393
  self.resolution = SampleResolution.BITS_8
383
394
  self._num_channels = 8
@@ -394,7 +405,7 @@ class GForce:
394
405
  self._raw_data_buf = buf
395
406
 
396
407
  try:
397
- await asyncio.wait_for(client.connect(), sensor_utils._TIMEOUT)
408
+ await sensor_utils.async_call(client.connect(), sensor_utils._TIMEOUT, self.gforce_event_loop)
398
409
  except Exception as e:
399
410
  return
400
411
 
@@ -403,19 +414,22 @@ class GForce:
403
414
 
404
415
  try:
405
416
  if not self._is_universal_stream:
406
- await asyncio.wait_for(
417
+ await sensor_utils.async_call(
407
418
  client.start_notify(self.cmd_char, self._on_cmd_response),
408
419
  sensor_utils._TIMEOUT,
420
+ self.gforce_event_loop,
409
421
  )
422
+
410
423
  else:
411
- await asyncio.wait_for(
424
+ await sensor_utils.async_call(
412
425
  client.start_notify(self.data_char, self._on_universal_response),
413
426
  sensor_utils._TIMEOUT,
427
+ self.gforce_event_loop,
414
428
  )
415
429
  except Exception as e:
416
430
  return
417
431
 
418
- def _on_data_response(self, q: Queue[bytes], bs: bytearray):
432
+ def _on_data_response(self, q: queue.Queue[bytes], bs: bytearray):
419
433
  bs = bytes(bs)
420
434
 
421
435
  full_packet = []
@@ -444,63 +458,6 @@ class GForce:
444
458
  return
445
459
 
446
460
  q.put_nowait(bytes(full_packet))
447
- # data = None
448
- # data_type = DataType(full_packet[0])
449
- # packet = full_packet[1:]
450
- # match data_type:
451
- # case DataType.EMG_ADC:
452
- # data = self._convert_emg_to_raw(packet)
453
-
454
- # case DataType.ACC:
455
- # data = self._convert_acceleration_to_g(packet)
456
-
457
- # case DataType.GYO:
458
- # data = self._convert_gyro_to_dps(packet)
459
-
460
- # case DataType.MAG:
461
- # data = self._convert_magnetometer_to_ut(packet)
462
-
463
- # case DataType.EULER:
464
- # data = self._convert_euler(packet)
465
-
466
- # case DataType.QUAT:
467
- # data = self._convert_quaternion(packet)
468
-
469
- # case DataType.ROTA:
470
- # data = self._convert_rotation_matrix(packet)
471
-
472
- # case DataType.EMG_GEST: # It is not supported by the device (?)
473
- # data = self._convert_emg_gesture(packet)
474
-
475
- # case DataType.HID_MOUSE: # It is not supported by the device
476
- # pass
477
-
478
- # case DataType.HID_JOYSTICK: # It is not supported by the device
479
- # pass
480
-
481
- # case DataType.PARTIAL:
482
- # pass
483
- # case _:
484
- # raise Exception(
485
- # f"Unknown data type {data_type}, full packet: {full_packet}"
486
- # )
487
-
488
- # q.put_nowait(data)
489
-
490
- # def _convert_emg_to_raw(self, data: bytes) -> np.ndarray[np.integer]:
491
- # match self.resolution:
492
- # case SampleResolution.BITS_8:
493
- # dtype = np.uint8
494
-
495
- # case SampleResolution.BITS_12:
496
- # dtype = np.uint16
497
-
498
- # case _:
499
- # raise Exception(f"Unsupported resolution {self.resolution}")
500
-
501
- # emg_data = np.frombuffer(data, dtype=dtype)
502
-
503
- # return emg_data.reshape(-1, self._num_channels)
504
461
 
505
462
  @staticmethod
506
463
  def _convert_acceleration_to_g(data: bytes) -> np.ndarray[np.float32]:
@@ -565,6 +522,9 @@ class GForce:
565
522
  self._raw_data_buf.put_nowait(bytes(bs))
566
523
 
567
524
  def _on_cmd_response(self, _: BleakGATTCharacteristic, bs: bytearray):
525
+ sensor_utils.async_exec(self.async_on_cmd_response(bs), self.event_loop)
526
+
527
+ async def async_on_cmd_response(self, bs: bytearray):
568
528
  try:
569
529
  # print(bytes(bs))
570
530
  response = self._parse_response(bytes(bs))
@@ -754,6 +714,20 @@ class GForce:
754
714
  )
755
715
  )
756
716
 
717
+ async def set_function_switch(self, funcSwitch)-> bool:
718
+ body = [0xFF & funcSwitch]
719
+ body = bytes(body)
720
+ ret = await self._send_request(
721
+ Request(
722
+ cmd=Command.SET_FUNCTION_SWITCH,
723
+ body=body,
724
+ has_res=True,
725
+ )
726
+ )
727
+ if (len(ret) > 0 and ret[0] == 0):
728
+ return True
729
+ return False
730
+
757
731
  async def set_firmware_filter_switch(self, switchStatus: int):
758
732
  body = [0xFF & switchStatus]
759
733
  body = bytes(body)
@@ -765,7 +739,7 @@ class GForce:
765
739
 
766
740
  async def set_emg_raw_data_config(self, cfg=EmgRawDataConfig()):
767
741
  body = cfg.to_bytes()
768
- await self._send_request(
742
+ ret = await self._send_request(
769
743
  Request(
770
744
  cmd=Command.SET_EMG_RAWDATA_CONFIG,
771
745
  body=body,
@@ -773,7 +747,7 @@ class GForce:
773
747
  )
774
748
  )
775
749
 
776
- # print('_send_request returned:', ret)
750
+ # print('set_emg_raw_data_config returned:', ret)
777
751
 
778
752
  self.resolution = cfg.resolution
779
753
 
@@ -858,22 +832,20 @@ class GForce:
858
832
  )
859
833
 
860
834
  async def start_streaming(self, q: queue.Queue):
861
- await asyncio.wait_for(
835
+ await sensor_utils.async_call(
862
836
  self.client.start_notify(
863
837
  self.data_char,
864
838
  lambda _, data: self._on_data_response(q, data),
865
839
  ),
866
840
  sensor_utils._TIMEOUT,
841
+ self.gforce_event_loop,
867
842
  )
868
843
 
869
844
  async def stop_streaming(self):
870
845
  exceptions = []
871
- # try:
872
- # await asyncio.wait_for(self.set_subscription(DataSubscription.OFF), sensor_utils._TIMEOUT)
873
- # except Exception as e:
874
- # exceptions.append(e)
846
+
875
847
  try:
876
- await asyncio.wait_for(self.client.stop_notify(self.data_char), sensor_utils._TIMEOUT)
848
+ await sensor_utils.async_call(self.client.stop_notify(self.data_char), sensor_utils._TIMEOUT, self.gforce_event_loop)
877
849
  except Exception as e:
878
850
  exceptions.append(e)
879
851
 
@@ -883,49 +855,62 @@ class GForce:
883
855
  async def disconnect(self):
884
856
  with suppress(asyncio.CancelledError):
885
857
  try:
886
- await asyncio.wait_for(self.client.disconnect(), sensor_utils._TIMEOUT)
858
+ await sensor_utils.async_call(self.client.disconnect(), sensor_utils._TIMEOUT, self.gforce_event_loop)
887
859
  except Exception as e:
888
860
  pass
889
861
 
890
862
  def _get_response_channel(self, cmd: Command) -> Queue:
891
863
  if self.responses.get(cmd) != None:
892
- return None
893
-
894
- q = Queue()
895
- self.responses[cmd] = q
896
- return q
864
+ return self.responses[cmd]
865
+ else:
866
+ q = Queue()
867
+ self.responses[cmd] = q
868
+ return q
897
869
 
898
870
  async def _send_request(self, req: Request) -> Optional[bytes]:
871
+ return await sensor_utils.async_call(self._send_request_internal(req=req), runloop=self.event_loop)
899
872
 
873
+ async def _send_request_internal(self, req: Request) -> Optional[bytes]:
900
874
  q = None
901
875
  if req.has_res:
902
876
  q = self._get_response_channel(req.cmd)
903
- if q == None:
904
- # print("duplicate")
905
- return None
906
877
 
907
- while self.current_request != None:
908
- # print("wait")
909
- await asyncio.sleep(0.1)
878
+ timeStamp_old = -1
879
+ while not q.empty():
880
+ timeStamp_old = q.get_nowait()
881
+
882
+ now = datetime.now()
883
+ timestamp_now = now.timestamp()
884
+ if (timeStamp_old > -1) and ((timestamp_now - timeStamp_old) < 3):
885
+ print("send request too fast")
886
+ q.put_nowait(timeStamp_old)
887
+ return None
910
888
 
911
- self.current_request = req
912
889
  bs = bytes([req.cmd])
913
890
  if req.body is not None:
914
891
  bs += req.body
915
892
 
916
893
  # print(str(req.cmd) + str(req.body))
917
- await asyncio.wait_for(self.client.write_gatt_char(self.cmd_char, bs, response=False), 0.1)
894
+ try:
895
+ await sensor_utils.async_call(
896
+ self.client.write_gatt_char(self.cmd_char, bs),
897
+ 1,
898
+ runloop=self.gforce_event_loop,
899
+ )
900
+ except Exception as e:
901
+ self.responses[req.cmd] = None
902
+ return None
918
903
 
919
904
  if not req.has_res:
920
- self.current_request = None
905
+ self.responses[req.cmd] = None
921
906
  return None
922
907
 
923
908
  try:
924
- ret = await asyncio.wait_for(q.get(), 0.5)
925
- self.current_request = None
926
- self.responses[req.cmd] = None
909
+ ret = await asyncio.wait_for(q.get(), 2)
910
+ now = datetime.now()
911
+ timestamp_now = now.timestamp()
912
+ q.put_nowait(timestamp_now)
927
913
  return ret
928
914
  except Exception as e:
929
- self.current_request = None
930
915
  self.responses[req.cmd] = None
931
916
  return None
@@ -41,10 +41,12 @@ class DataType(IntEnum):
41
41
  NTF_EMG = 0x8 # EMG,用于标识肌电传感器采集的数据
42
42
  NTF_EEG = 0x10 # EEG,用于标识脑电传感器采集的数据
43
43
  NTF_ECG = 0x11 # ECG,用于标识心电传感器采集的数据
44
- NTF_IMPEDANCE = (0x12,) # 阻抗数据
45
- NTF_IMU = (0x13,) # 包含ACC和GYRO数据
46
- NTF_ADS = (0x14,) # 无单位ads数据
44
+ NTF_IMPEDANCE = 0x12 # 阻抗数据
45
+ NTF_IMU = 0x13 # 包含ACC和GYRO数据
46
+ NTF_ADS = 0x14 # 无单位ads数据
47
47
  NTF_BRTH = 0x15 # 呼吸,用于标识呼吸传感器采集的数据
48
+ NTF_IMPEDANCE_EXT = 0x16 # 阻抗数据扩展
49
+ NTF_DATA_TYPE_MAX = 0x17
48
50
 
49
51
 
50
52
  # 一次采样的数据,包含多个通道的数据,channal_samples 为一个二维数组, 第一个维度为通道索引,第二个维度为采样索引
@@ -81,6 +83,7 @@ class SensorData:
81
83
  self.sampleRate = 0
82
84
  self.channelCount = 0
83
85
  self.packageSampleCount = 0
86
+ self.packageIndexLength = 2
84
87
  self.channelSamples: List[List[Sample]] = list()
85
88
  self.lastPackageCounter = 0
86
89
  self.lastPackageIndex = 0
@@ -61,7 +61,7 @@ class SensorProfileDataCtx:
61
61
  self.saturationData: List[float] = list()
62
62
  self.dataPool = ThreadPoolExecutor(1, "data")
63
63
  self.init_map = {"NTF_EMG": "ON", "NTF_EEG": "ON", "NTF_ECG": "ON", "NTF_IMU": "ON", "NTF_BRTH": "ON"}
64
- self.filter_map = {"FILTER_50Hz": "ON", "FILTER_60Hz": "ON", "FILTER_HPF": "ON", "FILTER_LPF": "ON"}
64
+ self.filter_map = {"FILTER_50HZ": "ON", "FILTER_60HZ": "ON", "FILTER_HPF": "ON", "FILTER_LPF": "ON"}
65
65
  self.debugCSVWriter = None
66
66
  self.debugCSVPath = None
67
67
 
@@ -126,18 +126,41 @@ class SensorProfileDataCtx:
126
126
  data.channelMask = config.channel_mask
127
127
  data.minPackageSampleCount = packageCount
128
128
  data.packageSampleCount = 8
129
- data.K = 4000000.0 / 8388607.0
129
+
130
130
  data.clear()
131
- self.sensorDatas[SensorDataType.DATA_TYPE_EMG] = data
132
- self.notifyDataFlag |= DataSubscription.EMG_RAW
131
+
132
+ await self.gForce.set_package_id(True)
133
+
134
+ isNewEMG = await self.gForce.set_function_switch(2)
135
+
136
+ if (isNewEMG):
137
+ #new emg
138
+ data.packageIndexLength = 2
139
+ data.packageSampleCount = 8
140
+ data.resolutionBits = 0
141
+ data.K = 4000000.0 / 8388607.0
142
+ config.resolution = 8
143
+ else:
144
+ #old emg
145
+ data.packageIndexLength = 1
146
+ data.packageSampleCount = 8
147
+ data.resolutionBits = 8
148
+ gain = 1200
149
+ min_voltage = -1.25 * 1000000
150
+ max_voltage = 1.25 * 100000
151
+ div = 127.0
152
+ conversion_factor = (max_voltage - min_voltage) / gain / div
153
+ data.K = conversion_factor
154
+ config.resolution = 8
133
155
 
134
156
  config.fs = SamplingRate.HZ_500
135
157
  config.channel_mask = 255
136
- config.resolution = 8
137
158
  config.batch_len = 128
138
159
  await self.gForce.set_emg_raw_data_config(config)
139
160
 
140
- await self.gForce.set_package_id(True)
161
+ self.sensorDatas[SensorDataType.DATA_TYPE_EMG] = data
162
+ self.notifyDataFlag |= DataSubscription.EMG_RAW
163
+
141
164
  return data.channelCount
142
165
 
143
166
  async def initEEG(self, packageCount: int) -> int:
@@ -337,10 +360,10 @@ class SensorProfileDataCtx:
337
360
  switch = 0
338
361
  for filter in self.filter_map.keys():
339
362
  value = self.filter_map[filter]
340
- if filter == "FILTER_50Hz":
363
+ if filter == "FILTER_50HZ":
341
364
  if value == "ON":
342
365
  switch |= 1
343
- elif filter == "FILTER_60Hz":
366
+ elif filter == "FILTER_60HZ":
344
367
  if value == "ON":
345
368
  switch |= 2
346
369
  elif filter == "FILTER_HPF":
@@ -350,8 +373,9 @@ class SensorProfileDataCtx:
350
373
  if value == "ON":
351
374
  switch |= 8
352
375
  try:
353
- await self.gForce.set_firmware_filter_switch(switch)
354
- # await asyncio.sleep(0.1)
376
+ ret = await self.gForce.set_firmware_filter_switch(switch)
377
+ if ret == None:
378
+ return "ERROR: not success"
355
379
  return "OK"
356
380
  except Exception as e:
357
381
  return "ERROR: " + str(e)
@@ -372,10 +396,8 @@ class SensorProfileDataCtx:
372
396
  ####################################################################################
373
397
 
374
398
  async def process_data(self, buf: Queue[SensorData], sensor, callback):
375
- while self._is_running and self._rawDataBuffer.empty():
376
- await asyncio.sleep(0.1)
377
-
378
- while self._is_running and not self._rawDataBuffer.empty():
399
+ while self._is_running:
400
+ while not self._rawDataBuffer.empty():
379
401
  try:
380
402
  data: bytes = self._rawDataBuffer.get_nowait()
381
403
  except Exception as e:
@@ -385,7 +407,7 @@ class SensorProfileDataCtx:
385
407
  self._processDataPackage(data, buf, sensor)
386
408
  self._rawDataBuffer.task_done()
387
409
 
388
- while self._is_running and self.isDataTransfering and not buf.empty():
410
+ if self.isDataTransfering and not buf.empty():
389
411
  sensorData: SensorData = None
390
412
  try:
391
413
  sensorData = buf.get_nowait()
@@ -398,6 +420,8 @@ class SensorProfileDataCtx:
398
420
  print(e)
399
421
 
400
422
  buf.task_done()
423
+ else:
424
+ await asyncio.sleep(0.01)
401
425
 
402
426
  def _processDataPackage(self, data: bytes, buf: Queue[SensorData], sensor):
403
427
  v = data[0] & 0x7F
@@ -423,9 +447,32 @@ class SensorProfileDataCtx:
423
447
 
424
448
  self.impedanceData = impedanceData
425
449
  self.saturationData = saturationData
450
+ elif v == DataType.NTF_IMPEDANCE_EXT:
451
+ offset = 1
452
+ # packageIndex = ((data[offset + 1] & 0xff) << 8) | (data[offset] & 0xff)
453
+ offset += 2
454
+
455
+ impedanceData = []
456
+ saturationData = []
457
+
458
+ dataCount = self._device_info.EegChannelCount + self._device_info.EcgChannelCount
459
+
460
+ for index in range(dataCount):
461
+ impedance = struct.unpack_from("<f", data, offset)[0]
462
+ offset += 4
463
+ impedanceData.append(impedance)
464
+
465
+ for index in range(dataCount):
466
+ saturation = struct.unpack_from("<H", data, offset)[0]
467
+ offset += 2
468
+ saturationData.append(saturation / 10) # firmware value range 0 - 1000
469
+
470
+ self.impedanceData = impedanceData
471
+ self.saturationData = saturationData
472
+
426
473
  elif v == DataType.NTF_EMG:
427
474
  sensor_data = self.sensorDatas[SensorDataType.DATA_TYPE_EMG]
428
- if self.checkReadSamples(sensor, data, sensor_data, 3, 0):
475
+ if self.checkReadSamples(sensor, data, sensor_data, sensor_data.packageIndexLength + 1, 0):
429
476
  self.sendSensorData(sensor_data, buf)
430
477
  elif v == DataType.NTF_EEG:
431
478
  sensor_data = self.sensorDatas[SensorDataType.DATA_TYPE_EEG]
@@ -454,16 +501,23 @@ class SensorProfileDataCtx:
454
501
  if not self._is_data_transfering:
455
502
  return False
456
503
  try:
504
+ packageIndex = 0
505
+ maxPackageIndex = 0
506
+ if (sensorData.packageIndexLength == 2):
507
+ packageIndex = ((data[offset + 1] & 0xFF) << 8) | (data[offset] & 0xFF)
508
+ maxPackageIndex = 65535
509
+ else:
510
+ packageIndex = (data[offset] & 0xFF)
511
+ maxPackageIndex = 255
457
512
 
458
- packageIndex = ((data[offset + 1] & 0xFF) << 8) | (data[offset] & 0xFF)
459
- offset += 2
513
+ offset += sensorData.packageIndexLength
460
514
  newPackageIndex = packageIndex
461
515
  lastPackageIndex = sensorData.lastPackageIndex
462
516
  if sensorData.lastPackageCounter == 0 and sensorData.lastPackageIndex == 0 and packageIndex > 1:
463
517
  return False
464
518
 
465
519
  if packageIndex < lastPackageIndex:
466
- packageIndex += 65536 # 包索引是 U16 类型
520
+ packageIndex += (maxPackageIndex + 1)
467
521
  elif packageIndex == lastPackageIndex:
468
522
  return False
469
523
 
@@ -488,12 +542,14 @@ class SensorProfileDataCtx:
488
542
  self.readSamples(data, sensorData, 0, dataGap, lostSampleCount)
489
543
 
490
544
  if newPackageIndex == 0:
491
- sensorData.lastPackageIndex = 65535
545
+ sensorData.lastPackageIndex = maxPackageIndex
492
546
  else:
493
547
  sensorData.lastPackageIndex = newPackageIndex - 1
494
548
  sensorData.lastPackageCounter += deltaPackageIndex - 1
495
549
 
496
- self.readSamples(data, sensorData, dataOffset, dataGap, 0)
550
+ if (dataGap >= 0):
551
+ self.readSamples(data, sensorData, dataOffset, dataGap, 0)
552
+
497
553
  sensorData.lastPackageIndex = newPackageIndex
498
554
  sensorData.lastPackageCounter += 1
499
555
  except Exception as e:
@@ -561,8 +617,15 @@ class SensorProfileDataCtx:
561
617
  rawData = 0
562
618
  if sensorData.resolutionBits == 8:
563
619
  rawData = data[offset]
564
- rawData -= 128
620
+ rawData -= 119
565
621
  offset += 1
622
+ elif sensorData.resolutionBits == 12:
623
+ rawData = int.from_bytes(
624
+ data[offset : offset + 2],
625
+ byteorder="little",
626
+ signed=True,
627
+ )
628
+ offset += 2
566
629
  elif sensorData.resolutionBits == 16:
567
630
  rawData = int.from_bytes(
568
631
  data[offset : offset + 2],
@@ -673,7 +736,21 @@ class SensorProfileDataCtx:
673
736
 
674
737
  while self._is_running:
675
738
  while self._is_running and self._rawDataBuffer.empty():
676
- await asyncio.sleep(0.1)
739
+ if self._is_running and self.isDataTransfering and not buf.empty():
740
+ sensorData: SensorData = None
741
+ try:
742
+ sensorData = buf.get_nowait()
743
+ except Exception as e:
744
+ break
745
+ if not sensor_utils._terminated and sensorData != None and callback != None:
746
+ try:
747
+ asyncio.get_event_loop().run_in_executor(self.dataPool, callback, sensor, sensorData)
748
+ except Exception as e:
749
+ print(e)
750
+
751
+ buf.task_done()
752
+ else:
753
+ await asyncio.sleep(0.01)
677
754
  continue
678
755
 
679
756
  try:
@@ -694,53 +771,39 @@ class SensorProfileDataCtx:
694
771
 
695
772
  if self._concatDataBuffer[index] == 0x55:
696
773
  if (index + 1) >= data_size:
697
- index += 1
774
+ index = data_size
698
775
  continue
699
776
  n = self._concatDataBuffer[index + 1]
700
- if (index + 1 + n + 1) >= data_size:
701
- index += 1
777
+ if (index + 1 + n + 2) >= data_size:
778
+ index = data_size
702
779
  continue
703
- crc = self._concatDataBuffer[index + 1 + n + 1]
704
- calc_crc = sensor_utils.calc_crc8(self._concatDataBuffer[index + 2 : index + 2 + n])
705
- if crc != calc_crc:
780
+ crc16 = (self._concatDataBuffer[index + 1 + n + 2] << 8) | self._concatDataBuffer[index + 1 + n + 1]
781
+ calc_crc = sensor_utils.crc16_cal(self._concatDataBuffer[index + 2 : index + 2 + n], n)
782
+ if crc16 != calc_crc:
706
783
  index += 1
707
784
  continue
708
785
  if self._is_data_transfering:
709
786
  data_package = bytes(self._concatDataBuffer[index + 2 : index + 2 + n])
710
787
  self._processDataPackage(data_package, buf, sensor)
711
- while self._is_running and self.isDataTransfering and not buf.empty():
712
- sensorData: SensorData = None
713
- try:
714
- sensorData = buf.get_nowait()
715
- except Exception as e:
716
- break
717
- if not sensor_utils._terminated and sensorData != None and callback != None:
718
- try:
719
- asyncio.get_event_loop().run_in_executor(self.dataPool, callback, sensor, sensorData)
720
- except Exception as e:
721
- print(e)
722
-
723
- buf.task_done()
724
- last_cut = index = index + 2 + n
725
-
788
+ last_cut = index = index + 2 + n + 1
726
789
  elif self._concatDataBuffer[index] == 0xAA:
727
790
  if (index + 1) >= data_size:
728
- index += 1
791
+ index = data_size
729
792
  continue
730
793
  n = self._concatDataBuffer[index + 1]
731
- if (index + 1 + n + 1) >= data_size:
732
- index += 1
794
+ if (index + 1 + n + 2) >= data_size:
795
+ index = data_size
733
796
  continue
734
- crc = self._concatDataBuffer[index + 1 + n + 1]
735
- calc_crc = sensor_utils.calc_crc8(self._concatDataBuffer[index + 2 : index + 2 + n])
736
- if crc != calc_crc:
797
+ crc16 = (self._concatDataBuffer[index + 1 + n + 2] << 8) | self._concatDataBuffer[index + 1 + n + 1]
798
+ calc_crc = sensor_utils.crc16_cal(self._concatDataBuffer[index + 2 : index + 2 + n], n)
799
+ if crc16 != calc_crc:
737
800
  index += 1
738
801
  continue
739
802
  data_package = bytes(self._concatDataBuffer[index + 2 : index + 2 + n])
740
- if not sensor_utils._terminated:
741
- self.gForce._on_cmd_response(None, data_package)
742
- last_cut = index = index + 2 + n
743
803
 
804
+ if not sensor_utils._terminated:
805
+ await sensor_utils.async_call(self.gForce.async_on_cmd_response(data_package), runloop=sensor._event_loop)
806
+ last_cut = index = index + 2 + n + 1
744
807
  else:
745
808
  index += 1
746
809