DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
dmx.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 dmx.h
6 * @brief DMX512 framing + RDM (ANSI E1.20) management codec (DETWS_ENABLE_DMX).
7 *
8 * DMX512 (lighting / stage control over RS-485) is positional: after a break, a start code
9 * octet (0x00 for dimmer data) is followed by up to 512 channel slots, with no checksum or
10 * in-frame addressing. This codec assembles / reads that slot array, and implements **RDM**
11 * (Remote Device Management, ANSI E1.20) - the addressed management layer that shares the
12 * DMX wire: a real packet with 48-bit source / destination UIDs, a command class + parameter
13 * id, and a 16-bit additive checksum.
14 *
15 * The break + RS-485 direction are the application's (a `MAX485`-class transceiver on a UART
16 * at 250 kbit/s, 8N2). This is the byte-level framing layer. Pure and host-tested. Bridge a
17 * lighting rig onto Wi-Fi: drive DMX slots or discover / configure RDM fixtures from the web.
18 *
19 * @author Douglas Quigg (dstroy0)
20 * @date 2026
21 */
22
23#ifndef DETERMINISTICESPASYNCWEBSERVER_DMX_H
24#define DETERMINISTICESPASYNCWEBSERVER_DMX_H
25
26#include "ServerConfig.h"
27
28#if DETWS_ENABLE_DMX
29
30#include <stddef.h>
31#include <stdint.h>
32
33#define DMX_MAX_CHANNELS 512u ///< slots per DMX512 universe
34#define DMX_SC_DIMMER 0x00u ///< start code for standard dimmer data
35
36#define RDM_SC 0xCCu ///< RDM start code (SC_RDM)
37#define RDM_SUB_SC 0x01u ///< RDM sub-start code (SC_SUB_MESSAGE)
38#define RDM_OVERHEAD 26u ///< full packet octets with PDL 0 (24-octet message + 2 checksum)
39
40// RDM command classes.
41#define RDM_CC_DISCOVERY 0x10u
42#define RDM_CC_DISCOVERY_RESPONSE 0x11u
43#define RDM_CC_GET 0x20u
44#define RDM_CC_GET_RESPONSE 0x21u
45#define RDM_CC_SET 0x30u
46#define RDM_CC_SET_RESPONSE 0x31u
47
48// RDM response types (carried in the port-id / response-type octet of a response).
49#define RDM_RESPONSE_ACK 0x00u
50#define RDM_RESPONSE_ACK_TIMER 0x01u
51#define RDM_RESPONSE_NACK_REASON 0x02u
52#define RDM_RESPONSE_ACK_OVERFLOW 0x03u
53
54// A few common RDM parameter ids (PIDs).
55#define RDM_PID_DISC_UNIQUE_BRANCH 0x0001u
56#define RDM_PID_DISC_MUTE 0x0002u
57#define RDM_PID_DISC_UN_MUTE 0x0003u
58#define RDM_PID_SUPPORTED_PARAMETERS 0x0050u
59#define RDM_PID_DEVICE_INFO 0x0060u
60#define RDM_PID_DMX_START_ADDRESS 0x00F0u
61#define RDM_PID_IDENTIFY_DEVICE 0x1000u
62
63// --- DMX512 ---
64
65/**
66 * @brief Assemble a DMX512 packet body: [start code][channel slots]. @p n <= 512.
67 * Returns the byte count (1 + n) or 0 on overflow. The break is the transport's job.
68 */
69size_t dmx_build(uint8_t *buf, size_t cap, uint8_t start_code, const uint8_t *channels, uint16_t n);
70
71/**
72 * @brief Read channel @p ch (1-based, per DMX convention) from a received packet body.
73 * Returns the slot value, or 0 if @p ch is out of range / not present.
74 */
75uint8_t dmx_get_channel(const uint8_t *buf, size_t len, uint16_t ch);
76
77// --- RDM (ANSI E1.20) ---
78
79/** @brief A parsed / to-be-built RDM packet. UIDs are 48-bit (manufacturer<<32 | device). */
80struct RdmPacket
81{
82 uint64_t dest_uid;
83 uint64_t src_uid;
84 uint8_t tn; ///< transaction number
85 uint8_t port_id; ///< port id (request) / response type (response)
86 uint8_t msg_count; ///< queued message count
87 uint16_t sub_device; ///< sub-device (0 = root)
88 uint8_t cc; ///< command class (RDM_CC_*)
89 uint16_t pid; ///< parameter id
90 uint8_t pdl; ///< parameter data length
91 const uint8_t *pdata; ///< parameter data (points into the parsed buffer); nullptr when pdl 0
92};
93
94/** @brief Compose a 48-bit RDM UID from a manufacturer id and a device id. */
95uint64_t rdm_uid(uint16_t manufacturer, uint32_t device);
96
97/** @brief 16-bit additive checksum over @p len octets (RDM message block). */
98uint16_t rdm_checksum(const uint8_t *buf, size_t len);
99
100/**
101 * @brief Build a full RDM packet (incl. the trailing 16-bit checksum) from @p p and its
102 * parameter data. Returns the total length (26 + pdl) or 0 on overflow.
103 */
104size_t rdm_build(uint8_t *buf, size_t cap, const RdmPacket *p, const uint8_t *pdata, uint8_t pdl);
105
106/**
107 * @brief Parse an RDM packet: validates the start codes, the message length vs PDL, and the
108 * checksum. Fills @p out and @p consumed (the whole packet length).
109 */
110bool rdm_parse(const uint8_t *buf, size_t len, RdmPacket *out, size_t *consumed);
111
112#endif // DETWS_ENABLE_DMX
113#endif // DETERMINISTICESPASYNCWEBSERVER_DMX_H
User-facing configuration for DeterministicESPAsyncWebServer.