|
7 | 7 |
|
8 | 8 | using System; |
9 | 9 | using System.Collections.Generic; |
10 | | -using System.Linq; |
11 | 10 | using System.Text; |
| 11 | +using System.Buffers.Binary; |
12 | 12 | using libplctag; |
13 | 13 |
|
14 | 14 | namespace CSharp_DotNetCore |
15 | 15 | { |
16 | 16 | class ExampleRaw |
17 | 17 | { |
18 | | - public static void Run() |
19 | | - { |
20 | | - var lister = new LogixTagListing() |
21 | | - { |
22 | | - Gateway = "192.168.0.1", |
23 | | - Path = "1,0", |
24 | | - Timeout = TimeSpan.FromMilliseconds(1000), |
25 | | - }; |
26 | | - |
27 | | - var tags = lister.ListTags(); |
28 | | - |
29 | | - foreach (var tag in tags) |
30 | | - Console.WriteLine($"Id={tag.Id} Name={tag.Name} Type={tag.Type} Length={tag.Length}"); |
31 | | - } |
32 | 18 |
|
33 | | - class LogixTagListing |
| 19 | + public static void Run() |
34 | 20 | { |
35 | | - readonly Tag _rawCip = new Tag() |
| 21 | + // This payload is taken from https://github.com/libplctag/libplctag/blob/release/src/examples/test_raw_cip.c |
| 22 | + // but others can be found by analysing the Rockwell or other manufacturer's documentation |
| 23 | + // https://literature.rockwellautomation.com/idc/groups/literature/documents/pm/1756-pm020_-en-p.pdf pg 39 |
| 24 | + |
| 25 | + ReadOnlySpan<byte> raw_payload = [ |
| 26 | + 0x55, |
| 27 | + 0x03, |
| 28 | + 0x20, 0x6b, 0x25, 0x00, 0x00, 0x00, |
| 29 | + 0x04, 0x00, |
| 30 | + 0x02, 0x00, |
| 31 | + 0x07, 0x00, |
| 32 | + 0x08, 0x00, |
| 33 | + 0x01, 0x00 |
| 34 | + ]; |
| 35 | + |
| 36 | + var cipService = new Tag() |
36 | 37 | { |
37 | 38 | PlcType = PlcType.ControlLogix, |
38 | 39 | Protocol = Protocol.ab_eip, |
| 40 | + Gateway = "10.10.10.10", |
| 41 | + Path = "1,0", |
39 | 42 | Name = "@raw", |
40 | 43 | }; |
41 | | - |
42 | | - public string Gateway { get => _rawCip.Gateway; set => _rawCip.Gateway = value; } |
43 | | - public string Path { get => _rawCip.Path; set => _rawCip.Path = value; } |
44 | | - public TimeSpan Timeout { get => _rawCip.Timeout; set => _rawCip.Timeout = value; } |
45 | | - |
46 | | - public List<TagInfo> ListTags() |
47 | | - { |
48 | | - // This payload is taken from https://github.com/libplctag/libplctag/blob/release/src/examples/test_raw_cip.c |
49 | | - // but others can be found by analysing the Rockwell or other manufacturer's documentation |
50 | | - // https://literature.rockwellautomation.com/idc/groups/literature/documents/pm/1756-pm020_-en-p.pdf pg 39 |
51 | | - |
52 | | - var raw_payload = new byte[] { |
53 | | - 0x55, |
54 | | - 0x03, |
55 | | - 0x20, |
56 | | - 0x6b, |
57 | | - 0x25, |
58 | | - 0x00, |
59 | | - 0x00, |
60 | | - 0x00, |
61 | | - 0x04, |
62 | | - 0x00, |
63 | | - 0x02, |
64 | | - 0x00, |
65 | | - 0x07, |
66 | | - 0x00, |
67 | | - 0x08, |
68 | | - 0x00, |
69 | | - 0x01, |
70 | | - 0x00 |
71 | | - }; |
72 | | - |
73 | | - _rawCip.Initialize(); |
74 | | - _rawCip.SetSize(raw_payload.Length); |
75 | | - _rawCip.SetBuffer(raw_payload); |
76 | | - _rawCip.Write(); |
77 | | - |
78 | | - var responseSize = _rawCip.GetSize(); |
79 | | - |
80 | | - var tagInfos = new List<TagInfo>(); |
81 | | - int offset = 0; |
82 | | - while (offset < responseSize) |
83 | | - tagInfos.Add(DecodeOneTagInfo(ref offset)); |
84 | | - |
85 | | - return tagInfos; |
86 | | - } |
87 | | - |
88 | | - public class TagInfo |
89 | | - { |
90 | | - public uint Id { get; set; } |
91 | | - public ushort Type { get; set; } |
92 | | - public string Name { get; set; } |
93 | | - public ushort Length { get; set; } |
94 | | - public uint[] Dimensions { get; set; } |
95 | | - } |
96 | | - |
97 | | - TagInfo DecodeOneTagInfo(ref int offset) |
| 44 | + cipService.Initialize(); |
| 45 | + cipService.SetSize(raw_payload.Length); |
| 46 | + cipService.SetBuffer(raw_payload); |
| 47 | + cipService.Write(); |
| 48 | + Span<byte> res = stackalloc byte[cipService.GetSize()]; |
| 49 | + cipService.GetBuffer(res); |
| 50 | + |
| 51 | + var tagInfos = new List<TagInfo>(); |
| 52 | + for (int cursor = 0; cursor < res.Length;) |
98 | 53 | { |
99 | | - |
100 | | - var tagInstanceId = _rawCip.GetUInt32(offset); |
101 | | - var tagType = _rawCip.GetUInt16(offset + 4); |
102 | | - var tagLength = _rawCip.GetUInt16(offset + 6); |
103 | | - var tagArrayDims = new uint[] |
104 | | - { |
105 | | - _rawCip.GetUInt32(offset + 8), |
106 | | - _rawCip.GetUInt32(offset + 12), |
107 | | - _rawCip.GetUInt32(offset + 16) |
108 | | - }; |
109 | | - |
110 | | - var apparentTagNameLength = (int)_rawCip.GetUInt16(offset + 20); |
111 | | - const int TAG_STRING_SIZE = 200; |
112 | | - var actualTagNameLength = Math.Min(apparentTagNameLength, TAG_STRING_SIZE * 2 - 1); |
113 | | - |
114 | | - var tagNameBytes = Enumerable.Range(offset + 22, actualTagNameLength) |
115 | | - .Select(o => _rawCip.GetUInt8(o)) |
116 | | - .Select(Convert.ToByte) |
117 | | - .ToArray(); |
118 | | - |
119 | | - var tagName = Encoding.ASCII.GetString(tagNameBytes); |
120 | | - |
121 | | - offset = 22 + actualTagNameLength; |
122 | | - |
123 | | - return new TagInfo() |
124 | | - { |
125 | | - Id = tagInstanceId, |
126 | | - Type = tagType, |
127 | | - Name = tagName, |
128 | | - Length = tagLength, |
129 | | - Dimensions = tagArrayDims |
130 | | - }; |
131 | | - |
| 54 | + var tagNameLength = U16(res, cursor + 20); |
| 55 | + tagInfos.Add(new ( |
| 56 | + Id : U32(res, cursor + 0), |
| 57 | + Type : U16(res, cursor + 4), |
| 58 | + Length : U16(res, cursor + 6), |
| 59 | + Dimensions : [ |
| 60 | + U32(res, cursor + 8), |
| 61 | + U32(res, cursor + 12), |
| 62 | + U32(res, cursor + 16) |
| 63 | + ], |
| 64 | + Name : ASCII(res, cursor + 22, tagNameLength) |
| 65 | + )); |
| 66 | + |
| 67 | + cursor += 22 + tagNameLength; |
132 | 68 | } |
133 | 69 |
|
| 70 | + foreach (var tag in tagInfos) |
| 71 | + Console.WriteLine($"Id={tag.Id} Name={tag.Name} Type={tag.Type} Length={tag.Length}"); |
134 | 72 | } |
135 | 73 |
|
| 74 | + record TagInfo(uint Id, ushort Type, ushort Length, uint[] Dimensions, string Name); |
| 75 | + static ushort U16(ReadOnlySpan<byte> bs, int offset) => BinaryPrimitives.ReadUInt16LittleEndian(bs[offset..]); |
| 76 | + static uint U32(ReadOnlySpan<byte> bs, int offset) => BinaryPrimitives.ReadUInt32LittleEndian(bs[offset..]); |
| 77 | + static string ASCII(ReadOnlySpan<byte> bs, int offset, int len) => Encoding.ASCII.GetString(bs[offset..(offset+len)]); |
136 | 78 | } |
137 | 79 |
|
138 | 80 | } |
0 commit comments