Browse Source

自定义序列化方法、leakcheck、report反馈数据结构
用ads仿真tcp测试路已走到尽头,后面换到台式机上,继续用真实PLC测试了

shishenghui 1 month ago
parent
commit
c44bafa653

+ 1 - 0
TIN001-PLC/Jet_Furance_PMC/Jet_Furance_PMC/Jet_Furance_PMC/FurancePMC/RecipeContext.h

@@ -519,6 +519,7 @@ public:
 		bool chargeOver();
 		bool dischargeOver();
 		bool simpleTick();
+		bool simpleReport();
 		bool  retryAlarm();
 		bool  ignoreAlarm();
 		bool  clearAlarm();

+ 9 - 2
TIN001-PLC/Jet_Furance_PMC/Jet_Furance_PMC/Jet_Furance_PMC/FurancePMC/RecipeContextMethod.cpp

@@ -12,13 +12,16 @@
 void RecipeContext::addSmCtrlTable()
 {
 	transition(RecipeExecuteStatusEnum::Idle, RecipeExecuteCommandEnum::Execute, &RecipeContext::executeNextStep, RecipeExecuteStatusEnum::Unknown);
-
+	//transition(RecipeExecuteStatusEnum::Idle, RecipeExecuteCommandEnum::Tick, &RecipeContext::simpleReport, RecipeExecuteStatusEnum::Unknown);
 	transition(RecipeExecuteStatusEnum::ExecStep, RecipeExecuteCommandEnum::Auto, &RecipeContext::toTimeOrConditionWait, RecipeExecuteStatusEnum::Unknown);
 	transition(RecipeExecuteStatusEnum::ExecStep, RecipeExecuteCommandEnum::Hold, &RecipeContext::holdStep, RecipeExecuteStatusEnum::Paused);
 	//skip 只需要把本步骤设置为完成即可
 	transition(RecipeExecuteStatusEnum::ExecStep, RecipeExecuteCommandEnum::Skip, NULL, RecipeExecuteStatusEnum::StepCompleted);
 	transition(RecipeExecuteStatusEnum::ExecStep, RecipeExecuteCommandEnum::Abort, &RecipeContext::abortRecipe, RecipeExecuteStatusEnum::Unknown);
 
+	transition(RecipeExecuteStatusEnum::TimeWait, RecipeExecuteCommandEnum::Skip, NULL, RecipeExecuteStatusEnum::StepCompleted);
+	transition(RecipeExecuteStatusEnum::ConditionWait, RecipeExecuteCommandEnum::Skip, NULL, RecipeExecuteStatusEnum::StepCompleted);
+
 	transition(RecipeExecuteStatusEnum::TimeWait, RecipeExecuteCommandEnum::Tick, &RecipeContext::checkStep, RecipeExecuteStatusEnum::Unknown);
 	transition(RecipeExecuteStatusEnum::TimeWait, RecipeExecuteCommandEnum::Abort, &RecipeContext::abortRecipe, RecipeExecuteStatusEnum::Unknown);
 	
@@ -306,7 +309,11 @@ bool  RecipeContext::simpleTick() {
 	report();
 	return true;
 }
- 
+bool  RecipeContext::simpleReport() {
+	
+	report();
+	return true;
+}
 bool  RecipeContext::retryAlarm() {
 	if (currentStepInfo == NULL) {
 		return false;

+ 94 - 0
TIN001-PLC/Jet_Furance_PMC/Jet_Furance_PMC/Jet_Furance_PMC/FurancePMC/RecipeReport.h

@@ -0,0 +1,94 @@
+#ifndef __RECIPE_REPORT_H__
+#define __RECIPE_REPORT_H__
+typedef enum class _t_recipe_reprot_tag_id {
+		NormalStepCompleted =51, 
+		StepRunning=52,
+		NormalStepBegin=53,
+		SubStepCompleted=54,
+        SubStepBegin=55,
+		AlarmStepFinish=56,
+		AlarmStepBegin=57,
+		AlarmTrigger=58,
+		AbortTrigger=59,
+		RecipeCompleted=60
+}ReportTagIdEnum;
+typedef enum class _t_recipe_report_command {
+	None=0,
+	Buzzer=1,
+}RecipeReportCommandEnum;
+class RecipeReport :SerializedBase {
+public:
+	short	tagId;
+	time_t  time;
+	unsigned char status;
+	unsigned char recipeType;
+	unsigned char stepNo;
+	unsigned char otherRecipeKey;
+	unsigned char otherStepNo;
+	short loopCount;
+	short elapsedLoopCount;
+	short subLoopCount;
+	short subElapsedLoopCount;
+	int remainTotalTime;
+	time_t startTime;
+	int elapsedTotalTime;
+	int holdTotalTime;
+	int elapsedStepTime;
+	int holdStepTime;
+	int remainStepTime;
+	unsigned char command;//补充命令,用于通知上位机做一些辅助动作
+	char alarmNo[20];
+	char message[255];
+	unsigned char  RecipeReportVersion = 0x01;
+	int serialize(char* buffer, int bufferSize)
+	{
+		BEGIN_SERIALIZE(buffer, bufferSize, RecipeReportVersion);
+		SERIALIZE(time);
+		SERIALIZE(status);
+		SERIALIZE(recipeType);
+		SERIALIZE(stepNo);
+		SERIALIZE(otherRecipeKey);
+		SERIALIZE(otherStepNo);
+		SERIALIZE(loopCount);
+		SERIALIZE(elapsedLoopCount);
+		SERIALIZE(subLoopCount);
+		SERIALIZE(subElapsedLoopCount);
+		SERIALIZE(remainTotalTime);
+		SERIALIZE(startTime);
+		SERIALIZE(elapsedTotalTime);
+		SERIALIZE(holdTotalTime);
+		SERIALIZE(elapsedStepTime);
+		SERIALIZE(holdStepTime);
+		SERIALIZE(remainStepTime);
+		SERIALIZE(command);
+		SERIALIZE_STR(alarmNo);
+		SERIALIZE_STR(message);
+		return END_SERIALIZE();
+	}
+	int unSerialize(char* buffer, int bufferSize)
+	{
+		BEGIN_UNSERIALIZE(buffer, bufferSize, RecipeReportVersion);
+		UNSERIALIZE(time);
+		UNSERIALIZE(status);
+		UNSERIALIZE(recipeType);
+		UNSERIALIZE(stepNo);
+		UNSERIALIZE(otherRecipeKey);
+		UNSERIALIZE(otherStepNo);
+		UNSERIALIZE(loopCount);
+		UNSERIALIZE(elapsedLoopCount);
+		UNSERIALIZE(subLoopCount);
+		UNSERIALIZE(subElapsedLoopCount);
+		UNSERIALIZE(remainTotalTime);
+		UNSERIALIZE(startTime);
+		UNSERIALIZE(elapsedTotalTime);
+		UNSERIALIZE(holdTotalTime);
+		UNSERIALIZE(elapsedStepTime);
+		UNSERIALIZE(holdStepTime);
+		UNSERIALIZE(remainStepTime);
+		UNSERIALIZE(command);
+		UNSERIALIZE_STR(alarmNo);
+		UNSERIALIZE_STR(message);
+		return END_UNSERIALIZE();
+	}
+};
+#endif

+ 77 - 0
TIN001-PLC/Jet_Furance_PMC/Jet_Furance_PMC/Jet_Furance_PMC/FurancePMC/SerializedBase.cpp

@@ -0,0 +1,77 @@
+#include"RecipeContext.h"
+#include"SerializedBase.h"
+
+void SerializedBase::SERIALIZE_do(char* fieldName, void* fieldAddr, int fieldLength) {
+	if (offset + fieldLength > bufferSize) {
+		logger->error("Field [%s] too long[%d]", fieldName, fieldLength);
+		return;
+	}
+	memcpy(buffer + offset, fieldAddr, fieldLength);
+	offset += fieldLength;
+}
+void SerializedBase::SERIALIZE_STR_do(char* fieldName, char* fieldAddr, int fieldLength) {
+	int l_str = strlen(fieldAddr);
+	if (offset + l_str > bufferSize) {
+		logger->error("Field [%s] too long[%d]", fieldName, l_str);
+		return;
+	}
+	strcpy(buffer + offset, fieldAddr);
+	offset += l_str + 1;
+}
+void SerializedBase::UNSERIALIZE_do(char* fieldName, void* fieldAddr, int fieldLength) {
+	if (!unSerializedSuccess || offset + fieldLength > bufferSize) {
+		logger->error("Field [%s] too long[%d]", fieldName, fieldLength);
+		unSerializedSuccess = false;
+		return;
+	}
+	memcpy(fieldAddr, buffer + offset, fieldLength);
+	offset += fieldLength;
+}
+void SerializedBase::UNSERIALIZE_STR_do(char* fieldName, char* fieldAddr, int fieldLength) {
+	if (!unSerializedSuccess || offset >= bufferSize) {
+		unSerializedSuccess = false;
+		return;
+	}
+	int l_str = strlen(buffer + offset);
+	if (l_str >= fieldLength) {
+		logger->error("Field [%s] too long[%d]", fieldName, l_str);
+		unSerializedSuccess = false;
+		return;
+	}
+	strcpy(fieldAddr, buffer + offset);
+	offset += l_str + 1;
+}
+void SerializedBase::BEGIN_SERIALIZE(char* buffer, int bufferSize, unsigned char version) {
+	this->buffer = buffer;
+	buffer[0] = version;
+	this->offset = 1;
+	this->bufferSize = bufferSize;
+}
+int SerializedBase::END_SERIALIZE() {
+	return offset;
+}
+void SerializedBase::BEGIN_UNSERIALIZE(char* buffer, int bufferSize, unsigned char version) {
+	unSerializedSuccess = true;
+	if (buffer == NULL) {
+		unSerializedSuccess = false;
+		return;
+	}
+	this->buffer = buffer;
+	this->bufferSize = bufferSize;
+	if ((unsigned char)buffer[0] != version) {
+		unSerializedSuccess = false;
+		RecipeContext* context = RecipeContext::GetInstance();
+		if (context != NULL) {
+			sprintf(OP->alarmText, "Serialized package version not match[%d][%d]", buffer[0], version);
+			context->report(OP->alarmText, RecipeReportCommandEnum::None);
+		}
+		return;
+	}
+	offset = 1;
+}
+int SerializedBase::END_UNSERIALIZE() {
+	if (!unSerializedSuccess) {
+		return -1;
+	}
+	return offset;
+}

+ 36 - 0
TIN001-PLC/Jet_Furance_PMC/Jet_Furance_PMC/Jet_Furance_PMC/FurancePMC/SerializedBase.h

@@ -0,0 +1,36 @@
+#ifndef __ISERIALIZED_H__
+#define __ISERIALIZED_H__
+#include"CRemoteLog.h"
+//SSH:自定义序列化方法
+	// 格式:版本+依次排列字段
+	//版本从1开始,每次结构体修改之后递增,用于检测上位机和pmc的匹配
+	// 字段如果是原始数据类型,直接按原始内存拷贝
+	//字段如果是字符串,以\0结尾
+	//command列表:以\0结尾,以0x0a分割command,以0x0d(避免雷同)分割命令名称和参数
+#define SERIALIZE(x) SERIALIZE_do(#x,&x,sizeof(x))
+#define SERIALIZE_STR(x) SERIALIZE_STR_do(#x,x,sizeof(x))
+#define UNSERIALIZE(x) UNSERIALIZE_do(#x,&x,sizeof(x))
+#define UNSERIALIZE_STR(x) UNSERIALIZE_STR_do(#x,x,sizeof(x))
+
+typedef unsigned char SERIALIZE_BOOL;
+class SerializedBase {
+private:
+	int offset = 0;
+	char* buffer;
+	int bufferSize = 0;
+	bool unSerializedSuccess = false;
+protected:
+	void SERIALIZE_do(char* fieldName, void* fieldAddr, int fieldLength);
+	void SERIALIZE_STR_do(char* fieldName, char* fieldAddr, int fieldLength);
+	void UNSERIALIZE_do(char* fieldName, void* fieldAddr, int fieldLength);
+	void UNSERIALIZE_STR_do(char* fieldName, char* fieldAddr, int fieldLength);
+protected:
+	void  BEGIN_SERIALIZE(char* buffer, int bufferSize, unsigned char version);
+	int  END_SERIALIZE();
+	void BEGIN_UNSERIALIZE(char* buffer, int bufferSize, unsigned char version);
+	int  END_UNSERIALIZE();
+public:
+	virtual int serialize(char* buffer,int bufferSize) = 0;
+	virtual int unSerialize(char* buffer,int bufferSize) = 0;
+};
+#endif

+ 187 - 0
TIN001-PLC/Jet_Furance_PMC/Jet_Furance_PMC/Jet_Furance_PMC/FurancePMC/SetCommand.cpp

@@ -0,0 +1,187 @@
+/**
+ *
+ * @author    seagle
+ * @date      2025-8-19
+ * @Description
+ *   按PMC框架重写的SetCommand
+ */
+
+#include"SetCommand.h"
+#include"SC.h"
+#include"string.h"
+#include"pmc_types.h"
+#include "DEVICE.h"
+#include "errcode.h"
+#include "EV.h"
+#include"IoSensor.h"
+#include"RecipeContext.h"
+#include"FurnaceSignalTower.h"
+#include"debug.h"
+SetCommandModule* setCommandModule;
+
+void SetCommandModule::initialize()
+{
+	char cmd[MAX_NAME_LEN];
+#pragma region SetCommand.Hold
+	sprintf(cmd, "SetCommand.Hold");
+	auto opNode = OP->subscribe(cmd);
+	opNode->addExec([]()->OperatorStatusEnum {
+		RecipeContext* context = RecipeContext::GetInstance();
+		if (context != NULL) {
+			context->pause();
+		}
+		return OperatorStatusEnum::SUCCESS;
+	});
+#pragma region SetCommand.Hold+Buzzer
+	sprintf(cmd, "SetCommand.Hold + Buzzer");
+	opNode = OP->subscribe(cmd);
+	opNode->addExec([]()->OperatorStatusEnum {
+		RecipeContext* context = RecipeContext::GetInstance();
+		if (context != NULL) {
+			context->pause();
+			context->buzzerOn();
+		}
+		return OperatorStatusEnum::SUCCESS;
+	});
+#pragma region SetCommand.Buzzer
+	sprintf(cmd, "SetCommand.Buzzer");
+	opNode = OP->subscribe(cmd);
+	opNode->addExec([]()->OperatorStatusEnum {
+		RecipeContext* context = RecipeContext::GetInstance();
+		if (context != NULL) {
+			context->buzzerOn();
+		}
+		return OperatorStatusEnum::SUCCESS;
+	});
+#pragma region SetCommand.Leak Check1/2/3
+	for (int leakIndex = 1; leakIndex <= 3; leakIndex++) {
+		sprintf(cmd, "SetCommand.Leak Check%d", leakIndex);
+        opNode = OP->subscribe(cmd,this);
+		opNode->addExec([]()->OperatorStatusEnum {
+			auto* op = OP->currentRoot;
+			SetCommandModule* device = (SetCommandModule*)op->device;
+			device->leakCheckIndex = op->name[strlen(op->name) - 1] - '0';
+			device->leakCheckTable = NULL;
+			device->beginPressure = 0;
+			device->sensor = NULL;
+			RecipeContext* context = RecipeContext::GetInstance();
+			if (context != NULL) {
+				char sIndex[5];
+				sprintf(sIndex,"%d",device->leakCheckIndex);
+				auto dicNode = context->leakCheckDic.get(sIndex);
+				if (dicNode != NULL) {
+					device->leakCheckTable = dicNode->getByIndex(0);
+					device->sensor=(IoPressureMeter *)DEVICE->getDevice(MODULE_NAME,device->leakCheckTable->DeviceName);
+					if (device->sensor == NULL) {
+						device->sensor = IoPressureMeter::poVG13;
+					}
+					device->beginPressure = device->sensor->aiFeedback.getDoubleValue();
+					if (device->beginPressure > device->leakCheckTable->HighLimit && GT_ZERO(device->leakCheckTable->HighLimit)) {
+						//基准压力超过PH
+						strcpy(OP->alarmText,EV->parseErrCode(ALARM_LEAK_PH,"PH=%f;BP=%f;", device->leakCheckTable->HighLimit, device->beginPressure));
+					 
+						AlarmCondition ac;
+						ac.alarmCommandEnum = device->leakCheckTable->HightLimitCommandEnum;
+						ac.alarmCallRecipeIndex = device->leakCheckTable->HightCallRecipeIndex;
+						//ac.alarmJumpStepName = "TODO:None";
+						ac.alarmJumpStepNo = device->leakCheckTable->HightLimitJumpStepNo;
+						return device->doAlarmConditionAlarm(&ac);
+					}
+					else if (device->beginPressure > device->leakCheckTable->LowLimit && GT_ZERO(device->leakCheckTable->LowLimit)) {
+						//基准压力超过PL
+						strcpy(OP->alarmText, EV->parseErrCode(ALARM_LEAK_PL, "PL=%f;BP=%f;", device->leakCheckTable->LowLimit, device->beginPressure));
+					 
+						AlarmCondition ac;
+						ac.alarmCommandEnum = device->leakCheckTable->LowLimitCommandEnum;
+						ac.alarmCallRecipeIndex = device->leakCheckTable->LowCallRecipeIndex;
+						//ac.alarmJumpStepName =TODO None
+						ac.alarmJumpStepNo = device->leakCheckTable->LowLimitJumpStepNo;
+						return device->doAlarmConditionAlarm(&ac);
+					}
+					else if (device->beginPressure < device->leakCheckTable->BasePressureLimit && GT_ZERO(device->leakCheckTable->BasePressureLimit)) {
+						//基准压力小于BPLIMIT
+						strcpy(OP->alarmText, EV->parseErrCode(ALARM_LEAK_BPLIMIT, "BP=%f;BPLIMIT=%s", device->beginPressure, device->leakCheckTable->BasePressureLimit));
+						
+						AlarmCondition ac;
+						ac.alarmCommandEnum = device->leakCheckTable->BasePressureLimitCommandEnum;
+						ac.alarmCallRecipeIndex = device->leakCheckTable->BaseCallRecipeIndex;
+						//ac.alarmJumpStepName = TODO None
+						ac.alarmJumpStepNo = device->leakCheckTable->BasePressureLimitJumpStepNo;
+						return device->doAlarmConditionAlarm(&ac);
+					}
+					op->setTimes(device->leakCheckTable->DelayTime, 0, 0, device->leakCheckTable->CheckTime);
+				}
+			}
+			//tryTimes在初始化部分不清除,而是在reset清除
+            return OperatorStatusEnum::SUCCESS;
+		});
+		opNode->addReset([]()->OperatorStatusEnum {
+			auto* op = OP->currentRoot;
+			SetCommandModule* device = (SetCommandModule*)op->device;
+			device->tryTimes = 0;
+			return OperatorStatusEnum::SUCCESS;
+		});
+		opNode->addCheck([]()->OperatorStatusEnum {
+			auto* op = OP->currentRoot;
+			SetCommandModule* device = (SetCommandModule*)op->device;
+			RecipeContext* context = RecipeContext::GetInstance();
+			if (op->isTimeout.value) {
+				double currentPressure = device->sensor->aiFeedback.getDoubleValue();
+				if (currentPressure - device->beginPressure > device->leakCheckTable->LeakLimit) {
+					device->tryTimes++;
+					if (device->tryTimes < device->leakCheckTable->RetryLimit) {
+						strcpy(OP->alarmText, EV->parseErrCode(WARNING_LEAK, "leak=%f;limit=%f", currentPressure - device->beginPressure, device->leakCheckTable->LeakLimit));
+						if (context != NULL) {
+							
+							char sPreStepName[64];
+							sPreStepName[0] = 0;
+							char scName[64];
+							sprintf(scName, "%s.Recipe.Command", MODULE_NAME);
+							if (context->currentRecipeType == RecipeTypeEnum::NormalRecipe) {
+								int preStepNo = context->currentStepNo - 1;
+								if (preStepNo >= 0) {
+									sprintf(sPreStepName, "Jump:%s", context->mainStepList.get(preStepNo)->name);
+									SC->setStringValue(scName, sPreStepName);
+								}
+							}
+							else if (context->currentRecipeType == RecipeTypeEnum::SubRecipe) {
+								int preStepNo = context->currentOtherStepNo-1;
+								if (preStepNo >= 0) {
+									char subKey[10];
+									sprintf(subKey,"%d",context->currentOtherRecipeKey);
+									auto subStepList = context->subStepListMap.get(subKey);
+									if (subStepList != NULL) {
+										sprintf(sPreStepName, "Jump:%s", subStepList->get(preStepNo)->name);
+										SC->setStringValue(scName, sPreStepName);
+									}								
+									
+								}
+							}
+						}
+
+					}
+					else {
+						//超过限制次数
+						device->tryTimes = 0;
+						strcpy(OP->alarmText, EV->parseErrCode(ALARM_LEAK, "times=%d", device->tryTimes));
+						 
+						
+						AlarmCondition ac;
+						ac.alarmCommandEnum = device->leakCheckTable->ErrorCommandEnum;
+						ac.alarmCallRecipeIndex = device->leakCheckTable->ErrorCallRecipeIndex;
+						//ac.alarmJumpStepName = TODO None
+						ac.alarmJumpStepNo = device->leakCheckTable->ErrorJumpStepNo;
+						return device->doAlarmConditionAlarm(&ac);
+					}
+				}
+				return OperatorStatusEnum::SUCCESS;	//返回成功为了能顺利跳回上一步
+			}
+			else {
+				return OperatorStatusEnum::RUNNING;
+			}
+			
+		});
+	}
+}
+
+

+ 22 - 0
TIN001-PLC/Jet_Furance_PMC/Jet_Furance_PMC/Jet_Furance_PMC/FurancePMC/SetCommand.h

@@ -0,0 +1,22 @@
+#ifndef __SETCOMMAND_H__
+#define __SETCOMMAND_H__
+#include"TriggerStatus.h"
+#include"Fields.h"
+#include"pmc_types.h"
+#include "OP.h"
+#include"IoPressureMeter.h"
+#include"LeakCheck.h"
+class SetCommandModule :BaseDevice {
+public:
+	void initialize();
+	OperatorStatusEnum SetCommandModule::processLeakCheckErrorCommand(AlarmCondition *ac);
+public:
+	LeakCheck *leakCheckTable=NULL;
+	IoPressureMeter* sensor = NULL;
+	int leakCheckIndex = 0;
+	double beginPressure = 0;//̽²âµÄ³õʼѹÁ¦
+
+	int tryTimes = 0;
+};
+extern SetCommandModule* setCommandModule;
+#endif // !__SETCOMMAND_H__