#include "rtapi.h"
#include "rtapi_app.h"
#include "hal.h"
#include "hal_priv.h"
#if !defined(__KERNEL__)
#include <stdio.h>
#include <stdlib.h>
#endif
MODULE_AUTHOR("Andy Pugh");
MODULE_DESCRIPTION("Generic mux component for linuxCNC");
MODULE_LICENSE("GPL");
#define MAX_CHAN 100
#define MAX_SIZE 1024
#define EPS 2e-7
#define MAX_S32 0x7FFFFFFF
#define MAX_U32 0xFFFFFFFF
typedef struct {
hal_data_u **inputs;
hal_data_u *output;
hal_u32_t *sel_int;
hal_bit_t **sel_bit;
unsigned int selection;
hal_u32_t *debounce;
unsigned int timer;
hal_bit_t *suppress;
int in_type;
int out_type;
int size;
int num_bits;
} mux_inst_t;
typedef struct {
mux_inst_t *insts;
int num_insts;
} mux_t;
static int comp_id;
static mux_t *mux;
static void write_fp(void *arg, long period);
static void write_nofp(void *arg, long period);
char *config[MAX_CHAN];
RTAPI_MP_ARRAY_STRING(config, MAX_CHAN, "mux specifiers inNUMout");
int rtapi_app_main(void){
int retval;
int i, f;
char hal_name[HAL_NAME_LEN];
char *types[5] = {"invalid", "bit", "float", "s32", "u32"};
if (!config[0]) {
rtapi_print_msg(RTAPI_MSG_ERR, "The mux_generic component requires at least"
" one valid format string\n");
return -EINVAL;
}
comp_id = hal_init("mux_generic");
if (comp_id < 0) {
rtapi_print_msg(RTAPI_MSG_ERR, "mux_generic: ERROR: hal_init() failed\n");
return -1;
}
mux = hal_malloc(sizeof(mux_t));
if (mux == 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"mux_generic component: Out of Memory\n");
hal_exit(comp_id);
return -1;
}
for (mux->num_insts = 0; config[mux->num_insts];mux->num_insts++) {}
mux->insts = hal_malloc(mux->num_insts * sizeof(mux_inst_t));
for (i = 0; i < mux->num_insts; i++) {
char c;
int s, p = 0;
mux_inst_t *inst = &mux->insts[i];
inst->in_type = -1;
inst->out_type = -1;
for (f = 0; (c = config[i][f]); f++) {
int type;
type = 0;
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
inst->size = (inst->size * 10) + (c - '0');
if (inst->size > MAX_SIZE) inst->size = MAX_SIZE;
break;
case 'b':
case 'B':
type = HAL_BIT;
break;
case 'f':
case 'F':
type = HAL_FLOAT;
break;
case 's':
case 'S':
type = HAL_S32;
break;
case 'u':
case 'U':
type = HAL_U32;
break;
default:
rtapi_print_msg(RTAPI_MSG_ERR, "mux_generic: invalid character in "
"fmt string\n");
goto fail0;
}
if (type) {
if (inst->in_type == -1) {
inst->in_type = type;
}
else if (inst->out_type == -1) {
inst->out_type = type;
}
else
{
rtapi_print_msg(RTAPI_MSG_ERR, "mux_generic: too many type "
"specifiers in fmt string\n");
goto fail0;
}
}
}
if (inst->size < 1) {
rtapi_print_msg(RTAPI_MSG_ERR, "mux_generic: No entry count given\n");
goto fail0;
}
else if (inst->size < 2) {
rtapi_print_msg(RTAPI_MSG_ERR, "mux_generic: A one-element mux makes "
"no sense\n");
goto fail0;
}
if (inst->in_type == -1) {
rtapi_print_msg(RTAPI_MSG_ERR, "mux_generic: No type specifiers in "
"fmt string\n");
goto fail0;
}
else if (inst->out_type == -1) {
inst->out_type = inst->in_type;
}
retval = rtapi_snprintf(hal_name, HAL_NAME_LEN, "mux-gen.%02i", i);
if (retval >= HAL_NAME_LEN) {
goto fail0;
}
if (inst->in_type == HAL_FLOAT || inst->out_type == HAL_FLOAT) {
retval = hal_export_funct(hal_name, write_fp, inst, 1, 0, comp_id);
if (retval < 0) {
rtapi_print_msg(RTAPI_MSG_ERR, "mux_generic: ERROR: function export"
" failed\n");
goto fail0;
}
}
else
{
retval = hal_export_funct(hal_name, write_nofp, inst, 0, 0, comp_id);
if (retval < 0) {
rtapi_print_msg(RTAPI_MSG_ERR, "mux_generic: ERROR: function export"
" failed\n");
goto fail0;
}
}
s = inst->size;
for(inst->num_bits = 1; (!((s >>= 1) & 1)); inst->num_bits++);
if (s !=1){
inst->num_bits = 0;
} else { inst->sel_bit = hal_malloc(inst->num_bits * sizeof(hal_bit_t*));
for (p = 0; p < inst->num_bits; p++) {
retval = hal_pin_bit_newf(HAL_IN, &inst->sel_bit[p], comp_id,
"mux-gen.%02i.sel-bit-%02i", i, p);
if (retval != 0) {
goto fail0;
}
}
}
retval = hal_pin_u32_newf(HAL_IN, &(inst->sel_int), comp_id,
"mux-gen.%02i.sel-int", i);
if (retval != 0) {
goto fail0;
}
inst->inputs = hal_malloc(inst->size * sizeof(hal_data_u*));
for (p = 0; p < inst->size; p++) {
retval = rtapi_snprintf(hal_name, HAL_NAME_LEN,
"mux-gen.%02i.in-%s-%02i", i, types[inst->in_type], p);
if (retval >= HAL_NAME_LEN) {
goto fail0;
}
retval = hal_pin_new(hal_name, inst->in_type, HAL_IN,
(void**)&(inst->inputs[p]), comp_id);
if (retval != 0) {
goto fail0;
}
}
retval = hal_pin_bit_newf(HAL_IN, &inst->suppress, comp_id,
"mux-gen.%02i.suppress-no-input", i);
if (retval != 0) {
goto fail0;
}
retval = hal_pin_u32_newf(HAL_IN, &inst->debounce, comp_id,
"mux-gen.%02i.debounce-us", i);
if (retval != 0) {
goto fail0;
}
retval = hal_param_u32_newf(HAL_RO, &inst->timer, comp_id,
"mux-gen.%02i.elapsed", i);
if (retval != 0) {
goto fail0;
}
retval = hal_param_u32_newf(HAL_RO, &inst->selection, comp_id,
"mux-gen.%02i.selected", i);
if (retval != 0) {
goto fail0;
}
retval = rtapi_snprintf(hal_name, HAL_NAME_LEN,
"mux-gen.%02i.out-%s", i, types[inst->out_type]);
if (retval >= HAL_NAME_LEN) {
goto fail0;
}
retval = hal_pin_new(hal_name, inst->out_type, HAL_OUT,
(void**)&(inst->output), comp_id);
if (retval != 0) {
goto fail0;
}
}
hal_ready(comp_id);
return 0;
fail0:
hal_exit(comp_id);
return -1;
}
void write_fp(void *arg, long period) {
mux_inst_t *inst = arg;
int i = 0, s = 0;
if (inst->num_bits > 0) {
while (i < inst->num_bits) {
s += (*inst->sel_bit[i] != 0) << i;
i++;
}
}
s += *inst->sel_int;
if (*inst->suppress && s == 0)
return;
if (s != inst->selection && inst->timer < *inst->debounce) {
inst->timer += period / 1000;
return;
}
inst->selection = s;
inst->timer = 0;
if (s >= inst->size)
s = inst->size - 1;
switch (inst->in_type * 8 + inst->out_type) {
case 012: inst->output->f = inst->inputs[s]->b ? 1.0 : 0.0; break;
case 021: inst->output->b =
(inst->inputs[s]->f > EPS || inst->inputs[s]->f < -EPS) ? 1 : 0;
break;
case 022: inst->output->f = inst->inputs[s]->f;
break;
case 023: if (inst->inputs[s]->f > MAX_S32) {
inst->output->s = MAX_S32;
} else if (inst->inputs[s]->f < -MAX_S32) {
inst->output->s = -MAX_S32;
} else {
inst->output->s = inst->inputs[s]->f;
}
break;
case 024: if (inst->inputs[s]->f > MAX_U32) {
inst->output->u = MAX_U32;
} else if (inst->inputs[s]->f < 0) {
inst->output->u = 0;
} else {
inst->output->u = inst->inputs[s]->f;
}
break;
case 032: inst->output->f = inst->inputs[s]->s;
break;
case 042: inst->output->f = (unsigned int) inst->inputs[s]->u;
break;
}
}
void write_nofp(void *arg, long period) {
mux_inst_t *inst = arg;
int i = 0, s = 0;
if (inst->num_bits > 0) {
while (i < inst->num_bits) {
s += (*inst->sel_bit[i] != 0) << i;
i++;
}
}
s += *inst->sel_int;
if (*inst->suppress && s == 0)
return;
if (s != inst->selection && inst->timer < *inst->debounce) {
inst->timer += period / 1000;
return;
}
inst->selection = s;
inst->timer = 0;
if (s >= inst->size)
s = inst->size - 1;
switch (inst->in_type * 8 + inst->out_type) {
case 011: inst->output->b = inst->inputs[s]->b;
break;
case 013: inst->output->s = inst->inputs[s]->b;
break;
case 014: inst->output->u = inst->inputs[s]->b;
break;
case 031: inst->output->b = inst->inputs[s]->s == 0 ? 0 : 1;
break;
case 033: inst->output->s = inst->inputs[s]->s;
break;
case 034: inst->output->u = (inst->inputs[s]->s > 0) ? inst->inputs[s]->s : 0;
break;
case 041: inst->output->b = inst->inputs[s]->u == 0 ? 0 : 1;
break;
case 043: inst->output->s =
((unsigned int) inst->inputs[s]->u > MAX_S32) ?
MAX_S32 : inst->inputs[s]->u;
break;
case 044: inst->output->u = inst->inputs[s]->u;
break;
}
}
void rtapi_app_exit(void){
hal_exit(comp_id);
}