13.4 Message, Folder类的实现

本文详细介绍了使用C++实现的消息与文件夹类设计,包括类的成员变量、构造函数、拷贝构造函数、赋值运算符、析构函数及友元函数等。深入探讨了消息保存、删除、移动等操作的实现细节,以及如何维护消息与文件夹之间的双向引用关系。

Message.h

#pragma once
#include <iostream>
#include <set>
#include <string>
#include "Folder.h"

class Folder;

class Message {
    friend class Folder;
    friend void swap(Message &lhs, Message &rhs);
public:
    explicit Message(const std::string &s)
        : m_content(s) {}
    Message(const Message &m);
    Message &operator=(const Message &m);
    Message(Message &&); // 不声明为noexcept是因为会执行insert,有可能会有bad_alloc异常
    Message &operaor=(Message &&);
    ~Message();
    void save(Folder&);
    void remove(Folder&);

    void addFld(Folder *);
    void remFld(Folder *);

private:
    std::set<Folder *> m_folders;
    std::string m_content;

    void add_to_folders(Message &);
    void remove_from_folders();

	void move_folders(Message *);

public:
    void debug_print();
};

Message.cpp

#include "Message.h"

Message::Message(const Message &m)
    : m_folders(m.m_folders), m_content(m.m_content) {
        add_to_folders(*this);
    }

Message &Message::operator=(const Message &m) {
    remove_from_folders();
    m_folders = m.m_folders;
    m_content = m.m_content;
    add_to_folders(*this);
    return *this;
}

Message::Message(Message &&obj) : m_content(std::move(obj.m_content) {
	move_folders(&obj); 
}

Message &operaor=(Message &&m) {
	if (this != &m) {
		remove_from_folders();
		move_folders(&m);
		m_content = std::move(m.m_content);
	}
	return *this;
}

Message::~Message() {
    remove_from_folders();
}

void Message::save(Folder &f) {
    m_folders.insert(&f);
    f.addMsg(this);
}

void Message::remove(Folder &f) {
    m_folders.erase(&f);
    f.remMsg(this);
}

void Message::add_to_folders(Message &m) {
    for (auto &i:m_folders) {
        i->addMsg(&m);
    }
}

void Message::remove_from_folders() {
    for (auto &i:m_folders) {
        i->remMsg(this);
    }
}

void Message::move_folders(Message *m) {
	m_folders = std::move(m->m_folders);
	for (auto &f:m_folders) {
		f->remMsg(m);
		f->addMsg(this);
	}
	m->clear();
}

void swap(Message &lhs, Message &rhs) {
    for (auto m:lhs.m_folders) {
        m->remMsg(&lhs);
    }
    for (auto m:rhs.m_folders) {
        m->remMsg(&rhs);
    }
    using std::swap;
    swap(lhs.m_content, rhs.m_content);
    swap(lhs.m_folders, rhs.m_folders);
    for (auto i:lhs.m_folders) {
        i->addMsg(&lhs);
    }
    for (auto i:rhs.m_folders) {
        i->addMsg(&rhs);
    }
}

void Message::addFld(Folder *f) {
    m_folders.insert(f);
}

void Message::remFld(Folder *f) {
    m_folders.erase(f);
}

void Message::debug_print()
{
    std::cout << "Message:\n\t" << m_content << std::endl;
    std::cout << "Appears in " << m_folders.size() << " Folders" << std::endl;
}

Folder.h

#pragma once
#include <iostream>
#include <string>
#include <set>
#include "Message.h"

class Message;

class Folder {
    friend class Message;
    friend void swap(Folder &lhs, Folder &rhs);
public:
    Folder() : m_msgs(), m_name() {}
    explicit Folder(const std::string &s)
        : m_msgs(), m_name(s) {}
    Folder(const Folder& f);
    Folder &operator=(const Folder&);

    void add_to_message(Folder &);
    void remove_from_message();

    void addMsg(Message *);
    void remMsg(Message *);

    void save(Message &m);
    void remove(Message &m);

private:
    std::set<Message *> m_msgs;
    std::string m_name;

public:
    void debug_print();
};

Folder.cpp

#include <set>
#include "Folder.h"

Folder::Folder(const Folder &f)
    : m_msgs(f.m_msgs), m_name(f.m_name) {}

Folder &Folder::operator=(const Folder &f) {
    remove_from_message();
    m_msgs = f.m_msgs;
    m_name = f.m_name;
    add_to_message(*this);
    return *this;
}

void Folder::add_to_message(Folder &f) {
    for (auto i:m_msgs) {
        i->addFld(&f);
    }
}

void Folder::remove_from_message() {
    while (!m_msgs.empty()) {
        (*m_msgs.begin())->remFld(this);
    }
}

void Folder::addMsg(Message *m) {
    m_msgs.insert(m);
}

void Folder::remMsg(Message *m) {
    m_msgs.erase(m);
}

void Folder::save(Message &m) {
    m_msgs.insert(&m);
    m.addFld(this);
}
void Folder::remove(Message &m) {
    m_msgs.erase(&m);
    m.remFld(this);
}

void swap(Folder &lhs, Folder &rhs) {
    for (auto f:lhs.m_msgs) {
        f->remFld(&lhs);
    }
    for (auto f:rhs.m_msgs) {
        f->remFld(&rhs);
    }
    using std::swap;
    swap(lhs.m_msgs, rhs.m_msgs);
    swap(lhs.m_name, rhs.m_name);
    for (auto f:lhs.m_msgs) {
        f->addFld(&lhs);
    }
    for (auto f:rhs.m_msgs) {
        f->addFld(&rhs);
    }
}

void Folder::debug_print()
{
    std::cout << "Folder contains " << m_msgs.size() << " messages" << std::endl;
    int ctr = 1;
    for (std::set<Message*>::iterator m = m_msgs.begin();
			m != m_msgs.end(); ++m) {
        std::cout << "Message " << ctr++ << ":\n\t" << (*m)->m_content << std::endl;
	}
}

main.cpp

#include <iostream>
#include <string>
#include <vector>
#include "Message.h"
#include "Folder.h"

using namespace std;

int main() {
    string s1("contents1");
	string s2("contents2");
	string s3("contents3");
	string s4("contents4");
	string s5("contents5");
	string s6("contents6");
	
	// all new messages, no copies yet
	Message m1(s1);
	Message m2(s2);
	Message m3(s3);
	Message m4(s4);
	Message m5(s5);
	Message m6(s6);

	Folder f1;
	Folder f2;

	m1.save(f1); m3.save(f1); m5.save(f1);
	m1.save(f2);
	m2.save(f2); m4.save(f2); m6.save(f2);
	
	m1.debug_print();
	f2.debug_print();

	// create some copies
	Message c1(m1);
	Message c2(m2), c4(m4), c6(m6);
	
	m1.debug_print();
	f2.debug_print();

	// now some assignments
	m2 = m3;
	m4 = m5;
	m6 = m3;
	m1 = m5;

	m1.debug_print();
	f2.debug_print();

	// finally, self-assignment
	m2 = m2;
	m1 = m1;

	m1.debug_print();
	f2.debug_print();

	vector<Message> vm;
	cout << "capacity: " << vm.capacity() << endl;
	vm.push_back(m1);

	cout << "capacity: " << vm.capacity() << endl;
	vm.push_back(m2);

	cout << "capacity: " << vm.capacity() << endl;
	vm.push_back(m3);

	cout << "capacity: " << vm.capacity() << endl;
	vm.push_back(m4);

	cout << "capacity: " << vm.capacity() << endl;
	vm.push_back(m5);

	cout << "capacity: " << vm.capacity() << endl;
	vm.push_back(m6);

	vector<Folder> vf;
	cout << "capacity: " << vf.capacity() << endl;
	vf.push_back(f1);

	cout << "capacity: " << vf.capacity() << endl;
	vf.push_back(f2);

	cout << "capacity: " << vf.capacity() << endl;
	vf.push_back(Folder(f1));

	cout << "capacity: " << vf.capacity() << endl;
	vf.push_back(Folder(f2));

	cout << "capacity: " << vf.capacity() << endl;
	vf.push_back(Folder());

	Folder f3;
	f3.save(m6);
	cout << "capacity: " << vf.capacity() << endl;
	vf.push_back(f3);

    return 0;
}

Result:

Message:
        contents1
Appears in 2 Folders
Folder contains 4 messages
Message 1:
        contents1
Message 2:
        contents2
Message 3:
        contents4
Message 4:
        contents6
Message:
        contents1
Appears in 2 Folders
Folder contains 8 messages
Message 1:
        contents1
Message 2:
        contents2
Message 3:
        contents4
Message 4:
        contents6
Message 5:
        contents1
Message 6:
        contents2
Message 7:
        contents4
Message 8:
        contents6
Message:
        contents5
Appears in 1 Folders
Folder contains 4 messages
Message 1:
        contents1
Message 2:
        contents2
Message 3:
        contents4
Message 4:
        contents6
Message:
        contents5
Appears in 1 Folders
Folder contains 4 messages
Message 1:
        contents1
Message 2:
        contents2
Message 3:
        contents4
Message 4:
        contents6
capacity: 0
capacity: 1
capacity: 2
capacity: 4
capacity: 4
capacity: 8
capacity: 0
capacity: 1
capacity: 2
capacity: 4
capacity: 4
capacity: 8

对于m2 = m3; m4 = m5; m6 = m3; m1 = m5;这一段的结果和我期望的不一致,需要再看一下。

from snap7 import client, util import fastapi import uvicorn import serial from fastapi import FastAPI, HTTPException from fastapi.responses import FileResponse from pydantic import BaseModel from typing_extensions import Literal from pathlib import Path from Modbus import ModbusMaster from ScannerInfo import ScannerInfo # from PLC_Siemens import UserControlReadWriteOp from Siemens_PLC import Device_SIEMENS_PLC_S1500 import json import os import glob from pydantic import BaseModel import threading import time # DB 块地址配置 import Config import struct import time import sys import asyncio import signal # 新增导入 from contextlib import asynccontextmanager from snap7 import util import uvicorn from fastapi import FastAPI from Siemens_PLC import Device_SIEMENS_PLC_S1500 import os import threading import time # DB 块地址配置 import Config import configparser import struct import sys import asyncio import signal # 新增导入 from contextlib import asynccontextmanager import json from typing import Dict, Any import logging from typing import Dict, Any import Modbus from pydantic import BaseModel # 单轴伺服运动日志 logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s", handlers=[ logging.StreamHandler(), # 输出到控制台 logging.FileHandler("configfiles/move.log") # 同时输出到文件 ] ) speed = 10 # 创建 logger 对象 logger = logging.getLogger(__name__) # 新增全局退出控制 exit_flag = threading.Event() lock_Barcode = threading.Lock() # 临时在代码开头添加测试断点 # import pdb; pdb.set_trace() # 传统调试 # print("DEBUG CHECK") # 在此行设断点 # 创建一个锁对象 lock = threading.Lock() # 指定本地图片文件夹的路径 # IMAGE_FOLDER = "C:\\Program Files\\VisionMaster4.3.0\\Applications\\RawPicture\\" # 替换为你的图片文件夹路径 # IMAGE_FOLDER = "D:\\RawPicture\\" PLC = Device_SIEMENS_PLC_S1500.CDevice_SIEMENS() #初始化钉枪实例 ModbusMaster= ModbusMaster("COM5",115200,1) ModbusMaster.open() ModbusMaster.write_register(61506,0x3BBB) # App Startup #根据路径下的json文件,创建螺钉机实例 base_dir = os.path.dirname(os.path.abspath(__file__)) # 使用Path对象处理路径 root_path = Path(base_dir) # 递归遍历所有.json文件 #构造空的扫码枪机字典 ScannerDeviceList ={} #遍历路径下 json文件 for json_file in root_path.rglob("*.json"): with open(json_file, 'r', encoding='utf-8') as file: data = json.load(file) # 获取配置文件中的IPPort DeviceType = data["DeviceType"] if DeviceType == "Scanner": #根据json配置内容,创建扫码枪对象实例 info = {json_file.stem: ScannerInfo(json_file.stem,data["Port"],data["Baudrate"])} ScannerDeviceList.update(info) # 定义扫码过程 def ScanBarcode(): try: while not exit_flag.is_set(): try: for key, scanner in ScannerDeviceList.items(): if not scanner.connected: continue try: waiting = scanner.Device.in_waiting if waiting > 0: #time.sleep(0.1) raw_data = scanner.Device.read(scanner.Device.in_waiting) try: decoded_data = raw_data.decode('utf-8').strip() if decoded_data: with lock_Barcode: scanner.Data = decoded_data print(decoded_data) #扫到码后调用HZG 服务端指令 HZG完成业务逻辑处理 # logging.info("扫码调用活字格文件") # print(hzg.BarcodeProcess(key,decoded_data)) # logging.info("扫码调用活字格文件完成") print(f"[扫码数据] {scanner.Data}") except UnicodeDecodeError as e: print(f"解码失败 @ {scanner.Port}: {raw_data.hex()}") raise RuntimeError("连续解码错误") from e except (serial.SerialException, OSError) as e: print(f"硬件错误 @ {scanner.Port}: {str(e)}") # hzg.SendMessageToHZG(f"硬件错误 @ {scanner.Port}: {str(e)}") raise # 向上抛出致命错误 except RuntimeError as e: print(f"扫码系统关键错误: {str(e)}") exit_flag.set() # 设置全局退出标志 break time.sleep(0.1) except Exception as e: #print(f"扫码线程崩溃: {str(e)}") exit_flag.set() os.kill(main_pid, signal.SIGINT) # 直接发送终止信号 @asynccontextmanager async def lifespan(app: FastAPI): try: # 启动时执行的代码 global db_ranges, positions db_ranges = calculate_db_ranges(Config.db_variables) positions = read_position_config(file_path) print("DB读取范围:", db_ranges) # 应输出如 {3: 112} print("加载的配置变量:", Config.db_variables) PLC.Connect("192.168.1.1", 0, 0) print("PLC connected and FastAPI started.") # 启动线程 threadCheckConnect = threading.Thread(target=CheckConnect, daemon=True) threadread_plc_data = threading.Thread(target=read_plc_data, daemon=True) threadCheckConnect.start() threadread_plc_data.start() yield # 应用运行期间保持 finally: # 关闭时执行的代码 print("关闭线程PLC连接...") # 停止线程(如果需要) # 注意:这里假设线程会自动停止,否则需要显式停止 PLC.DisConnect() print("PLC连接已释放") app = FastAPI(lifespan=lifespan) # 读取配置文件 # 假设 BaseResponse 已定义如下 class BaseResponse: def __init__(self, ErrCode: int, Message: str, data=None): self.ErrCode = ErrCode self.Message = Message self.data = data def read_position_config(file_path: str) -> Dict[str, Any]: """ 读取JSON格式的配置文件 :param file_path: JSON文件路径 :return: 包含所有位置数据的字典 """ try: with open(file_path, 'r', encoding='utf-8') as f: config = json.load(f) print(f"成功读取配置文件: {file_path}") # 调试信息:打印文件路径 print(f"配置内容: {json.dumps(config, indent=4)}") # 调试信息:打印配置内容 return config except FileNotFoundError: print(f"错误: 文件未找到 - {file_path}") return {} except json.JSONDecodeError as e: print(f"错误: 配置文件格式错误 - {e}") return {} except Exception as e: print(f"未知错误: {str(e)}") return {} # 全局定义文件路径 file_path = "configfiles\\position.json" # 在程序启动时加载配置文件 positions_config = read_position_config(file_path) data_store = {} db_ranges = None @app.get("/GetBarcode") async def GetBarcode (Device:str): try: if Device in ScannerDeviceList: device = ScannerDeviceList[Device] with lock_Barcode: barcode = device.Data device.Data = "" return {"status": 0, "msg": "success", "data": barcode} else: return {"status": -1, "msg": "该设备不存在", "data": None} except Exception as ex: return {"status": -1, "msg": str(ex), "data": None} @app.post("/Screw_Gun_Run") def Screw_Gun(): #设置扭力 set_screw_register(4002,1000) #设置速度 set_screw_register(4061, 200) #停止拧螺丝 ModbusMaster.write_register(61500, 0x2BBB) #开始拧螺丝 ModbusMaster.write_register(61500, 0x2AAA) time.sleep(3) value=hex((ModbusMaster.read_register(60630, 30))[0]) if(value==("0x4bbb")): return 0 return -1 # 设置寄存器值 @app.post("/set_screw_register") def set_screw_register(register_address: int, value: int): try: # 写入寄存器 ModbusMaster.write_register(register_address, value) return {"status": "success", "message": f"Successfully set register {register_address} to {value}"} except Exception as e: return {"status": "error", "message": str(e)} # 获取寄存器值 @app.get("/get_screw_register") def get_screw_register(register_address: int, length: int): try: # 读取寄存器 result = ModbusMaster.read_register(register_address, length) return {"status": "success", "data": str(result)} except Exception as e: return {"status": "error", "message": str(e)} @app.post("/Screw_Gun_Close") def Screw_Gun_Close(): ModbusMaster.close() def CheckConnect(): while 1: time.sleep(60) with lock: Rlt = PLC.GetCpuState() print(Rlt) if Rlt != "S7CpuStatusRun": PLC.Connect("192.168.1.1", 0, 0) print("PLC connected and FastAPI started.") # 计算每个DB块需要读取的字节范围 def calculate_db_ranges(db_vars): db_info = {} for group in db_vars: db = group['db'] max_length = 0 for var in group['vars']: offset = var['offset'] if var['type'] == 'Int': length = 2 elif var['type'] == 'Double': length = 8 elif var['type'] == 'Bool': length = 1 # 读取整个字节 else: length = 0 end = offset + length if end > max_length: max_length = end db_info[db] = max_length return db_info # 数据读取线程(整体读取DB块) def read_plc_data(): while True: try: global db_ranges global data_store # if not plc.get_connected(): # plc.connect(PLC_IP, RACK, SLOT) # 读取所有DB块数据 start_time = time.time() # 记录开始时间 db_data = {} for db, length in db_ranges.items(): if length > 0: # time.sleep(0.01) with lock: data = PLC.SiemensPLC.db_read(db, 0, length) db_data[db] = data end_time = time.time() # 记录结束时间 elapsed = (end_time - start_time) * 1000 print(f"耗时: {elapsed:.4f} ms") # 输出格式化为4位小数 # 解析变量 temp_data = {} for group in Config.db_variables: db = group['db'] data = db_data.get(db, b'') for var in group['vars']: offset = var['offset'] var_type = var['type'] try: if var_type == 'Int': value = util.get_int(data[offset:offset + 2], 0) if len(data) >= offset + 2 else None elif var_type == 'Float': # 新增对PLC Real型的支持 if len(data) >= offset + 4: try: value = struct.unpack('>f', data[offset:offset + 4])[0] except struct.error as e: print(f"解析Real型错误: {e}") value = None elif var_type == 'Double': if len(data) >= offset + 8: reversed_bytes = data[offset:(offset + 8)] # reversed_bytes.reverse() # value = util.get_lreal(reversed_bytes,0) # 转换为Double value = struct.unpack('>d', reversed_bytes)[0] # print("转换后的Double值:", value) elif var_type == 'Bool': byte = data[offset] if len(data) > offset else 0 bit = var.get('bit', 0) value = bool((byte >> bit) & 1) temp_data[var['name']] = value with lock: data_store[var['name']] = value print(data_store) # 更新全局存储 except Exception as e: raise "解析错误" print(f"解析错误 {var['name']}: {e}") # sys.exit() end_time = time.time() # 记录结束时间 elapsed = (end_time - start_time) * 1000 print(f"耗时: {elapsed:.4f} ms") # 输出格式化为4位小数 # time.sleep(0.01) # 可根据实际调整采样率 except Exception as e: print(f"PLC通信异常: {e}") os.kill(os.getpid(), signal.SIGINT) def find_plc_parameter(param_name): """ 在PLC配置中查找指定参数 :param param_name: 要查找的参数名称(如 "RightSafetyLightCurtainBypass") :param db_config: PLC配置数据 :return: 包含参数信息的字典,若不存在返回None """ for db_group in Config.db_variables: for var in db_group['vars']: if var['name'] == param_name: return { 'exists': True, 'db_block': db_group['db'], 'offset': var['offset'], 'type': var['type'], 'bit': var.get('bit', None) # 仅Bool型有bit位 } return None def SetDB(DB: str, Data: str): # 使用 DB 获取参数 rlt = find_plc_parameter(DB) # 检查 rlt 是否为 None if rlt is None: return -1 # 如果参数存在,则解析相关字段 if rlt["exists"]: DBNumber = rlt["db_block"] nType = rlt["type"] nPort = rlt["offset"] nBit = rlt["bit"] try: # 假设 lock 是一个全局变量或外部定义的对象 with lock: if nType == "Bool": if PLC.WriteDBBit(DBNumber, nPort, nBit, int(Data)): return True else: return False elif nType == "Float": if PLC.WriteDBFloat(DBNumber, nPort, float(Data)): return True else: return False elif nType == "Int": if PLC.WriteDBInt(DBNumber, nPort, int(Data)): return True else: return False elif nType == "Double": if PLC.WriteDBDouble(DBNumber, nPort, float(Data)): return True else: return False elif nType == "String": if PLC.WriteDBString(DBNumber, nPort, Data): return True else: return False except Exception as ex: # 打印异常信息以便调试 print(f"Exception occurred: {ex}") return -1 def GetDB(DB: str): value = data_store.get(DB, "未找到变量") # 如果是布尔值,转换为1/0 if isinstance(value, bool): return 1 if value else 0 return value class ModeSwitchRequest(BaseModel): mode: str @app.post("/Mode_Switch") async def Mode_Switch(request: ModeSwitchRequest): try: mode = request.mode if mode not in ["1", "2", "3"]: raise HTTPException(status_code=400, detail="Invalid mode") # 设置模式 value = SetDB("mode_switch", int(mode)) await asyncio.sleep(0.1) # 使用异步等待代替 time.sleep if mode == "1": if value and GetDB("Production_mode_1") == 1: return 0 else: return -1 elif mode == "2": if value and GetDB("Debugging_Mode_2") == 1: return 0 else: return -1 elif mode == "3": if value and GetDB("Test_run_mode_3") == 1: return 0 else: return -1 except Exception as ex: return -1 @app.post("/LeftReset") def LeftReset(): try: SetDB("axis_x_ready", 0) SetDB("axis_y_ready", 0) SetDB("axis_z_ready", 0) SetDB("left_reset", 1) time.sleep(1) SetDB("left_reset", 0) SetDB("axis_x_ready", 1) SetDB("axis_y_ready", 1) SetDB("axis_z_ready", 1) except Exception as ex: print(f"Exception occurred: {ex}") return 0 @app.post("/RightReset") def RightReset(): try: SetDB("axis_x2_ready", 0) SetDB("axis_y2_ready", 0) SetDB("axis_z2_ready", 0) SetDB("right_reset", 1) time.sleep(1) SetDB("right_reset", 0) SetDB("axis_x2_ready", 1) SetDB("axis_y2_ready", 1) SetDB("axis_z2_ready", 1) except Exception as ex: print(f"Exception occurred: {ex}") return 0 # # @app.get("/variable/{name}") # async def get_variable(name: str): # return data_store.get(name, "未找到变量") class SetSpeedRequest(BaseModel): x_speed: int y_speed: int z_speed: int @app.post("/Left_SetSpeed") async def LeftSetSpeed(request: SetSpeedRequest): # 设置成功返回 0,任意失败返回 -1 try: # 内部逻辑不变,仅修改传参方式 if not SetDB("actual_act_velocity_x1", request.x_speed): return -1 if not SetDB("actual_act_velocity_y1", request.y_speed): return -1 if not SetDB("actual_act_velocity_z1", request.z_speed): return -1 return 0 # 全部设置成功 except Exception as ex: # 实际生产环境应记录日志 # logger.error(f"LeftSetSpeed error: {str(ex)}") return -1 @app.post("/Right_SetSpeed") async def RightSetSpeed(request: SetSpeedRequest): # 设置成功返回 0,任意失败返回 -1 try: # 内部逻辑不变,仅修改传参方式 if not SetDB("actual_act_velocity_x2", request.x_speed): return -1 if not SetDB("actual_act_velocity_y2", request.y_speed): return -1 if not SetDB("actual_act_velocity_z2", request.z_speed): return -1 return 0 # 全部设置成功 except Exception as ex: # 实际生产环境应记录日志 # logger.error(f"LeftSetSpeed error: {str(ex)}") return -1 class GetDataRequest(BaseModel): name: str # The variable name to retrieve @app.post("/GetData") # Changed from GET to POST to match SetData style async def GetData(request: GetDataRequest): with lock: value = data_store.get(request.name, "未找到变量") # Convert boolean to 1/0 if isinstance(value, bool): return 1 if value else 0 return value @app.get("/all") async def get_all(): with lock: return data_store class SetDataRequest(BaseModel): DB: str Data: str @app.post("/SetData") async def SetData(request: SetDataRequest): # 设置成功返回0 反之返回-1 try: rlt = find_plc_parameter(request.DB) # 使用 request.DB 获取参数 # 检查 rlt 是否为 None if rlt is None: return BaseResponse(ErrCode=-1, Message="未找到 PLC 参数", data=None) if rlt["exists"]: DBNumber = rlt["db_block"] nType = rlt["type"] nPort = rlt["offset"] nBit = rlt["bit"] with lock: if nType == "Bool": if PLC.WriteDBBit(DBNumber, nPort, nBit, int(request.Data)): return 0 else: return -1 elif nType == "Float": if PLC.WriteDBFloat(DBNumber, nPort, float(request.Data)): return 0 else: return -1 elif nType == "Int": if PLC.WriteDBInt(DBNumber, nPort, int(request.Data)): return 0 else: return -1 elif nType == "Double": if PLC.WriteDBDouble(DBNumber, nPort, float(request.Data)): return 0 else: return -1 elif nType == "String": if PLC.WriteDBString(DBNumber, nPort, request.Data): return 0 else: return -1 return None else: return BaseResponse(ErrCode=-1, Message="DB 不存在", data=None) except Exception as ex: return BaseResponse(ErrCode=-1, Message=str(ex), data="NG") # def LeftMovePos(XPos: str, YPos: str, ZPos: str): # try: # # # LeftModePos DB13.0 int # # L_X_ExecuteMode DB13.2.0 bool # # L_Y_ExecuteMode DB13.20.0 bool # # L_Z_ExecuteMode DB13.38.0 bool # # # L_X_Position DB13.4 Double # # L_Y_Position DB13.22 Double # # L_Z_Position DB13.40 Double # # # 清除运动信号 # # L_X_ExecuteMode DB13.2.0 bool # with lock: # if not PLC.WriteDBBit(13, 2, 0, 0): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # time.sleep(0.1) # # L_Y_ExecuteMode DB13.20.0 bool # with lock: # if not PLC.WriteDBBit(13, 20, 0, 0): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # L_Z_ExecuteMode DB13.38.0 bool # with lock: # if not PLC.WriteDBBit(13, 38, 0, 0): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # # 写入运动模式 # # LeftModePos DB13.0 int # with lock: # if not PLC.WriteDBInt(13, 0, 2): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # # 写入坐标数值 # # L_X_Position DB13.4 Double # with lock: # if not PLC.WriteDBDouble(13, 4, float(XPos)): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # L_Y_Position DB13.22 Double # # with lock: # if not PLC.WriteDBDouble(13, 22, float(YPos)): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # L_Z_Position DB13.40 Double # with lock: # if not PLC.WriteDBDouble(13, 40, float(ZPos)): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # # 写入开始运动信号 # # L_X_ExecuteMode DB13.2.0 bool # with lock: # if not PLC.WriteDBBit(13, 2, 0, 1): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # L_Y_ExecuteMode DB13.20.0 bool # # with lock: # if not PLC.WriteDBBit(13, 20, 0, 1): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # L_Z_ExecuteMode DB13.38.0 bool # # with lock: # if not PLC.WriteDBBit(13, 38, 0, 1): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # 执行成功后返回 # return {"ErrCode": 0, "Message": "", "data": "OK"} # # except Exception as ex: # return {"ErrCode": -1, "Message": "", "data": "NG"} # # # def RightMovePos(XPos: str, YPos: str, ZPos: str): # try: # # # LeftModePos DB13.0 int # # L_X_ExecuteMode DB13.2.0 bool # # L_Y_ExecuteMode DB13.20.0 bool # # L_Z_ExecuteMode DB13.38.0 bool # # # L_X_Position DB13.4 Double # # L_Y_Position DB13.22 Double # # L_Z_Position DB13.40 Double # # # 清除运动信号 # # L_X_ExecuteMode DB13.2.0 bool # with lock: # if not PLC.WriteDBBit(13, 2, 0, 0): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # time.sleep(0.1) # # L_Y_ExecuteMode DB13.20.0 bool # with lock: # if not PLC.WriteDBBit(13, 20, 0, 0): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # L_Z_ExecuteMode DB13.38.0 bool # with lock: # if not PLC.WriteDBBit(13, 38, 0, 0): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # # 写入运动模式 # # LeftModePos DB13.0 int # with lock: # if not PLC.WriteDBInt(13, 0, 2): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # # 写入坐标数值 # # L_X_Position DB13.4 Double # with lock: # if not PLC.WriteDBDouble(13, 4, float(XPos)): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # L_Y_Position DB13.22 Double # # with lock: # if not PLC.WriteDBDouble(13, 22, float(YPos)): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # L_Z_Position DB13.40 Double # with lock: # if not PLC.WriteDBDouble(13, 40, float(ZPos)): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # # 写入开始运动信号 # # L_X_ExecuteMode DB13.2.0 bool # with lock: # if not PLC.WriteDBBit(13, 2, 0, 1): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # L_Y_ExecuteMode DB13.20.0 bool # # with lock: # if not PLC.WriteDBBit(13, 20, 0, 1): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # L_Z_ExecuteMode DB13.38.0 bool # # with lock: # if not PLC.WriteDBBit(13, 38, 0, 1): # return {"ErrCode": -1, "Message": "", "data": "NG"} # # 执行成功后返回 # return {"ErrCode": 0, "Message": "", "data": "OK"} # # except Exception as ex: # return {"ErrCode": -1, "Message": "", "data": "NG"} # # @app.get("/LeftMoveX") def LeftMoveX(pos: str) -> int: """左工位X轴运动""" try: # 1. 停止当前运动 if not SetDB("x1_executes_the_movement", 0): return -1 # 2. 开启使能 if not SetDB("axis_x_ready", 1): return -1 # 3.启动信号) if not SetDB("left_start", 1): return -1 if not SetDB("actual_pos_x1", pos): return -1 # 4.执行运动 if not SetDB("x1_executes_the_movement", 1): return -1 return 0 # 成功 except Exception as ex: logger.error(f"LeftMoveX error: {str(ex)}") return -1 @app.get("/LeftMoveY") def LeftMoveY(pos: str) -> int: """左工位X轴运动""" try: # 1. 停止当前运动 if not SetDB("y1_executes_the_movement", 0): return -1 if not SetDB("axis_y_ready", 1): return -1 if not SetDB("left_start", 1): return -1 if not SetDB("actual_pos_y1", pos): return -1 if not SetDB("y1_executes_the_movement", 1): return -1 return 0 # 成功 except Exception as ex: logger.error(f"LeftMoveY error: {str(ex)}") return -1 class RightMoveZRequest(BaseModel): pos: str # 保持原参数型为str @app.post("/LeftMoveZ") def LeftMoveZ(request: RightMoveZRequest) : """左工位Z轴运动""" try: # 1. 停止当前运动 if not SetDB("z1_executes_the_movement", 0): return -1 if not SetDB("axis_z_ready", 1): return -1 if not SetDB("left_start", 1): return -1 if not SetDB("actual_pos_z1", request.pos): return -1 if not SetDB("z1_executes_the_movement", 1): return -1 return 0 # 成功 except Exception as ex: logger.error(f"LeftMoveZ error: {str(ex)}") return -1 async def LeftMovePos(XPos: str, YPos: str, ZPos: str) -> Dict[str, Any]: """左工位全轴运动""" results = [] # 按顺序移动各轴 if XPos: results.append(LeftMoveX(XPos)) if YPos: results.append(LeftMoveY(YPos)) if ZPos: results.append(LeftMoveZ(ZPos)) # 检查所有轴是否都成功 if all(res == 0 for res in results): return {"ErrCode": 0, "Message": "", "data": "OK"} else: return {"ErrCode": -1, "Message": "部分轴运动失败", "data": "NG"} @app.post("/Move") def Move(pos_X: int, pos_Y: int, pos_Z: int, ready: int, start: int, ready2: int): SetDB("x1_executes_the_movement", 0) SetDB("y1_executes_the_movement", 0) SetDB("z1_executes_the_movement", 0) SetDB("axis_x_ready", ready) SetDB("axis_y_ready", ready) SetDB("axis_z_ready", ready) SetDB("left_start", start) SetDB("actual_act_velocity_x1", 10) SetDB("actual_act_velocity_y1", 10) SetDB("actual_act_velocity_z1", 10) SetDB("actual_pos_x1", pos_X) SetDB("actual_pos_y1", pos_Y) SetDB("actual_pos_z1", pos_Z) SetDB("x1_executes_the_movement", ready2) SetDB("x1_executes_the_movement", ready2) SetDB("x1_executes_the_movement", ready2) def _right_move_x(pos: str) -> int: """右工位 X 轴运动的核心逻辑""" try: if not SetDB("x2_executes_the_movement", 0): return -1 if not SetDB("axis_x2_ready", 1): return -1 if not SetDB("start_right", 1): return -1 if not SetDB("actual_pos_x2", pos): return -1 if not SetDB("x2_executes_the_movement", 1): return -1 return 0 except Exception as ex: logger.error(f"RightMoveX error: {str(ex)}") return -1 @app.get("/RightMoveX") def RightMoveX(pos: str) -> int: """左工位X轴运动""" try: # 1. 停止当前运动 if not SetDB("x2_executes_the_movement", 0): return -1 # 2. 开启使能 if not SetDB("axis_x2_ready", 1): return -1 # 3.启动信号) if not SetDB("right_start", 1): return -1 if not SetDB("actual_pos_x2", pos): return -1 # 4.执行运动 if not SetDB("x2_executes_the_movement", 1): return -1 return 0 # 成功 except Exception as ex: logger.error(f"LeftMoveX error: {str(ex)}") return -1 # # @app.get("/RightMoveY") def RightMoveY(pos: str) -> int: """右工位Y轴运动""" try: # 1. 停止当前运动 if not SetDB("y2_executes_the_movement", 0): return -1 # 2. 开启使能 if not SetDB("axis_y2_ready", 1): return -1 # 3.启动信号 if not SetDB("start_right", 1): return -1 if not SetDB("actual_pos_y2", pos): return -1 # 4.执行运动 if not SetDB("y2_executes_the_movement", 1): return -1 return 0 # 成功 except Exception as ex: logger.error(f"RightMoveY error: {str(ex)}") return -1 @app.post("/RightMoveZ") async def RightMoveZ(request: RightMoveZRequest) -> int: """右工位Z轴运动""" try: # 1. 停止当前运动 if not SetDB("z2_executes_the_movement", 0): return -1 # 2. 开启使能 if not SetDB("axis_z2_ready", 1): return -1 # 3.启动信号 if not SetDB("start_right", 1): return -1 if not SetDB("actual_pos_z2", request.pos): # 使用request.pos获取参数 return -1 # 4.执行运动 if not SetDB("z2_executes_the_movement", 1): return -1 return 0 # 成功 except Exception as ex: logger.error(f"RightMoveZ error: {str(ex)}") return -1 async def RightMovePos(XPos: str, YPos: str, ZPos: str) -> Dict[str, Any]: """右工位全轴运动""" results = [] if XPos: results.append(RightMoveX(XPos)) if YPos: results.append(RightMoveY(YPos)) if ZPos: results.append(RightMoveZ(ZPos)) if all(res == 0 for res in results): return {"ErrCode": 0, "Message": "", "data": "OK"} else: return {"ErrCode": -1, "Message": "部分轴运动失败", "data": "NG"} def _SetData_(DB: str, Data: str): try: rlt = find_plc_parameter(DB) if rlt["exists"]: DBNumber = rlt["db_block"] nType = rlt["type"] nPort = rlt["offset"] nBit = rlt["bit"] if nType == "Bool": with lock: if PLC.WriteDBBit(DBNumber, nPort, nBit, int(Data)): return {"ErrCode": 0, "Message": "success", "data": "OK"} else: return {"ErrCode": -1, "Message": "success", "data": "NG"} elif nType == "Float": with lock: if PLC.WriteDBFloat(DBNumber, nPort, float(Data)): return {"ErrCode": 0, "Message": "success", "data": "OK"} else: return {"ErrCode": -1, "Message": "success", "data": "NG"} elif nType == "Int": with lock: if PLC.WriteDBInt(DBNumber, nPort, int(Data)): return {"ErrCode": 0, "Message": "success", "data": "OK"} else: return {"ErrCode": -1, "Message": "success", "data": "NG"} elif nType == "Double": with lock: if PLC.WriteDBDouble(DBNumber, nPort, float(Data)): return {"ErrCode": 0, "Message": "success", "data": "OK"} else: return {"ErrCode": -1, "Message": "success", "data": "NG"} elif nType == "String": with lock: data = PLC.WriteDBString(DBNumber, nPort, Data) return {"ErrCode": 0, "Message": "success", "data": "OK"} return None else: return {"ErrCode": -1, "Message": "DB 不存在", "data": None} except Exception as ex: return {"ErrCode": -1, "Message": str(ex), "data": None} @app.post("/RightMoveZero") def RightMoveZero(Axis: str): try: if Axis.upper() == "X": Rlt1 = SetDB("x2_executes_the_movement", "0") Rlt2 = SetDB("axis_x2_ready", "1") Rlt3 = SetDB("start_right", "1") Rlt4 = SetDB("actual_pos_x2", "0") Rlt5 = SetDB("x2_executes_the_movement", "1") if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True: return 0 else: return -1 elif Axis.upper() == "Y": Rlt1 = SetDB("y2_executes_the_movement", "0") Rlt2 = SetDB("axis_y2_ready", "1") Rlt3 = SetDB("start_right", "1") Rlt4 = SetDB("actual_pos_y2", "0") Rlt5 = SetDB("y2_executes_the_movement", "1") if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True: return 0 else: return -1 elif Axis.upper() == "Z": Rlt1 = SetDB("z2_executes_the_movement", "0") Rlt2 = SetDB("axis_z2_ready", "1") Rlt3 = SetDB("start_right", "1") Rlt4 = SetDB("actual_pos_z2", "0") Rlt5 = SetDB("z2_executes_the_movement", "1") if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True: return 0 else: return -1 else: return -1 except Exception as ex: return -1 @app.post("/LeftMoveZero") def LeftMoveZero(Axis: str): try: if Axis.upper() == "X": Rlt1 = SetDB("x1_executes_the_movement", "0") Rlt2 = SetDB("axis_x_ready", "1") Rlt3 = SetDB("left_start", "1") Rlt4 = SetDB("actual_pos_x1", "0") Rlt5 = SetDB("x1_executes_the_movement", "1") if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True: return 0 else: return -1 elif Axis.upper() == "Y": Rlt1 = SetDB("y1_executes_the_movement", "0") Rlt2 = SetDB("axis_y_ready", "1") Rlt3 = SetDB("left_start", "1") Rlt4 = SetDB("actual_pos_y1", "0") Rlt5 = SetDB("y1_executes_the_movement", "1") if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True: return 0 else: return -1 elif Axis.upper() == "Z": Rlt1 = SetDB("z1_executes_the_movement", "0") Rlt2 = SetDB("axis_z_ready", "1") Rlt3 = SetDB("left_start", "1") Rlt4 = SetDB("actual_pos_z1", "0") Rlt5 = SetDB("z1_executes_the_movement", "1") if Rlt1 == True and Rlt2 == True and Rlt3 == True and Rlt4 == True and Rlt5 == True: return 0 else: return -1 else: return -1 except Exception as ex: return -1 class AxisArriveRequest(BaseModel): Axis: Literal['X', 'Y', 'Z','x','y','z'] # 限定只能传X,Y,Z @app.post("/Left_AxisArrive") async def Left_AxisArrive(request: AxisArriveRequest): try: axis = request.Axis if axis == "X": db_value = GetDB("x1_completed") if(db_value==1): return 0 else:return -1 elif axis == "Y": db_value = GetDB("y1_completed") if (db_value == 1): return 0 else: return -1 elif axis == "Z": db_value = GetDB("z1_completed") if (db_value == 1): return 0 else: return -1 except Exception as ex: return -1 @app.post("/Right_AxisArrive") async def Right_AxisArrive(request: AxisArriveRequest): try: axis = request.Axis.upper() if axis == "X": db_value = GetDB("x2_completed") if (db_value == 1): return 0 else: return -1 elif axis == "Y": db_value = GetDB("y2_completed") if (db_value == 1): return 0 else: return -1 elif axis == "Z": db_value = GetDB("z2_completed") if (db_value == 1): return 0 else: return -1 except Exception as ex: return -1 @app.get("/MoveToZero") async def MoveToZero(Station: str, Axis: str): try: if Station.upper() == "LEFT": return LeftMoveZero(Axis) elif Station.upper() == "RIGHT": return RightMoveZero(Axis) else: return -1 except Exception as ex: return -1 # @app.get("/MovePos") # async def MovePos(Station: str, XPos: str, YPos: str, ZPos: str): # try: # if Station == "0": # return LeftMovePos(XPos, YPos, ZPos) # elif Station == "1": # pass # # return RightMovePos(XPos, YPos, ZPos) # else: # return {"ErrCode": -1, "Message": "Station 错误", "data": "NG"} # # except Exception as ex: # return {"ErrCode": -1, "Message": "", "data": "NG"} class MoveAxisRequest(BaseModel): station: str position_name: str mode: str type_name: str @app.post("/MoveAxis") async def MoveAxis(request: MoveAxisRequest): """ 根据型号位置名称调用运动控制函数 :param request: 包含以下字段的请求体: station: 工位号 "LEFT" 或 "RIGHT" position_name: 位置名称(如 "PO1") mode: 运动模式 "X"/"Y"/"Z"/"ALL" type_name: 型号名称(如 "Type1") :return: 运动控制结果 """ try: station = request.station.upper() mode = request.mode.upper() position_name = request.position_name type_name = request.type_name # 检查配置文件 if not positions_config: raise HTTPException( status_code=500, detail=f"无法读取配置文件: {file_path}" ) # 参数校验 if station not in ("LEFT", "RIGHT"): raise HTTPException( status_code=400, detail="工位参数错误,只能是LEFT或RIGHT" ) if mode not in ("X", "Y", "Z", "ALL"): raise HTTPException( status_code=400, detail="运动模式错误,只能是X/Y/Z/ALL" ) # 验证型号存在 if type_name not in positions_config: available_types = ", ".join(positions_config.keys()) raise HTTPException( status_code=404, detail=f"型号 {type_name} 不存在,可用型号: {available_types}" ) type_positions = positions_config[type_name] # 验证位置存在 if position_name not in type_positions: available_positions = ", ".join(type_positions.keys()) raise HTTPException( status_code=404, detail=f"位置 {position_name} 在型号 {type_name} 中不存在,可用位置: {available_positions}" ) pos = type_positions[position_name] # 异步运动控制封装 async def execute_motion(func, *args): result = await asyncio.to_thread(func, *args) if result != 0: return -1 return 0 # 根据模式工位执行运动 if mode == "X": func = LeftMoveX if station == "LEFT" else RightMoveX # ✅ 直接调用核心函数 result = await execute_motion(func, pos["X"]) elif mode == "Y": func = LeftMoveY if station == "LEFT" else RightMoveY result = await execute_motion(func, pos["Y"]) elif mode == "Z": func = LeftMoveZ if station == "LEFT" else RightMoveZ result = await execute_motion(func, pos["Z"]) else: # ALL模式 func = LeftMovePos if station == "LEFT" else RightMovePos result = await execute_motion(func, pos["X"], pos["Y"], pos["Z"]) return 0 except HTTPException as he: # 传递已抛出的HTTP异常 raise he except Exception as ex: raise HTTPException( status_code=500, detail=f"运动控制执行错误: {str(ex)}" ) if __name__ == "__main__": # 创建 FastAPI 实例时传入 lifespan uvicorn.run(app, host="0.0.0.0", port=39000, log_level="info") 以上代码中遍历路径下的json文件,是哪个路径
最新发布
06-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值