sensor-sdk 0.0.4__py3-none-any.whl → 0.0.6__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 +73 -46
- sensor/sensor_controller.py +76 -47
- sensor/sensor_data_context.py +69 -61
- sensor/sensor_profile.py +147 -113
- sensor/utils.py +51 -8
- {sensor_sdk-0.0.4.dist-info → sensor_sdk-0.0.6.dist-info}/METADATA +14 -2
- sensor_sdk-0.0.6.dist-info/RECORD +14 -0
- sensor_sdk-0.0.4.dist-info/RECORD +0 -14
- {sensor_sdk-0.0.4.dist-info → sensor_sdk-0.0.6.dist-info}/LICENSE.txt +0 -0
- {sensor_sdk-0.0.4.dist-info → sensor_sdk-0.0.6.dist-info}/WHEEL +0 -0
- {sensor_sdk-0.0.4.dist-info → sensor_sdk-0.0.6.dist-info}/top_level.txt +0 -0
- {sensor_sdk-0.0.4.dist-info → sensor_sdk-0.0.6.dist-info}/zip-safe +0 -0
sensor/sensor_data_context.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from collections import deque
|
|
3
|
+
import platform
|
|
3
4
|
from queue import Queue
|
|
5
|
+
import struct
|
|
4
6
|
from typing import Deque, List
|
|
5
7
|
|
|
6
8
|
from sensor.gforce import DataSubscription, GForce
|
|
@@ -42,6 +44,7 @@ class SensorProfileDataCtx:
|
|
|
42
44
|
self.deviceMac = deviceMac
|
|
43
45
|
self._device_info: DeviceInfo = None
|
|
44
46
|
|
|
47
|
+
self._is_initing = False
|
|
45
48
|
self._is_running = True
|
|
46
49
|
self._is_data_transfering = False
|
|
47
50
|
self.isUniversalStream: bool = gForce._is_universal_stream
|
|
@@ -79,7 +82,7 @@ class SensorProfileDataCtx:
|
|
|
79
82
|
return self._is_data_transfering
|
|
80
83
|
|
|
81
84
|
def hasInit(self):
|
|
82
|
-
return self.featureMap != 0 and self.notifyDataFlag != 0
|
|
85
|
+
return not self._is_initing and self.featureMap != 0 and self.notifyDataFlag != 0
|
|
83
86
|
|
|
84
87
|
def hasEMG(self):
|
|
85
88
|
return (self.featureMap & FeatureMaps.GFD_FEAT_EMG.value) != 0
|
|
@@ -198,32 +201,44 @@ class SensorProfileDataCtx:
|
|
|
198
201
|
|
|
199
202
|
async def fetchDeviceInfo(self) -> DeviceInfo:
|
|
200
203
|
info = DeviceInfo()
|
|
201
|
-
|
|
204
|
+
if platform.system() != "Linux":
|
|
205
|
+
info.MTUSize = self.gForce.client.mtu_size
|
|
206
|
+
else:
|
|
207
|
+
info.MTUSize = 0
|
|
208
|
+
print("get_device_name")
|
|
202
209
|
info.DeviceName = await self.gForce.get_device_name()
|
|
210
|
+
print("get_model_number")
|
|
203
211
|
info.ModelName = await self.gForce.get_model_number()
|
|
212
|
+
print("get_hardware_revision")
|
|
204
213
|
info.HardwareVersion = await self.gForce.get_hardware_revision()
|
|
214
|
+
print("get_firmware_revision")
|
|
205
215
|
info.FirmwareVersion = await self.gForce.get_firmware_revision()
|
|
206
216
|
return info
|
|
207
217
|
|
|
208
218
|
async def init(self, packageCount: int) -> bool:
|
|
219
|
+
if self._is_initing:
|
|
220
|
+
return False
|
|
209
221
|
try:
|
|
222
|
+
self._is_initing = True
|
|
210
223
|
info = await self.fetchDeviceInfo()
|
|
211
|
-
|
|
212
224
|
await self.initDataTransfer(True)
|
|
213
|
-
|
|
214
225
|
if self.hasImpedance():
|
|
215
226
|
self.notifyDataFlag |= DataSubscription.DNF_IMPEDANCE
|
|
216
227
|
|
|
217
228
|
if self.hasEEG():
|
|
229
|
+
print("initEEG")
|
|
218
230
|
info.EegChannelCount = await self.initEEG(packageCount)
|
|
219
231
|
|
|
220
232
|
if self.hasECG():
|
|
233
|
+
print("initECG")
|
|
221
234
|
info.EcgChannelCount = await self.initECG(packageCount)
|
|
222
235
|
|
|
223
236
|
if self.hasBrth():
|
|
237
|
+
print("initBrth")
|
|
224
238
|
info.BrthChannelCount = await self.initBrth(packageCount)
|
|
225
239
|
|
|
226
240
|
if self.hasIMU():
|
|
241
|
+
print("initIMU")
|
|
227
242
|
imuChannelCount = await self.initIMU(packageCount)
|
|
228
243
|
info.AccChannelCount = imuChannelCount
|
|
229
244
|
info.GyroChannelCount = imuChannelCount
|
|
@@ -233,9 +248,11 @@ class SensorProfileDataCtx:
|
|
|
233
248
|
if not self.isUniversalStream:
|
|
234
249
|
await self.initDataTransfer(False)
|
|
235
250
|
|
|
251
|
+
self._is_initing = False
|
|
236
252
|
return True
|
|
237
253
|
except Exception as e:
|
|
238
254
|
print(e)
|
|
255
|
+
self._is_initing = False
|
|
239
256
|
return False
|
|
240
257
|
|
|
241
258
|
async def start_streaming(self) -> bool:
|
|
@@ -263,16 +280,16 @@ class SensorProfileDataCtx:
|
|
|
263
280
|
await self.gForce.set_subscription(0)
|
|
264
281
|
return True
|
|
265
282
|
|
|
266
|
-
def process_data(self, buf: Queue[SensorData]):
|
|
283
|
+
def process_data(self, buf: Queue[SensorData], sensor):
|
|
267
284
|
try:
|
|
268
285
|
data: bytes = self._rawDataBuffer.get_nowait()
|
|
269
286
|
except Exception as e:
|
|
270
287
|
return
|
|
271
288
|
|
|
272
|
-
self._processDataPackage(data, buf)
|
|
289
|
+
self._processDataPackage(data, buf, sensor)
|
|
273
290
|
self._rawDataBuffer.task_done()
|
|
274
291
|
|
|
275
|
-
def _processDataPackage(self, data: bytes, buf: Queue[SensorData]):
|
|
292
|
+
def _processDataPackage(self, data: bytes, buf: Queue[SensorData], sensor):
|
|
276
293
|
v = data[0]
|
|
277
294
|
if v == DataType.NTF_IMPEDANCE:
|
|
278
295
|
offset = 1
|
|
@@ -283,15 +300,14 @@ class SensorProfileDataCtx:
|
|
|
283
300
|
saturationData = []
|
|
284
301
|
|
|
285
302
|
dataCount = (len(data) - 3) // 4 // 2
|
|
303
|
+
|
|
286
304
|
for index in range(dataCount):
|
|
287
|
-
|
|
288
|
-
impedance = int.from_bytes(impedance_bytes, byteorder="little")
|
|
305
|
+
impedance = struct.unpack_from("<f", data, offset)[0]
|
|
289
306
|
offset += 4
|
|
290
307
|
impedanceData.append(impedance)
|
|
291
308
|
|
|
292
309
|
for index in range(dataCount):
|
|
293
|
-
|
|
294
|
-
saturation = int.from_bytes(saturation_bytes, byteorder="little")
|
|
310
|
+
saturation = struct.unpack_from("<f", data, offset)[0]
|
|
295
311
|
offset += 4
|
|
296
312
|
saturationData.append(saturation / 10) # firmware value range 0 - 1000
|
|
297
313
|
|
|
@@ -300,28 +316,26 @@ class SensorProfileDataCtx:
|
|
|
300
316
|
|
|
301
317
|
elif v == DataType.NTF_EEG:
|
|
302
318
|
sensor_data = self.sensorDatas[SensorDataType.DATA_TYPE_EEG]
|
|
303
|
-
if self.checkReadSamples(data, sensor_data, 3, 0):
|
|
319
|
+
if self.checkReadSamples(sensor, data, sensor_data, 3, 0):
|
|
304
320
|
self.sendSensorData(sensor_data, buf)
|
|
305
321
|
elif v == DataType.NTF_ECG:
|
|
306
322
|
sensor_data = self.sensorDatas[SensorDataType.DATA_TYPE_ECG]
|
|
307
|
-
if self.checkReadSamples(data, sensor_data, 3, 0):
|
|
323
|
+
if self.checkReadSamples(sensor, data, sensor_data, 3, 0):
|
|
308
324
|
self.sendSensorData(sensor_data, buf)
|
|
309
325
|
elif v == DataType.NTF_BRTH:
|
|
310
326
|
sensor_data = self.sensorDatas[SensorDataType.DATA_TYPE_BRTH]
|
|
311
|
-
if self.checkReadSamples(data, sensor_data, 3, 0):
|
|
327
|
+
if self.checkReadSamples(sensor, data, sensor_data, 3, 0):
|
|
312
328
|
self.sendSensorData(sensor_data, buf)
|
|
313
329
|
elif v == DataType.NTF_IMU:
|
|
314
330
|
sensor_data_acc = self.sensorDatas[SensorDataType.DATA_TYPE_ACC]
|
|
315
|
-
if self.checkReadSamples(data, sensor_data_acc, 3, 6):
|
|
331
|
+
if self.checkReadSamples(sensor, data, sensor_data_acc, 3, 6):
|
|
316
332
|
self.sendSensorData(sensor_data_acc, buf)
|
|
317
333
|
|
|
318
334
|
sensor_data_gyro = self.sensorDatas[SensorDataType.DATA_TYPE_GYRO]
|
|
319
|
-
if self.checkReadSamples(data, sensor_data_gyro, 9, 6):
|
|
335
|
+
if self.checkReadSamples(sensor, data, sensor_data_gyro, 9, 6):
|
|
320
336
|
self.sendSensorData(sensor_data_gyro, buf)
|
|
321
337
|
|
|
322
|
-
def checkReadSamples(
|
|
323
|
-
self, data: bytes, sensorData: SensorData, dataOffset: int, dataGap: int
|
|
324
|
-
):
|
|
338
|
+
def checkReadSamples(self, sensor, data: bytes, sensorData: SensorData, dataOffset: int, dataGap: int):
|
|
325
339
|
offset = 1
|
|
326
340
|
v = data[0]
|
|
327
341
|
if not self._is_data_transfering:
|
|
@@ -340,12 +354,22 @@ class SensorProfileDataCtx:
|
|
|
340
354
|
|
|
341
355
|
deltaPackageIndex = packageIndex - lastPackageIndex
|
|
342
356
|
if deltaPackageIndex > 1:
|
|
343
|
-
lostSampleCount = sensorData.packageSampleCount * (
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
357
|
+
lostSampleCount = sensorData.packageSampleCount * (deltaPackageIndex - 1)
|
|
358
|
+
lostLog = (
|
|
359
|
+
"MSG|LOST SAMPLE|MAC|"
|
|
360
|
+
+ str(sensorData.deviceMac)
|
|
361
|
+
+ "|TYPE|"
|
|
362
|
+
+ str(sensorData.dataType)
|
|
363
|
+
+ "|COUNT|"
|
|
364
|
+
+ str(lostSampleCount)
|
|
348
365
|
)
|
|
366
|
+
# print(lostLog)
|
|
367
|
+
if sensor._event_loop != None and sensor._on_error_callback != None:
|
|
368
|
+
try:
|
|
369
|
+
sensor._event_loop.call_soon_threadsafe(sensor._on_error_callback, sensor, lostLog)
|
|
370
|
+
except Exception as e:
|
|
371
|
+
pass
|
|
372
|
+
|
|
349
373
|
self.readSamples(data, sensorData, 0, dataGap, lostSampleCount)
|
|
350
374
|
if newPackageIndex == 0:
|
|
351
375
|
sensorData.lastPackageIndex = 65535
|
|
@@ -356,7 +380,8 @@ class SensorProfileDataCtx:
|
|
|
356
380
|
self.readSamples(data, sensorData, dataOffset, dataGap, 0)
|
|
357
381
|
sensorData.lastPackageIndex = newPackageIndex
|
|
358
382
|
sensorData.lastPackageCounter += 1
|
|
359
|
-
except Exception:
|
|
383
|
+
except Exception as e:
|
|
384
|
+
print(e)
|
|
360
385
|
return False
|
|
361
386
|
return True
|
|
362
387
|
|
|
@@ -385,19 +410,19 @@ class SensorProfileDataCtx:
|
|
|
385
410
|
channelSamples.append([])
|
|
386
411
|
|
|
387
412
|
for sampleIndex in range(sampleCount):
|
|
388
|
-
for channelIndex, impedanceChannelIndex in enumerate(
|
|
389
|
-
range(sensorData.channelCount)
|
|
390
|
-
):
|
|
413
|
+
for channelIndex, impedanceChannelIndex in enumerate(range(sensorData.channelCount)):
|
|
391
414
|
if (sensorData.channelMask & (1 << channelIndex)) != 0:
|
|
392
415
|
samples = channelSamples[channelIndex]
|
|
393
416
|
impedance = 0.0
|
|
394
417
|
saturation = 0.0
|
|
418
|
+
|
|
395
419
|
if sensorData.dataType == DataType.NTF_ECG:
|
|
396
|
-
impedanceChannelIndex = self.sensorDatas[
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
420
|
+
impedanceChannelIndex = self.sensorDatas[SensorDataType.DATA_TYPE_EEG].channelCount
|
|
421
|
+
|
|
422
|
+
if impedanceChannelIndex < len(_impedanceData):
|
|
423
|
+
impedance = _impedanceData[impedanceChannelIndex]
|
|
424
|
+
saturation = _saturationData[impedanceChannelIndex]
|
|
425
|
+
|
|
401
426
|
impedanceChannelIndex += 1
|
|
402
427
|
|
|
403
428
|
dataItem = Sample()
|
|
@@ -424,11 +449,7 @@ class SensorProfileDataCtx:
|
|
|
424
449
|
)
|
|
425
450
|
offset += 2
|
|
426
451
|
elif sensorData.resolutionBits == 24:
|
|
427
|
-
rawData = (
|
|
428
|
-
(data[offset] << 16)
|
|
429
|
-
| (data[offset + 1] << 8)
|
|
430
|
-
| data[offset + 2]
|
|
431
|
-
)
|
|
452
|
+
rawData = (data[offset] << 16) | (data[offset + 1] << 8) | data[offset + 2]
|
|
432
453
|
rawData -= 8388608
|
|
433
454
|
offset += 3
|
|
434
455
|
|
|
@@ -765,9 +786,7 @@ class SensorProfileDataCtx:
|
|
|
765
786
|
|
|
766
787
|
return crc8
|
|
767
788
|
|
|
768
|
-
def processUniversalData(
|
|
769
|
-
self, buf: Queue[SensorData], loop: asyncio.AbstractEventLoop, sensor, callback
|
|
770
|
-
):
|
|
789
|
+
def processUniversalData(self, buf: Queue[SensorData], loop: asyncio.AbstractEventLoop, sensor, callback):
|
|
771
790
|
|
|
772
791
|
while self._is_running:
|
|
773
792
|
try:
|
|
@@ -795,28 +814,22 @@ class SensorProfileDataCtx:
|
|
|
795
814
|
index += 1
|
|
796
815
|
continue
|
|
797
816
|
crc = self._concatDataBuffer[index + 1 + n + 1]
|
|
798
|
-
calc_crc = self.calc_crc8(
|
|
799
|
-
self._concatDataBuffer[index + 2 : index + 2 + n]
|
|
800
|
-
)
|
|
817
|
+
calc_crc = self.calc_crc8(self._concatDataBuffer[index + 2 : index + 2 + n])
|
|
801
818
|
if crc != calc_crc:
|
|
802
819
|
index += 1
|
|
803
820
|
continue
|
|
804
821
|
if self._is_data_transfering:
|
|
805
|
-
data_package = bytes(
|
|
806
|
-
|
|
807
|
-
)
|
|
808
|
-
self._processDataPackage(data_package, buf)
|
|
822
|
+
data_package = bytes(self._concatDataBuffer[index + 2 : index + 2 + n])
|
|
823
|
+
self._processDataPackage(data_package, buf, sensor)
|
|
809
824
|
while self._is_running and self.isDataTransfering:
|
|
810
825
|
sensorData: SensorData = None
|
|
811
826
|
try:
|
|
812
827
|
sensorData = buf.get_nowait()
|
|
813
828
|
except Exception as e:
|
|
814
829
|
break
|
|
815
|
-
if sensorData != None and callback != None:
|
|
830
|
+
if loop != None and sensorData != None and callback != None:
|
|
816
831
|
try:
|
|
817
|
-
loop.call_soon_threadsafe(
|
|
818
|
-
callback, sensor, sensorData
|
|
819
|
-
)
|
|
832
|
+
loop.call_soon_threadsafe(callback, sensor, sensorData)
|
|
820
833
|
except Exception as e:
|
|
821
834
|
print(e)
|
|
822
835
|
|
|
@@ -832,18 +845,13 @@ class SensorProfileDataCtx:
|
|
|
832
845
|
index += 1
|
|
833
846
|
continue
|
|
834
847
|
crc = self._concatDataBuffer[index + 1 + n + 1]
|
|
835
|
-
calc_crc = self.calc_crc8(
|
|
836
|
-
self._concatDataBuffer[index + 2 : index + 2 + n]
|
|
837
|
-
)
|
|
848
|
+
calc_crc = self.calc_crc8(self._concatDataBuffer[index + 2 : index + 2 + n])
|
|
838
849
|
if crc != calc_crc:
|
|
839
850
|
index += 1
|
|
840
851
|
continue
|
|
841
|
-
data_package = bytes(
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
loop.call_soon_threadsafe(
|
|
845
|
-
self.gForce._on_cmd_response, None, data_package
|
|
846
|
-
)
|
|
852
|
+
data_package = bytes(self._concatDataBuffer[index + 2 : index + 2 + n])
|
|
853
|
+
if loop != None:
|
|
854
|
+
loop.call_soon_threadsafe(self.gForce._on_cmd_response, None, data_package)
|
|
847
855
|
last_cut = index = index + 2 + n
|
|
848
856
|
else:
|
|
849
857
|
index += 1
|