component toggle2nist "toggle button to nist logic";

description
"""
Toggle2nist can be used with a momentary push button 
to control a device that has separate on and off inputs
and an is-on output.
A debounce delay in cycles can be set for 'in'. (default = 2)

\\[bu] On a rising edge on pin \\fIin\\fR when \\fIis-on\\fR is low: It sets \\fIon\\fR until \\fIis-on\\fR becomes high.

\\[bu] On a rising edge on pin \\fIin\\fR when \\fIis-on\\fR is high: It sets \\fIoff\\fR until \\fIis-on\\fR becomes low.


       ┐     ┌─────xxxxxxxxxxxx┐           ┌─────xxxxxxxxxxxx┐
.br
in   : └─────┘     xxxxxxxxxxxx└───────────┘     xxxxxxxxxxxx└─────
.br
       ┐     ┌───────────┐
.br
on   : └─────┘           └─────────────────────────────────────────
.br
       ┐                                   ┌───────────┐
.br
off  : └───────────────────────────────────┘           └───────────
.br
       ┐                 ┌─────────────────────────────┐
.br
is-on: └─────────────────┘                             └───────────

""";

pin in bit in  "momentary button in";
pin in bit is_on "current state of device";
pin in unsigned debounce = 2 "debounce delay for 'in'-pin in cycles";
pin out bit on "turn device on";
pin out bit off "turn device off";
variable int debounce_cntr;
variable unsigned debounce_set;
variable int state;

option period no;
function _ nofp;
license "GPL";
author "Anders Wallin, David Mueller";
;;
FUNCTION(_)  {

    if (( debounce < 1 ) || ( debounce > 10000 )) {
        debounce_set = 2; /* set a sane value */
    } else {
        debounce_set = debounce;
    }

    if (in && state == 0 )  { /* input has changed from debounced 0 -> 1 */
        debounce_cntr++;
        if ( debounce_cntr >= (int)debounce_set ) {
            if (!is_on) { /* turn ON if it's off */
                on=1;
                off=0;
            } else { /* turn OFF if it's on */
                on=0;
                off=1;
            }
            state = 1;
            debounce_cntr = 0;
        }
    } else if (!in && state == 1) { /* input has changed from debounced 1 -> 0 */
        debounce_cntr++;
        if ( debounce_cntr >= (int)debounce_set ) {
            state = 0;
            debounce_cntr = 0;
        }
    } else if ((!is_on && off) || (is_on && on)) { /* reset outputs once device has switched*/
        on = 0;
        off = 0;
        debounce_cntr = 0;
    } else {
    	debounce_cntr = 0;
    }
}