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; namespace Project.Device { public class Xbee : SerialPort { public string buffer = string.Empty; public System.Text.StringBuilder newbuffer = new StringBuilder(); public string errorMessage = string.Empty; public DateTime LastStatusSendTime = DateTime.Now; private EEProtocol proto; public Xbee() { 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; } /// /// 지그비장치에 데이터를 전송합니다 /// /// /// 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 Open() { try { base.Open(); return true; } 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}"); //TODO : 기능 처리필요 (XBee 메세지 데이터처리) //PUB.CheckManualChargeMode() : 수동충전확인 //VAR.BOOL[eVarBool.FLAG_AUTORUN] : 자동실행 //PUB.Speak("현재 위치는 QA 입니다.") : 음성출력 //ACS 수신 데이터 처리(타 장비는 확인하지 않는다) if (e.ReceivedPacket.ID == 0) { var data = e.ReceivedPacket.Data; switch (e.ReceivedPacket.Command) { case 1: //Request PATH var pathID = data[0]; var pathPage = data[1]; //TODO : 요청받은 맵 데이터를 전송해야한다 break; case 100: //move to tag var TargetTag = System.Text.Encoding.Default.GetString(data, 0, 6); //1.현재위치에서 경로계산 하여 경로저장 //2.현재위치를 모를경우 이전 이동 기록을 통해 위치를 추정한다 //3.대상태그에 맞는 전/후진 방향을 결정하여 이동을 수행한다 break; case 101: //stop PUB.AGV.AGVMoveStop("xbee"); break; case 102: //Error Reset PUB.AGV.AGVErrorReset(); break; case 103: //charing command (0:off, 1:on) var CharingCmd = data[0]; //0.자동모드가 아니라면 실행하지 않는다 //1.충전프로세스를 시작한다 //2.1분간 충전진행 신호가 없다면 반대편으로 1TAG이동하여 다시 시도한다 //3.3회 시도 실패시 오류 데이터를 HOST에 전송한다 break; case 104: //Manual Move (Direction, speed, runtime) var Direction = data[0]; //0=back, 1=forward, 2=left, 3=right var Speed = data[1]; //0=slow, 1=normal, 2=fast var Runtime = data[2]; // running seconds arDev.Narumi.ManulOpt opt = arDev.Narumi.ManulOpt.BS; arDev.Narumi.Speed spd = arDev.Narumi.Speed.Low; if (Speed == 1) spd = arDev.Narumi.Speed.Mid; else if (Speed == 2) spd = arDev.Narumi.Speed.High; //0.자동모드가 아니라면 실행하지 않는다 //1.입력된 파라미터로 AGV를 이동한다 if (Direction == 0) opt = arDev.Narumi.ManulOpt.BS; else if (Direction == 1) opt = arDev.Narumi.ManulOpt.FS; else if (Direction == 2) opt = arDev.Narumi.ManulOpt.LT; else if (Direction == 3) opt = arDev.Narumi.ManulOpt.RT; PUB.AGV.AGVMoveManual(opt, spd, arDev.Narumi.Sensor.PBSOn); break; case 105: //Set MarkStop var MarkStop = data[0]; //0=off, 1=on //마크센서에서 멈추게 한다 PUB.AGV.AGVMoveStop("Xbee", arDev.Narumi.eStopOpt.MarkStop); break; case 106: //Lift Control var LiftCommand = data[0]; //0=stop, 1=up, 2=down arDev.Narumi.LiftCommand LCmd = arDev.Narumi.LiftCommand.STP; if (LiftCommand == 1) LCmd = arDev.Narumi.LiftCommand.UP; else if (LiftCommand == 2) LCmd = arDev.Narumi.LiftCommand.DN; //리프트제어 PUB.AGV.LiftControl(LCmd); break; case 107: //clear path //TODO: 현재 설정된 경로삭제기능 필요 break; case 108: //send path //TODO : 경로정보를 수신받고 페이지가 1을 초과하면 나머지 페이지정보도 요청할 수 있어야 한다 break; } } } private void Proto_OnMessage(object sender, EEProtocol.MessageEventArgs e) { if (e.IsError) PUB.log.AddE(e.Message); else PUB.log.Add(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); } /// /// 이동완료 신호 전송 /// /// 목적지태그값 public void SendMoveComplete(string tag) { var id = PUB.setting.XBE_ID; byte cmd = 2; var data = System.Text.Encoding.Default.GetBytes(tag); var packet = proto.CreatePacket(id, cmd, data); Send(packet); } /// /// 신규 RFID태그값이 읽혔다면 이명령을 통해서 전송한다 /// public void SendRFIDTag(string tag) { var id = PUB.setting.XBE_ID; byte cmd = 3; var data = System.Text.Encoding.Default.GetBytes(tag); var packet = proto.CreatePacket(id, cmd, data); Send(packet); } /// /// AGV상태를 Xbee 로 전송한다 /// public void SendStatus() { /* Mode[1] : 0=manual, 1=auto RunSt[1] : 0=stop, 1=run, 2=error Diection[1] : 0=straight, 1=left, 2=right, 3=markstop Inposition[1] : 0=off, 1=on : 목적위치에 도달완료 시 설정 이동 이동시 OFF됨 ChargeSt[1] : 0=off, 1=on CartSt[1] : 0=off, 1=on, 2=unknown LiftSt[1] : 0=down , 1=up, 2=unknown LastTag[6] : "000000" */ try { byte[] data = new byte[13]; // 총 13바이트 데이터 // Mode data[0] = (byte)(VAR.BOOL[eVarBool.FLAG_AUTORUN] ? 1 : 0); // RunSt if (PUB.AGV.error.Emergency) data[1] = 2; // error else if (PUB.AGV.system1.agv_run) data[1] = 1; // run else data[1] = 0; // stop // Direction if (PUB.AGV.system1.stop_by_front_detect) data[2] = 3; // markstop else if (VAR.BOOL[eVarBool.FLAG_LEFT_RUN]) data[2] = 1; // left else if (VAR.BOOL[eVarBool.FLAG_RIGHT_RUN]) data[2] = 2; // right else data[2] = 0; // straight // Inposition data[3] = (byte)(PUB.AGV.system1.agv_stop ? 1 : 0); // ChargeSt data[4] = (byte)((VAR.BOOL[eVarBool.FLAG_CHARGEONA] || VAR.BOOL[eVarBool.FLAG_CHARGEONM]) ? 1 : 0); // CartSt if (PUB.AGV.signal.cart_detect1 && PUB.AGV.signal.cart_detect2) data[5] = 1; // 센서두개가 모두 감지되는 경우 else if (PUB.AGV.signal.cart_detect1 == false && PUB.AGV.signal.cart_detect2 == false) data[5] = 0; // 센서두개가 모두 감지되지 않는 경우 else data[5] = 2; // 센서하나만 감지되는 경우 // LiftSt if (PUB.AGV.signal.lift_up) data[6] = 1; // 위로 올라가는 경우 else if (PUB.AGV.signal.lift_down) data[6] = 0; // 아래로 내려가는 경우 else data[6] = 2; // unknown (기본값) // LastTag string lastTag = PUB.AGV.data.TagNo.ToString("000000") ?? "000000"; byte[] tagBytes = Encoding.ASCII.GetBytes(lastTag.PadRight(6, '0')); Array.Copy(tagBytes, 0, data, 7, 6); // 데이터 전송 var packet = proto.CreatePacket(PUB.setting.XBE_ID, 9, data); Send(packet); LastStatusSendTime = DateTime.Now; } catch (Exception ex) { errorMessage = ex.Message; PUB.logxbee.AddE(errorMessage); } } } }