using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.ComponentModel; using System.Reflection; using System.Runtime; using System.Runtime.InteropServices; using System.Collections.Concurrent; namespace arDev.Arduino { public partial class DIO : arRS232 { protected object lockobj = new object(); public struct SetupInfo { public byte ioInterval; public byte ResetCount; public byte SpeedH; public byte SpeedL; public byte SpeedZ; public byte pindirRevDILow; public byte pindirRevDIHigh; public byte UpTime; public byte BalanceThd; public byte MarkThd; public byte SpeedC; public byte BalanceThdUp; public Boolean IsValid; public void Clear() { pindirRevDIHigh = 0; pindirRevDILow = 0; ioInterval = 0; ResetCount = 0; SpeedH = 0; SpeedL = 0; SpeedC = 0; BalanceThd = 0; BalanceThd = 0; UpTime = 0; MarkThd = 0; SpeedZ = 0; IsValid = false; } } public SetupInfo setupInfo; private Boolean STX11 = false; private Boolean STX21 = false; //private Boolean ETX11 = false; // private byte[] buffer1; // readonly List Tempbuffer1 = new List(); readonly ManualResetEvent mre = new ManualResetEvent(true); // protected string errorMessage = string.Empty; // readonly System.IO.Ports.SerialPort dev = null; private byte LEN1 = 0; //private byte CHK1 = 0; //private int bufferCount1 = 0; public DateTime ConnTryTime = DateTime.Now.AddDays(-1); protected DateTime[] SetFlagTime = new DateTime[32]; readonly Boolean[] Flag = new bool[32]; readonly Boolean[] DIValue = new bool[16]; readonly Boolean[] DOValue = new bool[16]; public UInt16[] AIValue = new ushort[3]; public byte[] AOValue = new byte[3]; public string ioBinStr = string.Empty; public string SetupStr = string.Empty; public byte RunTime = 0; public byte[] MAG_VALUE = new byte[2]; public byte[] SV_SPEED = new byte[2]; public Boolean isDisposed = false; //dispose가 호출되었는가? public string LastMessage { get; set; } public DateTime LastMessageTime { get; set; } /// /// 생성자 /// public DIO() { //설정의 값 setupInfo = new SetupInfo(); setupInfo.Clear(); SV_SPEED[0] = 0; SV_SPEED[1] = 0; //마그넷 센서(0~100) MAG_VALUE[0] = 50; MAG_VALUE[1] = 50; lastRecvTime = DateTime.Parse("1982-11-23"); for (int i = 0; i < Flag.Length; i++) Flag[i] = false; for (int i = 0; i < DIValue.Length; i++) DIValue[i] = false; for (int i = 0; i < DOValue.Length; i++) DOValue[i] = false; for (int i = 0; i < AIValue.Length; i++) AIValue[i] = 0; for (int i = 0; i < AOValue.Length; i++) AOValue[i] = 0; for (int i = 0; i < SetFlagTime.Length; i++) SetFlagTime[i] = DateTime.Parse("1982-11-23"); } protected override bool CustomParser(byte[] buf, out byte[] remainBuffer) { List remain = new List(); Boolean bComplete = false; for (int i = 0; i < buf.Length; i++) { var incomByte = buf[i]; if (bComplete == true) { remain.Add(incomByte); } else { if (STX11 == false) { if (incomByte != '@') { STX21 = false; // ETX11 = false; continue; } else { STX11 = true; tempBuffer.Clear(); tempBuffer.Add(incomByte); } } else if (STX21 == false) { if (tempBuffer.Count != 1 || tempBuffer.Count < 1 || tempBuffer[0] != '@' || incomByte != '@') { STX11 = false; //ETX11 = false; continue; } else { STX21 = true; tempBuffer.Add(incomByte); } } else { tempBuffer.Add(incomByte); //여기서부터는무조건 누적한다. if (tempBuffer.Count == 3) { if (tempBuffer[0] != '@' || tempBuffer[1] != '@') { STX11 = false; STX21 = false; // ETX11 = false; LEN1 = 0; tempBuffer.Clear(); } else LEN1 = incomByte; //데이터 길이가온다 } //else if (Tempbuffer1.Count == LEN1 + 5) //ETX1 //{ // if (incomingByte != 0x0D) // { // //ETX가 와야하는데 다른데이터가 왔다 // STX11 = false; // STX21 = false; // // ETX11 = false; // var str = System.Text.Encoding.Default.GetString(Tempbuffer1.ToArray()); // RaiseMessage(MessageType.ReceiveData, "에러 모두 파기 : " + str, true); // Tempbuffer1.Clear(); // } //} else if (tempBuffer.Count == LEN1 + 6) { //전체길이를 만족햇다. if (incomByte != 0x0A) { //ETX가 와야하는데 다른데이터가 왔다 STX11 = false; STX21 = false; // ETX11 = false; //var str = System.Text.Encoding.Default.GetString(Tempbuffer1.ToArray()); RaiseMessage(MessageType.Error, "에러 모두 파기 : ETX 값 오류"); tempBuffer.Clear(); } else if (tempBuffer[tempBuffer.Count - 2] != 0x0D) { //ETX가 와야하는데 다른데이터가 왔다 STX11 = false; STX21 = false; // ETX11 = false; //var str = System.Text.Encoding.Default.GetString(Tempbuffer1.()); RaiseMessage(MessageType.Error, "에러 모두 파기 : ETX 값 오류"); tempBuffer.Clear(); } else { STX11 = false; STX21 = false; // ETX11 = false; //if (LastReceiveBuffer == null) LastReceiveBuffer = new byte[tempBuffer.Count]; //else if (LastReceiveBuffer.Length != tempBuffer.Count) Array.Resize(ref LastReceiveBuffer, Tempbuffer1.Count); //tempBuffer.CopyTo(LastReceiveBuffer)tempBuffer //tempBuffer.Clear(); bComplete = true; } } } } } remainBuffer = remain.ToArray(); return bComplete; } bool Checksum(byte[] buffer, int datalength) { //체크섬필요 221118 if (buffer[buffer.Length-3] == '*') { return true; } byte checksum = 0; for (int i = 3; i < datalength + 3; i++) { checksum = (byte)(checksum ^ buffer[i]); } return checksum == buffer[buffer.Length - 3]; } public override bool ProcessRecvData(byte[] data) { var hexString = GetHexString(data);//.gethe var len = data[2]; if (len + 6 != data.Length) { RaiseMessage(MessageType.Error, string.Format("길이오류 예상:{0},수신:{1},{2}", len + 5, data.Length, hexString)); } else if (data[0] != 0x40 || data[1] != 0x40 || data[data.Length - 2] != 0x0D || data[data.Length - 1] != 0x0A) { RaiseMessage(MessageType.Error, string.Format("헤더 오류 : {0}", hexString)); } else if (Checksum(data, len) == false) //체크섬 221118 { RaiseMessage(MessageType.Error, string.Format("체크섬 오류 : {0}", hexString)); } else { //RaiseMessage(MessageType.ReceiveData, hexString); lastRecvTime = DateTime.Now; var cmd = data[3]; if (cmd == 'I') //IOData { if (len != 10) RaiseMessage(MessageType.Error, "IO수신길이오류:" + DateTime.Now.ToString("mm:ss.fff") + " 수신 : " + hexString); else Parse_IOData(data); } else if (cmd == 'T') { // Boolean errorMessage = buffer[4] == 1; var message = System.Text.Encoding.Default.GetString(data, 5, len - 2);//데이터타입과 에러여부 제거 LastMessage = message; LastMessageTime = DateTime.Now; RaiseMessage(MessageType.Normal, message); } else if (cmd == 'S') //setup 정보 200310 (홈) { if (len != 13) RaiseMessage(MessageType.Error, "SETUP수신길이오류:" + DateTime.Now.ToString("mm:ss.fff") + " 수신 : " + hexString); else Parse_SetupData(data); } else { RaiseMessage(MessageType.Normal, "Unknown:" + hexString + "\n" + "Data=" + System.Text.Encoding.Default.GetString(data)); } } return true; } void Parse_IOData(byte[] buffer) { var IOData = BitConverter.ToUInt32(buffer, 4); //var newMagF = BitConverter.ToUInt16(buffer, 8); //va1r newMagB = BitConverter.ToUInt16(buffer, 10); //var newAlign = BitConverter.ToUInt16(buffer, 12); //if (newMagF != AIValue[0] || newMagB != AIValue[1]) //{ // AIValue[0] = newMagF;// BitConverter.ToUInt16(buffer, 8); //마그넷센서 F // AIValue[1] = newMagB; //BitConverter.ToUInt16(buffer, 10); //마그넷센서 B // PositionChanged?.Invoke(this, null); //} //AIValue[2] = newAlign; //AOValue[0] = buffer[14]; //왼쪽바퀴 속도 //AOValue[1] = buffer[15]; //오른쪽바퀴 속도 //AOValue[2] = buffer[16]; //Z축 속도 //SV_SPEED[0] = buffer[21]; //왼쪽바퀴의 설정속도 //SV_SPEED[1] = buffer[22]; //오른쪽바퀴의 설정속도 //MAG_VALUE[0] = buffer[23]; //magnet front //MAG_VALUE[1] = buffer[24]; //magnet rear RunTime = buffer[12]; //플래그값 확인 byte[] buf_flag = new byte[4]; Array.Copy(buffer, 8, buf_flag, 0, 4); var baF = new System.Collections.BitArray(buf_flag); for (int i = 0; i < 32; i++) { Boolean val = baF[i]; //입력 if (this.Flag[i] != val) { Flag[i] = val; //변경이벤트 생성 FlagChanged?.Invoke(this, new FlagValueEventArgs(i, !val, val)); } } //IO값 확인 byte[] buf_iodata = new byte[4]; Array.Copy(buffer, 4, buf_iodata, 0, 4); var ba = new System.Collections.BitArray(buf_iodata); for (int i = 0; i < 32; i++) { Boolean val = ba[i]; if (i >= 16) { //출력 if (DOValue[i - 16] != val) { DOValue[i - 16] = val; //변경이벤트 생성 ValueChanged?.Invoke(this, new IOValueEventArgs(IODirection.Output, i - 16, !val, val)); } } else { //입력 if (DIValue[i] != val) { DIValue[i] = val; //변경이벤트 생성 ValueChanged?.Invoke(this, new IOValueEventArgs(IODirection.Input, i, !val, val)); } } } ioBinStr = Convert.ToString(IOData, 2).PadLeft(32, '0'); //string msg = string.Format(DateTime.Now.ToString("mm:ss.fff") + " IO:{0},AN={1:0000},{2:0000},FG={3},AO={4},{5}", // binstr, An1, An2, FGData, Ao11, Ao12); } void Parse_SetupData(byte[] buffer) { setupInfo.ioInterval = buffer[4]; setupInfo.ResetCount = buffer[5]; setupInfo.SpeedH = buffer[6]; setupInfo.SpeedL = buffer[7]; setupInfo.SpeedZ = buffer[8]; setupInfo.pindirRevDIHigh = buffer[9]; setupInfo.pindirRevDILow = buffer[10]; setupInfo.UpTime = buffer[11]; setupInfo.BalanceThd = buffer[12]; setupInfo.MarkThd = buffer[13]; setupInfo.SpeedC = buffer[14]; setupInfo.BalanceThdUp = buffer[15]; SetupStr = string.Format("I:{0},R={1},H={2},L={3},Z={4},UP={5},BL={6},MK={7},SPD_C={8},BLUP={9}", setupInfo.ioInterval, setupInfo.ResetCount, setupInfo.SpeedH, setupInfo.SpeedL, setupInfo.SpeedZ, setupInfo.UpTime, setupInfo.BalanceThd, setupInfo.MarkThd, setupInfo.SpeedC, setupInfo.BalanceThdUp); } public byte MakeChecksum(byte[] buffer) { //return 0; byte chk = 0; foreach (var b in buffer) chk = (byte)(chk ^ b); return chk; } #region "Method" protected Boolean Sendcommand(byte cmd, byte p1, byte p2) { //이번호의 상태를 on/off 해줘야함 List buffer = new List { cmd, //command p1, p2 }; byte dataLen = (byte)buffer.Count; //데이터길이 byte checksum = MakeChecksum(buffer.ToArray()); buffer.Insert(0, (byte)'@'); //stx buffer.Insert(1, (byte)'@'); //stx buffer.Insert(2, dataLen); buffer.Add(checksum); //길이를 제외한 실제 데이터 영역만 체크섬 buffer.Add(0x0D); //etx buffer.Add(0x0A); //etx return WriteData(buffer.ToArray()); } /// /// 이벤트를 강제 생성합니다.(내부변수값도 변경됩니다) /// /// /// /// public void RaiseEvent(IODirection dir, int idx, Boolean value) { if (ValueChanged != null) { if (!mre.WaitOne(100)) { RaiseMessage( MessageType.Error, "RaiseEvent WaitOne Timeout"); return; } mre.Reset(); bool curValue; if (dir == IODirection.Input) { curValue = DIValue[idx]; DIValue[idx] = value; } else { curValue = DOValue[idx]; DOValue[idx] = value; } try { //이벤트를 할당한곳에서 오류가 나면 이곳에서 에러가 잡힌다. ValueChanged(this, new IOValueEventArgs(dir, idx, curValue, value)); } catch (Exception ex) { RaiseMessage(MessageType.Error, ex.Message); } finally { mre.Set(); } } } //public Boolean GetFlag(byte idx) //{ // return Flag[idx]; //} public Boolean GetValueI(byte idx) { if (idx < DIValue.Length) return DIValue[idx]; else return false; } public Boolean GetValueO(byte idx) { if (idx < DOValue.Length) return DOValue[idx]; else return false; } //public Boolean SetValueI(int idx,Boolean value) //{ // if (idx < DIValue.Length) // { // DIValue[idx] = value; // return true; // } // else return false; //} public Boolean SetValue(byte idx, Boolean value) { byte SET_PINMODE = 3; if (value == true) return Sendcommand(SET_PINMODE, idx, 1); else return Sendcommand(SET_PINMODE, idx, 0); } public Boolean SetToggle(byte idx) { var curbalue = GetValueO(idx); return SetValue(idx, !curbalue); } public string GetErrorMessage() { return errorMessage; } #endregion } }