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 CHANGED
@@ -1,4 +1,4 @@
1
1
  __all__ = ["base_driver"]
2
2
 
3
- __version__ = "0.1.13"
3
+ __version__ = "0.1.15"
4
4
 
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
- buffer = bytearray()
99
- HEADER = bytes.fromhex('86 AB') # 帧头
100
- FOOTER = bytes.fromhex('CF') # 帧尾
101
- MIN_FRAME_LEN = 9 # 最小帧长度
102
- if send_data:
103
- pro_check = calculate_pro_check(command_h, command_l, list(send_data))
104
- send_packet = [0x86, 0xAB, (0x09+len(send_data))//256, (0x09+len(send_data))%256, command_h, command_l, *send_data, 0x01, pro_check, 0xCF]
105
- else:
106
- pro_check = calculate_pro_check(command_h, command_l)
107
- send_packet = [0x86, 0xAB, 0x00, 0x09, command_h, command_l, 0x01, pro_check, 0xCF]
108
- send_bytes = bytes(send_packet)
109
-
110
- ser.write(send_bytes)
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
- global buffer
126
- # 读取所有可用数据
127
- data = ser.read(ser.in_waiting or 1)
128
- if data:
129
- buffer.extend(data)
130
- while len(buffer)>=2:
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
- # 1. 查找帧头
135
- start_idx = buffer.find(HEADER)
136
- if start_idx == -1:
137
- # 没有找到帧头,清空无效数据(保留最后可能的部分帧头)
138
- #print("Header no found")
139
- if len(buffer) > len(HEADER) - 1:
140
- buffer = buffer[-len(HEADER) + 1:]
141
- return
142
- # 2. 检查帧头后的长度字段是否足够
143
- if start_idx + 4 > len(buffer):
144
- # 长度字段不完整,等待更多数据
145
- return
146
- # 3. 解析帧长度
147
- frame_length = (buffer[start_idx + 2] << 8) + buffer[start_idx + 3]
148
- # 4. 检查完整帧是否已到达
149
- end_idx = start_idx + frame_length - 1
150
- if end_idx >= len(buffer):
151
- # 完整帧尚未完全到达
152
- return
153
- # 5. 检查帧尾
154
- if buffer[end_idx] != ord(FOOTER):
155
- # 跳过当前帧头,继续查找
156
- print("End no found")
157
- buffer = buffer[start_idx + 1:]
158
- continue
159
- # 6. 提取完整帧
160
- frame = buffer[start_idx:end_idx + 1]
161
- frames_queue.append(frame)
162
- # 7. 从缓冲区移除已处理帧
163
- buffer = buffer[end_idx + 1:]
164
- # 处理所有完整帧
165
- if len(frames_queue) > 0:
166
- frame = frames_queue.popleft()
167
- if check_frame(frame):
168
- return frame
169
- else:
170
- print("Check byte error")
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 > 3:
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
- try:
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
- if _connection is None and "pytest" not in sys.modules:
78
- return
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, _sender_thread, _stop_event
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
- try:
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
- #����ȡ port:����P�˿ڣ� �������أ��Ҷ�����; ��ȡ����-1
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]=1
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: smartpi
3
- Version: 0.1.13
3
+ Version: 0.1.15
4
4
  Summary: A library use for H2-RCU
5
5
  Author: ZMROBO
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,18 +1,20 @@
1
- smartpi/__init__.py,sha256=hSlULYmtHrtLpplBFTQagFL4pXXCSoMgkNVFfklgtzc,55
2
- smartpi/base_driver.py,sha256=FmnwZFqKE2HVUsDoqxXigdX1YlElcY07YkLnlvKY_x8,18033
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/gui.py,sha256=M0VXAxk9VmW8VXSbbcRfOtZUVigWIDn0pEEYZHMTeI0,4416
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=kWmoXklYS1QG0eDz4Qn9FF4WueR3GARb3OwQSkXqUNA,569
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.13.dist-info/METADATA,sha256=fyS1LxSRoLa2FGN9JpZ7QYayqJ6zx57Nyt_mTBP6JI0,311
16
- smartpi-0.1.13.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
17
- smartpi-0.1.13.dist-info/top_level.txt,sha256=PoLhUCmWAiQUg5UeN2fS-Y1iQyBbF2rdUlizXtpHGRQ,8
18
- smartpi-0.1.13.dist-info/RECORD,,
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,,