16static size_t put16le(uint8_t *p, uint16_t v)
18 p[0] = (uint8_t)(v & 0xFF);
19 p[1] = (uint8_t)(v >> 8);
23static size_t put32le(uint8_t *p, uint32_t v)
25 p[0] = (uint8_t)(v & 0xFF);
26 p[1] = (uint8_t)((v >> 8) & 0xFF);
27 p[2] = (uint8_t)((v >> 16) & 0xFF);
28 p[3] = (uint8_t)((v >> 24) & 0xFF);
32static uint16_t get16le(
const uint8_t *p)
34 return (uint16_t)(p[0] | ((uint16_t)p[1] << 8));
37static uint32_t get32le(
const uint8_t *p)
39 return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
42static uint64_t get64le(
const uint8_t *p)
44 return (uint64_t)get32le(p) | ((uint64_t)get32le(p + 4) << 32);
49static size_t write_header(uint8_t *buf,
size_t cap,
const AdsRequest *r, AdsCommand cmd, uint32_t payload_len)
51 if (!buf || !r || cap < (
size_t)ADS_HDR_LEN + payload_len)
57 p += put32le(buf + p, (uint32_t)ADS_AMS_HDR_LEN + payload_len);
59 memcpy(buf + p, r->target.net_id, ADS_NET_ID_LEN);
61 p += put16le(buf + p, r->target.port);
62 memcpy(buf + p, r->source.net_id, ADS_NET_ID_LEN);
64 p += put16le(buf + p, r->source.port);
65 p += put16le(buf + p, (uint16_t)cmd);
66 p += put16le(buf + p, AdsStateFlags::request);
67 p += put32le(buf + p, payload_len);
68 p += put32le(buf + p, 0);
69 p += put32le(buf + p, r->invoke_id);
73size_t ads_build_read_device_info(uint8_t *buf,
size_t cap,
const AdsRequest *r)
75 return write_header(buf, cap, r, AdsCommand::read_device_info, 0);
78size_t ads_build_read_state(uint8_t *buf,
size_t cap,
const AdsRequest *r)
80 return write_header(buf, cap, r, AdsCommand::read_state, 0);
83size_t ads_build_read(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint32_t index_group, uint32_t index_offset,
86 size_t p = write_header(buf, cap, r, AdsCommand::read, 12);
89 p += put32le(buf + p, index_group);
90 p += put32le(buf + p, index_offset);
91 p += put32le(buf + p, read_len);
95size_t ads_build_write(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint32_t index_group, uint32_t index_offset,
96 const uint8_t *data, uint32_t len)
100 size_t p = write_header(buf, cap, r, AdsCommand::write, 12 + len);
103 p += put32le(buf + p, index_group);
104 p += put32le(buf + p, index_offset);
105 p += put32le(buf + p, len);
108 memcpy(buf + p, data, len);
114size_t ads_build_read_write(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint32_t index_group, uint32_t index_offset,
115 uint32_t read_len,
const uint8_t *write_data, uint32_t write_len)
117 if (write_len && !write_data)
119 size_t p = write_header(buf, cap, r, AdsCommand::read_write, 16 + write_len);
122 p += put32le(buf + p, index_group);
123 p += put32le(buf + p, index_offset);
124 p += put32le(buf + p, read_len);
125 p += put32le(buf + p, write_len);
128 memcpy(buf + p, write_data, write_len);
134size_t ads_build_write_control(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint16_t ads_state, uint16_t device_state,
135 const uint8_t *data, uint32_t len)
139 size_t p = write_header(buf, cap, r, AdsCommand::write_control, 8 + len);
142 p += put16le(buf + p, ads_state);
143 p += put16le(buf + p, device_state);
144 p += put32le(buf + p, len);
147 memcpy(buf + p, data, len);
153size_t ads_build_add_notification(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint32_t index_group,
154 uint32_t index_offset, uint32_t length, AdsTransMode mode, uint32_t max_delay,
158 size_t p = write_header(buf, cap, r, AdsCommand::add_notification, 40);
161 p += put32le(buf + p, index_group);
162 p += put32le(buf + p, index_offset);
163 p += put32le(buf + p, length);
164 p += put32le(buf + p, (uint32_t)mode);
165 p += put32le(buf + p, max_delay);
166 p += put32le(buf + p, cycle_time);
167 memset(buf + p, 0, 16);
172size_t ads_build_del_notification(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint32_t notification_handle)
174 size_t p = write_header(buf, cap, r, AdsCommand::del_notification, 4);
177 p += put32le(buf + p, notification_handle);
181bool ads_parse_ams_header(
const uint8_t *buf,
size_t len, AdsAmsHeader *out)
183 if (!buf || !out || len < (
size_t)ADS_HDR_LEN)
185 if (buf[0] != 0x00 || buf[1] != 0x00)
187 uint32_t frame_len = get32le(buf + 2);
188 if (frame_len < (uint32_t)ADS_AMS_HDR_LEN)
190 if ((
size_t)ADS_AMSTCP_HDR_LEN + frame_len > len)
192 const uint8_t *a = buf + ADS_AMSTCP_HDR_LEN;
193 memcpy(out->target.net_id, a, ADS_NET_ID_LEN);
194 out->target.port = get16le(a + 6);
195 memcpy(out->source.net_id, a + 8, ADS_NET_ID_LEN);
196 out->source.port = get16le(a + 14);
197 out->cmd = (AdsCommand)get16le(a + 16);
198 out->state_flags = get16le(a + 18);
199 out->data_len = get32le(a + 20);
200 out->error_code = get32le(a + 24);
201 out->invoke_id = get32le(a + 28);
203 if ((uint32_t)ADS_AMS_HDR_LEN + out->data_len > frame_len)
205 out->data = a + ADS_AMS_HDR_LEN;
209bool ads_parse_read(
const uint8_t *data,
size_t data_len, AdsReadResult *out)
211 if (!data || !out || data_len < 8)
213 out->result = get32le(data);
214 out->len = get32le(data + 4);
215 if (8 + (
size_t)out->len > data_len)
217 out->data = data + 8;
221bool ads_parse_result(
const uint8_t *data,
size_t data_len, uint32_t *result)
223 if (!data || !result || data_len < 4)
225 *result = get32le(data);
229bool ads_parse_read_state(
const uint8_t *data,
size_t data_len, AdsReadStateResult *out)
231 if (!data || !out || data_len < 8)
233 out->result = get32le(data);
234 out->ads_state = get16le(data + 4);
235 out->device_state = get16le(data + 6);
239bool ads_parse_read_device_info(
const uint8_t *data,
size_t data_len, AdsDeviceInfo *out)
241 if (!data || !out || data_len < 4 + 4 + ADS_DEVICE_NAME_LEN)
243 out->result = get32le(data);
244 out->version_major = data[4];
245 out->version_minor = data[5];
246 out->version_build = get16le(data + 6);
247 memcpy(out->device_name, data + 8, ADS_DEVICE_NAME_LEN);
248 out->device_name[ADS_DEVICE_NAME_LEN] =
'\0';
252bool ads_parse_add_notification(
const uint8_t *data,
size_t data_len, uint32_t *result, uint32_t *handle)
254 if (!data || !result || !handle || data_len < 8)
256 *result = get32le(data);
257 *handle = get32le(data + 4);
261bool ads_parse_notification(
const uint8_t *data,
size_t data_len, AdsNotificationSampleFn on_sample,
void *user)
264 if (!data || !on_sample || data_len < 8)
266 uint32_t length = get32le(data);
267 uint32_t stamps = get32le(data + 4);
268 if (4 + (
size_t)length > data_len)
271 for (uint32_t s = 0; s < stamps; s++)
273 if (p + 12 > data_len)
275 uint64_t timestamp = get64le(data + p);
276 uint32_t samples = get32le(data + p + 8);
278 for (uint32_t i = 0; i < samples; i++)
280 if (p + 8 > data_len)
282 uint32_t handle = get32le(data + p);
283 uint32_t size = get32le(data + p + 4);
285 if (p + (
size_t)size > data_len)
287 on_sample(handle, data + p, size, timestamp, user);
Beckhoff ADS / AMS protocol codec (DETWS_ENABLE_ADS) - zero-heap request builders + response parsers ...