2026-06-05 13:44:39 +09:00

131 lines
5.8 KiB
C#

using Aurora.Api;
using AuroraPLC;
using System;
using System.Runtime.InteropServices;
namespace AuroraMelsecNet
{
public class MelsecNet : PLCNetwork
{
private readonly Logger Log = new Logger("PLC MelsecNet");
#region MelsecNet DLL import
// MelsecNet data link library
// For C#
// C:\Windows\SysWOW64 경로에 mdfunc32W.dll 파일 존재함
// 일단은 mdfunc32 로 검증후, mdfunc32w 검토...mdfunc32w 는 64비트를 의미하는걸까?
// Charset: 문자열 관련, 인자로 string 사용안하니, 중요하지 않을 것 같은데..???
// SetLastError: 에러를 셋 여부로 에러 처리 관련인듯한데..
[DllImport("MDFUNC32.DLL", EntryPoint = "mdOpen", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern short mdOpen(short chan, short mode, ref long path);
[DllImport("MDFUNC32.DLL", EntryPoint = "mdClose", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern short mdClose(long path);
[DllImport("MDFUNC32.DLL", EntryPoint = "mdSend", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern short mdSend(long path, short stno, short devtyp, short devno, ref short size, ref short data);
[DllImport("MDFUNC32.DLL", EntryPoint = "mdReceive", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern short mdReceive(long path, short stno, short devtyp, short devno, ref short size, ref short data);
/* // 현재 주기적 배치 Read/Write 방식상, 개별적인 콜이 불필요하여 일단 주석처리..
[DllImport("MDFUNC32.DLL", EntryPoint = "mdreceiveex", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern short mdReceiveEx(int path, short Netno, short Stno, short Devtyp, short DevNo, ref short Size_Renamed, ref short Buf);
[DllImport("MDFUNC32.DLL", EntryPoint = "mdsendex", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern short mdSendEx(int path, short Netno, short Stno, short Devtyp, short DevNo, ref short Size_Renamed, ref short Buf);
[DllImport("MDFUNC32.DLL", EntryPoint = "mddevset", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern short mdDevSet(int path, short Stno, short Devtyp, short DevNo);
[DllImport("MDFUNC32.DLL", EntryPoint = "mddevrst", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern short mdDevRst(int path, short Stno, short Devtyp, short DevNo);
*/
#endregion
#region 네트워크 설정 관련
// 채널: 51 for NET-H, 151 for NET-G
// owner station: 0xFF
// remote station: 0x102 .... 0xFF ??
#endregion
//public short StationNo { get; private set; }
//public short ChannelNo { get; private set; }
// 통신 연결된 path 포인터 (C++ 경우); Melsec 용
private long _pathForOpenedLine;
private short _channelNo;
private short _mode;
private short _stationNo;
private const int _success = 0;
private bool IsConnected = false;
public MelsecNet()
{
//_isSimul = isSimul;
}
public override void SetInitParams(short channelNo, short mode, short stationNo)
{
_channelNo = channelNo;
_mode = mode;
_stationNo = stationNo;
}
public override bool OpenToPLC()
{
try { // 장비가 없을 때 에러를 막기 위한 용...
// Repair 코드에서도 1회 재시도를 하고 있음...
// MX Component 와 비슷하게~~~
if (IsConnected) {
var result = mdClose(_pathForOpenedLine);
IsConnected = !result.Equals(_success);
Log.I($"mdClose: 0x{result:x8} [Hex]");
//Thread.Sleep(500); // Melsec 문서보고 재검토..
}
var res = mdOpen(_channelNo, _mode, ref _pathForOpenedLine);
IsConnected = res.Equals(_success);
Log.I($"mdOpen: 0x{res:x8} [Hex]");
// 1회 재시도..
if (IsConnected == false) {
// TODO : 리턴코드 확인 후...
}
return IsConnected;
} catch (Exception ex) { // 일단 무조건 장비가 없을 경우를 가정한다.
Log.E($"Exception from mdOpen: {ex.Message}");
IsConnected = false;
return false;
}
}
public override bool CloseToPLC()
{
try {
var res = mdClose(_pathForOpenedLine);
IsConnected = !res.Equals(_success); // 닫기 성공이면, false
Log.I($"mdClose: 0x{res:x8} [Hex]");
// Need 딜레이 ??
} catch (Exception ex) {
Log.E($"Exception from mdClose: {ex.Message}");
return !IsConnected;
}
return !IsConnected;
}
public override bool ReceiveFromPLC(short devType, short startDevNo, ref short readByteSize, ref short readData)
{
// 여긴 굳이 try-catch 가 불필요할듯..
return mdReceive(_pathForOpenedLine, _stationNo, devType, startDevNo, ref readByteSize, ref readData).Equals(_success);
}
public override bool SendToPLC(short devType, short startDevNo, ref short writtenByteSize, ref short writtenData)
{
return mdSend(_pathForOpenedLine, _stationNo, devType, startDevNo, ref writtenByteSize, ref writtenData).Equals(_success);
}
}
}