diff --git a/types/pigpio/index.d.ts b/types/pigpio/index.d.ts new file mode 100644 index 0000000000..fa89bc56ea --- /dev/null +++ b/types/pigpio/index.d.ts @@ -0,0 +1,412 @@ +// Type definitions for pigpio 0.4.0 +// Project: https://github.com/fivdi/pigpio +// Definitions by: ManerFan +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/// + +/************************************ + * Gpio + ************************************/ + +/** + * General Purpose Input Output + */ +export class Gpio extends NodeJS.EventEmitter { + /** + * Returns a new Gpio object for accessing a GPIO + * @param gpio an unsigned integer specifying the GPIO number + * @param options object (optional) + */ + constructor( + gpio: number, + options?: { + /** + * INPUT, OUTPUT, ALT0, ALT1, ALT2, ALT3, ALT4, or ALT5 (optional, no default) + */ + mode?: number; + + /** + * PUD_OFF, PUD_DOWN, or PUD_UP (optional, no default) + */ + pullUpDown?: number; + + /** + * interrupt edge for inputs. RISING_EDGE, FALLING_EDGE, or EITHER_EDGE (optional, no default) + */ + edge?: number; + + /** + * interrupt timeout in milliseconds (optional, defaults to 0 meaning no timeout if edge specified) + */ + timeout?: number; + + /** + * boolean specifying whether or not alert events are emitted when the GPIO changes state (optional, default false) + */ + alert?: boolean + } + ); + + /** + * Sets the GPIO mode. + * @param mode INPUT, OUTPUT, ALT0, ALT1, ALT2, ALT3, ALT4, or ALT5 + */ + mode(mode: number): Gpio; + + /** + * Sets or clears the resistor pull type for the GPIO. + * @param pud PUD_OFF, PUD_DOWN, or PUD_UP + */ + pullUpDown(pud: number): Gpio; + + /** + * Returns the GPIO mode. + */ + getMode(): number; + + /** + * Returns the GPIO level, 0 or 1. + */ + digitalRead(): number; + + /** + * Sets the GPIO level to 0 or 1. If PWM or servo pulses are active on the GPIO they are switched off. + * @param levle 0 or 1 + */ + digitalWrite(levle: number): Gpio; + + /** + * Sends a trigger pulse to the GPIO. The GPIO is set to level for pulseLen microseconds and then reset to not level. + * @param pulseLen pulse length in microseconds (1 - 100) + * @param level 0 or 1 + */ + trigger(pulseLen: number, level: number): Gpio; + + /** + * Starts PWM on the GPIO. Returns this. + * @param dutyCycle an unsigned integer >= 0 (off) and <= range (fully on). range defaults to 255. + */ + pwmWrite(dutyCycle: number): Gpio; + + /** + * The same to #pwmWrite. + * @param dutyCycle an unsigned integer >= 0 (off) and <= range (fully on). range defaults to 255. + */ + analogWrite(dutyCycle: number): Gpio; + + /** + * Starts hardware PWM on the GPIO at the specified frequency and dutyCycle. Frequencies above 30MHz are unlikely to work. + * @param frequency an unsigned integer >= 0 and <= 125000000 + * @param dutyCycle an unsigned integer >= 0 (off) and <= 1000000 (fully on). + */ + hardwarePwmWrite(frequency: number, dutyCycle: number): Gpio; + + /** + * Returns the PWM duty cycle setting on the GPIO. + */ + getPwmDutyCycle(): number; + + /** + * Selects the duty cycle range to be used for the GPIO. Subsequent calls to pwmWrite will use a duty cycle between 0 (off) and range (fully on). + * @param range an unsigned integer in the range 25 through 40000 + */ + pwmRange(range: number): Gpio; + + /** + * Returns the duty cycle range used for the GPIO. + * If hardware PWM is active on the GPIO the reported range will be 1000000. + */ + getPwmRange(): number; + + /** + * Returns the real range used for the GPIO. + * If hardware PWM is active on the GPIO the reported real range will be approximately 250M divided by the set PWM frequency. + */ + getPwmRealRange(): number; + + /** + * Sets the frequency in hertz to be used for the GPIO. Returns this. + * @param frequency an unsigned integer >= 0 + */ + pwmFrequency(frequency: number): Gpio; + + /** + * Returns the frequency (in hertz) used for the GPIO. The default frequency is 800Hz. + */ + getPwmFrequency(): number; + + /** + * Starts servo pulses at 50Hz on the GPIO, 0 (off), 500 (most anti-clockwise) to 2500 (most clockwise) + * @param pulseWidth pulse width in microseconds, an unsigned integer, 0 or a number in the range 500 through 2500 + */ + servoWrite(pulseWidth: number): Gpio; + + /** + * Returns the servo pulse width setting on the GPIO. + */ + getServoPulseWidth(): number; + + /** + * Enables interrupts for the GPI + * @param edge RISING_EDGE, FALLING_EDGE, or EITHER_EDGE + * @param timeout interrupt timeout in milliseconds (optional, defaults to 0 meaning no timeout) + */ + enableInterrupt(edge: number, timeout?: number): Gpio; + + /** + * Disables interrupts for the GPIO. Returns this. + */ + disableInterrupt(): Gpio; + + /** + * Enables alerts for the GPIO. + */ + enableAlert(): Gpio; + + /** + * Disables aterts for the GPIO. + */ + disableAlert(): Gpio; + + /*----------------------* + * mode + *----------------------*/ + + /** + * Indicates that the GPIO is an input. + */ + static INPUT: number; + + /** + * Indicates that the GPIO is an output. + */ + static OUTPUT: number; + + /** + * Indicates that the GPIO is in alternative mode 0. + */ + static ALT0: number; + + /** + * Indicates that the GPIO is in alternative mode 1. + */ + static ALT1: number; + + /** + * Indicates that the GPIO is in alternative mode 2. + */ + static ALT2: number; + + /** + * Indicates that the GPIO is in alternative mode 03. + */ + static ALT3: number; + + /** + * Indicates that the GPIO is in alternative mode 4. + */ + static ALT4: number; + + /** + * Indicates that the GPIO is in alternative mode 5. + */ + static ALT5: number; + + /*----------------------* + * pud + *----------------------*/ + + /** + * Niether the pull-up nor the pull-down resistor should be enabled. + */ + static PUD_OFF: number; + + /** + * Enable pull-down resistor. + */ + static PUD_DOWN: number; + + /** + * Enable pull-up resistor. + */ + static PUD_UP: number; + + /*----------------------* + * isr + *----------------------*/ + + /** + * Indicates that the GPIO fires interrupts on rising edges. + */ + static RISING_EDGE: number; + + /** + * Indicates that the GPIO fires interrupts on falling edges. + */ + static FALLING_EDGE: number; + + /** + * Indicates that the GPIO fires interrupts on both rising and falling edges. + */ + static EITHER_EDGE: number; + + /*----------------------* + * timeout + *----------------------*/ + + /** + * The level argument passed to an interrupt event listener when an interrupt timeout expires. + */ + static TIMEOUT: number; + + /*----------------------* + * gpio numbers + *----------------------* + + /** + * The smallest GPIO number. + */ + static MIN_GPIO: number; + + /** + * The largest GPIO number. + */ + static MAX_GPIO: number; + + /** + * The largest user GPIO number. + */ + static MAX_USER_GPIO: number; +} + +/************************************ + * GpioBank + ************************************ + + /** + * Banked General Purpose Input Output + */ +export class GpioBank { + /** + * Returns a new GpioBank object for accessing up to 32 GPIOs as one operation. + * @param bank BANK1 or BANK2 (optional, defaults to BANK1) + */ + constructor(bank?: number); + + /** + * Returns the current level of all GPIOs in the bank. + */ + read(): number; + + /** + * For each GPIO in the bank, sets the GPIO level to 1 if the corresponding bit in bits is set. + * @param bits a bit mask of the the GPIOs to set to 1 + */ + set(bits: number): GpioBank; + + /** + * For each GPIO in the bank, sets the GPIO level to 0 if the corresponding bit in bits is set. + * @param bits a bit mask of the the GPIOs to clear or set to 0 + */ + clear(bits: number): GpioBank; + + /** + * Returns the bank identifier (BANK1 or BANK2.) + */ + bank(): number; + + /** + * Identifies bank 1. + */ + static BANK1: number; + + /** + * Identifies bank 2. + */ + static BACK2: number; +} + +/************************************ + * Notifier + ************************************ + + /** + * Notification Stream + */ +export class Notifier { + /** + * Returns a new Notifier object that contains a stream which provides notifications about state changes on any of GPIOs 0 through 31 concurrently. + * @param options Used to configure which GPIOs notifications should be provided for. + */ + constructor(options?: { + /** + * a bit mask indicating the GPIOs of interest, bit0 corresponds to GPIO0, bit1 corresponds to GPIO1, ..., bit31 corresponds to GPIO31. + * If a bit is set, the corresponding GPIO will be monitored for state changes. (optional, no default) + */ + bits: number; + }) + + /** + * Starts notifications for the GPIOs specified in the bit mask. + * @param bits a bit mask indicating the GPIOs of interest, bit0 corresponds to GPIO0, bit1 corresponds to GPIO1, ..., bit31 corresponds to GPIO31. + * If a bit is set, the corresponding GPIO will be monitored for state changes. + */ + start(bits: number): Notifier; + + /** + * Stops notifications. Notifications can be restarted with the start method. + */ + stop(): Notifier; + + /** + * Stops notifications and releases resources. + */ + close(): Notifier; + + /** + * Returns the notification stream which is a Readable stream. + */ + stream(): NodeJS.ReadableStream; + + /** + * The number of bytes occupied by a notification in the notification stream. + */ + static NOTIFICATION_LENGTH: number; + + /** + * Indicates a keep alive signal on the stream and is sent once a minute in the absence of other notification activity. + */ + static PI_NTFY_FLAGS_ALIVE: number; +} + +/************************************ + * Configuration + ************************************/ + +/** + * PI_CLOCK_PWM + */ +export const CLOCK_PWM: number; + +/** + * PI_CLOCK_PCM + */ +export const CLOCK_PCM: number; + +/** + * Initialize the pigpio package + */ +export function initialize(): void; + +/** + * Terminate the pigpio package + */ +export function terminate(): void; + +/** + * The configureClock function can be used to configure the sample rate and timing peripheral. + * @param microseconds an unsigned integer specifying the sample rate in microseconds (1, 2, 4, 5, 8, or 10) + * @param peripheral an unsigned integer specifying the peripheral for timing (CLOCK_PWM or CLOCK_PCM) + */ +export function configureClock(microseconds: number, peripheral: number): void; diff --git a/types/pigpio/pigpio-tests.ts b/types/pigpio/pigpio-tests.ts new file mode 100644 index 0000000000..ea7f620082 --- /dev/null +++ b/types/pigpio/pigpio-tests.ts @@ -0,0 +1,905 @@ +import * as pigpio from 'pigpio'; +import * as assert from 'assert'; + +(function alert_pwm_measurement(): void { + const Gpio = pigpio.Gpio; + + pigpio.configureClock(1, pigpio.CLOCK_PWM); + + let led = new Gpio(18, { + mode: Gpio.OUTPUT, + alert: true + }); + + led.digitalWrite(0); + + (function closure(): void { + let pulseCounts: number[] = []; + let pulses: number = 0; + let risingTick: number = 0; + let fallingTick: number; + let i: number; + + led.on('alert', function event(level: number, tick: number): void { + let pulseLength: number; + + if (level === 1) { + risingTick = tick; + } else { + fallingTick = tick; + pulseLength = fallingTick - risingTick; + + if (pulseCounts[pulseLength] === undefined) { + pulseCounts[pulseLength] = 0; + } + pulseCounts[pulseLength] += 1; + + pulses += 1; + if (pulses === 1000) { + for (i = 0; i !== pulseCounts.length; i += 1) { + if (pulseCounts[i] !== undefined) { + console.log(i + 'us - ' + pulseCounts[i]); + } + } + + led.digitalWrite(0); + led.disableAlert(); + } + } + }); + }()); + + // frequency 250Hz, duty cycle 7us + led.hardwarePwmWrite(250, 250 * 7); +})(); + +(function alert_trigger_pulse_measurement(): void { + const Gpio = pigpio.Gpio; + let led: pigpio.Gpio; + let iv: NodeJS.Timer; + + // pigpio.configureClock(1, pigpio.CLOCK_PCM); + + led = new Gpio(17, { + mode: Gpio.OUTPUT, + alert: true + }); + + led.digitalWrite(0); + + (function closure(): void { + let pulseCounts: number[] = []; + let pulses: number = 0; + let risingTick: number; + let fallingTick: number; + let i: number; + + led.on('alert', function event(level: number, tick: number): void { + let pulseLength: number; + + if (level === 1) { + risingTick = tick; + } else { + fallingTick = tick; + pulseLength = fallingTick - risingTick; + + if (pulseCounts[pulseLength] === undefined) { + pulseCounts[pulseLength] = 0; + } + pulseCounts[pulseLength] += 1; + + pulses += 1; + if (pulses === 1000) { + for (i = 0; i !== pulseCounts.length; i += 1) { + if (pulseCounts[i] !== undefined) { + console.log(i + 'us - ' + pulseCounts[i]); + } + } + + clearInterval(iv); + led.digitalWrite(0); + led.disableAlert(); + } + } + }); + }()); + + iv = setInterval(function timer() { + led.trigger(10, 1); + }, 2); +})(); + +(function alert(): void { + const Gpio = pigpio.Gpio; + let button = new Gpio(4, { alert: true }); + + button.on('alert', function event(level: number, tick: number): void { + console.log(level + ' ' + tick); + }); + + console.log(' press the momentary push button a few times'); +})(); + +(function banked_leds(): void { + const Gpio = pigpio.Gpio; + const GpioBank = pigpio.GpioBank; + let led17 = new Gpio(17, { mode: Gpio.OUTPUT }); + let led18 = new Gpio(18, { mode: Gpio.OUTPUT }); + let bank1 = new GpioBank(); + let iv: NodeJS.Timer; + + bank1.clear(1 << 18 | 1 << 17); + assert.strictEqual((bank1.read() >> 17) & 0x3, 0, 'expected 0'); + + iv = setInterval(function timer(): void { + let bits = (bank1.read() >> 17) & 0x3; + + if (bits === 0) { + bank1.set(1 << 17); + assert.strictEqual((bank1.read() >> 17) & 0x3, 1, 'expected 1'); + } else if (bits === 1) { + bank1.clear(1 << 17); + bank1.set(1 << 18); + assert.strictEqual((bank1.read() >> 17) & 0x3, 2, 'expected 2'); + } else if (bits === 2) { + bank1.set(1 << 17); + bank1.set(1 << 18); + assert.strictEqual((bank1.read() >> 17) & 0x3, 3, 'expected 3'); + } else if (bits === 3) { + bank1.clear(1 << 17); + bank1.clear(1 << 18); + assert.strictEqual((bank1.read() >> 17) & 0x3, 0, 'expected 0'); + } + }, 250); + + setTimeout(function timer() { + bank1.clear(1 << 18 | 1 << 17); + clearInterval(iv); + }, 2000); +})(); + +(function blinky_pwm(): void { + const Gpio = pigpio.Gpio; + let led = new Gpio(18, { mode: Gpio.OUTPUT }); + + led.hardwarePwmWrite(10, 500000); + + setTimeout(function timer() { + led.digitalWrite(0); + }, 2000); +})(); + +(function blinky(): void { + const Gpio = pigpio.Gpio; + let iv: NodeJS.Timer; + let led = new Gpio(17, { mode: Gpio.OUTPUT }); + + iv = setInterval(function timer() { + led.digitalWrite(led.digitalRead() ^ 1); + }, 100); + + setTimeout(function timer() { + led.digitalWrite(0); + clearInterval(iv); + }, 2000); +})(); + +(function digital_read_performance(): void { + const Gpio = pigpio.Gpio; + let button = new Gpio(4, { + mode: Gpio.INPUT, + pullUpDown: Gpio.PUD_DOWN + }); + let time: [number, number]; + let ops: number; + let i: number; + + time = process.hrtime(); + + for (i = 0; i !== 2000000; i += 1) { + button.digitalRead(); + } + + time = process.hrtime(time); + ops = Math.floor(i / (time[0] + time[1] / 1E9)); + + console.log(' ' + ops + ' read ops per second'); +})(); + +(function digital_write_performance(): void { + const Gpio = pigpio.Gpio; + let led = new Gpio(17, { mode: Gpio.OUTPUT }); + let time: [number, number]; + let ops: number; + let i: number; + + time = process.hrtime(); + + for (i = 0; i !== 2000000; i += 1) { + led.digitalWrite(1); + led.digitalWrite(0); + } + + time = process.hrtime(time); + ops = Math.floor((i * 2) / (time[0] + time[1] / 1E9)); + + console.log(' ' + ops + ' write ops per second'); +})(); + +(function gpio_mode(): void { + const Gpio = pigpio.Gpio; + let gpio7 = new Gpio(7, { mode: Gpio.INPUT }); + let gpio8 = new Gpio(8, { mode: Gpio.OUTPUT }); + + assert.strictEqual(gpio7.getMode(), Gpio.INPUT, 'expected INPUT mode for gpio7'); + assert.strictEqual(gpio8.getMode(), Gpio.OUTPUT, 'expected OUTPUT mode for gpio8'); + + gpio8.mode(Gpio.INPUT); + assert.strictEqual(gpio8.getMode(), Gpio.INPUT, 'expected INPUT mode for gpio8'); + + gpio7.mode(Gpio.OUTPUT); + assert.strictEqual(gpio7.getMode(), Gpio.OUTPUT, 'expected OUTPUT mode for gpio7'); + + gpio7.mode(Gpio.INPUT); + assert.strictEqual(gpio7.getMode(), Gpio.INPUT, 'expected INPUT mode for gpio7'); +})(); + +(function gpio_numbers(): void { + const Gpio = pigpio.Gpio; + + assert.strictEqual(Gpio.MIN_GPIO, 0, 'expected Gpio.MIN_GPIO to be 0'); + assert.strictEqual(Gpio.MAX_GPIO, 53, 'expected Gpio.MAX_GPIO to be 53'); + assert.strictEqual(Gpio.MAX_USER_GPIO, 31, 'expected Gpio.MAX_USER_GPIO to be 31'); +})(); + +(function isr_enable_disable(): void { + const Gpio = pigpio.Gpio; + let input = new Gpio(7, { mode: Gpio.INPUT }); + let output = new Gpio(8, { mode: Gpio.OUTPUT }); + let risingCount = 0; + let fallingCount = 0; + let iv: NodeJS.Timer; + + // Put output (and input) in a known state. + output.digitalWrite(0); + + // Toggle output (and input) every 10 ms + iv = setInterval(function timer() { + output.digitalWrite(output.digitalRead() ^ 1); + }, 10); + + // ISR + input.on('interrupt', function event(level: number) { + if (level === 0) { + fallingCount += 1; + } else if (level === 1) { + risingCount += 1; + } + }); + + function noEdge() { + console.log(' no edge'); + + input.disableInterrupt(); + risingCount = 0; + fallingCount = 0; + + setTimeout(function timer() { + console.log(' ' + risingCount + ' rising edge interrupts (0 expected)'); + console.log(' ' + fallingCount + ' falling edge interrupts (0 expected)'); + + clearInterval(iv); + input.disableInterrupt(); + }, 1000); + } + + function fallingEdge() { + console.log(' falling edge'); + + input.enableInterrupt(Gpio.FALLING_EDGE); + risingCount = 0; + fallingCount = 0; + + setTimeout(function timer() { + console.log(' ' + risingCount + ' rising edge interrupts (0 expected)'); + console.log(' ' + fallingCount + ' falling edge interrupts (~50 expected)'); + + noEdge(); + }, 1000); + } + + function risingEdge() { + console.log(' rising edge'); + + input.enableInterrupt(Gpio.RISING_EDGE); + risingCount = 0; + fallingCount = 0; + + setTimeout(function timer() { + console.log(' ' + risingCount + ' rising edge interrupts (~50 expected)'); + console.log(' ' + fallingCount + ' falling edge interrupts (0 expected)'); + + fallingEdge(); + }, 1000); + } + + (function eitherEdge() { + console.log(' either edge'); + + input.enableInterrupt(Gpio.EITHER_EDGE); + risingCount = 0; + fallingCount = 0; + + setTimeout(function timer() { + console.log(' ' + risingCount + ' rising edge interrupts (~50 expected)'); + console.log(' ' + fallingCount + ' falling edge interrupts (~50 expected)'); + + risingEdge(); + }, 1000); + }()); +})(); + +(function isr_multiple_sources(): void { + const Gpio = pigpio.Gpio; + + [[7, 8], [9, 11]].forEach(function loop(gpioNos: [number, number]) { + let interruptCount = 0; + let input = new Gpio(gpioNos[0], { mode: Gpio.INPUT, edge: Gpio.EITHER_EDGE }); + let output = new Gpio(gpioNos[1], { mode: Gpio.OUTPUT }); + + // Put input and output in a known state + output.digitalWrite(0); + + input.on('interrupt', function event(level: number) { + interruptCount += 1; + output.digitalWrite(level ^ 1); + + if (interruptCount === 1000) { + console.log(' ' + interruptCount + ' interrupts detected on GPIO' + gpioNos[0]); + input.disableInterrupt(); + } + }); + + setTimeout(function timer() { + // Trigger first interrupt + output.digitalWrite(1); + }, 1); + }); +})(); + +(function isr_performance(): void { + const Gpio = pigpio.Gpio; + let interruptCount = 0; + let input = new Gpio(7, { mode: Gpio.INPUT, edge: Gpio.EITHER_EDGE }); + let output = new Gpio(8, { mode: Gpio.OUTPUT }); + + output.digitalWrite(0); + + input.on('interrupt', function event(level: number) { + interruptCount++; + output.digitalWrite(level ^ 1); + }); + + setTimeout(function timer() { + let time = process.hrtime(); + + output.digitalWrite(1); + + setTimeout(function timer() { + let interruptsPerSec: number; + + time = process.hrtime(time); + interruptsPerSec = Math.floor(interruptCount / (time[0] + time[1] / 1E9)); + + console.log(' ' + interruptsPerSec + ' interrupts per second'); + + input.disableInterrupt(); + }, 1000); + }, 1); +})(); + +(function isr_timeouts_2(): void { + const Gpio = pigpio.Gpio; + let timeoutCount = 0; + let input = new Gpio(7, { mode: Gpio.INPUT, edge: Gpio.EITHER_EDGE, timeout: 100 }); + + input.on('interrupt', function timer(level: number) { + if (level === Gpio.TIMEOUT) { + timeoutCount++; + } + }); + + setTimeout(function time() { + console.log(' ' + timeoutCount + ' timeouts detected (~10 expected)'); + + input.enableInterrupt(Gpio.EITHER_EDGE, 1); + timeoutCount = 0; + + setTimeout(function timer() { + input.disableInterrupt(); + console.log(' ' + timeoutCount + ' timeouts detected (~1000 expected)'); + }, 1000); + }, 1000); +})(); + +(function isr_timeouts(): void { + const Gpio = pigpio.Gpio; + let timeoutCount = 0; + let input = new Gpio(7, { mode: Gpio.INPUT, edge: Gpio.EITHER_EDGE, timeout: 10 }); + + input.on('interrupt', function timer(level: number) { + if (level === Gpio.TIMEOUT) { + timeoutCount++; + } + }); + + setTimeout(function timer() { + console.log(' ' + timeoutCount + ' timeouts detected (~100 expected)'); + + input.enableInterrupt(Gpio.EITHER_EDGE); + timeoutCount = 0; + + setTimeout(function timer() { + input.disableInterrupt(); + console.log(' ' + timeoutCount + ' timeouts detected (0 expected)'); + }, 1000); + }, 1000); +})(); + +(function light_switch(): void { + const Gpio = pigpio.Gpio; + let button = new Gpio(4, { + mode: Gpio.INPUT, + pullUpDown: Gpio.PUD_DOWN, + edge: Gpio.EITHER_EDGE + }); + let led = new Gpio(17, { mode: Gpio.OUTPUT }); + + button.on('interrupt', function event(level: number) { + led.digitalWrite(level); + }); + + setTimeout(function timer() { + led.digitalWrite(0); + button.disableInterrupt(); + }, 2000); + + console.log(' press the momentary push button a few times'); +})(); + +(function notifier_leak_check(): void { + const Gpio = pigpio.Gpio; + const Notifier = pigpio.Notifier; + let notifierCount = 0; + + let LED_GPIO = 18; + let FREQUENCY = 25000; + + (function closure() { + let led = new Gpio(LED_GPIO, { mode: Gpio.OUTPUT }); + + led.hardwarePwmWrite(FREQUENCY, 500000); + }()); + + (function next() { + let ledNotifier = new Notifier({ bits: 1 << LED_GPIO }); + let closing = false; + + ledNotifier.stream().on('data', function event() { + if (!closing) { + ledNotifier.stream().on('close', function event() { + notifierCount += 1; + + if (notifierCount % 1000 === 0) { + console.log(notifierCount); + } + + if (notifierCount < 100000) { + next(); + } + }); + + ledNotifier.close(); + closing = true; + } + }); + }()); +})(); + +(function notifier_pwm(): void { + const Gpio = pigpio.Gpio; + const Notifier = pigpio.Notifier; + + let LED_GPIO = 18; + let FREQUENCY = 25000; + + (function closure() { + let led = new Gpio(LED_GPIO, { mode: Gpio.OUTPUT }); + + led.hardwarePwmWrite(FREQUENCY, 500000); + }()); + + (function closure() { + let ledNotifier = new Notifier({ bits: 1 << LED_GPIO }); + let notificationsReceived = 0; + let seqnoErrors = 0; + let ledStateErrors = 0; + let lastSeqno: number; + let lastLedState: number; + let lastTick: number; + let minTickDiff = 0xffffffff; + let maxTickDiff = 0; + + ledNotifier.stream().on('data', function event(buf: Buffer) { + let ix = 0; + + for (ix = 0; ix < buf.length; ix += Notifier.NOTIFICATION_LENGTH) { + let seqno = buf.readUInt16LE(ix); + let tick = buf.readUInt32LE(ix + 4); + let level = buf.readUInt32LE(ix + 8); + + if (notificationsReceived > 0) { + if (lastLedState === (level & (1 << LED_GPIO))) { + console.log(' unexpected led state'); + ledStateErrors += 1; + } + + if ((lastSeqno + 1) !== seqno) { + console.log(' seqno error, was %d, expected %d', seqno, lastSeqno + 1); + seqnoErrors += 1; + } + + if (tick - lastTick < minTickDiff) { + minTickDiff = tick - lastTick; + } + + if (tick - lastTick > maxTickDiff) { + maxTickDiff = tick - lastTick; + } + } + + notificationsReceived += 1; + lastSeqno = seqno; + lastLedState = level & (1 << LED_GPIO); + lastTick = tick; + } + + if (notificationsReceived >= 50000) { + ledNotifier.stream().pause(); + ledNotifier.close(); + console.log(' notifications: %d', notificationsReceived); + console.log(' seqno errors: %d', seqnoErrors); + console.log(' led state errors: %d', ledStateErrors); + console.log(' expected tick diff: %d us', 1000000 / (FREQUENCY * 2)); + console.log(' min tick diff: %d us', minTickDiff); + console.log(' max tick diff: %d us', maxTickDiff); + } + }); + }()); +})(); + +(function notifier_stress(): void { + const Gpio = pigpio.Gpio; + const Notifier = pigpio.Notifier; + + let LED_GPIO = 18; + let FREQUENCY = 150000; + + pigpio.configureClock(1, pigpio.CLOCK_PCM); + + (function closure() { + let led = new Gpio(LED_GPIO, { mode: Gpio.OUTPUT }); + + led.hardwarePwmWrite(FREQUENCY, 500000); + }()); + + (function closure() { + let ledNotifier = new Notifier({ bits: 1 << LED_GPIO }); + let notificationsReceived = 0; + let events = 0; + let seqnoErrors = 0; + let ledStateErrors = 0; + let lastSeqno: number; + let lastLedState: number; + let lastTick: number; + let minTickDiff = 0xffffffff; + let maxTickDiff = 0; + let restBuf: Buffer | null = null; + let iv: NodeJS.Timer; + + function printInfo() { + console.log(); + console.log(' events: %d', events); + console.log(' notifications: %d', notificationsReceived); + console.log(' seqno errors: %d', seqnoErrors); + console.log(' led state errors: %d', ledStateErrors); + console.log(' expected tick diff: %d us', 1000000 / (FREQUENCY * 2)); + console.log(' min tick diff: %d us', minTickDiff); + console.log(' max tick diff: %d us', maxTickDiff); + + minTickDiff = 0xffffffff; + maxTickDiff = 0; + } + + ledNotifier.stream().on('data', function event(buf: Buffer) { + let ix: number; + let entries: number; + let rest: number; + + events += 1; + + if (restBuf !== null) { + buf = Buffer.concat([restBuf, buf]); + } + + entries = Math.floor(buf.length / Notifier.NOTIFICATION_LENGTH); + rest = buf.length % Notifier.NOTIFICATION_LENGTH; + + if (rest === 0) { + restBuf = null; + } else { + restBuf = new Buffer(buf.slice(buf.length - rest)); + } + + for (ix = 0; ix < buf.length - rest; ix += Notifier.NOTIFICATION_LENGTH) { + let seqno = buf.readUInt16LE(ix); + let tick = buf.readUInt32LE(ix + 4); + let level = buf.readUInt32LE(ix + 8); + + if (notificationsReceived > 0) { + if (lastLedState === (level & (1 << LED_GPIO))) { + console.log(' unexpected led state'); + ledStateErrors += 1; + } + + if (((lastSeqno + 1) & 0xffff) !== seqno) { + console.log(' seqno error, was %d, expected %d', seqno, lastSeqno + 1); + seqnoErrors += 1; + } + + if (tick - lastTick < minTickDiff) { + minTickDiff = tick - lastTick; + } + + if (tick - lastTick > maxTickDiff) { + maxTickDiff = tick - lastTick; + } + } + + notificationsReceived += 1; + lastSeqno = seqno; + lastLedState = level & (1 << LED_GPIO); + lastTick = tick; + } + + if (notificationsReceived >= 1e9) { + ledNotifier.stream().pause(); + ledNotifier.close(); + clearInterval(iv); + printInfo(); + } + }); + + iv = setInterval(printInfo, 5000); + }()); +})(); + +(function notifier(): void { + const Gpio = pigpio.Gpio; + const Notifier = pigpio.Notifier; + + let LED_GPIO = 17; + let LED_TOGGLES = 1000; + + (function closure() { + let led = new Gpio(LED_GPIO, { mode: Gpio.OUTPUT }); + let ledToggles = 0; + let lastTime = process.hrtime(); + let minSetIntervalDiff = 0xffffffff; + let maxSetIntervalDiff = 0; + let iv: NodeJS.Timer; + + iv = setInterval(function timer() { + let time = process.hrtime(); + let diff = Math.floor(((time[0] * 1e9 + time[1]) - (lastTime[0] * 1e9 + lastTime[1])) / 1000); + + lastTime = time; + + if (diff < minSetIntervalDiff) { + minSetIntervalDiff = diff; + } + + if (diff > maxSetIntervalDiff) { + maxSetIntervalDiff = diff; + } + + led.digitalWrite(led.digitalRead() ^ 1); + + ledToggles += 1; + if (ledToggles === LED_TOGGLES) { + clearInterval(iv); + + console.log(' led toggles: %d', ledToggles); + console.log(' min setInterval diff: %d us', minSetIntervalDiff); + console.log(' max setInterval diff: %d us', maxSetIntervalDiff); + } + }, 1); + }()); + + (function closure() { + let ledNotifier = new Notifier({ bits: 1 << LED_GPIO }); + let notificationsReceived = 0; + let seqnoErrors = 0; + let ledStateErrors = 0; + let lastSeqno: number; + let lastLedState: number; + let lastTick: number; + let minTickDiff = 0xffffffff; + let maxTickDiff = 0; + + ledNotifier.stream().on('data', function event(buf: Buffer) { + let ix = 0; + + for (ix = 0; ix < buf.length; ix += Notifier.NOTIFICATION_LENGTH) { + let seqno = buf.readUInt16LE(ix); + let tick = buf.readUInt32LE(ix + 4); + let level = buf.readUInt32LE(ix + 8); + + if (notificationsReceived > 0) { + if (lastLedState === (level & (1 << LED_GPIO))) { + console.log(' unexpected led state'); + ledStateErrors += 1; + } + + if ((lastSeqno + 1) !== seqno) { + console.log(' seqno error, was %d, expected %d', seqno, lastSeqno + 1); + seqnoErrors += 1; + } + + if (tick - lastTick < minTickDiff) { + minTickDiff = tick - lastTick; + } + + if (tick - lastTick > maxTickDiff) { + maxTickDiff = tick - lastTick; + } + } + + notificationsReceived += 1; + lastSeqno = seqno; + lastLedState = level & (1 << LED_GPIO); + lastTick = tick; + } + + if (notificationsReceived >= LED_TOGGLES) { + ledNotifier.close(); + console.log(' notifications: %d', notificationsReceived); + console.log(' seqno errors: %d', seqnoErrors); + console.log(' led state errors: %d', ledStateErrors); + console.log(' min tick diff: %d us', minTickDiff); + console.log(' max tick diff: %d us', maxTickDiff); + } + }); + }()); +})(); + +(function pull_up_down(): void { + const Gpio = pigpio.Gpio; + let input = new Gpio(22, { mode: Gpio.INPUT, pullUpDown: Gpio.PUD_UP }); + + assert.strictEqual(input.digitalRead(), 1, 'expected gpio22 to be 1'); + input.pullUpDown(Gpio.PUD_DOWN); + assert.strictEqual(input.digitalRead(), 0, 'expected gpio22 to be 0'); +})(); + +(function pulse_led(): void { + const Gpio = pigpio.Gpio; + let iv: NodeJS.Timer; + let led = new Gpio(17, { mode: Gpio.OUTPUT }); + let dutyCycle = 0; + + iv = setInterval(function timer() { + let dutyCycleRead: number; + + led.pwmWrite(dutyCycle); + + dutyCycleRead = led.getPwmDutyCycle(); + assert.strictEqual(dutyCycleRead, dutyCycle, + 'expected dutyCycle to be ' + dutyCycle + ', not ' + dutyCycleRead + ); + + dutyCycle += 5; + if (dutyCycle > 255) { + dutyCycle = 0; + } + }, 20); + + setTimeout(function timer() { + led.digitalWrite(0); + clearInterval(iv); + }, 2000); +})(); + +(function pwm(): void { + const Gpio = pigpio.Gpio; + let iv: NodeJS.Timer; + let led = new Gpio(18, { mode: Gpio.OUTPUT }); + let dutyCycle: number; + + assert.strictEqual(led.getPwmRange(), 255, 'expected pwm range to be 255'); + assert.strictEqual(led.getPwmRealRange(), 250, 'expected pwm real range to be 250'); + assert.strictEqual(led.getPwmFrequency(), 800, 'expected get pwm frequency to be 800'); + + led.pwmRange(125); + assert.strictEqual(led.getPwmRange(), 125, 'expected pwm range to be 125'); + assert.strictEqual(led.getPwmRealRange(), 250, 'expected pwm real range to be 250'); + assert.strictEqual(led.getPwmFrequency(), 800, 'expected get pwm frequency to be 800'); + + led.pwmFrequency(2000); + assert.strictEqual(led.getPwmRange(), 125, 'expected pwm range to be 125'); + assert.strictEqual(led.getPwmRealRange(), 100, 'expected pwm real range to be 100'); + assert.strictEqual(led.getPwmFrequency(), 2000, 'expected get pwm frequency to be 2000'); + + dutyCycle = Math.floor(led.getPwmRange() / 2); + led.pwmWrite(dutyCycle); + assert.strictEqual(led.getPwmDutyCycle(), dutyCycle, 'expected duty cycle to be ' + dutyCycle); + + led.hardwarePwmWrite(1e7, 500000); + assert.strictEqual(led.getPwmRange(), 1e6, 'expected pwm range to be 1e6'); + assert.strictEqual(led.getPwmRealRange(), 25, 'expected pwm real range to be 25'); + assert.strictEqual(led.getPwmFrequency(), 1e7, 'expected get pwm frequency to be 1e7'); + assert.strictEqual(led.getPwmDutyCycle(), 500000, 'expected duty cycle to be 500000'); + + led.digitalWrite(0); + assert.strictEqual(led.getPwmRange(), 125, 'expected pwm range to be 125'); + assert.strictEqual(led.getPwmRealRange(), 100, 'expected pwm real range to be 100'); + assert.strictEqual(led.getPwmFrequency(), 2000, 'expected get pwm frequency to be 2000'); +}); + +(function servo_control(): void { + const Gpio = pigpio.Gpio; + let iv: NodeJS.Timer; + let motor = new Gpio(17, { mode: Gpio.OUTPUT }); + let pulseWidth = 500; + + motor.servoWrite(0); + assert.strictEqual(motor.getServoPulseWidth(), 0, + 'expected pulseWidth to be 0' + ); + + iv = setInterval(function timer() { + let pulseWidthRead: number; + + motor.servoWrite(pulseWidth); + + pulseWidthRead = motor.getServoPulseWidth(); + assert.strictEqual(pulseWidthRead, pulseWidth, + 'expected pulseWidth to be ' + pulseWidth + ', not ' + pulseWidthRead + ); + + pulseWidth += 25; + if (pulseWidth > 2500) { + pulseWidth = 500; + } + }, 20); + + setTimeout(function timer() { + motor.digitalWrite(0); + clearInterval(iv); + }, 2000); +})(); + +(function tirgger_led(): void { + const Gpio = pigpio.Gpio; + let iv: NodeJS.Timer; + let led = new Gpio(17, { mode: Gpio.OUTPUT }); + + iv = setInterval(function timer() { + led.trigger(100, 1); + }, 2); + + setTimeout(function timer() { + led.digitalWrite(0); + clearInterval(iv); + }, 2000); +})(); diff --git a/types/pigpio/tsconfig.json b/types/pigpio/tsconfig.json new file mode 100644 index 0000000000..0ca0aba095 --- /dev/null +++ b/types/pigpio/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "pigpio-tests.ts" + ] +} \ No newline at end of file diff --git a/types/pigpio/tslint.json b/types/pigpio/tslint.json new file mode 100644 index 0000000000..377cc837d4 --- /dev/null +++ b/types/pigpio/tslint.json @@ -0,0 +1 @@ +{ "extends": "../tslint.json" }