sensor-sdk 0.0.27__tar.gz → 0.0.31__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.
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/PKG-INFO +14 -2
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor/gforce.py +70 -88
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor/sensor_data_context.py +28 -24
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor/sensor_profile.py +62 -22
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor_sdk.egg-info/PKG-INFO +14 -2
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/setup.py +1 -1
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/LICENSE.txt +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/README.md +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor/__init__.py +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor/sensor_controller.py +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor/sensor_data.py +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor/sensor_device.py +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor/sensor_utils.py +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor_sdk.egg-info/SOURCES.txt +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor_sdk.egg-info/dependency_links.txt +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor_sdk.egg-info/requires.txt +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor_sdk.egg-info/top_level.txt +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/sensor_sdk.egg-info/zip-safe +0 -0
- {sensor-sdk-0.0.27 → sensor_sdk-0.0.31}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: sensor-sdk
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.31
|
|
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
|
|
|
@@ -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__(
|
|
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
|
|
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
|
|
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
|
|
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,17 @@ class GForce:
|
|
|
754
714
|
)
|
|
755
715
|
)
|
|
756
716
|
|
|
717
|
+
async def set_function_switch(self, funcSwitch):
|
|
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
|
+
|
|
757
728
|
async def set_firmware_filter_switch(self, switchStatus: int):
|
|
758
729
|
body = [0xFF & switchStatus]
|
|
759
730
|
body = bytes(body)
|
|
@@ -858,22 +829,20 @@ class GForce:
|
|
|
858
829
|
)
|
|
859
830
|
|
|
860
831
|
async def start_streaming(self, q: queue.Queue):
|
|
861
|
-
await
|
|
832
|
+
await sensor_utils.async_call(
|
|
862
833
|
self.client.start_notify(
|
|
863
834
|
self.data_char,
|
|
864
835
|
lambda _, data: self._on_data_response(q, data),
|
|
865
836
|
),
|
|
866
837
|
sensor_utils._TIMEOUT,
|
|
838
|
+
self.gforce_event_loop,
|
|
867
839
|
)
|
|
868
840
|
|
|
869
841
|
async def stop_streaming(self):
|
|
870
842
|
exceptions = []
|
|
871
|
-
|
|
872
|
-
# await asyncio.wait_for(self.set_subscription(DataSubscription.OFF), sensor_utils._TIMEOUT)
|
|
873
|
-
# except Exception as e:
|
|
874
|
-
# exceptions.append(e)
|
|
843
|
+
|
|
875
844
|
try:
|
|
876
|
-
await
|
|
845
|
+
await sensor_utils.async_call(self.client.stop_notify(self.data_char), sensor_utils._TIMEOUT, self.gforce_event_loop)
|
|
877
846
|
except Exception as e:
|
|
878
847
|
exceptions.append(e)
|
|
879
848
|
|
|
@@ -883,49 +852,62 @@ class GForce:
|
|
|
883
852
|
async def disconnect(self):
|
|
884
853
|
with suppress(asyncio.CancelledError):
|
|
885
854
|
try:
|
|
886
|
-
await
|
|
855
|
+
await sensor_utils.async_call(self.client.disconnect(), sensor_utils._TIMEOUT, self.gforce_event_loop)
|
|
887
856
|
except Exception as e:
|
|
888
857
|
pass
|
|
889
858
|
|
|
890
859
|
def _get_response_channel(self, cmd: Command) -> Queue:
|
|
891
860
|
if self.responses.get(cmd) != None:
|
|
892
|
-
return
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
861
|
+
return self.responses[cmd]
|
|
862
|
+
else:
|
|
863
|
+
q = Queue()
|
|
864
|
+
self.responses[cmd] = q
|
|
865
|
+
return q
|
|
897
866
|
|
|
898
867
|
async def _send_request(self, req: Request) -> Optional[bytes]:
|
|
868
|
+
return await sensor_utils.async_call(self._send_request_internal(req=req), runloop=self.event_loop)
|
|
899
869
|
|
|
870
|
+
async def _send_request_internal(self, req: Request) -> Optional[bytes]:
|
|
900
871
|
q = None
|
|
901
872
|
if req.has_res:
|
|
902
873
|
q = self._get_response_channel(req.cmd)
|
|
903
|
-
if q == None:
|
|
904
|
-
# print("duplicate")
|
|
905
|
-
return None
|
|
906
874
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
875
|
+
timeStamp_old = -1
|
|
876
|
+
while not q.empty():
|
|
877
|
+
timeStamp_old = q.get_nowait()
|
|
878
|
+
|
|
879
|
+
now = datetime.now()
|
|
880
|
+
timestamp_now = now.timestamp()
|
|
881
|
+
if (timeStamp_old > -1) and ((timestamp_now - timeStamp_old) < 3):
|
|
882
|
+
print("send request too fast")
|
|
883
|
+
q.put_nowait(timeStamp_old)
|
|
884
|
+
return None
|
|
910
885
|
|
|
911
|
-
self.current_request = req
|
|
912
886
|
bs = bytes([req.cmd])
|
|
913
887
|
if req.body is not None:
|
|
914
888
|
bs += req.body
|
|
915
889
|
|
|
916
890
|
# print(str(req.cmd) + str(req.body))
|
|
917
|
-
|
|
891
|
+
try:
|
|
892
|
+
await sensor_utils.async_call(
|
|
893
|
+
self.client.write_gatt_char(self.cmd_char, bs),
|
|
894
|
+
1,
|
|
895
|
+
runloop=self.gforce_event_loop,
|
|
896
|
+
)
|
|
897
|
+
except Exception as e:
|
|
898
|
+
self.responses[req.cmd] = None
|
|
899
|
+
return None
|
|
918
900
|
|
|
919
901
|
if not req.has_res:
|
|
920
|
-
self.
|
|
902
|
+
self.responses[req.cmd] = None
|
|
921
903
|
return None
|
|
922
904
|
|
|
923
905
|
try:
|
|
924
|
-
ret = await asyncio.wait_for(q.get(),
|
|
925
|
-
|
|
926
|
-
|
|
906
|
+
ret = await asyncio.wait_for(q.get(), 2)
|
|
907
|
+
now = datetime.now()
|
|
908
|
+
timestamp_now = now.timestamp()
|
|
909
|
+
q.put_nowait(timestamp_now)
|
|
927
910
|
return ret
|
|
928
911
|
except Exception as e:
|
|
929
|
-
self.current_request = None
|
|
930
912
|
self.responses[req.cmd] = None
|
|
931
913
|
return None
|
|
@@ -138,6 +138,9 @@ class SensorProfileDataCtx:
|
|
|
138
138
|
await self.gForce.set_emg_raw_data_config(config)
|
|
139
139
|
|
|
140
140
|
await self.gForce.set_package_id(True)
|
|
141
|
+
|
|
142
|
+
await self.gForce.set_function_switch(2)
|
|
143
|
+
|
|
141
144
|
return data.channelCount
|
|
142
145
|
|
|
143
146
|
async def initEEG(self, packageCount: int) -> int:
|
|
@@ -350,8 +353,9 @@ class SensorProfileDataCtx:
|
|
|
350
353
|
if value == "ON":
|
|
351
354
|
switch |= 8
|
|
352
355
|
try:
|
|
353
|
-
await self.gForce.set_firmware_filter_switch(switch)
|
|
354
|
-
|
|
356
|
+
ret = await self.gForce.set_firmware_filter_switch(switch)
|
|
357
|
+
if ret == None:
|
|
358
|
+
return "ERROR: not success"
|
|
355
359
|
return "OK"
|
|
356
360
|
except Exception as e:
|
|
357
361
|
return "ERROR: " + str(e)
|
|
@@ -372,10 +376,8 @@ class SensorProfileDataCtx:
|
|
|
372
376
|
####################################################################################
|
|
373
377
|
|
|
374
378
|
async def process_data(self, buf: Queue[SensorData], sensor, callback):
|
|
375
|
-
while self._is_running
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
while self._is_running and not self._rawDataBuffer.empty():
|
|
379
|
+
while self._is_running:
|
|
380
|
+
while not self._rawDataBuffer.empty():
|
|
379
381
|
try:
|
|
380
382
|
data: bytes = self._rawDataBuffer.get_nowait()
|
|
381
383
|
except Exception as e:
|
|
@@ -385,7 +387,7 @@ class SensorProfileDataCtx:
|
|
|
385
387
|
self._processDataPackage(data, buf, sensor)
|
|
386
388
|
self._rawDataBuffer.task_done()
|
|
387
389
|
|
|
388
|
-
|
|
390
|
+
if self.isDataTransfering and not buf.empty():
|
|
389
391
|
sensorData: SensorData = None
|
|
390
392
|
try:
|
|
391
393
|
sensorData = buf.get_nowait()
|
|
@@ -398,6 +400,8 @@ class SensorProfileDataCtx:
|
|
|
398
400
|
print(e)
|
|
399
401
|
|
|
400
402
|
buf.task_done()
|
|
403
|
+
else:
|
|
404
|
+
await asyncio.sleep(0.01)
|
|
401
405
|
|
|
402
406
|
def _processDataPackage(self, data: bytes, buf: Queue[SensorData], sensor):
|
|
403
407
|
v = data[0] & 0x7F
|
|
@@ -673,7 +677,21 @@ class SensorProfileDataCtx:
|
|
|
673
677
|
|
|
674
678
|
while self._is_running:
|
|
675
679
|
while self._is_running and self._rawDataBuffer.empty():
|
|
676
|
-
|
|
680
|
+
if self._is_running and self.isDataTransfering and not buf.empty():
|
|
681
|
+
sensorData: SensorData = None
|
|
682
|
+
try:
|
|
683
|
+
sensorData = buf.get_nowait()
|
|
684
|
+
except Exception as e:
|
|
685
|
+
break
|
|
686
|
+
if not sensor_utils._terminated and sensorData != None and callback != None:
|
|
687
|
+
try:
|
|
688
|
+
asyncio.get_event_loop().run_in_executor(self.dataPool, callback, sensor, sensorData)
|
|
689
|
+
except Exception as e:
|
|
690
|
+
print(e)
|
|
691
|
+
|
|
692
|
+
buf.task_done()
|
|
693
|
+
else:
|
|
694
|
+
await asyncio.sleep(0.01)
|
|
677
695
|
continue
|
|
678
696
|
|
|
679
697
|
try:
|
|
@@ -708,21 +726,7 @@ class SensorProfileDataCtx:
|
|
|
708
726
|
if self._is_data_transfering:
|
|
709
727
|
data_package = bytes(self._concatDataBuffer[index + 2 : index + 2 + n])
|
|
710
728
|
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
729
|
last_cut = index = index + 2 + n
|
|
725
|
-
|
|
726
730
|
elif self._concatDataBuffer[index] == 0xAA:
|
|
727
731
|
if (index + 1) >= data_size:
|
|
728
732
|
index += 1
|
|
@@ -737,10 +741,10 @@ class SensorProfileDataCtx:
|
|
|
737
741
|
index += 1
|
|
738
742
|
continue
|
|
739
743
|
data_package = bytes(self._concatDataBuffer[index + 2 : index + 2 + n])
|
|
744
|
+
|
|
740
745
|
if not sensor_utils._terminated:
|
|
741
|
-
self.gForce.
|
|
746
|
+
await sensor_utils.async_call(self.gForce.async_on_cmd_response(data_package), runloop=sensor._event_loop)
|
|
742
747
|
last_cut = index = index + 2 + n
|
|
743
|
-
|
|
744
748
|
else:
|
|
745
749
|
index += 1
|
|
746
750
|
|
|
@@ -62,6 +62,8 @@ class SensorProfile:
|
|
|
62
62
|
self._gforce: GForce = None
|
|
63
63
|
self._data_event_loop: asyncio.AbstractEventLoop = None
|
|
64
64
|
self._data_event_thread: threading.Thread = None
|
|
65
|
+
self._gforce_event_loop: asyncio.AbstractEventLoop = None
|
|
66
|
+
self._gforce_event_thread: threading.Thread = None
|
|
65
67
|
self._event_loop: asyncio.AbstractEventLoop = None
|
|
66
68
|
self._event_thread: threading.Thread = None
|
|
67
69
|
self._is_starting = False
|
|
@@ -92,6 +94,17 @@ class SensorProfile:
|
|
|
92
94
|
except Exception as e:
|
|
93
95
|
pass
|
|
94
96
|
|
|
97
|
+
if self._gforce_event_loop != None:
|
|
98
|
+
try:
|
|
99
|
+
self._gforce_event_loop.stop()
|
|
100
|
+
self._gforce_event_loop.close()
|
|
101
|
+
self._gforce_event_loop = None
|
|
102
|
+
except Exception as e:
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
self._is_starting = False
|
|
106
|
+
self._is_setting_param = False
|
|
107
|
+
|
|
95
108
|
@property
|
|
96
109
|
def deviceState(self) -> DeviceStateEx:
|
|
97
110
|
"""
|
|
@@ -215,6 +228,13 @@ class SensorProfile:
|
|
|
215
228
|
self._on_power_changed = callback
|
|
216
229
|
|
|
217
230
|
async def _initGforce(self):
|
|
231
|
+
|
|
232
|
+
self._gforce_event_loop = asyncio.new_event_loop()
|
|
233
|
+
self._gforce_event_thread = threading.Thread(target=sensor_utils.start_loop, args=(self._gforce_event_loop,))
|
|
234
|
+
self._gforce_event_thread.daemon = True
|
|
235
|
+
self._gforce_event_thread.name = self._detail_device.name + "data event"
|
|
236
|
+
self._gforce_event_thread.start()
|
|
237
|
+
|
|
218
238
|
if self._gforce == None:
|
|
219
239
|
if self._adv.service_data.get(SERVICE_GUID) != None:
|
|
220
240
|
# print("OYM_SERVICE:" + self._detail_device.name)
|
|
@@ -223,21 +243,31 @@ class SensorProfile:
|
|
|
223
243
|
OYM_CMD_NOTIFY_CHAR_UUID,
|
|
224
244
|
OYM_DATA_NOTIFY_CHAR_UUID,
|
|
225
245
|
False,
|
|
246
|
+
self._event_loop,
|
|
247
|
+
self._gforce_event_loop,
|
|
226
248
|
)
|
|
227
249
|
elif self._adv.service_data.get(RFSTAR_SERVICE_GUID) != None:
|
|
228
250
|
# print("RFSTAR_SERVICE:" + self._detail_device.name)
|
|
229
|
-
self._gforce = GForce(
|
|
230
|
-
|
|
251
|
+
self._gforce = GForce(
|
|
252
|
+
self._detail_device, RFSTAR_CMD_UUID, RFSTAR_DATA_UUID, True, self._event_loop, self._gforce_event_loop
|
|
253
|
+
)
|
|
254
|
+
|
|
231
255
|
else:
|
|
232
256
|
print("Invalid device service uuid:" + self._detail_device.name + str(self._adv))
|
|
233
257
|
return False
|
|
234
258
|
|
|
259
|
+
self._data_event_loop = asyncio.new_event_loop()
|
|
260
|
+
self._data_event_thread = threading.Thread(target=sensor_utils.start_loop, args=(self._data_event_loop,))
|
|
261
|
+
self._data_event_thread.daemon = True
|
|
262
|
+
self._data_event_thread.name = self._detail_device.name + "data event"
|
|
263
|
+
self._data_event_thread.start()
|
|
264
|
+
|
|
235
265
|
if self._data_ctx == None and self._gforce != None:
|
|
236
266
|
self._data_ctx = SensorProfileDataCtx(self._gforce, self._device.Address, self._raw_data_buf)
|
|
237
267
|
if self._data_ctx.isUniversalStream:
|
|
238
|
-
async_exec(self._process_universal_data(), self.
|
|
268
|
+
async_exec(self._process_universal_data(), self._data_event_loop)
|
|
239
269
|
else:
|
|
240
|
-
async_exec(self._process_data(), self.
|
|
270
|
+
async_exec(self._process_data(), self._data_event_loop)
|
|
241
271
|
|
|
242
272
|
async def _connect(self) -> bool:
|
|
243
273
|
if sensor_utils._terminated:
|
|
@@ -249,6 +279,7 @@ class SensorProfile:
|
|
|
249
279
|
self._event_thread.daemon = True
|
|
250
280
|
self._event_thread.name = self._detail_device.name + "event"
|
|
251
281
|
self._event_thread.start()
|
|
282
|
+
|
|
252
283
|
self._data_buffer: Queue[SensorData] = Queue()
|
|
253
284
|
self._raw_data_buf: Queue[bytes] = Queue()
|
|
254
285
|
|
|
@@ -269,7 +300,7 @@ class SensorProfile:
|
|
|
269
300
|
self._set_device_state(DeviceStateEx.Disconnected)
|
|
270
301
|
pass
|
|
271
302
|
|
|
272
|
-
await
|
|
303
|
+
await self._gforce.connect(handle_disconnect, self._raw_data_buf)
|
|
273
304
|
|
|
274
305
|
if self._gforce != None and self._gforce.client.is_connected:
|
|
275
306
|
self._set_device_state(DeviceStateEx.Connected)
|
|
@@ -313,7 +344,7 @@ class SensorProfile:
|
|
|
313
344
|
if self._data_ctx == None:
|
|
314
345
|
return False
|
|
315
346
|
self._set_device_state(DeviceStateEx.Disconnecting)
|
|
316
|
-
|
|
347
|
+
await self._gforce.disconnect()
|
|
317
348
|
await asyncio.wait_for(self._waitForDisconnect(), sensor_utils._TIMEOUT)
|
|
318
349
|
|
|
319
350
|
return True
|
|
@@ -341,6 +372,7 @@ class SensorProfile:
|
|
|
341
372
|
|
|
342
373
|
async def _process_universal_data(self):
|
|
343
374
|
await self._data_ctx.processUniversalData(self._data_buffer, self, self._on_data_callback)
|
|
375
|
+
print("finished")
|
|
344
376
|
|
|
345
377
|
async def _startDataNotification(self) -> bool:
|
|
346
378
|
if self.deviceState != DeviceStateEx.Ready:
|
|
@@ -353,13 +385,10 @@ class SensorProfile:
|
|
|
353
385
|
if self._data_ctx.isDataTransfering:
|
|
354
386
|
return True
|
|
355
387
|
|
|
356
|
-
if self._data_event_loop == None:
|
|
357
|
-
self._data_event_loop = asyncio.new_event_loop()
|
|
358
|
-
|
|
359
388
|
self._raw_data_buf.queue.clear()
|
|
360
389
|
self._data_buffer.queue.clear()
|
|
361
390
|
|
|
362
|
-
result = await async_call(self._data_ctx.start_streaming(), runloop=
|
|
391
|
+
result = await async_call(self._data_ctx.start_streaming(), runloop=None)
|
|
363
392
|
await asyncio.sleep(0.2)
|
|
364
393
|
|
|
365
394
|
return result
|
|
@@ -413,7 +442,7 @@ class SensorProfile:
|
|
|
413
442
|
if not self._data_ctx.isDataTransfering:
|
|
414
443
|
return True
|
|
415
444
|
|
|
416
|
-
result = await async_call(self._data_ctx.stop_streaming(), runloop=
|
|
445
|
+
result = await async_call(self._data_ctx.stop_streaming(), runloop=None)
|
|
417
446
|
return result
|
|
418
447
|
|
|
419
448
|
def stopDataNotification(self) -> bool:
|
|
@@ -565,7 +594,6 @@ class SensorProfile:
|
|
|
565
594
|
if key == "DEBUG_BLE_DATA_PATH":
|
|
566
595
|
result = await self._data_ctx.setDebugCSV(value)
|
|
567
596
|
|
|
568
|
-
self._is_setting_param = False
|
|
569
597
|
return result
|
|
570
598
|
|
|
571
599
|
def setParam(self, key: str, value: str) -> str:
|
|
@@ -581,11 +609,17 @@ class SensorProfile:
|
|
|
581
609
|
if self._is_setting_param:
|
|
582
610
|
return "Error: Please wait for the previous operation to complete"
|
|
583
611
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
612
|
+
try:
|
|
613
|
+
self._is_setting_param = True
|
|
614
|
+
ret = sync_call(
|
|
615
|
+
self._setParam(key, value),
|
|
616
|
+
1,
|
|
617
|
+
)
|
|
618
|
+
self._is_setting_param = False
|
|
619
|
+
return ret
|
|
620
|
+
except Exception as e:
|
|
621
|
+
self._is_setting_param = False
|
|
622
|
+
print(e)
|
|
589
623
|
|
|
590
624
|
async def asyncSetParam(self, key: str, value: str) -> str:
|
|
591
625
|
"""
|
|
@@ -600,8 +634,14 @@ class SensorProfile:
|
|
|
600
634
|
if self._is_setting_param:
|
|
601
635
|
return "Error: Please wait for the previous operation to complete"
|
|
602
636
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
637
|
+
try:
|
|
638
|
+
self._is_setting_param = True
|
|
639
|
+
ret = await async_call(
|
|
640
|
+
self._setParam(key, value),
|
|
641
|
+
1,
|
|
642
|
+
)
|
|
643
|
+
self._is_setting_param = False
|
|
644
|
+
return ret
|
|
645
|
+
except Exception as e:
|
|
646
|
+
self._is_setting_param = False
|
|
647
|
+
print(e)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: sensor-sdk
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.31
|
|
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
|
|
|
@@ -8,7 +8,7 @@ with open(os.path.join(this_directory, "README.md"), "r", encoding="utf-8") as f
|
|
|
8
8
|
|
|
9
9
|
setup(
|
|
10
10
|
name="sensor-sdk",
|
|
11
|
-
version="0.0.
|
|
11
|
+
version="0.0.31",
|
|
12
12
|
description="Python sdk for Synchroni",
|
|
13
13
|
long_description=long_description,
|
|
14
14
|
long_description_content_type="text/markdown",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|