array-gpio
Advanced tools
+189
-686
| /*! | ||
| * array-gpio | ||
| * | ||
| * Copyright(c) 2017 Ed Alegrid | ||
| * Copyright(c) 2017 Ed Alegrid <ealegrid@gmail.com> | ||
| * MIT Licensed | ||
@@ -10,42 +10,38 @@ */ | ||
| const EventEmitter = require('events'); | ||
| class StateEmitter extends EventEmitter {} | ||
| const emitter = exports.emitter = new StateEmitter(); | ||
| emitter.setMaxListeners(2); | ||
| const rpi = require('./rpi.js'); | ||
| const I2C = require('./i2c.js'); | ||
| const SPI = require('./spi.js'); | ||
| const PWM = require('./pwm.js'); | ||
| const i2c = require('./i2c.js'); | ||
| const spi = require('./spi.js'); | ||
| const pwm = require('./pwm.js'); | ||
| const GpioInput = require('./gpio-input.js'); | ||
| const GpioOutput = require('./gpio-output.js'); | ||
| var pwr3 = [1,17]; | ||
| var pwr5 = [2,4]; | ||
| var uart = {txd:8,rxd:10}; | ||
| var i2c = {sda:3,scl:5}; | ||
| var pwm = {pwm0:[12,32],pwm1:[33,35]}; | ||
| var spi = {mosi:19,miso:21,sclk:23,cs0:24,cs1:26}; | ||
| var eprom = {sda:27,scl:28}; | ||
| var ground = [6,9,14,20,25,30,34,39]; | ||
| var gpio = [3,5,7,8,10,11,12,13,15,16,18,19,21,22,23,24,26,27,28,29,31,32,33,35,36,37,38,40]; | ||
| /* time variables */ | ||
| var d1, d2; | ||
| var outputPin = []; | ||
| var inputPin = [], inputObject = []; | ||
| var activeGpioPins = []; | ||
| /* debug mode variables */ | ||
| var debugState = false, debugStateAdvanced = false; | ||
| function startTime(){ | ||
| d1 = new Date(); | ||
| } | ||
| /* PWM variables */ | ||
| var pwmObjectTotal = 0, pwmPin = {c1:[], c2:[]}, pwmObject = 0; | ||
| function endTime(m){ | ||
| d2 = new Date(); | ||
| let eT = Math.abs(d2-d1); | ||
| if(m === undefined){ | ||
| console.log(eT + ' ms'); | ||
| } | ||
| else if(m === 1){ | ||
| return (eT + ' ms'); | ||
| } | ||
| } | ||
| /* GPIO setup variables */ | ||
| var eventPin = [], arrayPinCheck = []; | ||
| function findDuplicatePins(arr) { | ||
| let dup = arr.filter((item, index) => arr.indexOf(item) !== index); | ||
| if(dup[0]){ | ||
| console.log('*** WARNING : duplicate pin detected', dup, '***' ) | ||
| } | ||
| } | ||
| /* watch input object container */ | ||
| //var watchData = []; | ||
| /* GPIO option input default values */ | ||
| function setOption(options){ | ||
| if(options.index === undefined){ | ||
| function setInputDefaultOptions(options){ | ||
| if(!options.index === undefined){ | ||
| options.index = '0~n'; | ||
@@ -59,100 +55,122 @@ } | ||
| } | ||
| if(options.intR === undefined){ | ||
| options.intR = 'none'; | ||
| if(options.pud === undefined){ | ||
| options.pud = null; | ||
| } | ||
| if(options.pinCheck === undefined || options.pinCheck === true){ | ||
| options.pinCheck = true; | ||
| } | ||
| return options; | ||
| } | ||
| /* watch/monitor a gpio input pin */ | ||
| function watchPin(edge, cb, pin, td){ | ||
| rpi.gpio_watchPin(edge, cb, pin, td); | ||
| function createGpioSingleObject(arg, pinArray, type, options){ | ||
| let pin = arg[0]; | ||
| let gpioObject = {}; | ||
| let config = '{ ' + pin + ' } '; | ||
| if(Number.isInteger(pin)){ | ||
| pinArray.push(pin); | ||
| activeGpioPins.push(pin); | ||
| if(type === 0){ // input | ||
| inputPin.push(pin); | ||
| gpioObject = new GpioInput(pin, 0, options); | ||
| inputObject.push(gpioObject); | ||
| } | ||
| else if(type === 1){ // output | ||
| outputPin.push(pin); | ||
| gpioObject = new GpioOutput(pin, 0, options); | ||
| } | ||
| } | ||
| if(type === 0){ | ||
| console.log('GPIO Input', config + endTime(1)); | ||
| } | ||
| else if(type === 1){ | ||
| console.log('GPIO Output', config + endTime(1)); | ||
| } | ||
| return gpioObject; | ||
| } | ||
| /* unwatch a gpio input pin */ | ||
| function unwatchPin(pin){ | ||
| rpi.gpio_unwatchPin(pin); | ||
| function createGpioArrayObject(pinArray, type, options){ | ||
| let pins = []; | ||
| let objectArray = []; | ||
| let config = '{ pin:[' + pinArray + '], index:0~n } '; | ||
| for (let i = 0; i < pinArray.length; i++) { | ||
| let index = i, pin = pinArray[i]; | ||
| activeGpioPins.push(pin); | ||
| if(options.index === 'pin' || options.i === 1){ | ||
| config = '{ pin:[' + pinArray + '], index:pin } '; | ||
| index = pinArray[i]; | ||
| } | ||
| if(type === 0){ // input | ||
| inputPin.push(pin); | ||
| objectArray[index] = new GpioInput(pin, index, options); | ||
| inputObject.push(objectArray[index]); | ||
| } | ||
| else if(type === 1){ // output | ||
| outputPin.push(pin); | ||
| objectArray[index] = new GpioOutput(pin, index, options); | ||
| } | ||
| } | ||
| if(type === 0){ | ||
| console.log('GPIO Input', config + endTime(1)); | ||
| } | ||
| else if(type === 1){ | ||
| console.log('GPIO Output', config + endTime(1)); | ||
| } | ||
| return objectArray; | ||
| } | ||
| /* show warning msg for GPIO duplicate pin */ | ||
| function duplicatePinError(pin) { | ||
| console.log('pin ' + pin + ' is already in used\n'); | ||
| function setArrayObject1(args, pinArray, type, options){ | ||
| let pins = args[0].pin; | ||
| for (let x = 0; x < pins.length; x++) { | ||
| if(Number.isInteger(pins[x]) ){ | ||
| pinArray.push(pins[x]); | ||
| } | ||
| } | ||
| options.i = args[0].i; | ||
| options.index = args[0].index; | ||
| } | ||
| /* invalid pin error handler */ | ||
| function invalidPinError(pin) { | ||
| console.log('invalid pin', pin); | ||
| throw new Error('invalid pin'); | ||
| } | ||
| /* debug message function */ | ||
| function dmsg(x, msg, cb){ | ||
| if(x === undefined){ | ||
| console.log(msg); | ||
| } | ||
| else if(x === 0){ | ||
| if(debugState && !debugStateAdvanced){ | ||
| //continue | ||
| function setArrayObject2(args, pinArray, type, options){ | ||
| for (let x = 0; x < args.length; x++) { | ||
| let pin = args[x]; | ||
| if(Number.isInteger(pin) ){ | ||
| pinArray.push(pin); | ||
| } | ||
| else if(args[x] === 'pin'){ | ||
| options.index = args[x]; | ||
| } | ||
| } | ||
| else if (x === 1){ | ||
| if(debugState && debugStateAdvanced){ | ||
| if(msg){ | ||
| console.log(msg); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| /* process time functions */ | ||
| function getTime(){ | ||
| var d = new Date(); | ||
| var t = d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() + ':' + d.getMilliseconds(); | ||
| return t; | ||
| } | ||
| function createGpio(type, pins){ | ||
| startTime(); | ||
| function startTime(){ | ||
| d1 = new Date(); | ||
| } | ||
| let gpioObject = [], gpioPins = [], options = {}; | ||
| function endTime(m){ | ||
| d2 = new Date(); | ||
| var eT = Math.abs(d2-d1); | ||
| if(m === undefined){ | ||
| console.log(eT + ' ms'); | ||
| pins = Array.from(pins); | ||
| rpi.validatePins(pins); | ||
| if(type == 0){ | ||
| setInputDefaultOptions(options); | ||
| } | ||
| // single gpio object, e.g. r.setInput(11) or r.Output(33) | ||
| if(Number.isInteger(pins[0]) && pins.length === 1){ | ||
| delete options.index; | ||
| gpioObject = createGpioSingleObject(pins, gpioPins, type, options); | ||
| } | ||
| else if(m === 1){ | ||
| return (eT + ' ms'); | ||
| // array object type 1, e.g. r.input({pin:[pin1, pin2, pin3, ... pinN], options}) | ||
| else if(!Number.isInteger(pins[0]) && pins.length === 1) { | ||
| setArrayObject1(pins, gpioPins, type, options) | ||
| gpioObject = createGpioArrayObject(gpioPins, type, options); | ||
| } | ||
| } | ||
| // array object type 2, e.g. r.output(pin1, pin2, pin3, ... pinN, options) | ||
| else if(pins.length > 1) { | ||
| setArrayObject2(pins, gpioPins, type, options); | ||
| gpioObject = createGpioArrayObject(gpioPins, type, options); | ||
| } | ||
| findDuplicatePins(activeGpioPins); | ||
| /* Check GPIO duplicate pins */ | ||
| function checkPinOnArray(arr1){ | ||
| var pinCheck = '\n*** Warning ***\nDuplicate pin detected ['; | ||
| for (var x = 0; x < arr1.length; x++) { | ||
| for (var i = 0; i < arr1.length; i++) { | ||
| if(x === i){ | ||
| pinCheck += ' ' + arr1[i]; | ||
| break; | ||
| } | ||
| else if (arr1[x] === arr1[i]) { | ||
| pinCheck += ' *' + arr1[i]; | ||
| if(debugStateAdvanced){ | ||
| dmsg(1, pinCheck + ' ] *** Fail ***'); | ||
| return false | ||
| } | ||
| else{ | ||
| console.log('** warning **'); | ||
| duplicatePinError(arr1[x]); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| dmsg(1, pinCheck + ' ] OK'); | ||
| return true; | ||
| Object.preventExtensions(gpioObject); | ||
| return gpioObject; | ||
| } | ||
| /****************************** | ||
@@ -165,630 +183,115 @@ * | ||
| constructor (){ | ||
| this.in = this.setInput; | ||
| this.input = this.setInput; | ||
| this.Input = this.setInput; | ||
| this.out = this.setOutput; | ||
| this.output = this.setOutput; | ||
| this.Output = this.setOutput; | ||
| } | ||
| constructor (){} | ||
| close() | ||
| { | ||
| rpi.lib_close(); | ||
| close (){ | ||
| rpi.rpi_close(); | ||
| } | ||
| /* watchInput - shared GPIO input monitoring method */ | ||
| watchInput (edge, cb, td){ | ||
| if(typeof edge === 'function' && typeof cb === 'number'){ | ||
| td = cb; | ||
| cb = edge; | ||
| edge = null; | ||
| for (let x = 0; x < inputObject.length; x++) { | ||
| inputObject[x].watchPin(edge, cb, td); | ||
| } | ||
| else if(typeof edge === 'function' && cb === undefined){ | ||
| cb = edge; | ||
| edge = null; | ||
| } | ||
| else if(typeof edge !== 'string' && typeof edge !== 'number' && edge !== null){ | ||
| throw new Error('invalid edge argument'); | ||
| } | ||
| else if ((typeof edge === 'string' || typeof edge === 'number') && typeof cb !== 'function'){ | ||
| throw new Error('invalid callback argument'); | ||
| } | ||
| for (var x = 0; x < eventPin.length; x++) { | ||
| watchPin(edge, cb, eventPin[x], td); | ||
| } | ||
| } | ||
| /* unwatch() method (for watchInput) */ | ||
| unwatchInput(){ | ||
| for (var x = 0; x < eventPin.length; x++) { | ||
| unwatchPin(eventPin[x]); | ||
| } | ||
| for (let x = 0; x < inputObject.length; x++) { | ||
| inputObject[x].unwatchPin(edge, cb, td); | ||
| } | ||
| } | ||
| /******************************************** | ||
| /*********** | ||
| GPIO Methods | ||
| GPIO | ||
| ********************************************/ | ||
| /* | ||
| * GPIO setInput method | ||
| */ | ||
| ***********/ | ||
| setInput () { | ||
| startTime(); | ||
| var input = [], options = {}, inputPin = [], pinCheck = true, config, arraySetup; | ||
| return createGpio(0, arguments); | ||
| } | ||
| if(arguments[0] === undefined || arguments[0] === null ){ | ||
| console.log('\nsetInput() - empty argument!'); | ||
| invalidPinError(arguments[0]); | ||
| } | ||
| in = this.setInput; | ||
| input = this.setInput; | ||
| Input = this.setInput; | ||
| if(typeof arguments[0] === 'string' || typeof arguments[0] === 'function' ){ | ||
| console.log('\nsetInput() - invalid argument!'); | ||
| invalidPinError(arguments[0]); | ||
| } | ||
| /* check for invalid pin arguments - empty {} or {pin:[]} */ | ||
| if(typeof arguments[0] === 'object' && (arguments[0].pin === undefined || arguments[0].pin[0] == undefined)){ | ||
| console.log('\nsetInput({pin:[]}) - array pin property is empty!'); | ||
| invalidPinError(arguments[0]); | ||
| } | ||
| /* | ||
| * barebone single input object | ||
| * r.setInput(11); | ||
| */ | ||
| if(Number.isInteger(arguments[0]) && arguments.length === 1) { | ||
| var pin = arguments[0]; | ||
| try{ | ||
| rpi.gpio_open(arguments[0], 0); | ||
| inputPin.push(arguments[0]); | ||
| eventPin.push(arguments[0]); | ||
| arrayPinCheck.push(arguments[0]); | ||
| config = '{ pin:' + inputPin + ' } ' + endTime(1); | ||
| console.log('GPIO Input', config); | ||
| return new GpioInput(0, pin, {}); | ||
| } | ||
| catch(e){ | ||
| return invalidPinError(arguments[0]); | ||
| } | ||
| } | ||
| /* | ||
| * array object | ||
| * r.input({pin:[pin1, pin2, pin3, ... pinN], options}) | ||
| */ | ||
| if(!Number.isInteger(arguments[0]) && typeof arguments[0] === 'object' && arguments.length === 1) { | ||
| for (var x = 0; x < arguments[0].pin.length; x++) { | ||
| // check if pins are from numbers 1 ~ 40 and validate for input use | ||
| if(Number.isInteger(arguments[0].pin[x]) && arguments[0].pin[x] > 0 && arguments[0].pin[x] < 41){ | ||
| try{ | ||
| rpi.gpio_open(arguments[0].pin[x], 0); | ||
| } | ||
| catch(e){ | ||
| inputPin.push(' *' + arguments[0].pin[x]); | ||
| console.log('input pins [ ' + inputPin + ' ]'); | ||
| invalidPinError(arguments[0].pin[x]); | ||
| } | ||
| inputPin.push(arguments[0].pin[x]); | ||
| arrayPinCheck.push(arguments[0].pin[x]); | ||
| } | ||
| // invalid pin number | ||
| else{ | ||
| invalidPinError(arguments[0].pin[x]); | ||
| } | ||
| } | ||
| options = arguments[0]; | ||
| } | ||
| /* | ||
| * array object | ||
| * r.input(pin1, pin2, pin3, ... pinN, options) | ||
| */ | ||
| if(Number.isInteger(arguments[0]) && arguments.length >= 1) { | ||
| for (var x = 0; x < arguments.length; x++) { | ||
| // check if pins are from numbers 1 ~ 40 and validate for input use | ||
| if(Number.isInteger(arguments[x]) && arguments[x] > 0 && arguments[x] < 41){ | ||
| try{ | ||
| rpi.gpio_open(arguments[x], 0); | ||
| } | ||
| catch(e){ | ||
| inputPin.push(' *' + arguments[x]); | ||
| console.log('input pins [ ' + inputPin + ' ]'); | ||
| invalidPinError(arguments[x]); | ||
| } | ||
| inputPin.push(arguments[x]); | ||
| arrayPinCheck.push(inputPin[x]); | ||
| } | ||
| // invalid pin number | ||
| else if(Number.isInteger(arguments[x]) && arguments[x] <= 0 || arguments[x] > 40){ | ||
| invalidPinError(arguments[x]); | ||
| } | ||
| else if(arguments[x] === 're' || arguments[x] === 'fe'){ | ||
| options.edge = arguments[x]; | ||
| } | ||
| else if(arguments[x] === 'pu' || arguments[x] === 'pd'){ | ||
| options.intR = arguments[x]; | ||
| } | ||
| else if(arguments[x] === true || arguments[x] === false){ | ||
| options.event = arguments[x]; | ||
| } | ||
| else if(arguments[x] === 'PinAsIndex'){ | ||
| options.index = arguments[x]; | ||
| } | ||
| else if(arguments[x] === 'NoPinCheck'){ | ||
| options.pinCheck = arguments[x]; | ||
| pinCheck = false; | ||
| } | ||
| else if(arguments[x] instanceof Object ){ | ||
| options = arguments[x]; | ||
| } | ||
| else { | ||
| console.log('Invalid arguments', arguments[x]); | ||
| } | ||
| } // for | ||
| } | ||
| setOption(options); | ||
| /* | ||
| * function to create an input array object | ||
| */ | ||
| function createObject(inputPin, options, GpioInput){ | ||
| for (var i = 0; i < inputPin.length; i++) { | ||
| var index = i, pin = inputPin[i]; | ||
| if(options){ | ||
| if(options.pinCheck === 'NoPinCheck' || options.pinCheck === false){ | ||
| pinCheck = false; | ||
| } | ||
| if(options.index === 'PinAsIndex' || options.index === 'pin'){ | ||
| index = inputPin[i]; | ||
| } | ||
| eventPin.push(pin); | ||
| input[index] = new GpioInput(index, pin, options); | ||
| } | ||
| } | ||
| } | ||
| createObject(inputPin, options, GpioInput); | ||
| /* check for duplicate pins */ | ||
| if(debugState || debugStateAdvanced){ | ||
| arrayPinCheck = []; | ||
| } | ||
| else if(pinCheck){ | ||
| checkPinOnArray(arrayPinCheck); | ||
| } | ||
| if(inputPin.length > 1) { | ||
| arraySetup = options.index; | ||
| config = '{ pin:[' + inputPin + ']' + ', index:' + options.index + ' } ' + endTime(1); | ||
| if(options.array){ | ||
| config = '{ pin:[' + inputPin + ']' + ', array:true, index:' + options.index + ' } ' + endTime(1); | ||
| } | ||
| } | ||
| else if(inputPin.length < 2 && options.array === true && (options.index === 'PinAsIndex' || options.index === 'pin')){ | ||
| config = '{ pin:[' + inputPin + '], array:true, index:pin } ' + endTime(1); | ||
| } | ||
| else if(inputPin.length < 2 && options.array === true ){ | ||
| config = '{ pin:[' + inputPin + '], array:true, index:0~n } ' + endTime(1); | ||
| } | ||
| else{ | ||
| config = '{ pin:' + inputPin + ' } ' + endTime(1); | ||
| } | ||
| /* INPUT GPIO config output */ | ||
| console.log('GPIO input ', config); | ||
| Object.preventExtensions(input); | ||
| return input; | ||
| } // end of setInput | ||
| /* | ||
| * GPIO setOutput method property | ||
| */ | ||
| setOutput () { | ||
| return createGpio(1, arguments); | ||
| } | ||
| startTime(); | ||
| out = this.setOutput; | ||
| output = this.setOutput; | ||
| Output = this.setOutput; | ||
| var output = [], outputPin = [], options = {}, pinCheck = true, config, arraySetup; | ||
| /********* | ||
| if(arguments[0] === undefined || arguments[0] === null ){ | ||
| console.log('\nsetOutput() - empty argument!'); | ||
| invalidPinError(arguments[0]); | ||
| } | ||
| PWM | ||
| if(typeof arguments[0] === 'string' || typeof arguments[0] === 'function' ){ | ||
| console.log('\nsetOutput() - invalid argument!'); | ||
| invalidPinError(arguments[0]); | ||
| } | ||
| *********/ | ||
| // classic api | ||
| // e.g let pwm = new r.PWM(12) | ||
| PWM = pwm; | ||
| /* check for invalid arguments - empty {} or {pin:[]} */ | ||
| if(typeof arguments[0] === 'object' && (arguments[0].pin === undefined || arguments[0].pin[0] == undefined)){ | ||
| console.log('\nsetOutput({pin:[]}) - array pin property is empty!'); | ||
| invalidPinError(arguments[0]); | ||
| } | ||
| /* | ||
| * barebone single output object | ||
| * r.setOutput(33); | ||
| */ | ||
| if(Number.isInteger(arguments[0]) && arguments.length === 1 && arguments[0] > 0 && arguments[0] < 41) { | ||
| var pin = arguments[0]; | ||
| try{ | ||
| rpi.gpio_open(arguments[0] , 1); | ||
| outputPin.push(arguments[0]); | ||
| arrayPinCheck.push(arguments[0]); | ||
| config = '{ pin:' + outputPin + ' } ' + endTime(1); | ||
| console.log('GPIO Output', config); | ||
| return new GpioOutput(0, pin, {}); | ||
| } | ||
| catch(e){ | ||
| return invalidPinError(arguments[0]); | ||
| } | ||
| } | ||
| /* | ||
| * array object | ||
| * r.output({pin:[pin1, pin2, pin3, ... pinN], options}) | ||
| */ | ||
| if(!Number.isInteger(arguments[0]) && typeof arguments[0] === 'object' && arguments.length === 1) { | ||
| for (var x = 0; x < arguments[0].pin.length; x++) { | ||
| // check if pins are from numbers 1 ~ 40 and validate for output use | ||
| if(Number.isInteger(arguments[0].pin[x]) && arguments[0].pin[x] > 0 && arguments[0].pin[x] < 41){ | ||
| try{ | ||
| rpi.gpio_open(arguments[0].pin[x], 1); | ||
| } | ||
| catch(e){ | ||
| outputPin.push(' *' + arguments[0].pin[x]); | ||
| console.log('output pins [ ' + outputPin + ' ]'); | ||
| invalidPinError(arguments[0].pin[x]); | ||
| } | ||
| outputPin.push(arguments[0].pin[x]); | ||
| arrayPinCheck.push(arguments[0].pin[x]); | ||
| } | ||
| // invalid pin number | ||
| else{ | ||
| invalidPinError(arguments[0].pin[x]); | ||
| } | ||
| } | ||
| options = arguments[0]; | ||
| } | ||
| /* | ||
| * array object | ||
| * r.output(pin1, pin2, pin3, ... pinN, options) | ||
| */ | ||
| if (Number.isInteger(arguments[0]) && arguments.length >= 1) { | ||
| for (var x = 0; x < arguments.length; x++) { | ||
| // check if pins are from numbers 1 ~ 40 and validate for output use | ||
| if(Number.isInteger(arguments[x]) && arguments[x] > 0 && arguments[x] < 41 ){ | ||
| try{ | ||
| rpi.gpio_open(arguments[x], 1); | ||
| } | ||
| catch(e){ | ||
| outputPin.push(' *' + arguments[x]); | ||
| console.log('output pins [ ' + outputPin + ' ]'); | ||
| invalidPinError(arguments[x]); | ||
| } | ||
| outputPin[x] = arguments[x]; /* direct */ | ||
| //outputPin.push(arguments[x]); /* push method */ | ||
| arrayPinCheck.push(arguments[x]); | ||
| } | ||
| // invalid pin number | ||
| else if(Number.isInteger(arguments[x]) && arguments[x] <= 0 || arguments[x] > 40){ | ||
| invalidPinError(arguments[x]); | ||
| } | ||
| else if(arguments[x] === 'PinAsIndex'){ | ||
| options = arguments[x]; | ||
| } | ||
| else if(arguments[x] === 'NoPinCheck'){ | ||
| options = arguments[x]; | ||
| pinCheck = false; | ||
| } | ||
| else if(arguments[x] instanceof Object ){ | ||
| if(arguments[x].pinCheck === false){ | ||
| pinCheck = false; | ||
| } | ||
| if(arguments[x].pinCheck === true){ | ||
| pinCheck = true; | ||
| } | ||
| options = arguments[x]; | ||
| } | ||
| else{ | ||
| console.log('Invalid arguments', arguments[x]); | ||
| } | ||
| } | ||
| } | ||
| /* | ||
| * function to create an output object | ||
| */ | ||
| function createObject(outputPin, options, GpioOutput){ | ||
| for (var x = 0; x < outputPin.length; x++) { /* Dec. 27, 2017 */ | ||
| var index = x; | ||
| if(options){ | ||
| if(options === 'PinAsIndex' || options.index === 'pin'){ | ||
| index = outputPin[x]; | ||
| } | ||
| } | ||
| output[index] = new GpioOutput(index, outputPin[x]); | ||
| } | ||
| } | ||
| createObject(outputPin, options, GpioOutput); | ||
| /* check for duplicate pins */ | ||
| if(debugState || debugStateAdvanced){ | ||
| arrayPinCheck = []; | ||
| } | ||
| else if(pinCheck) { | ||
| checkPinOnArray(arrayPinCheck); | ||
| } | ||
| if(outputPin.length > 1) { | ||
| if(options === undefined || !options.index){ | ||
| arraySetup = 'index:0~n'; | ||
| } | ||
| else if(options.index && !options.array) { | ||
| arraySetup = 'index:pin'; | ||
| } | ||
| else if(options.array && !options.index) { | ||
| arraySetup = 'array:true, index:0~n'; | ||
| } | ||
| else if(options.array && options.index){ | ||
| arraySetup = 'array:true, index:pin'; | ||
| } | ||
| config = '{ pin:[' + outputPin + '], ' + arraySetup + ' } ' + endTime(1); | ||
| } | ||
| else if(outputPin.length < 2 && options && options.array == true && (options.index === 'pin' || options === 'PinAsIndex')){ | ||
| config = '{ pin:[' + outputPin + '], array:true, index:pin } ' + endTime(1); | ||
| } | ||
| else if(outputPin.length < 2 && options && options.array){ | ||
| config = '{ pin:[' + outputPin + '], array:true, index:0~n } ' + endTime(1); | ||
| } | ||
| else{ | ||
| config = '{ pin:' + outputPin + ' } ' + endTime(1); | ||
| } | ||
| /* OUTPUT GPIO config output */ | ||
| console.log('GPIO output ' + config); | ||
| Object.preventExtensions(output); | ||
| return output; | ||
| } // end of setOutput | ||
| /* validPin helper method */ | ||
| validPin (){ | ||
| var validPin = [], invalidPin = []; | ||
| for(var x = 0; x < 41 ; x++){ | ||
| try{ | ||
| rpi.gpio_open(x, 0); | ||
| validPin.push(x); | ||
| } | ||
| catch(e){ | ||
| invalidPin.push(x); | ||
| } | ||
| } | ||
| console.log('GPIO valid pins', validPin); | ||
| console.log('GPIO invalid pins', invalidPin); | ||
| // w/o new e.g let pwm = r.PWM(12) | ||
| PWM(pin, freq, T, pw) { | ||
| return new spi(pin, freq, T, pw); | ||
| } | ||
| /* debug mode setup method for test */ | ||
| debug(x){ | ||
| if(x === 1){ | ||
| debugState = true; | ||
| debugStateAdvanced = true; | ||
| } | ||
| return debugState; | ||
| startPWM(pin, freq, T, pw){ | ||
| return new pwm(pin, freq, T, pw); | ||
| } | ||
| /******************************************** | ||
| /********* | ||
| PWM Methods | ||
| I2C | ||
| ********************************************/ | ||
| setPWM(pin, freq, T, pw){ | ||
| if(arguments.length > 4 || arguments.length < 1){ | ||
| throw new Error('invalid PWM(pin, freq, T, pw) arguments'); | ||
| } | ||
| /* arguments validation */ | ||
| if(arguments[0] === 33 || arguments[0] === 35 || arguments[0] === 12 || arguments[0] === 32){ | ||
| var validPin = pin; | ||
| /* store validated pin in array */ | ||
| if(validPin === 12 || validPin === 32){ | ||
| pwmPin.c1.push(validPin); | ||
| } | ||
| else{ | ||
| pwmPin.c2.push(validPin); | ||
| } | ||
| /* check duplicate pins */ | ||
| if(pwmPin.c1.length > 1 ){ | ||
| if(validPin === pwmPin.c1[0]){ | ||
| throw new Error('\nsetPWM() error: pin ' + validPin + ' is already in use.\n'); | ||
| } | ||
| } | ||
| if(pwmPin.c2.length > 1){ | ||
| if(validPin === pwmPin.c2[0]){ | ||
| throw new Error('\nsetPWM() error: pin ' + validPin + ' is already in use.\n'); | ||
| } | ||
| } | ||
| } | ||
| else{ | ||
| throw new Error('invalid setPulse() pin argument'); | ||
| } | ||
| *********/ | ||
| // classic api | ||
| // e.g let i2c = new r.I2C() | ||
| // i2c.begin() | ||
| I2C = i2c; | ||
| if(arguments[1] === 10 || arguments[1] === 100 || arguments[1] === 1000 ){ | ||
| var validFreq = freq; | ||
| } | ||
| else if(arguments[1] === undefined){ | ||
| var validFreq = 1; | ||
| } | ||
| else{ | ||
| throw new Error('invalid setPulse() freq argument'); | ||
| } | ||
| /* T or range */ | ||
| if(arguments[2] > 0 || arguments[2] < 1000000 ){ | ||
| var validT = T; | ||
| } | ||
| else if(arguments[2] === undefined){ | ||
| var validT = 0; | ||
| } | ||
| else{ | ||
| throw new Error('invalid setPulse() period T argument'); | ||
| } | ||
| /* pw or data */ | ||
| if(arguments[3] > 0 || arguments[3] < 1000000 ){ | ||
| var validPW = pw; | ||
| } | ||
| else if( arguments[3] === undefined){ | ||
| var validPW = 0; | ||
| } | ||
| else{ | ||
| throw new Error('invalid setPulse() pw argument'); | ||
| } | ||
| /* create pwm object using validated arguments */ | ||
| var pwm = new PWM(validPin, validFreq, validT, validPW); | ||
| /* track Freq from pwm.js */ | ||
| var Freq = require('./pwm.js').Freq; | ||
| /* PWM setup reference console output */ | ||
| if(Freq === 10){ | ||
| var res = '0.1 ms'; | ||
| } | ||
| else if(Freq === 100){ | ||
| var res = '0.01 ms'; | ||
| } | ||
| else if(Freq === 1000){ | ||
| var res = '0.001 ms'; | ||
| } | ||
| if(validFreq === 1){ | ||
| console.log('PWM setup: (pin ' + validPin + ')'); | ||
| } | ||
| else{ | ||
| /* Freq is global, not validFreq - one freq only for all */ | ||
| console.log('PWM setup: pin ' + validPin + ', Freq ' + Freq + ' KHz (' + res + '), T ' + validT + ', pw ' + validPW); | ||
| } | ||
| /* get the pwmObject from pwm.js */ | ||
| pwmObject = require('./pwm.js').pwmObject; | ||
| /* check for more than 1 peripheral and channel pairs */ | ||
| setImmediate(function(){ | ||
| pwmObjectTotal += 1; | ||
| if(pwmObject === pwmObjectTotal && pwmObject > 1){ | ||
| console.log("\nArray-gpio has detected you are using more than 1 PWM peripheral." | ||
| + "\nAll PWM peripherals are using 1 clock oscillator.\nClock frequency is set to " + Freq + " KHz for all.\n"); | ||
| } | ||
| /* pwm pin channel check */ | ||
| setImmediate(function(){ | ||
| /* channel 1 */ | ||
| if(pwmPin.c1.length > 1 && pwmObject > 1){ | ||
| if(pwmPin.c1[1] === validPin){ | ||
| console.log("Paired PWM peripherals (pin " + pwmPin.c1 + ") detected."); | ||
| console.log("Range and data will be same for both peripherals.\n"); | ||
| } | ||
| } | ||
| /* channel 2 */ | ||
| if(pwmPin.c2.length > 1 && pwmObject > 1){ | ||
| if(pwmPin.c2[1] === validPin){ | ||
| console.log("Paired PWM peripherals (pin " + pwmPin.c2 + ") detected."); | ||
| console.log("Range and data will be same for both peripherals.\n"); | ||
| } | ||
| } | ||
| }); | ||
| }); | ||
| return pwm; | ||
| // w/o new e.g let i2c = r.I2C(pin_select) | ||
| I2C(pin_select) { | ||
| return new i2c(pin_select); | ||
| } | ||
| PWM(pin, freq, T, pw){ | ||
| return this.setPWM(pin, freq, T, pw); | ||
| startI2C(pin_select) { | ||
| return new i2c(1); | ||
| } | ||
| startPWM(pin, freq, T, pw){ | ||
| return this.setPWM(pin, freq, T, pw); | ||
| createI2C(pinSet) { | ||
| return new I2C(1); | ||
| } | ||
| /******************************************** | ||
| /********* | ||
| I2C Methods | ||
| SPI | ||
| ********************************************/ | ||
| I2C(pin) { | ||
| return new I2C(pin); | ||
| } | ||
| *********/ | ||
| // classic api | ||
| // e.g let spi = new r.SPI() | ||
| // spi.begin() | ||
| SPI = spi; | ||
| setI2C(pin) { | ||
| return new I2C(pin); | ||
| } | ||
| startI2C(pinSet) { | ||
| return new I2C(pinSet); | ||
| } | ||
| /******************************************** | ||
| SPI Methods | ||
| ********************************************/ | ||
| // w/o new e.g let spi = r.I2C() | ||
| SPI() { | ||
| var spi = new SPI(); | ||
| return spi; | ||
| return new spi(); | ||
| } | ||
| setSPI() { | ||
| var spi = new SPI(); | ||
| return spi; | ||
| return new spi(); | ||
| } | ||
| startSPI() { | ||
| var spi = new SPI(); | ||
| return spi; | ||
| return new spi(1); | ||
| } | ||
| /******************************************** | ||
| Other Helper Methods | ||
| ********************************************/ | ||
| /* mswait (millisecond) method */ | ||
| mswait (ms) | ||
| { | ||
| rpi.mswait(ms); | ||
| createSPI() { | ||
| return new spi(1); | ||
| } | ||
| /* uswait (microsecond) method */ | ||
| uswait (us) | ||
| { | ||
| rpi.uswait(us); | ||
| } | ||
| pinout = rpi.pinout; | ||
| pinout(){ | ||
| console.log('** common pins for rpi zero, rpi3 and rpi4 **'); | ||
| console.log('(based on the physical pinout numbering from the board header)\n'); | ||
| console.log('5v', pwr5); | ||
| console.log('3.3v', pwr3); | ||
| console.log('ground', ground); | ||
| console.log('eeprom id',eprom); | ||
| console.log('uart', uart); | ||
| console.log('i2c', i2c); | ||
| console.log('spi', spi); | ||
| console.log('pwm', pwm); | ||
| console.log('gpio (ALT0)', gpio, '\n'); | ||
| } | ||
| } // end of ArrayGpio class | ||
| module.exports = new ArrayGpio(); | ||
| module.exports = new ArrayGpio; | ||
+130
-57
@@ -12,87 +12,160 @@ /*! | ||
| //var watchData = []; | ||
| const watchPinEvent = []; | ||
| /* | ||
| * Gpio input class module | ||
| */ | ||
| class GpioInput { | ||
| constructor(i, pin, o ){ | ||
| this._index = i; | ||
| this.pin = pin; | ||
| #pin = 0; | ||
| #index = 0; | ||
| if(o.intR === 'pu' || o.intR === 'pd' || o.intR === 1 || o.intR === 0){ | ||
| /* istanbul ignore next */ | ||
| this.intR(o.intR); | ||
| } | ||
| else{ | ||
| this.intR(null); | ||
| } | ||
| this.setR = this.intR; | ||
| #open(pin) { | ||
| rpi.gpio_open(pin, 0); | ||
| } | ||
| open () { | ||
| rpi.gpio_open(this.pin, 0); | ||
| constructor(pin, i, o){ | ||
| this.#pin = pin; | ||
| this.#index = i; | ||
| this.#open(pin); | ||
| if(o.pud === 0 || o.pud === 1 || o.pud === 'pd' || o.pud === 'pu'){ | ||
| this.setPud(o.pud); | ||
| } | ||
| } | ||
| close () { | ||
| rpi.gpio_close(this.pin); | ||
| close() { | ||
| rpi.gpio_close(this.#pin); | ||
| } | ||
| get pin(){ | ||
| return this.#pin; | ||
| } | ||
| get state(){ | ||
| let state = rpi.gpio_read(this.pin); | ||
| if(state === 1){ | ||
| return true; | ||
| } | ||
| else{ | ||
| return false; | ||
| } | ||
| let state = rpi.gpio_read(this.#pin); | ||
| if(state === 1){ | ||
| return true; | ||
| } | ||
| else if(state === 0){ | ||
| return false; | ||
| } | ||
| } | ||
| get isOn(){ | ||
| return this.state; | ||
| return this.state; | ||
| } | ||
| get isOff(){ | ||
| return !this.state; | ||
| return !this.state; | ||
| } | ||
| intR (x) { | ||
| if(x === null || x === undefined) { | ||
| return rpi.gpio_enable_pud(this.pin, 0); | ||
| } | ||
| else if(x === 'pu' || x == 1) { | ||
| return rpi.gpio_enable_pud(this.pin, 2); | ||
| } | ||
| else if(x === 'pd' || x === 0) { | ||
| return rpi.gpio_enable_pud(this.pin, 1); | ||
| } | ||
| read(cb){ | ||
| let s = rpi.gpio_read(this.#pin); | ||
| if(cb){ | ||
| return setImmediate(cb, s); | ||
| } | ||
| return s; | ||
| } | ||
| read(cb){ | ||
| let s = rpi.gpio_read(this.pin); | ||
| // rpi 4 only | ||
| getPud(){ | ||
| let pud = rpi.gpio_get_pud(this.#pin); | ||
| if(pud === 0){ // no pull resistor | ||
| return null; | ||
| } | ||
| else if(pud === 1){ // pull-up | ||
| return 1; | ||
| } | ||
| else if(pud === 2){ // pull-down | ||
| return 0; | ||
| } | ||
| else{ | ||
| return 'n/a'; // not available | ||
| } | ||
| } | ||
| if(arguments.length === 0){ | ||
| return s; | ||
| } | ||
| else if(arguments.length === 1 && typeof arguments[0] === 'function'){ | ||
| return setImmediate(cb, s); | ||
| } | ||
| else { | ||
| throw new Error('invalid callback argument'); | ||
| } | ||
| setPud(pud){ | ||
| if(pud === null || pud === undefined ) { | ||
| rpi.gpio_set_pud(this.#pin, 0); // no pull resistor | ||
| } | ||
| else if(pud === 0 || pud === 'pd') { | ||
| rpi.gpio_set_pud(this.#pin, 1); // pull-down | ||
| } | ||
| else if(pud == 1 || pud === 'pu') { | ||
| rpi.gpio_set_pud(this.#pin, 2); // pull-up | ||
| } | ||
| else{ | ||
| throw new Error('Invalid pull resistor select'); | ||
| } | ||
| } | ||
| watch(edge, cb, td){ | ||
| let pin = this.pin; | ||
| rpi.gpio_watchPin(edge, cb, pin, td); | ||
| watchPin(edge, cb, td){ | ||
| const pin = this.#pin; | ||
| let on = false; | ||
| if(typeof edge === 'function' && typeof cb === 'number'){ | ||
| td = cb; | ||
| cb = edge; | ||
| edge = null; | ||
| } | ||
| else if(typeof edge === 'function' && cb === undefined){ | ||
| cb = edge; | ||
| edge = null; | ||
| } | ||
| else if(typeof edge !== 'string' && typeof edge !== 'number' && edge !== null ){ | ||
| console.log('invalid input watch edge argument'); | ||
| process.exit(1); | ||
| } | ||
| else if ((typeof edge === 'string' || typeof edge === 'number') && typeof cb !== 'function'){ | ||
| console.log('invalid input watch callback argument'); | ||
| process.exit(1); | ||
| } | ||
| const watch_pin_state = () => { | ||
| let pin_state = rpi.gpio_read(pin); | ||
| if(pin_state && !on){ | ||
| on = true; | ||
| if(edge === 1 || edge === 're' || edge === 'both' || edge === null ){ | ||
| setImmediate(cb, true, pin); | ||
| } | ||
| } | ||
| else if(!pin_state && on){ | ||
| on = false; | ||
| if(edge === 0 || edge === 'fe' || edge == 'both' || edge === null){ | ||
| setImmediate(cb, false, pin); | ||
| } | ||
| } | ||
| } | ||
| if(!td){ | ||
| td = 100; | ||
| } | ||
| let monInt = setInterval(watch_pin_state, td); | ||
| watchPinEvent.push({monInt:monInt, pin:pin}); | ||
| } | ||
| unwatch(){ | ||
| let pin = this.pin; | ||
| rpi.gpio_unwatchPin(pin); | ||
| unwatchPin(){ | ||
| const pin = this.#pin; | ||
| watchPinEvent.forEach((monData, x) => { | ||
| if(monData.pin === pin){ | ||
| clearInterval(monData.monInt); | ||
| if(monData.monInt._destroyed){ | ||
| try{ | ||
| watchPinEvent.splice(x, 1); | ||
| } | ||
| catch(e){ | ||
| console.log('gpio_unwatch error:', e); | ||
| } | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| } // end of GpioInput class | ||
| setR = this.setPud; // for compatibility with old versions 4/25/25 | ||
| watch = this.watchPin; | ||
| unwatch = this.unwatchPin; | ||
| } | ||
| module.exports = GpioInput; | ||
@@ -99,0 +172,0 @@ |
+52
-90
@@ -12,29 +12,12 @@ /*! | ||
| /* OnOff helper function */ | ||
| function OnOff(pin, c, t, cb){ | ||
| let state; | ||
| if(c === 1 || c === true){ | ||
| rpi.gpio_write(pin, 1); // returns 1 | ||
| state = true; | ||
| if(t === 'w'){ | ||
| state = 1; | ||
| } | ||
| } | ||
| else{ // c === 0 || c === false | ||
| rpi.gpio_write(pin, 0); // returns 0 | ||
| state = false; | ||
| if(t === 'w'){ | ||
| state = 0; | ||
| } | ||
| } | ||
| function OnOff(pin, c, cb){ | ||
| if(cb){ | ||
| setImmediate(cb, state); | ||
| setImmediate(cb, c); | ||
| } | ||
| return state; | ||
| return rpi.gpio_write(pin, c); | ||
| } | ||
| /* pulse helper function */ | ||
| function startPulse(pin, c, t, cb){ | ||
| rpi.gpio_write(pin, 1); | ||
| setTimeout( function() { | ||
| setTimeout(() => { | ||
| rpi.gpio_write(pin, 0); | ||
@@ -47,65 +30,50 @@ if(cb){ | ||
| /* internal gpio control function */ | ||
| function OutputPinControl(pin, c, t, cb) { | ||
| // pulse | ||
| if(c === null && t){ | ||
| return startPulse(pin, c, t, cb); | ||
| } | ||
| // on/off control | ||
| else if(t){ | ||
| return setTimeout( function() { | ||
| OnOff(pin, c, t, cb); | ||
| return setTimeout(() => { | ||
| OnOff(pin, c, cb); | ||
| }, t); | ||
| } | ||
| else{ | ||
| return OnOff(pin, c, t, cb); | ||
| return OnOff(pin, c, cb); | ||
| } | ||
| } | ||
| /* | ||
| * Gpio output class module | ||
| */ | ||
| class GpioOutput { | ||
| constructor(i, pin, o ){ | ||
| this._index = i; | ||
| this.pin = pin; | ||
| this.stop = 0; | ||
| this.start = 0; | ||
| this.pulseRef = null; | ||
| this.pulseStarted = false; | ||
| #pin = 0; | ||
| #index = 0; | ||
| this.loopStop = 0; | ||
| this.loopStart = 0; | ||
| this.loopRef = null; | ||
| this.loopStarted = false; | ||
| this.delayOn = this.on; | ||
| this.delayOff = this.off; | ||
| //this.pulse = this.startPulse; | ||
| //this.loop = this.processLoop; | ||
| #open(pin){ | ||
| rpi.gpio_open(pin, 1); | ||
| } | ||
| open(){ | ||
| rpi.gpio_open(this.pin, 1); | ||
| return this.state; | ||
| constructor(pin, i, o ){ | ||
| this.#pin = pin; | ||
| this.#index = i; | ||
| this.#open(pin); | ||
| } | ||
| close(){ | ||
| rpi.gpio_close(this.pin); | ||
| rpi.gpio_close(this.#pin); | ||
| return this.state; | ||
| } | ||
| get pin(){ | ||
| return this.#pin; | ||
| } | ||
| get state(){ | ||
| let state = rpi.gpio_read(this.pin); | ||
| let state = rpi.gpio_read(this.#pin); | ||
| if(state === 1){ | ||
| return true; | ||
| return true; | ||
| } | ||
| else{ | ||
| return false; | ||
| } | ||
| else if(state === 0){ | ||
| return false; | ||
| } | ||
| } | ||
| get isOn(){ | ||
@@ -120,21 +88,16 @@ return this.state; | ||
| read(cb){ | ||
| let s = rpi.gpio_read(this.pin); | ||
| if(arguments.length === 0){ | ||
| return s; | ||
| } | ||
| else if(arguments.length === 1 && typeof arguments[0] === 'function'){ | ||
| let s = rpi.gpio_read(this.#pin); | ||
| if(cb){ | ||
| return setImmediate(cb, s); | ||
| } | ||
| else { | ||
| throw new Error('invalid callback argument'); | ||
| } | ||
| return s | ||
| } | ||
| write (bit, cb){ | ||
| write(bit, cb){ | ||
| if(arguments.length === 0){ | ||
| throw new Error('missing control bit argument'); | ||
| } | ||
| throw new Error('missing control bit argument'); | ||
| } | ||
| else if(arguments.length === 1){ | ||
| if((typeof arguments[0] === 'number' && arguments[0] < 2 ) || typeof arguments[0] === 'boolean'){ | ||
| return OutputPinControl(this.pin, bit, 'w', null); | ||
| return OutputPinControl(this.#pin, bit, null, null); | ||
| } | ||
@@ -145,3 +108,3 @@ throw new Error('invalid control bit argument'); | ||
| if((typeof arguments[0] === 'number' || typeof arguments[0] === 'boolean') && arguments[1] instanceof Function){ | ||
| return OutputPinControl(this.pin, bit, 'w', cb); | ||
| return OutputPinControl(this.#pin, bit, null, cb); | ||
| } | ||
@@ -154,10 +117,10 @@ throw new Error('invalid argument'); | ||
| if(arguments.length === 0){ | ||
| return OutputPinControl(this.pin, 1, 0, null); | ||
| return OutputPinControl(this.#pin, 1, 0, null); | ||
| } | ||
| else if(arguments.length === 1){ | ||
| if(typeof arguments[0] === 'number' || arguments[0] === undefined){ | ||
| return OutputPinControl(this.pin, 1, t, null); | ||
| return OutputPinControl(this.#pin, 1, t, null); | ||
| } | ||
| if(arguments[0] instanceof Function){ | ||
| return OutputPinControl(this.pin, 1, t, arguments[0]); | ||
| return OutputPinControl(this.#pin, 1, t, arguments[0]); | ||
| } | ||
@@ -168,3 +131,3 @@ throw new Error('invalid argument'); | ||
| if(typeof arguments[0] === 'number' && arguments[1] instanceof Function){ | ||
| return OutputPinControl(this.pin, 1, t, cb); | ||
| return OutputPinControl(this.#pin, 1, t, cb); | ||
| } | ||
@@ -183,10 +146,10 @@ if(typeof arguments[0] !== 'number' && arguments[1] instanceof Function){ | ||
| if(arguments.length === 0){ | ||
| return OutputPinControl(this.pin, 0, 0, null); | ||
| } | ||
| else if(arguments.length === 1){ | ||
| return OutputPinControl(this.#pin, 0, 0, null); | ||
| } | ||
| else if(arguments.length === 1){ | ||
| if(typeof arguments[0] === 'number' || arguments[0] === undefined){ | ||
| return OutputPinControl(this.pin, 0, t, null); | ||
| return OutputPinControl(this.#pin, 0, t, null); | ||
| } | ||
| if(arguments[0] instanceof Function){ | ||
| return OutputPinControl(this.pin, 0, t, arguments[0]); | ||
| return OutputPinControl(this.#pin, 0, t, arguments[0]); | ||
| } | ||
@@ -197,3 +160,3 @@ throw new Error('invalid argument'); | ||
| if(typeof arguments[0] === 'number' && arguments[1] instanceof Function){ | ||
| return OutputPinControl(this.pin, 0, t, cb); | ||
| return OutputPinControl(this.#pin, 0, t, cb); | ||
| } | ||
@@ -212,24 +175,24 @@ if(typeof arguments[0] !== 'number' && arguments[1] instanceof Function){ | ||
| pulse(t, cb){ | ||
| let pwError = 'invalid pulse width time duration'; | ||
| let error = 'pulse - invalid pulse width time duration'; | ||
| this.on(); | ||
| if(arguments.length === 0){ | ||
| throw new Error(pwError); | ||
| throw new Error(error); | ||
| } | ||
| else if(arguments.length === 1){ | ||
| if(typeof arguments[0] === 'number'){ | ||
| return OutputPinControl(this.pin, null, t, null); | ||
| return OutputPinControl(this.#pin, null, t, null); | ||
| } | ||
| throw new Error(pwError); | ||
| throw new Error(error); | ||
| } | ||
| else { | ||
| if(typeof arguments[0] === 'number' && arguments[1] instanceof Function){ | ||
| return OutputPinControl(this.pin, null, t, cb); | ||
| return OutputPinControl(this.#pin, null, t, cb); | ||
| } | ||
| if(typeof arguments[0] !== 'number' && arguments[1] instanceof Function){ | ||
| throw new Error(pwError); | ||
| throw new Error(error); | ||
| } | ||
| if(typeof arguments[0] === 'number' && !(arguments[1] instanceof Function)){ | ||
| throw new Error('invalid callback argument'); | ||
| throw new Error('pulse - invalid callback argument'); | ||
| } | ||
| throw new Error('invalid arguments'); | ||
| throw new Error('pulse - invalid arguments'); | ||
| } | ||
@@ -239,3 +202,2 @@ } | ||
| } | ||
| // end of class GpioOutput | ||
@@ -242,0 +204,0 @@ module.exports = GpioOutput; |
+62
-59
@@ -12,64 +12,61 @@ /*! | ||
| var test = false; | ||
| // 0 - SDA0 (GPIO 00/pin 27) and SCL0 (GPIO 01/pin 28) (disabled) | ||
| // 1 - BSC1_BASE, using SDA1 (GPIO 02/pin 03) and SCL1 (GPIO 03/pin 05) (default) | ||
| /* | ||
| * i2c class | ||
| */ | ||
| class I2C { | ||
| /*constructor (){ | ||
| this.begin(); | ||
| }*/ | ||
| constructor (pinSet){ | ||
| /*if(!pinSet){ | ||
| this.startI2C(1); | ||
| }*/ | ||
| if(pinSet === undefined){ | ||
| this.startI2C(1); | ||
| #init = 0; | ||
| #start(ps){ | ||
| this.#init = 1; | ||
| if(ps === undefined){ | ||
| rpi.i2c_start(1); | ||
| } | ||
| else{ | ||
| this.startI2C(pinSet); | ||
| else if(ps === 0 || ps === 1){ | ||
| rpi.i2c_start(ps); | ||
| } | ||
| else{ | ||
| throw new Error('Invalid i2c pin select ' + ps); | ||
| } | ||
| } | ||
| begin(){ | ||
| return rpi.i2cBegin(); | ||
| constructor(ps){ | ||
| if(ps == undefined){ | ||
| // start manually using begin | ||
| this.#init = 0; | ||
| } | ||
| else{ | ||
| this.#init = 1; | ||
| this.#start(ps) | ||
| } | ||
| } | ||
| startI2C(pinSet){ | ||
| return rpi.i2cInit(pinSet); | ||
| } | ||
| test(){ | ||
| test = true; | ||
| begin(){ | ||
| this.#init = 1; | ||
| rpi.i2c_start(1); | ||
| } | ||
| setBaudRate(baud) { | ||
| if(test){ | ||
| return; | ||
| } | ||
| rpi.i2cSetBaudRate(baud); | ||
| var Baud = baud/1000; | ||
| console.log('I2C data rate: ' + Baud + ' kHz'); | ||
| if(this.#init){ | ||
| rpi.i2c_set_baud_rate(baud); | ||
| let Baud = baud/1000; | ||
| console.log('I2C data rate: ' + Baud + ' kHz'); | ||
| } | ||
| } | ||
| setTransferSpeed(baud) { | ||
| if(test){ | ||
| return; | ||
| } | ||
| rpi.i2cSetBaudRate(baud); | ||
| var Baud = baud/1000; | ||
| console.log('I2C data rate: ' + Baud + ' kHz'); | ||
| if(this.#init){ | ||
| rpi.i2c_set_baud_rate(baud); | ||
| let Baud = baud/1000; | ||
| console.log('I2C data rate: ' + Baud + ' kHz'); | ||
| } | ||
| } | ||
| setClockFreq(div) { | ||
| var freq = Math.round(250000000/div); | ||
| var Freq = Math.round(freq/1000); | ||
| console.log('I2C data rate: ' + Freq + ' kHz (div ' + div +')'); | ||
| if(test){ | ||
| return; | ||
| } | ||
| rpi.i2cSetClockDivider(div); | ||
| if(this.#init){ | ||
| let freq = Math.round(250000000/div); | ||
| let Freq = Math.round(freq/1000); | ||
| console.log('I2C data rate: ' + Freq + ' kHz (div ' + div +')'); | ||
| rpi.i2c_set_clock_divider(div); | ||
| } | ||
| } | ||
@@ -79,6 +76,5 @@ | ||
| setSlaveAddress(value){ | ||
| if(test){ | ||
| return; | ||
| } | ||
| return rpi.i2cSetSlaveAddress(value); | ||
| if(this.#init){ | ||
| return rpi.i2c_set_slave_address(value); | ||
| } | ||
| } | ||
@@ -88,6 +84,5 @@ | ||
| selectSlave(value){ | ||
| if(test){ | ||
| return; | ||
| if(this.#init){ | ||
| return rpi.i2c_set_slave_address(value); | ||
| } | ||
| return rpi.i2cSetSlaveAddress(value); | ||
| } | ||
@@ -97,6 +92,5 @@ | ||
| read(buf, len){ | ||
| if(test){ | ||
| return; | ||
| if(this.#init){ | ||
| rpi.i2c_read(buf, len); | ||
| } | ||
| rpi.i2cRead(buf, len); | ||
| } | ||
@@ -106,14 +100,23 @@ | ||
| write(buf, len){ | ||
| if(test){ | ||
| return; | ||
| if(this.#init){ | ||
| rpi.i2c_write(buf, len); | ||
| } | ||
| rpi.i2cWrite(buf, len); | ||
| } | ||
| end(){ | ||
| rpi.i2cEnd(); | ||
| if(this.#init){ | ||
| rpi.i2c_stop(); | ||
| this.#init = 0; | ||
| } | ||
| } | ||
| } // end of I2C class | ||
| stop(){ | ||
| if(this.#init){ | ||
| rpi.i2c_stop(); | ||
| this.#init = 0; | ||
| } | ||
| } | ||
| } | ||
| module.exports = I2C; |
+193
-84
@@ -12,55 +12,171 @@ /*! | ||
| var Freq = 1, pwmObject = 0; | ||
| var pwm_instance = 0; | ||
| var pwmPin = {c1:[], c2:[]}; | ||
| var freqF = 1, validT = 0, validPW = 0, validPin = 0, validFreqF = 0; | ||
| class PWM { | ||
| constructor(pin, freq, T, pw){ | ||
| /* track pwm object */ | ||
| pwmObject += 1; | ||
| exports.pwmObject = pwmObject; | ||
| #T = 0; | ||
| #pw = 0; | ||
| #pin = 0; | ||
| #pwmStarted = false; | ||
| #pinOnlySetup = false; | ||
| this._T = T; | ||
| this._pw = pw; | ||
| this._pin = pin; | ||
| this._freq = freq; | ||
| this._pinOnlySetup = false; | ||
| #validate_pwm_params(pin, freq, T, pw){ | ||
| ++pwm_instance; | ||
| if(pin === 33 || pin === 35 || pin === 12 || pin === 32){ | ||
| validPin = pin; | ||
| if(validPin === 12 || validPin === 32){ | ||
| pwmPin.c1.push(validPin); | ||
| } | ||
| else{ | ||
| pwmPin.c2.push(validPin); | ||
| } | ||
| // check duplicate pins | ||
| if(pwmPin.c1.length > 1 ){ | ||
| if(validPin === pwmPin.c1[0]){ | ||
| throw new Error('\nsetPWM() error: pin ' + validPin + ' is already in use.\n'); | ||
| } | ||
| } | ||
| if(pwmPin.c2.length > 1){ | ||
| if(validPin === pwmPin.c2[0]){ | ||
| throw new Error('\nsetPWM() error: pin ' + validPin + ' is already in use.\n'); | ||
| } | ||
| } | ||
| } | ||
| else{ | ||
| throw new Error('invalid pwm pin'); | ||
| } | ||
| // Get frequecy factor (freq) | ||
| if(freq === undefined){ | ||
| validFreqF = 1; | ||
| } | ||
| else if(freq === 10 || freq === 100 || freq === 1000 ){ | ||
| validFreqF = freq; | ||
| } | ||
| else{ | ||
| throw new Error('invalid pwm freq'); | ||
| } | ||
| // T or range | ||
| if(T === undefined){ | ||
| validT = 0; | ||
| } | ||
| else if(T > 0 || T < 1000000 ){ | ||
| validT = T; | ||
| } | ||
| else{ | ||
| throw new Error('invalid pwm period T'); | ||
| } | ||
| // pw or data | ||
| if(pw === undefined){ | ||
| validPW = 0; | ||
| } | ||
| else if(pw > 0 || pw < 1000000 ){ | ||
| validPW = pw; | ||
| } | ||
| else{ | ||
| throw new Error('invalid pwm data'); | ||
| } | ||
| this.#T = validT; | ||
| this.#pw = validPW; | ||
| this.#pin = validPin; | ||
| if(freq === 1){ | ||
| this._pinOnlySetup = true; | ||
| this.#pinOnlySetup = true; | ||
| } | ||
| /* | ||
| * initilize PWM | ||
| * servo control will use only mark/space (M/S) mode | ||
| */ | ||
| rpi.pwmInit(); | ||
| /* Initilize PWM. Servo control will use only mark/space (M/S) mode. */ | ||
| this.pwm_init(); | ||
| this.enable(false); | ||
| this._pwmStarted = false; | ||
| this.#pwmStarted = false; | ||
| let div = null, res = null; | ||
| if( freq !== 1 && T !== 0 && pw !== 0){ | ||
| if( pwmObject === 1){ | ||
| /* 10kHz -> 0.1 ms */ | ||
| if(freq === 10){ | ||
| Freq = 10; | ||
| this.setClockFreq(1920); | ||
| } | ||
| /* 100KHz -> 0.01 ms */ | ||
| else if(freq === 100){ | ||
| Freq = 100; | ||
| this.setClockFreq(192); | ||
| } | ||
| /* 100KHz -> 0.001 ms */ | ||
| else if(freq === 1000){ | ||
| Freq = 1000; | ||
| this.setClockFreq(19); | ||
| } | ||
| // e.g. var pwm = r.startPWM(pin, freq, T, pw); | ||
| if(validFreqF > 1 && validT > 0 && validPW > 0){ | ||
| // 10kHz -> 0.1 ms | ||
| if(freq === 10){ | ||
| freqF = 10; | ||
| div = 1920 | ||
| this.setClockFreq(div); | ||
| } | ||
| this.setRange(this._T); | ||
| this.setData(this._pw); | ||
| // 100KHz -> 0.01 ms | ||
| else if(freq === 100){ | ||
| freqF = 100; | ||
| div = 192 | ||
| this.setClockFreq(div); | ||
| } | ||
| // 100KHz -> 0.001 ms | ||
| else if(freq === 1000){ | ||
| freqF = 1000; | ||
| div = 19 | ||
| this.setClockFreq(div); | ||
| } | ||
| let freqC = (Math.round(19200000/div))/1000; | ||
| if(freqF === 10){ | ||
| res = '0.1 ms'; | ||
| } | ||
| else if(freqF === 100){ | ||
| res = '0.01 ms'; | ||
| } | ||
| else if(freqF === 1000){ | ||
| res = '0.001 ms'; | ||
| } | ||
| /* freqF is freq factor and not validFreqF, pwm is using one freq for all pins */ | ||
| console.log('PWM config: pin ' + validPin + ', freq ' + freqC + ' KHz (' + res + '), T ' + validT + ', pw ' + validPW); | ||
| this.setRange(this.#T); | ||
| this.setData(this.#pw); | ||
| } | ||
| else if(validFreqF === 1){ // e.g var pwm = r.startPWM(12); | ||
| console.log('PWM config: (pin ' + validPin + ')'); | ||
| this.#pinOnlySetup = true; | ||
| // Note: setClockFreq(), setRange() and setData() must be set manually | ||
| } | ||
| /* Check for more than 1 peripheral used and channel pairs */ | ||
| if(pwm_instance > 1){ | ||
| console.log("\nArray-gpio has detected you are using more than 1 PWM peripheral." | ||
| + "\nClock frequency is set to " + freqF + " KHz for all.\n"); | ||
| } | ||
| /* channel 1 */ | ||
| if(pwmPin.c1.length > 1 && pwm_instance > 1){ | ||
| if(pwmPin.c1[1] === validPin){ | ||
| console.log("Paired PWM peripherals (pin " + pwmPin.c1 + ") detected."); | ||
| console.log("Range and data will be same for both peripherals.\n"); | ||
| } | ||
| } | ||
| /* channel 2 */ | ||
| if(pwmPin.c2.length > 1 && pwm_instance > 1){ | ||
| if(pwmPin.c2[1] === validPin){ | ||
| console.log("Paired PWM peripherals (pin " + pwmPin.c2 + ") detected."); | ||
| console.log("Range and data will be same for both peripherals.\n"); | ||
| } | ||
| } | ||
| } | ||
| constructor(pin, freq, T, pw){ | ||
| this.#validate_pwm_params(pin, freq, T, pw); | ||
| } | ||
| pwm_init(){ | ||
| rpi.pwm_init(); | ||
| } | ||
| /* initialize PWM object */ | ||
| enable (start){ | ||
| rpi.pwmSetup(this._pin, start); | ||
| rpi.pwm_setup(this.#pin, start); | ||
| } | ||
@@ -71,46 +187,37 @@ | ||
| if(div > 0 && div < 4095 ){ | ||
| rpi.pwmSetClockDivider(div); | ||
| var freq = Math.round(19200000/div); | ||
| Freq = freq/1000; | ||
| if(pwmObject === 1){ | ||
| setImmediate(function(){ | ||
| console.log('Frequency calculation (div ' + div +'): ' + Freq + ' KHz'); | ||
| }); | ||
| rpi.pwm_set_clock_divider(div); | ||
| let freqC = (Math.round(19200000/div))/1000; // calculated freq | ||
| if(pwm_instance === 1){ | ||
| console.log('Frequency calculated using (div ' + div +'): ' + freqC + ' KHz'); | ||
| } | ||
| exports.Freq = Freq; | ||
| } | ||
| else{ | ||
| throw new Error('setClock() error: invalid div value'); | ||
| throw new Error('setClockFreq error: invalid div value ' + div); | ||
| } | ||
| } | ||
| /* | ||
| * set period T or space value from m/s mode | ||
| */ | ||
| /* set period T or space value from m/s mode */ | ||
| setRange (range){ | ||
| // console.log('this. _pin ' + this._pin + ' this._T ' + this._T + ' range ' + range + ' this._pw ' + this._pw ); | ||
| this._T = range; | ||
| rpi.pwmSetRange(this._pin, range); | ||
| this.#T = range; | ||
| rpi.pwm_set_range(this.#pin, range); | ||
| } | ||
| /* | ||
| * set pw(pulse width) over period T or mark value over space | ||
| */ | ||
| /* set pw(pulse width) over period T or mark value over space */ | ||
| setData (data){ | ||
| this._pw = data; | ||
| this.#pw = data; | ||
| this.enable(true); | ||
| /* validate pw vs range */ | ||
| if(Freq === 10 || Freq === 100 || Freq === 1000 || Freq === 1){ | ||
| if(this._T === 0 ){ | ||
| console.log('Alert! pin ' + this._pin + ' period T or range is zero.'); | ||
| if(freqF === 1 || freqF === 10 || freqF === 100 || freqF === 1000){ | ||
| if(this.#T === 0 ){ | ||
| console.log('WARNING! pwm pin', this.#pin, 'period T or range is', 0); | ||
| console.log('Please set a range first using the setRange(range) method'); | ||
| } | ||
| if(data > 0 && data <= this._T){ | ||
| rpi.pwmSetData(this._pin, data); | ||
| else if(data > 0 && data <= this.#T){ | ||
| rpi.pwm_set_data(this.#pin, data); | ||
| } | ||
| if(data > this._T){ | ||
| console.log('Alert! pin ' + this._pin + ', pw ' + data + ' is higher than the period T ' + this._T ); | ||
| rpi.pwmSetData(this._pin, data); | ||
| else if(data > this.#T){ | ||
| console.log('WARNING! pwm pin', this.#pin, ' pw ' + data + ' is higher than the period T', this.#T ); | ||
| rpi.pwm_set_data(this.#pin, data); | ||
| } | ||
@@ -121,6 +228,6 @@ } | ||
| start (){ | ||
| if(this._pw === 1){ | ||
| this._pw = this._T; | ||
| if(this.#pw === 1){ | ||
| this.#pw = this.#T; | ||
| } | ||
| rpi.pwmSetData(this._pin, this._pw); | ||
| rpi.pwm_set_data(this.#pin, this.#pw); | ||
| } | ||
@@ -130,15 +237,17 @@ | ||
| this.enable(false); | ||
| this._pwmStarted = false; | ||
| this.#pwmStarted = false; | ||
| } | ||
| pulse (pw){ | ||
| if(!this._pwmStarted){ | ||
| if(!this.#pwmStarted){ | ||
| this.enable(true); | ||
| } | ||
| this._pwmStarted = true; | ||
| this.#pwmStarted = true; | ||
| if(pw === undefined){ | ||
| this.setData(this._pw); | ||
| this.setData(this.#pw); | ||
| } | ||
| else { | ||
| rpi.pwmSetData(this._pin, pw); | ||
| rpi.pwm_set_data(this.#pin, pw); | ||
| } | ||
@@ -149,19 +258,19 @@ } | ||
| this.enable(false); | ||
| this._pwmStarted = false; | ||
| this.#pwmStarted = false; | ||
| } | ||
| close (){ | ||
| this._pwmStarted = false; | ||
| this.#pwmStarted = false; | ||
| /* reset to 19.2MHz */ | ||
| //rpi.pwmSetClockDivider(1); | ||
| rpi.pwmSetup(this._pin, false); | ||
| rpi.pwmSetRange(this._pin, 0); | ||
| rpi.pwmSetData(this._pin, 0); | ||
| rpi.pwmReset(); | ||
| //rpi.pwmResetPin(this._pin); | ||
| //rpi.pwm_set_clock_divider(1); | ||
| rpi.pwm_setup(this.#pin, false); | ||
| rpi.pwm_set_range(this.#pin, 0); | ||
| rpi.pwm_set_data(this.#pin, 0); | ||
| rpi.pwm_reset(); | ||
| //rpi.pwm_reset_pin(this.#pin); | ||
| } | ||
| } // end of PWM class | ||
| } | ||
| module.exports = PWM; | ||
+338
-383
@@ -10,124 +10,149 @@ /*! | ||
| const fs = require('fs'); | ||
| const os = require('os'); | ||
| const fs = require('node:fs'); | ||
| const { arch } = require('node:process'); | ||
| const cc = require('bindings')('node_rpi'); | ||
| const EventEmitter = require('events'); | ||
| class StateEmitter extends EventEmitter {} | ||
| const emitter = exports.emitter = new StateEmitter(); | ||
| emitter.setMaxListeners(2); | ||
| var rpi_board_rev = null, rpi_model = null, eventStarted = null, BcmPin = []; | ||
| var rpiInit = { initialized:false, gpio:false, pwm:false , i2c:false , spi:false, gpiomem:false, devmem:false }; | ||
| var match; | ||
| var BoardRev; | ||
| var BcmPin = {}; | ||
| var inputPin = []; | ||
| var outputPin = []; | ||
| var watchData = []; | ||
| var eventStarted = null; | ||
| var rpiSetup = { initialized:false, gpiomem:false, initI2c:false , initSpi:false }; | ||
| /* | ||
| * Verify if the board is a Raspberry Pi | ||
| */ | ||
| if(os.arch() === 'arm' || os.arch() === 'arm64'){ | ||
| //continue | ||
| if(arch === 'arm' || arch === 'arm64'){ | ||
| // continue | ||
| } | ||
| else{ | ||
| console.log('Sorry, array-gpio has detected that your device is not a Raspberry Pi.\narray-gpio will only work in Raspberry Pi devices.\n'); | ||
| throw new Error('device is not a raspberry pi'); | ||
| throw new Error('Device is not a raspberry pi'); | ||
| } | ||
| /* | ||
| * Check rpi board revision. | ||
| */ | ||
| /*fs.readFile('/proc/cpuinfo', function (err, info) { | ||
| if (err) throw err; | ||
| if (!info){ | ||
| return false; | ||
| function get_rpi_model(){ | ||
| let model = null, match = null; | ||
| try{ | ||
| let info = fs.readFileSync('/proc/cpuinfo'); | ||
| info.toString().split(/\n/).forEach((line) => { | ||
| model = line.match(/^Model.*(.{4})/); | ||
| if(model){ | ||
| //rpi_model = model[0].slice(8, 30); // e.g. Raspberry Pi 4 Model | ||
| rpi_model = model[0].slice(18, 24).trim(); // e.g. Pi 4 | ||
| } | ||
| match = line.match(/^Revision.*(.{4})/); | ||
| if(match) { | ||
| rpi_board_rev = parseInt(match[1], 16); | ||
| } | ||
| }); | ||
| } | ||
| info.toString().split(/\n/).forEach(function (line) { | ||
| match = line.match(/^Revision.*(.{4})/); | ||
| if (match) { | ||
| return BoardRev = parseInt(match[1], 16); | ||
| } | ||
| }); | ||
| //console.log('BoardRev', BoardRev.toString(16)); | ||
| switch (BoardRev) { | ||
| case 0x10: | ||
| case 0x12: | ||
| case 0x13: | ||
| case 0x14: | ||
| case 0x15: | ||
| case 0x32: | ||
| case 0x92: | ||
| case 0x93: | ||
| case 0xc1: | ||
| case 0x1041: | ||
| case 0x2042: | ||
| case 0x2082: | ||
| case 0x20d3: | ||
| case 0x20a0: | ||
| case 0x20e0: | ||
| break; | ||
| default: | ||
| console.log('\nSorry, your raspberry pi model is not currently supported at this time.\n'); | ||
| throw new Error('unsupported rpi board'); | ||
| return false; | ||
| catch(e){ | ||
| console.log("fs.readFileSync('/proc/cpuinfo')", e.message); | ||
| } | ||
| return true; | ||
| });*/ | ||
| } | ||
| get_rpi_model(); | ||
| /* | ||
| * This module only supports 40-pin Raspberry Pi Models. | ||
| * 40-pin Physical Board Pinout Mapping with BCM GPIOxx Pin Numbering. | ||
| * | ||
| * Note: This module only supports 40-pin Raspberry Pi Models. | ||
| * Below is the BCM GPIOxx pin numbering to the physical board header (40-pins) pinout map. | ||
| * -1 indicates a power supply or a ground pin. | ||
| */ | ||
| var pinLayout = [ | ||
| const rpi_pin_map = [ | ||
| // BCM GPIOxx Physical Board Header (*ground or power supply) | ||
| -1, | ||
| -1, -1, /* P1 P2 */ | ||
| 2, -1, /* P3 P4 */ | ||
| 3, -1, /* P5 P6 */ | ||
| 4, 14, /* P7 P8 */ | ||
| -1, 15, /* P9 P10 */ | ||
| 17, 18, /* P11 P12 */ | ||
| 27, -1, /* P13 P14 */ | ||
| 22, 23, /* P15 P16 */ | ||
| -1, 24, /* P17 P18 */ | ||
| 10, -1, /* P19 P20 */ | ||
| 9, 25, /* P21 P22 */ | ||
| 11, 8, /* P23 P24 */ | ||
| -1, 7, /* P25 P26 */ | ||
| 0, 1, /* P27 P28 */ | ||
| 5, -1, /* P29 P30 */ | ||
| 6, 12, /* P31 P32 */ | ||
| 13, -1, /* P33 P34 */ | ||
| 19, 16, /* P35 P36 */ | ||
| 26, 20, /* P37 P38 */ | ||
| -1, 21 /* P39 P40 */ | ||
| -1, -1, // *1 *2 | ||
| 2, -1, // 3 *4 | ||
| 3, -1, // 5 *6 | ||
| 4, 14, // 7 8 | ||
| -1, 15, // *9 10 | ||
| 17, 18, // 11 12 | ||
| 27, -1, // 13 *14 | ||
| 22, 23, // 15 16 | ||
| -1, 24, // *17 18 | ||
| 10, -1, // 19 *20 | ||
| 9, 25, // 21 22 | ||
| 11, 8, // 23 24 | ||
| -1, 7, // *25 26 | ||
| 0, 1, // 27 28 | ||
| 5, -1, // 29 *30 | ||
| 6, 12, // 31 32 | ||
| 13, -1, // 33 *34 | ||
| 19, 16, // 35 36 | ||
| 26, 20, // 37 38 | ||
| -1, 21 // *39 40 | ||
| ] | ||
| /* Convert physical board pinout number to BCM pin numbering */ | ||
| function convertPin(pin) | ||
| // gound pins | ||
| const gnd = [6, 9, 14, 20, 25, 30, 34, 39]; | ||
| // 3.3 V pins | ||
| const p3 = [1, 17]; | ||
| // 5.0 V pins | ||
| const p5 = [2, 4]; | ||
| function checkInvalidPin(pin){ | ||
| if(gnd.includes(pin)) { | ||
| throw new Error('*Ground header pin ' + pin + '\n'); | ||
| } | ||
| if(p3.includes(pin)) { | ||
| throw new Error('*3.3 power supply header pin ' + pin + '\n'); | ||
| } | ||
| if(p5.includes(pin)) { | ||
| throw new Error('*5 power supply header pin ' + pin + '\n'); | ||
| } | ||
| if(pin === 0 || pin < 0 || pin > 40){ | ||
| throw new Error('*Out-of-range (1 ~ 40 only) header pin ' + pin + '\n'); | ||
| } | ||
| } | ||
| /* Convert board header pin number to BCM (Broadcom) pin number */ | ||
| function header_to_bcm(pin) | ||
| { | ||
| if (BcmPin[pin]) { | ||
| return BcmPin[pin]; | ||
| } | ||
| if (pinLayout[pin] === -1 || pinLayout[pin] === null){ | ||
| throw new Error(pin, 'is invalid!'); | ||
| } | ||
| BcmPin[pin] = pinLayout[pin]; | ||
| return BcmPin[pin]; | ||
| try{ | ||
| if(BcmPin[pin]) { | ||
| return BcmPin[pin]; | ||
| } | ||
| checkInvalidPin(pin); | ||
| if (rpi_pin_map[pin] === -1){ | ||
| throw new Error('Power supply or gound header pin ' + pin + '\n'); | ||
| } | ||
| BcmPin[pin] = rpi_pin_map[pin]; | ||
| return BcmPin[pin]; | ||
| } | ||
| catch(e){ | ||
| console.log('Invalid pin', pin); | ||
| console.log(e.message); | ||
| process.exit(1); | ||
| } | ||
| } | ||
| function validate_pins(pin){ | ||
| let currentPin = null; | ||
| try{ | ||
| if(pin[0] === undefined){ | ||
| currentPin = pin[0]; | ||
| throw new Error('*Cannot set input/output gpio w/o pecified pins\n'); | ||
| } | ||
| if(typeof pin[0] === 'object'){ | ||
| currentPin = pin[0]; | ||
| if(!pin[0].pin || pin[0].pin[0] == undefined){ | ||
| throw new Error('*createGpio - pin property is empty!\n') | ||
| } | ||
| pin = pin[0].pin; | ||
| } | ||
| pin.forEach((_pin, x) => { | ||
| currentPin = _pin; | ||
| checkInvalidPin(_pin); | ||
| }); | ||
| } | ||
| catch(e){ | ||
| console.log('\nInvalid pin', currentPin); | ||
| console.log(e.message); | ||
| process.exit(1); | ||
| } | ||
| } | ||
| /* Check if the pin is being used by another application using '/sys/class/gpio/gpio' */ | ||
| function check_sys_gpio(gpioPin, pin) | ||
| function check_sys_gpio(bcm_pin, pin) | ||
| { | ||
| fs.stat('/sys/class/gpio/gpio' + gpioPin, (err, stats) => { | ||
| fs.stat('/sys/class/gpio/gpio' + bcm_pin, (err, stats) => { | ||
| if(err) { | ||
| if(err.code === 'ENOENT'){ | ||
| // '/sys/class/gpio/gpio' + gpioPin file does not exist | ||
| // '/sys/class/gpio/gpio' + bcm_pin file does not exist | ||
| return; | ||
@@ -146,7 +171,19 @@ } | ||
| /* error message for rpi mode conflict */ | ||
| function rpiModeConflict(){ | ||
| console.log('\n** Peripheral access conflict.'); | ||
| console.log('** I2C, SPI and PWM object creation takes precedence over GPIO object creation.'); | ||
| console.log('** Try creating I2C/SPI/PWM objects before creating GPIO input/output objects.\n'); | ||
| function pinout(){ | ||
| console.log('Common Board Header Physical Pinout Numbers'); | ||
| let uart = {txd:8, rxd:10}; | ||
| let i2c = {sda1:3, scl1:5, sda0:27, scl0:28}; | ||
| let pwm = {pwm0:[12,32], pwm1:[33,35]}; | ||
| let spi = {mosi:19, miso:21, sclk:23, cs0:24, cs1:26}; | ||
| let eprom = {sda:27, scl:28}; | ||
| let gpio = [3,5,7,8,10,11,12,13,15,16,18,19,21,22,23,24,26,27,28,29,31,32,33,35,36,37,38,40]; | ||
| console.log('3.3v', p3); | ||
| console.log('5v', p5); | ||
| console.log('ground', gnd); | ||
| console.log('eeprom id',eprom); | ||
| console.log('uart', uart); | ||
| console.log('i2c', i2c); | ||
| console.log('spi', spi); | ||
| console.log('pwm', pwm); | ||
| console.log('gpio (ALT0)', gpio, '\n'); | ||
| } | ||
@@ -159,6 +196,13 @@ | ||
| * Incorrect use of this functions may cause hang-up/file corruptions | ||
| * | ||
| * Note: gpio is using 'dev/gpiomem' and i2c, spi, pwm is using 'dev/mem' | ||
| * 1 - Start gpio only, then load all other peripherals together (i2c, spi, pwm) on demand | ||
| * 0 - Start gpio first, then load each peripheral individually on demand (default) | ||
| */ | ||
| var clock1 = 250000000; | ||
| var clock2 = 400000000; | ||
| class Rpi { | ||
| constructor (){ | ||
| constructor (init){ | ||
| this.LOW = 0x0; | ||
@@ -177,23 +221,19 @@ this.HIGH = 0x1; | ||
| this.BOTH = 0x3; | ||
| if(init === 1){ | ||
| this.rpi_init_access = 1; | ||
| } | ||
| else if(init == 0){ | ||
| this.rpi_init_access = 0; | ||
| } | ||
| } | ||
| /* | ||
| * rpi lib access methods | ||
| */ | ||
| lib_init (access) | ||
| /* Explicit initialization of rpi lib */ | ||
| rpi_init (access) | ||
| { | ||
| /* reset pin store */ | ||
| BcmPin = {}; | ||
| cc.rpi_init(access); | ||
| if(access === 0){ | ||
| rpiSetup.gpiomem = true; // rpi in dev/gpiomem for GPIO | ||
| } | ||
| else{ | ||
| rpiSetup.gpiomem = false; // rpi in dev/mem for i2c, spi, pwm | ||
| } | ||
| rpiSetup.initialized = true; // rpi must be initialized only once | ||
| cc.rpi_init(access); | ||
| this.rpi_init_access = 1; | ||
| } | ||
| lib_close () | ||
| rpi_close () | ||
| { | ||
@@ -208,50 +248,45 @@ return cc.rpi_close(); | ||
| { | ||
| var gpioPin = convertPin(pin); | ||
| if (!rpiSetup.initialized) { | ||
| this.lib_init(0); | ||
| } | ||
| //console.log('open', pin) | ||
| let bcm_pin = header_to_bcm(pin); | ||
| check_sys_gpio(gpioPin, pin); | ||
| check_sys_gpio(bcm_pin, pin); | ||
| /* pin initial state */ | ||
| cc.gpio_config(gpioPin, this.INPUT); | ||
| cc.gpio_enable_pud(gpioPin, this.PULL_OFF); | ||
| /* set as INPUT */ | ||
| if(this.rpi_init_access){ | ||
| if(!rpiInit.gpiomem){ | ||
| rpiInit.gpiomem = true; | ||
| cc.rpi_init(0); | ||
| } | ||
| } | ||
| else{ | ||
| if(!rpiInit.gpio){ | ||
| rpiInit.gpio = true; | ||
| cc.gpio_init(); | ||
| } | ||
| } | ||
| if(mode === this.INPUT){ | ||
| var result = cc.gpio_config(gpioPin, this.INPUT); | ||
| let result = cc.gpio_config(bcm_pin, this.INPUT); | ||
| if(init){ | ||
| cc.gpio_enable_pud(gpioPin, init); | ||
| cc.gpio_set_pud(bcm_pin, this.PULL_OFF); | ||
| if(init){ | ||
| cc.gpio_set_pud(bcm_pin, init); | ||
| } | ||
| else{ | ||
| cc.gpio_enable_pud(gpioPin, this.PULL_OFF); /* initial PUD setup, none */ | ||
| } | ||
| // track all input pins | ||
| inputPin.push(pin); | ||
| // remove duplicates | ||
| inputPin = inputPin.filter(function(c, index){return inputPin.indexOf(c) === index}); | ||
| return result; | ||
| } | ||
| /* set as OUTPUT */ | ||
| else if(mode === this.OUTPUT){ | ||
| var result = cc.gpio_config(gpioPin, this.OUTPUT); | ||
| let result = cc.gpio_config(bcm_pin, this.OUTPUT); | ||
| cc.gpio_write(bcm_pin, this.LOW); | ||
| if (init){ | ||
| cc.gpio_write(gpioPin, init); | ||
| cc.gpio_write(bcm_pin, init); | ||
| } | ||
| else{ | ||
| cc.gpio_write(gpioPin, this.LOW); /* initial state is OFF */ | ||
| } | ||
| // track all output pins | ||
| outputPin.push(pin); | ||
| // remove duplicates | ||
| outputPin = outputPin.filter(function(c, index){return outputPin.indexOf(c) === index}); | ||
| return result; | ||
| } | ||
| else { | ||
| throw new Error('Unsupported mode ' + mode); | ||
| console.log('Unsupported GPIO mode:', mode); | ||
| process.exit(1); | ||
| } | ||
@@ -262,19 +297,9 @@ } | ||
| { | ||
| var gpioPin = convertPin(pin); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| cc.gpio_config(bcm_pin, this.INPUT); | ||
| cc.gpio_set_pud(bcm_pin, this.PULL_OFF); | ||
| } | ||
| if (!rpiSetup.gpiomem){ | ||
| cc.gpio_enable_pud(gpioPin, this.PULL_OFF); | ||
| } | ||
| /* reset pin to input */ | ||
| cc.gpio_config(gpioPin, this.INPUT); | ||
| cc.gpio_enable_pud(gpioPin, this.PULL_OFF); | ||
| inputPin = inputPin.filter(function(item) { | ||
| return item !== pin; | ||
| }); | ||
| outputPin = outputPin.filter(function(item) { | ||
| return item !== pin; | ||
| }); | ||
| gpio_get_bcm(){ | ||
| return BcmPin; | ||
| } | ||
@@ -284,3 +309,4 @@ | ||
| { | ||
| cc.gpio_enable_async_rising_event(convertPin(pin), 1); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| cc.gpio_enable_async_rising_event(bcm_pin, 1); | ||
| } | ||
@@ -290,3 +316,4 @@ | ||
| { | ||
| return cc.gpio_detect_input_event(convertPin(pin)); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| return cc.gpio_detect_input_event(bcm_pin); | ||
| } | ||
@@ -296,3 +323,4 @@ | ||
| { | ||
| cc.gpio_reset_all_events(convertPin(pin)); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| cc.gpio_reset_all_events(bcm_pin); | ||
| } | ||
@@ -302,3 +330,4 @@ | ||
| { | ||
| cc.gpio_reset_event(convertPin(pin)); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| cc.gpio_reset_event(bcm_pin); | ||
| } | ||
@@ -308,3 +337,4 @@ | ||
| { | ||
| return cc.gpio_write(convertPin(pin), value); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| return cc.gpio_write(bcm_pin, value); | ||
| } | ||
@@ -314,128 +344,45 @@ | ||
| { | ||
| return cc.gpio_read(convertPin(pin)); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| return cc.gpio_read(bcm_pin); | ||
| } | ||
| gpio_enable_pud (pin, value) | ||
| gpio_set_pud (pin, pud) | ||
| { | ||
| return cc.gpio_enable_pud(convertPin(pin), value); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| cc.gpio_set_pud(bcm_pin, pud); | ||
| } | ||
| gpio_watchPin(edge, cb, pin, td){ | ||
| /* check pin if valid */ | ||
| if(cb){ | ||
| try{ | ||
| this.gpio_read(pin); | ||
| } | ||
| catch(e){ | ||
| throw new Error('invalid pin'); | ||
| } | ||
| } | ||
| let on = false; | ||
| if(typeof edge === 'function' && typeof cb === 'number'){ | ||
| td = cb; | ||
| cb = edge; | ||
| edge = null; | ||
| } | ||
| else if(typeof edge === 'function' && cb === undefined){ | ||
| cb = edge; | ||
| edge = null; | ||
| } | ||
| else if(typeof edge !== 'string' && typeof edge !== 'number' && edge !== null ){ | ||
| throw new Error('invalid edge argument'); | ||
| } | ||
| else if ((typeof edge === 'string' || typeof edge === 'number') && typeof cb !== 'function'){ | ||
| throw new Error('invalid callback argument'); | ||
| } | ||
| /* set internal pull-down resistor */ | ||
| // conflict with pull-up resistor from Paulo Castro 1/14/2022 | ||
| // need to validate with new RPI boards as well as with new RPI OS's | ||
| //cc.gpio_enable_pud(convertPin(pin), this.PULL_DOWN); | ||
| if(!td){ | ||
| td = 100; | ||
| } | ||
| function logic () { | ||
| if(cc.gpio_read(convertPin(pin)) && !on){ | ||
| on = true; | ||
| if(edge === 1 || edge === 're' || edge === 'both' || edge === null ){ | ||
| setImmediate(cb, true, pin); | ||
| } | ||
| } | ||
| else if(!cc.gpio_read(convertPin(pin)) && on){ | ||
| on = false; | ||
| if(edge === 0 || edge === 'fe' || edge == 'both' || edge === null){ | ||
| setImmediate(cb, false, pin); | ||
| } | ||
| } | ||
| } | ||
| /*cc.gpio_reset_all_events(convertPin(pin)); | ||
| cc.gpio_enable_async_rising_event(convertPin(pin), 1); | ||
| function logic () { | ||
| if(cc.gpio_detect_input_event(convertPin(pin)) && !on){ | ||
| on = true; | ||
| if(edge === 1 || edge === 're' || edge === 'both' || edge === null ){ | ||
| setImmediate(cb, true, pin); | ||
| } | ||
| cc.gpio_reset_event(convertPin(pin)) | ||
| } | ||
| else if(!cc.gpio_detect_input_event(convertPin(pin)) && on){ | ||
| on = false; | ||
| if(edge === 0 || edge === 'fe' || edge == 'both' || edge === null){ | ||
| setImmediate(cb, false, pin); | ||
| } | ||
| cc.gpio_reset_event(convertPin(pin)) | ||
| } | ||
| }*/ | ||
| let monitor = setInterval(logic, td); | ||
| let monData = {monitor:monitor, pin:pin}; | ||
| watchData.push(monData); | ||
| gpio_get_pud (pin) | ||
| { | ||
| let bcm_pin = header_to_bcm(pin); | ||
| return cc.gpio_get_pud(bcm_pin); | ||
| } | ||
| gpio_unwatchPin(pin){ | ||
| watchData.forEach((monData, index) => { | ||
| if(monData.pin === pin){ | ||
| clearInterval(monData.monitor); | ||
| watchData.splice(index,1); | ||
| } | ||
| }); | ||
| } | ||
| /* | ||
| * PWM | ||
| */ | ||
| pwmInit () | ||
| pwm_init() | ||
| { | ||
| /* check if GPIO is already using the rpi library in gpiomem */ | ||
| if (rpiSetup.initialized && rpiSetup.gpiomem){ | ||
| rpiModeConflict(); | ||
| rpiSetup.gpiomem = false; | ||
| this.pwmReset(); | ||
| throw new Error('pwm peripheral access conflict'); | ||
| } | ||
| /* PWM peripheral requires /dev/mem */ | ||
| if (!rpiSetup.initialized) { | ||
| this.lib_init(1); | ||
| if(this.rpi_init_access){ | ||
| if(!rpiInit.devmem){ | ||
| rpiInit.devmem = true; | ||
| cc.rpi_init(1); | ||
| } | ||
| } | ||
| else{ | ||
| if(!rpiInit.pwm){ | ||
| rpiInit.gpio = true; | ||
| rpiInit.pwm = true; | ||
| cc.pwm_init(); | ||
| } | ||
| } | ||
| } | ||
| pwmResetPin (pin) | ||
| pwm_reset_pin (pin) | ||
| { | ||
| var gpioPin = convertPin(pin); | ||
| var v = outputPin.indexOf(gpioPin); | ||
| if(v === -1){ | ||
| cc.pwm_reset_pin(gpioPin); | ||
| this.gpio_close(gpioPin); | ||
| } | ||
| let bcm_pin = header_to_bcm(pin); | ||
| cc.pwm_reset_pin(bcm_pin); | ||
| } | ||
| pwmReset () | ||
| pwm_reset () | ||
| { | ||
@@ -446,3 +393,3 @@ cc.pwm_reset_all_pins(); | ||
| /* | ||
| * available pins for PWM - RPi 3 / RPi 4 | ||
| * Available pins for PWM - RPi 3 / RPi 4 | ||
| * PHY pin BCM GPIO pin | ||
@@ -454,7 +401,7 @@ * 12 18 | ||
| */ | ||
| pwmSetup (pin, start, mode) | ||
| pwm_setup (pin, start, mode) | ||
| { | ||
| var gpioPin = convertPin(pin); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| check_sys_gpio(gpioPin); | ||
| check_sys_gpio(bcm_pin); | ||
@@ -469,9 +416,10 @@ /* true - enable pwm, false - disable */ | ||
| } | ||
| //console.log('pin', pin, 'start', Number(start), 'mode', Number(mode)); | ||
| cc.pwm_set_pin(gpioPin); | ||
| cc.pwm_set_mode(gpioPin, Number(mode)); | ||
| cc.pwm_enable(gpioPin, Number(start)); | ||
| cc.pwm_set_pin(bcm_pin); | ||
| cc.pwm_set_mode(bcm_pin, Number(mode)); | ||
| cc.pwm_enable(bcm_pin, Number(start)); | ||
| } | ||
| pwmSetClockDivider (divider) | ||
| pwm_set_clock_divider (divider) | ||
| { | ||
@@ -481,10 +429,12 @@ return cc.pwm_set_clock_freq(divider); | ||
| pwmSetRange (pin, range) | ||
| pwm_set_range (pin, range) | ||
| { | ||
| return cc.pwm_set_range(convertPin(pin), range); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| return cc.pwm_set_range(bcm_pin, range); | ||
| } | ||
| pwmSetData (pin, data) | ||
| pwm_set_data (pin, data) | ||
| { | ||
| return cc.pwm_set_data(convertPin(pin), data); | ||
| let bcm_pin = header_to_bcm(pin); | ||
| return cc.pwm_set_data(bcm_pin, data); | ||
| } | ||
@@ -494,34 +444,20 @@ | ||
| * I2C | ||
| * | ||
| * pinSet 0, use SDA0 and SCL0 pins (disabled) | ||
| * pinSet 1, use SDA1 and SCL1 pins (default) | ||
| */ | ||
| i2cBegin () | ||
| i2c_start(pinSet) | ||
| { | ||
| if(rpiSetup.initialized && rpiSetup.gpiomem){ | ||
| rpiModeConflict(); | ||
| rpiSetup.gpiomem = false; | ||
| throw new Error('i2c peripheral access conflict'); | ||
| } | ||
| /* I2C requires /dev/mem */ | ||
| if (!rpiSetup.initialized){ | ||
| this.lib_init(1); | ||
| rpiSetup.initI2c = true; | ||
| return cc.i2c_start(); | ||
| } | ||
| } | ||
| i2cInit (pinSet) | ||
| { | ||
| if(rpiSetup.initialized && rpiSetup.gpiomem){ | ||
| rpiModeConflict(); | ||
| rpiSetup.gpiomem = false; | ||
| throw new Error('i2c peripheral access conflict'); | ||
| } | ||
| /* I2C requires /dev/mem */ | ||
| if (!rpiSetup.initialized){ | ||
| rpiSetup.initI2c = true; | ||
| rpiSetup.initialized = true; | ||
| if(pinSet === 0){ | ||
| return cc.i2c_init(0); // use SDA0 and SCL0 pins | ||
| if(this.rpi_init_access){ | ||
| if(!rpiInit.devmem){ | ||
| rpiInit.devmem = true; | ||
| cc.rpi_init(1); | ||
| cc.spi_start(); | ||
| } | ||
| else if(pinSet === 1){ | ||
| return cc.i2c_init(1); // use SDA1 and SCL1 pins | ||
| } | ||
| else{ | ||
| if (!rpiInit.i2c){ | ||
| rpiInit.gpio = true; | ||
| rpiInit.i2c = true; | ||
| cc.i2c_start(pinSet); | ||
| } | ||
@@ -531,3 +467,3 @@ } | ||
| i2cSetSlaveAddress (addr) | ||
| i2c_set_slave_address (addr) | ||
| { | ||
@@ -537,3 +473,3 @@ return cc.i2c_select_slave(addr); | ||
| i2cSetClockDivider (divider) | ||
| i2c_set_clock_divider (divider) | ||
| { | ||
@@ -543,3 +479,3 @@ cc.i2c_set_clock_freq(divider); | ||
| i2cSetBaudRate (baud) | ||
| i2c_set_baud_rate (baud) | ||
| { | ||
@@ -549,11 +485,16 @@ return cc.i2c_data_transfer_speed(baud); | ||
| i2cRead (buf, len) | ||
| i2c_read (buf, len) | ||
| { | ||
| if (len === undefined){ | ||
| len = buf.length; | ||
| try{ | ||
| if (len === undefined){ | ||
| len = buf.length; | ||
| } | ||
| if (len > buf.length){ | ||
| throw new Error('Insufficient buffer size'); | ||
| } | ||
| return cc.i2c_read(buf, len); | ||
| } | ||
| catch(e){ | ||
| console.log(e); | ||
| } | ||
| if (len > buf.length){ | ||
| throw new Error('Insufficient buffer size'); | ||
| } | ||
| return cc.i2c_read(buf, len); | ||
| } | ||
@@ -566,14 +507,19 @@ | ||
| i2cWrite (buf, len) | ||
| i2c_write (buf, len) | ||
| { | ||
| if (len === undefined){ | ||
| len = buf.length; | ||
| try{ | ||
| if (len === undefined){ | ||
| len = buf.length; | ||
| } | ||
| if (len > buf.length){ | ||
| throw new Error('Insufficient buffer size'); | ||
| } | ||
| return cc.i2c_write(buf, len); | ||
| } | ||
| if (len > buf.length){ | ||
| throw new Error('Insufficient buffer size'); | ||
| catch(e){ | ||
| console.log(e); | ||
| } | ||
| return cc.i2c_write(buf, len); | ||
| } | ||
| i2cEnd () | ||
| i2c_stop () | ||
| { | ||
@@ -586,25 +532,26 @@ cc.i2c_stop(); | ||
| */ | ||
| spiGetBoardRev () | ||
| spi_get_board_rev () | ||
| { | ||
| return BoardRev; | ||
| return { model:rpi_model, rev:rpi_board_rev.toString(16) }; | ||
| } | ||
| spiBegin () | ||
| spi_start() | ||
| { | ||
| if (rpiSetup.initialized && rpiSetup.gpiomem){ | ||
| rpiModeConflict(); | ||
| rpiSetup.gpiomem = false; | ||
| throw new Error('spi peripheral access conflict'); | ||
| if(this.rpi_init_access){ | ||
| if(!rpiInit.devmem){ | ||
| rpiInit.devmem = true; | ||
| cc.rpi_init(1); | ||
| cc.spi_start(); | ||
| } | ||
| } | ||
| /* SPI requires /dev/mem */ | ||
| if (!rpiSetup.initialized) { | ||
| this.lib_init(1); | ||
| rpiSetup.initSpi = true; | ||
| return cc.spi_start(); | ||
| else{ | ||
| if (!rpiInit.spi){ | ||
| rpiInit.gpio = true; | ||
| rpiInit.spi = true; | ||
| cc.spi_start(); | ||
| } | ||
| } | ||
| } | ||
| spiChipSelect (cs) | ||
| spi_chip_select (cs) | ||
| { | ||
@@ -614,3 +561,3 @@ cc.spi_chip_select(cs); | ||
| spiSetCSPolarity (cs, active) | ||
| spi_set_cs_polarity (cs, active) | ||
| { | ||
@@ -620,11 +567,29 @@ cc.spi_set_chip_select_polarity(cs, active); | ||
| spiSetClockDivider (divider) | ||
| spi_set_clock_freq (div) | ||
| { | ||
| if ((divider % 2) !== 0 || divider < 0 || divider > 65536){ | ||
| throw new Error('Clock divider must be an even number between 0 and 65536'); | ||
| let freq = null; | ||
| try{ | ||
| if ((div % 2) !== 0 || div < 0 || div > 65536){ | ||
| throw new Error('Clock divider must be an even number between 0 and 65536'); | ||
| } | ||
| if( rpi_model === 'Pi 3' || rpi_model === 'Pi 4'){ | ||
| freq = Math.round(clock2/div); | ||
| } | ||
| else{ | ||
| freq = Math.round(clock1/div); | ||
| } | ||
| let Freq = freq/1000; | ||
| console.log('SPI clock freq: ' + Freq + ' kHz (div ' + div +')'); | ||
| cc.spi_set_clock_freq(div); | ||
| } | ||
| cc.spi_set_clock_freq(divider); | ||
| catch(e){ | ||
| console.log(e); | ||
| } | ||
| } | ||
| spiSetDataMode (mode) | ||
| spi_set_data_mode (mode) | ||
| { | ||
@@ -634,3 +599,3 @@ cc.spi_set_data_mode(mode); | ||
| spiTransfer (wbuf, rbuf, len) | ||
| spi_data_transfer (wbuf, rbuf, len) | ||
| { | ||
@@ -640,3 +605,3 @@ cc.spi_data_transfer(wbuf, rbuf, len); | ||
| spiWrite (wbuf, len) | ||
| spi_write (wbuf, len) | ||
| { | ||
@@ -646,3 +611,3 @@ cc.spi_write(wbuf, len); | ||
| spiRead (rbuf, len) | ||
| spi_read (rbuf, len) | ||
| { | ||
@@ -652,3 +617,3 @@ cc.spi_read(rbuf, len); | ||
| spiEnd () | ||
| spi_end () | ||
| { | ||
@@ -658,21 +623,11 @@ cc.spi_stop(); | ||
| /* | ||
| * time delay methods | ||
| */ | ||
| // delay in milliseconds | ||
| mswait (ms) | ||
| { | ||
| cc.mswait(ms); | ||
| validatePins = validate_pins; | ||
| pinout = pinout; | ||
| } | ||
| // delay in microseconds | ||
| uswait (us) | ||
| { | ||
| cc.uswait(us); | ||
| } | ||
| }// end of Rpi class | ||
| module.exports = new Rpi(0); | ||
| module.exports = new Rpi(); | ||
| process.on('exit', function (code) { | ||
| process.on('exit', (code) => { | ||
| cc.rpi_close(); | ||
@@ -679,0 +634,0 @@ }); |
+42
-63
@@ -12,77 +12,55 @@ /*! | ||
| /* | ||
| * spi class | ||
| */ | ||
| class SPI { | ||
| var test = false; | ||
| #init = 0; | ||
| class SPI { | ||
| #start(){ | ||
| this.#init = 1; | ||
| rpi.spi_start(); | ||
| } | ||
| constructor (){ | ||
| this.begin(); | ||
| constructor(s){ | ||
| if(s === 1){ | ||
| this.#init = 1; | ||
| this.#start(); | ||
| } | ||
| else{ | ||
| this.#init = 0; | ||
| } | ||
| } | ||
| /* returns 1 if successful, otherwise returns 0*/ | ||
| begin(){ | ||
| return rpi.spiBegin(); | ||
| this.#init = 1; | ||
| rpi.spi_start(); | ||
| } | ||
| test(){ | ||
| test = true; | ||
| } | ||
| setDataMode (mode) { | ||
| rpi.spiSetDataMode(mode); | ||
| if(this.#init){ | ||
| rpi.spi_set_data_mode(mode); | ||
| } | ||
| } | ||
| /* 250MHz on RPi1 and RPi2, and 400MHz on RPi3 */ | ||
| setClockFreq(div) { | ||
| var clock1 = 250000000; | ||
| var clock3 = 400000000; | ||
| var boardRev = rpi.spiGetBoardRev(); | ||
| if( boardRev === 8322){ | ||
| var freq = Math.round(clock3/div); | ||
| }else{ | ||
| var freq = Math.round(clock1/div); | ||
| if(this.#init){ | ||
| rpi.spi_set_clock_freq(div); | ||
| } | ||
| var Freq = freq/1000; | ||
| console.log('SPI clock freq: ' + Freq + ' kHz (div ' + div +')'); | ||
| rpi.spiSetClockDivider(div); | ||
| } | ||
| /* 250MHz on RPi1 and RPi2, and 400MHz on RPi3 */ | ||
| setClock(div) { | ||
| var clock1 = 250000000; | ||
| var clock3 = 400000000; | ||
| var boardRev = rpi.spiGetBoardRev(); | ||
| if( boardRev === 8322){ | ||
| var freq = Math.round(clock3/div); | ||
| } | ||
| else{ | ||
| var freq = Math.round(clock1/div); | ||
| } | ||
| var Freq = freq/1000; | ||
| console.log('SPI clock freq: ' + Freq + ' kHz (div ' + div +')'); | ||
| rpi.spiSetClockDivider(div); | ||
| } | ||
| setCSPolarity(cs, active){ | ||
| rpi.spiSetCSPolarity(cs, active); | ||
| if(this.#init){ | ||
| rpi.spi_set_cs_polarity(cs, active); | ||
| } | ||
| } | ||
| chipSelect(cs){ | ||
| rpi.spiChipSelect(cs); | ||
| if(this.#init){ | ||
| rpi.spi_chip_select(cs); | ||
| } | ||
| } | ||
| /* transfer data bytes to/from periphetal registers using node buffer objects */ | ||
| transfer (wbuf, rbuf, len){ | ||
| if(test){ | ||
| return; | ||
| } | ||
| rpi.spiTransfer(wbuf, rbuf, len); | ||
| dataTransfer (wbuf, rbuf, len){ | ||
| if(this.#init){ | ||
| rpi.spi_data_transfer(wbuf, rbuf, len); | ||
| } | ||
| } | ||
@@ -92,6 +70,5 @@ | ||
| write(wbuf, len){ | ||
| if(test){ | ||
| return; | ||
| } | ||
| rpi.spiWrite(wbuf, len); | ||
| if(this.#init){ | ||
| rpi.spi_write(wbuf, len); | ||
| } | ||
| } | ||
@@ -101,14 +78,16 @@ | ||
| read(rbuf, len){ | ||
| if(test){ | ||
| return; | ||
| } | ||
| rpi.spiRead(rbuf, len); | ||
| if(this.#init){ | ||
| rpi.spi_read(rbuf, len); | ||
| } | ||
| } | ||
| end(){ | ||
| rpi.spiEnd(); | ||
| if(this.#init){ | ||
| rpi.spi_end(); | ||
| this.#init = 0; | ||
| } | ||
| } | ||
| } // end of SPI class | ||
| } | ||
| module.exports = SPI; |
+1
-1
| { | ||
| "name": "array-gpio", | ||
| "version": "1.7.3", | ||
| "version": "1.7.4", | ||
| "description": "array-gpio is low-level javascript library for Raspberry Pi using direct register access.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
+36
-30
@@ -8,9 +8,5 @@ /** | ||
| #include <nan.h> | ||
| #include <unistd.h> | ||
| #include <errno.h> | ||
| #include "rpi.h" | ||
| #define LIBNAME node_bcm | ||
| #define BCM_EVENT_LOW 0x1 | ||
| #define BCM_EVENT_HIGH 0x2 | ||
@@ -34,3 +30,3 @@ using namespace Nan; | ||
| /* | ||
| * rpi closing | ||
| * rpi close | ||
| */ | ||
@@ -47,3 +43,3 @@ NAN_METHOD(rpi_close) | ||
| /* | ||
| * time delays | ||
| * Timers | ||
| */ | ||
@@ -86,2 +82,8 @@ NAN_METHOD(nswait) | ||
| */ | ||
| NAN_METHOD(gpio_init) | ||
| { | ||
| gpio_init(); | ||
| } | ||
| NAN_METHOD(gpio_config) | ||
@@ -201,3 +203,3 @@ { | ||
| NAN_METHOD(gpio_enable_pud) | ||
| NAN_METHOD(gpio_set_pud) | ||
| { | ||
@@ -211,8 +213,27 @@ if((info.Length() != 2) || (!info[0]->IsNumber()) || (!info[1]->IsNumber())){ | ||
| gpio_enable_pud(arg1, arg2); | ||
| gpio_set_pud(arg1, arg2); | ||
| } | ||
| NAN_METHOD(gpio_get_pud) | ||
| { | ||
| uint8_t ret; | ||
| if((info.Length() != 1) || (!info[0]->IsNumber())){ | ||
| return ThrowTypeError("Incorrect arguments"); | ||
| } | ||
| uint8_t arg1 = info[0]->IntegerValue(Nan::GetCurrentContext()).ToChecked(); | ||
| ret = gpio_get_pud(arg1); | ||
| info.GetReturnValue().Set(ret); | ||
| } | ||
| /* | ||
| * PWM | ||
| */ | ||
| NAN_METHOD(pwm_init) | ||
| { | ||
| pwm_init(); | ||
| } | ||
| NAN_METHOD(pwm_set_pin) | ||
@@ -334,13 +355,2 @@ { | ||
| { | ||
| uint8_t rval; | ||
| rval = i2c_start(); | ||
| info.GetReturnValue().Set(rval); | ||
| } | ||
| NAN_METHOD(i2c_init) | ||
| { | ||
| uint8_t rval; | ||
| if((info.Length() != 1) || (!info[0]->IsNumber() )){ | ||
@@ -352,5 +362,3 @@ return ThrowTypeError("Incorrect argument"); | ||
| rval = i2c_init(arg); | ||
| info.GetReturnValue().Set(rval); | ||
| i2c_start(arg); | ||
| } | ||
@@ -397,3 +405,3 @@ | ||
| { | ||
| uint8_t rval; | ||
| uint8_t rval; | ||
@@ -442,7 +450,3 @@ if((info.Length() != 2) || (!info[0]->IsObject()) || (!info[1]->IsNumber())){ | ||
| { | ||
| uint8_t rval; | ||
| rval = spi_start(); | ||
| info.GetReturnValue().Set(rval); | ||
| spi_start(); | ||
| } | ||
@@ -547,2 +551,3 @@ | ||
| /* gpio */ | ||
| NAN_EXPORT(target, gpio_init); | ||
| NAN_EXPORT(target, gpio_config); | ||
@@ -557,5 +562,7 @@ NAN_EXPORT(target, gpio_input); | ||
| NAN_EXPORT(target, gpio_write); | ||
| NAN_EXPORT(target, gpio_enable_pud); | ||
| NAN_EXPORT(target, gpio_set_pud); | ||
| NAN_EXPORT(target, gpio_get_pud); | ||
| /* pwm */ | ||
| NAN_EXPORT(target, pwm_init); | ||
| NAN_EXPORT(target, pwm_set_pin); | ||
@@ -574,3 +581,2 @@ NAN_EXPORT(target, pwm_reset_pin); | ||
| NAN_EXPORT(target, i2c_start); | ||
| NAN_EXPORT(target, i2c_init); | ||
| NAN_EXPORT(target, i2c_stop); | ||
@@ -577,0 +583,0 @@ NAN_EXPORT(target, i2c_select_slave); |
+605
-526
@@ -21,3 +21,2 @@ /** | ||
| #include <time.h> | ||
| //#include <bcm_host.h> | ||
@@ -30,25 +29,18 @@ #include "rpi.h" | ||
| //#define debug 0 | ||
| /* Peripherals base addresses for different Rpi models */ | ||
| #define PERI_BASE_RPI1 0x20000000 // Rpi 1 | ||
| #define PERI_BASE_RPI23 0x3F000000 // Rpi 2 & 3 | ||
| #define PERI_BASE_RPI4 0xFE000000 // Rpi 4 | ||
| #define PERI_BASE_1 0x20000000 // Rpi 1 & Rpi Zero/Rpi Zero W | ||
| #define PERI_BASE_2 0x3F000000 // Rpi 2 & 3 | ||
| #define PERI_BASE_3 0xFE000000 // Rpi 4 | ||
| /* Common core clock frequency for all RPI models */ | ||
| #define CORE_CLK_FREQ 250000000 // 250 MHz | ||
| //#define CORE_CLK_FREQ 250000000 // 250 MHz | ||
| /* Dynamic CORE_CLOCK_FREQ for different models | ||
| * that can affect UART, SPI and I2C performance | ||
| */ | ||
| #define CORE_CLOCK_FREQ_RPI1 250000000 // 250 MHz | ||
| #define CORE_CLOCK_FREQ_RPI23 400000000 // 400 MHz | ||
| #define CORE_CLOCK_FREQ_RPI4 400000000 // 400 MHz | ||
| /* Base address of each peripheral registers | ||
| * with a dynamic peri_base offset value | ||
| */ | ||
| /* Base address of each peripheral registers based on the Rpi model */ | ||
| #define ST_BASE (peri_base + 0x003000) // 0x7E003000 | ||
| #define GPIO_PADS (peri_base + 0x100000) // 0x7E100000 unused | ||
| #define GPIO_PADS (peri_base + 0x100000) // 0x7E100000 unused | ||
| #define CLK_BASE (peri_base + 0x101000) // 0x7E101000 | ||
| #define GPIO_BASE (peri_base + 0x200000) // 0x7E200000 | ||
| #define SPI0_BASE (peri_base + 0x204000) // 0x7E204000 SPI0 | ||
| #define SPI0_BASE (peri_base + 0x204000) // 0x7E204000 SPI0 | ||
| #define BSC0_BASE (peri_base + 0x205000) // 0x7E205000 BSC0 // GPIO 00 & 01/pin 27 & 28 | ||
@@ -64,14 +56,12 @@ #define PWM_BASE (peri_base + 0x20C000) // 0x7E20C000 PWM0 | ||
| /* Size of base_add[] and *base_pointer[] arrays */ | ||
| #define BASE_INDEX 6 // from the current total of 11 base addresses | ||
| /* System timer registers */ | ||
| #define ST_PERI_BASE base_pointer[0] // ST_BASE | ||
| /* System timer registers */ | ||
| #define ST_PERI_ BASE base_pointer[0] // ST_BASE | ||
| #define ST_CS (ST_PERI_BASE + 0x00/4) | ||
| #define ST_CS (ST_PERI_BASE + 0x00/4) | ||
| #define ST_CLO (ST_PERI_BASE + 0x04/4) | ||
| #define ST_CHI_CLO (ST_PERI_BASE + 0x08/4) | ||
| #define ST_C0 (ST_PERI_BASE + 0x0C/4) | ||
| #define ST_C1 (ST_PERI_BASE + 0x10/4) | ||
| #define ST_C2 (ST_PERI_BASE + 0x14/4) | ||
| #define ST_C3 (ST_PERI_BASE + 0x18/4) | ||
| #define ST_C0 (ST_PERI_BASE + 0x0C/4) | ||
| #define ST_C1 (ST_PERI_BASE + 0x10/4) | ||
| #define ST_C2 (ST_PERI_BASE + 0x14/4) | ||
| #define ST_C3 (ST_PERI_BASE + 0x18/4) | ||
@@ -90,8 +80,8 @@ /* PWM control manager clocks control registers | ||
| #define GPIO_PERI_BASE base_pointer[2] // GPIO_BASE | ||
| #define GPIO_GPFSEL0 (GPIO_PERI_BASE + 0x00/4) | ||
| #define GPIO_GPFSEL1 (GPIO_PERI_BASE + 0x04/4) | ||
| #define GPIO_GPFSEL2 (GPIO_PERI_BASE + 0x08/4) | ||
| #define GPIO_GPFSEL3 (GPIO_PERI_BASE + 0x0C/4) | ||
| #define GPIO_GPFSEL4 (GPIO_PERI_BASE + 0x10/4) | ||
| #define GPIO_GPFSEL5 (GPIO_PERI_BASE + 0x14/4) | ||
| #define GPIO_GPFSEL0 (GPIO_PERI_BASE + 0x00/4) | ||
| #define GPIO_GPFSEL1 (GPIO_PERI_BASE + 0x04/4) | ||
| #define GPIO_GPFSEL2 (GPIO_PERI_BASE + 0x08/4) | ||
| #define GPIO_GPFSEL3 (GPIO_PERI_BASE + 0x0C/4) | ||
| #define GPIO_GPFSEL4 (GPIO_PERI_BASE + 0x10/4) | ||
| #define GPIO_GPFSEL5 (GPIO_PERI_BASE + 0x14/4) | ||
| #define GPIO_GPSET0 (GPIO_PERI_BASE + 0x1C/4) | ||
@@ -112,21 +102,18 @@ #define GPIO_GPSET1 (GPIO_PERI_BASE + 0x20/4) | ||
| #define GPIO_GPLEN0 (GPIO_PERI_BASE + 0x70/4) | ||
| #define GPIO_GPAREN0 (GPIO_PERI_BASE + 0x7C/4) | ||
| #define GPIO_GPAREN1 (GPIO_PERI_BASE + 0x80/4) | ||
| #define GPIO_GPAFEN0 (GPIO_PERI_BASE + 0x88/4) | ||
| #define GPIO_GPAFEN1 (GPIO_PERI_BASE + 0x8C/4) | ||
| #define GPIO_GPAREN0 (GPIO_PERI_BASE + 0x7C/4) | ||
| #define GPIO_GPAREN1 (GPIO_PERI_BASE + 0x80/4) | ||
| #define GPIO_GPAFEN0 (GPIO_PERI_BASE + 0x88/4) | ||
| #define GPIO_GPAFEN1 (GPIO_PERI_BASE + 0x8C/4) | ||
| #define GPIO_GPPUD (GPIO_PERI_BASE + 0x94/4) | ||
| #define GPIO_GPPUDCLK0 (GPIO_PERI_BASE + 0x98/4) | ||
| #define GPIO_GPPUDCLK1 (GPIO_PERI_BASE + 0x9C/4) | ||
| #define GPIO_GPPUDCLK1 (GPIO_PERI_BASE + 0x9C/4) | ||
| /* SPI registers */ | ||
| #define SPI_PERI_BASE base_pointer[3] // SPI0_BASE | ||
| #define SPI_CS (SPI_PERI_BASE + 0x00/4) | ||
| #define SPI_FIFO (SPI_PERI_BASE + 0x04/4) | ||
| #define SPI_CLK (SPI_PERI_BASE + 0x08/4) | ||
| #define SPI_DLEN (SPI_PERI_BASE + 0x0C/4) | ||
| #define SPI_LTOH (SPI_PERI_BASE + 0x10/4) | ||
| #define SPI_DC (SPI_PERI_BASE + 0x14/4) | ||
| /* BCM2711 (rpi4) gpio pull-up/down registers */ | ||
| #define GPIO_GPPUPPDN0 (GPIO_PERI_BASE + 0xe4/4) // for pins 0 ~ 15 | ||
| #define GPIO_GPPUPPDN1 (GPIO_PERI_BASE + 0xe8/4) // for pins 16 ~ 31 | ||
| #define GPIO_GPPUPPDN2 (GPIO_PERI_BASE + 0xec/4) // for pins 32 ~ 47 | ||
| #define GPIO_GPPUPPDN3 (GPIO_PERI_BASE + 0xf0/4) // for pins 48 ~ 57 | ||
| /* PWM control and status registers */ | ||
| #define PWM_PERI_BASE base_pointer[4] // PWM_BASE | ||
| #define PWM_PERI_BASE base_pointer[3] // from 4 PWM_BASE | ||
| #define PWM_CTL (PWM_PERI_BASE + 0x00/4) | ||
@@ -140,12 +127,21 @@ #define PWM_STA (PWM_PERI_BASE + 0x04/4) | ||
| /* SPI registers */ | ||
| #define SPI_PERI_BASE base_pointer[4] // from 3 SPI0_BASE | ||
| #define SPI_CS (SPI_PERI_BASE + 0x00/4) | ||
| #define SPI_FIFO (SPI_PERI_BASE + 0x04/4) | ||
| #define SPI_CLK (SPI_PERI_BASE + 0x08/4) | ||
| #define SPI_DLEN (SPI_PERI_BASE + 0x0C/4) | ||
| #define SPI_LTOH (SPI_PERI_BASE + 0x10/4) | ||
| #define SPI_DC (SPI_PERI_BASE + 0x14/4) | ||
| /* I2C registers */ | ||
| #define I2C_PERI_BASE base_pointer[5] // BSC1_BASE | ||
| #define I2C_C (I2C_PERI_BASE + 0x00/4) | ||
| #define I2C_S (I2C_PERI_BASE + 0x04/4) | ||
| #define I2C_C (I2C_PERI_BASE + 0x00/4) | ||
| #define I2C_S (I2C_PERI_BASE + 0x04/4) | ||
| #define I2C_DLEN (I2C_PERI_BASE + 0x08/4) | ||
| #define I2C_A (I2C_PERI_BASE + 0x0C/4) | ||
| #define I2C_A (I2C_PERI_BASE + 0x0C/4) | ||
| #define I2C_FIFO (I2C_PERI_BASE + 0x10/4) | ||
| #define I2C_DIV (I2C_PERI_BASE + 0x14/4) | ||
| #define I2C_DEL (I2C_PERI_BASE + 0x18/4) | ||
| #define I2C_CLKT (I2C_PERI_BASE + 0x1C/4) | ||
| #define I2C_CLKT (I2C_PERI_BASE + 0x1C/4) | ||
@@ -155,4 +151,12 @@ /* Size of info[] array */ | ||
| /* Dynamic peripheral base address array */ | ||
| volatile uint32_t base_add[10] = {}; // ininialize each element to 0 | ||
| /* Dynamic peripheral base address array pointer | ||
| * This is the return mapped address of each peripheral base address | ||
| */ | ||
| volatile uint32_t *base_pointer[10] = {}; // ininialize each element to 0 | ||
| /* page_size variable */ | ||
| int page_size = 0; // (4*1024) | ||
| uint32_t page_size = 0; | ||
@@ -164,11 +168,5 @@ /* Peripheral base address variable. The value of which will be determined | ||
| /* Dynamic peripheral base address container */ | ||
| volatile uint32_t base_add[BASE_INDEX] = {0}; | ||
| /* core_clock frequency for for all RPI models */ | ||
| uint32_t core_clock_freq = 250000000; // 250 MHz | ||
| /* Dynamic base address pointer to be used during mmap() process */ | ||
| volatile uint32_t *base_pointer[BASE_INDEX] = {0}; | ||
| /* Temporary dynamic core_clock frequency container (RPi 1 & 2 = 250 MHz, RPi 3 & 4 = 400 MHz) */ | ||
| uint32_t core_clock_freq = 250000000; // Initial value is 250 MHz | ||
| /********************************** | ||
@@ -179,4 +177,5 @@ | ||
| ***********************************/ | ||
| /* Get device RPI model and set peripheral base address accordingly */ | ||
| void set_peri_base_address(uint8_t pwm_option, uint8_t spi_option, uint8_t i2c_option){ | ||
| uint8_t cpu_type = 0, init_devmem = 0, init_gpiomem = 0, rpi_init_access = 0; | ||
| void get_cpu_type(){ | ||
| FILE *fp; | ||
@@ -188,157 +187,236 @@ char info[INFO_SIZE]; | ||
| if (fp == NULL) { | ||
| fputs ("reading file /proc/cpuinfo error", stderr); | ||
| exit (1); | ||
| fputs ("fopen /proc/cpuinfo error", stderr); | ||
| exit(1); | ||
| } | ||
| /* Get 'Model' info */ | ||
| while (fgets (info, INFO_SIZE, fp) != NULL){ | ||
| if (strncmp (info, "Model", 5) == 0) | ||
| break; | ||
| break; | ||
| } | ||
| //printf("%s", info); | ||
| if(strstr(info, "Pi Zero")||strstr(info, "Pi 1")){ | ||
| //puts("Pi zero/Pi 1"); | ||
| peri_base = PERI_BASE_RPI1; | ||
| } | ||
| if(debug) printf("%s", info); | ||
| if(strstr(info, "Pi Zero")||strstr(info, "Pi 1")){ | ||
| if(debug) puts("Pi zero/Pi 1"); | ||
| peri_base = PERI_BASE_1; | ||
| cpu_type = 1; | ||
| } | ||
| else if(strstr(info, "Pi Zero 2")||strstr(info, "Pi 3")){ | ||
| //puts("Pi Zero 2/Pi 3"); | ||
| peri_base = PERI_BASE_RPI23; | ||
| core_clock_freq = CORE_CLOCK_FREQ_RPI23; | ||
| } | ||
| if(debug) puts("Pi Zero 2/Pi 3"); | ||
| peri_base = PERI_BASE_2; | ||
| cpu_type = 2; | ||
| } | ||
| else if(strstr(info, "Pi Compute Module 3")){ | ||
| //puts("Pi Compute Module 3 Model"); | ||
| peri_base = PERI_BASE_RPI23; | ||
| core_clock_freq = CORE_CLOCK_FREQ_RPI23; | ||
| } | ||
| if(debug) puts("Pi Compute Module 3 Model"); | ||
| peri_base = PERI_BASE_2; | ||
| cpu_type = 3; | ||
| } | ||
| else if(strstr(info, "Pi 4")||strstr(info, "Pi Compute Module 4")){ | ||
| //puts("Pi 4 Model B/Pi Compute Module 4"); | ||
| peri_base = PERI_BASE_RPI4; | ||
| core_clock_freq = CORE_CLOCK_FREQ_RPI4; | ||
| } | ||
| if(debug) puts("Pi 4 Model B/Pi Compute Module 4"); | ||
| peri_base = PERI_BASE_3; | ||
| cpu_type = 4; | ||
| } | ||
| else if(strstr(info, "Pi 400")){ | ||
| //puts("Pi 400 Model"); | ||
| peri_base = PERI_BASE_RPI4; | ||
| core_clock_freq = CORE_CLOCK_FREQ_RPI4; | ||
| } | ||
| if(debug) puts("Pi 400 Model"); | ||
| peri_base = PERI_BASE_3; | ||
| cpu_type = 4; | ||
| } | ||
| else{ | ||
| //puts("Other Rpi Model"); | ||
| peri_base = PERI_BASE_RPI4; | ||
| core_clock_freq = CORE_CLOCK_FREQ_RPI4; | ||
| } | ||
| /* Verify ST_BASE, its new value should be other than 0x3000 | ||
| * otherwise its peripheral base address was not correctly initialized | ||
| * along with other peripherals during runtime | ||
| */ | ||
| if(debug) puts("Other Rpi Model"); | ||
| cpu_type = 0; | ||
| } | ||
| if(ST_BASE == 0x3000){ | ||
| puts("peri_base address setup error:"); | ||
| puts("peri_base address initialization error:"); | ||
| printf("Target ST_BASE: %X\n", peri_base); | ||
| printf("Actual ST_BASE: %X\n", ST_BASE); | ||
| exit(1); | ||
| } | ||
| /* | ||
| // Check other information | ||
| // Get 'Hardware' info | ||
| rewind (fp); | ||
| while (fgets (info, INFO_SIZE, fp) != NULL){ | ||
| if (strncmp (info, "Hardware", 8) == 0) | ||
| } | ||
| if(debug){ | ||
| // 'Hardware' info | ||
| rewind (fp); | ||
| while (fgets (info, INFO_SIZE, fp) != NULL){ | ||
| if (strncmp (info, "Hardware", 8) == 0) | ||
| break ; | ||
| } | ||
| printf("%s", info); // show Hardware line info | ||
| } | ||
| printf("%s", info); // show Hardware line info | ||
| // Get 'Revision' info | ||
| // 'Revision' info | ||
| rewind (fp); | ||
| while (fgets (info, INFO_SIZE, fp) != NULL){ | ||
| if (strncmp (info, "Revision", 8) == 0) | ||
| break ; | ||
| } | ||
| printf("%s", info); // show Revision line info | ||
| */ | ||
| while (fgets (info, INFO_SIZE, fp) != NULL){ | ||
| if (strncmp (info, "Revision", 8) == 0) | ||
| break ; | ||
| } | ||
| // show Revision line info | ||
| printf("%s", info); | ||
| } | ||
| /* Set each peripheral base address | ||
| * consecutively for each base array element | ||
| */ | ||
| base_add[0] = ST_BASE; | ||
| base_add[1] = CLK_BASE; | ||
| base_add[2] = GPIO_BASE; | ||
| fclose(fp); | ||
| } | ||
| if(spi_option == 0){ | ||
| base_add[3] = SPI0_BASE; | ||
| /* Set each peripheral register on demand */ | ||
| uint8_t set_each_peri_mmap(uint8_t peri_type){ | ||
| int fd = 0; | ||
| char *mem = NULL, *type = NULL; | ||
| uint8_t i = 0, end_index = 0, start_index = 0; | ||
| if(peri_type == 0 && init_gpiomem == 0){ | ||
| mem = "/dev/gpiomem", type = "gpio"; | ||
| start_index = 0, end_index = 3; | ||
| base_add[0] = ST_BASE; | ||
| base_add[1] = CLK_BASE; | ||
| base_add[2] = GPIO_BASE; | ||
| } | ||
| else if(peri_type == 1){ | ||
| mem = "/dev/mem", type = "pwm"; | ||
| start_index = 3, end_index = 4; | ||
| base_add[3] = PWM_BASE; | ||
| } | ||
| else if(peri_type == 2){ | ||
| mem = "/dev/mem", type = "spi"; | ||
| start_index = 4, end_index = 5; | ||
| base_add[4] = SPI0_BASE; | ||
| } | ||
| else if(peri_type == 3){ | ||
| mem = "/dev/mem", type = "i2c"; | ||
| start_index = 5, end_index = 7; | ||
| base_add[5] = BSC1_BASE; | ||
| //base_add[6] = BSC0_BASE; | ||
| } | ||
| else{ | ||
| return 1; | ||
| } | ||
| uswait(5); | ||
| if(pwm_option == 0){ | ||
| base_add[4] = PWM_BASE; | ||
| } | ||
| if((fd = open(mem, O_RDWR|O_SYNC)) < 0) { | ||
| if(peri_type == 0){ | ||
| if(debug) printf("open error: %s, %s, %u\n", mem, type, peri_type); | ||
| perror("Opening gpio in /dev/gpiomem"); | ||
| printf("%s() error: ", __func__); | ||
| } | ||
| else { | ||
| if(debug) printf("open error: %s, %s, %u\n", mem, type, peri_type); | ||
| perror("Opening pwm, spi or i2c in /dev/mem requires root access"); | ||
| puts("Try running your app in root or sudo\n"); | ||
| } | ||
| exit(1); | ||
| } | ||
| if(i2c_option == 0){ | ||
| base_add[5] = BSC0_BASE; | ||
| uswait(5); | ||
| for(i = start_index; i < end_index; i++){ | ||
| base_pointer[i] = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, base_add[i]); | ||
| if (base_pointer[i] == MAP_FAILED) { | ||
| perror("set_each_peri_mmap error"); | ||
| printf("%s() error: ", __func__); | ||
| if(close(fd) < 0){ | ||
| perror("map failed - fd close"); | ||
| exit(1); | ||
| } | ||
| } | ||
| if(debug){ | ||
| printf("base_add[i]: %lu\n", (unsigned long)base_add[i]); | ||
| printf("base_pointer[i]: %lu\n", (unsigned long)base_pointer[i]); | ||
| } | ||
| // Note: Disable this for SocketCan operation | ||
| *base_pointer[i] = 0; | ||
| uswait(5); | ||
| } | ||
| else if(i2c_option == 1){ | ||
| base_add[5] = BSC1_BASE; | ||
| if(peri_type == 0 && init_gpiomem == 0){ | ||
| init_gpiomem = 1; | ||
| } | ||
| fclose(fp); | ||
| if(close(fd) < 0){ | ||
| perror("set_each_peri_mmap - fd close"); | ||
| } | ||
| if(debug) printf("set individual mmap success: %s, %s, %u\n", mem, type, peri_type); | ||
| return 0; | ||
| } | ||
| void start_mmap(int access){ | ||
| int fd, i; | ||
| /* Set gpio peripheral register and other registers (pwm, i2c, spi) on demand */ | ||
| uint8_t set_all_peri_mmap(uint8_t access){ | ||
| int fd = 0; | ||
| char *mem = NULL, *type = NULL; | ||
| uint8_t i, end_index = 0, start_index = 0; | ||
| /* | ||
| page_size = (size_t)sysconf(_SC_PAGESIZE); | ||
| //printf("init page_size: %i\n", page_size); | ||
| base_add[0] = ST_BASE; | ||
| base_add[1] = CLK_BASE; | ||
| base_add[2] = GPIO_BASE; | ||
| base_add[3] = PWM_BASE; | ||
| base_add[4] = SPI0_BASE; | ||
| base_add[5] = BSC1_BASE; | ||
| //base_add[6] = BSC0_BASE; | ||
| if(page_size < 0){ | ||
| perror("page_size"); | ||
| exit(1); | ||
| // access = 0, non-root | ||
| if (access == 0 && init_gpiomem == 0){ | ||
| mem = "/dev/gpiomem", type = "gpio"; | ||
| start_index = 0, end_index = 3; | ||
| } | ||
| */ | ||
| // access = 1, root | ||
| else if(access == 1 && init_devmem == 0) { | ||
| mem = "/dev/mem", type = "pwm, i2c, spi"; | ||
| start_index = 3, end_index = 7; | ||
| } | ||
| else{ | ||
| return 1; | ||
| } | ||
| // access = 0, non-root | ||
| if (!access) { | ||
| if ((fd = open("/dev/gpiomem", O_RDWR|O_SYNC)) < 0) { | ||
| perror("Opening rpi in /dev/gpiomem"); | ||
| if((fd = open(mem, O_RDWR|O_SYNC)) < 0) { | ||
| if(access == 0){ | ||
| if(debug) printf("open error: %s, %s, %u\n", mem, type, access); | ||
| perror("Opening gpio in /dev/gpiomem"); | ||
| printf("%s() error: ", __func__); | ||
| exit(1); | ||
| } | ||
| } | ||
| // access = 1, root | ||
| else if(access) { | ||
| if ((fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0) { | ||
| perror("Opening rpi in /dev/mem requires root access"); | ||
| //printf("%s() error: ", __func__); | ||
| puts("Try running your application with sudo or in root!\n"); | ||
| exit(1); | ||
| } | ||
| } | ||
| /* Start mmap() process for each peripheral base address | ||
| * and capture the corresponding peripheral memory base pointers | ||
| */ | ||
| for(i = 0; i < BASE_INDEX; i++){ | ||
| } | ||
| else { | ||
| if(debug) printf("open error: %s, %s, %u\n", mem, type, access); | ||
| perror("Opening pwm, spi or i2c in /dev/mem requires root access"); | ||
| puts("Try running your app in root or sudo\n"); | ||
| } | ||
| exit(1); | ||
| } | ||
| base_pointer[i] = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, base_add[i]); | ||
| for(i = start_index; i < end_index; i++){ | ||
| base_pointer[i] = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, base_add[i]); | ||
| if (base_pointer[i] == MAP_FAILED) { | ||
| perror("mmap() error"); | ||
| perror("set_all_peri_mmap error"); | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid peripheral register base address."); | ||
| if(close(fd) < 0) | ||
| if(close(fd) < 0){ | ||
| perror("fd close"); | ||
| exit(1); | ||
| } | ||
| /* Reset peripheral base register pointers back to 0 */ | ||
| exit(1); | ||
| } | ||
| } | ||
| uswait(5); | ||
| // Note: Disable this for SocketCan operation | ||
| *base_pointer[i] = 0; | ||
| *base_pointer[i] = 0; | ||
| } | ||
| /* Close fd after memory-mapped operation */ | ||
| if(access == 0 && init_gpiomem == 0){ | ||
| init_gpiomem = 1; | ||
| } | ||
| else if(access == 1 && init_devmem == 0){ | ||
| init_devmem = 1; | ||
| } | ||
| if(close(fd) < 0) | ||
| perror("fd close"); | ||
| perror("set_all_peri_mmap - fd close"); | ||
| if(debug) printf("set all mmap success: %s, %s, %u\n", mem, type, access); | ||
| return 0; | ||
| } | ||
| /* Initialize Arm Peripheral Base Register Adressses | ||
| * using mmap() either using "/dev/gpiomem" or "/dev/mem" | ||
| /* Initialize GPIO, PWM, I2C and SPI Peripheral Base Register Adressses using mmap() | ||
| * | ||
@@ -348,50 +426,36 @@ * access = 0 ("/dev/gpiomem") // GPIO | ||
| */ | ||
| void rpi_init(int access) { | ||
| set_peri_base_address(0, 0, 1); | ||
| start_mmap(access); | ||
| } | ||
| /* Initialize Arm peripheral base register w/ i2c pin options | ||
| * | ||
| * value = 0 (use SDA0 and SCL0 pins) | ||
| * value = 1 (use SDA1 and SCL1 pins) | ||
| */ | ||
| void rpi_init_i2c(uint8_t access, uint8_t value) { | ||
| if(value == 0){ | ||
| set_peri_base_address(0, 0, 0); // use SDA0 and SCL0 pins | ||
| void rpi_init(uint8_t access) { | ||
| get_cpu_type(); | ||
| if(access == 1){ | ||
| set_all_peri_mmap(0); | ||
| } | ||
| else if(value == 1){ | ||
| set_peri_base_address(0, 0, 1); // use SDA1 and SCL1 pins | ||
| } | ||
| start_mmap(access); | ||
| set_all_peri_mmap(access); | ||
| rpi_init_access = 1; | ||
| } | ||
| /* | ||
| * Close the library and reset all memory pointers to 0 or NULL | ||
| /* Close the library and reset all memory pointers to 0 or NULL | ||
| */ | ||
| uint8_t rpi_close() | ||
| { | ||
| int i; | ||
| //page_size = (size_t)sysconf(_SC_PAGESIZE); | ||
| //printf("close page_size: %i\n", page_size); | ||
| uint32_t i; | ||
| uint8_t end_index = 7; | ||
| for(i = 0; i < BASE_INDEX; i++){ | ||
| rpi_init_access = 1; | ||
| for(i = 0; i < end_index; i++){ | ||
| if (munmap((uint32_t *) base_pointer[i] , BLOCK_SIZE) < 0){ | ||
| perror("munmap() error"); | ||
| perror("munmap() error"); | ||
| printf("%s() error: ", __func__); | ||
| puts("munmap() operation fail"); | ||
| return -1; | ||
| } | ||
| } | ||
| } | ||
| /* munmap() success */ | ||
| return 0; | ||
| return 0; | ||
| } | ||
| /************************************** | ||
| /***************************************** | ||
| Time Delay Functions | ||
| *************************************** | ||
| 1 ms = 1000 us or microsecond | ||
@@ -404,3 +468,5 @@ 1 ms = 1000000 ns or nanosecond | ||
| 1 sec = 1000000000 ns or nanosecond | ||
| ***************************************/ | ||
| ******************************************/ | ||
| /* Time delay function in nanoseconds */ | ||
@@ -411,7 +477,7 @@ void nswait(uint64_t ns) { | ||
| while ( nanosleep(&req,&rem) == -1 ) | ||
| req.tv_nsec = rem.tv_nsec; | ||
| while ( nanosleep(&req,&rem) == -1 ) | ||
| req.tv_nsec = rem.tv_nsec; | ||
| } | ||
| /* Time delay function in us or microseconds, valid only if us is below 1000 */ | ||
| /* Time delay function in microseconds, valid only if us is below 1000 */ | ||
| void uswait(uint32_t us) { | ||
@@ -431,3 +497,3 @@ struct timespec req = { us / 1000, us % 1000 * 1000 }; | ||
| while ( nanosleep(&req, &rem) == -1 ) | ||
| req.tv_nsec = rem.tv_nsec; | ||
| req.tv_nsec = rem.tv_nsec; | ||
| } | ||
@@ -440,2 +506,3 @@ | ||
| **********************************************************/ | ||
| /* Set register bit position to 1 (ON state) */ | ||
@@ -483,7 +550,26 @@ uint32_t setBit(volatile uint32_t* reg, uint8_t position) | ||
| /******************************* | ||
| /****************************** | ||
| GPIO Control Functions | ||
| ********************************/ | ||
| *******************************/ | ||
| /* Initialize only the gpio peripheral register */ | ||
| void gpio_init(){ | ||
| if(rpi_init_access == 0){ | ||
| get_cpu_type(); | ||
| set_each_peri_mmap(0); | ||
| } | ||
| mswait(5); | ||
| if(debug) printf("GPIO_PERI_BASE: %lu\n", (unsigned long)GPIO_PERI_BASE); | ||
| __sync_synchronize(); | ||
| if (GPIO_PERI_BASE == 0){ | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid memory-mapped GPIO peripheral base register"); | ||
| exit(1); | ||
| } | ||
| } | ||
| /* | ||
@@ -509,13 +595,13 @@ * Set a GPIO pin based on fsel hex value | ||
| volatile uint32_t *gpsel = (uint32_t *)(GPIO_GPFSEL0 + (pin/10)); // get the GPFSEL0 pointer (GPFSEL0 ~ GPFSEL5) based on the pin number selected | ||
| uint32_t mask = ~ (7 << (pin % 10)*3); // mask to reset fsel to 0 first | ||
| *gpsel &= mask; // reset gpsel value to 0 | ||
| mask = (fsel << ((pin) % 10)*3); // mask for new fsel value | ||
| __sync_synchronize(); | ||
| *gpsel |= mask; // write new fsel value to gpselect pointer | ||
| __sync_synchronize(); | ||
| // get the GPFSEL0 pointer (GPFSEL0 ~ GPFSEL5) based on the pin number selected | ||
| volatile uint32_t *gpsel = (uint32_t *)(GPIO_GPFSEL0 + (pin/10)); | ||
| uint32_t mask = ~ (7 << (pin % 10)*3); // mask to reset fsel to 0 first | ||
| *gpsel &= mask; // reset gpsel value to 0 | ||
| mask = (fsel << ((pin) % 10)*3); // mask for new fsel value | ||
| __sync_synchronize(); | ||
| *gpsel |= mask; // write new fsel value to gpselect pointer | ||
| __sync_synchronize(); | ||
| } | ||
| /* | ||
| * Set a GPIO pin as input | ||
| /* Set a GPIO pin as input | ||
| */ | ||
@@ -526,7 +612,6 @@ void gpio_input(uint8_t pin){ | ||
| /* | ||
| * Set a GPIO pin as output | ||
| /* Set a GPIO pin as output | ||
| */ | ||
| void gpio_output(uint8_t pin){ | ||
| set_gpio(pin, 1); | ||
| set_gpio(pin, 1); | ||
| } | ||
@@ -547,28 +632,28 @@ | ||
| if(mode == 0){ | ||
| set_gpio(pin, 0); // input | ||
| set_gpio(pin, 0); // input | ||
| } | ||
| else if(mode == 1){ | ||
| set_gpio(pin, 1); // output | ||
| set_gpio(pin, 1); // output | ||
| } | ||
| else if(mode == 4){ | ||
| set_gpio(pin, 4); // alt-func 0 | ||
| set_gpio(pin, 4); // alt-func 0 | ||
| } | ||
| else if(mode == 5){ | ||
| set_gpio(pin, 5); // alt-func 1 | ||
| } | ||
| set_gpio(pin, 5); // alt-func 1 | ||
| } | ||
| else if(mode == 6){ | ||
| set_gpio(pin, 6); // alt-func 2 | ||
| } | ||
| set_gpio(pin, 6); // alt-func 2 | ||
| } | ||
| else if(mode == 7){ | ||
| set_gpio(pin, 7); // alt-func 3 | ||
| } | ||
| set_gpio(pin, 7); // alt-func 3 | ||
| } | ||
| else if(mode == 3){ | ||
| set_gpio(pin, 3); // alt-func 4 | ||
| } | ||
| else if(mode == 2){ | ||
| set_gpio(pin, 2); // alt-func 5 | ||
| set_gpio(pin, 3); // alt-func 4 | ||
| } | ||
| else if(mode == 2){ | ||
| set_gpio(pin, 2); // alt-func 5 | ||
| } | ||
| else{ | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid mode parameter."); | ||
| puts("Invalid mode parameter."); | ||
| } | ||
@@ -582,3 +667,3 @@ } | ||
| */ | ||
| uint8_t gpio_write(uint8_t pin, uint8_t bit) { | ||
| uint8_t gpio_write(uint8_t pin, uint8_t bit) { | ||
| volatile uint32_t *p = NULL; | ||
@@ -617,7 +702,7 @@ __sync_synchronize(); | ||
| /* Create a simple sing-shot pulse | ||
| /* Create a single-shot pulse | ||
| * | ||
| * td as time duration or period of the pulse | ||
| */ | ||
| void gpio_pulse(uint8_t pin, int td){ | ||
| void gpio_pulse(uint8_t pin, uint32_t td){ | ||
| gpio_on(pin); | ||
@@ -668,10 +753,10 @@ mswait(td); | ||
| if(bit == 1){ | ||
| setBit(GPIO_GPHEN0, pin); | ||
| setBit(GPIO_GPHEN0, pin); | ||
| } | ||
| else if(bit == 0){ | ||
| clearBit(GPIO_GPHEN0, pin); | ||
| clearBit(GPIO_GPHEN0, pin); | ||
| } | ||
| else { | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid bit parameter."); | ||
| puts("Invalid bit parameter."); | ||
| } | ||
@@ -687,10 +772,10 @@ } | ||
| if(bit == 1){ | ||
| setBit(GPIO_GPLEN0, pin); | ||
| setBit(GPIO_GPLEN0, pin); | ||
| } | ||
| else if(bit == 0){ | ||
| clearBit(GPIO_GPLEN0, pin); | ||
| clearBit(GPIO_GPLEN0, pin); | ||
| } | ||
| else { | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid bit parameter."); | ||
| puts("Invalid bit parameter."); | ||
| } | ||
@@ -701,3 +786,3 @@ } | ||
| Edge Detection Event | ||
| Edge Detection Event | ||
@@ -730,10 +815,10 @@ ***************************/ | ||
| if(bit == 1){ | ||
| setBit(GPIO_GPFEN0, pin); | ||
| setBit(GPIO_GPFEN0, pin); | ||
| } | ||
| else if(bit == 0){ | ||
| clearBit(GPIO_GPFEN0, pin); | ||
| clearBit(GPIO_GPFEN0, pin); | ||
| } | ||
| else { | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid bit parameter."); | ||
| puts("Invalid bit parameter."); | ||
| } | ||
@@ -749,10 +834,10 @@ } | ||
| if(bit == 1){ | ||
| setBit(GPIO_GPAREN0, pin); | ||
| setBit(GPIO_GPAREN0, pin); | ||
| } | ||
| else if(bit == 0){ | ||
| clearBit(GPIO_GPAREN0, pin); | ||
| clearBit(GPIO_GPAREN0, pin); | ||
| } | ||
| else { | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid bit parameter."); | ||
| puts("Invalid bit parameter."); | ||
| } | ||
@@ -768,10 +853,10 @@ } | ||
| if(bit == 1){ | ||
| setBit(GPIO_GPAFEN0, pin); | ||
| setBit(GPIO_GPAFEN0, pin); | ||
| } | ||
| else if(bit == 0){ | ||
| clearBit(GPIO_GPAFEN0, pin); | ||
| clearBit(GPIO_GPAFEN0, pin); | ||
| } | ||
| else { | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid bit parameter."); | ||
| puts("Invalid bit parameter."); | ||
| } | ||
@@ -784,3 +869,3 @@ } | ||
| */ | ||
| uint8_t gpio_detect_input_event(uint8_t pin) { | ||
| uint8_t gpio_detect_input_event(uint8_t pin) { | ||
| return isBitSet(GPIO_GPEDS0, pin); | ||
@@ -794,38 +879,84 @@ } | ||
| void gpio_reset_event(uint8_t pin) { | ||
| setBit(GPIO_GPEDS0, pin); | ||
| setBit(GPIO_GPEDS0, pin); | ||
| } | ||
| /* Enable internal PULL-UP/PULL-DOWN resistor for input pin | ||
| /* Enable internal PULL-UP/PULL-DOWN resistor for gpio pins | ||
| * | ||
| * value = 0, 0x0 or 00b, Disable Pull-Up/Down, no PU/PD resistor will be used | ||
| * value = 1, 0x1 or 01b, Enable Pull-Down resistor | ||
| * value = 2, 0x2 or 10b, Enable Pull-Up resistor | ||
| * rpi 4 | ||
| * BCM2711 GPIO_GPPUPPDN0, GPIO_GPPUPPDN1, GPIO_GPPUPPDN2, GPIO_GPPUPPDN3 | ||
| * | ||
| * value = 0, 0x0 or 00b, // Disable pull-up/down | ||
| * value = 1, 0x1 or 01b, // Enable pull-up | ||
| * value = 2, 0x2 or 10b, // Enable pull-down | ||
| * pi zero, rpi3 and others | ||
| * BCM2835 GPIO_GPPUD | ||
| * | ||
| * value = 0, 0x0 or 00b, // Disable pull-up/down | ||
| * value = 1, 0x1 or 01b, // Enable pull-down | ||
| * value = 2, 0x2 or 10b, // Enable pull-up | ||
| */ | ||
| void gpio_enable_pud(uint8_t pin, uint8_t value) { | ||
| if(value == 0){ | ||
| *GPIO_GPPUD = 0x0; // Disable PUD/Pull-UP/Down | ||
| } | ||
| else if(value == 1){ | ||
| *GPIO_GPPUD = 0x1; // Enable PD/Pull-Down | ||
| void gpio_set_pud(uint8_t pin, uint8_t pud) { | ||
| if(cpu_type == 4){ | ||
| uint32_t pull = 0x0; | ||
| uint32_t lsb = (pin & 0xf) << 1; | ||
| if(pud == 0){ | ||
| pull = 0x0; // No pull-up/down resistor is selected | ||
| } | ||
| else if(pud == 1){ | ||
| pull = 0x2; // Pull-down is selected | ||
| } | ||
| else if(pud == 2){ | ||
| pull = 0x1; // Pull-up is selected | ||
| } | ||
| else{ | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid pull select pud."); | ||
| } | ||
| *(GPIO_GPPUPPDN0 + (pin >> 4)) = (*(GPIO_GPPUPPDN0 + (pin >> 4)) & ~(3 << lsb)) | (pull << lsb); | ||
| } | ||
| else{ | ||
| if(pud == 0){ | ||
| *GPIO_GPPUD = 0x0; // No pull-up/down resistor is selected | ||
| } | ||
| else if(pud == 1){ | ||
| *GPIO_GPPUD = 0x1; // Pull-down is selected | ||
| } | ||
| else if(pud == 2){ | ||
| *GPIO_GPPUD = 0x2; // Pull-up is selected | ||
| } | ||
| else{ | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid pull select pud."); | ||
| } | ||
| uswait(10); | ||
| setBit(GPIO_GPPUDCLK0, pin); | ||
| uswait(10); | ||
| *GPIO_GPPUD = 0x0; | ||
| uswait(10); | ||
| clearBit(GPIO_GPPUDCLK0, pin); | ||
| } | ||
| else if(value == 2){ | ||
| *GPIO_GPPUD = 0x2; // Enable PU/Pull-Up | ||
| } | ||
| else{ | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid pud value."); | ||
| } | ||
| } | ||
| uswait(150); /* required wait times based on bcm2835 manual */ | ||
| setBit(GPIO_GPPUDCLK0, pin); | ||
| uswait(150); /* required wait times based on bcm2835 manual */ | ||
| *GPIO_GPPUD = 0x0; | ||
| clearBit(GPIO_GPPUDCLK0, pin); | ||
| uint8_t gpio_get_pud(uint8_t pin) { | ||
| uint8_t pull_state = -1; | ||
| if(cpu_type == 4){ | ||
| volatile uint32_t *addr = GPIO_GPPUPPDN0 + (pin >> 4); | ||
| pull_state = (*addr) >> ((pin & 0xf) << 1) & 0x3; | ||
| } | ||
| return pull_state; | ||
| } | ||
| /********************************* | ||
| /*************************** | ||
| PWM Setup functions | ||
| *********************************/ | ||
| ****************************/ | ||
| /* Reset all PWM pins to GPIO input */ | ||
@@ -844,14 +975,14 @@ void pwm_reset_all_pins(){ | ||
| void pwm_set_pin(uint8_t pin){ | ||
| if(pin == 12||pin ==13) { // alt 100b, PHY pin 33, GPIO 13, alt 0 | ||
| set_gpio(pin, 4); // alt 100b, PHY pin 32, GPIO 12, alt 0 | ||
| } | ||
| else if(pin == 18||pin == 19) { // alt 10b, PHY pin 35, GPIO 19, alt 5 | ||
| set_gpio(pin, 2); // alt 10b, PHY pin 12, GPIO 18, alt 5 | ||
| if(pin == 12 || pin == 13) { // alt 100b, PHY pin 33, GPIO 13, alt 0 | ||
| set_gpio(pin, 4); // alt 100b, PHY pin 32, GPIO 12, alt 0 | ||
| } | ||
| else if(pin == 18 || pin == 19) { // alt 10b, PHY pin 35, GPIO 19, alt 5 | ||
| set_gpio(pin, 2); // alt 10b, PHY pin 12, GPIO 18, alt 5 | ||
| } | ||
| else { | ||
| printf("%s() error: ", __func__); | ||
| else { | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid pin number for PWM."); | ||
| puts("Choose only from board header layout pins 12, 32, 33 and 35."); | ||
| puts("Choose only from the board header pins 12, 32, 33 and 35."); | ||
| exit(1); | ||
| } | ||
| } | ||
| } | ||
@@ -861,20 +992,21 @@ | ||
| void pwm_reset_pin(uint8_t pin){ | ||
| if(pin == 18||pin ==12||pin==13||pin==19) { | ||
| gpio_input(pin); // GPIO18/PHY12, GPIO12/PHY32, GPIO13/PHY33, GPIO19/PHY35 | ||
| } | ||
| else { | ||
| printf("%s() error: ", __func__); | ||
| if(pin == 18 || pin == 12 || pin== 13 || pin== 19) { | ||
| gpio_input(pin); // GPIO18/PHY12, GPIO12/PHY32, GPIO13/PHY33, GPIO19/PHY35 | ||
| gpio_set_pud(pin, 0); | ||
| } | ||
| else { | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid pin."); | ||
| exit(1); | ||
| } | ||
| exit(1); | ||
| } | ||
| } | ||
| /***************************************** | ||
| /************************************* | ||
| PWM Clock operation functions | ||
| ******************************************/ | ||
| /* define clock source constants */ | ||
| **************************************/ | ||
| /* clock source constants */ | ||
| #define OSC 0x1 | ||
| #define PLLD 0x6 | ||
| #define PLLD 0x6 | ||
@@ -896,13 +1028,12 @@ /* A quick check which clock generator is running | ||
| if(isBitSet(CM_PWMCTL, 7)){ | ||
| return 1; // clk is running | ||
| } | ||
| return 1; // clk is running | ||
| } | ||
| else{ | ||
| return 0; // clk is not running | ||
| } | ||
| return 0; // clk is not running | ||
| } | ||
| } | ||
| /* Calculate clock freq based on divisor div value */ | ||
| /* Calculate clock freq based on div (divisor) value */ | ||
| void set_clock_div(uint32_t div){ | ||
| // using 5A as clock manager password for PASSWD field | ||
| // on bit num 31-21 | ||
| // using 5A as clock manager password for PASSWD field on bit num 31-21 | ||
@@ -922,2 +1053,3 @@ /* disable PWM while performing clk operations */ | ||
| } | ||
| uswait(20); | ||
@@ -930,10 +1062,10 @@ | ||
| } | ||
| /* | ||
| set DIVF (bit num 11-0) divisor from clock manager | ||
| general purpose register (CM_GP2DIV) while clk is not running | ||
| */ | ||
| /* set DIVF (bit num 11-0) divisor from clock manager | ||
| * general purpose register (CM_GP2DIV) while clk is not running | ||
| */ | ||
| if(!isBitSet(CM_PWMCTL, 7)){ | ||
| *CM_PWMDIV = 0x5A000000 | ( div << 12 ); | ||
| } | ||
| } | ||
| uswait(20); | ||
@@ -944,3 +1076,4 @@ } | ||
| uint8_t pwm_set_clock_freq(uint32_t divider) { | ||
| if( 0 < divider && divider < 4096){ | ||
| //if( 0 < divider && divider < 4096){ | ||
| if(divider > 0 && divider < 4096){ | ||
| set_clock_div(divider); | ||
@@ -964,10 +1097,28 @@ } | ||
| return -1; | ||
| } | ||
| } | ||
| } | ||
| /*************************************** | ||
| /******************************* | ||
| PWM Operation functions | ||
| ***************************************/ | ||
| ********************************/ | ||
| void pwm_init(){ | ||
| if(rpi_init_access == 0){ | ||
| gpio_init(); // map gpio for alt pin sel | ||
| set_each_peri_mmap(1); // map pwm peripheral register | ||
| } | ||
| mswait(5); | ||
| if(debug) printf("PWM_PERI_BASE: %lu\n", (unsigned long)PWM_PERI_BASE); | ||
| __sync_synchronize(); | ||
| if (PWM_PERI_BASE == 0){ | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid memory-mapped PWM peripheral base register"); | ||
| exit(1); | ||
| } | ||
| } | ||
| /* Monitor PWM status register and reset accordingly | ||
@@ -986,3 +1137,3 @@ * (Internal use only) | ||
| bool WERR1 = isBitSet(PWM_STA, 2); | ||
| uswait(10); | ||
| uswait(10); | ||
@@ -999,9 +1150,9 @@ if(!STA1) { | ||
| if(RERR1) | ||
| setBit(PWM_STA, 3); // reset RERR1 | ||
| if(WERR1) | ||
| setBit(PWM_STA, 2); // reset WERR1 | ||
| if(BERR) | ||
| setBit(PWM_STA, 8); // reset BERR | ||
| setBit(PWM_STA, 3); // reset RERR1 | ||
| if(WERR1) | ||
| setBit(PWM_STA, 2); // reset WERR1 | ||
| if(BERR) | ||
| setBit(PWM_STA, 8); // reset BERR | ||
| } | ||
| uswait(10); | ||
| uswait(10); | ||
| } | ||
@@ -1014,11 +1165,11 @@ | ||
| if(n == 1){ | ||
| setBit(PWM_CTL, position); | ||
| } | ||
| else if(n == 0) { | ||
| clearBit(PWM_CTL, position); | ||
| } | ||
| else{ | ||
| puts("Invalid n control parameter. Choose 1 or 0 only."); | ||
| } | ||
| uswait(10); | ||
| setBit(PWM_CTL, position); | ||
| } | ||
| else if(n == 0) { | ||
| clearBit(PWM_CTL, position); | ||
| } | ||
| else{ | ||
| puts("Invalid n control parameter. Choose 1 or 0 only."); | ||
| } | ||
| uswait(10); | ||
| } | ||
@@ -1033,4 +1184,4 @@ | ||
| // Channel 1 | ||
| if( pin == 18 || pin == 12) { // GPIO 18/12, PHY 12/32 | ||
| pwm_reg_ctrl(n, 0); | ||
| if( pin == 18 || pin == 12) { // GPIO 18/12, PHY 12/32 | ||
| pwm_reg_ctrl(n, 0); | ||
| } | ||
@@ -1055,3 +1206,3 @@ // Channel 2 | ||
| if( pin == 18 || pin == 12) { // GPIO 18/12, PHY 12/32 | ||
| pwm_reg_ctrl(n, 7); | ||
| pwm_reg_ctrl(n, 7); | ||
| } | ||
@@ -1108,23 +1259,23 @@ // Channel 2 | ||
| void pwm_set_data(uint8_t pin, uint32_t data){ | ||
| // Channel 1 | ||
| if( pin == 18 || pin == 12) { // GPIO 18/12, PHY 12/32 | ||
| *PWM_DAT1 = data; | ||
| // Channel 1 | ||
| if( pin == 18 || pin == 12) { // GPIO 18/12, PHY 12/32 | ||
| *PWM_DAT1 = data; | ||
| reset_status_reg(); | ||
| } | ||
| // Channel 2 | ||
| else if(pin == 13 || pin == 19) { // GPIO 13/19, PHY 33/35 | ||
| *PWM_DAT2 = data; | ||
| reset_status_reg(); | ||
| } | ||
| else{ | ||
| // Channel 2 | ||
| else if(pin == 13 || pin == 19) { // GPIO 13/19, PHY 33/35 | ||
| *PWM_DAT2 = data; | ||
| reset_status_reg(); | ||
| } | ||
| else{ | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid pin."); | ||
| } | ||
| } | ||
| } | ||
| /************************************************** | ||
| /**************************************** | ||
| Helper functions for I2C and SPI | ||
| **************************************************/ | ||
| ****************************************/ | ||
| /* Clear FIFO buffer function for I2C and SPI operation */ | ||
@@ -1134,17 +1285,12 @@ void clear_fifo(volatile uint32_t* reg){ | ||
| setBit(reg, 5); // Set bit 5 of CLEAR field | ||
| /* alternative code */ | ||
| //uint32_t mask = (3 << 4); // create a mask to set bit 4 and 5 (CLEAR field) to 1 (covers both I2C & SPI FIFO) | ||
| //*reg |= mask; // using bitwise OR assignment to clear FIFO | ||
| //uint32_t mask = 0x00000010; // mask to clear bit 4 (CLEAR field) only | ||
| //*reg |= mask; | ||
| } | ||
| /**************************** | ||
| /******************* | ||
| I2C Functons | ||
| *****************************/ | ||
| ********************/ | ||
| // Write cycles place data into the 16-byte FIFO ready for BSC bus transmission (sends data to FIFO) | ||
| // Read cycles access data received from the BSC bus (read data from FIFO). | ||
| uint8_t i2c_pin_set = 1; | ||
@@ -1158,34 +1304,3 @@ | ||
| } | ||
| // Write cycles place data into the 16-byte FIFO ready for BSC bus transmission (sends data to FIFO) | ||
| // Read cycles access data received from the BSC bus (read data from FIFO). | ||
| /* Start I2C operation */ | ||
| int i2c_start() | ||
| { | ||
| //rpi_init(1); | ||
| //mswait(25); | ||
| if ( I2C_C == 0 ){ | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid I2C registers addresses."); | ||
| return 0; | ||
| } | ||
| /* BSC0_BASE */ | ||
| //set_gpio(0, 4); // alt 100b, PHY 27, GPIO 00, alt 0 SDA0 | ||
| //set_gpio(1, 4); // alt 100b, PHY 28, GPIO 01, alt 0 SCL0 | ||
| /* BSC1_BASE */ | ||
| set_gpio(2, 4); // alt 100b, PHY 03, GPIO 02, alt 0 SDA1 | ||
| set_gpio(3, 4); // alt 100b, PHY 05, GPIO 03, alt 0 SCL1 | ||
| mswait(10); | ||
| setBit(I2C_C, 15); // set I2CEN field, enable I2C operation (BSC controller is enabled) | ||
| return 1; // i2c initialization is successful | ||
| } | ||
| /* Start I2C operation immediately w/o calling 'rpi_init(1)' | ||
| /* Start I2C operation immediately w/o calling rpi_init(1) | ||
| * (Initialization process is integrated with the function) | ||
@@ -1198,30 +1313,33 @@ * | ||
| */ | ||
| int i2c_init(uint8_t value) | ||
| { | ||
| if(value == 1){ | ||
| rpi_init_i2c(1, 1); | ||
| i2c_pin_set = 1; | ||
| void i2c_start(uint8_t sel) { | ||
| if(rpi_init_access == 0){ | ||
| gpio_init(); // init gpio for alt pin sel | ||
| set_each_peri_mmap(3); // init i2c | ||
| } | ||
| else if(value == 0){ | ||
| rpi_init_i2c(1, 0); | ||
| i2c_pin_set = 0; | ||
| mswait(5); | ||
| if(debug){ | ||
| printf("I2C_PERI_BASE: %lu\n", (unsigned long)I2C_PERI_BASE); | ||
| //printf("I2C_PERI_BASE2: %lu\n", (unsigned long)I2C_PERI_BASE2); | ||
| printf("base_pointer[6]: %lu\n", (unsigned long)base_pointer[6]); | ||
| } | ||
| mswait(25); | ||
| if (I2C_C == 0){ | ||
| if (I2C_PERI_BASE == 0){ | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid I2C register addresses."); | ||
| return 0; | ||
| puts("Invalid memory-mapped I2C peripheral base register"); | ||
| exit(1); | ||
| } | ||
| mswait(10); | ||
| mswait(5); | ||
| // BSC0_BASE, using SDA0 (GPIO 00/pin 27) and SCL0 (GPIO 01/pin 28) | ||
| if(value == 0){ | ||
| if(sel == 0){ | ||
| i2c_pin_set = 0; | ||
| set_gpio(0, 4); // GPIO 00 alt 100b, alt 0 SDA0 | ||
| set_gpio(1, 4); // GPIO 01 alt 100b, alt 0 SCL0 | ||
| } | ||
| } | ||
| // BSC1_BASE, using SDA1 (GPIO 02/pin 03) and SCL1 (GPIO 03/pin 05) | ||
| else if(value == 1){ | ||
| else if(sel == 1){ | ||
| i2c_pin_set = 1; | ||
| set_gpio(2, 4); // GPIO 02 alt 100b, alt 0 SDA1 | ||
@@ -1231,9 +1349,7 @@ set_gpio(3, 4); // GPIO 03 alt 100b, alt 0 SCL1 | ||
| mswait(10); | ||
| mswait(5); | ||
| setBit(I2C_C, 15); // set I2CEN field, enable I2C operation (BSC controller is enabled) | ||
| setBit(I2C_C, 15); // set I2CEN field, enable I2C operation (BSC controller is enabled) | ||
| // or | ||
| //*I2C_C |= 0x00008000; | ||
| return 1; // i2c initialization is successful | ||
| } | ||
@@ -1262,3 +1378,3 @@ | ||
| // set a new msb and lsb values to data delay register | ||
| // set a new msb and lsb values to data delay register | ||
| volatile uint32_t value = (volatile uint32_t)(msb << 16 | lsb); | ||
@@ -1268,5 +1384,2 @@ | ||
| *I2C_DEL = value; | ||
| //printf("msb:%x\n", msb); | ||
| //printf("lsb:%x\n", lsb); | ||
| //printf("value:%x\n", value); | ||
| } | ||
@@ -1278,14 +1391,2 @@ else{ | ||
| /* | ||
| volatile uint32_t delay_reg = *I2C_DEL; | ||
| // Extract the msb and lsb values from a pointer | ||
| volatile uint32_t msb1 = delay_reg & 0xFFFF0000; | ||
| volatile uint32_t lsb1 = delay_reg & 0x0000FFFF; | ||
| printf("msb1:%x\n", msb1); | ||
| printf("lsb1:%x\n", lsb1); | ||
| printf("delay_reg:%x\n", delay_reg); | ||
| */ | ||
| return *I2C_DEL; | ||
@@ -1301,23 +1402,11 @@ } | ||
| /* | ||
| printf("cdiv msb:%x\n", msb); | ||
| printf("cdiv lsb:%x\n", lsb); | ||
| printf("cdiv_reg:%x\n", div_reg); | ||
| */ | ||
| volatile uint32_t *div = I2C_DIV; | ||
| volatile uint32_t *div = I2C_DIV; | ||
| lsb = 0x05DC; | ||
| // reset | ||
| lsb = 0x05DC; | ||
| *div = (volatile uint32_t)(msb << 16 | lsb); | ||
| //or | ||
| //*div = lsb; | ||
| //printf("reset value I2C_DIV:%x\n", *I2C_DIV); | ||
| *div = divider; | ||
| //printf("new value I2C_DIV:%x\n", *I2C_DIV); | ||
| set_clock_delay(1, 1); | ||
| //printf("set_clock_delay: %i\n", set_clock_delay(11, 11)); | ||
| } | ||
@@ -1329,5 +1418,5 @@ | ||
| /* get the divisor value from the 250 MHz system clock source */ | ||
| //uint32_t divider = (core_clock_freq / baud); // using a dynamic core clock freq | ||
| //uint32_t divider = (CORE_CLK_FREQ/baud); | ||
| uint32_t divider = (core_clock_freq/baud); | ||
| uint32_t divider = (CORE_CLK_FREQ/baud); // using a fixed core clock freq | ||
@@ -1341,11 +1430,2 @@ i2c_set_clock_freq((uint16_t)divider); | ||
| /* | ||
| volatile uint32_t *clkt = I2C_CLKT; | ||
| printf("clkt:%i\n", *clkt); | ||
| if(i == buf_len){ | ||
| puts("Data tansfer is complete."); | ||
| } | ||
| */ | ||
| if(i < buf_len) | ||
@@ -1355,3 +1435,3 @@ { | ||
| printf("%s(): ", __func__); | ||
| puts("Data tansfer is incomplete."); | ||
| if(debug) puts("Data tansfer is incomplete."); | ||
| } | ||
@@ -1362,3 +1442,3 @@ else if(i > buf_len) | ||
| printf("%s(): ", __func__); | ||
| puts("Data tansfer error."); | ||
| if(debug) puts("Data tansfer error."); | ||
| } | ||
@@ -1371,3 +1451,3 @@ | ||
| printf("%s(): ", __func__); | ||
| puts("Slave address is not acknowledged."); | ||
| if(debug) puts("Slave address is not acknowledged."); | ||
| } | ||
@@ -1380,3 +1460,3 @@ | ||
| printf("%s(): ", __func__); | ||
| puts("Clock stretch timeout."); | ||
| puts("Clock stretch timeout."); | ||
| } | ||
@@ -1389,6 +1469,6 @@ /* write error | ||
| { | ||
| //puts("The i2c controller did not send all data to slave device."); | ||
| if(debug) puts("The i2c controller did not send all the data to slave device."); | ||
| result = 4; | ||
| printf("%s(): ", __func__); | ||
| puts("Not all data were sent to the slave device."); | ||
| if(debug) puts("Not all data were sent to the slave device."); | ||
| } | ||
@@ -1401,6 +1481,6 @@ /* read error | ||
| { | ||
| //puts("The i2c controller did not receive all data from slave device."); | ||
| if(debug) puts("The i2c controller did not receive all the data from slave device."); | ||
| result = 4; | ||
| printf("%s(): ", __func__); | ||
| puts("Not all data were received from the slave device."); | ||
| if(debug) puts("Not all data were received from the slave device."); | ||
| } | ||
@@ -1419,4 +1499,4 @@ | ||
| result = 4; | ||
| printf("%s(): ", __func__); | ||
| puts("Data transfer is incomplete."); | ||
| printf("%s(): ", __func__); | ||
| if(debug) puts("Data transfer is incomplete."); | ||
| } | ||
@@ -1535,7 +1615,6 @@ | ||
| { | ||
| //while(isBitSet(I2C_S, 5) && (i <= rbuf_len)) | ||
| while(isBitSet(I2C_S, 5) && (rbuf_len >= i )) // check RXD field (RXD = 0 FIFO is empty, RXD = 1 FIFO contains at least 1 byte of data) | ||
| while(isBitSet(I2C_S, 5) && (rbuf_len >= i )) // check RXD field (RXD = 0 FIFO is empty, RXD = 1 FIFO contains at least 1 byte of data) | ||
| { | ||
| rbuf[i] = *fifo; | ||
| i++; | ||
| rbuf[i] = *fifo; | ||
| i++; | ||
| } | ||
@@ -1592,6 +1671,5 @@ } | ||
| clearBit(I2C_C, 15); /* clear I2CEN field to disable I2C operation (BSC controller is disabled) */ | ||
| clearBit(I2C_C, 15); | ||
| if(i2c_pin_set == 0){ | ||
| //puts("reset SDA0/SCL0 pins to GPIO input"); | ||
| set_gpio(0, 0); /* alt 00b, PHY 27, GPIO 00, alt 0 SDA */ | ||
@@ -1601,24 +1679,28 @@ set_gpio(1, 0); /* alt 00b, PHY 28, GPIO 01, alt 0 SCL */ | ||
| else{ | ||
| //puts("reset SDA1/SCL1 pins to GPIO input"); | ||
| set_gpio(2, 0); /* alt 00b, PHY 3, GPIO 02, alt 0 SDA */ | ||
| set_gpio(3, 0); /* alt 00b, PHY 5, GPIO 03, alt 0 SCL */ | ||
| } | ||
| } | ||
| } | ||
| /**************************** | ||
| /******************** | ||
| SPI Functons | ||
| SPI Functons | ||
| *****************************/ | ||
| *********************/ | ||
| /* Start SPI operation */ | ||
| int spi_start() | ||
| { | ||
| //rpi_init(1); | ||
| //mswait(25); | ||
| void spi_start() { | ||
| if(rpi_init_access == 0){ | ||
| gpio_init(); // map gpio for alt pin sel | ||
| set_each_peri_mmap(2); // map spi peripheral register | ||
| } | ||
| mswait(5); | ||
| if(debug) printf("SPI_PERI_BASE: %lu\n", (unsigned long)SPI_PERI_BASE); | ||
| __sync_synchronize(); | ||
| if (SPI_CS == 0){ | ||
| if (SPI_PERI_BASE == 0){ | ||
| printf("%s() error: ", __func__); | ||
| puts("Invalid SPI registers addresses."); | ||
| return 0; | ||
| puts("Invalid memory-mapped SPI peripheral base register"); | ||
| exit(1); | ||
| } | ||
@@ -1632,8 +1714,6 @@ | ||
| mswait(10); | ||
| mswait(5); | ||
| clearBit(SPI_CS, 13); // set SPI to SPI Master (Standard SPI) | ||
| clear_fifo(SPI_CS); // Clear SPI TX and RX FIFO | ||
| return 1; | ||
| } | ||
@@ -1671,11 +1751,11 @@ | ||
| clearBit(SPI_CS, 2); //CPHA 0 | ||
| clearBit(SPI_CS, 3); //CPOL 0 | ||
| clearBit(SPI_CS, 3); //CPOL 0 | ||
| } | ||
| else if(mode == 1){ | ||
| setBit(SPI_CS, 2); //CPHA 1 | ||
| clearBit(SPI_CS, 3); //CPOL 0 | ||
| setBit(SPI_CS, 2); //CPHA 1 | ||
| clearBit(SPI_CS, 3); //CPOL 0 | ||
| } | ||
| else if(mode == 2){ | ||
| clearBit(SPI_CS, 2); //CPHA 0 | ||
| setBit(SPI_CS, 3); //CPOL 1 | ||
| setBit(SPI_CS, 3); //CPOL 1 | ||
| } | ||
@@ -1686,15 +1766,15 @@ else if(mode == 3){ | ||
| } | ||
| else{ | ||
| printf("%s() error: ", __func__); | ||
| puts("invalid mode"); | ||
| } | ||
| else{ | ||
| printf("%s() error: ", __func__); | ||
| puts("invalid mode"); | ||
| } | ||
| // alternate code | ||
| /* | ||
| volatile uint32_t *cs = SPI_CS; | ||
| uint32_t mask = ~ (3 << 2); // clear bit position 2 and 3 first | ||
| *cs &= mask; // set mask to 0 | ||
| mask = (mode << 2); // write mode value to set SPI data mode | ||
| *cs |= mask; // set data mode | ||
| */ | ||
| // alternate code | ||
| /* | ||
| volatile uint32_t *cs = SPI_CS; | ||
| uint32_t mask = ~ (3 << 2); // clear bit position 2 and 3 first | ||
| *cs &= mask; // set mask to 0 | ||
| mask = (mode << 2); // write mode value to set SPI data mode | ||
| *cs |= mask; // set data mode | ||
| */ | ||
| } | ||
@@ -1714,5 +1794,5 @@ | ||
| uint32_t mask = ~ (3 << 0); // clear bit 0 and 1 first | ||
| *cs_addr &= mask; // set mask to value 0 | ||
| mask = (cs << 0); // write cs value to set SPI data mode | ||
| *cs_addr |= mask; // set cs value | ||
| *cs_addr &= mask; // set mask to value 0 | ||
| mask = (cs << 0); // write cs value to set SPI data mode | ||
| *cs_addr |= mask; // set cs value | ||
| } | ||
@@ -1732,3 +1812,3 @@ | ||
| else if(cs == 0 && active == 1){ | ||
| setBit(SPI_CS, 21); | ||
| setBit(SPI_CS, 21); | ||
| } | ||
@@ -1766,8 +1846,8 @@ else if(cs == 1 && active == 0){ | ||
| { | ||
| // TX fifo is not full, add/write more bytes | ||
| while(isBitSet(SPI_CS, 18) && (w < len)) | ||
| { | ||
| *fifo = wbuf[w]; | ||
| w++; | ||
| } | ||
| // TX fifo is not full, add/write more bytes | ||
| while(isBitSet(SPI_CS, 18) && (w < len)) | ||
| { | ||
| *fifo = wbuf[w]; | ||
| w++; | ||
| } | ||
| } | ||
@@ -1778,8 +1858,8 @@ | ||
| { | ||
| // RX fifo is not empty, read more received bytes | ||
| // RX fifo is not empty, read more received bytes | ||
| while(isBitSet(SPI_CS, 17) && (r < len )) | ||
| { | ||
| rbuf[r] = *fifo; | ||
| r++; | ||
| } | ||
| { | ||
| rbuf[r] = *fifo; | ||
| r++; | ||
| } | ||
| } | ||
@@ -1792,4 +1872,4 @@ | ||
| if(isBitSet(SPI_CS, 16)){ | ||
| printf("%s() error: ", __func__); | ||
| puts("data transfer error"); | ||
| printf("%s() error: ", __func__); | ||
| puts("data transfer error"); | ||
| } | ||
@@ -1816,4 +1896,4 @@ } | ||
| { | ||
| *fifo = wbuf[i]; | ||
| i++; | ||
| *fifo = wbuf[i]; | ||
| i++; | ||
| } | ||
@@ -1835,3 +1915,3 @@ } | ||
| /* continue data transfer from spi_write start transfer */ | ||
| //setBit(SPI_CS, 7); // no need to start data transfer | ||
| //setBit(SPI_CS, 7); // currently no need to set to start data transfer | ||
@@ -1845,4 +1925,4 @@ uint8_t i = 0; | ||
| { | ||
| rbuf[i] = *fifo; | ||
| i++; | ||
| rbuf[i] = *fifo; | ||
| i++; | ||
| } | ||
@@ -1855,2 +1935,1 @@ } | ||
+18
-13
@@ -15,2 +15,4 @@ /** | ||
| #define debug 0 | ||
| #ifdef __cplusplus | ||
@@ -20,17 +22,16 @@ extern "C" { | ||
| /* Initialize RPI library */ | ||
| extern void rpi_init(int access); | ||
| void rpi_init(uint8_t access); | ||
| /* Close RPI library */ | ||
| extern uint8_t rpi_close(); | ||
| uint8_t rpi_close(); | ||
| /** | ||
| * Time Delays | ||
| * Timers | ||
| */ | ||
| void nswait(uint64_t ns); //nanosecond time delay | ||
| void nswait(uint64_t ns); //nanosecond | ||
| void uswait(uint32_t us); //microsecond time delay | ||
| void uswait(uint32_t us); //microsecond | ||
| void mswait(uint32_t ms); //millisecond time delay | ||
| void mswait(uint32_t ms); //millisecond | ||
@@ -40,2 +41,4 @@ /** | ||
| */ | ||
| void gpio_init(); | ||
| void gpio_config(uint8_t pin, uint8_t mode); | ||
@@ -55,3 +58,3 @@ | ||
| void gpio_pulse(uint8_t pin, int td); | ||
| void gpio_pulse(uint8_t pin, uint32_t td); | ||
@@ -76,7 +79,11 @@ void gpio_reset_all_events(uint8_t pin); | ||
| void gpio_enable_pud(uint8_t pin, uint8_t value); | ||
| void gpio_set_pud(uint8_t pin, uint8_t value); | ||
| uint8_t gpio_get_pud(uint8_t pin); | ||
| /** | ||
| * PWM | ||
| */ | ||
| void pwm_init(); | ||
| void pwm_set_pin(uint8_t pin); | ||
@@ -105,6 +112,4 @@ | ||
| */ | ||
| int i2c_start(); | ||
| void i2c_start(uint8_t sel); | ||
| int i2c_init(uint8_t value); | ||
| void i2c_stop(); | ||
@@ -127,3 +132,3 @@ | ||
| */ | ||
| int spi_start(); | ||
| void spi_start(); | ||
@@ -130,0 +135,0 @@ void spi_stop(); |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
1
-66.67%152556
-6.43%3092
-11.05%