
component mux16v2 	"Select from one of sixteen input values";
description """\
pin_ptr in bit use_graycode
This signifies the input will use Gray code instead of binary.
Gray code is a good choice when using physical switches because
for each increment only one select input changes at a time.

pin_ptr in bit suppress_no_input
This suppresses changing the output if all select lines are false.
This stops unwanted jumps in output between transitions of input.
but make in00 unavaliable.

pin_ptr in float debounce_time
sets debouce time in seconds.  eg. .10 = a tenth of a second
input must be stable this long before outputs changes. This
helps to ignore 'noisy' switches.

pin_ptr in bit sel#[4]
Together, these determine which \\fBin\\fIN\\fR value is copied to \\fBout\\fR.

pin_ptr out float out_f
pin_ptr out s32 out_s
Follows the value of one of the \\fBin\\fIN\\fR values according to the four \\fBsel\\fR values
and whether use-graycode is active.

The s32 value will be trunuated and limited to the max and min values of signed values.
.RS
.TP
\\fBsel3=false\\fR, \\fBsel2=false\\fR, \\fBsel1=false\\fR, \\fBsel0=false\\fR
\\fBout\\fR follows \\fBin0\\fR
.TP
\\fBsel3=false\\fR, \\fBsel2=false\\fR, \\fBsel1=false\\fR, \\fBsel0=true\\fR
\\fBout\\fR follows \\fBin1\\fR
.TP
etc.
.RE
""";

pin_ptr in bit use_graycode;
pin_ptr in bit suppress_no_input;
pin_ptr in float debounce_time;
pin_ptr in bit sel#[4];
pin_ptr out float out_f;
pin_ptr out s32 out_s;

pin_ptr out float elapsed "Current value of the internal debounce timer\n for debugging.";
pin_ptr out s32 selected "Current value of the internal selection variable after conversion\n for debugging";
pin_ptr in float in##[16] "array of selectable outputs";

variable hal_float_t delaytime;
variable hal_s32_t lastnum;
variable hal_bit_t running;
function _;
license "GPL";
;;
FUNCTION(_)
{
    hal_s32_t i,num = 0;
    hal_bit_t internal[4];

    if(gb(suppress_no_input)) 
        {
        if (gb(sel(0)) + gb(sel(1)) + gb(sel(2)) + gb(sel(3)) == false) 
            return 0;
        }
    
    if (gb(use_graycode)) 
        {
        internal[0] = gb(sel(3));
        internal[1] = gb(sel(2));
        internal[2] = gb(sel(1));
        internal[3] = gb(sel(0));
        
        for(i = 1; i < 4; i++)
            internal[i] = internal[i] ^ internal[i - 1];
        
        ss(selected, num = internal[3]+(internal[2]*2) + (internal[1]*4) + (internal[0]*8));
        }
    else
        ss(selected, num = (gb(sel(0)))+(gb(sel(1))*2) + (gb(sel(2))*4) + (gb(sel(3))*8));
    
    if(gf(debounce_time)) 
        {
        if (num != lastnum) 
            {
            if (!running) 
                {
                running = true;
                delaytime = 0.0;
                }
            if (delaytime < gf(debounce_time)) 
                {
                delaytime += fperiod;
                sf(elapsed, delaytime);
                return 0;
                }
            else
                {
                running = false;
                lastnum = num;
                sf(out_f, gf(in(num)));
                ss(out_s, gf(out_f) );
                return 0;
                }
            }
        }
    /* select the output */
    sf(out_f, gf(in(num)));
    ss(out_s, gf(out_f) );

return 0;

}
