UNPKG

rpio-define

Version:

Modern style define GPIO for RaspberryPi.

298 lines (290 loc) 11.9 kB
import rpio from 'rpio'; export { I2CDevice } from './i2c'; function definePort(type, modifier) { return function (option) { option.type = type; if (typeof modifier == 'function') modifier(option); return option; }; } export const DigitalOutput = definePort(Boolean); export const DigitalInput = definePort(Boolean, (opt) => { if (typeof opt.mode == 'undefined') opt.mode = 'input'; }); export const Servo = definePort('servo'); export const PWM = definePort('pwm'); /** use example ```javascript import rpio from 'rpio' import { defineIO, DigitalOutput, Servo } from 'rpio-define' rpio.init({ mapping: 'gpio' }); const io = defineIO({ led: DigitalOutput({ pin: 16 }), motor: Servo({ pin: 12, }) }); io.led = true; // LED on! setInterval(() => { io.led = !io.led; // LED blinking }, 1000); ``` */ export function defineIO(descriptors) { const io = {}; for (const [_key, descriptor] of Object.entries(descriptors)) { const key = _key; const type = typeof descriptor.type == 'string' ? descriptor.type.toLowerCase() : descriptor.type && 'name' in descriptor.type && typeof descriptor.type.name == 'string' ? descriptor.type.name.toLowerCase() : ''; const isDigitalPortDescriptor = (descriptor) => descriptor.type == Boolean || type == 'digital'; const isServoPortDescriptor = (descriptor) => type == 'servo'; const isPWMPortDescriptor = (descriptor) => type == 'pwm'; if (isDigitalPortDescriptor(descriptor)) { if (typeof descriptor.mode == 'string') { const mode = descriptor.mode.toLowerCase(); if (mode == 'output') descriptor.mode = rpio.OUTPUT; else if (mode == 'input') descriptor.mode = rpio.INPUT; } if (descriptor.mode == undefined) descriptor.mode = rpio.OUTPUT; const isDigitalPortOutputDescriptor = (descriptor) => descriptor.mode == rpio.OUTPUT || descriptor.mode == 'outputopendrain'; const isDigitalPortInputDescriptor = (descriptor) => descriptor.mode == rpio.INPUT || descriptor.mode == 'inputpullup'; if (isDigitalPortOutputDescriptor(descriptor)) { let value = descriptor.default || false; if (descriptor.mode == rpio.OUTPUT) { rpio.mode(descriptor.pin, descriptor.mode, value ? rpio.HIGH : rpio.LOW); } else { rpio.mode(descriptor.pin, rpio.INPUT, rpio.LOW); if (descriptor.default) { rpio.mode(descriptor.pin, rpio.OUTPUT, rpio.LOW); } } Object.defineProperty(io, key, { get() { return value; }, set(val) { value = val; if (descriptor.mode == rpio.OUTPUT) { rpio.write(descriptor.pin, value ? rpio.HIGH : rpio.LOW); } else if (descriptor.mode == 'outputopendrain') { rpio.mode(descriptor.pin, value ? rpio.OUTPUT : rpio.INPUT); } }, enumerable: true, }); } else if (isDigitalPortInputDescriptor(descriptor)) { if (typeof descriptor.callback == 'function') { const opt = { pin: descriptor.pin, mode: descriptor.mode, edge: descriptor.edge, }; if (typeof opt.edge == 'string') { if (opt.edge == 'rising') opt.edge = rpio.POLL_HIGH; else if (opt.edge == 'falling') opt.edge = rpio.POLL_LOW; else if (opt.edge == 'both') opt.edge = rpio.POLL_BOTH; } if (typeof opt.mode == 'undefined') // @ts-ignore delete opt.mode; if (typeof opt.edge == 'undefined') delete opt.edge; rpio.poll(descriptor.pin, descriptor.callback, descriptor.edge !== undefined ? opt.edge : rpio.POLL_BOTH); Object.defineProperty(io, key, { get() { const value = !!rpio.read(descriptor.pin); return descriptor.mode == rpio.PULL_UP ? !value : value; }, enumerable: true, }); } else { rpio.mode(descriptor.pin, rpio.INPUT, descriptor.mode == 'inputpullup' ? rpio.PULL_UP : rpio.PULL_OFF); Object.defineProperty(io, key, { get() { const value = !!rpio.read(descriptor.pin); return descriptor.mode == rpio.PULL_UP ? !value : value; }, enumerable: true, }); } } } /* RaspberryPiにはDAC/ADCは標準搭載されていないらしい・・・。残念。 else if ((descriptor.type == Analog || descriptor.type == Number || type == 'analog')) { // [Analog] https://github.com/Moddable-OpenSource/moddable/blob/public/documentation/pins/pins.md#analog const scale = typeof descriptor.scale == 'number' ? descriptor.scale : 1 // ESP32の場合のDigital -> Analog ピン番号読み替え // https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-gpio.c#L27 const analogPin = descriptor.pin > 7 ? { 36: 0, 37: 1, 38: 2, 39: 3, 32: 4, 33: 5, 34: 6, 35: 7, //8 //9 //4: 10, //0: 11, //2: 12, 15: 13, 13: 14, 12: 15, 14: 16, 27: 17, 25: 18, 26: 19 }[descriptor.pin] : descriptor.pin const port = new Digital(descriptor.pin, Digital.Input) // 44や971は実測の最大・最小値  いったんこの値でキャリブレーション let min = 44 let max = 971 Object.defineProperty(io, key, { get() { const raw = Analog.read(analogPin) if (raw > max) max = raw if (raw < min) min = raw const value = Math.min(Math.max(raw - min, 0) / (max - min), 1) return value * scale }, enumerable: true, }) } */ else if (isServoPortDescriptor(descriptor)) { let value = descriptor.default || 0; const option = { pin: descriptor.pin, min: descriptor.min, max: descriptor.max }; let minAngle = 0; let maxAngle = 180; let offsetAngle = 0; if (typeof option.min == 'undefined') option.min = 500; if (typeof option.min == 'object') { if (typeof option.min.angle == 'number') minAngle = option.min.angle; option.min = option.min.pulse; } if (typeof option.max == 'undefined') option.max = 2400; if (typeof option.max == 'object') { if (typeof option.max.angle == 'number') maxAngle = option.max.angle; option.max = option.max.pulse; } if (typeof descriptor.offset == 'number') { offsetAngle = descriptor.offset; } const scale = (option.max - option.min) / (maxAngle - minAngle); let minPulse = option.min; if (option.min === undefined) delete option.min; if (option.max === undefined) delete option.max; rpio.open(descriptor.pin, rpio.PWM); rpio.pwmSetClockDivider(128); // 1.92MHz / 128 = 150kHz rpio.pwmSetRange(descriptor.pin, 3000); // 150kHz / 3000 = 50Hz = 20ms const rate = 20000 / 3000; // (20ms = 20,000us) / 3000 = 6.6us Object.defineProperty(io, key, { get() { return value; }, set(val) { value = val; rpio.pwmSetData(descriptor.pin, ((((val - minAngle + offsetAngle) * scale) + minPulse) / rate) | 0); }, enumerable: true, }); // @ts-ignore io[key] = value; } /* else if (type =='tone' || type == 'pulse') { const option = { pin: descriptor.pin } Object.defineProperty(io, key, { value(frequency, duration) { option.freq = frequency const port = new Tone(option) port.write(frequency) if (duration) { Timer.delay(duration) port.close() } else { return () => port.close() } } }) } */ else if (isPWMPortDescriptor(descriptor)) { let value = descriptor.default || 0; const opt = { pin: descriptor.pin, hz: 300000 }; const max = descriptor.max || 1; if (typeof descriptor.hz == 'number') opt.hz = descriptor.hz; rpio.open(opt.pin, rpio.PWM); rpio.pwmSetRange(opt.pin, 1023); rpio.pwmSetClockDivider(Math.floor((19.2 * 1000000) / opt.hz)); Object.defineProperty(io, key, { get() { return value; }, set(val) { value = val; if (max > 1) { val /= max; } if (val <= 1) val *= 1023; rpio.pwmSetData(opt.pin, val); }, enumerable: true, }); // @ts-ignore io[key] = value; } else if ('get' in descriptor) { Object.defineProperty(io, key, { get: descriptor.get, set: descriptor.set, enumerable: true, }); } else if ('value' in descriptor) { Object.defineProperty(io, key, { value: descriptor.value, enumerable: true, }); } } return io; } Object.freeze(defineIO); export default defineIO;