sensor-sdk 0.1.2__tar.gz → 0.1.5__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.
Files changed (30) hide show
  1. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/PKG-INFO +2 -1
  2. sensor_sdk-0.1.5/sensor/__init__.py +20 -0
  3. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor/bleak_host.py +57 -25
  4. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor/bleak_process.py +30 -9
  5. sensor_sdk-0.1.5/sensor/fb/DataType.py +32 -0
  6. sensor_sdk-0.1.5/sensor/fb/Sample.py +49 -0
  7. sensor_sdk-0.1.5/sensor/fb/SensorData.py +296 -0
  8. sensor_sdk-0.1.5/sensor/fb/__init__.py +0 -0
  9. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor/gforce.py +11 -1
  10. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor/sdk_log.py +93 -5
  11. sensor_sdk-0.1.5/sensor/sensor_data.py +241 -0
  12. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor/sensor_data_context.py +298 -136
  13. sensor_sdk-0.1.5/sensor/sensor_data_pool.py +110 -0
  14. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor/sensor_utils.py +28 -10
  15. sensor_sdk-0.1.5/sensor/winrt_high_throughput.py +104 -0
  16. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor_sdk.egg-info/PKG-INFO +2 -1
  17. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor_sdk.egg-info/SOURCES.txt +6 -0
  18. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor_sdk.egg-info/requires.txt +1 -0
  19. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/setup.py +2 -2
  20. sensor_sdk-0.1.2/sensor/__init__.py +0 -4
  21. sensor_sdk-0.1.2/sensor/sensor_data.py +0 -103
  22. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/LICENSE.txt +0 -0
  23. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/README.md +0 -0
  24. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor/sensor_controller.py +0 -0
  25. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor/sensor_device.py +0 -0
  26. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor/sensor_profile.py +0 -0
  27. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor_sdk.egg-info/dependency_links.txt +0 -0
  28. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor_sdk.egg-info/top_level.txt +0 -0
  29. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/sensor_sdk.egg-info/zip-safe +0 -0
  30. {sensor_sdk-0.1.2 → sensor_sdk-0.1.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sensor-sdk
3
- Version: 0.1.2
3
+ Version: 0.1.5
4
4
  Summary: Python sdk for Synchroni
5
5
  Home-page: https://github.com/oymotion/SynchroniSDKPython
6
6
  Author: Martin Ye
@@ -11,6 +11,7 @@ License-File: LICENSE.txt
11
11
  Requires-Dist: numpy
12
12
  Requires-Dist: setuptools
13
13
  Requires-Dist: bleak>=3.0.2
14
+ Requires-Dist: flatbuffers>=25.0.0
14
15
  Dynamic: author
15
16
  Dynamic: author-email
16
17
  Dynamic: description
@@ -0,0 +1,20 @@
1
+ from sensor.sensor_controller import SensorController, SensorControllerInstance
2
+ from sensor.sensor_profile import SensorProfile
3
+ from sensor.sensor_device import BLEDevice, DeviceInfo, DeviceStateEx
4
+ from sensor.sensor_data import DataType, Sample, SensorData
5
+ from sensor.winrt_high_throughput import apply as _apply_winrt_high_throughput_patch
6
+
7
+ # Windows 下尝试给 bleak WinRT backend 打高吞吐率连接参数补丁
8
+ _apply_winrt_high_throughput_patch()
9
+
10
+ __all__ = [
11
+ "SensorController",
12
+ "SensorControllerInstance",
13
+ "SensorProfile",
14
+ "BLEDevice",
15
+ "DeviceInfo",
16
+ "DeviceStateEx",
17
+ "DataType",
18
+ "Sample",
19
+ "SensorData",
20
+ ]
@@ -17,7 +17,8 @@ class BleakHost:
17
17
  def __init__(self):
18
18
  self._cmd_queue = multiprocessing.Queue(maxsize=50)
19
19
  self._result_queue = multiprocessing.Queue(maxsize=sensor_utils.BLEAK_RESULT_QUEUE_MAXSIZE)
20
- self._bleak_process = BleakProcess(self._cmd_queue, self._result_queue, SdkLog.get_log_path())
20
+ self._data_queue = multiprocessing.Queue(maxsize=sensor_utils.BLEAK_DATA_QUEUE_MAXSIZE)
21
+ self._bleak_process = BleakProcess(self._cmd_queue, self._result_queue, self._data_queue, SdkLog.get_log_path())
21
22
  self._started = False
22
23
 
23
24
 
@@ -69,6 +70,7 @@ class BleakHost:
69
70
  try:
70
71
  self._cmd_queue.close()
71
72
  self._result_queue.close()
73
+ self._data_queue.close()
72
74
  except Exception as e:
73
75
  SdkLog.exception(_TAG, "Error closing queues")
74
76
 
@@ -125,38 +127,68 @@ class BleakHost:
125
127
 
126
128
  async def _consume_results(self):
127
129
 
130
+ def _try_get(q, timeout):
131
+ try:
132
+ return q.get(True, timeout)
133
+ except queue.Empty:
134
+ return None
135
+
128
136
  while not getattr(self, '_should_exit', False):
129
137
  try:
138
+ # Prioritize control/result messages; data messages are drained in batch below.
130
139
  msg = await asyncio.get_event_loop().run_in_executor(
131
- None, self._result_queue.get, True, 0.1
140
+ None, _try_get, self._result_queue, 0.02
132
141
  )
133
- except queue.Empty:
134
- continue
135
142
  except Exception:
143
+ msg = None
144
+
145
+ if msg is None:
146
+ try:
147
+ msg = await asyncio.get_event_loop().run_in_executor(
148
+ None, _try_get, self._data_queue, 0.02
149
+ )
150
+ except Exception:
151
+ msg = None
152
+
153
+ if msg is None:
154
+ await asyncio.sleep(0.001)
136
155
  continue
137
156
 
138
- msg_type = msg.get("type")
139
- if msg_type == "scan_once_result":
140
- if self.on_scan_once_result is not None:
141
- try:
142
- self.on_scan_once_result(msg)
143
- except Exception as e:
144
- SdkLog.exception(_TAG, "Unexpected error")
145
- elif msg_type == "devices":
146
- if self.on_scan_result is not None:
147
- try:
148
- self.on_scan_result(msg)
149
- except Exception as e:
150
- SdkLog.exception(_TAG, "Unexpected error")
151
- elif msg_type == "command_result":
152
- self._handle_command_result(msg)
153
- elif msg_type in ("state_changed", "power_changed", "sensor_data", "error"):
154
- if self.on_device_message is not None:
155
- device_mac = msg.get("device_mac")
157
+ self._dispatch_message(msg)
158
+
159
+ # Batch drain both queues to catch up quickly and reduce per-get overhead.
160
+ for q in (self._result_queue, self._data_queue):
161
+ while True:
156
162
  try:
157
- self.on_device_message(device_mac, msg)
158
- except Exception as e:
159
- SdkLog.exception(_TAG, "Unexpected error")
163
+ self._dispatch_message(q.get_nowait())
164
+ except queue.Empty:
165
+ break
166
+ except Exception:
167
+ break
168
+
169
+ def _dispatch_message(self, msg):
170
+ msg_type = msg.get("type")
171
+ if msg_type == "scan_once_result":
172
+ if self.on_scan_once_result is not None:
173
+ try:
174
+ self.on_scan_once_result(msg)
175
+ except Exception as e:
176
+ SdkLog.exception(_TAG, "Unexpected error")
177
+ elif msg_type == "devices":
178
+ if self.on_scan_result is not None:
179
+ try:
180
+ self.on_scan_result(msg)
181
+ except Exception as e:
182
+ SdkLog.exception(_TAG, "Unexpected error")
183
+ elif msg_type == "command_result":
184
+ self._handle_command_result(msg)
185
+ elif msg_type in ("state_changed", "power_changed", "sensor_data", "error"):
186
+ if self.on_device_message is not None:
187
+ device_mac = msg.get("device_mac")
188
+ try:
189
+ self.on_device_message(device_mac, msg)
190
+ except Exception as e:
191
+ SdkLog.exception(_TAG, "Unexpected error")
160
192
 
161
193
  def _handle_command_result(self, msg):
162
194
 
@@ -72,11 +72,13 @@ class BleakProcess(multiprocessing.Process):
72
72
  self,
73
73
  cmd_queue: multiprocessing.Queue,
74
74
  result_queue: multiprocessing.Queue,
75
+ data_queue: multiprocessing.Queue,
75
76
  log_path: str = None,
76
77
  ):
77
78
  super().__init__(daemon=True)
78
79
  self.cmd_queue = cmd_queue
79
80
  self.result_queue = result_queue
81
+ self.data_queue = data_queue
80
82
  self._log_path = log_path
81
83
  self._scanner = None
82
84
  self._is_scanning = False
@@ -141,15 +143,23 @@ class BleakProcess(multiprocessing.Process):
141
143
 
142
144
  def _flush_msg_queue(self):
143
145
 
146
+ def _route_and_put(msg):
147
+ msg_type = msg.get("type")
148
+ if msg_type == "sensor_data":
149
+ try:
150
+ self.data_queue.put_nowait(msg)
151
+ except queue.Full:
152
+ pass
153
+ elif msg_type in self._DROPABLE_MSG_TYPES:
154
+ self.result_queue.put_nowait(msg)
155
+ else:
156
+ # Use a short timeout during shutdown so the child process can exit cleanly.
157
+ self.result_queue.put(msg, timeout=2.0)
158
+
144
159
  while True:
145
160
  try:
146
161
  msg = self._msg_queue.get_nowait()
147
- msg_type = msg.get("type")
148
- if msg_type in self._DROPABLE_MSG_TYPES:
149
- self.result_queue.put_nowait(msg)
150
- else:
151
- # Use a short timeout during shutdown so the child process can exit cleanly.
152
- self.result_queue.put(msg, timeout=2.0)
162
+ _route_and_put(msg)
153
163
  except queue.Empty:
154
164
  break
155
165
  except queue.Full:
@@ -170,6 +180,7 @@ class BleakProcess(multiprocessing.Process):
170
180
  async def _publisher_task(self):
171
181
  # Throttle queue-full logs to avoid blocking stdout on Windows.
172
182
  _last_queue_full_log = 0.0
183
+ _last_data_queue_full_log = 0.0
173
184
 
174
185
  while True:
175
186
  msg = None
@@ -177,7 +188,17 @@ class BleakProcess(multiprocessing.Process):
177
188
  try:
178
189
  msg = self._msg_queue.get_nowait()
179
190
  msg_type = msg.get("type")
180
- if msg_type in self._DROPABLE_MSG_TYPES:
191
+ if msg_type == "sensor_data":
192
+ # High-frequency data: use a dedicated drop-capable queue so it cannot
193
+ # block control/result messages in the main result queue.
194
+ try:
195
+ self.data_queue.put_nowait(msg)
196
+ except queue.Full:
197
+ now = time.time()
198
+ if now - _last_data_queue_full_log >= 2.0:
199
+ _last_data_queue_full_log = now
200
+ SdkLog.w(_TAG, "Data queue is full, dropping sensor_data")
201
+ elif msg_type in self._DROPABLE_MSG_TYPES:
181
202
  self.result_queue.put_nowait(msg)
182
203
  else:
183
204
  # Use a short timeout for important messages so the publisher does not stall.
@@ -845,9 +866,9 @@ class BleakProcess(multiprocessing.Process):
845
866
 
846
867
  try:
847
868
  if ctx.isUniversalStream:
848
- await ctx.processUniversalData(local_buf, on_data, on_error)
869
+ await ctx._processUniversalData(local_buf, on_data, on_error)
849
870
  else:
850
- await ctx.process_data(local_buf, on_data, on_error)
871
+ await ctx._process_data(local_buf, on_data, on_error)
851
872
  except asyncio.CancelledError as e:
852
873
  SdkLog.exception(_TAG, "Data loop cancelled")
853
874
  except Exception as e:
@@ -0,0 +1,32 @@
1
+ # automatically generated by the FlatBuffers compiler, do not modify
2
+
3
+ # namespace: fb
4
+
5
+ # BLE 数据通知类型,与 SensorSDKCXX src/SensorProfileImpl.h 中的 NotifyDataType 保持一致
6
+ class DataType(object):
7
+ NONE = 0
8
+ NTF_ACC_DATA = 1
9
+ NTF_GYO_DATA = 2
10
+ NTF_MAG_DATA = 3
11
+ NTF_EULER_DATA = 4
12
+ NTF_QUAT_FLOAT_DATA = 5
13
+ NTF_ROTA_DATA = 6
14
+ NTF_EMG_GEST_DATA = 7
15
+ NTF_EMG_ADC_DATA = 8
16
+ NTF_HID_MOUSE = 9
17
+ NTF_HID_JOYSTICK = 10
18
+ NTF_DEV_STATUS = 11
19
+ NTF_LOG_DATA = 12
20
+ NTF_MAG_ANGLE_DATA = 13
21
+ NTF_MOT_CURRENT_DATA = 14
22
+ NTF_NEUCIR_STATUS = 15
23
+ NTF_EEG = 16
24
+ NTF_ECG = 17
25
+ NTF_IMPEDANCE = 18
26
+ NTF_IMU = 19
27
+ NTF_ADS = 20
28
+ NTF_BRTH = 21
29
+ NTF_IMPEDANCE_EXT = 22
30
+ NTF_SPO2 = 23
31
+ NTF_PPG = 24
32
+ NTF_PARTIAL_DATA = 255
@@ -0,0 +1,49 @@
1
+ # automatically generated by the FlatBuffers compiler, do not modify
2
+
3
+ # namespace: fb
4
+
5
+ import flatbuffers
6
+ from flatbuffers.compat import import_numpy
7
+ np = import_numpy()
8
+
9
+ # 单个采样点,内存紧凑的 struct
10
+ class Sample(object):
11
+ __slots__ = ['_tab']
12
+
13
+ @classmethod
14
+ def SizeOf(cls):
15
+ return 32
16
+
17
+ # Sample
18
+ def Init(self, buf, pos):
19
+ self._tab = flatbuffers.table.Table(buf, pos)
20
+
21
+ # Sample
22
+ def TimeStampInMs(self): return self._tab.Get(flatbuffers.number_types.Int32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0))
23
+ # Sample
24
+ def ChannelIndex(self): return self._tab.Get(flatbuffers.number_types.Int32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(4))
25
+ # Sample
26
+ def SampleIndex(self): return self._tab.Get(flatbuffers.number_types.Int32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(8))
27
+ # Sample
28
+ def RawData(self): return self._tab.Get(flatbuffers.number_types.Int32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(12))
29
+ # Sample
30
+ def Data(self): return self._tab.Get(flatbuffers.number_types.Float32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(16))
31
+ # Sample
32
+ def Impedance(self): return self._tab.Get(flatbuffers.number_types.Float32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(20))
33
+ # Sample
34
+ def Saturation(self): return self._tab.Get(flatbuffers.number_types.Float32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(24))
35
+ # Sample
36
+ def IsLost(self): return self._tab.Get(flatbuffers.number_types.BoolFlags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(28))
37
+
38
+ def CreateSample(builder, timeStampInMs, channelIndex, sampleIndex, rawData, data, impedance, saturation, isLost):
39
+ builder.Prep(4, 32)
40
+ builder.Pad(3)
41
+ builder.PrependBool(isLost)
42
+ builder.PrependFloat32(saturation)
43
+ builder.PrependFloat32(impedance)
44
+ builder.PrependFloat32(data)
45
+ builder.PrependInt32(rawData)
46
+ builder.PrependInt32(sampleIndex)
47
+ builder.PrependInt32(channelIndex)
48
+ builder.PrependInt32(timeStampInMs)
49
+ return builder.Offset()
@@ -0,0 +1,296 @@
1
+ # automatically generated by the FlatBuffers compiler, do not modify
2
+
3
+ # namespace: fb
4
+
5
+ import flatbuffers
6
+ from flatbuffers.compat import import_numpy
7
+ np = import_numpy()
8
+
9
+ # SensorData 统一数据表
10
+ # samples 为一维扁平数组,按通道顺序存放;samples_per_channel 记录每个通道的 sample 数量。
11
+ class SensorData(object):
12
+ __slots__ = ['_tab']
13
+
14
+ @classmethod
15
+ def GetRootAs(cls, buf, offset=0):
16
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
17
+ x = SensorData()
18
+ x.Init(buf, n + offset)
19
+ return x
20
+
21
+ @classmethod
22
+ def GetRootAsSensorData(cls, buf, offset=0):
23
+ """This method is deprecated. Please switch to GetRootAs."""
24
+ return cls.GetRootAs(buf, offset)
25
+ # SensorData
26
+ def Init(self, buf, pos):
27
+ self._tab = flatbuffers.table.Table(buf, pos)
28
+
29
+ # SensorData
30
+ def DeviceMac(self):
31
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
32
+ if o != 0:
33
+ return self._tab.String(o + self._tab.Pos)
34
+ return None
35
+
36
+ # SensorData
37
+ def DataType(self):
38
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
39
+ if o != 0:
40
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
41
+ return 0
42
+
43
+ # SensorData
44
+ def LastPackageCounter(self):
45
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
46
+ if o != 0:
47
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
48
+ return 0
49
+
50
+ # SensorData
51
+ def LastPackageIndex(self):
52
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
53
+ if o != 0:
54
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
55
+ return 0
56
+
57
+ # SensorData
58
+ def LostPackageCount(self):
59
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
60
+ if o != 0:
61
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
62
+ return 0
63
+
64
+ # SensorData
65
+ def ResolutionBits(self):
66
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
67
+ if o != 0:
68
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
69
+ return 0
70
+
71
+ # SensorData
72
+ def ResolutionSigned(self):
73
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
74
+ if o != 0:
75
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
76
+ return 0
77
+
78
+ # SensorData
79
+ def SampleRate(self):
80
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
81
+ if o != 0:
82
+ return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
83
+ return 0.0
84
+
85
+ # SensorData
86
+ def ChannelCount(self):
87
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
88
+ if o != 0:
89
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
90
+ return 0
91
+
92
+ # SensorData
93
+ def ChannelMask(self):
94
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
95
+ if o != 0:
96
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
97
+ return 0
98
+
99
+ # SensorData
100
+ def MinPackageSampleCount(self):
101
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
102
+ if o != 0:
103
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
104
+ return 0
105
+
106
+ # SensorData
107
+ def PackageSampleCount(self):
108
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
109
+ if o != 0:
110
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
111
+ return 0
112
+
113
+ # SensorData
114
+ def PackageIndexLength(self):
115
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(28))
116
+ if o != 0:
117
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
118
+ return 0
119
+
120
+ # SensorData
121
+ def K(self):
122
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
123
+ if o != 0:
124
+ return self._tab.Get(flatbuffers.number_types.Float64Flags, o + self._tab.Pos)
125
+ return 0.0
126
+
127
+ # SensorData
128
+ def Samples(self, j):
129
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(32))
130
+ if o != 0:
131
+ x = self._tab.Vector(o)
132
+ x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 32
133
+ from sensor.fb.Sample import Sample
134
+ obj = Sample()
135
+ obj.Init(self._tab.Bytes, x)
136
+ return obj
137
+ return None
138
+
139
+ # SensorData
140
+ def SamplesLength(self):
141
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(32))
142
+ if o != 0:
143
+ return self._tab.VectorLen(o)
144
+ return 0
145
+
146
+ # SensorData
147
+ def SamplesIsNone(self):
148
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(32))
149
+ return o == 0
150
+
151
+ # SensorData
152
+ def SamplesPerChannel(self, j):
153
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(34))
154
+ if o != 0:
155
+ a = self._tab.Vector(o)
156
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 4))
157
+ return 0
158
+
159
+ # SensorData
160
+ def SamplesPerChannelAsNumpy(self):
161
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(34))
162
+ if o != 0:
163
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Int32Flags, o)
164
+ return 0
165
+
166
+ # SensorData
167
+ def SamplesPerChannelLength(self):
168
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(34))
169
+ if o != 0:
170
+ return self._tab.VectorLen(o)
171
+ return 0
172
+
173
+ # SensorData
174
+ def SamplesPerChannelIsNone(self):
175
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(34))
176
+ return o == 0
177
+
178
+ def SensorDataStart(builder):
179
+ builder.StartObject(16)
180
+
181
+ def Start(builder):
182
+ SensorDataStart(builder)
183
+
184
+ def SensorDataAddDeviceMac(builder, deviceMac):
185
+ builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(deviceMac), 0)
186
+
187
+ def AddDeviceMac(builder, deviceMac):
188
+ SensorDataAddDeviceMac(builder, deviceMac)
189
+
190
+ def SensorDataAddDataType(builder, dataType):
191
+ builder.PrependUint8Slot(1, dataType, 0)
192
+
193
+ def AddDataType(builder, dataType):
194
+ SensorDataAddDataType(builder, dataType)
195
+
196
+ def SensorDataAddLastPackageCounter(builder, lastPackageCounter):
197
+ builder.PrependInt32Slot(2, lastPackageCounter, 0)
198
+
199
+ def AddLastPackageCounter(builder, lastPackageCounter):
200
+ SensorDataAddLastPackageCounter(builder, lastPackageCounter)
201
+
202
+ def SensorDataAddLastPackageIndex(builder, lastPackageIndex):
203
+ builder.PrependInt32Slot(3, lastPackageIndex, 0)
204
+
205
+ def AddLastPackageIndex(builder, lastPackageIndex):
206
+ SensorDataAddLastPackageIndex(builder, lastPackageIndex)
207
+
208
+ def SensorDataAddLostPackageCount(builder, lostPackageCount):
209
+ builder.PrependInt32Slot(4, lostPackageCount, 0)
210
+
211
+ def AddLostPackageCount(builder, lostPackageCount):
212
+ SensorDataAddLostPackageCount(builder, lostPackageCount)
213
+
214
+ def SensorDataAddResolutionBits(builder, resolutionBits):
215
+ builder.PrependInt32Slot(5, resolutionBits, 0)
216
+
217
+ def AddResolutionBits(builder, resolutionBits):
218
+ SensorDataAddResolutionBits(builder, resolutionBits)
219
+
220
+ def SensorDataAddResolutionSigned(builder, resolutionSigned):
221
+ builder.PrependInt32Slot(6, resolutionSigned, 0)
222
+
223
+ def AddResolutionSigned(builder, resolutionSigned):
224
+ SensorDataAddResolutionSigned(builder, resolutionSigned)
225
+
226
+ def SensorDataAddSampleRate(builder, sampleRate):
227
+ builder.PrependFloat32Slot(7, sampleRate, 0.0)
228
+
229
+ def AddSampleRate(builder, sampleRate):
230
+ SensorDataAddSampleRate(builder, sampleRate)
231
+
232
+ def SensorDataAddChannelCount(builder, channelCount):
233
+ builder.PrependInt32Slot(8, channelCount, 0)
234
+
235
+ def AddChannelCount(builder, channelCount):
236
+ SensorDataAddChannelCount(builder, channelCount)
237
+
238
+ def SensorDataAddChannelMask(builder, channelMask):
239
+ builder.PrependUint64Slot(9, channelMask, 0)
240
+
241
+ def AddChannelMask(builder, channelMask):
242
+ SensorDataAddChannelMask(builder, channelMask)
243
+
244
+ def SensorDataAddMinPackageSampleCount(builder, minPackageSampleCount):
245
+ builder.PrependInt32Slot(10, minPackageSampleCount, 0)
246
+
247
+ def AddMinPackageSampleCount(builder, minPackageSampleCount):
248
+ SensorDataAddMinPackageSampleCount(builder, minPackageSampleCount)
249
+
250
+ def SensorDataAddPackageSampleCount(builder, packageSampleCount):
251
+ builder.PrependInt32Slot(11, packageSampleCount, 0)
252
+
253
+ def AddPackageSampleCount(builder, packageSampleCount):
254
+ SensorDataAddPackageSampleCount(builder, packageSampleCount)
255
+
256
+ def SensorDataAddPackageIndexLength(builder, packageIndexLength):
257
+ builder.PrependInt32Slot(12, packageIndexLength, 0)
258
+
259
+ def AddPackageIndexLength(builder, packageIndexLength):
260
+ SensorDataAddPackageIndexLength(builder, packageIndexLength)
261
+
262
+ def SensorDataAddK(builder, k):
263
+ builder.PrependFloat64Slot(13, k, 0.0)
264
+
265
+ def AddK(builder, k):
266
+ SensorDataAddK(builder, k)
267
+
268
+ def SensorDataAddSamples(builder, samples):
269
+ builder.PrependUOffsetTRelativeSlot(14, flatbuffers.number_types.UOffsetTFlags.py_type(samples), 0)
270
+
271
+ def AddSamples(builder, samples):
272
+ SensorDataAddSamples(builder, samples)
273
+
274
+ def SensorDataStartSamplesVector(builder, numElems):
275
+ return builder.StartVector(32, numElems, 4)
276
+
277
+ def StartSamplesVector(builder, numElems):
278
+ return SensorDataStartSamplesVector(builder, numElems)
279
+
280
+ def SensorDataAddSamplesPerChannel(builder, samplesPerChannel):
281
+ builder.PrependUOffsetTRelativeSlot(15, flatbuffers.number_types.UOffsetTFlags.py_type(samplesPerChannel), 0)
282
+
283
+ def AddSamplesPerChannel(builder, samplesPerChannel):
284
+ SensorDataAddSamplesPerChannel(builder, samplesPerChannel)
285
+
286
+ def SensorDataStartSamplesPerChannelVector(builder, numElems):
287
+ return builder.StartVector(4, numElems, 4)
288
+
289
+ def StartSamplesPerChannelVector(builder, numElems):
290
+ return SensorDataStartSamplesPerChannelVector(builder, numElems)
291
+
292
+ def SensorDataEnd(builder):
293
+ return builder.EndObject()
294
+
295
+ def End(builder):
296
+ return SensorDataEnd(builder)
File without changes
@@ -680,7 +680,13 @@ class GForce:
680
680
  has_res=True,
681
681
  )
682
682
  )
683
- return buf.decode("utf-8")
683
+ # 硬件版本定义:temp[2]=SYS_HARDWARE_REV_ADDR, temp[3]=SYS_HARDWARE_TYPE_ADDR
684
+ # 响应数据中前两个字节分别为硬件版本号和硬件类型
685
+ if len(buf) >= 2:
686
+ return f"{buf[0]}.{buf[1]}"
687
+ if len(buf) == 1:
688
+ return str(buf[0])
689
+ return "0"
684
690
 
685
691
  async def get_model_number(self) -> str:
686
692
  buf = await self._send_request(
@@ -727,6 +733,8 @@ class GForce:
727
733
  has_res=True,
728
734
  )
729
735
  )
736
+ if buf is None or len(buf) == 0:
737
+ return -1
730
738
  return int.from_bytes(buf, byteorder="big")
731
739
 
732
740
  async def get_temperature(self) -> int:
@@ -736,6 +744,8 @@ class GForce:
736
744
  has_res=True,
737
745
  )
738
746
  )
747
+ if buf is None or len(buf) == 0:
748
+ return -1
739
749
  return int.from_bytes(buf, byteorder="big")
740
750
 
741
751
  async def power_off(self) -> None: