19static size_t write_header(uint8_t *buf,
size_t cap,
const AdsRequest *r, AdsCommand cmd, uint32_t payload_len)
21 if (!buf || !r || cap < (
size_t)ADS_HDR_LEN + payload_len)
29 p +=
pc_wr32le(buf + p, (uint32_t)ADS_AMS_HDR_LEN + payload_len);
31 memcpy(buf + p, r->target.net_id, ADS_NET_ID_LEN);
34 memcpy(buf + p, r->source.net_id, ADS_NET_ID_LEN);
38 p +=
pc_wr16le(buf + p, AdsStateFlags::request);
45size_t pc_ads_build_read_device_info(uint8_t *buf,
size_t cap,
const AdsRequest *r)
47 return write_header(buf, cap, r, AdsCommand::read_device_info, 0);
50size_t pc_ads_build_read_state(uint8_t *buf,
size_t cap,
const AdsRequest *r)
52 return write_header(buf, cap, r, AdsCommand::read_state, 0);
55size_t pc_ads_build_read(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint32_t index_group, uint32_t index_offset,
58 size_t p = write_header(buf, cap, r, AdsCommand::read, 12);
69size_t pc_ads_build_write(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint32_t index_group, uint32_t index_offset,
70 const uint8_t *data, uint32_t len)
76 size_t p = write_header(buf, cap, r, AdsCommand::write, 12 + len);
86 memcpy(buf + p, data, len);
92size_t pc_ads_build_read_write(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint32_t index_group,
93 uint32_t index_offset, uint32_t read_len,
const uint8_t *write_data, uint32_t write_len)
95 if (write_len && !write_data)
99 size_t p = write_header(buf, cap, r, AdsCommand::read_write, 16 + write_len);
110 memcpy(buf + p, write_data, write_len);
116size_t pc_ads_build_write_control(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint16_t pc_ads_state,
117 uint16_t device_state,
const uint8_t *data, uint32_t len)
123 size_t p = write_header(buf, cap, r, AdsCommand::write_control, 8 + len);
133 memcpy(buf + p, data, len);
139size_t pc_ads_build_add_notification(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint32_t index_group,
140 uint32_t index_offset, uint32_t length, AdsTransMode mode, uint32_t max_delay,
144 size_t p = write_header(buf, cap, r, AdsCommand::add_notification, 40);
155 memset(buf + p, 0, 16);
160size_t pc_ads_build_del_notification(uint8_t *buf,
size_t cap,
const AdsRequest *r, uint32_t notification_handle)
162 size_t p = write_header(buf, cap, r, AdsCommand::del_notification, 4);
167 p +=
pc_wr32le(buf + p, notification_handle);
171bool pc_ads_parse_ams_header(
const uint8_t *buf,
size_t len, AdsAmsHeader *out)
173 if (!buf || !out || len < (
size_t)ADS_HDR_LEN)
177 if (buf[0] != 0x00 || buf[1] != 0x00)
182 if (frame_len < (uint32_t)ADS_AMS_HDR_LEN)
186 if ((
size_t)ADS_AMSTCP_HDR_LEN + frame_len > len)
190 const uint8_t *a = buf + ADS_AMSTCP_HDR_LEN;
191 memcpy(out->target.net_id, a, ADS_NET_ID_LEN);
193 memcpy(out->source.net_id, a + 8, ADS_NET_ID_LEN);
195 out->cmd = (AdsCommand)
pc_rd16le(a + 16);
201 if ((uint32_t)ADS_AMS_HDR_LEN + out->data_len > frame_len)
205 out->data = a + ADS_AMS_HDR_LEN;
209bool pc_ads_parse_read(
const uint8_t *data,
size_t data_len, AdsReadResult *out)
211 if (!data || !out || data_len < 8)
217 if (8 + (
size_t)out->len > data_len)
221 out->data = data + 8;
225bool pc_ads_parse_result(
const uint8_t *data,
size_t data_len, uint32_t *result)
227 if (!data || !result || data_len < 4)
235bool pc_ads_parse_read_state(
const uint8_t *data,
size_t data_len, AdsReadStateResult *out)
237 if (!data || !out || data_len < 8)
247bool pc_ads_parse_read_device_info(
const uint8_t *data,
size_t data_len, AdsDeviceInfo *out)
249 if (!data || !out || data_len < 4 + 4 + ADS_DEVICE_NAME_LEN)
254 out->version_major = data[4];
255 out->version_minor = data[5];
256 out->version_build =
pc_rd16le(data + 6);
257 memcpy(out->device_name, data + 8, ADS_DEVICE_NAME_LEN);
258 out->device_name[ADS_DEVICE_NAME_LEN] =
'\0';
262bool pc_ads_parse_add_notification(
const uint8_t *data,
size_t data_len, uint32_t *result, uint32_t *handle)
264 if (!data || !result || !handle || data_len < 8)
273bool pc_ads_parse_notification(
const uint8_t *data,
size_t data_len, AdsNotificationSampleFn on_sample,
void *user)
276 if (!data || !on_sample || data_len < 8)
282 if (4 + (
size_t)length > data_len)
287 for (uint32_t s = 0; s < stamps; s++)
289 if (p + 12 > data_len)
293 uint64_t timestamp =
pc_rd64le(data + p);
294 uint32_t samples =
pc_rd32le(data + p + 8);
296 for (uint32_t i = 0; i < samples; i++)
298 if (p + 8 > data_len)
305 if (p + (
size_t)size > data_len)
309 on_sample(handle, data + p, size, timestamp, user);
Beckhoff ADS / AMS protocol codec (PC_ENABLE_ADS) - zero-heap request builders + response parsers for...
Fixed-width integer serializers into a raw uint8_t* buffer - one source of truth.
uint64_t pc_rd64le(const uint8_t *p)
Read a little-endian u64 at p.
uint32_t pc_rd32le(const uint8_t *p)
Read a little-endian u32 at p.
size_t pc_wr32le(uint8_t *p, uint32_t v)
Write v little-endian at p.
uint16_t pc_rd16le(const uint8_t *p)
Read a little-endian u16 at p.
size_t pc_wr16le(uint8_t *p, uint16_t v)
Write v little-endian at p.