DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
umati.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 umati.h
6 * @brief umati - OPC UA for Machine Tools (OPC 40501-1) information model (DETWS_ENABLE_UMATI).
7 *
8 * umati ("universal machine technology interface") is the OPC UA companion specification for machine
9 * tools (VDW / OPC Foundation, OPC 40501-1, namespace `http://opcfoundation.org/UA/MachineTool/`). It
10 * standardises how a machine tool exposes its identity and live state so any umati / OPC UA client (the
11 * umati dashboard, UaExpert, python `asyncua`, ...) reads the same structure across vendors.
12 *
13 * This module builds the MachineTool address space on top of the OPC UA Binary server
14 * (`services/opcua`, DETWS_ENABLE_OPCUA): it registers a Browse + Read resolver that answers for the
15 * MachineTool node hierarchy and serves live values out of a caller-owned @ref UmatiMachineTool struct
16 * you refresh in your loop. No heap, no stdlib - the model is a fixed node table, the values are
17 * pointers/scalars in your struct.
18 *
19 * Model exposed (BrowseNames per OPC 40501-1), under the Objects folder:
20 *
21 * MachineTool
22 * Identification Manufacturer, Model, SerialNumber, YearOfConstruction, SoftwareRevision,
23 * ProductInstanceUri
24 * Monitoring
25 * MachineTool OperationMode, PowerOnDuration
26 * Channel ChannelState, FeedOverride, RapidOverride, ActiveProgram
27 * Spindle RotationSpeed, OverrideValue, IsRotating
28 * Axis_X/Y/Z ActualPosition
29 * Production ActiveProgram, ProducedPartCount
30 * Notification ActiveMessage, Severity
31 *
32 * The model is read-only (a monitoring model - the machine reports, the client observes). Scope note:
33 * a single Channel/Spindle and three linear axes are exposed (the common embedded machine); the values
34 * carry faithful BrowseNames, but the companion-spec TypeDefinitions and the NamespaceArray entry for
35 * the MachineTool URI (which needs array-Variant support in the base server) are a documented follow-on
36 * - a generic OPC UA client still browses the structure and reads every value by BrowseName today.
37 *
38 * @author Douglas Quigg (dstroy0)
39 * @date 2026
40 */
41
42#ifndef DETERMINISTICESPASYNCWEBSERVER_UMATI_H
43#define DETERMINISTICESPASYNCWEBSERVER_UMATI_H
44
45#include "ServerConfig.h"
46
47#if DETWS_ENABLE_UMATI
48
49#include "services/opcua/opcua.h" // OpcUaVariant / OpcUaReference / handler typedefs (shares the OPC UA codec)
50#include <stdint.h>
51
52/** @brief The OPC UA for Machine Tools companion-spec namespace URI (OPC 40501-1). */
53#define UMATI_NS_URI "http://opcfoundation.org/UA/MachineTool/"
54
55/**
56 * @brief MachineTool OperationMode (OPC 40501-1 MachineOperationMode). Exposed as Int32; the numeric
57 * values follow the companion-spec enumeration. The machine reports its current mode.
58 */
59enum class UmatiOperationMode : int32_t
60{
61 UMATI_OP_OTHER = 0, ///< a mode outside the ones below.
62 UMATI_OP_MANUAL = 1, ///< hand / jog operation.
63 UMATI_OP_MDA = 2, ///< manual data automatic (single-block MDI).
64 UMATI_OP_AUTOMATIC = 3, ///< running a stored program automatically.
65 UMATI_OP_SETUP = 4, ///< set-up / preparation.
66};
67
68/**
69 * @brief Channel state (OPC 40501-1 ChannelState). Exposed as Int32; the numeric values follow the
70 * companion-spec enumeration.
71 */
72enum class UmatiChannelState : int32_t
73{
74 UMATI_CH_INTERRUPTED = 0, ///< program interrupted / feed hold.
75 UMATI_CH_RESET = 1, ///< channel reset (no program active).
76 UMATI_CH_RUNNING = 2, ///< a program is executing.
77 UMATI_CH_WAITING = 3, ///< waiting (e.g. for a synchronisation / dwell).
78};
79
80/** @brief MachineTool identification (OPC 40501-1 Identification, subtype of Machinery MachineIdentification). */
81struct UmatiIdentification
82{
83 const char *manufacturer; ///< Manufacturer (LocalizedText -> String).
84 const char *model; ///< Model (LocalizedText -> String).
85 const char *serial_number; ///< SerialNumber (String).
86 const char *software_revision; ///< SoftwareRevision (String).
87 const char *product_instance_uri; ///< ProductInstanceUri (String) - the unique instance URI.
88 uint16_t year_of_construction; ///< YearOfConstruction (UInt16, exposed as UInt32).
89};
90
91/** @brief One Channel's live monitoring values (OPC 40501-1 ChannelType, common subset). */
92struct UmatiChannel
93{
94 UmatiChannelState state; ///< ChannelState.
95 double feed_override; ///< FeedOverride (%).
96 double rapid_override; ///< RapidOverride (%).
97 const char *active_program; ///< ActiveProgram.Name (the running NC program).
98};
99
100/** @brief One Spindle's live monitoring values (OPC 40501-1 SpindleType, common subset). */
101struct UmatiSpindle
102{
103 double rotation_speed; ///< RotationSpeed (rpm).
104 double override_value; ///< OverrideValue (%).
105 bool is_rotating; ///< IsRotating.
106};
107
108/** @brief One linear Axis' live monitoring value (OPC 40501-1 LinearAxisType, common subset). */
109struct UmatiAxis
110{
111 double actual_position; ///< ActualPosition (mm).
112};
113
114/**
115 * @brief The whole MachineTool the server exposes. Own it in your sketch and refresh its fields each
116 * loop from your machine I/O; the umati resolvers read straight out of it (no copy). String
117 * fields may be null (served as an empty String).
118 */
119struct UmatiMachineTool
120{
121 const char *name; ///< MachineTool BrowseName / DisplayName (the machine's name).
122 UmatiIdentification ident; ///< Identification.
123 UmatiOperationMode operation_mode; ///< Monitoring.MachineTool.OperationMode.
124 double power_on_duration_s; ///< Monitoring.MachineTool.PowerOnDuration (seconds).
125 UmatiChannel channel; ///< Monitoring.Channel.
126 UmatiSpindle spindle; ///< Monitoring.Spindle.
127 UmatiAxis axis_x; ///< Monitoring.Axis_X.
128 UmatiAxis axis_y; ///< Monitoring.Axis_Y.
129 UmatiAxis axis_z; ///< Monitoring.Axis_Z.
130 const char *active_program; ///< Production.ActiveProgram.Name.
131 uint32_t produced_part_count; ///< Production.ProducedPartCount.
132 const char *message_text; ///< Notification.ActiveMessage (most-recent active message text).
133 uint32_t message_severity; ///< Notification.Severity (0..1000, OPC UA event severity scale).
134};
135
136/**
137 * @brief Bind the MachineTool the resolvers serve. @p mt must outlive the server (own it statically).
138 * Refresh its fields any time; each Read returns the current values.
139 */
140void umati_bind(const UmatiMachineTool *mt);
141
142/**
143 * @brief Read resolver for the MachineTool model (an @ref OpcUaReadHandler): fills @p out for a umati
144 * node's Value attribute. Returns false for a node outside the model (the server answers
145 * BadNodeIdUnknown). Install with `opcua_set_read_handler(umati_read)`.
146 */
147bool umati_read(uint16_t ns, uint32_t id, uint32_t attribute, OpcUaVariant *out);
148
149/**
150 * @brief Browse resolver for the MachineTool model (an @ref OpcUaBrowseHandler): writes the child
151 * references of a umati node (and of the Objects folder, which organizes the MachineTool) into
152 * @p out. Returns the count, or -1 for a node outside the model. Install with
153 * `opcua_set_browse_handler(umati_browse)`.
154 */
155int32_t umati_browse(uint16_t ns, uint32_t id, OpcUaReference *out, uint32_t max);
156
157/**
158 * @brief Convenience: bind @p mt and register both resolvers on the OPC UA server in one call
159 * (`opcua_set_read_handler` + `opcua_set_browse_handler`). Call before `server.begin()`.
160 */
161void umati_install(const UmatiMachineTool *mt);
162
163#endif // DETWS_ENABLE_UMATI
164#endif // DETERMINISTICESPASYNCWEBSERVER_UMATI_H
User-facing configuration for DeterministicESPAsyncWebServer.
OPC UA Binary server: handshake + SecureChannel + Session + Read/Write + Browse (DETWS_ENABLE_OPCUA).