파일정리
This commit is contained in:
605
HMI/Project/Device/BMS.cs
Normal file
605
HMI/Project/Device/BMS.cs
Normal file
@@ -0,0 +1,605 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.CodeDom;
|
||||
|
||||
namespace arDev
|
||||
{
|
||||
public class BMSCellInformation
|
||||
{
|
||||
public float[] Voltage = new float[8];
|
||||
public float Average
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Voltage.Any() == false) return 0f;
|
||||
return Voltage.Average();
|
||||
}
|
||||
}
|
||||
public float Delta
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Voltage.Any() == false) return 0f;
|
||||
var value = Math.Abs(Voltage.Max() - Voltage.Min());
|
||||
return value * 1000f;
|
||||
}
|
||||
}
|
||||
}
|
||||
public class BMSBasicInformation
|
||||
{
|
||||
public float packVoltage { get; set; }
|
||||
public float current { get; set; }
|
||||
public float remainingCapacity { get; set; }
|
||||
public float fullCapacity { get; set; }
|
||||
public UInt16 cycleCount { get; set; }
|
||||
public DateTime productionDate { get; set; }
|
||||
public UInt32 fullBalance { get; set; }
|
||||
public BMSProtectionStatus protectionStatus { get; set; }
|
||||
public byte version { get; set; }
|
||||
public byte rsoc { get; set; }
|
||||
public BMSMosfetStatus mosfetStatus { get; set; }
|
||||
public byte ntcCount { get; set; }
|
||||
public float[] ntcTemp { get; set; }
|
||||
|
||||
public ushort raw_protection { get; set; }
|
||||
public float watt
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.current * packVoltage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remain / Full * 100
|
||||
/// </summary>
|
||||
public float RawLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fullCapacity < 1) return 0f;
|
||||
return (remainingCapacity / fullCapacity) * 100f;
|
||||
}
|
||||
}
|
||||
|
||||
public BMSBasicInformation()
|
||||
{
|
||||
protectionStatus = new BMSProtectionStatus();
|
||||
mosfetStatus = new BMSMosfetStatus();
|
||||
productionDate = new DateTime();
|
||||
ntcTemp = new float[] { 0f, 0f };
|
||||
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
packVoltage = 0;
|
||||
current = 0;
|
||||
remainingCapacity = 0;
|
||||
fullBalance = 0;
|
||||
fullCapacity = 0;
|
||||
cycleCount = 0;
|
||||
productionDate = new DateTime();
|
||||
protectionStatus = new BMSProtectionStatus();
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"packVoltage:{packVoltage}\n" +
|
||||
$"current:{current}\n" +
|
||||
$"remainingCapacity:{remainingCapacity}\n" +
|
||||
$"fullCapacity:{fullCapacity}\n" +
|
||||
$"cycleCount:{cycleCount}\n" +
|
||||
$"productionDate:{productionDate}\n" +
|
||||
$"fullBalance:{fullBalance}\n" +
|
||||
$"protectionStatus:{protectionStatus}\n" +
|
||||
$"version:{version}\n" +
|
||||
$"rsoc:{rsoc}\n" +
|
||||
$"mosfetStatus:{mosfetStatus}\n" +
|
||||
$"ntcCount:{ntcCount}\n" +
|
||||
$"ntcTemp:{ntcTemp}\n" +
|
||||
$"watt:{watt}\n" +
|
||||
$"RawLevel:{RawLevel}";
|
||||
}
|
||||
}
|
||||
public class BMSProtectionStatus
|
||||
{
|
||||
public bool covp { get; set; }// Cell Over Voltage Protection
|
||||
public bool cuvp { get; set; } // Cell Under Voltage Protection
|
||||
public bool povp { get; set; } // Pack Over Voltage Protection
|
||||
public bool puvp { get; set; } // Pack Under Voltage Protection
|
||||
public bool chgot { get; set; }// Charge Over Temp
|
||||
public bool chgut { get; set; } // Charge Under Temp
|
||||
public bool dsgot { get; set; } // Discharge Over Temp
|
||||
public bool dsgut { get; set; } // Discharge Under Temp
|
||||
public bool chgoc { get; set; } // Charge Over Current
|
||||
public bool dsgoc { get; set; } // Discharge Over Current
|
||||
public bool sc { get; set; } // Short Circuit
|
||||
public bool afe { get; set; } // AFE Error
|
||||
public override string ToString()
|
||||
{
|
||||
return "BMSProtectionStatus\n" +
|
||||
$"covp={covp}\n" +// { get; set; }// Cell Over Voltage Protection
|
||||
$"cuvp={cuvp}\n" +// { get; set; } // Cell Under Voltage Protection
|
||||
$"povp={povp}\n" +// { get; set; } // Pack Over Voltage Protection
|
||||
$"puvp={puvp}\n" +// { get; set; } // Pack Under Voltage Protection
|
||||
$"chgot={chgot}\n" +// { get; set; }// Charge Over Temp
|
||||
$"chgut={chgut}\n" +// { get; set; } // Charge Under Temp
|
||||
$"dsgot={dsgot}\n" +// { get; set; } // Discharge Over Temp
|
||||
$"dsgut={dsgut}\n" +// { get; set; } // Discharge Under Temp
|
||||
$"chgoc={chgoc}\n" +// { get; set; } // Charge Over Current
|
||||
$"dsgoc={dsgoc}\n" +// { get; set; } // Discharge Over Current
|
||||
$"sc={sc}\n" +// { get; set; } // Short Circuit
|
||||
$"afe={afe}";// +// { get; set; } // AFE Error
|
||||
}
|
||||
}
|
||||
public class BMSMosfetStatus
|
||||
{
|
||||
public bool charge { get; set; }
|
||||
public bool discharge { get; set; }
|
||||
public override string ToString()
|
||||
{
|
||||
return $"charge:{charge}\n" +
|
||||
$"discharge:{discharge}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class BMS : BMSSerialComm
|
||||
{
|
||||
public BMS()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 시리얼포트의 핀 상태값이 변경될 때 발생합니다.
|
||||
/// </summary>
|
||||
public event EventHandler<BMSInformationEventArgs> BMSDataReceive;
|
||||
public event EventHandler<BMSCelvoltageEventArgs> BMSCellDataReceive;
|
||||
|
||||
protected override bool CustomParser(byte[] buf, out byte[] remainBuffer)
|
||||
{
|
||||
List<byte> remain = new List<byte>();
|
||||
|
||||
//데이터는 총 34byt 이며 , DD~77로 구성됨
|
||||
Boolean bComplete = false;
|
||||
for (int i = 0; i < buf.Length; i++)
|
||||
{
|
||||
var incomByte = buf[i];
|
||||
if (bComplete == true)
|
||||
{
|
||||
remain.Add(incomByte);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (findSTX == false)
|
||||
{
|
||||
if (incomByte != 0xDD)
|
||||
{
|
||||
//버리는데이터
|
||||
}
|
||||
else
|
||||
{
|
||||
findSTX = true;
|
||||
tempBuffer.Clear();
|
||||
tempBuffer.Add(incomByte);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer.Add(incomByte);
|
||||
|
||||
if (tempBuffer.Count > 7)
|
||||
{
|
||||
byte len = tempBuffer[3];
|
||||
if (tempBuffer.Count >= 4 + len + 3) // Start+Reg+Status+Len + Data + Chk(2) + End
|
||||
{
|
||||
if (tempBuffer.Last() == 0x77)
|
||||
{
|
||||
//데이터가 맞게 수신됨
|
||||
LastReceiveBuffer = tempBuffer.ToArray();
|
||||
bComplete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//종단기호가 맞지 않다. 이자료는 폐기한다.
|
||||
var hexstr = string.Join(" ", tempBuffer.Select(t => t.ToString("X2")));
|
||||
RaiseMessage(MessageType.Error, $"discard : {hexstr}");
|
||||
tempBuffer.Clear();
|
||||
}
|
||||
findSTX = false;
|
||||
}
|
||||
}
|
||||
|
||||
// [22 - 12 - 27 14:32:49] open: True
|
||||
//[22 - 12 - 27 14:32:49] Send: DD A5 03 00 FF FD 77 0D
|
||||
//[22 - 12 - 27 14:32:50] Send: DD A5 03 00 FF FD 77 0D
|
||||
//[22 - 12 - 27 14:32:50] Recv: 26.61v,81.4 %
|
||||
//[22 - 12 - 27 14:32:50] Recv: DD 03 00 1B 0A 65 00 00 21 63 29 04 00 00 2C 92 00 00 00 00 00 00 28 51 03 08 02 0B 69 0B 66 FC 9C 77
|
||||
//[22 - 12 - 27 14:32:50] Send: DD A5 03 00 FF FD 77 0D
|
||||
//[22 - 12 - 27 14:32:51] Recv: 26.61v,81.4 %
|
||||
//[22 - 12 - 27 14:32:51] Recv: DD 03 00 1B 0A 65 00 00 21 63 29 04 00 00 2C 92 00 00 00 00 00 00 28 51 03 08 02 0B 69 0B 66 FC 9C 77
|
||||
|
||||
|
||||
//var queylen = QueryIndex == 0 ? 34 : 23;
|
||||
//if (tempBuffer.Count == queylen)
|
||||
//{
|
||||
// if (incomByte != 0x77)
|
||||
// {
|
||||
// //종단기호가 맞지 않다. 이자료는 폐기한다.
|
||||
// var hexstr = string.Join(" ", tempBuffer.Select(t => t.ToString("X2")));
|
||||
// RaiseMessage(MessageType.Error, $"discard : {hexstr}");
|
||||
// tempBuffer.Clear();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //데이터가 맞게 수신됨
|
||||
// LastReceiveBuffer = tempBuffer.ToArray();
|
||||
// bComplete = true;
|
||||
// }
|
||||
// findSTX = false;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// //아직 모자르므로 대기한다
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remainBuffer = remain.ToArray();
|
||||
return bComplete;
|
||||
}
|
||||
|
||||
bool Recv0 = false;
|
||||
bool Recv1 = false;
|
||||
public event EventHandler<ChargetDetectArgs> ChargeDetect;
|
||||
public override bool ProcessRecvData(byte[] data)
|
||||
{
|
||||
//LastReceiveBuffer
|
||||
if (data == null)
|
||||
{
|
||||
RaiseMessage(MessageType.Error, "수신 데이터가 없습니다");
|
||||
return false;
|
||||
}
|
||||
|
||||
var datalne = QueryIndex == 0 ? 34 : 23;
|
||||
if (data.Length != datalne)
|
||||
{
|
||||
RaiseMessage(MessageType.Error, $"데이터의 길이가 {MinRecvLength}가 아닙니다 길이={data.Length}");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var rxstr = string.Join(" ", data.Select(t => t.ToString("X2")));
|
||||
RaiseMessage(MessageType.Recv, rxstr);
|
||||
}
|
||||
|
||||
if (QueryIndex == 0)
|
||||
{
|
||||
return ParseBMSInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
return ParseBMSCellVoltage();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
bool ParseBMSCellVoltage()
|
||||
{
|
||||
//var i = 0;
|
||||
var BatteryCell_Checksum = 0xffff;// - (LastReceiveBuffer[i + 3] + LastReceiveBuffer[i + 4] + LastReceiveBuffer[i + 5] + LastReceiveBuffer[i + 6] + LastReceiveBuffer[i + 7] + LastReceiveBuffer[i + 8] + LastReceiveBuffer[i + 9] + LastReceiveBuffer[i + 10] + LastReceiveBuffer[i + 11] + LastReceiveBuffer[i + 12] + LastReceiveBuffer[i + 13] + LastReceiveBuffer[i + 14] + LastReceiveBuffer[i + 15] + LastReceiveBuffer[i + 16] + LastReceiveBuffer[i + 17] + LastReceiveBuffer[i + 18] + LastReceiveBuffer[i + 19])) + 1;
|
||||
for (int i = 3; i < 20; i++)
|
||||
{
|
||||
BatteryCell_Checksum -= LastReceiveBuffer[i];// + LastReceiveBuffer[i + 4] + LastReceiveBuffer[i + 5] + LastReceiveBuffer[i + 6] + LastReceiveBuffer[i + 7] + LastReceiveBuffer[i + 8] + LastReceiveBuffer[i + 9] + LastReceiveBuffer[i + 10] + LastReceiveBuffer[i + 11] + LastReceiveBuffer[i + 12] + LastReceiveBuffer[i + 13] + LastReceiveBuffer[i + 14] + LastReceiveBuffer[i + 15] + LastReceiveBuffer[i + 16] + LastReceiveBuffer[i + 17] + LastReceiveBuffer[i + 18] + LastReceiveBuffer[i + 19])) + 1;
|
||||
}
|
||||
|
||||
BatteryCell_Checksum += 1;
|
||||
var recvchecksum = BitConverter.ToUInt16(LastReceiveBuffer.Skip(20).Take(2).Reverse().ToArray(), 0);
|
||||
if (recvchecksum == BatteryCell_Checksum)
|
||||
{
|
||||
var v1 = BitConverter.ToUInt16(LastReceiveBuffer.Skip(4).Take(2).Reverse().ToArray(), 0) / 1000f;
|
||||
var v2 = BitConverter.ToUInt16(LastReceiveBuffer.Skip(6).Take(2).Reverse().ToArray(), 0) / 1000f;
|
||||
var v3 = BitConverter.ToUInt16(LastReceiveBuffer.Skip(8).Take(2).Reverse().ToArray(), 0) / 1000f;
|
||||
var v4 = BitConverter.ToUInt16(LastReceiveBuffer.Skip(10).Take(2).Reverse().ToArray(), 0) / 1000f;
|
||||
var v5 = BitConverter.ToUInt16(LastReceiveBuffer.Skip(12).Take(2).Reverse().ToArray(), 0) / 1000f;
|
||||
var v6 = BitConverter.ToUInt16(LastReceiveBuffer.Skip(14).Take(2).Reverse().ToArray(), 0) / 1000f;
|
||||
var v7 = BitConverter.ToUInt16(LastReceiveBuffer.Skip(16).Take(2).Reverse().ToArray(), 0) / 1000f;
|
||||
var v8 = BitConverter.ToUInt16(LastReceiveBuffer.Skip(18).Take(2).Reverse().ToArray(), 0) / 1000f;
|
||||
|
||||
var idx = 0;
|
||||
BMSCellVoltage.Voltage[idx++] = v1;
|
||||
BMSCellVoltage.Voltage[idx++] = v2;
|
||||
BMSCellVoltage.Voltage[idx++] = v3;
|
||||
BMSCellVoltage.Voltage[idx++] = v4;
|
||||
BMSCellVoltage.Voltage[idx++] = v5;
|
||||
BMSCellVoltage.Voltage[idx++] = v6;
|
||||
BMSCellVoltage.Voltage[idx++] = v7;
|
||||
BMSCellVoltage.Voltage[idx++] = v8;
|
||||
|
||||
Recv1 = true;
|
||||
|
||||
try
|
||||
{
|
||||
BMSCellDataReceive?.Invoke(this, new BMSCelvoltageEventArgs(v1, v2, v3, v4, v5, v6, v7, v8));
|
||||
Current_CellTime = DateTime.Now;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
RaiseMessage(MessageType.Error, ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
bool ParseBMSInfo()
|
||||
{
|
||||
var newinfo = new BMSBasicInformation();
|
||||
|
||||
//전압확인
|
||||
var offset = 4;
|
||||
UInt16 batH = (UInt16)LastReceiveBuffer[offset + 0];
|
||||
UInt16 batL = (UInt16)LastReceiveBuffer[offset + 1];
|
||||
batH = (UInt16)(batH << 8);
|
||||
batH = (UInt16)(batH | batL);
|
||||
newinfo.packVoltage = (float)(batH / 100.0);
|
||||
|
||||
//충방전전류
|
||||
Int16 batHi = (Int16)LastReceiveBuffer[offset + 2];
|
||||
Int16 batLi = (Int16)LastReceiveBuffer[offset + 3];
|
||||
batHi = (Int16)(batHi << 8);
|
||||
batHi = (Int16)(batHi | batLi);
|
||||
newinfo.current = (float)(batHi / 100.0);
|
||||
|
||||
//잔량확인
|
||||
batH = (UInt16)LastReceiveBuffer[offset + 4];
|
||||
batL = (UInt16)LastReceiveBuffer[offset + 5];
|
||||
batH = (UInt16)(batH << 8);
|
||||
batH = (UInt16)(batH | batL);
|
||||
newinfo.remainingCapacity = (float)(batH / 100.0);
|
||||
|
||||
//총량확인
|
||||
batH = (UInt16)LastReceiveBuffer[offset + 6];
|
||||
batL = (UInt16)LastReceiveBuffer[offset + 7];
|
||||
batH = (UInt16)(batH << 8);
|
||||
batH = (UInt16)(batH | batL);
|
||||
newinfo.fullCapacity = (float)(batH / 100.0);
|
||||
|
||||
//cycle
|
||||
batH = (UInt16)LastReceiveBuffer[offset + 8];
|
||||
batL = (UInt16)LastReceiveBuffer[offset + 9];
|
||||
batH = (UInt16)(batH << 8);
|
||||
batH = (UInt16)(batH | batL);
|
||||
newinfo.cycleCount = batH;
|
||||
|
||||
//productiondate
|
||||
batH = (UInt16)LastReceiveBuffer[offset + 10];
|
||||
batL = (UInt16)LastReceiveBuffer[offset + 11];
|
||||
batH = (UInt16)(batH << 8);
|
||||
batH = (UInt16)(batH | batL);
|
||||
var info_productiondateint = batH;
|
||||
var date_year = (info_productiondateint >> 9) + 2000;
|
||||
var date_month = (info_productiondateint >> 5) & 0x0F;
|
||||
var date_day = info_productiondateint & 0x1F;
|
||||
newinfo.productionDate = new DateTime(date_year, date_month, date_day);
|
||||
|
||||
//balnace status
|
||||
batH = (UInt16)LastReceiveBuffer[offset + 12];
|
||||
batL = (UInt16)LastReceiveBuffer[offset + 13];
|
||||
batH = (UInt16)(batH << 8);
|
||||
var balanceStatus = (UInt16)(batH | batL);
|
||||
|
||||
//balnace status(HIGH)
|
||||
batH = (UInt16)LastReceiveBuffer[offset + 14];
|
||||
batL = (UInt16)LastReceiveBuffer[offset + 15];
|
||||
batH = (UInt16)(batH << 8);
|
||||
var balanceStatusHigh = (UInt16)(batH | batL);
|
||||
newinfo.fullBalance = (UInt32)(balanceStatus | (balanceStatusHigh << 16));
|
||||
|
||||
//protectionStatusRaw
|
||||
batH = (UInt16)LastReceiveBuffer[offset + 16];
|
||||
batL = (UInt16)LastReceiveBuffer[offset + 17];
|
||||
batH = (UInt16)(batH << 8);
|
||||
newinfo.raw_protection = batH;// view.getUint16(16, false);
|
||||
var protectionStatusRaw = newinfo.raw_protection;
|
||||
newinfo.protectionStatus.covp = (protectionStatusRaw & 1) > 0;
|
||||
newinfo.protectionStatus.cuvp = ((protectionStatusRaw >> 1) & 1) > 0;
|
||||
newinfo.protectionStatus.povp = ((protectionStatusRaw >> 2) & 1) > 0;
|
||||
newinfo.protectionStatus.puvp = ((protectionStatusRaw >> 3) & 1) > 0;
|
||||
newinfo.protectionStatus.chgot = ((protectionStatusRaw >> 4) & 1) > 0;
|
||||
newinfo.protectionStatus.chgut = ((protectionStatusRaw >> 5) & 1) > 0;
|
||||
newinfo.protectionStatus.dsgot = ((protectionStatusRaw >> 6) & 1) > 0;
|
||||
newinfo.protectionStatus.dsgut = ((protectionStatusRaw >> 7) & 1) > 0;
|
||||
newinfo.protectionStatus.chgoc = ((protectionStatusRaw >> 8) & 1) > 0;
|
||||
newinfo.protectionStatus.dsgoc = ((protectionStatusRaw >> 9) & 1) > 0;
|
||||
newinfo.protectionStatus.sc = ((protectionStatusRaw >> 10) & 1) > 0;
|
||||
newinfo.protectionStatus.afe = ((protectionStatusRaw >> 11) & 1) > 0;
|
||||
|
||||
|
||||
//version
|
||||
newinfo.version = LastReceiveBuffer[offset + 18];
|
||||
newinfo.rsoc = LastReceiveBuffer[offset + 19];
|
||||
var mosfetRaw = LastReceiveBuffer[offset + 20];
|
||||
newinfo.mosfetStatus.charge = (mosfetRaw & 1) == 1;
|
||||
newinfo.mosfetStatus.discharge = ((mosfetRaw >> 1) & 1) == 1;
|
||||
|
||||
|
||||
//250620 jwlee 추가
|
||||
newinfo.ntcCount = LastReceiveBuffer[offset + 22]; //센서갯수
|
||||
int temp1 = (LastReceiveBuffer[offset + 23] << 8) | LastReceiveBuffer[offset + 24];
|
||||
int temp2 = (LastReceiveBuffer[offset + 25] << 8) | LastReceiveBuffer[offset + 26];
|
||||
var Current_temp1 = (temp1 - 2731) / 10f;
|
||||
var Current_temp2 = (temp2 - 2731) / 10f;
|
||||
newinfo.ntcTemp = new float[] { (temp1 - 2731) / 10f, (temp2 - 2731) / 10f };
|
||||
|
||||
CheckManualCharge(newinfo);
|
||||
|
||||
Recv0 = true;
|
||||
|
||||
try
|
||||
{
|
||||
this.BMSInformation = newinfo;
|
||||
BMSDataReceive?.Invoke(this, new BMSInformationEventArgs(BMSInformation));
|
||||
Current_DataTime = DateTime.Now;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
RaiseMessage(MessageType.Error, ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public BMSBasicInformation BMSInformation = new BMSBasicInformation();
|
||||
public BMSCellInformation BMSCellVoltage = new BMSCellInformation();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 현재 충전중인지?
|
||||
/// </summary>
|
||||
public bool IsCharging { get; private set; }
|
||||
DateTime ChargeStart = DateTime.Now;
|
||||
DateTime ChargeEnd = DateTime.Now;
|
||||
void CheckManualCharge(BMSBasicInformation info)
|
||||
{
|
||||
//충방전전력이 1보다 크면 충전으로 한다.
|
||||
if (this.BMSInformation.current > 0.1)
|
||||
{
|
||||
//기존에 충전상태가 OFF였다면 충전중으로 알려준다
|
||||
if (IsCharging == false)
|
||||
{
|
||||
IsCharging = true;
|
||||
ChargeStart = DateTime.Now;
|
||||
ChargeEnd = new DateTime(1982, 11, 23);
|
||||
try
|
||||
{
|
||||
ChargeDetect?.Invoke(this, new ChargetDetectArgs(ChargeStart, true, info.RawLevel));
|
||||
}
|
||||
catch (Exception ex) { RaiseMessage(MessageType.Error, ex.Message); }
|
||||
}
|
||||
else
|
||||
{
|
||||
//충전상태가 유지되고 있다.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//충전이해제되었다.. 단 바로 해제하지않고 1초정도 텀을 주고 OFF한다.
|
||||
if (IsCharging)
|
||||
{
|
||||
if (ChargeEnd.Year == 1982)
|
||||
{
|
||||
ChargeEnd = DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ts = DateTime.Now - ChargeEnd;
|
||||
if (ts.TotalSeconds > 2) //충전종료시그널후 2초후에 충전off를 알린다.
|
||||
{
|
||||
ChargeEnd = DateTime.Now;
|
||||
IsCharging = false;
|
||||
try
|
||||
{
|
||||
ChargeDetect?.Invoke(this, new ChargetDetectArgs(ChargeEnd, false, info.RawLevel));
|
||||
}
|
||||
catch (Exception ex) { RaiseMessage(MessageType.Error, ex.Message); }
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//방전상태가 유지되고 있다.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public DateTime chk_times { get; set; } = new DateTime(1982, 11, 23);
|
||||
public DateTime chk_timee { get; set; } = new DateTime(1982, 11, 23);
|
||||
public float chk_values { get; set; } = 0f;
|
||||
public float chk_valuee { get; set; } = 0f;
|
||||
public DateTime Current_DataTime = DateTime.Parse("1982-11-23");
|
||||
public DateTime Current_CellTime = DateTime.Parse("1982-11-23");
|
||||
|
||||
public int QueryIndex { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 상태읽기와 전압읽기명령을 반복합니다
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Boolean SendQuery()
|
||||
{
|
||||
if (QueryIndex == 0)
|
||||
{
|
||||
if (Recv0 == true)
|
||||
{
|
||||
QueryIndex = 1;
|
||||
Recv1 = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SendQuery_ReadStatue();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Recv1 == true)
|
||||
{
|
||||
QueryIndex = 0;
|
||||
Recv0 = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SendQuery_ReadCellvoltage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean SendQuery_ReadStatue()
|
||||
{
|
||||
Recv0 = false;
|
||||
var cmd = new List<byte>();
|
||||
cmd.Add(0xDD);
|
||||
cmd.Add(0xA5);
|
||||
cmd.Add(0x03);
|
||||
cmd.Add(0x00);
|
||||
cmd.Add(0xFF);
|
||||
cmd.Add(0xFD);
|
||||
cmd.Add(0x77);
|
||||
//cmd.Add(0x0D);
|
||||
//_device.DiscardInBuffer();
|
||||
return WriteData(cmd.ToArray());
|
||||
}
|
||||
|
||||
|
||||
public Boolean SendQuery_ReadCellvoltage()
|
||||
{
|
||||
Recv1 = false;
|
||||
var cmd = new List<byte>();
|
||||
cmd.Add(0xDD);
|
||||
cmd.Add(0xA5);
|
||||
cmd.Add(0x04);
|
||||
cmd.Add(0x00);
|
||||
cmd.Add(0xFF);
|
||||
cmd.Add(0xFC);
|
||||
cmd.Add(0x77);
|
||||
//cmd.Add(0x0D);
|
||||
//_device.DiscardInBuffer();
|
||||
return WriteData(cmd.ToArray());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
39
HMI/Project/Device/BMSInformationEventArgs.cs
Normal file
39
HMI/Project/Device/BMSInformationEventArgs.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace arDev
|
||||
{
|
||||
public class ChargetDetectArgs : EventArgs
|
||||
{
|
||||
public DateTime time { get; set; }
|
||||
public float level { get; set; }
|
||||
public bool Detected { get; set; }
|
||||
public ChargetDetectArgs(DateTime times, bool detected, float values)
|
||||
{
|
||||
this.time = times;
|
||||
this.level = values;
|
||||
this.Detected = detected;
|
||||
}
|
||||
}
|
||||
public class BMSInformationEventArgs : EventArgs
|
||||
{
|
||||
public BMSBasicInformation Data { get; set; }
|
||||
public BMSInformationEventArgs(BMSBasicInformation info)
|
||||
{
|
||||
this.Data = info;
|
||||
}
|
||||
}
|
||||
|
||||
public class BMSCelvoltageEventArgs : EventArgs
|
||||
{
|
||||
public double[] voltage;
|
||||
public BMSCelvoltageEventArgs(double v1, double v2, double v3, double v4, double v5, double v6, double v7, double v8)
|
||||
{
|
||||
voltage = new double[] { v1, v2, v3, v4, v5, v6, v7, v8 };
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join(" ", voltage.Select(t => t.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
607
HMI/Project/Device/BMSSerialComm.cs
Normal file
607
HMI/Project/Device/BMSSerialComm.cs
Normal file
@@ -0,0 +1,607 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace arDev
|
||||
{
|
||||
public abstract class BMSSerialComm : ISerialComm, IDisposable
|
||||
{
|
||||
protected System.IO.Ports.SerialPort _device;
|
||||
protected ManualResetEvent _mre;
|
||||
protected byte[] LastReceiveBuffer = new byte[] { };
|
||||
/// <summary>
|
||||
/// 최종 전송 메세지
|
||||
/// </summary>
|
||||
public byte[] lastSendBuffer = new byte[] { };
|
||||
//public int ValidCheckTimeMSec { get; set; } = 5000;
|
||||
protected List<byte> tempBuffer = new List<byte>();
|
||||
protected Boolean findSTX = false;
|
||||
public string ErrorMessage { get; set; }
|
||||
public DateTime LastConnTime { get; set; }
|
||||
public DateTime LastConnTryTime { get; set; }
|
||||
public DateTime lastSendTime;
|
||||
/// <summary>
|
||||
/// 메세지 수신시 사용하는 내부버퍼
|
||||
/// </summary>
|
||||
protected List<byte> _buffer = new List<byte>();
|
||||
/// <summary>
|
||||
/// 데이터조회간격(초)
|
||||
/// </summary>
|
||||
public float ScanInterval { get; set; }
|
||||
|
||||
// public byte[] LastRecvData;
|
||||
public string LastRecvString
|
||||
{
|
||||
get
|
||||
{
|
||||
if (LastReceiveBuffer == null) return String.Empty;
|
||||
else return System.Text.Encoding.Default.GetString(LastReceiveBuffer);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 마지막으로 데이터를 받은 시간
|
||||
/// </summary>
|
||||
public DateTime lastRecvTime;
|
||||
|
||||
|
||||
public int WriteError = 0;
|
||||
public string WriteErrorMessage = string.Empty;
|
||||
public int WaitTimeout { get; set; } = 1000;
|
||||
public int MinRecvLength { get; set; } = 1;
|
||||
|
||||
// Polling Thread related
|
||||
protected Thread _recvThread;
|
||||
protected volatile bool _isReading = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 포트이름
|
||||
/// </summary>
|
||||
[Description("시리얼 포트 이름")]
|
||||
[Category("설정"), DisplayName("Port Name")]
|
||||
public string PortName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_device == null) return string.Empty;
|
||||
else return _device.PortName;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (this.IsOpen)
|
||||
{
|
||||
Message?.Invoke(this, new MessageEventArgs("포트가 열려있어 포트이름을 변경할 수 없습니다", true));
|
||||
}
|
||||
else if (String.IsNullOrEmpty(value) == false)
|
||||
_device.PortName = value;
|
||||
else
|
||||
{
|
||||
Message?.Invoke(this, new MessageEventArgs("No PortName", true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int BaudRate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_device == null) return 0;
|
||||
else return _device.BaudRate;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (this.IsOpen)
|
||||
{
|
||||
Message?.Invoke(this, new MessageEventArgs("포트가 열려있어 BaudRate(를) 변경할 수 없습니다", true));
|
||||
}
|
||||
else if (value != 0)
|
||||
_device.BaudRate = value;
|
||||
else Message?.Invoke(this, new MessageEventArgs("No baud rate", true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public BMSSerialComm()
|
||||
{
|
||||
_device = new System.IO.Ports.SerialPort();
|
||||
this.BaudRate = 9600;
|
||||
ScanInterval = 10;
|
||||
// _device.DataReceived += barcode_DataReceived; // Removed event handler
|
||||
_device.ErrorReceived += this.barcode_ErrorReceived;
|
||||
_device.WriteTimeout = 3000;
|
||||
_device.ReadTimeout = 3000;
|
||||
_device.ReadBufferSize = 8192;
|
||||
_device.WriteBufferSize = 8192;
|
||||
//_device.DiscardInBuffer();
|
||||
//_device.DiscardOutBuffer();
|
||||
ErrorMessage = string.Empty;
|
||||
lastRecvTime = DateTime.Parse("1982-11-23");
|
||||
LastConnTime = DateTime.Parse("1982-11-23");
|
||||
LastConnTryTime = DateTime.Parse("1982-11-23");
|
||||
lastRecvTime = DateTime.Parse("1982-11-23");
|
||||
this._mre = new ManualResetEvent(true);
|
||||
}
|
||||
|
||||
~BMSSerialComm()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
|
||||
// Flag: Has Dispose already been called?
|
||||
bool disposed = false;
|
||||
|
||||
// Public implementation of Dispose pattern callable by consumers.
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// Protected implementation of Dispose pattern.
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
// Free any other managed objects here.
|
||||
//
|
||||
}
|
||||
|
||||
// Stop reading thread
|
||||
_isReading = false;
|
||||
|
||||
// _device.DataReceived -= barcode_DataReceived; // Removed event handler
|
||||
_device.ErrorReceived -= this.barcode_ErrorReceived;
|
||||
|
||||
if (_recvThread != null && _recvThread.IsAlive)
|
||||
{
|
||||
_recvThread.Join(500);
|
||||
}
|
||||
|
||||
if (_device != null)
|
||||
{
|
||||
if (_device.IsOpen) _device.Close();
|
||||
_device.Dispose();
|
||||
}
|
||||
|
||||
// Free any unmanaged objects here.
|
||||
//
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public Boolean Open()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_device.IsOpen == false)
|
||||
{
|
||||
_device.Open();
|
||||
}
|
||||
|
||||
if (_device.IsOpen)
|
||||
{
|
||||
// Start polling thread
|
||||
if (_isReading == false)
|
||||
{
|
||||
_isReading = true;
|
||||
_recvThread = new Thread(ReadPort);
|
||||
_recvThread.IsBackground = true;
|
||||
_recvThread.Start();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = ex.Message;
|
||||
Message.Invoke(this, new MessageEventArgs(ex.Message, true));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public string GetHexString(Byte[] input)
|
||||
{
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
foreach (byte b in input)
|
||||
sb.Append(" " + b.ToString("X2"));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 포트가 열려있는지 확인
|
||||
/// </summary>
|
||||
[Description("현재 시리얼포트가 열려있는지 확인합니다")]
|
||||
[Category("정보"), DisplayName("Port Open")]
|
||||
public Boolean IsOpen
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_device == null) return false;
|
||||
return _device.IsOpen;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
_isReading = false; // Stop thread loop
|
||||
|
||||
if (_recvThread != null && _recvThread.IsAlive)
|
||||
{
|
||||
if (!_recvThread.Join(500)) // Wait for thread to finish
|
||||
{
|
||||
// _recvThread.Abort(); // Avoid Abort if possible
|
||||
}
|
||||
}
|
||||
|
||||
if (_device != null && _device.IsOpen)
|
||||
{
|
||||
_device.DiscardInBuffer();
|
||||
_device.DiscardOutBuffer();
|
||||
_device.Close(); //dispose에서는 포트를 직접 클리어하지 않게 해뒀다.
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
protected Boolean RaiseRecvData()
|
||||
{
|
||||
return RaiseRecvData(LastReceiveBuffer.ToArray(), false);
|
||||
}
|
||||
/// <summary>
|
||||
/// 수신받은 메세지를 발생 시킵니다
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public virtual Boolean RaiseRecvData(byte[] Data, bool udpatelastbuffer)
|
||||
{
|
||||
//181206 - 최종수신 메세지 기록
|
||||
lastRecvTime = DateTime.Now;
|
||||
if (udpatelastbuffer && Data != null)
|
||||
{
|
||||
if (LastReceiveBuffer == null || LastReceiveBuffer.Length != Data.Length)
|
||||
{
|
||||
LastReceiveBuffer = new byte[Data.Length];
|
||||
Array.Copy(Data, LastReceiveBuffer, Data.Length);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// UI update might need Invoke if this event handler updates UI directly,
|
||||
// but usually the subscriber handles Invoke.
|
||||
// Since we are running on a background thread now, subscribers must be aware.
|
||||
Message?.Invoke(this, new MessageEventArgs(Data, true)); //recvmessage
|
||||
if (ProcessRecvData(Data) == false)
|
||||
{
|
||||
//Message?.Invoke(this, new MessageEventArgs(Data, true)); //recvmessage
|
||||
Message?.Invoke(this, new MessageEventArgs(this.ErrorMessage, true)); //errormessage
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.ErrorMessage = ex.Message;
|
||||
this.Message?.Invoke(this, new MessageEventArgs(ex.Message, true));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 수신받은 자료를 처리한다
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool ProcessRecvData(byte[] data);
|
||||
|
||||
#region "Internal Events"
|
||||
|
||||
void barcode_ErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
|
||||
{
|
||||
Message?.Invoke(this, new MessageEventArgs(e.ToString(), true));
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[] { };
|
||||
|
||||
// Replaced with ReadPort Loop
|
||||
/*
|
||||
void barcode_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
int ReadCount = _device.BytesToRead;
|
||||
|
||||
buffer = new byte[ReadCount];
|
||||
_device.Read(buffer, 0, buffer.Length);
|
||||
|
||||
System.Text.StringBuilder LogMsg = new StringBuilder();
|
||||
|
||||
byte[] remainBuffer;
|
||||
Repeat:
|
||||
if (CustomParser(buffer, out remainBuffer))
|
||||
{
|
||||
//분석완료이므로 받은 데이터를 버퍼에 기록한다
|
||||
if (LastReceiveBuffer == null || (LastReceiveBuffer.Length != tempBuffer.Count))
|
||||
Array.Resize(ref LastReceiveBuffer, tempBuffer.Count);
|
||||
Array.Copy(tempBuffer.ToArray(), LastReceiveBuffer, tempBuffer.Count);
|
||||
tempBuffer.Clear();
|
||||
|
||||
//수신메세지발생
|
||||
RaiseRecvData();
|
||||
if (remainBuffer != null && remainBuffer.Length > 0)
|
||||
{
|
||||
//버퍼를 변경해서 다시 전송을 해준다.
|
||||
Array.Resize(ref buffer, remainBuffer.Length);
|
||||
Array.Copy(remainBuffer, buffer, remainBuffer.Length);
|
||||
goto Repeat; //남은 버퍼가 있다면 진행을 해준다.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//if (IsOpen)
|
||||
//{
|
||||
// //_device.DiscardInBuffer();
|
||||
// //_device.DiscardOutBuffer();
|
||||
//}
|
||||
ErrorMessage = ex.Message;
|
||||
this.Message?.Invoke(this, new MessageEventArgs(ex.Message, true));
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
void ReadPort()
|
||||
{
|
||||
while (_isReading)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_device == null || !_device.IsOpen)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
int readCount = _device.BytesToRead;
|
||||
if (readCount > 0)
|
||||
{
|
||||
byte[] buffer = new byte[readCount];
|
||||
_device.Read(buffer, 0, buffer.Length);
|
||||
|
||||
byte[] remainBuffer;
|
||||
Repeat:
|
||||
if (CustomParser(buffer, out remainBuffer))
|
||||
{
|
||||
//분석완료이므로 받은 데이터를 버퍼에 기록한다
|
||||
if (LastReceiveBuffer == null || (LastReceiveBuffer.Length != tempBuffer.Count))
|
||||
Array.Resize(ref LastReceiveBuffer, tempBuffer.Count);
|
||||
Array.Copy(tempBuffer.ToArray(), LastReceiveBuffer, tempBuffer.Count);
|
||||
tempBuffer.Clear();
|
||||
|
||||
//수신메세지발생
|
||||
RaiseRecvData();
|
||||
if (remainBuffer != null && remainBuffer.Length > 0)
|
||||
{
|
||||
//버퍼를 변경해서 다시 전송을 해준다.
|
||||
buffer = new byte[remainBuffer.Length]; // Reallocate buffer for remaining data
|
||||
Array.Copy(remainBuffer, buffer, remainBuffer.Length);
|
||||
goto Repeat; //남은 버퍼가 있다면 진행을 해준다.
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep(20); // Data 없음, 대기
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Thread 상에서 Exception 발생 시 로그 남기고 계속 진행 여부 결정
|
||||
// 여기서는 에러 메시지 발생시키고 Sleep
|
||||
ErrorMessage = ex.Message;
|
||||
this.Message?.Invoke(this, new MessageEventArgs(ex.Message, true));
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region "External Events"
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 오류 및 기타 일반 메세지
|
||||
/// </summary>
|
||||
public event EventHandler<MessageEventArgs> Message;
|
||||
|
||||
#endregion
|
||||
|
||||
#region "Event Args"
|
||||
|
||||
/// <summary>
|
||||
/// 데이터를 수신할떄 사용함(RAW 포함)
|
||||
/// </summary>
|
||||
public class ReceiveDataEventArgs : EventArgs
|
||||
{
|
||||
private byte[] _buffer = null;
|
||||
|
||||
/// <summary>
|
||||
/// 바이트배열의 버퍼값
|
||||
/// </summary>
|
||||
public byte[] Value { get { return _buffer; } }
|
||||
|
||||
/// <summary>
|
||||
/// 버퍼(바이트배열)의 데이터를 문자로 반환합니다.
|
||||
/// </summary>
|
||||
public string StrValue
|
||||
{
|
||||
get
|
||||
{
|
||||
//return string.Empty;
|
||||
|
||||
if (_buffer == null || _buffer.Length < 1) return string.Empty;
|
||||
else return System.Text.Encoding.Default.GetString(_buffer);
|
||||
}
|
||||
}
|
||||
public ReceiveDataEventArgs(byte[] buffer)
|
||||
{
|
||||
_buffer = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 메세지를 강제 발생
|
||||
/// </summary>
|
||||
/// <param name="mt"></param>
|
||||
/// <param name="message"></param>
|
||||
protected virtual void RaiseMessage(MessageType mt, string message)
|
||||
{
|
||||
this.Message?.Invoke(this, new MessageEventArgs(mt, message));
|
||||
}
|
||||
public enum MessageType
|
||||
{
|
||||
Normal,
|
||||
Error,
|
||||
Send,
|
||||
Recv,
|
||||
}
|
||||
|
||||
public class MessageEventArgs : EventArgs
|
||||
{
|
||||
public MessageType MsgType { get; set; }
|
||||
private string _message = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Recv,Send,Normal,Error 모두 지원
|
||||
/// </summary>
|
||||
public string Message { get { return _message; } }
|
||||
|
||||
private byte[] _data = null;
|
||||
|
||||
/// <summary>
|
||||
/// Recv,Send에서만 값이 존재 합니다
|
||||
/// </summary>
|
||||
public byte[] Data { get { return _data; } }
|
||||
public MessageEventArgs(string Message, bool isError = false)
|
||||
{
|
||||
if (isError) MsgType = MessageType.Error;
|
||||
else MsgType = MessageType.Normal;
|
||||
_message = Message;
|
||||
}
|
||||
public MessageEventArgs(MessageType msgtype, string Message)
|
||||
{
|
||||
MsgType = msgtype;
|
||||
_message = Message;
|
||||
_data = System.Text.Encoding.Default.GetBytes(Message);
|
||||
}
|
||||
|
||||
public MessageEventArgs(byte[] buffer, bool isRecv = true)
|
||||
{
|
||||
if (isRecv) MsgType = MessageType.Recv;
|
||||
else MsgType = MessageType.Send;
|
||||
_data = new byte[buffer.Length];
|
||||
Array.Copy(buffer, _data, Data.Length);
|
||||
_message = System.Text.Encoding.Default.GetString(_data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected abstract bool CustomParser(byte[] buf, out byte[] remainBuffer);
|
||||
|
||||
/// <summary>
|
||||
/// 포트가 열려있거나 데이터 수신시간이 없는경우 false를 반환합니다
|
||||
/// </summary>
|
||||
public Boolean IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsOpen == false) return false;
|
||||
if (lastRecvTime.Year == 1982) return false;
|
||||
var ts = DateTime.Now - lastRecvTime;
|
||||
if (ts.TotalSeconds > (this.ScanInterval * 2.5)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected bool WriteData(string cmd)
|
||||
{
|
||||
return WriteData(System.Text.Encoding.Default.GetBytes(cmd));
|
||||
}
|
||||
/// <summary>
|
||||
/// 포트에 쓰기(barcode_DataReceived 이벤트로 메세지수신)
|
||||
/// </summary>
|
||||
protected Boolean WriteData(byte[] data)
|
||||
{
|
||||
Boolean bRet = false;
|
||||
|
||||
//171205 : 타임아웃시간추가
|
||||
if (!_mre.WaitOne(WaitTimeout))
|
||||
{
|
||||
ErrorMessage = $"WriteData:MRE:WaitOne:TimeOut {WaitTimeout}ms";
|
||||
this.Message?.Invoke(this, new MessageEventArgs(ErrorMessage, true));
|
||||
return false;
|
||||
}
|
||||
|
||||
_mre.Reset();
|
||||
|
||||
//Array.Resize(ref data, data.Length + 2);
|
||||
|
||||
try
|
||||
{
|
||||
lastSendTime = DateTime.Now;
|
||||
if (lastSendBuffer == null) lastSendBuffer = new byte[data.Length]; //171113
|
||||
else Array.Resize(ref lastSendBuffer, data.Length);
|
||||
Array.Copy(data, lastSendBuffer, data.Length);
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
_device.Write(data, i, 1);
|
||||
|
||||
//_device.Write(data, 0, data.Length);
|
||||
|
||||
//171113
|
||||
this.Message?.Invoke(this, new MessageEventArgs(data, false));
|
||||
|
||||
bRet = true;
|
||||
WriteError = 0;
|
||||
WriteErrorMessage = string.Empty;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// this.isinit = false;
|
||||
this.Message?.Invoke(this, new MessageEventArgs(ex.Message, true));
|
||||
bRet = false;
|
||||
WriteError += 1; //연속쓰기오류횟수
|
||||
WriteErrorMessage = ex.Message;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mre.Set();
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
37
HMI/Project/Device/CFlag.cs
Normal file
37
HMI/Project/Device/CFlag.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Project.Device
|
||||
{
|
||||
public class CFlag : COMM.Flag
|
||||
{
|
||||
public CFlag() : base(64)
|
||||
{
|
||||
|
||||
}
|
||||
public bool get(EFlag flag)
|
||||
{
|
||||
return Get((int)flag);
|
||||
}
|
||||
public void set(EFlag flag, bool value)
|
||||
{
|
||||
var idx = (int)flag;
|
||||
Set(idx, value);
|
||||
}
|
||||
public void Toggle(EFlag flag)
|
||||
{
|
||||
int idx = (int)flag;
|
||||
var curValue = Get(idx);
|
||||
Set(idx, !curValue);
|
||||
}
|
||||
|
||||
public void Toggle(int idx)
|
||||
{
|
||||
var curValue = Get(idx);
|
||||
Set(idx, !curValue);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
427
HMI/Project/Device/Socket.cs
Normal file
427
HMI/Project/Device/Socket.cs
Normal file
@@ -0,0 +1,427 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Project.Device
|
||||
{
|
||||
public class Socket
|
||||
{
|
||||
public enum eType
|
||||
{
|
||||
REQUEST,
|
||||
REPLY,
|
||||
}
|
||||
public enum eSType
|
||||
{
|
||||
STATUS,
|
||||
GEN,
|
||||
SPL
|
||||
}
|
||||
|
||||
public struct Message
|
||||
{
|
||||
public Boolean isError;
|
||||
public string ErrorMessage;
|
||||
public string Asset;
|
||||
public eType Type;
|
||||
public eSType SType;
|
||||
public string Body;
|
||||
public string timeStamp;
|
||||
}
|
||||
|
||||
private Winsock_Orcas.Winsock wsListen;
|
||||
private Winsock_Orcas.Winsock wsData;
|
||||
private char sepMsg = (char)0x07;
|
||||
private char sepBody = (char)0x09;
|
||||
|
||||
public int ListenPort { get; set; }
|
||||
public string errorMessage { get; set; }
|
||||
public event EventHandler<SocketMessageEventArgs> RecvMessage;
|
||||
public event EventHandler<SocketMessageEventArgs> SendMessage;
|
||||
public event EventHandler<MesasgeEventArgs> GetMessage;
|
||||
|
||||
private void RaiseMessage(string msg, Boolean isErr = false)
|
||||
{
|
||||
if (GetMessage != null) GetMessage(this, new MesasgeEventArgs(msg, isErr));
|
||||
}
|
||||
private void RaiseSendMessage(Message msg, string raw)
|
||||
{
|
||||
if (SendMessage != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
SendMessage(this, new SocketMessageEventArgs(msg, raw));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.errorMessage = ex.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void RaiseRecvMessage(Message msg, string raw)
|
||||
{
|
||||
if (RecvMessage != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
RecvMessage(this, new SocketMessageEventArgs(msg, raw));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.errorMessage = ex.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
public Socket()
|
||||
{
|
||||
wsListen = new Winsock_Orcas.Winsock();
|
||||
wsData = new Winsock_Orcas.Winsock();
|
||||
wsListen.LegacySupport = true;
|
||||
wsData.LegacySupport = true;
|
||||
wsData.Connected += wsData_Connected;
|
||||
wsData.Disconnected += wsData_Disconnected;
|
||||
wsData.DataArrival += wsData_DataArrival;
|
||||
wsData.ErrorReceived += wsData_ErrorReceived;
|
||||
wsListen.ConnectionRequest += wsListen_ConnectionRequest;
|
||||
wsListen.ErrorReceived += wsListen_ErrorReceived;
|
||||
}
|
||||
|
||||
void wsListen_ErrorReceived(object sender, Winsock_Orcas.WinsockErrorReceivedEventArgs e)
|
||||
{
|
||||
RaiseMessage("LTERR:" + e.Details, true);
|
||||
}
|
||||
|
||||
void wsData_ErrorReceived(object sender, Winsock_Orcas.WinsockErrorReceivedEventArgs e)
|
||||
{
|
||||
RaiseMessage("RXERR:"+e.Details, true);
|
||||
}
|
||||
|
||||
void wsData_Disconnected(object sender, EventArgs e)
|
||||
{
|
||||
RaiseMessage("Disconnected");
|
||||
}
|
||||
|
||||
void wsData_Connected(object sender, Winsock_Orcas.WinsockConnectedEventArgs e)
|
||||
{
|
||||
RaiseMessage("Conncted");
|
||||
}
|
||||
|
||||
void wsListen_ConnectionRequest(object sender, Winsock_Orcas.WinsockConnectionRequestEventArgs e)
|
||||
{
|
||||
if (wsData.State != Winsock_Orcas.WinsockStates.Closed)
|
||||
{
|
||||
wsData.Close();
|
||||
System.Threading.Thread.Sleep(500);
|
||||
}
|
||||
RaiseMessage("Connection Request " + e.ClientIP);
|
||||
try
|
||||
{
|
||||
wsData.Accept(e.Client);
|
||||
}catch (Exception ex)
|
||||
{
|
||||
RaiseMessage("Connection Request\n"+ex.Message, true);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
~Socket()
|
||||
{
|
||||
if (wsData != null)
|
||||
{
|
||||
wsData.DataArrival -= wsData_DataArrival;
|
||||
wsData.Connected += wsData_Connected;
|
||||
wsData.Disconnected += wsData_Disconnected;
|
||||
}
|
||||
if (wsListen != null)
|
||||
{
|
||||
wsListen.ConnectionRequest += wsListen_ConnectionRequest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (wsListen != null && wsListen.State != Winsock_Orcas.WinsockStates.Closed)
|
||||
wsListen.Close();
|
||||
if (wsData != null && wsData.State != Winsock_Orcas.WinsockStates.Closed)
|
||||
wsData.Close();
|
||||
wsData.Dispose();
|
||||
wsListen.Dispose();
|
||||
}
|
||||
|
||||
public Boolean Listen(int port)
|
||||
{
|
||||
try
|
||||
{
|
||||
ListenPort = port;
|
||||
wsListen.Listen(this.ListenPort);
|
||||
this.errorMessage = string.Empty;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.errorMessage = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public Boolean isListen
|
||||
{
|
||||
get
|
||||
{
|
||||
return wsListen.State == Winsock_Orcas.WinsockStates.Listening;
|
||||
}
|
||||
}
|
||||
public Boolean isConn
|
||||
{
|
||||
get
|
||||
{
|
||||
return wsData.State == Winsock_Orcas.WinsockStates.Connected;
|
||||
}
|
||||
}
|
||||
|
||||
public Message LastSendMessage = new Message();
|
||||
private Message makeMessage(string Asset, eType type, eSType subtype, string body)
|
||||
{
|
||||
Message retval = new Message();
|
||||
retval.Asset = Asset;
|
||||
retval.Type = type;
|
||||
retval.SType = subtype;
|
||||
retval.Body = body;
|
||||
retval.isError = true;
|
||||
retval.ErrorMessage = string.Empty;
|
||||
retval.timeStamp = DateTime.Now.ToString("yyyyMMddHHmmss");
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Body문자열을 구분자를 기준으로 한 배열로 반환 함
|
||||
/// </summary>
|
||||
/// <param name="bodyMessage"></param>
|
||||
/// <returns></returns>
|
||||
public string[] getBodyArray(string bodyMessage)
|
||||
{
|
||||
return bodyMessage.Split(sepBody);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 패킷의 내용을 메세지로 분리한다.
|
||||
/// </summary>
|
||||
/// <param name="PacketMessage"></param>
|
||||
/// <returns></returns>
|
||||
private Message ParseMessage(string PacketMessage)
|
||||
{
|
||||
Message retval = new Message();
|
||||
retval.isError = false;
|
||||
retval.ErrorMessage = string.Empty;
|
||||
|
||||
var buffer = PacketMessage.Split(sepMsg);
|
||||
if (buffer.Length != 5)
|
||||
{
|
||||
retval.isError = true;
|
||||
retval.ErrorMessage = "Packet Size Error : Expect 5 Array";
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval.Asset = buffer[0];
|
||||
if (!getType(buffer[1], out retval.Type))
|
||||
{
|
||||
retval.isError = true;
|
||||
retval.ErrorMessage = "지정된 Type 이 아닙니다(" + buffer[1] + ")";
|
||||
return retval;
|
||||
}
|
||||
if (!getSType(buffer[2], out retval.SType))
|
||||
{
|
||||
retval.isError = true;
|
||||
retval.ErrorMessage = "지정된 SubType 이 아닙니다(" + buffer[2] + ")";
|
||||
return retval;
|
||||
}
|
||||
retval.timeStamp = buffer[3];
|
||||
//DateTime timeStamp;
|
||||
//if (!DateTime.TryParse(retval.timeStamp, out timeStamp))
|
||||
//{
|
||||
// retval.isError = true;
|
||||
// retval.ErrorMessage = "timeStamp 해석 오류(" + retval.timeStamp + ")";
|
||||
// return retval;
|
||||
//}
|
||||
retval.Body = buffer[4];
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
private Boolean getType(string strType, out eType type)
|
||||
{
|
||||
type = eType.REPLY;
|
||||
var list = Enum.GetNames(typeof(eType));
|
||||
int value = -1;
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
{
|
||||
if (list[i].ToUpper() == strType.ToUpper())
|
||||
{
|
||||
value = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value == -1) return false;
|
||||
type = (eType)value;
|
||||
return true;
|
||||
}
|
||||
private Boolean getSType(string strSType, out eSType stype)
|
||||
{
|
||||
stype = eSType.GEN;
|
||||
var list = Enum.GetNames(typeof(eSType));
|
||||
int value = -1;
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
{
|
||||
if (list[i].ToUpper() == strSType.ToUpper())
|
||||
{
|
||||
value = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value == -1) return false;
|
||||
stype = (eSType)value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public string makePacket(Message msg)
|
||||
{
|
||||
//프레임구조 asset chr(7) + type + chr(7) + stype + char(7) + timeStamp + char(7) + body"
|
||||
//timestamp = yyyymmddhhmmss
|
||||
//sepChar = (char)0x07;
|
||||
|
||||
System.Text.StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append(msg.Asset);
|
||||
buffer.Append(sepMsg);
|
||||
buffer.Append(msg.Type.ToString());
|
||||
buffer.Append(sepMsg);
|
||||
buffer.Append(msg.SType.ToString());
|
||||
buffer.Append(sepMsg);
|
||||
buffer.Append(msg.timeStamp);
|
||||
buffer.Append(sepMsg);
|
||||
buffer.Append(msg.Body);
|
||||
return buffer.ToString();
|
||||
}
|
||||
|
||||
public string makeLotSplitPacket( string fcst, string tcst, string slot, string wafer)
|
||||
{
|
||||
System.Text.StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append(fcst);
|
||||
buffer.Append(sepBody);
|
||||
buffer.Append(tcst);
|
||||
buffer.Append(sepBody);
|
||||
buffer.Append(slot);
|
||||
buffer.Append(sepBody);
|
||||
buffer.Append(wafer);
|
||||
return buffer.ToString();
|
||||
}
|
||||
public string makeLotGenPacket(string Lot, string cst, string slot, string wafer)
|
||||
{
|
||||
System.Text.StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append(Lot);
|
||||
buffer.Append(sepBody);
|
||||
buffer.Append(cst);
|
||||
buffer.Append(sepBody);
|
||||
buffer.Append(slot);
|
||||
buffer.Append(sepBody);
|
||||
buffer.Append(wafer);
|
||||
return buffer.ToString();
|
||||
}
|
||||
public enum eStatus
|
||||
{
|
||||
RUN =0,
|
||||
IDLE ,
|
||||
ALARM,
|
||||
}
|
||||
public string makeReplyStatus(eStatus Status)
|
||||
{
|
||||
System.Text.StringBuilder buffer = new StringBuilder();
|
||||
buffer.Append(((int)Status).ToString());
|
||||
return buffer.ToString();
|
||||
}
|
||||
public Boolean Send(string Asset, eType type, eSType subtype, string body)
|
||||
{
|
||||
var msg = makeMessage(Asset, type, subtype, body);
|
||||
var isStatus = subtype == eSType.STATUS;
|
||||
return Send(msg, isStatus);
|
||||
}
|
||||
|
||||
public Boolean isReplyRecv = false;
|
||||
public Boolean Send(Message msg,Boolean isStatus)
|
||||
{
|
||||
|
||||
var packet = makePacket(msg);
|
||||
if (wsData.State != Winsock_Orcas.WinsockStates.Connected)
|
||||
{
|
||||
errorMessage = "Not Connected";
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
if(isStatus==false) isReplyRecv = false; //190129
|
||||
wsData.Send(packet + "\r\n");
|
||||
errorMessage = string.Empty;
|
||||
LastSendMessage = msg;
|
||||
RaiseSendMessage(msg, packet);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Message LastReplyMessage = new Message();
|
||||
public Message LastRecvMessage = new Message();
|
||||
void wsData_DataArrival(object sender, Winsock_Orcas.WinsockDataArrivalEventArgs e)
|
||||
{
|
||||
var sock = sender as Winsock_Orcas.Winsock;
|
||||
var data = sock.Get<String>();
|
||||
if(PUB.setting.LOg_SocketRecv)
|
||||
{
|
||||
if (data.IndexOf("REQUEST") != -1 && data.IndexOf("STATUS") != -1)
|
||||
{
|
||||
//핑 명령
|
||||
}
|
||||
else PUB.log.AddE("Socket Recv : " + data); //190129
|
||||
}
|
||||
|
||||
LastRecvMessage = ParseMessage(data);
|
||||
if (LastRecvMessage.isError) PUB.log.AddE("Socket Message error" + LastRecvMessage.ErrorMessage);
|
||||
else
|
||||
{
|
||||
//190129 - reply만 별도 처리함
|
||||
if (LastRecvMessage.Type == eType.REPLY)
|
||||
{
|
||||
LastReplyMessage = ParseMessage(data);
|
||||
isReplyRecv = true;
|
||||
}
|
||||
}
|
||||
RaiseRecvMessage(LastRecvMessage, data);
|
||||
}
|
||||
|
||||
|
||||
public class SocketMessageEventArgs : EventArgs
|
||||
{
|
||||
public string rawData { get; set; }
|
||||
public Device.Socket.Message Message { get; set; }
|
||||
public SocketMessageEventArgs(Device.Socket.Message msg, string raw)
|
||||
{
|
||||
this.Message = msg;
|
||||
this.rawData = raw;
|
||||
}
|
||||
}
|
||||
public class MesasgeEventArgs : EventArgs
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public Boolean isError { get; set; }
|
||||
public MesasgeEventArgs(string msg, Boolean iserr)
|
||||
{
|
||||
this.Message = msg;
|
||||
this.isError = iserr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
330
HMI/Project/Device/Xbee.cs
Normal file
330
HMI/Project/Device/Xbee.cs
Normal file
@@ -0,0 +1,330 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using COMM;
|
||||
using ENIG;
|
||||
using System.Security.Cryptography;
|
||||
using AR;
|
||||
using System.IO.Ports;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Project.Device
|
||||
{
|
||||
public enum eDocStep : byte
|
||||
{
|
||||
NotSet = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 투입준비됨
|
||||
/// </summary>
|
||||
ReadyForEnter = 10,
|
||||
|
||||
/// <summary>
|
||||
/// 투입완료
|
||||
/// </summary>
|
||||
EnterComplete = 11,
|
||||
|
||||
/// <summary>
|
||||
/// 투입(진행중)
|
||||
/// </summary>
|
||||
EnterIng = 12,
|
||||
|
||||
/// <summary>
|
||||
/// 진출완료
|
||||
/// </summary>
|
||||
ExitComplete = 21,
|
||||
|
||||
/// <summary>
|
||||
/// 진출중
|
||||
/// </summary>
|
||||
ExitIng = 22,
|
||||
}
|
||||
|
||||
public class Xbee : SerialPort, arDev.ISerialComm
|
||||
{
|
||||
public string buffer = string.Empty;
|
||||
public System.Text.StringBuilder newbuffer = new StringBuilder();
|
||||
public string ErrorMessage { get; set; } = string.Empty;
|
||||
public DateTime LastStatusSendTime { get; set; } = DateTime.Now;
|
||||
private EEProtocol proto;
|
||||
|
||||
public class MessageArgs : EventArgs
|
||||
{
|
||||
public bool IsError { get; set; }
|
||||
public string Message { get; set; }
|
||||
public MessageArgs(bool iserr, string m)
|
||||
{
|
||||
this.IsError = iserr;
|
||||
this.Message = m;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<MessageArgs> MessageReceived;
|
||||
public event EventHandler<EEProtocol.DataEventArgs> ProtocReceived;
|
||||
|
||||
public Xbee()
|
||||
{
|
||||
this.WriteTimeout = 500;
|
||||
this.ReadTimeout = 500;
|
||||
this.DataReceived += Xbee_DataReceived;
|
||||
proto = new EEProtocol();
|
||||
proto.OnDataReceived += Proto_OnDataReceived;
|
||||
proto.OnMessage += Proto_OnMessage;
|
||||
}
|
||||
~Xbee()
|
||||
{
|
||||
this.DataReceived -= Xbee_DataReceived;
|
||||
proto.OnDataReceived -= Proto_OnDataReceived;
|
||||
proto.OnMessage -= Proto_OnMessage;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 지그비장치에 데이터를 전송합니다
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public bool Send(byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.Write(data, 0, data.Length);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public new bool Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
base.Close();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
public new bool Open()
|
||||
{
|
||||
try
|
||||
{
|
||||
base.Open();
|
||||
return IsOpen;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = ex.Message;
|
||||
PUB.logxbee.AddE(ErrorMessage);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Proto_OnDataReceived(object sender, EEProtocol.DataEventArgs e)
|
||||
{
|
||||
var hexstrRaw = e.ReceivedPacket.RawData.HexString();
|
||||
var hexstr = e.ReceivedPacket.Data.HexString();
|
||||
var cmd = e.ReceivedPacket.Command.ToString("X2");
|
||||
var id = e.ReceivedPacket.ID.ToString("X2");
|
||||
PUB.logxbee.Add("RX", $"{hexstrRaw}\nID:{id},CMD:{cmd},DATA:{hexstr}");
|
||||
ProtocReceived?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private void Proto_OnMessage(object sender, EEProtocol.MessageEventArgs e)
|
||||
{
|
||||
MessageReceived?.Invoke(this, new MessageArgs(e.IsError, e.Message));
|
||||
}
|
||||
|
||||
private void Xbee_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
|
||||
{
|
||||
var dev = sender as System.IO.Ports.SerialPort;
|
||||
var buffer = new byte[dev.BytesToRead];
|
||||
dev.Read(buffer, 0, buffer.Length);
|
||||
proto.ProcessReceivedData(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이동완료 신호 전송
|
||||
/// </summary>
|
||||
/// <param name="tag">목적지태그값</param>
|
||||
public void SendMoveComplete(string tag)
|
||||
{
|
||||
var id = PUB.setting.XBE_ID;
|
||||
byte cmd = (byte)ENIGProtocol.AGVCommandEH.Arrived;
|
||||
var data = System.Text.Encoding.Default.GetBytes(tag);
|
||||
var packet = proto.CreatePacket(id, cmd, data);
|
||||
Send(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 신규 RFID태그값이 읽혔다면 이명령을 통해서 전송한다
|
||||
/// </summary>
|
||||
public void SendRFIDTag(string tag)
|
||||
{
|
||||
var id = PUB.setting.XBE_ID;
|
||||
byte cmd = (byte)ENIGProtocol.AGVCommandEH.ReadRFID;
|
||||
var data = System.Text.Encoding.Default.GetBytes(tag);
|
||||
var packet = proto.CreatePacket(id, cmd, data);
|
||||
Send(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 오류코드를 호스트에 전송합니다
|
||||
/// </summary>
|
||||
/// <param name="errcode"></param>
|
||||
public void SendError(ENIGProtocol.AGVErrorCode errcode, string errormessage)
|
||||
{
|
||||
// Update global error state so it persists in Status messages
|
||||
PUB.Result.RunStepErrorCode = errcode;
|
||||
PUB.Result.ResultMessage = errormessage;
|
||||
|
||||
var id = PUB.setting.XBE_ID;
|
||||
byte cmd = (byte)ENIGProtocol.AGVCommandEH.Error;
|
||||
if (errormessage.Length > 30) errormessage = errormessage.Substring(0, 29);
|
||||
|
||||
var data = new List<byte>();
|
||||
data.Add((byte)errcode);
|
||||
var datamsg = System.Text.Encoding.Default.GetBytes(errormessage);
|
||||
data.AddRange(datamsg);
|
||||
|
||||
var packet = proto.CreatePacket(id, cmd, data.ToArray());
|
||||
Send(packet);
|
||||
}
|
||||
|
||||
public eDocStep StepMC { get; set; } = eDocStep.NotSet;
|
||||
|
||||
ManualResetEvent sendlock = new ManualResetEvent(true);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AGV상태를 Xbee 로 전송한다
|
||||
/// </summary>
|
||||
public void SendStatus()
|
||||
{
|
||||
if (this.IsOpen == false) return;
|
||||
if (sendlock.WaitOne() == false) return;
|
||||
sendlock.Reset();
|
||||
|
||||
/*
|
||||
Mode[1] : 0=manual, 1=auto
|
||||
RunSt[1] : 0=stop, 1=run, 2=error
|
||||
RunStep[1] : (byte)PUB.sm.RunStep
|
||||
RunStepSeq[1] : (byte)StepMC
|
||||
MotorDir[1] : 0=F(Forward), 1=B(Backward)
|
||||
MagnetDir[1] : 0=S(Straight), 1=L(Left), 2=R(Right)
|
||||
ChargeSt[1] : 0=off, 1=on
|
||||
CartSt[1] : 0=off, 1=on, 2=unknown
|
||||
LiftSt[1] : 0=down , 1=up, 2=unknown
|
||||
ErrorCode[1] : (byte)PUB.Result.ResultErrorCode
|
||||
LastTag[4] : "0000"
|
||||
*/
|
||||
try
|
||||
{
|
||||
List<byte> data = new List<byte>();
|
||||
byte value = 0;
|
||||
// Autoron Mode
|
||||
|
||||
value = (byte)(VAR.BOOL[eVarBool.FLAG_AUTORUN] ? 1 : 0);
|
||||
data.Add(value);
|
||||
|
||||
// RunSt
|
||||
if (PUB.AGV.error.Emergency)
|
||||
value = 2; // error
|
||||
else if (PUB.AGV.system1.agv_run)
|
||||
value = 1; // run
|
||||
else
|
||||
value = 0; // stop
|
||||
data.Add(value);
|
||||
|
||||
//runstep
|
||||
value = (byte)PUB.sm.RunStep;
|
||||
data.Add(value);
|
||||
|
||||
//runstepseq
|
||||
value = (byte)StepMC;
|
||||
data.Add(value);
|
||||
|
||||
// Motor Direction
|
||||
if (PUB.AGV.data.Direction == 'F')
|
||||
value = 0;
|
||||
else if (PUB.AGV.data.Direction == 'B')
|
||||
value = 1;
|
||||
else
|
||||
value = 0xff; //unknown
|
||||
data.Add(value);
|
||||
|
||||
// Magnet Direction
|
||||
if (PUB.AGV.data.Sts == 'L')
|
||||
value = 1; // left
|
||||
else if (PUB.AGV.data.Sts == 'R')
|
||||
value = 2; // right
|
||||
else if (PUB.AGV.data.Sts == 'S')
|
||||
value = 0; // straight
|
||||
else
|
||||
value = 0xFF; //unknown
|
||||
data.Add(value);
|
||||
|
||||
// ChargeSt
|
||||
value = (byte)((VAR.BOOL[eVarBool.FLAG_CHARGEONA] || VAR.BOOL[eVarBool.FLAG_CHARGEONM]) ? 1 : 0);
|
||||
data.Add(value);
|
||||
|
||||
// CartSt
|
||||
if (PUB.AGV.signal2.cart_detect1 && PUB.AGV.signal2.cart_detect2)
|
||||
value = 1; // 센서두개가 모두 감지되는 경우
|
||||
else if (PUB.AGV.signal2.cart_detect1 == false && PUB.AGV.signal2.cart_detect2 == false)
|
||||
value = 0; // 센서두개가 모두 감지되지 않는 경우
|
||||
else
|
||||
value = 2; // 센서하나만 감지되는 경우
|
||||
data.Add(value);
|
||||
|
||||
// LiftSt
|
||||
if (PUB.AGV.signal1.lift_up)
|
||||
value = 1; // 위로 올라가는 경우
|
||||
else if (PUB.AGV.signal1.lift_down)
|
||||
value = 0; // 아래로 내려가는 경우
|
||||
else
|
||||
value = 2; // unknown (기본값)
|
||||
data.Add(value);
|
||||
|
||||
// ErrorCode [New RunStepErrorCode]
|
||||
value = (byte)PUB.Result.RunStepErrorCode;
|
||||
data.Add(value);
|
||||
|
||||
// LastTag
|
||||
string lastTag = PUB.AGV.data.TagNo.ToString("0000") ?? "0000";
|
||||
byte[] tagBytes = Encoding.ASCII.GetBytes(lastTag.PadRight(4, '0'));
|
||||
data.AddRange(tagBytes);
|
||||
|
||||
// 데이터 전송
|
||||
var cmd = (byte)ENIGProtocol.AGVCommandEH.Status;
|
||||
var packet = proto.CreatePacket(PUB.setting.XBE_ID, cmd, data.ToArray());
|
||||
if (Send(packet))
|
||||
PUB.logxbee.AddI($"Send status [O] : {packet.Length} {packet.HexString()}");
|
||||
else
|
||||
PUB.logxbee.AddE($"Send status [X] : {packet.Length} {packet.HexString()}");
|
||||
LastStatusSendTime = DateTime.Now;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = ex.Message;
|
||||
PUB.logxbee.AddE(ErrorMessage);
|
||||
}
|
||||
finally
|
||||
{
|
||||
sendlock.Set();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user