DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
directnet.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 directnet.h
6 * @brief AutomationDirect / Koyo DirectNET serial frame codec (DETWS_ENABLE_DIRECTNET).
7 *
8 * DirectNET is the AutomationDirect (Koyo) DirectLOGIC-PLC master-slave serial protocol for reading and
9 * writing V-memory. A transaction is a control-char-delimited frame with an LRC checksum. This builds
10 * the two framed messages the master sends:
11 *
12 * - **Header/enquiry**: `SOH [slave-hex][type][addr-hex 4][blocks-hex 2] ETB [LRC]` - the request that
13 * announces a read/write of N data blocks at a V-memory address.
14 * - **Data frame**: `STX [data...] ETX [LRC]` - the payload block.
15 *
16 * The LRC is the longitudinal XOR of the framed bytes (between the start control char and the LRC,
17 * inclusive of the terminating ETB/ETX). This provides the framing + LRC + the ASCII-hex field helpers;
18 * the UART transport + the ACK/NAK handshake sequencing are the device step. Pure, zero heap,
19 * host-testable.
20 */
21
22#ifndef DETERMINISTICESPASYNCWEBSERVER_DIRECTNET_H
23#define DETERMINISTICESPASYNCWEBSERVER_DIRECTNET_H
24
25#include "ServerConfig.h"
26#include <stddef.h>
27#include <stdint.h>
28
29#if DETWS_ENABLE_DIRECTNET
30
31/** @brief DirectNET control bytes: wire values compared/emitted, so integer constants in a struct. */
32struct DnetByte
33{
34 static constexpr uint8_t DNET_ENQ = 0x05;
35 static constexpr uint8_t DNET_ACK = 0x06;
36 static constexpr uint8_t DNET_NAK = 0x15;
37 static constexpr uint8_t DNET_SOH = 0x01;
38 static constexpr uint8_t DNET_STX = 0x02;
39 static constexpr uint8_t DNET_ETX = 0x03;
40 static constexpr uint8_t DNET_ETB = 0x17;
41 static constexpr uint8_t DNET_EOT = 0x04;
42 static constexpr uint8_t DNET_READ = 0x30; ///< request type: read ('0').
43 static constexpr uint8_t DNET_WRITE = 0x38; ///< request type: write ('8').
44};
45
46/** @brief Longitudinal XOR checksum (the DirectNET LRC) over @p len bytes. */
47uint8_t detws_dnet_lrc(const uint8_t *bytes, size_t len);
48
49/**
50 * @brief Build a DirectNET header frame: SOH + [slave][type][addr:4hex][blocks:2hex] + ETB + LRC.
51 * @param slave station number 0..99 (emitted as two ASCII-hex digits).
52 * @param type DNET_READ or DNET_WRITE.
53 * @param address V-memory octal address, emitted as 4 ASCII-hex digits.
54 * @param blocks number of data blocks, emitted as 2 ASCII-hex digits.
55 * @return the frame length, or 0 on overflow. The LRC covers slave..ETB.
56 */
57size_t detws_dnet_header(uint8_t slave, uint8_t type, uint16_t address, uint8_t blocks, uint8_t *out, size_t cap);
58
59/**
60 * @brief Build a DirectNET data frame: STX + data + ETX + LRC. The LRC covers data..ETX.
61 * @return the frame length (1 + data_len + 1 + 1), or 0 on overflow.
62 */
63size_t detws_dnet_data(const uint8_t *data, size_t data_len, uint8_t *out, size_t cap);
64
65/**
66 * @brief Validate a DirectNET data frame (STX..ETX + LRC) and expose its payload.
67 * @return true if it is well-formed and the LRC matches; sets @p data / @p data_len (pointers into @p frame).
68 */
69bool detws_dnet_data_parse(const uint8_t *frame, size_t len, const uint8_t **data, size_t *data_len);
70
71#endif // DETWS_ENABLE_DIRECTNET
72#endif // DETERMINISTICESPASYNCWEBSERVER_DIRECTNET_H
User-facing configuration for DeterministicESPAsyncWebServer.