Skip to content

Commit efa219a

Browse files
author
Thouen
committed
fix(ethernetip): 修复数组索引默认值和零索引处理逻辑
1. 将非数组标签的ArrayIndex默认值从0改为-1 2. 新增零索引数组标签的测试用例 3. 调整调度器中数组索引的判断条件,支持零索引
1 parent f3b28a0 commit efa219a

5 files changed

Lines changed: 43 additions & 23 deletions

File tree

internal/driver/ethernetip/debug_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,12 @@ func TestENIPDecoder_EncodeValue(t *testing.T) {
673673
value: float64(3.1415926535),
674674
expected: []byte{0x44, 0x17, 0x41, 0x54, 0xFB, 0x21, 0x09, 0x40}, // 3.1415926535 as float64 in little-endian
675675
},
676+
{
677+
name: "STRING 类型写入",
678+
dataType: "STRING",
679+
value: "Hi",
680+
expected: []byte{0x02, 0x00, 0x00, 0x00, 'H', 'i'}, // CIP STRING format: [length:2][capacity:2][data]
681+
},
676682
}
677683

678684
decoder := NewENIPDecoder()

internal/driver/ethernetip/decoder.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (d *ENIPDecoder) ParseAddress(addr string) (*ENIPTag, error) {
4848
if m := reSimpleTag.FindStringSubmatch(addr); m != nil {
4949
return &ENIPTag{
5050
Name: m[1],
51-
ArrayIndex: 0,
51+
ArrayIndex: -1,
5252
Path: []string{m[1]},
5353
}, nil
5454
}
@@ -79,14 +79,14 @@ func (d *ENIPDecoder) ParseAddress(addr string) (*ENIPTag, error) {
7979
if len(parts) >= 2 {
8080
return &ENIPTag{
8181
Name: parts[0],
82-
ArrayIndex: 0,
82+
ArrayIndex: -1,
8383
Path: parts,
8484
}, nil
8585
}
8686

8787
return &ENIPTag{
8888
Name: addr,
89-
ArrayIndex: 0,
89+
ArrayIndex: -1,
9090
Path: []string{addr},
9191
}, nil
9292
}
@@ -97,8 +97,9 @@ func (d *ENIPDecoder) ParseAddress(addr string) (*ENIPTag, error) {
9797
}
9898

9999
tag := &ENIPTag{
100-
Name: parts[0],
101-
Path: parts,
100+
Name: parts[0],
101+
ArrayIndex: -1,
102+
Path: parts,
102103
}
103104

104105
if len(parts) > 1 {
@@ -383,7 +384,18 @@ func (d *ENIPDecoder) EncodeValue(value interface{}, dataType string) ([]byte, e
383384
case "STRING":
384385
switch v := value.(type) {
385386
case string:
386-
return []byte(v), nil
387+
// CIP STRING 格式:[length:2][max_capacity:2][data:n]
388+
// 总长度 = 4 + len(v)
389+
result := make([]byte, 4+len(v))
390+
// 前 2 字节:实际长度(小端)
391+
result[0] = byte(len(v) & 0xFF)
392+
result[1] = byte((len(v) >> 8) & 0xFF)
393+
// 接下来 2 字节:最大容量(小端,设为 255)
394+
result[2] = 0xFF
395+
result[3] = 0x00
396+
// 剩余字节:字符串数据
397+
copy(result[4:], []byte(v))
398+
return result, nil
387399
default:
388400
return nil, fmt.Errorf("unsupported data type for encoding: %T", value)
389401
}

internal/driver/ethernetip/integration_test.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ import (
1212
func TestIntegrationWithSimulator(t *testing.T) {
1313
// 配置模拟器连接
1414
cfg := map[string]any{
15-
"ip": "127.0.0.1",
16-
"port": 44818,
17-
"slot": 0,
18-
"timeout": 3000,
19-
"maxRetries": 3,
20-
"retryInterval": 100,
15+
"ip": "127.0.0.1",
16+
"port": 44818,
17+
"slot": 0,
18+
"timeout": 3000,
19+
"maxRetries": 3,
20+
"retryInterval": 100,
21+
"connection_type": "cip",
2122
}
2223

2324
// 创建传输层
@@ -172,7 +173,7 @@ func testSinglePointWrite(t *testing.T, scheduler *ENIPScheduler) {
172173
{"WriteInt", "Program:MainProgram.IntTag", "INT", 12345},
173174
{"WriteDint", "Program:MainProgram.DintTag", "DINT", 987654321},
174175
{"WriteReal", "Program:MainProgram.RealTag", "REAL", float32(2.71828)},
175-
{"WriteString", "Program:MainProgram.StringTag", "STRING", "Test Message"},
176+
{"WriteString", "Program:MainProgram.StringTag", "STRING", "Hi"},
176177
}
177178

178179
for _, tc := range testCases {
@@ -259,11 +260,11 @@ func testArrayRead(t *testing.T, scheduler *ENIPScheduler) {
259260
// TestConnectionReconnect 测试连接断开后自动重连
260261
func TestConnectionReconnect(t *testing.T) {
261262
cfg := map[string]any{
262-
"ip": "127.0.0.1",
263-
"port": 44818,
264-
"slot": 0,
265-
"timeout": 2000,
266-
"maxRetries": 2,
263+
"ip": "127.0.0.1",
264+
"port": 44818,
265+
"slot": 0,
266+
"timeout": 2000,
267+
"maxRetries": 2,
267268
"retryInterval": 500,
268269
}
269270

@@ -298,4 +299,4 @@ func TestConnectionReconnect(t *testing.T) {
298299

299300
t.Log("Reconnection successful")
300301
defer transport.Disconnect()
301-
}
302+
}

internal/driver/ethernetip/scheduler.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ func (s *ENIPScheduler) readGroup(ctx context.Context, tcp *go_ethernet_ip.EIPTC
304304
fullName = strings.Join(pwt.Tag.Path, ".")
305305
}
306306
// 如果是简单数组标签(非程序标签),添加数组索引
307-
if pwt.Tag.ArrayIndex > 0 && len(pwt.Tag.Path) == 1 {
307+
if pwt.Tag.ArrayIndex >= 0 && len(pwt.Tag.Path) == 1 {
308308
fullName = fmt.Sprintf("%s[%d]", pwt.Tag.Name, pwt.Tag.ArrayIndex)
309309
}
310310

@@ -506,7 +506,7 @@ func (s *ENIPScheduler) WritePoint(ctx context.Context, p model.Point, value int
506506

507507
// 执行写入
508508
if err := tag.Write(); err != nil {
509-
return fmt.Errorf("failed to write tag %s: %w", p.Name, err)
509+
return fmt.Errorf("failed to write tag %s: %w", address, err)
510510
}
511511

512512
return nil

internal/driver/ethernetip/scheduler_perf_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,10 @@ func TestDecoderAddressParsing(t *testing.T) {
178178
wantPath []string
179179
wantIdx int
180180
}{
181-
{"simple_tag", "MyTag", "MyTag", []string{"MyTag"}, 0},
182-
{"program_tag", "Program:Main.MyTag", "Program:Main", []string{"Program:Main", "MyTag"}, 0},
181+
{"simple_tag", "MyTag", "MyTag", []string{"MyTag"}, -1},
182+
{"program_tag", "Program:Main.MyTag", "Program:Main", []string{"Program:Main", "MyTag"}, -1},
183183
{"array_tag", "MyArray[10]", "MyArray", []string{"MyArray"}, 10},
184+
{"array_tag_zero", "MyArray[0]", "MyArray", []string{"MyArray"}, 0},
184185
{"program_array_tag", "Program:Main.MyArray[5]", "Program:Main", []string{"Program:Main", "MyArray[5]"}, 0},
185186
}
186187

0 commit comments

Comments
 (0)