• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

traintastic / traintastic / 23719854638

29 Mar 2026 09:47PM UTC coverage: 25.872% (-0.3%) from 26.14%
23719854638

push

github

reinder
[cbus] added CANCAB node in simulation

0 of 12 new or added lines in 2 files covered. (0.0%)

648 existing lines in 6 files now uncovered.

8256 of 31911 relevant lines covered (25.87%)

180.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/server/src/hardware/interface/cbusinterface.cpp
1
/**
2
 * This file is part of Traintastic,
3
 * see <https://github.com/traintastic/traintastic>.
4
 *
5
 * Copyright (C) 2026 Reinder Feenstra
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 *
12
 * This program 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
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
 */
21

22
#include "cbusinterface.hpp"
23
#include "cbus/cbusnodelist.hpp"
24
#include "cbus/cbussessionlist.hpp"
25
#include "cbus/cbussettings.hpp"
26
#include "../decoder/decoderchangeflags.hpp"
27
#include "../decoder/list/decoderlist.hpp"
28
#include "../decoder/list/decoderlisttablemodel.hpp"
29
#include "../input/list/inputlist.hpp"
30
#include "../output/list/outputlist.hpp"
31
#include "../protocol/cbus/cbusconst.hpp"
32
#include "../protocol/cbus/cbuskernel.hpp"
33
#include "../protocol/cbus/iohandler/cbuscanusbiohandler.hpp"
34
#include "../protocol/cbus/iohandler/cbuscanetheriohandler.hpp"
35
#include "../protocol/cbus/iohandler/cbussimulationiohandler.hpp"
36
#ifdef __linux__
37
  #include "../protocol/cbus/iohandler/cbussocketcaniohandler.hpp"
38
#endif
39
#include "../protocol/cbus/simulator/cbussimulator.hpp"
40
#include "../protocol/cbus/simulator/module/cbuscancab.hpp"
41
#include "../protocol/cbus/simulator/module/cbuscancmd.hpp"
42
#include "../../core/attributes.hpp"
43
#include "../../core/eventloop.hpp"
44
#include "../../core/method.tpp"
45
#include "../../core/objectproperty.tpp"
46
#include "../../log/log.hpp"
47
#include "../../log/logmessageexception.hpp"
48
#include "../../utils/displayname.hpp"
49
#include "../../utils/inrange.hpp"
50
#include "../../world/world.hpp"
51

52
constexpr auto decoderListColumns = DecoderListColumn::Id | DecoderListColumn::Name | DecoderListColumn::Address;
53
constexpr auto inputListColumns = InputListColumn::Channel | InputListColumn::Node | InputListColumn::Address;
54
constexpr auto outputListColumns = OutputListColumn::Channel | OutputListColumn::Node | OutputListColumn::Address;
55

56
constexpr auto nodeNumberRange = std::make_pair(std::numeric_limits<uint16_t>::min(), std::numeric_limits<uint16_t>::max());
57
constexpr auto eventNumberRange = std::make_pair(std::numeric_limits<uint16_t>::min(), std::numeric_limits<uint16_t>::max());
58

UNCOV
59
CREATE_IMPL(CBUSInterface)
×
60

UNCOV
61
CBUSInterface::CBUSInterface(World& world, std::string_view _id)
×
62
  : Interface(world, _id)
63
  , DecoderController(*this, decoderListColumns)
64
  , InputController(static_cast<IdObject&>(*this))
65
  , OutputController(static_cast<IdObject&>(*this))
66
  , type{this, "type", CBUSInterfaceType::CANUSB, PropertyFlags::ReadWrite | PropertyFlags::Store,
×
UNCOV
67
      [this](CBUSInterfaceType /*value*/)
×
68
      {
69
        updateVisible();
×
70
      }}
×
71
  , device{this, "device", "", PropertyFlags::ReadWrite | PropertyFlags::Store}
×
72
  , hostname{this, "hostname", "", PropertyFlags::ReadWrite | PropertyFlags::Store}
×
73
  , port{this, "port", 0, PropertyFlags::ReadWrite | PropertyFlags::Store}
×
74
  , interface{this, "interface", "", PropertyFlags::ReadWrite | PropertyFlags::Store}
×
75
  , canId{this, "can_id", 0x7D, PropertyFlags::ReadWrite | PropertyFlags::Store}
×
76
  , cbus{this, "cbus", nullptr, PropertyFlags::ReadOnly | PropertyFlags::Store | PropertyFlags::SubObject}
×
UNCOV
77
  , cbusNodeList{this, "cbus_node_list", nullptr, PropertyFlags::ReadOnly | PropertyFlags::NoStore | PropertyFlags::SubObject}
×
78
  , cbusSessionList{this, "cbus_session_list", nullptr, PropertyFlags::ReadOnly | PropertyFlags::NoStore | PropertyFlags::SubObject}
×
79
{
80
  name = "CBUS/VLCB";
×
UNCOV
81
  cbus.setValueInternal(std::make_shared<CBUSSettings>(*this, cbus.name()));
×
82
  cbusNodeList.setValueInternal(std::make_shared<CBUSNodeList>(*this, cbusNodeList.name()));
×
83
  cbusSessionList.setValueInternal(std::make_shared<CBUSSessionList>(*this, cbusSessionList.name()));
×
84

85
  Attributes::addDisplayName(type, DisplayName::Interface::type);
×
UNCOV
86
  Attributes::addEnabled(type, !online);
×
87
  Attributes::addValues(type, CBUSInterfaceTypeValues);
×
88
  m_interfaceItems.insertBefore(type, notes);
×
89

UNCOV
90
  Attributes::addEnabled(device, !online);
×
91
  Attributes::addVisible(device, false);
×
92
  m_interfaceItems.insertBefore(device, notes);
×
93

94
  Attributes::addDisplayName(hostname, DisplayName::IP::hostname);
×
UNCOV
95
  Attributes::addEnabled(hostname, !online);
×
96
  Attributes::addVisible(hostname, false);
×
97
  m_interfaceItems.insertBefore(hostname, notes);
×
98

99
  Attributes::addDisplayName(port, DisplayName::IP::port);
×
UNCOV
100
  Attributes::addEnabled(port, !online);
×
101
  Attributes::addVisible(port, false);
×
102
  m_interfaceItems.insertBefore(port, notes);
×
103

104
  Attributes::addDisplayName(interface, DisplayName::Hardware::interface);
×
UNCOV
105
  Attributes::addEnabled(interface, !online);
×
106
  Attributes::addVisible(interface, false);
×
107
  m_interfaceItems.insertBefore(interface, notes);
×
108

109
  Attributes::addEnabled(canId, !online);
×
UNCOV
110
  Attributes::addMinMax(canId, CBUS::canIdMin, CBUS::canIdMax);
×
111
  Attributes::addVisible(canId, false);
×
UNCOV
112
  m_interfaceItems.insertBefore(canId, notes);
×
113

UNCOV
114
  m_interfaceItems.insertBefore(cbus, notes);
×
115

UNCOV
116
  m_interfaceItems.insertBefore(cbusNodeList, notes);
×
117

UNCOV
118
  m_interfaceItems.insertBefore(cbusSessionList, notes);
×
119

UNCOV
120
  m_interfaceItems.insertBefore(decoders, notes);
×
121

122
  m_interfaceItems.insertBefore(inputs, notes);
×
123

124
  m_interfaceItems.insertBefore(outputs, notes);
×
125

126
  m_cbusPropertyChanged = cbus->propertyChanged.connect(
×
UNCOV
127
    [this](BaseProperty& /*property*/)
×
128
    {
UNCOV
129
      if(m_kernel)
×
130
      {
131
        m_kernel->setConfig(cbus->config());
×
132
      }
133
    });
×
134

135
  updateVisible();
×
UNCOV
136
}
×
137

UNCOV
138
CBUSInterface::~CBUSInterface() = default;
×
139

UNCOV
140
bool CBUSInterface::send(std::vector<uint8_t> message)
×
141
{
UNCOV
142
  if(m_kernel)
×
143
  {
144
    return m_kernel->send(std::move(message));
×
145
  }
146
  return false;
×
147
}
148

UNCOV
149
bool CBUSInterface::sendDCC(std::vector<uint8_t> dccPacket, uint8_t repeat)
×
150
{
UNCOV
151
  if(m_kernel)
×
152
  {
153
    return m_kernel->sendDCC(std::move(dccPacket), repeat);
×
154
  }
UNCOV
155
  return false;
×
156
}
157

UNCOV
158
std::span<const DecoderProtocol> CBUSInterface::decoderProtocols() const
×
159
{
160
  static constexpr std::array<DecoderProtocol, 2> protocols{DecoderProtocol::DCCShort, DecoderProtocol::DCCLong};
161
  return std::span<const DecoderProtocol>{protocols.data(), protocols.size()};
×
162
}
163

UNCOV
164
void CBUSInterface::decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber)
×
165
{
UNCOV
166
  if(m_kernel)
×
167
  {
UNCOV
168
    const bool longAddress = (decoder.protocol == DecoderProtocol::DCCLong);
×
169

UNCOV
170
    if(has(changes, DecoderChangeFlags::FunctionValue) && functionNumber <= CBUS::engineFunctionMax)
×
171
    {
UNCOV
172
      m_kernel->setEngineFunction(
×
173
        decoder.address,
174
        longAddress,
175
        static_cast<uint8_t>(functionNumber),
UNCOV
176
        decoder.getFunctionValue(functionNumber));
×
177
    }
178
    else
179
    {
UNCOV
180
      m_kernel->setEngineSpeedDirection(
×
181
        decoder.address,
182
        longAddress,
UNCOV
183
        Decoder::throttleToSpeedStep<uint8_t>(decoder.throttle, decoder.speedSteps),
×
184
        decoder.speedSteps,
185
        decoder.emergencyStop,
186
        decoder.direction == Direction::Forward);
×
187
    }
188
  }
UNCOV
189
}
×
190

UNCOV
191
std::span<const InputChannel> CBUSInterface::inputChannels() const
×
192
{
193
  static const std::array<InputChannel, 2> channels{
194
    InputChannel::ShortEvent,
195
    InputChannel::LongEvent,
196
  };
197
  return channels;
×
198
}
199

200
bool CBUSInterface::isInputLocation(InputChannel channel, const InputLocation& location) const
×
201
{
UNCOV
202
  if(hasNodeAddressLocation(channel))
×
203
  {
204
    return
UNCOV
205
      inRange<uint32_t>(std::get<InputNodeAddress>(location).node, nodeNumberRange) &&
×
206
      inRange<uint32_t>(std::get<InputNodeAddress>(location).address, inputAddressMinMax(channel));
×
207
  }
208
  return InputController::isInputLocation(channel, location);
×
209
}
210

211
std::pair<uint32_t, uint32_t> CBUSInterface::inputAddressMinMax(InputChannel /*channel*/) const
×
212
{
213
  return eventNumberRange;
×
214
}
215

216
void CBUSInterface::inputSimulateChange(InputChannel channel, const InputLocation& location, SimulateInputAction action)
×
217
{
218
  if(m_simulator)
×
219
  {
220
    boost::asio::post(m_kernel->ioContext(),
×
221
      [this, channel, location, action]
×
222
      {
UNCOV
223
        switch(channel)
×
224
        {
225
          case InputChannel::ShortEvent:
×
226
            m_simulator->shortEvent(std::get<InputAddress>(location).address, action);
×
UNCOV
227
            break;
×
228

229
          case InputChannel::LongEvent:
×
UNCOV
230
            m_simulator->longEvent(std::get<InputNodeAddress>(location).node, std::get<InputNodeAddress>(location).address, action);
×
UNCOV
231
            break;
×
232

UNCOV
233
          default: [[unlikely]]
×
234
            assert(false);
×
235
            break;
236
        }
UNCOV
237
      });
×
238
  }
UNCOV
239
}
×
240

UNCOV
241
std::span<const OutputChannel> CBUSInterface::outputChannels() const
×
242
{
243
  static const std::array<OutputChannel, 4> channels{
244
    OutputChannel::ShortEvent,
245
    OutputChannel::LongEvent,
246
    OutputChannel::AccessoryDCC,
247
    OutputChannel::DCCext,
248
  };
249
  return channels;
×
250
}
251

252
std::pair<uint32_t, uint32_t> CBUSInterface::outputNodeMinMax(OutputChannel /*channel*/) const
×
253
{
254
  return eventNumberRange;
×
255
}
256

UNCOV
257
std::pair<uint32_t, uint32_t> CBUSInterface::outputAddressMinMax(OutputChannel channel) const
×
258
{
UNCOV
259
  switch(channel)
×
260
  {
261
    case OutputChannel::LongEvent:
×
262
    case OutputChannel::ShortEvent:
UNCOV
263
      return {std::numeric_limits<uint16_t>::min(), std::numeric_limits<uint16_t>::max()};
×
264

265
    default:
×
UNCOV
266
      return OutputController::outputAddressMinMax(channel);
×
267
  }
268
}
269

UNCOV
270
bool CBUSInterface::setOutputValue(OutputChannel channel, const OutputLocation& location, OutputValue value)
×
271
{
272
  if(m_kernel)
×
273
  {
UNCOV
274
    switch(channel)
×
275
    {
276
      case OutputChannel::ShortEvent:
×
277
        assert(std::holds_alternative<TriState>(value));
×
278
        if(auto v = std::get<TriState>(value); v != TriState::Undefined)
×
279
        {
280
          assert(std::holds_alternative<OutputAddress>(location));
×
UNCOV
281
          const auto address = static_cast<uint16_t>(std::get<OutputAddress>(location).address);
×
282
          m_kernel->setAccessoryShort(address, v == TriState::True);
×
283
          return true;
×
284
        }
UNCOV
285
        break;
×
286

287
      case OutputChannel::LongEvent:
×
288
        assert(std::holds_alternative<TriState>(value));
×
289
        if(auto v = std::get<TriState>(value); v != TriState::Undefined)
×
290
        {
UNCOV
291
          assert(std::holds_alternative<OutputNodeAddress>(location));
×
292
          const auto node = static_cast<uint16_t>(std::get<OutputNodeAddress>(location).node);
×
UNCOV
293
          const auto address = static_cast<uint16_t>(std::get<OutputNodeAddress>(location).address);
×
294
          m_kernel->setAccessory(node, address, v == TriState::True);
×
295
          return true;
×
296
        }
UNCOV
297
        break;
×
298

299
      case OutputChannel::AccessoryDCC:
×
300
        assert(std::holds_alternative<OutputPairValue>(value));
×
301
        if(const auto v = std::get<OutputPairValue>(value); v == OutputPairValue::First || v == OutputPairValue::Second)
×
302
        {
303
          assert(std::holds_alternative<OutputAddress>(location));
×
UNCOV
304
          const auto address = static_cast<uint16_t>(std::get<OutputAddress>(location).address);
×
305
          m_kernel->setDccAccessory(address, v == OutputPairValue::Second);
×
306
          return true;
×
307
        }
UNCOV
308
        break;
×
309

310
      case OutputChannel::DCCext:
×
311
        assert(std::holds_alternative<int16_t>(value));
×
312
        if(const auto v = std::get<int16_t>(value); inRange<int16_t>(v, std::numeric_limits<uint8_t>::min(), std::numeric_limits<uint8_t>::max()))
×
313
        {
314
          assert(std::holds_alternative<OutputAddress>(location));
×
UNCOV
315
          const auto address = static_cast<uint16_t>(std::get<OutputAddress>(location).address);
×
316
          m_kernel->setDccAdvancedAccessoryValue(address, static_cast<uint8_t>(v));
×
317
          return true;
×
318
        }
UNCOV
319
        break;
×
320

321
      default: [[unlikely]]
×
UNCOV
322
        assert(false);
×
323
        break;
324
    }
325
  }
326
  return false;
×
327
}
328

329
void CBUSInterface::addToWorld()
×
330
{
UNCOV
331
  Interface::addToWorld();
×
332
  DecoderController::addToWorld();
×
UNCOV
333
  InputController::addToWorld(inputListColumns);
×
334
  OutputController::addToWorld(outputListColumns);
×
UNCOV
335
}
×
336

337
void CBUSInterface::loaded()
×
338
{
339
  Interface::loaded();
×
340

341
  updateVisible();
×
342
}
×
343

344
void CBUSInterface::destroying()
×
345
{
346
  m_cbusPropertyChanged.disconnect();
×
UNCOV
347
  OutputController::destroying();
×
348
  InputController::destroying();
×
UNCOV
349
  DecoderController::destroying();
×
350
  Interface::destroying();
×
UNCOV
351
}
×
352

UNCOV
353
void CBUSInterface::worldEvent(WorldState state, WorldEvent event)
×
354
{
355
  Interface::worldEvent(state, event);
×
356

357
  switch(event)
×
358
  {
359
    case WorldEvent::PowerOff:
×
UNCOV
360
      if(m_kernel)
×
361
      {
362
        m_kernel->trackOff();
×
363
      }
364
      break;
×
365

366
    case WorldEvent::PowerOn:
×
UNCOV
367
      if(m_kernel)
×
368
      {
369
        m_kernel->trackOn();
×
370
      }
371
      break;
×
372

373
    case WorldEvent::Stop:
×
UNCOV
374
      if(m_kernel)
×
375
      {
376
        m_kernel->requestEmergencyStop();
×
377
      }
UNCOV
378
      break;
×
379

380
    case WorldEvent::Run:
×
UNCOV
381
      if(m_kernel)
×
382
      {
383
        // TODO: send all known speed values
384
      }
385
      break;
×
386

387
    default:
×
UNCOV
388
      break;
×
389
  }
UNCOV
390
}
×
391

UNCOV
392
bool CBUSInterface::setOnline(bool& value, bool simulation)
×
393
{
UNCOV
394
  if(!m_kernel && value)
×
395
  {
396
    try
397
    {
UNCOV
398
      if(simulation)
×
399
      {
UNCOV
400
        m_simulator = std::make_unique<CBUS::Simulator>();
×
401
        m_simulator->addModule(std::make_unique<CBUS::Module::CANCMD>(*m_simulator));
×
NEW
402
        m_simulator->addModule(std::make_unique<CBUS::Module::CANCAB>(*m_simulator));
×
403
        m_kernel = CBUS::Kernel::create<CBUS::SimulationIOHandler>(id.value(), cbus->config(), std::ref(*m_simulator));
×
404
      }
405
      else
406
      {
UNCOV
407
        switch(type)
×
408
        {
409
          case CBUSInterfaceType::CANUSB:
×
410
            m_kernel = CBUS::Kernel::create<CBUS::CANUSBIOHandler>(id.value(), cbus->config(), device.value());
×
UNCOV
411
            break;
×
412

UNCOV
413
          case CBUSInterfaceType::CANEther:
×
414
            m_kernel = CBUS::Kernel::create<CBUS::CANEtherIOHandler>(id.value(), cbus->config(), hostname.value(), port.value());
×
415
            break;
×
416

UNCOV
417
          case CBUSInterfaceType::SocketCAN:
×
418
#ifdef __linux__
UNCOV
419
            m_kernel = CBUS::Kernel::create<CBUS::SocketCANIOHandler>(id.value(), cbus->config(), interface.value(), canId.value());
×
UNCOV
420
            break;
×
421
#else
422
            setState(InterfaceState::Error);
423
            Log::log(*this, LogMessage::C2005_SOCKETCAN_IS_ONLY_AVAILABLE_ON_LINUX);
424
            return false;
425
#endif
426
        }
427
      }
428

429
      setState(InterfaceState::Initializing);
×
430

431
      m_kernel->setOnStarted(
×
432
        [this]()
×
433
        {
434
          setState(InterfaceState::Online);
×
435
        });
×
436
      m_kernel->setOnError(
×
437
        [this]()
×
438
        {
UNCOV
439
          setState(InterfaceState::Error);
×
440
          online = false; // communication no longer possible
×
UNCOV
441
        });
×
UNCOV
442
      m_kernel->onPresenceOfNode =
×
UNCOV
443
        [this](uint8_t canId_, uint16_t nodeNumber, uint8_t manufacturerId, uint8_t moduleId, bool flimMode, bool supportsServiceDiscovery)
×
444
        {
UNCOV
445
          cbusNodeList->add(CBUSNodeList::Node{
×
446
            .nodeNumber = nodeNumber,
447
            .canId = canId_,
448
            .manufacturerId = manufacturerId,
449
            .moduleId = moduleId,
450
            .flim = flimMode,
451
            .vlcb = supportsServiceDiscovery,
452
            .parameters = {},
453
          });
454
        };
×
455
      m_kernel->onNodeParameterResponse =
×
UNCOV
456
        [this](uint8_t canId_, uint16_t nodeNumber, CBUS::NodeParameter parameter, uint8_t parameterValue)
×
457
        {
458
          auto& nodes = cbusNodeList->m_nodes;
×
UNCOV
459
          if(auto it = std::find_if(nodes.begin(), nodes.end(),
×
460
              [canId_, nodeNumber](const auto& item)
×
461
              {
UNCOV
462
                return item.canId == canId_ && item.nodeNumber == nodeNumber;
×
UNCOV
463
              }); it != nodes.end())
×
464
          {
465
            switch(parameter)
×
466
            {
467
              using enum CBUS::NodeParameter;
468

469
              case VersionMajor:
×
470
                it->parameters.versionMajor = parameterValue;
×
UNCOV
471
                break;
×
472

473
              case VersionMinor:
×
474
                it->parameters.versionMinor = parameterValue;
×
UNCOV
475
                break;
×
476

477
              case BetaReleaseCode:
×
UNCOV
478
                it->parameters.betaReleaseCode = parameterValue;
×
479
                break;
×
480

481
              default:
×
482
                return;
×
483
            }
UNCOV
484
            cbusNodeList->rowChanged(static_cast<uint32_t>(std::distance(nodes.begin(), it)));
×
485
          }
UNCOV
486
        };
×
487
      m_kernel->onTrackOff =
×
UNCOV
488
        [this]()
×
489
        {
490
          if(contains(m_world.state, WorldState::PowerOn))
×
491
          {
UNCOV
492
            m_world.powerOff();
×
493
          }
UNCOV
494
        };
×
495
      m_kernel->onTrackOn =
×
UNCOV
496
        [this]()
×
497
        {
498
          if(!contains(m_world.state, WorldState::PowerOn))
×
499
          {
UNCOV
500
            m_world.powerOn();
×
501
          }
UNCOV
502
        };
×
503
      m_kernel->onEmergencyStop =
×
UNCOV
504
        [this]()
×
505
        {
506
          if(contains(m_world.state, WorldState::Run))
×
507
          {
UNCOV
508
            m_world.stop();
×
509
          }
510
        };
×
511
      m_kernel->onEngineSessionAcquire =
×
512
        [this](uint8_t session, uint16_t address, bool isLongAddress)
×
513
        {
UNCOV
514
          if(auto it = cbusSessionList->findEngine(address, isLongAddress); it != cbusSessionList->end())
×
515
          {
516
            it->session = session;
×
517
            cbusSessionList->rowChanged(static_cast<uint32_t>(std::distance(cbusSessionList->begin(), it)));
×
518
          }
519
          else
520
          {
521
            cbusSessionList->add({session, address, isLongAddress});
×
522
          }
523
        };
×
UNCOV
524
      m_kernel->onEngineSpeedDirectionChanged =
×
525
        [this](uint8_t session, uint8_t speed, bool forward)
×
526
        {
527
          if(auto it = cbusSessionList->findSession(session); it != cbusSessionList->end())
×
528
          {
UNCOV
529
            it->speed = speed;
×
530
            it->direction = forward ? Direction::Forward : Direction::Reverse;
×
UNCOV
531
            cbusSessionList->rowChanged(static_cast<uint32_t>(std::distance(cbusSessionList->begin(), it)));
×
532
          }
UNCOV
533
        };
×
534
      m_kernel->onEngineFunctionChanged =
×
535
        [this](uint8_t session, uint8_t number, bool on)
×
536
        {
UNCOV
537
          if(auto it = cbusSessionList->findSession(session); it != cbusSessionList->end())
×
538
          {
UNCOV
539
            assert(number < it->functions.size());
×
540
            it->functions[number] = toTriState(on);
×
UNCOV
541
            cbusSessionList->rowChanged(static_cast<uint32_t>(std::distance(cbusSessionList->begin(), it)));
×
542
          }
UNCOV
543
        };
×
UNCOV
544
      m_kernel->onEngineSessionReleased =
×
545
        [this](uint8_t session)
×
546
        {
UNCOV
547
          if(auto it = cbusSessionList->findSession(session); it != cbusSessionList->end())
×
548
          {
UNCOV
549
            it->session = std::nullopt;
×
550
            cbusSessionList->rowChanged(static_cast<uint32_t>(std::distance(cbusSessionList->begin(), it)));
×
551
          }
552
        };
×
553
      m_kernel->onEngineSessionCancelled =
×
UNCOV
554
        [this](uint16_t address, bool isLongAddress)
×
555
        {
UNCOV
556
          if(auto it = cbusSessionList->findEngine(address, isLongAddress); it != cbusSessionList->end())
×
557
          {
UNCOV
558
            it->session = std::nullopt;
×
UNCOV
559
            cbusSessionList->rowChanged(static_cast<uint32_t>(std::distance(cbusSessionList->begin(), it)));
×
560
          }
UNCOV
561
        };
×
UNCOV
562
      m_kernel->onShortEvent =
×
UNCOV
563
        [this](uint16_t eventNumber, bool on)
×
564
        {
UNCOV
565
          updateInputValue(InputChannel::ShortEvent, InputAddress(eventNumber), toTriState(on));
×
UNCOV
566
          updateOutputValue(OutputChannel::ShortEvent, OutputAddress(eventNumber), toTriState(on));
×
UNCOV
567
        };
×
UNCOV
568
      m_kernel->onLongEvent =
×
UNCOV
569
        [this](uint16_t nodeNumber, uint16_t eventNumber, bool on)
×
570
        {
UNCOV
571
          updateInputValue(InputChannel::LongEvent, InputNodeAddress(nodeNumber, eventNumber), toTriState(on));
×
UNCOV
572
          updateOutputValue(OutputChannel::LongEvent, OutputNodeAddress(nodeNumber, eventNumber), toTriState(on));
×
UNCOV
573
        };
×
574

UNCOV
575
      m_kernel->start();
×
576

UNCOV
577
      Attributes::setEnabled({type, device, hostname, port, interface, canId}, false);
×
578
    }
UNCOV
579
    catch(const LogMessageException& e)
×
580
    {
UNCOV
581
      setState(InterfaceState::Offline);
×
UNCOV
582
      Log::log(*this, e.message(), e.args());
×
UNCOV
583
      return false;
×
UNCOV
584
    }
×
585
  }
UNCOV
586
  else if(m_kernel && !value)
×
587
  {
UNCOV
588
    Attributes::setEnabled({type, device, hostname, port, interface, canId}, true);
×
589

UNCOV
590
    m_kernel->stop();
×
UNCOV
591
    EventLoop::deleteLater(m_kernel.release());
×
UNCOV
592
    EventLoop::deleteLater(m_simulator.release());
×
593

UNCOV
594
    cbusNodeList->clear();
×
595

UNCOV
596
    if(status->state != InterfaceState::Error)
×
597
    {
UNCOV
598
      setState(InterfaceState::Offline);
×
599
    }
600
  }
UNCOV
601
  return true;
×
602
}
603

UNCOV
604
void CBUSInterface::updateVisible()
×
605
{
UNCOV
606
  Attributes::setVisible(device, (type == CBUSInterfaceType::CANUSB));
×
UNCOV
607
  Attributes::setVisible({hostname, port}, (type == CBUSInterfaceType::CANEther));
×
UNCOV
608
  Attributes::setVisible({interface, canId}, (type == CBUSInterfaceType::SocketCAN));
×
UNCOV
609
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc