Skip to content

Commit bed3ad9

Browse files
committed
fix: 요청 패킷 멀티 쓰기 오류 수정 및 서비스 응답 에러 패킷 응답 추가
1 parent f23640c commit bed3ad9

File tree

3 files changed

+53
-24
lines changed

3 files changed

+53
-24
lines changed

ModBusSimulatorSlave/Data/RequestPacket.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
namespace ModBusSimSlave.Data
22
{
3+
/**
4+
* Request Packet 요청 패킷
5+
* Function Code 15, 16을 제외한 모든 코드에서는 총 8바이트 고정 크기를 가짐
6+
* 15, 16 코드에서는 수량과 코일 혹은 레지스터에 따라 Byte Count와 Write Data의 길이가 달라짐
7+
* 수량 및 바이트 카운터에 따라 패킷 검수 과정
8+
*/
39
class RequestPacket
410
{
511
private byte[] _frame;
@@ -38,12 +44,18 @@ private RequestPacket(byte slaveAddr, byte functionCode, byte[] data, byte[] wri
3844
};
3945
_multiWirteData = writeData;
4046

47+
if (_multiWirteData.Length != _byteCount)
48+
throw new ArgumentException($"바이트 크기에 맞지 않는 데이터 들어옴\n바이크 크기: {_byteCount}, 들어온 데이터 크기: {_multiWirteData.Length}");
49+
4150
_frame = GetMultiWriteFrame();
4251
_crc = new byte[2];
4352
Array.Copy(_frame, _frame.Length - 2, _crc, 0, 2);
4453

4554
}
4655

56+
/**
57+
* 외부에서 받아온 패킷을 가공하기 위한 생성자
58+
*/
4759
public RequestPacket(byte[] frame)
4860
{
4961
_frame = frame;
@@ -54,7 +66,7 @@ public RequestPacket(byte[] frame)
5466
_functionCode = frame[1];
5567
_data = frame.Skip(2).Take(4).ToArray();
5668
_byteCount = frame[6];
57-
_multiWirteData = frame.Skip(6).Take(_byteCount).ToArray();
69+
_multiWirteData = frame.Skip(7).Take(_byteCount).ToArray();
5870
_crc = new byte[2];
5971
Array.Copy(frame, frame.Length - 2, _crc, 0, 2);
6072
}
@@ -103,6 +115,9 @@ private byte[] GetMultiWriteFrame()
103115
}
104116

105117

118+
/**
119+
* Getter & Setter
120+
*/
106121
public byte[] Frame
107122
{
108123
get { return _frame; }
@@ -146,6 +161,9 @@ public byte[] Crc
146161
}
147162

148163

164+
/**
165+
* 패킷 빌더
166+
*/
149167
public class RequestPacketBuilder
150168
{
151169
private byte _slaveAddr;

ModBusSimulatorSlave/SerialPortConnector.cs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,16 @@ private async void DataReceivedHandler(object sender, SerialDataReceivedEventArg
5151

5252
private void ProcessPacketBuffer(byte[] bytes)
5353
{
54-
lock(packBufferLock)
54+
lock (packBufferLock)
5555
{
5656
packetBuffer.AddRange(bytes);
57-
while(packetBuffer.Count >= 8)
57+
while (packetBuffer.Count >= 8)
5858
{
59-
int expectedLength = PacketHelpers.GetExpectedRequestPKLength(packetBuffer.ToArray());
59+
int expectedLength = PacketHelpers.GetExpectedRequestPKLength([.. packetBuffer]);
6060

6161
if (packetBuffer.Count < expectedLength) break;
6262

63-
byte[] packetBytes = packetBuffer.GetRange(0, expectedLength).ToArray();
63+
byte[] packetBytes = [.. packetBuffer.GetRange(0, expectedLength)];
6464

6565
if (PacketHelpers.CheckCRC(packetBytes))
6666
{
@@ -71,25 +71,18 @@ private void ProcessPacketBuffer(byte[] bytes)
7171
packet.Data.ToList().ForEach(e => Debug.Write($"{e:X2} "));
7272
Debug.WriteLine("");
7373

74-
ResponsePacket? response = service.Response(packet);
74+
ResponsePacket response = service.Response(packet);
7575
byte[] frame;
7676

77-
if (response == null)
78-
{
79-
Debug.WriteLine("응답 데이터 없음");
80-
frame = [1];
81-
}
82-
else
83-
{
84-
frame = response.Frame;
85-
Debug.WriteLine("응답 데이터");
86-
frame.ToList().ForEach(e => Debug.Write($"{e:X2} "));
87-
Debug.WriteLine("");
88-
}
77+
frame = response.Frame;
78+
Debug.WriteLine("응답 데이터");
79+
frame.ToList().ForEach(e => Debug.Write($"{e:X2} "));
80+
Debug.WriteLine("");
8981

9082
seriallPort.Write(frame, 0, frame.Length);
9183
packetBuffer.RemoveRange(0, expectedLength);
92-
} else
84+
}
85+
else
9386
{
9487
Console.Error.WriteLine("CRC 불일치");
9588
packetBuffer.RemoveAt(0);

ModBusSimulatorSlave/Service.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ public Service(VirtualDevice device)
1111
VirtualDevice = device;
1212
}
1313

14-
public ResponsePacket? Response(RequestPacket requestPacket)
14+
public ResponsePacket Response(RequestPacket requestPacket)
1515
{
16-
if (requestPacket.SlaveAddr != VirtualDevice.SlaveID) return null;
16+
if (requestPacket.SlaveAddr != VirtualDevice.SlaveID) return ErrorResponse(0x02, requestPacket);
1717

1818
Console.WriteLine("수신 데이터");
1919
Console.WriteLine($"SlaveAddr: {requestPacket.SlaveAddr} FunctioanCode: {requestPacket.FunctionCode}");
@@ -33,7 +33,7 @@ public Service(VirtualDevice device)
3333
0x06 => WriteSingleRegister(requestPacket),
3434
0x0F => WriteMultipleCoils(requestPacket),
3535
0x10 => WriteMultipleRegisters(requestPacket),
36-
_ => null,
36+
_ => ErrorResponse(0x01, requestPacket),
3737
};
3838
}
3939

@@ -132,6 +132,9 @@ private ResponsePacket WriteSingleCoil(RequestPacket packet)
132132
ushort address = (ushort)((packet.Data[0] << 8) | packet.Data[1] & 0xFF);
133133
ushort data = (ushort)((packet.Data[2] << 8) | packet.Data[3] & 0xFF);
134134

135+
if (data != 0xFF00 && data != 0x0000)
136+
return ErrorResponse(0x03, packet);
137+
135138
// 0xFF00이면 true, 0x0000이면 false
136139
VirtualDevice.Coils[address] = data == 0xFF00;
137140

@@ -161,8 +164,11 @@ private ResponsePacket WriteMultipleCoils(RequestPacket packet)
161164
{
162165
ushort address = (ushort)((packet.Data[0] << 8) | packet.Data[1] & 0xFF);
163166
ushort quantity = (ushort)((packet.Data[2] << 8) | packet.Data[3] & 0xFF);
164-
byte byteCount = packet.Data[4];
165-
byte[] writeData = packet.Data.Skip(5).ToArray();
167+
byte byteCount = packet.ByteCount;
168+
byte[] writeData = packet.MultiWriteData;
169+
170+
if (byteCount != writeData.Length || VirtualDevice.Coils.Length < quantity)
171+
return ErrorResponse(0x03, packet);
166172

167173
// 쓰기 데이터를 코일에 쓰기
168174
for (int i = 0; i < quantity; i++)
@@ -187,6 +193,9 @@ private ResponsePacket WriteMultipleRegisters(RequestPacket packet)
187193
byte byteCount = packet.ByteCount;
188194
byte[] writeData = packet.MultiWriteData;
189195

196+
if (byteCount != writeData.Length || VirtualDevice.HoldingRegisters.Length < quantity)
197+
return ErrorResponse(0x03, packet);
198+
190199
// 쓰기 데이터를 레지스터에 쓰기
191200
for (int i = 0; i < quantity; i++)
192201
{
@@ -201,5 +210,14 @@ private ResponsePacket WriteMultipleRegisters(RequestPacket packet)
201210
.Build();
202211
}
203212

213+
private ResponsePacket ErrorResponse(byte errorCode, RequestPacket packet)
214+
{
215+
return new ResponsePacket.ResponsePacketBuilder()
216+
.SetSlaveAddr(packet.SlaveAddr)
217+
.SetFunctionCode((byte)(packet.FunctionCode | 0x80))
218+
.SetData([errorCode])
219+
.Build();
220+
}
221+
204222
}
205223
}

0 commit comments

Comments
 (0)