GCC Code Coverage Report


Directory: ./
File: src/devices/Movitrac.cpp
Date: 2026-09-23 16:22:15
Exec Total Coverage
Lines: 98 156 62.8%
Branches: 87 492 17.7%

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/Movitrac.h"
24
25 #include "SlaveContext.h"
26 #include "ecapp/Domain.h"
27 #include "ecapp/Exceptions.h"
28 #include "ecapp/Factory.h"
29 #include "ecapp/Master.h"
30 #include "ecapp/SwappedSync.h"
31
32 #include <cmath>
33 #include <memory>
34 #include <sstream>
35 #include <stdexcept>
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 /****************************************************************************/
44
45 namespace EcApp {
46
47 /* Statuswort (aus Dokument 31556108.pdf)
48 *
49 * 0 Endstufe freigegeben "1" / Endstufe gesperrt "0"
50 * 1 Umrichter betriebsbereit "1" / Umrichter nicht betriebsbereit "0"
51 * 2 PA-Daten freigegeben "1" / PA-Daten gesperrt "0"
52 * 3 Aktueller Integratorsatz: Integrator 2 "1" / Integrator 1 "0"
53 * 4 Aktueller Parametersatz: Parametersatz 2 "1" / Parametersatz 1 "0"
54 * 5 Störung / Warnung: Störung / Warnung liegt an "1" / Keine Störung "0"
55 */
56
57 /* Master 0, Slave 5, "MOVITRAC+FSE24B"
58 * Vendor ID: 0x00000059
59 * Product code: 0x00000004
60 * Revision number: 0x00000002
61 */
62
63 ec_pdo_entry_info_t movitrac_pdo_entries[] = {
64 {0x3db8, 0x00, 16}, /* PO 0001 Steuerwort */
65 {0x3db9, 0x00, 16}, /* PO 0002 Sollgeschw. LSW */
66 {0x3dba, 0x00, 16}, /* PO 0003 Sollgeschw. MSW */
67 {0x3e1c, 0x00, 16}, /* PI 0001 Statuswort */
68 {0x3e1d, 0x00, 16}, /* PI 0002 Istgeschw. LSW */
69 {0x3e1e, 0x00, 16}, /* PI 0003 Istgeschw. MSW */
70 };
71
72 ec_pdo_info_t movitrac_pdos[] = {
73 {0x1600, 3, movitrac_pdo_entries + 0}, /* RxPDO 1 mapping */
74 {0x1a00, 3, movitrac_pdo_entries + 3}, /* TxPDO 1 mapping */
75 };
76
77 ec_sync_info_t movitrac_syncs[] = {
78 {0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
79 {1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
80 {2, EC_DIR_OUTPUT, 1, movitrac_pdos + 0, EC_WD_ENABLE},
81 {3, EC_DIR_INPUT, 1, movitrac_pdos + 1, EC_WD_DISABLE},
82 {0xff}};
83
84 /****************************************************************************/
85
86 template <Mode mode>
87 1 Movitrac<mode>::Movitrac(
88 Master *master,
89 uint16_t alias,
90 uint16_t position,
91 Domain *domainOut,
92 Domain *domainIn) :
93 sc(NULL),
94 domainOut(domainOut),
95 domainIn(domainIn),
96 offControl(-1),
97 offTargetSpeed(-1),
98 offStatus(-1),
99 offCurrentSpeed(-1),
100 enable(false),
101 controlWord(0x0002),
102 statusWord(0x0002),
103 targetSpeed(0.0),
104 currentSpeed(0.0),
105 speedScale(M_PI / 150.0), // 157.08 rad/s ~ 1500 RPM ~ 7500 inc.
106 enableForcing(false),
107 forcedControlWord(0x0002),
108 forcedTargetSpeed(0.0),
109 effControlWord(0x0002),
110 effTargetSpeed(0.0),
111 rawTargetSpeed(0x0000),
112 status0Enabled(false),
113 status1Ready(false),
114 status2PaDataEnabled(false),
115 status5FaultWarning(false),
116 faultFlag(false),
117 warning(false),
118 deviceState(0),
119 1 errorNumber(0)
120 {
121 // pdserv publishing happens in MovitracAdapter's constructor
122 // below, via SubDevice::registerInputChannel()/
123 // registerOutputChannel()/registerParameter() -- that is also what
124 // makes each channel alias-able through SubDevice::setAlias().
125
126
1/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!master) {
127 1 return;
128 }
129
130 ✗ sc = ecrt_master_slave_config(
131 master->getMaster(), alias, position, 0x00000059, 0x00000004);
132 ✗ if (!sc) {
133 ✗ stringstream err;
134 ✗ err << "Failed to get slave configuration for Movitrac.";
135 ✗ throw runtime_error(err.str());
136 }
137
138 ✗ if (ecrt_slave_config_pdos(
139 sc, EC_END, SwappedSync<mode>(movitrac_syncs).getSync())) {
140 ✗ stringstream err;
141 ✗ err << "Failed to configure PDOs of Movitrac.";
142 ✗ throw runtime_error(err.str());
143 }
144
145 ✗ offControl = ecrt_slave_config_reg_pdo_entry(
146 sc, 0x3db8, 0x00, domainOut->getDomain(), NULL);
147 ✗ if (offControl < 0) {
148 ✗ stringstream err;
149 ✗ err << "Failed to register Movitrac control word PDO entry.";
150 ✗ throw runtime_error(err.str());
151 }
152
153 ✗ offTargetSpeed = ecrt_slave_config_reg_pdo_entry(
154 sc, 0x3db9, 0x00, domainOut->getDomain(), NULL);
155 ✗ if (offTargetSpeed < 0) {
156 ✗ stringstream err;
157 ✗ err << "Failed to register Movitrac target speed PDO entry.";
158 ✗ throw runtime_error(err.str());
159 }
160
161 ✗ offStatus = ecrt_slave_config_reg_pdo_entry(
162 sc, 0x3e1c, 0x00, domainIn->getDomain(), NULL);
163 ✗ if (offStatus < 0) {
164 ✗ stringstream err;
165 ✗ err << "Failed to register Movitrac status word PDO entry.";
166 ✗ throw runtime_error(err.str());
167 }
168
169 ✗ offCurrentSpeed = ecrt_slave_config_reg_pdo_entry(
170 sc, 0x3e1d, 0x00, domainIn->getDomain(), NULL);
171 ✗ if (offCurrentSpeed < 0) {
172 ✗ stringstream err;
173 ✗ err << "Failed to register Movitrac current speed PDO entry.";
174 ✗ throw runtime_error(err.str());
175 }
176 }
177
178 /****************************************************************************/
179
180 template <Mode mode>
181 1 void Movitrac<mode>::updateInputs()
182 {
183
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (domainIn->getData()) {
184 ✗ statusWord = EC_READ_U16(domainIn->getData() + offStatus);
185 ✗ currentSpeed = EC_READ_S16(domainIn->getData() + offCurrentSpeed)
186 ✗ * speedScale;
187 }
188 else {
189 1 statusWord = 0x0000;
190 1 currentSpeed = 0.0;
191 }
192
193 1 status0Enabled = (statusWord & 0x0001) != 0;
194 1 status1Ready = (statusWord & 0x0002) != 0;
195 1 status2PaDataEnabled = (statusWord & 0x0004) != 0;
196 1 status5FaultWarning = (statusWord & 0x0020) != 0;
197
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 faultFlag = status5FaultWarning && !status1Ready;
198
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 warning = status5FaultWarning && status1Ready;
199
200
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 deviceState = status5FaultWarning ? 0x00 : ((statusWord & 0xff00) >> 8);
201
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 errorNumber = status5FaultWarning ? ((statusWord & 0xff00) >> 8) : 0x00;
202 1 }
203
204 /****************************************************************************/
205
206 template <Mode mode>
207 1 void Movitrac<mode>::setEnableMotor(bool en)
208 {
209 1 enable = en;
210 1 }
211
212 /****************************************************************************/
213
214 template <Mode mode>
215 1 void Movitrac<mode>::setTargetSpeed(double target)
216 {
217 1 targetSpeed = target;
218 1 }
219
220 /****************************************************************************/
221
222 template <Mode mode>
223 1 void Movitrac<mode>::updateOutputs()
224 {
225
1/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 controlWord = enable ? 0x0006 : 0x0002;
226
227
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (enableForcing) {
228 ✗ effControlWord = forcedControlWord;
229 ✗ effTargetSpeed = forcedTargetSpeed;
230 }
231 else {
232 1 effControlWord = controlWord;
233 1 effTargetSpeed = targetSpeed;
234 }
235
236
1/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (speedScale) {
237 1 rawTargetSpeed = effTargetSpeed / speedScale;
238 }
239 else {
240 ✗ rawTargetSpeed = 0x0000;
241 }
242
243
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (domainOut->getData()) {
244 ✗ EC_WRITE_U16(domainOut->getData() + offControl, effControlWord);
245 ✗ EC_WRITE_S16(domainOut->getData() + offTargetSpeed, rawTargetSpeed);
246 }
247 1 }
248
249 /****************************************************************************/
250
251 template class Movitrac<Mode::Control>;
252 template class Movitrac<Mode::Simulation>;
253
254 /****************************************************************************/
255 // Generic SubDevice adapter. Every channel is its own distinctly-named
256 // scalar (no repeated kind) -- application code never names Movitrac,
257 // only "SEW-MOVITRAC+FSE24B" itself as the createSubDevice() name
258 // (there is only the one product).
259 /****************************************************************************/
260
261 template <Mode mode>
262 2 class MovitracAdapter : public SubDevice
263 {
264 public:
265 1 explicit MovitracAdapter(const SlaveContext &ctx) :
266 SubDevice(
267 1 ctx.domainOut,
268 1 ctx.domainIn,
269 1 ctx.pdServ,
270 1 ctx.task,
271 ctx.prefix),
272 1 device(ctx.master,
273 1 ctx.alias,
274 1 ctx.position,
275 1 ctx.domainOut,
276 1 ctx.domainIn),
277 inputKinds_ {
278 {"StatusWord", 1, uint16_t(0)},
279 {"CurrentSpeed", 1, double(0)},
280 {"Status0Enabled", 1, false},
281 {"Status1Ready", 1, false},
282 {"Status2PaDataEnabled", 1, false},
283 {"Status5FaultWarning", 1, false},
284 {"Fault", 1, false},
285 {"Warning", 1, false},
286 {"DeviceState", 1, uint16_t(0)},
287 {"ErrorNumber", 1, uint16_t(0)},
288 {"AnyFault", 1, false}},
289 outputKinds_ {
290 {"EnableMotor", 1, false},
291
21/84
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 30 taken 1 times.
✗ Branch 31 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✓ Branch 38 taken 1 times.
✗ Branch 39 not taken.
✓ Branch 42 taken 1 times.
✗ Branch 43 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
✓ Branch 50 taken 1 times.
✗ Branch 51 not taken.
✓ Branch 54 taken 1 times.
✗ Branch 55 not taken.
✓ Branch 57 taken 11 times.
✓ Branch 58 taken 1 times.
✓ Branch 73 taken 1 times.
✗ Branch 74 not taken.
✓ Branch 77 taken 1 times.
✗ Branch 78 not taken.
✓ Branch 81 taken 1 times.
✗ Branch 82 not taken.
✓ Branch 84 taken 2 times.
✓ Branch 85 taken 1 times.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
✗ Branch 107 not taken.
✗ Branch 108 not taken.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 121 not taken.
✗ Branch 122 not taken.
✗ Branch 125 not taken.
✗ Branch 126 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✗ Branch 133 not taken.
✗ Branch 134 not taken.
✗ Branch 137 not taken.
✗ Branch 138 not taken.
✗ Branch 141 not taken.
✗ Branch 142 not taken.
✗ Branch 145 not taken.
✗ Branch 146 not taken.
✗ Branch 149 not taken.
✗ Branch 150 not taken.
✗ Branch 153 not taken.
✗ Branch 154 not taken.
✗ Branch 157 not taken.
✗ Branch 158 not taken.
✗ Branch 161 not taken.
✗ Branch 162 not taken.
✗ Branch 165 not taken.
✗ Branch 166 not taken.
✗ Branch 169 not taken.
✗ Branch 170 not taken.
✗ Branch 172 not taken.
✗ Branch 173 not taken.
✗ Branch 188 not taken.
✗ Branch 189 not taken.
✗ Branch 192 not taken.
✗ Branch 193 not taken.
✗ Branch 196 not taken.
✗ Branch 197 not taken.
✗ Branch 199 not taken.
✗ Branch 200 not taken.
✗ Branch 207 not taken.
✗ Branch 208 not taken.
✗ Branch 222 not taken.
✗ Branch 223 not taken.
5 {"TargetSpeed", 1, double(0)}}
292 {
293 // Kind names match inputKinds_/outputKinds_ above, not
294 // necessarily the old pdserv paths (e.g. "Status0Enabled" was
295 // "/Status_0_Enabled", "EnableMotor" was "/Enable") --
296 // registerInputChannel()'s/registerOutputChannel()'s kind
297 // argument is also the setAlias() lookup key, so it must agree
298 // with what inputKinds()/outputKinds() advertise.
299
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("StatusWord", device.statusWord);
300
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("CurrentSpeed", device.currentSpeed);
301
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("Status0Enabled", device.status0Enabled);
302
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("Status1Ready", device.status1Ready);
303
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel(
304 "Status2PaDataEnabled", device.status2PaDataEnabled);
305
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel(
306 "Status5FaultWarning", device.status5FaultWarning);
307
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("Fault", device.faultFlag);
308
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("Warning", device.warning);
309
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("DeviceState", device.deviceState);
310
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("ErrorNumber", device.errorNumber);
311 // AnyFault has no backing storage of its own (getFault() is a
312 // computed expression, see Movitrac.h) -- alias-based lookup
313 // in code still works via getInputAt(), it just gets no extra
314 // pdserv signal.
315
316
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerOutputChannel("EnableMotor", device.enable);
317
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerOutputChannel("TargetSpeed", device.targetSpeed);
318
3/12
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
1 registerParameter("SpeedScale", "TargetSpeed", device.speedScale);
319
3/12
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
1 registerParameter(
320 "EnableForcing", "TargetSpeed", device.enableForcing);
321
3/12
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
1 registerParameter(
322 "ForcedControlWord", "TargetSpeed", device.forcedControlWord);
323
3/12
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
1 registerParameter(
324 "ForcedTargetSpeed", "TargetSpeed", device.forcedTargetSpeed);
325
326 // Internal/diagnostic signals with no matching ChannelKind --
327 // published for visibility, same as before, but not part of
328 // the generic (kind, index) API and so not alias-able.
329
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("ControlWord", device.controlWord);
330
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("EffControlWord", device.effControlWord);
331
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("EffTargetSpeed", device.effTargetSpeed);
332
2/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1 registerInputChannel("RawTargetSpeed", device.rawTargetSpeed);
333 1 }
334
335 1 void updateInputs() override { device.updateInputs(); }
336 1 void updateOutputs() override { device.updateOutputs(); }
337
338 5 const std::vector<ChannelKind> &inputKinds() const override
339 {
340 5 return inputKinds_;
341 }
342 5 const std::vector<ChannelKind> &outputKinds() const override
343 {
344 5 return outputKinds_;
345 }
346
347 protected:
348 3 ChannelValue getInputAt(size_t i) const override
349 {
350
3/24
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
3 switch (i) {
351 1 case 0:
352 1 return device.getStatusWord();
353 ✗ case 1:
354 ✗ return device.getCurrentSpeed();
355 ✗ case 2:
356 ✗ return device.getStatus0Enabled();
357 ✗ case 3:
358 ✗ return device.getStatus1Ready();
359 ✗ case 4:
360 ✗ return device.getStatus2PaDataEnabled();
361 ✗ case 5:
362 ✗ return device.getStatus5FaultWarning();
363 1 case 6:
364 1 return device.getFaultFlag();
365 ✗ case 7:
366 ✗ return device.getWarning();
367 ✗ case 8:
368 ✗ return uint16_t(device.getDeviceState());
369 ✗ case 9:
370 ✗ return uint16_t(device.getErrorNumber());
371 1 case 10:
372 1 return device.getFault();
373 ✗ default:
374 ✗ throw UnknownChannel("Movitrac: invalid channel index.");
375 }
376 }
377
378 2 void setOutputAt(size_t i, const ChannelValue &value) override
379 {
380
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 switch (i) {
381 1 case 0:
382 1 device.setEnableMotor(std::get<bool>(value));
383 1 return;
384 1 case 1:
385 1 device.setTargetSpeed(std::get<double>(value));
386 1 return;
387 ✗ default:
388 ✗ throw UnknownChannel("Movitrac: invalid channel index.");
389 }
390 }
391
392 private:
393 Movitrac<mode> device;
394 std::vector<ChannelKind> inputKinds_;
395 std::vector<ChannelKind> outputKinds_;
396 };
397
398 /****************************************************************************/
399
400 namespace {
401
402 12 DeviceFactoryFn makeMovitracFactory()
403 {
404 1 return [](const SlaveContext &ctx) -> unique_ptr<SubDevice> {
405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ctx.mode == Mode::Control) {
406 ✗ return make_unique<MovitracAdapter<Mode::Control>>(ctx);
407 }
408 else {
409 1 return make_unique<MovitracAdapter<Mode::Simulation>>(ctx);
410 }
411
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 };
412 }
413
414 struct MovitracRegistration
415 {
416 12 MovitracRegistration()
417 {
418
4/8
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 14 not taken.
36 Registry::instance().add(
419 {"SEW-MOVITRAC+FSE24B", __FILE__, 0x00000059, 0x00000004,
420
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 AnyRevision, wrapFactory(makeMovitracFactory())});
421 12 }
422 12 } movitracRegistration;
423
424 } // namespace
425
426 36 } // namespace EcApp
427
428 /****************************************************************************/
429