Files
wire_controlsystem/RK1106/RK1106_server.py

211 lines
7.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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()