Skip to content

Commit 537cf2d

Browse files
authored
Merge pull request #4739 from BsAtHome/fix_mux-demux-power-of-two
components: Fix bit-sel inputs of generic mux/demux when not a power of two
2 parents 24e84c4 + 94d4d92 commit 537cf2d

4 files changed

Lines changed: 75 additions & 66 deletions

File tree

‎docs/src/man/man9/demux_generic.9.adoc‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ demux-gen.NN.in-[bool/real/sint/uint] ───┤ ─────o o──
4141
changes. This helps to ignore 'noisy' switches.
4242
**demux-gen**.__N__.**sel-bit-**__BB__ bool in (BB=0..bit width of _size_)::
4343
**demux-gen**.__N__.**sel-int** uint in::
44-
The sel-bit pins are only created when the size of the demux_gen
45-
component is an integer power of two.
4644
Together, these determine to which **out**-__MM__ the **in** value is forwarded.
4745
The bit pins are interpreted as binary bits, and the result is simply
4846
added on to the integer pin input. It is expected that either one or

‎docs/src/man/man9/mux_generic.9.adoc‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,8 @@ mux-gen.NN.in-[bool/real/sint/uint]-MM ───┤ ─────o
4545
added on to the integer pin input. It is expected that either one or
4646
the other would normally be used. However, the possibility exists to
4747
use a higher-order bit to "shift" the values set by the integer pin.
48-
The sel-bit pins are only created when the size of the mux_gen
49-
component is an integer power of two. This component (unlike mux16)
50-
does not offer the option of decoding Gray-code, however the same
51-
effect can be achieved by arranging the order of the input values to suit.
48+
This component (unlike mux16) does not offer the option of decoding Gray-code,
49+
however the same effect can be achieved by arranging the order of the input values to suit.
5250
**mux-gen**.__N__.**in-**[**bool**/**real**/**sint**/**uint**]**-**__MM__ variable-type in::
5351
The possible output values that are selected by the selection pins.
5452
**mux-gen**.__N__.**out-**[**bool**/**real**/**sint**/**uint**] variable-type out::

‎src/hal/components/demux_generic.c‎

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ int rtapi_app_main(void){
9191
// Parse the config string
9292
for (i = 0; i < demux->num_insts; i++) {
9393
char c;
94-
int s, p = 0;
9594
demux_inst_t *inst = &demux->insts[i];
9695
inst->in_type = -1;
9796
inst->out_type = -1;
@@ -176,21 +175,32 @@ int rtapi_app_main(void){
176175
" failed\n");
177176
goto fail0;
178177
}
178+
179179
// Input pins
180-
181-
// if the demux size is a power of 2 then create the bit inputs
182-
s = inst->size;
183-
for(inst->num_bits = 1; (!((s >>= 1) & 1)); inst->num_bits++);
184-
if (s !=1){
185-
inst->num_bits = 0;
186-
} else { //make the bit pins
187-
inst->sel_bit = hal_malloc(inst->num_bits * sizeof(*inst->sel_bit));
188-
for (p = 0; p < inst->num_bits; p++) {
189-
retval = hal_pin_new_bool(comp_id, HAL_IN, &inst->sel_bit[p], 0,
190-
"demux-gen.%02i.sel-bit-%02i", i, p);
191-
if (retval != 0) {
192-
goto fail0;
193-
}
180+
inst->num_bits = 0;
181+
// Count the position of the highest bit set in inst->size-1.
182+
// We know that inst->size >= 2 from tests above. This will work
183+
// for any value, regardless whether it is a power of two or not
184+
// because of the -1 on the size and counting until all bits
185+
// have become zero.
186+
for (int s = inst->size - 1; 0 != s; inst->num_bits++) {
187+
s >>= 1;
188+
}
189+
if (inst->num_bits < 1) {
190+
// This is a safety guard. It should never happen.
191+
rtapi_print_msg(RTAPI_MSG_ERR, "demux_generic: INTERNAL ERROR: num_bits == 0\n");
192+
goto fail0;
193+
}
194+
inst->sel_bit = hal_malloc(inst->num_bits * sizeof(*inst->sel_bit));
195+
if (!inst->sel_bit) {
196+
rtapi_print_msg(RTAPI_MSG_ERR, "demux_generic: ERROR: out of HAL memory\n");
197+
goto fail0;
198+
}
199+
for (int p = 0; p < inst->num_bits; p++) {
200+
retval = hal_pin_new_bool(comp_id, HAL_IN, &inst->sel_bit[p], 0,
201+
"demux-gen.%02i.sel-bit-%02i", i, p);
202+
if (retval != 0) {
203+
goto fail0;
194204
}
195205
}
196206

@@ -240,7 +250,7 @@ int rtapi_app_main(void){
240250

241251
//output pins
242252
inst->outputs = hal_malloc(inst->size * sizeof(*inst->outputs));
243-
for (p = 0; p < inst->size; p++) {
253+
for (int p = 0; p < inst->size; p++) {
244254
retval = rtapi_snprintf(hal_name, sizeof(hal_name),
245255
"demux-gen.%02i.out-%s-%02i", i, types[inst->out_type], p);
246256
if (retval > HAL_NAME_LEN) {
@@ -262,40 +272,37 @@ int rtapi_app_main(void){
262272
hal_ready(comp_id);
263273
return 0;
264274

265-
fail0:
275+
fail0:
266276
hal_exit(comp_id);
267277
return -1;
268-
269278
}
270279

271280
// From 'f' to 't' conversion
272281
#define FT(f,t) ((((f) & 0x0f) << 4) + ((t) & 0x0f))
273282

274283
void write_fp(void *arg, long period) {
275284
demux_inst_t *inst = arg;
276-
int i = 0;
277-
rtapi_uint s = 0;
278-
if (inst->num_bits > 0) {
279-
while (i < inst->num_bits) {
280-
s += (hal_get_bool(inst->sel_bit[i]) != 0) << i;
281-
i++;
282-
}
285+
rtapi_sint s = 0;
286+
for (int i = 0; i < inst->num_bits; i++) {
287+
s += (rtapi_sint)hal_get_bool(inst->sel_bit[i]) << i;
283288
}
284289
// if you document it, it's not a bug, it's a feature. Might even be useful
285-
s += hal_get_uint(inst->sel_int);
290+
rtapi_uint u = hal_get_uint(inst->sel_int);
291+
// The calculation here is to prevent signed/unsigned overflow.
292+
s += u > MAX_SIZE ? MAX_SIZE : u;
286293

287294
if (hal_get_bool(inst->suppress) && s == 0)
288295
return;
289296
rtapi_uint timer = hal_get_uint(inst->timer);
290-
if (s != hal_get_uint(inst->selection) && timer < hal_get_uint(inst->debounce)) {
297+
if ((rtapi_uint)s != hal_get_uint(inst->selection) && timer < hal_get_uint(inst->debounce)) {
291298
hal_set_uint(inst->timer, timer + period / 1000);
292299
return;
293300
}
294301

295302
hal_set_uint(inst->selection, s);
296303
hal_set_uint(inst->timer, 0);
297304

298-
if ((rtapi_sint)s >= inst->size)
305+
if (s >= inst->size)
299306
s = inst->size - 1;
300307

301308
switch (FT(inst->in_type, inst->out_type)) {
@@ -370,6 +377,6 @@ void write_fp(void *arg, long period) {
370377
}
371378

372379
void rtapi_app_exit(void){
373-
//everything is hal_malloc-ed which saves a lot of cleanup here
374-
hal_exit(comp_id);
380+
// everything is hal_malloc-ed which saves a lot of cleanup here
381+
hal_exit(comp_id);
375382
}

‎src/hal/components/mux_generic.c‎

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ int rtapi_app_main(void){
9191
// Parse the config string
9292
for (i = 0; i < mux->num_insts; i++) {
9393
char c;
94-
int s, p = 0;
9594
mux_inst_t *inst = &mux->insts[i];
9695
inst->in_type = -1;
9796
inst->out_type = -1;
@@ -178,20 +177,30 @@ int rtapi_app_main(void){
178177
}
179178

180179
// Input pins
181-
182-
// if the mux size is a power of 2 then create the bit inputs
183-
s = inst->size;
184-
for(inst->num_bits = 1; (!((s >>= 1) & 1)); inst->num_bits++);
185-
if (s !=1){
186-
inst->num_bits = 0;
187-
} else { //make the bit pins
188-
inst->sel_bit = hal_malloc(inst->num_bits * sizeof(*inst->sel_bit));
189-
for (p = 0; p < inst->num_bits; p++) {
190-
retval = hal_pin_new_bool(comp_id, HAL_IN, &inst->sel_bit[p], 0,
191-
"mux-gen.%02i.sel-bit-%02i", i, p);
192-
if (retval != 0) {
193-
goto fail0;
194-
}
180+
inst->num_bits = 0;
181+
// Count the position of the highest bit set in inst->size-1.
182+
// We know that inst->size >= 2 from tests above. This will work
183+
// for any value, regardless whether it is a power of two or not
184+
// because of the -1 on the size and counting until all bits
185+
// have become zero.
186+
for (int s = inst->size - 1; 0 != s; inst->num_bits++) {
187+
s >>= 1;
188+
}
189+
if (inst->num_bits < 1) {
190+
// This is a safety guard. It should never happen.
191+
rtapi_print_msg(RTAPI_MSG_ERR, "mux_generic: INTERNAL ERROR: num_bits == 0\n");
192+
goto fail0;
193+
}
194+
inst->sel_bit = hal_malloc(inst->num_bits * sizeof(*inst->sel_bit));
195+
if (!inst->sel_bit) {
196+
rtapi_print_msg(RTAPI_MSG_ERR, "mux_generic: ERROR: out of HAL memory\n");
197+
goto fail0;
198+
}
199+
for (int p = 0; p < inst->num_bits; p++) {
200+
retval = hal_pin_new_bool(comp_id, HAL_IN, &inst->sel_bit[p], 0,
201+
"mux-gen.%02i.sel-bit-%02i", i, p);
202+
if (retval != 0) {
203+
goto fail0;
195204
}
196205
}
197206

@@ -202,7 +211,7 @@ int rtapi_app_main(void){
202211
}
203212

204213
inst->inputs = hal_malloc(inst->size * sizeof(*inst->inputs));
205-
for (p = 0; p < inst->size; p++) {
214+
for (int p = 0; p < inst->size; p++) {
206215
retval = rtapi_snprintf(hal_name, HAL_NAME_LEN,
207216
"mux-gen.%02i.in-%s-%02i", i, types[inst->in_type], p);
208217
if (retval >= HAL_NAME_LEN) {
@@ -263,39 +272,36 @@ int rtapi_app_main(void){
263272
hal_ready(comp_id);
264273
return 0;
265274

266-
fail0:
275+
fail0:
267276
hal_exit(comp_id);
268277
return -1;
269-
270278
}
271279

272280
// From 'f' to 't' conversion
273281
#define FT(f,t) ((((f) & 0x0f) << 4) + ((t) & 0x0f))
274282

275283
void write_fp(void *arg, long period) {
276284
mux_inst_t *inst = arg;
277-
int i = 0;
278-
rtapi_uint s = 0;
279-
if (inst->num_bits > 0) {
280-
while (i < inst->num_bits) {
281-
s += (hal_get_bool(inst->sel_bit[i]) != 0) << i;
282-
i++;
283-
}
285+
rtapi_sint s = 0;
286+
for (int i = 0; i < inst->num_bits; i++) {
287+
s += (rtapi_sint)hal_get_bool(inst->sel_bit[i]) << i;
284288
}
285289
// if you document it, it's not a bug, it's a feature. Might even be useful
286-
s += hal_get_uint(inst->sel_int);
290+
rtapi_uint u = hal_get_uint(inst->sel_int);
291+
// The calculation here is to prevent signed/unsigned overflow.
292+
s += u > MAX_SIZE ? MAX_SIZE : u;
287293

288294
if (hal_get_bool(inst->suppress) && s == 0)
289295
return;
290-
if (s != hal_get_uint(inst->selection) && hal_get_uint(inst->timer) < hal_get_uint(inst->debounce)) {
296+
if ((rtapi_uint)s != hal_get_uint(inst->selection) && hal_get_uint(inst->timer) < hal_get_uint(inst->debounce)) {
291297
hal_set_uint(inst->timer, hal_get_uint(inst->timer) + period / 1000);
292298
return;
293299
}
294300

295301
hal_set_uint(inst->selection, s);
296302
hal_set_uint(inst->timer, 0);
297303

298-
if ((rtapi_sint)s >= inst->size)
304+
if (s >= inst->size)
299305
s = inst->size - 1;
300306

301307
switch (FT(inst->in_type, inst->out_type)) {
@@ -370,6 +376,6 @@ void write_fp(void *arg, long period) {
370376
}
371377

372378
void rtapi_app_exit(void){
373-
//everything is hal_malloc-ed which saves a lot of cleanup here
374-
hal_exit(comp_id);
379+
// everything is hal_malloc-ed which saves a lot of cleanup here
380+
hal_exit(comp_id);
375381
}

0 commit comments

Comments
 (0)