Files
ENIG/Arduino_PLC/HmiClass.cpp
2025-01-07 16:07:58 +09:00

570 lines
15 KiB
C++

#include "IO.h"
#include "VarClass.h"
#include "HmiClass.h"
#include "UtilClass.h"
#include "motor.h"
#include "arduino.h"
unsigned long errtime = 0;
unsigned long eruntime = 0;
void HmiClass::Setup()
{
hmi.SendMessage("##:HMI:SETUP", false);
updatetime = millis();
ClearTempBuffer0();
ClearTempBuffer1();
}
void HmiClass::Update()
{
//데이터는 일정 주기로 전송한다.
unsigned long runtime = millis() - updatetime;
uint8_t loopterm = var._eep_iosendinterval;
loopterm = 500;
//설정 중에는 통신속도를 초당 10번으로 고정한다
if (var.getFlag(FLAG_SETUP) == true) loopterm = 100;
if (runtime > loopterm)
{
//IO상태전송
SendIOStatus();
//설정모드에서는 계속 전송 한다
if (var.getFlag(FLAG_SETUP) == true)
{
//EEP정보 전송
SendSetupInfo();
}
updatetime = millis();
}
//입력값 감지 190319
CheckReceiveS0();
CheckReceiveS1();
}
void HmiClass::SendIOStatus()
{
//전송데이터처리
byte payload[29]; //IO4바이트(uint32), A0~A3 A는 각 2바이트(uint16)
byte payidx = 0;
payload[payidx++] = '@'; //@
payload[payidx++] = '@'; //@
payload[payidx++] = 10; //데이터 길이
payload[payidx++] = 'I'; //49=I(IO)
payload[payidx++] = (byte)(var.IOData >> 0); //INPUT(16)
payload[payidx++] = (byte)(var.IOData >> 8); //OUTPUT(16)
payload[payidx++] = (byte)(var.IOData >> 16);
payload[payidx++] = (byte)(var.IOData >> 24);
uint32_t flagValue = var.getFlagValue();
payload[payidx++] = (byte)(flagValue >> 0); //FLAG (0~31)
payload[payidx++] = (byte)(flagValue >> 8);
payload[payidx++] = (byte)(flagValue >> 16);
payload[payidx++] = (byte)(flagValue >> 24);
//쓰레드진행시간
payload[payidx++] = (byte)var.runtime;
//checksum
byte checksum = 0;
for (int i = 3; i < payidx; i++)
checksum = checksum ^ payload[i];
payload[payidx++] = checksum;
payload[payidx++] = 0x0D;
payload[payidx++] = 0x0A;
//Serial.print("Send Payload len=");
//Serial.println(payidx);
hmiSerial.write(payload, payidx);
hmiSerial.flush();
//20190325 - 1번포트로 미러링
//dbgSerial.write(payload, sizeof(payload));
//dbgSerial.flush();
}
void HmiClass::SendSetupInfo()
{
//전송데이터처리
byte payload[19]; //IO4바이트(uint32), A0~A3 A는 각 2바이트(uint16)
byte payidx = 0;
payload[payidx++] = '@'; //@
payload[payidx++] = '@'; //@
payload[payidx++] = 5; //데이터 길이
payload[payidx++] = 'S'; //49=I(IO),T=TEXT,S=SETUP
payload[payidx++] = var._eep_iosendinterval;
payload[payidx++] = var._eep_resetcount;
payload[payidx++] = var._eep_pindir_iH;
payload[payidx++] = var._eep_pindir_iL;
//checksum
byte checksum = 0;
for (int i = 3; i < payidx; i++)
checksum = checksum ^ payload[i];
payload[payidx++] = checksum;
payload[payidx++] = 0x0D;
payload[payidx++] = 0x0A;
//Serial.print("Send Payload len=");
//Serial.println(sizeof(payload));
hmiSerial.write(payload, sizeof(payload));
hmiSerial.flush();
//20190325 - 1번포트로 미러링
//dbgSerial.write(payload, sizeof(payload));
//dbgSerial.flush();
}
void HmiClass::CheckReceiveS0()
{
//수신데이터가 있는경우에만 처리함
//bool newdata = hmiSerial.available() > 0;
//if (newdata) sprint(F("HMI Received Data ["));
while (hmiSerial.available() > 0) {
incomingByte0 = (char)(hmiSerial.read());
if (STX1S0 == false)
{
if (incomingByte0 != '@')
{
STX2S0 = false;
ETX1S0 = false;
SendMessage(F("ERROR:STX1"), true);
continue;
}
else
{
STX1S0 = true;
ClearTempBuffer0();
Tempbuffer1[bufferIndex0++] = incomingByte0; //Tempbuffer1 += incomingByte;
}
}
else if (STX2S0 == false)
{
if (bufferIndex0 != 1 || bufferIndex0 < 1 || Tempbuffer1[0] != '@' || incomingByte0 != '@')
{
STX1S0 = false;
ETX1S0 = false;
SendMessage(F("ERROR:STX2"), true);
continue;
}
else
{
STX2S0 = true;
Tempbuffer1[bufferIndex0++] = incomingByte0; //Tempbuffer1 += incomingByte;
}
}
else
{
Tempbuffer1[bufferIndex0++] = incomingByte0; //Tempbuffer1 += incomingByte;
//여기서부터는무조건 누적한다.
if (bufferIndex0 == 3)
{
if (Tempbuffer1[0] != 0x40 || Tempbuffer1[1] != '@')
{
STX1S0 = false;
STX2S0 = false;
ETX1S0 = false;
bufferIndex0 = 0; // = "";
}
else LEN1 = incomingByte0; //데이터 길이가온다
}
else if (bufferIndex0 == LEN1 + 2 + 1 + 1) //체크섬이 왔다
{
CHK1 = incomingByte0;
}
else if (bufferIndex0 == LEN1 + 2 + 1 + 1 + 1) //ETX1
{
if (incomingByte0 != 0x0D)
{
//ETX가 와야하는데 다른데이터가 왔다
STX1S0 = false;
STX2S0 = false;
ETX1S0 = false;
bufferIndex0 = 0;//
SendMessage(F("ERROR:STX3"), true);
}
}
else if (bufferIndex0 == LEN1 + 2 + 1 + 1 + 1 + 1)
{
//전체길이를 만족햇다.
if (incomingByte0 != 0x0A)
{
//ETX가 와야하는데 다른데이터가 왔다
STX1S0 = false;
STX2S0 = false;
ETX1S0 = false;
//Console.WriteLine("에러 모두 파기");
bufferIndex0 = 0;// == "";//.Clear();
SendMessage(F("ERROR:STX4"), true);
}
else
{
STX1S0 = false;
STX2S0 = false;
ETX1S0 = false;
//임시버퍼의 데이터를 수신데이터 변수에 넣는다
//memcpy(buffer.c_str(), Tempbuffer1.c_str(), sizeof(Tempbuffer1));
//Tempbuffer1.toCharArray()
//buffer = Tempbuffer1;
Parser(bufferIndex0);
bufferIndex0 = 0;
//Tempbuffer1[0] = 0; //첫비트에 nullstring 을 넣는다
//var.runCommand( parser(buffer1, addMsg1, 0);
}
}
}
////stx ,etx 는 hex 처리하고 번호와 값을 ascii처리함
//if (incomingByte == 0x02) buffer = "";
//else if (incomingByte == 0x03)
//{
// //ETX값이나 전체 길이가 4가아니라면 추가해야함
// uint8_t butNo = (uint8_t)(buffer.substring(0, 3).toInt());
// uint8_t butValue = (uint8_t)(buffer.substring(3, 4).toInt());
// //remote 명령과 공유하기 위해서 util로 이동
// var.runCommand((eCommand)butNo, butValue,0); //NewMsgEvent(butNo, butValue);
// break;
//}
//else{
// buffer += (char)incomingByte; //문자를 누적시킨다.
// if (buffer.length() > 10) {
// sprintln(F("HMI buffer Over error"));
// buffer = "";
// }
//}
}
//if (newdata) sprintln("]");
}
void HmiClass::CheckReceiveS1()
{
//수신데이터가 있는경우에만 처리함
//bool newdata = dbgSerial.available() > 0;
//if (newdata) sprint(F("HMI Received Data ["));
while (dbgSerial.available() > 0) {
incomingByte1 = (char)(dbgSerial.read());
if(incomingByte1 == 0x0A) //if newline
{
String cmd = "";
for(int i = 0 ; i < bufferIndex1;i++)
{
cmd += String((char)Tempbuffer1[i]);
}
if(cmd.equals("UP")||cmd.equals("up"))
{
Serial.println("User command : z-up");
mot.SetZRun(ZRUN_UP);
}
else if(cmd.equals("DN")||cmd.equals("dn"))
{
Serial.println("User command : z-down");
mot.SetZRun(ZRUN_DN);
}
else if(cmd.equals("STOP")||cmd.equals("stop"))
{
Serial.println("User command : z-stop");
mot.SetZRun(ZRUN_STOP);
}
else{
Serial.print("Unknown Command : ");
Serial.println(cmd);
}
bufferIndex1 = 0;
}
else if(bufferIndex1 > 99)
{
Serial.println(F("recv1 length error(>99"));
bufferIndex1 = 0;
}
else {
Tempbuffer1[bufferIndex1++] = incomingByte1; //Tempbuffer1 += incomingByte;
}
}
//if (newdata) sprintln("]");
}
/*
void HmiClass::CheckReceiveS1_Backup_221117()
{
//수신데이터가 있는경우에만 처리함
bool newdata = dbgSerial.available() > 0;
//if (newdata) sprint(F("HMI Received Data ["));
while (dbgSerial.available() > 0) {
incomingByte1 = (char)(dbgSerial.read());
if (STX1S1 == false)
{
if (incomingByte1 != '@')
{
STX2S1 = false;
ETX1S1 = false;
SendMessage(F("ERROR:STX1"), true);
continue;
}
else
{
STX1S1 = true;
ClearTempBuffer1();
Tempbuffer1[bufferIndex1++] = incomingByte1; //Tempbuffer1 += incomingByte;
}
}
else if (STX2S1 == false)
{
if (bufferIndex1 != 1 || bufferIndex1 < 1 || Tempbuffer1[0] != '@' || incomingByte1 != '@')
{
STX1S1 = false;
ETX1S1 = false;
SendMessage(F("ERROR:STX2"), true);
continue;
}
else
{
STX2S1 = true;
Tempbuffer1[bufferIndex1++] = incomingByte1; //Tempbuffer1 += incomingByte;
}
}
else
{
Tempbuffer1[bufferIndex1++] = incomingByte1; //Tempbuffer1 += incomingByte;
//여기서부터는무조건 누적한다.
if (bufferIndex1 == 3)
{
if (Tempbuffer1[0] != 0x40 || Tempbuffer1[1] != '@')
{
STX1S1 = false;
STX2S1 = false;
ETX1S1 = false;
bufferIndex1 = 0; // = "";
}
else LEN1 = incomingByte1; //데이터 길이가온다
}
else if (bufferIndex1 == LEN1 + 2 + 1 + 1) //체크섬이 왔다
{
CHK1 = incomingByte1;
}
else if (bufferIndex1 == LEN1 + 2 + 1 + 1 + 1) //ETX1
{
if (incomingByte1 != 0x0D)
{
//ETX가 와야하는데 다른데이터가 왔다
STX1S1 = false;
STX2S1 = false;
ETX1S1 = false;
bufferIndex1 = 0;//
SendMessage(F("ERROR:STX3"), true);
}
}
else if (bufferIndex1 == LEN1 + 2 + 1 + 1 + 1 + 1)
{
//전체길이를 만족햇다.
if (incomingByte1 != 0x0A)
{
//ETX가 와야하는데 다른데이터가 왔다
STX1S1 = false;
STX2S1 = false;
ETX1S1 = false;
//Console.WriteLine("에러 모두 파기");
bufferIndex1 = 0;// == "";//.Clear();
SendMessage(F("ERROR:STX4"), true);
}
else
{
STX1S1 = false;
STX2S1 = false;
ETX1S1 = false;
//임시버퍼의 데이터를 수신데이터 변수에 넣는다
//memcpy(buffer.c_str(), Tempbuffer1.c_str(), sizeof(Tempbuffer1));
//Tempbuffer1.toCharArray()
//buffer = Tempbuffer1;
Parser(bufferIndex1);
bufferIndex1 = 0;
//Tempbuffer1[0] = 0; //첫비트에 nullstring 을 넣는다
//var.runCommand( parser(buffer1, addMsg1, 0);
}
}
}
////stx ,etx 는 hex 처리하고 번호와 값을 ascii처리함
//if (incomingByte == 0x02) buffer = "";
//else if (incomingByte == 0x03)
//{
// //ETX값이나 전체 길이가 4가아니라면 추가해야함
// uint8_t butNo = (uint8_t)(buffer.substring(0, 3).toInt());
// uint8_t butValue = (uint8_t)(buffer.substring(3, 4).toInt());
// //remote 명령과 공유하기 위해서 util로 이동
// var.runCommand((eCommand)butNo, butValue,0); //NewMsgEvent(butNo, butValue);
// break;
//}
//else{
// buffer += (char)incomingByte; //문자를 누적시킨다.
// if (buffer.length() > 10) {
// sprintln(F("HMI buffer Over error"));
// buffer = "";
// }
//}
}
//if (newdata) sprintln("]");
}
*/
void HmiClass::Parser(byte bufferIndex)
{
Serial.println("Remote Command Parse");
//데이터를 분석해야 함
if (Tempbuffer1[0] == '@' && Tempbuffer1[1] == '@' &&
Tempbuffer1[bufferIndex - 2] == 0x0D && Tempbuffer1[bufferIndex - 1] == 0x0A)
{
byte len = Tempbuffer1[2];
byte chk = Tempbuffer1[len + 3];
if (bufferIndex != len + 6)
{
String msg = ("===>Frame length error len=");
msg += String(bufferIndex);
msg += (",receive=");
msg += String(len + 6);
SendMessage(msg, true);
}
else {
//체크섬확인
byte cs = 0;
for (int i = 3; i < (3 + len); i++)
cs = cs ^ Tempbuffer1[i];
if (chk != cs)
{
String msg = ("===>checksum error calc=");
msg.concat( String(cs));
msg.concat("receive=");
msg.concat(String(chk));
SendMessage(msg, true);
}
else {
//체크섬일치
byte command = Tempbuffer1[3];
byte param1 = Tempbuffer1[4];
byte param2 = Tempbuffer1[5];
var.runCommand((eCommand)command, param1, param2);
}
}
}
else {
//프레임이 이상하다.
//sprintln("===>Frame error stx, etx");
SendMessage("==>Frame error no stx,etx", true);
}
}
void HmiClass::ClearTempBuffer0()
{
LEN0 = 0;
bufferIndex0 = 0;
memcpy(Tempbuffer0, 0, sizeof(Tempbuffer0));
}
void HmiClass::ClearTempBuffer1()
{
LEN1 = 0;
bufferIndex1 = 0;
memcpy(Tempbuffer1, 0, sizeof(Tempbuffer1));
}
void HmiClass::SendMessage(String message, bool isError)
{
if(message.equals(hmimessage))
{
//동일메세지가 왓다면 1초이내로 다시 전송하지 못하게 한다.
if(hmimessagerepeat == 0 || hmimessagerepeat > millis())
hmimessagerepeat = millis();
hmimessagetime = millis()-hmimessagerepeat;
if(hmimessagetime < 999) return;
} else{
hmimessagerepeat = millis();
hmimessage = message;
}
// test = len 4 , totals 4+4=8
// @ @ 6 T 0 t e s t chk \r \n
byte totalLength = message.length() + 8;
byte payload[100]; //IO4바이트(uint32), A0~A3 A는 각 2바이트(uint16)
byte payidx = 0;
payload[payidx++] = '@'; //@
payload[payidx++] = '@'; //@
payload[payidx++] = message.length() + 2; //데이터 길이
payload[payidx++] = 'T';
payload[payidx++] = isError; //오류여부
for (int i = 0; i < message.length(); i++)
{
payload[payidx++] = message[i];
}
//checksum
byte checksum = 0;
for (int i = 3; i < (3 + message.length() + 2); i++)
checksum = checksum ^ payload[i];
payload[payidx++] = checksum;
payload[payidx++] = 0x0D;
payload[payidx++] = 0x0A;
hmiSerial.write(payload, totalLength);
hmiSerial.flush();
//20190325 - 1번포트로 미러링
dbgSerial.println(message);
//dbgSerial.write(message, message.length);
//dbgSerial.flush();
}
bool HmiClass::SendValue(char msg, uint32_t value)
{
byte totalLength = 11;
byte payload[100]; //IO4바이트(uint32), A0~A3 A는 각 2바이트(uint16)
byte payidx = 0;
payload[payidx++] = '@'; //@
payload[payidx++] = '@'; //@
payload[payidx++] = 6; //데이터 길이
payload[payidx++] = 'V';
payload[payidx++] = msg; //값종류
payload[payidx++] = (byte)(value >> 0);
payload[payidx++] = (byte)(value >> 8);
payload[payidx++] = (byte)(value >> 16);
payload[payidx++] = (byte)(value >> 24);
//checksum
byte checksum = 0;
for (int i = 3; i < (3 + 4 + 2); i++)
checksum = checksum ^ payload[i];
payload[payidx++] = checksum;
payload[payidx++] = 0x0D;
payload[payidx++] = 0x0C;
hmiSerial.write(payload, totalLength);
hmiSerial.flush();
//20190325 - 1번포트로 미러링
dbgSerial.write(payload, totalLength);
dbgSerial.flush();
}
HmiClass hmi;