파일정리

This commit is contained in:
ChiKyun Kim
2026-01-29 14:03:17 +09:00
parent 00cc0ef5b7
commit 58ca67150d
440 changed files with 47236 additions and 99165 deletions

View File

@@ -0,0 +1,414 @@
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;
}
}
/// <summary>
/// error 이상은모두 처리불가한 오류 조건을 의미한다
/// </summary>
public enum eNarumiCommandResult : byte
{
Fail = 0,
Success = 1,
Wait = 2,
Error = 100,
Timeout,
}
public partial class Narumi
{
public NarumiTurnInfo TurnInformation { get; set; } = null;
Dictionary<string, NarumiCommandTime> SendCommandFailList { get; set; } = new Dictionary<string, NarumiCommandTime>();
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}");
}
///// <summary>
///// 전송에 성공한 명령시간
///// </summary>
////public Dictionary<String, DateTime> 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());
}
/// <summary>
/// CBR커맨드를 사용하여 옵션값을 전송 합니다
/// 11.분기명령 = CBR
/// </summary>
/// <param name="param"></param>
/// <param name="Repeat"></param>
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;
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
namespace arDev
{
public partial class Narumi
{
public class DataEventArgs : EventArgs
{
public DataType DataType { get; set; }
public DataEventArgs(DataType type)
{
DataType = type;
}
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
using System.Linq;
using AR;
namespace arDev
{
public partial class Narumi
{
public class Dataframe
{
public byte STX { get; private set; }
public byte ETX { get; private set; }
public byte[] Data { get; private set; }
public string DataString { get; private set; }
public byte[] checksum { get; private set; } = new byte[2];
public bool Valid { get; private set; } = false;
public string Message { get; private set; } = string.Empty;
public byte[] Buffer { get; private set; }
public string Cmd { get; private set; } = string.Empty;
public bool Parse(byte[] data, int MinRecvLength = 0)
{
if (data == null || data.Any() == false)
{
this.Message = string.Format("수신 데이터가 없습니다");
return false;
}
else if (data.Length < 5)
{
this.Message = $"데이터의 길이가 5보다 작습니다 길이={data.Length}";
return false;
}
else if (MinRecvLength > 0 && data.Length < MinRecvLength)
{
this.Message = $"데이터의 길이가 {MinRecvLength}보다 작습니다 길이={data.Length}";
return false;
}
else if (data[0] != 0x02 || data[data.Length - 1] != 0x03)
{
this.Message = $"STX/ETX Error";
return false;
}
Buffer = new byte[data.Length];
Array.Copy(data, Buffer, data.Length);
STX = data[0];
ETX = data[data.Length - 1];
Array.Copy(data, data.Length - 3, checksum, 0, 2);
Data = new byte[data.Length - 4];
Array.Copy(data, 1, Data, 0, data.Length - 4);
if (data.Length > 2) Cmd = System.Text.Encoding.Default.GetString(Data, 0, 3);
this.DataString = System.Text.Encoding.Default.GetString(Data);
Valid = true;
return true;
}
public Dataframe(byte[] buffer = null, int minlen = 0)
{
if (buffer != null) Parse(buffer);
}
}
}
}

View File

@@ -0,0 +1,221 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace arDev
{
public partial class Narumi
{
public enum eMoveDir
{
Forward,
Backward,
}
public enum eMoveSpd
{
High,
Mid,
Low,
}
public enum eSetPIDSpeed
{
High,
Middle,
Low,
Stop,
}
public enum eSetSpeed
{
High,
Middle,
Low,
Stop,
Rotation,
}
public enum eBunki
{
Right,
Strate,
Left,
}
public enum Messagetype
{
Normal,
Error,
Send,
Recv,
}
public enum DataType
{
UNKNOWN,
TAG,
CALL,
STS,
ACK,
NAK,
CCA,
}
public class BunkiData
{
public BunkiData()
{
}
public BunkiData(char dir, char bunki, char speed)
{
if (dir == 'F') Direction = eMoveDir.Forward;
else if (dir == 'B') Direction = eMoveDir.Backward;
if (bunki == 'S') Bunki = eBunki.Strate;
else if (bunki == 'L') Bunki = eBunki.Left;
else if (bunki == 'R') Bunki = eBunki.Right;
if (speed == 'H') this.Speed = eMoveSpd.High;
else if (speed == 'M') this.Speed = eMoveSpd.Mid;
else if (speed == 'L') this.Speed = eMoveSpd.Low;
}
public eMoveDir Direction { get; set; } = eMoveDir.Forward;
public eBunki Bunki { get; set; } = eBunki.Strate;
public eMoveSpd Speed { get; set; } = eMoveSpd.Mid;
public int PBSSensor { get; set; } = 1;
public override string ToString()
{
System.Text.StringBuilder sb = new StringBuilder();
sb.Append(Direction.ToString()[0]);
sb.Append(Bunki.ToString()[0]);
sb.Append(Speed.ToString()[0]);
sb.Append(PBSSensor.ToString()[0]);
return sb.ToString();
}
}
public enum eAgvCmd
{
/// <summary>
/// 충전시작
/// CMD : CBT02{nBatteryNo}I0103
/// </summary>
ChargeOn,
/// <summary>
/// 충전취소
/// CMD : CBT02{nBatteryNo}O0103
/// </summary>
ChargeOf,
/// <summary>
/// 이동명령(파라미터필요)
/// 이동대상,속도(H,M,L),센서사용여부(1,0)
/// ex) BSLTH0
/// CMD : CRT{param}
/// </summary>
ManualMove,
/// <summary>
/// 기동명령
/// CMD : CRN0000
/// </summary>
MoveStart,
/// <summary>
/// 분기명령
/// CMD : CBR{param}
/// </summary>
MoveSet,
/// <summary>
/// 정지 명령
/// CMD : CST0S000000
/// </summary>
MoveStop,
/// <summary>
/// 콜 취소,
/// Param : 번호 char(1)
/// CMD : CCL0{param}010000
/// </summary>
CallCancle,
/// <summary>
/// CMD : CTL0000
/// </summary>
TurnLeft,
/// <summary>
/// CMD : CTR0000
/// </summary>
TurnRight,
/// <summary>
/// CMD : CTB0000
/// </summary>
BackAndTurn,
/// <summary>
/// CMD : CBZ
/// </summary>
TowerLamp,
/// <summary>
/// CMD : SFR
/// </summary>
ErrorReset,
/// <summary>
/// CMD : CLF
/// </summary>
LiftControl,
/// <summary>
/// SS(H/M/L/S)
/// SRS
/// </summary>
SetSpeed,
CPUReset,
TurnGDSCenterScope,
BackTrunResumeTime,
GateoutTime,
}
public enum eForm
{
DriveControl,
ManualControl,
RouteSelect,
Setting,
ModeChange,
}
public enum eNotify
{
ReadTag,
IpAddresschanged,
NameChanged,
ReadViewStep,
ReadViewCall,
WatchError,
/// <summary>
/// 통신에서받은 AGV의 상태값이며, 속도 진행 방향을 가지고 있음
/// Dashboardform 하단에 상태 표시 함
/// </summary>
StatusDisplay,
StatusComm,
StatusRiv,
StatusETC,
ChangeMode,
/// <summary>
/// 편집대상경로는 아래 변수에 저장되어잇음
/// datamanager.sEditrRoute
/// </summary>
EditRoute,
}
}
}

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8BAE0EAC-3D25-402F-9A65-2BA1ECFE28B7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>arDevice</RootNamespace>
<AssemblyName>Narumi</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="arCommUtil">
<HintPath>..\..\..\DLL\arCommUtil.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DataEventArgs.cs" />
<Compile Include="Dataframe.cs" />
<Compile Include="EnumData.cs" />
<Compile Include="Command.cs" />
<Compile Include="NarumiSerialComm.cs" />
<Compile Include="Structure\ErrorFlag.cs" />
<Compile Include="Narumi.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Structure\SystemFlag0.cs" />
<Compile Include="Structure\AgvData.cs" />
<Compile Include="Structure\Signals.cs" />
<Compile Include="Structure\SystemFlag1.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CommData\CommData.csproj">
<Project>{14e8c9a5-013e-49ba-b435-efefc77dd623}</Project>
<Name>CommData</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,519 @@
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 AR;
using System.Xml;
namespace arDev
{
public partial class Narumi : arDev.NarumiSerialComm
{
Hashtable SystemCheck, ErrorCheck;
private Queue Errlog; // 에러발생시 코드 임시 저장용(쓰레드 동기화용)
public int nBatteryNo { get; set; } = 0;
public Narumi()
{
SystemCheck = new Hashtable();
SystemCheck.Add(15, "100");
SystemCheck.Add(14, "9");
SystemCheck.Add(13, "8");
SystemCheck.Add(12, "53");
SystemCheck.Add(11, "3");
//SystemCheck.Add(10, "66");
//SystemCheck.Add(9, "56");
SystemCheck.Add(8, "6");
SystemCheck.Add(7, "5");
SystemCheck.Add(6, "60");
SystemCheck.Add(5, "1");
SystemCheck.Add(4, "2");
//SystemCheck.Add(3, "65");
//SystemCheck.Add(2, "55");
//SystemCheck.Add(1, "11");
//SystemCheck.Add(0, "22");
ErrorCheck = new Hashtable();
ErrorCheck.Add(15, "17");
ErrorCheck.Add(14, "15");
ErrorCheck.Add(13, "18");
ErrorCheck.Add(12, "19");
//ErrorCheck.Add(11, "300");
ErrorCheck.Add(10, "299");
ErrorCheck.Add(9, "298");
ErrorCheck.Add(8, "297");
ErrorCheck.Add(7, "296");
//ErrorCheck.Add(6,"");
ErrorCheck.Add(5, "12");
ErrorCheck.Add(4, "13");
ErrorCheck.Add(3, "14");
ErrorCheck.Add(2, "16");
ErrorCheck.Add(1, "11");
ErrorCheck.Add(0, "10");
Errlog = new Queue();
MinRecvLength = 4;
}
#region "External Events"
/// <summary>
/// 분석완료된 데이터 이벤트
/// </summary>
public event EventHandler<DataEventArgs> DataReceive;
#endregion
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 (incomByte == 0x02)
{
findSTX = true;
tempBuffer.Clear();
tempBuffer.Add(incomByte);
}
else if (incomByte == 0x03)
{
//데이터가 맞게 수신됨
//tempBuffer.Add(incomByte);
tempBuffer.Add(incomByte);
findSTX = false;
bComplete = true;
}
else
{
tempBuffer.Add(incomByte);
if (tempBuffer.Count == 150) //data overload
{
findSTX = false;
tempBuffer.Clear();
bComplete = false;
RaiseMessage(MessageType.Error, "Buffer Over");
}
}
}
}
remainBuffer = remain.ToArray();
return bComplete;
}
public override bool ProcessRecvData(byte[] data)
{
//LastReceiveBuffer
var frame = new Dataframe(data, MinRecvLength);
if (frame.Valid == false)
{
RaiseMessage(MessageType.Error, frame.Message);
return false;
}
else if (frame.DataString.StartsWith("$") == false && CheckSum(data) == false)
{
RaiseMessage(MessageType.Error, "Checksum Error MSG=" + frame.DataString);
return false;
}
var retval = true;
///////////////////////////////////////////////////////////////////////////////
if (frame.Cmd.Equals("ACK") || frame.Cmd.Equals("NAK"))
{ // 응답확인값 수신 : Header(ACX), Length(9), CheckSum 확인
RevACK(frame);
}
///////////////////////////////////////////////////////////////////////////////
else if (frame.Cmd.Equals("STS"))
{ // AGV 상태 정보 : Header(STS), Length(30), CheckSum 확인
RevSTS(frame);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
else if ((frame.Cmd.Equals("TAG") || frame.Cmd.Equals("CAL") || frame.Cmd.Equals("CCA")))
{ // TAG ID 정보 : Header(STX), Length(13), CheckSum 확인
RevTAG(frame);
}
else if (frame.DataString.StartsWith("$"))
{
// $로 시작되는 AGV 상태 표시
//var text_Sts_Etc = Encoding.Default.GetString(bRcvData, 3, bRcvData.Length - 2).TrimStart(' '); //20210311 김정만 - SmartX FrameWork 사용 안함으로 주석처리
//var sMessageOther = Encoding.Default.GetString(bRcvData, 3, bRcvData.Length - 2).TrimStart(' ');
RaiseMessage(MessageType.Normal, "$메세지수신:" + frame.DataString);
}
else
{
try
{
DataReceive?.Invoke(this, new DataEventArgs(DataType.UNKNOWN));
}
catch (Exception ex)
{
RaiseMessage(MessageType.Error, ex.Message);
retval = false;
}
}
return retval;
}
#region [] ACK()
public string ACKData { get; set; } = string.Empty;
public DateTime ACKtime { get; set; } = DateTime.Now;
private void RevACK(Dataframe frame)
{
//ACKSADA7
var rcvdNow = frame.DataString;
var bRcvData = frame.Buffer;
ACKData = rcvdNow.Substring(3);
ACKtime = DateTime.Now;
if (rcvdNow.StartsWith("ACK"))
{
//RaiseMessage("get ack");
DataReceive?.Invoke(this, new DataEventArgs(DataType.ACK));
//if (datamanager.commandQueue.Count != 0)
//{
// byte[] bCmdData = encoding.GetBytes((String)datamanager.commandQueue.Peek());
// if (bCmdData[1] == bRcvData[4] && bCmdData[2] == bRcvData[5] && bCmdData[3] == bRcvData[6]) //보낸값이 맞는지 확인후 Dequeue
// {
// nSendCount = 0;
// datamanager.commandQueue.Dequeue();
// sSendCommandString = "";
// }
//}
}
else if (rcvdNow.StartsWith("NAK"))
{
//RaiseMessage("get nak");
DataReceive?.Invoke(this, new DataEventArgs(DataType.NAK));
//nSendCount = 0; //NAK - 재전송이 날아왔을때 nSendCommandCounter 초기화
}
}
#endregion
public SystemFlag0 system0 = new SystemFlag0();
public SystemFlag1 system1 = new SystemFlag1();
public ErrorFlag error = new ErrorFlag();
public AgvData data = new AgvData();
public Signal1 signal1 = new Signal1();
public Signal2 signal2 = new Signal2();
#region [] STS(AGV상태정보)
public string LastSTS { get; set; } = string.Empty;
private void RevSTS(Dataframe frame)
{
LastSTS = frame.DataString;
string rcvdNow = frame.DataString.Replace("\0", "");
byte[] bRcvData = frame.Buffer;
var encoding = System.Text.Encoding.Default;
try
{
// AGV 베터리 잔량 표시 flag (4~6) /////////////////////////////////////////////////////////////////////////////////////////////////////////////
var idx = 3;
var battery = int.Parse(rcvdNow.Substring(idx, 3)) / 10f;// Convert.ToDouble(encoding.GetString(rcvdNow, 3, 3)) / 10;
idx += 3;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AGV 장치연결상태 flag (7~10) - System Flag 0
var nDataTemp = Convert.ToInt16(rcvdNow.Substring(idx, 4), 16);
system0.SetValue(nDataTemp);
idx += 4;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AGV Sts(현재 상태) flag (11~14) - System Flag 1
nDataTemp = Convert.ToInt16(rcvdNow.Substring(idx, 4), 16);
system1.SetValue(nDataTemp);
idx += 4;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AGV Error flag (15~18) - Error Flag
nDataTemp = Convert.ToInt16(rcvdNow.Substring(idx, 4), 16);
error.SetValue(nDataTemp);
idx += 4;
data.Speed = rcvdNow.Substring(idx, 1)[0]; idx += 1; //L,M.H
data.Sts = rcvdNow.Substring(idx, 1)[0]; idx += 1; //S(직진),L(좌분기),R(우분기)
data.Direction = rcvdNow.Substring(idx, 1)[0]; idx += 1; //F,B,L,R
data.guidesensor = int.Parse(rcvdNow.Substring(idx, 1)); idx += 1; //가이드 좌측부터 1~9
nDataTemp = Convert.ToByte(rcvdNow.Substring(idx, 2), 16);
signal1.SetValue(nDataTemp); idx += 2;
//agv가 멈춰있고 마크센서가 들어온경우, 턴 작업이었다면 턴 셋팅을 한다
if (system1.agv_run == false && system1.agv_stop == true &&
TurnInformation != null && signal1.mark_sensor)
{
if (TurnInformation.Start.Year > 2000)
{
if (TurnInformation.State == eNarumiTurn.LeftIng || TurnInformation.State == eNarumiTurn.RightIng)
{
TurnInformation.End = DateTime.Now;
if (TurnInformation.State == eNarumiTurn.LeftIng) TurnInformation.State = eNarumiTurn.Left;
if (TurnInformation.State == eNarumiTurn.RightIng) TurnInformation.State = eNarumiTurn.Right;
}
}
else
{
//시작시간이 설정되지 않았다면 처리하지 않는다.
}
}
if (idx <= rcvdNow.Length - 2)
{
nDataTemp = Convert.ToByte(rcvdNow.Substring(idx, 2), 16);
signal2.SetValue(nDataTemp);
}
DataReceive?.Invoke(this, new DataEventArgs(DataType.STS));
}
catch (Exception ex)
{
RaiseMessage(MessageType.Error, $"Parse Error(STS) = {ex.Message}");
}
}
#endregion
#region [] TAG()
System.Text.Encoding encoding = System.Text.Encoding.Default;
string old_TagString = string.Empty;
string old_CALString = string.Empty;
string old_CCAString = string.Empty;
private void RevTAG(Dataframe frame)
{
string rcvdNow = frame.DataString;
byte[] bRcvData = frame.Buffer;
if (rcvdNow.StartsWith("TAG"))
{
//221123 chi 숫자로변경
var tagnostr = rcvdNow.Substring(3);
if (ushort.TryParse(tagnostr, out ushort tagnoint))
{
var Changed = !old_TagString.Equals(tagnostr);
data.TagString = tagnostr;
data.TagNo = tagnoint;
old_TagString = tagnostr;
DataReceive?.Invoke(this, new DataEventArgs(DataType.TAG));
}
WriteData(MakeCheckSum("ACKTAG"));
}
else if (rcvdNow.StartsWith("CAL"))
{
var tagnostr = encoding.GetString(bRcvData, 4, 4);
if (int.TryParse(tagnostr, out int tagnoint))
{
var Changed = !old_CALString.Equals(tagnostr);
data.CallString = tagnostr;
data.CallNo = tagnoint;
old_CALString = tagnostr;
if (Changed) DataReceive?.Invoke(this, new DataEventArgs(DataType.CALL));
}
WriteData(MakeCheckSum("ACKCAL"));
}
else if (rcvdNow.StartsWith("CCA")) //능동형 Call에 의하여 들어 오는 구문
{
var tagnostr = encoding.GetString(bRcvData, 4, 4);
if (int.TryParse(tagnostr, out int tagnoint))
{
var Changed = !old_CCAString.Equals(tagnostr);
data.CCAString = tagnostr;
data.CCANo = tagnoint;
old_CCAString = tagnostr;
if (Changed) DataReceive?.Invoke(this, new DataEventArgs(DataType.CCA));
}
WriteData(MakeCheckSum("ACKCCA"));
}
}
#endregion
private string MakeCheckSum(string sCommand)
{
//sCommand = sCommand.ToUpper();
List<byte> buffer = new List<byte>();
buffer.Add(0x02);
//byte[] bCommand = System.Text.ASCIIEncoding.ASCII.GetBytes(sCommand);
buffer.AddRange(System.Text.ASCIIEncoding.ASCII.GetBytes(sCommand));
//make sum
int nSum = 0;
for (int nCnt = 1; nCnt < buffer.Count; nCnt++)
nSum += buffer[nCnt];
string sSum = nSum.ToString("X2").ToUpper();// Convert.ToString(nSum, 16).ToUpper();
if (sSum.Length < 2) sSum = "0" + sSum;
sSum = sSum.Substring(sSum.Length - 2);
//if (sSum.Length == 3)
// sSum = sSum.Remove(0, 1);
//else if (sSum.Length == 4)
// sSum = sSum.Remove(0, 2);
buffer.AddRange(System.Text.ASCIIEncoding.Default.GetBytes(sSum));
buffer.Add(0x03);
// byte[] bStxEtx = { 0x02, 0x03 };
//var orgstr = (System.Text.ASCIIEncoding.ASCII.GetString(bStxEtx, 0, 1) + sCommand + sSum + System.Text.ASCIIEncoding.ASCII.GetString(bStxEtx, 1, 1));
var newstr = System.Text.Encoding.Default.GetString(buffer.ToArray());
return newstr;
}
///// <summary>
///// commandQueue에 명령을 추가합니다(체크섬은 자동 추가됨)
///// </summary>
///// <param name="cmd">체크섬을 제외한 평문</param>
///// <param name="addlog">sendlog 에 추가할 경우 true를 입력하세요</param>
//public void AddCommand(string cmd, bool addlog = true, int Repeat = 1)
//{
// var fullcmd = MakeCheckSum(cmd);
// for (int i = 0; i < Repeat; i++)
// commandQueue.Enqueue(fullcmd);
// if (addlog)
// {
// Message?.Invoke(this, new MessageEventArgs()
// }
//}
public enum eStopOpt
{
Stop = 0,
MarkStop,
MarkRotateLeft,
MarkRotateRight,
MarkChangeDirection,
}
public enum eRunOpt
{
NotSet,
Forward,
Backward,
}
public enum ManulOpt
{
FS,
BS,
RT,
LT,
FL,
FR,
BL,
BR,
}
public enum Sensor
{
PBSOff = 0,
PBSOn,
AllOn,
}
public enum Speed
{
High,
Mid,
Low,
}
public enum LiftCommand
{
/// <summary>
/// lift up
/// </summary>
UP,
/// <summary>
/// lift down
/// </summary>
DN,
/// <summary>
/// lift 동작 정지
/// </summary>
STP,
/// <summary>
/// magnet holder on
/// </summary>
ON,
/// <summary>
/// magnet holder off
/// </summary>
OFF
}
private bool CheckSum(byte[] bData)
{
if (bData.Length < 2) // 데이터 길이가 2이하일 경우 비정상 처리
return false;
int nSum = 0;
// byte[] bData = encoding.GetBytes(sData);
for (int nCnt = 1; nCnt < bData.Length - 3; nCnt++)
{
nSum += bData[nCnt];
}
string sSum = Convert.ToString(nSum, 16).ToUpper();
string sCSTemp = string.Empty;
if (sSum.Length == 3)
sCSTemp = sSum.Remove(0, 1);
else if (sSum.Length == 4)
sCSTemp = sSum.Remove(0, 2);
if (bData[bData.Length - 2] == '*' && bData[bData.Length - 3] == '*')
return true;
if (sCSTemp[0] == (char)(bData[bData.Length - 3]) && sCSTemp[1] == (char)(bData[bData.Length - 2]))
return true;
else
return false;
}
}
}

View File

@@ -0,0 +1,609 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
namespace arDev
{
public abstract class NarumiSerialComm : 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 NarumiSerialComm()
{
_device = new System.IO.Ports.SerialPort();
this.BaudRate = 57600;
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);
}
~NarumiSerialComm()
{
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;
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("BMS Commnunication Module")]
[assembly: AssemblyDescription("BMS Commnunication Module")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ATK4")]
[assembly: AssemblyProduct("BMS Commnunication Module")]
[assembly: AssemblyCopyright("Copyright ©ATK4 2020")]
[assembly: AssemblyTrademark("ATK4")]
[assembly: AssemblyCulture("")]
// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("7a94c30c-6772-4f71-bf9c-111071a1bc70")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 버전
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("20.03.09.0000")]
[assembly: AssemblyFileVersion("20.03.09.0000")]

View File

@@ -0,0 +1,86 @@
using System;
namespace arDev
{
public partial class Narumi
{
public class AgvData
{
/// <summary>
/// S: Straight
/// L: Left
/// R: Right
/// </summary>
public char Sts { get; set; }
/// <summary>
/// H : High
/// M : Middle
/// L : Low
/// S : Mark Stop
/// </summary>
public char Speed { get; set; }
/// <summary>
/// F : Front
/// B : Back
/// </summary>
public char Direction { get; set; }
public int guidesensor { get; set; }
public string TagString { get; set; } = string.Empty;
public ushort TagNo { get; set; } = 0;
public string CallString { get; set; } = string.Empty;
public int CallNo { get; set; } = -1;
public string CCAString { get; set; } = string.Empty;
public int CCANo { get; set; } = -1;
public override string ToString()
{
//모든사태값을 탭으로 구분하여 문자를 생성한다
var sb = new System.Text.StringBuilder();
sb.AppendLine($"[Sts] : {Sts}");
sb.AppendLine($"[Speed] : {Speed}");
sb.AppendLine($"[Direction] : {Direction}");
sb.AppendLine($"[guidesensor] : {guidesensor}");
sb.AppendLine($"[TagNo] : {TagNo}");
sb.AppendLine($"[CallNo] : {CallNo}");
sb.AppendLine($"[CCANo] : {CCANo}");
return sb.ToString();
}
public string ToRtfString()
{
var sb = new System.Text.StringBuilder();
sb.AppendLine(@"{\rtf1\ansi\deff0");
sb.AppendLine(@"{\colortbl ;\red0\green0\blue255;}"); // Color 1 = Blue
sb.AppendLine($"[Sts] : {Sts}" + @"\line");
sb.AppendLine($"[Speed] : {Speed}" + @"\line");
sb.AppendLine($"[Direction] : {Direction}" + @"\line");
sb.AppendLine($"[guidesensor] : {guidesensor}" + @"\line");
sb.AppendLine($"[TagNo] : {TagNo}" + @"\line");
sb.AppendLine($"[CallNo] : {CallNo}" + @"\line");
sb.AppendLine($"[CCANo] : {CCANo}" + @"\line");
sb.AppendLine("}");
return sb.ToString();
}
}
}
}

View File

@@ -0,0 +1,142 @@
using System;
namespace arDev
{
public partial class Narumi
{
public class ErrorFlag
{
private COMM.Flag _value { get; set; } = new COMM.Flag(16);
public void SetValue(Int16 value) { this._value.writeValue(value); }
public UInt16 Value
{
get
{
return (UInt16)_value.Value;
}
}
public enum eflag
{
Emergency = 0,
Overcurrent,
Charger_run_error,
Charger_pos_error,
line_out_error = 4,
/// <summary>
/// 기동시 자석 감지 에러
/// </summary>
runerror_by_no_magent_line=5,
/// <summary>
/// 호출제어기 통신 오류
/// </summary>
controller_comm_error =6,
/// <summary>
/// 배터리 저전압
/// </summary>
battery_low_voltage=7,
spare08=8,
lift_timeout=9,
lift_driver_overcurrent=10,
lift_driver_emergency = 11,
/// <summary>
/// 도착경보기 통신 오류
/// </summary>
arrive_ctl_comm_error,
/// <summary>
/// 자동문제어기 통신 오류
/// </summary>
door_ctl_comm_error,
/// <summary>
/// 자동충전기 통신 오류
/// </summary>
charger_comm_error,
/// <summary>
/// 교차로 제어기 통신 오류
/// </summary>
cross_ctrl_comm_error,
}
public bool GetValue(eflag idx)
{
return _value.Get((int)idx);
}
public bool GetChanged(eflag idx)
{
return _value.GetChanged((int)idx);
}
public bool Emergency { get { return GetValue(eflag.Emergency); } }
public bool Overcurrent { get { return GetValue(eflag.Overcurrent); } }
public bool Charger_run_error { get { return GetValue(eflag.Charger_run_error); } }
public bool Charger_pos_error { get { return GetValue(eflag.Charger_pos_error); } }
public bool line_out_error { get { return GetValue(eflag.line_out_error); } }
public bool runerror_by_no_magent_line { get { return GetValue(eflag.runerror_by_no_magent_line); } }
public bool controller_comm_error { get { return GetValue(eflag.controller_comm_error); } }
public bool arrive_ctl_comm_error { get { return GetValue(eflag.arrive_ctl_comm_error); } }
public bool door_ctl_comm_error { get { return GetValue(eflag.door_ctl_comm_error); } }
public bool charger_comm_error { get { return GetValue(eflag.charger_comm_error); } }
public bool cross_ctrl_comm_error { get { return GetValue(eflag.cross_ctrl_comm_error); } }
public override string ToString()
{
//모든사태값을 탭으로 구분하여 문자를 생성한다
var sb = new System.Text.StringBuilder();
for (int i = 0; i < 16; i++)
{
var def = Enum.IsDefined(typeof(eflag), i);
if (def)
{
var flag = (eflag)i;
var value = _value.Get(i);
sb.AppendLine($"[{i:00}][{flag}] : {value}");
}
}
return sb.ToString();
}
public string ToRtfString()
{
var sb = new System.Text.StringBuilder();
sb.AppendLine(@"{\rtf1\ansi\deff0");
sb.AppendLine(@"{\colortbl ;\red0\green0\blue255;}"); // Color 1 = Blue
for (int i = 0; i < 16; i++)
{
var def = Enum.IsDefined(typeof(eflag), i);
if (def)
{
var flag = (eflag)i;
var value = _value.Get(i);
string line = $"[{i:00}][{flag}] : {value}";
// : true가 포함된 줄은 파란색
if (value == true)
{
sb.AppendLine(@"\cf1 " + line + @"\cf0\line");
}
else
{
sb.AppendLine(line + @"\line");
}
}
}
sb.AppendLine("}");
return sb.ToString();
}
}
}
}

View File

@@ -0,0 +1,187 @@
using System;
namespace arDev
{
public partial class Narumi
{
public enum eSignal1
{
front_gate_out = 0,
rear_gte_out,
mark_sensor_1,
mark_sensor_2,
lift_down_sensor,
lift_up_sensor,
magnet_relay,
charger_align_sensor,
}
public enum eSignal2
{
cart_detect1 = 0,
cart_detect2,
}
public class Signal1
{
private COMM.Flag _value { get; set; } = new COMM.Flag(8);
public void SetValue(Int16 value) { this._value.writeValue(value); }
public UInt16 Value
{
get
{
return (UInt16)_value.Value;
}
}
public bool GetValue(eSignal1 idx)
{
return _value.Get((int)idx);
}
public bool GetChanged(eSignal1 idx)
{
return _value.GetChanged((int)idx);
}
public Boolean front_gate_out { get { return GetValue(eSignal1.front_gate_out); } }
public Boolean rear_sensor_out { get { return GetValue(eSignal1.rear_gte_out); } }
public Boolean mark_sensor_1 { get { return GetValue(eSignal1.mark_sensor_1); } }
public Boolean mark_sensor_2 { get { return GetValue(eSignal1.mark_sensor_2); } }
public Boolean mark_sensor { get { return mark_sensor_1 || mark_sensor_2; } }
public Boolean charger_align_sensor { get { return GetValue(eSignal1.charger_align_sensor); } }
public Boolean lift_up { get { return GetValue(eSignal1.lift_up_sensor); } }
public Boolean lift_down { get { return GetValue(eSignal1.lift_down_sensor); } }
public Boolean magnet_on { get { return GetValue(eSignal1.magnet_relay); } }
public override string ToString()
{
//모든사태값을 탭으로 구분하여 문자를 생성한다
var sb = new System.Text.StringBuilder();
for (int i = 0; i < 16; i++)
{
var def = Enum.IsDefined(typeof(eSignal1), i);
if (def)
{
var flag = (eSignal1)i;
var value = _value.Get(i);
sb.AppendLine($"[{i:00}][{flag}] : {value}");
}
}
return sb.ToString();
}
public string ToRtfString()
{
var sb = new System.Text.StringBuilder();
sb.AppendLine(@"{\rtf1\ansi\deff0");
sb.AppendLine(@"{\colortbl ;\red0\green0\blue255;}"); // Color 1 = Blue
for (int i = 0; i < 16; i++)
{
var def = Enum.IsDefined(typeof(eSignal1), i);
if (def)
{
var flag = (eSignal1)i;
var value = _value.Get(i);
string line = $"[{i:00}][{flag}] : {value}";
// : true가 포함된 줄은 파란색
if (value == true)
{
sb.AppendLine(@"\cf1 " + line + @"\cf0\line");
}
else
{
sb.AppendLine(line + @"\line");
}
}
}
sb.AppendLine("}");
return sb.ToString();
}
}
public class Signal2
{
private COMM.Flag _value { get; set; } = new COMM.Flag(8);
public void SetValue(Int16 value) { this._value.writeValue(value); }
public UInt16 Value
{
get
{
return (UInt16)_value.Value;
}
}
public bool GetValue(eSignal2 idx)
{
return _value.Get((int)idx);
}
public bool GetChanged(eSignal2 idx)
{
return _value.GetChanged((int)idx);
}
public Boolean cart_detect1 { get { return GetValue(eSignal2.cart_detect1); } }
public Boolean cart_detect2 { get { return GetValue(eSignal2.cart_detect2); } }
public override string ToString()
{
//모든사태값을 탭으로 구분하여 문자를 생성한다
var sb = new System.Text.StringBuilder();
for (int i = 0; i < 16; i++)
{
var def = Enum.IsDefined(typeof(eSignal2), i);
if(def)
{
var flag = (eSignal2)i;
var value = _value.Get(i);
sb.AppendLine($"[{i:00}][{flag}] : {value}");
}
}
return sb.ToString();
}
public string ToRtfString()
{
var sb = new System.Text.StringBuilder();
sb.AppendLine(@"{\rtf1\ansi\deff0");
sb.AppendLine(@"{\colortbl ;\red0\green0\blue255;}"); // Color 1 = Blue
for (int i = 0; i < 16; i++)
{
var def = Enum.IsDefined(typeof(eSignal2), i);
if (def)
{
var flag = (eSignal2)i;
var value = _value.Get(i);
string line = $"[{i:00}][{flag}] : {value}";
// : true가 포함된 줄은 파란색
if (value == true)
{
sb.AppendLine(@"\cf1 " + line + @"\cf0\line");
}
else
{
sb.AppendLine(line + @"\line");
}
}
}
sb.AppendLine("}");
return sb.ToString();
}
}
}
}

View File

@@ -0,0 +1,108 @@
using System;
namespace arDev
{
public partial class Narumi
{
public class SystemFlag0
{
private COMM.Flag _value { get; set; } = new COMM.Flag(16);
public void SetValue(Int16 value) { this._value.writeValue(value); }
public UInt16 Value
{
get
{
return (UInt16)_value.Value;
}
}
public enum eflag
{
Memory_RW_State = 5,
EXT_IO_Conn_State,
RFID_Conn_State,
M5E_Module_Run_State = 8,
Front_Ultrasonic_Conn_State,
Front_Untrasonic_Sensor_State,
Side_Ultrasonic_Conn_State,
Side_Ultrasonic_Sensor_State = 12,
Front_Guide_Sensor_State,
Rear_Guide_Sensor_State,
Battery_Level_Check
}
public bool GetValue(eflag idx)
{
return _value.Get((int)idx);
}
public bool GetChanged(eflag idx)
{
return _value.GetChanged((int)idx);
}
public bool Memory_RW_State { get { return GetValue(eflag.Memory_RW_State); } }
public bool EXT_IO_Conn_State { get { return GetValue(eflag.EXT_IO_Conn_State); } }
public bool RFID_Conn_State { get { return GetValue(eflag.RFID_Conn_State); } }
public bool M5E_Module_Run_State { get { return GetValue(eflag.M5E_Module_Run_State); } }
public bool Front_Ultrasonic_Conn_State { get { return GetValue(eflag.Front_Ultrasonic_Conn_State); } }
public bool Front_Untrasonic_Sensor_State { get { return GetValue(eflag.Front_Untrasonic_Sensor_State); } }
public bool Side_Ultrasonic_Conn_State { get { return GetValue(eflag.Side_Ultrasonic_Conn_State); } }
public bool Side_Ultrasonic_Sensor_State { get { return GetValue(eflag.Side_Ultrasonic_Sensor_State); } }
public bool Front_Guide_Sensor_State { get { return GetValue(eflag.Front_Guide_Sensor_State); } }
public bool Rear_Guide_Sensor_State { get { return GetValue(eflag.Rear_Guide_Sensor_State); } }
public bool Battery_Level_Check { get { return GetValue(eflag.Battery_Level_Check); } }
public override string ToString()
{
//모든사태값을 탭으로 구분하여 문자를 생성한다
var sb = new System.Text.StringBuilder();
for(int i = 0; i < 16; i++)
{
var def = Enum.IsDefined(typeof(eflag), i);
if (def)
{
var flag = (eflag)i;
var value = _value.Get(i);
sb.AppendLine($"[{i:00}][{flag}] : {value}");
}
}
return sb.ToString();
}
public string ToRtfString()
{
var sb = new System.Text.StringBuilder();
sb.AppendLine(@"{\rtf1\ansi\deff0");
sb.AppendLine(@"{\colortbl ;\red0\green0\blue255;}"); // Color 1 = Blue
for (int i = 0; i < 16; i++)
{
var def = Enum.IsDefined(typeof(eflag), i);
if (def)
{
var flag = (eflag)i;
var value = _value.Get(i);
string line = $"[{i:00}][{flag}] : {value}";
// : true가 포함된 줄은 파란색
if (value == true)
{
sb.AppendLine(@"\cf1 " + line + @"\cf0\line");
}
else
{
sb.AppendLine(line + @"\line");
}
}
}
sb.AppendLine("}");
return sb.ToString();
}
}
}
}

View File

@@ -0,0 +1,128 @@
using System;
namespace arDev
{
public partial class Narumi
{
public class SystemFlag1
{
private COMM.Flag _value { get; set; } = new COMM.Flag(16);
public void SetValue(Int16 value) { this._value.writeValue(value); }
public UInt16 Value
{
get
{
return (UInt16)_value.Value;
}
}
public enum eflag
{
Side_Detect_Ignore = 3,
Melody_check,
Mark2_check,
Mark1_check,
gateout_check,
Battery_charging = 8,
re_Start,
/// <summary>
/// 전방 감지 무시
/// </summary>
front_detect_ignore,
/// <summary>
/// 전방장애물감지상태
/// </summary>
front_detect_check,
/// <summary>
/// 전방감지 후 정지 상태
/// </summary>
stop_by_front_detect = 12,
/// <summary>
/// 교차로 진입 후 정지 상태
/// </summary>
stop_by_cross_in,
agv_stop,
agv_run
}
public bool GetValue(eflag idx)
{
return _value.Get((int)idx);
}
public bool GetChanged(eflag idx)
{
return _value.GetChanged((int)idx);
}
public bool Side_Detect_Ignore { get { return GetValue(eflag.Side_Detect_Ignore); } }
public bool Melody_check { get { return GetValue(eflag.Melody_check); } }
public bool Mark2_check { get { return GetValue(eflag.Mark2_check); } }
public bool Mark1_check { get { return GetValue(eflag.Mark1_check); } }
public bool gateout_check { get { return GetValue(eflag.gateout_check); } }
public bool Battery_charging { get { return GetValue(eflag.Battery_charging); } }
public bool re_Start { get { return GetValue(eflag.re_Start); } }
public bool front_detect_ignore { get { return GetValue(eflag.front_detect_ignore); } }
public bool front_detect_check { get { return GetValue(eflag.front_detect_check); } }
public bool stop_by_front_detect { get { return GetValue(eflag.stop_by_front_detect); } }
public bool stop_by_cross_in { get { return GetValue(eflag.stop_by_cross_in); } }
public bool agv_stop { get { return GetValue(eflag.agv_stop); } }
public bool agv_run { get { return GetValue(eflag.agv_run); } }
public bool agv_run_manual { get; set; }
public override string ToString()
{
//모든사태값을 탭으로 구분하여 문자를 생성한다
var sb = new System.Text.StringBuilder();
for (int i = 0; i < 16; i++)
{
var def = Enum.IsDefined(typeof(eflag), i);
if (def)
{
var flag = (eflag)i;
var value = _value.Get(i);
sb.AppendLine($"[{i:00}][{flag}] : {value}");
}
}
return sb.ToString();
}
public string ToRtfString()
{
var sb = new System.Text.StringBuilder();
sb.AppendLine(@"{\rtf1\ansi\deff0");
sb.AppendLine(@"{\colortbl ;\red0\green0\blue255;}"); // Color 1 = Blue
for (int i = 0; i < 16; i++)
{
var def = Enum.IsDefined(typeof(eflag), i);
if (def)
{
var flag = (eflag)i;
var value = _value.Get(i);
string line = $"[{i:00}][{flag}] : {value}";
// : true가 포함된 줄은 파란색
if (value == true)
{
sb.AppendLine(@"\cf1 " + line + @"\cf0\line");
}
else
{
sb.AppendLine(line + @"\line");
}
}
}
sb.AppendLine("}");
return sb.ToString();
}
}
}
}

View File

@@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "agvControl", "agvControl.csproj", "{EB23DC0D-9A07-407C-762D-DF1CC8B3D822}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EB23DC0D-9A07-407C-762D-DF1CC8B3D822}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB23DC0D-9A07-407C-762D-DF1CC8B3D822}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB23DC0D-9A07-407C-762D-DF1CC8B3D822}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB23DC0D-9A07-407C-762D-DF1CC8B3D822}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {586342A4-FEA6-4584-82F4-39BA06630ABB}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,37 @@
namespace AGVControl
{
partial class BatteryLevelGauge
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AGVControl
{
public partial class BatteryLevelGauge : Control
{
float _vlevel = 50;
public float VLevel { get { return _vlevel; } set { _vlevel = value; } }
public float Volt { get; set; } = 0;
public String sign { get; set; } = "%";
public float CurA { get; set; } = 0;
public float MaxA { get; set; } = 0;
bool isopen = false;
public Boolean IsOpen { get { return isopen; } set { isopen = value; this.Invalidate(); } }
public Color BorderColor { get; set; } = Color.DimGray;
public BatteryLevelGauge()
{
InitializeComponent();
// Set Optimized Double Buffer to reduce flickering
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
// Redraw when resized
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.Resize += arLabel_Resize;
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.InterpolationMode = InterpolationMode.High;
pe.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
pe.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
//base.OnPaint(pe);
pe.Graphics.FillRectangle(new SolidBrush(BackColor), DisplayRectangle);
var r = new RectangleF(this.DisplayRectangle.Left + Padding.Left,
this.DisplayRectangle.Top + Padding.Top,
this.DisplayRectangle.Width - Padding.Left - Padding.Right,
this.DisplayRectangle.Height - Padding.Top - Padding.Bottom);
pe.Graphics.FillRectangle(new SolidBrush(this.BackColor), r);
var w = r.Width * (this.VLevel / 100f);
var lr = new RectangleF(r.Left, r.Top, w, r.Height);
Color bColor = Color.Red;
if (VLevel > 80) bColor = Color.YellowGreen;
else if (VLevel > 60) bColor = Color.Yellow;
else if (VLevel > 40) bColor = Color.Orange;
else if (VLevel > 20) bColor = Color.Tomato;
else bColor = Color.Red;
pe.Graphics.FillRectangle(new SolidBrush(bColor), lr);
Color textcolor = this.ForeColor;
if (IsOpen == false) textcolor = Color.Black;
var smg = IsOpen ? $"{ this.VLevel:N0}{ this.sign}" : "연결안됨";
pe.Graphics.DrawString(smg, this.Font, new SolidBrush(textcolor), r,
new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
});
pe.Graphics.DrawRectangle(Pens.Black, r.Left, r.Top, r.Width, r.Height);
}
void arLabel_Resize(object sender, EventArgs e)
{
Invalidate();
}
}
}

View File

@@ -0,0 +1,103 @@
namespace AGVControl.Dialog
{
partial class fMapDesign
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(fMapDesign));
this.panel1 = new System.Windows.Forms.Panel();
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.btOK = new System.Windows.Forms.ToolStripButton();
this.toolStrip1.SuspendLayout();
this.SuspendLayout();
//
// panel1
//
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.Font = new System.Drawing.Font("Tahoma", 8F, System.Drawing.FontStyle.Bold);
this.panel1.Location = new System.Drawing.Point(0, 47);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(888, 547);
this.panel1.TabIndex = 22;
//
// toolStrip1
//
this.toolStrip1.ImageScalingSize = new System.Drawing.Size(40, 40);
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.btOK});
this.toolStrip1.Location = new System.Drawing.Point(0, 0);
this.toolStrip1.Name = "toolStrip1";
this.toolStrip1.Size = new System.Drawing.Size(888, 47);
this.toolStrip1.TabIndex = 23;
this.toolStrip1.Text = "toolStrip1";
//
// statusStrip1
//
this.statusStrip1.Location = new System.Drawing.Point(0, 594);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(888, 22);
this.statusStrip1.TabIndex = 24;
this.statusStrip1.Text = "statusStrip1";
//
// btOK
//
this.btOK.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
this.btOK.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.btOK.Image = ((System.Drawing.Image)(resources.GetObject("btOK.Image")));
this.btOK.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btOK.Name = "btOK";
this.btOK.Size = new System.Drawing.Size(44, 44);
this.btOK.Text = "toolStripButton1";
this.btOK.Click += new System.EventHandler(this.btOK_Click);
//
// fMapDesign
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(888, 616);
this.Controls.Add(this.panel1);
this.Controls.Add(this.statusStrip1);
this.Controls.Add(this.toolStrip1);
this.Name = "fMapDesign";
this.Text = "fMapDesign";
this.Load += new System.EventHandler(this.fMapDesign_Load);
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.ToolStrip toolStrip1;
private System.Windows.Forms.ToolStripButton btOK;
private System.Windows.Forms.StatusStrip statusStrip1;
}
}

View File

@@ -0,0 +1,48 @@
using AR;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AGVControl.Dialog
{
public partial class fMapDesign : Form
{
AGVControl.MapControl mapctl;
public fMapDesign(string fn)
{
InitializeComponent();
mapctl = new AGVControl.MapControl();
mapctl.Dock = DockStyle.Fill;
mapctl.Visible = true;
mapctl.Font = this.panel1.Font;
mapctl.BackColor = Color.FromArgb(32, 32, 32);
this.panel1.Controls.Add(mapctl);
if (System.IO.File.Exists(fn))
{
//auto load
var rlt = mapctl.LoadFromFile(fn, out string errmsg);
if (rlt == false) AR.UTIL.MsgE(errmsg);
}
}
private void fMapDesign_Load(object sender, EventArgs e)
{
}
private void btOK_Click(object sender, EventArgs e)
{
this.mapctl.SaveToFile(this.mapctl.Filename);
DialogResult = DialogResult.OK;
}
}
}

View File

@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="btOK.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
</value>
</data>
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>124, 17</value>
</metadata>
</root>

View File

@@ -0,0 +1,158 @@
namespace AGVControl.Dialog
{
partial class fPropertyRFIDPoint
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.propertyGrid2 = new System.Windows.Forms.PropertyGrid();
this.panel1 = new System.Windows.Forms.Panel();
this.label2 = new System.Windows.Forms.Label();
this.panel2 = new System.Windows.Forms.Panel();
this.label1 = new System.Windows.Forms.Label();
this.button1 = new System.Windows.Forms.Button();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
this.SuspendLayout();
//
// propertyGrid1
//
this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill;
this.propertyGrid1.Location = new System.Drawing.Point(0, 31);
this.propertyGrid1.Name = "propertyGrid1";
this.propertyGrid1.Size = new System.Drawing.Size(346, 456);
this.propertyGrid1.TabIndex = 0;
//
// comboBox1
//
this.comboBox1.Dock = System.Windows.Forms.DockStyle.Top;
this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBox1.Font = new System.Drawing.Font("굴림", 18F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.comboBox1.FormattingEnabled = true;
this.comboBox1.Location = new System.Drawing.Point(1, 32);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(519, 32);
this.comboBox1.TabIndex = 1;
this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
//
// propertyGrid2
//
this.propertyGrid2.Dock = System.Windows.Forms.DockStyle.Fill;
this.propertyGrid2.Location = new System.Drawing.Point(1, 64);
this.propertyGrid2.Name = "propertyGrid2";
this.propertyGrid2.Size = new System.Drawing.Size(519, 362);
this.propertyGrid2.TabIndex = 2;
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.Gray;
this.panel1.Controls.Add(this.propertyGrid2);
this.panel1.Controls.Add(this.button1);
this.panel1.Controls.Add(this.comboBox1);
this.panel1.Controls.Add(this.label2);
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.Location = new System.Drawing.Point(346, 0);
this.panel1.Name = "panel1";
this.panel1.Padding = new System.Windows.Forms.Padding(1);
this.panel1.Size = new System.Drawing.Size(521, 487);
this.panel1.TabIndex = 3;
//
// label2
//
this.label2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
this.label2.Dock = System.Windows.Forms.DockStyle.Top;
this.label2.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.label2.Location = new System.Drawing.Point(1, 1);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(519, 31);
this.label2.TabIndex = 3;
this.label2.Text = "Connection Information";
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// panel2
//
this.panel2.Controls.Add(this.propertyGrid1);
this.panel2.Controls.Add(this.label1);
this.panel2.Dock = System.Windows.Forms.DockStyle.Left;
this.panel2.Location = new System.Drawing.Point(0, 0);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(346, 487);
this.panel2.TabIndex = 4;
//
// label1
//
this.label1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
this.label1.Dock = System.Windows.Forms.DockStyle.Top;
this.label1.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(129)));
this.label1.Location = new System.Drawing.Point(0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(346, 31);
this.label1.TabIndex = 0;
this.label1.Text = "Point Information";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// button1
//
this.button1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.button1.Font = new System.Drawing.Font("Arial Rounded MT Bold", 27.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.button1.Location = new System.Drawing.Point(1, 426);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(519, 60);
this.button1.TabIndex = 4;
this.button1.Text = "P1 ↔ P2";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// fPropertyRFIDPoint
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(867, 487);
this.Controls.Add(this.panel1);
this.Controls.Add(this.panel2);
this.Name = "fPropertyRFIDPoint";
this.Text = "fPropertyRFIDPoint";
this.Load += new System.EventHandler(this.fPropertyRFIDPoint_Load);
this.panel1.ResumeLayout(false);
this.panel2.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.PropertyGrid propertyGrid1;
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.PropertyGrid propertyGrid2;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button button1;
}
}

View File

@@ -0,0 +1,55 @@
using AGVControl.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AGVControl.Dialog
{
public partial class fPropertyRFIDPoint : Form
{
RFIDPoint RFIDPt;
List<RFIDConnection> Connections;
public fPropertyRFIDPoint(RFIDPoint point, List<RFIDConnection> connection)
{
InitializeComponent();
this.RFIDPt = point;
this.Connections = connection;
this.propertyGrid1.SelectedObject = point;
this.KeyPreview = true;
this.KeyDown += (s1, e1) => {
if (e1.KeyCode == Keys.Escape) this.Close();
};
}
private void fPropertyRFIDPoint_Load(object sender, EventArgs e)
{
foreach (var item in Connections)
comboBox1.Items.Add($"{item.P1.Value} ↔ {item.P2.Value}");
if(comboBox1.Items.Count > 0)
comboBox1.SelectedIndex = 0;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
this.propertyGrid2.SelectedObject = this.Connections[this.comboBox1.SelectedIndex];
}
private void button1_Click(object sender, EventArgs e)
{
var item = this.Connections[this.comboBox1.SelectedIndex];
var p1 = item.P1;
var p2 = item.P2;
item.P2 = p1;// item.P1;
item.P1 = p2;// p1;
this.propertyGrid2.SelectedObject = item;
this.Validate();
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace arFrame.Control
{
[TypeConverterAttribute(typeof(ExpandableObjectConverter))]
public class ColorListItem
{
public System.Drawing.Color BackColor1 { get; set; }
public System.Drawing.Color BackColor2 { get; set; }
public string Remark { get; set; }
public ColorListItem()
{
BackColor1 = System.Drawing.Color.Transparent;
BackColor2 = System.Drawing.Color.Transparent;
Remark = string.Empty;
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace arFrame.Control
{
[TypeConverterAttribute(typeof(ExpandableObjectConverter))]
public class GridViewItem
{
public int row { get; private set; }
public int col { get; private set; }
public int idx { get; private set; }
[Category("arFrame"), DisplayName("Tag")]
public string Tag { get; set; }
[Category("arFrame"), DisplayName("글자 정렬 방식")]
public System.Drawing.ContentAlignment TextAlign { get; set; }
[Category("arFrame"), DisplayName("글자 여백")]
public System.Windows.Forms.Padding Padding { get; set; }
[Category("arFrame"), DisplayName("메뉴 사용여부"), Description("활성화시 메뉴의 클릭이벤트가 발생하지 않습니다")]
public Boolean Enable { get; set; }
public System.Drawing.Color BackColor1 { get; set; }
public System.Drawing.Color BackColor2 { get; set; }
public Boolean Dirty { get; set; }
public System.Drawing.RectangleF rect { get; set; }
[Category("arFrame"), DisplayName("번호")]
public int No { get; set; }
public GridViewItem(int idx_,int _r,int _c)
{
this.row = _r;
this.col = _c;
BackColor1 = System.Drawing.Color.Transparent;
BackColor2 = System.Drawing.Color.Transparent;
rect = System.Drawing.RectangleF.Empty;
Enable = true;
this.idx = idx_;
TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
Padding = new System.Windows.Forms.Padding(0, 0, 0, 0);
No = 0;
this.Dirty = true;
}
}
}

View File

@@ -0,0 +1,36 @@
namespace arFrame.Control
{
partial class GridView
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마십시오.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@@ -0,0 +1,624 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace arFrame.Control
{
public partial class GridView : System.Windows.Forms.Control
{
private int bordersize = 0;
private int menubordersize = 1;
private int menugap = 5;
private System.Windows.Forms.Padding padding = new Padding(3, 3, 3, 3);
private System.Drawing.Color backcolor = System.Drawing.Color.White;
private System.Drawing.Color bordercolor = System.Drawing.Color.Black;
private Boolean textattachtoimage = true;
private Boolean _showIndexString = true;
private System.Drawing.Color _shadowColor = System.Drawing.Color.Transparent;
private System.Drawing.Color foreColorPin = System.Drawing.Color.WhiteSmoke;
private System.Drawing.Font fontPin = new Font("Consolas", 8, FontStyle.Bold);
private Point _matrixsize = new Point(8, 2);
public Point MatrixSize { get { return _matrixsize; } set { _matrixsize = value; ResetArray(); RemakeChartRect(); } }
[Browsable(false)]
public int ColumnCount { get { return _matrixsize.X; } }
[Browsable(false)]
public int RowCount { get { return _matrixsize.Y; } }
public int ItemCount { get { return ColumnCount * RowCount; } }
private GridViewItem[] Items;
private UInt16[] _values;
private string[] _titles;
private string[] _tags;
private string[] _names;
private ColorListItem[] _colorlist;
public ColorListItem[] ColorList { get { return _colorlist; } set { _colorlist = value; this.Invalidate(); } }
public string[] Names { get { return _names; } set { _names = value; Invalidate(); } }
public string[] Titles { get { return _titles; } set { _titles = value; Invalidate(); } }
public UInt16[] Values { get { return _values; } set { _values = value; Invalidate(); } }
public string[] Tags { get { return _tags; } set { _tags = value; } }
private bool _showdebuginfo = false;
public Boolean showDebugInfo { get { return _showdebuginfo; } set { _showdebuginfo = value; Invalidate(); } }
public void setNames(string[] value)
{
_names = value;
}
public void setTitle(string[] value)
{
List<string> titlerows = new List<string>();
List<string> tagrows = new List<string>();
for (int i = 0; i < value.Length; i++)
{
var r = (int)(Math.Floor((double)(i / ColumnCount)));
var c = i % ColumnCount;
if (titlerows.Count < r + 1) titlerows.Add(string.Empty);
if (tagrows.Count < r + 1) tagrows.Add(string.Empty);
var prestr = titlerows[r];
if (prestr != "") prestr += "|";
titlerows[r] = prestr + value[i];
var prestr_t = tagrows[r];
if (prestr_t != "") prestr_t += "|";
tagrows[r] = prestr_t + "";
if (i < itemCount) this.Items[i].Enable = true;
}
this._titles = titlerows.ToArray();
this._tags = tagrows.ToArray();
}
public Boolean setTitle(int row, int col, string value, string itemtag = "")
{
if (_titles == null) _titles = new string[0];
if (_tags == null) _tags = new string[0];
if ( row >= _titles.Length) Array.Resize(ref _titles, row + 1);
if( row >= _tags.Length) Array.Resize(ref _tags, row+1);
if (_titles[row] == null) _titles[row] = string.Empty;
if (_tags[row] == null) _tags[row] = string.Empty;
var linebuf = _titles[row].Split('|');
var linebuf_t = _tags[row].Split('|');
if (col >= linebuf.Length) Array.Resize(ref linebuf, col + 1);
if (col >= linebuf_t.Length) Array.Resize(ref linebuf_t, col + 1);
linebuf[col] = value;
linebuf_t[col] = itemtag;
_titles[row] = string.Join("|", linebuf);
_tags[row] = string.Join("|", linebuf_t);
return true;
//var idx = row * this.ColumnCount + col;
//return setTitle(idx, value);
}
public Boolean setTitle(int idx, string value)
{
if (idx < ColumnCount) return setTitle(0, idx, value);
else
{
//줄값이 필요하다
var row = (int)(Math.Floor((double)(idx / ColumnCount)));
var col = idx % ColumnCount;
return setTitle(row, col, value);
}
}
public void setValue(bool[] value)
{
var v = new UInt16[value.Length];
for (int i = 0; i < value.Length; i++)
v[i] = (UInt16)(value[i] ? 1 : 0);
_values = v;
}
public void setValue(UInt16[] value)
{
_values = value;
}
public Boolean setValue(int idx, ushort value)
{
if (this._values == null) _values = new ushort[idx + 1];
if (idx >= this._values.Length) Array.Resize(ref _values, idx + 1);
this._values[idx] = value;
return true;
}
public Boolean setTag(string[] value)
{
this._tags = value;
return true;
}
public Boolean setTag(int idx, string value)
{
if (this._tags == null) Tags = new string[idx + 1];
if (idx >= this.Tags.Length) Array.Resize(ref _tags, idx + 1);
this._tags[idx] = value;
return true;
}
public void ClearValue(ushort defaultValue = 0)
{
if (_values != null)
for(int i = 0; i < _values.Length;i++)
_values[i] = defaultValue;
}
public void ClearTitle(string defaultValue = "")
{
if (_values != null)
for (int i = 0; i < _titles.Length; i++)
_titles[i] = defaultValue;
}
public void ClearTag(string defaultValue = "")
{
if (_tags != null)
for (int i = 0; i < _tags.Length; i++)
_tags[i] = defaultValue;
}
public void setValue(ushort value)
{
for(int i = 0; i < _values.Length;i++)
this._values[i] = value;
}
public void setItemEnable(int idx, bool value)
{
if (idx >= _values.Length || idx >= this.Items.Length) return;
this.Items[idx].Enable = value;
}
/// <summary>
/// 지정된 컬러태그값을 입력한다.
/// </summary>
/// <param name="idx"></param>
/// <param name="tagString"></param>
/// <returns></returns>
public Boolean setValue(int idx, string tagString)
{
//동일태그값을 찾는다
if (idx >= _values.Length) return false;
int value = -1;
for (int i = 0; i < ColorList.Length; i++)
if (ColorList[i].Remark.ToLower() == tagString.ToLower())
{
value = i;
break;
}
if (value != -1)
{
this._values[idx] = (ushort)value;
this.Items[idx].Enable = true;
return true;
}
else return false;
}
public Boolean setValue(int idx, bool value)
{
return setValue(idx, (ushort)(value ? 1 : 0));
}
public Boolean setValue(int row, int col, ushort value)
{
var idx = row * this.ColumnCount + col;
return setValue(idx, value);
}
public Boolean setValue(int row, int col, int value)
{
var idx = row * this.ColumnCount + col;
return setValue(idx, (ushort)value);
}
public Boolean setValueToggle(int row, int col, ushort value1,ushort value2)
{
var idx = row * this.ColumnCount + col;
if(getValue(idx) == value1) return setValue(idx, value2);
else return setValue(idx, value1);
}
public Boolean setValue(int row, int col, bool value)
{
var idx = row * this.ColumnCount + col;
return setValue(idx, (ushort)(value ? 1 : 0));
}
public Boolean setValue(int row, int col, string value)
{
var idx = row * this.ColumnCount + col;
return setValue(idx, value);
}
public ushort getValue(int idx)
{
if (idx >= _values.Length) return 0;
return _values[idx];
}
public ushort getValue(int row, int col)
{
var idx = row * this.ColumnCount + col;
return getValue(idx);
}
[Category("arFrame")]
public bool ShowIndexString { get { return _showIndexString; } set { _showIndexString = value; Invalidate(); } }
[Category("arFrame"), DisplayName("테두리 굵기")]
public int BorderSize { get { return bordersize; } set { this.bordersize = value; Invalidate(); } }
[Category("arFrame"), DisplayName("메뉴 테두리 굵기")]
public int MenuBorderSize { get { return menubordersize; } set { this.menubordersize = value; Invalidate(); } }
[Category("arFrame"), DisplayName("메뉴 간격")]
public int MenuGap { get { return menugap; } set { this.menugap = value; RemakeChartRect(); Invalidate(); } }
[Category("arFrame"), DisplayName("글자를 이미지 다음에 표시"), Description("이미지가 있는 경우 해당 이미지 옆에 글자를 붙입니다")]
public Boolean TextAttachToImage { get { return textattachtoimage; } set { this.textattachtoimage = value; Invalidate(); } }
[Category("arFrame"), DisplayName("색상-테두리")]
public System.Drawing.Color BorderColor { get { return bordercolor; } set { this.bordercolor = value; Invalidate(); } }
[Category("arFrame"), DisplayName("내부 여백")]
public new System.Windows.Forms.Padding Padding { get { return padding; } set { this.padding = value; RemakeChartRect(); Invalidate(); } }
[Category("arFrame"), DisplayName("색상-전체배경색")]
public override System.Drawing.Color BackColor { get { return backcolor; } set { this.backcolor = value; Invalidate(); } }
[Category("arFrame"), DisplayName("색상-글자(그림자)")]
public System.Drawing.Color ShadowColor { get { return _shadowColor; } set { _shadowColor = value; this.Invalidate(); } }
[Category("arFrame"), DisplayName("색상-글자")]
public override Color ForeColor { get { return base.ForeColor; } set { base.ForeColor = value; } }
[Category("arFrame"), DisplayName("색상-글자(번호)")]
public Color ForeColorPin { get { return foreColorPin; } set { foreColorPin = value; } }
[Category("arFrame"), DisplayName("글꼴-번호")]
public Font FontPin { get { return fontPin; } set { fontPin = value; Invalidate(); } }
[Category("arFrame"), DisplayName("글꼴-항목")]
public override Font Font { get { return base.Font; } set { base.Font = value; Invalidate(); } }
private int mouseOverItemIndex = -1;
public GridView()
{
InitializeComponent();
// Set Optimized Double Buffer to reduce flickering
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
// Redraw when resized
this.SetStyle(ControlStyles.ResizeRedraw, true);
//값과 이름은 외부의 값을 사용한다
ResetArray();
if (MinimumSize.Width == 0 || MinimumSize.Height == 0)
MinimumSize = new Size(100, 50);
}
void ResetArray()
{
if (this._values != null) Array.Resize(ref this._values, itemCount);// = new UInt16[itemCount];
// if (this._titles != null) Array.Resize(ref this._titles, itemCount);//
// if (this._names != null) Array.Resize(ref this._names, itemCount);//
}
int itemCount { get { return ColumnCount * RowCount; } }
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
RemakeChartRect();
}
public event EventHandler<ItemClickEventArgs> ItemClick;
public class ItemClickEventArgs : EventArgs
{
public int idx { get; set; }
public GridViewItem Item { get; set; }
public ItemClickEventArgs(int idx_, GridViewItem item)
{
this.Item = item;
this.idx = idx_;
}
}
protected override void OnMouseClick(MouseEventArgs e)
{
//마우스클릭시 해당 버튼을 찾아서 반환한다.
if (Items == null || Items.Length < 1) return;
for (int i = 0; i < Items.Length; i++)
{
var rect = Items[i].rect;//[i];
if (rect.Contains(e.Location))
{
var menu = Items[i];
//미사용개체는 이벤트를 아에 발생하지 않는다
if (menu.Enable == true && ItemClick != null)
ItemClick(this, new ItemClickEventArgs(i, menu));
break;
}
}
}
protected override void OnMouseLeave(EventArgs e)
{
this.mouseOverItemIndex = -1;
this.Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (Items == null || Items.Length < 1)
{
this.mouseOverItemIndex = -1;
return;
}
for (int i = 0; i < Items.Length; i++)
{
var rect = Items[i].rect;// rects[i];
if (rect.Contains(e.Location))
{
if (i != mouseOverItemIndex)
{
mouseOverItemIndex = i;
this.Invalidate();
}
break;
}
}
}
public void setItemTextAlign(int row, int col, System.Drawing.ContentAlignment TextAlign)
{
var item = this.Items.Where(t => t.row == row && t.col == col).FirstOrDefault();
if (item != null) item.TextAlign = TextAlign;
}
public void setItemTextAlign(System.Drawing.ContentAlignment TextAlign)
{
foreach (var item in this.Items)
item.TextAlign = TextAlign;
}
protected override void OnPaint(PaintEventArgs pe)
{
//배경그리기
//using (var sb = new System.Drawing.Drawing2D.LinearGradientBrush(DisplayRectangle, BackColor, BackColor2On, System.Drawing.Drawing2D.LinearGradientMode.Vertical))
pe.Graphics.FillRectangle(new SolidBrush(BackColor), DisplayRectangle);
if (Items == null)
{
pe.Graphics.DrawString("no items", this.Font, Brushes.Red, 100, 100);
return;
}
var items = Items.OrderBy(t => t.No);
foreach (var menu in items)
{
drawItem(menu.idx, pe.Graphics);
}
//테두리 그리기
if (BorderSize > 0)
{
pe.Graphics.DrawRectangle(new Pen(this.BorderColor, BorderSize),
this.DisplayRectangle.Left,
this.DisplayRectangle.Top,
this.DisplayRectangle.Width - 1,
this.DisplayRectangle.Height - 1);
}
}
public void drawItem(int itemIndex, Graphics g = null)
{
if (g == null) g = this.CreateGraphics();
var menu = this.Items[itemIndex];
if (menu.rect == RectangleF.Empty) return;
var rect = menu.rect;// rects[i];
var diplayText = string.Empty;
//타이틀이 줄번호별로 처리됨
if (_titles != null && menu.row < _titles.Length && _titles[menu.row] != null )
{
var linebif = _titles[menu.row].Split('|');
if (menu.col < linebif.Length)
diplayText = linebif[menu.col];
}
UInt16 Value = 0;
if (_values != null && menu.idx < _values.Length) Value = _values[menu.idx];
//배경이 투명이 아니라면 그린다.
var bgColor1 = Color.FromArgb(30, 30, 30);// BackColor1Off;
var bgColor2 = Color.FromArgb(30, 30, 30);// BackColor2Off;
//해당 값에 따른 컬러값을 읽는다.
if (ColorList != null && Value < ColorList.Length)
{
bgColor1 = this.ColorList[Value].BackColor1;
bgColor2 = this.ColorList[Value].BackColor2;
}
using (var sb = new System.Drawing.Drawing2D.LinearGradientBrush(rect, bgColor1, bgColor2, System.Drawing.Drawing2D.LinearGradientMode.Vertical))
g.FillRectangle(sb, rect);
// if (mouseOverItemIndex == menu.idx)
// this.Cursor = Cursors.Hand;
// else
// this.Cursor = Cursors.Arrow;
//테두리를 그리는 속성과 트기가 설정된 경우에만 표시
//if (mouseOverItemIndex == i)
// {
// pe.Graphics.DrawRectangle(new Pen(Color.DeepSkyBlue), rect.Left, rect.Top, rect.Width, rect.Height);
//}
//else
{
if (MenuBorderSize > 0)
{
using (var p = new Pen(BorderColor, MenuBorderSize))
g.DrawRectangle(p, rect.Left, rect.Top, rect.Width, rect.Height);
}
}
//인덱스번호 출력
if (ShowIndexString && _names != null && menu.idx < _names.Length)
{
//표시글자
var idxstr = string.Format("[{0}] {1}", menu.idx, _names[menu.idx]);
//그림자 추가
if (ShadowColor != System.Drawing.Color.Transparent)
g.DrawString(idxstr, FontPin, new SolidBrush(ShadowColor), menu.rect.Left + 4, menu.rect.Top + 4);
//일반글자표시
g.DrawString(idxstr, FontPin, new SolidBrush(this.ForeColorPin), menu.rect.Left + 3, menu.rect.Top + 3);
}
if (diplayText != "")
{
using (StringFormat sf = new StringFormat(StringFormatFlags.NoClip))
{
//글자를 텍스트 이후에 붙이는 거라면?
if (menu.TextAlign == ContentAlignment.BottomCenter || menu.TextAlign == ContentAlignment.BottomLeft ||
menu.TextAlign == ContentAlignment.BottomRight) sf.LineAlignment = StringAlignment.Far;
else if (menu.TextAlign == ContentAlignment.MiddleCenter || menu.TextAlign == ContentAlignment.MiddleLeft ||
menu.TextAlign == ContentAlignment.MiddleRight) sf.LineAlignment = StringAlignment.Center;
else if (menu.TextAlign == ContentAlignment.TopCenter || menu.TextAlign == ContentAlignment.TopLeft ||
menu.TextAlign == ContentAlignment.TopRight) sf.LineAlignment = StringAlignment.Near;
if (menu.TextAlign == ContentAlignment.BottomCenter || menu.TextAlign == ContentAlignment.MiddleCenter ||
menu.TextAlign == ContentAlignment.TopCenter) sf.Alignment = StringAlignment.Center;
else if (menu.TextAlign == ContentAlignment.BottomLeft || menu.TextAlign == ContentAlignment.MiddleLeft ||
menu.TextAlign == ContentAlignment.TopLeft) sf.Alignment = StringAlignment.Near;
else if (menu.TextAlign == ContentAlignment.BottomRight || menu.TextAlign == ContentAlignment.MiddleRight ||
menu.TextAlign == ContentAlignment.TopRight) sf.Alignment = StringAlignment.Far;
//그림자 추가
if (ShadowColor != System.Drawing.Color.Transparent)
g.DrawString(diplayText, this.Font, new SolidBrush(ShadowColor),
new RectangleF((float)(rect.Left + 1f), (float)(rect.Top + 1f), (float)rect.Width, (float)rect.Height), sf);
g.DrawString(diplayText, this.Font, new SolidBrush(ForeColor), rect, sf);
}
}
if (showDebugInfo)
{
g.DrawString(Value.ToString(), this.fontPin, Brushes.SkyBlue, rect.Left, rect.Top);
}
}
/// <summary>
/// arFrame 전용 속성값을 복사 합니다
/// </summary>
/// <param name="ctl"></param>
public void copyTo(GridView ctl)
{
ctl.backcolor = this.backcolor;
ctl.menugap = this.menugap;
ctl.Items = this.Items;
ctl.menubordersize = this.menubordersize;
ctl.padding = this.padding;
ctl.ForeColor = this.ForeColor;
ctl.Font = this.Font;
ctl.TextAttachToImage = this.TextAttachToImage;
ctl.bordercolor = this.bordercolor;
ctl.bordersize = this.bordersize;
}
public void RemakeChartRect()
{
if (DisplayRectangle == Rectangle.Empty) return;
double x = 0;
double y = 0;
double w = DisplayRectangle.Width / (ColumnCount * 1.0);
double h = DisplayRectangle.Height / (RowCount * 1.0);
if (this.Items == null || itemCount != this.Items.Length)
{
//아이템갯수가 달라졌으므로 다시 갱신해야함
GridViewItem[] item = new GridViewItem[RowCount * ColumnCount];
for (int r = 0; r < RowCount; r++)
{
for (int c = 0; c < ColumnCount; c++)
{
int idx = r * ColumnCount + c;
item[idx] = new GridViewItem(idx, r, c);
item[idx].Enable = false;
item[idx].Padding = new Padding(0, 0, 0, 0);
item[idx].TextAlign = ContentAlignment.MiddleCenter;
x = (c * w);
y = (r * h);
item[idx].rect = new RectangleF((float)x, (float)y, (float)w, (float)h);
}
}
this.Items = item;
}
else
{
//아이템의 갯수는 같으므로 좌표값만 변경해준다.
for (int r = 0; r < RowCount; r++)
{
for (int c = 0; c < ColumnCount; c++)
{
int idx = r * ColumnCount + c;
var item = Items[idx];
x = (c * w);
y = (r * h);
item.Dirty = true;
item.rect = new RectangleF((float)x, (float)y, (float)w, (float)h);
}
}
}
this.Invalidate();
//int i = 0;
//var menuList = this.Items.OrderBy(t => t.No).ToArray();
//foreach (var menu in menuList)
//{
// int x, y, w, h;
// // var menu = menus[i];
// var mWidth = menuwidth;
// if (menu.MenuWidth > 0) mWidth = menu.MenuWidth;
// w = mWidth;
// h = DisplayRectangle.Height - Padding.Top - Padding.Bottom;
// if (menu.isRightMenu)
// {
// x = DisplayRectangle.Right - Padding.Right - (rightAcc) - (MenuGap * rightIdx);
// y = DisplayRectangle.Top + Padding.Top;
// rightAcc += 0;// = 0;// x;
// rightIdx += 1;
// }
// else
// {
// x = DisplayRectangle.Left + Padding.Left + leftAcc + (MenuGap * leftIdx);
// y = DisplayRectangle.Top + Padding.Top;
// leftAcc += mWidth;
// leftIdx += 1;
// }
// rects[i] = new Rectangle(x, y, w, h);
// i += 1;
//}
}
}
}

View File

@@ -0,0 +1,37 @@
namespace Narumi.UC
{
partial class GuideSensor
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Narumi.UC
{
public partial class GuideSensor : Control
{
public int SensorValue { get; set; } = 0;
public bool LMark { get; set; } = false;
public bool RMark { get; set; } = false;
public GuideSensor()
{
InitializeComponent();
// Set Optimized Double Buffer to reduce flickering
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
// Redraw when resized
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.Resize += arLabel_Resize;
}
void arLabel_Resize(object sender, EventArgs e)
{
Invalidate();
}
protected override void OnPaint(PaintEventArgs pe)
{
var boxcount = 11;
var r = new RectangleF(this.DisplayRectangle.Left + Padding.Left,
this.DisplayRectangle.Top + Padding.Top,
this.DisplayRectangle.Width - Padding.Left - Padding.Right,
this.DisplayRectangle.Height - Padding.Top - Padding.Bottom);
var term = 3;
var w = ((r.Width -1) - (term * (boxcount - 1))) / boxcount;
var h = r.Height -1;
pe.Graphics.FillRectangle(new SolidBrush(this.BackColor), this.DisplayRectangle);
//pe.Graphics.DrawRectangle(Pens.Red, r.Left, r.Top, r.Width, r.Height);
for (int i = 0; i < boxcount; i++)
{
var x = r.Left + i * term + i * w;
var y = r.Top;
var r2 = new RectangleF(x, y, w, h);
if (this.Enabled == false)
{
pe.Graphics.FillRectangle(Brushes.LightGray, r2);
}
else
{
if (i == 0)
{
if (LMark)
pe.Graphics.FillRectangle(Brushes.SkyBlue, r2);
else
pe.Graphics.FillRectangle(Brushes.LightGray, r2);
}
else if (i == 9)
{
if (RMark)
pe.Graphics.FillRectangle(Brushes.SkyBlue, r2);
else
pe.Graphics.FillRectangle(Brushes.LightGray, r2);
}
else
{
if (SensorValue == i)
pe.Graphics.FillRectangle(Brushes.Tomato, r2);
else
pe.Graphics.FillRectangle(Brushes.LightGray, r2);
}
pe.Graphics.DrawRectangle(Pens.DimGray, r2.Left,r2.Top,r2.Width,r2.Height);
if (i == 0 || i == 10)
{
pe.Graphics.DrawString("M/K", this.Font,
new SolidBrush(this.ForeColor), r2,
new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
});
}
}
}
}
}
}

View File

@@ -0,0 +1,37 @@
namespace AGVControl
{
partial class MapControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.ClientSize = new System.Drawing.Size(800, 450);
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,621 @@
using AGVControl.Models;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TextBox;
namespace AGVControl
{
public class MapControlManager
{
public AGVActionPrediction PredictResult = null;
public AGV agv = new AGV();
public List<RFIDPoint> RFIDPoints = new List<RFIDPoint>();
public HashSet<RFIDConnection> rfidConnections = new HashSet<RFIDConnection>();
private ManualResetEvent mrepredict = new ManualResetEvent(true);
public MapControlManager()
{
}
~MapControlManager()
{
}
/// <summary>
/// 목표지정으로 모터방향이 이동하고 있는가?
/// history 데이터가 있어야 하며 기준데이터가 없는 경우 null 반환
/// </summary>
/// <returns></returns>
public bool? IsMotDirection_To_Target()
{
if (agv.MovementHistory.Any() == false || agv.MovementHistory.Count < 2) return null;
if (agv.MainPath.Any() == false) return null;
var prept = agv.MovementHistory.Skip(agv.MovementHistory.Count - 2).First();
var lstpt = agv.MovementHistory.Last();
//현재 이후의 경로를 가져온다
var curidx = agv.MainPath.FindIndex(t => t.Value == lstpt.Value);
var preidx = agv.MainPath.FindIndex(t => t.Value == prept.Value);
if (curidx == -1 || preidx == -1) return null;
//지정된경로 반대방향으로 이동하고 있다
return preidx < curidx;
}
public float GetDistance(Point p1, Point p2)
{
float dx = p1.X - p2.X;
float dy = p1.Y - p2.Y;
return (float)Math.Sqrt(dx * dx + dy * dy); // double을 float로 명시적 캐스팅
}
public AGVActionPrediction PredictNextAction()
{
if (mrepredict.WaitOne(1) == false)
{
PredictResult = CreatePrediction("이전 작업이 완료되지 않았습니다",
AGVActionReasonCode.busy,
AGVMoveState.Stop,
agv.Current_Motor_Direction, false);
return PredictResult;
}
mrepredict.Reset();
try
{
// 0. 설정경로와 리프트 방향 체크 (경로설정이 없을때에는 직선이동경로내의 방향들과 체크한다)
agv.IsTargetDirectionMatch = IsLiftDirectionMatch() ?? false;
// 1. 위치를 모를 때 (CurrentRFID가 0 또는 미설정)
if (agv.CurrentRFID.Value == 0)
{
PredictResult = CreatePrediction("AGV 위치 미확정(처음 기동)",
AGVActionReasonCode.NoPosition,
AGVMoveState.Run,
AgvDir.Backward, true,
moveSpeed: AgvSpeed.Low,
moveDiv: AgvSts.Straight);
return PredictResult;
}
//2. 이동방향을 모른다
if (agv.MovementHistory.Any() == false || agv.MovementHistory.Count < 2)
{
PredictResult = CreatePrediction("AGV이동방향 알수없음",
AGVActionReasonCode.NoDirection,
AGVMoveState.Run,
AgvDir.Backward, true,
moveSpeed: AgvSpeed.Low,
moveDiv: AgvSts.Straight);
return PredictResult;
}
// 3. 경로가 없거나 현재 위치가 경로에 없음
if ((agv.MainPath?.Count ?? 0) < 2 || agv.MainPath.Last().Value != agv.TargetRFID.Value)
{
//목적지가 없다면 진행할 수 없다
if (agv.TargetRFID == null)
{
PredictResult = CreatePrediction("경로 없음 또는 현재 위치 미확정",
AGVActionReasonCode.NoPath,
AGVMoveState.Stop,
agv.Current_Motor_Direction, true);
return PredictResult;
}
else
{
//목적지가 있는데 경로가 없다면 경로 예측을 진행해야한다.
var CurPt = agv.MovementHistory.Last();
var prlt = CalculatePath(CurPt, agv.TargetRFID);
if (prlt.Success == false)
{
PredictResult = CreatePrediction("목적지 경로 예측 실패",
AGVActionReasonCode.Unknown,
AGVMoveState.Stop,
agv.Current_Motor_Direction, true,
nextRFID: agv.TargetRFID);
return PredictResult;
}
else
{
//신규목적지에 대한 경로예측이 성공했다
agv.SubPath.Clear();
agv.MainPath = prlt.Path;
}
}
}
// 4. 경로상에서 다음 RFID 예측
int idx = agv.MainPath.FindIndex(p => p.Value == agv.CurrentRFID.Value);
if (idx < 0)
{
PredictResult = CreatePrediction("현재 위치가 경로에 없음",
AGVActionReasonCode.NotOnPath,
AGVMoveState.Stop,
agv.Current_Motor_Direction, true);
return PredictResult;
}
// 4. 목적지 도달 전, 회전이 필요한경우인가?
// 목적지 RFID 정보
var destRFID = agv.MainPath.Last();
//리프트 방향이 맞는가?
var IsLiftDir = IsLiftDirectionMatch() ?? false;
//모션이동방향이 맞는가?
var IsMotDir = IsMotDirection_To_Target() ?? false;
var PrePT = agv.MovementHistory.Skip(agv.MovementHistory.Count - 2).First();
var curPT = agv.MovementHistory.Last();
//리프트방향이 맞지 않다면 회전가능한 위치로 이동을 해야한다
if (IsLiftDir == false)
{
AgvSpeed? agv_spd = null;
AgvSts? agv_dir = null;
//회전가능한 위치로 이동을 해야한다
//1. 가까운 회전위치를 찾는다
var nearTurnPoint = RFIDPoints.Where(t => t.IsRotatable)?.OrderBy(t => GetDistance(t.Location, agv.CurrentRFID.Location)).FirstOrDefault() ?? null;
if (nearTurnPoint == null)
{
PredictResult = CreatePrediction("회전 가능한 위치가 없습니다",
AGVActionReasonCode.NoTurnPoint,
AGVMoveState.Stop,
agv.Current_Motor_Direction, true);
return PredictResult;
}
//2. 이동하기위한 경로계산 및 이동을 한다 (생성조건)
//2-1. 서브경로가없는경우
//2-2. 시작과 종료번호가 다른 경우(경로가 변경이 되는 조건이다)
if (agv.CurrentRFID.Value != nearTurnPoint.Value)
{
if (agv.SubPath.Any() == false || agv.SubPath.Count < 2 ||
agv.SubPath.First().Value != agv.CurrentRFID.Value ||
agv.SubPath.Last().Value != nearTurnPoint.Value)
{
var rlt = CalculatePath(agv.CurrentRFID, nearTurnPoint); //이전포인트도 추가를 해준다
if (rlt.Success) agv.SubPath = rlt.Path;
else
{
agv.SubPath.Clear();
PredictResult = CreatePrediction("회전 위치까지의 경로를 계산할 수 없습니다",
AGVActionReasonCode.PathCalcError,
AGVMoveState.Stop,
agv.Current_Motor_Direction, true,
nextRFID: nearTurnPoint);
return PredictResult;
}
}
//현재 모터방향을 확인하여 대상까지 이동하도록 해야한다
var curidx = agv.SubPath.FindIndex(t => t.Value == curPT.Value);
var preidx = agv.SubPath.FindIndex(t => t.Value == PrePT.Value);
AgvDir newdirection = agv.Current_Motor_Direction;
string message = "턴위치로 이동중";
if (preidx > curidx)
{
//지정경로를 거꾸로 이동하고 있다
if (agv.Current_Motor_Direction == AgvDir.Forward)
newdirection = AgvDir.Backward;
else
newdirection = AgvDir.Forward;
message += "(방향전환)";
}
//도로정보를 확인하여 속도와 분기명령을 실행한다
var roadinfo = GetRoadInfo(agv.SubPath, curPT);
agv_spd = roadinfo.spd;
agv_dir = roadinfo.dir;
PredictResult = CreatePrediction(message,
AGVActionReasonCode.MoveForTurn,
AGVMoveState.Run,
newdirection, true,
moveSpeed: agv_spd,
moveDiv: agv_dir,
nextRFID: nearTurnPoint);
return PredictResult;
}
var roadinfo2 = GetRoadInfo(agv.SubPath.Any() ? agv.SubPath : agv.MainPath, curPT);
agv_spd = roadinfo2.spd;
agv_dir = roadinfo2.dir;
PredictResult = CreatePrediction("턴(이동) 완료 대기",
AGVActionReasonCode.NeedTurnMove,
AGVMoveState.Stop,
agv.Current_Motor_Direction, true,
moveSpeed: agv_spd,
moveDiv: agv_dir,
nextRFID: nearTurnPoint);
return PredictResult;
}
//보조이동선제거
if (agv.SubPath != null && agv.SubPath.Any())
agv.SubPath.Clear();
//현재위치의 RFID에서 턴이 필요한경우
if (agv.CurrentRFID.NeedTurn)
{
//Turn이 완료되지 않았다면 턴 완료를 대기한다.
if (agv.CurrentRFID.TurnOK == false)
{
//아직 턴위치에 멈추지 않았다
if (agv.CurrentRFID.TurnStop == false)
{
//현재위치로 마크스탑이동을 하게한다
PredictResult = CreatePrediction("Wait for Turn(P)-Mark Stop",
AGVActionReasonCode.WaitForMarkStop,
AGVMoveState.Run,
agv.Current_Motor_Direction, true,
moveSpeed: agv.CurrentSpeed,
moveDiv: agv.CurrentSTS);
}
else
{
//턴위치에 정지했으니. 턴완료를 기다려야 한다
PredictResult = CreatePrediction("Wait for Turn(P)",
AGVActionReasonCode.NeedTurnPoint,
AGVMoveState.Run,
agv.Current_Motor_Direction, true,
moveSpeed: agv.CurrentSpeed,
moveDiv: agv.CurrentSTS);
}
return PredictResult;
}
}
//3. 목적지위치까지 이동이 완료되지 않았다면 계속 이동을 하게한다
if (agv.CurrentRFID.Value != destRFID.Value)
{
//현재 모터방향을 확인하여 대상까지 이동하도록 해야한다
var curidx = agv.MainPath.FindIndex(t => t.Value == curPT.Value);
var preidx = agv.MainPath.FindIndex(t => t.Value == PrePT.Value);
AgvDir newdirection = agv.Current_Motor_Direction;
string message = "목적지 이동중";
if (preidx > curidx)
{
//지정경로를 거꾸로 이동하고 있다
if (agv.Current_Motor_Direction == AgvDir.Forward)
newdirection = AgvDir.Backward;
else
newdirection = AgvDir.Forward;
message += "(방향전환)";
}
//경로상 바로 다음 위치를 확인한다
var nexstRFID = agv.MainPath.Skip(agv.MainPath.FindIndex(t => t.Value == curPT.Value) + 1).First();
var roadinfo = GetRoadInfo(agv.MainPath, curPT);
PredictResult = CreatePrediction(message,
AGVActionReasonCode.Normal,
AGVMoveState.Run,
newdirection, true,
moveSpeed: roadinfo.spd,
moveDiv: roadinfo.dir,
nextRFID: nexstRFID);
return PredictResult;
}
// 5. 목적지 도달 시
PredictResult = CreatePrediction("경로의 마지막 지점(목적지 도달)",
AGVActionReasonCode.Arrived,
AGVMoveState.Stop,
agv.Current_Motor_Direction, true,
nextRFID: destRFID);
return PredictResult;
}
catch (Exception ex)
{
PredictResult = CreatePrediction($"ERR:{ex.Message}",
AGVActionReasonCode.Unknown,
AGVMoveState.Stop,
agv.Current_Motor_Direction, true);
return PredictResult;
}
finally
{
mrepredict.Set();
}
}
(AgvSpeed? spd, AgvSts? dir, RFIDConnection info) GetRoadInfo(List<RFIDPoint> paths, RFIDPoint curPT)
{
//도로정보를 확인하여 속도와 분기명령을 실행한다
AgvSpeed? agv_spd = null;
AgvSts? agv_div = null;
RFIDConnection info = null;
var nextpt = paths.Skip(paths.FindIndex(t => t.Value == curPT.Value) + 1).FirstOrDefault();
if (nextpt != null)
{
var p1 = rfidConnections.Where(t => t.P1.Value == curPT.Value && t.P2.Value == nextpt.Value).FirstOrDefault();
if (p1 != null)
{
//positive
agv_spd = p1.MoveSpeedP;
agv_div = p1.MoveDirectionP;
info = p1;
}
var p2 = rfidConnections.Where(t => t.P2.Value == curPT.Value && t.P1.Value == nextpt.Value).FirstOrDefault();
if (p2 != null)
{
//negative
agv_spd = p2.MoveSpeedN;
agv_div = p2.MoveDirectionN;
info = p2;
}
}
return (agv_spd, agv_div, info);
}
/// <summary>
/// 이웃포인터를 반환합니다
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
public List<RFIDPoint> GetNeighbors(RFIDPoint pt)
{
var neighbors = new List<RFIDPoint>();
//값이 없는 경우 오류 반환
if (pt == null) return neighbors;
//연결정보에서 데이터를 찾은 후 반환한다
foreach (var connection in rfidConnections)
{
RFIDPoint nPT = null;
if (connection.P1.Value == pt.Value)
{
nPT = connection.P2;
}
else if (connection.P2.Value == pt.Value)
{
nPT = connection.P1;
}
if (nPT != null) neighbors.Add(nPT);
}
//중복제거후 반한
return neighbors.Distinct().ToList();
}
public RFIDPoint FindRFIDPoint(uint rfidValue)
{
if (RFIDPoints == null || RFIDPoints.Any() == false) return null;
return RFIDPoints.FirstOrDefault(r => r.Value == rfidValue);
}
private float Heuristic(Point a, Point b)
{
return (float)Math.Sqrt(Math.Pow(a.X - b.X, 2) + Math.Pow(a.Y - b.Y, 2));
}
private PathResult ReconstructPath(Dictionary<uint, RFIDPoint> cameFrom, RFIDPoint current)
{
var path = new List<RFIDPoint> { current };
while (cameFrom.ContainsKey(current.Value))
{
current = cameFrom[current.Value];
if (path.Contains(current) == false)
path.Insert(0, current);
else
break; //왜인지 반복되는경우가있어 종료한다
}
return new PathResult
{
Path = path,
};
}
public PathResult CalculatePath(RFIDPoint start, RFIDPoint end)
{
var openList = new List<RFIDPoint> { start };
var closedList = new List<RFIDPoint>();
var cameFrom = new Dictionary<uint, RFIDPoint>();
var gScore = new Dictionary<RFIDPoint, float> { { start, 0 } };
var fScore = new Dictionary<RFIDPoint, float> { { start, Heuristic(start.Location, end.Location) } };
if (start.Value == end.Value)
{
return new PathResult
{
Message = "시작위치와 대상위치가 동일 합니다",
Path = null,
};
}
//if (autorun) openList.Clear();
while (openList.Count > 0)
{
var current = openList.OrderBy(p => fScore.ContainsKey(p) ? fScore[p] : float.MaxValue).First();
if (current.Value == end.Value)
{
return ReconstructPath(cameFrom, current);
}
openList.Remove(current);
closedList.Add(current);
var nb = GetNeighbors(current);
foreach (var neighbor in nb)
{
if (closedList.Contains(neighbor))
continue;
float tentativeGScore = gScore[current] + GetDistance(current.Location, neighbor.Location);
if (!openList.Contains(neighbor))
openList.Add(neighbor);
else if (tentativeGScore >= gScore[neighbor])
continue;
cameFrom[neighbor.Value] = (RFIDPoint)current;
gScore[neighbor] = tentativeGScore;
fScore[neighbor] = gScore[neighbor] + Heuristic(neighbor.Location, end.Location);
}
}
return new PathResult
{
Path = openList,
};
}
public PathResult CalculatePath(uint tagStrt, uint tagEnd)
{
var retval = new PathResult
{
Message = string.Empty,
Path = new List<RFIDPoint>(),
};
var startPoint = FindRFIDPoint(tagStrt);
var endPoint = FindRFIDPoint(tagEnd);
if (startPoint == null || endPoint == null)
{
retval.Message = "유효한 RFID 값을 입력해주세요.";
return retval;
}
retval = CalculatePath(startPoint, endPoint);
if (retval.Success == false)
retval.Message = "경로를 찾을 수 없습니다";
return retval;
}
/// <summary>
/// 리프트방향과 대상위치와의 방향이 일치하는가?
/// 목적지경로가 셋팅된 경우 현재 이동방향이 목적지방향과 일치하는가?
/// 이동경로정보가 없거나 목적지가 없으면 null 이 반환됨
/// </summary>
/// <returns></returns>
public bool? IsLiftDirectionMatch()
{
if (agv.MovementHistory.Any() && agv.MovementHistory.Count > 1)
{
RFIDPoint TargetPT = null;
var prept = agv.MovementHistory.Skip(agv.MovementHistory.Count - 2).First();
var lstpt = agv.MovementHistory.Last();
//뒤로이동하는경우라면 이전위치에 리프트가 있다.
if (lstpt.Direction == AgvDir.Backward)
{
TargetPT = prept;
}
else //앞으로 이동한다면 이동방향과 동일하다
{
//이전위치는 제거 하고 처음발견된 것을 대상으로 한다
TargetPT = GetNeighbors(lstpt).Where(t => t.Value != prept.Value).FirstOrDefault();
}
//목적지가 있다면 목적지의 방향과 일치하는지 확인해야한다
//남은경로중에 방향이 고정된 핀이 있다면 그것과 일치하는지 확인해야 한다
if (agv.MainPath.Any())
{
//지정된경로 반대방향으로 이동하고 있다
if ((IsMotDirection_To_Target() ?? false) == false)
{
return false;
}
else
{
var nextRoutes = agv.MainPath.Skip(agv.MainPath.FindIndex(t => t.Value == lstpt.Value) + 1).ToList();
var DirectionMatch = true;
foreach (var item in nextRoutes)
{
if (item.FixedDirection != null && item.FixedDirection != lstpt.Direction)
{
DirectionMatch = false;
break;
}
}
return DirectionMatch;
}
}
else
{
//대상포인트와의 방향만 체크한다.
//고정대상이없다면 방향이 맞는것으로 한다
return (TargetPT.FixedDirection ?? lstpt.Direction) == lstpt.Direction;
}
}
else
{
//이동된경로정보가 없다면 리프트 방향을 체크할 수 없으므로 대상과 위치가 맞지 않는걸로 기본값을 설정한다
//이렇게 설정하면 대상으로 이동불가하고 뒤로 가도록 유도된다
return null;
}
}
// Changed 속성 설정을 위한 헬퍼 메서드
private bool IsPredictionChanged(AGVActionPrediction newPrediction)
{
if (PredictResult == null) return true; // 이전 예측이 없으면 변경됨
// Idx와 Changed를 제외하고 비교
return !PredictResult.Equals(newPrediction);
}
private AGVActionPrediction CreatePrediction(
string reason,
AGVActionReasonCode reasonCode,
AGVMoveState moveState,
AgvDir direction, bool IDXUpdate = true,
AgvSpeed? moveSpeed = null,
AgvSts? moveDiv = null,
RFIDPoint nextRFID = null
)
{
var newPrediction = new AGVActionPrediction
{
NextRFID = nextRFID,
Reason = reason,
ReasonCode = reasonCode,
MoveState = moveState,
Direction = direction,
MoveSpeed = moveSpeed,
MoveDiv = moveDiv,
Idx = IDXUpdate ? (PredictResult?.Idx + 1 ?? 1) : (PredictResult?.Idx ?? 0),
CreateTime = DateTime.Now,
};
newPrediction.Changed = IsPredictionChanged(newPrediction);
return newPrediction;
}
}
}

View File

@@ -0,0 +1,352 @@
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Security.Permissions;
using System.Windows.Forms;
namespace AGVControl.Models
{
//public class CRFIDData
//{
// public UInt16 Value { get; set; }
// public Point Location { get; set; }
// public override string ToString()
// {
// return $"RFID:{Value},P:{Location.X},{Location.Y}";
// }
//}
public class movehistorydata : RFIDPoint
{
public AgvDir Direction { get; set; }
public override string ToString()
{
return $"RFID:{Value},DIR:{Direction},P:{Location.X},{Location.Y}";
}
}
public class AGV
{
/// <summary>
/// RFID 번호
/// </summary>
public RFIDPoint CurrentRFID { get; set; }
/// <summary>
/// 목적지가 셋팅된경우 해당 값
/// </summary>
public RFIDPoint TargetRFID { get; set; }
/// <summary>
/// 배터리잔량(%)
/// </summary>
public float BatteryLevel { get; set; } = 0f;
/// <summary>
/// 배터리온도(board)
/// </summary>
public double BatteryTemp1 { get; set; } = 0;
/// <summary>
/// 배터리온도(cell)
/// </summary>
public double BatteryTemp2 { get; set; } = 0;
/// <summary>
/// AGV Speed
/// </summary>
public AgvSpeed CurrentSpeed { get; set; }
/// <summary>
/// AGV STS
/// </summary>
public AgvSts CurrentSTS { get; set; }
/// <summary>
/// AGV Motor Direction
/// </summary>
public AgvDir Current_Motor_Direction { get; set; }
/// <summary>
/// 현재위치가 수산되면 목적지까지의 방향값이 계산됩니다.
/// </summary>
public AgvDir? TargetDirection { get; set; }
/// <summary>
/// AGV.System1.agv_Run
/// </summary>
public bool IsMoving { get; set; }
/// <summary>
/// AGV.System1.Mark1_Check | Mark2_Check
/// </summary>
public bool IsMarkCheck { get; set; }
/// <summary>
/// 이동대상과 AGV의 머리방향이 일치하는지?
/// </summary>
public bool IsTargetDirectionMatch { get; set; }
/// <summary>
/// 메인경로
/// 경로검색으로 입력된 경로
/// </summary>
public List<RFIDPoint> MainPath { get; set; } = new List<RFIDPoint>();
/// <summary>
/// 메인경로외에 거쳐가는 중간 경로
/// </summary>
public List<RFIDPoint> SubPath { get; set; }
public List<string> PathRFIDs { get; set; }
// 이동 경로 기록을 위한 새로운 속성들
public List<movehistorydata> MovementHistory { get; } = new List<movehistorydata>();
public const int HISTORY_SIZE = 10; // 최근 4개 위치 기록
public AGV()
{
MainPath = new List<RFIDPoint>();
SubPath = new List<RFIDPoint>();
PathRFIDs = new List<string>();
CurrentRFID = new RFIDPoint();
TargetRFID = new RFIDPoint();
TargetDirection = AgvDir.Forward;
// BodyAngle = null;
}
// 이동 경로에 새로운 RFID 추가
public void AddToMovementHistory(UInt16 rfidValue, Point position, AgvDir direction)
{
// 중복 RFID가 연속으로 들어오는 경우 무시
if (MovementHistory.Count > 0 && MovementHistory.Last().Value == rfidValue)
return;
MovementHistory.Add(new movehistorydata { Value = rfidValue, Direction = direction, Location = position });
// 기록 크기 제한
if (MovementHistory.Count > HISTORY_SIZE)
{
MovementHistory.RemoveAt(0);
}
//최초방향과 마지막 방향이 일치하지 않으면 그 이전의 데이터는 삭제한다.
if (MovementHistory.Count > 2 && MovementHistory.First().Direction != MovementHistory.Last().Direction)
{
var lastTwo = MovementHistory.Skip(MovementHistory.Count - 2).Take(2).ToArray(); // [9, 10]
MovementHistory.Clear();
MovementHistory.AddRange(lastTwo);
}
// 위치 업데이트 시 자동으로 히스토리 파일에 저장
SaveHistoryOnUpdate();
}
// 연결 정보 기반 실제 이동 방향 계산
public AgvDir? CalculateActualDirectionByConnection(uint currentRFID, uint previousRFID, List<RFIDConnection> connections)
{
if (connections == null || connections.Count == 0)
return null;
// 이전 RFID에서 현재 RFID로의 연결 확인
var connection = connections.FirstOrDefault(c =>
(c.P1.Value == previousRFID && c.P2.Value == currentRFID) ||
(c.P1.Value == currentRFID && c.P2.Value == previousRFID));
if (connection == null)
return null; // 연결되지 않은 경로
// 연결 방향에 따라 실제 이동 방향 결정
if (connection.P1.Value == previousRFID && connection.P2.Value == currentRFID)
{
return AgvDir.Forward; // Start -> End 방향으로 이동
}
else
{
return AgvDir.Backward; // End -> Start 방향으로 이동
}
}
// 연결 정보 기반 방향 불일치 검증 및 정정
public bool ValidateAndCorrectDirectionByConnection(AgvDir expectedDirection, List<RFIDConnection> connections)
{
if (MovementHistory.Count < 2 || connections == null)
return true; // 검증 불가능한 경우
// 최근 두 RFID 값 가져오기
var recentRFIDs = MovementHistory.Skip(MovementHistory.Count - 2).Take(2).ToList();
if (recentRFIDs.Count < 2)
return true;
var previousRFID = recentRFIDs[0];
var currentRFID = recentRFIDs[1];
var actualDirection = CalculateActualDirectionByConnection(currentRFID.Value, previousRFID.Value, connections);
if (!actualDirection.HasValue)
return true; // 연결 정보로 방향 판단 불가
// 방향이 일치하지 않는 경우
if (actualDirection.Value != expectedDirection)
{
// AGV 모터 방향을 실제 이동 방향으로 정정
//CurrentAGVDirection = actualDirection.Value;
TargetDirection = actualDirection.Value;
return false; // 정정됨을 알림
}
return true; // 방향 일치
}
// RFID 순서 기반 실제 이동 방향 계산 (기존 메서드 - 호환성 유지)
public AgvDir? CalculateActualDirectionByRFID()
{
if (MovementHistory.Count < 2)
return null;
// 최근 두 RFID 값으로부터 실제 이동 방향 계산
var recentRFIDs = MovementHistory.Skip(Math.Max(0, MovementHistory.Count - 2)).Take(2).ToList();
if (recentRFIDs.Count < 2)
return null;
var prevRFID = recentRFIDs[0];
var currentRFID = recentRFIDs[1];
// RFID 값의 증가/감소로 방향 판단
if (currentRFID.Value > prevRFID.Value)
{
return AgvDir.Forward; // RFID 값이 증가하면 전진
}
else if (currentRFID.Value < prevRFID.Value)
{
return AgvDir.Backward; // RFID 값이 감소하면 후진
}
else
{
return null; // 같은 RFID 값이면 방향 판단 불가
}
}
// 위치 히스토리 파일 저장 (최근 3개만 저장)
public void SavePositionHistory(string filePath)
{
try
{
// 최근 3개의 히스토리만 저장
var recentHistory = MovementHistory.Skip(Math.Max(0, MovementHistory.Count - 3)).ToList();
var lines = new List<string>();
lines.Add($"# AGV Position History - {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
lines.Add("# Format: RFID,Direction,X,Y,Timestamp");
foreach (var history in recentHistory)
{
lines.Add($"{history.Value},{history.Direction},{history.Location.X},{history.Location.Y},{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
}
System.IO.File.WriteAllLines(filePath, lines);
}
catch (Exception ex)
{
// 로그 기록 (실제 환경에서는 로깅 시스템 사용)
System.Diagnostics.Debug.WriteLine($"SavePositionHistory Error: {ex.Message}");
}
}
// 위치 히스토리 파일 로드
public bool LoadPositionHistory(string filePath)
{
try
{
if (!System.IO.File.Exists(filePath))
return false;
var lines = System.IO.File.ReadAllLines(filePath);
MovementHistory.Clear();
foreach (var line in lines)
{
// 주석 라인 건너뛰기
if (line.StartsWith("#") || string.IsNullOrWhiteSpace(line))
continue;
var parts = line.Split(',');
if (parts.Length >= 4)
{
if (UInt16.TryParse(parts[0], out UInt16 rfidValue) &&
Enum.TryParse<AgvDir>(parts[1], out AgvDir direction) &&
int.TryParse(parts[2], out int x) &&
int.TryParse(parts[3], out int y))
{
MovementHistory.Add(new movehistorydata
{
Value = rfidValue,
Direction = direction,
Location = new Point(x, y)
});
}
}
}
return MovementHistory.Count > 0;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"LoadPositionHistory Error: {ex.Message}");
return false;
}
}
// 시작 시 위치 히스토리 자동 로드
public void LoadHistoryOnStartup()
{
string historyFilePath = System.IO.Path.Combine(
System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
"agv_position_history.dat"
);
LoadPositionHistory(historyFilePath);
}
// 위치 업데이트 시 자동 저장
public void SaveHistoryOnUpdate()
{
string historyFilePath = System.IO.Path.Combine(
System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
"agv_position_history.dat"
);
SavePositionHistory(historyFilePath);
}
}
public class PathNode
{
public Point Location { get; set; }
public string RFID { get; set; }
public double G { get; set; } // 시작점에서 현재 노드까지의 비용
public double H { get; set; } // 현재 노드에서 목표점까지의 예상 비용
public double F => G + H; // 총 비용
public PathNode Parent { get; set; }
public PathNode(Point location, string rfid)
{
Location = location;
RFID = rfid;
G = 0;
H = 0;
Parent = null;
}
}
}

View File

@@ -0,0 +1,58 @@
using AGVControl.Models;
using System;
namespace AGVControl
{
public class AGVActionPrediction
{
public AgvDir Direction { get; set; }
public RFIDPoint NextRFID { get; set; }
public string Reason { get; set; }
public AGVActionReasonCode ReasonCode { get; set; }
public AGVMoveState MoveState { get; set; } // RUN 또는 STOP
public AgvSpeed? MoveSpeed { get; set; }
public AgvSts? MoveDiv { get; set; }
public UInt32 Idx { get; set; }
public bool Changed { get; set; }
public DateTime CreateTime { get; set; }
// override object.Equals
public bool Equals(AGVActionPrediction obj)
{
// null 체크
if (obj == null) return false;
// 참조가 같으면 true
if (ReferenceEquals(this, obj)) return true;
// 핵심 속성들만 비교 (Idx, Changed 제외)
if (obj.Direction != this.Direction) return false;
if (obj.ReasonCode != this.ReasonCode) return false;
if (obj.MoveState != this.MoveState) return false;
if (obj.MoveSpeed != this.MoveSpeed) return false;
if (obj.MoveDiv != this.MoveDiv) return false;
// NextRFID 비교 (null 체크 포함)
if (obj.NextRFID == null || this.NextRFID == null)
{
if (obj.NextRFID != this.NextRFID) return false; // 하나만 null이면 false
}
else
{
if (obj.NextRFID.Value != this.NextRFID.Value) return false;
}
// Reason 비교 (null 체크 포함)
if (obj.Reason == null || this.Reason == null)
{
if (obj.Reason != this.Reason) return false; // 하나만 null이면 false
}
else
{
if (obj.Reason != this.Reason) return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,14 @@
using System.Drawing;
using System;
namespace AGVControl.Models
{
public class CustomLine
{
public Point StartPoint { get; set; }
public Point EndPoint { get; set; }
public Color LineColor { get; set; }
public int LineWidth { get; set; }
}
}

View File

@@ -0,0 +1,86 @@
using System.Drawing;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace AGVControl.Models
{
/// <summary>
/// 도로특성정보
/// </summary>
public class RoadInformation
{
/// <summary>
/// 시작지점
/// </summary>
public RFIDPoint P1 { get; set; }
/// <summary>
/// 종료지점
/// </summary>
public RFIDPoint P2 { get; set; }
/// <summary>
/// 도로의 사용여부
/// </summary>
public bool Enable { get; set; }
/// <summary>
/// AGV의 이동방향(리프트방향)
/// 목적지 방향과의 일치를 위해 해당 방향을 설정할 수 있따
/// </summary>
public AgvDir? LiftDirection { get; set; }
/// <summary>
/// AGV이동시 속도 (high, middle, low)
/// </summary>
public AgvSpeed? MoveSpeed { get; set; }
/// <summary>
/// AGV이동시 방향모드(좌분기, 전진, 우분기)
/// </summary>
public AgvSts? MoveDirection { get; set; }
public RoadInformation()
{
P1 = null;
P2 = null;
LiftDirection = null;
MoveSpeed = null;
MoveDirection = null;
Enable = false;
}
/// <summary>
/// 값이 설정되어있는지
/// </summary>
public bool HasValue
{
get
{
if (P1 == null || P2 == null) return false;
if (LiftDirection == null && MoveSpeed == null && MoveDirection == null) return false;
return true;
}
}
}
public class MagnetLine
{
public Point StartPoint { get; set; }
public Point EndPoint { get; set; }
public List<Point> BranchPoints { get; set; }
public Dictionary<Point, BranchDirection> BranchDirections { get; set; }
public MagnetLine()
{
BranchPoints = new List<Point>();
BranchDirections = new Dictionary<Point, BranchDirection>();
}
}
}

View File

@@ -0,0 +1,13 @@
using System.Drawing;
using System;
using System.Collections.Generic;
namespace AGVControl.Models
{
public enum BranchDirection
{
Left,
Straight,
Right
}
}

View File

@@ -0,0 +1,63 @@
using System.Drawing;
using System;
using System.Collections.Generic;
namespace AGVControl.Models
{
public class MapText
{
private bool _dirty = true;
private Point _location;
private string _text;
private Font _font;
public bool Dirty
{
get => _dirty;
set => _dirty = value;
}
public Point Location
{
get => _location;
set
{
if (_location != value)
{
_location = value;
_dirty = true;
}
}
}
public string Text
{
get => _text;
set
{
if (_text != value)
{
_text = value;
_dirty = true;
}
}
}
public Color TextColor { get; set; }
public Color BackgroundColor { get; set; }
public Font Font
{
get => _font;
set
{
if (_font != value)
{
_font = value;
_dirty = true;
}
}
}
public RectangleF Bounds { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
using AGVControl.Models;
using System.Collections.Generic;
using System.Linq;
namespace AGVControl
{
public class PathResult
{
public bool Success
{
get
{
return Path != null && Path.Any();
}
}
public string Message { get; set; }
public List<RFIDPoint> Path { get; set; }
}
}

View File

@@ -0,0 +1,214 @@
using AGVControl.Models;
using AR;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.Tracing;
namespace AGVControl
{
public class RFIDConnection
{
/// <summary>
/// 시작지점
/// </summary>
public RFIDPoint P1 { get; set; }
/// <summary>
/// 종료지점
/// </summary>
public RFIDPoint P2 { get; set; }
/// <summary>
/// 도로의 사용여부
/// </summary>
public bool EnableP { get; set; }
public bool EnableN { get; set; }
/// <summary>
/// AGV의 이동방향(리프트방향)
/// 목적지 방향과의 일치를 위해 해당 방향을 설정할 수 있따
/// </summary>
public AgvDir? LiftDirectionP { get; set; }
public AgvDir? LiftDirectionN { get; set; }
/// <summary>
/// AGV이동시 속도 (high, middle, low)
/// </summary>
public AgvSpeed? MoveSpeedP { get; set; }
public AgvSpeed? MoveSpeedN { get; set; }
/// <summary>
/// AGV이동시 방향모드(좌분기, 전진, 우분기)
/// </summary>
public AgvSts? MoveDirectionP { get; set; }
public AgvSts? MoveDirectionN { get; set; }
/// <summary>
/// 파일저장 및 불러오기시 사용하는 문자열로 반환
/// </summary>
[Browsable(false)]
public string DataFileString
{
get
{
var str_enbP = EnableP ? "1" : "0";
var str_liftP = "";
if (LiftDirectionP != null) str_liftP = ((int)LiftDirectionP).ToString();
var str_movespeedP = "";
if (MoveSpeedP != null) str_movespeedP = ((int)MoveSpeedP).ToString();
var str_movdirP = "";
if (MoveDirectionP != null) str_movdirP = ((int)MoveDirectionP).ToString();
var str_enbN = EnableP ? "1" : "0";
var str_liftN = "";
if (LiftDirectionN != null) str_liftN = ((int)LiftDirectionN).ToString();
var str_movespeedN = "";
if (MoveSpeedN != null) str_movespeedN = ((int)MoveSpeedN).ToString();
var str_movdirN = "";
if (MoveDirectionN != null) str_movdirN = ((int)MoveDirectionN).ToString();
var PStr= $"{P1.Location.X},{P1.Location.Y},{P2.Location.X},{P2.Location.Y}," + //location
$"{P1.Value},{P2.Value}," + //rfid values
$"{str_enbP};{str_liftP};{str_movespeedP};{str_movdirP}," +
$"{str_enbN};{str_liftN};{str_movespeedN};{str_movdirN}";
return $"{PStr}";
}
set
{
var buf = value.Split(',');
if (buf.Length >= 2)
{
var p1x = int.Parse(buf[0]);
var p1y = int.Parse(buf[1]);
var p2x = int.Parse(buf[2]);
var p2y = int.Parse(buf[3]);
var p1v = ushort.Parse(buf[4]);
var p2v = ushort.Parse(buf[5]);
if (P1 == null) P1 = new RFIDPoint();
P1.Location = new System.Drawing.Point(p1x, p1y);
P1.Value = p1v;
if (P2 == null) P2 = new RFIDPoint();
P2.Location = new System.Drawing.Point(p2x, p2y);
P2.Value = p2v;
if (buf[6].Contains(";")) //양방향 정보
{
var StrP = buf[6].Split(';');
var StrN = buf[7].Split(';');
//Positive
this.EnableP = StrP[0] == "1";
if (StrP[1].isEmpty()) LiftDirectionP = null;
else LiftDirectionP = (AgvDir)int.Parse(StrP[1]);
if (StrP[2].isEmpty()) MoveSpeedP = null;
else MoveSpeedP = (AgvSpeed)int.Parse(StrP[2]);
if (StrP[3].isEmpty()) MoveDirectionP = null;
else MoveDirectionP = (AgvSts)int.Parse(StrP[3]);
//Negative
this.EnableN = StrN[0] == "1";
if (StrN[1].isEmpty()) LiftDirectionN = null;
else LiftDirectionN = (AgvDir)int.Parse(StrN[1]);
if (StrN[2].isEmpty()) MoveSpeedN = null;
else MoveSpeedN = (AgvSpeed)int.Parse(StrN[2]);
if (StrN[3].isEmpty()) MoveDirectionN = null;
else MoveDirectionN = (AgvSts)int.Parse(StrN[3]);
}
else
{
this.EnableP = buf[6] == "1";
if (buf[7].isEmpty()) LiftDirectionP = null;
else LiftDirectionP = (AgvDir)int.Parse(buf[7]);
if (buf[8].isEmpty()) MoveSpeedP = null;
else MoveSpeedP = (AgvSpeed)int.Parse(buf[8]);
if (buf[9].isEmpty()) MoveDirectionP = null;
else MoveDirectionP = (AgvSts)int.Parse(buf[9]);
this.EnableN = this.EnableP;
this.LiftDirectionN = this.LiftDirectionP;
this.MoveSpeedN = this.MoveSpeedP;
this.MoveDirectionN = this.MoveDirectionP;
}
}
}
}
public RFIDConnection(string dataline = "")
{
P1 = null;
P2 = null;
LiftDirectionP = null;
MoveSpeedP = null;
MoveDirectionP = null;
EnableP = false;
LiftDirectionN = null;
MoveSpeedN = null;
MoveDirectionP = null;
EnableP = false;
if (dataline.isEmpty() == false) DataFileString = dataline;
}
/// <summary>
/// 값이 설정되어있는지
/// </summary>
public bool HasValue
{
get
{
if (P1 == null || P2 == null) return false;
if (LiftDirectionP == null && MoveSpeedP == null && MoveDirectionP == null &&
LiftDirectionN == null && MoveSpeedN == null && MoveDirectionN == null) return false;
return true;
}
}
public override bool Equals(object obj)
{
if (obj is RFIDConnection other)
{
return (P1 == other.P1 && P2 == other.P2);
}
return false;
}
public override int GetHashCode()
{
return P1.GetHashCode() ^ P2.GetHashCode();
}
public override string ToString()
{
//연결정보를 확인
return $"{P1.Value} ↔ {P2.Value},ENB:{(EnableP ? "O" : "X")}|{(EnableN ? "O" : "X")}";
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Drawing;
using System;
using System.Collections.Generic;
namespace AGVControl.Models
{
public class RFIDLine
{
public Point StartPoint { get; set; }
public Point EndPoint { get; set; }
public float Distance
{
get {
float dx = StartPoint.X - EndPoint.X;
float dy = StartPoint.Y - EndPoint.Y;
return (float)Math.Sqrt(dx * dx + dy * dy); // double을 float로 명시적 캐스팅
}
}
//public uint StartRFID { get; set; }
//public uint EndRFID { get; set; }
//public bool IsBidirectional { get; set; } = true; // 양방향 이동 가능 여부
//public float Distance { get; set; } // 두 RFID 포인트 사이의 거리
//public List<uint> ConnectedRFIDs { get; set; } = new List<uint>(); // 연결된 모든 RFID 값들
//public Dictionary<uint, uint> NextRFID { get; set; } = new Dictionary<uint, uint>(); // 각 RFID의 다음 RFID
//public Dictionary<uint, uint> PrevRFID { get; set; } = new Dictionary<uint, uint>(); // 각 RFID의 이전 RFID
}
}

View File

@@ -0,0 +1,59 @@
using System.Drawing;
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace AGVControl.Models
{
public class RFIDPoint
{
public Point Location { get; set; }
public ushort Value { get; set; }
public string NextRFID { get; set; } // 다음 RFID 포인트의 값
public bool IsBidirectional { get; set; } // 양방향 연결 여부
public bool IsRotatable { get; set; } // 회전 가능 여부
public AgvDir? FixedDirection { get; set; } // 고정 방향(없으면 null)
public bool IsTerminal { get; set; } // 종단 여부
public bool NeedTurn { get; set; }
public bool TurnStop { get; set; }
public bool TurnOK { get; set; }
public DateTime TurnStart { get; set; }
public DateTime TurnEnd { get; set; }
[Browsable(false)]
public RectangleF Bounds { get; set; }
public void Clear()
{
this.Location = Point.Empty;
this.Value = 0;
TurnStop = false;
TurnOK = false;
TurnStart = new DateTime(1982, 11, 23);
TurnEnd = new DateTime(1982, 11, 23);
}
public bool IsEmpty
{
get
{
//RFID값이나 위치 값이 없으면 비어있는 것으로 한다.
if (this.Location.IsEmpty) return true;
if ((this.Value < 1)) return true;
return false;
}
}
public RFIDPoint()
{
IsRotatable = false; // 기본값은 회전 불가능
IsBidirectional = true; // 기본값은 양방향
FixedDirection = null;
IsTerminal = false; // 기본값은 종단 아님
Clear();
}
public override string ToString()
{
return $"[RFIDPoint] {Value},P:{Location.X},{Location.Y}";
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
namespace AGVControl.Models
{
public class ToolBarItem
{
private bool _ishovering = false;
public int Idx { get; set; }
public Rectangle Bounds { get; set; }
public bool isHovering
{
get { return _ishovering; }
set
{
Dirty = _ishovering != value;
_ishovering = value;
}
}
public string Title { get; set; }
public bool Dirty { get; private set; }
public ToolBarItem()
{
Bounds = Rectangle.Empty;
}
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AGVControl
{
/// <summary>
/// 실제 AGV컨트롤러의 STS값에는 F,B의 값이 들어있고
/// 아래 항목은 해당 문자의 ASCII코드값이다 첫자를 byte로 변경하고 변환하면 된다
/// </summary>
public enum AgvDir : byte
{
Forward = 0x46,
Backward = 0x42,
}
public enum AGVMoveState
{
Stop = 0,
Run
}
/// <summary>
/// 실제 AGV컨트롤러의 STS값에는 H,L,M,S의 값이 들어있고
/// 아래 항목은 해당 문자의 ASCII코드값이다 첫자를 byte로 변경하고 변환하면 된다
/// </summary>
public enum AgvSpeed : byte
{
High = 0x48,
Middle = 0x4D,
Low = 0x4C,
MarkStop = 0x53,
}
/// <summary>
/// STS : S,L,R
/// </summary>
public enum AgvSts : byte
{
Straight = 0x53,
Left = 0x4c,
Right = 0x052,
}
public enum AGVActionReasonCode
{
Unknown = 0,
NoPosition, // 위치 미확정(처음 기동)
NoPath, // 경로 없음 또는 현재 위치 미확정
NotOnPath, // 현재 위치가 경로에 없음
Arrived, // 경로의 마지막 지점(목적지 도달)
Normal, // 정상(다음 RFID 있음)
/// <summary>
/// 방향전환을 위한 턴이다
/// </summary>
NeedTurnMove,
/// <summary>
/// 지정된 RFID위치에서 TURN이 요청되었다
/// </summary>
NeedTurnPoint,
NoTurnPoint,
PathCalcError,
NoDirection,
MoveForTurn,
busy,
WaitForMarkStop,
}
}

View File

@@ -0,0 +1,37 @@
namespace AGVControl
{
partial class MyRadioButton
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AGVControl
{
public partial class MyRadioButton : RadioButton
{
public int CheckWidth { get; set; } = 30;
public Color CheckOnColor { get; set; } = Color.OrangeRed;
public Color CheckOffColor { get; set; } = Color.DimGray;
public Color Bordercolor { get; set; } = Color.DimGray;
public int BorderSize { get; set; } = 2;
public int BorderRadius { get; set; } = 7;
public MyRadioButton()
{
InitializeComponent();
// Set Optimized Double Buffer to reduce flickering
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
// Redraw when resized
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.Resize += arLabel_Resize;
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.InterpolationMode = InterpolationMode.High;
pe.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
pe.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
pe.Graphics.Clear(this.BackColor);
var XPosition = this.DisplayRectangle.Left;
var YPosition = this.DisplayRectangle.Top;
using (GraphicsPath Path = new GraphicsPath())
{
Path.AddLine(XPosition + BorderRadius, YPosition, XPosition + Width - (BorderRadius * 2), YPosition);
Path.AddArc(XPosition + Width - (BorderRadius * 2), YPosition, BorderRadius * 2, BorderRadius * 2, 270, 90);
Path.AddLine(XPosition + Width, YPosition + BorderRadius, XPosition + Width, YPosition + Height - (BorderRadius * 2));
Path.AddArc(XPosition + Width - (BorderRadius * 2), YPosition + Height - (BorderRadius * 2), BorderRadius * 2, BorderRadius * 2, 0, 90);
Path.AddLine(XPosition + Width - (BorderRadius * 2), YPosition + Height, XPosition + BorderRadius, YPosition + Height);
Path.AddArc(XPosition, YPosition + Height - (BorderRadius * 2), BorderRadius * 2, BorderRadius * 2, 90, 90);
Path.AddLine(XPosition, YPosition + Height - (BorderRadius * 2), XPosition, YPosition + BorderRadius);
Path.AddArc(XPosition, YPosition, BorderRadius * 2, BorderRadius * 2, 180, 90);
Path.CloseFigure();
var r1 = new Rectangle(
DisplayRectangle.Left, DisplayRectangle.Top,
CheckWidth,
DisplayRectangle.Height - 1);
var r2 = new Rectangle(r1.Right + 3, r1.Top, DisplayRectangle.Width - r1.Width - 3 - Padding.Right, r1.Height);
var CC = Checked ? CheckOnColor : CheckOffColor;
pe.Graphics.FillRectangle(new SolidBrush(CC), r1);
StringFormat sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
if (this.TextAlign == ContentAlignment.MiddleLeft) sf.Alignment = StringAlignment.Near;
else if (this.TextAlign == ContentAlignment.MiddleRight) sf.Alignment = StringAlignment.Far;
pe.Graphics.DrawString(this.Text, this.Font, new SolidBrush(ForeColor), r2, sf);
//pe.Graphics.DrawRectangle(new Pen(this.Bordercolor, this.BorderSize), DisplayRectangle);
this.Region = new System.Drawing.Region(Path);
pe.Graphics.DrawPath(new Pen(this.Bordercolor, this.BorderSize), Path);
}
}
void arLabel_Resize(object sender, EventArgs e)
{
Invalidate();
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("AGVControl")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AGVControl")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("8cb883c0-99c3-4dd4-b017-f9b92010a806")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 버전
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AGVControl.Properties {
using System;
/// <summary>
/// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
/// </summary>
// 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
// 클래스에서 자동으로 생성되었습니다.
// 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여 ResGen을
// 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AGVControl.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대한 현재 스레드의 CurrentUICulture
/// 속성을 재정의합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
/// </summary>
internal static System.Drawing.Bitmap ico_navi_40 {
get {
object obj = ResourceManager.GetObject("ico_navi_40", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="ico_navi_40" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ico_navi_40.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

View File

@@ -0,0 +1,37 @@
namespace AGVControl
{
partial class RoundButton
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AGVControl
{
public partial class RoundButton : Button
{
public int CornerRadius { get; set; } = 7;
public RoundButton()
{
InitializeComponent();
// Set Optimized Double Buffer to reduce flickering
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
// Redraw when resized
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.Resize += arLabel_Resize;
}
protected override void OnPaint(PaintEventArgs pevent)
{
pevent.Graphics.InterpolationMode = InterpolationMode.High;
pevent.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
pevent.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
var XPosition = this.DisplayRectangle.Left;
var YPosition = this.DisplayRectangle.Top;
using (GraphicsPath Path = new GraphicsPath())
{
Path.AddLine(XPosition + CornerRadius, YPosition, XPosition + Width - (CornerRadius * 2), YPosition);
Path.AddArc(XPosition + Width - (CornerRadius * 2), YPosition, CornerRadius * 2, CornerRadius * 2, 270, 90);
Path.AddLine(XPosition + Width, YPosition + CornerRadius, XPosition + Width, YPosition + Height - (CornerRadius * 2));
Path.AddArc(XPosition + Width - (CornerRadius * 2), YPosition + Height - (CornerRadius * 2), CornerRadius * 2, CornerRadius * 2, 0, 90);
Path.AddLine(XPosition + Width - (CornerRadius * 2), YPosition + Height, XPosition + CornerRadius, YPosition + Height);
Path.AddArc(XPosition, YPosition + Height - (CornerRadius * 2), CornerRadius * 2, CornerRadius * 2, 90, 90);
Path.AddLine(XPosition, YPosition + Height - (CornerRadius * 2), XPosition, YPosition + CornerRadius);
Path.AddArc(XPosition, YPosition, CornerRadius * 2, CornerRadius * 2, 180, 90);
Path.CloseFigure();
this.Region = new System.Drawing.Region(Path);
}
base.OnPaint(pevent);
}
void arLabel_Resize(object sender, EventArgs e)
{
Invalidate();
}
}
}

View File

@@ -0,0 +1,36 @@
namespace AGVControl
{
partial class ValueSelect
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@@ -0,0 +1,262 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Windows.Forms;
namespace AGVControl
{
public partial class ValueSelect : Control
{
public ValueSelect()
{
InitializeComponent();
// Set Optimized Double Buffer to reduce flickering
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
// Redraw when resized
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.Resize += arLabel_Resize;
this.MouseClick += ValueSelect_MouseClick;
this.MouseEnter += (s1, e1) => { this.Cursor = Cursors.Hand; };
this.MouseLeave += (s1, e1) => { this.Cursor = Cursors.Default; };
}
private void ValueSelect_MouseClick(object sender, MouseEventArgs e)
{
//마우스클릭
if (rectLButton.IsEmpty == false && rectLButton.Contains(e.Location))
{
if (SideButtonClickValue != 0.0)
{
var newvalue = this.Value - SideButtonClickValue;
if (newvalue < MinValue) newvalue = MinValue;
this.Value = newvalue;
}
if (ButtonClick != null) ButtonClick(this, new ButtonClickEventArgs(MouseButtons.Left));
}
if (rectRButton.IsEmpty == false && rectRButton.Contains(e.Location))
{
if (SideButtonClickValue != 0.0)
{
var newvalue = this.Value + SideButtonClickValue;
if (newvalue > MaxValue) newvalue = MaxValue;
this.Value = newvalue;
}
if (ButtonClick != null) ButtonClick(this, new ButtonClickEventArgs(MouseButtons.Right));
}
if (rectCButton.IsEmpty == false && rectCButton.Contains(e.Location))
if (ButtonClick != null) ButtonClick(this, new ButtonClickEventArgs(MouseButtons.Middle));
}
private Rectangle rectLButton;
private Rectangle rectRButton;
private Rectangle rectCButton;
private Boolean bMakeRect = true;
private double _minvalue = 0.0;
private double _maxvalue = 9999999999.0;
public double MinValue { get { return _minvalue; } set { _minvalue = value; Invalidate(); } }
public double MaxValue { get { return _maxvalue; } set { _maxvalue = value; Invalidate(); } }
private UInt16 _decimalposition = 0;
private string _buttonwdith = string.Empty;
private double _value = 0;
private Color _border = Color.Lime;
private double buttongabp;
public double SideButtonClickValue { get { return buttongabp; } set { buttongabp = value; Invalidate(); } }
private Color _backbutton = Color.White;
private Color _sidebutto = Color.Black;
public Color BackColorButton { get { return _backbutton; } set { _backbutton = value; Invalidate(); } }
public Color ForeColorButton { get { return _sidebutto; } set { _sidebutto = value; Invalidate(); } }
public Color ColorBorder { get { return _border; } set { _border = value; Invalidate(); } }
public override string Text
{
get => Value.ToString();
set
{
if (double.TryParse(value, out double dblval) == true)
this.Value = dblval;
}
}
public double Value
{
get { return _value; }
set
{
if (_value != value)
{
//이 값이 범위를 초과했는지 확인
if (value < MinValue)
{
_value = MinValue;
//throw new Exception(string.Format("입력값이 컨트롤의 최소값보다 작습니다(입력:{0},최소값:{1})",value,MinValue));
}
else if (value > MaxValue)
{
_value = MaxValue;
//throw new Exception(string.Format("입력값이 컨트롤의 최대값보다 작습니다(입력:{0},최대값:{1})", value, MaxValue));
}
else
{
_value = value;
}
Invalidate();
if (ValueChanged != null) ValueChanged(this, new EventArgs());
}
}
}
public UInt16 DecimalPosition { get { return _decimalposition; } set { _decimalposition = value; Invalidate(); } }
public string ButtonWidth { get { return _buttonwdith; } set { _buttonwdith = value; Invalidate(); } }
private string _nulldisplay = string.Empty;
public string NullDisplay { get { return _nulldisplay; } set { _nulldisplay = value; Invalidate(); } }
private Font _sidefont;
public Font FontSideButton { get { if (_sidefont == null) return this.Font; else return _sidefont; } set { _sidefont = value; Invalidate(); } }
void arLabel_Resize(object sender, EventArgs e)
{
this.bMakeRect = true;
Invalidate();
}
public class ButtonClickEventArgs : EventArgs
{
public MouseButtons Button;
public ButtonClickEventArgs(MouseButtons button)
{
this.Button = button;
// Console.WriteLine("button clickc : " +button.ToString());
}
}
public event EventHandler<ButtonClickEventArgs> ButtonClick;
public event EventHandler ValueChanged;
protected override void OnPaint(PaintEventArgs pe)
{
//base.OnPaint(pe);
if (bMakeRect) MakeRect();
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
sf.Trimming = StringTrimming.None;
sf.FormatFlags = StringFormatFlags.NoWrap;
//좌측버튼표시
if (rectLButton.IsEmpty == false)
{
pe.Graphics.FillRectangle(new SolidBrush(BackColorButton), rectLButton);
pe.Graphics.DrawString("<<", this.FontSideButton, new SolidBrush(this.ForeColorButton), rectLButton, sf);
}
if (rectRButton.IsEmpty == false)
{
pe.Graphics.FillRectangle(new SolidBrush(BackColorButton), rectRButton);
pe.Graphics.DrawString(">>", this.FontSideButton, new SolidBrush(this.ForeColorButton), rectRButton, sf);
}
//값표시
string valuestr;
if (Value == 0.0 && string.IsNullOrEmpty(NullDisplay) == false)
valuestr = NullDisplay;
else
valuestr = Value.ToString("N" + DecimalPosition.ToString());
pe.Graphics.FillRectangle(new SolidBrush(BackColor), rectCButton);
pe.Graphics.DrawString(valuestr, this.Font, new SolidBrush(this.ForeColor), rectCButton, sf);
sf.Dispose();
//테두리표시
if (rectLButton.IsEmpty == false)
pe.Graphics.DrawRectangle(new Pen(ColorBorder), rectLButton);
if (rectRButton.IsEmpty == false)
pe.Graphics.DrawRectangle(new Pen(ColorBorder), rectRButton);
pe.Graphics.DrawRectangle(new Pen(ColorBorder), rectCButton);
}
void MakeRect()
{
int bWidth;
if (string.IsNullOrEmpty(ButtonWidth) == false)
{
if (ButtonWidth.EndsWith("%"))
{
if (int.TryParse(ButtonWidth.Substring(0, ButtonWidth.Length - 1), out bWidth) == false)
bWidth = 0; //숫자로 바꾸는거 실패
else bWidth = (int)(this.DisplayRectangle.Width * (bWidth / 100.0));
}
else
{
if (int.TryParse(ButtonWidth, out bWidth) == false)
bWidth = 0;
}
}
else bWidth = 0;
if (bWidth > 0)
{
int buttongap = 1;
//각버튼간 2px 간격을 띄운다.
bWidth = bWidth - buttongap * 2;
rectLButton = new Rectangle(
DisplayRectangle.Left,
DisplayRectangle.Top,
bWidth,
DisplayRectangle.Height - 1);
rectCButton = new Rectangle(
rectLButton.Right + buttongap,
DisplayRectangle.Top,
DisplayRectangle.Width - rectLButton.Width * 2 - buttongap * 2,
DisplayRectangle.Height - 1);
rectRButton = new Rectangle(
rectCButton.Right + buttongap,
DisplayRectangle.Top,
bWidth - 1,
DisplayRectangle.Height - 1);
}
else
{
rectLButton = Rectangle.Empty;
rectRButton = Rectangle.Empty;
rectCButton = new Rectangle(DisplayRectangle.Left,
DisplayRectangle.Top,
DisplayRectangle.Width - 1,
DisplayRectangle.Height - 1);
}
bMakeRect = true;
}
}
}

View File

@@ -0,0 +1,153 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8CB883C0-99C3-4DD4-B017-F9B92010A806}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AGVControl</RootNamespace>
<AssemblyName>AGVControl</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="arCommUtil">
<HintPath>..\..\..\DLL\arCommUtil.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Dialog\fMapDesign.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Dialog\fMapDesign.Designer.cs">
<DependentUpon>fMapDesign.cs</DependentUpon>
</Compile>
<Compile Include="Dialog\fPropertyRFIDPoint.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Dialog\fPropertyRFIDPoint.Designer.cs">
<DependentUpon>fPropertyRFIDPoint.cs</DependentUpon>
</Compile>
<Compile Include="GridView\ColorListItem.cs" />
<Compile Include="GridView\GridItem.cs" />
<Compile Include="GridView\GridView.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="GridView\GridView.Designer.cs">
<DependentUpon>GridView.cs</DependentUpon>
</Compile>
<Compile Include="MapControlManager.cs" />
<Compile Include="Models\AGVActionPrediction.cs" />
<Compile Include="BatteryLevelGauge.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="BatteryLevelGauge.Designer.cs">
<DependentUpon>BatteryLevelGauge.cs</DependentUpon>
</Compile>
<Compile Include="GuideSensor.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="GuideSensor.Designer.cs">
<DependentUpon>GuideSensor.cs</DependentUpon>
</Compile>
<Compile Include="MapControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="MapControl.Designer.cs">
<DependentUpon>MapControl.cs</DependentUpon>
</Compile>
<Compile Include="Models\AGV.cs" />
<Compile Include="Models\CustomLine.cs" />
<Compile Include="Models\enumStruct.cs" />
<Compile Include="Models\MagnetLine.cs" />
<Compile Include="Models\MapElements.cs" />
<Compile Include="Models\MapText.cs" />
<Compile Include="Models\PathResult.cs" />
<Compile Include="Models\RFIDLine.cs" />
<Compile Include="Models\RFIDPoint.cs" />
<Compile Include="Models\ToolBarItem.cs" />
<Compile Include="MyRadioButton.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="MyRadioButton.Designer.cs">
<DependentUpon>MyRadioButton.cs</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Models\RFIDConnection.cs" />
<Compile Include="RoundButton.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="RoundButton.Designer.cs">
<DependentUpon>RoundButton.cs</DependentUpon>
</Compile>
<Compile Include="ValueSelect.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ValueSelect.Designer.cs">
<DependentUpon>ValueSelect.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Dialog\fMapDesign.resx">
<DependentUpon>fMapDesign.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Dialog\fPropertyRFIDPoint.resx">
<DependentUpon>fPropertyRFIDPoint.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="MapControl.resx">
<DependentUpon>MapControl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CommData\CommData.csproj">
<Project>{14e8c9a5-013e-49ba-b435-efefc77dd623}</Project>
<Name>CommData</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Resources\ico_navi_40.png" />
<None Include="sample.route" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,105 @@
[RFID_POINTS]
100,486,517
173,488,516
230,493,515
309,489,514
370,490,513
437,487,512
483,459,511
511,421,510
543,371,509
569,329,508
608,289,507
661,279,506
701,297,505
698,349,504
698,391,503
699,449,502
691,491,501
570,275,400
517,264,401
454,264,402
388,262,403
315,258,404
639,234,600
621,182,601
641,183,602
657,101,603
627,82,604
560,73,605
499,65,606
432,65,607
264,232,405
363,60,608
654,508,500
96,542,100
159,542,101
226,542,102
309,541,103
369,542,104
483,165,753
735,163,700
523,170,752
565,175,751
597,182,750
665,181,703
700,176,702
722,170,701
[RFID_LINES]
100,486,173,488,517,516,False,73.02739
173,488,230,493,516,515,False,57.21888
230,493,309,489,515,514,False,79.1012
309,489,370,490,514,513,False,61.0082
370,490,437,487,513,512,False,67.06713
437,487,483,459,512,511,False,53.85165
483,459,511,421,511,510,False,47.20169
511,421,543,371,510,509,False,59.36329
543,371,569,329,509,508,False,49.39635
569,329,608,289,508,507,False,55.86591
608,289,639,234,507,600,False,63.13478
639,234,665,181,600,703,False,59.03389
665,181,657,101,703,603,False,80.399
657,101,627,82,603,604,False,35.51056
627,82,560,73,604,605,False,67.60178
560,73,499,65,605,606,False,61.52235
499,65,432,65,606,607,False,67
432,65,363,60,607,608,False,69.18092
641,183,665,181,602,703,False,24.08319
665,181,700,176,703,702,False,35.35534
700,176,722,170,702,701,False,22.80351
722,170,735,163,701,700,False,14.76482
641,183,621,182,602,601,False,20.02498
621,182,597,182,601,750,False,24
597,182,565,175,750,751,False,32.75668
565,175,523,170,751,752,False,42.29657
523,170,483,165,752,753,False,40.31129
264,232,315,258,405,404,False,57.24509
315,258,388,262,404,403,False,73.1095
388,262,454,264,403,402,False,66.0303
454,264,517,264,402,401,False,63
517,264,570,275,401,400,False,54.12947
570,275,608,289,400,507,False,40.49691
608,289,661,279,507,506,False,53.93515
661,279,701,297,506,505,False,43.86343
701,297,698,349,505,504,False,52.08647
698,349,698,391,504,503,False,42
698,391,699,449,503,502,False,58.00862
699,449,691,491,502,501,False,42.75512
691,491,654,508,501,500,False,40.71855
96,542,100,486,100,517,False,56.14267
159,542,173,488,101,516,False,55.7853
226,542,230,493,102,515,False,49.16299
309,541,309,489,103,514,False,52
369,542,370,490,104,513,False,52.00961
[MAP_TEXTS]
179,251,-1,-16777216,Arial,12,OPS-2
239,52,-256,-65408,Arial,12,SSOTRON-3
617,527,-16711936,-16777216,Arial,12,SSOTRON-1
87,551,-16777216,16777215,Arial,12,B1
150,550,-16777216,16777215,Arial,12,B2
227,553,-16777216,16777215,Arial,12,B3
299,555,-16777216,16777215,Arial,12,B4
367,554,-16777216,16777215,Arial,12,B5
453,128,-16777216,-8323073,Arial,12,CHG1
725,124,-16777216,-8323073,Arial,12,CHG2
[CUSTOM_LINES]

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{14E8C9A5-013E-49BA-B435-EFEFC77DD623}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VarData</RootNamespace>
<AssemblyName>VarData</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Flag.cs" />
<Compile Include="ISerialComm.cs" />
<Compile Include="RS232.cs" />
<Compile Include="Var.cs" />
<Compile Include="Enum.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,217 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace COMM
{
public enum eVarInt32
{
PickOnCount = 0,
PickOfCount,
LPickOnCount,
SumQty,
ChargeWaitSec,
SyncItemCount,
PathValidationError,
}
public enum eVarUInt32
{
Spare=0,
}
public enum eVarDBL
{
LeftJogSpeed,
RightJogSpeed,
CurrentLeftJogSpeed,
CurrentRightJogSpeed,
SpeedOffsetCW,
SpeedOffsetCCW,
MaxSpeedCW,
MaxSpeedCCW,
SQLConnection,
}
public enum eVarByte
{
None = 0,
/// <summary>
/// 충전명련전송횟수
/// </summary>
CHARGE_CMDCNT,
ButtonJog,
DataIndex ,
}
public enum eVarBool
{
//comm area start(0~31)
None = 0,
DebugMode,
SQLCONN,
//plc area start (32~63)
FLAG_STOPZ = 32,
FLAG_SETUP,
FLAG_SYNC,
FLAG_WAIT,
/// <summary>
/// 상태머신이 동작중인가
/// 장비동작은 AGV_RUN 플래그를 확인 하세요.
/// </summary>
FLAG_AUTORUN,
FLAG_MANUALRUN,
FLAG_LIMITHIGH,
FLAG_LIMITLOW,
FLAG_POWERLOSS,
/// <summary>
/// AGV 진행방향(UP = backward, DOWN = forward)
/// </summary>
AGVDIR_BACK,
/// <summary>
/// 마크센서가 감지되면 활성화됨
/// (알림용으로도 쓰니 삭제 안됨)
/// </summary>
MARK_SENSOR,
MARK_SENSOROFF,
FLAG_LEFT_RUN,
FLAG_RIGHT_RUN,
FLAG_RUN_CMD,
FLAG_GO_CHAGER,
FLAG_NEXTSTOP_ALIGN,
///NEXTSTOP_MARK,
/// <summary>
/// mark 1 혹은 2 의 값이 들어오면 설정됨
/// </summary>
//SENSOR_MARK,
CHG_POSERR,
FLAG_CHARGEONA,
FLAG_CHARGEONM,
OVERLOAD,
OVERLOADL,
OVERLOADR,
BATTERY_LOW,
BATTERY_HIGH,
MINSPACE,
CHARGE_CMDCNT,
CHARGE_READY,
CHARGE_WAIT,
AGV_ERROR,
WAIT_COVER_DOWN,
WAIT_COVER_UP,
EMERGENCY,
ITEMON,
/// <summary>
/// 충전시작명령을 전송했다
/// </summary>
WAIT_CHARGEACK,
//agv area start ( 64 ~ 95)
DISABLE_AUTOCONN_XBEE,
//area start (96~127)
}
public enum eVarString
{
MCStatus,
DataIndex,
StatusMessage,
JOBType,
JOBCustCode,
SWVersion,
ChargeCheckMsg,
}
public enum eVarTime
{
LastConnTry_PLC,
LastConn_PLC,
LastRecv_PLC,
LastConnTry_XBE,
LastConn_XBE,
LastRecv_XBE,
LastConnTry_BAT,
LastConn_BAT,
LastRecv_BAT,
LastSend_CMD,
LastSend_BAT,
LastConnTry_AGV,
LastConn_AGV,
LastRecv_AGV,
/// <summary>
/// 상태머신이 IDLE 전환시 설정
/// </summary>
IdleStart,
/// <summary>
/// 충전시도시 설정
/// </summary>
ChargeTry,
/// <summary>
/// 충전시작(확인)시 설정
/// </summary>
ChargeStart,
/// <summary>
/// 충전종료시점
/// </summary>
ChargeEnd,
/// <summary>
/// 장비가동중 READY상태 전환시 설정
/// </summary>
ReadyStart,
MarkSensorOn,
MarkSensorOff,
/// <summary>
/// 상태머신이 RUN되는 경우에 설정
/// 단 세부스텝이 READY 인 경우는 제외
/// </summary>
RunStart,
SendChargeOff,
ChargeSearch,
BatWarnTime,
IdleStopTime,
StatusReporttime,
CheckGotoTargetSet,
SendGotoCommand,
/// <summary>
/// 마지막으로 멈춤 명령을 전송한 시간
/// </summary>
LastStopCommandTime,
/// <summary>
/// 마지막으로 멈춤(마크스탑) 명령을 전송한 시간
/// </summary>
LastMarkStopCommandTime,
/// <summary>
/// 마지막으로 턴 명령을 전송한 시간
/// </summary>
LastTurnCommandTime,
/// <summary>
/// 마지막을 실행 명령을 전송한 시간
/// </summary>
LastRunCommandTime,
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace COMM
{
public class Flag
{
public Boolean IsInit; //H/W설정이 안된경우에만 FALSE로 한다
public string errorMessage;
public int PortCount;
private UInt64 _value;
private UInt64 _changed;
public string[] Name;
public UInt64 Value { get { return _value; } }
public event EventHandler<ValueEventArgs> ValueChanged;
public class ValueEventArgs : EventArgs
{
private int _arridx;
private Boolean _oldvalue;
private Boolean _newvalue;
public int ArrIDX { get { return _arridx; } }
public Boolean OldValue { get { return _oldvalue; } }
public Boolean NewValue { get { return _newvalue; } }
public ValueEventArgs(int arridx, Boolean oldvalue, Boolean newvalue)
{
_arridx = arridx;
_oldvalue = oldvalue;
_newvalue = newvalue;
}
}
public Flag(int pcnt)
{
if (pcnt > 64) throw new Exception("Max count is 64");
PortCount = pcnt;
IsInit = true;
errorMessage = string.Empty;
_value = 0;
_changed = 0;
Name = new string[PortCount];
for (int i = 0; i < Name.Length; i++)
{
Name[i] = string.Empty;
}
}
public void writeValue(Int16 val)
{
var NewValue = (ulong)val;
_changed = this._value ^ NewValue;
this._value = NewValue;
}
//private Boolean readValue(ref UInt64 value, int idx)
//{
// var offset = (UInt64)(1 << idx);
// return ((value & offset) != 0);
//}
public Boolean Get(int idx)
{
var offset = (UInt64)(1 << idx);
return (_value & offset) != 0;
}
/// <summary>
/// 변경여부를 확인 합니다
/// </summary>
/// <param name="idx"></param>
/// <returns></returns>
public Boolean GetChanged(int idx)
{
var offset = (UInt64)(1 << idx);
return (this._changed & offset) != 0;
}
public void Set(int idx, Boolean value)
{
var oldvalue = Get(idx);
if (value)
{
var offset = (UInt64)(1 << idx);
_value = _value | offset;
}
else
{
var offset = (UInt64)(~(1 << idx));
_value = _value & offset;
}
if (oldvalue != value)
{
if (ValueChanged != null)
ValueChanged(this, new ValueEventArgs(idx, oldvalue, value));
}
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
namespace arDev
{
/// <summary>
/// 시리얼통신모듈의기본형태정의
/// </summary>
public interface ISerialComm
{
string PortName { get; set; }
int BaudRate { get; set; }
bool IsOpen { get; }
string ErrorMessage { get; set; }
Boolean Open();
Boolean Close();
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("VarData")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VarData")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("14e8c9a5-013e-49ba-b435-efefc77dd623")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 버전
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,493 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
namespace arDev
{
public abstract partial class arRS232 : 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;
/// <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 arRS232()
{
_device = new System.IO.Ports.SerialPort();
this.BaudRate = 9600;
ScanInterval = 10;
_device.DataReceived += barcode_DataReceived;
_device.ErrorReceived += this.barcode_ErrorReceived;
_device.WriteTimeout = 5000;
_device.ReadTimeout = 5000;
// _device.DtrEnable = false;
_device.ReadBufferSize = 8192;
_device.WriteBufferSize = 8192;
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);
}
~arRS232()
{
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.
//
}
_device.DataReceived -= barcode_DataReceived;
_device.ErrorReceived -= this.barcode_ErrorReceived;
// Free any unmanaged objects here.
//
disposed = true;
}
public Boolean Open()
{
try
{
_device.Open();
return IsOpen;
}
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()
{
if (_device != null && _device.IsOpen)
{
_device.DiscardInBuffer();
_device.DiscardOutBuffer();
_device.Close(); //dispose에서는 포트를 직접 클리어하지 않게 해뒀다.
return true;
}
else 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
{
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[] { };
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));
}
}
#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;
}
}
}

View File

@@ -0,0 +1,340 @@
//using System;
//using System.Collections.Generic;
//using System.ComponentModel;
//using System.Linq;
//using System.Text;
//namespace COMM
//{
// public abstract class VarData<T> : INotifyPropertyChanged
// {
// protected T[] _values;
// protected T defaultvalue;
// protected string[] _code;
// protected string[] _desc;
// public event PropertyChangedEventHandler PropertyChanged;
// protected void OnPropertyChanged(string name)
// {
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
// }
// public T this[int idx]
// {
// get { return Get(idx); }
// set { Set(idx, value); }
// }
// public string StrType
// {
// get
// {
// return typeof(T).ToString();
// }
// }
// public VarData(int capa, T defvalue = default(T))
// {
// _values = new T[capa];
// _code = new string[capa];
// _desc = new string[capa];
// defaultvalue = defvalue;
// Clear();
// if (typeof(T) == typeof(UInt16)) SupportAdd = true;
// else if (typeof(T) == typeof(UInt32)) SupportAdd = true;
// else if (typeof(T) == typeof(Int16)) SupportAdd = true;
// else if (typeof(T) == typeof(Int32)) SupportAdd = true;
// else if (typeof(T) == typeof(Int64)) SupportAdd = true;
// else if (typeof(T) == typeof(UInt64)) SupportAdd = true;
// else if (typeof(T) == typeof(byte)) SupportAdd = true;
// else if (typeof(T) == typeof(double)) SupportAdd = true;
// else if (typeof(T) == typeof(Single)) SupportAdd = true;
// else if (typeof(T) == typeof(string)) SupportAdd = false;
// else if (typeof(T) == typeof(bool)) SupportAdd = false;
// else if (typeof(T) == typeof(DateTime)) SupportAdd = false;
// else throw new Exception($"Support Data Type : {typeof(T)}");
// }
// public virtual void Set(int idx, T value)
// {
// var changed = _values[idx].Equals(value);
// _values[idx] = value;
// if (changed) OnPropertyChanged($"{idx}|{value}"); //idx값을 알림한다
// }
// public virtual T Get(int idx)
// {
// return _values[idx];
// }
// public virtual void Clear(T value)
// {
// for (int i = 0; i < _values.Length; i++)
// _values[i] = value;
// }
// public virtual void Clear()
// {
// Clear(defaultvalue);
// }
// public void Clear(int idx)
// {
// _values[idx] = defaultvalue;
// }
// public Tuple<string, string> GetCodeDesc(int idx)
// {
// return new Tuple<string, string>(_code[idx], _desc[idx]);
// }
// public virtual bool SupportAdd { get; private set; }
// }
// public abstract class VarDataNumber<T> : VarData<T>
// {
// public VarDataNumber(int capa) : base(capa) { }
// public abstract void Add(T value);
// public abstract void Add(int idx, T value);
// }
// public class VarDataI32 : VarDataNumber<Int32>
// {
// public VarDataI32(int capa) : base(capa) { }
// public override void Add(Int32 value)
// {
// for (int i = 0; i < _values.Length; i++)
// _values[i] += value;
// }
// public override void Add(int idx, Int32 value)
// {
// _values[idx] += value;
// }
// public void Add(eVarInt32 idx, Int32 value = 1)
// {
// Add((int)idx, value);
// }
// public void Clear(eVarInt32 idx)
// {
// Clear((int)idx);
// }
// public Int32 this[eVarInt32 idx]
// {
// get { return Get((int)idx); }
// set { Set((int)idx, value); }
// }
// }
// public class VarDataDBL : VarDataNumber<double>
// {
// public VarDataDBL(int capa) : base(capa) { }
// public override void Add(double value)
// {
// for (int i = 0; i < _values.Length; i++)
// _values[i] += value;
// }
// public override void Add(int idx, double value)
// {
// _values[idx] += value;
// }
// public void Add(eVarDBL idx, double value = 1)
// {
// Add((int)idx, value);
// }
// public void Clear(eVarDBL idx)
// {
// Clear((int)idx);
// }
// public double this[eVarDBL idx]
// {
// get { return Get((int)idx); }
// set { Set((int)idx, value); }
// }
// }
// public class VarDataUI32 : VarDataNumber<UInt32>
// {
// public VarDataUI32(int capa) : base(capa) { }
// public override void Add(UInt32 value)
// {
// for (int i = 0; i < _values.Length; i++)
// _values[i] += value;
// }
// public override void Add(int idx, UInt32 value)
// {
// _values[idx] += value;
// }
// public void Add(eVarUInt32 idx, UInt32 value = 1)
// {
// Add((int)idx, value);
// }
// public void Clear(eVarUInt32 idx)
// {
// Clear((int)idx);
// }
// public UInt32 this[eVarUInt32 idx]
// {
// get { return Get((int)idx); }
// set { Set((int)idx, value); }
// }
// }
// public class VarDataByte : VarDataNumber<byte>
// {
// public VarDataByte(int capa) : base(capa) { }
// public override void Add(byte value)
// {
// for (int i = 0; i < _values.Length; i++)
// _values[i] += value;
// }
// public override void Add(int idx, byte value)
// {
// _values[idx] += value;
// }
// public void Add(eVarByte idx, byte value)
// {
// Add((int)idx, value);
// }
// public byte this[eVarByte idx]
// {
// get
// {
// return Get((int)idx);
// }
// set
// {
// Set((int)idx, value);
// }
// }
// }
// public class VarDataBool : VarData<bool>
// {
// public VarDataBool(int capa) : base(capa) { }
// public bool this[eVarBool idx]
// {
// get
// {
// return Get(idx);
// }
// set
// {
// Set(idx, value);
// }
// }
// public bool Get(eVarBool idx)
// {
// return Get((int)idx);
// }
// public void Set(eVarBool idx, bool value)
// {
// Set((int)idx, value);
// }
// }
// public class VarDataStr : VarData<string>
// {
// public VarDataStr(int capa) : base(capa, string.Empty) { }
// public string Get(eVarString idx)
// {
// return Get((int)idx);
// }
// public void Set(eVarString idx, string value)
// {
// Set((int)idx, value);
// }
// public string this[eVarString idx]
// {
// get { return Get(idx); }
// set { Set(idx, value); }
// }
// }
// public class VarDataDateTime : VarData<DateTime>
// {
// public VarDataDateTime(int capa) : base(capa, new DateTime(1982, 11, 23)) { }
// public DateTime this[eVarTime idx]
// {
// get
// {
// return Get((int)idx);
// }
// set
// {
// Set(idx, value);
// }
// }
// public TimeSpan RUN(int idx)
// {
// return DateTime.Now - _values[idx];
// }
// public TimeSpan RUN(eVarTime idx)
// {
// return RUN((int)idx);
// }
// [Browsable(false)]
// public void Add(int idx, TimeSpan value)
// {
// _values[idx] += value;
// }
// public void Add(eVarTime idx, TimeSpan value)
// {
// Add((int)idx, value);
// }
// /// <summary>
// /// 지정된 시간으로 업데이트 합니다
// /// </summary>
// /// <param name="idx"></param>
// /// <param name="value"></param>
// public void Set(eVarTime idx, DateTime value)
// {
// Set((int)idx, value);
// }
// /// <summary>
// /// 현재시간으로 업데이트 합니다
// /// </summary>
// /// <param name="idx"></param>
// public void Set(eVarTime idx)
// {
// Set(idx, DateTime.Now);
// }
// public bool IsSet(eVarTime idx)
// {
// return this[idx].Year != 1982;
// }
// }
// //공용변수(시간)
// public static class VAR
// {
// public static VarDataBool BOOL;
// public static VarDataByte BYTE;
// public static VarDataStr STR;
// public static VarDataDateTime TIME;
// public static VarDataI32 I32;
// public static VarDataUI32 U32;
// public static VarDataDBL DBL;
// public static bool isInit { get; private set; } = false;
// public static void Init(int varlen)
// {
// if (isInit) return; //already init
// //가변 데이트타임변수
// BOOL = new VarDataBool(varlen);
// BYTE = new VarDataByte(varlen);
// STR = new VarDataStr(varlen);
// TIME = new VarDataDateTime(varlen);
// I32 = new VarDataI32(varlen);
// U32 = new VarDataUI32(varlen);
// DBL = new VarDataDBL(varlen);
// isInit = true;
// }
// }
//}

View File

@@ -0,0 +1,5 @@
@echo off
echo Git AutoUpdate
echo tindevil@nate.com
for /d %%i in (*) do echo Enterinng "%i" | cd "%i" | git.exe pull --progress -v --no-rebase "origin" master | cd ..
@pause

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
</configuration>

63
HMI/SubProject/Patch/Form1.Designer.cs generated Normal file
View File

@@ -0,0 +1,63 @@
namespace Patch
{
partial class Form1
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.SuspendLayout();
//
// progressBar1
//
this.progressBar1.Dock = System.Windows.Forms.DockStyle.Fill;
this.progressBar1.Location = new System.Drawing.Point(0, 0);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(481, 68);
this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
this.progressBar1.TabIndex = 1;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(481, 68);
this.Controls.Add(this.progressBar1);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ProgressBar progressBar1;
}
}

View File

@@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Patch
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.Text = "Software Patch";
this.Show();
Application.DoEvents();
//현재폴더에서 _patch 폴더 찾는다
Boolean runClient = true;
var srcpath = new System.IO.DirectoryInfo ( System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "_patch"));
if (srcpath.Exists == true)
{
//기존 프로그램 종료될떄까지 기다린다
this.Text = "기존 프로그램 종료 대기";
Application.DoEvents();
bool closeok = true;
System.Diagnostics.Stopwatch wat = new System.Diagnostics.Stopwatch();
wat.Restart();
while (CheckExistProcess("Amkor") == true)
{
Application.DoEvents();
System.Threading.Thread.Sleep(10);
if(wat.ElapsedMilliseconds >= 10000)
{
MessageBox.Show("기존프로그램이 종료되지 않았습니다", "패치실패", MessageBoxButtons.OK, MessageBoxIcon.Error);
closeok = false;
break;
}
}
if (CheckExistProcess("Amkor") == false)
{
//버젼체크하고 파일 복사해준다
var files = srcpath.GetFiles();
this.progressBar1.Maximum = files.Length;
this.progressBar1.Value = 0;
this.progressBar1.Style = ProgressBarStyle.Continuous;
var myPath = new System.IO.DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
try
{
foreach (var file in files)
{
this.Text = "패치파일 : " + file.Name;
Application.DoEvents();
file.CopyTo(System.IO.Path.Combine(file.Directory.Parent.FullName, file.Name), true); // System.IO.File.Copy(file, myPath.FullName, true);
this.progressBar1.Value += 1;
System.Threading.Thread.Sleep(100);
}
//패치파일을 삭제한다
srcpath.Delete(true);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else runClient = false;
}
//클라이언트실행
if(runClient==true)
{
var file_run = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Amkor.exe");
RunProcess(file_run);
}
//프로그래램 종료
this.Close();
}
public Boolean CheckExistProcess(string ProcessName)
{
foreach (var prc in System.Diagnostics.Process.GetProcesses())
{
if (prc.ProcessName.StartsWith("svchost")) continue;
if (prc.ProcessName.ToUpper() == ProcessName.ToUpper()) return true;
}
return false;
}
public Boolean RunProcess(string file, string arg = "")
{
var fi = new System.IO.FileInfo(file);
if (!fi.Exists)
{
//Pub.log.AddE("Run Error : " + file);
return false;
}
System.Diagnostics.Process prc = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo si = new System.Diagnostics.ProcessStartInfo(file);
si.Arguments = arg;
prc.StartInfo = si;
prc.Start();
return true;
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Patch
{
static class Program
{
/// <summary>
/// 해당 애플리케이션의 주 진입점입니다.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("Patch")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Patch")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("37dc0bae-50bf-41e4-baab-b0e211467ad1")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 버전
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Patch.Properties {
using System;
/// <summary>
/// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
/// </summary>
// 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
// 클래스에서 자동으로 생성되었습니다.
// 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여 ResGen을
// 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Patch.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대해 현재 스레드의 CurrentUICulture 속성을
/// 재정의합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Patch.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{37DC0BAE-50BF-41E4-BAAB-B0E211467AD1}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Patch</RootNamespace>
<AssemblyName>SWPatch</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\..\..\Amkor\AGV4\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

1
HMI/SubProject/arCtl Submodule

Submodule HMI/SubProject/arCtl added at 768d71ebca