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;
}
}
}