GCC Code Coverage Report


Directory: ./
File: src/devices/Ex20xx.cpp
Date: 2026-09-03 16:05:57
Exec Total Coverage
Lines: 75 129 58.1%
Branches: 46 366 12.6%

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 #include "devices/Ex20xx.h"
24
25 #include "SlaveContext.h"
26 #include "ecapp/Domain.h"
27 #include "ecapp/Factory.h"
28 #include "ecapp/Master.h"
29 #include "ecapp/SwappedSync.h"
30
31 #include <memory>
32 #include <sstream>
33 #include <stdexcept>
34
35 /****************************************************************************/
36
37 using std::make_unique;
38 using std::runtime_error;
39 using std::size_t;
40 using std::stringstream;
41 using std::unique_ptr;
42
43 namespace EcApp {
44
45 /* Master 0, Slave 4, "EL2004"
46 * Vendor ID: 0x00000002
47 * Product code: 0x07d43052
48 * Revision number: 0x00000000
49 */
50
51 ec_pdo_entry_info_t el2004_pdo_entries[] = {
52 {0x3001, 0x01, 1}, /* Output */
53 {0x3001, 0x02, 1}, /* Output */
54 {0x3001, 0x03, 1}, /* Output */
55 {0x3001, 0x04, 1}, /* Output */
56 };
57
58 ec_pdo_info_t el2004_pdos[] = {
59 {0x1600, 1, el2004_pdo_entries + 0}, /* Channel 1 */
60 {0x1601, 1, el2004_pdo_entries + 1}, /* Channel 2 */
61 {0x1602, 1, el2004_pdo_entries + 2}, /* Channel 3 */
62 {0x1603, 1, el2004_pdo_entries + 3}, /* Channel 4 */
63 };
64
65 ec_sync_info_t el2004_syncs[] = {
66 {0, EC_DIR_OUTPUT, 4, el2004_pdos + 0, EC_WD_ENABLE},
67 {0xff}};
68
69 /* Master 0, Slave 17, "EL2024"
70 * Vendor ID: 0x00000002
71 * Product code: 0x07e83052
72 * Revision number: 0x00130000
73 */
74
75 ec_pdo_entry_info_t el2024_pdo_entries[] = {
76 {0x7000, 0x01, 1}, /* Output */
77 {0x7010, 0x01, 1}, /* Output */
78 {0x7020, 0x01, 1}, /* Output */
79 {0x7030, 0x01, 1}, /* Output */
80 };
81
82 ec_pdo_info_t el2024_pdos[] = {
83 {0x1600, 1, el2024_pdo_entries + 0}, /* Channel 1 */
84 {0x1601, 1, el2024_pdo_entries + 1}, /* Channel 2 */
85 {0x1602, 1, el2024_pdo_entries + 2}, /* Channel 3 */
86 {0x1603, 1, el2024_pdo_entries + 3}, /* Channel 4 */
87 };
88
89 ec_sync_info_t el2024_syncs[] = {
90 {0, EC_DIR_OUTPUT, 4, el2024_pdos + 0, EC_WD_ENABLE},
91 {0xff}};
92
93 /* Master 0, Slave 7, "EL2008"
94 * Vendor ID: 0x00000002
95 * Product code: 0x07d83052
96 * Revision number: 0x00120000
97 */
98
99 ec_pdo_entry_info_t el2008_pdo_entries[] = {
100 {0x7000, 0x01, 1}, /* Output */
101 {0x7010, 0x01, 1}, /* Output */
102 {0x7020, 0x01, 1}, /* Output */
103 {0x7030, 0x01, 1}, /* Output */
104 {0x7040, 0x01, 1}, /* Output */
105 {0x7050, 0x01, 1}, /* Output */
106 {0x7060, 0x01, 1}, /* Output */
107 {0x7070, 0x01, 1}, /* Output */
108 };
109
110 ec_pdo_info_t el2008_pdos[] = {
111 {0x1600, 1, el2008_pdo_entries + 0}, /* Channel 1 */
112 {0x1601, 1, el2008_pdo_entries + 1}, /* Channel 2 */
113 {0x1602, 1, el2008_pdo_entries + 2}, /* Channel 3 */
114 {0x1603, 1, el2008_pdo_entries + 3}, /* Channel 4 */
115 {0x1604, 1, el2008_pdo_entries + 4}, /* Channel 5 */
116 {0x1605, 1, el2008_pdo_entries + 5}, /* Channel 6 */
117 {0x1606, 1, el2008_pdo_entries + 6}, /* Channel 7 */
118 {0x1607, 1, el2008_pdo_entries + 7}, /* Channel 8 */
119 };
120
121 ec_sync_info_t el2008_syncs[] = {
122 {0, EC_DIR_OUTPUT, 8, el2008_pdos + 0, EC_WD_ENABLE},
123 {0xff}};
124
125 /* Master 0, Slave 8, "EL2034"
126 * Vendor ID: 0x00000002
127 * Product code: 0x07f23052
128 * Revision number: 0x00110000
129 */
130
131 ec_pdo_entry_info_t el2034_pdo_entries[] = {
132 {0x7000, 0x01, 1}, /* Output */
133 {0x7010, 0x01, 1}, /* Output */
134 {0x7020, 0x01, 1}, /* Output */
135 {0x7030, 0x01, 1}, /* Output */
136 {0x6000, 0x01, 1}, /* Diag */
137 {0x6010, 0x01, 1}, /* Diag */
138 {0x6020, 0x01, 1}, /* Diag */
139 {0x6030, 0x01, 1}, /* Diag */
140 };
141
142 ec_pdo_info_t el2034_pdos[] = {
143 {0x1600, 1, el2034_pdo_entries + 0}, /* Channel 1 */
144 {0x1601, 1, el2034_pdo_entries + 1}, /* Channel 2 */
145 {0x1602, 1, el2034_pdo_entries + 2}, /* Channel 3 */
146 {0x1603, 1, el2034_pdo_entries + 3}, /* Channel 4 */
147 {0x1a00, 1, el2034_pdo_entries + 4}, /* Diag 1 */
148 {0x1a01, 1, el2034_pdo_entries + 5}, /* Diag 2 */
149 {0x1a02, 1, el2034_pdo_entries + 6}, /* Diag 3 */
150 {0x1a03, 1, el2034_pdo_entries + 7}, /* Diag 4 */
151 };
152
153 ec_sync_info_t el2034_syncs[] = {
154 {0, EC_DIR_OUTPUT, 4, el2034_pdos + 0, EC_WD_ENABLE},
155 {1, EC_DIR_INPUT, 4, el2034_pdos + 4, EC_WD_DISABLE},
156 {0xff}};
157
158 /* Master 0, Slave 19, "EP2028-0032"
159 * Vendor ID: 0x00000002
160 * Product code: 0x07ec4052
161 * Revision number: 0x00120020
162 */
163
164 ec_pdo_entry_info_t ep2028_0032_pdo_entries[] = {
165 {0x7000, 0x01, 1}, /* Output */
166 {0x7010, 0x01, 1}, /* Output */
167 {0x7020, 0x01, 1}, /* Output */
168 {0x7030, 0x01, 1}, /* Output */
169 {0x7040, 0x01, 1}, /* Output */
170 {0x7050, 0x01, 1}, /* Output */
171 {0x7060, 0x01, 1}, /* Output */
172 {0x7070, 0x01, 1}, /* Output */
173 };
174
175 ec_pdo_info_t ep2028_0032_pdos[] = {
176 {0x1600, 1, ep2028_0032_pdo_entries + 0}, /* Channel 1 */
177 {0x1601, 1, ep2028_0032_pdo_entries + 1}, /* Channel 2 */
178 {0x1602, 1, ep2028_0032_pdo_entries + 2}, /* Channel 3 */
179 {0x1603, 1, ep2028_0032_pdo_entries + 3}, /* Channel 4 */
180 {0x1604, 1, ep2028_0032_pdo_entries + 4}, /* Channel 5 */
181 {0x1605, 1, ep2028_0032_pdo_entries + 5}, /* Channel 6 */
182 {0x1606, 1, ep2028_0032_pdo_entries + 6}, /* Channel 7 */
183 {0x1607, 1, ep2028_0032_pdo_entries + 7}, /* Channel 8 */
184 };
185
186 ec_sync_info_t ep2028_0032_syncs[] = {
187 {0, EC_DIR_OUTPUT, 8, ep2028_0032_pdos + 0, EC_WD_ENABLE},
188 {0xff}};
189
190 /* Master 0, Slave 1, "EL2622"
191 * Vendor ID: 0x00000002
192 * Product code: 0x0a3e3052
193 * Revision number: 0x00120000
194 */
195
196 ec_pdo_entry_info_t el2622_pdo_entries[] = {
197 {0x7000, 0x01, 1}, /* Output */
198 {0x7010, 0x01, 1}, /* Output */
199 };
200
201 ec_pdo_info_t el2622_pdos[] = {
202 {0x1600, 1, el2622_pdo_entries + 0}, /* Channel 1 */
203 {0x1601, 1, el2622_pdo_entries + 1}, /* Channel 2 */
204 };
205
206 ec_sync_info_t el2622_syncs[] = {
207 {0, EC_DIR_OUTPUT, 2, el2622_pdos + 0, EC_WD_ENABLE},
208 {0xff}};
209
210 /****************************************************************************/
211
212 struct Ex20xxType
213 {
214 const char *name;
215 uint32_t product_code;
216 unsigned int num_channels;
217 uint16_t entry_index;
218 uint16_t entry_index_inc;
219 uint16_t entry_subindex_inc;
220 bool has_diagnosis;
221 ec_sync_info_t *sync;
222 };
223
224 const static Ex20xxType el20xxType[Ex20xx<Mode::Control>::NumTypes] = {
225 {"EL2004", 0x07d43052, 4, 0x3001, 0x0000, 0x01, false, el2004_syncs},
226 {"EL2008", 0x07d83052, 8, 0x7000, 0x0010, 0x00, false, el2008_syncs},
227 {"EL2024", 0x07e83052, 4, 0x7000, 0x0010, 0x00, false, el2024_syncs},
228 {"EL2034", 0x07f23052, 4, 0x7000, 0x0010, 0x00, true, el2034_syncs},
229 {"EP2028-0032", 0x07ec4052, 8, 0x7000, 0x0010, 0x00, false,
230 ep2028_0032_syncs},
231 {"EL2521", 0x09d93052, 4, 0x3001, 0x0000, 0x01, false, el2004_syncs},
232 {"EL2622", 0x0a3e3052, 2, 0x7000, 0x0010, 0x00, false, el2622_syncs},
233 {"EL2808", 0x0af83052, 8, 0x7000, 0x0010, 0x00, false, el2008_syncs},
234 };
235
236 /****************************************************************************/
237
238 template <Mode mode>
239 1 Ex20xx<mode>::Ex20xx(
240 pdserv *pdserv,
241 pdtask *task,
242 const std::string &prefix,
243 Master *master,
244 uint16_t alias,
245 uint16_t position,
246 Domain *domainOut,
247 Domain *domainIn,
248 Type typeIdx) :
249 1 type(el20xxType[typeIdx]),
250 sc(NULL),
251 domainOut(domainOut),
252 domainIn(domainIn),
253 1 off_out(type.num_channels, -1),
254 1 off_out_bit(type.num_channels, 0),
255 off_in(0),
256 1 input(type.num_channels, 0),
257 1 prevInput(type.num_channels, 0),
258 1 toggle(type.num_channels, 0),
259 1 prevToggle(type.num_channels, 0),
260 1 autoValue(type.num_channels, 0),
261 1 enableForcing(type.num_channels, 0),
262 1 forcedValue(type.num_channels, 0),
263 1 output(type.num_channels, 0),
264
11/44
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 27 taken 1 times.
✗ Branch 28 not taken.
✓ Branch 32 taken 1 times.
✗ Branch 33 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 38 not taken.
✓ Branch 42 taken 1 times.
✗ Branch 43 not taken.
✓ Branch 47 taken 1 times.
✗ Branch 48 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
✗ Branch 80 not taken.
✗ Branch 81 not taken.
✗ Branch 85 not taken.
✗ Branch 86 not taken.
✗ Branch 90 not taken.
✗ Branch 91 not taken.
✗ Branch 95 not taken.
✗ Branch 96 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 105 not taken.
✗ Branch 106 not taken.
✗ Branch 110 not taken.
✗ Branch 111 not taken.
✗ Branch 115 not taken.
✗ Branch 116 not taken.
✗ Branch 120 not taken.
✗ Branch 121 not taken.
✗ Branch 125 not taken.
✗ Branch 126 not taken.
✗ Branch 130 not taken.
✗ Branch 131 not taken.
11 diagnosis(type.num_channels, 0)
265 {
266
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 if (pdserv && task) {
267 pdserv_signal(
268 task, 1, (prefix + "/Output").c_str(), pd_boolean_T,
269 output.data(), output.size(), NULL);
270 pdserv_parameter(
271 pdserv, (prefix + "/EnableForcing").c_str(), 0666,
272 pd_boolean_T, enableForcing.data(), enableForcing.size(),
273 NULL, NULL, NULL);
274 pdserv_parameter(
275 pdserv, (prefix + "/ForcedValue").c_str(), 0666, pd_boolean_T,
276 forcedValue.data(), forcedValue.size(), NULL, NULL, NULL);
277 pdserv_parameter(
278 pdserv, (prefix + "/Toggle").c_str(), 0666, pd_uint32_T,
279 toggle.data(), toggle.size(), NULL, NULL, NULL);
280
281 if (type.has_diagnosis) {
282 pdserv_signal(
283 task, 1, (prefix + "/Diagnosis").c_str(), pd_boolean_T,
284 diagnosis.data(), diagnosis.size(), NULL);
285 }
286 }
287
288
1/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!master) {
289 1 return;
290 }
291
292 sc = ecrt_master_slave_config(
293 master->getMaster(), alias, position, 0x00000002,
294 type.product_code);
295 if (!sc) {
296 stringstream err;
297 err << "Failed to get slave configuration.";
298 throw runtime_error(err.str());
299 }
300
301 if (ecrt_slave_config_pdos(
302 sc, EC_END, SwappedSync<mode>(type.sync).getSync())) {
303 stringstream err;
304 err << "Failed to configure PDOs.";
305 throw runtime_error(err.str());
306 }
307
308 for (unsigned int i = 0; i < type.num_channels; i++) {
309 uint16_t entry_index = type.entry_index + type.entry_index_inc * i;
310 uint8_t entry_subindex = 0x01 + type.entry_subindex_inc * i;
311 off_out[i] = ecrt_slave_config_reg_pdo_entry(
312 sc, entry_index, entry_subindex, domainOut->getDomain(),
313 &off_out_bit[i]);
314 if (off_out[i] < 0) {
315 stringstream err;
316 err << "Failed to register Ex2xxx value PDO entry.";
317 throw runtime_error(err.str());
318 }
319 }
320
321 if (type.has_diagnosis) {
322 off_in = ecrt_slave_config_reg_pdo_entry(
323 sc, 0x6000, 0x01, domainIn->getDomain(), NULL);
324 if (off_in < 0) {
325 stringstream err;
326 err << "Failed to register Ex2xxx diagnosis PDO entry.";
327 throw runtime_error(err.str());
328 }
329 }
330 }
331
332 /****************************************************************************/
333
334 template <Mode mode>
335 3 void Ex20xx<mode>::setOutput(unsigned int channel, bool value)
336 {
337
1/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (channel < type.num_channels) {
338 3 input[channel] = value;
339 }
340 3 }
341
342 /****************************************************************************/
343
344 template <Mode mode>
345 bool Ex20xx<mode>::getOutput(unsigned int channel) const
346 {
347 if (channel < type.num_channels and domainOut->getData()) {
348 return EC_READ_BIT(
349 domainOut->getData() + off_out[channel],
350 off_out_bit[channel]);
351 }
352 else {
353 return false;
354 }
355 }
356
357 /****************************************************************************/
358
359 template <Mode mode>
360 1 unsigned int Ex20xx<mode>::numChannels() const
361 {
362 1 return type.num_channels;
363 }
364
365 /****************************************************************************/
366
367 template <Mode mode>
368 1 bool Ex20xx<mode>::hasDiagnosis() const
369 {
370 1 return type.has_diagnosis;
371 }
372
373 /****************************************************************************/
374
375 template <Mode mode>
376 bool Ex20xx<mode>::getDiagnosis(unsigned int channel) const
377 {
378 return channel < diagnosis.size() ? diagnosis[channel] : false;
379 }
380
381 /****************************************************************************/
382
383 template <Mode mode>
384 1 void Ex20xx<mode>::updateInputs()
385 {
386
2/12
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
1 if (type.has_diagnosis && domainIn->getData()) {
387 for (unsigned int i = 0; i < type.num_channels; i++) {
388 diagnosis[i] = EC_READ_BIT(domainIn->getData() + off_in, i);
389 }
390 }
391 1 }
392
393 /****************************************************************************/
394
395 template <Mode mode>
396 1 void Ex20xx<mode>::updateOutputs()
397 {
398
2/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
9 for (unsigned int i = 0; i < type.num_channels; i++) {
399 // toggle logic
400
3/8
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
8 const bool inputRising = input[i] && !prevInput[i];
401 8 const bool inputUnchanged = input[i] == prevInput[i];
402 8 prevInput[i] = input[i];
403
404 8 const bool toggleChanged = toggle[i] != prevToggle[i];
405 8 prevToggle[i] = toggle[i];
406
407 8 const bool toggleXorState = toggleChanged != autoValue[i];
408
3/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
8 const bool toggledState = inputUnchanged && toggleXorState;
409
3/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
8 autoValue[i] = inputRising || toggledState;
410
411
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
8 if (enableForcing[i]) {
412 output[i] = forcedValue[i];
413 }
414 else {
415 8 output[i] = autoValue[i];
416 }
417
418
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
8 if (domainOut->getData()) {
419 EC_WRITE_BIT(
420 domainOut->getData() + off_out[i], off_out_bit[i],
421 output[i]);
422 }
423 }
424 1 }
425
426 /****************************************************************************/
427
428 template class Ex20xx<Mode::Control>;
429 template class Ex20xx<Mode::Simulation>;
430
431 /****************************************************************************/
432 // Generic SubDevice adapter: translates the family's typed, bit-indexed
433 // setOutput()/getOutput() into ChannelValue, and registers each type
434 // with the factory so createSubDevice("EL2008") never has to know it
435 // resolves to Ex20xx.
436 /****************************************************************************/
437
438 template <Mode mode>
439 2 class Ex20xxAdapter : public SubDevice
440 {
441 public:
442 1 Ex20xxAdapter(const SlaveContext &ctx, typename Ex20xx<mode>::Type t) :
443 1 device(ctx.pdServ,
444 1 ctx.task,
445 ctx.prefix,
446 1 ctx.master,
447 1 ctx.alias,
448 1 ctx.position,
449 1 ctx.domainOut,
450 1 ctx.domainIn,
451 t),
452
6/24
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1 times.
✓ Branch 18 taken 1 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
5 outputKinds_ {{"Output", device.numChannels(), false}}
453 {
454
2/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1 if (device.hasDiagnosis()) {
455 inputKinds_.push_back({"Diagnosis", device.numChannels(), false});
456 }
457 1 }
458
459 1 void updateInputs() override { device.updateInputs(); }
460 1 void updateOutputs() override { device.updateOutputs(); }
461
462 const std::vector<ChannelKind> &inputKinds() const override
463 {
464 return inputKinds_;
465 }
466 11 const std::vector<ChannelKind> &outputKinds() const override
467 {
468 11 return outputKinds_;
469 }
470
471 protected:
472 ChannelValue getInputAt(size_t i) const override
473 {
474 return device.getDiagnosis(static_cast<unsigned int>(i));
475 }
476 4 void setOutputAt(size_t i, const ChannelValue &value) override
477 {
478 4 device.setOutput(static_cast<unsigned int>(i), std::get<bool>(value));
479 3 }
480
481 private:
482 Ex20xx<mode> device;
483 std::vector<ChannelKind> inputKinds_;
484 std::vector<ChannelKind> outputKinds_;
485 };
486
487 /****************************************************************************/
488
489 namespace {
490
491 64 DeviceFactoryFn makeEx20xxFactory(unsigned int typeIdx)
492 {
493 2 return [typeIdx](const SlaveContext &ctx) -> unique_ptr<SubDevice> {
494
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ctx.mode == Mode::Control) {
495 return make_unique<Ex20xxAdapter<Mode::Control>>(
496 ctx, static_cast<Ex20xx<Mode::Control>::Type>(typeIdx));
497 }
498 else {
499
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 return make_unique<Ex20xxAdapter<Mode::Simulation>>(
500 ctx,
501 3 static_cast<Ex20xx<Mode::Simulation>::Type>(typeIdx));
502 }
503 64 };
504 }
505
506 struct Ex20xxRegistrations
507 {
508 8 Ex20xxRegistrations()
509 {
510
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 8 times.
72 for (unsigned int i = 0; i < Ex20xx<Mode::Control>::NumTypes; i++) {
511 64 const auto &t = el20xxType[i];
512
4/8
✓ Branch 3 taken 64 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 64 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 64 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 64 times.
✗ Branch 14 not taken.
320 Registry::instance().add(
513 128 {t.name, __FILE__, 0x00000002, t.product_code,
514
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
128 AnyRevision, wrapFactory(makeEx20xxFactory(i))});
515 }
516 8 }
517 8 } ex20xxRegistrations;
518
519 } // namespace
520
521 24 } // namespace EcApp
522
523 /****************************************************************************/
524