square-wave

xod/waves/square-wave

Generates square wave signal
square-wave
@/square-wave
Generates square wave signal
DUTYnumber
Duty cycle. Ratio of `true` signal duration to the whole `IVAL`.
Tnumber
Time interval between switches to `true`, i.e. the period of the square wave.
RSTpulse
Resets the wave phase and `N` to zero.
ENboolean
Enabled or not. When set to `false` pauses generation preserving the current phase. When set to `true` again continues counting from the saved phase.
square-wave
DUTY
T
RST
EN
OUT
N
Nnumber
The number of current cycle. Starts from 0. The cycle is considered to start with the `true` value.
OUTboolean
The signal value: `true` or `false`. When the phase is at switch boundary, the value is the same as `EN`, i.e. `false` if paused and `true` if active.

C++ implementation

node {
    bool wasEnabled;
    TimeMs timeToSwitch;
    TimeMs nextSwitchTime;

    void evaluate(Context ctx) {
        TimeMs t = transactionTime();

        bool enabled = getValue<input_EN>(ctx);
        bool reset = isInputDirty<input_RST>(ctx);
        Number period = getValue<input_T>(ctx);
        Number duty = getValue<input_DUTY>(ctx);

        if (reset) {
            emitValue<output_OUT>(ctx, enabled);
            emitValue<output_N>(ctx, 0);
            clearTimeout(ctx);
            // enforce rescheduling at the next stage if enabled
            wasEnabled = false;
        }

        if (enabled && !wasEnabled) {
            // just enabled/resumed
            timeToSwitch = (period * duty) * 1000.0;
            setTimeout(ctx, timeToSwitch);
            nextSwitchTime = t + timeToSwitch;
            emitValue<output_OUT>(ctx, true);
        } else if (!enabled && wasEnabled) {
            // just paused
            // TODO: we can get rid of storing nextSwitchTime if API would
            // have a function to fetch current scheduled time for a ctx
            timeToSwitch = nextSwitchTime - t;
            clearTimeout(ctx);
        } else if (isTimedOut(ctx)) {
            // switch time
            auto newValue = !getValue<output_OUT>(ctx);
            auto k = newValue ? duty : (1.0 - duty);
            timeToSwitch = period * k * 1000.0;

            setTimeout(ctx, timeToSwitch);
            nextSwitchTime = t + timeToSwitch;

            emitValue<output_OUT>(ctx, newValue);
            if (newValue)
                emitValue<output_N>(ctx, getValue<output_N>(ctx) + 1);
        }

        wasEnabled = enabled;
    }
}