Skip to content

Commit f23640c

Browse files
committed
feat: 멀티 쓰기 처리 로직 추가
1 parent bef6190 commit f23640c

File tree

4 files changed

+122
-50
lines changed

4 files changed

+122
-50
lines changed

Data/RequestPacket.cs

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class RequestPacket
77
private byte _functionCode;
88
private byte[] _data;
99
private byte _byteCount;
10-
private byte[] _writeData;
10+
private byte[] _multiWirteData;
1111
private byte[] _crc;
1212

1313
private RequestPacket(byte slaveAddr, byte functionCode, byte[] data)
@@ -22,13 +22,21 @@ private RequestPacket(byte slaveAddr, byte functionCode, byte[] data)
2222
}
2323

2424
// 멀티 코일 & 레지스터 쓰기를 위한 생성자
25-
private RequestPacket(byte slaveAddr, byte functionCode, byte[] data, byte byteCnt, byte[] writeData)
25+
private RequestPacket(byte slaveAddr, byte functionCode, byte[] data, byte[] writeData)
2626
{
2727
_slaveAddr = slaveAddr;
2828
_functionCode = functionCode;
2929
_data = data;
30-
_byteCount = byteCnt;
31-
_writeData = writeData;
30+
31+
ushort quantity = (ushort)(data[2] << 8 | data[3] & 0xFF);
32+
33+
_byteCount = _functionCode switch
34+
{
35+
0x0F => (byte)(quantity / 8 + (quantity % 8 == 0 ? 0 : 1)),
36+
0x10 => (byte)(quantity * 2),
37+
_ => 0
38+
};
39+
_multiWirteData = writeData;
3240

3341
_frame = GetMultiWriteFrame();
3442
_crc = new byte[2];
@@ -44,11 +52,9 @@ public RequestPacket(byte[] frame)
4452
{
4553
_slaveAddr = frame[0];
4654
_functionCode = frame[1];
47-
_data = new byte[frame.Length - 7];
48-
Array.Copy(frame, 2, _data, 0, _data.Length);
49-
_byteCount = frame[frame.Length - 4];
50-
_writeData = new byte[frame.Length - 7 - 1];
51-
Array.Copy(frame, 3 + _data.Length, _writeData, 0, _writeData.Length);
55+
_data = frame.Skip(2).Take(4).ToArray();
56+
_byteCount = frame[6];
57+
_multiWirteData = frame.Skip(6).Take(_byteCount).ToArray();
5258
_crc = new byte[2];
5359
Array.Copy(frame, frame.Length - 2, _crc, 0, 2);
5460
}
@@ -80,14 +86,14 @@ private byte[] GetFrame()
8086

8187
private byte[] GetMultiWriteFrame()
8288
{
83-
byte[] frame = new byte[1 + 1 + _data.Length + 1 + _writeData.Length + 2]; // SlaveAddr + FunctionCode + Data + CRC
89+
byte[] frame = new byte[1 + 1 + _data.Length + 1 + _multiWirteData.Length + 2]; // SlaveAddr + FunctionCode + Data + CRC
8490

8591
frame[0] = _slaveAddr;
8692
frame[1] = _functionCode;
8793
Array.Copy(_data, 0, frame, 2, _data.Length);
8894

8995
frame[2 + _data.Length] = _byteCount;
90-
Array.Copy(_writeData, 0, frame, 3 + _data.Length, _writeData.Length);
96+
Array.Copy(_multiWirteData, 0, frame, 3 + _data.Length, _multiWirteData.Length);
9197

9298
ushort crc = PacketHelpers.CalcCRC(frame, 0, frame.Length - 2);
9399
frame[frame.Length - 2] = (byte)(crc & 0xFF);
@@ -121,6 +127,18 @@ public byte[] Data
121127
set { _data = value; }
122128
}
123129

130+
public byte ByteCount
131+
{
132+
get { return _byteCount; }
133+
set { _byteCount = value; }
134+
}
135+
136+
public byte[] MultiWriteData
137+
{
138+
get { return _multiWirteData; }
139+
set { _multiWirteData = value; }
140+
}
141+
124142
public byte[] Crc
125143
{
126144
get { return _crc; }
@@ -134,7 +152,7 @@ public class RequestPacketBuilder
134152
private byte _functionCode;
135153
private byte[] _data;
136154
private byte _byteCount;
137-
private byte[] _writeData;
155+
private byte[] _multiWriteData;
138156

139157
public RequestPacketBuilder SetSlaveAddr(byte slaveAddr)
140158
{
@@ -154,24 +172,19 @@ public RequestPacketBuilder SetData(byte[] data)
154172
return this;
155173
}
156174

157-
public RequestPacketBuilder SetByteCount(byte byteCount)
175+
public RequestPacketBuilder SetWriteData(byte[] multiWriteData)
158176
{
159-
_byteCount = byteCount;
160-
return this;
161-
}
162-
163-
public RequestPacketBuilder SetWriteData(byte[] writeData)
164-
{
165-
_writeData = writeData;
177+
_multiWriteData = multiWriteData;
166178
return this;
167179
}
168180

169181
public RequestPacket Build()
170182
{
171183
return _functionCode == 0x0F || _functionCode == 0x10 ?
172-
new RequestPacket(_slaveAddr, _functionCode, _data, _byteCount, _writeData) :
184+
new RequestPacket(_slaveAddr, _functionCode, _data, _multiWriteData) :
173185
new RequestPacket(_slaveAddr, _functionCode, _data);
174186
}
175187
}
176188
}
189+
177190
}

Data/ResponsePacket.cs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ class ResponsePacket
55
private byte[] _frame;
66
private byte _slaveAddr;
77
private byte _functionCode;
8-
private byte _dataLength;
8+
private byte _byteCount;
99
private byte[] _data;
1010
private byte[] _crc;
1111

1212
private ResponsePacket(byte slaveArr, byte functionCode, byte dataLength, byte[] data)
1313
{
1414
_slaveAddr = slaveArr;
1515
_functionCode = functionCode;
16-
_dataLength = dataLength;
16+
_byteCount = dataLength;
1717
_data = data;
1818

1919
_frame = GetReadFrame();
@@ -37,11 +37,19 @@ public ResponsePacket(byte[] frame)
3737
_frame = frame;
3838
_slaveAddr = frame[0];
3939
_functionCode = frame[1];
40-
_dataLength = frame[2];
41-
_data = new byte[_dataLength];
42-
Array.Copy(frame, 3, _data, 0, _dataLength);
40+
41+
if (_functionCode is 0x0F or 0x10)
42+
{
43+
_data = frame.Skip(2).Take(4).ToArray();
44+
_crc = frame.Skip(6).Take(2).ToArray();
45+
return;
46+
}
47+
48+
_byteCount = frame[2];
49+
_data = new byte[_byteCount];
50+
Array.Copy(frame, 3, _data, 0, _byteCount);
4351
_crc = new byte[2];
44-
Array.Copy(frame, 3 + _dataLength, _crc, 0, 2);
52+
Array.Copy(frame, 3 + _byteCount, _crc, 0, 2);
4553
}
4654

4755
private byte[] GetReadFrame()
@@ -51,7 +59,7 @@ private byte[] GetReadFrame()
5159

5260
frame[0] = _slaveAddr;
5361
frame[1] = _functionCode;
54-
frame[2] = _dataLength;
62+
frame[2] = _byteCount;
5563
Array.Copy(_data, 0, frame, 3, _data.Length);
5664

5765
ushort crc = PacketHelpers.CalcCRC(frame, 0, frame.Length - 2);
@@ -93,10 +101,10 @@ public byte FunctionCode
93101
set { _functionCode = value; }
94102
}
95103

96-
public byte DataLength
104+
public byte ByteCount
97105
{
98-
get { return _dataLength; }
99-
set { _dataLength = value; }
106+
get { return _byteCount; }
107+
set { _byteCount = value; }
100108
}
101109

102110
public byte[] Data
@@ -115,7 +123,7 @@ public class ResponsePacketBuilder
115123
{
116124
private byte _slaveAddr;
117125
private byte _functionCode;
118-
private byte _dataLength;
126+
private byte _byteCount;
119127
private byte[] _data;
120128

121129
public ResponsePacketBuilder SetSlaveAddr(byte slaveAddr)
@@ -130,9 +138,9 @@ public ResponsePacketBuilder SetFunctionCode(byte functionCode)
130138
return this;
131139
}
132140

133-
public ResponsePacketBuilder SetDataLength(byte dataLength)
141+
public ResponsePacketBuilder SetByteCount(byte byteCount)
134142
{
135-
_dataLength = dataLength;
143+
_byteCount = byteCount;
136144
return this;
137145
}
138146

@@ -146,7 +154,7 @@ public ResponsePacket Build()
146154
{
147155
return _functionCode == 0x05 || _functionCode == 0x06 || _functionCode == 0x0F || _functionCode == 0x10 ?
148156
new ResponsePacket(_slaveAddr, _functionCode, _data) :
149-
new ResponsePacket(_slaveAddr, _functionCode, _dataLength, _data);
157+
new ResponsePacket(_slaveAddr, _functionCode, _byteCount, _data);
150158
}
151159
}
152160
}

MainForm.Designer.cs

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

MainForm.cs

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.IO.Ports;
22
using System.Text;
3+
using System.Text.RegularExpressions;
34
using ModBusSimMaster.Data;
45

56
namespace ModBusSimMaster
@@ -131,29 +132,48 @@ private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
131132
}
132133

133134
private void txBtn_Click(object sender, EventArgs e)
135+
{
136+
CreatePacket(out RequestPacket packet);
137+
byte[] frame = packet.Frame;
138+
serialPort.Write(frame, 0, frame.Length);
139+
}
140+
141+
private void CreatePacket(out RequestPacket packet)
134142
{
135143
byte slaveAddr = Convert.ToByte(slaveTextBox.Text, 16);
136144
byte functionCode = SelFuncCodeToByte();
137-
ushort address = Convert.ToUInt16(addressTextBox.Text, 16);
145+
byte[] address = BitConverter.GetBytes(Convert.ToInt16(addressTextBox.Text, 16))
146+
.Reverse()
147+
.ToArray();
148+
149+
byte[] quantity = string.IsNullOrEmpty(quantityTxBox.Text) ? [] :
150+
BitConverter.GetBytes(Convert.ToInt16(quantityTxBox.Text, 16))
151+
.Reverse()
152+
.ToArray();
153+
154+
byte[] writeData = string.IsNullOrEmpty(dataTextBox.Text) ? [] :
155+
Enumerable.Range(0, dataTextBox.Text.Length)
156+
.Where(x => x % 2 == 0)
157+
.Select(x => Convert.ToByte(dataTextBox.Text.Substring(x, 2), 16))
158+
.ToArray();
138159

139-
// TODO: 수량, 데이터 functionCode에 따라 다르게 처리
140160
// 0x01, 0x02, 0x03, 0x04: 수량
141161
// 0x05, 0x06: 데이터
142162
// 0x0F, 0x10: 수량, 데이터
143-
ushort quantity = Convert.ToUInt16(quantityTxBox.Text, 16);
144-
ushort data = dataTextBox.Enabled ? Convert.ToUInt16(dataTextBox.Text, 16) : quantity;
163+
byte[] data = SelFuncCodeToByte() switch
164+
{
165+
0x01 or 0x02 or 0x03 or 0x04 or 0x0F or 0x10 => [.. address, .. quantity],
166+
0x05 or 0x06 => [.. address, .. writeData],
167+
_ => [],
168+
};
145169

146-
// TODO: RequestPacket FunctionCode에 따라 다르게 생성
147-
var packet = new RequestPacket.RequestPacketBuilder()
170+
RequestPacket.RequestPacketBuilder builder = new RequestPacket.RequestPacketBuilder()
148171
.SetSlaveAddr(slaveAddr)
149172
.SetFunctionCode(functionCode)
150-
.SetData([
151-
(byte)(address >> 8), (byte)(address & 0xFF), (byte)(data >> 8), (byte)(data & 0xFF)
152-
])
153-
.Build();
173+
.SetData(data);
174+
if (functionCode == 0x0F || functionCode == 0x10) builder.SetWriteData(writeData);
154175

155-
byte[] frame = packet.Frame;
156-
serialPort.Write(frame, 0, frame.Length);
176+
packet = builder.Build();
157177
}
158178

159179
private byte SelFuncCodeToByte()
@@ -170,13 +190,26 @@ private byte SelFuncCodeToByte()
170190
7 => 0x10,
171191
_ => 0x01,
172192
};
173-
;
174193
}
175194

176195
private void dataTextBox_TextChanged(object sender, EventArgs e)
177196
{
178-
// TODO: dataTextBox의 값이 0xFFFF를 넘어가면 0xFFFF로 설정
179-
// 멀티 쓰기 일 경우 byteCount를 넘어가면 byteCount로 설정
197+
198+
byte funcCode = SelFuncCodeToByte();
199+
byte byteCount = 4;
200+
201+
if (funcCode is 0x0F or 0x10)
202+
{
203+
ushort quantity = Convert.ToUInt16(quantityTxBox.Text, 16);
204+
byteCount = (byte)(funcCode == 0x0F ?
205+
(quantity / 8 + (quantity % 8 == 0 ? 0 : 1)) :
206+
quantity * 2);
207+
}
208+
209+
if (dataTextBox.Text.Length > byteCount)
210+
{
211+
dataTextBox.Text = new string('F', byteCount);
212+
}
180213
}
181214

182215
private void selFuncCode_SelectedIndexChanged(object sender, EventArgs e)
@@ -202,5 +235,19 @@ private void ToggleInputFields()
202235
dataTextBox.Enabled = true;
203236
}
204237
}
238+
239+
private void TextBox_KeyPress(object sender, KeyPressEventArgs e)
240+
{
241+
ValidateHexInput(e);
242+
}
243+
244+
private static void ValidateHexInput(KeyPressEventArgs e)
245+
{
246+
string pattern = @"\b[0-9a-fA-F]+\b";
247+
if (!Regex.IsMatch(e.KeyChar.ToString(), pattern) && !char.IsControl(e.KeyChar))
248+
{
249+
e.Handled = true;
250+
}
251+
}
205252
}
206253
}

0 commit comments

Comments
 (0)