GCC Code Coverage Report


Directory: ./
File: ecapp/Factory.h
Date: 2026-09-03 16:05:57
Exec Total Coverage
Lines: 3 3 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * This file is part of the ecapp library (EtherCAT application devices).
4 *
5 * Copyright (C) 2026 Florian Pose <fp@igh.de>
6 *
7 * The ecapp library is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation, version 3 of the
10 * License.
11 *
12 * The ecapp library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with the ecapp library. If not, see
19 * <https://www.gnu.org/licenses/>.
20 *
21 ****************************************************************************/
22
23 #ifndef ECAPP_FACTORY_H
24 #define ECAPP_FACTORY_H
25
26 /****************************************************************************/
27
28 #include "ecapp/Mode.h"
29 #include "ecapp/SubDevice.h"
30 #include "ecapp_export.h"
31
32 #include <cstdint>
33 #include <functional>
34 #include <memory>
35 #include <string>
36 #include <vector>
37
38 /****************************************************************************/
39
40 struct pdserv;
41 struct pdtask;
42
43 namespace EcApp {
44
45 class Master;
46 class Domain;
47
48 /** Any revision matches when looked up by vendor/product code without an
49 * explicit revision. */
50 constexpr uint32_t AnyRevision = 0xffffffffU;
51
52 /** A device family's registered factory takes every construction
53 * parameter directly -- the same convention as createSubDevice()
54 * itself (see below) -- rather than a bundling struct, so nothing
55 * like that ever needs to appear in this public header. pdserv and
56 * task may be null if the caller doesn't want the device to register
57 * signals/parameters itself. */
58 using FactoryFn = std::function<std::unique_ptr<SubDevice>(
59 Master *master,
60 Domain *domainOut,
61 Domain *domainIn,
62 uint16_t alias,
63 uint16_t position,
64 Mode mode,
65 const std::string &prefix,
66 pdserv *pdServ,
67 pdtask *task)>;
68
69 2136 struct DeviceDescriptor
70 {
71 std::string name; // e.g. "EL2032"
72 std::string sourceFile; // __FILE__ of the registering translation
73 // unit, e.g. for a "see the source" link
74 uint32_t vendorId;
75 uint32_t productCode;
76 uint32_t revision; // AnyRevision to match any
77 FactoryFn factory;
78 };
79
80 /****************************************************************************/
81
82 /** Process-wide table of known device types, populated by each device
83 * family's translation unit at static-init time via Registrar/
84 * ECAPP_REGISTER_DEVICE below. Callers never touch this directly --
85 * use createSubDevice(). */
86 8 class ECAPP_EXPORT Registry
87 {
88 public:
89 static Registry &instance();
90
91 void add(DeviceDescriptor);
92
93 const DeviceDescriptor &find(const std::string &name) const;
94 const DeviceDescriptor &
95 find(uint32_t vendorId,
96 uint32_t productCode,
97 uint32_t revision = AnyRevision) const;
98
99 /** Every registered device, in registration order. For
100 * introspection (e.g. generating a list of supported devices) --
101 * createSubDevice()/find() remain the way to actually instantiate
102 * one. */
103 const std::vector<DeviceDescriptor> &all() const;
104
105 private:
106 8 Registry() = default;
107 std::vector<DeviceDescriptor> descriptors;
108 };
109
110 /** Registers one DeviceDescriptor as a static-init side effect; see
111 * ECAPP_REGISTER_DEVICE. */
112 struct Registrar
113 {
114 explicit Registrar(DeviceDescriptor d)
115 {
116 Registry::instance().add(std::move(d));
117 }
118 };
119
120 /****************************************************************************/
121
122 /** Usable as a single expression, e.g. in a constructor's
123 * member-initializer list -- every construction parameter is a
124 * direct argument, not a bundling struct. */
125 ECAPP_EXPORT std::unique_ptr<SubDevice> createSubDevice(
126 const std::string &name,
127 Master *master,
128 Domain *domainOut,
129 Domain *domainIn,
130 uint16_t alias,
131 uint16_t position,
132 Mode mode,
133 const std::string &prefix,
134 pdserv *pdServ = nullptr,
135 pdtask *task = nullptr);
136
137 ECAPP_EXPORT std::unique_ptr<SubDevice> createSubDevice(
138 uint32_t vendorId,
139 uint32_t productCode,
140 Master *master,
141 Domain *domainOut,
142 Domain *domainIn,
143 uint16_t alias,
144 uint16_t position,
145 Mode mode,
146 const std::string &prefix,
147 pdserv *pdServ = nullptr,
148 pdtask *task = nullptr,
149 uint32_t revision = AnyRevision);
150
151 } // namespace EcApp
152
153 /****************************************************************************/
154
155 #define ECAPP_CONCAT_(a, b) a##b
156 #define ECAPP_CONCAT(a, b) ECAPP_CONCAT_(a, b)
157
158 /** Place at namespace scope in a device family's .cpp to make it
159 * discoverable via createSubDevice(), without the caller needing to know
160 * which family class implements it. */
161 #define ECAPP_REGISTER_DEVICE(...) \
162 static const ::EcApp::Registrar ECAPP_CONCAT(ecappRegistrar_, __LINE__)( \
163 __VA_ARGS__)
164
165 #endif // ECAPP_FACTORY_H
166
167 /****************************************************************************/
168