├── .gitignore ├── .npmignore ├── samples ├── sysex │ ├── README.md │ ├── sysex_led_blink.js │ ├── SysexLedBlinkFirmata │ │ ├── SysexLedBlinkFirmata.ino │ │ ├── BLEFirmata.h │ │ └── BLEFirmata.cpp │ └── BLEFirmataWithLedBlink │ │ ├── BLEFirmata.h │ │ ├── BLEFirmata.cpp │ │ ├── Boards.h │ │ ├── LICENSE.txt │ │ └── BLEFirmataWithLedBlink.ino ├── server │ ├── README.md │ ├── main.js │ ├── index.html │ └── server.js ├── analog_change.js ├── analog_read.js ├── digital_change.js ├── analog_write.js ├── servo_write.js ├── led_blink.js └── digital_read.js ├── .travis.yml ├── History.txt ├── LICENSE.txt ├── package.json ├── Gruntfile.coffee ├── tests └── test_ble.coffee ├── README.md ├── firmware └── BLEFirmataSketch │ ├── BLEFirmata.h │ ├── BLEFirmata.cpp │ ├── Boards.h │ └── BLEFirmataSketch.ino └── src └── ble-firmata.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *#* 3 | .DS_Store 4 | *.log 5 | tmp 6 | node_modules 7 | lib 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | samples/ 3 | Gruntfile.coffee 4 | circle.yml 5 | .travis.yml 6 | -------------------------------------------------------------------------------- /samples/sysex/README.md: -------------------------------------------------------------------------------- 1 | # Sysex Command Samples 2 | 3 | Sysex 4 | ----- 5 | - http://firmata.org/wiki/V2.1ProtocolDetails#Sysex_Message_Format 6 | -------------------------------------------------------------------------------- /samples/server/README.md: -------------------------------------------------------------------------------- 1 | Server Sample 2 | ============= 3 | 4 | display arduino sensor value via socket.io 5 | 6 | ## Install Dependencies 7 | 8 | % npm install 9 | 10 | 11 | ## Start Server 12 | 13 | % node server.js 14 | 15 | => http://localhost:3000 16 | 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '0.12' 5 | install: node -e 'console.log(Object.keys(require("./package.json").devDependencies).join(" "))' | xargs npm install 6 | script: npm run build 7 | notifications: 8 | slack: 9 | secure: KP6jKLbLDQzOdhNJG8p/yTujpSD7+1aLDOBT6u1xiZWcdbauY8euN55KnpSNxUsqTbJu79cC+Mb3Gji4jNmRaqLsOUWmtFPmqvlvDXMStnl2266shcLcNtzXvY9hZCyoYyuc7Bc20JD2RQPRzMqPycI3U6Y/hj8LQ4cg1lZhXlw= 10 | -------------------------------------------------------------------------------- /samples/sysex/sysex_led_blink.js: -------------------------------------------------------------------------------- 1 | var BLEFirmata = require(__dirname+'/../../'); 2 | // var BLEFirmata = require('ble-firmata'); 3 | 4 | var arduino = new BLEFirmata().connect(); 5 | 6 | arduino.on('connect', function(){ 7 | arduino.sysex(0x01, [13, 5, 2]); // pin13, blink 5 times, 200 msec interval 8 | arduino.sysex(0x01, [12, 3, 10]); // pin12, blink 3 times, 1000 msec interval 9 | }); 10 | 11 | arduino.on('sysex', function(e){ 12 | console.log("command : " + e.command); 13 | console.log("data : " + JSON.stringify(e.data)); 14 | }); 15 | -------------------------------------------------------------------------------- /samples/server/main.js: -------------------------------------------------------------------------------- 1 | var socket = io.connect(location.protocol+"//"+location.hostname) 2 | 3 | socket.on('connect', function(){ 4 | console.log('connect!!'); 5 | 6 | socket.on('analogRead', function(v){ 7 | $("#analog").text(v); 8 | }); 9 | 10 | socket.on('bleState', function(v){ 11 | $("#ble_state").text(v); 12 | }); 13 | }); 14 | 15 | $(function(){ 16 | $("#btn_on").click(function(){ 17 | socket.emit("digitalWrite", true); 18 | }); 19 | 20 | $("#btn_off").click(function(){ 21 | socket.emit("digitalWrite", false); 22 | }); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /samples/analog_change.js: -------------------------------------------------------------------------------- 1 | var BLEFirmata = require(__dirname+'/../'); 2 | // var BLEFirmata = require('ble-firmata'); 3 | 4 | var device_name = process.argv[2] || "BlendMicro"; 5 | 6 | var arduino = new BLEFirmata().connect(device_name); 7 | 8 | arduino.on('connect', function(){ 9 | console.log("connect!!"); 10 | console.log("board version: "+arduino.boardVersion); 11 | }); 12 | 13 | arduino.on('analogChange', function(e){ 14 | if(e.pin != 0) return; 15 | console.log("pin" + e.pin + " : " + e.old_value + " -> " + e.value); 16 | }); 17 | 18 | arduino.on('disconnect', function(){ 19 | console.log("disconnect!"); 20 | }); 21 | -------------------------------------------------------------------------------- /samples/analog_read.js: -------------------------------------------------------------------------------- 1 | var BLEFirmata = require(__dirname+'/../'); 2 | // var BLEFirmata = require('ble-firmata'); 3 | 4 | var device_name = process.argv[2] || "BlendMicro"; 5 | 6 | var arduino = new BLEFirmata().connect(device_name); 7 | 8 | arduino.on('connect', function(){ 9 | console.log("connect!!"); 10 | console.log("board version: "+arduino.boardVersion); 11 | }); 12 | 13 | arduino.once('connect', function(){ 14 | setInterval(function(){ 15 | var an = arduino.analogRead(0); 16 | console.log(an); 17 | }, 300); 18 | }); 19 | 20 | arduino.on('disconnect', function(){ 21 | console.log("disconnect!"); 22 | }); 23 | -------------------------------------------------------------------------------- /samples/digital_change.js: -------------------------------------------------------------------------------- 1 | var BLEFirmata = require(__dirname+'/../'); 2 | // var BLEFirmata = require('ble-firmata'); 3 | 4 | var device_name = process.argv[2] || "BlendMicro"; 5 | 6 | var arduino = new BLEFirmata().connect(device_name); 7 | 8 | arduino.on('connect', function(){ 9 | console.log("connect!!"); 10 | console.log("board version: "+arduino.boardVersion); 11 | 12 | arduino.pinMode(1, BLEFirmata.INPUT); 13 | }); 14 | 15 | arduino.on('digitalChange', function(e){ 16 | console.log("pin" + e.pin + " : " + e.old_value + " -> " + e.value); 17 | }); 18 | 19 | arduino.on('disconnect', function(){ 20 | console.log("disconnect!"); 21 | }); 22 | -------------------------------------------------------------------------------- /samples/analog_write.js: -------------------------------------------------------------------------------- 1 | var BLEFirmata = require(__dirname+'/../'); 2 | // var BLEFirmata = require('ble-firmata'); 3 | 4 | var device_name = process.argv[2] || "BlendMicro"; 5 | 6 | var arduino = new BLEFirmata().connect(device_name); 7 | 8 | arduino.on('connect', function(){ 9 | console.log("connect!!"); 10 | console.log("board version: "+arduino.boardVersion); 11 | }); 12 | 13 | arduino.once('connect', function(){ 14 | setInterval(function(){ 15 | var an = Math.random()*255; 16 | console.log("analog write 9 pin : " + an); 17 | arduino.analogWrite(9, an); 18 | }, 100); 19 | }); 20 | 21 | arduino.on('disconnect', function(){ 22 | console.log("disconnect!"); 23 | }); 24 | -------------------------------------------------------------------------------- /samples/servo_write.js: -------------------------------------------------------------------------------- 1 | var BLEFirmata = require(__dirname+'/../'); 2 | // var BLEFirmata = require('ble-firmata'); 3 | 4 | var device_name = process.argv[2] || "BlendMicro"; 5 | 6 | var arduino = new BLEFirmata().connect(device_name); 7 | 8 | arduino.on('connect', function(){ 9 | console.log("connect!!"); 10 | console.log("board version: "+arduino.boardVersion); 11 | }); 12 | 13 | arduino.once('connect', function(){ 14 | setInterval(function(){ 15 | var angle = Math.random()*180; 16 | console.log("servo write 9 pin : " + angle); 17 | arduino.servoWrite(9, angle); 18 | }, 1000); 19 | }); 20 | 21 | arduino.on('disconnect', function(){ 22 | console.log("disconnect!"); 23 | }); 24 | -------------------------------------------------------------------------------- /samples/led_blink.js: -------------------------------------------------------------------------------- 1 | var BLEFirmata = require(__dirname+'/../'); 2 | // var BLEFirmata = require('ble-firmata'); 3 | 4 | var device_name = process.argv[2] || "BlendMicro"; 5 | 6 | var arduino = new BLEFirmata().connect(device_name); 7 | 8 | arduino.on('connect', function(){ 9 | console.log("connect!!"); 10 | console.log("board version: "+arduino.boardVersion); 11 | }); 12 | 13 | arduino.once('connect', function(){ 14 | var stat = true 15 | setInterval(function(){ 16 | console.log(stat); 17 | arduino.digitalWrite(13, stat); 18 | arduino.digitalWrite(12, !stat); 19 | stat = !stat; // blink 20 | }, 300); 21 | }); 22 | 23 | arduino.on('disconnect', function(){ 24 | console.log("disconnect!"); 25 | }); 26 | -------------------------------------------------------------------------------- /samples/digital_read.js: -------------------------------------------------------------------------------- 1 | var BLEFirmata = require(__dirname+'/../'); 2 | // var BLEFirmata = require('ble-firmata'); 3 | 4 | var device_name = process.argv[2] || "BlendMicro"; 5 | 6 | var arduino = new BLEFirmata().connect(device_name); 7 | 8 | arduino.on('connect', function(){ 9 | console.log("connect!!"); 10 | console.log("board version: "+arduino.boardVersion); 11 | }); 12 | 13 | arduino.once('connect', function(){ 14 | setInterval(function(){ 15 | arduino.pinMode(1, BLEFirmata.INPUT); 16 | var pin_stat = arduino.digitalRead(1); 17 | console.log("pin 1 -> "+pin_stat); 18 | arduino.digitalWrite(13, pin_stat); 19 | }, 100); 20 | }); 21 | 22 | arduino.on('disconnect', function(){ 23 | console.log("disconnect!"); 24 | }); 25 | -------------------------------------------------------------------------------- /samples/server/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ble-firmata 4 | 5 | 6 |

ble-firmata

7 |

8 | BLE state: 9 | 10 |

11 |

12 | digitalWrite 13pin: 13 | 14 | 15 |

16 |

17 | analogRead 0pin: 18 | 19 |

20 |
21 | https://github.com/shokai/node-ble-firmata 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /History.txt: -------------------------------------------------------------------------------- 1 | === 0.2.1 2015-12-09 2 | 3 | * update for blendmicro v0.4.0 4 | 5 | === 0.2.0 2015-10-24 6 | 7 | * bugfixed reconnection #2 8 | 9 | === 0.1.4 2015-07-29 10 | 11 | * update blendmicro npm to support OSX Yosemite 12 | * ignore compiled js from git repos 13 | * ignore src/ and samples/ to push npmjs.com 14 | 15 | === 0.1.3 2014-12-24 16 | 17 | * add method "sendI2CConfig" and "sendI2CWriteRequest" 18 | thank you for contributing @noopkat 19 | 20 | === 0.1.2 2014-06-15 21 | 22 | * fix dependencies 23 | 24 | === 0.1.1 2014-06-14 25 | 26 | * add property BLEFirmata#reconnect to control auto-reconnect #3 27 | 28 | === 0.1.0 2014-06-14 29 | 30 | * re-connect on BLE closed #2 31 | * fix samples 32 | 33 | === 0.0.2 2014-06-14 34 | 35 | * fix samples 36 | * fix firmware for BLE Shield 37 | 38 | === 0.0.1 2014-06-13 39 | 40 | * first release 41 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Sho Hashimoto 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /samples/sysex/SysexLedBlinkFirmata/SysexLedBlinkFirmata.ino: -------------------------------------------------------------------------------- 1 | #define BLE_NAME "BlendMicro" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "BLEFirmata.h" 8 | #include 9 | 10 | void setup() 11 | { 12 | BleFirmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); 13 | BleFirmata.attach(START_SYSEX, sysexCallback); 14 | 15 | ble_set_name(BLE_NAME); 16 | ble_begin(); 17 | } 18 | 19 | void loop() 20 | { 21 | ble_do_events(); 22 | 23 | while(BleFirmata.available()) { 24 | BleFirmata.processInput(); 25 | } 26 | } 27 | 28 | void sysexCallback(byte command, byte argc, byte*argv) 29 | { 30 | switch(command){ 31 | case 0x01: // LED Blink Command 32 | if(argc < 3) break; 33 | byte blink_pin; 34 | byte blink_count; 35 | int delayTime; 36 | blink_pin = argv[0]; 37 | blink_count = argv[1]; 38 | delayTime = argv[2] * 100; 39 | 40 | pinMode(blink_pin, OUTPUT); 41 | byte i; 42 | for(i = 0; i < blink_count; i++){ 43 | digitalWrite(blink_pin, true); 44 | delay(delayTime); 45 | digitalWrite(blink_pin, false); 46 | delay(delayTime); 47 | } 48 | BleFirmata.sendSysex(command, argc, argv); // callback 49 | break; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ble-firmata", 3 | "private": false, 4 | "version": "0.2.1", 5 | "description": "BlendMicro & Arduino BLE-Shield Firmata implementation for Node.js", 6 | "main": "lib/ble-firmata.js", 7 | "scripts": { 8 | "test": "grunt test", 9 | "build": "grunt build", 10 | "watch": "grunt" 11 | }, 12 | "devDependencies": { 13 | "coffee-errors": "*", 14 | "coffee-script": "*", 15 | "async": "*", 16 | "mocha": "*", 17 | "grunt": "*", 18 | "grunt-cli": "*", 19 | "grunt-simple-mocha": "*", 20 | "grunt-notify": "*", 21 | "grunt-contrib-coffee": "*", 22 | "grunt-coffeelint": "*", 23 | "grunt-contrib-watch": "*", 24 | "socket.io": "*" 25 | }, 26 | "keywords": [ 27 | "arduino", 28 | "blendmicro", 29 | "BLE", 30 | "bluetooth", 31 | "firmata" 32 | ], 33 | "author": "Sho Hashimoto ", 34 | "license": "MIT", 35 | "dependencies": { 36 | "blendmicro": ">=0.4.0", 37 | "debug": "*", 38 | "eventemitter2": "*" 39 | }, 40 | "directories": { 41 | "test": "tests" 42 | }, 43 | "repository": { 44 | "type": "git", 45 | "url": "git://github.com/shokai/node-ble-firmata.git" 46 | }, 47 | "bugs": { 48 | "url": "https://github.com/shokai/node-ble-firmata/issues" 49 | }, 50 | "homepage": "https://github.com/shokai/node-ble-firmata" 51 | } 52 | -------------------------------------------------------------------------------- /Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = (grunt) -> 4 | 5 | require 'coffee-errors' 6 | 7 | grunt.loadNpmTasks 'grunt-contrib-coffee' 8 | grunt.loadNpmTasks 'grunt-contrib-watch' 9 | grunt.loadNpmTasks 'grunt-coffeelint' 10 | grunt.loadNpmTasks 'grunt-simple-mocha' 11 | grunt.loadNpmTasks 'grunt-notify' 12 | 13 | grunt.registerTask 'build', [ 'coffeelint', 'coffee' ] 14 | grunt.registerTask 'test', [ 'build', 'simplemocha' ] 15 | grunt.registerTask 'default', [ 'build', 'watch' ] 16 | 17 | grunt.initConfig 18 | 19 | coffeelint: 20 | options: 21 | max_line_length: 22 | value: 119 23 | indentation: 24 | value: 2 25 | newlines_after_classes: 26 | level: 'error' 27 | no_empty_param_list: 28 | level: 'error' 29 | no_unnecessary_fat_arrows: 30 | level: 'ignore' 31 | dist: 32 | files: [ 33 | { expand: yes, cwd: 'src/', src: [ '**/*.coffee' ] } 34 | { expand: yes, cwd: 'tests/', src: [ '**/*.coffee' ] } 35 | ] 36 | 37 | coffee: 38 | dist: 39 | files: [{ 40 | expand: yes 41 | cwd: 'src/' 42 | src: [ '**/*.coffee' ] 43 | dest: 'lib/' 44 | ext: '.js' 45 | }] 46 | 47 | simplemocha: 48 | options: 49 | ui: 'bdd' 50 | reporter: 'spec' 51 | compilers: 'coffee:coffee-script' 52 | ignoreLeaks: no 53 | dist: 54 | src: [ 'tests/test_*.coffee' ] 55 | 56 | watch: 57 | options: 58 | interrupt: yes 59 | dist: 60 | files: [ 'src/**/*.coffee' ] 61 | tasks: [ 'build' ] 62 | -------------------------------------------------------------------------------- /samples/server/server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var fs = require('fs'); 3 | var url = require('url'); 4 | 5 | var app_handler = function(req, res) { 6 | var path, _url; 7 | _url = url.parse(decodeURI(req.url), true); 8 | path = _url.pathname === '/' ? '/index.html' : _url.pathname; 9 | console.log(req.method + " - " + path); 10 | fs.readFile(__dirname + path, function(err, data) { 11 | if (err) { 12 | res.writeHead(500); 13 | res.end('error load file'); 14 | } 15 | res.writeHead(200); 16 | res.end(data); 17 | }); 18 | }; 19 | 20 | var app = http.createServer(app_handler); 21 | var io = require('socket.io').listen(app); 22 | 23 | // var BLEFirmata = require('ble-firmata'); 24 | var BLEFirmata = require('../../'); 25 | arduino = new BLEFirmata().connect(); 26 | 27 | arduino.on('connect', function(){ 28 | console.log('arduino connect!'); 29 | io.sockets.emit('bleState', arduino.state); 30 | }); 31 | 32 | arduino.on('disconnect', function(){ 33 | console.log('arduino disconnect!'); 34 | io.sockets.emit('bleState', arduino.state); 35 | }); 36 | 37 | // emit sensor-value to HTML-side 38 | arduino.on('analogChange', function(e){ 39 | if(e.pin != 0) return; 40 | console.log(e); 41 | io.sockets.emit('analogRead', e.value); 42 | }); 43 | 44 | io.sockets.on('connection', function(socket) { 45 | 46 | socket.emit('bleState', arduino.state); 47 | socket.emit('analogRead', arduino.analogRead(0)); 48 | 49 | // on click button on HTML-side, change LED 50 | socket.on('digitalWrite', function(stat) { 51 | console.log("pin13:"+stat); 52 | arduino.digitalWrite(13, stat); 53 | }); 54 | 55 | }); 56 | 57 | var port = process.argv[2]-0 || 3000; 58 | app.listen(port); 59 | console.log("server start - port:" + port); 60 | console.log(" => http://localhost:"+port) 61 | -------------------------------------------------------------------------------- /tests/test_ble.coffee: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'test' 2 | 3 | path = require 'path' 4 | assert = require 'assert' 5 | async = require 'async' 6 | 7 | BLEFirmata = require path.resolve() 8 | 9 | describe 'instance of BLEFirmata', -> 10 | 11 | arduino = new BLEFirmata() 12 | 13 | it 'should have method "connect"', -> 14 | assert.equal typeof arduino['connect'], 'function' 15 | 16 | 17 | it 'should have method "close"', -> 18 | assert.equal typeof arduino['close'], 'function' 19 | 20 | 21 | it 'should have method "isOpen"', -> 22 | assert.equal typeof arduino['isOpen'], 'function' 23 | 24 | 25 | it 'should emit "connect" event', (done) -> 26 | @timeout 10000 27 | arduino.connect() 28 | arduino.on 'connect', -> 29 | assert.equal arduino.isOpen(), true 30 | done() 31 | assert.equal arduino.isOpen(), false 32 | 33 | 34 | it 'should have property "boardVersion"', -> 35 | assert.ok arduino.boardVersion.match(/^\d+\.\d+$/) 36 | 37 | 38 | it 'should have method "pinMode"', -> 39 | assert.equal typeof arduino['pinMode'], 'function' 40 | 41 | 42 | it 'should have method "digitalWrite"', -> 43 | assert.equal typeof arduino['digitalWrite'], 'function' 44 | 45 | describe 'method "digitalWrite"', -> 46 | 47 | it 'output digital', -> 48 | for i in [0..13] 49 | arduino.digitalWrite(i, true) 50 | arduino.digitalWrite(i, false) 51 | 52 | 53 | it 'should have method "analogWrite"', -> 54 | assert.equal typeof arduino['analogWrite'], 'function' 55 | 56 | describe 'method "analogWrite"', -> 57 | 58 | it 'output analog', -> 59 | for i in [0..13] 60 | out = Math.random()*256 61 | arduino.analogWrite(i, out) 62 | arduino.analogWrite(i, out) 63 | 64 | 65 | it 'should have method "servoWrite"', -> 66 | assert.equal typeof arduino['servoWrite'], 'function' 67 | 68 | describe 'method "servoWrite"', -> 69 | 70 | it 'output servo angle', -> 71 | for i in [0..13] 72 | out = Math.random()*180 73 | arduino.servoWrite(i, out) 74 | arduino.servoWrite(i, out) 75 | 76 | 77 | it 'should have method "digitalRead"', -> 78 | assert.equal typeof arduino['digitalRead'], 'function' 79 | 80 | describe 'method "digitalRead"', -> 81 | 82 | it 'should return value true or false', -> 83 | for i in [0..13] 84 | stat = arduino.digitalRead(i) 85 | assert.ok ((stat is true) or (stat is false)) 86 | 87 | 88 | it 'should have method "analogRead"', -> 89 | assert.equal typeof arduino['analogRead'], 'function' 90 | 91 | describe 'method "analogRead"', -> 92 | 93 | it 'should return value 0~1023', -> 94 | for i in [0..5] 95 | val = arduino.analogRead(i) 96 | assert.ok (0 <= val and val < 1024) 97 | 98 | 99 | it 'should have method "sysex"', -> 100 | assert.equal typeof arduino['sysex'], 'function' 101 | 102 | describe 'method "sysex"', -> 103 | 104 | it 'should send sysex command', (done) -> 105 | arduino.on 'sysex', (e) -> 106 | assert e.command, 0x01 107 | assert e.data, [0x01, 0, 3, 0, 2] 108 | done() 109 | arduino.sysex 0x01, [13,3,2] 110 | 111 | it 'should have method "sendI2CConfig"', -> 112 | assert.equal typeof arduino['sendI2CConfig'], 'function' 113 | 114 | describe 'method "sendI2CConfig"', -> 115 | 116 | it 'should send I2C config command', -> 117 | arduino.sendI2CConfig 118 | 119 | it 'should have method "sendI2CWriteRequest"', -> 120 | assert.equal typeof arduino['sendI2CWriteRequest'], 'function' 121 | 122 | describe 'method "sendI2CWriteRequest"', -> 123 | 124 | it 'should send I2C write request command', -> 125 | arduino.sendI2CWriteRequest 0x3D, [13,3,2] 126 | 127 | describe 'method "close"', -> 128 | 129 | it 'should close BLE connection', (done) -> 130 | arduino.close -> 131 | done() 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BLE Firmata 2 | =========== 3 | Arduino [Firmata](http://firmata.org) implementation on BLE (Bluetooth Low Energy) and Node.js. 4 | 5 | [![Build Status](https://travis-ci.org/shokai/node-ble-firmata.svg?branch=master)](https://travis-ci.org/shokai/node-ble-firmata) 6 | 7 | - Firmata is a protocol to controll Arduino from software on PC. 8 | - You can embed Arduino code into Node.js application. 9 | - supports [BlendMicro](http://redbearlab.squarespace.com/blendmicro/). 10 | - also should works on [BLE Shield](http://redbearlab.squarespace.com/bleshield/), but I dont't have it. 11 | 12 | 13 | sites 14 | 15 | - https://github.com/shokai/node-ble-firmata 16 | - https://npmjs.org/package/ble-firmata 17 | 18 | 19 | Install 20 | ------- 21 | 22 | % npm install ble-firmata 23 | 24 | 25 | Requirements 26 | ------------ 27 | 28 | - [BlendMicro](http://redbearlab.squarespace.com/blendmicro) 29 | - you have to check pin function. pin 4/6/7 are reserved for BLE controll. 30 | - Install [patched Standard Firmata v2.3](./firmware/BLEFirmataSketch/BLEFirmataSketch.ino) to BlendMicro 31 | - fix `#define BLE_NAME "BlendMicro"` if you need. 32 | - [download zip](https://github.com/shokai/node-ble-firmata/archive/master.zip) 33 | 34 | 35 | Usage 36 | ----- 37 | 38 | ### Samples 39 | 40 | - https://github.com/shokai/ble-arduino-firmata/tree/master/samples 41 | 42 | 43 | ### Setup 44 | 45 | Connect 46 | ```javascript 47 | var BLEFirmata = require('ble-firmata'); 48 | var arduino = new BLEFirmata(); 49 | 50 | // search device with BLE peripheral name 51 | arduino.connect("BlendMicro"); 52 | 53 | // search with default name "BlendMicro" 54 | arduino.connect(); 55 | 56 | arduino.on('connect', function(){ 57 | 58 | console.log("board version"+arduino.boardVersion); 59 | // your-code-here 60 | 61 | }); 62 | ``` 63 | 64 | Reset 65 | ```javascript 66 | arduino.reset(callback); 67 | ``` 68 | 69 | Close 70 | ```javascript 71 | arduino.close(callback); 72 | ``` 73 | 74 | 75 | ### I/O 76 | 77 | Digital Write 78 | ```javascript 79 | arduino.digitalWrite(13, true, callback); 80 | arduino.digitalWrite(13, false, callback); 81 | ``` 82 | 83 | Digital Read 84 | ```javascript 85 | arduino.pinMode(1, BLEFirmata.INPUT); 86 | console.log( arduino.digitalRead(1) ); // => true/false 87 | ``` 88 | 89 | Digital Read (event) 90 | ```javascript 91 | arduino.pinMode(1, BLEFirmata.INPUT); 92 | 93 | arduino.on('digitalChange', function(e){ 94 | console.log("pin" + e.pin + " : " + e.old_value + " -> " + e.value); 95 | }); 96 | ``` 97 | 98 | Analog Write (PWM) 99 | ``` 100 | setInterval(function(){ 101 | var an = Math.random()*255; // 0 ~ 255 102 | arduino.analogWrite(9, an, callback); 103 | }, 100); 104 | ``` 105 | 106 | Analog Read 107 | ```javascript 108 | console.log( arduino.analogRead(0) ); // => 0 ~ 1023 109 | ``` 110 | 111 | Analog Read (event) 112 | ```javascript 113 | arduino.on('analogChange', function(e){ 114 | console.log("pin" + e.pin + " : " + e.old_value + " -> " + e.value); 115 | }); 116 | ``` 117 | 118 | Servo Motor 119 | ```javascript 120 | setInterval(function(){ 121 | var angle = Math.random()*180; // 0 ~ 180 122 | arduino.servoWrite(11, angle, callback); 123 | }, 1000); 124 | ``` 125 | 126 | ### Sysex 127 | 128 | - http://firmata.org/wiki/V2.1ProtocolDetails#Sysex_Message_Format 129 | - https://github.com/shokai/ble-arduino-firmata/tree/master/samples/sysex 130 | 131 | Send 132 | ```javascript 133 | arduino.sysex(0x01, [13, 5, 2], callback); // command, data_array, callback 134 | ``` 135 | 136 | Register Sysex Event 137 | ```javascript 138 | arduino.on('sysex', function(e){ 139 | console.log("command : " + e.command); 140 | console.log(e.data); 141 | }); 142 | ``` 143 | 144 | Debug 145 | ----- 146 | 147 | set `DEBUG` env var 148 | 149 | % DEBUG=ble-firmata node samples/analog_write.js 150 | % DEBUG=*ble* node samples/analog_write.js 151 | 152 | Test 153 | ---- 154 | 155 | ### Install SysexLedBlinkFirmata into Arduino 156 | 157 | * https://github.com/shokai/node-ble-firmata/blob/master/samples/sysex/BLEFirmataWithLedBlink/BLEFirmataWithLedBlink.ino 158 | 159 | 160 | ### Run Test 161 | 162 | % npm install 163 | % npm test 164 | 165 | 166 | Contributing 167 | ------------ 168 | 1. Fork it 169 | 2. Create your feature branch (`git checkout -b my-new-feature`) 170 | 3. Commit your changes (`git commit -am 'Add some feature'`) 171 | 4. Push to the branch (`git push origin my-new-feature`) 172 | 5. Create new Pull Request 173 | -------------------------------------------------------------------------------- /firmware/BLEFirmataSketch/BLEFirmata.h: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.h - Firmata library 3 | Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | See file LICENSE.txt for further informations on licensing terms. 11 | */ 12 | 13 | #ifndef BleFirmata_h 14 | #define BleFirmata_h 15 | 16 | #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ 17 | 18 | /* Version numbers for the protocol. The protocol is still changing, so these 19 | * version numbers are important. This number can be queried so that host 20 | * software can test whether it will be compatible with the currently 21 | * installed firmware. */ 22 | #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes 23 | #define FIRMATA_MINOR_VERSION 3 // for backwards compatible changes 24 | #define FIRMATA_BUGFIX_VERSION 1 // for bugfix releases 25 | 26 | #define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages 27 | 28 | // message command bytes (128-255/0x80-0xFF) 29 | #define DIGITAL_MESSAGE 0x90 // send data for a digital pin 30 | #define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) 31 | #define REPORT_ANALOG 0xC0 // enable analog input by pin # 32 | #define REPORT_DIGITAL 0xD0 // enable digital input by port pair 33 | // 34 | #define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc 35 | // 36 | #define REPORT_VERSION 0xF9 // report protocol version 37 | #define SYSTEM_RESET 0xFF // reset from MIDI 38 | // 39 | #define START_SYSEX 0xF0 // start a MIDI Sysex message 40 | #define END_SYSEX 0xF7 // end a MIDI Sysex message 41 | 42 | // extended command set using sysex (0-127/0x00-0x7F) 43 | /* 0x00-0x0F reserved for user-defined commands */ 44 | #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq 45 | #define STRING_DATA 0x71 // a string message with 14-bits per char 46 | #define SHIFT_DATA 0x75 // a bitstream to/from a shift register 47 | #define I2C_REQUEST 0x76 // send an I2C read/write request 48 | #define I2C_REPLY 0x77 // a reply to an I2C read request 49 | #define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins 50 | #define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin 51 | #define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value 52 | #define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value 53 | #define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins 54 | #define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution 55 | #define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers 56 | #define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info 57 | #define REPORT_FIRMWARE 0x79 // report name and version of the firmware 58 | #define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop 59 | #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages 60 | #define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages 61 | // these are DEPRECATED to make the naming more consistent 62 | #define FIRMATA_STRING 0x71 // same as STRING_DATA 63 | #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST 64 | #define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY 65 | #define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL 66 | 67 | // pin modes 68 | //#define INPUT 0x00 // defined in wiring.h 69 | //#define OUTPUT 0x01 // defined in wiring.h 70 | #define ANALOG 0x02 // analog pin in analogInput mode 71 | #define PWM 0x03 // digital pin in PWM output mode 72 | #define SERVO 0x04 // digital pin in Servo output mode 73 | #define SHIFT 0x05 // shiftIn/shiftOut mode 74 | #define I2C 0x06 // pin included in I2C setup 75 | #define TOTAL_PIN_MODES 7 76 | 77 | extern "C" { 78 | // callback function types 79 | typedef void (*callbackFunction)(byte, int); 80 | typedef void (*systemResetCallbackFunction)(void); 81 | typedef void (*stringCallbackFunction)(char*); 82 | typedef void (*sysexCallbackFunction)(byte command, byte argc, byte*argv); 83 | } 84 | 85 | 86 | // TODO make it a subclass of a generic Serial/Stream base class 87 | class BleFirmataClass 88 | { 89 | public: 90 | BleFirmataClass(Stream &s); 91 | /* Arduino constructors */ 92 | void begin(); 93 | void begin(long); 94 | void begin(Stream &s); 95 | /* querying functions */ 96 | void printVersion(void); 97 | void blinkVersion(void); 98 | void printFirmwareVersion(void); 99 | //void setFirmwareVersion(byte major, byte minor); // see macro below 100 | void setFirmwareNameAndVersion(const char *name, byte major, byte minor); 101 | /* serial receive handling */ 102 | int available(void); 103 | void processInput(void); 104 | /* serial send handling */ 105 | void sendAnalog(byte pin, int value); 106 | void sendDigital(byte pin, int value); // TODO implement this 107 | void sendDigitalPort(byte portNumber, int portData); 108 | void sendString(const char* string); 109 | void sendString(byte command, const char* string); 110 | void sendSysex(byte command, byte bytec, byte* bytev); 111 | /* attach & detach callback functions to messages */ 112 | void attach(byte command, callbackFunction newFunction); 113 | void attach(byte command, systemResetCallbackFunction newFunction); 114 | void attach(byte command, stringCallbackFunction newFunction); 115 | void attach(byte command, sysexCallbackFunction newFunction); 116 | void detach(byte command); 117 | 118 | private: 119 | Stream &BleFirmataSerial; 120 | /* firmware name and version */ 121 | byte firmwareVersionCount; 122 | byte *firmwareVersionVector; 123 | /* input message handling */ 124 | byte waitForData; // this flag says the next serial input will be data 125 | byte executeMultiByteCommand; // execute this after getting multi-byte data 126 | byte multiByteChannel; // channel data for multiByteCommands 127 | byte storedInputData[MAX_DATA_BYTES]; // multi-byte data 128 | /* sysex */ 129 | boolean parsingSysex; 130 | int sysexBytesRead; 131 | /* callback functions */ 132 | callbackFunction currentAnalogCallback; 133 | callbackFunction currentDigitalCallback; 134 | callbackFunction currentReportAnalogCallback; 135 | callbackFunction currentReportDigitalCallback; 136 | callbackFunction currentPinModeCallback; 137 | systemResetCallbackFunction currentSystemResetCallback; 138 | stringCallbackFunction currentStringCallback; 139 | sysexCallbackFunction currentSysexCallback; 140 | 141 | /* private methods ------------------------------ */ 142 | void processSysexMessage(void); 143 | void systemReset(void); 144 | void pin13strobe(int count, int onInterval, int offInterval); 145 | void sendValueAsTwo7bitBytes(int value); 146 | void startSysex(void); 147 | void endSysex(void); 148 | }; 149 | 150 | extern BleFirmataClass BleFirmata; 151 | 152 | /*============================================================================== 153 | * MACROS 154 | *============================================================================*/ 155 | 156 | /* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the 157 | * firmware name. It needs to be a macro so that __FILE__ is included in the 158 | * firmware source file rather than the library source file. 159 | */ 160 | #define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y) 161 | 162 | #endif /* Firmata_h */ 163 | 164 | -------------------------------------------------------------------------------- /samples/sysex/SysexLedBlinkFirmata/BLEFirmata.h: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.h - Firmata library 3 | Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | See file LICENSE.txt for further informations on licensing terms. 11 | */ 12 | 13 | #ifndef BleFirmata_h 14 | #define BleFirmata_h 15 | 16 | #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ 17 | 18 | /* Version numbers for the protocol. The protocol is still changing, so these 19 | * version numbers are important. This number can be queried so that host 20 | * software can test whether it will be compatible with the currently 21 | * installed firmware. */ 22 | #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes 23 | #define FIRMATA_MINOR_VERSION 3 // for backwards compatible changes 24 | #define FIRMATA_BUGFIX_VERSION 1 // for bugfix releases 25 | 26 | #define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages 27 | 28 | // message command bytes (128-255/0x80-0xFF) 29 | #define DIGITAL_MESSAGE 0x90 // send data for a digital pin 30 | #define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) 31 | #define REPORT_ANALOG 0xC0 // enable analog input by pin # 32 | #define REPORT_DIGITAL 0xD0 // enable digital input by port pair 33 | // 34 | #define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc 35 | // 36 | #define REPORT_VERSION 0xF9 // report protocol version 37 | #define SYSTEM_RESET 0xFF // reset from MIDI 38 | // 39 | #define START_SYSEX 0xF0 // start a MIDI Sysex message 40 | #define END_SYSEX 0xF7 // end a MIDI Sysex message 41 | 42 | // extended command set using sysex (0-127/0x00-0x7F) 43 | /* 0x00-0x0F reserved for user-defined commands */ 44 | #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq 45 | #define STRING_DATA 0x71 // a string message with 14-bits per char 46 | #define SHIFT_DATA 0x75 // a bitstream to/from a shift register 47 | #define I2C_REQUEST 0x76 // send an I2C read/write request 48 | #define I2C_REPLY 0x77 // a reply to an I2C read request 49 | #define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins 50 | #define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin 51 | #define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value 52 | #define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value 53 | #define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins 54 | #define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution 55 | #define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers 56 | #define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info 57 | #define REPORT_FIRMWARE 0x79 // report name and version of the firmware 58 | #define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop 59 | #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages 60 | #define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages 61 | // these are DEPRECATED to make the naming more consistent 62 | #define FIRMATA_STRING 0x71 // same as STRING_DATA 63 | #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST 64 | #define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY 65 | #define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL 66 | 67 | // pin modes 68 | //#define INPUT 0x00 // defined in wiring.h 69 | //#define OUTPUT 0x01 // defined in wiring.h 70 | #define ANALOG 0x02 // analog pin in analogInput mode 71 | #define PWM 0x03 // digital pin in PWM output mode 72 | #define SERVO 0x04 // digital pin in Servo output mode 73 | #define SHIFT 0x05 // shiftIn/shiftOut mode 74 | #define I2C 0x06 // pin included in I2C setup 75 | #define TOTAL_PIN_MODES 7 76 | 77 | extern "C" { 78 | // callback function types 79 | typedef void (*callbackFunction)(byte, int); 80 | typedef void (*systemResetCallbackFunction)(void); 81 | typedef void (*stringCallbackFunction)(char*); 82 | typedef void (*sysexCallbackFunction)(byte command, byte argc, byte*argv); 83 | } 84 | 85 | 86 | // TODO make it a subclass of a generic Serial/Stream base class 87 | class BleFirmataClass 88 | { 89 | public: 90 | BleFirmataClass(Stream &s); 91 | /* Arduino constructors */ 92 | void begin(); 93 | void begin(long); 94 | void begin(Stream &s); 95 | /* querying functions */ 96 | void printVersion(void); 97 | void blinkVersion(void); 98 | void printFirmwareVersion(void); 99 | //void setFirmwareVersion(byte major, byte minor); // see macro below 100 | void setFirmwareNameAndVersion(const char *name, byte major, byte minor); 101 | /* serial receive handling */ 102 | int available(void); 103 | void processInput(void); 104 | /* serial send handling */ 105 | void sendAnalog(byte pin, int value); 106 | void sendDigital(byte pin, int value); // TODO implement this 107 | void sendDigitalPort(byte portNumber, int portData); 108 | void sendString(const char* string); 109 | void sendString(byte command, const char* string); 110 | void sendSysex(byte command, byte bytec, byte* bytev); 111 | /* attach & detach callback functions to messages */ 112 | void attach(byte command, callbackFunction newFunction); 113 | void attach(byte command, systemResetCallbackFunction newFunction); 114 | void attach(byte command, stringCallbackFunction newFunction); 115 | void attach(byte command, sysexCallbackFunction newFunction); 116 | void detach(byte command); 117 | 118 | private: 119 | Stream &BleFirmataSerial; 120 | /* firmware name and version */ 121 | byte firmwareVersionCount; 122 | byte *firmwareVersionVector; 123 | /* input message handling */ 124 | byte waitForData; // this flag says the next serial input will be data 125 | byte executeMultiByteCommand; // execute this after getting multi-byte data 126 | byte multiByteChannel; // channel data for multiByteCommands 127 | byte storedInputData[MAX_DATA_BYTES]; // multi-byte data 128 | /* sysex */ 129 | boolean parsingSysex; 130 | int sysexBytesRead; 131 | /* callback functions */ 132 | callbackFunction currentAnalogCallback; 133 | callbackFunction currentDigitalCallback; 134 | callbackFunction currentReportAnalogCallback; 135 | callbackFunction currentReportDigitalCallback; 136 | callbackFunction currentPinModeCallback; 137 | systemResetCallbackFunction currentSystemResetCallback; 138 | stringCallbackFunction currentStringCallback; 139 | sysexCallbackFunction currentSysexCallback; 140 | 141 | /* private methods ------------------------------ */ 142 | void processSysexMessage(void); 143 | void systemReset(void); 144 | void pin13strobe(int count, int onInterval, int offInterval); 145 | void sendValueAsTwo7bitBytes(int value); 146 | void startSysex(void); 147 | void endSysex(void); 148 | }; 149 | 150 | extern BleFirmataClass BleFirmata; 151 | 152 | /*============================================================================== 153 | * MACROS 154 | *============================================================================*/ 155 | 156 | /* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the 157 | * firmware name. It needs to be a macro so that __FILE__ is included in the 158 | * firmware source file rather than the library source file. 159 | */ 160 | #define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y) 161 | 162 | #endif /* Firmata_h */ 163 | 164 | -------------------------------------------------------------------------------- /samples/sysex/BLEFirmataWithLedBlink/BLEFirmata.h: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.h - Firmata library 3 | Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | See file LICENSE.txt for further informations on licensing terms. 11 | */ 12 | 13 | #ifndef BleFirmata_h 14 | #define BleFirmata_h 15 | 16 | #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ 17 | 18 | /* Version numbers for the protocol. The protocol is still changing, so these 19 | * version numbers are important. This number can be queried so that host 20 | * software can test whether it will be compatible with the currently 21 | * installed firmware. */ 22 | #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes 23 | #define FIRMATA_MINOR_VERSION 3 // for backwards compatible changes 24 | #define FIRMATA_BUGFIX_VERSION 1 // for bugfix releases 25 | 26 | #define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages 27 | 28 | // message command bytes (128-255/0x80-0xFF) 29 | #define DIGITAL_MESSAGE 0x90 // send data for a digital pin 30 | #define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) 31 | #define REPORT_ANALOG 0xC0 // enable analog input by pin # 32 | #define REPORT_DIGITAL 0xD0 // enable digital input by port pair 33 | // 34 | #define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc 35 | // 36 | #define REPORT_VERSION 0xF9 // report protocol version 37 | #define SYSTEM_RESET 0xFF // reset from MIDI 38 | // 39 | #define START_SYSEX 0xF0 // start a MIDI Sysex message 40 | #define END_SYSEX 0xF7 // end a MIDI Sysex message 41 | 42 | // extended command set using sysex (0-127/0x00-0x7F) 43 | /* 0x00-0x0F reserved for user-defined commands */ 44 | #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq 45 | #define STRING_DATA 0x71 // a string message with 14-bits per char 46 | #define SHIFT_DATA 0x75 // a bitstream to/from a shift register 47 | #define I2C_REQUEST 0x76 // send an I2C read/write request 48 | #define I2C_REPLY 0x77 // a reply to an I2C read request 49 | #define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins 50 | #define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin 51 | #define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value 52 | #define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value 53 | #define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins 54 | #define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution 55 | #define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers 56 | #define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info 57 | #define REPORT_FIRMWARE 0x79 // report name and version of the firmware 58 | #define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop 59 | #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages 60 | #define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages 61 | // these are DEPRECATED to make the naming more consistent 62 | #define FIRMATA_STRING 0x71 // same as STRING_DATA 63 | #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST 64 | #define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY 65 | #define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL 66 | 67 | // pin modes 68 | //#define INPUT 0x00 // defined in wiring.h 69 | //#define OUTPUT 0x01 // defined in wiring.h 70 | #define ANALOG 0x02 // analog pin in analogInput mode 71 | #define PWM 0x03 // digital pin in PWM output mode 72 | #define SERVO 0x04 // digital pin in Servo output mode 73 | #define SHIFT 0x05 // shiftIn/shiftOut mode 74 | #define I2C 0x06 // pin included in I2C setup 75 | #define TOTAL_PIN_MODES 7 76 | 77 | extern "C" { 78 | // callback function types 79 | typedef void (*callbackFunction)(byte, int); 80 | typedef void (*systemResetCallbackFunction)(void); 81 | typedef void (*stringCallbackFunction)(char*); 82 | typedef void (*sysexCallbackFunction)(byte command, byte argc, byte*argv); 83 | } 84 | 85 | 86 | // TODO make it a subclass of a generic Serial/Stream base class 87 | class BleFirmataClass 88 | { 89 | public: 90 | BleFirmataClass(Stream &s); 91 | /* Arduino constructors */ 92 | void begin(); 93 | void begin(long); 94 | void begin(Stream &s); 95 | /* querying functions */ 96 | void printVersion(void); 97 | void blinkVersion(void); 98 | void printFirmwareVersion(void); 99 | //void setFirmwareVersion(byte major, byte minor); // see macro below 100 | void setFirmwareNameAndVersion(const char *name, byte major, byte minor); 101 | /* serial receive handling */ 102 | int available(void); 103 | void processInput(void); 104 | /* serial send handling */ 105 | void sendAnalog(byte pin, int value); 106 | void sendDigital(byte pin, int value); // TODO implement this 107 | void sendDigitalPort(byte portNumber, int portData); 108 | void sendString(const char* string); 109 | void sendString(byte command, const char* string); 110 | void sendSysex(byte command, byte bytec, byte* bytev); 111 | /* attach & detach callback functions to messages */ 112 | void attach(byte command, callbackFunction newFunction); 113 | void attach(byte command, systemResetCallbackFunction newFunction); 114 | void attach(byte command, stringCallbackFunction newFunction); 115 | void attach(byte command, sysexCallbackFunction newFunction); 116 | void detach(byte command); 117 | 118 | private: 119 | Stream &BleFirmataSerial; 120 | /* firmware name and version */ 121 | byte firmwareVersionCount; 122 | byte *firmwareVersionVector; 123 | /* input message handling */ 124 | byte waitForData; // this flag says the next serial input will be data 125 | byte executeMultiByteCommand; // execute this after getting multi-byte data 126 | byte multiByteChannel; // channel data for multiByteCommands 127 | byte storedInputData[MAX_DATA_BYTES]; // multi-byte data 128 | /* sysex */ 129 | boolean parsingSysex; 130 | int sysexBytesRead; 131 | /* callback functions */ 132 | callbackFunction currentAnalogCallback; 133 | callbackFunction currentDigitalCallback; 134 | callbackFunction currentReportAnalogCallback; 135 | callbackFunction currentReportDigitalCallback; 136 | callbackFunction currentPinModeCallback; 137 | systemResetCallbackFunction currentSystemResetCallback; 138 | stringCallbackFunction currentStringCallback; 139 | sysexCallbackFunction currentSysexCallback; 140 | 141 | /* private methods ------------------------------ */ 142 | void processSysexMessage(void); 143 | void systemReset(void); 144 | void pin13strobe(int count, int onInterval, int offInterval); 145 | void sendValueAsTwo7bitBytes(int value); 146 | void startSysex(void); 147 | void endSysex(void); 148 | }; 149 | 150 | extern BleFirmataClass BleFirmata; 151 | 152 | /*============================================================================== 153 | * MACROS 154 | *============================================================================*/ 155 | 156 | /* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the 157 | * firmware name. It needs to be a macro so that __FILE__ is included in the 158 | * firmware source file rather than the library source file. 159 | */ 160 | #define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y) 161 | 162 | #endif /* Firmata_h */ 163 | 164 | -------------------------------------------------------------------------------- /src/ble-firmata.coffee: -------------------------------------------------------------------------------- 1 | events = require 'eventemitter2' 2 | BlendMicro = require 'blendmicro' 3 | 4 | debug = require('debug')('ble-firmata') 5 | 6 | exports = module.exports = class BLEFirmata extends events.EventEmitter2 7 | 8 | @INPUT = 0 9 | @OUTPUT = 1 10 | @ANALOG = 2 11 | @PWM = 3 12 | @SERVO = 4 13 | @SHIFT = 5 14 | @I2C = 6 15 | @LOW = 0 16 | @HIGH = 1 17 | 18 | @MAX_DATA_BYTES = 32 19 | @DIGITAL_MESSAGE = 0x90 # send data for a digital port 20 | @ANALOG_MESSAGE = 0xE0 # send data for an analog pin (or PWM) 21 | @REPORT_ANALOG = 0xC0 # enable analog input by pin 22 | @REPORT_DIGITAL = 0xD0 # enable digital input by port 23 | @SET_PIN_MODE = 0xF4 # set a pin to INPUT/OUTPUT/PWM/etc 24 | @REPORT_VERSION = 0xF9 # report firmware version 25 | @SYSTEM_RESET = 0xFF # reset from MIDI 26 | @START_SYSEX = 0xF0 # start a MIDI SysEx message 27 | @END_SYSEX = 0xF7 # end a MIDI SysEx message 28 | 29 | @I2C_REQUEST = 0x76 30 | @I2C_REPLY = 0x77 31 | @I2C_CONFIG = 0x78 32 | 33 | @I2C_MODES = { 34 | WRITE: 0x00, 35 | READ: 1, 36 | CONTINUOUS_READ: 2, 37 | STOP_READING: 3 38 | } 39 | 40 | constructor: -> 41 | @ble = null 42 | @state = 'close' 43 | @wait_for_data = 0 44 | @execute_multi_byte_command = 0 45 | @multi_byte_channel = 0 46 | @stored_input_data = [] 47 | @parsing_sysex = false 48 | @sysex_bytes_read = 0 49 | @digital_output_data = [0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0] 50 | @digital_input_data = [0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0] 51 | @analog_input_data = [0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0] 52 | @boardVersion = null 53 | 54 | @__defineGetter__ "reconnect", => 55 | return @ble?.reconnect 56 | 57 | @__defineSetter__ "reconnect", (enable) => 58 | @ble?.reconnect = enable 59 | 60 | @on 'boardReady', -> 61 | debug "boardReady \"#{@peripheralName}\"" 62 | io_init_wait = 100 63 | debug "wait #{io_init_wait}(msec)" 64 | setTimeout => 65 | for i in [0...6] 66 | @write [(BLEFirmata.REPORT_ANALOG | i), 1] 67 | for i in [0...2] 68 | @write [(BLEFirmata.REPORT_DIGITAL | i), 1] 69 | debug 'init IO ports' 70 | @emit 'connect' 71 | , io_init_wait 72 | 73 | connect: (@peripheralName = "BlendMicro") -> 74 | return if @state isnt "close" 75 | 76 | debug "connect(#{@peripheralName})" 77 | if @ble is null 78 | @ble = new BlendMicro @peripheralName 79 | else 80 | @ble.open @peripheralName 81 | 82 | @ble.on 'open', => 83 | debug 'BLE open' 84 | timer_report_version = setInterval => 85 | debug 'request REPORT_VERSION' 86 | @force_write [BLEFirmata.REPORT_VERSION] 87 | , 1000 88 | 89 | @once 'boardVersion', (version) => 90 | clearInterval timer_report_version 91 | @state = 'open' 92 | @emit 'boardReady' 93 | 94 | @ble.on 'data', (data) => 95 | for byte in data 96 | @process_input byte 97 | 98 | @ble.once 'close', => 99 | @state = 'close' 100 | clearInterval timer_report_version 101 | debug 'BLE close' 102 | @emit 'disconnect' 103 | 104 | return @ 105 | 106 | isOpen: -> 107 | return @state is 'open' 108 | 109 | close: (callback) -> 110 | debug 'close' 111 | @state = 'close' 112 | @ble.removeAllListeners() 113 | @ble.close callback 114 | 115 | reset: (callback) -> 116 | @write [BLEFirmata.SYSTEM_RESET], callback 117 | 118 | write: (bytes, callback) -> 119 | return if @state isnt 'open' 120 | @force_write bytes, callback 121 | 122 | force_write: (bytes, callback) -> 123 | try 124 | unless @ble.state is 'open' 125 | return 126 | @ble.write bytes, callback 127 | catch err 128 | @ble.close 129 | 130 | sysex: (command, data=[], callback) -> 131 | ## http://firmata.org/wiki/V2.1ProtocolDetails#Sysex_Message_Format 132 | data = data.map (i) -> i & 0b1111111 # 7bit 133 | write_data = [BLEFirmata.START_SYSEX, command].concat data, [BLEFirmata.END_SYSEX] 134 | @write write_data, callback 135 | 136 | sendI2CConfig: (delay=0, callback) -> 137 | data = [delay, delay >>> 8] 138 | data = data.map (i) -> i & 0b11111111 # 7bit 139 | write_data = [BLEFirmata.START_SYSEX, BLEFirmata.I2C_CONFIG].concat data, [BLEFirmata.END_SYSEX] 140 | @write write_data, callback 141 | 142 | sendI2CWriteRequest: (slaveAddress, bytes, callback) -> 143 | data = [slaveAddress, BLEFirmata.I2C_MODES.WRITE << 3] 144 | bytes.map (i) -> 145 | data.push i, i >>> 7 146 | @sysex BLEFirmata.I2C_REQUEST, data, callback 147 | 148 | pinMode: (pin, mode, callback) -> 149 | switch mode 150 | when true 151 | mode = BLEFirmata.OUTPUT 152 | when false 153 | mode = BLEFirmata.INPUT 154 | @write [BLEFirmata.SET_PIN_MODE, pin, mode], callback 155 | 156 | digitalWrite: (pin, value, callback) -> 157 | @pinMode pin, BLEFirmata.OUTPUT 158 | port_num = (pin >>> 3) & 0x0F 159 | if value is 0 or value is false 160 | @digital_output_data[port_num] &= ~(1 << (pin & 0x07)) 161 | else 162 | @digital_output_data[port_num] |= (1 << (pin & 0x07)) 163 | @write [ (BLEFirmata.DIGITAL_MESSAGE | port_num), 164 | (@digital_output_data[port_num] & 0x7F), 165 | (@digital_output_data[port_num] >>> 7) ], 166 | callback 167 | 168 | analogWrite: (pin, value, callback) -> 169 | value = Math.floor value 170 | @pinMode pin, BLEFirmata.PWM 171 | @write [ (BLEFirmata.ANALOG_MESSAGE | (pin & 0x0F)), 172 | (value & 0x7F), 173 | (value >>> 7) ], 174 | callback 175 | 176 | servoWrite: (pin, angle, callback) -> 177 | @pinMode pin, BLEFirmata.SERVO 178 | @write [ (BLEFirmata.ANALOG_MESSAGE | (pin & 0x0F)), 179 | (angle & 0x7F), 180 | (angle >>> 7) ], 181 | callback 182 | 183 | digitalRead: (pin) -> 184 | return ((@digital_input_data[pin >>> 3] >>> (pin & 0x07)) & 0x01) > 0 185 | 186 | analogRead: (pin) -> 187 | return @analog_input_data[pin] 188 | 189 | process_input: (input_data) -> 190 | if @parsing_sysex 191 | if input_data is BLEFirmata.END_SYSEX 192 | @parsing_sysex = false 193 | sysex_command = @stored_input_data[0] 194 | sysex_data = @stored_input_data[1...@sysex_bytes_read] 195 | @emit 'sysex', {command: sysex_command, data: sysex_data} 196 | else 197 | @stored_input_data[@sysex_bytes_read] = input_data 198 | @sysex_bytes_read += 1 199 | else if @wait_for_data > 0 and input_data < 128 200 | @wait_for_data -= 1 201 | @stored_input_data[@wait_for_data] = input_data 202 | if @execute_multi_byte_command isnt 0 and @wait_for_data is 0 203 | switch @execute_multi_byte_command 204 | when BLEFirmata.DIGITAL_MESSAGE 205 | input_data = (@stored_input_data[0] << 7) + @stored_input_data[1] 206 | diff = @digital_input_data[@multi_byte_channel] ^ input_data 207 | @digital_input_data[@multi_byte_channel] = input_data 208 | if @listeners('digitalChange').length > 0 209 | for i in [0..13] 210 | if ((0x01 << i) & diff) > 0 211 | stat = (input_data&diff) > 0 212 | @emit 'digitalChange', 213 | {pin: i+@multi_byte_channel*8, value: stat, old_value: !stat} 214 | when BLEFirmata.ANALOG_MESSAGE 215 | analog_value = (@stored_input_data[0] << 7) + @stored_input_data[1] 216 | old_analog_value = @analogRead(@multi_byte_channel) 217 | @analog_input_data[@multi_byte_channel] = analog_value 218 | if old_analog_value != analog_value 219 | @emit 'analogChange', { 220 | pin: @multi_byte_channel, 221 | value: analog_value, 222 | old_value: old_analog_value 223 | } 224 | when BLEFirmata.REPORT_VERSION 225 | @boardVersion = "#{@stored_input_data[1]}.#{@stored_input_data[0]}" 226 | @emit 'boardVersion', @boardVersion 227 | else 228 | if input_data < 0xF0 229 | command = input_data & 0xF0 230 | @multi_byte_channel = input_data & 0x0F 231 | else 232 | command = input_data 233 | if command is BLEFirmata.START_SYSEX 234 | @parsing_sysex = true 235 | @sysex_bytes_read = 0 236 | else if command is BLEFirmata.DIGITAL_MESSAGE or 237 | command is BLEFirmata.ANALOG_MESSAGE or 238 | command is BLEFirmata.REPORT_VERSION 239 | @wait_for_data = 2 240 | @execute_multi_byte_command = command 241 | -------------------------------------------------------------------------------- /firmware/BLEFirmataSketch/BLEFirmata.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Firmata.cpp - Firmata library 3 | Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | See file LICENSE.txt for further informations on licensing terms. 11 | */ 12 | 13 | //****************************************************************************** 14 | //* Includes 15 | //****************************************************************************** 16 | 17 | #include "BLEFirmata.h" 18 | #include "HardwareSerial.h" 19 | #include "RBL_nRF8001.h" 20 | 21 | extern "C" { 22 | #include 23 | #include 24 | } 25 | 26 | //****************************************************************************** 27 | //* Support Functions 28 | //****************************************************************************** 29 | 30 | void BleFirmataClass::sendValueAsTwo7bitBytes(int value) 31 | { 32 | ble_write(value & B01111111); // LSB 33 | ble_write(value >> 7 & B01111111); // MSB 34 | } 35 | 36 | void BleFirmataClass::startSysex(void) 37 | { 38 | ble_write(START_SYSEX); 39 | } 40 | 41 | void BleFirmataClass::endSysex(void) 42 | { 43 | ble_write(END_SYSEX); 44 | } 45 | 46 | //****************************************************************************** 47 | //* Constructors 48 | //****************************************************************************** 49 | 50 | BleFirmataClass::BleFirmataClass(Stream &s) : BleFirmataSerial(s) 51 | { 52 | firmwareVersionCount = 0; 53 | systemReset(); 54 | } 55 | 56 | //****************************************************************************** 57 | //* Public Methods 58 | //****************************************************************************** 59 | 60 | /* begin method for overriding default serial bitrate */ 61 | void BleFirmataClass::begin(void) 62 | { 63 | begin(57600); 64 | } 65 | 66 | /* begin method for overriding default serial bitrate */ 67 | void BleFirmataClass::begin(long speed) 68 | { 69 | // Serial.begin(speed); 70 | BleFirmataSerial = Serial; 71 | blinkVersion(); 72 | printVersion(); 73 | printFirmwareVersion(); 74 | } 75 | 76 | void BleFirmataClass::begin(Stream &s) 77 | { 78 | BleFirmataSerial = s; 79 | systemReset(); 80 | printVersion(); 81 | printFirmwareVersion(); 82 | } 83 | 84 | // output the protocol version message to the serial port 85 | void BleFirmataClass::printVersion(void) { 86 | ble_write(REPORT_VERSION); 87 | ble_write(FIRMATA_MAJOR_VERSION); 88 | ble_write(FIRMATA_MINOR_VERSION); 89 | } 90 | 91 | void BleFirmataClass::blinkVersion(void) 92 | { 93 | // flash the pin with the protocol version 94 | pinMode(VERSION_BLINK_PIN,OUTPUT); 95 | pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210); 96 | delay(250); 97 | pin13strobe(FIRMATA_MINOR_VERSION, 40, 210); 98 | delay(125); 99 | } 100 | 101 | void BleFirmataClass::printFirmwareVersion(void) 102 | { 103 | byte i; 104 | 105 | if(firmwareVersionCount) { // make sure that the name has been set before reporting 106 | startSysex(); 107 | ble_write(REPORT_FIRMWARE); 108 | ble_write(firmwareVersionVector[0]); // major version number 109 | ble_write(firmwareVersionVector[1]); // minor version number 110 | for(i=2; i 0) && (inputData < 128) ) { 198 | waitForData--; 199 | storedInputData[waitForData] = inputData; 200 | if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message 201 | switch(executeMultiByteCommand) { 202 | case ANALOG_MESSAGE: 203 | if(currentAnalogCallback) { 204 | (*currentAnalogCallback)(multiByteChannel, 205 | (storedInputData[0] << 7) 206 | + storedInputData[1]); 207 | } 208 | break; 209 | case DIGITAL_MESSAGE: 210 | if(currentDigitalCallback) { 211 | (*currentDigitalCallback)(multiByteChannel, 212 | (storedInputData[0] << 7) 213 | + storedInputData[1]); 214 | } 215 | break; 216 | case SET_PIN_MODE: 217 | if(currentPinModeCallback) 218 | (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); 219 | break; 220 | case REPORT_ANALOG: 221 | if(currentReportAnalogCallback) 222 | (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]); 223 | break; 224 | case REPORT_DIGITAL: 225 | if(currentReportDigitalCallback) 226 | (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]); 227 | break; 228 | } 229 | executeMultiByteCommand = 0; 230 | } 231 | } else { 232 | // remove channel info from command byte if less than 0xF0 233 | if(inputData < 0xF0) { 234 | command = inputData & 0xF0; 235 | multiByteChannel = inputData & 0x0F; 236 | } else { 237 | command = inputData; 238 | // commands in the 0xF* range don't use channel data 239 | } 240 | switch (command) { 241 | case ANALOG_MESSAGE: 242 | case DIGITAL_MESSAGE: 243 | case SET_PIN_MODE: 244 | waitForData = 2; // two data bytes needed 245 | executeMultiByteCommand = command; 246 | break; 247 | case REPORT_ANALOG: 248 | case REPORT_DIGITAL: 249 | waitForData = 1; // two data bytes needed 250 | executeMultiByteCommand = command; 251 | break; 252 | case START_SYSEX: 253 | parsingSysex = true; 254 | sysexBytesRead = 0; 255 | break; 256 | case SYSTEM_RESET: 257 | systemReset(); 258 | break; 259 | case REPORT_VERSION: 260 | BleFirmata.printVersion(); 261 | break; 262 | } 263 | } 264 | } 265 | 266 | //------------------------------------------------------------------------------ 267 | // Serial Send Handling 268 | 269 | // send an analog message 270 | void BleFirmataClass::sendAnalog(byte pin, int value) 271 | { 272 | // pin can only be 0-15, so chop higher bits 273 | ble_write(ANALOG_MESSAGE | (pin & 0xF)); 274 | sendValueAsTwo7bitBytes(value); 275 | } 276 | 277 | // send a single digital pin in a digital message 278 | void BleFirmataClass::sendDigital(byte pin, int value) 279 | { 280 | /* TODO add single pin digital messages to the protocol, this needs to 281 | * track the last digital data sent so that it can be sure to change just 282 | * one bit in the packet. This is complicated by the fact that the 283 | * numbering of the pins will probably differ on Arduino, Wiring, and 284 | * other boards. The DIGITAL_MESSAGE sends 14 bits at a time, but it is 285 | * probably easier to send 8 bit ports for any board with more than 14 286 | * digital pins. 287 | */ 288 | 289 | // TODO: the digital message should not be sent on the serial port every 290 | // time sendDigital() is called. Instead, it should add it to an int 291 | // which will be sent on a schedule. If a pin changes more than once 292 | // before the digital message is sent on the serial port, it should send a 293 | // digital message for each change. 294 | 295 | // if(value == 0) 296 | // sendDigitalPortPair(); 297 | } 298 | 299 | 300 | // send 14-bits in a single digital message (protocol v1) 301 | // send an 8-bit port in a single digital message (protocol v2) 302 | void BleFirmataClass::sendDigitalPort(byte portNumber, int portData) 303 | { 304 | ble_write(DIGITAL_MESSAGE | (portNumber & 0xF)); 305 | ble_write((byte)portData % 128); // Tx bits 0-6 306 | ble_write(portData >> 7); // Tx bits 7-13 307 | } 308 | 309 | 310 | void BleFirmataClass::sendSysex(byte command, byte bytec, byte* bytev) 311 | { 312 | byte i; 313 | startSysex(); 314 | ble_write(command); 315 | for(i=0; i 23 | #include 24 | } 25 | 26 | //****************************************************************************** 27 | //* Support Functions 28 | //****************************************************************************** 29 | 30 | void BleFirmataClass::sendValueAsTwo7bitBytes(int value) 31 | { 32 | ble_write(value & B01111111); // LSB 33 | ble_write(value >> 7 & B01111111); // MSB 34 | } 35 | 36 | void BleFirmataClass::startSysex(void) 37 | { 38 | ble_write(START_SYSEX); 39 | } 40 | 41 | void BleFirmataClass::endSysex(void) 42 | { 43 | ble_write(END_SYSEX); 44 | } 45 | 46 | //****************************************************************************** 47 | //* Constructors 48 | //****************************************************************************** 49 | 50 | BleFirmataClass::BleFirmataClass(Stream &s) : BleFirmataSerial(s) 51 | { 52 | firmwareVersionCount = 0; 53 | systemReset(); 54 | } 55 | 56 | //****************************************************************************** 57 | //* Public Methods 58 | //****************************************************************************** 59 | 60 | /* begin method for overriding default serial bitrate */ 61 | void BleFirmataClass::begin(void) 62 | { 63 | begin(57600); 64 | } 65 | 66 | /* begin method for overriding default serial bitrate */ 67 | void BleFirmataClass::begin(long speed) 68 | { 69 | // Serial.begin(speed); 70 | BleFirmataSerial = Serial; 71 | blinkVersion(); 72 | printVersion(); 73 | printFirmwareVersion(); 74 | } 75 | 76 | void BleFirmataClass::begin(Stream &s) 77 | { 78 | BleFirmataSerial = s; 79 | systemReset(); 80 | printVersion(); 81 | printFirmwareVersion(); 82 | } 83 | 84 | // output the protocol version message to the serial port 85 | void BleFirmataClass::printVersion(void) { 86 | ble_write(REPORT_VERSION); 87 | ble_write(FIRMATA_MAJOR_VERSION); 88 | ble_write(FIRMATA_MINOR_VERSION); 89 | } 90 | 91 | void BleFirmataClass::blinkVersion(void) 92 | { 93 | // flash the pin with the protocol version 94 | pinMode(VERSION_BLINK_PIN,OUTPUT); 95 | pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210); 96 | delay(250); 97 | pin13strobe(FIRMATA_MINOR_VERSION, 40, 210); 98 | delay(125); 99 | } 100 | 101 | void BleFirmataClass::printFirmwareVersion(void) 102 | { 103 | byte i; 104 | 105 | if(firmwareVersionCount) { // make sure that the name has been set before reporting 106 | startSysex(); 107 | ble_write(REPORT_FIRMWARE); 108 | ble_write(firmwareVersionVector[0]); // major version number 109 | ble_write(firmwareVersionVector[1]); // minor version number 110 | for(i=2; i 0) && (inputData < 128) ) { 198 | waitForData--; 199 | storedInputData[waitForData] = inputData; 200 | if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message 201 | switch(executeMultiByteCommand) { 202 | case ANALOG_MESSAGE: 203 | if(currentAnalogCallback) { 204 | (*currentAnalogCallback)(multiByteChannel, 205 | (storedInputData[0] << 7) 206 | + storedInputData[1]); 207 | } 208 | break; 209 | case DIGITAL_MESSAGE: 210 | if(currentDigitalCallback) { 211 | (*currentDigitalCallback)(multiByteChannel, 212 | (storedInputData[0] << 7) 213 | + storedInputData[1]); 214 | } 215 | break; 216 | case SET_PIN_MODE: 217 | if(currentPinModeCallback) 218 | (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); 219 | break; 220 | case REPORT_ANALOG: 221 | if(currentReportAnalogCallback) 222 | (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]); 223 | break; 224 | case REPORT_DIGITAL: 225 | if(currentReportDigitalCallback) 226 | (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]); 227 | break; 228 | } 229 | executeMultiByteCommand = 0; 230 | } 231 | } else { 232 | // remove channel info from command byte if less than 0xF0 233 | if(inputData < 0xF0) { 234 | command = inputData & 0xF0; 235 | multiByteChannel = inputData & 0x0F; 236 | } else { 237 | command = inputData; 238 | // commands in the 0xF* range don't use channel data 239 | } 240 | switch (command) { 241 | case ANALOG_MESSAGE: 242 | case DIGITAL_MESSAGE: 243 | case SET_PIN_MODE: 244 | waitForData = 2; // two data bytes needed 245 | executeMultiByteCommand = command; 246 | break; 247 | case REPORT_ANALOG: 248 | case REPORT_DIGITAL: 249 | waitForData = 1; // two data bytes needed 250 | executeMultiByteCommand = command; 251 | break; 252 | case START_SYSEX: 253 | parsingSysex = true; 254 | sysexBytesRead = 0; 255 | break; 256 | case SYSTEM_RESET: 257 | systemReset(); 258 | break; 259 | case REPORT_VERSION: 260 | BleFirmata.printVersion(); 261 | break; 262 | } 263 | } 264 | } 265 | 266 | //------------------------------------------------------------------------------ 267 | // Serial Send Handling 268 | 269 | // send an analog message 270 | void BleFirmataClass::sendAnalog(byte pin, int value) 271 | { 272 | // pin can only be 0-15, so chop higher bits 273 | ble_write(ANALOG_MESSAGE | (pin & 0xF)); 274 | sendValueAsTwo7bitBytes(value); 275 | } 276 | 277 | // send a single digital pin in a digital message 278 | void BleFirmataClass::sendDigital(byte pin, int value) 279 | { 280 | /* TODO add single pin digital messages to the protocol, this needs to 281 | * track the last digital data sent so that it can be sure to change just 282 | * one bit in the packet. This is complicated by the fact that the 283 | * numbering of the pins will probably differ on Arduino, Wiring, and 284 | * other boards. The DIGITAL_MESSAGE sends 14 bits at a time, but it is 285 | * probably easier to send 8 bit ports for any board with more than 14 286 | * digital pins. 287 | */ 288 | 289 | // TODO: the digital message should not be sent on the serial port every 290 | // time sendDigital() is called. Instead, it should add it to an int 291 | // which will be sent on a schedule. If a pin changes more than once 292 | // before the digital message is sent on the serial port, it should send a 293 | // digital message for each change. 294 | 295 | // if(value == 0) 296 | // sendDigitalPortPair(); 297 | } 298 | 299 | 300 | // send 14-bits in a single digital message (protocol v1) 301 | // send an 8-bit port in a single digital message (protocol v2) 302 | void BleFirmataClass::sendDigitalPort(byte portNumber, int portData) 303 | { 304 | ble_write(DIGITAL_MESSAGE | (portNumber & 0xF)); 305 | ble_write((byte)portData % 128); // Tx bits 0-6 306 | ble_write(portData >> 7); // Tx bits 7-13 307 | } 308 | 309 | 310 | void BleFirmataClass::sendSysex(byte command, byte bytec, byte* bytev) 311 | { 312 | byte i; 313 | startSysex(); 314 | ble_write(command); 315 | for(i=0; i 23 | #include 24 | } 25 | 26 | //****************************************************************************** 27 | //* Support Functions 28 | //****************************************************************************** 29 | 30 | void BleFirmataClass::sendValueAsTwo7bitBytes(int value) 31 | { 32 | ble_write(value & B01111111); // LSB 33 | ble_write(value >> 7 & B01111111); // MSB 34 | } 35 | 36 | void BleFirmataClass::startSysex(void) 37 | { 38 | ble_write(START_SYSEX); 39 | } 40 | 41 | void BleFirmataClass::endSysex(void) 42 | { 43 | ble_write(END_SYSEX); 44 | } 45 | 46 | //****************************************************************************** 47 | //* Constructors 48 | //****************************************************************************** 49 | 50 | BleFirmataClass::BleFirmataClass(Stream &s) : BleFirmataSerial(s) 51 | { 52 | firmwareVersionCount = 0; 53 | systemReset(); 54 | } 55 | 56 | //****************************************************************************** 57 | //* Public Methods 58 | //****************************************************************************** 59 | 60 | /* begin method for overriding default serial bitrate */ 61 | void BleFirmataClass::begin(void) 62 | { 63 | begin(57600); 64 | } 65 | 66 | /* begin method for overriding default serial bitrate */ 67 | void BleFirmataClass::begin(long speed) 68 | { 69 | // Serial.begin(speed); 70 | BleFirmataSerial = Serial; 71 | blinkVersion(); 72 | printVersion(); 73 | printFirmwareVersion(); 74 | } 75 | 76 | void BleFirmataClass::begin(Stream &s) 77 | { 78 | BleFirmataSerial = s; 79 | systemReset(); 80 | printVersion(); 81 | printFirmwareVersion(); 82 | } 83 | 84 | // output the protocol version message to the serial port 85 | void BleFirmataClass::printVersion(void) { 86 | ble_write(REPORT_VERSION); 87 | ble_write(FIRMATA_MAJOR_VERSION); 88 | ble_write(FIRMATA_MINOR_VERSION); 89 | } 90 | 91 | void BleFirmataClass::blinkVersion(void) 92 | { 93 | // flash the pin with the protocol version 94 | pinMode(VERSION_BLINK_PIN,OUTPUT); 95 | pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210); 96 | delay(250); 97 | pin13strobe(FIRMATA_MINOR_VERSION, 40, 210); 98 | delay(125); 99 | } 100 | 101 | void BleFirmataClass::printFirmwareVersion(void) 102 | { 103 | byte i; 104 | 105 | if(firmwareVersionCount) { // make sure that the name has been set before reporting 106 | startSysex(); 107 | ble_write(REPORT_FIRMWARE); 108 | ble_write(firmwareVersionVector[0]); // major version number 109 | ble_write(firmwareVersionVector[1]); // minor version number 110 | for(i=2; i 0) && (inputData < 128) ) { 198 | waitForData--; 199 | storedInputData[waitForData] = inputData; 200 | if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message 201 | switch(executeMultiByteCommand) { 202 | case ANALOG_MESSAGE: 203 | if(currentAnalogCallback) { 204 | (*currentAnalogCallback)(multiByteChannel, 205 | (storedInputData[0] << 7) 206 | + storedInputData[1]); 207 | } 208 | break; 209 | case DIGITAL_MESSAGE: 210 | if(currentDigitalCallback) { 211 | (*currentDigitalCallback)(multiByteChannel, 212 | (storedInputData[0] << 7) 213 | + storedInputData[1]); 214 | } 215 | break; 216 | case SET_PIN_MODE: 217 | if(currentPinModeCallback) 218 | (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); 219 | break; 220 | case REPORT_ANALOG: 221 | if(currentReportAnalogCallback) 222 | (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]); 223 | break; 224 | case REPORT_DIGITAL: 225 | if(currentReportDigitalCallback) 226 | (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]); 227 | break; 228 | } 229 | executeMultiByteCommand = 0; 230 | } 231 | } else { 232 | // remove channel info from command byte if less than 0xF0 233 | if(inputData < 0xF0) { 234 | command = inputData & 0xF0; 235 | multiByteChannel = inputData & 0x0F; 236 | } else { 237 | command = inputData; 238 | // commands in the 0xF* range don't use channel data 239 | } 240 | switch (command) { 241 | case ANALOG_MESSAGE: 242 | case DIGITAL_MESSAGE: 243 | case SET_PIN_MODE: 244 | waitForData = 2; // two data bytes needed 245 | executeMultiByteCommand = command; 246 | break; 247 | case REPORT_ANALOG: 248 | case REPORT_DIGITAL: 249 | waitForData = 1; // two data bytes needed 250 | executeMultiByteCommand = command; 251 | break; 252 | case START_SYSEX: 253 | parsingSysex = true; 254 | sysexBytesRead = 0; 255 | break; 256 | case SYSTEM_RESET: 257 | systemReset(); 258 | break; 259 | case REPORT_VERSION: 260 | BleFirmata.printVersion(); 261 | break; 262 | } 263 | } 264 | } 265 | 266 | //------------------------------------------------------------------------------ 267 | // Serial Send Handling 268 | 269 | // send an analog message 270 | void BleFirmataClass::sendAnalog(byte pin, int value) 271 | { 272 | // pin can only be 0-15, so chop higher bits 273 | ble_write(ANALOG_MESSAGE | (pin & 0xF)); 274 | sendValueAsTwo7bitBytes(value); 275 | } 276 | 277 | // send a single digital pin in a digital message 278 | void BleFirmataClass::sendDigital(byte pin, int value) 279 | { 280 | /* TODO add single pin digital messages to the protocol, this needs to 281 | * track the last digital data sent so that it can be sure to change just 282 | * one bit in the packet. This is complicated by the fact that the 283 | * numbering of the pins will probably differ on Arduino, Wiring, and 284 | * other boards. The DIGITAL_MESSAGE sends 14 bits at a time, but it is 285 | * probably easier to send 8 bit ports for any board with more than 14 286 | * digital pins. 287 | */ 288 | 289 | // TODO: the digital message should not be sent on the serial port every 290 | // time sendDigital() is called. Instead, it should add it to an int 291 | // which will be sent on a schedule. If a pin changes more than once 292 | // before the digital message is sent on the serial port, it should send a 293 | // digital message for each change. 294 | 295 | // if(value == 0) 296 | // sendDigitalPortPair(); 297 | } 298 | 299 | 300 | // send 14-bits in a single digital message (protocol v1) 301 | // send an 8-bit port in a single digital message (protocol v2) 302 | void BleFirmataClass::sendDigitalPort(byte portNumber, int portData) 303 | { 304 | ble_write(DIGITAL_MESSAGE | (portNumber & 0xF)); 305 | ble_write((byte)portData % 128); // Tx bits 0-6 306 | ble_write(portData >> 7); // Tx bits 7-13 307 | } 308 | 309 | 310 | void BleFirmataClass::sendSysex(byte command, byte bytec, byte* bytev) 311 | { 312 | byte i; 313 | startSysex(); 314 | ble_write(command); 315 | for(i=0; i 7 | 8 | #if defined(ARDUINO) && ARDUINO >= 100 9 | #include "Arduino.h" // for digitalRead, digitalWrite, etc 10 | #else 11 | #include "WProgram.h" 12 | #endif 13 | 14 | // Normally Servo.h must be included before Firmata.h (which then includes 15 | // this file). If Servo.h wasn't included, this allows the code to still 16 | // compile, but without support for any Servos. Hopefully that's what the 17 | // user intended by not including Servo.h 18 | #ifndef MAX_SERVOS 19 | #define MAX_SERVOS 0 20 | #endif 21 | 22 | /* 23 | Firmata Hardware Abstraction Layer 24 | 25 | Firmata is built on top of the hardware abstraction functions of Arduino, 26 | specifically digitalWrite, digitalRead, analogWrite, analogRead, and 27 | pinMode. While these functions offer simple integer pin numbers, Firmata 28 | needs more information than is provided by Arduino. This file provides 29 | all other hardware specific details. To make Firmata support a new board, 30 | only this file should require editing. 31 | 32 | The key concept is every "pin" implemented by Firmata may be mapped to 33 | any pin as implemented by Arduino. Usually a simple 1-to-1 mapping is 34 | best, but such mapping should not be assumed. This hardware abstraction 35 | layer allows Firmata to implement any number of pins which map onto the 36 | Arduino implemented pins in almost any arbitrary way. 37 | 38 | 39 | General Constants: 40 | 41 | These constants provide basic information Firmata requires. 42 | 43 | TOTAL_PINS: The total number of pins Firmata implemented by Firmata. 44 | Usually this will match the number of pins the Arduino functions 45 | implement, including any pins pins capable of analog or digital. 46 | However, Firmata may implement any number of pins. For example, 47 | on Arduino Mini with 8 analog inputs, 6 of these may be used 48 | for digital functions, and 2 are analog only. On such boards, 49 | Firmata can implement more pins than Arduino's pinMode() 50 | function, in order to accommodate those special pins. The 51 | Firmata protocol supports a maximum of 128 pins, so this 52 | constant must not exceed 128. 53 | 54 | TOTAL_ANALOG_PINS: The total number of analog input pins implemented. 55 | The Firmata protocol allows up to 16 analog inputs, accessed 56 | using offsets 0 to 15. Because Firmata presents the analog 57 | inputs using different offsets than the actual pin numbers 58 | (a legacy of Arduino's analogRead function, and the way the 59 | analog input capable pins are physically labeled on all 60 | Arduino boards), the total number of analog input signals 61 | must be specified. 16 is the maximum. 62 | 63 | VERSION_BLINK_PIN: When Firmata starts up, it will blink the version 64 | number. This constant is the Arduino pin number where a 65 | LED is connected. 66 | 67 | 68 | Pin Mapping Macros: 69 | 70 | These macros provide the mapping between pins as implemented by 71 | Firmata protocol and the actual pin numbers used by the Arduino 72 | functions. Even though such mappings are often simple, pin 73 | numbers received by Firmata protocol should always be used as 74 | input to these macros, and the result of the macro should be 75 | used with with any Arduino function. 76 | 77 | When Firmata is extended to support a new pin mode or feature, 78 | a pair of macros should be added and used for all hardware 79 | access. For simple 1:1 mapping, these macros add no actual 80 | overhead, yet their consistent use allows source code which 81 | uses them consistently to be easily adapted to all other boards 82 | with different requirements. 83 | 84 | IS_PIN_XXXX(pin): The IS_PIN macros resolve to true or non-zero 85 | if a pin as implemented by Firmata corresponds to a pin 86 | that actually implements the named feature. 87 | 88 | PIN_TO_XXXX(pin): The PIN_TO macros translate pin numbers as 89 | implemented by Firmata to the pin numbers needed as inputs 90 | to the Arduino functions. The corresponding IS_PIN macro 91 | should always be tested before using a PIN_TO macro, so 92 | these macros only need to handle valid Firmata pin 93 | numbers for the named feature. 94 | 95 | 96 | Port Access Inline Funtions: 97 | 98 | For efficiency, Firmata protocol provides access to digital 99 | input and output pins grouped by 8 bit ports. When these 100 | groups of 8 correspond to actual 8 bit ports as implemented 101 | by the hardware, these inline functions can provide high 102 | speed direct port access. Otherwise, a default implementation 103 | using 8 calls to digitalWrite or digitalRead is used. 104 | 105 | When porting Firmata to a new board, it is recommended to 106 | use the default functions first and focus only on the constants 107 | and macros above. When those are working, if optimized port 108 | access is desired, these inline functions may be extended. 109 | The recommended approach defines a symbol indicating which 110 | optimization to use, and then conditional complication is 111 | used within these functions. 112 | 113 | readPort(port, bitmask): Read an 8 bit port, returning the value. 114 | port: The port number, Firmata pins port*8 to port*8+7 115 | bitmask: The actual pins to read, indicated by 1 bits. 116 | 117 | writePort(port, value, bitmask): Write an 8 bit port. 118 | port: The port number, Firmata pins port*8 to port*8+7 119 | value: The 8 bit value to write 120 | bitmask: The actual pins to write, indicated by 1 bits. 121 | */ 122 | 123 | /*============================================================================== 124 | * Board Specific Configuration 125 | *============================================================================*/ 126 | 127 | #ifndef digitalPinHasPWM 128 | #define digitalPinHasPWM(p) IS_PIN_DIGITAL(p) 129 | #endif 130 | 131 | // Arduino Duemilanove, Diecimila, and NG 132 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) 133 | #if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6 134 | #define TOTAL_ANALOG_PINS 6 135 | #define TOTAL_PINS 20 // 14 digital + 6 analog 136 | #else 137 | #define TOTAL_ANALOG_PINS 8 138 | #define TOTAL_PINS 22 // 14 digital + 8 analog 139 | #endif 140 | #define VERSION_BLINK_PIN 13 141 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) 142 | #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) 143 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 144 | #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) 145 | #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) 146 | #define PIN_TO_DIGITAL(p) (p) 147 | #define PIN_TO_ANALOG(p) ((p) - 14) 148 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 149 | #define PIN_TO_SERVO(p) ((p) - 2) 150 | #define ARDUINO_PINOUT_OPTIMIZE 1 151 | 152 | 153 | // Wiring (and board) 154 | #elif defined(WIRING) 155 | #define VERSION_BLINK_PIN WLED 156 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 157 | #define IS_PIN_ANALOG(p) ((p) >= FIRST_ANALOG_PIN && (p) < (FIRST_ANALOG_PIN+TOTAL_ANALOG_PINS)) 158 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 159 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 160 | #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) 161 | #define PIN_TO_DIGITAL(p) (p) 162 | #define PIN_TO_ANALOG(p) ((p) - FIRST_ANALOG_PIN) 163 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 164 | #define PIN_TO_SERVO(p) (p) 165 | 166 | 167 | // old Arduinos 168 | #elif defined(__AVR_ATmega8__) 169 | #define TOTAL_ANALOG_PINS 6 170 | #define TOTAL_PINS 20 // 14 digital + 6 analog 171 | #define VERSION_BLINK_PIN 13 172 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) 173 | #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19) 174 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 175 | #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) 176 | #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) 177 | #define PIN_TO_DIGITAL(p) (p) 178 | #define PIN_TO_ANALOG(p) ((p) - 14) 179 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 180 | #define PIN_TO_SERVO(p) ((p) - 2) 181 | #define ARDUINO_PINOUT_OPTIMIZE 1 182 | 183 | 184 | // Arduino Mega 185 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 186 | #define TOTAL_ANALOG_PINS 16 187 | #define TOTAL_PINS 70 // 54 digital + 16 analog 188 | #define VERSION_BLINK_PIN 13 189 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 190 | #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS) 191 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 192 | #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) 193 | #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) 194 | #define PIN_TO_DIGITAL(p) (p) 195 | #define PIN_TO_ANALOG(p) ((p) - 54) 196 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 197 | #define PIN_TO_SERVO(p) ((p) - 2) 198 | 199 | 200 | // Teensy 1.0 201 | #elif defined(__AVR_AT90USB162__) 202 | #define TOTAL_ANALOG_PINS 0 203 | #define TOTAL_PINS 21 // 21 digital + no analog 204 | #define VERSION_BLINK_PIN 6 205 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 206 | #define IS_PIN_ANALOG(p) (0) 207 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 208 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 209 | #define IS_PIN_I2C(p) (0) 210 | #define PIN_TO_DIGITAL(p) (p) 211 | #define PIN_TO_ANALOG(p) (0) 212 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 213 | #define PIN_TO_SERVO(p) (p) 214 | 215 | 216 | // Teensy 2.0 217 | #elif defined(__AVR_ATmega32U4__) 218 | #define TOTAL_ANALOG_PINS 12 219 | #define TOTAL_PINS 25 // 11 digital + 12 analog 220 | #define VERSION_BLINK_PIN 11 221 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 222 | #define IS_PIN_ANALOG(p) ((p) >= 11 && (p) <= 22) 223 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 224 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 225 | #define IS_PIN_I2C(p) ((p) == 5 || (p) == 6) 226 | #define PIN_TO_DIGITAL(p) (p) 227 | #define PIN_TO_ANALOG(p) (((p)<22)?21-(p):11) 228 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 229 | #define PIN_TO_SERVO(p) (p) 230 | 231 | 232 | // Teensy++ 1.0 and 2.0 233 | #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) 234 | #define TOTAL_ANALOG_PINS 8 235 | #define TOTAL_PINS 46 // 38 digital + 8 analog 236 | #define VERSION_BLINK_PIN 6 237 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 238 | #define IS_PIN_ANALOG(p) ((p) >= 38 && (p) < TOTAL_PINS) 239 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 240 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 241 | #define IS_PIN_I2C(p) ((p) == 0 || (p) == 1) 242 | #define PIN_TO_DIGITAL(p) (p) 243 | #define PIN_TO_ANALOG(p) ((p) - 38) 244 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 245 | #define PIN_TO_SERVO(p) (p) 246 | 247 | 248 | // Sanguino 249 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 250 | #define TOTAL_ANALOG_PINS 8 251 | #define TOTAL_PINS 32 // 24 digital + 8 analog 252 | #define VERSION_BLINK_PIN 0 253 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 254 | #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS) 255 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 256 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 257 | #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17) 258 | #define PIN_TO_DIGITAL(p) (p) 259 | #define PIN_TO_ANALOG(p) ((p) - 24) 260 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 261 | #define PIN_TO_SERVO(p) ((p) - 2) 262 | 263 | 264 | // Illuminato 265 | #elif defined(__AVR_ATmega645__) 266 | #define TOTAL_ANALOG_PINS 6 267 | #define TOTAL_PINS 42 // 36 digital + 6 analog 268 | #define VERSION_BLINK_PIN 13 269 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 270 | #define IS_PIN_ANALOG(p) ((p) >= 36 && (p) < TOTAL_PINS) 271 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 272 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 273 | #define IS_PIN_I2C(p) ((p) == 4 || (p) == 5) 274 | #define PIN_TO_DIGITAL(p) (p) 275 | #define PIN_TO_ANALOG(p) ((p) - 36) 276 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 277 | #define PIN_TO_SERVO(p) ((p) - 2) 278 | 279 | 280 | // Arduino DUE 281 | #elif defined(__SAM3X8E__) 282 | #define TOTAL_ANALOG_PINS 12 283 | #define TOTAL_PINS 66 // 54 digital + 12 analog 284 | #define VERSION_BLINK_PIN 13 285 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 286 | #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS) 287 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 288 | #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) 289 | #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // 70 71 290 | #define PIN_TO_DIGITAL(p) (p) 291 | #define PIN_TO_ANALOG(p) ((p) - 54) 292 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 293 | #define PIN_TO_SERVO(p) ((p) - 2) 294 | 295 | 296 | // anything else 297 | #else 298 | #error "Please edit Boards.h with a hardware abstraction for this board" 299 | #endif 300 | 301 | 302 | /*============================================================================== 303 | * readPort() - Read an 8 bit port 304 | *============================================================================*/ 305 | 306 | static inline unsigned char readPort(byte, byte) __attribute__((always_inline, unused)); 307 | static inline unsigned char readPort(byte port, byte bitmask) 308 | { 309 | #if defined(ARDUINO_PINOUT_OPTIMIZE) 310 | if (port == 0) return (PIND & 0xFC) & bitmask; // ignore Rx/Tx 0/1 311 | if (port == 1) return ((PINB & 0x3F) | ((PINC & 0x03) << 6)) & bitmask; 312 | if (port == 2) return ((PINC & 0x3C) >> 2) & bitmask; 313 | return 0; 314 | #else 315 | unsigned char out=0, pin=port*8; 316 | if (IS_PIN_DIGITAL(pin+0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin+0))) out |= 0x01; 317 | if (IS_PIN_DIGITAL(pin+1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin+1))) out |= 0x02; 318 | if (IS_PIN_DIGITAL(pin+2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin+2))) out |= 0x04; 319 | if (IS_PIN_DIGITAL(pin+3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin+3))) out |= 0x08; 320 | if (IS_PIN_DIGITAL(pin+4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin+4))) out |= 0x10; 321 | if (IS_PIN_DIGITAL(pin+5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin+5))) out |= 0x20; 322 | if (IS_PIN_DIGITAL(pin+6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin+6))) out |= 0x40; 323 | if (IS_PIN_DIGITAL(pin+7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin+7))) out |= 0x80; 324 | return out; 325 | #endif 326 | } 327 | 328 | /*============================================================================== 329 | * writePort() - Write an 8 bit port, only touch pins specified by a bitmask 330 | *============================================================================*/ 331 | 332 | static inline unsigned char writePort(byte, byte, byte) __attribute__((always_inline, unused)); 333 | static inline unsigned char writePort(byte port, byte value, byte bitmask) 334 | { 335 | #if defined(ARDUINO_PINOUT_OPTIMIZE) 336 | if (port == 0) { 337 | bitmask = bitmask & 0xFC; // do not touch Tx & Rx pins 338 | byte valD = value & bitmask; 339 | byte maskD = ~bitmask; 340 | cli(); 341 | PORTD = (PORTD & maskD) | valD; 342 | sei(); 343 | } else if (port == 1) { 344 | byte valB = (value & bitmask) & 0x3F; 345 | byte valC = (value & bitmask) >> 6; 346 | byte maskB = ~(bitmask & 0x3F); 347 | byte maskC = ~((bitmask & 0xC0) >> 6); 348 | cli(); 349 | PORTB = (PORTB & maskB) | valB; 350 | PORTC = (PORTC & maskC) | valC; 351 | sei(); 352 | } else if (port == 2) { 353 | bitmask = bitmask & 0x0F; 354 | byte valC = (value & bitmask) << 2; 355 | byte maskC = ~(bitmask << 2); 356 | cli(); 357 | PORTC = (PORTC & maskC) | valC; 358 | sei(); 359 | } 360 | #else 361 | byte pin=port*8; 362 | if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin+0), (value & 0x01)); 363 | if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin+1), (value & 0x02)); 364 | if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin+2), (value & 0x04)); 365 | if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin+3), (value & 0x08)); 366 | if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin+4), (value & 0x10)); 367 | if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin+5), (value & 0x20)); 368 | if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin+6), (value & 0x40)); 369 | if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin+7), (value & 0x80)); 370 | #endif 371 | } 372 | 373 | 374 | 375 | 376 | #ifndef TOTAL_PORTS 377 | #define TOTAL_PORTS ((TOTAL_PINS + 7) / 8) 378 | #endif 379 | 380 | 381 | #endif /* Firmata_Boards_h */ 382 | 383 | -------------------------------------------------------------------------------- /samples/sysex/BLEFirmataWithLedBlink/Boards.h: -------------------------------------------------------------------------------- 1 | /* Boards.h - Hardware Abstraction Layer for Firmata library */ 2 | 3 | #ifndef Firmata_Boards_h 4 | #define Firmata_Boards_h 5 | 6 | #include 7 | 8 | #if defined(ARDUINO) && ARDUINO >= 100 9 | #include "Arduino.h" // for digitalRead, digitalWrite, etc 10 | #else 11 | #include "WProgram.h" 12 | #endif 13 | 14 | // Normally Servo.h must be included before Firmata.h (which then includes 15 | // this file). If Servo.h wasn't included, this allows the code to still 16 | // compile, but without support for any Servos. Hopefully that's what the 17 | // user intended by not including Servo.h 18 | #ifndef MAX_SERVOS 19 | #define MAX_SERVOS 0 20 | #endif 21 | 22 | /* 23 | Firmata Hardware Abstraction Layer 24 | 25 | Firmata is built on top of the hardware abstraction functions of Arduino, 26 | specifically digitalWrite, digitalRead, analogWrite, analogRead, and 27 | pinMode. While these functions offer simple integer pin numbers, Firmata 28 | needs more information than is provided by Arduino. This file provides 29 | all other hardware specific details. To make Firmata support a new board, 30 | only this file should require editing. 31 | 32 | The key concept is every "pin" implemented by Firmata may be mapped to 33 | any pin as implemented by Arduino. Usually a simple 1-to-1 mapping is 34 | best, but such mapping should not be assumed. This hardware abstraction 35 | layer allows Firmata to implement any number of pins which map onto the 36 | Arduino implemented pins in almost any arbitrary way. 37 | 38 | 39 | General Constants: 40 | 41 | These constants provide basic information Firmata requires. 42 | 43 | TOTAL_PINS: The total number of pins Firmata implemented by Firmata. 44 | Usually this will match the number of pins the Arduino functions 45 | implement, including any pins pins capable of analog or digital. 46 | However, Firmata may implement any number of pins. For example, 47 | on Arduino Mini with 8 analog inputs, 6 of these may be used 48 | for digital functions, and 2 are analog only. On such boards, 49 | Firmata can implement more pins than Arduino's pinMode() 50 | function, in order to accommodate those special pins. The 51 | Firmata protocol supports a maximum of 128 pins, so this 52 | constant must not exceed 128. 53 | 54 | TOTAL_ANALOG_PINS: The total number of analog input pins implemented. 55 | The Firmata protocol allows up to 16 analog inputs, accessed 56 | using offsets 0 to 15. Because Firmata presents the analog 57 | inputs using different offsets than the actual pin numbers 58 | (a legacy of Arduino's analogRead function, and the way the 59 | analog input capable pins are physically labeled on all 60 | Arduino boards), the total number of analog input signals 61 | must be specified. 16 is the maximum. 62 | 63 | VERSION_BLINK_PIN: When Firmata starts up, it will blink the version 64 | number. This constant is the Arduino pin number where a 65 | LED is connected. 66 | 67 | 68 | Pin Mapping Macros: 69 | 70 | These macros provide the mapping between pins as implemented by 71 | Firmata protocol and the actual pin numbers used by the Arduino 72 | functions. Even though such mappings are often simple, pin 73 | numbers received by Firmata protocol should always be used as 74 | input to these macros, and the result of the macro should be 75 | used with with any Arduino function. 76 | 77 | When Firmata is extended to support a new pin mode or feature, 78 | a pair of macros should be added and used for all hardware 79 | access. For simple 1:1 mapping, these macros add no actual 80 | overhead, yet their consistent use allows source code which 81 | uses them consistently to be easily adapted to all other boards 82 | with different requirements. 83 | 84 | IS_PIN_XXXX(pin): The IS_PIN macros resolve to true or non-zero 85 | if a pin as implemented by Firmata corresponds to a pin 86 | that actually implements the named feature. 87 | 88 | PIN_TO_XXXX(pin): The PIN_TO macros translate pin numbers as 89 | implemented by Firmata to the pin numbers needed as inputs 90 | to the Arduino functions. The corresponding IS_PIN macro 91 | should always be tested before using a PIN_TO macro, so 92 | these macros only need to handle valid Firmata pin 93 | numbers for the named feature. 94 | 95 | 96 | Port Access Inline Funtions: 97 | 98 | For efficiency, Firmata protocol provides access to digital 99 | input and output pins grouped by 8 bit ports. When these 100 | groups of 8 correspond to actual 8 bit ports as implemented 101 | by the hardware, these inline functions can provide high 102 | speed direct port access. Otherwise, a default implementation 103 | using 8 calls to digitalWrite or digitalRead is used. 104 | 105 | When porting Firmata to a new board, it is recommended to 106 | use the default functions first and focus only on the constants 107 | and macros above. When those are working, if optimized port 108 | access is desired, these inline functions may be extended. 109 | The recommended approach defines a symbol indicating which 110 | optimization to use, and then conditional complication is 111 | used within these functions. 112 | 113 | readPort(port, bitmask): Read an 8 bit port, returning the value. 114 | port: The port number, Firmata pins port*8 to port*8+7 115 | bitmask: The actual pins to read, indicated by 1 bits. 116 | 117 | writePort(port, value, bitmask): Write an 8 bit port. 118 | port: The port number, Firmata pins port*8 to port*8+7 119 | value: The 8 bit value to write 120 | bitmask: The actual pins to write, indicated by 1 bits. 121 | */ 122 | 123 | /*============================================================================== 124 | * Board Specific Configuration 125 | *============================================================================*/ 126 | 127 | #ifndef digitalPinHasPWM 128 | #define digitalPinHasPWM(p) IS_PIN_DIGITAL(p) 129 | #endif 130 | 131 | // Arduino Duemilanove, Diecimila, and NG 132 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) 133 | #if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6 134 | #define TOTAL_ANALOG_PINS 6 135 | #define TOTAL_PINS 20 // 14 digital + 6 analog 136 | #else 137 | #define TOTAL_ANALOG_PINS 8 138 | #define TOTAL_PINS 22 // 14 digital + 8 analog 139 | #endif 140 | #define VERSION_BLINK_PIN 13 141 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) 142 | #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) 143 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 144 | #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) 145 | #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) 146 | #define PIN_TO_DIGITAL(p) (p) 147 | #define PIN_TO_ANALOG(p) ((p) - 14) 148 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 149 | #define PIN_TO_SERVO(p) ((p) - 2) 150 | #define ARDUINO_PINOUT_OPTIMIZE 1 151 | 152 | 153 | // Wiring (and board) 154 | #elif defined(WIRING) 155 | #define VERSION_BLINK_PIN WLED 156 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 157 | #define IS_PIN_ANALOG(p) ((p) >= FIRST_ANALOG_PIN && (p) < (FIRST_ANALOG_PIN+TOTAL_ANALOG_PINS)) 158 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 159 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 160 | #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) 161 | #define PIN_TO_DIGITAL(p) (p) 162 | #define PIN_TO_ANALOG(p) ((p) - FIRST_ANALOG_PIN) 163 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 164 | #define PIN_TO_SERVO(p) (p) 165 | 166 | 167 | // old Arduinos 168 | #elif defined(__AVR_ATmega8__) 169 | #define TOTAL_ANALOG_PINS 6 170 | #define TOTAL_PINS 20 // 14 digital + 6 analog 171 | #define VERSION_BLINK_PIN 13 172 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) 173 | #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19) 174 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 175 | #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) 176 | #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) 177 | #define PIN_TO_DIGITAL(p) (p) 178 | #define PIN_TO_ANALOG(p) ((p) - 14) 179 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 180 | #define PIN_TO_SERVO(p) ((p) - 2) 181 | #define ARDUINO_PINOUT_OPTIMIZE 1 182 | 183 | 184 | // Arduino Mega 185 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 186 | #define TOTAL_ANALOG_PINS 16 187 | #define TOTAL_PINS 70 // 54 digital + 16 analog 188 | #define VERSION_BLINK_PIN 13 189 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 190 | #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS) 191 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 192 | #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) 193 | #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) 194 | #define PIN_TO_DIGITAL(p) (p) 195 | #define PIN_TO_ANALOG(p) ((p) - 54) 196 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 197 | #define PIN_TO_SERVO(p) ((p) - 2) 198 | 199 | 200 | // Teensy 1.0 201 | #elif defined(__AVR_AT90USB162__) 202 | #define TOTAL_ANALOG_PINS 0 203 | #define TOTAL_PINS 21 // 21 digital + no analog 204 | #define VERSION_BLINK_PIN 6 205 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 206 | #define IS_PIN_ANALOG(p) (0) 207 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 208 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 209 | #define IS_PIN_I2C(p) (0) 210 | #define PIN_TO_DIGITAL(p) (p) 211 | #define PIN_TO_ANALOG(p) (0) 212 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 213 | #define PIN_TO_SERVO(p) (p) 214 | 215 | 216 | // Teensy 2.0 217 | #elif defined(__AVR_ATmega32U4__) 218 | #define TOTAL_ANALOG_PINS 12 219 | #define TOTAL_PINS 25 // 11 digital + 12 analog 220 | #define VERSION_BLINK_PIN 11 221 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 222 | #define IS_PIN_ANALOG(p) ((p) >= 11 && (p) <= 22) 223 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 224 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 225 | #define IS_PIN_I2C(p) ((p) == 5 || (p) == 6) 226 | #define PIN_TO_DIGITAL(p) (p) 227 | #define PIN_TO_ANALOG(p) (((p)<22)?21-(p):11) 228 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 229 | #define PIN_TO_SERVO(p) (p) 230 | 231 | 232 | // Teensy++ 1.0 and 2.0 233 | #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) 234 | #define TOTAL_ANALOG_PINS 8 235 | #define TOTAL_PINS 46 // 38 digital + 8 analog 236 | #define VERSION_BLINK_PIN 6 237 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 238 | #define IS_PIN_ANALOG(p) ((p) >= 38 && (p) < TOTAL_PINS) 239 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 240 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 241 | #define IS_PIN_I2C(p) ((p) == 0 || (p) == 1) 242 | #define PIN_TO_DIGITAL(p) (p) 243 | #define PIN_TO_ANALOG(p) ((p) - 38) 244 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 245 | #define PIN_TO_SERVO(p) (p) 246 | 247 | 248 | // Sanguino 249 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 250 | #define TOTAL_ANALOG_PINS 8 251 | #define TOTAL_PINS 32 // 24 digital + 8 analog 252 | #define VERSION_BLINK_PIN 0 253 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 254 | #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS) 255 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 256 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 257 | #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17) 258 | #define PIN_TO_DIGITAL(p) (p) 259 | #define PIN_TO_ANALOG(p) ((p) - 24) 260 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 261 | #define PIN_TO_SERVO(p) ((p) - 2) 262 | 263 | 264 | // Illuminato 265 | #elif defined(__AVR_ATmega645__) 266 | #define TOTAL_ANALOG_PINS 6 267 | #define TOTAL_PINS 42 // 36 digital + 6 analog 268 | #define VERSION_BLINK_PIN 13 269 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 270 | #define IS_PIN_ANALOG(p) ((p) >= 36 && (p) < TOTAL_PINS) 271 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 272 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 273 | #define IS_PIN_I2C(p) ((p) == 4 || (p) == 5) 274 | #define PIN_TO_DIGITAL(p) (p) 275 | #define PIN_TO_ANALOG(p) ((p) - 36) 276 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 277 | #define PIN_TO_SERVO(p) ((p) - 2) 278 | 279 | 280 | // Arduino DUE 281 | #elif defined(__SAM3X8E__) 282 | #define TOTAL_ANALOG_PINS 12 283 | #define TOTAL_PINS 66 // 54 digital + 12 analog 284 | #define VERSION_BLINK_PIN 13 285 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 286 | #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS) 287 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 288 | #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) 289 | #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // 70 71 290 | #define PIN_TO_DIGITAL(p) (p) 291 | #define PIN_TO_ANALOG(p) ((p) - 54) 292 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 293 | #define PIN_TO_SERVO(p) ((p) - 2) 294 | 295 | 296 | // anything else 297 | #else 298 | #error "Please edit Boards.h with a hardware abstraction for this board" 299 | #endif 300 | 301 | 302 | /*============================================================================== 303 | * readPort() - Read an 8 bit port 304 | *============================================================================*/ 305 | 306 | static inline unsigned char readPort(byte, byte) __attribute__((always_inline, unused)); 307 | static inline unsigned char readPort(byte port, byte bitmask) 308 | { 309 | #if defined(ARDUINO_PINOUT_OPTIMIZE) 310 | if (port == 0) return (PIND & 0xFC) & bitmask; // ignore Rx/Tx 0/1 311 | if (port == 1) return ((PINB & 0x3F) | ((PINC & 0x03) << 6)) & bitmask; 312 | if (port == 2) return ((PINC & 0x3C) >> 2) & bitmask; 313 | return 0; 314 | #else 315 | unsigned char out=0, pin=port*8; 316 | if (IS_PIN_DIGITAL(pin+0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin+0))) out |= 0x01; 317 | if (IS_PIN_DIGITAL(pin+1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin+1))) out |= 0x02; 318 | if (IS_PIN_DIGITAL(pin+2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin+2))) out |= 0x04; 319 | if (IS_PIN_DIGITAL(pin+3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin+3))) out |= 0x08; 320 | if (IS_PIN_DIGITAL(pin+4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin+4))) out |= 0x10; 321 | if (IS_PIN_DIGITAL(pin+5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin+5))) out |= 0x20; 322 | if (IS_PIN_DIGITAL(pin+6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin+6))) out |= 0x40; 323 | if (IS_PIN_DIGITAL(pin+7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin+7))) out |= 0x80; 324 | return out; 325 | #endif 326 | } 327 | 328 | /*============================================================================== 329 | * writePort() - Write an 8 bit port, only touch pins specified by a bitmask 330 | *============================================================================*/ 331 | 332 | static inline unsigned char writePort(byte, byte, byte) __attribute__((always_inline, unused)); 333 | static inline unsigned char writePort(byte port, byte value, byte bitmask) 334 | { 335 | #if defined(ARDUINO_PINOUT_OPTIMIZE) 336 | if (port == 0) { 337 | bitmask = bitmask & 0xFC; // do not touch Tx & Rx pins 338 | byte valD = value & bitmask; 339 | byte maskD = ~bitmask; 340 | cli(); 341 | PORTD = (PORTD & maskD) | valD; 342 | sei(); 343 | } else if (port == 1) { 344 | byte valB = (value & bitmask) & 0x3F; 345 | byte valC = (value & bitmask) >> 6; 346 | byte maskB = ~(bitmask & 0x3F); 347 | byte maskC = ~((bitmask & 0xC0) >> 6); 348 | cli(); 349 | PORTB = (PORTB & maskB) | valB; 350 | PORTC = (PORTC & maskC) | valC; 351 | sei(); 352 | } else if (port == 2) { 353 | bitmask = bitmask & 0x0F; 354 | byte valC = (value & bitmask) << 2; 355 | byte maskC = ~(bitmask << 2); 356 | cli(); 357 | PORTC = (PORTC & maskC) | valC; 358 | sei(); 359 | } 360 | #else 361 | byte pin=port*8; 362 | if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin+0), (value & 0x01)); 363 | if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin+1), (value & 0x02)); 364 | if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin+2), (value & 0x04)); 365 | if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin+3), (value & 0x08)); 366 | if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin+4), (value & 0x10)); 367 | if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin+5), (value & 0x20)); 368 | if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin+6), (value & 0x40)); 369 | if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin+7), (value & 0x80)); 370 | #endif 371 | } 372 | 373 | 374 | 375 | 376 | #ifndef TOTAL_PORTS 377 | #define TOTAL_PORTS ((TOTAL_PINS + 7) / 8) 378 | #endif 379 | 380 | 381 | #endif /* Firmata_Boards_h */ 382 | 383 | -------------------------------------------------------------------------------- /firmware/BLEFirmataSketch/BLEFirmataSketch.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEFirmataSketch 3 | * 4 | * This sketch is for the BLE Arduino App 5 | * It is a modified version of the Standard Firmata 6 | * sketch by adding support for BLE. 7 | * 8 | */ 9 | 10 | #define BLE_NAME "BlendMicro" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "BLEFirmata.h" 17 | #include 18 | 19 | /* 20 | * Firmata is a generic protocol for communicating with microcontrollers 21 | * from software on a host computer. It is intended to work with 22 | * any host computer software package. 23 | * 24 | * To download a host software package, please clink on the following link 25 | * to open the download page in your default browser. 26 | * 27 | * http://firmata.org/wiki/Download 28 | */ 29 | 30 | /* 31 | Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. 32 | Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. 33 | Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. 34 | Copyright (C) 2009-2011 Jeff Hoefs. All rights reserved. 35 | 36 | This library is free software; you can redistribute it and/or 37 | modify it under the terms of the GNU Lesser General Public 38 | License as published by the Free Software Foundation; either 39 | version 2.1 of the License, or (at your option) any later version. 40 | 41 | See file LICENSE.txt for further informations on licensing terms. 42 | 43 | formatted using the GNU C formatting and indenting 44 | */ 45 | 46 | /* 47 | * TODO: use Program Control to load stored profiles from EEPROM 48 | */ 49 | 50 | // move the following defines to Firmata.h? 51 | #define I2C_WRITE B00000000 52 | #define I2C_READ B00001000 53 | #define I2C_READ_CONTINUOUSLY B00010000 54 | #define I2C_STOP_READING B00011000 55 | #define I2C_READ_WRITE_MODE_MASK B00011000 56 | #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 57 | 58 | #define MAX_QUERIES 8 59 | #define MINIMUM_SAMPLING_INTERVAL 10 60 | 61 | #define REGISTER_NOT_SPECIFIED -1 62 | 63 | /*============================================================================== 64 | * GLOBAL VARIABLES 65 | *============================================================================*/ 66 | 67 | /* analog inputs */ 68 | int analogInputsToReport = 0; // bitwise array to store pin reporting 69 | 70 | /* digital input ports */ 71 | byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence 72 | byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent 73 | 74 | /* pins configuration */ 75 | byte pinConfig[TOTAL_PINS]; // configuration of every pin 76 | byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else 77 | int pinState[TOTAL_PINS]; // any value that has been written 78 | 79 | /* timer variables */ 80 | unsigned long currentMillis; // store the current value from millis() 81 | unsigned long previousMillis; // for comparison with currentMillis 82 | int samplingInterval = 38; // how often to run the main loop (in ms) 83 | 84 | /* i2c data */ 85 | struct i2c_device_info { 86 | byte addr; 87 | byte reg; 88 | byte bytes; 89 | }; 90 | 91 | /* for i2c read continuous more */ 92 | i2c_device_info query[MAX_QUERIES]; 93 | 94 | byte i2cRxData[32]; 95 | boolean isI2CEnabled = false; 96 | signed char queryIndex = -1; 97 | unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() 98 | 99 | Servo servos[MAX_SERVOS]; 100 | /*============================================================================== 101 | * FUNCTIONS 102 | *============================================================================*/ 103 | 104 | void readAndReportData(byte address, int theRegister, byte numBytes) { 105 | // allow I2C requests that don't require a register read 106 | // for example, some devices using an interrupt pin to signify new data available 107 | // do not always require the register read so upon interrupt you call Wire.requestFrom() 108 | if (theRegister != REGISTER_NOT_SPECIFIED) { 109 | Wire.beginTransmission(address); 110 | #if ARDUINO >= 100 111 | Wire.write((byte)theRegister); 112 | #else 113 | Wire.send((byte)theRegister); 114 | #endif 115 | Wire.endTransmission(); 116 | delayMicroseconds(i2cReadDelayTime); // delay is necessary for some devices such as WiiNunchuck 117 | } else { 118 | theRegister = 0; // fill the register with a dummy value 119 | } 120 | 121 | Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom 122 | 123 | // check to be sure correct number of bytes were returned by slave 124 | if(numBytes == Wire.available()) { 125 | i2cRxData[0] = address; 126 | i2cRxData[1] = theRegister; 127 | for (int i = 0; i < numBytes; i++) { 128 | #if ARDUINO >= 100 129 | i2cRxData[2 + i] = Wire.read(); 130 | #else 131 | i2cRxData[2 + i] = Wire.receive(); 132 | #endif 133 | } 134 | } 135 | else { 136 | if(numBytes > Wire.available()) { 137 | BleFirmata.sendString("I2C Read Error: Too many bytes received"); 138 | } else { 139 | BleFirmata.sendString("I2C Read Error: Too few bytes received"); 140 | } 141 | } 142 | 143 | // send slave address, register and received bytes 144 | BleFirmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); 145 | } 146 | 147 | void outputPort(byte portNumber, byte portValue, byte forceSend) 148 | { 149 | // pins not configured as INPUT are cleared to zeros 150 | portValue = portValue & portConfigInputs[portNumber]; 151 | 152 | // only send if the value is different than previously sent 153 | if(forceSend || previousPINs[portNumber] != portValue) { 154 | BleFirmata.sendDigitalPort(portNumber, portValue); 155 | previousPINs[portNumber] = portValue; 156 | } 157 | } 158 | 159 | /* ----------------------------------------------------------------------------- 160 | * check all the active digital inputs for change of state, then add any events 161 | * to the Serial output queue using Serial.print() */ 162 | void checkDigitalInputs(void) 163 | { 164 | /* Using non-looping code allows constants to be given to readPort(). 165 | * The compiler will apply substantial optimizations if the inputs 166 | * to readPort() are compile-time constants. */ 167 | if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); 168 | if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); 169 | if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); 170 | if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); 171 | if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); 172 | if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); 173 | if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); 174 | if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); 175 | if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); 176 | if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); 177 | if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); 178 | if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); 179 | if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); 180 | if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); 181 | if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); 182 | if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); 183 | } 184 | 185 | // ----------------------------------------------------------------------------- 186 | /* sets the pin mode to the correct state and sets the relevant bits in the 187 | * two bit-arrays that track Digital I/O and PWM status 188 | */ 189 | void setPinModeCallback(byte pin, int mode) 190 | { 191 | if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { 192 | // disable i2c so pins can be used for other functions 193 | // the following if statements should reconfigure the pins properly 194 | disableI2CPins(); 195 | } 196 | if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) { 197 | servos[PIN_TO_SERVO(pin)].detach(); 198 | } 199 | if (IS_PIN_ANALOG(pin)) { 200 | reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting 201 | } 202 | if (IS_PIN_DIGITAL(pin)) { 203 | if (mode == INPUT) { 204 | portConfigInputs[pin/8] |= (1 << (pin & 7)); 205 | } else { 206 | portConfigInputs[pin/8] &= ~(1 << (pin & 7)); 207 | } 208 | } 209 | pinState[pin] = 0; 210 | switch(mode) { 211 | case ANALOG: 212 | if (IS_PIN_ANALOG(pin)) { 213 | if (IS_PIN_DIGITAL(pin)) { 214 | pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver 215 | digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups 216 | } 217 | pinConfig[pin] = ANALOG; 218 | } 219 | break; 220 | case INPUT: 221 | if (IS_PIN_DIGITAL(pin)) { 222 | pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver 223 | 224 | // Select your internal pull-up here 225 | digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups 226 | //digitalWrite(PIN_TO_DIGITAL(pin), HIGH); // enable internal pull-ups if you have only a wire to test 227 | pinConfig[pin] = INPUT; 228 | 229 | // hack it only 230 | reportPINs[pin/8] |= (1 << (pin & 7)); 231 | } 232 | break; 233 | case OUTPUT: 234 | if (IS_PIN_DIGITAL(pin)) { 235 | digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM 236 | pinMode(PIN_TO_DIGITAL(pin), OUTPUT); 237 | pinConfig[pin] = OUTPUT; 238 | } 239 | break; 240 | case PWM: 241 | if (IS_PIN_PWM(pin)) { 242 | pinMode(PIN_TO_PWM(pin), OUTPUT); 243 | analogWrite(PIN_TO_PWM(pin), 0); 244 | pinConfig[pin] = PWM; 245 | } 246 | break; 247 | case SERVO: 248 | if (IS_PIN_SERVO(pin)) { 249 | pinConfig[pin] = SERVO; 250 | if (!servos[PIN_TO_SERVO(pin)].attached()) { 251 | servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); 252 | } 253 | } 254 | break; 255 | case I2C: 256 | if (IS_PIN_I2C(pin)) { 257 | // mark the pin as i2c 258 | // the user must call I2C_CONFIG to enable I2C for a device 259 | pinConfig[pin] = I2C; 260 | } 261 | break; 262 | default: 263 | BleFirmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM 264 | } 265 | // TODO: save status to EEPROM here, if changed 266 | } 267 | 268 | void analogWriteCallback(byte pin, int value) 269 | { 270 | if (pin < TOTAL_PINS) { 271 | switch(pinConfig[pin]) { 272 | case SERVO: 273 | if (IS_PIN_SERVO(pin)) 274 | servos[PIN_TO_SERVO(pin)].write(value); 275 | pinState[pin] = value; 276 | break; 277 | case PWM: 278 | if (IS_PIN_PWM(pin)) 279 | analogWrite(PIN_TO_PWM(pin), value); 280 | pinState[pin] = value; 281 | break; 282 | } 283 | } 284 | } 285 | 286 | void digitalWriteCallback(byte port, int value) 287 | { 288 | byte pin, lastPin, mask=1, pinWriteMask=0; 289 | 290 | if (port < TOTAL_PORTS) { 291 | // create a mask of the pins on this port that are writable. 292 | lastPin = port*8+8; 293 | if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; 294 | for (pin=port*8; pin < lastPin; pin++) { 295 | // do not disturb non-digital pins (eg, Rx & Tx) 296 | if (IS_PIN_DIGITAL(pin)) { 297 | // only write to OUTPUT and INPUT (enables pullup) 298 | // do not touch pins in PWM, ANALOG, SERVO or other modes 299 | if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { 300 | pinWriteMask |= mask; 301 | pinState[pin] = ((byte)value & mask) ? 1 : 0; 302 | } 303 | } 304 | mask = mask << 1; 305 | } 306 | writePort(port, (byte)value, pinWriteMask); 307 | } 308 | } 309 | 310 | 311 | // ----------------------------------------------------------------------------- 312 | /* sets bits in a bit array (int) to toggle the reporting of the analogIns 313 | */ 314 | //void FirmataClass::setAnalogPinReporting(byte pin, byte state) { 315 | //} 316 | void reportAnalogCallback(byte analogPin, int value) 317 | { 318 | if (analogPin < TOTAL_ANALOG_PINS) { 319 | if(value == 0) { 320 | analogInputsToReport = analogInputsToReport &~ (1 << analogPin); 321 | } else { 322 | analogInputsToReport = analogInputsToReport | (1 << analogPin); 323 | } 324 | } 325 | // TODO: save status to EEPROM here, if changed 326 | } 327 | 328 | void reportDigitalCallback(byte port, int value) 329 | { 330 | if (port < TOTAL_PORTS) { 331 | reportPINs[port] = (byte)value; 332 | } 333 | // do not disable analog reporting on these 8 pins, to allow some 334 | // pins used for digital, others analog. Instead, allow both types 335 | // of reporting to be enabled, but check if the pin is configured 336 | // as analog when sampling the analog inputs. Likewise, while 337 | // scanning digital pins, portConfigInputs will mask off values from any 338 | // pins configured as analog 339 | } 340 | 341 | /*============================================================================== 342 | * SYSEX-BASED commands 343 | *============================================================================*/ 344 | 345 | void sysexCallback(byte command, byte argc, byte *argv) 346 | { 347 | byte mode; 348 | byte slaveAddress; 349 | byte slaveRegister; 350 | byte data; 351 | unsigned int delayTime; 352 | 353 | switch(command) { 354 | case I2C_REQUEST: 355 | mode = argv[1] & I2C_READ_WRITE_MODE_MASK; 356 | if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { 357 | BleFirmata.sendString("10-bit addressing mode is not yet supported"); 358 | return; 359 | } 360 | else { 361 | slaveAddress = argv[0]; 362 | } 363 | 364 | switch(mode) { 365 | case I2C_WRITE: 366 | Wire.beginTransmission(slaveAddress); 367 | for (byte i = 2; i < argc; i += 2) { 368 | data = argv[i] + (argv[i + 1] << 7); 369 | #if ARDUINO >= 100 370 | Wire.write(data); 371 | #else 372 | Wire.send(data); 373 | #endif 374 | } 375 | Wire.endTransmission(); 376 | delayMicroseconds(70); 377 | break; 378 | case I2C_READ: 379 | if (argc == 6) { 380 | // a slave register is specified 381 | slaveRegister = argv[2] + (argv[3] << 7); 382 | data = argv[4] + (argv[5] << 7); // bytes to read 383 | readAndReportData(slaveAddress, (int)slaveRegister, data); 384 | } 385 | else { 386 | // a slave register is NOT specified 387 | data = argv[2] + (argv[3] << 7); // bytes to read 388 | readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); 389 | } 390 | break; 391 | case I2C_READ_CONTINUOUSLY: 392 | if ((queryIndex + 1) >= MAX_QUERIES) { 393 | // too many queries, just ignore 394 | BleFirmata.sendString("too many queries"); 395 | break; 396 | } 397 | queryIndex++; 398 | query[queryIndex].addr = slaveAddress; 399 | query[queryIndex].reg = argv[2] + (argv[3] << 7); 400 | query[queryIndex].bytes = argv[4] + (argv[5] << 7); 401 | break; 402 | case I2C_STOP_READING: 403 | byte queryIndexToSkip; 404 | // if read continuous mode is enabled for only 1 i2c device, disable 405 | // read continuous reporting for that device 406 | if (queryIndex <= 0) { 407 | queryIndex = -1; 408 | } else { 409 | // if read continuous mode is enabled for multiple devices, 410 | // determine which device to stop reading and remove it's data from 411 | // the array, shifiting other array data to fill the space 412 | for (byte i = 0; i < queryIndex + 1; i++) { 413 | if (query[i].addr = slaveAddress) { 414 | queryIndexToSkip = i; 415 | break; 416 | } 417 | } 418 | 419 | for (byte i = queryIndexToSkip; i 0) { 437 | i2cReadDelayTime = delayTime; 438 | } 439 | 440 | if (!isI2CEnabled) { 441 | enableI2CPins(); 442 | } 443 | 444 | break; 445 | case SERVO_CONFIG: 446 | if(argc > 4) { 447 | // these vars are here for clarity, they'll optimized away by the compiler 448 | byte pin = argv[0]; 449 | int minPulse = argv[1] + (argv[2] << 7); 450 | int maxPulse = argv[3] + (argv[4] << 7); 451 | 452 | if (IS_PIN_SERVO(pin)) { 453 | if (servos[PIN_TO_SERVO(pin)].attached()) 454 | servos[PIN_TO_SERVO(pin)].detach(); 455 | servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); 456 | setPinModeCallback(pin, SERVO); 457 | } 458 | } 459 | break; 460 | case SAMPLING_INTERVAL: 461 | if (argc > 1) { 462 | samplingInterval = argv[0] + (argv[1] << 7); 463 | if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { 464 | samplingInterval = MINIMUM_SAMPLING_INTERVAL; 465 | } 466 | } else { 467 | //Firmata.sendString("Not enough data"); 468 | } 469 | break; 470 | case EXTENDED_ANALOG: 471 | if (argc > 1) { 472 | int val = argv[1]; 473 | if (argc > 2) val |= (argv[2] << 7); 474 | if (argc > 3) val |= (argv[3] << 14); 475 | analogWriteCallback(argv[0], val); 476 | } 477 | break; 478 | case CAPABILITY_QUERY: 479 | ble_write(START_SYSEX); 480 | ble_write(CAPABILITY_RESPONSE); 481 | for (byte pin=0; pin < TOTAL_PINS; pin++) { 482 | if (IS_PIN_DIGITAL(pin)) { 483 | ble_write((byte)INPUT); 484 | ble_write(1); 485 | ble_write((byte)OUTPUT); 486 | ble_write(1); 487 | } 488 | if (IS_PIN_ANALOG(pin)) { 489 | ble_write(ANALOG); 490 | ble_write(10); 491 | } 492 | if (IS_PIN_PWM(pin)) { 493 | ble_write(PWM); 494 | ble_write(8); 495 | } 496 | if (IS_PIN_SERVO(pin)) { 497 | ble_write(SERVO); 498 | ble_write(14); 499 | } 500 | if (IS_PIN_I2C(pin)) { 501 | ble_write(I2C); 502 | ble_write(1); // to do: determine appropriate value 503 | } 504 | ble_write(127); 505 | } 506 | ble_write(END_SYSEX); 507 | break; 508 | case PIN_STATE_QUERY: 509 | if (argc > 0) { 510 | byte pin=argv[0]; 511 | ble_write(START_SYSEX); 512 | ble_write(PIN_STATE_RESPONSE); 513 | ble_write(pin); 514 | if (pin < TOTAL_PINS) { 515 | ble_write((byte)pinConfig[pin]); 516 | ble_write((byte)pinState[pin] & 0x7F); 517 | if (pinState[pin] & 0xFF80) ble_write((byte)(pinState[pin] >> 7) & 0x7F); 518 | if (pinState[pin] & 0xC000) ble_write((byte)(pinState[pin] >> 14) & 0x7F); 519 | } 520 | ble_write(END_SYSEX); 521 | } 522 | break; 523 | case ANALOG_MAPPING_QUERY: 524 | ble_write(START_SYSEX); 525 | ble_write(ANALOG_MAPPING_RESPONSE); 526 | for (byte pin=0; pin < TOTAL_PINS; pin++) { 527 | ble_write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); 528 | } 529 | ble_write(END_SYSEX); 530 | break; 531 | } 532 | } 533 | 534 | void enableI2CPins() 535 | { 536 | byte i; 537 | // is there a faster way to do this? would probaby require importing 538 | // Arduino.h to get SCL and SDA pins 539 | for (i=0; i < TOTAL_PINS; i++) { 540 | if(IS_PIN_I2C(i)) { 541 | // mark pins as i2c so they are ignore in non i2c data requests 542 | setPinModeCallback(i, I2C); 543 | } 544 | } 545 | 546 | isI2CEnabled = true; 547 | 548 | // is there enough time before the first I2C request to call this here? 549 | Wire.begin(); 550 | } 551 | 552 | /* disable the i2c pins so they can be used for other functions */ 553 | void disableI2CPins() { 554 | isI2CEnabled = false; 555 | // disable read continuous mode for all devices 556 | queryIndex = -1; 557 | // uncomment the following if or when the end() method is added to Wire library 558 | // Wire.end(); 559 | } 560 | 561 | /*============================================================================== 562 | * SETUP() 563 | *============================================================================*/ 564 | 565 | void systemResetCallback() 566 | { 567 | // initialize a defalt state 568 | // TODO: option to load config from EEPROM instead of default 569 | if (isI2CEnabled) { 570 | disableI2CPins(); 571 | } 572 | for (byte i=0; i < TOTAL_PORTS; i++) { 573 | reportPINs[i] = false; // by default, reporting off 574 | portConfigInputs[i] = 0; // until activated 575 | previousPINs[i] = 0; 576 | } 577 | // pins with analog capability default to analog input 578 | // otherwise, pins default to digital output 579 | for (byte i=0; i < TOTAL_PINS; i++) { 580 | 581 | #if defined(BLEND_MICRO) 582 | // skip pin 4, 6, 7 for BlendMicro BLE controll 583 | if ((i == 4) || (i == 6) || (i == 7)) 584 | continue; 585 | #else 586 | // skip pin 8, 9 for BLE Shield 587 | if ((i == 8) || (i == 9)) 588 | continue; 589 | #endif 590 | 591 | // skip SPI pins 592 | if ( (i==MOSI) || (i==MISO) || (i==SCK) || (i==SS) ) 593 | continue; 594 | 595 | // Default all to digital pins 596 | if (IS_PIN_ANALOG(i)) { 597 | // turns off pullup, configures everything 598 | setPinModeCallback(i, ANALOG); 599 | } else { 600 | // sets the output to 0, configures portConfigInputs 601 | //setPinModeCallback(i, OUTPUT); 602 | } 603 | } 604 | // by default, do not report any analog inputs 605 | analogInputsToReport = 0; 606 | 607 | /* send digital inputs to set the initial state on the host computer, 608 | * since once in the loop(), this firmware will only send on change */ 609 | /* 610 | TODO: this can never execute, since no pins default to digital input 611 | but it will be needed when/if we support EEPROM stored config 612 | for (byte i=0; i < TOTAL_PORTS; i++) { 613 | outputPort(i, readPort(i, portConfigInputs[i]), true); 614 | } 615 | */ 616 | } 617 | 618 | void setup() 619 | { 620 | BleFirmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); 621 | 622 | BleFirmata.attach(ANALOG_MESSAGE, analogWriteCallback); 623 | BleFirmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); 624 | BleFirmata.attach(REPORT_ANALOG, reportAnalogCallback); 625 | BleFirmata.attach(REPORT_DIGITAL, reportDigitalCallback); 626 | BleFirmata.attach(SET_PIN_MODE, setPinModeCallback); 627 | BleFirmata.attach(START_SYSEX, sysexCallback); 628 | BleFirmata.attach(SYSTEM_RESET, systemResetCallback); 629 | 630 | // BleFirmata.begin(57600); 631 | systemResetCallback(); // reset to default config 632 | 633 | // Enable serial debug 634 | Serial.begin(57600); 635 | 636 | // Default pins set to 9 and 8 for REQN and RDYN 637 | // Set your REQN and RDYN here before ble_begin() if you need 638 | //ble_set_pins(3, 2); 639 | 640 | // Set your BLE Shield name here, max. length 10 641 | ble_set_name(BLE_NAME); 642 | 643 | // Init. BLE and start BLE library. 644 | ble_begin(); 645 | } 646 | 647 | /*============================================================================== 648 | * LOOP() 649 | *============================================================================*/ 650 | void loop() 651 | { 652 | byte pin, analogPin; 653 | 654 | /* DIGITALREAD - as fast as possible, check for changes and output them to the 655 | * FTDI buffer using Serial.print() */ 656 | checkDigitalInputs(); 657 | 658 | /* SERIALREAD - processing incoming messagse as soon as possible, while still 659 | * checking digital inputs. */ 660 | while(BleFirmata.available()) 661 | BleFirmata.processInput(); 662 | 663 | /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over 664 | * 60 bytes. use a timer to sending an event character every 4 ms to 665 | * trigger the buffer to dump. */ 666 | 667 | currentMillis = millis(); 668 | if (currentMillis - previousMillis > samplingInterval) { 669 | previousMillis += samplingInterval; 670 | /* ANALOGREAD - do all analogReads() at the configured sampling interval */ 671 | for(pin=0; pin -1) { 684 | for (byte i = 0; i < queryIndex + 1; i++) { 685 | readAndReportData(query[i].addr, query[i].reg, query[i].bytes); 686 | } 687 | } 688 | } 689 | 690 | if (!ble_connected()) 691 | systemResetCallback(); 692 | 693 | ble_do_events(); 694 | } 695 | 696 | -------------------------------------------------------------------------------- /samples/sysex/BLEFirmataWithLedBlink/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | GNU LESSER GENERAL PUBLIC LICENSE 3 | Version 2.1, February 1999 4 | 5 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 6 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 7 | Everyone is permitted to copy and distribute verbatim copies 8 | of this license document, but changing it is not allowed. 9 | 10 | [This is the first released version of the Lesser GPL. It also counts 11 | as the successor of the GNU Library Public License, version 2, hence 12 | the version number 2.1.] 13 | 14 | Preamble 15 | 16 | The licenses for most software are designed to take away your 17 | freedom to share and change it. By contrast, the GNU General Public 18 | Licenses are intended to guarantee your freedom to share and change 19 | free software--to make sure the software is free for all its users. 20 | 21 | This license, the Lesser General Public License, applies to some 22 | specially designated software packages--typically libraries--of the 23 | Free Software Foundation and other authors who decide to use it. You 24 | can use it too, but we suggest you first think carefully about whether 25 | this license or the ordinary General Public License is the better 26 | strategy to use in any particular case, based on the explanations below. 27 | 28 | When we speak of free software, we are referring to freedom of use, 29 | not price. Our General Public Licenses are designed to make sure that 30 | you have the freedom to distribute copies of free software (and charge 31 | for this service if you wish); that you receive source code or can get 32 | it if you want it; that you can change the software and use pieces of 33 | it in new free programs; and that you are informed that you can do 34 | these things. 35 | 36 | To protect your rights, we need to make restrictions that forbid 37 | distributors to deny you these rights or to ask you to surrender these 38 | rights. These restrictions translate to certain responsibilities for 39 | you if you distribute copies of the library or if you modify it. 40 | 41 | For example, if you distribute copies of the library, whether gratis 42 | or for a fee, you must give the recipients all the rights that we gave 43 | you. You must make sure that they, too, receive or can get the source 44 | code. If you link other code with the library, you must provide 45 | complete object files to the recipients, so that they can relink them 46 | with the library after making changes to the library and recompiling 47 | it. And you must show them these terms so they know their rights. 48 | 49 | We protect your rights with a two-step method: (1) we copyright the 50 | library, and (2) we offer you this license, which gives you legal 51 | permission to copy, distribute and/or modify the library. 52 | 53 | To protect each distributor, we want to make it very clear that 54 | there is no warranty for the free library. Also, if the library is 55 | modified by someone else and passed on, the recipients should know 56 | that what they have is not the original version, so that the original 57 | author's reputation will not be affected by problems that might be 58 | introduced by others. 59 | 60 | Finally, software patents pose a constant threat to the existence of 61 | any free program. We wish to make sure that a company cannot 62 | effectively restrict the users of a free program by obtaining a 63 | restrictive license from a patent holder. Therefore, we insist that 64 | any patent license obtained for a version of the library must be 65 | consistent with the full freedom of use specified in this license. 66 | 67 | Most GNU software, including some libraries, is covered by the 68 | ordinary GNU General Public License. This license, the GNU Lesser 69 | General Public License, applies to certain designated libraries, and 70 | is quite different from the ordinary General Public License. We use 71 | this license for certain libraries in order to permit linking those 72 | libraries into non-free programs. 73 | 74 | When a program is linked with a library, whether statically or using 75 | a shared library, the combination of the two is legally speaking a 76 | combined work, a derivative of the original library. The ordinary 77 | General Public License therefore permits such linking only if the 78 | entire combination fits its criteria of freedom. The Lesser General 79 | Public License permits more lax criteria for linking other code with 80 | the library. 81 | 82 | We call this license the "Lesser" General Public License because it 83 | does Less to protect the user's freedom than the ordinary General 84 | Public License. It also provides other free software developers Less 85 | of an advantage over competing non-free programs. These disadvantages 86 | are the reason we use the ordinary General Public License for many 87 | libraries. However, the Lesser license provides advantages in certain 88 | special circumstances. 89 | 90 | For example, on rare occasions, there may be a special need to 91 | encourage the widest possible use of a certain library, so that it becomes 92 | a de-facto standard. To achieve this, non-free programs must be 93 | allowed to use the library. A more frequent case is that a free 94 | library does the same job as widely used non-free libraries. In this 95 | case, there is little to gain by limiting the free library to free 96 | software only, so we use the Lesser General Public License. 97 | 98 | In other cases, permission to use a particular library in non-free 99 | programs enables a greater number of people to use a large body of 100 | free software. For example, permission to use the GNU C Library in 101 | non-free programs enables many more people to use the whole GNU 102 | operating system, as well as its variant, the GNU/Linux operating 103 | system. 104 | 105 | Although the Lesser General Public License is Less protective of the 106 | users' freedom, it does ensure that the user of a program that is 107 | linked with the Library has the freedom and the wherewithal to run 108 | that program using a modified version of the Library. 109 | 110 | The precise terms and conditions for copying, distribution and 111 | modification follow. Pay close attention to the difference between a 112 | "work based on the library" and a "work that uses the library". The 113 | former contains code derived from the library, whereas the latter must 114 | be combined with the library in order to run. 115 | 116 | GNU LESSER GENERAL PUBLIC LICENSE 117 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 118 | 119 | 0. This License Agreement applies to any software library or other 120 | program which contains a notice placed by the copyright holder or 121 | other authorized party saying it may be distributed under the terms of 122 | this Lesser General Public License (also called "this License"). 123 | Each licensee is addressed as "you". 124 | 125 | A "library" means a collection of software functions and/or data 126 | prepared so as to be conveniently linked with application programs 127 | (which use some of those functions and data) to form executables. 128 | 129 | The "Library", below, refers to any such software library or work 130 | which has been distributed under these terms. A "work based on the 131 | Library" means either the Library or any derivative work under 132 | copyright law: that is to say, a work containing the Library or a 133 | portion of it, either verbatim or with modifications and/or translated 134 | straightforwardly into another language. (Hereinafter, translation is 135 | included without limitation in the term "modification".) 136 | 137 | "Source code" for a work means the preferred form of the work for 138 | making modifications to it. For a library, complete source code means 139 | all the source code for all modules it contains, plus any associated 140 | interface definition files, plus the scripts used to control compilation 141 | and installation of the library. 142 | 143 | Activities other than copying, distribution and modification are not 144 | covered by this License; they are outside its scope. The act of 145 | running a program using the Library is not restricted, and output from 146 | such a program is covered only if its contents constitute a work based 147 | on the Library (independent of the use of the Library in a tool for 148 | writing it). Whether that is true depends on what the Library does 149 | and what the program that uses the Library does. 150 | 151 | 1. You may copy and distribute verbatim copies of the Library's 152 | complete source code as you receive it, in any medium, provided that 153 | you conspicuously and appropriately publish on each copy an 154 | appropriate copyright notice and disclaimer of warranty; keep intact 155 | all the notices that refer to this License and to the absence of any 156 | warranty; and distribute a copy of this License along with the 157 | Library. 158 | 159 | You may charge a fee for the physical act of transferring a copy, 160 | and you may at your option offer warranty protection in exchange for a 161 | fee. 162 | 163 | 2. You may modify your copy or copies of the Library or any portion 164 | of it, thus forming a work based on the Library, and copy and 165 | distribute such modifications or work under the terms of Section 1 166 | above, provided that you also meet all of these conditions: 167 | 168 | a) The modified work must itself be a software library. 169 | 170 | b) You must cause the files modified to carry prominent notices 171 | stating that you changed the files and the date of any change. 172 | 173 | c) You must cause the whole of the work to be licensed at no 174 | charge to all third parties under the terms of this License. 175 | 176 | d) If a facility in the modified Library refers to a function or a 177 | table of data to be supplied by an application program that uses 178 | the facility, other than as an argument passed when the facility 179 | is invoked, then you must make a good faith effort to ensure that, 180 | in the event an application does not supply such function or 181 | table, the facility still operates, and performs whatever part of 182 | its purpose remains meaningful. 183 | 184 | (For example, a function in a library to compute square roots has 185 | a purpose that is entirely well-defined independent of the 186 | application. Therefore, Subsection 2d requires that any 187 | application-supplied function or table used by this function must 188 | be optional: if the application does not supply it, the square 189 | root function must still compute square roots.) 190 | 191 | These requirements apply to the modified work as a whole. If 192 | identifiable sections of that work are not derived from the Library, 193 | and can be reasonably considered independent and separate works in 194 | themselves, then this License, and its terms, do not apply to those 195 | sections when you distribute them as separate works. But when you 196 | distribute the same sections as part of a whole which is a work based 197 | on the Library, the distribution of the whole must be on the terms of 198 | this License, whose permissions for other licensees extend to the 199 | entire whole, and thus to each and every part regardless of who wrote 200 | it. 201 | 202 | Thus, it is not the intent of this section to claim rights or contest 203 | your rights to work written entirely by you; rather, the intent is to 204 | exercise the right to control the distribution of derivative or 205 | collective works based on the Library. 206 | 207 | In addition, mere aggregation of another work not based on the Library 208 | with the Library (or with a work based on the Library) on a volume of 209 | a storage or distribution medium does not bring the other work under 210 | the scope of this License. 211 | 212 | 3. You may opt to apply the terms of the ordinary GNU General Public 213 | License instead of this License to a given copy of the Library. To do 214 | this, you must alter all the notices that refer to this License, so 215 | that they refer to the ordinary GNU General Public License, version 2, 216 | instead of to this License. (If a newer version than version 2 of the 217 | ordinary GNU General Public License has appeared, then you can specify 218 | that version instead if you wish.) Do not make any other change in 219 | these notices. 220 | 221 | Once this change is made in a given copy, it is irreversible for 222 | that copy, so the ordinary GNU General Public License applies to all 223 | subsequent copies and derivative works made from that copy. 224 | 225 | This option is useful when you wish to copy part of the code of 226 | the Library into a program that is not a library. 227 | 228 | 4. You may copy and distribute the Library (or a portion or 229 | derivative of it, under Section 2) in object code or executable form 230 | under the terms of Sections 1 and 2 above provided that you accompany 231 | it with the complete corresponding machine-readable source code, which 232 | must be distributed under the terms of Sections 1 and 2 above on a 233 | medium customarily used for software interchange. 234 | 235 | If distribution of object code is made by offering access to copy 236 | from a designated place, then offering equivalent access to copy the 237 | source code from the same place satisfies the requirement to 238 | distribute the source code, even though third parties are not 239 | compelled to copy the source along with the object code. 240 | 241 | 5. A program that contains no derivative of any portion of the 242 | Library, but is designed to work with the Library by being compiled or 243 | linked with it, is called a "work that uses the Library". Such a 244 | work, in isolation, is not a derivative work of the Library, and 245 | therefore falls outside the scope of this License. 246 | 247 | However, linking a "work that uses the Library" with the Library 248 | creates an executable that is a derivative of the Library (because it 249 | contains portions of the Library), rather than a "work that uses the 250 | library". The executable is therefore covered by this License. 251 | Section 6 states terms for distribution of such executables. 252 | 253 | When a "work that uses the Library" uses material from a header file 254 | that is part of the Library, the object code for the work may be a 255 | derivative work of the Library even though the source code is not. 256 | Whether this is true is especially significant if the work can be 257 | linked without the Library, or if the work is itself a library. The 258 | threshold for this to be true is not precisely defined by law. 259 | 260 | If such an object file uses only numerical parameters, data 261 | structure layouts and accessors, and small macros and small inline 262 | functions (ten lines or less in length), then the use of the object 263 | file is unrestricted, regardless of whether it is legally a derivative 264 | work. (Executables containing this object code plus portions of the 265 | Library will still fall under Section 6.) 266 | 267 | Otherwise, if the work is a derivative of the Library, you may 268 | distribute the object code for the work under the terms of Section 6. 269 | Any executables containing that work also fall under Section 6, 270 | whether or not they are linked directly with the Library itself. 271 | 272 | 6. As an exception to the Sections above, you may also combine or 273 | link a "work that uses the Library" with the Library to produce a 274 | work containing portions of the Library, and distribute that work 275 | under terms of your choice, provided that the terms permit 276 | modification of the work for the customer's own use and reverse 277 | engineering for debugging such modifications. 278 | 279 | You must give prominent notice with each copy of the work that the 280 | Library is used in it and that the Library and its use are covered by 281 | this License. You must supply a copy of this License. If the work 282 | during execution displays copyright notices, you must include the 283 | copyright notice for the Library among them, as well as a reference 284 | directing the user to the copy of this License. Also, you must do one 285 | of these things: 286 | 287 | a) Accompany the work with the complete corresponding 288 | machine-readable source code for the Library including whatever 289 | changes were used in the work (which must be distributed under 290 | Sections 1 and 2 above); and, if the work is an executable linked 291 | with the Library, with the complete machine-readable "work that 292 | uses the Library", as object code and/or source code, so that the 293 | user can modify the Library and then relink to produce a modified 294 | executable containing the modified Library. (It is understood 295 | that the user who changes the contents of definitions files in the 296 | Library will not necessarily be able to recompile the application 297 | to use the modified definitions.) 298 | 299 | b) Use a suitable shared library mechanism for linking with the 300 | Library. A suitable mechanism is one that (1) uses at run time a 301 | copy of the library already present on the user's computer system, 302 | rather than copying library functions into the executable, and (2) 303 | will operate properly with a modified version of the library, if 304 | the user installs one, as long as the modified version is 305 | interface-compatible with the version that the work was made with. 306 | 307 | c) Accompany the work with a written offer, valid for at 308 | least three years, to give the same user the materials 309 | specified in Subsection 6a, above, for a charge no more 310 | than the cost of performing this distribution. 311 | 312 | d) If distribution of the work is made by offering access to copy 313 | from a designated place, offer equivalent access to copy the above 314 | specified materials from the same place. 315 | 316 | e) Verify that the user has already received a copy of these 317 | materials or that you have already sent this user a copy. 318 | 319 | For an executable, the required form of the "work that uses the 320 | Library" must include any data and utility programs needed for 321 | reproducing the executable from it. However, as a special exception, 322 | the materials to be distributed need not include anything that is 323 | normally distributed (in either source or binary form) with the major 324 | components (compiler, kernel, and so on) of the operating system on 325 | which the executable runs, unless that component itself accompanies 326 | the executable. 327 | 328 | It may happen that this requirement contradicts the license 329 | restrictions of other proprietary libraries that do not normally 330 | accompany the operating system. Such a contradiction means you cannot 331 | use both them and the Library together in an executable that you 332 | distribute. 333 | 334 | 7. You may place library facilities that are a work based on the 335 | Library side-by-side in a single library together with other library 336 | facilities not covered by this License, and distribute such a combined 337 | library, provided that the separate distribution of the work based on 338 | the Library and of the other library facilities is otherwise 339 | permitted, and provided that you do these two things: 340 | 341 | a) Accompany the combined library with a copy of the same work 342 | based on the Library, uncombined with any other library 343 | facilities. This must be distributed under the terms of the 344 | Sections above. 345 | 346 | b) Give prominent notice with the combined library of the fact 347 | that part of it is a work based on the Library, and explaining 348 | where to find the accompanying uncombined form of the same work. 349 | 350 | 8. You may not copy, modify, sublicense, link with, or distribute 351 | the Library except as expressly provided under this License. Any 352 | attempt otherwise to copy, modify, sublicense, link with, or 353 | distribute the Library is void, and will automatically terminate your 354 | rights under this License. However, parties who have received copies, 355 | or rights, from you under this License will not have their licenses 356 | terminated so long as such parties remain in full compliance. 357 | 358 | 9. You are not required to accept this License, since you have not 359 | signed it. However, nothing else grants you permission to modify or 360 | distribute the Library or its derivative works. These actions are 361 | prohibited by law if you do not accept this License. Therefore, by 362 | modifying or distributing the Library (or any work based on the 363 | Library), you indicate your acceptance of this License to do so, and 364 | all its terms and conditions for copying, distributing or modifying 365 | the Library or works based on it. 366 | 367 | 10. Each time you redistribute the Library (or any work based on the 368 | Library), the recipient automatically receives a license from the 369 | original licensor to copy, distribute, link with or modify the Library 370 | subject to these terms and conditions. You may not impose any further 371 | restrictions on the recipients' exercise of the rights granted herein. 372 | You are not responsible for enforcing compliance by third parties with 373 | this License. 374 | 375 | 11. If, as a consequence of a court judgment or allegation of patent 376 | infringement or for any other reason (not limited to patent issues), 377 | conditions are imposed on you (whether by court order, agreement or 378 | otherwise) that contradict the conditions of this License, they do not 379 | excuse you from the conditions of this License. If you cannot 380 | distribute so as to satisfy simultaneously your obligations under this 381 | License and any other pertinent obligations, then as a consequence you 382 | may not distribute the Library at all. For example, if a patent 383 | license would not permit royalty-free redistribution of the Library by 384 | all those who receive copies directly or indirectly through you, then 385 | the only way you could satisfy both it and this License would be to 386 | refrain entirely from distribution of the Library. 387 | 388 | If any portion of this section is held invalid or unenforceable under any 389 | particular circumstance, the balance of the section is intended to apply, 390 | and the section as a whole is intended to apply in other circumstances. 391 | 392 | It is not the purpose of this section to induce you to infringe any 393 | patents or other property right claims or to contest validity of any 394 | such claims; this section has the sole purpose of protecting the 395 | integrity of the free software distribution system which is 396 | implemented by public license practices. Many people have made 397 | generous contributions to the wide range of software distributed 398 | through that system in reliance on consistent application of that 399 | system; it is up to the author/donor to decide if he or she is willing 400 | to distribute software through any other system and a licensee cannot 401 | impose that choice. 402 | 403 | This section is intended to make thoroughly clear what is believed to 404 | be a consequence of the rest of this License. 405 | 406 | 12. If the distribution and/or use of the Library is restricted in 407 | certain countries either by patents or by copyrighted interfaces, the 408 | original copyright holder who places the Library under this License may add 409 | an explicit geographical distribution limitation excluding those countries, 410 | so that distribution is permitted only in or among countries not thus 411 | excluded. In such case, this License incorporates the limitation as if 412 | written in the body of this License. 413 | 414 | 13. The Free Software Foundation may publish revised and/or new 415 | versions of the Lesser General Public License from time to time. 416 | Such new versions will be similar in spirit to the present version, 417 | but may differ in detail to address new problems or concerns. 418 | 419 | Each version is given a distinguishing version number. If the Library 420 | specifies a version number of this License which applies to it and 421 | "any later version", you have the option of following the terms and 422 | conditions either of that version or of any later version published by 423 | the Free Software Foundation. If the Library does not specify a 424 | license version number, you may choose any version ever published by 425 | the Free Software Foundation. 426 | 427 | 14. If you wish to incorporate parts of the Library into other free 428 | programs whose distribution conditions are incompatible with these, 429 | write to the author to ask for permission. For software which is 430 | copyrighted by the Free Software Foundation, write to the Free 431 | Software Foundation; we sometimes make exceptions for this. Our 432 | decision will be guided by the two goals of preserving the free status 433 | of all derivatives of our free software and of promoting the sharing 434 | and reuse of software generally. 435 | 436 | NO WARRANTY 437 | 438 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 439 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 440 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 441 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 442 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 443 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 444 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 445 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 446 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 447 | 448 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 449 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 450 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 451 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 452 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 453 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 454 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 455 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 456 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 457 | DAMAGES. 458 | 459 | -------------------------------------------------------------------------------- /samples/sysex/BLEFirmataWithLedBlink/BLEFirmataWithLedBlink.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * BLEFirmataSketch 3 | * 4 | * This sketch is for the BLE Arduino App 5 | * It is a modified version of the Standard Firmata 6 | * sketch by adding support for BLE. 7 | * 8 | */ 9 | 10 | #define BLE_NAME "BlendMicro" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "BLEFirmata.h" 17 | #include 18 | 19 | /* 20 | * Firmata is a generic protocol for communicating with microcontrollers 21 | * from software on a host computer. It is intended to work with 22 | * any host computer software package. 23 | * 24 | * To download a host software package, please clink on the following link 25 | * to open the download page in your default browser. 26 | * 27 | * http://firmata.org/wiki/Download 28 | */ 29 | 30 | /* 31 | Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. 32 | Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. 33 | Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. 34 | Copyright (C) 2009-2011 Jeff Hoefs. All rights reserved. 35 | 36 | This library is free software; you can redistribute it and/or 37 | modify it under the terms of the GNU Lesser General Public 38 | License as published by the Free Software Foundation; either 39 | version 2.1 of the License, or (at your option) any later version. 40 | 41 | See file LICENSE.txt for further informations on licensing terms. 42 | 43 | formatted using the GNU C formatting and indenting 44 | */ 45 | 46 | /* 47 | * TODO: use Program Control to load stored profiles from EEPROM 48 | */ 49 | 50 | // move the following defines to Firmata.h? 51 | #define I2C_WRITE B00000000 52 | #define I2C_READ B00001000 53 | #define I2C_READ_CONTINUOUSLY B00010000 54 | #define I2C_STOP_READING B00011000 55 | #define I2C_READ_WRITE_MODE_MASK B00011000 56 | #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 57 | 58 | #define MAX_QUERIES 8 59 | #define MINIMUM_SAMPLING_INTERVAL 10 60 | 61 | #define REGISTER_NOT_SPECIFIED -1 62 | 63 | /*============================================================================== 64 | * GLOBAL VARIABLES 65 | *============================================================================*/ 66 | 67 | /* analog inputs */ 68 | int analogInputsToReport = 0; // bitwise array to store pin reporting 69 | 70 | /* digital input ports */ 71 | byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence 72 | byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent 73 | 74 | /* pins configuration */ 75 | byte pinConfig[TOTAL_PINS]; // configuration of every pin 76 | byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else 77 | int pinState[TOTAL_PINS]; // any value that has been written 78 | 79 | /* timer variables */ 80 | unsigned long currentMillis; // store the current value from millis() 81 | unsigned long previousMillis; // for comparison with currentMillis 82 | int samplingInterval = 38; // how often to run the main loop (in ms) 83 | 84 | /* i2c data */ 85 | struct i2c_device_info { 86 | byte addr; 87 | byte reg; 88 | byte bytes; 89 | }; 90 | 91 | /* for i2c read continuous more */ 92 | i2c_device_info query[MAX_QUERIES]; 93 | 94 | byte i2cRxData[32]; 95 | boolean isI2CEnabled = false; 96 | signed char queryIndex = -1; 97 | unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() 98 | 99 | Servo servos[MAX_SERVOS]; 100 | /*============================================================================== 101 | * FUNCTIONS 102 | *============================================================================*/ 103 | 104 | void readAndReportData(byte address, int theRegister, byte numBytes) { 105 | // allow I2C requests that don't require a register read 106 | // for example, some devices using an interrupt pin to signify new data available 107 | // do not always require the register read so upon interrupt you call Wire.requestFrom() 108 | if (theRegister != REGISTER_NOT_SPECIFIED) { 109 | Wire.beginTransmission(address); 110 | #if ARDUINO >= 100 111 | Wire.write((byte)theRegister); 112 | #else 113 | Wire.send((byte)theRegister); 114 | #endif 115 | Wire.endTransmission(); 116 | delayMicroseconds(i2cReadDelayTime); // delay is necessary for some devices such as WiiNunchuck 117 | } else { 118 | theRegister = 0; // fill the register with a dummy value 119 | } 120 | 121 | Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom 122 | 123 | // check to be sure correct number of bytes were returned by slave 124 | if(numBytes == Wire.available()) { 125 | i2cRxData[0] = address; 126 | i2cRxData[1] = theRegister; 127 | for (int i = 0; i < numBytes; i++) { 128 | #if ARDUINO >= 100 129 | i2cRxData[2 + i] = Wire.read(); 130 | #else 131 | i2cRxData[2 + i] = Wire.receive(); 132 | #endif 133 | } 134 | } 135 | else { 136 | if(numBytes > Wire.available()) { 137 | BleFirmata.sendString("I2C Read Error: Too many bytes received"); 138 | } else { 139 | BleFirmata.sendString("I2C Read Error: Too few bytes received"); 140 | } 141 | } 142 | 143 | // send slave address, register and received bytes 144 | BleFirmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); 145 | } 146 | 147 | void outputPort(byte portNumber, byte portValue, byte forceSend) 148 | { 149 | // pins not configured as INPUT are cleared to zeros 150 | portValue = portValue & portConfigInputs[portNumber]; 151 | 152 | // only send if the value is different than previously sent 153 | if(forceSend || previousPINs[portNumber] != portValue) { 154 | BleFirmata.sendDigitalPort(portNumber, portValue); 155 | previousPINs[portNumber] = portValue; 156 | } 157 | } 158 | 159 | /* ----------------------------------------------------------------------------- 160 | * check all the active digital inputs for change of state, then add any events 161 | * to the Serial output queue using Serial.print() */ 162 | void checkDigitalInputs(void) 163 | { 164 | /* Using non-looping code allows constants to be given to readPort(). 165 | * The compiler will apply substantial optimizations if the inputs 166 | * to readPort() are compile-time constants. */ 167 | if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); 168 | if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); 169 | if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); 170 | if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); 171 | if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); 172 | if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); 173 | if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); 174 | if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); 175 | if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); 176 | if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); 177 | if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); 178 | if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); 179 | if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); 180 | if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); 181 | if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); 182 | if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); 183 | } 184 | 185 | // ----------------------------------------------------------------------------- 186 | /* sets the pin mode to the correct state and sets the relevant bits in the 187 | * two bit-arrays that track Digital I/O and PWM status 188 | */ 189 | void setPinModeCallback(byte pin, int mode) 190 | { 191 | if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { 192 | // disable i2c so pins can be used for other functions 193 | // the following if statements should reconfigure the pins properly 194 | disableI2CPins(); 195 | } 196 | if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) { 197 | servos[PIN_TO_SERVO(pin)].detach(); 198 | } 199 | if (IS_PIN_ANALOG(pin)) { 200 | reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting 201 | } 202 | if (IS_PIN_DIGITAL(pin)) { 203 | if (mode == INPUT) { 204 | portConfigInputs[pin/8] |= (1 << (pin & 7)); 205 | } else { 206 | portConfigInputs[pin/8] &= ~(1 << (pin & 7)); 207 | } 208 | } 209 | pinState[pin] = 0; 210 | switch(mode) { 211 | case ANALOG: 212 | if (IS_PIN_ANALOG(pin)) { 213 | if (IS_PIN_DIGITAL(pin)) { 214 | pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver 215 | digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups 216 | } 217 | pinConfig[pin] = ANALOG; 218 | } 219 | break; 220 | case INPUT: 221 | if (IS_PIN_DIGITAL(pin)) { 222 | pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver 223 | 224 | // Select your internal pull-up here 225 | digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups 226 | //digitalWrite(PIN_TO_DIGITAL(pin), HIGH); // enable internal pull-ups if you have only a wire to test 227 | pinConfig[pin] = INPUT; 228 | 229 | // hack it only 230 | reportPINs[pin/8] |= (1 << (pin & 7)); 231 | } 232 | break; 233 | case OUTPUT: 234 | if (IS_PIN_DIGITAL(pin)) { 235 | digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM 236 | pinMode(PIN_TO_DIGITAL(pin), OUTPUT); 237 | pinConfig[pin] = OUTPUT; 238 | } 239 | break; 240 | case PWM: 241 | if (IS_PIN_PWM(pin)) { 242 | pinMode(PIN_TO_PWM(pin), OUTPUT); 243 | analogWrite(PIN_TO_PWM(pin), 0); 244 | pinConfig[pin] = PWM; 245 | } 246 | break; 247 | case SERVO: 248 | if (IS_PIN_SERVO(pin)) { 249 | pinConfig[pin] = SERVO; 250 | if (!servos[PIN_TO_SERVO(pin)].attached()) { 251 | servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); 252 | } 253 | } 254 | break; 255 | case I2C: 256 | if (IS_PIN_I2C(pin)) { 257 | // mark the pin as i2c 258 | // the user must call I2C_CONFIG to enable I2C for a device 259 | pinConfig[pin] = I2C; 260 | } 261 | break; 262 | default: 263 | BleFirmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM 264 | } 265 | // TODO: save status to EEPROM here, if changed 266 | } 267 | 268 | void analogWriteCallback(byte pin, int value) 269 | { 270 | if (pin < TOTAL_PINS) { 271 | switch(pinConfig[pin]) { 272 | case SERVO: 273 | if (IS_PIN_SERVO(pin)) 274 | servos[PIN_TO_SERVO(pin)].write(value); 275 | pinState[pin] = value; 276 | break; 277 | case PWM: 278 | if (IS_PIN_PWM(pin)) 279 | analogWrite(PIN_TO_PWM(pin), value); 280 | pinState[pin] = value; 281 | break; 282 | } 283 | } 284 | } 285 | 286 | void digitalWriteCallback(byte port, int value) 287 | { 288 | byte pin, lastPin, mask=1, pinWriteMask=0; 289 | 290 | if (port < TOTAL_PORTS) { 291 | // create a mask of the pins on this port that are writable. 292 | lastPin = port*8+8; 293 | if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; 294 | for (pin=port*8; pin < lastPin; pin++) { 295 | // do not disturb non-digital pins (eg, Rx & Tx) 296 | if (IS_PIN_DIGITAL(pin)) { 297 | // only write to OUTPUT and INPUT (enables pullup) 298 | // do not touch pins in PWM, ANALOG, SERVO or other modes 299 | if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { 300 | pinWriteMask |= mask; 301 | pinState[pin] = ((byte)value & mask) ? 1 : 0; 302 | } 303 | } 304 | mask = mask << 1; 305 | } 306 | writePort(port, (byte)value, pinWriteMask); 307 | } 308 | } 309 | 310 | 311 | // ----------------------------------------------------------------------------- 312 | /* sets bits in a bit array (int) to toggle the reporting of the analogIns 313 | */ 314 | //void FirmataClass::setAnalogPinReporting(byte pin, byte state) { 315 | //} 316 | void reportAnalogCallback(byte analogPin, int value) 317 | { 318 | if (analogPin < TOTAL_ANALOG_PINS) { 319 | if(value == 0) { 320 | analogInputsToReport = analogInputsToReport &~ (1 << analogPin); 321 | } else { 322 | analogInputsToReport = analogInputsToReport | (1 << analogPin); 323 | } 324 | } 325 | // TODO: save status to EEPROM here, if changed 326 | } 327 | 328 | void reportDigitalCallback(byte port, int value) 329 | { 330 | if (port < TOTAL_PORTS) { 331 | reportPINs[port] = (byte)value; 332 | } 333 | // do not disable analog reporting on these 8 pins, to allow some 334 | // pins used for digital, others analog. Instead, allow both types 335 | // of reporting to be enabled, but check if the pin is configured 336 | // as analog when sampling the analog inputs. Likewise, while 337 | // scanning digital pins, portConfigInputs will mask off values from any 338 | // pins configured as analog 339 | } 340 | 341 | /*============================================================================== 342 | * SYSEX-BASED commands 343 | *============================================================================*/ 344 | 345 | void sysexCallback(byte command, byte argc, byte *argv) 346 | { 347 | byte mode; 348 | byte slaveAddress; 349 | byte slaveRegister; 350 | byte data; 351 | unsigned int delayTime; 352 | 353 | switch(command) { 354 | case 0x01: // LED Blink Command 355 | if(argc < 3) break; 356 | byte blink_pin; 357 | byte blink_count; 358 | blink_pin = argv[0]; 359 | blink_count = argv[1]; 360 | delayTime = argv[2] * 100; 361 | pinMode(blink_pin, OUTPUT); 362 | byte i; 363 | for(i = 0; i < blink_count; i++){ 364 | digitalWrite(blink_pin, true); 365 | delay(delayTime); 366 | digitalWrite(blink_pin, false); 367 | delay(delayTime); 368 | } 369 | BleFirmata.sendSysex(command, argc, argv); // callback 370 | break; 371 | case I2C_REQUEST: 372 | mode = argv[1] & I2C_READ_WRITE_MODE_MASK; 373 | if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { 374 | BleFirmata.sendString("10-bit addressing mode is not yet supported"); 375 | return; 376 | } 377 | else { 378 | slaveAddress = argv[0]; 379 | } 380 | 381 | switch(mode) { 382 | case I2C_WRITE: 383 | Wire.beginTransmission(slaveAddress); 384 | for (byte i = 2; i < argc; i += 2) { 385 | data = argv[i] + (argv[i + 1] << 7); 386 | #if ARDUINO >= 100 387 | Wire.write(data); 388 | #else 389 | Wire.send(data); 390 | #endif 391 | } 392 | Wire.endTransmission(); 393 | delayMicroseconds(70); 394 | break; 395 | case I2C_READ: 396 | if (argc == 6) { 397 | // a slave register is specified 398 | slaveRegister = argv[2] + (argv[3] << 7); 399 | data = argv[4] + (argv[5] << 7); // bytes to read 400 | readAndReportData(slaveAddress, (int)slaveRegister, data); 401 | } 402 | else { 403 | // a slave register is NOT specified 404 | data = argv[2] + (argv[3] << 7); // bytes to read 405 | readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); 406 | } 407 | break; 408 | case I2C_READ_CONTINUOUSLY: 409 | if ((queryIndex + 1) >= MAX_QUERIES) { 410 | // too many queries, just ignore 411 | BleFirmata.sendString("too many queries"); 412 | break; 413 | } 414 | queryIndex++; 415 | query[queryIndex].addr = slaveAddress; 416 | query[queryIndex].reg = argv[2] + (argv[3] << 7); 417 | query[queryIndex].bytes = argv[4] + (argv[5] << 7); 418 | break; 419 | case I2C_STOP_READING: 420 | byte queryIndexToSkip; 421 | // if read continuous mode is enabled for only 1 i2c device, disable 422 | // read continuous reporting for that device 423 | if (queryIndex <= 0) { 424 | queryIndex = -1; 425 | } else { 426 | // if read continuous mode is enabled for multiple devices, 427 | // determine which device to stop reading and remove it's data from 428 | // the array, shifiting other array data to fill the space 429 | for (byte i = 0; i < queryIndex + 1; i++) { 430 | if (query[i].addr = slaveAddress) { 431 | queryIndexToSkip = i; 432 | break; 433 | } 434 | } 435 | 436 | for (byte i = queryIndexToSkip; i 0) { 454 | i2cReadDelayTime = delayTime; 455 | } 456 | 457 | if (!isI2CEnabled) { 458 | enableI2CPins(); 459 | } 460 | 461 | break; 462 | case SERVO_CONFIG: 463 | if(argc > 4) { 464 | // these vars are here for clarity, they'll optimized away by the compiler 465 | byte pin = argv[0]; 466 | int minPulse = argv[1] + (argv[2] << 7); 467 | int maxPulse = argv[3] + (argv[4] << 7); 468 | 469 | if (IS_PIN_SERVO(pin)) { 470 | if (servos[PIN_TO_SERVO(pin)].attached()) 471 | servos[PIN_TO_SERVO(pin)].detach(); 472 | servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); 473 | setPinModeCallback(pin, SERVO); 474 | } 475 | } 476 | break; 477 | case SAMPLING_INTERVAL: 478 | if (argc > 1) { 479 | samplingInterval = argv[0] + (argv[1] << 7); 480 | if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { 481 | samplingInterval = MINIMUM_SAMPLING_INTERVAL; 482 | } 483 | } else { 484 | //Firmata.sendString("Not enough data"); 485 | } 486 | break; 487 | case EXTENDED_ANALOG: 488 | if (argc > 1) { 489 | int val = argv[1]; 490 | if (argc > 2) val |= (argv[2] << 7); 491 | if (argc > 3) val |= (argv[3] << 14); 492 | analogWriteCallback(argv[0], val); 493 | } 494 | break; 495 | case CAPABILITY_QUERY: 496 | ble_write(START_SYSEX); 497 | ble_write(CAPABILITY_RESPONSE); 498 | for (byte pin=0; pin < TOTAL_PINS; pin++) { 499 | if (IS_PIN_DIGITAL(pin)) { 500 | ble_write((byte)INPUT); 501 | ble_write(1); 502 | ble_write((byte)OUTPUT); 503 | ble_write(1); 504 | } 505 | if (IS_PIN_ANALOG(pin)) { 506 | ble_write(ANALOG); 507 | ble_write(10); 508 | } 509 | if (IS_PIN_PWM(pin)) { 510 | ble_write(PWM); 511 | ble_write(8); 512 | } 513 | if (IS_PIN_SERVO(pin)) { 514 | ble_write(SERVO); 515 | ble_write(14); 516 | } 517 | if (IS_PIN_I2C(pin)) { 518 | ble_write(I2C); 519 | ble_write(1); // to do: determine appropriate value 520 | } 521 | ble_write(127); 522 | } 523 | ble_write(END_SYSEX); 524 | break; 525 | case PIN_STATE_QUERY: 526 | if (argc > 0) { 527 | byte pin=argv[0]; 528 | ble_write(START_SYSEX); 529 | ble_write(PIN_STATE_RESPONSE); 530 | ble_write(pin); 531 | if (pin < TOTAL_PINS) { 532 | ble_write((byte)pinConfig[pin]); 533 | ble_write((byte)pinState[pin] & 0x7F); 534 | if (pinState[pin] & 0xFF80) ble_write((byte)(pinState[pin] >> 7) & 0x7F); 535 | if (pinState[pin] & 0xC000) ble_write((byte)(pinState[pin] >> 14) & 0x7F); 536 | } 537 | ble_write(END_SYSEX); 538 | } 539 | break; 540 | case ANALOG_MAPPING_QUERY: 541 | ble_write(START_SYSEX); 542 | ble_write(ANALOG_MAPPING_RESPONSE); 543 | for (byte pin=0; pin < TOTAL_PINS; pin++) { 544 | ble_write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); 545 | } 546 | ble_write(END_SYSEX); 547 | break; 548 | } 549 | } 550 | 551 | void enableI2CPins() 552 | { 553 | byte i; 554 | // is there a faster way to do this? would probaby require importing 555 | // Arduino.h to get SCL and SDA pins 556 | for (i=0; i < TOTAL_PINS; i++) { 557 | if(IS_PIN_I2C(i)) { 558 | // mark pins as i2c so they are ignore in non i2c data requests 559 | setPinModeCallback(i, I2C); 560 | } 561 | } 562 | 563 | isI2CEnabled = true; 564 | 565 | // is there enough time before the first I2C request to call this here? 566 | Wire.begin(); 567 | } 568 | 569 | /* disable the i2c pins so they can be used for other functions */ 570 | void disableI2CPins() { 571 | isI2CEnabled = false; 572 | // disable read continuous mode for all devices 573 | queryIndex = -1; 574 | // uncomment the following if or when the end() method is added to Wire library 575 | // Wire.end(); 576 | } 577 | 578 | /*============================================================================== 579 | * SETUP() 580 | *============================================================================*/ 581 | 582 | void systemResetCallback() 583 | { 584 | // initialize a defalt state 585 | // TODO: option to load config from EEPROM instead of default 586 | if (isI2CEnabled) { 587 | disableI2CPins(); 588 | } 589 | for (byte i=0; i < TOTAL_PORTS; i++) { 590 | reportPINs[i] = false; // by default, reporting off 591 | portConfigInputs[i] = 0; // until activated 592 | previousPINs[i] = 0; 593 | } 594 | // pins with analog capability default to analog input 595 | // otherwise, pins default to digital output 596 | for (byte i=0; i < TOTAL_PINS; i++) { 597 | 598 | // skip pin 8, 9 for BLE Shield 599 | //if ((i == 8) || (i == 9)) 600 | // continue; 601 | 602 | // skip pin 4, 6, 7 for BlendMicro BLE controll 603 | if ((i == 4) || (i == 6) || (i == 7)) 604 | continue; 605 | 606 | // skip SPI pins 607 | if ( (i==MOSI) || (i==MISO) || (i==SCK) || (i==SS) ) 608 | continue; 609 | 610 | // Default all to digital pins 611 | if (IS_PIN_ANALOG(i)) { 612 | // turns off pullup, configures everything 613 | setPinModeCallback(i, ANALOG); 614 | } else { 615 | // sets the output to 0, configures portConfigInputs 616 | //setPinModeCallback(i, OUTPUT); 617 | } 618 | } 619 | // by default, do not report any analog inputs 620 | analogInputsToReport = 0; 621 | 622 | /* send digital inputs to set the initial state on the host computer, 623 | * since once in the loop(), this firmware will only send on change */ 624 | /* 625 | TODO: this can never execute, since no pins default to digital input 626 | but it will be needed when/if we support EEPROM stored config 627 | for (byte i=0; i < TOTAL_PORTS; i++) { 628 | outputPort(i, readPort(i, portConfigInputs[i]), true); 629 | } 630 | */ 631 | } 632 | 633 | void setup() 634 | { 635 | BleFirmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); 636 | 637 | BleFirmata.attach(ANALOG_MESSAGE, analogWriteCallback); 638 | BleFirmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); 639 | BleFirmata.attach(REPORT_ANALOG, reportAnalogCallback); 640 | BleFirmata.attach(REPORT_DIGITAL, reportDigitalCallback); 641 | BleFirmata.attach(SET_PIN_MODE, setPinModeCallback); 642 | BleFirmata.attach(START_SYSEX, sysexCallback); 643 | BleFirmata.attach(SYSTEM_RESET, systemResetCallback); 644 | 645 | // BleFirmata.begin(57600); 646 | systemResetCallback(); // reset to default config 647 | 648 | // Enable serial debug 649 | Serial.begin(57600); 650 | 651 | // Default pins set to 9 and 8 for REQN and RDYN 652 | // Set your REQN and RDYN here before ble_begin() if you need 653 | //ble_set_pins(3, 2); 654 | 655 | // Set your BLE Shield name here, max. length 10 656 | ble_set_name(BLE_NAME); 657 | 658 | // Init. BLE and start BLE library. 659 | ble_begin(); 660 | } 661 | 662 | /*============================================================================== 663 | * LOOP() 664 | *============================================================================*/ 665 | void loop() 666 | { 667 | byte pin, analogPin; 668 | 669 | /* DIGITALREAD - as fast as possible, check for changes and output them to the 670 | * FTDI buffer using Serial.print() */ 671 | checkDigitalInputs(); 672 | 673 | /* SERIALREAD - processing incoming messagse as soon as possible, while still 674 | * checking digital inputs. */ 675 | while(BleFirmata.available()) 676 | BleFirmata.processInput(); 677 | 678 | /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over 679 | * 60 bytes. use a timer to sending an event character every 4 ms to 680 | * trigger the buffer to dump. */ 681 | 682 | currentMillis = millis(); 683 | if (currentMillis - previousMillis > samplingInterval) { 684 | previousMillis += samplingInterval; 685 | /* ANALOGREAD - do all analogReads() at the configured sampling interval */ 686 | for(pin=0; pin -1) { 699 | for (byte i = 0; i < queryIndex + 1; i++) { 700 | readAndReportData(query[i].addr, query[i].reg, query[i].bytes); 701 | } 702 | } 703 | } 704 | 705 | if (!ble_connected()) 706 | systemResetCallback(); 707 | 708 | ble_do_events(); 709 | } 710 | 711 | --------------------------------------------------------------------------------