smartpi 0.1.13__py3-none-any.whl → 0.1.15__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.
- smartpi/__init__.py +1 -1
- smartpi/base_driver.py +175 -131
- smartpi/flash.py +130 -0
- smartpi/gui.py +11 -87
- smartpi/light_sensor.py +39 -2
- smartpi/trace.py +31 -0
- {smartpi-0.1.13.dist-info → smartpi-0.1.15.dist-info}/METADATA +1 -1
- {smartpi-0.1.13.dist-info → smartpi-0.1.15.dist-info}/RECORD +10 -8
- {smartpi-0.1.13.dist-info → smartpi-0.1.15.dist-info}/WHEEL +0 -0
- {smartpi-0.1.13.dist-info → smartpi-0.1.15.dist-info}/top_level.txt +0 -0
smartpi/__init__.py
CHANGED
smartpi/base_driver.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# coding=utf-8
|
|
2
|
-
import serial,time,struct
|
|
2
|
+
import serial,time,struct,threading
|
|
3
3
|
from typing import List, Optional
|
|
4
4
|
from collections import deque
|
|
5
5
|
from . import servo,motor,cw2015,gui
|
|
6
6
|
|
|
7
|
+
# 创建全局线程锁
|
|
8
|
+
serial_lock = threading.RLock()
|
|
7
9
|
|
|
8
10
|
# 命令常量
|
|
9
11
|
BOOT_UPDATE_H = 0XFF
|
|
@@ -66,10 +68,16 @@ ser = serial.Serial(
|
|
|
66
68
|
stopbits=serial.STOPBITS_ONE, # 1位停止位
|
|
67
69
|
timeout=TIMEOUT,
|
|
68
70
|
xonxoff=False, # 关闭软件流控
|
|
69
|
-
rtscts=False, # 关闭硬件流控
|
|
70
|
-
|
|
71
|
+
rtscts=False, # 关闭硬件流控
|
|
71
72
|
)
|
|
72
73
|
|
|
74
|
+
def is_lock_locked(lock):
|
|
75
|
+
"""检查锁是否被占用"""
|
|
76
|
+
acquired = serial_lock.acquire(blocking=True)
|
|
77
|
+
if acquired:
|
|
78
|
+
serial_lock.release()
|
|
79
|
+
return False
|
|
80
|
+
return True
|
|
73
81
|
|
|
74
82
|
def uart3_init() -> Optional[serial.Serial]:
|
|
75
83
|
"""初始化串口"""
|
|
@@ -94,20 +102,25 @@ def calculate_pro_check(command_h: int, command_l: int, data: List[bytes] = None
|
|
|
94
102
|
|
|
95
103
|
return base_sum % 256 # 确保结果为单字节(原C代码未取模,需根据实际协议调整)
|
|
96
104
|
|
|
97
|
-
def write_data(command_h: int, command_l: int, send_data: bytes= None) -> Optional[bytes]:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
105
|
+
def write_data(command_h: int, command_l: int, send_data: bytes= None) -> Optional[bytes]:
|
|
106
|
+
#with serial_lock:
|
|
107
|
+
buffer = bytearray()
|
|
108
|
+
HEADER = bytes.fromhex('86 AB') # 帧头
|
|
109
|
+
FOOTER = bytes.fromhex('CF') # 帧尾
|
|
110
|
+
MIN_FRAME_LEN = 9 # 最小帧长度
|
|
111
|
+
if send_data:
|
|
112
|
+
pro_check = calculate_pro_check(command_h, command_l, list(send_data))
|
|
113
|
+
send_packet = [0x86, 0xAB, (0x09+len(send_data))//256, (0x09+len(send_data))%256, command_h, command_l, *send_data, 0x01, pro_check, 0xCF]
|
|
114
|
+
else:
|
|
115
|
+
pro_check = calculate_pro_check(command_h, command_l)
|
|
116
|
+
send_packet = [0x86, 0xAB, 0x00, 0x09, command_h, command_l, 0x01, pro_check, 0xCF]
|
|
117
|
+
send_bytes = bytes(send_packet)
|
|
118
|
+
|
|
119
|
+
# for x in send_bytes:
|
|
120
|
+
# print(f"{x:02X}", end=' ')
|
|
121
|
+
# print("\n")
|
|
122
|
+
|
|
123
|
+
ser.write(send_bytes)
|
|
111
124
|
|
|
112
125
|
|
|
113
126
|
def check_frame(frame: bytes) -> bool:
|
|
@@ -122,85 +135,79 @@ def check_frame(frame: bytes) -> bool:
|
|
|
122
135
|
return calculated_checksum == frame_checksum
|
|
123
136
|
|
|
124
137
|
def process_received_data():
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
138
|
+
#with serial_lock:
|
|
139
|
+
global buffer
|
|
140
|
+
# 读取所有可用数据
|
|
141
|
+
data = ser.read(ser.in_waiting or 1)
|
|
142
|
+
|
|
143
|
+
# if data:
|
|
144
|
+
# buffer.extend(data)
|
|
145
|
+
#
|
|
146
|
+
# # 检查缓冲区中是否有0xCF
|
|
147
|
+
# if 0xCF in buffer:
|
|
148
|
+
# # 找到0xCF的位置
|
|
149
|
+
# cf_index = buffer.index(0xCF)
|
|
150
|
+
# # 提取从开始到0xCF的完整帧(包括0xCF)
|
|
151
|
+
# frame = buffer[:cf_index + 1]
|
|
152
|
+
# # 从缓冲区中移除已处理的数据
|
|
153
|
+
# buffer = buffer[cf_index + 1:]
|
|
154
|
+
# return bytes(frame)
|
|
155
|
+
|
|
156
|
+
if data:
|
|
157
|
+
buffer.extend(data)
|
|
158
|
+
while len(buffer)>=2:
|
|
131
159
|
# for x in buffer:
|
|
132
160
|
# print(f"{x:02X}", end=' ')
|
|
133
161
|
# print("\n")
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
162
|
+
# 1. 查找帧头
|
|
163
|
+
start_idx = buffer.find(HEADER)
|
|
164
|
+
if start_idx == -1:
|
|
165
|
+
# 没有找到帧头,清空无效数据(保留最后可能的部分帧头)
|
|
166
|
+
#print("Header no found")
|
|
167
|
+
if len(buffer) > len(HEADER) - 1:
|
|
168
|
+
buffer = buffer[-len(HEADER) + 1:]
|
|
169
|
+
return
|
|
170
|
+
# 2. 检查帧头后的长度字段是否足够
|
|
171
|
+
if start_idx + 4 > len(buffer):
|
|
172
|
+
# 长度字段不完整,等待更多数据
|
|
173
|
+
return
|
|
174
|
+
# 3. 解析帧长度
|
|
175
|
+
frame_length = (buffer[start_idx + 2] << 8) + buffer[start_idx + 3]
|
|
176
|
+
# 4. 检查完整帧是否已到达
|
|
177
|
+
end_idx = start_idx + frame_length - 1
|
|
178
|
+
if end_idx >= len(buffer):
|
|
179
|
+
# 完整帧尚未完全到达
|
|
180
|
+
return
|
|
181
|
+
# 5. 检查帧尾
|
|
182
|
+
if buffer[end_idx] != ord(FOOTER):
|
|
183
|
+
# 跳过当前帧头,继续查找
|
|
184
|
+
print("End no found")
|
|
185
|
+
buffer = buffer[start_idx + 1:]
|
|
186
|
+
continue
|
|
187
|
+
# 6. 提取完整帧
|
|
188
|
+
frame = buffer[start_idx:end_idx + 1]
|
|
189
|
+
frames_queue.append(frame)
|
|
190
|
+
# 7. 从缓冲区移除已处理帧
|
|
191
|
+
buffer = buffer[end_idx + 1:]
|
|
192
|
+
# 处理所有完整帧
|
|
193
|
+
if len(frames_queue) > 0:
|
|
194
|
+
frame = frames_queue.popleft()
|
|
195
|
+
if check_frame(frame):
|
|
196
|
+
return frame
|
|
197
|
+
else:
|
|
198
|
+
print("Check byte error")
|
|
171
199
|
|
|
172
200
|
# 功能函数类
|
|
173
201
|
##############################################################################读取设备信息
|
|
174
|
-
"""固件升级模式"""
|
|
175
|
-
def boot_update() -> None:
|
|
176
|
-
write_data(BOOT_UPDATE_H, BOOT_UPDATE_L)
|
|
177
|
-
while True:
|
|
178
|
-
response =process_received_data()
|
|
179
|
-
if response:
|
|
180
|
-
display_data = response[6:-3]
|
|
181
|
-
if display_data[0]==0X03:
|
|
182
|
-
print("固件更新启动\n")
|
|
183
|
-
elif display_data[0]==0X01:
|
|
184
|
-
print("擦除中......",f"{10*display_data[1]}","%\n")
|
|
185
|
-
elif display_data[0]==0X02:
|
|
186
|
-
print("升级中......",f"{10*display_data[1]}","%\n")
|
|
187
|
-
elif display_data[0]==0X05:
|
|
188
|
-
print("更新成功!\n")
|
|
189
|
-
elif display_data[0]==0X06:
|
|
190
|
-
print("更新失败!\n")
|
|
191
|
-
else:
|
|
192
|
-
for x in display_data:
|
|
193
|
-
print(f"{x:02X}", end=' ')
|
|
194
|
-
print("\n")
|
|
195
|
-
|
|
196
|
-
|
|
197
202
|
"""读取设备型号"""
|
|
198
203
|
def read_device_model() -> Optional[bytes]:
|
|
204
|
+
serial_lock.acquire() #获取线程锁
|
|
199
205
|
write_data(READ_MODEL_H, READ_MODEL_L)
|
|
200
206
|
start_time = time.time()
|
|
201
207
|
while True:
|
|
202
208
|
response =process_received_data()
|
|
203
209
|
if response:
|
|
210
|
+
serial_lock.release() #释放线程锁
|
|
204
211
|
display_data = response[6:-3].decode(errors="ignore")
|
|
205
212
|
# print(f"设备型号: {display_data}")
|
|
206
213
|
return display_data
|
|
@@ -208,15 +215,18 @@ def read_device_model() -> Optional[bytes]:
|
|
|
208
215
|
if time.time() - start_time > 3:
|
|
209
216
|
print("读取超时")
|
|
210
217
|
buffer.clear()
|
|
218
|
+
serial_lock.release() #释放线程锁
|
|
211
219
|
return None
|
|
212
220
|
|
|
213
221
|
"""读取版本号"""
|
|
214
222
|
def read_version() -> Optional[bytes]:
|
|
223
|
+
serial_lock.acquire() #获取线程锁
|
|
215
224
|
write_data(READ_VERSION_H, READ_VERSION_L)
|
|
216
225
|
start_time = time.time()
|
|
217
226
|
while True:
|
|
218
227
|
response =process_received_data()
|
|
219
228
|
if response:
|
|
229
|
+
serial_lock.release() #释放线程锁
|
|
220
230
|
display_data = response[6:-3].decode(errors="ignore")
|
|
221
231
|
# print(f"版本号: {display_data}")
|
|
222
232
|
return display_data
|
|
@@ -224,15 +234,18 @@ def read_version() -> Optional[bytes]:
|
|
|
224
234
|
if time.time() - start_time > 3:
|
|
225
235
|
print("读取超时")
|
|
226
236
|
buffer.clear()
|
|
237
|
+
serial_lock.release() #释放线程锁
|
|
227
238
|
return None
|
|
228
239
|
|
|
229
240
|
"""读取工厂信息"""
|
|
230
241
|
def read_factory_data() -> Optional[bytes]:
|
|
242
|
+
serial_lock.acquire() #获取线程锁
|
|
231
243
|
write_data(READ_FACTORY_H, READ_FACTORY_L)
|
|
232
244
|
start_time = time.time()
|
|
233
245
|
while True:
|
|
234
246
|
response =process_received_data()
|
|
235
247
|
if response:
|
|
248
|
+
serial_lock.release() #释放线程锁
|
|
236
249
|
display_data = response[6:-3].decode(errors="ignore")
|
|
237
250
|
# print(f"厂家信息: {display_data}")
|
|
238
251
|
return display_data
|
|
@@ -240,15 +253,18 @@ def read_factory_data() -> Optional[bytes]:
|
|
|
240
253
|
if time.time() - start_time > 3:
|
|
241
254
|
print("读取超时")
|
|
242
255
|
buffer.clear()
|
|
256
|
+
serial_lock.release() #释放线程锁
|
|
243
257
|
return None
|
|
244
258
|
|
|
245
259
|
"""读取硬件ID"""
|
|
246
260
|
def read_hardware_ID() -> Optional[bytes]:
|
|
261
|
+
serial_lock.acquire() #获取线程锁
|
|
247
262
|
write_data(READ_HW_ID_H, READ_HW_ID_L)
|
|
248
263
|
start_time = time.time()
|
|
249
264
|
while True:
|
|
250
265
|
response =process_received_data()
|
|
251
266
|
if response:
|
|
267
|
+
serial_lock.release() #释放线程锁
|
|
252
268
|
display_data = response[6:-3].decode(errors="ignore")
|
|
253
269
|
# print(f"硬件ID: {display_data}")
|
|
254
270
|
return display_data
|
|
@@ -256,15 +272,18 @@ def read_hardware_ID() -> Optional[bytes]:
|
|
|
256
272
|
if time.time() - start_time > 3:
|
|
257
273
|
print("读取超时")
|
|
258
274
|
buffer.clear()
|
|
275
|
+
serial_lock.release() #释放线程锁
|
|
259
276
|
return None
|
|
260
277
|
|
|
261
278
|
"""读取设备名称"""
|
|
262
|
-
def read_device_name() -> Optional[bytes]:
|
|
279
|
+
def read_device_name() -> Optional[bytes]:
|
|
280
|
+
serial_lock.acquire() #获取线程锁
|
|
263
281
|
write_data(READ_NAME_H, READ_NAME_L)
|
|
264
282
|
start_time = time.time()
|
|
265
283
|
while True:
|
|
266
284
|
response =process_received_data()
|
|
267
285
|
if response:
|
|
286
|
+
serial_lock.release() #释放线程锁
|
|
268
287
|
display_data = response[6:-3].decode(errors="ignore")
|
|
269
288
|
# print(f"设备名称: {display_data}")
|
|
270
289
|
return display_data
|
|
@@ -272,16 +291,19 @@ def read_device_name() -> Optional[bytes]:
|
|
|
272
291
|
if time.time() - start_time > 3:
|
|
273
292
|
print("读取超时")
|
|
274
293
|
buffer.clear()
|
|
294
|
+
serial_lock.release() #释放线程锁
|
|
275
295
|
return None
|
|
276
296
|
|
|
277
297
|
"""设置设备名称"""
|
|
278
298
|
def write_device_name(send_data: str) -> Optional[bytes]:
|
|
299
|
+
serial_lock.acquire() #获取线程锁
|
|
279
300
|
data_bytes = send_data.encode('utf-8')
|
|
280
301
|
write_data(WRITE_NAME_H, WRITE_NAME_L, data_bytes)
|
|
281
302
|
start_time = time.time()
|
|
282
303
|
while True:
|
|
283
304
|
response =process_received_data()
|
|
284
305
|
if response:
|
|
306
|
+
serial_lock.release() #释放线程锁
|
|
285
307
|
display_data = response[6:-3].decode(errors="ignore")
|
|
286
308
|
# print(f"设置状态: {display_data}")
|
|
287
309
|
return 0
|
|
@@ -289,22 +311,26 @@ def write_device_name(send_data: str) -> Optional[bytes]:
|
|
|
289
311
|
if time.time() - start_time > 3:
|
|
290
312
|
print("读取超时")
|
|
291
313
|
buffer.clear()
|
|
314
|
+
serial_lock.release() #释放线程锁
|
|
292
315
|
return None
|
|
293
316
|
|
|
294
317
|
"""读取连接方式"""
|
|
295
318
|
def read_connected() -> Optional[bytes]:
|
|
319
|
+
serial_lock.acquire() #获取线程锁
|
|
296
320
|
write_data(READ_CONNECT_H, READ_CONNECT_L)
|
|
297
321
|
start_time = time.time()
|
|
298
322
|
while True:
|
|
299
323
|
response =process_received_data()
|
|
300
324
|
if response:
|
|
325
|
+
serial_lock.release() #释放线程锁
|
|
301
326
|
display_data = response[6:-3].decode(errors="ignore")
|
|
302
327
|
# print(f"连接方式: {display_data}")
|
|
303
328
|
return display_data
|
|
304
329
|
else:
|
|
305
330
|
if time.time() - start_time > 3:
|
|
306
331
|
print("读取超时")
|
|
307
|
-
buffer.clear()
|
|
332
|
+
buffer.clear()
|
|
333
|
+
serial_lock.release() #释放线程锁
|
|
308
334
|
return None
|
|
309
335
|
|
|
310
336
|
"""读取电池电量百分比"""
|
|
@@ -317,39 +343,39 @@ def read_battery() -> Optional[bytes]:
|
|
|
317
343
|
|
|
318
344
|
###############################################################################固件升级
|
|
319
345
|
|
|
320
|
-
"""下载更新请求"""
|
|
321
|
-
def update_request() -> Optional[bytes]:
|
|
322
|
-
write_data(UPDATE_REQUEST_H, UPDATE_REQUEST_L)
|
|
323
|
-
start_time = time.time()
|
|
324
|
-
while True:
|
|
325
|
-
response =process_received_data()
|
|
326
|
-
if response:
|
|
327
|
-
display_data = response[6:-3].decode(errors="ignore")
|
|
328
|
-
print(f"从机响应: {display_data}")
|
|
329
|
-
return display_data
|
|
330
|
-
else:
|
|
331
|
-
if time.time() - start_time > 3:
|
|
332
|
-
print("读取超时")
|
|
333
|
-
buffer.clear()
|
|
334
|
-
return None
|
|
335
|
-
|
|
336
|
-
"""查询最大通讯长度"""
|
|
337
|
-
def read_max_com_len() -> Optional[bytes]:
|
|
338
|
-
write_data(MAX_COM_LEN_H, MAX_COM_LEN_L)
|
|
339
|
-
start_time = time.time()
|
|
340
|
-
while True:
|
|
341
|
-
response =process_received_data()
|
|
342
|
-
if response:
|
|
343
|
-
display_data = response[6:-3].decode(errors="ignore")
|
|
344
|
-
print(f"从机响应: {display_data}")
|
|
345
|
-
return display_data
|
|
346
|
-
else:
|
|
347
|
-
if time.time() - start_time > 3:
|
|
348
|
-
print("读取超时")
|
|
349
|
-
buffer.clear()
|
|
350
|
-
return None
|
|
351
|
-
|
|
352
|
-
"""下载文件的信息"""
|
|
346
|
+
#"""下载更新请求"""
|
|
347
|
+
#def update_request() -> Optional[bytes]:
|
|
348
|
+
# write_data(UPDATE_REQUEST_H, UPDATE_REQUEST_L)
|
|
349
|
+
# start_time = time.time()
|
|
350
|
+
# while True:
|
|
351
|
+
# response =process_received_data()
|
|
352
|
+
# if response:
|
|
353
|
+
# display_data = response[6:-3].decode(errors="ignore")
|
|
354
|
+
# print(f"从机响应: {display_data}")
|
|
355
|
+
# return display_data
|
|
356
|
+
# else:
|
|
357
|
+
# if time.time() - start_time > 3:
|
|
358
|
+
# print("读取超时")
|
|
359
|
+
# buffer.clear()
|
|
360
|
+
# return None
|
|
361
|
+
#
|
|
362
|
+
#"""查询最大通讯长度"""
|
|
363
|
+
#def read_max_com_len() -> Optional[bytes]:
|
|
364
|
+
# write_data(MAX_COM_LEN_H, MAX_COM_LEN_L)
|
|
365
|
+
# start_time = time.time()
|
|
366
|
+
# while True:
|
|
367
|
+
# response =process_received_data()
|
|
368
|
+
# if response:
|
|
369
|
+
# display_data = response[6:-3].decode(errors="ignore")
|
|
370
|
+
# print(f"从机响应: {display_data}")
|
|
371
|
+
# return display_data
|
|
372
|
+
# else:
|
|
373
|
+
# if time.time() - start_time > 3:
|
|
374
|
+
# print("读取超时")
|
|
375
|
+
# buffer.clear()
|
|
376
|
+
# return None
|
|
377
|
+
#
|
|
378
|
+
#"""下载文件的信息"""
|
|
353
379
|
#def download_massage() -> Optional[bytes]:
|
|
354
380
|
# write_data(DL_MESSAGE_H, DL_MESSAGE_L, file_data)#文件信息来源从哪获取?
|
|
355
381
|
# start_time = time.time()
|
|
@@ -416,12 +442,14 @@ def read_max_com_len() -> Optional[bytes]:
|
|
|
416
442
|
###############################################################################读取传感器信息
|
|
417
443
|
|
|
418
444
|
"""读取外设连接情况"""
|
|
419
|
-
def read_peripheral() -> Optional[bytes]:
|
|
445
|
+
def read_peripheral() -> Optional[bytes]:
|
|
446
|
+
serial_lock.acquire() #获取线程锁
|
|
420
447
|
write_data(READ_PERIPH_H, READ_PERIPH_L)
|
|
421
448
|
start_time = time.time()
|
|
422
449
|
while True:
|
|
423
450
|
response =process_received_data()
|
|
424
451
|
if response:
|
|
452
|
+
serial_lock.release() #释放线程锁
|
|
425
453
|
display_data = response[6:-3]
|
|
426
454
|
# for x in display_data:
|
|
427
455
|
# print(f"{x:02X}", end=' ')
|
|
@@ -431,24 +459,28 @@ def read_peripheral() -> Optional[bytes]:
|
|
|
431
459
|
if time.time() - start_time > 3:
|
|
432
460
|
print("读取超时")
|
|
433
461
|
buffer.clear()
|
|
462
|
+
serial_lock.release() #释放线程锁
|
|
434
463
|
return None
|
|
435
464
|
|
|
436
465
|
"""单次操作外设"""
|
|
437
|
-
def single_operate_sensor(op_struct: bytes) -> Optional[bytes]:
|
|
466
|
+
def single_operate_sensor(op_struct: bytes) -> Optional[bytes]:
|
|
467
|
+
serial_lock.acquire() #获取线程锁
|
|
438
468
|
write_data(SINGLE_OP_H, SINGLE_OP_L, op_struct)
|
|
439
469
|
start_time = time.time()
|
|
440
470
|
while True:
|
|
441
471
|
response =process_received_data()
|
|
442
472
|
if response:
|
|
473
|
+
serial_lock.release() #释放线程锁
|
|
443
474
|
display_data = response[6:-3]
|
|
444
475
|
# for x in display_data:
|
|
445
476
|
# print(f"{x:02X}", end=' ')
|
|
446
477
|
# print("\n")
|
|
447
478
|
return display_data
|
|
448
479
|
else:
|
|
449
|
-
if time.time() - start_time >
|
|
480
|
+
if time.time() - start_time > 2:
|
|
450
481
|
print("读取超时")
|
|
451
482
|
buffer.clear()
|
|
483
|
+
serial_lock.release() #释放线程锁
|
|
452
484
|
return None
|
|
453
485
|
|
|
454
486
|
#P端口初始化释放
|
|
@@ -462,43 +494,54 @@ def P_port_init(port:bytes) -> Optional[bytes]:
|
|
|
462
494
|
return None
|
|
463
495
|
|
|
464
496
|
"""从机模式转换"""
|
|
465
|
-
def mode_change(send_data: str) -> Optional[bytes]:
|
|
497
|
+
def mode_change(send_data: str) -> Optional[bytes]:
|
|
498
|
+
serial_lock.acquire() #获取线程锁
|
|
466
499
|
write_data(MODE_CHANGE_H, MODE_CHANGE_L, send_data)
|
|
467
500
|
start_time = time.time()
|
|
468
501
|
while True:
|
|
469
502
|
response =process_received_data()
|
|
470
503
|
if response:
|
|
504
|
+
serial_lock.release() #释放线程锁
|
|
471
505
|
display_data = response[6:-3]
|
|
472
|
-
for x in display_data:
|
|
473
|
-
print(f"{x:02X}", end=' ')
|
|
474
|
-
print("\n")
|
|
506
|
+
# for x in display_data:
|
|
507
|
+
# print(f"{x:02X}", end=' ')
|
|
508
|
+
# print("\n")
|
|
475
509
|
return display_data
|
|
476
510
|
else:
|
|
477
511
|
if time.time() - start_time > 3:
|
|
478
512
|
print("读取超时")
|
|
479
513
|
buffer.clear()
|
|
514
|
+
serial_lock.release() #释放线程锁
|
|
480
515
|
return None
|
|
481
516
|
|
|
482
517
|
"""智能模式发送周期"""
|
|
483
|
-
def mode_change(send_data: str) -> Optional[bytes]:
|
|
518
|
+
def mode_change(send_data: str) -> Optional[bytes]:
|
|
519
|
+
serial_lock.acquire() #获取线程锁
|
|
484
520
|
write_data(SEND_CYCLE_H, SEND_CYCLE_L, send_data)
|
|
485
521
|
start_time = time.time()
|
|
486
522
|
while True:
|
|
487
523
|
response =process_received_data()
|
|
488
524
|
if response:
|
|
525
|
+
serial_lock.release() #释放线程锁
|
|
489
526
|
display_data = response[6:-3]
|
|
490
|
-
for x in display_data:
|
|
491
|
-
print(f"{x:02X}", end=' ')
|
|
492
|
-
print("\n")
|
|
527
|
+
# for x in display_data:
|
|
528
|
+
# print(f"{x:02X}", end=' ')
|
|
529
|
+
# print("\n")
|
|
493
530
|
return display_data
|
|
494
531
|
else:
|
|
495
532
|
if time.time() - start_time > 3:
|
|
496
533
|
print("读取超时")
|
|
497
|
-
buffer.clear()
|
|
534
|
+
buffer.clear()
|
|
535
|
+
serial_lock.release() #释放线程锁
|
|
498
536
|
return None
|
|
499
537
|
|
|
500
538
|
"""H2-RCU初始化"""
|
|
501
539
|
def smartpi_init():
|
|
540
|
+
|
|
541
|
+
if is_lock_locked(serial_lock):
|
|
542
|
+
serial_lock.release()
|
|
543
|
+
|
|
544
|
+
serial_lock.acquire()
|
|
502
545
|
uart3_init()
|
|
503
546
|
P_port_init(1)
|
|
504
547
|
P_port_init(2)
|
|
@@ -531,6 +574,7 @@ def smartpi_init():
|
|
|
531
574
|
motor.reset_motor_encoder(5)
|
|
532
575
|
motor.reset_motor_encoder(6)
|
|
533
576
|
time.sleep(0.1)
|
|
534
|
-
gui.init()
|
|
577
|
+
gui.init()
|
|
578
|
+
serial_lock.release()
|
|
535
579
|
time.sleep(0.1)
|
|
536
580
|
|
smartpi/flash.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import struct
|
|
3
|
+
import fcntl
|
|
4
|
+
|
|
5
|
+
# 配置文件路径 (当前目录下的flash.bin)
|
|
6
|
+
FLASH_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "/home/Interface/flash/flash.bin")
|
|
7
|
+
FLASH_FILE_2 = os.path.join(os.path.dirname(os.path.abspath(__file__)), "/home/Interface/flash/flash_2.bin")
|
|
8
|
+
|
|
9
|
+
DATA_SIZE = 2 # 每个数据2字节
|
|
10
|
+
TOTAL_SLOTS = 100 # 100个数据槽
|
|
11
|
+
|
|
12
|
+
def _init_flash_file():
|
|
13
|
+
"""初始化存储文件"""
|
|
14
|
+
if not os.path.exists(FLASH_FILE):
|
|
15
|
+
with open(FLASH_FILE, "wb") as f:
|
|
16
|
+
f.write(b'\x00' * DATA_SIZE * TOTAL_SLOTS)
|
|
17
|
+
|
|
18
|
+
def write(address, data):
|
|
19
|
+
"""
|
|
20
|
+
写入数据到指定地址
|
|
21
|
+
:param address: 地址编号 (1-100)
|
|
22
|
+
:param data: 要写入的整数数据 (2字节范围)
|
|
23
|
+
"""
|
|
24
|
+
if not 1 <= address <= TOTAL_SLOTS:
|
|
25
|
+
raise ValueError(f"地址必须在1-{TOTAL_SLOTS}范围内")
|
|
26
|
+
|
|
27
|
+
# 2字节数据范围: 0-65535 (0xFFFF)
|
|
28
|
+
if not 0 <= data <= 0xFFFF:
|
|
29
|
+
raise ValueError("数据必须在0-65535范围内")
|
|
30
|
+
|
|
31
|
+
_init_flash_file()
|
|
32
|
+
|
|
33
|
+
# 计算文件偏移量 (每个地址2字节)
|
|
34
|
+
offset = (address - 1) * DATA_SIZE
|
|
35
|
+
|
|
36
|
+
with open(FLASH_FILE, "r+b") as f:
|
|
37
|
+
# 使用文件锁确保写入安全
|
|
38
|
+
fcntl.flock(f, fcntl.LOCK_EX)
|
|
39
|
+
f.seek(offset)
|
|
40
|
+
# 将整数打包为2字节小端格式
|
|
41
|
+
f.write(struct.pack('<H', data))
|
|
42
|
+
f.flush()
|
|
43
|
+
fcntl.flock(f, fcntl.LOCK_UN)
|
|
44
|
+
|
|
45
|
+
def read(address):
|
|
46
|
+
"""
|
|
47
|
+
从指定地址读取数据
|
|
48
|
+
:param address: 地址编号 (1-100)
|
|
49
|
+
:return: 读取到的整数数据
|
|
50
|
+
"""
|
|
51
|
+
if not 1 <= address <= TOTAL_SLOTS:
|
|
52
|
+
raise ValueError(f"地址必须在1-{TOTAL_SLOTS}范围内")
|
|
53
|
+
|
|
54
|
+
_init_flash_file()
|
|
55
|
+
|
|
56
|
+
offset = (address - 1) * DATA_SIZE
|
|
57
|
+
|
|
58
|
+
with open(FLASH_FILE, "rb") as f:
|
|
59
|
+
fcntl.flock(f, fcntl.LOCK_SH) # 共享锁
|
|
60
|
+
f.seek(offset)
|
|
61
|
+
# 读取2字节并解包为整数
|
|
62
|
+
data_bytes = f.read(DATA_SIZE)
|
|
63
|
+
fcntl.flock(f, fcntl.LOCK_UN)
|
|
64
|
+
|
|
65
|
+
if len(data_bytes) != DATA_SIZE:
|
|
66
|
+
return 0 # 返回默认值0
|
|
67
|
+
|
|
68
|
+
return struct.unpack('<H', data_bytes)[0]
|
|
69
|
+
|
|
70
|
+
# 可选扩展功能
|
|
71
|
+
def erase_all():
|
|
72
|
+
"""擦除所有数据(重置为0)"""
|
|
73
|
+
with open(FLASH_FILE, "wb") as f:
|
|
74
|
+
f.write(b'\x00' * DATA_SIZE * TOTAL_SLOTS)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _init_flash_file_2():
|
|
78
|
+
"""初始化存储文件"""
|
|
79
|
+
if not os.path.exists(FLASH_FILE_2):
|
|
80
|
+
with open(FLASH_FILE_2, "wb") as f:
|
|
81
|
+
f.write(b'\x00' * DATA_SIZE * TOTAL_SLOTS)
|
|
82
|
+
|
|
83
|
+
def write_2(address, data):
|
|
84
|
+
if not 1 <= address <= TOTAL_SLOTS:
|
|
85
|
+
raise ValueError(f"地址必须在1-{TOTAL_SLOTS}范围内")
|
|
86
|
+
|
|
87
|
+
# 2字节数据范围: 0-65535 (0xFFFF)
|
|
88
|
+
if not 0 <= data <= 0xFFFF:
|
|
89
|
+
raise ValueError("数据必须在0-65535范围内")
|
|
90
|
+
|
|
91
|
+
_init_flash_file_2()
|
|
92
|
+
|
|
93
|
+
# 计算文件偏移量 (每个地址2字节)
|
|
94
|
+
offset = (address - 1) * DATA_SIZE
|
|
95
|
+
|
|
96
|
+
with open(FLASH_FILE_2, "r+b") as f:
|
|
97
|
+
# 使用文件锁确保写入安全
|
|
98
|
+
fcntl.flock(f, fcntl.LOCK_EX)
|
|
99
|
+
f.seek(offset)
|
|
100
|
+
# 将整数打包为2字节小端格式
|
|
101
|
+
f.write(struct.pack('<H', data))
|
|
102
|
+
f.flush()
|
|
103
|
+
fcntl.flock(f, fcntl.LOCK_UN)
|
|
104
|
+
|
|
105
|
+
def read_2(address):
|
|
106
|
+
if not 1 <= address <= TOTAL_SLOTS:
|
|
107
|
+
raise ValueError(f"地址必须在1-{TOTAL_SLOTS}范围内")
|
|
108
|
+
|
|
109
|
+
_init_flash_file_2()
|
|
110
|
+
|
|
111
|
+
offset = (address - 1) * DATA_SIZE
|
|
112
|
+
|
|
113
|
+
with open(FLASH_FILE_2, "rb") as f:
|
|
114
|
+
fcntl.flock(f, fcntl.LOCK_SH) # 共享锁
|
|
115
|
+
f.seek(offset)
|
|
116
|
+
# 读取2字节并解包为整数
|
|
117
|
+
data_bytes = f.read(DATA_SIZE)
|
|
118
|
+
fcntl.flock(f, fcntl.LOCK_UN)
|
|
119
|
+
|
|
120
|
+
if len(data_bytes) != DATA_SIZE:
|
|
121
|
+
return 0 # 返回默认值0
|
|
122
|
+
|
|
123
|
+
return struct.unpack('<H', data_bytes)[0]
|
|
124
|
+
|
|
125
|
+
# 可选扩展功能
|
|
126
|
+
def erase_all_2():
|
|
127
|
+
"""擦除所有数据(重置为0)"""
|
|
128
|
+
with open(FLASH_FILE_2, "wb") as f:
|
|
129
|
+
f.write(b'\x00' * DATA_SIZE * TOTAL_SLOTS)
|
|
130
|
+
|
smartpi/gui.py
CHANGED
|
@@ -1,97 +1,28 @@
|
|
|
1
1
|
import socket
|
|
2
2
|
import json
|
|
3
3
|
import sys
|
|
4
|
-
import threading
|
|
5
|
-
import queue
|
|
6
|
-
import atexit
|
|
7
4
|
|
|
8
5
|
# 连接对象(模块级单例)
|
|
9
6
|
_connection = None
|
|
10
|
-
# 命令队列
|
|
11
|
-
_command_queue = queue.Queue(maxsize=1000)
|
|
12
|
-
# 后台发送线程
|
|
13
|
-
_sender_thread = None
|
|
14
|
-
# 线程停止标志
|
|
15
|
-
_stop_event = threading.Event()
|
|
16
7
|
|
|
17
8
|
def init(host="127.0.0.1", port=65167):
|
|
18
9
|
"""初始化GUI连接"""
|
|
19
|
-
global _connection, _sender_thread, _stop_event
|
|
20
|
-
if _connection is None:
|
|
21
|
-
try:
|
|
22
|
-
_connection = socket.create_connection((host, port))
|
|
23
|
-
_connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
|
24
|
-
except ConnectionRefusedError:
|
|
25
|
-
print(f"无法连接到GUI服务器 {host}:{port}", file=sys.stderr)
|
|
26
|
-
return
|
|
27
|
-
|
|
28
|
-
# 启动后台发送线程
|
|
29
|
-
_stop_event.clear()
|
|
30
|
-
_sender_thread = threading.Thread(target=_send_worker, daemon=True)
|
|
31
|
-
_sender_thread.start()
|
|
32
|
-
_send({"type": "clear"})
|
|
33
|
-
|
|
34
|
-
def _send_worker():
|
|
35
|
-
"""后台发送线程的工作函数"""
|
|
36
|
-
while not _stop_event.is_set():
|
|
37
|
-
try:
|
|
38
|
-
# 从队列中获取命令,最多等待0.01秒
|
|
39
|
-
cmd = _command_queue.get(timeout=0.01)
|
|
40
|
-
|
|
41
|
-
if _connection:
|
|
42
|
-
data = json.dumps(cmd) + "\n"
|
|
43
|
-
_connection.sendall(data.encode())
|
|
44
|
-
|
|
45
|
-
# 标记任务完成
|
|
46
|
-
_command_queue.task_done()
|
|
47
|
-
except queue.Empty:
|
|
48
|
-
continue
|
|
49
|
-
except (BrokenPipeError, ConnectionResetError):
|
|
50
|
-
# 连接断开,尝试重新连接
|
|
51
|
-
_reconnect()
|
|
52
|
-
except Exception as e:
|
|
53
|
-
print(f"发送错误: {e}", file=sys.stderr)
|
|
54
|
-
time.sleep(0.1)
|
|
55
|
-
|
|
56
|
-
def _reconnect():
|
|
57
|
-
"""尝试重新连接服务器"""
|
|
58
10
|
global _connection
|
|
59
|
-
if _connection:
|
|
60
|
-
|
|
61
|
-
_connection.close()
|
|
62
|
-
except:
|
|
63
|
-
pass
|
|
64
|
-
_connection = None
|
|
65
|
-
|
|
66
|
-
# 尝试重新连接
|
|
67
|
-
try:
|
|
68
|
-
_connection = socket.create_connection(("127.0.0.1", 65167))
|
|
69
|
-
_connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
|
11
|
+
if _connection is None:
|
|
12
|
+
_connection = socket.create_connection((host, port))
|
|
70
13
|
_send({"type": "clear"})
|
|
71
|
-
except Exception as e:
|
|
72
|
-
print(f"重新连接失败: {e}", file=sys.stderr)
|
|
73
14
|
|
|
74
15
|
def _send(cmd):
|
|
75
|
-
"""
|
|
76
|
-
#
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
# 将命令放入队列由后台线程发送
|
|
81
|
-
try:
|
|
82
|
-
_command_queue.put(cmd, block=False)
|
|
83
|
-
except queue.Full:
|
|
84
|
-
# 队列满时丢弃最旧的一条命令
|
|
85
|
-
try:
|
|
86
|
-
_command_queue.get_nowait()
|
|
87
|
-
except queue.Empty:
|
|
88
|
-
pass
|
|
89
|
-
_command_queue.put(cmd, block=False)
|
|
16
|
+
"""发送命令到服务器"""
|
|
17
|
+
if _connection is None and "pytest" not in sys.modules: # 允许测试环境不初始化
|
|
18
|
+
raise ConnectionError("GUI not initialized. Call gui.init() first.")
|
|
19
|
+
if _connection:
|
|
20
|
+
_connection.sendall((json.dumps(cmd) + "\n").encode())
|
|
90
21
|
|
|
91
22
|
def show_text(x, y, text, color="black", size=16):
|
|
92
23
|
_send({"type": "text", "x": x, "y": y, "text": text, "color": color, "size": size})
|
|
93
24
|
|
|
94
|
-
def print(text):
|
|
25
|
+
def print(text): # 使用print作为函数名,因为调用时使用gui.print()
|
|
95
26
|
_send({"type": "print", "text": text})
|
|
96
27
|
|
|
97
28
|
def println(text):
|
|
@@ -120,18 +51,11 @@ def clear():
|
|
|
120
51
|
|
|
121
52
|
def close():
|
|
122
53
|
"""关闭GUI连接"""
|
|
123
|
-
global _connection
|
|
124
|
-
# 设置停止事件
|
|
125
|
-
_stop_event.set()
|
|
126
|
-
if _sender_thread:
|
|
127
|
-
# 等待发送线程退出
|
|
128
|
-
_sender_thread.join(timeout=0.5)
|
|
54
|
+
global _connection
|
|
129
55
|
if _connection:
|
|
130
|
-
|
|
131
|
-
_connection.close()
|
|
132
|
-
except:
|
|
133
|
-
pass
|
|
56
|
+
_connection.close()
|
|
134
57
|
_connection = None
|
|
135
58
|
|
|
136
59
|
# 注册程序退出时自动关闭连接
|
|
60
|
+
import atexit
|
|
137
61
|
atexit.register(close)
|
smartpi/light_sensor.py
CHANGED
|
@@ -3,11 +3,11 @@ import time
|
|
|
3
3
|
from typing import List, Optional
|
|
4
4
|
from smartpi import base_driver
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
#����ֵ��ȡ port:����P�˿ڣ� �������أ���ֵ����; ��ȡ����-1
|
|
7
7
|
def get_value(port:bytes) -> Optional[bytes]:
|
|
8
8
|
light_str=[0xA0, 0x02, 0x00, 0xBE]
|
|
9
9
|
light_str[0]=0XA0+port
|
|
10
|
-
light_str[2]=
|
|
10
|
+
light_str[2]=0x01
|
|
11
11
|
response = base_driver.single_operate_sensor(light_str)
|
|
12
12
|
if response == None:
|
|
13
13
|
return None
|
|
@@ -15,4 +15,41 @@ def get_value(port:bytes) -> Optional[bytes]:
|
|
|
15
15
|
light_data=response[4:-1]
|
|
16
16
|
light_num=int.from_bytes(light_data, byteorder='big', signed=True)
|
|
17
17
|
return light_num
|
|
18
|
+
|
|
19
|
+
#�����ֵ���� port:����P�˿ڣ� threshold�����õ���ֵ0~4000
|
|
20
|
+
def set_threshold(port:bytes,threshold:int) -> Optional[bytes]:
|
|
21
|
+
light_str=[0xA0, 0x02, 0x00, 0x81, 0x00, 0x00, 0xBE]
|
|
22
|
+
light_str[0]=0XA0+port
|
|
23
|
+
light_str[2]=0x04
|
|
24
|
+
light_str[4]=threshold//256
|
|
25
|
+
light_str[5]=threshold%256
|
|
26
|
+
response = base_driver.single_operate_sensor(light_str)
|
|
27
|
+
if response == None:
|
|
28
|
+
return None
|
|
29
|
+
else:
|
|
30
|
+
return 0
|
|
31
|
+
|
|
32
|
+
#�����ֵ��ȡ port:����P�˿ڣ�
|
|
33
|
+
def get_threshold(port:bytes) -> Optional[bytes]:
|
|
34
|
+
light_str=[0xA0, 0x02, 0x00, 0xBE]
|
|
35
|
+
light_str[0]=0XA0+port
|
|
36
|
+
light_str[2]=0x05
|
|
37
|
+
response = base_driver.single_operate_sensor(light_str)
|
|
38
|
+
if response == None:
|
|
39
|
+
return None
|
|
40
|
+
else:
|
|
41
|
+
light_data=response[4:-1]
|
|
42
|
+
light_num=int.from_bytes(light_data, byteorder='big', signed=True)
|
|
43
|
+
return light_num
|
|
44
|
+
|
|
45
|
+
#����ȡ��ǰֵ���趨��ֵ�ȽϺ��boolֵ port:����P�˿ڣ�
|
|
46
|
+
def get_bool_data(port:bytes) -> Optional[bytes]:
|
|
47
|
+
light_str=[0xA0, 0x02, 0x00, 0xBE]
|
|
48
|
+
light_str[0]=0XA0+port
|
|
49
|
+
light_str[2]=0x06
|
|
50
|
+
response = base_driver.single_operate_sensor(light_str)
|
|
51
|
+
if response == None:
|
|
52
|
+
return None
|
|
53
|
+
else:
|
|
54
|
+
return response[4]
|
|
18
55
|
|
smartpi/trace.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
import time
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
from smartpi import base_driver
|
|
5
|
+
|
|
6
|
+
#循迹卡单通道光值读取 port:连接P端口;正常返回:通道光值数据; 读取错误:None
|
|
7
|
+
def get_analog(port:bytes, chn:bytes) -> Optional[bytes]:
|
|
8
|
+
trace_str=[0xA0, 0x21, 0x01, 0x71, 0x00, 0xBE]
|
|
9
|
+
trace_str[0]=0XA0+port
|
|
10
|
+
trace_str[4]=0x20+chn
|
|
11
|
+
response = base_driver.single_operate_sensor(trace_str)
|
|
12
|
+
if response == None:
|
|
13
|
+
return None
|
|
14
|
+
else:
|
|
15
|
+
trace_data=response[4:-1]
|
|
16
|
+
trace_num=int.from_bytes(trace_data, byteorder='big', signed=True)
|
|
17
|
+
return trace_num
|
|
18
|
+
|
|
19
|
+
#循迹卡设置全部颜色 port:连接P端口;正常返回:通道光值数据; 读取错误:None
|
|
20
|
+
def set_color(port:bytes, color:bytes) -> Optional[bytes]:
|
|
21
|
+
trace_str=[0xA0, 0x20, 0x01, 0x71, 0x00, 0xBE]
|
|
22
|
+
trace_str[0]=0XA0+port
|
|
23
|
+
trace_str[4]=color
|
|
24
|
+
response = base_driver.single_operate_sensor(trace_str)
|
|
25
|
+
if response == None:
|
|
26
|
+
return None
|
|
27
|
+
else:
|
|
28
|
+
return response[4]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
smartpi/__init__.py,sha256=
|
|
2
|
-
smartpi/base_driver.py,sha256=
|
|
1
|
+
smartpi/__init__.py,sha256=dSznPiZfuuDogA_EVuESFxs3sJut0lzCo-ys_AJaccE,55
|
|
2
|
+
smartpi/base_driver.py,sha256=3_dsEM1Sbx43HVICOFZmByHGAjIRbba902GEWsThDSU,20202
|
|
3
3
|
smartpi/color_sensor.py,sha256=sTqD3jApjmc6qHMrDyEy2UjaRt8vhJZNR88vzgUiLKs,496
|
|
4
4
|
smartpi/cw2015.py,sha256=1lAF-pi_ye_ya1AZQS1sjbgsDf7MThO5IAskKsNGBzA,5695
|
|
5
|
-
smartpi/
|
|
5
|
+
smartpi/flash.py,sha256=Luz0TjinQSkx31uVknqfSWkiAiVrqIE2Iba7lk3AOzM,4132
|
|
6
|
+
smartpi/gui.py,sha256=E98_soyWbEf_dwYhXZgMSXrgY5QuYoDTuFCPK63flIQ,2102
|
|
6
7
|
smartpi/humidity.py,sha256=xtALQ_IlcwR2RCYvopCSmeNajB45kQU_ckk6FZ0rqko,497
|
|
7
8
|
smartpi/led.py,sha256=n3_k1jGcQptfGXhezDLaYzH6UptgluP4Ze6qP_Y4WmU,536
|
|
8
|
-
smartpi/light_sensor.py,sha256=
|
|
9
|
+
smartpi/light_sensor.py,sha256=glDa4O0wW0kamb-tI3qf509qM7zA8UUjVXbA9si3TXM,1844
|
|
9
10
|
smartpi/motor.py,sha256=uvuAwt2j5LjdLaMfNisXqaGh1ro3fZDvHU8IXd2fn9Q,4527
|
|
10
11
|
smartpi/move.py,sha256=3qzrJCGA-qbsLXBpklY2DErtw0jlzMELzozjhEvRzKs,6028
|
|
11
12
|
smartpi/servo.py,sha256=B6X3yCoEz82qqpUIE5MSO0Eg9YZJ5zDzJEcRpioZpUo,4625
|
|
12
13
|
smartpi/temperature.py,sha256=px2YeqgG63nPkyhJA1wDg3dwYx_oOCYuhMjtsVm_YO0,460
|
|
13
14
|
smartpi/touch_sensor.py,sha256=F6IIQGewNRhC9U1RbHpVzuGYqb8H41lpeQ1Ejwsc_T8,438
|
|
15
|
+
smartpi/trace.py,sha256=pa85IKqNzqAPGtRAoGGYwYmTh3RXOtuKnLrv9_z9qmM,1095
|
|
14
16
|
smartpi/ultrasonic.py,sha256=0meczFKXFLUt92kLxipeEc37vb5duvJjPs4kgtlpO8M,622
|
|
15
|
-
smartpi-0.1.
|
|
16
|
-
smartpi-0.1.
|
|
17
|
-
smartpi-0.1.
|
|
18
|
-
smartpi-0.1.
|
|
17
|
+
smartpi-0.1.15.dist-info/METADATA,sha256=OVWU7rX_t-hjb8WDnOQKBCfmW7Sh17APIuXUs7A9cnM,311
|
|
18
|
+
smartpi-0.1.15.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
19
|
+
smartpi-0.1.15.dist-info/top_level.txt,sha256=PoLhUCmWAiQUg5UeN2fS-Y1iQyBbF2rdUlizXtpHGRQ,8
|
|
20
|
+
smartpi-0.1.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|