sensor-sdk 0.0.5__py3-none-any.whl → 0.0.7__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 +8 -21
- sensor/sensor_controller.py +15 -36
- sensor/sensor_data_context.py +34 -57
- sensor/sensor_profile.py +32 -75
- sensor/utils.py +15 -14
- {sensor_sdk-0.0.5.dist-info → sensor_sdk-0.0.7.dist-info}/METADATA +1 -1
- sensor_sdk-0.0.7.dist-info/RECORD +14 -0
- sensor_sdk-0.0.5.dist-info/RECORD +0 -14
- {sensor_sdk-0.0.5.dist-info → sensor_sdk-0.0.7.dist-info}/LICENSE.txt +0 -0
- {sensor_sdk-0.0.5.dist-info → sensor_sdk-0.0.7.dist-info}/WHEEL +0 -0
- {sensor_sdk-0.0.5.dist-info → sensor_sdk-0.0.7.dist-info}/top_level.txt +0 -0
- {sensor_sdk-0.0.5.dist-info → sensor_sdk-0.0.7.dist-info}/zip-safe +0 -0
sensor/gforce.py
CHANGED
|
@@ -370,9 +370,7 @@ class Response:
|
|
|
370
370
|
|
|
371
371
|
|
|
372
372
|
class GForce:
|
|
373
|
-
def __init__(
|
|
374
|
-
self, device: BLEDevice, cmd_char: str, data_char: str, isUniversalStream: bool
|
|
375
|
-
):
|
|
373
|
+
def __init__(self, device: BLEDevice, cmd_char: str, data_char: str, isUniversalStream: bool):
|
|
376
374
|
self.device_name = ""
|
|
377
375
|
self.client = None
|
|
378
376
|
self.cmd_char = cmd_char
|
|
@@ -412,6 +410,7 @@ class GForce:
|
|
|
412
410
|
|
|
413
411
|
def _on_data_response(self, q: Queue[bytes], bs: bytearray):
|
|
414
412
|
bs = bytes(bs)
|
|
413
|
+
|
|
415
414
|
full_packet = []
|
|
416
415
|
|
|
417
416
|
is_partial_data = bs[0] == ResponseCode.PARTIAL_PACKET
|
|
@@ -500,9 +499,7 @@ class GForce:
|
|
|
500
499
|
def _convert_acceleration_to_g(data: bytes) -> np.ndarray[np.float32]:
|
|
501
500
|
normalizing_factor = 65536.0
|
|
502
501
|
|
|
503
|
-
acceleration_data = (
|
|
504
|
-
np.frombuffer(data, dtype=np.int32).astype(np.float32) / normalizing_factor
|
|
505
|
-
)
|
|
502
|
+
acceleration_data = np.frombuffer(data, dtype=np.int32).astype(np.float32) / normalizing_factor
|
|
506
503
|
num_channels = 3
|
|
507
504
|
|
|
508
505
|
return acceleration_data.reshape(-1, num_channels)
|
|
@@ -511,9 +508,7 @@ class GForce:
|
|
|
511
508
|
def _convert_gyro_to_dps(data: bytes) -> np.ndarray[np.float32]:
|
|
512
509
|
normalizing_factor = 65536.0
|
|
513
510
|
|
|
514
|
-
gyro_data = (
|
|
515
|
-
np.frombuffer(data, dtype=np.int32).astype(np.float32) / normalizing_factor
|
|
516
|
-
)
|
|
511
|
+
gyro_data = np.frombuffer(data, dtype=np.int32).astype(np.float32) / normalizing_factor
|
|
517
512
|
num_channels = 3
|
|
518
513
|
|
|
519
514
|
return gyro_data.reshape(-1, num_channels)
|
|
@@ -522,9 +517,7 @@ class GForce:
|
|
|
522
517
|
def _convert_magnetometer_to_ut(data: bytes) -> np.ndarray[np.float32]:
|
|
523
518
|
normalizing_factor = 65536.0
|
|
524
519
|
|
|
525
|
-
magnetometer_data = (
|
|
526
|
-
np.frombuffer(data, dtype=np.int32).astype(np.float32) / normalizing_factor
|
|
527
|
-
)
|
|
520
|
+
magnetometer_data = np.frombuffer(data, dtype=np.int32).astype(np.float32) / normalizing_factor
|
|
528
521
|
num_channels = 3
|
|
529
522
|
|
|
530
523
|
return magnetometer_data.reshape(-1, num_channels)
|
|
@@ -846,15 +839,11 @@ class GForce:
|
|
|
846
839
|
async def stop_streaming(self):
|
|
847
840
|
exceptions = []
|
|
848
841
|
try:
|
|
849
|
-
await asyncio.wait_for(
|
|
850
|
-
self.set_subscription(DataSubscription.OFF), utils._TIMEOUT
|
|
851
|
-
)
|
|
842
|
+
await asyncio.wait_for(self.set_subscription(DataSubscription.OFF), utils._TIMEOUT)
|
|
852
843
|
except Exception as e:
|
|
853
844
|
exceptions.append(e)
|
|
854
845
|
try:
|
|
855
|
-
await asyncio.wait_for(
|
|
856
|
-
self.client.stop_notify(self.data_char), utils._TIMEOUT
|
|
857
|
-
)
|
|
846
|
+
await asyncio.wait_for(self.client.stop_notify(self.data_char), utils._TIMEOUT)
|
|
858
847
|
except Exception as e:
|
|
859
848
|
exceptions.append(e)
|
|
860
849
|
|
|
@@ -881,9 +870,7 @@ class GForce:
|
|
|
881
870
|
bs = bytes([req.cmd])
|
|
882
871
|
if req.body is not None:
|
|
883
872
|
bs += req.body
|
|
884
|
-
await asyncio.wait_for(
|
|
885
|
-
self.client.write_gatt_char(self.cmd_char, bs), utils._TIMEOUT
|
|
886
|
-
)
|
|
873
|
+
await asyncio.wait_for(self.client.write_gatt_char(self.cmd_char, bs), utils._TIMEOUT)
|
|
887
874
|
|
|
888
875
|
if not req.has_res:
|
|
889
876
|
return None
|
sensor/sensor_controller.py
CHANGED
|
@@ -9,7 +9,7 @@ from sensor import utils
|
|
|
9
9
|
from sensor.sensor_profile import DeviceStateEx, SensorProfile
|
|
10
10
|
import asyncio
|
|
11
11
|
|
|
12
|
-
from sensor.utils import
|
|
12
|
+
from sensor.utils import async_call, start_loop, sync_call, async_exec, timer
|
|
13
13
|
from bleak import (
|
|
14
14
|
BleakScanner,
|
|
15
15
|
AdvertisementData,
|
|
@@ -38,16 +38,12 @@ class SensorController:
|
|
|
38
38
|
初始化 SensorController 实例。
|
|
39
39
|
"""
|
|
40
40
|
self._event_loop = asyncio.new_event_loop()
|
|
41
|
-
self._event_thread = threading.Thread(
|
|
42
|
-
target=start_loop, args=(self._event_loop,)
|
|
43
|
-
)
|
|
41
|
+
self._event_thread = threading.Thread(target=start_loop, args=(self._event_loop,))
|
|
44
42
|
self._event_thread.daemon = True
|
|
45
43
|
self._event_thread.name = "SensorController event"
|
|
46
44
|
self._event_thread.start()
|
|
47
45
|
self._gforce_event_loop = asyncio.new_event_loop()
|
|
48
|
-
self._gforce_event_thread = threading.Thread(
|
|
49
|
-
target=start_loop, args=(self._gforce_event_loop,)
|
|
50
|
-
)
|
|
46
|
+
self._gforce_event_thread = threading.Thread(target=start_loop, args=(self._gforce_event_loop,))
|
|
51
47
|
self._gforce_event_thread.daemon = True
|
|
52
48
|
self._gforce_event_thread.name = "BLE operation"
|
|
53
49
|
self._gforce_event_thread.start()
|
|
@@ -72,10 +68,7 @@ class SensorController:
|
|
|
72
68
|
def terminate(self):
|
|
73
69
|
utils._terminated = True
|
|
74
70
|
for sensor in self._sensor_profiles.values():
|
|
75
|
-
if
|
|
76
|
-
sensor.deviceState == DeviceStateEx.Connected
|
|
77
|
-
or sensor.deviceState == DeviceStateEx.Ready
|
|
78
|
-
):
|
|
71
|
+
if sensor.deviceState == DeviceStateEx.Connected or sensor.deviceState == DeviceStateEx.Ready:
|
|
79
72
|
sensor._destroy()
|
|
80
73
|
|
|
81
74
|
def _match_device(self, _device: bleak.BLEDevice, adv: AdvertisementData):
|
|
@@ -125,9 +118,7 @@ class SensorController:
|
|
|
125
118
|
return self._device_callback != None
|
|
126
119
|
|
|
127
120
|
@hasDeviceFoundCallback.setter
|
|
128
|
-
def onDeviceFoundCallback(
|
|
129
|
-
self, callback: Callable[[List[sensor_profile.BLEDevice]], None]
|
|
130
|
-
):
|
|
121
|
+
def onDeviceFoundCallback(self, callback: Callable[[List[sensor_profile.BLEDevice]], None]):
|
|
131
122
|
"""
|
|
132
123
|
设置扫描设备回调。
|
|
133
124
|
|
|
@@ -168,9 +159,7 @@ class SensorController:
|
|
|
168
159
|
|
|
169
160
|
async def _async_scan(self, period):
|
|
170
161
|
self._is_scanning = True
|
|
171
|
-
found_devices = await self._scanner.discover(
|
|
172
|
-
timeout=period / 1000, return_adv=True
|
|
173
|
-
)
|
|
162
|
+
found_devices = await self._scanner.discover(timeout=period / 1000, return_adv=True)
|
|
174
163
|
self._is_scanning = False
|
|
175
164
|
return self._process_ble_devices(found_devices)
|
|
176
165
|
|
|
@@ -182,7 +171,7 @@ class SensorController:
|
|
|
182
171
|
|
|
183
172
|
:return: List[sensor_profile.BLEDevice]: BLEDevice列表
|
|
184
173
|
"""
|
|
185
|
-
return
|
|
174
|
+
return sync_call(self._gforce_event_loop, self._async_scan(period))
|
|
186
175
|
|
|
187
176
|
async def asyncScan(self, period) -> List[sensor_profile.BLEDevice]:
|
|
188
177
|
"""
|
|
@@ -192,7 +181,7 @@ class SensorController:
|
|
|
192
181
|
|
|
193
182
|
:return: List[sensor_profile.BLEDevice]: BLEDevice列表
|
|
194
183
|
"""
|
|
195
|
-
return await
|
|
184
|
+
return await async_call(self._gforce_event_loop, self._async_scan(period))
|
|
196
185
|
|
|
197
186
|
async def _device_scan_callback(self, devices: List[sensor_profile.BLEDevice]):
|
|
198
187
|
if self._device_callback:
|
|
@@ -202,14 +191,12 @@ class SensorController:
|
|
|
202
191
|
print(e)
|
|
203
192
|
|
|
204
193
|
if self._is_scanning:
|
|
205
|
-
|
|
194
|
+
async_exec(self._gforce_event_loop, self._startScan())
|
|
206
195
|
|
|
207
196
|
async def _startScan(self) -> bool:
|
|
208
|
-
found_devices = await self._scanner.discover(
|
|
209
|
-
timeout=self._device_callback_period / 1000, return_adv=True
|
|
210
|
-
)
|
|
197
|
+
found_devices = await self._scanner.discover(timeout=self._device_callback_period / 1000, return_adv=True)
|
|
211
198
|
devices = self._process_ble_devices(found_devices)
|
|
212
|
-
|
|
199
|
+
async_exec(self._event_loop, self._device_scan_callback(devices))
|
|
213
200
|
|
|
214
201
|
def startScan(self, periodInMs: int) -> bool:
|
|
215
202
|
"""
|
|
@@ -225,7 +212,7 @@ class SensorController:
|
|
|
225
212
|
self._is_scanning = True
|
|
226
213
|
self._device_callback_period = periodInMs
|
|
227
214
|
|
|
228
|
-
|
|
215
|
+
async_exec(self._gforce_event_loop, self._startScan())
|
|
229
216
|
return True
|
|
230
217
|
|
|
231
218
|
def stopScan(self) -> None:
|
|
@@ -237,9 +224,7 @@ class SensorController:
|
|
|
237
224
|
|
|
238
225
|
self._is_scanning = False
|
|
239
226
|
|
|
240
|
-
def requireSensor(
|
|
241
|
-
self, device: sensor_profile.BLEDevice
|
|
242
|
-
) -> Optional[SensorProfile]:
|
|
227
|
+
def requireSensor(self, device: sensor_profile.BLEDevice) -> Optional[SensorProfile]:
|
|
243
228
|
"""
|
|
244
229
|
根据设备信息获取或创建SensorProfile。
|
|
245
230
|
|
|
@@ -271,10 +256,7 @@ class SensorController:
|
|
|
271
256
|
"""
|
|
272
257
|
sensors: List[SensorProfile] = list()
|
|
273
258
|
for sensor in self._sensor_profiles.values():
|
|
274
|
-
if
|
|
275
|
-
sensor.deviceState == DeviceStateEx.Connected
|
|
276
|
-
or sensor.deviceState == DeviceStateEx.Ready
|
|
277
|
-
):
|
|
259
|
+
if sensor.deviceState == DeviceStateEx.Connected or sensor.deviceState == DeviceStateEx.Ready:
|
|
278
260
|
sensors.append(sensor)
|
|
279
261
|
|
|
280
262
|
return sensors
|
|
@@ -287,10 +269,7 @@ class SensorController:
|
|
|
287
269
|
"""
|
|
288
270
|
devices: List[sensor_profile.BLEDevice] = list()
|
|
289
271
|
for sensor in self._sensor_profiles.values():
|
|
290
|
-
if
|
|
291
|
-
sensor.deviceState == DeviceStateEx.Connected
|
|
292
|
-
or sensor.deviceState == DeviceStateEx.Ready
|
|
293
|
-
):
|
|
272
|
+
if sensor.deviceState == DeviceStateEx.Connected or sensor.deviceState == DeviceStateEx.Ready:
|
|
294
273
|
devices.append(sensor.BLEDevice)
|
|
295
274
|
|
|
296
275
|
return devices
|
sensor/sensor_data_context.py
CHANGED
|
@@ -82,9 +82,7 @@ class SensorProfileDataCtx:
|
|
|
82
82
|
return self._is_data_transfering
|
|
83
83
|
|
|
84
84
|
def hasInit(self):
|
|
85
|
-
return
|
|
86
|
-
not self._is_initing and self.featureMap != 0 and self.notifyDataFlag != 0
|
|
87
|
-
)
|
|
85
|
+
return not self._is_initing and self.featureMap != 0 and self.notifyDataFlag != 0
|
|
88
86
|
|
|
89
87
|
def hasEMG(self):
|
|
90
88
|
return (self.featureMap & FeatureMaps.GFD_FEAT_EMG.value) != 0
|
|
@@ -207,13 +205,13 @@ class SensorProfileDataCtx:
|
|
|
207
205
|
info.MTUSize = self.gForce.client.mtu_size
|
|
208
206
|
else:
|
|
209
207
|
info.MTUSize = 0
|
|
210
|
-
print("get_device_name")
|
|
208
|
+
# print("get_device_name")
|
|
211
209
|
info.DeviceName = await self.gForce.get_device_name()
|
|
212
|
-
print("get_model_number")
|
|
210
|
+
# print("get_model_number")
|
|
213
211
|
info.ModelName = await self.gForce.get_model_number()
|
|
214
|
-
print("get_hardware_revision")
|
|
212
|
+
# print("get_hardware_revision")
|
|
215
213
|
info.HardwareVersion = await self.gForce.get_hardware_revision()
|
|
216
|
-
print("get_firmware_revision")
|
|
214
|
+
# print("get_firmware_revision")
|
|
217
215
|
info.FirmwareVersion = await self.gForce.get_firmware_revision()
|
|
218
216
|
return info
|
|
219
217
|
|
|
@@ -228,19 +226,19 @@ class SensorProfileDataCtx:
|
|
|
228
226
|
self.notifyDataFlag |= DataSubscription.DNF_IMPEDANCE
|
|
229
227
|
|
|
230
228
|
if self.hasEEG():
|
|
231
|
-
print("initEEG")
|
|
229
|
+
# print("initEEG")
|
|
232
230
|
info.EegChannelCount = await self.initEEG(packageCount)
|
|
233
231
|
|
|
234
232
|
if self.hasECG():
|
|
235
|
-
print("initECG")
|
|
233
|
+
# print("initECG")
|
|
236
234
|
info.EcgChannelCount = await self.initECG(packageCount)
|
|
237
235
|
|
|
238
236
|
if self.hasBrth():
|
|
239
|
-
print("initBrth")
|
|
237
|
+
# print("initBrth")
|
|
240
238
|
info.BrthChannelCount = await self.initBrth(packageCount)
|
|
241
239
|
|
|
242
240
|
if self.hasIMU():
|
|
243
|
-
print("initIMU")
|
|
241
|
+
# print("initIMU")
|
|
244
242
|
imuChannelCount = await self.initIMU(packageCount)
|
|
245
243
|
info.AccChannelCount = imuChannelCount
|
|
246
244
|
info.GyroChannelCount = imuChannelCount
|
|
@@ -337,9 +335,7 @@ class SensorProfileDataCtx:
|
|
|
337
335
|
if self.checkReadSamples(sensor, data, sensor_data_gyro, 9, 6):
|
|
338
336
|
self.sendSensorData(sensor_data_gyro, buf)
|
|
339
337
|
|
|
340
|
-
def checkReadSamples(
|
|
341
|
-
self, sensor, data: bytes, sensorData: SensorData, dataOffset: int, dataGap: int
|
|
342
|
-
):
|
|
338
|
+
def checkReadSamples(self, sensor, data: bytes, sensorData: SensorData, dataOffset: int, dataGap: int):
|
|
343
339
|
offset = 1
|
|
344
340
|
v = data[0]
|
|
345
341
|
if not self._is_data_transfering:
|
|
@@ -358,9 +354,7 @@ class SensorProfileDataCtx:
|
|
|
358
354
|
|
|
359
355
|
deltaPackageIndex = packageIndex - lastPackageIndex
|
|
360
356
|
if deltaPackageIndex > 1:
|
|
361
|
-
lostSampleCount = sensorData.packageSampleCount * (
|
|
362
|
-
deltaPackageIndex - 1
|
|
363
|
-
)
|
|
357
|
+
lostSampleCount = sensorData.packageSampleCount * (deltaPackageIndex - 1)
|
|
364
358
|
lostLog = (
|
|
365
359
|
"MSG|LOST SAMPLE|MAC|"
|
|
366
360
|
+ str(sensorData.deviceMac)
|
|
@@ -372,9 +366,7 @@ class SensorProfileDataCtx:
|
|
|
372
366
|
# print(lostLog)
|
|
373
367
|
if sensor._event_loop != None and sensor._on_error_callback != None:
|
|
374
368
|
try:
|
|
375
|
-
sensor._event_loop.call_soon_threadsafe(
|
|
376
|
-
sensor._on_error_callback, sensor, lostLog
|
|
377
|
-
)
|
|
369
|
+
sensor._event_loop.call_soon_threadsafe(sensor._on_error_callback, sensor, lostLog)
|
|
378
370
|
except Exception as e:
|
|
379
371
|
pass
|
|
380
372
|
|
|
@@ -418,18 +410,14 @@ class SensorProfileDataCtx:
|
|
|
418
410
|
channelSamples.append([])
|
|
419
411
|
|
|
420
412
|
for sampleIndex in range(sampleCount):
|
|
421
|
-
for channelIndex, impedanceChannelIndex in enumerate(
|
|
422
|
-
range(sensorData.channelCount)
|
|
423
|
-
):
|
|
413
|
+
for channelIndex, impedanceChannelIndex in enumerate(range(sensorData.channelCount)):
|
|
424
414
|
if (sensorData.channelMask & (1 << channelIndex)) != 0:
|
|
425
415
|
samples = channelSamples[channelIndex]
|
|
426
416
|
impedance = 0.0
|
|
427
417
|
saturation = 0.0
|
|
428
418
|
|
|
429
419
|
if sensorData.dataType == DataType.NTF_ECG:
|
|
430
|
-
impedanceChannelIndex = self.sensorDatas[
|
|
431
|
-
SensorDataType.DATA_TYPE_EEG
|
|
432
|
-
].channelCount
|
|
420
|
+
impedanceChannelIndex = self.sensorDatas[SensorDataType.DATA_TYPE_EEG].channelCount
|
|
433
421
|
|
|
434
422
|
if impedanceChannelIndex < len(_impedanceData):
|
|
435
423
|
impedance = _impedanceData[impedanceChannelIndex]
|
|
@@ -461,11 +449,7 @@ class SensorProfileDataCtx:
|
|
|
461
449
|
)
|
|
462
450
|
offset += 2
|
|
463
451
|
elif sensorData.resolutionBits == 24:
|
|
464
|
-
rawData = (
|
|
465
|
-
(data[offset] << 16)
|
|
466
|
-
| (data[offset + 1] << 8)
|
|
467
|
-
| data[offset + 2]
|
|
468
|
-
)
|
|
452
|
+
rawData = (data[offset] << 16) | (data[offset + 1] << 8) | data[offset + 2]
|
|
469
453
|
rawData -= 8388608
|
|
470
454
|
offset += 3
|
|
471
455
|
|
|
@@ -802,11 +786,15 @@ class SensorProfileDataCtx:
|
|
|
802
786
|
|
|
803
787
|
return crc8
|
|
804
788
|
|
|
805
|
-
def processUniversalData(
|
|
806
|
-
self, buf: Queue[SensorData],
|
|
789
|
+
async def processUniversalData(
|
|
790
|
+
self, buf: Queue[SensorData], event_loop: asyncio.AbstractEventLoop, cmd_loop: asyncio.AbstractEventLoop, sensor, callback
|
|
807
791
|
):
|
|
808
792
|
|
|
809
793
|
while self._is_running:
|
|
794
|
+
while self._is_running and self._rawDataBuffer.empty():
|
|
795
|
+
await asyncio.sleep(0.01)
|
|
796
|
+
continue
|
|
797
|
+
|
|
810
798
|
try:
|
|
811
799
|
while self._is_running and not self._rawDataBuffer.empty():
|
|
812
800
|
data = self._rawDataBuffer.get_nowait()
|
|
@@ -832,34 +820,28 @@ class SensorProfileDataCtx:
|
|
|
832
820
|
index += 1
|
|
833
821
|
continue
|
|
834
822
|
crc = self._concatDataBuffer[index + 1 + n + 1]
|
|
835
|
-
calc_crc = self.calc_crc8(
|
|
836
|
-
self._concatDataBuffer[index + 2 : index + 2 + n]
|
|
837
|
-
)
|
|
823
|
+
calc_crc = self.calc_crc8(self._concatDataBuffer[index + 2 : index + 2 + n])
|
|
838
824
|
if crc != calc_crc:
|
|
839
825
|
index += 1
|
|
840
826
|
continue
|
|
841
827
|
if self._is_data_transfering:
|
|
842
|
-
data_package = bytes(
|
|
843
|
-
self._concatDataBuffer[index + 2 : index + 2 + n]
|
|
844
|
-
)
|
|
828
|
+
data_package = bytes(self._concatDataBuffer[index + 2 : index + 2 + n])
|
|
845
829
|
self._processDataPackage(data_package, buf, sensor)
|
|
846
|
-
while self._is_running and self.isDataTransfering:
|
|
830
|
+
while self._is_running and self.isDataTransfering and not buf.empty():
|
|
847
831
|
sensorData: SensorData = None
|
|
848
832
|
try:
|
|
849
833
|
sensorData = buf.get_nowait()
|
|
850
834
|
except Exception as e:
|
|
851
835
|
break
|
|
852
|
-
if
|
|
836
|
+
if event_loop != None and sensorData != None and callback != None:
|
|
853
837
|
try:
|
|
854
|
-
|
|
855
|
-
callback, sensor, sensorData
|
|
856
|
-
)
|
|
838
|
+
event_loop.call_soon_threadsafe(callback, sensor, sensorData)
|
|
857
839
|
except Exception as e:
|
|
858
840
|
print(e)
|
|
859
841
|
|
|
860
842
|
buf.task_done()
|
|
861
|
-
|
|
862
843
|
last_cut = index = index + 2 + n
|
|
844
|
+
|
|
863
845
|
elif self._concatDataBuffer[index] == 0xAA:
|
|
864
846
|
if (index + 1) >= data_size:
|
|
865
847
|
index += 1
|
|
@@ -869,22 +851,17 @@ class SensorProfileDataCtx:
|
|
|
869
851
|
index += 1
|
|
870
852
|
continue
|
|
871
853
|
crc = self._concatDataBuffer[index + 1 + n + 1]
|
|
872
|
-
calc_crc = self.calc_crc8(
|
|
873
|
-
self._concatDataBuffer[index + 2 : index + 2 + n]
|
|
874
|
-
)
|
|
854
|
+
calc_crc = self.calc_crc8(self._concatDataBuffer[index + 2 : index + 2 + n])
|
|
875
855
|
if crc != calc_crc:
|
|
876
856
|
index += 1
|
|
877
857
|
continue
|
|
878
|
-
data_package = bytes(
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
if loop != None:
|
|
882
|
-
loop.call_soon_threadsafe(
|
|
883
|
-
self.gForce._on_cmd_response, None, data_package
|
|
884
|
-
)
|
|
858
|
+
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)
|
|
885
861
|
last_cut = index = index + 2 + n
|
|
862
|
+
|
|
886
863
|
else:
|
|
887
864
|
index += 1
|
|
888
865
|
|
|
889
|
-
|
|
890
|
-
|
|
866
|
+
if last_cut > 0:
|
|
867
|
+
self._concatDataBuffer = self._concatDataBuffer[last_cut + 1 :]
|
sensor/sensor_profile.py
CHANGED
|
@@ -21,7 +21,7 @@ import threading
|
|
|
21
21
|
|
|
22
22
|
from sensor.sensor_data_context import SensorProfileDataCtx
|
|
23
23
|
from sensor.sensor_device import BLEDevice, DeviceInfo, DeviceStateEx
|
|
24
|
-
from sensor.utils import
|
|
24
|
+
from sensor.utils import async_call, start_loop, sync_call, async_exec, timer
|
|
25
25
|
from contextlib import suppress
|
|
26
26
|
from dataclasses import dataclass
|
|
27
27
|
|
|
@@ -78,10 +78,7 @@ class SensorProfile:
|
|
|
78
78
|
self._destroy()
|
|
79
79
|
|
|
80
80
|
def _destroy(self):
|
|
81
|
-
if
|
|
82
|
-
self._device_state == DeviceStateEx.Connected
|
|
83
|
-
or self._device_state == DeviceStateEx.Ready
|
|
84
|
-
):
|
|
81
|
+
if self._device_state == DeviceStateEx.Connected or self._device_state == DeviceStateEx.Ready:
|
|
85
82
|
self.disconnect()
|
|
86
83
|
if self._data_event_loop != None:
|
|
87
84
|
try:
|
|
@@ -114,9 +111,7 @@ class SensorProfile:
|
|
|
114
111
|
self._device_state = newState
|
|
115
112
|
if self._event_loop != None and self._on_state_changed != None:
|
|
116
113
|
try:
|
|
117
|
-
self._event_loop.call_soon_threadsafe(
|
|
118
|
-
self._on_state_changed, self, newState
|
|
119
|
-
)
|
|
114
|
+
self._event_loop.call_soon_threadsafe(self._on_state_changed, self, newState)
|
|
120
115
|
except Exception as e:
|
|
121
116
|
print(e)
|
|
122
117
|
pass
|
|
@@ -162,9 +157,7 @@ class SensorProfile:
|
|
|
162
157
|
return self._on_state_changed
|
|
163
158
|
|
|
164
159
|
@onStateChanged.setter
|
|
165
|
-
def onStateChanged(
|
|
166
|
-
self, callback: Callable[["SensorProfile", DeviceStateEx], None]
|
|
167
|
-
):
|
|
160
|
+
def onStateChanged(self, callback: Callable[["SensorProfile", DeviceStateEx], None]):
|
|
168
161
|
"""
|
|
169
162
|
设置状态变化的回调函数。
|
|
170
163
|
|
|
@@ -229,9 +222,7 @@ class SensorProfile:
|
|
|
229
222
|
async def _connect(self) -> bool:
|
|
230
223
|
if self._event_thread == None:
|
|
231
224
|
self._event_loop = asyncio.new_event_loop()
|
|
232
|
-
self._event_thread = threading.Thread(
|
|
233
|
-
target=start_loop, args=(self._event_loop,)
|
|
234
|
-
)
|
|
225
|
+
self._event_thread = threading.Thread(target=start_loop, args=(self._event_loop,))
|
|
235
226
|
self._event_thread.daemon = True
|
|
236
227
|
self._event_thread.name = self._device.Name + " event"
|
|
237
228
|
self._event_thread.start()
|
|
@@ -249,35 +240,22 @@ class SensorProfile:
|
|
|
249
240
|
)
|
|
250
241
|
elif self._adv.service_data.get(RFSTAR_SERVICE_GUID) != None:
|
|
251
242
|
# print("RFSTAR_SERVICE:" + self._detail_device.name)
|
|
252
|
-
self._gforce = GForce(
|
|
253
|
-
self._detail_device, RFSTAR_CMD_UUID, RFSTAR_DATA_UUID, True
|
|
254
|
-
)
|
|
243
|
+
self._gforce = GForce(self._detail_device, RFSTAR_CMD_UUID, RFSTAR_DATA_UUID, True)
|
|
255
244
|
self._data_event_loop = asyncio.new_event_loop()
|
|
256
|
-
self._data_event_thread = threading.Thread(
|
|
257
|
-
target=start_loop, args=(self._data_event_loop,)
|
|
258
|
-
)
|
|
245
|
+
self._data_event_thread = threading.Thread(target=start_loop, args=(self._data_event_loop,))
|
|
259
246
|
self._data_event_thread.daemon = True
|
|
260
247
|
self._data_event_thread.name = self._detail_device.name + " data"
|
|
261
248
|
self._data_event_thread.start()
|
|
262
249
|
else:
|
|
263
|
-
print(
|
|
264
|
-
"Invalid device service uuid:"
|
|
265
|
-
+ self._detail_device.name
|
|
266
|
-
+ str(self._adv)
|
|
267
|
-
)
|
|
250
|
+
print("Invalid device service uuid:" + self._detail_device.name + str(self._adv))
|
|
268
251
|
return False
|
|
269
252
|
|
|
270
253
|
if self._data_ctx == None and self._gforce != None:
|
|
271
|
-
self._data_ctx = SensorProfileDataCtx(
|
|
272
|
-
self._gforce, self._device.Address, self._raw_data_buf
|
|
273
|
-
)
|
|
254
|
+
self._data_ctx = SensorProfileDataCtx(self._gforce, self._device.Address, self._raw_data_buf)
|
|
274
255
|
if self._data_ctx.isUniversalStream:
|
|
275
|
-
|
|
256
|
+
async_exec(self._data_event_loop, self._process_universal_data())
|
|
276
257
|
|
|
277
|
-
if
|
|
278
|
-
self.deviceState == DeviceStateEx.Connected
|
|
279
|
-
or self.deviceState == DeviceStateEx.Ready
|
|
280
|
-
):
|
|
258
|
+
if self.deviceState == DeviceStateEx.Connected or self.deviceState == DeviceStateEx.Ready:
|
|
281
259
|
return True
|
|
282
260
|
self._set_device_state(DeviceStateEx.Connecting)
|
|
283
261
|
|
|
@@ -311,7 +289,7 @@ class SensorProfile:
|
|
|
311
289
|
:return: bool: 如果连接成功,返回 True;否则返回 False。
|
|
312
290
|
|
|
313
291
|
"""
|
|
314
|
-
result =
|
|
292
|
+
result = sync_call(self._gforce_event_loop, self._connect())
|
|
315
293
|
return result
|
|
316
294
|
|
|
317
295
|
async def asyncConnect(self) -> bool:
|
|
@@ -321,7 +299,7 @@ class SensorProfile:
|
|
|
321
299
|
:return: bool: 如果连接成功,返回 True;否则返回 False。
|
|
322
300
|
|
|
323
301
|
"""
|
|
324
|
-
return await
|
|
302
|
+
return await async_call(self._gforce_event_loop, self._connect())
|
|
325
303
|
|
|
326
304
|
async def _waitForDisconnect(self) -> bool:
|
|
327
305
|
while self.deviceState != DeviceStateEx.Disconnected:
|
|
@@ -329,10 +307,7 @@ class SensorProfile:
|
|
|
329
307
|
return True
|
|
330
308
|
|
|
331
309
|
async def _disconnect(self) -> bool:
|
|
332
|
-
if
|
|
333
|
-
self.deviceState != DeviceStateEx.Connected
|
|
334
|
-
and self.deviceState != DeviceStateEx.Ready
|
|
335
|
-
):
|
|
310
|
+
if self.deviceState != DeviceStateEx.Connected and self.deviceState != DeviceStateEx.Ready:
|
|
336
311
|
return True
|
|
337
312
|
if self._data_ctx == None:
|
|
338
313
|
return False
|
|
@@ -348,7 +323,7 @@ class SensorProfile:
|
|
|
348
323
|
:return: bool: 如果断开连接成功,返回 True;否则返回 False。
|
|
349
324
|
|
|
350
325
|
"""
|
|
351
|
-
return
|
|
326
|
+
return sync_call(self._gforce_event_loop, self._disconnect())
|
|
352
327
|
|
|
353
328
|
async def asyncDisconnect(self) -> bool:
|
|
354
329
|
"""
|
|
@@ -357,7 +332,7 @@ class SensorProfile:
|
|
|
357
332
|
:return: bool: 如果断开连接成功,返回 True;否则返回 False。
|
|
358
333
|
|
|
359
334
|
"""
|
|
360
|
-
return await
|
|
335
|
+
return await async_call(self._gforce_event_loop, self._disconnect())
|
|
361
336
|
|
|
362
337
|
async def _process_data(self):
|
|
363
338
|
while self._data_ctx._is_running and self._data_ctx.isDataTransfering:
|
|
@@ -368,22 +343,16 @@ class SensorProfile:
|
|
|
368
343
|
sensorData = self._data_buffer.get_nowait()
|
|
369
344
|
except Exception as e:
|
|
370
345
|
break
|
|
371
|
-
if
|
|
372
|
-
self._event_loop != None
|
|
373
|
-
and sensorData != None
|
|
374
|
-
and self._on_data_callback != None
|
|
375
|
-
):
|
|
346
|
+
if self._event_loop != None and sensorData != None and self._on_data_callback != None:
|
|
376
347
|
try:
|
|
377
|
-
self._event_loop.call_soon_threadsafe(
|
|
378
|
-
self._on_data_callback, self, sensorData
|
|
379
|
-
)
|
|
348
|
+
self._event_loop.call_soon_threadsafe(self._on_data_callback, self, sensorData)
|
|
380
349
|
except Exception as e:
|
|
381
350
|
print(e)
|
|
382
351
|
self._data_buffer.task_done()
|
|
383
352
|
|
|
384
353
|
async def _process_universal_data(self):
|
|
385
|
-
self._data_ctx.processUniversalData(
|
|
386
|
-
self._data_buffer, self._event_loop, self, self._on_data_callback
|
|
354
|
+
await self._data_ctx.processUniversalData(
|
|
355
|
+
self._data_buffer, self._event_loop, self._gforce_event_loop, self, self._on_data_callback
|
|
387
356
|
)
|
|
388
357
|
|
|
389
358
|
async def _startDataNotification(self) -> bool:
|
|
@@ -399,9 +368,7 @@ class SensorProfile:
|
|
|
399
368
|
|
|
400
369
|
if self._data_event_loop == None:
|
|
401
370
|
self._data_event_loop = asyncio.new_event_loop()
|
|
402
|
-
self._data_event_thread = threading.Thread(
|
|
403
|
-
target=start_loop, args=(self._data_event_loop,)
|
|
404
|
-
)
|
|
371
|
+
self._data_event_thread = threading.Thread(target=start_loop, args=(self._data_event_loop,))
|
|
405
372
|
self._data_event_thread.daemon = True
|
|
406
373
|
self._data_event_thread.name = self.BLEDevice.Name + " data"
|
|
407
374
|
self._data_event_thread.start()
|
|
@@ -410,7 +377,7 @@ class SensorProfile:
|
|
|
410
377
|
self._data_buffer.queue.clear()
|
|
411
378
|
self._data_ctx.clear()
|
|
412
379
|
if not self._data_ctx.isUniversalStream:
|
|
413
|
-
|
|
380
|
+
async_exec(self._data_event_loop, self._process_data())
|
|
414
381
|
return result
|
|
415
382
|
|
|
416
383
|
def startDataNotification(self) -> bool:
|
|
@@ -420,7 +387,7 @@ class SensorProfile:
|
|
|
420
387
|
:return: bool: 如果开始数据通知成功,返回 True;否则返回 False。
|
|
421
388
|
|
|
422
389
|
"""
|
|
423
|
-
return
|
|
390
|
+
return sync_call(self._gforce_event_loop, self._startDataNotification())
|
|
424
391
|
|
|
425
392
|
async def asyncStartDataNotification(self) -> bool:
|
|
426
393
|
"""
|
|
@@ -429,9 +396,7 @@ class SensorProfile:
|
|
|
429
396
|
:return: bool: 如果开始数据通知成功,返回 True;否则返回 False。
|
|
430
397
|
|
|
431
398
|
"""
|
|
432
|
-
return await
|
|
433
|
-
self._gforce_event_loop, 0, self._startDataNotification()
|
|
434
|
-
)
|
|
399
|
+
return await async_call(self._gforce_event_loop, self._startDataNotification())
|
|
435
400
|
|
|
436
401
|
async def _stopDataNotification(self) -> bool:
|
|
437
402
|
if self.deviceState != DeviceStateEx.Ready:
|
|
@@ -453,7 +418,7 @@ class SensorProfile:
|
|
|
453
418
|
:return: bool: 如果停止数据通知成功,返回 True;否则返回 False。
|
|
454
419
|
|
|
455
420
|
"""
|
|
456
|
-
return
|
|
421
|
+
return sync_call(self._gforce_event_loop, self._stopDataNotification())
|
|
457
422
|
|
|
458
423
|
async def asyncStopDataNotification(self) -> bool:
|
|
459
424
|
"""
|
|
@@ -462,18 +427,14 @@ class SensorProfile:
|
|
|
462
427
|
:return: bool: 如果停止数据通知成功,返回 True;否则返回 False。
|
|
463
428
|
|
|
464
429
|
"""
|
|
465
|
-
return await
|
|
466
|
-
self._gforce_event_loop, 0, self._stopDataNotification()
|
|
467
|
-
)
|
|
430
|
+
return await async_call(self._gforce_event_loop, self._stopDataNotification())
|
|
468
431
|
|
|
469
432
|
async def _refresh_power(self):
|
|
470
433
|
self._power = await self._gforce.get_battery_level()
|
|
471
434
|
|
|
472
435
|
if self._event_loop != None and self._on_power_changed != None:
|
|
473
436
|
try:
|
|
474
|
-
self._event_loop.call_soon_threadsafe(
|
|
475
|
-
self._on_power_changed, self, self._power
|
|
476
|
-
)
|
|
437
|
+
self._event_loop.call_soon_threadsafe(self._on_power_changed, self, self._power)
|
|
477
438
|
except Exception as e:
|
|
478
439
|
print(e)
|
|
479
440
|
|
|
@@ -512,16 +473,13 @@ class SensorProfile:
|
|
|
512
473
|
:return: bool: 初始化结果。True 表示成功,False 表示失败。
|
|
513
474
|
|
|
514
475
|
"""
|
|
515
|
-
return
|
|
476
|
+
return sync_call(
|
|
516
477
|
self._gforce_event_loop,
|
|
517
|
-
0,
|
|
518
478
|
self._init(packageSampleCount, powerRefreshInterval),
|
|
519
|
-
|
|
479
|
+
20,
|
|
520
480
|
)
|
|
521
481
|
|
|
522
|
-
async def asyncInit(
|
|
523
|
-
self, packageSampleCount: int, powerRefreshInterval: int
|
|
524
|
-
) -> bool:
|
|
482
|
+
async def asyncInit(self, packageSampleCount: int, powerRefreshInterval: int) -> bool:
|
|
525
483
|
"""
|
|
526
484
|
初始化数据采集。
|
|
527
485
|
|
|
@@ -531,11 +489,10 @@ class SensorProfile:
|
|
|
531
489
|
:return: bool: 初始化结果。True 表示成功,False 表示失败。
|
|
532
490
|
|
|
533
491
|
"""
|
|
534
|
-
return await
|
|
492
|
+
return await async_call(
|
|
535
493
|
self._gforce_event_loop,
|
|
536
|
-
0,
|
|
537
494
|
self._init(packageSampleCount, powerRefreshInterval),
|
|
538
|
-
|
|
495
|
+
20,
|
|
539
496
|
)
|
|
540
497
|
|
|
541
498
|
def getBatteryLevel(self) -> int:
|
sensor/utils.py
CHANGED
|
@@ -9,8 +9,7 @@ _TIMEOUT = 10
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
async def delay(_time: float, function) -> any:
|
|
12
|
-
|
|
13
|
-
await asyncio.sleep(_time)
|
|
12
|
+
await asyncio.sleep(_time)
|
|
14
13
|
return await function
|
|
15
14
|
|
|
16
15
|
|
|
@@ -24,32 +23,34 @@ def timer(_loop: asyncio.AbstractEventLoop, _delay: float, function):
|
|
|
24
23
|
pass
|
|
25
24
|
|
|
26
25
|
|
|
27
|
-
def
|
|
28
|
-
_loop
|
|
29
|
-
|
|
26
|
+
def async_exec(_loop: asyncio.AbstractEventLoop, function):
|
|
27
|
+
if _loop == None:
|
|
28
|
+
return
|
|
29
|
+
try:
|
|
30
|
+
asyncio.run_coroutine_threadsafe(function, _loop)
|
|
31
|
+
except Exception as e:
|
|
32
|
+
print(e)
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def sync_call(_loop: asyncio.AbstractEventLoop, function, _timeout=_TIMEOUT) -> any:
|
|
30
37
|
if _loop == None:
|
|
31
38
|
return
|
|
32
39
|
|
|
33
40
|
try:
|
|
34
|
-
f = asyncio.run_coroutine_threadsafe(
|
|
35
|
-
asyncio.wait_for(delay(_delay, function), _delay + _timeout), _loop
|
|
36
|
-
)
|
|
41
|
+
f = asyncio.run_coroutine_threadsafe(asyncio.wait_for(function, _timeout), _loop)
|
|
37
42
|
return f.result(timeout=_timeout)
|
|
38
43
|
except Exception as e:
|
|
39
44
|
print(e)
|
|
40
45
|
pass
|
|
41
46
|
|
|
42
47
|
|
|
43
|
-
async def
|
|
44
|
-
_loop: asyncio.AbstractEventLoop, _delay: float, function, _timeout=_TIMEOUT
|
|
45
|
-
) -> any:
|
|
48
|
+
async def async_call(_loop: asyncio.AbstractEventLoop, function, _timeout=_TIMEOUT) -> any:
|
|
46
49
|
if _loop == None:
|
|
47
50
|
return
|
|
48
51
|
|
|
49
52
|
try:
|
|
50
|
-
f = asyncio.run_coroutine_threadsafe(
|
|
51
|
-
asyncio.wait_for(delay(_delay, function), _delay + _timeout), _loop
|
|
52
|
-
)
|
|
53
|
+
f = asyncio.run_coroutine_threadsafe(asyncio.wait_for(function, _timeout), _loop)
|
|
53
54
|
except Exception as e:
|
|
54
55
|
print(e)
|
|
55
56
|
pass
|
|
@@ -0,0 +1,14 @@
|
|
|
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,,
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
sensor/__init__.py,sha256=L1VyAP0EDEnJIMeMTzp4iXHSRUUHyHScF_GIl3iYKRI,123
|
|
2
|
-
sensor/gforce.py,sha256=z-w9POiw5rtj6AgTvwFAI6tZt_5jv_3eSiKt_0jA1Ps,25229
|
|
3
|
-
sensor/sensor_controller.py,sha256=p4AFR_x6qer2PHqbQiVEJOU4xPcqT0WcOvZJJyb946w,10301
|
|
4
|
-
sensor/sensor_data.py,sha256=Hu7Ql0LgQ7V24xYZhaLrKPwU4KWZeWE655v8Gy8xphY,3934
|
|
5
|
-
sensor/sensor_data_context.py,sha256=Mf09kF5SA8jqSgNHZhSHvnV6KXxOuKC1U_unrsBiFd8,29285
|
|
6
|
-
sensor/sensor_device.py,sha256=LCjBzm2TuOh2KpHsFTjm1sF8hzwvS22LhF_ueAct0Jo,2848
|
|
7
|
-
sensor/sensor_profile.py,sha256=40p0YvkzsGcGgOoNePtOIVwiCKRa7B0NyprN1jHXDBA,20384
|
|
8
|
-
sensor/utils.py,sha256=9hcEVjAf9kUbsdgKiKZT0B2QDsBLBx5gocrNdBCYjpE,1707
|
|
9
|
-
sensor_sdk-0.0.5.dist-info/LICENSE.txt,sha256=8CSivOpub3IuXODTyqBRI91AxouJZk02YrcKuOAkWu8,1111
|
|
10
|
-
sensor_sdk-0.0.5.dist-info/METADATA,sha256=hGZJafML055JDFdYkbnEHNElcMgl_J-1ymzKEeL_lRc,8374
|
|
11
|
-
sensor_sdk-0.0.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
12
|
-
sensor_sdk-0.0.5.dist-info/top_level.txt,sha256=Ftq49B6bH0Ffdc7c8LkcyakHo6lsg_snlBbpEUoILSk,7
|
|
13
|
-
sensor_sdk-0.0.5.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
|
|
14
|
-
sensor_sdk-0.0.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|