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

traintastic / traintastic / 23088148108

14 Mar 2026 12:40PM UTC coverage: 26.661% (-0.2%) from 26.84%
23088148108

push

github

reinder
[cbus] added input support for short/long events

0 of 133 new or added lines in 4 files covered. (0.0%)

587 existing lines in 20 files now uncovered.

8246 of 30929 relevant lines covered (26.66%)

185.83 hits per line

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

6.67
/server/src/lua/object/interface.cpp
1
/**
2
 * This file is part of Traintastic,
3
 * see <https://github.com/traintastic/traintastic>.
4
 *
5
 * Copyright (C) 2024-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 "interface.hpp"
23
#include <traintastic/enum/outputchannel.hpp>
24
#include "object.hpp"
25
#include "../sandbox.hpp"
26
#include "../script.hpp"
27
#include "../check.hpp"
28
#include "../checkarguments.hpp"
29
#include "../checkvector.hpp"
30
#include "../enum.hpp"
31
#include "../push.hpp"
32
#include "../to.hpp"
33
#include "../metatable.hpp"
34
#include "../../hardware/input/inputcontroller.hpp"
35
#include "../../hardware/input/input.hpp"
36
#include "../../hardware/output/outputcontroller.hpp"
37
#include "../../hardware/output/output.hpp"
38

39
namespace Lua::Object {
40

41
void Interface::registerType(lua_State* L)
99✔
42
{
43
  MetaTable::clone(L, Object::metaTableName, metaTableName);
99✔
44
  lua_pushcfunction(L, __index);
99✔
45
  lua_setfield(L, -2, "__index");
99✔
46
  lua_pop(L, 1);
99✔
47
}
99✔
48

UNCOV
49
int Interface::index(lua_State* L, ::Interface& object)
×
50
{
51
  const auto key = to<std::string_view>(L, 2);
×
UNCOV
52
  if(auto* inputController = dynamic_cast<::InputController*>(&object))
×
53
  {
UNCOV
54
    LUA_OBJECT_PROPERTY(input_channels)
×
55
    {
56
      auto channels = inputController->inputChannels();
×
57
      lua_createtable(L, static_cast<int>(channels.size()), 0);
×
58
      lua_Integer n = 1;
×
UNCOV
59
      for(auto channel : channels)
×
60
      {
61
        Enum<std::remove_const_t<decltype(channels)::element_type>>::push(L, channel);
×
62
        lua_rawseti(L, -2, n);
×
UNCOV
63
        n++;
×
64
      }
UNCOV
65
      return 1;
×
66
    }
UNCOV
67
    LUA_OBJECT_METHOD(get_input)
×
68
  }
UNCOV
69
  if(auto* outputController = dynamic_cast<::OutputController*>(&object))
×
70
  {
UNCOV
71
    LUA_OBJECT_PROPERTY(output_channels)
×
72
    {
73
      auto channels = outputController->outputChannels();
×
74
      lua_createtable(L, static_cast<int>(channels.size()), 0);
×
75
      lua_Integer n = 1;
×
UNCOV
76
      for(auto channel : channels)
×
77
      {
78
        Enum<std::remove_const_t<decltype(channels)::element_type>>::push(L, channel);
×
79
        lua_rawseti(L, -2, n);
×
UNCOV
80
        n++;
×
81
      }
UNCOV
82
      return 1;
×
83
    }
UNCOV
84
    LUA_OBJECT_METHOD(get_output)
×
85
  }
UNCOV
86
  return Object::index(L, object);
×
87
}
88

UNCOV
89
int Interface::__index(lua_State* L)
×
90
{
UNCOV
91
  return index(L, *check<::Interface>(L, 1));
×
92
}
93

UNCOV
94
int Interface::get_input(lua_State* L)
×
95
{
96
  checkArguments(L, 1, 3);
×
97
  auto inputController = std::dynamic_pointer_cast<::InputController>(check<::Interface>(L, lua_upvalueindex(1)));
×
98
  assert(inputController);
×
99
  const auto inputChannels = inputController->inputChannels();
×
100
  assert(!inputChannels.empty());
×
101

102
  int index = 1;
×
103

104
  InputChannel channel;
105
  if(inputChannels.size() != 1) // channel required
×
106
  {
107
    channel = Enum<InputChannel>::check(L, index);
×
108
    index++;
×
109
  }
UNCOV
110
  else if(Enum<InputChannel>::test(L, index, channel)) // channel optional
×
111
  {
112
    index++;
×
113
  }
114
  else // channel implicit (there is only one)
115
  {
UNCOV
116
    channel = inputChannels.front();
×
117
  }
118

119
  InputLocation location;
×
120
  if(hasAddressLocation(channel))
×
121
  {
122
    checkArguments(L, index);
×
123
    location = InputAddress(check<uint32_t>(L, index));
×
124
  }
UNCOV
125
  else if(hasNodeAddressLocation(channel))
×
126
  {
UNCOV
127
    checkArguments(L, index + 1);
×
128
    location = InputNodeAddress(check<uint32_t>(L, index), check<uint32_t>(L, index + 1));
×
129
  }
UNCOV
130
  else [[unlikely]]
×
131
  {
UNCOV
132
    assert(false);
×
133
    errorInternal(L);
134
  }
135
  auto& stateData = Lua::Sandbox::getStateData(L);
×
136
  auto input = inputController->getInput(channel, location, stateData.script());
×
137
  if(input)
×
138
  {
139
    stateData.registerInput(inputController, input);
×
140
    Lua::push(L, input);
×
141
  }
142
  else
143
  {
144
    Lua::push(L, nullptr);
×
145
  }
146
  return 1;
×
147
}
×
148

149
int Interface::get_output(lua_State* L)
×
150
{
151
  checkArguments(L, 2, 3);
×
UNCOV
152
  auto outputController = std::dynamic_pointer_cast<::OutputController>(check<::Interface>(L, lua_upvalueindex(1)));
×
153
  assert(outputController);
×
154
  auto channel = check<::OutputChannel>(L, 1);
×
UNCOV
155
  OutputLocation location;
×
UNCOV
156
  switch(channel)
×
157
  {
158
    using enum OutputChannel;
159

160
    case Output:
×
161
    case Accessory:
162
    case AccessoryDCC:
163
    case AccessoryMotorola:
164
    case DCCext:
165
    case Turnout:
166
    case ShortEvent:
UNCOV
167
      checkArguments(L, 2);
×
UNCOV
168
      location = OutputAddress(check<uint32_t>(L, 2));
×
UNCOV
169
      break;
×
170

UNCOV
171
    case LongEvent:
×
UNCOV
172
      checkArguments(L, 3);
×
UNCOV
173
      location = OutputNodeAddress(check<uint32_t>(L, 2), check<uint32_t>(L, 3));
×
UNCOV
174
      break;
×
175

UNCOV
176
    case ECoSObject:
×
UNCOV
177
      checkArguments(L, 2);
×
UNCOV
178
      location = OutputECoSObject(check<uint16_t>(L, 2));
×
UNCOV
179
      break;
×
180
  }
UNCOV
181
  auto& stateData = Lua::Sandbox::getStateData(L);
×
UNCOV
182
  auto output = outputController->getOutput(channel, location, stateData.script());
×
UNCOV
183
  if(output)
×
184
  {
UNCOV
185
    stateData.registerOutput(outputController, output);
×
UNCOV
186
    Lua::push(L, output);
×
187
  }
188
  else
189
  {
UNCOV
190
    Lua::push(L, nullptr);
×
191
  }
UNCOV
192
  return 1;
×
UNCOV
193
}
×
194

195
}
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