#!/usr/bin/env python # -*- coding: utf-8 -*- ''' # @Time : 2026/1/9 10:45 # @Author : reenrr # @File : RK1106_server.py # @Desc : RK1106服务端,等待工控机调用 通信为JSON格式 ''' import socket import logging import sys import json from stepper_motor import motor_start, align_wire, cleanup, motor_stop # ------------日志配置(终端+文件双输出)-------------- logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', # 核心新增:日志文件配置 handlers=[ # 1. 文件处理器:保存到.log文件 logging.FileHandler( "RK1106_server.log", # Buildroot推荐路径,临时测试可改/tmp/1106_server.log mode='a', # 追加模式(不会覆盖历史日志) encoding='utf-8' # 防止中文乱码(必加) ), # 2. 终端处理器:输出到控制台 logging.StreamHandler(sys.stdout) ] ) # --------配置TCP服务端---------- HOST = "192.168.0.100" PORT = 8888 # 全局参数缓存 MOTOR_CONFIG = { "speed": 2500, # 默认速度 "cycle": 10.0, # 默认旋转圈数 } def handle_setting(para_type: str, para_value: str) ->dict: """ 处理客户端发送的参数设置指令(cmd:"setting"),更新全局电机配置 :param para_type: 要设置的参数类型,仅支持"speed"或"cycle" :param para_value: 参数值字符串,将尝试转换为int(speed)或float(cycle) :return: 标准化相应字典dict,如: { "Result": "1"表示成功,"0"表示失败, "ErrMsg": str # 成功提示或错误详情 } """ try: if para_type == "speed": MOTOR_CONFIG["speed"] = int(para_value) elif para_type == "cycle": MOTOR_CONFIG["cycle"] = float(para_value) else: return {"Result": "0", "ErrMsg": f"不支持的参数类型: {para_type}"} return {"Result": "1", "ErrMsg": "设置成功"} except ValueError as e: return {"Result": "0", "ErrMsg": f"参数值格式错误: {str(e)}"} def handle_start(para_type: str, para_value: str) -> dict: """ 处理启动电机指令(cmd: "start"),使用当前MOTOR_CONFIG配置运行电机 :param para_type:为"direction"时,使用"para_value"作为临时方向 :param para_value:为0或1 :return: 标准化相应字典dict,如: { "Result": "1"表示成功,"0"表示失败, "ErrMsg": str #执行结果或异常信息 } """ try: if para_type == "direction": direction = int(para_value) if direction not in (0,1): return {"Result": "0", "ErrMsg": "方向必须为0或1"} motor_start(speed=MOTOR_CONFIG["speed"], cycle=MOTOR_CONFIG["cycle"], direction=direction) dir_str = "正向" if direction == 1 else "负向" return {"Result": "1", "ErrMsg": f"电机启动成功({dir_str})"} else: return {"Result": "0", "ErrMsg": "start 指令仅支持'direction'"} except Exception as e: return {"Result": "0", "ErrMsg": f"电机启动失败:{str(e)}"} def handle_stop() -> dict: """ 处理停止电机指令(cmd: "stop") :return: 标准化相应字典dict,如: { "Result": "1"表示成功,"0"表示失败, "ErrMsg": str #执行结果或异常信息 } """ try: motor_stop() return {"Result": "1", "ErrMsg": "电机已停止"} except Exception as e: return {"Result": "0", "ErrMsg": f"电机停止失败:{str(e)}"} def handle_align() -> dict: """ 处理线条对齐(挡板一来一回) :return: dict """ try: align_wire(MOTOR_CONFIG['speed'], MOTOR_CONFIG['cycle']) return {"Result": "1", "ErrMsg": "处理线条对齐"} except Exception as e: return {"Result": "0", "ErrMsg": "线条对齐失败"} def parse_json_command(data: str) -> dict: """ 解析客户端发送的原始JSON字符串指令,并分发至对应处理函数 :param data: 客户端发送的原始JSON字符串 :return dict:标准化响应字典 """ try: cmd_obj = json.loads(data.strip()) except json.JSONDecodeError as e: return {"Result": "0", "ErrMsg": f"JSON 格式错误: {str(e)}"} cmd = cmd_obj.get("cmd", "").strip() para_type = cmd_obj.get("para_type", "").strip() para_value = cmd_obj.get("para_value", "").strip() if cmd == "setting": return handle_setting(para_type, para_value) elif cmd == "start": return handle_start(para_type, para_value) elif cmd == "stop": if para_type == "none" and para_value == "none": return handle_stop() else: return {"Result": "0", "ErrMsg": "stop指令参数必须为none"} elif cmd == "alignment": if para_type == "none" and para_value == "none": return handle_align() else: return {"Result": "0", "ErrMsg": "alignment指令参数必须为none"} else: return {"Result": "0", "ErrMsg": f"未知指令:{cmd}"} # ----------对外接口---------- def server(): """启动TCP服务端,监听指定端口,接收工控机连接并循环处理JSON指令""" # 创建TCP socket server_socket = None conn = None try: server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind((HOST, PORT)) server_socket.listen(1) # 只允许1个工控机连接 logging.info(f"[1106] 服务已启动,监听端口:{PORT},等待工控机连接...") while True: # 持续接受新连接 try: # 等待工控机连接 conn, addr = server_socket.accept() logging.info(f"[1106] 工控机已连接:{addr}") # 循环接收指令 while True: # 接收指令(最大1024字节) data = conn.recv(1024).decode() if not data: logging.warning("客户端断开连接") break logging.info(f"\n[1106] 收到工控机指令:{data}") # 解析指令 response_dict = parse_json_command(data) response_json = json.dumps(response_dict, ensure_ascii=False) + "\n" # 看需不需要加换行符\n # 发送响应给工控机 conn.sendall(response_json.encode("utf-8")) logging.info(f"[1106] 已发送响应:{response_json}") except ConnectionError: logging.info("客户端异常断开") except Exception as e: logging.info(f"处理连接时发生错误: {e}") finally: if conn is not None: conn.close() conn = None # 重置,避免重复关闭 logging.info("客户端连接已关闭,等待新连接...") except KeyboardInterrupt: logging.info("\n收到 Ctrl+C,正在关闭服务...") finally: if server_socket: server_socket.close() logging.info("服务已停止,监听 socket 已释放") # ----------测试接口---------- if __name__ == "__main__": server()