Dreamine.PLC.Mitsubishi.MC
1.0.1
Dreamine.PLC.Mitsubishi.MC 산업 자동화 및 I/O 기능을 제공합니다.
Toggle main menu visibility
로딩중...
검색중...
일치하는것 없음
MitsubishiMcBinary3ESimulatorProtocol.cs
이 파일의 문서화 페이지로 가기
1
using
Dreamine.PLC.Abstractions.Devices;
2
using
Dreamine.PLC.Abstractions.Results;
3
using
Dreamine.PLC.Core.Memory;
4
using
Dreamine.PLC.Mitsubishi.MC.Protocol
;
5
6
namespace
Dreamine.PLC.Mitsubishi.MC.Simulation
;
7
16
public
sealed
class
MitsubishiMcBinary3ESimulatorProtocol
17
{
26
private
const
ushort
RequestSubHeader
= 0x5000;
35
private
const
ushort
ResponseSubHeader
= 0xD000;
44
private
readonly InMemoryPlcMemory
_memory
;
53
private
readonly
MitsubishiMcSimulatorServerOptions
_options
;
54
85
public
MitsubishiMcBinary3ESimulatorProtocol
(
86
InMemoryPlcMemory memory,
87
MitsubishiMcSimulatorServerOptions
options)
88
{
89
_memory
= memory ??
throw
new
ArgumentNullException(nameof(memory));
90
_options
= options ??
throw
new
ArgumentNullException(nameof(options));
91
}
92
101
public
event
EventHandler<string>?
StatusChanged
;
102
126
public
byte
[]
Execute
(ReadOnlySpan<byte> requestFrame)
127
{
128
if
(!
TryParseRequest
(requestFrame, out var request, out var errorMessage))
129
{
130
StatusChanged
?.Invoke(
this
, errorMessage ??
"Invalid MC request frame."
);
131
return
BuildErrorResponse
(requestFrame, 0xC051);
132
}
133
134
return
request.Command
switch
135
{
136
(ushort)
MitsubishiMcCommand
.BatchRead =>
ExecuteRead
(request),
137
(ushort)
MitsubishiMcCommand
.BatchWrite =>
ExecuteWrite
(request),
138
_ =>
BuildResponse
(request.Header, 0xC059, [])
139
};
140
}
141
164
private
byte
[]
ExecuteRead
(
McRequest
request)
165
{
166
if
(request.Points <= 0)
167
{
168
return
BuildResponse
(request.Header, 0xC051, []);
169
}
170
171
var address =
new
PlcAddress(
ToDeviceType
(request.DeviceCode), request.DeviceOffset);
172
173
if
(request.SubCommand == (ushort)
MitsubishiMcSubCommand
.Word)
174
{
175
var readResult =
_memory
.ReadWords(address, request.Points);
176
if
(!readResult.IsSuccess || readResult.Value is
null
)
177
{
178
return
BuildResponse
(request.Header, 0xC051, []);
179
}
180
181
var data =
new
List<byte>(request.Points * 2);
182
foreach
(var value
in
readResult.Value)
183
{
184
MitsubishiMcEndian
.
WriteUInt16LittleEndian
(data, unchecked((ushort)value));
185
}
186
187
return
BuildResponse
(request.Header, 0x0000, data);
188
}
189
190
if
(request.SubCommand == (ushort)
MitsubishiMcSubCommand
.Bit)
191
{
192
var readResult =
_memory
.ReadBits(address, request.Points);
193
if
(!readResult.IsSuccess || readResult.Value is
null
)
194
{
195
return
BuildResponse
(request.Header, 0xC051, []);
196
}
197
198
var data =
PackBits
(readResult.Value);
199
return
BuildResponse
(request.Header, 0x0000, data);
200
}
201
202
return
BuildResponse
(request.Header, 0xC059, []);
203
}
204
227
private
byte
[]
ExecuteWrite
(
McRequest
request)
228
{
229
if
(request.Points <= 0)
230
{
231
return
BuildResponse
(request.Header, 0xC051, []);
232
}
233
234
var address =
new
PlcAddress(
ToDeviceType
(request.DeviceCode), request.DeviceOffset);
235
236
if
(request.SubCommand == (ushort)
MitsubishiMcSubCommand
.Word)
237
{
238
var requiredLength = request.Points * 2;
239
if
(request.Data.Length < requiredLength)
240
{
241
return
BuildResponse
(request.Header, 0xC051, []);
242
}
243
244
var values =
new
short
[request.Points];
245
for
(var i = 0; i < request.Points; i++)
246
{
247
values[i] = unchecked((
short
)
ReadUInt16LittleEndian
(request.Data, i * 2));
248
}
249
250
var writeResult =
_memory
.WriteWords(address, values);
251
if
(!writeResult.IsSuccess)
252
{
253
return
BuildResponse
(request.Header, 0xC051, []);
254
}
255
256
ApplyAutoWordResponse
(request, values);
257
return
BuildResponse
(request.Header, 0x0000, []);
258
}
259
260
if
(request.SubCommand == (ushort)
MitsubishiMcSubCommand
.Bit)
261
{
262
var requiredLength = (request.Points + 1) / 2;
263
if
(request.Data.Length < requiredLength)
264
{
265
return
BuildResponse
(request.Header, 0xC051, []);
266
}
267
268
var values =
UnpackBits
(request.Data, request.Points);
269
var writeResult =
_memory
.WriteBits(address, values);
270
return
writeResult.IsSuccess
271
?
BuildResponse
(request.Header, 0x0000, [])
272
:
BuildResponse
(request.Header, 0xC051, []);
273
}
274
275
return
BuildResponse
(request.Header, 0xC059, []);
276
}
277
300
private
void
ApplyAutoWordResponse
(
McRequest
request, IReadOnlyList<short> values)
301
{
302
if
(!
_options
.EnableAutoWordResponse || values.Count != 1)
303
{
304
return
;
305
}
306
307
if
(request.DeviceCode !=
_options
.AutoResponseTriggerDeviceCode ||
308
request.DeviceOffset !=
_options
.AutoResponseTriggerOffset)
309
{
310
return
;
311
}
312
313
var rawResponseValue = values[0] +
_options
.AutoResponseIncrement;
314
if
(rawResponseValue is < short.MinValue or >
short
.MaxValue)
315
{
316
StatusChanged
?.Invoke(
this
, $
"MC auto response skipped: value overflow. value={rawResponseValue}"
);
317
return
;
318
}
319
320
var responseValue = (short)rawResponseValue;
321
var responseAddress =
new
PlcAddress(
ToDeviceType
(
_options
.AutoResponseDeviceCode),
_options
.AutoResponseOffset);
322
_memory
.WriteWords(responseAddress, [responseValue]);
323
StatusChanged
?.Invoke(
this
, $
"MC auto response: D{_options.AutoResponseOffset}={responseValue}"
);
324
}
325
362
private
static
bool
TryParseRequest
(
363
ReadOnlySpan<byte> frame,
364
out
McRequest
request,
365
out
string
? errorMessage)
366
{
367
request =
default
;
368
errorMessage =
null
;
369
370
if
(frame.Length < 21)
371
{
372
errorMessage = $
"The MC request frame is too short. Length={frame.Length}."
;
373
return
false
;
374
}
375
376
var subHeader =
ReadUInt16LittleEndian
(frame, 0);
377
if
(subHeader !=
RequestSubHeader
)
378
{
379
errorMessage = $
"Invalid MC request sub-header: 0x{subHeader:X4}."
;
380
return
false
;
381
}
382
383
var requestDataLength =
ReadUInt16LittleEndian
(frame, 7);
384
var expectedFrameLength = 9 + requestDataLength;
385
if
(frame.Length < expectedFrameLength)
386
{
387
errorMessage = $
"The MC request frame is incomplete. Expected={expectedFrameLength}, Actual={frame.Length}."
;
388
return
false
;
389
}
390
391
var header = frame[..7].ToArray();
392
var command =
ReadUInt16LittleEndian
(frame, 11);
393
var subCommand =
ReadUInt16LittleEndian
(frame, 13);
394
var deviceOffset =
ReadUInt24LittleEndian
(frame, 15);
395
var deviceCode = frame[18];
396
var points =
ReadUInt16LittleEndian
(frame, 19);
397
var dataStart = 21;
398
var dataLength = expectedFrameLength - dataStart;
399
var data = dataLength > 0 ? frame.Slice(dataStart, dataLength).ToArray() : [];
400
401
if
(!
IsSupportedDeviceCode
(deviceCode))
402
{
403
errorMessage = $
"Unsupported MC device code: 0x{deviceCode:X2}."
;
404
return
false
;
405
}
406
407
request =
new
McRequest
(header, command, subCommand, deviceOffset, deviceCode, points, data);
408
return
true
;
409
}
410
440
private
static
byte
[]
BuildErrorResponse
(ReadOnlySpan<byte> requestFrame, ushort endCode)
441
{
442
var header =
new
byte
[7];
443
if
(requestFrame.Length >= 7)
444
{
445
requestFrame[..7].CopyTo(header);
446
}
447
else
448
{
449
header[0] = 0x00;
450
header[1] = 0x50;
451
}
452
453
return
BuildResponse
(header, endCode, []);
454
}
455
499
private
static
byte
[]
BuildResponse
(IReadOnlyList<byte> requestHeader, ushort endCode, IReadOnlyList<byte> data)
500
{
501
var frame =
new
List<byte>(11 + data.Count);
502
MitsubishiMcEndian
.
WriteUInt16LittleEndian
(frame,
ResponseSubHeader
);
503
504
frame.Add(requestHeader.Count > 2 ? requestHeader[2] : (
byte
)0x00);
505
frame.Add(requestHeader.Count > 3 ? requestHeader[3] : (
byte
)0xFF);
506
frame.Add(requestHeader.Count > 4 ? requestHeader[4] : (
byte
)0xFF);
507
frame.Add(requestHeader.Count > 5 ? requestHeader[5] : (
byte
)0x03);
508
frame.Add(requestHeader.Count > 6 ? requestHeader[6] : (
byte
)0x00);
509
510
var responseDataLength = checked((ushort)(data.Count + 2));
511
MitsubishiMcEndian
.
WriteUInt16LittleEndian
(frame, responseDataLength);
512
MitsubishiMcEndian
.
WriteUInt16LittleEndian
(frame, endCode);
513
foreach
(var item
in
data)
514
{
515
frame.Add(item);
516
}
517
518
return
frame.ToArray();
519
}
520
543
private
static
byte
[]
PackBits
(IReadOnlyList<bool> values)
544
{
545
var bytes =
new
byte
[(values.Count + 1) / 2];
546
for
(var i = 0; i < values.Count; i++)
547
{
548
if
(!values[i])
549
{
550
continue
;
551
}
552
553
if
(i % 2 == 0)
554
{
555
bytes[i / 2] |= 0x10;
556
}
557
else
558
{
559
bytes[i / 2] |= 0x01;
560
}
561
}
562
563
return
bytes;
564
}
565
595
private
static
bool
[]
UnpackBits
(ReadOnlySpan<byte> data,
int
count)
596
{
597
var values =
new
bool
[count];
598
for
(var i = 0; i < count; i++)
599
{
600
var packed = data[i / 2];
601
values[i] = i % 2 == 0
602
? (packed & 0x10) != 0
603
: (packed & 0x01) != 0;
604
}
605
606
return
values;
607
}
608
638
private
static
ushort
ReadUInt16LittleEndian
(ReadOnlySpan<byte> buffer,
int
offset)
639
{
640
return
(ushort)(buffer[offset] | (buffer[offset + 1] << 8));
641
}
642
672
private
static
int
ReadUInt24LittleEndian
(ReadOnlySpan<byte> buffer,
int
offset)
673
{
674
return
buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16);
675
}
676
699
private
static
bool
IsSupportedDeviceCode
(
byte
deviceCode)
700
{
701
return
deviceCode is 0xA8 or 0x90 or 0x9C or 0x9D or 0xA0 or 0xB4 or 0xAF or 0xB0;
702
}
703
726
private
static
PlcDeviceType
ToDeviceType
(
byte
deviceCode)
727
{
728
return
deviceCode
switch
729
{
730
0xA8 => PlcDeviceType.D,
731
0x90 => PlcDeviceType.M,
732
0x9C => PlcDeviceType.X,
733
0x9D => PlcDeviceType.Y,
734
0xA0 => PlcDeviceType.B,
735
0xB4 => PlcDeviceType.W,
736
0xAF => PlcDeviceType.R,
737
0xB0 => PlcDeviceType.ZR,
738
_ => PlcDeviceType.Unknown
739
};
740
}
741
800
private
readonly record
struct
McRequest
(
801
byte[] Header,
802
ushort Command,
803
ushort SubCommand,
804
int DeviceOffset,
805
byte DeviceCode,
806
int Points,
807
byte[] Data);
808
}
Dreamine.PLC.Mitsubishi.MC.Protocol
Definition
MitsubishiMcBinary3EFrameBuilder.cs:6
Dreamine.PLC.Mitsubishi.MC.Protocol.MitsubishiMcSubCommand
MitsubishiMcSubCommand
Definition
MitsubishiMcSubCommand.cs:12
Dreamine.PLC.Mitsubishi.MC.Protocol.MitsubishiMcCommand
MitsubishiMcCommand
Definition
MitsubishiMcCommand.cs:12
Dreamine.PLC.Mitsubishi.MC.Simulation
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:6
Dreamine.PLC.Mitsubishi.MC.Protocol.MitsubishiMcEndian
Definition
MitsubishiMcEndian.cs:12
Dreamine.PLC.Mitsubishi.MC.Protocol.MitsubishiMcEndian.WriteUInt16LittleEndian
static void WriteUInt16LittleEndian(ICollection< byte > buffer, ushort value)
Definition
MitsubishiMcEndian.cs:44
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol._options
readonly MitsubishiMcSimulatorServerOptions _options
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:53
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol._memory
readonly InMemoryPlcMemory _memory
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:44
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.ReadUInt24LittleEndian
static int ReadUInt24LittleEndian(ReadOnlySpan< byte > buffer, int offset)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:672
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.IsSupportedDeviceCode
static bool IsSupportedDeviceCode(byte deviceCode)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:699
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.BuildErrorResponse
static byte[] BuildErrorResponse(ReadOnlySpan< byte > requestFrame, ushort endCode)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:440
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.BuildResponse
static byte[] BuildResponse(IReadOnlyList< byte > requestHeader, ushort endCode, IReadOnlyList< byte > data)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:499
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.ReadUInt16LittleEndian
static ushort ReadUInt16LittleEndian(ReadOnlySpan< byte > buffer, int offset)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:638
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.ResponseSubHeader
const ushort ResponseSubHeader
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:35
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.ToDeviceType
static PlcDeviceType ToDeviceType(byte deviceCode)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:726
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.TryParseRequest
static bool TryParseRequest(ReadOnlySpan< byte > frame, out McRequest request, out string? errorMessage)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:362
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.UnpackBits
static bool[] UnpackBits(ReadOnlySpan< byte > data, int count)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:595
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.ApplyAutoWordResponse
void ApplyAutoWordResponse(McRequest request, IReadOnlyList< short > values)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:300
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.RequestSubHeader
const ushort RequestSubHeader
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:26
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.Execute
byte[] Execute(ReadOnlySpan< byte > requestFrame)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:126
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.PackBits
static byte[] PackBits(IReadOnlyList< bool > values)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:543
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.ExecuteWrite
byte[] ExecuteWrite(McRequest request)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:227
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.ExecuteRead
byte[] ExecuteRead(McRequest request)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:164
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.McRequest
readonly record struct McRequest(byte[] Header, ushort Command, ushort SubCommand, int DeviceOffset, byte DeviceCode, int Points, byte[] Data)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:800
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.MitsubishiMcBinary3ESimulatorProtocol
MitsubishiMcBinary3ESimulatorProtocol(InMemoryPlcMemory memory, MitsubishiMcSimulatorServerOptions options)
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:85
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcBinary3ESimulatorProtocol.StatusChanged
EventHandler< string >? StatusChanged
Definition
MitsubishiMcBinary3ESimulatorProtocol.cs:101
Dreamine.PLC.Mitsubishi.MC.Simulation.MitsubishiMcSimulatorServerOptions
Definition
MitsubishiMcSimulatorServerOptions.cs:12
Simulation
MitsubishiMcBinary3ESimulatorProtocol.cs
다음에 의해 생성됨 :
1.17.0