| Directory: | ./ |
|---|---|
| File: | src/SubDevice.cpp |
| Date: | 2026-09-23 16:22:15 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 119 | 251 | 47.4% |
| Branches: | 134 | 1200 | 11.2% |
| 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 "ecapp/SubDevice.h" | ||
| 24 | |||
| 25 | #include "ecapp/Domain.h" | ||
| 26 | #include "ecapp/Exceptions.h" | ||
| 27 | |||
| 28 | #include <map> | ||
| 29 | #include <memory> | ||
| 30 | #include <pdserv.h> | ||
| 31 | #include <sstream> | ||
| 32 | #include <stdexcept> | ||
| 33 | #include <string> | ||
| 34 | #include <type_traits> | ||
| 35 | #include <utility> | ||
| 36 | #include <variant> | ||
| 37 | |||
| 38 | using std::size_t; | ||
| 39 | using std::string; | ||
| 40 | using std::stringstream; | ||
| 41 | |||
| 42 | /****************************************************************************/ | ||
| 43 | |||
| 44 | namespace { | ||
| 45 | |||
| 46 | /** The pdserv type identifier (pd_*_T) matching a ChannelValue's | ||
| 47 | * currently active alternative. */ | ||
| 48 | ✗ | int pdservTypeOf(const EcApp::ChannelValue &v) | |
| 49 | { | ||
| 50 | ✗ | return std::visit( | |
| 51 | ✗ | [](auto &&value) -> int { | |
| 52 | using T = std::decay_t<decltype(value)>; | ||
| 53 | if constexpr (std::is_same_v<T, bool>) { | ||
| 54 | ✗ | return pd_boolean_T; | |
| 55 | } | ||
| 56 | else if constexpr (std::is_same_v<T, uint8_t>) { | ||
| 57 | ✗ | return pd_uint8_T; | |
| 58 | } | ||
| 59 | else if constexpr (std::is_same_v<T, int8_t>) { | ||
| 60 | ✗ | return pd_sint8_T; | |
| 61 | } | ||
| 62 | else if constexpr (std::is_same_v<T, uint16_t>) { | ||
| 63 | ✗ | return pd_uint16_T; | |
| 64 | } | ||
| 65 | else if constexpr (std::is_same_v<T, int16_t>) { | ||
| 66 | ✗ | return pd_sint16_T; | |
| 67 | } | ||
| 68 | else if constexpr (std::is_same_v<T, uint32_t>) { | ||
| 69 | ✗ | return pd_uint32_T; | |
| 70 | } | ||
| 71 | else if constexpr (std::is_same_v<T, int32_t>) { | ||
| 72 | ✗ | return pd_sint32_T; | |
| 73 | } | ||
| 74 | else if constexpr (std::is_same_v<T, float>) { | ||
| 75 | ✗ | return pd_single_T; | |
| 76 | } | ||
| 77 | else { // double | ||
| 78 | ✗ | return pd_double_T; | |
| 79 | } | ||
| 80 | }, | ||
| 81 | ✗ | v); | |
| 82 | } | ||
| 83 | |||
| 84 | /** `base`, offset by `index` elements of whatever type `tag` is | ||
| 85 | * currently tagging -- `base` must actually point at an array of that | ||
| 86 | * type (guaranteed by registerInputChannel()/registerOutputChannel()/ | ||
| 87 | * registerParameter(), the only places that ever populate the tables | ||
| 88 | * this is read back from). */ | ||
| 89 | ✗ | void *offsetOf(void *base, const EcApp::ChannelValue &tag, std::size_t index) | |
| 90 | { | ||
| 91 | ✗ | return std::visit( | |
| 92 | ✗ | [&](auto &&value) -> void * { | |
| 93 | using T = std::decay_t<decltype(value)>; | ||
| 94 | ✗ | return static_cast<T *>(base) + index; | |
| 95 | }, | ||
| 96 | ✗ | tag); | |
| 97 | } | ||
| 98 | |||
| 99 | /** Address of the alternative currently active in `v`. Only valid | ||
| 100 | * while `v` keeps that same alternative (a differently-indexed | ||
| 101 | * assignment could reallocate/retag it) -- callers of the | ||
| 102 | * ChannelValue overloads of registerInputChannel()/ | ||
| 103 | * registerOutputChannel()/registerParameter() are documented to | ||
| 104 | * uphold that. */ | ||
| 105 | 9 | void *addressOf(EcApp::ChannelValue &v) | |
| 106 | { | ||
| 107 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
18 | return std::visit([](auto &value) -> void * { return &value; }, v); |
| 108 | } | ||
| 109 | |||
| 110 | } // namespace | ||
| 111 | |||
| 112 | /****************************************************************************/ | ||
| 113 | |||
| 114 | namespace EcApp { | ||
| 115 | |||
| 116 | /** Everything SubDevice needs to store privately -- see the doc | ||
| 117 | * comment on SubDevice::impl in SubDevice.h for why this is a Pimpl | ||
| 118 | * rather than direct members. */ | ||
| 119 | 20 | struct SubDevice::Impl | |
| 120 | { | ||
| 121 | 20 | Impl(Domain *domainOut, | |
| 122 | Domain *domainIn, | ||
| 123 | pdserv *pdServ, | ||
| 124 | pdtask *task, | ||
| 125 | 20 | std::string prefix) : | |
| 126 | domainOut(domainOut), | ||
| 127 | domainIn(domainIn), | ||
| 128 | pdServ(pdServ), | ||
| 129 | task(task), | ||
| 130 | 20 | prefix(std::move(prefix)) | |
| 131 | 20 | {} | |
| 132 | |||
| 133 | Domain *domainOut; | ||
| 134 | Domain *domainIn; | ||
| 135 | pdserv *pdServ; | ||
| 136 | pdtask *task; | ||
| 137 | std::string prefix; | ||
| 138 | |||
| 139 | std::map<std::string, std::vector<std::string>> inputAliases; | ||
| 140 | std::map<std::string, std::vector<std::string>> outputAliases; | ||
| 141 | |||
| 142 | // Address + type tag of a kind registered through | ||
| 143 | // registerInputChannel()/registerOutputChannel(), for setAlias()'s | ||
| 144 | // use; absent for a kind that hasn't been migrated to it yet. | ||
| 145 | std::map<std::string, std::pair<void *, ChannelValue>> inputChannelData; | ||
| 146 | std::map<std::string, std::pair<void *, ChannelValue>> outputChannelData; | ||
| 147 | |||
| 148 | 57 | struct ParamEntry | |
| 149 | { | ||
| 150 | std::string name; | ||
| 151 | void *data; | ||
| 152 | ChannelValue type; | ||
| 153 | unsigned int mode; | ||
| 154 | }; | ||
| 155 | // Keyed by the associated channel kind's name (see | ||
| 156 | // registerParameter()); one kind may have several parameters | ||
| 157 | // registered against it (e.g. "Gain" and "Offset" both against | ||
| 158 | // "Input"), hence multimap. | ||
| 159 | std::multimap<std::string, ParamEntry> paramsByKind; | ||
| 160 | }; | ||
| 161 | |||
| 162 | /****************************************************************************/ | ||
| 163 | |||
| 164 | 20 | SubDevice::SubDevice( | |
| 165 | Domain *domainOut, | ||
| 166 | Domain *domainIn, | ||
| 167 | pdserv *pdServ, | ||
| 168 | pdtask *task, | ||
| 169 | 20 | std::string prefix) : | |
| 170 | impl(std::make_unique<Impl>( | ||
| 171 | domainOut, | ||
| 172 | domainIn, | ||
| 173 | pdServ, | ||
| 174 | task, | ||
| 175 | 20 | std::move(prefix))) | |
| 176 | { | ||
| 177 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 6 times.
|
20 | if (impl->domainOut) { |
| 178 |
1/2✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | impl->domainOut->addOutputDevice(this); |
| 179 | } | ||
| 180 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 6 times.
|
20 | if (impl->domainIn) { |
| 181 |
1/2✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | impl->domainIn->addInputDevice(this); |
| 182 | } | ||
| 183 | 20 | } | |
| 184 | |||
| 185 | /****************************************************************************/ | ||
| 186 | |||
| 187 | 40 | SubDevice::~SubDevice() | |
| 188 | { | ||
| 189 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 6 times.
|
20 | if (impl->domainOut) { |
| 190 | 14 | impl->domainOut->removeOutputDevice(this); | |
| 191 | } | ||
| 192 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 6 times.
|
20 | if (impl->domainIn) { |
| 193 | 14 | impl->domainIn->removeInputDevice(this); | |
| 194 | } | ||
| 195 | 20 | } | |
| 196 | |||
| 197 | /****************************************************************************/ | ||
| 198 | |||
| 199 | 22 | size_t SubDevice::inputIndex(const string &kind, unsigned int index) const | |
| 200 | { | ||
| 201 | 22 | size_t position = 0; | |
| 202 |
3/4✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 80 times.
✓ Branch 7 taken 2 times.
|
82 | for (const auto &ck : inputKinds()) { |
| 203 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 60 times.
|
80 | if (ck.name == kind) { |
| 204 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | if (index < ck.count) { |
| 205 | 40 | return position + index; | |
| 206 | } | ||
| 207 | ✗ | break; | |
| 208 | } | ||
| 209 | 60 | position += ck.count; | |
| 210 | } | ||
| 211 | |||
| 212 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | stringstream err; |
| 213 |
5/10✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
|
2 | err << "Unknown input channel \"" << kind << "\" index " << index << "."; |
| 214 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
2 | throw UnknownChannel(err.str()); |
| 215 | } | ||
| 216 | |||
| 217 | /****************************************************************************/ | ||
| 218 | |||
| 219 | 4 | size_t SubDevice::inputIndex(unsigned int index) const | |
| 220 | { | ||
| 221 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
4 | return inputIndex(soleInputKind(), index); |
| 222 | } | ||
| 223 | |||
| 224 | /****************************************************************************/ | ||
| 225 | |||
| 226 | 24 | size_t SubDevice::outputIndex(const string &kind, unsigned int index) const | |
| 227 | { | ||
| 228 | 24 | size_t position = 0; | |
| 229 |
2/4✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 47 times.
✗ Branch 7 not taken.
|
47 | for (const auto &ck : outputKinds()) { |
| 230 |
2/2✓ Branch 1 taken 24 times.
✓ Branch 2 taken 23 times.
|
47 | if (ck.name == kind) { |
| 231 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | if (index < ck.count) { |
| 232 | 48 | return position + index; | |
| 233 | } | ||
| 234 | ✗ | break; | |
| 235 | } | ||
| 236 | 23 | position += ck.count; | |
| 237 | } | ||
| 238 | |||
| 239 | ✗ | stringstream err; | |
| 240 | ✗ | err << "Unknown output channel \"" << kind << "\" index " << index << "."; | |
| 241 | ✗ | throw UnknownChannel(err.str()); | |
| 242 | } | ||
| 243 | |||
| 244 | /****************************************************************************/ | ||
| 245 | |||
| 246 | 5 | size_t SubDevice::outputIndex(unsigned int index) const | |
| 247 | { | ||
| 248 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | return outputIndex(soleOutputKind(), index); |
| 249 | } | ||
| 250 | |||
| 251 | /****************************************************************************/ | ||
| 252 | |||
| 253 | ✗ | size_t SubDevice::inputIndex(const string &kind, const string &alias) const | |
| 254 | { | ||
| 255 | ✗ | auto it = impl->inputAliases.find(kind); | |
| 256 | ✗ | if (it != impl->inputAliases.end()) { | |
| 257 | ✗ | for (size_t i = 0; i < it->second.size(); i++) { | |
| 258 | ✗ | if (it->second[i] == alias) { | |
| 259 | ✗ | return inputIndex(kind, static_cast<unsigned int>(i)); | |
| 260 | } | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | ✗ | stringstream err; | |
| 265 | err << "Unknown alias \"" << alias << "\" for input channel \"" << kind | ||
| 266 | ✗ | << "\"."; | |
| 267 | ✗ | throw UnknownChannel(err.str()); | |
| 268 | } | ||
| 269 | |||
| 270 | /****************************************************************************/ | ||
| 271 | |||
| 272 | ✗ | size_t SubDevice::outputIndex(const string &kind, const string &alias) const | |
| 273 | { | ||
| 274 | ✗ | auto it = impl->outputAliases.find(kind); | |
| 275 | ✗ | if (it != impl->outputAliases.end()) { | |
| 276 | ✗ | for (size_t i = 0; i < it->second.size(); i++) { | |
| 277 | ✗ | if (it->second[i] == alias) { | |
| 278 | ✗ | return outputIndex(kind, static_cast<unsigned int>(i)); | |
| 279 | } | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | ✗ | stringstream err; | |
| 284 | err << "Unknown alias \"" << alias << "\" for output channel \"" << kind | ||
| 285 | ✗ | << "\"."; | |
| 286 | ✗ | throw UnknownChannel(err.str()); | |
| 287 | } | ||
| 288 | |||
| 289 | /****************************************************************************/ | ||
| 290 | |||
| 291 | ✗ | void SubDevice::setAlias( | |
| 292 | const string &kind, | ||
| 293 | const std::vector<string> &aliases) | ||
| 294 | { | ||
| 295 | ✗ | const ChannelKind *k = nullptr; | |
| 296 | ✗ | bool isInput = true; | |
| 297 | |||
| 298 | ✗ | for (const auto &ck : inputKinds()) { | |
| 299 | ✗ | if (ck.name == kind) { | |
| 300 | ✗ | k = &ck; | |
| 301 | ✗ | isInput = true; | |
| 302 | ✗ | break; | |
| 303 | } | ||
| 304 | } | ||
| 305 | ✗ | if (!k) { | |
| 306 | ✗ | for (const auto &ck : outputKinds()) { | |
| 307 | ✗ | if (ck.name == kind) { | |
| 308 | ✗ | k = &ck; | |
| 309 | ✗ | isInput = false; | |
| 310 | ✗ | break; | |
| 311 | } | ||
| 312 | } | ||
| 313 | } | ||
| 314 | ✗ | if (!k) { | |
| 315 | ✗ | stringstream err; | |
| 316 | ✗ | err << "setAlias(): unknown channel kind \"" << kind << "\"."; | |
| 317 | ✗ | throw UnknownChannel(err.str()); | |
| 318 | } | ||
| 319 | |||
| 320 | ✗ | if (aliases.size() != k->count) { | |
| 321 | ✗ | stringstream err; | |
| 322 | ✗ | err << "setAlias(\"" << kind << "\", ...): " << aliases.size() | |
| 323 | ✗ | << " alias(es) given, but this kind has " << k->count | |
| 324 | ✗ | << " channel(s)."; | |
| 325 | ✗ | throw AliasCountMismatch(err.str()); | |
| 326 | } | ||
| 327 | |||
| 328 | ✗ | auto &aliasTable = isInput ? impl->inputAliases : impl->outputAliases; | |
| 329 | auto &channelDataTable = | ||
| 330 | ✗ | isInput ? impl->inputChannelData : impl->outputChannelData; | |
| 331 | |||
| 332 | ✗ | if (aliasTable.count(kind)) { | |
| 333 | throw std::logic_error( | ||
| 334 | ✗ | "setAlias() already called for channel \"" + kind + "\"."); | |
| 335 | } | ||
| 336 | ✗ | aliasTable[kind] = aliases; | |
| 337 | |||
| 338 | ✗ | if (!impl->pdServ || !impl->task) { | |
| 339 | ✗ | return; | |
| 340 | } | ||
| 341 | |||
| 342 | ✗ | auto dit = channelDataTable.find(kind); | |
| 343 | ✗ | if (dit != channelDataTable.end()) { | |
| 344 | ✗ | void *base = dit->second.first; | |
| 345 | ✗ | const ChannelValue &tag = dit->second.second; | |
| 346 | ✗ | for (size_t i = 0; i < aliases.size(); i++) { | |
| 347 | ✗ | if (aliases[i].empty()) { | |
| 348 | ✗ | continue; | |
| 349 | } | ||
| 350 | ✗ | pdserv_signal( | |
| 351 | ✗ | impl->task, 1, | |
| 352 | ✗ | (impl->prefix + "/" + kind + "/" + aliases[i]).c_str(), | |
| 353 | ✗ | pdservTypeOf(tag), offsetOf(base, tag, i), 1, NULL); | |
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | ✗ | auto range = impl->paramsByKind.equal_range(kind); | |
| 358 | ✗ | for (auto pit = range.first; pit != range.second; ++pit) { | |
| 359 | ✗ | const Impl::ParamEntry ¶m = pit->second; | |
| 360 | ✗ | for (size_t i = 0; i < aliases.size(); i++) { | |
| 361 | ✗ | if (aliases[i].empty()) { | |
| 362 | ✗ | continue; | |
| 363 | } | ||
| 364 | ✗ | pdserv_parameter( | |
| 365 | ✗ | impl->pdServ, | |
| 366 | ✗ | (impl->prefix + "/" + param.name + "/" + aliases[i]) | |
| 367 | .c_str(), | ||
| 368 | ✗ | param.mode, pdservTypeOf(param.type), | |
| 369 | ✗ | offsetOf(param.data, param.type, i), 1, NULL, NULL, NULL); | |
| 370 | } | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | /****************************************************************************/ | ||
| 375 | |||
| 376 | template <typename T> | ||
| 377 | 8 | void SubDevice::registerInputChannel(const string &kind, std::vector<T> &data) | |
| 378 | { | ||
| 379 |
6/48✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 2 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 2 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 57 not taken.
✓ Branch 58 taken 4 times.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✓ Branch 63 taken 4 times.
|
8 | if (impl->pdServ && impl->task) { |
| 380 | ✗ | pdserv_signal( | |
| 381 | ✗ | impl->task, 1, (impl->prefix + "/" + kind).c_str(), | |
| 382 | pdservTypeOf(ChannelValue(T {})), data.data(), data.size(), | ||
| 383 | NULL); | ||
| 384 | } | ||
| 385 |
3/16✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 21 taken 2 times.
✗ Branch 22 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✓ Branch 61 taken 4 times.
✗ Branch 62 not taken.
|
8 | impl->inputChannelData[kind] = {data.data(), ChannelValue(T {})}; |
| 386 | 8 | } | |
| 387 | |||
| 388 | 15 | void SubDevice::registerInputChannel( | |
| 389 | const string &kind, | ||
| 390 | std::vector<uint8_t> &data, | ||
| 391 | AsBoolean) | ||
| 392 | { | ||
| 393 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
|
15 | if (impl->pdServ && impl->task) { |
| 394 | ✗ | pdserv_signal( | |
| 395 | ✗ | impl->task, 1, (impl->prefix + "/" + kind).c_str(), | |
| 396 | ✗ | pd_boolean_T, data.data(), data.size(), NULL); | |
| 397 | } | ||
| 398 |
1/2✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
|
15 | impl->inputChannelData[kind] = {data.data(), ChannelValue(uint8_t {})}; |
| 399 | 15 | } | |
| 400 | |||
| 401 | template <typename T> | ||
| 402 | 8 | void SubDevice::registerOutputChannel( | |
| 403 | const string &kind, | ||
| 404 | std::vector<T> &data) | ||
| 405 | { | ||
| 406 |
6/48✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 4 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 4 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✓ Branch 34 taken 2 times.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✓ Branch 39 taken 2 times.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
|
8 | if (impl->pdServ && impl->task) { |
| 407 | ✗ | pdserv_signal( | |
| 408 | ✗ | impl->task, 1, (impl->prefix + "/" + kind).c_str(), | |
| 409 | pdservTypeOf(ChannelValue(T {})), data.data(), data.size(), | ||
| 410 | NULL); | ||
| 411 | } | ||
| 412 |
3/16✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 21 taken 4 times.
✗ Branch 22 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✓ Branch 37 taken 2 times.
✗ Branch 38 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
|
8 | impl->outputChannelData[kind] = {data.data(), ChannelValue(T {})}; |
| 413 | 8 | } | |
| 414 | |||
| 415 | 12 | void SubDevice::registerOutputChannel( | |
| 416 | const string &kind, | ||
| 417 | std::vector<uint8_t> &data, | ||
| 418 | AsBoolean) | ||
| 419 | { | ||
| 420 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
|
12 | if (impl->pdServ && impl->task) { |
| 421 | ✗ | pdserv_signal( | |
| 422 | ✗ | impl->task, 1, (impl->prefix + "/" + kind).c_str(), | |
| 423 | ✗ | pd_boolean_T, data.data(), data.size(), NULL); | |
| 424 | } | ||
| 425 |
1/2✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
|
12 | impl->outputChannelData[kind] = {data.data(), ChannelValue(uint8_t {})}; |
| 426 | 12 | } | |
| 427 | |||
| 428 | template <typename T> | ||
| 429 | 8 | void SubDevice::registerParameter( | |
| 430 | const string &name, | ||
| 431 | const string &kind, | ||
| 432 | std::vector<T> &data, | ||
| 433 | unsigned int mode) | ||
| 434 | { | ||
| 435 |
4/48✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 2 times.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✓ Branch 31 taken 2 times.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
|
8 | if (impl->pdServ && impl->task) { |
| 436 | ✗ | pdserv_parameter( | |
| 437 | ✗ | impl->pdServ, (impl->prefix + "/" + name).c_str(), mode, | |
| 438 | pdservTypeOf(ChannelValue(T {})), data.data(), data.size(), | ||
| 439 | NULL, NULL, NULL); | ||
| 440 | } | ||
| 441 |
2/16✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 29 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
|
8 | impl->paramsByKind.emplace( |
| 442 | kind, | ||
| 443 | Impl::ParamEntry {name, data.data(), ChannelValue(T {}), mode}); | ||
| 444 | 8 | } | |
| 445 | |||
| 446 | 5 | void SubDevice::registerParameter( | |
| 447 | const string &name, | ||
| 448 | const string &kind, | ||
| 449 | std::vector<uint8_t> &data, | ||
| 450 | AsBoolean, | ||
| 451 | unsigned int mode) | ||
| 452 | { | ||
| 453 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5 times.
|
5 | if (impl->pdServ && impl->task) { |
| 454 | ✗ | pdserv_parameter( | |
| 455 | ✗ | impl->pdServ, (impl->prefix + "/" + name).c_str(), mode, | |
| 456 | ✗ | pd_boolean_T, data.data(), data.size(), NULL, NULL, NULL); | |
| 457 | } | ||
| 458 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | impl->paramsByKind.emplace( |
| 459 | kind, | ||
| 460 | 15 | Impl::ParamEntry { | |
| 461 | 10 | name, data.data(), ChannelValue(uint8_t {}), mode}); | |
| 462 | 5 | } | |
| 463 | |||
| 464 | template <typename T> | ||
| 465 | 19 | void SubDevice::registerInputChannel(const string &kind, T &data) | |
| 466 | { | ||
| 467 |
12/54✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 2 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 2 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 41 not taken.
✓ Branch 42 taken 1 times.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✓ Branch 47 taken 1 times.
✗ Branch 49 not taken.
✓ Branch 50 taken 3 times.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✓ Branch 55 taken 3 times.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 65 not taken.
✓ Branch 66 taken 3 times.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✓ Branch 71 taken 3 times.
|
19 | if (impl->pdServ && impl->task) { |
| 468 | ✗ | pdserv_signal( | |
| 469 | ✗ | impl->task, 1, (impl->prefix + "/" + kind).c_str(), | |
| 470 | pdservTypeOf(ChannelValue(T {})), &data, 1, NULL); | ||
| 471 | } | ||
| 472 |
6/18✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 18 taken 2 times.
✗ Branch 19 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✓ Branch 39 taken 1 times.
✗ Branch 40 not taken.
✓ Branch 46 taken 3 times.
✗ Branch 47 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✓ Branch 60 taken 3 times.
✗ Branch 61 not taken.
|
19 | impl->inputChannelData[kind] = {&data, ChannelValue(T {})}; |
| 473 | 19 | } | |
| 474 | |||
| 475 | 1 | void SubDevice::registerInputChannel( | |
| 476 | const string &kind, | ||
| 477 | uint8_t &data, | ||
| 478 | AsBoolean) | ||
| 479 | { | ||
| 480 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
|
1 | if (impl->pdServ && impl->task) { |
| 481 | ✗ | pdserv_signal( | |
| 482 | ✗ | impl->task, 1, (impl->prefix + "/" + kind).c_str(), | |
| 483 | pd_boolean_T, &data, 1, NULL); | ||
| 484 | } | ||
| 485 |
1/2✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | impl->inputChannelData[kind] = {&data, ChannelValue(uint8_t {})}; |
| 486 | 1 | } | |
| 487 | |||
| 488 | template <typename T> | ||
| 489 | 2 | void SubDevice::registerOutputChannel(const string &kind, T &data) | |
| 490 | { | ||
| 491 |
4/54✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
|
2 | if (impl->pdServ && impl->task) { |
| 492 | ✗ | pdserv_signal( | |
| 493 | ✗ | impl->task, 1, (impl->prefix + "/" + kind).c_str(), | |
| 494 | pdservTypeOf(ChannelValue(T {})), &data, 1, NULL); | ||
| 495 | } | ||
| 496 |
2/18✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
|
2 | impl->outputChannelData[kind] = {&data, ChannelValue(T {})}; |
| 497 | 2 | } | |
| 498 | |||
| 499 | ✗ | void SubDevice::registerOutputChannel( | |
| 500 | const string &kind, | ||
| 501 | uint8_t &data, | ||
| 502 | AsBoolean) | ||
| 503 | { | ||
| 504 | ✗ | if (impl->pdServ && impl->task) { | |
| 505 | ✗ | pdserv_signal( | |
| 506 | ✗ | impl->task, 1, (impl->prefix + "/" + kind).c_str(), | |
| 507 | pd_boolean_T, &data, 1, NULL); | ||
| 508 | } | ||
| 509 | ✗ | impl->outputChannelData[kind] = {&data, ChannelValue(uint8_t {})}; | |
| 510 | } | ||
| 511 | |||
| 512 | template <typename T> | ||
| 513 | 4 | void SubDevice::registerParameter( | |
| 514 | const string &name, | ||
| 515 | const string &kind, | ||
| 516 | T &data, | ||
| 517 | unsigned int mode) | ||
| 518 | { | ||
| 519 |
6/54✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 2 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 49 not taken.
✓ Branch 50 taken 1 times.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✓ Branch 55 taken 1 times.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
|
4 | if (impl->pdServ && impl->task) { |
| 520 | ✗ | pdserv_parameter( | |
| 521 | ✗ | impl->pdServ, (impl->prefix + "/" + name).c_str(), mode, | |
| 522 | pdservTypeOf(ChannelValue(T {})), &data, 1, NULL, NULL, NULL); | ||
| 523 | } | ||
| 524 |
3/18✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✓ Branch 45 taken 1 times.
✗ Branch 46 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
|
4 | impl->paramsByKind.emplace( |
| 525 | kind, Impl::ParamEntry {name, &data, ChannelValue(T {}), mode}); | ||
| 526 | 4 | } | |
| 527 | |||
| 528 | 1 | void SubDevice::registerParameter( | |
| 529 | const string &name, | ||
| 530 | const string &kind, | ||
| 531 | uint8_t &data, | ||
| 532 | AsBoolean, | ||
| 533 | unsigned int mode) | ||
| 534 | { | ||
| 535 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
|
1 | if (impl->pdServ && impl->task) { |
| 536 | ✗ | pdserv_parameter( | |
| 537 | ✗ | impl->pdServ, (impl->prefix + "/" + name).c_str(), mode, | |
| 538 | pd_boolean_T, &data, 1, NULL, NULL, NULL); | ||
| 539 | } | ||
| 540 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | impl->paramsByKind.emplace( |
| 541 | kind, | ||
| 542 | 2 | Impl::ParamEntry {name, &data, ChannelValue(uint8_t {}), mode}); | |
| 543 | 1 | } | |
| 544 | |||
| 545 | 3 | void SubDevice::registerInputChannel(const string &kind, ChannelValue &value) | |
| 546 | { | ||
| 547 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
|
3 | if (impl->pdServ && impl->task) { |
| 548 | ✗ | pdserv_signal( | |
| 549 | ✗ | impl->task, 1, (impl->prefix + "/" + kind).c_str(), | |
| 550 | ✗ | pdservTypeOf(value), addressOf(value), 1, NULL); | |
| 551 | } | ||
| 552 |
2/4✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
|
3 | impl->inputChannelData[kind] = {addressOf(value), value}; |
| 553 | 3 | } | |
| 554 | |||
| 555 | 5 | void SubDevice::registerOutputChannel(const string &kind, ChannelValue &value) | |
| 556 | { | ||
| 557 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5 times.
|
5 | if (impl->pdServ && impl->task) { |
| 558 | ✗ | pdserv_signal( | |
| 559 | ✗ | impl->task, 1, (impl->prefix + "/" + kind).c_str(), | |
| 560 | ✗ | pdservTypeOf(value), addressOf(value), 1, NULL); | |
| 561 | } | ||
| 562 |
2/4✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
|
5 | impl->outputChannelData[kind] = {addressOf(value), value}; |
| 563 | 5 | } | |
| 564 | |||
| 565 | 1 | void SubDevice::registerParameter( | |
| 566 | const string &name, | ||
| 567 | const string &kind, | ||
| 568 | ChannelValue &value, | ||
| 569 | unsigned int mode) | ||
| 570 | { | ||
| 571 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
|
1 | if (impl->pdServ && impl->task) { |
| 572 | ✗ | pdserv_parameter( | |
| 573 | ✗ | impl->pdServ, (impl->prefix + "/" + name).c_str(), mode, | |
| 574 | pdservTypeOf(value), addressOf(value), 1, NULL, NULL, NULL); | ||
| 575 | } | ||
| 576 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | impl->paramsByKind.emplace( |
| 577 | 2 | kind, Impl::ParamEntry {name, addressOf(value), value, mode}); | |
| 578 | 1 | } | |
| 579 | |||
| 580 | // Explicitly instantiated for every ChannelValue alternative except | ||
| 581 | // bool for the vector overloads (a std::vector<bool> has no contiguous | ||
| 582 | // storage to publish -- use the AsBoolean overload of | ||
| 583 | // std::vector<uint8_t> instead); bool included for the scalar | ||
| 584 | // overloads, which have no such problem. | ||
| 585 | #define ECAPP_INSTANTIATE_VECTOR_REGISTRATION(T) \ | ||
| 586 | template void SubDevice::registerInputChannel<T>( \ | ||
| 587 | const string &, std::vector<T> &); \ | ||
| 588 | template void SubDevice::registerOutputChannel<T>( \ | ||
| 589 | const string &, std::vector<T> &); \ | ||
| 590 | template void SubDevice::registerParameter<T>( \ | ||
| 591 | const string &, const string &, std::vector<T> &, unsigned int) | ||
| 592 | |||
| 593 | #define ECAPP_INSTANTIATE_SCALAR_REGISTRATION(T) \ | ||
| 594 | template void SubDevice::registerInputChannel<T>(const string &, T &); \ | ||
| 595 | template void SubDevice::registerOutputChannel<T>(const string &, T &); \ | ||
| 596 | template void SubDevice::registerParameter<T>( \ | ||
| 597 | const string &, const string &, T &, unsigned int) | ||
| 598 | |||
| 599 | #define ECAPP_INSTANTIATE_CHANNEL_REGISTRATION(T) \ | ||
| 600 | ECAPP_INSTANTIATE_VECTOR_REGISTRATION(T); \ | ||
| 601 | ECAPP_INSTANTIATE_SCALAR_REGISTRATION(T) | ||
| 602 | |||
| 603 | ECAPP_INSTANTIATE_CHANNEL_REGISTRATION(uint8_t); | ||
| 604 | ECAPP_INSTANTIATE_CHANNEL_REGISTRATION(int8_t); | ||
| 605 | ECAPP_INSTANTIATE_CHANNEL_REGISTRATION(uint16_t); | ||
| 606 | ECAPP_INSTANTIATE_CHANNEL_REGISTRATION(int16_t); | ||
| 607 | ECAPP_INSTANTIATE_CHANNEL_REGISTRATION(uint32_t); | ||
| 608 | ECAPP_INSTANTIATE_CHANNEL_REGISTRATION(int32_t); | ||
| 609 | ECAPP_INSTANTIATE_CHANNEL_REGISTRATION(float); | ||
| 610 | ECAPP_INSTANTIATE_CHANNEL_REGISTRATION(double); | ||
| 611 | ECAPP_INSTANTIATE_SCALAR_REGISTRATION(bool); | ||
| 612 | |||
| 613 | #undef ECAPP_INSTANTIATE_CHANNEL_REGISTRATION | ||
| 614 | #undef ECAPP_INSTANTIATE_SCALAR_REGISTRATION | ||
| 615 | #undef ECAPP_INSTANTIATE_VECTOR_REGISTRATION | ||
| 616 | |||
| 617 | /****************************************************************************/ | ||
| 618 | |||
| 619 | 8 | string SubDevice::soleInputKind() const | |
| 620 | { | ||
| 621 | 8 | const auto &kinds = inputKinds(); | |
| 622 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 3 times.
|
8 | if (kinds.size() != 1) { |
| 623 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | stringstream err; |
| 624 | err << "Ambiguous input channel: " | ||
| 625 | 5 | << (kinds.empty() ? "no kind is registered" | |
| 626 | : "more than one kind is registered") | ||
| 627 |
5/8✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 5 times.
✗ Branch 10 not taken.
|
10 | << " (name one explicitly)."; |
| 628 |
2/4✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
|
5 | throw UnknownChannel(err.str()); |
| 629 | } | ||
| 630 | 3 | return kinds.front().name; | |
| 631 | } | ||
| 632 | |||
| 633 | /****************************************************************************/ | ||
| 634 | |||
| 635 | 14 | string SubDevice::soleOutputKind() const | |
| 636 | { | ||
| 637 | 14 | const auto &kinds = outputKinds(); | |
| 638 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 12 times.
|
14 | if (kinds.size() != 1) { |
| 639 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | stringstream err; |
| 640 | err << "Ambiguous output channel: " | ||
| 641 | 2 | << (kinds.empty() ? "no kind is registered" | |
| 642 | : "more than one kind is registered") | ||
| 643 |
4/8✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
|
4 | << " (name one explicitly)."; |
| 644 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
2 | throw UnknownChannel(err.str()); |
| 645 | } | ||
| 646 | 12 | return kinds.front().name; | |
| 647 | } | ||
| 648 | |||
| 649 | } // namespace EcApp | ||
| 650 | |||
| 651 | /****************************************************************************/ | ||
| 652 |