15static size_t put16(uint8_t *p, uint16_t v)
17 p[0] = (uint8_t)(v >> 8);
22static uint16_t get16(
const uint8_t *p)
24 return (uint16_t)(((uint16_t)p[0] << 8) | p[1]);
28static size_t write_job_header(uint8_t *buf, uint16_t pdu_ref, uint16_t param_len, uint16_t data_len)
31 buf[p++] = S7_PROTOCOL_ID;
32 buf[p++] = S7_ROSCTR_JOB;
33 p += put16(buf + p, 0);
34 p += put16(buf + p, pdu_ref);
35 p += put16(buf + p, param_len);
36 p += put16(buf + p, data_len);
40size_t pc_s7_build_setup(uint8_t *buf,
size_t cap, uint16_t pdu_ref, uint16_t max_amq_calling, uint16_t max_amq_called,
47 const uint16_t param_len = 8;
48 size_t total = 10 + param_len;
53 size_t p = write_job_header(buf, pdu_ref, param_len, 0);
54 buf[p++] = S7_FUNC_SETUP_COMM;
56 p += put16(buf + p, max_amq_calling);
57 p += put16(buf + p, max_amq_called);
58 p += put16(buf + p, pdu_size);
62size_t pc_s7_build_read_request(uint8_t *buf,
size_t cap, uint16_t pdu_ref,
const S7ReadItem *items,
size_t n)
64 if (!buf || !items || n == 0 || n > 0xFF)
68 uint16_t param_len = (uint16_t)(2 + 12 * n);
69 size_t total = 10 + param_len;
74 size_t p = write_job_header(buf, pdu_ref, param_len, 0);
75 buf[p++] = S7_FUNC_READ_VAR;
76 buf[p++] = (uint8_t)n;
77 for (
size_t i = 0; i < n; i++)
79 const S7ReadItem &it = items[i];
82 buf[p++] = S7_SYNTAX_S7ANY;
83 buf[p++] = it.transport_size;
84 p += put16(buf + p, it.count);
85 p += put16(buf + p, it.db_number);
87 uint32_t addr = it.byte_address << 3;
88 buf[p++] = (uint8_t)(addr >> 16);
89 buf[p++] = (uint8_t)(addr >> 8);
90 buf[p++] = (uint8_t)(addr & 0xFF);
97static uint16_t s7_data_wire_len(uint8_t data_transport_size, uint16_t data_len)
99 if (data_transport_size == S7_DTS_BIT || data_transport_size == S7_DTS_BYTE || data_transport_size == S7_DTS_INT)
101 return (uint16_t)(data_len * 8);
106size_t pc_s7_build_write_request(uint8_t *buf,
size_t cap, uint16_t pdu_ref,
const S7WriteItem *items,
size_t n)
108 if (!buf || !items || n == 0 || n > 0xFF)
112 uint16_t param_len = (uint16_t)(2 + 12 * n);
115 for (
size_t i = 0; i < n; i++)
117 if (items[i].data_len && !items[i].data)
121 size_t item_bytes = 4 + items[i].data_len;
122 if (i + 1 < n && (items[i].data_len & 1))
126 data_len += item_bytes;
128 if (data_len > 0xFFFF)
132 size_t total = 10 + param_len + data_len;
138 size_t p = write_job_header(buf, pdu_ref, param_len, (uint16_t)data_len);
139 buf[p++] = S7_FUNC_WRITE_VAR;
140 buf[p++] = (uint8_t)n;
141 for (
size_t i = 0; i < n; i++)
143 const S7WriteItem &it = items[i];
146 buf[p++] = S7_SYNTAX_S7ANY;
147 buf[p++] = it.transport_size;
148 p += put16(buf + p, it.count);
149 p += put16(buf + p, it.db_number);
151 uint32_t addr = it.byte_address << 3;
152 buf[p++] = (uint8_t)(addr >> 16);
153 buf[p++] = (uint8_t)(addr >> 8);
154 buf[p++] = (uint8_t)(addr & 0xFF);
156 for (
size_t i = 0; i < n; i++)
158 const S7WriteItem &it = items[i];
160 buf[p++] = it.data_transport_size;
161 p += put16(buf + p, s7_data_wire_len(it.data_transport_size, it.data_len));
164 memcpy(buf + p, it.data, it.data_len);
167 if (i + 1 < n && (it.data_len & 1))
175bool pc_s7_parse_header(
const uint8_t *buf,
size_t len, S7Header *out)
177 if (!buf || !out || len < 10)
181 if (buf[0] != S7_PROTOCOL_ID)
185 out->rosctr = buf[1];
186 out->pdu_ref = get16(buf + 4);
187 out->param_len = get16(buf + 6);
188 out->data_len = get16(buf + 8);
189 out->error_class = 0;
191 out->header_len = (out->rosctr == S7_ROSCTR_ACK_DATA) ? 12 : 10;
192 if (out->header_len == 12)
198 out->error_class = buf[10];
199 out->error_code = buf[11];
201 if (out->header_len + (
size_t)out->param_len + (
size_t)out->data_len > len)
205 out->param = buf + out->header_len;
206 out->data = out->param + out->param_len;
210bool pc_s7_read_next_item(
const uint8_t *data,
size_t data_len,
size_t *offset, S7DataItem *out)
212 if (!data || !offset || !out)
217 if (o + 4 > data_len)
221 out->return_code = data[o];
222 out->transport_size = data[o + 1];
223 uint16_t raw_len = get16(data + o + 2);
227 if (out->transport_size == S7_DTS_BIT || out->transport_size == S7_DTS_BYTE || out->transport_size == S7_DTS_INT)
229 bytes = (raw_len + 7) / 8;
236 if (o + 4 + bytes > data_len)
240 out->data = data + o + 4;
241 out->data_len = bytes;
245 if (o < data_len && (bytes & 1))
Siemens S7comm PDU codec (PC_ENABLE_S7COMM) - zero-heap builder + parser for the S7-300/400 communica...