DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
s7comm.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file s7comm.h
6 * @brief Siemens S7comm PDU codec (DETWS_ENABLE_S7COMM) - zero-heap builder + parser for the
7 * S7-300/400 communication PDUs, carried inside a COTP Data TPDU (services/cotp) over
8 * ISO-on-TCP (port 102).
9 *
10 * An S7comm PDU starts with a header then a parameter section then an optional data section:
11 * @code
12 * 0x32 ROSCTR redundancy(2) pdu-ref(2) param-len(2) data-len(2) [err-class err-code]
13 * <parameter ...> <data ...>
14 * @endcode
15 * The header is 10 octets, or 12 for an Ack_Data response (which adds a 2-octet error code).
16 * A Read Var job (function 0x04) carries one or more S7-ANY request items (area / DB / byte
17 * address / element count); the Ack_Data response carries, per item, a return code + a data
18 * transport size + a length + the value bytes. Per the protocol, the response length is in
19 * BITS for the bit/byte/int transport sizes (3/4/5) and in BYTES otherwise, and each item
20 * is padded to an even length except the last.
21 *
22 * Constants and the length rule are verified against the Wireshark S7comm dissector. This
23 * codec produces / consumes the S7 PDU; wrap it with `cotp_build_dt` + `tpkt_build`.
24 *
25 * @author Douglas Quigg (dstroy0)
26 * @date 2026
27 */
28
29#ifndef DETERMINISTICESPASYNCWEBSERVER_S7COMM_H
30#define DETERMINISTICESPASYNCWEBSERVER_S7COMM_H
31
32#include "ServerConfig.h"
33
34#if DETWS_ENABLE_S7COMM
35
36#include <stddef.h>
37#include <stdint.h>
38
39#define S7_PROTOCOL_ID 0x32 ///< constant first octet of every S7comm PDU
40
41// ROSCTR (message type).
42#define S7_ROSCTR_JOB 0x01
43#define S7_ROSCTR_ACK 0x02
44#define S7_ROSCTR_ACK_DATA 0x03
45#define S7_ROSCTR_USERDATA 0x07
46
47// Parameter function codes.
48#define S7_FUNC_SETUP_COMM 0xF0
49#define S7_FUNC_READ_VAR 0x04
50#define S7_FUNC_WRITE_VAR 0x05
51
52// Memory area codes (in an S7-ANY item).
53#define S7_AREA_INPUTS 0x81 ///< process inputs (I/E)
54#define S7_AREA_OUTPUTS 0x82 ///< process outputs (Q/A)
55#define S7_AREA_FLAGS 0x83 ///< flags / merker (M)
56#define S7_AREA_DB 0x84 ///< data blocks (DB)
57#define S7_AREA_COUNTER 0x1C
58#define S7_AREA_TIMER 0x1D
59
60// Request-item transport sizes (the element type).
61#define S7_TS_BIT 1
62#define S7_TS_BYTE 2
63#define S7_TS_CHAR 3
64#define S7_TS_WORD 4
65#define S7_TS_INT 5
66#define S7_TS_DWORD 6
67#define S7_TS_DINT 7
68#define S7_TS_REAL 8
69
70// Response data transport sizes (length-in-bits for BIT/BYTE/INT = 3/4/5).
71#define S7_DTS_NULL 0
72#define S7_DTS_BIT 3
73#define S7_DTS_BYTE 4
74#define S7_DTS_INT 5
75#define S7_DTS_DINT 6
76#define S7_DTS_REAL 7
77#define S7_DTS_OCTET 9
78
79#define S7_SYNTAX_S7ANY 0x10 ///< S7-ANY address syntax id
80#define S7_RET_OK 0xFF ///< data item return code: success
81
82/** @brief Build a Setup Communication job. Returns the PDU length, or 0 on overflow. */
83size_t s7_build_setup(uint8_t *buf, size_t cap, uint16_t pdu_ref, uint16_t max_amq_calling, uint16_t max_amq_called,
84 uint16_t pdu_size);
85
86/** @brief One Read Var item (an S7-ANY pointer). */
87struct S7ReadItem
88{
89 uint8_t area; ///< S7_AREA_*
90 uint16_t db_number; ///< DB number (0 for non-DB areas)
91 uint32_t byte_address; ///< starting byte address
92 uint8_t transport_size; ///< S7_TS_* (element type)
93 uint16_t count; ///< number of elements
94};
95
96/** @brief Build a Read Var job for @p n items. Returns the PDU length, or 0 on overflow. */
97size_t s7_build_read_request(uint8_t *buf, size_t cap, uint16_t pdu_ref, const S7ReadItem *items, size_t n);
98
99/** @brief A parsed S7comm header. @ref param / @ref data point INTO the source buffer. */
100struct S7Header
101{
102 uint8_t rosctr;
103 uint16_t pdu_ref;
104 uint16_t param_len;
105 uint16_t data_len;
106 uint8_t error_class; ///< Ack_Data only
107 uint8_t error_code; ///< Ack_Data only
108 size_t header_len; ///< 10 or 12
109 const uint8_t *param;
110 const uint8_t *data;
111};
112
113/** @brief Parse + validate an S7comm header (protocol id, lengths). */
114bool s7_parse_header(const uint8_t *buf, size_t len, S7Header *out);
115
116/** @brief One Read Var response data item. @ref data points INTO the source buffer. */
117struct S7DataItem
118{
119 uint8_t return_code; ///< S7_RET_OK on success
120 uint8_t transport_size; ///< S7_DTS_*
121 const uint8_t *data; ///< value bytes
122 size_t data_len; ///< value length in BYTES (the bit length is converted)
123};
124
125/**
126 * @brief Read the next Read Var response data item from the data section.
127 * @param data the @ref S7Header data pointer; @param data_len its data_len.
128 * @param offset in/out cursor, start at 0; advanced past the item (and its even-pad).
129 * @return true on a complete item; false at end-of-section or on truncation.
130 */
131bool s7_read_next_item(const uint8_t *data, size_t data_len, size_t *offset, S7DataItem *out);
132
133#endif // DETWS_ENABLE_S7COMM
134
135#endif // DETERMINISTICESPASYNCWEBSERVER_S7COMM_H
User-facing configuration for DeterministicESPAsyncWebServer.