GCC Code Coverage Report


Directory: src/
File: src/UserSignal.cpp
Date: 2026-09-03 17:04:53
Exec Total Coverage
Lines: 78 80 97.5%
Branches: 99 150 66.0%

Line Branch Exec Source
1 /*****************************************************************************
2 *
3 * Copyright (C) 2021 - 2022 Jonathan Grahl <jonathan.grahl@igh.de>
4 * 2021 - 2022 Florian Pose <florian.pose@igh.de>
5 *
6 * This file is part of the reta library (realtime-automation).
7 *
8 * The reta library is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation, either version 3 of the License, or (at
11 * your option) any later version.
12 *
13 * The reta library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with the reta library. If not, see <http://www.gnu.org/licenses/>.
20 *
21 ****************************************************************************/
22
23 #include "reta/UserSignal.h"
24
25 #include "Base.h"
26
27 #include <algorithm> // max(), min()
28 #include <cstdint> // uint8_t, uint32_T
29 #include <cstring> // memcpy()
30 #include <iostream>
31 #include <limits> // numeric_limits
32 #include <sstream> // stringstream
33 #include <type_traits> // is_same
34 #include <utility> // pair
35
36 using std::invalid_argument;
37 using std::is_same;
38 using std::make_unique;
39 using std::max;
40 using std::min;
41 using std::numeric_limits;
42 using std::shared_ptr;
43 using std::string;
44 using std::stringstream;
45 using std::vector;
46
47 using namespace Reta;
48
49 /****************************************************************************/
50
51 template <class T>
52 struct Limit
53 {
54 Limit();
55 T lower;
56 T upper;
57 };
58
59 /****************************************************************************/
60
61 template <class T>
62 49 Limit<T>::Limit()
63 {
64 if (is_same<T, double>::value) {
65 17 lower = -numeric_limits<T>::infinity();
66 17 upper = numeric_limits<T>::infinity();
67 }
68 else {
69 32 lower = numeric_limits<T>::min();
70 32 upper = numeric_limits<T>::max();
71 }
72 49 }
73
74 /****************************************************************************/
75
76 template <class T>
77 60 int checkLimits(
78 const struct pdvariable *,
79 void *dst,
80 const void *src,
81 size_t len,
82 struct timespec *,
83 void *priv_data)
84 {
85 60 T value = *(T *) src;
86 60 Limit<T> limit = *(Limit<T> *) priv_data;
87
88
12/12
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 11 times.
✓ Branch 8 taken 26 times.
✓ Branch 9 taken 4 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 21 times.
60 if (value < limit.lower || value > limit.upper) {
89 17 return -EINVAL;
90 }
91
92 43 memcpy(dst, src, len);
93 43 return 0;
94 }
95
96 /****************************************************************************/
97
98 template <class T>
99 49 struct RETA_LOCAL UserSignal<T>::Impl : public Base
100 {
101 Impl(shared_ptr<Task>, const string &, unsigned int);
102
103
104 shared_ptr<Task> task;
105 vector<uint8_t> changed;
106 };
107
108 /****************************************************************************/
109
110 template <class T>
111 49 UserSignal<T>::Impl::Impl(
112 shared_ptr<Task> task,
113 const string &prefix,
114 unsigned int width) :
115
3/6
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 15 taken 16 times.
✗ Branch 16 not taken.
✓ Branch 26 taken 17 times.
✗ Branch 27 not taken.
49 Base {prefix}, task {task}, changed(width, false)
116 {
117
3/6
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 17 times.
✗ Branch 8 not taken.
49 checkZeroWidth(width);
118
119
3/6
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 17 times.
✗ Branch 11 not taken.
49 pdtask *pdtask {task->getPdTask()};
120
121
6/12
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✓ Branch 12 taken 16 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 16 times.
✗ Branch 17 not taken.
✓ Branch 22 taken 17 times.
✗ Branch 23 not taken.
✓ Branch 26 taken 17 times.
✗ Branch 27 not taken.
98 pdserv_signal(
122 pdtask, 1, (prefix + "/Changed").c_str(), pd_boolean_T,
123 49 changed.data(), changed.size(), NULL);
124 49 }
125
126 /****************************************************************************/
127
128 template <class T>
129 49 struct RETA_LOCAL UserSignal<T>::Impl_T : public UserSignal<T>::Impl
130 {
131 Impl_T(shared_ptr<Task>, const string &, T, unsigned int);
132
133 vector<T> userValue;
134 vector<T> value;
135 vector<T> lastValue;
136
137 Limit<T> limit;
138 };
139
140 /****************************************************************************/
141
142 template <class T>
143 49 UserSignal<T>::Impl_T::Impl_T(
144 shared_ptr<Task> task,
145 const string &prefix,
146 T initValue,
147 unsigned int width) :
148 Impl {task, prefix, width},
149 userValue(width, initValue),
150 value(width, initValue),
151 lastValue(width, initValue),
152
12/24
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 16 times.
✗ Branch 13 not taken.
✓ Branch 17 taken 16 times.
✗ Branch 18 not taken.
✓ Branch 32 taken 16 times.
✗ Branch 33 not taken.
✓ Branch 37 taken 16 times.
✗ Branch 38 not taken.
✓ Branch 42 taken 16 times.
✗ Branch 43 not taken.
✓ Branch 47 taken 16 times.
✗ Branch 48 not taken.
✓ Branch 62 taken 17 times.
✗ Branch 63 not taken.
✓ Branch 67 taken 17 times.
✗ Branch 68 not taken.
✓ Branch 72 taken 17 times.
✗ Branch 73 not taken.
✓ Branch 77 taken 17 times.
✗ Branch 78 not taken.
49 limit()
153 {
154
3/6
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 17 times.
✗ Branch 11 not taken.
49 pdserv *pdserv {task->getPdServ()};
155
3/6
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 17 times.
✗ Branch 11 not taken.
49 pdtask *pdtask {task->getPdTask()};
156
157
3/6
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 17 times.
✗ Branch 8 not taken.
49 int pd_Type = convertPdType();
158
159
6/12
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✓ Branch 14 taken 16 times.
✗ Branch 15 not taken.
✓ Branch 18 taken 16 times.
✗ Branch 19 not taken.
✓ Branch 25 taken 17 times.
✗ Branch 26 not taken.
✓ Branch 29 taken 17 times.
✗ Branch 30 not taken.
49 pdserv_parameter(
160 pdserv, (prefix + "/UserValue").c_str(), 0666, pd_Type,
161 userValue.data(), userValue.size(), NULL, checkLimits<T>, &limit);
162
6/12
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 16 times.
✗ Branch 8 not taken.
✓ Branch 14 taken 16 times.
✗ Branch 15 not taken.
✓ Branch 18 taken 16 times.
✗ Branch 19 not taken.
✓ Branch 25 taken 17 times.
✗ Branch 26 not taken.
✓ Branch 29 taken 17 times.
✗ Branch 30 not taken.
49 pdserv_signal(
163 pdtask, 1, (prefix + "/Value").c_str(), pd_Type, value.data(),
164 value.size(), NULL);
165 49 }
166
167 /****************************************************************************/
168
169 template class UserSignal<double>;
170 template class UserSignal<int>;
171 template class UserSignal<unsigned int>;
172
173 /****************************************************************************/
174
175 template <class T>
176 52 UserSignal<T>::UserSignal(
177 shared_ptr<Task> task,
178 const string &prefix,
179 T initValue,
180 unsigned int width) :
181 impl {make_unique<Impl_T>(task, prefix, initValue, width)},
182
9/12
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 1 times.
✓ Branch 8 taken 16 times.
✗ Branch 9 not taken.
✓ Branch 17 taken 16 times.
✓ Branch 18 taken 1 times.
✓ Branch 22 taken 16 times.
✗ Branch 23 not taken.
✓ Branch 31 taken 17 times.
✓ Branch 32 taken 1 times.
✓ Branch 36 taken 17 times.
✗ Branch 37 not taken.
55 apply(task, prefix + "/Apply", width)
183
184 49 {}
185
186 /****************************************************************************/
187
188 template <class T>
189 49 UserSignal<T>::~UserSignal()
190 49 {}
191
192 /****************************************************************************/
193
194 template <class T>
195 81 void UserSignal<T>::update()
196 {
197 81 apply.update();
198
199
6/6
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 22 times.
✓ Branch 6 taken 52 times.
✓ Branch 7 taken 22 times.
✓ Branch 10 taken 67 times.
✓ Branch 11 taken 37 times.
252 for (unsigned int i = 0; i < impl->value.size(); i++) {
200
6/6
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 35 times.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 35 times.
✓ Branch 7 taken 32 times.
✓ Branch 8 taken 35 times.
171 if (apply.getChanged(i)) {
201 66 impl->value.at(i) = impl->userValue.at(i);
202 }
203 171 impl->changed.at(i) = impl->value.at(i) != impl->lastValue.at(i);
204 171 impl->lastValue.at(i) = impl->value.at(i);
205 }
206 81 }
207
208 /****************************************************************************/
209
210 template <class T>
211 18 void UserSignal<T>::setValue(T newValue, unsigned int i)
212 {
213 18 impl->value.at(i) = newValue;
214 18 }
215
216 /****************************************************************************/
217
218 template <class T>
219 3 void UserSignal<T>::setValueVector(vector<T> newValueVector)
220 {
221 3 impl->value = newValueVector;
222 3 }
223
224 /****************************************************************************/
225
226 template <class T>
227 12 void UserSignal<T>::setUserValueLimit(T in1, T in2)
228 {
229 12 impl->limit.lower = min(in1, in2);
230 12 impl->limit.upper = max(in1, in2);
231 12 }
232
233 /****************************************************************************/
234
235 template <class T>
236 15 void UserSignal<T>::addValue(T addend, unsigned int i)
237 {
238 15 impl->value.at(i) += addend;
239 15 }
240
241 /****************************************************************************/
242
243 template <class T>
244 3 void UserSignal<T>::addValueVector(vector<T> addendVector)
245 {
246
6/6
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 1 times.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 1 times.
15 for (int i = 0; i < impl->value.size(); i++) {
247 12 impl->value.at(i) += addendVector.at(i);
248 }
249 3 }
250
251 /****************************************************************************/
252
253 template <class T>
254 30 T UserSignal<T>::getValue(unsigned int i) const
255 {
256 30 return impl->value.at(i);
257 }
258
259 /****************************************************************************/
260
261 template <class T>
262 18 vector<T> UserSignal<T>::getValueVector() const
263 {
264 18 return impl->value;
265 }
266
267 /****************************************************************************/
268
269 template <class T>
270 27 bool UserSignal<T>::getChanged(unsigned int i) const
271 {
272 27 return impl->changed.at(i);
273 }
274
275 /****************************************************************************/
276
277 template <class T>
278 vector<uint8_t> UserSignal<T>::getChangedVector() const
279 {
280 return impl->changed;
281 }
282
283 /****************************************************************************/
284
285 template <class T>
286 21 bool UserSignal<T>::anyChanged() const
287 {
288
6/6
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 4 times.
✓ Branch 12 taken 11 times.
✓ Branch 13 taken 4 times.
✓ Branch 20 taken 11 times.
✓ Branch 21 taken 4 times.
45 for (auto state : impl->changed) {
289
6/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 8 times.
33 if (state) {
290 9 return state;
291 }
292 }
293
294 12 return false;
295 }
296
297 /****************************************************************************/
298
299 template <class T>
300 6 unsigned int UserSignal<T>::size() const
301 {
302 6 return impl->value.size();
303 }
304
305 /****************************************************************************/
306
307 template <class T>
308 49 int UserSignal<T>::convertPdType()
309 {
310 if (is_same<T, double>::value) {
311 17 return pd_double_T;
312 }
313 else if (is_same<T, int>::value) {
314 16 return pd_sint32_T;
315 }
316 else if (is_same<T, unsigned int>::value) {
317 16 return pd_uint32_T;
318 }
319 else {
320 stringstream err;
321 err << __PRETTY_FUNCTION__ << " : Wrong data type!";
322 throw invalid_argument(err.str());
323 }
324 6 }
325
326 /****************************************************************************/
327