ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
euromap77.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file euromap77.h
6 * @brief EUROMAP 77 / OPC 40077 - OPC UA for injection moulding machines (IMM <-> MES), the
7 * IMM_MES_Interface information model (PROTOCORE_ENABLE_EUROMAP77).
8 *
9 * EUROMAP 77 (published as OPC 40077, ModelUri `http://opcfoundation.org/UA/PlasticsRubber/IMM2MES/`)
10 * standardizes how an injection molding machine (IMM) reports its identity, status, and the active job's
11 * live production counters to a MES, so any OPC UA client reads the same structure across machine vendors.
12 * It builds on EUROMAP 83 (OPC 40083, ModelUri
13 * `http://opcfoundation.org/UA/PlasticsRubber/GeneralTypes/`), the shared plastics/rubber type + enum
14 * library (MachineModeEnumeration, JobStatusEnumeration, ...).
15 *
16 * This module builds the IMM_MES_Interface address space on top of the OPC UA Binary server
17 * (`services/opcua`, PROTOCORE_ENABLE_OPCUA): it registers a Browse + Read resolver that answers for the
18 * IMM_MES_Interface node hierarchy and serves live values out of a caller-owned @ref EmImm struct you
19 * refresh in your loop. Same pattern as `services/umati` / `services/robotics`; no heap, no stdlib - the
20 * model is a fixed node table, the values are pointers/scalars in your struct.
21 *
22 * Model exposed (BrowseNames per the EUROMAP 77 NodeSet), under the Objects folder:
23 *
24 * IMM_MES_Interface
25 * MachineInformation Manufacturer, Model, SerialNumber, ProductCode, HardwareRevision,
26 * SoftwareRevision, DeviceRevision, ManufacturerUri
27 * MachineStatus IsPresent, MachineMode
28 * Jobs
29 * ActiveJob JobName, JobDescription, Material, ProductName, MouldId, ExpectedCycleTime,
30 * NumCavities, NominalParts
31 * ActiveJobValues JobCycleCounter, MachineCycleCounter, LastCycleTime, AverageCycleTime,
32 * JobPartsCounter, JobGoodPartsCounter, JobBadPartsCounter, JobStatus
33 *
34 * The production counters are faithful UInt64 (EUROMAP 77 defines them 64-bit), served through the OPC UA
35 * Variant's UInt64 encoding. The model is read-only (a monitoring model - the machine reports, the MES
36 * observes). Scope note: one IMM with its active job is exposed (the common single-machine MES feed); the
37 * companion-spec TypeDefinitions, methods, file/dataset transfer, and the multi-cardinality arrays
38 * (InjectionUnits, Moulds, MachineConfiguration detail) are a documented follow-on - a generic OPC UA
39 * client still browses the structure and reads every value by BrowseName today.
40 *
41 * Like umati / robotics, this installs the single OPC UA read + browse handler, so one companion model is
42 * active per server build (EUROMAP 77, umati, and robotics are mutually exclusive per OPC UA endpoint).
43 *
44 * @author Douglas Quigg (dstroy0)
45 * @date 2026
46 */
47
48#ifndef PROTOCORE_EUROMAP77_H
49#define PROTOCORE_EUROMAP77_H
50
51#include "protocore_config.h" // the entry point: protocore_types.h for the widths
52
53#if PROTOCORE_ENABLE_EUROMAP77
54
56
57// PROTOCORE_EUROMAP77_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
58// it into its arena. A caller takes them once and passes the pointer to every call. How they
59// are carved is this module's and is never named here.
60
61/** @brief The IMM2MES namespace URI: the ModelUri Opc.Ua.PlasticsRubber.IMM2MES.NodeSet2.xml publishes. */
62#define EUROMAP77_NS_URI "http://opcfoundation.org/UA/PlasticsRubber/IMM2MES/"
63
64/** @brief The GeneralTypes namespace URI: the ModelUri Opc.Ua.PlasticsRubber.GeneralTypes.NodeSet2.xml publishes. */
65#define EUROMAP83_NS_URI "http://opcfoundation.org/UA/PlasticsRubber/GeneralTypes/"
66
67/**
68 * @brief Machine mode (EUROMAP 83 MachineModeEnumeration, em83 i=3011). Exposed as Int32; the numeric
69 * values are the companion-spec enumeration.
70 */
71typedef enum PROTO_ENUM_PACKED
72{
73 EM_MODE_OTHER = 0, ///< a mode outside the ones below.
74 EM_MODE_AUTOMATIC = 1, ///< automatic production.
75 EM_MODE_SEMI_AUTOMATIC = 2, ///< semi-automatic (operator-triggered cycles).
76 EM_MODE_MANUAL = 3, ///< manual / hand operation.
77 EM_MODE_SETUP = 4, ///< set-up / preparation.
78 EM_MODE_SLEEP = 5, ///< energy-saving sleep.
79} EmMachineMode;
80
81/**
82 * @brief Active-job status (EUROMAP 83 JobStatusEnumeration, em83 i=3017). Exposed as Int32; the numeric
83 * values are the companion-spec enumeration.
84 */
85typedef enum PROTO_ENUM_PACKED
86{
87 EM_JOB_OTHER = 0, ///< a status outside the ones below.
88 EM_JOB_TRANSFERRED_ASSIGNED = 1, ///< transferred / assigned to the machine.
89 EM_JOB_SET_UP_ACTIVE = 2, ///< set-up in progress.
90 EM_JOB_SET_UP_INTERRUPTED = 3, ///< set-up interrupted.
91 EM_JOB_SET_UP_FINISHED = 4, ///< set-up finished.
92 EM_JOB_START_UP_ACTIVE = 5, ///< start-up in progress.
93 EM_JOB_IN_PRODUCTION = 6, ///< running production.
94 EM_JOB_INTERRUPTED = 7, ///< production interrupted.
95 EM_JOB_FINISHED = 8, ///< job finished.
96 EM_JOB_TEAR_DOWN_ACTIVE = 9, ///< tear-down in progress.
97 EM_JOB_TEAR_DOWN_INTERRUPTED = 10, ///< tear-down interrupted.
98 EM_JOB_TEAR_DOWN_FINISHED = 11, ///< tear-down finished.
99} EmJobStatus;
100
101/** @brief IMM identity (EUROMAP 77 MachineInformation, common subset; all String). */
102typedef struct
103{
104 const char *manufacturer; ///< Manufacturer.
105 const char *model; ///< Model.
106 const char *serial_number; ///< SerialNumber.
107 const char *product_code; ///< ProductCode.
108 const char *hardware_revision; ///< HardwareRevision.
109 const char *software_revision; ///< SoftwareRevision.
110 const char *device_revision; ///< DeviceRevision.
111 const char *manufacturer_uri; ///< ManufacturerUri.
112} EmMachineInformation;
113
114/** @brief IMM live status (EUROMAP 77 MachineStatus, common subset). */
115typedef struct
116{
117 proto_bool is_present; ///< IsPresent.
118 EmMachineMode machine_mode; ///< MachineMode.
119} EmMachineStatus;
120
121/** @brief The active job's static parameters (EUROMAP 77 Jobs.ActiveJob, common subset). */
122typedef struct
123{
124 const char *job_name; ///< JobName.
125 const char *job_description; ///< JobDescription.
126 const char *material; ///< Material.
127 const char *product_name; ///< ProductName.
128 const char *mould_id; ///< MouldId.
129 double expected_cycle_time; ///< ExpectedCycleTime (Duration, seconds -> Double).
130 uint32_t num_cavities; ///< NumCavities.
131 uint64_t nominal_parts; ///< NominalParts.
132} EmActiveJob;
133
134/** @brief The active job's live production counters (EUROMAP 77 Jobs.ActiveJobValues; counters UInt64). */
135typedef struct
136{
137 uint64_t job_cycle_counter; ///< JobCycleCounter.
138 uint64_t machine_cycle_counter; ///< MachineCycleCounter.
139 double last_cycle_time; ///< LastCycleTime (Duration -> Double).
140 double average_cycle_time; ///< AverageCycleTime (Duration -> Double).
141 uint64_t job_parts_counter; ///< JobPartsCounter.
142 uint64_t job_good_parts_counter; ///< JobGoodPartsCounter.
143 uint64_t job_bad_parts_counter; ///< JobBadPartsCounter.
144 EmJobStatus job_status; ///< JobStatus.
145} EmActiveJobValues;
146
147/**
148 * @brief The whole IMM_MES_Interface the server exposes. Own it in your sketch and refresh its fields
149 * each loop from your machine I/O; the resolvers read straight out of it (no copy). String fields
150 * may be null (served as an empty String).
151 */
152typedef struct
153{
154 const char *name; ///< IMM_MES_Interface BrowseName / DisplayName.
155 EmMachineInformation info; ///< MachineInformation.
156 EmMachineStatus status; ///< MachineStatus.
157 EmActiveJob active_job; ///< Jobs.ActiveJob.
158 EmActiveJobValues active_job_values; ///< Jobs.ActiveJobValues.
159} EmImm;
160
161/** @brief What bind takes: imm. */
162typedef struct
163{
164 const EmImm *imm;
165} Euromap77BindArgs;
166
167/** @brief What install takes: imm. */
168typedef struct
169{
170 const EmImm *imm;
171} Euromap77InstallArgs;
172
173/**
174 * @brief EUROMAP 77 / OPC 40077 - OPC UA for injection moulding machines (IMM <-> MES), the IMM_MES_Interface
175 * information model (PROTOCORE_ENABLE_EUROMAP77).
176 *
177 * A caller sets the members a call takes, invokes it through ::Euromap77 with the bytes it runs
178 * out of, and reads the outcome off the same handle.
179 *
180 * Euromap77.bind_args.imm = ...;
181 * Euromap77.bind(work);
182 *
183 * @var Euromap77Ns::bind_args what bind takes: imm
184 * @var Euromap77Ns::install_args what install takes: imm
185 * @var Euromap77Ns::ok a call's true/false outcome
186 * @var Euromap77Ns::ns the NamespaceIndex the server gave EUROMAP77_NS_URI, once a bind has run
187 * @var Euromap77Ns::bind bind the IMM the resolvers serve. imm must outlive the server (own ...
188 * @var Euromap77Ns::install bind imm and hand the model's Read and Browse resolvers to the OPC ...
189 *
190 * @c work is PROTOCORE_EUROMAP77_BORROW bytes the CALLER took, at an address it knows. It is not held past the call, so
191 * nothing here aliases it. How those bytes are carved is this module's and is never named here.
192 */
193typedef struct
194{
195 Euromap77BindArgs bind_args;
196 Euromap77InstallArgs install_args;
197 proto_bool ok;
198 uint16_t ns;
199} Euromap77Vars;
200
201/** @brief The operands and the outcome. */
202extern Euromap77Vars Euromap77V;
203
204/** @brief The entries. */
205typedef struct
206{
207 void (*const bind)(uint8_t *work);
208 void (*const install)(uint8_t *work);
209} Euromap77Ns;
210
211// What the table binds, defined once in the .c and taking one parameter each: everything
212// else an entry needs is an operand in Euromap77V or a region of the borrow at a fixed offset.
213void protocore_euromap77_bind(uint8_t *work);
214void protocore_euromap77_install(uint8_t *work);
215
216// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
217// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
218// `Euromap77.bind(work)` resolves to a named function and becomes a DIRECT call. An extern table
219// leaves the call indirect and the symbol live at every level, -O2 -flto included.
220static const Euromap77Ns Euromap77 __attribute__((unused)) = {
221 .bind = protocore_euromap77_bind,
222 .install = protocore_euromap77_install,
223};
224
225/**
226 * @brief The PROTOCORE_EUROMAP77_BORROW bytes this module's state lives in.
227 *
228 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
229 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
230 * walks, so the state lasts the life of the program.
231 *
232 * @return the span.
233 */
234uint8_t *protocore_euromap77_span(void);
235
237
238#endif // PROTOCORE_ENABLE_EUROMAP77
239
240#endif // PROTOCORE_EUROMAP77_H
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97