component gearchangev2 """Select from one two speed ranges
The output will be a value scaled for the selected gear, and clamped to
the min/max values for that gear.
The scale of gear 1 is assumed to be 1, so the output device scale
should be chosen accordingly.
The scale of gear 2 is relative to gear 1, so if gear 2 runs the spindle
2.5 times as fast as gear 1, scale2 should be set to 2.5.""";

pin_ptr in bit sel "Gear selection input";
pin_ptr in float speed_in "Speed command input";
pin_ptr out float speed_out "Speed command to DAC/PWM";
pin_ptr in bit dir_in "Direction command input";
pin_ptr out bit dir_out "Direction output - possibly inverted for second gear";
pin_ptr io float min1 = 0.0 "Minimum allowed speed in gear range 1";
pin_ptr io float max1 = 100000 "Maximum allowed speed in gear range 1";
pin_ptr io float min2 = 0.0 "Minimum allowed speed in gear range 2";
pin_ptr io float max2 = 100000 "Maximum allowed speed in gear range 2";
pin_ptr io float scale2 = 1.0 """Relative scale of gear 2 vs. gear 1
Since it is assumed that gear 2 is "high gear", \\fBscale2\\fR must be
greater than 1, and will be reset to 1 if set lower.""";
pin_ptr io bit reverse = 0.0 "Set to 1 to reverse the spindle in second gear";

function _;
license "GPL";
;;
FUNCTION(_)
{
hal_float_t temp_in = gf(speed_in);
hal_float_t sign=1.0;

    /* Assume that the output device is scaled so that gear 1 is "Pass-through" */
    /* the other gear(s) need to be scaled by the relative scale for that gear */
    if (gf(scale2) < 1.0) 
        sf(scale2, 1.0);
    if (temp_in < 0.0) {
        sign = -1.0;
        temp_in = -temp_in;
        }
    if(gb(sel)) {		/* gear 2 */
        if (temp_in < gf(min2)) 
            temp_in = gf(min2);
        else if (temp_in > gf(max2)) 
            temp_in = gf(max2);
        temp_in /= gf(scale2);		/* scale up to second gear output range */
        sb(dir_out, gb(dir_in) ^ gb(reverse));
        } 
    else {
        if (temp_in < gf(min1)) 
            temp_in = gf(min1);
        else if (temp_in > gf(max1)) 
            temp_in = gf(max1);
        sb(dir_out, gb(dir_in));
        }
    sf(speed_out, sign*temp_in);

return 0;
}
