sensor-sdk 0.0.7__tar.gz → 0.0.10__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.

Potentially problematic release.


This version of sensor-sdk might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sensor-sdk
3
- Version: 0.0.7
3
+ Version: 0.0.10
4
4
  Summary: Python sdk for Synchroni
5
5
  Home-page: https://github.com/oymotion/SynchroniSDKPython
6
6
  Author: Martin Ye
@@ -397,16 +397,20 @@ class GForce:
397
397
 
398
398
  if not client.is_connected:
399
399
  return
400
- if not self._is_universal_stream:
401
- await asyncio.wait_for(
402
- client.start_notify(self.cmd_char, self._on_cmd_response),
403
- utils._TIMEOUT,
404
- )
405
- else:
406
- await asyncio.wait_for(
407
- client.start_notify(self.data_char, self._on_universal_response),
408
- utils._TIMEOUT,
409
- )
400
+
401
+ try:
402
+ if not self._is_universal_stream:
403
+ await asyncio.wait_for(
404
+ client.start_notify(self.cmd_char, self._on_cmd_response),
405
+ utils._TIMEOUT,
406
+ )
407
+ else:
408
+ await asyncio.wait_for(
409
+ client.start_notify(self.data_char, self._on_universal_response),
410
+ utils._TIMEOUT,
411
+ )
412
+ except Exception as e:
413
+ return
410
414
 
411
415
  def _on_data_response(self, q: Queue[bytes], bs: bytearray):
412
416
  bs = bytes(bs)
@@ -875,4 +879,7 @@ class GForce:
875
879
  if not req.has_res:
876
880
  return None
877
881
 
878
- return await asyncio.wait_for(q.get(), utils._TIMEOUT)
882
+ try:
883
+ return await asyncio.wait_for(q.get(), utils._TIMEOUT)
884
+ except Exception as e:
885
+ return None
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  from concurrent.futures import ThreadPoolExecutor
2
3
  import threading
3
4
  from typing import Callable, Dict, List, Optional, Tuple
@@ -7,9 +8,8 @@ import bleak
7
8
  from sensor import sensor_profile
8
9
  from sensor import utils
9
10
  from sensor.sensor_profile import DeviceStateEx, SensorProfile
10
- import asyncio
11
11
 
12
- from sensor.utils import async_call, start_loop, sync_call, async_exec, timer
12
+ from sensor.utils import async_call, sync_call, async_exec
13
13
  from bleak import (
14
14
  BleakScanner,
15
15
  AdvertisementData,
@@ -27,6 +27,7 @@ class SensorController:
27
27
  with SensorController._instance_lock:
28
28
  if not hasattr(SensorController, "_instance"):
29
29
  SensorController._instance = object.__new__(cls)
30
+
30
31
  return SensorController._instance
31
32
 
32
33
  """
@@ -37,21 +38,8 @@ class SensorController:
37
38
  """
38
39
  初始化 SensorController 实例。
39
40
  """
40
- self._event_loop = asyncio.new_event_loop()
41
- self._event_thread = threading.Thread(target=start_loop, args=(self._event_loop,))
42
- self._event_thread.daemon = True
43
- self._event_thread.name = "SensorController event"
44
- self._event_thread.start()
45
- self._gforce_event_loop = asyncio.new_event_loop()
46
- self._gforce_event_thread = threading.Thread(target=start_loop, args=(self._gforce_event_loop,))
47
- self._gforce_event_thread.daemon = True
48
- self._gforce_event_thread.name = "BLE operation"
49
- self._gforce_event_thread.start()
50
- self._scanner = BleakScanner(
51
- detection_callback=self._match_device,
52
- service_uuids=[SERVICE_GUID, RFSTAR_SERVICE_GUID],
53
- )
54
41
  self._is_scanning = False
42
+ self._scanner: BleakScanner = None
55
43
  self._device_callback: Callable[[List[sensor_profile.BLEDevice]], None] = None
56
44
  self._device_callback_period = 0
57
45
  self._enable_callback: Callable[[bool], None] = None
@@ -62,15 +50,16 @@ class SensorController:
62
50
  反初始化 SensorController 类的实例。
63
51
 
64
52
  """
65
- self._event_loop.close()
66
- self._gforce_event_loop.close()
67
53
 
68
54
  def terminate(self):
69
55
  utils._terminated = True
56
+
70
57
  for sensor in self._sensor_profiles.values():
71
58
  if sensor.deviceState == DeviceStateEx.Connected or sensor.deviceState == DeviceStateEx.Ready:
72
59
  sensor._destroy()
73
60
 
61
+ utils.Terminate()
62
+
74
63
  def _match_device(self, _device: bleak.BLEDevice, adv: AdvertisementData):
75
64
  if _device.name == None:
76
65
  return False
@@ -150,15 +139,23 @@ class SensorController:
150
139
  if deviceMap.get(mac) != None:
151
140
  devices.append(self._sensor_profiles[mac].BLEDevice)
152
141
  else:
153
- newSensor = SensorProfile(device, adv, mac, self._gforce_event_loop)
142
+ newSensor = SensorProfile(device, adv, mac)
154
143
  deviceMap[mac] = newSensor
155
144
  devices.append(newSensor.BLEDevice)
156
145
 
157
146
  self._sensor_profiles = deviceMap
158
147
  return devices
159
148
 
149
+ def _init_scan(self):
150
+ if self._scanner == None:
151
+ self._scanner = BleakScanner(
152
+ detection_callback=self._match_device,
153
+ service_uuids=[SERVICE_GUID, RFSTAR_SERVICE_GUID],
154
+ )
155
+
160
156
  async def _async_scan(self, period):
161
157
  self._is_scanning = True
158
+ self._init_scan()
162
159
  found_devices = await self._scanner.discover(timeout=period / 1000, return_adv=True)
163
160
  self._is_scanning = False
164
161
  return self._process_ble_devices(found_devices)
@@ -171,7 +168,7 @@ class SensorController:
171
168
 
172
169
  :return: List[sensor_profile.BLEDevice]: BLEDevice列表
173
170
  """
174
- return sync_call(self._gforce_event_loop, self._async_scan(period))
171
+ return sync_call(self._async_scan(period))
175
172
 
176
173
  async def asyncScan(self, period) -> List[sensor_profile.BLEDevice]:
177
174
  """
@@ -181,22 +178,23 @@ class SensorController:
181
178
 
182
179
  :return: List[sensor_profile.BLEDevice]: BLEDevice列表
183
180
  """
184
- return await async_call(self._gforce_event_loop, self._async_scan(period))
181
+ return await async_call(self._async_scan(period))
185
182
 
186
183
  async def _device_scan_callback(self, devices: List[sensor_profile.BLEDevice]):
187
184
  if self._device_callback:
188
185
  try:
189
- self._device_callback(devices)
186
+ asyncio.get_event_loop().run_in_executor(None, self._device_callback, devices)
190
187
  except Exception as e:
191
188
  print(e)
192
189
 
193
190
  if self._is_scanning:
194
- async_exec(self._gforce_event_loop, self._startScan())
191
+ async_exec(self._startScan())
195
192
 
196
193
  async def _startScan(self) -> bool:
194
+ self._init_scan()
197
195
  found_devices = await self._scanner.discover(timeout=self._device_callback_period / 1000, return_adv=True)
198
196
  devices = self._process_ble_devices(found_devices)
199
- async_exec(self._event_loop, self._device_scan_callback(devices))
197
+ async_exec(self._device_scan_callback(devices))
200
198
 
201
199
  def startScan(self, periodInMs: int) -> bool:
202
200
  """
@@ -212,7 +210,7 @@ class SensorController:
212
210
  self._is_scanning = True
213
211
  self._device_callback_period = periodInMs
214
212
 
215
- async_exec(self._gforce_event_loop, self._startScan())
213
+ async_exec(self._startScan())
216
214
  return True
217
215
 
218
216
  def stopScan(self) -> None:
@@ -5,13 +5,13 @@ from queue import Queue
5
5
  import struct
6
6
  from typing import Deque, List
7
7
 
8
+ from sensor import utils
8
9
  from sensor.gforce import DataSubscription, GForce
9
10
  from sensor.sensor_data import DataType, Sample, SensorData
10
11
 
11
12
  from enum import Enum, IntEnum
12
13
 
13
14
  from sensor.sensor_device import DeviceInfo
14
- from sensor.utils import timer
15
15
 
16
16
 
17
17
  class SensorDataType(IntEnum):
@@ -228,20 +228,25 @@ class SensorProfileDataCtx:
228
228
  if self.hasEEG():
229
229
  # print("initEEG")
230
230
  info.EegChannelCount = await self.initEEG(packageCount)
231
+ info.EegSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_EEG].sampleRate
231
232
 
232
233
  if self.hasECG():
233
234
  # print("initECG")
234
235
  info.EcgChannelCount = await self.initECG(packageCount)
236
+ info.EcgSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_ECG].sampleRate
235
237
 
236
238
  if self.hasBrth():
237
239
  # print("initBrth")
238
240
  info.BrthChannelCount = await self.initBrth(packageCount)
241
+ info.BrthSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_BRTH].sampleRate
239
242
 
240
243
  if self.hasIMU():
241
244
  # print("initIMU")
242
245
  imuChannelCount = await self.initIMU(packageCount)
243
246
  info.AccChannelCount = imuChannelCount
244
247
  info.GyroChannelCount = imuChannelCount
248
+ info.AccSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_ACC].sampleRate
249
+ info.GyroSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_GYRO].sampleRate
245
250
 
246
251
  self._device_info = info
247
252
 
@@ -280,14 +285,32 @@ class SensorProfileDataCtx:
280
285
  await self.gForce.set_subscription(0)
281
286
  return True
282
287
 
283
- def process_data(self, buf: Queue[SensorData], sensor):
284
- try:
285
- data: bytes = self._rawDataBuffer.get_nowait()
286
- except Exception as e:
287
- return
288
+ async def process_data(self, buf: Queue[SensorData], sensor, callback):
289
+ while self._is_running and self._rawDataBuffer.empty():
290
+ await asyncio.sleep(0.01)
288
291
 
289
- self._processDataPackage(data, buf, sensor)
290
- self._rawDataBuffer.task_done()
292
+ while self._is_running and not self._rawDataBuffer.empty():
293
+ try:
294
+ data: bytes = self._rawDataBuffer.get_nowait()
295
+ except Exception as e:
296
+ continue
297
+
298
+ self._processDataPackage(data, buf, sensor)
299
+ self._rawDataBuffer.task_done()
300
+
301
+ while self._is_running and self.isDataTransfering and not buf.empty():
302
+ sensorData: SensorData = None
303
+ try:
304
+ sensorData = buf.get_nowait()
305
+ except Exception as e:
306
+ break
307
+ if sensorData != None and callback != None:
308
+ try:
309
+ asyncio.get_event_loop().run_in_executor(None, callback, sensor, sensorData)
310
+ except Exception as e:
311
+ print(e)
312
+
313
+ buf.task_done()
291
314
 
292
315
  def _processDataPackage(self, data: bytes, buf: Queue[SensorData], sensor):
293
316
  v = data[0]
@@ -366,7 +389,7 @@ class SensorProfileDataCtx:
366
389
  # print(lostLog)
367
390
  if sensor._event_loop != None and sensor._on_error_callback != None:
368
391
  try:
369
- sensor._event_loop.call_soon_threadsafe(sensor._on_error_callback, sensor, lostLog)
392
+ asyncio.get_event_loop().run_in_executor(None, sensor._on_error_callback, sensor, lostLog)
370
393
  except Exception as e:
371
394
  pass
372
395
 
@@ -518,277 +541,7 @@ class SensorProfileDataCtx:
518
541
  for sensorDataResult in sensorDataList:
519
542
  buf.put(sensorDataResult)
520
543
 
521
- def calc_crc8(self, data):
522
- crc8Table = [
523
- 0x00,
524
- 0x07,
525
- 0x0E,
526
- 0x09,
527
- 0x1C,
528
- 0x1B,
529
- 0x12,
530
- 0x15,
531
- 0x38,
532
- 0x3F,
533
- 0x36,
534
- 0x31,
535
- 0x24,
536
- 0x23,
537
- 0x2A,
538
- 0x2D,
539
- 0x70,
540
- 0x77,
541
- 0x7E,
542
- 0x79,
543
- 0x6C,
544
- 0x6B,
545
- 0x62,
546
- 0x65,
547
- 0x48,
548
- 0x4F,
549
- 0x46,
550
- 0x41,
551
- 0x54,
552
- 0x53,
553
- 0x5A,
554
- 0x5D,
555
- 0xE0,
556
- 0xE7,
557
- 0xEE,
558
- 0xE9,
559
- 0xFC,
560
- 0xFB,
561
- 0xF2,
562
- 0xF5,
563
- 0xD8,
564
- 0xDF,
565
- 0xD6,
566
- 0xD1,
567
- 0xC4,
568
- 0xC3,
569
- 0xCA,
570
- 0xCD,
571
- 0x90,
572
- 0x97,
573
- 0x9E,
574
- 0x99,
575
- 0x8C,
576
- 0x8B,
577
- 0x82,
578
- 0x85,
579
- 0xA8,
580
- 0xAF,
581
- 0xA6,
582
- 0xA1,
583
- 0xB4,
584
- 0xB3,
585
- 0xBA,
586
- 0xBD,
587
- 0xC7,
588
- 0xC0,
589
- 0xC9,
590
- 0xCE,
591
- 0xDB,
592
- 0xDC,
593
- 0xD5,
594
- 0xD2,
595
- 0xFF,
596
- 0xF8,
597
- 0xF1,
598
- 0xF6,
599
- 0xE3,
600
- 0xE4,
601
- 0xED,
602
- 0xEA,
603
- 0xB7,
604
- 0xB0,
605
- 0xB9,
606
- 0xBE,
607
- 0xAB,
608
- 0xAC,
609
- 0xA5,
610
- 0xA2,
611
- 0x8F,
612
- 0x88,
613
- 0x81,
614
- 0x86,
615
- 0x93,
616
- 0x94,
617
- 0x9D,
618
- 0x9A,
619
- 0x27,
620
- 0x20,
621
- 0x29,
622
- 0x2E,
623
- 0x3B,
624
- 0x3C,
625
- 0x35,
626
- 0x32,
627
- 0x1F,
628
- 0x18,
629
- 0x11,
630
- 0x16,
631
- 0x03,
632
- 0x04,
633
- 0x0D,
634
- 0x0A,
635
- 0x57,
636
- 0x50,
637
- 0x59,
638
- 0x5E,
639
- 0x4B,
640
- 0x4C,
641
- 0x45,
642
- 0x42,
643
- 0x6F,
644
- 0x68,
645
- 0x61,
646
- 0x66,
647
- 0x73,
648
- 0x74,
649
- 0x7D,
650
- 0x7A,
651
- 0x89,
652
- 0x8E,
653
- 0x87,
654
- 0x80,
655
- 0x95,
656
- 0x92,
657
- 0x9B,
658
- 0x9C,
659
- 0xB1,
660
- 0xB6,
661
- 0xBF,
662
- 0xB8,
663
- 0xAD,
664
- 0xAA,
665
- 0xA3,
666
- 0xA4,
667
- 0xF9,
668
- 0xFE,
669
- 0xF7,
670
- 0xF0,
671
- 0xE5,
672
- 0xE2,
673
- 0xEB,
674
- 0xEC,
675
- 0xC1,
676
- 0xC6,
677
- 0xCF,
678
- 0xC8,
679
- 0xDD,
680
- 0xDA,
681
- 0xD3,
682
- 0xD4,
683
- 0x69,
684
- 0x6E,
685
- 0x67,
686
- 0x60,
687
- 0x75,
688
- 0x72,
689
- 0x7B,
690
- 0x7C,
691
- 0x51,
692
- 0x56,
693
- 0x5F,
694
- 0x58,
695
- 0x4D,
696
- 0x4A,
697
- 0x43,
698
- 0x44,
699
- 0x19,
700
- 0x1E,
701
- 0x17,
702
- 0x10,
703
- 0x05,
704
- 0x02,
705
- 0x0B,
706
- 0x0C,
707
- 0x21,
708
- 0x26,
709
- 0x2F,
710
- 0x28,
711
- 0x3D,
712
- 0x3A,
713
- 0x33,
714
- 0x34,
715
- 0x4E,
716
- 0x49,
717
- 0x40,
718
- 0x47,
719
- 0x52,
720
- 0x55,
721
- 0x5C,
722
- 0x5B,
723
- 0x76,
724
- 0x71,
725
- 0x78,
726
- 0x7F,
727
- 0x6A,
728
- 0x6D,
729
- 0x64,
730
- 0x63,
731
- 0x3E,
732
- 0x39,
733
- 0x30,
734
- 0x37,
735
- 0x22,
736
- 0x25,
737
- 0x2C,
738
- 0x2B,
739
- 0x06,
740
- 0x01,
741
- 0x08,
742
- 0x0F,
743
- 0x1A,
744
- 0x1D,
745
- 0x14,
746
- 0x13,
747
- 0xAE,
748
- 0xA9,
749
- 0xA0,
750
- 0xA7,
751
- 0xB2,
752
- 0xB5,
753
- 0xBC,
754
- 0xBB,
755
- 0x96,
756
- 0x91,
757
- 0x98,
758
- 0x9F,
759
- 0x8A,
760
- 0x8D,
761
- 0x84,
762
- 0x83,
763
- 0xDE,
764
- 0xD9,
765
- 0xD0,
766
- 0xD7,
767
- 0xC2,
768
- 0xC5,
769
- 0xCC,
770
- 0xCB,
771
- 0xE6,
772
- 0xE1,
773
- 0xE8,
774
- 0xEF,
775
- 0xFA,
776
- 0xFD,
777
- 0xF4,
778
- 0xF3,
779
- ]
780
- crc8 = 0
781
- len_data = len(data)
782
-
783
- for i in range(len_data):
784
- crc8 ^= data[i]
785
- crc8 = crc8Table[crc8]
786
-
787
- return crc8
788
-
789
- async def processUniversalData(
790
- self, buf: Queue[SensorData], event_loop: asyncio.AbstractEventLoop, cmd_loop: asyncio.AbstractEventLoop, sensor, callback
791
- ):
544
+ async def processUniversalData(self, buf: Queue[SensorData], sensor, callback):
792
545
 
793
546
  while self._is_running:
794
547
  while self._is_running and self._rawDataBuffer.empty():
@@ -820,7 +573,7 @@ class SensorProfileDataCtx:
820
573
  index += 1
821
574
  continue
822
575
  crc = self._concatDataBuffer[index + 1 + n + 1]
823
- calc_crc = self.calc_crc8(self._concatDataBuffer[index + 2 : index + 2 + n])
576
+ calc_crc = utils.calc_crc8(self._concatDataBuffer[index + 2 : index + 2 + n])
824
577
  if crc != calc_crc:
825
578
  index += 1
826
579
  continue
@@ -833,9 +586,9 @@ class SensorProfileDataCtx:
833
586
  sensorData = buf.get_nowait()
834
587
  except Exception as e:
835
588
  break
836
- if event_loop != None and sensorData != None and callback != None:
589
+ if sensorData != None and callback != None:
837
590
  try:
838
- event_loop.call_soon_threadsafe(callback, sensor, sensorData)
591
+ asyncio.get_event_loop().run_in_executor(None, callback, sensor, sensorData)
839
592
  except Exception as e:
840
593
  print(e)
841
594
 
@@ -851,13 +604,12 @@ class SensorProfileDataCtx:
851
604
  index += 1
852
605
  continue
853
606
  crc = self._concatDataBuffer[index + 1 + n + 1]
854
- calc_crc = self.calc_crc8(self._concatDataBuffer[index + 2 : index + 2 + n])
607
+ calc_crc = utils.calc_crc8(self._concatDataBuffer[index + 2 : index + 2 + n])
855
608
  if crc != calc_crc:
856
609
  index += 1
857
610
  continue
858
611
  data_package = bytes(self._concatDataBuffer[index + 2 : index + 2 + n])
859
- if cmd_loop != None:
860
- cmd_loop.call_soon_threadsafe(self.gForce._on_cmd_response, None, data_package)
612
+ asyncio.get_event_loop().run_in_executor(None, self.gForce._on_cmd_response, None, data_package)
861
613
  last_cut = index = index + 2 + n
862
614
 
863
615
  else:
@@ -865,3 +617,5 @@ class SensorProfileDataCtx:
865
617
 
866
618
  if last_cut > 0:
867
619
  self._concatDataBuffer = self._concatDataBuffer[last_cut + 1 :]
620
+ last_cut = -1
621
+ index = 0
@@ -40,11 +40,17 @@ class DeviceInfo:
40
40
  self.HardwareVersion = ""
41
41
  self.FirmwareVersion = ""
42
42
  self.EmgChannelCount = 0
43
+ self.EmgSampleRate = 0
43
44
  self.EegChannelCount = 0
45
+ self.EegSampleRate = 0
44
46
  self.EcgChannelCount = 0
47
+ self.EcgSampleRate = 0
45
48
  self.AccChannelCount = 0
49
+ self.AccSampleRate = 0
46
50
  self.GyroChannelCount = 0
51
+ self.GyroSampleRate = 0
47
52
  self.BrthChannelCount = 0
53
+ self.BrthSampleRate = 0
48
54
  self.MTUSize = 0
49
55
 
50
56