sensor-sdk 0.0.7__py3-none-any.whl → 0.0.10__py3-none-any.whl

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.

sensor/gforce.py CHANGED
@@ -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
sensor/sensor_device.py CHANGED
@@ -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
 
sensor/sensor_profile.py CHANGED
@@ -2,28 +2,23 @@
2
2
  # 该枚举类定义了设备的各种状态,用于表示设备在不同操作阶段的状态信息
3
3
  from enum import Enum, IntEnum
4
4
  from queue import Queue
5
- import struct
6
5
  import time
7
- from typing import Callable, Dict, List, Optional
6
+ from typing import Callable, Optional
8
7
 
9
8
  import bleak
10
9
  from bleak import (
11
10
  BleakClient,
12
- BleakGATTCharacteristic,
13
11
  )
14
12
 
15
- import sensor
16
13
  from sensor import utils
17
14
  from sensor.gforce import GForce
18
- from sensor.sensor_data import DataType, Sample, SensorData
15
+ from sensor.sensor_data import SensorData
19
16
  import asyncio
20
- import threading
17
+
21
18
 
22
19
  from sensor.sensor_data_context import SensorProfileDataCtx
23
20
  from sensor.sensor_device import BLEDevice, DeviceInfo, DeviceStateEx
24
- from sensor.utils import async_call, start_loop, sync_call, async_exec, timer
25
- from contextlib import suppress
26
- from dataclasses import dataclass
21
+ from sensor.utils import async_call, sync_call, async_exec, timer
27
22
 
28
23
  SERVICE_GUID = "0000ffd0-0000-1000-8000-00805f9b34fb"
29
24
  OYM_CMD_NOTIFY_CHAR_UUID = "f000ffe1-0451-4000-b000-000000000000"
@@ -46,7 +41,6 @@ class SensorProfile:
46
41
  device: bleak.BLEDevice,
47
42
  adv: bleak.AdvertisementData,
48
43
  mac: str,
49
- gforce_event_loop: asyncio.AbstractEventLoop,
50
44
  ):
51
45
  """
52
46
  初始化 SensorProfile 类的实例。
@@ -66,9 +60,7 @@ class SensorProfile:
66
60
  self._data_ctx: SensorProfileDataCtx = None
67
61
  self._gforce: GForce = None
68
62
  self._data_event_loop: asyncio.AbstractEventLoop = None
69
- self._gforce_event_loop: asyncio.AbstractEventLoop = gforce_event_loop
70
63
  self._event_loop: asyncio.AbstractEventLoop = None
71
- self._event_thread = None
72
64
 
73
65
  def __del__(self) -> None:
74
66
  """
@@ -85,7 +77,6 @@ class SensorProfile:
85
77
  self._data_event_loop.stop()
86
78
  self._data_event_loop.close()
87
79
  self._data_event_loop = None
88
- self._data_event_thread.join()
89
80
  except Exception as e:
90
81
  pass
91
82
  if self._event_loop != None:
@@ -93,7 +84,6 @@ class SensorProfile:
93
84
  self._event_loop.stop()
94
85
  self._event_loop.close()
95
86
  self._event_loop = None
96
- self._event_thread.join()
97
87
  except Exception as e:
98
88
  pass
99
89
 
@@ -111,7 +101,7 @@ class SensorProfile:
111
101
  self._device_state = newState
112
102
  if self._event_loop != None and self._on_state_changed != None:
113
103
  try:
114
- self._event_loop.call_soon_threadsafe(self._on_state_changed, self, newState)
104
+ asyncio.get_event_loop().run_in_executor(None, self._on_state_changed, self, newState)
115
105
  except Exception as e:
116
106
  print(e)
117
107
  pass
@@ -220,12 +210,11 @@ class SensorProfile:
220
210
  self._on_power_changed = callback
221
211
 
222
212
  async def _connect(self) -> bool:
223
- if self._event_thread == None:
213
+ if utils._terminated:
214
+ return False
215
+
216
+ if self._event_loop == None:
224
217
  self._event_loop = asyncio.new_event_loop()
225
- self._event_thread = threading.Thread(target=start_loop, args=(self._event_loop,))
226
- self._event_thread.daemon = True
227
- self._event_thread.name = self._device.Name + " event"
228
- self._event_thread.start()
229
218
  self._data_buffer: Queue[SensorData] = Queue()
230
219
  self._raw_data_buf: Queue[bytes] = Queue()
231
220
 
@@ -242,10 +231,6 @@ class SensorProfile:
242
231
  # print("RFSTAR_SERVICE:" + self._detail_device.name)
243
232
  self._gforce = GForce(self._detail_device, RFSTAR_CMD_UUID, RFSTAR_DATA_UUID, True)
244
233
  self._data_event_loop = asyncio.new_event_loop()
245
- self._data_event_thread = threading.Thread(target=start_loop, args=(self._data_event_loop,))
246
- self._data_event_thread.daemon = True
247
- self._data_event_thread.name = self._detail_device.name + " data"
248
- self._data_event_thread.start()
249
234
  else:
250
235
  print("Invalid device service uuid:" + self._detail_device.name + str(self._adv))
251
236
  return False
@@ -253,24 +238,25 @@ class SensorProfile:
253
238
  if self._data_ctx == None and self._gforce != None:
254
239
  self._data_ctx = SensorProfileDataCtx(self._gforce, self._device.Address, self._raw_data_buf)
255
240
  if self._data_ctx.isUniversalStream:
256
- async_exec(self._data_event_loop, self._process_universal_data())
241
+ async_exec(self._process_universal_data())
257
242
 
258
243
  if self.deviceState == DeviceStateEx.Connected or self.deviceState == DeviceStateEx.Ready:
259
244
  return True
260
245
  self._set_device_state(DeviceStateEx.Connecting)
261
246
 
262
247
  def handle_disconnect(_: BleakClient):
263
- self._data_ctx.close()
264
- time.sleep(0.1)
265
- self._data_buffer.queue.clear()
266
- self._data_ctx = None
267
- self._gforce = None
248
+ if self._data_ctx != None:
249
+ self._data_ctx.close()
250
+ time.sleep(1)
251
+ self._data_buffer.queue.clear()
252
+ self._data_ctx = None
253
+ self._gforce = None
268
254
  self._set_device_state(DeviceStateEx.Disconnected)
269
255
  pass
270
256
 
271
257
  await self._gforce.connect(handle_disconnect, self._raw_data_buf)
272
258
 
273
- if self._gforce.client.is_connected:
259
+ if self._gforce != None and self._gforce.client.is_connected:
274
260
  self._set_device_state(DeviceStateEx.Connected)
275
261
  self._set_device_state(DeviceStateEx.Ready)
276
262
  # if self._gforce.client.mtu_size >= 80:
@@ -289,7 +275,7 @@ class SensorProfile:
289
275
  :return: bool: 如果连接成功,返回 True;否则返回 False。
290
276
 
291
277
  """
292
- result = sync_call(self._gforce_event_loop, self._connect())
278
+ result = sync_call(self._connect())
293
279
  return result
294
280
 
295
281
  async def asyncConnect(self) -> bool:
@@ -299,7 +285,7 @@ class SensorProfile:
299
285
  :return: bool: 如果连接成功,返回 True;否则返回 False。
300
286
 
301
287
  """
302
- return await async_call(self._gforce_event_loop, self._connect())
288
+ return await async_call(self._connect())
303
289
 
304
290
  async def _waitForDisconnect(self) -> bool:
305
291
  while self.deviceState != DeviceStateEx.Disconnected:
@@ -314,6 +300,7 @@ class SensorProfile:
314
300
  self._set_device_state(DeviceStateEx.Disconnecting)
315
301
  await self._gforce.disconnect()
316
302
  await asyncio.wait_for(self._waitForDisconnect(), utils._TIMEOUT)
303
+
317
304
  return True
318
305
 
319
306
  def disconnect(self) -> bool:
@@ -323,7 +310,7 @@ class SensorProfile:
323
310
  :return: bool: 如果断开连接成功,返回 True;否则返回 False。
324
311
 
325
312
  """
326
- return sync_call(self._gforce_event_loop, self._disconnect())
313
+ return sync_call(self._disconnect())
327
314
 
328
315
  async def asyncDisconnect(self) -> bool:
329
316
  """
@@ -332,28 +319,13 @@ class SensorProfile:
332
319
  :return: bool: 如果断开连接成功,返回 True;否则返回 False。
333
320
 
334
321
  """
335
- return await async_call(self._gforce_event_loop, self._disconnect())
322
+ return await async_call(self._disconnect())
336
323
 
337
324
  async def _process_data(self):
338
- while self._data_ctx._is_running and self._data_ctx.isDataTransfering:
339
- self._data_ctx.process_data(self._data_buffer, self)
340
- while self._data_ctx._is_running and self._data_ctx.isDataTransfering:
341
- sensorData: SensorData = None
342
- try:
343
- sensorData = self._data_buffer.get_nowait()
344
- except Exception as e:
345
- break
346
- if self._event_loop != None and sensorData != None and self._on_data_callback != None:
347
- try:
348
- self._event_loop.call_soon_threadsafe(self._on_data_callback, self, sensorData)
349
- except Exception as e:
350
- print(e)
351
- self._data_buffer.task_done()
325
+ await self._data_ctx.process_data(self._data_buffer, self, self._on_data_callback)
352
326
 
353
327
  async def _process_universal_data(self):
354
- await self._data_ctx.processUniversalData(
355
- self._data_buffer, self._event_loop, self._gforce_event_loop, self, self._on_data_callback
356
- )
328
+ await self._data_ctx.processUniversalData(self._data_buffer, self, self._on_data_callback)
357
329
 
358
330
  async def _startDataNotification(self) -> bool:
359
331
  if self.deviceState != DeviceStateEx.Ready:
@@ -368,16 +340,12 @@ class SensorProfile:
368
340
 
369
341
  if self._data_event_loop == None:
370
342
  self._data_event_loop = asyncio.new_event_loop()
371
- self._data_event_thread = threading.Thread(target=start_loop, args=(self._data_event_loop,))
372
- self._data_event_thread.daemon = True
373
- self._data_event_thread.name = self.BLEDevice.Name + " data"
374
- self._data_event_thread.start()
375
343
 
376
344
  result = await self._data_ctx.start_streaming()
377
345
  self._data_buffer.queue.clear()
378
346
  self._data_ctx.clear()
379
347
  if not self._data_ctx.isUniversalStream:
380
- async_exec(self._data_event_loop, self._process_data())
348
+ async_exec(self._process_data())
381
349
  return result
382
350
 
383
351
  def startDataNotification(self) -> bool:
@@ -387,7 +355,7 @@ class SensorProfile:
387
355
  :return: bool: 如果开始数据通知成功,返回 True;否则返回 False。
388
356
 
389
357
  """
390
- return sync_call(self._gforce_event_loop, self._startDataNotification())
358
+ return sync_call(self._startDataNotification())
391
359
 
392
360
  async def asyncStartDataNotification(self) -> bool:
393
361
  """
@@ -396,7 +364,7 @@ class SensorProfile:
396
364
  :return: bool: 如果开始数据通知成功,返回 True;否则返回 False。
397
365
 
398
366
  """
399
- return await async_call(self._gforce_event_loop, self._startDataNotification())
367
+ return await async_call(self._startDataNotification())
400
368
 
401
369
  async def _stopDataNotification(self) -> bool:
402
370
  if self.deviceState != DeviceStateEx.Ready:
@@ -418,7 +386,7 @@ class SensorProfile:
418
386
  :return: bool: 如果停止数据通知成功,返回 True;否则返回 False。
419
387
 
420
388
  """
421
- return sync_call(self._gforce_event_loop, self._stopDataNotification())
389
+ return sync_call(self._stopDataNotification())
422
390
 
423
391
  async def asyncStopDataNotification(self) -> bool:
424
392
  """
@@ -427,23 +395,19 @@ class SensorProfile:
427
395
  :return: bool: 如果停止数据通知成功,返回 True;否则返回 False。
428
396
 
429
397
  """
430
- return await async_call(self._gforce_event_loop, self._stopDataNotification())
398
+ return await async_call(self._stopDataNotification())
431
399
 
432
400
  async def _refresh_power(self):
433
- self._power = await self._gforce.get_battery_level()
401
+ while not utils._terminated and self.deviceState == DeviceStateEx.Ready:
402
+ await asyncio.sleep(self._power_interval / 1000)
434
403
 
435
- if self._event_loop != None and self._on_power_changed != None:
436
- try:
437
- self._event_loop.call_soon_threadsafe(self._on_power_changed, self, self._power)
438
- except Exception as e:
439
- print(e)
404
+ self._power = await self._gforce.get_battery_level()
440
405
 
441
- if self.deviceState == DeviceStateEx.Ready:
442
- timer(
443
- self._gforce_event_loop,
444
- self._power_interval / 1000,
445
- self._refresh_power(),
446
- )
406
+ if self._event_loop != None and self._on_power_changed != None:
407
+ try:
408
+ asyncio.get_event_loop().run_in_executor(None, self._on_power_changed, self, self._power)
409
+ except Exception as e:
410
+ print(e)
447
411
 
448
412
  async def _init(self, packageSampleCount: int, powerRefreshInterval: int) -> bool:
449
413
  if self.deviceState != DeviceStateEx.Ready:
@@ -455,11 +419,7 @@ class SensorProfile:
455
419
 
456
420
  if await self._data_ctx.init(packageSampleCount):
457
421
  self._power_interval = powerRefreshInterval
458
- timer(
459
- self._gforce_event_loop,
460
- self._power_interval / 1000,
461
- self._refresh_power(),
462
- )
422
+ utils.async_exec(self._refresh_power())
463
423
 
464
424
  return self._data_ctx.hasInit()
465
425
 
@@ -474,7 +434,6 @@ class SensorProfile:
474
434
 
475
435
  """
476
436
  return sync_call(
477
- self._gforce_event_loop,
478
437
  self._init(packageSampleCount, powerRefreshInterval),
479
438
  20,
480
439
  )
@@ -490,7 +449,6 @@ class SensorProfile:
490
449
 
491
450
  """
492
451
  return await async_call(
493
- self._gforce_event_loop,
494
452
  self._init(packageSampleCount, powerRefreshInterval),
495
453
  20,
496
454
  )
sensor/utils.py CHANGED
@@ -2,72 +2,381 @@ import asyncio
2
2
  import platform
3
3
  import queue
4
4
  import signal
5
+ import threading
5
6
  import time
6
7
 
7
8
  _terminated = False
8
9
  _TIMEOUT = 10
10
+ running_tasks = set()
11
+ _runloop: asyncio.AbstractEventLoop = None
12
+ _event_thread: threading.Thread = None
13
+ _needCloseRunloop = False
14
+
15
+
16
+ def checkRunLoop():
17
+ global _runloop, _needCloseRunloop, _event_thread
18
+ if _runloop == None:
19
+ try:
20
+ _runloop = asyncio.get_running_loop()
21
+ except Exception as e:
22
+ _needCloseRunloop = True
23
+ _runloop = asyncio.new_event_loop()
24
+ _event_thread = threading.Thread(target=start_loop, args=(_runloop,))
25
+ _event_thread.daemon = True
26
+ _event_thread.name = "SensorController event"
27
+ _event_thread.start()
28
+
29
+
30
+ def Terminate():
31
+ global _runloop, _needCloseRunloop, _event_thread
32
+ if _needCloseRunloop:
33
+ try:
34
+ _runloop.stop()
35
+ _runloop.close()
36
+ except Exception as e:
37
+ pass
9
38
 
10
39
 
11
40
  async def delay(_time: float, function) -> any:
12
- await asyncio.sleep(_time)
13
- return await function
41
+ try:
42
+ await asyncio.sleep(_time)
43
+ except Exception as e:
44
+ pass
14
45
 
46
+ try:
47
+ return await function
48
+ except Exception as e:
49
+ pass
15
50
 
16
- def timer(_loop: asyncio.AbstractEventLoop, _delay: float, function):
17
- if _loop == None:
18
- return
51
+
52
+ def timer(_delay: float, function):
53
+ checkRunLoop()
54
+ task: asyncio.Future = None
19
55
  try:
20
- asyncio.run_coroutine_threadsafe(delay(_delay, function), _loop)
56
+ task = asyncio.run_coroutine_threadsafe(delay(_delay, function), _runloop)
57
+ running_tasks.add(task)
58
+ task.add_done_callback(lambda t: running_tasks.remove(t))
21
59
  except Exception as e:
22
60
  print(e)
23
61
  pass
24
62
 
25
63
 
26
- def async_exec(_loop: asyncio.AbstractEventLoop, function):
27
- if _loop == None:
28
- return
64
+ def async_exec(function):
65
+ checkRunLoop()
66
+ task: asyncio.Future = None
29
67
  try:
30
- asyncio.run_coroutine_threadsafe(function, _loop)
68
+ task = asyncio.run_coroutine_threadsafe(function, _runloop)
69
+ running_tasks.add(task)
70
+ task.add_done_callback(lambda t: running_tasks.remove(t))
31
71
  except Exception as e:
32
72
  print(e)
33
73
  pass
34
74
 
35
75
 
36
- def sync_call(_loop: asyncio.AbstractEventLoop, function, _timeout=_TIMEOUT) -> any:
37
- if _loop == None:
38
- return
39
-
76
+ def sync_call(function, _timeout=_TIMEOUT) -> any:
77
+ checkRunLoop()
78
+ task: asyncio.Future = None
40
79
  try:
41
- f = asyncio.run_coroutine_threadsafe(asyncio.wait_for(function, _timeout), _loop)
42
- return f.result(timeout=_timeout)
80
+ task = asyncio.run_coroutine_threadsafe(asyncio.wait_for(function, _timeout), _runloop)
81
+ running_tasks.add(task)
82
+ task.add_done_callback(lambda t: running_tasks.remove(t))
83
+ return task.result(timeout=_timeout)
43
84
  except Exception as e:
44
85
  print(e)
45
86
  pass
46
87
 
47
88
 
48
- async def async_call(_loop: asyncio.AbstractEventLoop, function, _timeout=_TIMEOUT) -> any:
49
- if _loop == None:
50
- return
51
-
89
+ async def async_call(function, _timeout=_TIMEOUT) -> any:
90
+ checkRunLoop()
91
+ task: asyncio.Future = None
52
92
  try:
53
- f = asyncio.run_coroutine_threadsafe(asyncio.wait_for(function, _timeout), _loop)
93
+ task = asyncio.run_coroutine_threadsafe(asyncio.wait_for(function, _timeout), _runloop)
94
+ running_tasks.add(task)
95
+ task.add_done_callback(lambda t: running_tasks.remove(t))
54
96
  except Exception as e:
55
97
  print(e)
56
98
  pass
57
99
 
58
- while not _terminated and not f.done():
100
+ while not _terminated and not task.done():
59
101
  await asyncio.sleep(0.1)
60
102
 
61
103
  try:
62
- if not f.cancelled():
63
- return f.result()
104
+ if not task.cancelled():
105
+ return task.result()
64
106
  except Exception as e:
65
107
  print(e)
66
108
  return
67
109
 
68
110
 
69
111
  def start_loop(loop: asyncio.BaseEventLoop):
70
- if platform.system() == "Darwin":
71
- asyncio.get_running_loop = asyncio.get_event_loop
72
112
  asyncio.set_event_loop(loop)
73
113
  loop.run_forever()
114
+
115
+
116
+ def calc_crc8(data):
117
+ crc8Table = [
118
+ 0x00,
119
+ 0x07,
120
+ 0x0E,
121
+ 0x09,
122
+ 0x1C,
123
+ 0x1B,
124
+ 0x12,
125
+ 0x15,
126
+ 0x38,
127
+ 0x3F,
128
+ 0x36,
129
+ 0x31,
130
+ 0x24,
131
+ 0x23,
132
+ 0x2A,
133
+ 0x2D,
134
+ 0x70,
135
+ 0x77,
136
+ 0x7E,
137
+ 0x79,
138
+ 0x6C,
139
+ 0x6B,
140
+ 0x62,
141
+ 0x65,
142
+ 0x48,
143
+ 0x4F,
144
+ 0x46,
145
+ 0x41,
146
+ 0x54,
147
+ 0x53,
148
+ 0x5A,
149
+ 0x5D,
150
+ 0xE0,
151
+ 0xE7,
152
+ 0xEE,
153
+ 0xE9,
154
+ 0xFC,
155
+ 0xFB,
156
+ 0xF2,
157
+ 0xF5,
158
+ 0xD8,
159
+ 0xDF,
160
+ 0xD6,
161
+ 0xD1,
162
+ 0xC4,
163
+ 0xC3,
164
+ 0xCA,
165
+ 0xCD,
166
+ 0x90,
167
+ 0x97,
168
+ 0x9E,
169
+ 0x99,
170
+ 0x8C,
171
+ 0x8B,
172
+ 0x82,
173
+ 0x85,
174
+ 0xA8,
175
+ 0xAF,
176
+ 0xA6,
177
+ 0xA1,
178
+ 0xB4,
179
+ 0xB3,
180
+ 0xBA,
181
+ 0xBD,
182
+ 0xC7,
183
+ 0xC0,
184
+ 0xC9,
185
+ 0xCE,
186
+ 0xDB,
187
+ 0xDC,
188
+ 0xD5,
189
+ 0xD2,
190
+ 0xFF,
191
+ 0xF8,
192
+ 0xF1,
193
+ 0xF6,
194
+ 0xE3,
195
+ 0xE4,
196
+ 0xED,
197
+ 0xEA,
198
+ 0xB7,
199
+ 0xB0,
200
+ 0xB9,
201
+ 0xBE,
202
+ 0xAB,
203
+ 0xAC,
204
+ 0xA5,
205
+ 0xA2,
206
+ 0x8F,
207
+ 0x88,
208
+ 0x81,
209
+ 0x86,
210
+ 0x93,
211
+ 0x94,
212
+ 0x9D,
213
+ 0x9A,
214
+ 0x27,
215
+ 0x20,
216
+ 0x29,
217
+ 0x2E,
218
+ 0x3B,
219
+ 0x3C,
220
+ 0x35,
221
+ 0x32,
222
+ 0x1F,
223
+ 0x18,
224
+ 0x11,
225
+ 0x16,
226
+ 0x03,
227
+ 0x04,
228
+ 0x0D,
229
+ 0x0A,
230
+ 0x57,
231
+ 0x50,
232
+ 0x59,
233
+ 0x5E,
234
+ 0x4B,
235
+ 0x4C,
236
+ 0x45,
237
+ 0x42,
238
+ 0x6F,
239
+ 0x68,
240
+ 0x61,
241
+ 0x66,
242
+ 0x73,
243
+ 0x74,
244
+ 0x7D,
245
+ 0x7A,
246
+ 0x89,
247
+ 0x8E,
248
+ 0x87,
249
+ 0x80,
250
+ 0x95,
251
+ 0x92,
252
+ 0x9B,
253
+ 0x9C,
254
+ 0xB1,
255
+ 0xB6,
256
+ 0xBF,
257
+ 0xB8,
258
+ 0xAD,
259
+ 0xAA,
260
+ 0xA3,
261
+ 0xA4,
262
+ 0xF9,
263
+ 0xFE,
264
+ 0xF7,
265
+ 0xF0,
266
+ 0xE5,
267
+ 0xE2,
268
+ 0xEB,
269
+ 0xEC,
270
+ 0xC1,
271
+ 0xC6,
272
+ 0xCF,
273
+ 0xC8,
274
+ 0xDD,
275
+ 0xDA,
276
+ 0xD3,
277
+ 0xD4,
278
+ 0x69,
279
+ 0x6E,
280
+ 0x67,
281
+ 0x60,
282
+ 0x75,
283
+ 0x72,
284
+ 0x7B,
285
+ 0x7C,
286
+ 0x51,
287
+ 0x56,
288
+ 0x5F,
289
+ 0x58,
290
+ 0x4D,
291
+ 0x4A,
292
+ 0x43,
293
+ 0x44,
294
+ 0x19,
295
+ 0x1E,
296
+ 0x17,
297
+ 0x10,
298
+ 0x05,
299
+ 0x02,
300
+ 0x0B,
301
+ 0x0C,
302
+ 0x21,
303
+ 0x26,
304
+ 0x2F,
305
+ 0x28,
306
+ 0x3D,
307
+ 0x3A,
308
+ 0x33,
309
+ 0x34,
310
+ 0x4E,
311
+ 0x49,
312
+ 0x40,
313
+ 0x47,
314
+ 0x52,
315
+ 0x55,
316
+ 0x5C,
317
+ 0x5B,
318
+ 0x76,
319
+ 0x71,
320
+ 0x78,
321
+ 0x7F,
322
+ 0x6A,
323
+ 0x6D,
324
+ 0x64,
325
+ 0x63,
326
+ 0x3E,
327
+ 0x39,
328
+ 0x30,
329
+ 0x37,
330
+ 0x22,
331
+ 0x25,
332
+ 0x2C,
333
+ 0x2B,
334
+ 0x06,
335
+ 0x01,
336
+ 0x08,
337
+ 0x0F,
338
+ 0x1A,
339
+ 0x1D,
340
+ 0x14,
341
+ 0x13,
342
+ 0xAE,
343
+ 0xA9,
344
+ 0xA0,
345
+ 0xA7,
346
+ 0xB2,
347
+ 0xB5,
348
+ 0xBC,
349
+ 0xBB,
350
+ 0x96,
351
+ 0x91,
352
+ 0x98,
353
+ 0x9F,
354
+ 0x8A,
355
+ 0x8D,
356
+ 0x84,
357
+ 0x83,
358
+ 0xDE,
359
+ 0xD9,
360
+ 0xD0,
361
+ 0xD7,
362
+ 0xC2,
363
+ 0xC5,
364
+ 0xCC,
365
+ 0xCB,
366
+ 0xE6,
367
+ 0xE1,
368
+ 0xE8,
369
+ 0xEF,
370
+ 0xFA,
371
+ 0xFD,
372
+ 0xF4,
373
+ 0xF3,
374
+ ]
375
+ crc8 = 0
376
+ len_data = len(data)
377
+
378
+ for i in range(len_data):
379
+ crc8 ^= data[i]
380
+ crc8 = crc8Table[crc8]
381
+
382
+ return crc8
@@ -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
@@ -0,0 +1,14 @@
1
+ sensor/__init__.py,sha256=L1VyAP0EDEnJIMeMTzp4iXHSRUUHyHScF_GIl3iYKRI,123
2
+ sensor/gforce.py,sha256=mTw0VVQSxPiTzZmjK7I9knTlTkEeu4PISQdlAkMU6WE,25232
3
+ sensor/sensor_controller.py,sha256=qnM9mVwpJn9PCnxlvbgWFeaLktqVnmaquZgasYGEHqs,9451
4
+ sensor/sensor_data.py,sha256=Hu7Ql0LgQ7V24xYZhaLrKPwU4KWZeWE655v8Gy8xphY,3934
5
+ sensor/sensor_data_context.py,sha256=9IvXAHhCSQGnkNW5nFNz4Rs6kVq1hEyxxu6ROKjb-Dk,25033
6
+ sensor/sensor_device.py,sha256=eO1vaqjxCc2UCPBoKXqlk6o498uRyWt6IYs7r7wXSD0,3042
7
+ sensor/sensor_profile.py,sha256=64MFNyLJajX6HeGS_tmN9R9wfEW1qjsP_MjH3ZRPq4s,17322
8
+ sensor/utils.py,sha256=FuBEChpJYbXnUaDvlta3aT6dYGAK2fQdGbIB7BYMQp4,7077
9
+ sensor_sdk-0.0.10.dist-info/LICENSE.txt,sha256=8CSivOpub3IuXODTyqBRI91AxouJZk02YrcKuOAkWu8,1111
10
+ sensor_sdk-0.0.10.dist-info/METADATA,sha256=OjhjiuAo0t9cgFCyuIC-5PB_O7KTi8duBZz-H2RCTAw,8375
11
+ sensor_sdk-0.0.10.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
12
+ sensor_sdk-0.0.10.dist-info/top_level.txt,sha256=Ftq49B6bH0Ffdc7c8LkcyakHo6lsg_snlBbpEUoILSk,7
13
+ sensor_sdk-0.0.10.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
14
+ sensor_sdk-0.0.10.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- sensor/__init__.py,sha256=L1VyAP0EDEnJIMeMTzp4iXHSRUUHyHScF_GIl3iYKRI,123
2
- sensor/gforce.py,sha256=wHnZ9fJiqzD9TpHekWsEqp3VIyIBhbXwJSj5k6FjVNw,25049
3
- sensor/sensor_controller.py,sha256=lNi7i3T_aAHEJvv963OvVv_PNAYy_5-BwXD82XNvnGg,10028
4
- sensor/sensor_data.py,sha256=Hu7Ql0LgQ7V24xYZhaLrKPwU4KWZeWE655v8Gy8xphY,3934
5
- sensor/sensor_data_context.py,sha256=6bhpPRwTrVemdkCz43FTYIElKLW_S4ESSg6xgelTQow,28846
6
- sensor/sensor_device.py,sha256=LCjBzm2TuOh2KpHsFTjm1sF8hzwvS22LhF_ueAct0Jo,2848
7
- sensor/sensor_profile.py,sha256=mjqOEZLGJQYY8zhH8TA0HRVxrFC4AjjKAj_zGOQMgHg,19678
8
- sensor/utils.py,sha256=ybmByBldCQ_x-sVtjA2mdXWo0QOafPAupfnWAxLrkV0,1773
9
- sensor_sdk-0.0.7.dist-info/LICENSE.txt,sha256=8CSivOpub3IuXODTyqBRI91AxouJZk02YrcKuOAkWu8,1111
10
- sensor_sdk-0.0.7.dist-info/METADATA,sha256=oAl9HPAImzRPcLdVyjOaPTxBCrlJIsAAXqZtNAghh-c,8374
11
- sensor_sdk-0.0.7.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
12
- sensor_sdk-0.0.7.dist-info/top_level.txt,sha256=Ftq49B6bH0Ffdc7c8LkcyakHo6lsg_snlBbpEUoILSk,7
13
- sensor_sdk-0.0.7.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
14
- sensor_sdk-0.0.7.dist-info/RECORD,,