|
@@ -2,9 +2,250 @@
|
|
|
#pragma hdrstop
|
|
|
#include"IoHeater.h"
|
|
|
#include"DEVICE.h"
|
|
|
+#include"OP.h"
|
|
|
+#include"EV.h"
|
|
|
+#include"SC.h"
|
|
|
+#include"errcode.h"
|
|
|
+#include"RecipeContext.h"
|
|
|
+#include"HeaterModule.h"
|
|
|
+#include"AlarmConditionModule.h"
|
|
|
+#include"pmc_types.h"
|
|
|
#include"debug.h"
|
|
|
+
|
|
|
+
|
|
|
IoHeater::IoHeater(const char* className,const char* name,const char* module):BaseDevice(className, name, module){
|
|
|
}
|
|
|
+void IoHeater::setAlarmConditionTable(const char* alarmConditionKey, const char* deviceName)
|
|
|
+{
|
|
|
+ //因为SetParameter和SetAlarmConditionTable这两个OP的执行顺序不定,可能会造成参数初始化不完整
|
|
|
+ //要求SetAlarmConditionTable先执行(可执行多次没问题)
|
|
|
+ this->alarmCondition = NULL;
|
|
|
+ if (alarmConditionModule->alarmConditionKey[0] != '\0') {
|
|
|
+
|
|
|
+ RecipeContext* context = RecipeContext::GetInstance();
|
|
|
+ if (context != NULL) {
|
|
|
+ auto indexNode = context->alarmConditionDic.get(alarmConditionKey);
|
|
|
+ if (indexNode != NULL) {
|
|
|
+ auto deviceNode = indexNode->get(deviceName);
|
|
|
+ if (deviceNode != NULL) {
|
|
|
+ this->alarmCondition = deviceNode;
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+void IoHeater::initialize()
|
|
|
+{
|
|
|
+ char opName[MAX_NAME_LEN];
|
|
|
+ sprintf(opName, "%s.SetParameters", this->id);
|
|
|
+ auto op = OP->subscribe(opName);
|
|
|
+ op->addExec([]()->OperatorStatusEnum {
|
|
|
+ OperatorNode* op = OP->currentRoot;
|
|
|
+ IoHeater* device = (IoHeater*)op->device;
|
|
|
+ //参数0:温区名称
|
|
|
+ //参数1:温度设置值
|
|
|
+
|
|
|
+ static char vName[MAX_NAME_LEN];
|
|
|
+
|
|
|
+ if (op->params.length <2) {
|
|
|
+ logger->error("%s:Not enough parameter:[%d]", op->name, op->params.length);
|
|
|
+ char* err = EV->parseErrCode(ALARM_OP_FAILED, "name=%s;reason=parameters missing;", op->name);
|
|
|
+ strcpy(OP->alarmText, err);
|
|
|
+ return OperatorStatusEnum::ALARM;
|
|
|
+ }
|
|
|
+ double temperature = 0;
|
|
|
+ if (strcmp_ignoreAa(op->params.get(0), "Continue") == 0) {
|
|
|
+ //TODO:保持原设置值不变,严格来说,这里的保持不变是与上一个step比较
|
|
|
+ //有可能上一个step被skip了,则当前step的设置值就不能不变,而是要读取上一个step的设置了
|
|
|
+ //实际工艺中大概这种情况不多见,暂不考虑
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ }
|
|
|
+ else if (SC->isVP(op->params.get(0))) {
|
|
|
+ static char vpName[MAX_NAME_LEN];
|
|
|
+ sprintf(vpName, "%s.RecipeEditParameter.TempSetting.%s.%s", MODULE_NAME, device->id, SC->getBaseName(op->params.get(1), ':'));
|
|
|
+ const char* vpValue = SC->getStringValue(vpName);
|
|
|
+ if (vpValue != NULL && vpValue[0] != '\0') {
|
|
|
+ temperature=atof(vpValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ temperature=atof(op->params.get(0));
|
|
|
+ }
|
|
|
+ double profileTCCalib = 0;
|
|
|
+ if (heaterModule->correctKey[0] != '\0') {
|
|
|
+ auto keyNode = RecipeContext::GetInstance()->tempCorrectionDic.get(heaterModule->correctKey);
|
|
|
+ if (keyNode != NULL) {
|
|
|
+ device->correct = keyNode->get(device->id);
|
|
|
+ profileTCCalib = device->correct->profileTCCalib;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ double setPointValue = temperature + profileTCCalib;
|
|
|
+ double feedBackValue = 0;
|
|
|
+ if (memcmp(heaterModule->controlMode, "Ou", 2) == 0) {
|
|
|
+ device->setPoint = &device->aoHeaterControlModeSetPoint;
|
|
|
+ device->setPoint->setDoubleValue(setPointValue);
|
|
|
+ device->feedBack = &device->aiHeaterPV;
|
|
|
+ feedBackValue = device->feedBack->getDoubleValue();
|
|
|
+ }else if (memcmp(heaterModule->controlMode, "In", 2) == 0) {
|
|
|
+ device->setPoint = &device->aoCascadeControlModeSetPoint;
|
|
|
+ device->setPoint->setDoubleValue(setPointValue);
|
|
|
+ device->feedBack = &device->aiCascadePV;
|
|
|
+ feedBackValue = device->feedBack->getDoubleValue();
|
|
|
+
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ //TODO:profile mode
|
|
|
+ }
|
|
|
+
|
|
|
+ double ramp = 0;
|
|
|
+ if (op->params.length >= 4) {
|
|
|
+ ramp = atof(op->params.get(3));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (op->params.length >= 17) {
|
|
|
+ if (strcmp_ignoreAa(op->params.get(15), "open") == 0) {
|
|
|
+ device->DPR = TRUE;
|
|
|
+ }
|
|
|
+ if (strcmp_ignoreAa(op->params.get(16), "open") == 0) {
|
|
|
+ device->BWR = TRUE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ double downRate = 0;
|
|
|
+ double upRate = 0;
|
|
|
+ double rampTime = 0;
|
|
|
+ if (device->DPR && device->BWR)
|
|
|
+ {
|
|
|
+ downRate = 0;
|
|
|
+ upRate = 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ const char* rampUnit = op->params.get(4);
|
|
|
+ if (rampUnit == NULL ||IS_ZERO(ramp))
|
|
|
+ {
|
|
|
+
|
|
|
+ downRate = FABS(setPointValue - feedBackValue);//单位是°C/min
|
|
|
+ upRate = FABS(feedBackValue - setPointValue);//单位是°C/min
|
|
|
+ }
|
|
|
+ else if (strcmp_ignoreAa(rampUnit, "time")==0)
|
|
|
+ {
|
|
|
+ downRate = FABS(feedBackValue - setPointValue) / ramp;//单位是°C/min
|
|
|
+ upRate = FABS(setPointValue - feedBackValue) / ramp;//单位是°C/min
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ downRate = ramp;//单位是°C/min
|
|
|
+ upRate = ramp;//单位是°C/min
|
|
|
+ }
|
|
|
+ }
|
|
|
+ device->aoUpRate.setDoubleValue(upRate);
|
|
|
+ device->aoDownRate.setDoubleValue(downRate);
|
|
|
+ if (op->params.length >= 8) {
|
|
|
+ //Heater相比MFC,waitHigh和waitLow要简单,就是以度数为单位不需要换算
|
|
|
+ device->waitHigh = atof(op->params.get(6));
|
|
|
+ device->waitLow = atof(op->params.get(7));
|
|
|
+ }
|
|
|
+ //设置时间
|
|
|
+ //从alarm condition 中取delay time和trigger time(check time)
|
|
|
+ device->setAlarmConditionTable(alarmConditionModule->alarmConditionKey, device->id);
|
|
|
+ if (device->alarmCondition == NULL) {
|
|
|
+ op->setTimes(TIME_DELAY_DEFAULT, TIME_STABLE_DEFAULT, TIME_ALARM_DEFAULT, 0);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ op->setTimes(device->alarmCondition->alarmDelayDetectTimeS * 1000, TIME_STABLE_DEFAULT, device->alarmCondition->alarmCheckTime, 0);
|
|
|
+ }
|
|
|
+ return OperatorStatusEnum::RUNNING;
|
|
|
+ });
|
|
|
+ op->addCheck([]()->OperatorStatusEnum {
|
|
|
+ OperatorNode* op = OP->currentRoot;
|
|
|
+ IoHeater* device = (IoHeater*)op->device;
|
|
|
+ if (IS_ZERO(device->waitHigh) || IS_ZERO(device->waitLow)) {
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ }
|
|
|
+ if (device->setPoint == NULL || device->feedBack == NULL) {
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ }
|
|
|
+ double high = device->waitHigh + device->setPoint->getDoubleValue();
|
|
|
+ double low = -device->waitLow + device->setPoint->getDoubleValue();
|
|
|
+ if (device->feedBack->getDoubleValue() >= low && device->feedBack->getDoubleValue() <= high) {
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ }
|
|
|
+ if (op->isTimeout.value) {
|
|
|
+ if (device->isWait) {
|
|
|
+ //需要wait
|
|
|
+ if (op->isTimeout.trigger()) {
|
|
|
+ //第一次超时,打印个日志
|
|
|
+ logger->error("%s:wait time out", op->name);
|
|
|
+ char* err = EV->parseErrCode(WARNING_WAIT_TIMEOUT, "name=%s", device->id);
|
|
|
+ EV->postWarningLog(err);
|
|
|
+ op->isTimeout.clearTrigger();
|
|
|
+
|
|
|
+ }
|
|
|
+ return OperatorStatusEnum::RUNNING;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (op->isTimeout.trigger()) {
|
|
|
+ //第一次超时,打印个日志
|
|
|
+ logger->error("%s:wait time out", op->name);
|
|
|
+ char* err = EV->parseErrCode(WARNING_WAIT_TIMEOUT, "name=%s", device->id);
|
|
|
+ EV->postWarningLog(err);
|
|
|
+ op->isTimeout.clearTrigger();
|
|
|
+
|
|
|
+ }
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return OperatorStatusEnum::RUNNING;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ op->addAlarmCheck([]()->OperatorStatusEnum {
|
|
|
+ OperatorNode* op = OP->currentRoot;
|
|
|
+ IoHeater* device = (IoHeater*)op->device;
|
|
|
+ if (device->alarmCondition == NULL) {
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ }
|
|
|
+ if (IS_ZERO(device->alarmCondition->alarmHigh) || IS_ZERO(device->alarmCondition->alarmLow)) {
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ }
|
|
|
+ if (device->setPoint == NULL || device->feedBack == NULL) {
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ }
|
|
|
+ double high = device->alarmCondition->alarmHigh + device->setPoint->getDoubleValue();
|
|
|
+ double low = -device->alarmCondition->alarmLow + device->setPoint->getDoubleValue();
|
|
|
+ if (device->feedBack->getDoubleValue() >= low && device->feedBack->getDoubleValue() <= high) {
|
|
|
+ double warningHigh = device->alarmCondition->warningHigh + device->setPoint->getDoubleValue();
|
|
|
+ double warningLow = -device->alarmCondition->warningLow + device->setPoint->getDoubleValue();
|
|
|
+ if (device->feedBack->getDoubleValue() >= warningLow && device->feedBack->getDoubleValue() <= warningHigh) {
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ logger->error("%s:alarm condition[%f][%f][%f] warning", op->name, warningLow, device->feedBack->getBoolValue(), warningHigh);
|
|
|
+ char* err = EV->parseErrCode(WARNING_CONDITION_TRIGGER, "name=%s;", device->id);
|
|
|
+ strcpy(OP->alarmText, err);
|
|
|
+ return OperatorStatusEnum::WARNING;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ logger->error("%s:alarm condition[%f][%f][%f] error", op->name, low, device->feedBack->getBoolValue(), high);
|
|
|
+ char* err = EV->parseErrCode(ALARM_CONDITION_TRIGGER, "name=%s;", device->id);
|
|
|
+ strcpy(OP->alarmText, err);
|
|
|
+ return OperatorStatusEnum::ALARM;
|
|
|
+ }
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ });
|
|
|
+ op->addAlarmCallback([]()->OperatorStatusEnum {
|
|
|
+ OperatorNode* op = OP->currentRoot;
|
|
|
+ IoHeater* device = (IoHeater*)op->device;
|
|
|
+ if (device->alarmCondition == NULL) {
|
|
|
+ return OperatorStatusEnum::ALARM;
|
|
|
+ }
|
|
|
+ //TODO
|
|
|
+ return OperatorStatusEnum::SUCCESS;
|
|
|
+ });
|
|
|
+}
|
|
|
//AUTOIO_BEGIN
|
|
|
IoHeater* _initHeaterSUB_0(){
|
|
|
static IoHeater staticHeaterSUB("IoHeater","HeaterSUB",MODULE_NAME);
|