using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; using System.Threading; using System.Threading.Tasks; using System.Collections; using COMM; using System.Security.Cryptography.X509Certificates; using AR; namespace arDev { public enum eNarumiTurn { None = 0, LeftIng, Left, RightIng, Right, } public class NarumiTurnInfo { public DateTime Start { get; set; } public DateTime End { get; set; } public TimeSpan Runtime { get { if (End.Year < 2000) return DateTime.Now - Start; if (End < Start) return DateTime.Now - Start; else return End - Start; } } public eNarumiTurn State { get; set; } public NarumiTurnInfo() { Start = new DateTime(1982, 11, 23); End = new DateTime(1982, 11, 23); State = eNarumiTurn.None; } } public class NarumiCommandTime { public DateTime Time { get; set; } public ushort count { get; set; } public NarumiCommandTime(ushort cnt) { Time = DateTime.Now; this.count = cnt; } } /// /// error 이상은모두 처리불가한 오류 조건을 의미한다 /// public enum eNarumiCommandResult : byte { Fail = 0, Success = 1, Wait = 2, Error = 100, Timeout, } public partial class Narumi { public NarumiTurnInfo TurnInformation { get; set; } = null; Dictionary SendCommandFailList { get; set; } = new Dictionary(); public eNarumiCommandResult AGVMoveSet(BunkiData opt) { var param = opt.ToString(); return AddCommand(eAgvCmd.MoveSet, param); } public eNarumiCommandResult AGVMoveManual(ManulOpt opt, Speed spd, Sensor ss) { var param = opt.ToString() + spd.ToString()[0] + ((int)ss).ToString(); return AddCommand(eAgvCmd.ManualMove, param); } public eNarumiCommandResult AGVMoveRun(eRunOpt opt = eRunOpt.NotSet) { System.Text.StringBuilder sb = new StringBuilder(); if (opt == eRunOpt.Backward) sb.Append("B"); else if (opt == eRunOpt.Forward) sb.Append("F"); else sb.Append("0"); sb.Append("000"); return AddCommand(eAgvCmd.MoveStart, sb.ToString()); } public eNarumiCommandResult AGVSetSpeed(eSetSpeed item, int speed) { string cmd = "SS"; if (item == eSetSpeed.Rotation) cmd = "SRS"; else cmd += item.ToString()[0]; cmd += speed.ToString("0000"); return AddCommand(cmd); } public eNarumiCommandResult AGVMoveStop(string Reason, eStopOpt opt = eStopOpt.Stop) { System.Text.StringBuilder sb = new StringBuilder(); if (opt == eStopOpt.MarkStop) sb.Append("MS"); else if (opt == eStopOpt.MarkRotateLeft) sb.Append("TL"); else if (opt == eStopOpt.MarkRotateRight) sb.Append("TR"); else if (opt == eStopOpt.MarkChangeDirection) sb.Append("BS"); else sb.Append("0S"); sb.Append("00"); sb.Append("0000"); //재기동시간 //동작중이면 이 멈춤 명령을 기록으로 남긴다 230116 if (this.system1.agv_run) RaiseMessage(MessageType.Normal, $"stop command from {Reason}"); var retval = AddCommand(eAgvCmd.MoveStop, sb.ToString()); if (retval == eNarumiCommandResult.Success && opt == eStopOpt.MarkStop) VAR.BOOL[eVarBool.NEXTSTOP_MARK] = true; return retval; } public eNarumiCommandResult AGVCommand(string cmd, string data) { return AddCommand(cmd + data); } public eNarumiCommandResult LiftControl(LiftCommand cmd) { return AddCommand(eAgvCmd.LiftControl, cmd.ToString()); } public eNarumiCommandResult AGVCharge(int chargetID, bool on, int waittime = 3) { if (on) return AddCommand(eAgvCmd.ChargeOn, chargetID.ToString("0000")); else return AddCommand(eAgvCmd.ChargeOf, chargetID.ToString("0000")); } public eNarumiCommandResult SetBackturnTime(int time) { return AddCommand(eAgvCmd.BackTrunResumeTime, time.ToString("0000")); } public eNarumiCommandResult SetGateOutOffTime(int time) { return AddCommand(eAgvCmd.GateoutTime, time.ToString("0000")); } public eNarumiCommandResult TurnGDSCenterScope(UInt16 time) { if (time > 2000) time = 2000; return AddCommand(eAgvCmd.TurnGDSCenterScope, time.ToString("0000")); } public eNarumiCommandResult AGVMoveLeft180Turn() { return AddCommand(eAgvCmd.TurnLeft); } public eNarumiCommandResult AGVMoveRight180Turn() { return AddCommand(eAgvCmd.TurnRight); } public eNarumiCommandResult AGVMoveBack180Turn(bool leftTurn) { var dir = leftTurn ? "L" : "R"; return AddCommand(eAgvCmd.BackAndTurn, dir); } public eNarumiCommandResult AGVErrorReset() { return AddCommand(eAgvCmd.ErrorReset, "FFFF"); } public eNarumiCommandResult AGVTowerLamp(bool on) { return AddCommand(eAgvCmd.TowerLamp, (on ? "I" : "O")); } public eNarumiCommandResult AGVSetAddress(int value) { return AddCommand($"SAD{value:0000}"); } public eNarumiCommandResult AGVSetPanID(string value) { value = value.PadLeft(4, '0'); return AddCommand($"SPN{value}"); } public eNarumiCommandResult AGVSetChannel(string value) { value = value.PadLeft(4, '0'); return AddCommand($"SCH{value}"); } public eNarumiCommandResult AGVSetTagReinputTime(int value) { return AddCommand($"STT{value:0000}"); } ///// ///// 전송에 성공한 명령시간 ///// ////public Dictionary LastCommandOKTime { get; set; } protected bool SendCommand(string cmdline) { bool ret = true; ACKData = string.Empty; var fullcmd = MakeCheckSum(cmdline); if (WriteData(fullcmd) == false) ret = false; System.Threading.Thread.Sleep(1); return ret; } ManualResetEvent mrecmd = new ManualResetEvent(true); public eNarumiCommandResult AddCommand(string cmd, int waitms = 1) { if (mrecmd.WaitOne(waitms) == false) { //다른명령을 처리하는 중이므로 대기상태로 반환한다 return eNarumiCommandResult.Wait; } //다른신호를 처리하지 못하게한다. mrecmd.Reset(); try { if (SendCommandFailList.ContainsKey(cmd) == false) { //실패기록이 없다 var ret = SendCommand(cmd); if (ret == false) { SendCommandFailList.Add(cmd, new NarumiCommandTime(1)); return eNarumiCommandResult.Fail; } else return eNarumiCommandResult.Success; } else { //실패기록이 존재한다. //1.동일 명령이 아니면 바로 전송한다 var precmd = SendCommandFailList[cmd]; //동일명령의 실패기록이 존재한다. //2초간의 간격을 둔다 var ts = DateTime.Now - precmd.Time; if (ts.TotalSeconds < 2) { precmd.Time = DateTime.Now; SendCommandFailList[cmd] = precmd; return eNarumiCommandResult.Wait; //대기한다 } else { //오류가 누적되었다. var ret = SendCommand(cmd); if (ret == false) { precmd.Time = DateTime.Now; precmd.count += 1; SendCommandFailList[cmd] = precmd; //5회연속 실패했다면 타임아웃처리한다 if (precmd.count > 5) { //타임아웃 return eNarumiCommandResult.Timeout; } else { //실패 return eNarumiCommandResult.Fail; } } else { //전송이성공했으니 키를 제거한다. SendCommandFailList.Remove(cmd); return eNarumiCommandResult.Success; } } } } catch (Exception ex) { Console.WriteLine($"narumi addCommand error : {ex.Message}"); return eNarumiCommandResult.Error; } finally { mrecmd.Set(); } } protected eNarumiCommandResult AddCommand(eAgvCmd command, BunkiData param) { return AddCommand(command, param.ToString()); } /// /// CBR커맨드를 사용하여 옵션값을 전송 합니다 /// 11.분기명령 = CBR /// /// /// protected eNarumiCommandResult AddCommand(BunkiData param) { return AddCommand(eAgvCmd.MoveSet, param.ToString()); } protected eNarumiCommandResult AddCommand(eAgvCmd command, string param = "") { string cmdString; eNarumiCommandResult retval = eNarumiCommandResult.Error; switch (command) { case eAgvCmd.ErrorReset: cmdString = $"SFR{param}"; retval = AddCommand(cmdString); break; case eAgvCmd.TowerLamp: cmdString = $"CBZ" + $"0299{param}0000"; retval = AddCommand(cmdString); break; case eAgvCmd.MoveStop: cmdString = $"CST{param}"; system1.agv_run_manual = false; retval = AddCommand(cmdString); break; case eAgvCmd.MoveStart: cmdString = $"CRN{param}"; retval = AddCommand(cmdString); break; case eAgvCmd.ChargeOf: cmdString = $"CBT{param}O0003"; ///0003=충전대기시간 retval = AddCommand(cmdString); RaiseMessage(NarumiSerialComm.MessageType.Normal, "충전취소전송"); break; case eAgvCmd.ChargeOn: cmdString = $"CBT{param}I0003"; ///0003=충전대기시간 retval = AddCommand(cmdString); RaiseMessage(NarumiSerialComm.MessageType.Normal, "충전명령전송"); break; case eAgvCmd.TurnLeft: cmdString = $"CTL0000"; retval = AddCommand(cmdString); if (retval == eNarumiCommandResult.Success) { if (TurnInformation == null) TurnInformation = new NarumiTurnInfo(); TurnInformation.Start = DateTime.Now; TurnInformation.End = new DateTime(1982, 11, 23); TurnInformation.State = eNarumiTurn.LeftIng; } break; case eAgvCmd.TurnRight: cmdString = $"CTR0000"; retval = AddCommand(cmdString); if (retval == eNarumiCommandResult.Success) { if (TurnInformation == null) TurnInformation = new NarumiTurnInfo(); TurnInformation.Start = DateTime.Now; TurnInformation.End = new DateTime(1982, 11, 23); TurnInformation.State = eNarumiTurn.RightIng; } break; case eAgvCmd.BackAndTurn: if (param.isEmpty()) param = "L"; cmdString = $"CTB000{param}"; retval = AddCommand(cmdString); break; case eAgvCmd.CallCancle: cmdString = $"CCL0{param}010000"; retval = AddCommand(cmdString); break; case eAgvCmd.MoveSet: cmdString = $"CBR{param}"; retval = AddCommand(cmdString); break; case eAgvCmd.ManualMove: system1.agv_run_manual = true; cmdString = $"CRT{param}"; retval = AddCommand(cmdString); break; case eAgvCmd.LiftControl: cmdString = "CLF" + param.PadRight(6, '0'); retval = AddCommand(cmdString); break; case eAgvCmd.CPUReset: cmdString = "CRS0000"; retval = AddCommand(cmdString); break; case eAgvCmd.TurnGDSCenterScope: if (param.isEmpty()) param = "1000"; cmdString = $"SGS{param}"; retval = AddCommand(cmdString); break; case eAgvCmd.BackTrunResumeTime: cmdString = $"SST{param}"; retval = AddCommand(cmdString); break; case eAgvCmd.GateoutTime: cmdString = $"SGT{param}"; retval = AddCommand(cmdString); break; } return retval; } } }