├── README.md ├── examples ├── BLEControllerSketch │ ├── BLEControllerSketch.ino │ └── Boards.h ├── BLEFirmataSketch │ ├── BLEFirmata.cpp │ ├── BLEFirmata.h │ ├── BLEFirmataSketch.ino │ └── Boards.h ├── BLE_RGB │ ├── Adafruit_NeoPixel.cpp │ ├── Adafruit_NeoPixel.h │ └── BLE_RGB.ino ├── BLE_SD │ └── BLE_SD.ino ├── HelloWorld │ └── HelloWorld.ino ├── SimpleChat │ └── SimpleChat.ino └── SimpleControls │ └── SimpleControls.ino ├── library.properties └── src ├── RBL_nRF8001.cpp ├── RBL_nRF8001.h ├── RBL_nRF8001.xml ├── RBL_services.h └── run_me_compile_xml_to_nRF8001_setup.bat /README.md: -------------------------------------------------------------------------------- 1 | 2 | nRF8001 3 | ======= 4 | 5 | Last updated: 2015/06/04 6 | 7 | Provides simple API for nRF8001 BLE chip such as the [BLE Shield](http://redbearlab.com/bleshield/) and [Blend Micro](http://redbearlab.com/blendmicro/) to exchange data via RBL TxRx Service to BLE Central device (e.g. iPhone 5). 8 | 9 | Other 3rd party breakout breads may also be workable. 10 | 11 | Tested with Arduino IDE 1.6.4 (we will only support this version). 12 | 13 | Installation 14 | ============ 15 | 16 | You have to see this for installing libraries first. 17 | http://www.arduino.cc/en/Guide/Libraries 18 | 19 | Method 1 - Using Library Manager 20 | 21 | Follow this guide: 22 | 23 | https://github.com/RedBearLab/BLEShield/blob/master/Docs/LibraryManager.pdf 24 | 25 | Method 2 - Manual installation ("Importing a .zip Library") 26 | 27 | Step 1: Get the latest release of [Nordic nRF8001 SDK for Arduino](https://github.com/Cheong2K/ble-sdk-arduino/archive/RBL.zip). 28 | 29 | Step 2: Get the latest release of [RBL nRF8001 API](https://github.com/RedBearLab/nRF8001/archive/master.zip). 30 | 31 | Step 3: Load an example to your Arduino board. 32 | 33 | 34 | How to use 35 | ========== 36 | 37 | 38 | The library structure and dependency: 39 | YourSketch.ino -> RBL_nRF8001 -> Nordic's BLE 40 | 41 | Also, you can use Nordic's library directly such as: 42 | YourSketch.ino -> Nordic's BLE 43 | 44 | Nordic also provides many examples and tutorials. 45 | 46 | Read Nordic's BLE SDK for Arduino for details with tutorials to write your own services. 47 | 48 | There are two Apps available from the Apple AppStore:
49 | 50 | 1. BLE Arduino
51 | It is for the BLEFirmata sketch and works for iOS 6 52 | 53 | 2. BLE Controller
54 | It is for the BLEController sketch and works for iOS 7 55 | 56 | 57 | Change BLE Advertising Name 58 | =========================== 59 | 60 | Before calling to ble_begin(), you can make use of ble_set_name("My BLE") to change the name. 61 | 62 | 63 | Supported Boards 64 | ================ 65 | 66 | Arduino UNO (328p), Leonardo (32u4), MEGA2560, DUE and their compatible.
67 | ChipKit Uno32
68 | 69 | 70 | API 71 | === 72 | 73 | ### ble_begin 74 | 75 | ``` 76 | void ble_begin(); 77 | ``` 78 | 79 | * ble_begin starts the BLE stack and broadcasting the advertising packet 80 | 81 | ### ble_set_name 82 | 83 | ``` 84 | void ble_set_name(char *name); 85 | ``` 86 | 87 | * Call ble_set_name by giving name before calling to ble_begin to set the broadcasting name. 88 | 89 | ### ble_write 90 | 91 | ``` 92 | void ble_write(unsigned char data); 93 | ``` 94 | 95 | * ble_write sends a single byte data to the BLE Central. 96 | 97 | ### ble_write_bytes 98 | 99 | ``` 100 | void ble_write_bytes(unsigned char *data, unsigned char len); 101 | ``` 102 | 103 | * ble_write_bytes writes an array of bytes in data with length in len. 104 | 105 | ### ble_do_events 106 | 107 | ``` 108 | void ble_do_events(); 109 | ``` 110 | 111 | * ble_do_events allows the BLE to process its events, if data is pending, it will be sent out. 112 | 113 | ### ble_read 114 | 115 | ``` 116 | int ble_read(); 117 | ``` 118 | 119 | * ble_read reads a byte from BLE Central, It returns -1 if nothing to be read. 120 | 121 | ### ble_available 122 | 123 | ``` 124 | unsigned char ble_available(); 125 | ``` 126 | 127 | * Returns the number of bytes ready for reading. 128 | 129 | ### ble_connected 130 | 131 | ``` 132 | unsigned char ble_connected(void); 133 | ``` 134 | 135 | * ble_connected returns 1 if connected by BLE Central or 0 if not. 136 | 137 | ### ble_set_pins 138 | 139 | ``` 140 | void ble_set_pins(uint8_t reqn, uint8_t rdyn); 141 | ``` 142 | 143 | * ble_set_pins is to specify the REQN and RDYN pins to the BLE chip, i.e. the jumper on the BLE Shield. 144 | 145 | ### ble_busy 146 | 147 | ``` 148 | unsigned char ble_busy(); 149 | ``` 150 | 151 | * ble_busy return the status if the BLE is busy, i.e. it is using the SPI interface. It is for using the SPI for other components at the same time. 152 | 153 | ### ble_reset 154 | 155 | ``` 156 | void ble_reset(uint8_t reset_pin); 157 | ``` 158 | 159 | * ble_reset resets the BLE chip using the specified pin, reset_pin 160 | 161 | 162 | Resources 163 | ========= 164 | 165 | 1. [Nordic nRF8001 SDK for Arduino - Library](https://github.com/Cheong2K/ble-sdk-arduino) 166 | 167 | 2. [Nordic nRF8001 SDK for Arduino - Forum](https://redbearlab.zendesk.com/forums/21921933-Nordic-nRF8001-SDK-for-Arduino) 168 | 169 | 3. [Nordic Developer Zone](https://devzone.nordicsemi.com/) 170 | 171 | 4. [Bluetooth SIG](https://www.bluetooth.org/en-us) 172 | 173 | 174 | License 175 | ======= 176 | 177 | Copyright (c) 2012-2014 RedBearLab 178 | 179 | Permission is hereby granted, free of charge, to any person obtaining a copy 180 | of this software and associated documentation files (the "Software"), to deal 181 | in the Software without restriction, including without limitation the rights 182 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 183 | copies of the Software, and to permit persons to whom the Software is 184 | furnished to do so, subject to the following conditions: 185 | 186 | The above copyright notice and this permission notice shall be included in all 187 | copies or substantial portions of the Software. 188 | 189 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 190 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 191 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 192 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 193 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 194 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 195 | SOFTWARE. 196 | 197 | -------------------------------------------------------------------------------- /examples/BLEControllerSketch/BLEControllerSketch.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2012, 2013 RedBearLab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "Boards.h" 19 | 20 | #define PROTOCOL_MAJOR_VERSION 0 // 21 | #define PROTOCOL_MINOR_VERSION 0 // 22 | #define PROTOCOL_BUGFIX_VERSION 2 // bugfix 23 | 24 | #define PIN_CAPABILITY_NONE 0x00 25 | #define PIN_CAPABILITY_DIGITAL 0x01 26 | #define PIN_CAPABILITY_ANALOG 0x02 27 | #define PIN_CAPABILITY_PWM 0x04 28 | #define PIN_CAPABILITY_SERVO 0x08 29 | #define PIN_CAPABILITY_I2C 0x10 30 | 31 | // pin modes 32 | //#define INPUT 0x00 // defined in wiring.h 33 | //#define OUTPUT 0x01 // defined in wiring.h 34 | #define ANALOG 0x02 // analog pin in analogInput mode 35 | #define PWM 0x03 // digital pin in PWM output mode 36 | #define SERVO 0x04 // digital pin in Servo output mode 37 | 38 | byte pin_mode[TOTAL_PINS]; 39 | byte pin_state[TOTAL_PINS]; 40 | byte pin_pwm[TOTAL_PINS]; 41 | byte pin_servo[TOTAL_PINS]; 42 | 43 | Servo servos[MAX_SERVOS]; 44 | 45 | void setup() 46 | { 47 | Serial.begin(57600); 48 | Serial.println("BLE Arduino Slave"); 49 | 50 | /* Default all to digital input */ 51 | for (int pin = 0; pin < TOTAL_PINS; pin++) 52 | { 53 | // Set pin to input with internal pull up 54 | pinMode(pin, INPUT); 55 | digitalWrite(pin, HIGH); 56 | 57 | // Save pin mode and state 58 | pin_mode[pin] = INPUT; 59 | pin_state[pin] = LOW; 60 | } 61 | 62 | // Default pins set to 9 and 8 for REQN and RDYN 63 | // Set your REQN and RDYN here before ble_begin() if you need 64 | //ble_set_pins(3, 2); 65 | 66 | // Set your BLE Shield name here, max. length 10 67 | //ble_set_name("My Name"); 68 | 69 | // Init. and start BLE library. 70 | ble_begin(); 71 | } 72 | 73 | static byte buf_len = 0; 74 | 75 | void ble_write_string(byte *bytes, uint8_t len) 76 | { 77 | if (buf_len + len > 20) 78 | { 79 | for (int j = 0; j < 15000; j++) 80 | ble_do_events(); 81 | 82 | buf_len = 0; 83 | } 84 | 85 | for (int j = 0; j < len; j++) 86 | { 87 | ble_write(bytes[j]); 88 | buf_len++; 89 | } 90 | 91 | if (buf_len == 20) 92 | { 93 | for (int j = 0; j < 15000; j++) 94 | ble_do_events(); 95 | 96 | buf_len = 0; 97 | } 98 | } 99 | 100 | byte reportDigitalInput() 101 | { 102 | if (!ble_connected()) 103 | return 0; 104 | 105 | static byte pin = 0; 106 | byte report = 0; 107 | 108 | if (!IS_PIN_DIGITAL(pin)) 109 | { 110 | pin++; 111 | if (pin >= TOTAL_PINS) 112 | pin = 0; 113 | return 0; 114 | } 115 | 116 | if (pin_mode[pin] == INPUT) 117 | { 118 | byte current_state = digitalRead(pin); 119 | 120 | if (pin_state[pin] != current_state) 121 | { 122 | pin_state[pin] = current_state; 123 | byte buf[] = {'G', pin, INPUT, current_state}; 124 | ble_write_string(buf, 4); 125 | 126 | report = 1; 127 | } 128 | } 129 | 130 | pin++; 131 | if (pin >= TOTAL_PINS) 132 | pin = 0; 133 | 134 | return report; 135 | } 136 | 137 | void reportPinCapability(byte pin) 138 | { 139 | byte buf[] = {'P', pin, 0x00}; 140 | byte pin_cap = 0; 141 | 142 | if (IS_PIN_DIGITAL(pin)) 143 | pin_cap |= PIN_CAPABILITY_DIGITAL; 144 | 145 | if (IS_PIN_ANALOG(pin)) 146 | pin_cap |= PIN_CAPABILITY_ANALOG; 147 | 148 | if (IS_PIN_PWM(pin)) 149 | pin_cap |= PIN_CAPABILITY_PWM; 150 | 151 | if (IS_PIN_SERVO(pin)) 152 | pin_cap |= PIN_CAPABILITY_SERVO; 153 | 154 | buf[2] = pin_cap; 155 | ble_write_string(buf, 3); 156 | } 157 | 158 | void reportPinServoData(byte pin) 159 | { 160 | // if (IS_PIN_SERVO(pin)) 161 | // servos[PIN_TO_SERVO(pin)].write(value); 162 | // pin_servo[pin] = value; 163 | 164 | byte value = pin_servo[pin]; 165 | byte mode = pin_mode[pin]; 166 | byte buf[] = {'G', pin, mode, value}; 167 | ble_write_string(buf, 4); 168 | } 169 | 170 | byte reportPinAnalogData() 171 | { 172 | if (!ble_connected()) 173 | return 0; 174 | 175 | static byte pin = 0; 176 | byte report = 0; 177 | 178 | if (!IS_PIN_DIGITAL(pin)) 179 | { 180 | pin++; 181 | if (pin >= TOTAL_PINS) 182 | pin = 0; 183 | return 0; 184 | } 185 | 186 | if (pin_mode[pin] == ANALOG) 187 | { 188 | uint16_t value = analogRead(pin); 189 | byte value_lo = value; 190 | byte value_hi = value>>8; 191 | 192 | byte mode = pin_mode[pin]; 193 | mode = (value_hi << 4) | mode; 194 | 195 | byte buf[] = {'G', pin, mode, value_lo}; 196 | ble_write_string(buf, 4); 197 | } 198 | 199 | pin++; 200 | if (pin >= TOTAL_PINS) 201 | pin = 0; 202 | 203 | return report; 204 | } 205 | 206 | void reportPinDigitalData(byte pin) 207 | { 208 | byte state = digitalRead(pin); 209 | byte mode = pin_mode[pin]; 210 | byte buf[] = {'G', pin, mode, state}; 211 | ble_write_string(buf, 4); 212 | } 213 | 214 | void reportPinPWMData(byte pin) 215 | { 216 | byte value = pin_pwm[pin]; 217 | byte mode = pin_mode[pin]; 218 | byte buf[] = {'G', pin, mode, value}; 219 | ble_write_string(buf, 4); 220 | } 221 | 222 | void sendCustomData(uint8_t *buf, uint8_t len) 223 | { 224 | uint8_t data[20] = "Z"; 225 | memcpy(&data[1], buf, len); 226 | ble_write_string(data, len+1); 227 | } 228 | 229 | byte queryDone = false; 230 | 231 | void loop() 232 | { 233 | while(ble_available()) 234 | { 235 | byte cmd; 236 | cmd = ble_read(); 237 | Serial.write(cmd); 238 | 239 | // Parse data here 240 | switch (cmd) 241 | { 242 | case 'V': // query protocol version 243 | { 244 | byte buf[] = {'V', 0x00, 0x00, 0x01}; 245 | ble_write_string(buf, 4); 246 | } 247 | break; 248 | 249 | case 'C': // query board total pin count 250 | { 251 | byte buf[2]; 252 | buf[0] = 'C'; 253 | buf[1] = TOTAL_PINS; 254 | ble_write_string(buf, 2); 255 | } 256 | break; 257 | 258 | case 'M': // query pin mode 259 | { 260 | byte pin = ble_read(); 261 | byte buf[] = {'M', pin, pin_mode[pin]}; // report pin mode 262 | ble_write_string(buf, 3); 263 | } 264 | break; 265 | 266 | case 'S': // set pin mode 267 | { 268 | byte pin = ble_read(); 269 | byte mode = ble_read(); 270 | 271 | if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) 272 | servos[PIN_TO_SERVO(pin)].detach(); 273 | 274 | /* ToDo: check the mode is in its capability or not */ 275 | /* assume always ok */ 276 | if (mode != pin_mode[pin]) 277 | { 278 | pinMode(pin, mode); 279 | pin_mode[pin] = mode; 280 | 281 | if (mode == OUTPUT) 282 | { 283 | digitalWrite(pin, LOW); 284 | pin_state[pin] = LOW; 285 | } 286 | else if (mode == INPUT) 287 | { 288 | digitalWrite(pin, HIGH); 289 | pin_state[pin] = HIGH; 290 | } 291 | else if (mode == ANALOG) 292 | { 293 | if (IS_PIN_ANALOG(pin)) { 294 | if (IS_PIN_DIGITAL(pin)) { 295 | pinMode(PIN_TO_DIGITAL(pin), LOW); 296 | } 297 | } 298 | } 299 | else if (mode == PWM) 300 | { 301 | if (IS_PIN_PWM(pin)) 302 | { 303 | pinMode(PIN_TO_PWM(pin), OUTPUT); 304 | analogWrite(PIN_TO_PWM(pin), 0); 305 | pin_pwm[pin] = 0; 306 | pin_mode[pin] = PWM; 307 | } 308 | } 309 | else if (mode == SERVO) 310 | { 311 | if (IS_PIN_SERVO(pin)) 312 | { 313 | pin_servo[pin] = 0; 314 | pin_mode[pin] = SERVO; 315 | if (!servos[PIN_TO_SERVO(pin)].attached()) 316 | servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); 317 | } 318 | } 319 | } 320 | 321 | // if (mode == ANALOG) 322 | // reportPinAnalogData(pin); 323 | if ( (mode == INPUT) || (mode == OUTPUT) ) 324 | reportPinDigitalData(pin); 325 | else if (mode == PWM) 326 | reportPinPWMData(pin); 327 | else if (mode == SERVO) 328 | reportPinServoData(pin); 329 | } 330 | break; 331 | 332 | case 'G': // query pin data 333 | { 334 | byte pin = ble_read(); 335 | reportPinDigitalData(pin); 336 | } 337 | break; 338 | 339 | case 'T': // set pin digital state 340 | { 341 | byte pin = ble_read(); 342 | byte state = ble_read(); 343 | 344 | digitalWrite(pin, state); 345 | reportPinDigitalData(pin); 346 | } 347 | break; 348 | 349 | case 'N': // set PWM 350 | { 351 | byte pin = ble_read(); 352 | byte value = ble_read(); 353 | 354 | analogWrite(PIN_TO_PWM(pin), value); 355 | pin_pwm[pin] = value; 356 | reportPinPWMData(pin); 357 | } 358 | break; 359 | 360 | case 'O': // set Servo 361 | { 362 | byte pin = ble_read(); 363 | byte value = ble_read(); 364 | 365 | if (IS_PIN_SERVO(pin)) 366 | servos[PIN_TO_SERVO(pin)].write(value); 367 | pin_servo[pin] = value; 368 | reportPinServoData(pin); 369 | } 370 | break; 371 | 372 | case 'A': // query all pin status 373 | for (int pin = 0; pin < TOTAL_PINS; pin++) 374 | { 375 | reportPinCapability(pin); 376 | if ( (pin_mode[pin] == INPUT) || (pin_mode[pin] == OUTPUT) ) 377 | reportPinDigitalData(pin); 378 | else if (pin_mode[pin] == PWM) 379 | reportPinPWMData(pin); 380 | else if (pin_mode[pin] == SERVO) 381 | reportPinServoData(pin); 382 | } 383 | 384 | queryDone = true; 385 | { 386 | uint8_t str[] = "ABC"; 387 | sendCustomData(str, 3); 388 | } 389 | 390 | break; 391 | 392 | case 'P': // query pin capability 393 | { 394 | byte pin = ble_read(); 395 | reportPinCapability(pin); 396 | } 397 | break; 398 | 399 | case 'Z': 400 | { 401 | byte len = ble_read(); 402 | byte buf[len]; 403 | for (int i=0;i"); 406 | Serial.print("Received: "); 407 | Serial.print(len); 408 | Serial.println(" byte(s)"); 409 | Serial.print(" Hex: "); 410 | for (int 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) && !((p) >= 8 && (p) <= 13)) 142 | //#define IS_PIN_DIGITAL(p) ( ((p) >= 2 && (p) <= 7) || ((p) >= 13 && (p) <= 19) ) 143 | #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) 144 | #define IS_PIN_PWM(p) (digitalPinHasPWM(p) && !((p) >= 8 && (p) <= 12)) 145 | #define IS_PIN_SERVO(p) ( (p) >= 2 && (p) <= 7 ) 146 | #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) 147 | #define PIN_TO_DIGITAL(p) (p) 148 | #define PIN_TO_ANALOG(p) ((p) - 14) 149 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 150 | #define PIN_TO_SERVO(p) ((p) - 2) 151 | #define ARDUINO_PINOUT_OPTIMIZE 1 152 | 153 | 154 | // Wiring (and board) 155 | #elif defined(WIRING) 156 | #define VERSION_BLINK_PIN WLED 157 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 158 | #define IS_PIN_ANALOG(p) ((p) >= FIRST_ANALOG_PIN && (p) < (FIRST_ANALOG_PIN+TOTAL_ANALOG_PINS)) 159 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 160 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 161 | #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) 162 | #define PIN_TO_DIGITAL(p) (p) 163 | #define PIN_TO_ANALOG(p) ((p) - FIRST_ANALOG_PIN) 164 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 165 | #define PIN_TO_SERVO(p) (p) 166 | 167 | 168 | // old Arduinos 169 | #elif defined(__AVR_ATmega8__) 170 | #define TOTAL_ANALOG_PINS 6 171 | #define TOTAL_PINS 20 // 14 digital + 6 analog 172 | #define VERSION_BLINK_PIN 13 173 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) 174 | #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19) 175 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 176 | #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) 177 | #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) 178 | #define PIN_TO_DIGITAL(p) (p) 179 | #define PIN_TO_ANALOG(p) ((p) - 14) 180 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 181 | #define PIN_TO_SERVO(p) ((p) - 2) 182 | #define ARDUINO_PINOUT_OPTIMIZE 1 183 | 184 | 185 | // Arduino Mega 186 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 187 | #define TOTAL_ANALOG_PINS 16 188 | #define TOTAL_PINS 70 // 54 digital + 16 analog 189 | #define VERSION_BLINK_PIN 13 190 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 191 | #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS) 192 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 193 | #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) 194 | #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) 195 | #define PIN_TO_DIGITAL(p) (p) 196 | #define PIN_TO_ANALOG(p) ((p) - 54) 197 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 198 | #define PIN_TO_SERVO(p) ((p) - 2) 199 | 200 | 201 | // Teensy 1.0 202 | #elif defined(__AVR_AT90USB162__) 203 | #define TOTAL_ANALOG_PINS 0 204 | #define TOTAL_PINS 21 // 21 digital + no analog 205 | #define VERSION_BLINK_PIN 6 206 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 207 | #define IS_PIN_ANALOG(p) (0) 208 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 209 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 210 | #define IS_PIN_I2C(p) (0) 211 | #define PIN_TO_DIGITAL(p) (p) 212 | #define PIN_TO_ANALOG(p) (0) 213 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 214 | #define PIN_TO_SERVO(p) (p) 215 | 216 | 217 | // Blend Micro 218 | #elif defined(BLEND_MICRO) 219 | #define TOTAL_ANALOG_PINS 6 220 | #define TOTAL_PINS 24 // 11 digital + 12 analog 221 | #define VERSION_BLINK_PIN 13 222 | #define IS_PIN_DIGITAL(p) ( (p) >= 0 && (p) < 24 && !((p) == 4) && !((p) >= 6 && (p) <= 7) && !((p) >=14 && (p) <= 17) ) 223 | #define IS_PIN_ANALOG(p) ((p) >= 18 && (p) < 24) 224 | #define IS_PIN_PWM(p) ( (p) == 3 || (p) == 5 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 13 ) 225 | #define IS_PIN_SERVO(p) ( (p) >= 0 && (p) < MAX_SERVOS && !((p) == 4) && !((p) >= 6 && (p) <= 7) ) 226 | #define IS_PIN_I2C(p) ((p) == 5 || (p) == 6) 227 | #define PIN_TO_DIGITAL(p) (p) 228 | #define PIN_TO_ANALOG(p) ((p)-18) 229 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 230 | #define PIN_TO_SERVO(p) (p) 231 | 232 | 233 | // Teensy 2.0 234 | #elif defined(__AVR_ATmega32U4__) 235 | #define TOTAL_ANALOG_PINS 6 236 | #define TOTAL_PINS 24 // 11 digital + 12 analog 237 | #define VERSION_BLINK_PIN 13 238 | #define IS_PIN_DIGITAL(p) ( (p) >= 0 && (p) < 24 && !((p) >= 8 && (p) <= 9) && !((p) >=14 && (p) <= 17) ) 239 | #define IS_PIN_ANALOG(p) ((p) >= 18 && (p) < 24) 240 | #define IS_PIN_PWM(p) ( (p) == 3 || (p) == 5 || (p) == 6 || (p) == 10 || (p) == 11 || (p) == 13 ) 241 | #define IS_PIN_SERVO(p) ( (p) >= 0 && (p) < MAX_SERVOS && !((p) >= 8 && (p) <= 9) ) 242 | #define IS_PIN_I2C(p) ((p) == 5 || (p) == 6) 243 | #define PIN_TO_DIGITAL(p) (p) 244 | #define PIN_TO_ANALOG(p) ((p)-18) 245 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 246 | #define PIN_TO_SERVO(p) (p) 247 | 248 | 249 | // Teensy++ 1.0 and 2.0 250 | #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) 251 | #define TOTAL_ANALOG_PINS 8 252 | #define TOTAL_PINS 46 // 38 digital + 8 analog 253 | #define VERSION_BLINK_PIN 6 254 | #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) 255 | #define IS_PIN_ANALOG(p) ((p) >= 38 && (p) < TOTAL_PINS) 256 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 257 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 258 | #define IS_PIN_I2C(p) ((p) == 0 || (p) == 1) 259 | #define PIN_TO_DIGITAL(p) (p) 260 | #define PIN_TO_ANALOG(p) ((p) - 38) 261 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 262 | #define PIN_TO_SERVO(p) (p) 263 | 264 | 265 | // Sanguino 266 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 267 | #define TOTAL_ANALOG_PINS 8 268 | #define TOTAL_PINS 32 // 24 digital + 8 analog 269 | #define VERSION_BLINK_PIN 0 270 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 271 | #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS) 272 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 273 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 274 | #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17) 275 | #define PIN_TO_DIGITAL(p) (p) 276 | #define PIN_TO_ANALOG(p) ((p) - 24) 277 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 278 | #define PIN_TO_SERVO(p) ((p) - 2) 279 | 280 | 281 | // Illuminato 282 | #elif defined(__AVR_ATmega645__) 283 | #define TOTAL_ANALOG_PINS 6 284 | #define TOTAL_PINS 42 // 36 digital + 6 analog 285 | #define VERSION_BLINK_PIN 13 286 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 287 | #define IS_PIN_ANALOG(p) ((p) >= 36 && (p) < TOTAL_PINS) 288 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 289 | #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) 290 | #define IS_PIN_I2C(p) ((p) == 4 || (p) == 5) 291 | #define PIN_TO_DIGITAL(p) (p) 292 | #define PIN_TO_ANALOG(p) ((p) - 36) 293 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 294 | #define PIN_TO_SERVO(p) ((p) - 2) 295 | 296 | 297 | // Arduino DUE 298 | #elif defined(__SAM3X8E__) 299 | #define TOTAL_ANALOG_PINS 12 300 | #define TOTAL_PINS 66 // 54 digital + 12 analog 301 | #define VERSION_BLINK_PIN 13 302 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) 303 | #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS) 304 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 305 | #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) 306 | #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // 70 71 307 | #define PIN_TO_DIGITAL(p) (p) 308 | #define PIN_TO_ANALOG(p) ((p) - 54) 309 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 310 | #define PIN_TO_SERVO(p) ((p) - 2) 311 | 312 | 313 | // chipKIT 314 | #elif defined(__PIC32MX__) 315 | #define TOTAL_ANALOG_PINS 6 316 | #define TOTAL_PINS 20 // 14 digital + 6 analog 317 | #define VERSION_BLINK_PIN 13 318 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) 319 | #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19) 320 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 321 | #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) 322 | #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) 323 | #define PIN_TO_DIGITAL(p) (p) 324 | #define PIN_TO_ANALOG(p) ((p) - 14) 325 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 326 | #define PIN_TO_SERVO(p) ((p) - 2) 327 | 328 | // anything else 329 | #else 330 | #error "Please edit Boards.h with a hardware abstraction for this board" 331 | #endif 332 | 333 | 334 | /*============================================================================== 335 | * readPort() - Read an 8 bit port 336 | *============================================================================*/ 337 | 338 | static inline unsigned char readPort(byte, byte) __attribute__((always_inline, unused)); 339 | static inline unsigned char readPort(byte port, byte bitmask) 340 | { 341 | #if defined(ARDUINO_PINOUT_OPTIMIZE) 342 | if (port == 0) return (PIND & 0xFC) & bitmask; // ignore Rx/Tx 0/1 343 | if (port == 1) return ((PINB & 0x3F) | ((PINC & 0x03) << 6)) & bitmask; 344 | if (port == 2) return ((PINC & 0x3C) >> 2) & bitmask; 345 | return 0; 346 | #else 347 | unsigned char out=0, pin=port*8; 348 | if (IS_PIN_DIGITAL(pin+0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin+0))) out |= 0x01; 349 | if (IS_PIN_DIGITAL(pin+1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin+1))) out |= 0x02; 350 | if (IS_PIN_DIGITAL(pin+2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin+2))) out |= 0x04; 351 | if (IS_PIN_DIGITAL(pin+3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin+3))) out |= 0x08; 352 | if (IS_PIN_DIGITAL(pin+4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin+4))) out |= 0x10; 353 | if (IS_PIN_DIGITAL(pin+5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin+5))) out |= 0x20; 354 | if (IS_PIN_DIGITAL(pin+6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin+6))) out |= 0x40; 355 | if (IS_PIN_DIGITAL(pin+7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin+7))) out |= 0x80; 356 | return out; 357 | #endif 358 | } 359 | 360 | /*============================================================================== 361 | * writePort() - Write an 8 bit port, only touch pins specified by a bitmask 362 | *============================================================================*/ 363 | 364 | static inline unsigned char writePort(byte, byte, byte) __attribute__((always_inline, unused)); 365 | static inline unsigned char writePort(byte port, byte value, byte bitmask) 366 | { 367 | #if defined(ARDUINO_PINOUT_OPTIMIZE) 368 | if (port == 0) { 369 | bitmask = bitmask & 0xFC; // do not touch Tx & Rx pins 370 | byte valD = value & bitmask; 371 | byte maskD = ~bitmask; 372 | cli(); 373 | PORTD = (PORTD & maskD) | valD; 374 | sei(); 375 | } else if (port == 1) { 376 | byte valB = (value & bitmask) & 0x3F; 377 | byte valC = (value & bitmask) >> 6; 378 | byte maskB = ~(bitmask & 0x3F); 379 | byte maskC = ~((bitmask & 0xC0) >> 6); 380 | cli(); 381 | PORTB = (PORTB & maskB) | valB; 382 | PORTC = (PORTC & maskC) | valC; 383 | sei(); 384 | } else if (port == 2) { 385 | bitmask = bitmask & 0x0F; 386 | byte valC = (value & bitmask) << 2; 387 | byte maskC = ~(bitmask << 2); 388 | cli(); 389 | PORTC = (PORTC & maskC) | valC; 390 | sei(); 391 | } 392 | #else 393 | byte pin=port*8; 394 | if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin+0), (value & 0x01)); 395 | if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin+1), (value & 0x02)); 396 | if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin+2), (value & 0x04)); 397 | if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin+3), (value & 0x08)); 398 | if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin+4), (value & 0x10)); 399 | if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin+5), (value & 0x20)); 400 | if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin+6), (value & 0x40)); 401 | if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin+7), (value & 0x80)); 402 | #endif 403 | } 404 | 405 | 406 | 407 | 408 | #ifndef TOTAL_PORTS 409 | #define TOTAL_PORTS ((TOTAL_PINS + 7) / 8) 410 | #endif 411 | 412 | 413 | #endif /* Firmata_Boards_h */ 414 | -------------------------------------------------------------------------------- /examples/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 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "BLEFirmata.h" 19 | #include 20 | 21 | /* 22 | * Firmata is a generic protocol for communicating with microcontrollers 23 | * from software on a host computer. It is intended to work with 24 | * any host computer software package. 25 | * 26 | * To download a host software package, please clink on the following link 27 | * to open the download page in your default browser. 28 | * 29 | * http://firmata.org/wiki/Download 30 | */ 31 | 32 | /* 33 | Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. 34 | Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. 35 | Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. 36 | Copyright (C) 2009-2011 Jeff Hoefs. All rights reserved. 37 | 38 | This library is free software; you can redistribute it and/or 39 | modify it under the terms of the GNU Lesser General Public 40 | License as published by the Free Software Foundation; either 41 | version 2.1 of the License, or (at your option) any later version. 42 | 43 | See file LICENSE.txt for further informations on licensing terms. 44 | 45 | formatted using the GNU C formatting and indenting 46 | */ 47 | 48 | /* 49 | * TODO: use Program Control to load stored profiles from EEPROM 50 | */ 51 | 52 | // move the following defines to Firmata.h? 53 | #define I2C_WRITE B00000000 54 | #define I2C_READ B00001000 55 | #define I2C_READ_CONTINUOUSLY B00010000 56 | #define I2C_STOP_READING B00011000 57 | #define I2C_READ_WRITE_MODE_MASK B00011000 58 | #define I2C_10BIT_ADDRESS_MODE_MASK B00100000 59 | 60 | #define MAX_QUERIES 8 61 | #define MINIMUM_SAMPLING_INTERVAL 10 62 | 63 | #define REGISTER_NOT_SPECIFIED -1 64 | 65 | /*============================================================================== 66 | * GLOBAL VARIABLES 67 | *============================================================================*/ 68 | 69 | /* analog inputs */ 70 | int analogInputsToReport = 0; // bitwise array to store pin reporting 71 | 72 | /* digital input ports */ 73 | byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence 74 | byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent 75 | 76 | /* pins configuration */ 77 | byte pinConfig[TOTAL_PINS]; // configuration of every pin 78 | byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else 79 | int pinState[TOTAL_PINS]; // any value that has been written 80 | 81 | /* timer variables */ 82 | unsigned long currentMillis; // store the current value from millis() 83 | unsigned long previousMillis; // for comparison with currentMillis 84 | int samplingInterval = 38; // how often to run the main loop (in ms) 85 | 86 | /* i2c data */ 87 | struct i2c_device_info { 88 | byte addr; 89 | byte reg; 90 | byte bytes; 91 | }; 92 | 93 | /* for i2c read continuous more */ 94 | i2c_device_info query[MAX_QUERIES]; 95 | 96 | byte i2cRxData[32]; 97 | boolean isI2CEnabled = false; 98 | signed char queryIndex = -1; 99 | unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() 100 | 101 | Servo servos[MAX_SERVOS]; 102 | /*============================================================================== 103 | * FUNCTIONS 104 | *============================================================================*/ 105 | 106 | void readAndReportData(byte address, int theRegister, byte numBytes) { 107 | // allow I2C requests that don't require a register read 108 | // for example, some devices using an interrupt pin to signify new data available 109 | // do not always require the register read so upon interrupt you call Wire.requestFrom() 110 | if (theRegister != REGISTER_NOT_SPECIFIED) { 111 | Wire.beginTransmission(address); 112 | #if ARDUINO >= 100 113 | Wire.write((byte)theRegister); 114 | #else 115 | Wire.send((byte)theRegister); 116 | #endif 117 | Wire.endTransmission(); 118 | delayMicroseconds(i2cReadDelayTime); // delay is necessary for some devices such as WiiNunchuck 119 | } else { 120 | theRegister = 0; // fill the register with a dummy value 121 | } 122 | 123 | Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom 124 | 125 | // check to be sure correct number of bytes were returned by slave 126 | if(numBytes == Wire.available()) { 127 | i2cRxData[0] = address; 128 | i2cRxData[1] = theRegister; 129 | for (int i = 0; i < numBytes; i++) { 130 | #if ARDUINO >= 100 131 | i2cRxData[2 + i] = Wire.read(); 132 | #else 133 | i2cRxData[2 + i] = Wire.receive(); 134 | #endif 135 | } 136 | } 137 | else { 138 | if(numBytes > Wire.available()) { 139 | BleFirmata.sendString("I2C Read Error: Too many bytes received"); 140 | } else { 141 | BleFirmata.sendString("I2C Read Error: Too few bytes received"); 142 | } 143 | } 144 | 145 | // send slave address, register and received bytes 146 | BleFirmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); 147 | } 148 | 149 | void outputPort(byte portNumber, byte portValue, byte forceSend) 150 | { 151 | // pins not configured as INPUT are cleared to zeros 152 | portValue = portValue & portConfigInputs[portNumber]; 153 | 154 | // only send if the value is different than previously sent 155 | if(forceSend || previousPINs[portNumber] != portValue) { 156 | BleFirmata.sendDigitalPort(portNumber, portValue); 157 | previousPINs[portNumber] = portValue; 158 | } 159 | } 160 | 161 | /* ----------------------------------------------------------------------------- 162 | * check all the active digital inputs for change of state, then add any events 163 | * to the Serial output queue using Serial.print() */ 164 | void checkDigitalInputs(void) 165 | { 166 | /* Using non-looping code allows constants to be given to readPort(). 167 | * The compiler will apply substantial optimizations if the inputs 168 | * to readPort() are compile-time constants. */ 169 | if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); 170 | if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); 171 | if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); 172 | if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); 173 | if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); 174 | if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); 175 | if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); 176 | if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); 177 | if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); 178 | if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); 179 | if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); 180 | if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); 181 | if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); 182 | if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); 183 | if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); 184 | if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); 185 | } 186 | 187 | // ----------------------------------------------------------------------------- 188 | /* sets the pin mode to the correct state and sets the relevant bits in the 189 | * two bit-arrays that track Digital I/O and PWM status 190 | */ 191 | void setPinModeCallback(byte pin, int mode) 192 | { 193 | if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { 194 | // disable i2c so pins can be used for other functions 195 | // the following if statements should reconfigure the pins properly 196 | disableI2CPins(); 197 | } 198 | if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) { 199 | servos[PIN_TO_SERVO(pin)].detach(); 200 | } 201 | if (IS_PIN_ANALOG(pin)) { 202 | reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting 203 | } 204 | if (IS_PIN_DIGITAL(pin)) { 205 | if (mode == INPUT) { 206 | portConfigInputs[pin/8] |= (1 << (pin & 7)); 207 | } else { 208 | portConfigInputs[pin/8] &= ~(1 << (pin & 7)); 209 | } 210 | } 211 | pinState[pin] = 0; 212 | switch(mode) { 213 | case ANALOG: 214 | if (IS_PIN_ANALOG(pin)) { 215 | if (IS_PIN_DIGITAL(pin)) { 216 | pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver 217 | digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups 218 | } 219 | pinConfig[pin] = ANALOG; 220 | } 221 | break; 222 | case INPUT: 223 | if (IS_PIN_DIGITAL(pin)) { 224 | pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver 225 | 226 | // Select your internal pull-up here 227 | digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups 228 | //digitalWrite(PIN_TO_DIGITAL(pin), HIGH); // enable internal pull-ups if you have only a wire to test 229 | pinConfig[pin] = INPUT; 230 | 231 | // hack it only 232 | reportPINs[pin/8] |= (1 << (pin & 7)); 233 | } 234 | break; 235 | case OUTPUT: 236 | if (IS_PIN_DIGITAL(pin)) { 237 | digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM 238 | pinMode(PIN_TO_DIGITAL(pin), OUTPUT); 239 | pinConfig[pin] = OUTPUT; 240 | } 241 | break; 242 | case PWM: 243 | if (IS_PIN_PWM(pin)) { 244 | pinMode(PIN_TO_PWM(pin), OUTPUT); 245 | analogWrite(PIN_TO_PWM(pin), 0); 246 | pinConfig[pin] = PWM; 247 | } 248 | break; 249 | case SERVO: 250 | if (IS_PIN_SERVO(pin)) { 251 | pinConfig[pin] = SERVO; 252 | if (!servos[PIN_TO_SERVO(pin)].attached()) { 253 | servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); 254 | } 255 | } 256 | break; 257 | case I2C: 258 | if (IS_PIN_I2C(pin)) { 259 | // mark the pin as i2c 260 | // the user must call I2C_CONFIG to enable I2C for a device 261 | pinConfig[pin] = I2C; 262 | } 263 | break; 264 | default: 265 | BleFirmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM 266 | } 267 | // TODO: save status to EEPROM here, if changed 268 | } 269 | 270 | void analogWriteCallback(byte pin, int value) 271 | { 272 | if (pin < TOTAL_PINS) { 273 | switch(pinConfig[pin]) { 274 | case SERVO: 275 | if (IS_PIN_SERVO(pin)) 276 | servos[PIN_TO_SERVO(pin)].write(value); 277 | pinState[pin] = value; 278 | break; 279 | case PWM: 280 | if (IS_PIN_PWM(pin)) 281 | analogWrite(PIN_TO_PWM(pin), value); 282 | pinState[pin] = value; 283 | break; 284 | } 285 | } 286 | } 287 | 288 | void digitalWriteCallback(byte port, int value) 289 | { 290 | byte pin, lastPin, mask=1, pinWriteMask=0; 291 | 292 | if (port < TOTAL_PORTS) { 293 | // create a mask of the pins on this port that are writable. 294 | lastPin = port*8+8; 295 | if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; 296 | for (pin=port*8; pin < lastPin; pin++) { 297 | // do not disturb non-digital pins (eg, Rx & Tx) 298 | if (IS_PIN_DIGITAL(pin)) { 299 | // only write to OUTPUT and INPUT (enables pullup) 300 | // do not touch pins in PWM, ANALOG, SERVO or other modes 301 | if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { 302 | pinWriteMask |= mask; 303 | pinState[pin] = ((byte)value & mask) ? 1 : 0; 304 | } 305 | } 306 | mask = mask << 1; 307 | } 308 | writePort(port, (byte)value, pinWriteMask); 309 | } 310 | } 311 | 312 | 313 | // ----------------------------------------------------------------------------- 314 | /* sets bits in a bit array (int) to toggle the reporting of the analogIns 315 | */ 316 | //void FirmataClass::setAnalogPinReporting(byte pin, byte state) { 317 | //} 318 | void reportAnalogCallback(byte analogPin, int value) 319 | { 320 | if (analogPin < TOTAL_ANALOG_PINS) { 321 | if(value == 0) { 322 | analogInputsToReport = analogInputsToReport &~ (1 << analogPin); 323 | } else { 324 | analogInputsToReport = analogInputsToReport | (1 << analogPin); 325 | } 326 | } 327 | // TODO: save status to EEPROM here, if changed 328 | } 329 | 330 | void reportDigitalCallback(byte port, int value) 331 | { 332 | if (port < TOTAL_PORTS) { 333 | reportPINs[port] = (byte)value; 334 | } 335 | // do not disable analog reporting on these 8 pins, to allow some 336 | // pins used for digital, others analog. Instead, allow both types 337 | // of reporting to be enabled, but check if the pin is configured 338 | // as analog when sampling the analog inputs. Likewise, while 339 | // scanning digital pins, portConfigInputs will mask off values from any 340 | // pins configured as analog 341 | } 342 | 343 | /*============================================================================== 344 | * SYSEX-BASED commands 345 | *============================================================================*/ 346 | 347 | void sysexCallback(byte command, byte argc, byte *argv) 348 | { 349 | byte mode; 350 | byte slaveAddress; 351 | byte slaveRegister; 352 | byte data; 353 | unsigned int delayTime; 354 | 355 | switch(command) { 356 | case I2C_REQUEST: 357 | mode = argv[1] & I2C_READ_WRITE_MODE_MASK; 358 | if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { 359 | BleFirmata.sendString("10-bit addressing mode is not yet supported"); 360 | return; 361 | } 362 | else { 363 | slaveAddress = argv[0]; 364 | } 365 | 366 | switch(mode) { 367 | case I2C_WRITE: 368 | Wire.beginTransmission(slaveAddress); 369 | for (byte i = 2; i < argc; i += 2) { 370 | data = argv[i] + (argv[i + 1] << 7); 371 | #if ARDUINO >= 100 372 | Wire.write(data); 373 | #else 374 | Wire.send(data); 375 | #endif 376 | } 377 | Wire.endTransmission(); 378 | delayMicroseconds(70); 379 | break; 380 | case I2C_READ: 381 | if (argc == 6) { 382 | // a slave register is specified 383 | slaveRegister = argv[2] + (argv[3] << 7); 384 | data = argv[4] + (argv[5] << 7); // bytes to read 385 | readAndReportData(slaveAddress, (int)slaveRegister, data); 386 | } 387 | else { 388 | // a slave register is NOT specified 389 | data = argv[2] + (argv[3] << 7); // bytes to read 390 | readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); 391 | } 392 | break; 393 | case I2C_READ_CONTINUOUSLY: 394 | if ((queryIndex + 1) >= MAX_QUERIES) { 395 | // too many queries, just ignore 396 | BleFirmata.sendString("too many queries"); 397 | break; 398 | } 399 | queryIndex++; 400 | query[queryIndex].addr = slaveAddress; 401 | query[queryIndex].reg = argv[2] + (argv[3] << 7); 402 | query[queryIndex].bytes = argv[4] + (argv[5] << 7); 403 | break; 404 | case I2C_STOP_READING: 405 | byte queryIndexToSkip; 406 | // if read continuous mode is enabled for only 1 i2c device, disable 407 | // read continuous reporting for that device 408 | if (queryIndex <= 0) { 409 | queryIndex = -1; 410 | } else { 411 | // if read continuous mode is enabled for multiple devices, 412 | // determine which device to stop reading and remove it's data from 413 | // the array, shifiting other array data to fill the space 414 | for (byte i = 0; i < queryIndex + 1; i++) { 415 | if (query[i].addr = slaveAddress) { 416 | queryIndexToSkip = i; 417 | break; 418 | } 419 | } 420 | 421 | for (byte i = queryIndexToSkip; i 0) { 439 | i2cReadDelayTime = delayTime; 440 | } 441 | 442 | if (!isI2CEnabled) { 443 | enableI2CPins(); 444 | } 445 | 446 | break; 447 | case SERVO_CONFIG: 448 | if(argc > 4) { 449 | // these vars are here for clarity, they'll optimized away by the compiler 450 | byte pin = argv[0]; 451 | int minPulse = argv[1] + (argv[2] << 7); 452 | int maxPulse = argv[3] + (argv[4] << 7); 453 | 454 | if (IS_PIN_SERVO(pin)) { 455 | if (servos[PIN_TO_SERVO(pin)].attached()) 456 | servos[PIN_TO_SERVO(pin)].detach(); 457 | servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); 458 | setPinModeCallback(pin, SERVO); 459 | } 460 | } 461 | break; 462 | case SAMPLING_INTERVAL: 463 | if (argc > 1) { 464 | samplingInterval = argv[0] + (argv[1] << 7); 465 | if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { 466 | samplingInterval = MINIMUM_SAMPLING_INTERVAL; 467 | } 468 | } else { 469 | //Firmata.sendString("Not enough data"); 470 | } 471 | break; 472 | case EXTENDED_ANALOG: 473 | if (argc > 1) { 474 | int val = argv[1]; 475 | if (argc > 2) val |= (argv[2] << 7); 476 | if (argc > 3) val |= (argv[3] << 14); 477 | analogWriteCallback(argv[0], val); 478 | } 479 | break; 480 | case CAPABILITY_QUERY: 481 | ble_write(START_SYSEX); 482 | ble_write(CAPABILITY_RESPONSE); 483 | for (byte pin=0; pin < TOTAL_PINS; pin++) { 484 | if (IS_PIN_DIGITAL(pin)) { 485 | ble_write((byte)INPUT); 486 | ble_write(1); 487 | ble_write((byte)OUTPUT); 488 | ble_write(1); 489 | } 490 | if (IS_PIN_ANALOG(pin)) { 491 | ble_write(ANALOG); 492 | ble_write(10); 493 | } 494 | if (IS_PIN_PWM(pin)) { 495 | ble_write(PWM); 496 | ble_write(8); 497 | } 498 | if (IS_PIN_SERVO(pin)) { 499 | ble_write(SERVO); 500 | ble_write(14); 501 | } 502 | if (IS_PIN_I2C(pin)) { 503 | ble_write(I2C); 504 | ble_write(1); // to do: determine appropriate value 505 | } 506 | ble_write(127); 507 | } 508 | ble_write(END_SYSEX); 509 | break; 510 | case PIN_STATE_QUERY: 511 | if (argc > 0) { 512 | byte pin=argv[0]; 513 | ble_write(START_SYSEX); 514 | ble_write(PIN_STATE_RESPONSE); 515 | ble_write(pin); 516 | if (pin < TOTAL_PINS) { 517 | ble_write((byte)pinConfig[pin]); 518 | ble_write((byte)pinState[pin] & 0x7F); 519 | if (pinState[pin] & 0xFF80) ble_write((byte)(pinState[pin] >> 7) & 0x7F); 520 | if (pinState[pin] & 0xC000) ble_write((byte)(pinState[pin] >> 14) & 0x7F); 521 | } 522 | ble_write(END_SYSEX); 523 | } 524 | break; 525 | case ANALOG_MAPPING_QUERY: 526 | ble_write(START_SYSEX); 527 | ble_write(ANALOG_MAPPING_RESPONSE); 528 | for (byte pin=0; pin < TOTAL_PINS; pin++) { 529 | ble_write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); 530 | } 531 | ble_write(END_SYSEX); 532 | break; 533 | } 534 | } 535 | 536 | void enableI2CPins() 537 | { 538 | byte i; 539 | // is there a faster way to do this? would probaby require importing 540 | // Arduino.h to get SCL and SDA pins 541 | for (i=0; i < TOTAL_PINS; i++) { 542 | if(IS_PIN_I2C(i)) { 543 | // mark pins as i2c so they are ignore in non i2c data requests 544 | setPinModeCallback(i, I2C); 545 | } 546 | } 547 | 548 | isI2CEnabled = true; 549 | 550 | // is there enough time before the first I2C request to call this here? 551 | Wire.begin(); 552 | } 553 | 554 | /* disable the i2c pins so they can be used for other functions */ 555 | void disableI2CPins() { 556 | isI2CEnabled = false; 557 | // disable read continuous mode for all devices 558 | queryIndex = -1; 559 | // uncomment the following if or when the end() method is added to Wire library 560 | // Wire.end(); 561 | } 562 | 563 | /*============================================================================== 564 | * SETUP() 565 | *============================================================================*/ 566 | 567 | void systemResetCallback() 568 | { 569 | // initialize a defalt state 570 | // TODO: option to load config from EEPROM instead of default 571 | if (isI2CEnabled) { 572 | disableI2CPins(); 573 | } 574 | for (byte i=0; i < TOTAL_PORTS; i++) { 575 | reportPINs[i] = false; // by default, reporting off 576 | portConfigInputs[i] = 0; // until activated 577 | previousPINs[i] = 0; 578 | } 579 | // pins with analog capability default to analog input 580 | // otherwise, pins default to digital output 581 | for (byte i=0; i < TOTAL_PINS; i++) { 582 | 583 | #if defined(BLEND_MICRO) 584 | // skip pin 4, 6, 7 for BlendMicro BLE controll 585 | if ((i == 4) || (i == 6) || (i == 7)) 586 | continue; 587 | #else 588 | // skip pin 8, 9 for BLE Shield 589 | if ((i == 8) || (i == 9)) 590 | continue; 591 | #endif 592 | 593 | // skip SPI pins 594 | if ( (i==MOSI) || (i==MISO) || (i==SCK) || (i==SS) ) 595 | continue; 596 | 597 | // Default all to digital pins 598 | if (IS_PIN_ANALOG(i)) { 599 | // turns off pullup, configures everything 600 | setPinModeCallback(i, ANALOG); 601 | } else { 602 | // sets the output to 0, configures portConfigInputs 603 | // setPinModeCallback(i, OUTPUT); 604 | } 605 | } 606 | // by default, do not report any analog inputs 607 | analogInputsToReport = 0; 608 | 609 | /* send digital inputs to set the initial state on the host computer, 610 | * since once in the loop(), this firmware will only send on change */ 611 | /* 612 | TODO: this can never execute, since no pins default to digital input 613 | but it will be needed when/if we support EEPROM stored config 614 | for (byte i=0; i < TOTAL_PORTS; i++) { 615 | outputPort(i, readPort(i, portConfigInputs[i]), true); 616 | } 617 | */ 618 | } 619 | 620 | void setup() 621 | { 622 | // BleFirmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); 623 | 624 | BleFirmata.attach(ANALOG_MESSAGE, analogWriteCallback); 625 | BleFirmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); 626 | BleFirmata.attach(REPORT_ANALOG, reportAnalogCallback); 627 | BleFirmata.attach(REPORT_DIGITAL, reportDigitalCallback); 628 | BleFirmata.attach(SET_PIN_MODE, setPinModeCallback); 629 | BleFirmata.attach(START_SYSEX, sysexCallback); 630 | BleFirmata.attach(SYSTEM_RESET, systemResetCallback); 631 | 632 | // BleFirmata.begin(57600); 633 | systemResetCallback(); // reset to default config 634 | 635 | // Enable serial debug 636 | Serial.begin(57600); 637 | 638 | // Default pins set to 9 and 8 for REQN and RDYN 639 | // Set your REQN and RDYN here before ble_begin() if you need 640 | //ble_set_pins(3, 2); 641 | 642 | ble_set_name(BLE_NAME); 643 | 644 | // Init. BLE and start BLE library. 645 | ble_begin(); 646 | } 647 | 648 | /*============================================================================== 649 | * LOOP() 650 | *============================================================================*/ 651 | void loop() 652 | { 653 | byte pin, analogPin; 654 | 655 | /* DIGITALREAD - as fast as possible, check for changes and output them to the 656 | * FTDI buffer using Serial.print() */ 657 | checkDigitalInputs(); 658 | 659 | /* SERIALREAD - processing incoming messagse as soon as possible, while still 660 | * checking digital inputs. */ 661 | while(BleFirmata.available()) 662 | BleFirmata.processInput(); 663 | 664 | /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over 665 | * 60 bytes. use a timer to sending an event character every 4 ms to 666 | * trigger the buffer to dump. */ 667 | 668 | currentMillis = millis(); 669 | if (currentMillis - previousMillis > samplingInterval) { 670 | previousMillis += samplingInterval; 671 | /* ANALOGREAD - do all analogReads() at the configured sampling interval */ 672 | for(pin=0; pin -1) { 685 | for (byte i = 0; i < queryIndex + 1; i++) { 686 | readAndReportData(query[i].addr, query[i].reg, query[i].bytes); 687 | } 688 | } 689 | } 690 | 691 | if (!ble_connected()) 692 | systemResetCallback(); 693 | 694 | ble_do_events(); 695 | } 696 | 697 | -------------------------------------------------------------------------------- /examples/BLEFirmataSketch/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 | // chipKIT 297 | #elif defined(__PIC32MX__) 298 | #define TOTAL_ANALOG_PINS 6 299 | #define TOTAL_PINS 20 // 14 digital + 6 analog 300 | #define VERSION_BLINK_PIN 13 301 | #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) 302 | #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19) 303 | #define IS_PIN_PWM(p) digitalPinHasPWM(p) 304 | #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) 305 | #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) 306 | #define PIN_TO_DIGITAL(p) (p) 307 | #define PIN_TO_ANALOG(p) ((p) - 14) 308 | #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) 309 | #define PIN_TO_SERVO(p) ((p) - 2) 310 | 311 | // anything else 312 | #else 313 | #error "Please edit Boards.h with a hardware abstraction for this board" 314 | #endif 315 | 316 | 317 | /*============================================================================== 318 | * readPort() - Read an 8 bit port 319 | *============================================================================*/ 320 | 321 | static inline unsigned char readPort(byte, byte) __attribute__((always_inline, unused)); 322 | static inline unsigned char readPort(byte port, byte bitmask) 323 | { 324 | #if defined(ARDUINO_PINOUT_OPTIMIZE) 325 | if (port == 0) return (PIND & 0xFC) & bitmask; // ignore Rx/Tx 0/1 326 | if (port == 1) return ((PINB & 0x3F) | ((PINC & 0x03) << 6)) & bitmask; 327 | if (port == 2) return ((PINC & 0x3C) >> 2) & bitmask; 328 | return 0; 329 | #else 330 | unsigned char out=0, pin=port*8; 331 | if (IS_PIN_DIGITAL(pin+0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin+0))) out |= 0x01; 332 | if (IS_PIN_DIGITAL(pin+1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin+1))) out |= 0x02; 333 | if (IS_PIN_DIGITAL(pin+2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin+2))) out |= 0x04; 334 | if (IS_PIN_DIGITAL(pin+3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin+3))) out |= 0x08; 335 | if (IS_PIN_DIGITAL(pin+4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin+4))) out |= 0x10; 336 | if (IS_PIN_DIGITAL(pin+5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin+5))) out |= 0x20; 337 | if (IS_PIN_DIGITAL(pin+6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin+6))) out |= 0x40; 338 | if (IS_PIN_DIGITAL(pin+7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin+7))) out |= 0x80; 339 | return out; 340 | #endif 341 | } 342 | 343 | /*============================================================================== 344 | * writePort() - Write an 8 bit port, only touch pins specified by a bitmask 345 | *============================================================================*/ 346 | 347 | static inline unsigned char writePort(byte, byte, byte) __attribute__((always_inline, unused)); 348 | static inline unsigned char writePort(byte port, byte value, byte bitmask) 349 | { 350 | #if defined(ARDUINO_PINOUT_OPTIMIZE) 351 | if (port == 0) { 352 | bitmask = bitmask & 0xFC; // do not touch Tx & Rx pins 353 | byte valD = value & bitmask; 354 | byte maskD = ~bitmask; 355 | cli(); 356 | PORTD = (PORTD & maskD) | valD; 357 | sei(); 358 | } else if (port == 1) { 359 | byte valB = (value & bitmask) & 0x3F; 360 | byte valC = (value & bitmask) >> 6; 361 | byte maskB = ~(bitmask & 0x3F); 362 | byte maskC = ~((bitmask & 0xC0) >> 6); 363 | cli(); 364 | PORTB = (PORTB & maskB) | valB; 365 | PORTC = (PORTC & maskC) | valC; 366 | sei(); 367 | } else if (port == 2) { 368 | bitmask = bitmask & 0x0F; 369 | byte valC = (value & bitmask) << 2; 370 | byte maskC = ~(bitmask << 2); 371 | cli(); 372 | PORTC = (PORTC & maskC) | valC; 373 | sei(); 374 | } 375 | #else 376 | byte pin=port*8; 377 | if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin+0), (value & 0x01)); 378 | if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin+1), (value & 0x02)); 379 | if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin+2), (value & 0x04)); 380 | if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin+3), (value & 0x08)); 381 | if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin+4), (value & 0x10)); 382 | if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin+5), (value & 0x20)); 383 | if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin+6), (value & 0x40)); 384 | if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin+7), (value & 0x80)); 385 | #endif 386 | } 387 | 388 | 389 | 390 | 391 | #ifndef TOTAL_PORTS 392 | #define TOTAL_PORTS ((TOTAL_PINS + 7) / 8) 393 | #endif 394 | 395 | 396 | #endif /* Firmata_Boards_h */ 397 | 398 | -------------------------------------------------------------------------------- /examples/BLE_RGB/Adafruit_NeoPixel.cpp: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------- 2 | Arduino library to control a wide variety of WS2811-based RGB LED 3 | devices such as Adafruit FLORA RGB Smart Pixels. Currently handles 4 | 400 and 800 KHz bitstreams on both 8 MHz and 16 MHz ATmega MCUs, 5 | with LEDs wired for RGB or GRB color order. 8 MHz MCUs provide 6 | output on PORTB and PORTD, while 16 MHz chips can handle most output 7 | pins (possible exception with some of the upper PORT registers on 8 | the Arduino Mega). 9 | 10 | WILL NOT COMPILE OR WORK ON ARDUINO DUE. Uses inline assembly. 11 | 12 | Written by Phil Burgess / Paint Your Dragon for Adafruit Industries. 13 | 14 | Adafruit invests time and resources providing this open source code, 15 | please support Adafruit and open-source hardware by purchasing 16 | products from Adafruit! 17 | 18 | -------------------------------------------------------------------- 19 | This file is part of the Adafruit NeoPixel library. 20 | 21 | NeoPixel is free software: you can redistribute it and/or modify 22 | it under the terms of the GNU Lesser General Public License as 23 | published by the Free Software Foundation, either version 3 of 24 | the License, or (at your option) any later version. 25 | 26 | NeoPixel is distributed in the hope that it will be useful, 27 | but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | GNU Lesser General Public License for more details. 30 | 31 | You should have received a copy of the GNU Lesser General Public 32 | License along with NeoPixel. If not, see 33 | . 34 | 35 | -------------------------------------------------------------------- 36 | This library does not support chipKIT and DUE, only support AVR. 37 | 38 | --------------------------------------------------------------------*/ 39 | 40 | #include "Adafruit_NeoPixel.h" 41 | 42 | Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p, uint8_t t) { 43 | numBytes = n * 3; 44 | if((pixels = (uint8_t *)malloc(numBytes))) { 45 | memset(pixels, 0, numBytes); 46 | numLEDs = n; 47 | type = t; 48 | pin = p; 49 | port = portOutputRegister(digitalPinToPort(p)); 50 | pinMask = digitalPinToBitMask(p); 51 | endTime = 0L; 52 | } else { 53 | numLEDs = 0; 54 | } 55 | } 56 | 57 | void Adafruit_NeoPixel::begin(void) { 58 | pinMode(pin, OUTPUT); 59 | digitalWrite(pin, LOW); 60 | } 61 | 62 | 63 | #ifdef __arm__ 64 | static inline void delayShort(uint32_t) __attribute__((always_inline, unused)); 65 | static inline void delayShort(uint32_t num) 66 | { 67 | asm volatile( 68 | "L_%=_delayMicroseconds:" "\n\t" 69 | "subs %0, #1" "\n\t" 70 | "bne L_%=_delayMicroseconds" "\n" 71 | //#if F_CPU == 48000000 72 | //"nop" "\n\t" 73 | //#endif 74 | : "+r" (num) : 75 | ); 76 | } 77 | #endif // __arm__ 78 | 79 | 80 | void Adafruit_NeoPixel::show(void) { 81 | 82 | if(!numLEDs) return; 83 | 84 | volatile uint16_t 85 | i = numBytes; // Loop counter 86 | volatile uint8_t 87 | *ptr = pixels, // Pointer to next byte 88 | b = *ptr++, // Current byte value 89 | hi, // PORT w/output bit set high 90 | lo; // PORT w/output bit set low 91 | 92 | // Data latch = 50+ microsecond pause in the output stream. 93 | // Rather than put a delay at the end of the function, the ending 94 | // time is noted and the function will simply hold off (if needed) 95 | // on issuing the subsequent round of data until the latch time has 96 | // elapsed. This allows the mainline code to start generating the 97 | // next frame of data rather than stalling for the latch. 98 | while((micros() - endTime) < 50L); 99 | // endTime is a private member (rather than global var) so that 100 | // mutliple instances on different pins can be quickly issued in 101 | // succession (each instance doesn't delay the next). 102 | 103 | // In order to make this code runtime-configurable to work with 104 | // any pin, SBI/CBI instructions are eschewed in favor of full 105 | // PORT writes via the OUT or ST instructions. It relies on two 106 | // facts: that peripheral functions (such as PWM) take precedence 107 | // on output pins, so our PORT-wide writes won't interfere, and 108 | // that interrupts are globally disabled while data is being issued 109 | // to the LEDs, so no other code will be accessing the PORT. The 110 | // code takes an initial 'snapshot' of the PORT state, computes 111 | // 'pin high' and 'pin low' values, and writes these back to the 112 | // PORT register as needed. 113 | 114 | cli(); // Disable interrupts; need 100% focus on instruction timing 115 | 116 | #ifdef __AVR__ 117 | 118 | #if (F_CPU == 8000000UL) // FLORA, Lilypad, Arduino Pro 8 MHz, etc. 119 | 120 | if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream 121 | 122 | volatile uint8_t n1, n2 = 0; // First, next bits out 123 | 124 | // Squeezing an 800 KHz stream out of an 8 MHz chip requires code 125 | // specific to each PORT register. At present this is only written 126 | // to work with pins on PORTD or PORTB, the most likely use case -- 127 | // this covers all the pins on the Adafruit Flora and the bulk of 128 | // digital pins on the Arduino Pro 8 MHz (keep in mind, this code 129 | // doesn't even get compiled for 16 MHz boards like the Uno, Mega, 130 | // Leonardo, etc., so don't bother extending this out of hand). 131 | // Additional PORTs could be added if you really need them, just 132 | // duplicate the else and loop and change the PORT. Each add'l 133 | // PORT will require about 150(ish) bytes of program space. 134 | 135 | // 10 instruction clocks per bit: HHxxxxxLLL 136 | // OUT instructions: ^ ^ ^ 137 | 138 | if(port == &PORTD) { 139 | 140 | hi = PORTD | pinMask; 141 | lo = hi & ~pinMask; 142 | n1 = lo; 143 | if(b & 0x80) n1 = hi; 144 | 145 | // Dirty trick here: meaningless MULs are used to delay two clock 146 | // cycles in one instruction word (rather than using two NOPs). 147 | // This was necessary in order to squeeze the loop down to exactly 148 | // 64 words -- the maximum possible for a relative branch. 149 | 150 | asm volatile( 151 | "headD:\n\t" // Clk Pseudocode 152 | // Bit 7: 153 | "out %0, %1\n\t" // 1 PORT = hi 154 | "mov %3, %4\n\t" // 1 n2 = lo 155 | "out %0, %2\n\t" // 1 PORT = n1 156 | "mul r0, r0\n\t" // 2 nop nop 157 | "sbrc %5, 6\n\t" // 1-2 if(b & 0x40) 158 | "mov %3, %1\n\t" // 0-1 n2 = hi 159 | "out %0, %4\n\t" // 1 PORT = lo 160 | "mul r0, r0\n\t" // 2 nop nop 161 | // Bit 6: 162 | "out %0, %1\n\t" // 1 PORT = hi 163 | "mov %2, %4\n\t" // 1 n1 = lo 164 | "out %0, %3\n\t" // 1 PORT = n2 165 | "mul r0, r0\n\t" // 2 nop nop 166 | "sbrc %5, 5\n\t" // 1-2 if(b & 0x20) 167 | "mov %2, %1\n\t" // 0-1 n1 = hi 168 | "out %0, %4\n\t" // 1 PORT = lo 169 | "mul r0, r0\n\t" // 2 nop nop 170 | // Bit 5: 171 | "out %0, %1\n\t" // 1 PORT = hi 172 | "mov %3, %4\n\t" // 1 n2 = lo 173 | "out %0, %2\n\t" // 1 PORT = n1 174 | "mul r0, r0\n\t" // 2 nop nop 175 | "sbrc %5, 4\n\t" // 1-2 if(b & 0x10) 176 | "mov %3, %1\n\t" // 0-1 n2 = hi 177 | "out %0, %4\n\t" // 1 PORT = lo 178 | "mul r0, r0\n\t" // 2 nop nop 179 | // Bit 4: 180 | "out %0, %1\n\t" // 1 PORT = hi 181 | "mov %2, %4\n\t" // 1 n1 = lo 182 | "out %0, %3\n\t" // 1 PORT = n2 183 | "mul r0, r0\n\t" // 2 nop nop 184 | "sbrc %5, 3\n\t" // 1-2 if(b & 0x08) 185 | "mov %2, %1\n\t" // 0-1 n1 = hi 186 | "out %0, %4\n\t" // 1 PORT = lo 187 | "mul r0, r0\n\t" // 2 nop nop 188 | // Bit 3: 189 | "out %0, %1\n\t" // 1 PORT = hi 190 | "mov %3, %4\n\t" // 1 n2 = lo 191 | "out %0, %2\n\t" // 1 PORT = n1 192 | "mul r0, r0\n\t" // 2 nop nop 193 | "sbrc %5, 2\n\t" // 1-2 if(b & 0x04) 194 | "mov %3, %1\n\t" // 0-1 n2 = hi 195 | "out %0, %4\n\t" // 1 PORT = lo 196 | "mul r0, r0\n\t" // 2 nop nop 197 | // Bit 2: 198 | "out %0, %1\n\t" // 1 PORT = hi 199 | "mov %2, %4\n\t" // 1 n1 = lo 200 | "out %0, %3\n\t" // 1 PORT = n2 201 | "mul r0, r0\n\t" // 2 nop nop 202 | "sbrc %5, 1\n\t" // 1-2 if(b & 0x02) 203 | "mov %2, %1\n\t" // 0-1 n1 = hi 204 | "out %0, %4\n\t" // 1 PORT = lo 205 | "mul r0, r0\n\t" // 2 nop nop 206 | // Bit 1: 207 | "out %0, %1\n\t" // 1 PORT = hi 208 | "mov %3, %4\n\t" // 1 n2 = lo 209 | "out %0, %2\n\t" // 1 PORT = n1 210 | "mul r0, r0\n\t" // 2 nop nop 211 | "sbrc %5, 0\n\t" // 1-2 if(b & 0x01) 212 | "mov %3, %1\n\t" // 0-1 n2 = hi 213 | "out %0, %4\n\t" // 1 PORT = lo 214 | "sbiw %6, 1\n\t" // 2 i-- (dec. but don't act on zero flag yet) 215 | // Bit 0: 216 | "out %0, %1\n\t" // 1 PORT = hi 217 | "mov %2, %4\n\t" // 1 n1 = lo 218 | "out %0, %3\n\t" // 1 PORT = n2 219 | "ld %5, %a7+\n\t" // 2 b = *ptr++ 220 | "sbrc %5, 7\n\t" // 1-2 if(b & 0x80) 221 | "mov %2, %1\n\t" // 0-1 n1 = hi 222 | "out %0, %4\n\t" // 1 PORT = lo 223 | "brne headD\n" // 2 while(i) (zero flag determined above) 224 | :: 225 | "I" (_SFR_IO_ADDR(PORTD)), // %0 226 | "r" (hi), // %1 227 | "r" (n1), // %2 228 | "r" (n2), // %3 229 | "r" (lo), // %4 230 | "r" (b), // %5 231 | "w" (i), // %6 232 | "e" (ptr) // %a7 233 | ); // end asm 234 | 235 | } else if(port == &PORTB) { 236 | 237 | // Same as above, just switched to PORTB and stripped of comments. 238 | hi = PORTB | pinMask; 239 | lo = hi & ~pinMask; 240 | n1 = lo; 241 | if(b & 0x80) n1 = hi; 242 | asm volatile( 243 | "headB:\n\t" 244 | "out %0, %1\n\t" 245 | "mov %3, %4\n\t" 246 | "out %0, %2\n\t" 247 | "mul r0, r0\n\t" 248 | "sbrc %5, 6\n\t" 249 | "mov %3, %1\n\t" 250 | "out %0, %4\n\t" 251 | "mul r0, r0\n\t" 252 | "out %0, %1\n\t" 253 | "mov %2, %4\n\t" 254 | "out %0, %3\n\t" 255 | "mul r0, r0\n\t" 256 | "sbrc %5, 5\n\t" 257 | "mov %2, %1\n\t" 258 | "out %0, %4\n\t" 259 | "mul r0, r0\n\t" 260 | "out %0, %1\n\t" 261 | "mov %3, %4\n\t" 262 | "out %0, %2\n\t" 263 | "mul r0, r0\n\t" 264 | "sbrc %5, 4\n\t" 265 | "mov %3, %1\n\t" 266 | "out %0, %4\n\t" 267 | "mul r0, r0\n\t" 268 | "out %0, %1\n\t" 269 | "mov %2, %4\n\t" 270 | "out %0, %3\n\t" 271 | "mul r0, r0\n\t" 272 | "sbrc %5, 3\n\t" 273 | "mov %2, %1\n\t" 274 | "out %0, %4\n\t" 275 | "mul r0, r0\n\t" 276 | "out %0, %1\n\t" 277 | "mov %3, %4\n\t" 278 | "out %0, %2\n\t" 279 | "mul r0, r0\n\t" 280 | "sbrc %5, 2\n\t" 281 | "mov %3, %1\n\t" 282 | "out %0, %4\n\t" 283 | "mul r0, r0\n\t" 284 | "out %0, %1\n\t" 285 | "mov %2, %4\n\t" 286 | "out %0, %3\n\t" 287 | "mul r0, r0\n\t" 288 | "sbrc %5, 1\n\t" 289 | "mov %2, %1\n\t" 290 | "out %0, %4\n\t" 291 | "mul r0, r0\n\t" 292 | "out %0, %1\n\t" 293 | "mov %3, %4\n\t" 294 | "out %0, %2\n\t" 295 | "mul r0, r0\n\t" 296 | "sbrc %5, 0\n\t" 297 | "mov %3, %1\n\t" 298 | "out %0, %4\n\t" 299 | "sbiw %6, 1\n\t" 300 | "out %0, %1\n\t" 301 | "mov %2, %4\n\t" 302 | "out %0, %3\n\t" 303 | "ld %5, %a7+\n\t" 304 | "sbrc %5, 7\n\t" 305 | "mov %2, %1\n\t" 306 | "out %0, %4\n\t" 307 | "brne headB\n" :: "I" (_SFR_IO_ADDR(PORTB)), "r" (hi), 308 | "r" (n1), "r" (n2), "r" (lo), "r" (b), "w" (i), "e" (ptr) 309 | ); // end asm 310 | } // endif PORTB 311 | } // end 800 KHz, see comments later re 'else' 312 | 313 | #elif (F_CPU == 16000000UL) 314 | 315 | if((type & NEO_SPDMASK) == NEO_KHZ400) { // 400 KHz bitstream 316 | 317 | // The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version. 318 | // Unrolling the inner loop for each bit is not necessary. 319 | 320 | // 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxxxxxxxxxxxxxLLLLLLLL 321 | // ST instructions: ^ ^ ^ 322 | 323 | volatile uint8_t next, bit; 324 | 325 | hi = *port | pinMask; 326 | lo = hi & ~pinMask; 327 | next = lo; 328 | bit = 8; 329 | 330 | asm volatile( 331 | "head40:\n\t" // Clk Pseudocode (T = 0) 332 | "st %a0, %1\n\t" // 2 PORT = hi (T = 2) 333 | "sbrc %2, 7\n\t" // 1-2 if(b & 128) 334 | "mov %4, %1\n\t" // 0-1 next = hi (T = 4) 335 | "mul r0, r0\n\t" // 2 nop nop (T = 6) 336 | "mul r0, r0\n\t" // 2 nop nop (T = 8) 337 | "st %a0, %4\n\t" // 2 PORT = next (T = 10) 338 | "mul r0, r0\n\t" // 2 nop nop (T = 12) 339 | "mul r0, r0\n\t" // 2 nop nop (T = 14) 340 | "mul r0, r0\n\t" // 2 nop nop (T = 16) 341 | "mul r0, r0\n\t" // 2 nop nop (T = 18) 342 | "mul r0, r0\n\t" // 2 nop nop (T = 20) 343 | "mul r0, r0\n\t" // 2 nop nop (T = 22) 344 | "nop\n\t" // 1 nop (T = 23) 345 | "mov %4, %5\n\t" // 1 next = lo (T = 24) 346 | "dec %3\n\t" // 1 bit-- (T = 25) 347 | "breq nextbyte40\n\t" // 1-2 if(bit == 0) 348 | "rol %2\n\t" // 1 b <<= 1 (T = 27) 349 | "nop\n\t" // 1 nop (T = 28) 350 | "mul r0, r0\n\t" // 2 nop nop (T = 30) 351 | "mul r0, r0\n\t" // 2 nop nop (T = 32) 352 | "st %a0, %5\n\t" // 2 PORT = lo (T = 34) 353 | "mul r0, r0\n\t" // 2 nop nop (T = 36) 354 | "mul r0, r0\n\t" // 2 nop nop (T = 38) 355 | "rjmp head40\n\t" // 2 -> head40 (next bit out) 356 | "nextbyte40:\n\t" // (T = 27) 357 | "ldi %3, 8\n\t" // 1 bit = 8 (T = 28) 358 | "ld %2, %a6+\n\t" // 2 b = *ptr++ (T = 30) 359 | "mul r0, r0\n\t" // 2 nop nop (T = 32) 360 | "st %a0, %5\n\t" // 2 PORT = lo (T = 34) 361 | "mul r0, r0\n\t" // 2 nop nop (T = 36) 362 | "sbiw %7, 1\n\t" // 2 i-- (T = 38) 363 | "brne head40\n\t" // 1-2 if(i != 0) -> head40 (next byte) 364 | :: 365 | "e" (port), // %a0 366 | "r" (hi), // %1 367 | "r" (b), // %2 368 | "r" (bit), // %3 369 | "r" (next), // %4 370 | "r" (lo), // %5 371 | "e" (ptr), // %a6 372 | "w" (i) // %7 373 | ); // end asm 374 | 375 | } // See comments later re 'else' 376 | 377 | #elif ((F_CPU == 16500000UL) && defined(__AVR_ATtiny85__)) 378 | if((type & NEO_SPDMASK) == NEO_KHZ400) { 379 | // Empty case. 400 KHz pixels not supported on 16.5 MHz ATtiny85. 380 | } // See comments later re 'else' 381 | // 800 KHz pixel support on 16.5 MHz ATtiny is experimental and 382 | // NOT guaranteed to work. It's essentially the same loop as the 383 | // 16 MHz ATmega code...as a result, the timing is slightly off 384 | // (825 KHz vs 800), but the WS2811 datasheet suggests this is 385 | // within the allowable margin of error. 386 | #else 387 | #error "CPU SPEED NOT SUPPORTED" 388 | #endif 389 | 390 | // This bizarre floating 'else' is intentional. Only one of the above 391 | // blocks is actually compiled (depending on CPU speed), each with one 392 | // specific 'if' case for pixel speed. This block now handles the 393 | // common alternate case for either: 800 KHz pixels w/16 MHz CPU, or 394 | // 400 KHz pixels w/8 MHz CPU. Instruction timing is the same. 395 | else { 396 | 397 | // Can use nested loop; no need for unrolling. Very similar to 398 | // 16MHz/400KHz code above, but with fewer NOPs and different end. 399 | 400 | // 20 inst. clocks per bit: HHHHxxxxxxxxxxxxLLLL 401 | // ST instructions: ^ ^ ^ 402 | 403 | volatile uint8_t next, bit; 404 | 405 | hi = *port | pinMask; 406 | lo = hi & ~pinMask; 407 | next = lo; 408 | bit = 8; 409 | 410 | asm volatile( 411 | "head20:\n\t" // Clk Pseudocode (T = 0) 412 | "st %a0, %1\n\t" // 2 PORT = hi (T = 2) 413 | "sbrc %2, 7\n\t" // 1-2 if(b & 128) 414 | "mov %4, %1\n\t" // 0-1 next = hi (T = 4) 415 | "st %a0, %4\n\t" // 2 PORT = next (T = 6) 416 | "mov %4, %5\n\t" // 1 next = lo (T = 7) 417 | "dec %3\n\t" // 1 bit-- (T = 8) 418 | "breq nextbyte20\n\t" // 1-2 if(bit == 0) 419 | "rol %2\n\t" // 1 b <<= 1 (T = 10) 420 | #ifdef __AVR_ATtiny85__ 421 | "nop\n\t" // 1 ea. 422 | "nop\n\t" // No MUL on ATtiny 423 | "nop\n\t" 424 | "nop\n\t" 425 | "nop\n\t" 426 | "nop\n\t" 427 | #else 428 | "mul r0, r0\n\t" // 2 nop nop (T = 12) 429 | "mul r0, r0\n\t" // 2 nop nop (T = 14) 430 | "mul r0, r0\n\t" // 2 nop nop (T = 16) 431 | #endif 432 | "st %a0, %5\n\t" // 2 PORT = lo (T = 18) 433 | "rjmp head20\n\t" // 2 -> head20 (next bit out) 434 | "nextbyte20:\n\t" // (T = 10) 435 | "nop\n\t" // 1 nop (T = 11) 436 | "ldi %3, 8\n\t" // 1 bit = 8 (T = 12) 437 | "ld %2, %a6+\n\t" // 2 b = *ptr++ (T = 14) 438 | "sbiw %7, 1\n\t" // 2 i-- (T = 16) 439 | "st %a0, %5\n\t" // 2 PORT = lo (T = 18) 440 | "brne head20\n\t" // 2 if(i != 0) -> head20 (next byte) 441 | :: 442 | "e" (port), // %a0 443 | "r" (hi), // %1 444 | "r" (b), // %2 445 | "r" (bit), // %3 446 | "r" (next), // %4 447 | "r" (lo), // %5 448 | "e" (ptr), // %a6 449 | "w" (i) // %7 450 | ); // end asm 451 | 452 | } // end wacky else (see comment above) 453 | 454 | #endif // __AVR__ 455 | 456 | 457 | 458 | #ifdef __MK20DX128__ // Teensy 3.0 459 | 460 | // This implementation may not be quite perfect, but it seems to work 461 | // reasonably well with an actual 20 LED WS2811 strip. The timing at 462 | // 48 MHz is off a bit, perhaps due to flash cache misses? Ideally 463 | // this code should execute from RAM to eliminate slight timing 464 | // differences between flash caches hits and misses. But it seems to 465 | // quite well. More testing is needed with longer strips. 466 | #if F_CPU == 96000000 467 | #define DELAY_800_T0H 2 468 | #define DELAY_800_T0L 25 469 | #define DELAY_800_T1H 16 470 | #define DELAY_800_T1L 11 471 | #define DELAY_400_T0H 8 472 | #define DELAY_400_T0L 56 473 | #define DELAY_400_T1H 33 474 | #define DELAY_400_T1L 31 475 | #elif F_CPU == 48000000 476 | #define DELAY_800_T0H 1 477 | #define DELAY_800_T0L 13 478 | #define DELAY_800_T1H 8 479 | #define DELAY_800_T1L 6 480 | #define DELAY_400_T0H 4 481 | #define DELAY_400_T0L 29 482 | #define DELAY_400_T1H 16 483 | #define DELAY_400_T1L 17 484 | #elif F_CPU == 24000000 485 | #error "24 MHz not supported, use Tools > CPU Speed at 48 or 96 MHz" 486 | #endif 487 | uint8_t *p = pixels; 488 | uint8_t *end = pixels + numBytes; 489 | volatile uint8_t *set = portSetRegister(pin); 490 | volatile uint8_t *clr = portClearRegister(pin); 491 | if ((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream 492 | while (p < end) { 493 | uint8_t pix = *p++; 494 | for (int mask = 0x80; mask; mask >>= 1) { 495 | if (pix & mask) { 496 | *set = 1; 497 | delayShort(DELAY_800_T1H); 498 | *clr = 1; 499 | delayShort(DELAY_800_T1L); 500 | } else { 501 | *set = 1; 502 | delayShort(DELAY_800_T0H); 503 | *clr = 1; 504 | delayShort(DELAY_800_T0L); 505 | } 506 | } 507 | } 508 | } else { // 400 kHz bitstream 509 | while (p < end) { 510 | uint8_t pix = *p++; 511 | for (int mask = 0x80; mask; mask >>= 1) { 512 | if (pix & mask) { 513 | *set = 1; 514 | delayShort(DELAY_400_T1H); 515 | *clr = 1; 516 | delayShort(DELAY_400_T1L); 517 | } else { 518 | *set = 1; 519 | delayShort(DELAY_400_T0H); 520 | *clr = 1; 521 | delayShort(DELAY_400_T0L); 522 | } 523 | } 524 | } 525 | } 526 | 527 | #endif // __MK20DX128__ Teensy 3.0 528 | 529 | sei(); // Re-enable interrupts 530 | endTime = micros(); // Note EOD time for latch on next call 531 | } 532 | 533 | // Set pixel color from separate R,G,B components: 534 | void Adafruit_NeoPixel::setPixelColor( 535 | uint16_t n, uint8_t r, uint8_t g, uint8_t b) { 536 | if(n < numLEDs) { 537 | uint8_t *p = &pixels[n * 3]; 538 | if((type & NEO_COLMASK) == NEO_GRB) { *p++ = g; *p++ = r; } 539 | else { *p++ = r; *p++ = g; } 540 | *p = b; 541 | } 542 | } 543 | 544 | // Set pixel color from 'packed' 32-bit RGB color: 545 | void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { 546 | if(n < numLEDs) { 547 | uint8_t *p = &pixels[n * 3]; 548 | if((type & NEO_COLMASK) == NEO_GRB) { *p++ = c >> 8; *p++ = c >> 16; } 549 | else { *p++ = c >> 16; *p++ = c >> 8; } 550 | *p = c; 551 | } 552 | } 553 | 554 | // Convert separate R,G,B into packed 32-bit RGB color. 555 | // Packed format is always RGB, regardless of LED strand color order. 556 | uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) { 557 | return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; 558 | } 559 | 560 | // Query color from previously-set pixel (returns packed 32-bit RGB value) 561 | uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) { 562 | 563 | if(n < numLEDs) { 564 | uint16_t ofs = n * 3; 565 | return (uint32_t)(pixels[ofs + 2]) | 566 | (((type & NEO_COLMASK) == NEO_GRB) ? 567 | ((uint32_t)(pixels[ofs ]) << 8) | 568 | ((uint32_t)(pixels[ofs + 1]) << 16) 569 | : 570 | ((uint32_t)(pixels[ofs ]) << 16) | 571 | ((uint32_t)(pixels[ofs + 1]) << 8) ); 572 | } 573 | 574 | return 0; // Pixel # is out of bounds 575 | } 576 | 577 | uint16_t Adafruit_NeoPixel::numPixels(void) { 578 | return numLEDs; 579 | } 580 | -------------------------------------------------------------------------------- /examples/BLE_RGB/Adafruit_NeoPixel.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------- 2 | This file is part of the Adafruit NeoPixel library. 3 | 4 | NeoPixel is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as 6 | published by the Free Software Foundation, either version 3 of 7 | the License, or (at your option) any later version. 8 | 9 | NeoPixel is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with NeoPixel. If not, see 16 | . 17 | --------------------------------------------------------------------*/ 18 | 19 | #if (ARDUINO >= 100) 20 | #include 21 | #else 22 | #include 23 | #include 24 | #endif 25 | 26 | // 'type' flags for LED pixels (third parameter to constructor): 27 | #define NEO_RGB 0x00 // Wired for RGB data order 28 | #define NEO_GRB 0x01 // Wired for GRB data order 29 | #define NEO_COLMASK 0x01 30 | #define NEO_KHZ400 0x00 // 400 KHz datastream 31 | #define NEO_KHZ800 0x02 // 800 KHz datastream 32 | #define NEO_SPDMASK 0x02 33 | 34 | class Adafruit_NeoPixel { 35 | 36 | public: 37 | 38 | // Constructor: number of LEDs, pin number, LED type 39 | Adafruit_NeoPixel(uint16_t n, uint8_t p=6, uint8_t t=NEO_GRB + NEO_KHZ800); 40 | 41 | void 42 | begin(void), 43 | show(void), 44 | setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b), 45 | setPixelColor(uint16_t n, uint32_t c); 46 | uint16_t 47 | numPixels(void); 48 | uint32_t 49 | Color(uint8_t r, uint8_t g, uint8_t b), 50 | getPixelColor(uint16_t n); 51 | 52 | private: 53 | 54 | uint16_t 55 | numLEDs, // Number of RGB LEDs in strip 56 | numBytes; // Size of 'pixels' buffer below 57 | uint8_t 58 | *pixels, // Holds LED color values (3 bytes each) 59 | pin, // Output pin number 60 | pinMask, // Output PORT bitmask 61 | type; // Pixel flags (400 vs 800 KHz, RGB vs GRB color) 62 | volatile uint8_t 63 | *port; // Output PORT register 64 | uint32_t 65 | endTime; // Latch timing reference 66 | 67 | }; 68 | -------------------------------------------------------------------------------- /examples/BLE_RGB/BLE_RGB.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2012, 2013 RedBearLab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include "Adafruit_NeoPixel.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | // Parameter 1 = number of pixels in strip 20 | // Parameter 2 = pin number (most are valid) 21 | // Parameter 3 = pixel type flags, add together as needed: 22 | // NEO_RGB Pixels are wired for RGB bitstream 23 | // NEO_GRB Pixels are wired for GRB bitstream 24 | // NEO_KHZ400 400 KHz bitstream (e.g. FLORA pixels) 25 | // NEO_KHZ800 800 KHz bitstream (e.g. High Density LED strip) 26 | Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, 7, NEO_GRB + NEO_KHZ800); 27 | 28 | int R = 0; 29 | int G = 0; 30 | int B = 0; 31 | 32 | void setup() 33 | { 34 | strip.begin(); 35 | strip.show(); // Initialize all pixels to 'off' 36 | ble_begin(); 37 | } 38 | 39 | void loop() 40 | { 41 | if(3 == ble_available()) 42 | { 43 | R = ble_read(); 44 | G = ble_read(); 45 | B = ble_read(); 46 | colorWipe( strip.Color(R, G, B) ); 47 | } 48 | ble_do_events(); 49 | } 50 | 51 | // Fill the dots one after the other with a color 52 | void colorWipe(uint32_t c) 53 | { 54 | for(uint16_t i=0; i 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | File myFile; 43 | // change this to match your SD shield or module; 44 | // Arduino Ethernet shield: pin 4 45 | // Adafruit SD shields and modules: pin 10 46 | // Sparkfun SD shield: pin 8 47 | const int chipSelect = 4; 48 | 49 | 50 | void setup() 51 | { 52 | // Open serial communications and wait for port to open: 53 | Serial.begin(9600); 54 | while (!Serial) { 55 | ;// wait for serial port to connect. Needed for Leonardo only 56 | } 57 | // Default pins set to 9 and 8 for REQN and RDYN 58 | // Set your REQN and RDYN here before ble_begin() if you need 59 | //ble_set_pins(3, 2); 60 | 61 | // Set your BLE Shield name here, max. length 10 62 | //ble_set_name("My Name"); 63 | 64 | // Init. and start BLE library. 65 | ble_begin(); 66 | 67 | Serial.print("Initializing SD card..."); 68 | // On the Ethernet Shield, CS is pin 4. It's set as an output by default. 69 | // Note that even if it's not used as the CS pin, the hardware SS pin 70 | // (10 on most Arduino boards, 53 on the Mega) must be left as an output 71 | // or the SD library functions will not work. 72 | pinMode(SS, OUTPUT); 73 | 74 | if (!SD.begin(chipSelect)) { 75 | Serial.println("initialization failed!"); 76 | return; 77 | } 78 | Serial.println("initialization done."); 79 | } 80 | 81 | unsigned char rx_buf[20] = {0}; 82 | unsigned char rx_len = 0; 83 | unsigned char ret_dat; 84 | 85 | void loop() 86 | { 87 | if ( ble_available() ) 88 | { 89 | while ( ble_available() ) 90 | { 91 | rx_buf[rx_len] = ble_read(); 92 | Serial.write(rx_buf[rx_len]); 93 | rx_len++; 94 | } 95 | Serial.println(); 96 | } 97 | 98 | if((!ble_busy()) && (rx_len > 0)) 99 | { 100 | Serial.println("Write data to BLE_SD.txt"); 101 | myFile = SD.open("BLE_SD.txt", FILE_WRITE); 102 | // if the file opened okay, write to it: 103 | if (myFile) { 104 | //Serial.print("Writing to BLE_Data.txt..."); 105 | while(--rx_len) 106 | myFile.write(rx_buf[rx_len]); 107 | myFile.write(rx_buf[0]); 108 | // close the file: 109 | myFile.close(); 110 | Serial.println("Write done."); 111 | } else { 112 | // if the file didn't open, print an error: 113 | Serial.println("Open error"); 114 | } 115 | rx_len = 0; 116 | Serial.println("Read data from BLE_SD.txt"); 117 | myFile = SD.open("BLE_SD.txt"); 118 | if (myFile) { 119 | // read from the file until there's nothing else in it: 120 | while (myFile.available()) { 121 | ret_dat = myFile.read(); 122 | ble_write(ret_dat); 123 | Serial.write(ret_dat); 124 | } 125 | Serial.println(""); 126 | Serial.println("Read Done"); 127 | // close the file: 128 | myFile.close(); 129 | } else { 130 | // if the file didn't open, print an error: 131 | Serial.println("Open error"); 132 | } 133 | } 134 | 135 | ble_do_events(); 136 | } 137 | 138 | -------------------------------------------------------------------------------- /examples/HelloWorld/HelloWorld.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2012-2014 RedBearLab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | /* 14 | * HelloWorld 15 | * 16 | * HelloWorld sketch, work with the Chat iOS/Android App. 17 | * It will send "Hello World" string to the App every 1 sec. 18 | * 19 | */ 20 | 21 | //"RBL_nRF8001.h/spi.h/boards.h" is needed in every new project 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | void setup() 28 | { 29 | // 30 | // For BLE Shield and Blend: 31 | // Default pins set to 9 and 8 for REQN and RDYN 32 | // Set your REQN and RDYN here before ble_begin() if you need 33 | // 34 | // For Blend Micro: 35 | // Default pins set to 6 and 7 for REQN and RDYN 36 | // So, no need to set for Blend Micro. 37 | // 38 | //ble_set_pins(3, 2); 39 | 40 | // Set your BLE advertising name here, max. length 10 41 | //ble_set_name("My BLE"); 42 | 43 | // Init. and start BLE library. 44 | ble_begin(); 45 | 46 | // Enable serial debug 47 | Serial.begin(57600); 48 | } 49 | 50 | unsigned char buf[16] = {0}; 51 | unsigned char len = 0; 52 | 53 | void loop() 54 | { 55 | if ( ble_connected() ) 56 | { 57 | ble_write('H'); 58 | ble_write('e'); 59 | ble_write('l'); 60 | ble_write('l'); 61 | ble_write('o'); 62 | ble_write(' '); 63 | ble_write('W'); 64 | ble_write('o'); 65 | ble_write('r'); 66 | ble_write('l'); 67 | ble_write('d'); 68 | ble_write('!'); 69 | } 70 | 71 | ble_do_events(); 72 | 73 | if ( ble_available() ) 74 | { 75 | while ( ble_available() ) 76 | { 77 | Serial.write(ble_read()); 78 | } 79 | 80 | Serial.println(); 81 | } 82 | 83 | delay(1000); 84 | } 85 | 86 | -------------------------------------------------------------------------------- /examples/SimpleChat/SimpleChat.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2012-2014 RedBearLab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | /* 14 | * Chat 15 | * 16 | * Simple chat sketch, work with the Chat iOS/Android App. 17 | * Type something from the Arduino serial monitor to send 18 | * to the Chat App or vice verse. 19 | * 20 | */ 21 | 22 | //"RBL_nRF8001.h/spi.h/boards.h" is needed in every new project 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | void setup() 29 | { 30 | // Default pins set to 9 and 8 for REQN and RDYN 31 | // Set your REQN and RDYN here before ble_begin() if you need 32 | //ble_set_pins(3, 2); 33 | 34 | // Set your BLE Shield name here, max. length 10 35 | //ble_set_name("My Name"); 36 | 37 | // Init. and start BLE library. 38 | ble_begin(); 39 | 40 | // Enable serial debug 41 | Serial.begin(57600); 42 | } 43 | 44 | unsigned char buf[16] = {0}; 45 | unsigned char len = 0; 46 | 47 | void loop() 48 | { 49 | if ( ble_available() ) 50 | { 51 | while ( ble_available() ) 52 | Serial.write(ble_read()); 53 | 54 | Serial.println(); 55 | } 56 | 57 | if ( Serial.available() ) 58 | { 59 | delay(5); 60 | 61 | while ( Serial.available() ) 62 | ble_write( Serial.read() ); 63 | } 64 | 65 | ble_do_events(); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /examples/SimpleControls/SimpleControls.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2012, 2013 RedBearLab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | //"RBL_nRF8001.h/spi.h/boards.h" is needed in every new project 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define DIGITAL_OUT_PIN 2 21 | #define DIGITAL_IN_PIN A4 22 | #define PWM_PIN 3 23 | #define SERVO_PIN 5 24 | #define ANALOG_IN_PIN A5 25 | 26 | Servo myservo; 27 | 28 | void setup() 29 | { 30 | // Default pins set to 9 and 8 for REQN and RDYN 31 | // Set your REQN and RDYN here before ble_begin() if you need 32 | //ble_set_pins(3, 2); 33 | 34 | // Set your BLE Shield name here, max. length 10 35 | //ble_set_name("My Name"); 36 | 37 | // Init. and start BLE library. 38 | ble_begin(); 39 | 40 | // Enable serial debug 41 | Serial.begin(57600); 42 | 43 | pinMode(DIGITAL_OUT_PIN, OUTPUT); 44 | pinMode(DIGITAL_IN_PIN, INPUT); 45 | 46 | // Default to internally pull high, change it if you need 47 | digitalWrite(DIGITAL_IN_PIN, HIGH); 48 | //digitalWrite(DIGITAL_IN_PIN, LOW); 49 | 50 | myservo.attach(SERVO_PIN); 51 | } 52 | 53 | void loop() 54 | { 55 | static boolean analog_enabled = false; 56 | static byte old_state = LOW; 57 | 58 | // If data is ready 59 | while(ble_available()) 60 | { 61 | // read out command and data 62 | byte data0 = ble_read(); 63 | byte data1 = ble_read(); 64 | byte data2 = ble_read(); 65 | 66 | if (data0 == 0x01) // Command is to control digital out pin 67 | { 68 | if (data1 == 0x01) 69 | digitalWrite(DIGITAL_OUT_PIN, HIGH); 70 | else 71 | digitalWrite(DIGITAL_OUT_PIN, LOW); 72 | } 73 | else if (data0 == 0xA0) // Command is to enable analog in reading 74 | { 75 | if (data1 == 0x01) 76 | analog_enabled = true; 77 | else 78 | analog_enabled = false; 79 | } 80 | else if (data0 == 0x02) // Command is to control PWM pin 81 | { 82 | analogWrite(PWM_PIN, data1); 83 | } 84 | else if (data0 == 0x03) // Command is to control Servo pin 85 | { 86 | myservo.write(data1); 87 | } 88 | else if (data0 == 0x04) 89 | { 90 | analog_enabled = false; 91 | myservo.write(0); 92 | analogWrite(PWM_PIN, 0); 93 | digitalWrite(DIGITAL_OUT_PIN, LOW); 94 | } 95 | } 96 | 97 | if (analog_enabled) // if analog reading enabled 98 | { 99 | // Read and send out 100 | uint16_t value = analogRead(ANALOG_IN_PIN); 101 | ble_write(0x0B); 102 | ble_write(value >> 8); 103 | ble_write(value); 104 | } 105 | 106 | // If digital in changes, report the state 107 | if (digitalRead(DIGITAL_IN_PIN) != old_state) 108 | { 109 | old_state = digitalRead(DIGITAL_IN_PIN); 110 | 111 | if (digitalRead(DIGITAL_IN_PIN) == HIGH) 112 | { 113 | ble_write(0x0A); 114 | ble_write(0x01); 115 | ble_write(0x00); 116 | } 117 | else 118 | { 119 | ble_write(0x0A); 120 | ble_write(0x00); 121 | ble_write(0x00); 122 | } 123 | } 124 | 125 | if (!ble_connected()) 126 | { 127 | analog_enabled = false; 128 | digitalWrite(DIGITAL_OUT_PIN, LOW); 129 | } 130 | 131 | // Allow BLE Shield to send/receive data 132 | ble_do_events(); 133 | } 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=RBL_nRF8001 2 | version=1.0.0 3 | author=Cheong 4 | maintainer=Cheong 5 | sentence=An Arduino library for the nRF8001 products such as the BLE Shield and Blend. 6 | paragraph=Providing a simple service (TxRx) for exchanging data between nRF8001 and BLE Central (e.g. iPhone 6), this library requires Nordic BLE SDK for Arduino to function, please also install that library. 7 | category=Communication 8 | url=https://github.com/RedBearLab/nRF8001 9 | architectures=avr 10 | -------------------------------------------------------------------------------- /src/RBL_nRF8001.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | 4 | Copyright (c) 2012, 2013 RedBearLab 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | 12 | */ 13 | 14 | #include 15 | 16 | #include "RBL_nRF8001.h" 17 | 18 | #ifdef SERVICES_PIPE_TYPE_MAPPING_CONTENT 19 | static services_pipe_type_mapping_t 20 | services_pipe_type_mapping[NUMBER_OF_PIPES] = SERVICES_PIPE_TYPE_MAPPING_CONTENT; 21 | #else 22 | #define NUMBER_OF_PIPES 0 23 | static services_pipe_type_mapping_t * services_pipe_type_mapping = NULL; 24 | #endif 25 | 26 | /* Store the setup for the nRF8001 in the flash of the AVR to save on RAM */ 27 | #if ARDUINO < 150 28 | static /*const*/ hal_aci_data_t setup_msgs[NB_SETUP_MESSAGES] PROGMEM = SETUP_MESSAGES_CONTENT; 29 | #else 30 | static const hal_aci_data_t setup_msgs[NB_SETUP_MESSAGES] PROGMEM = SETUP_MESSAGES_CONTENT; 31 | #endif 32 | 33 | #if defined(BLEND_MICRO) 34 | static char device_name[11] = "BlendMicro"; 35 | #elif defined(BLEND) 36 | static char device_name[11] = "Blend "; 37 | #else 38 | static char device_name[11] = "BLE Shield"; 39 | #endif 40 | 41 | static uint8_t bd_addr_own[BTLE_DEVICE_ADDRESS_SIZE]; 42 | static aci_bd_addr_type_t bd_addr_type; 43 | static uint8_t addr_get = 0; 44 | 45 | static uint16_t Adv_Timeout = 0; // Advertising all the time 46 | static uint16_t Adv_Interval = 0x0050; /* advertising interval 50ms 47 | 48 | /*aci_struct that will contain : 49 | total initial credits 50 | current credit 51 | current state of the aci (setup/standby/active/sleep) 52 | open remote pipe pending 53 | close remote pipe pending 54 | Current pipe available bitmap 55 | Current pipe closed bitmap 56 | Current connection interval, slave latency and link supervision timeout 57 | Current State of the the GATT client (Service Discovery) 58 | Status of the bond (R) Peer address*/ 59 | static struct aci_state_t aci_state; 60 | 61 | /*Temporary buffers for sending ACI commands*/ 62 | static hal_aci_evt_t aci_data; 63 | //static hal_aci_data_t aci_cmd; 64 | 65 | /*Timing change state variable*/ 66 | static bool timing_change_done = false; 67 | 68 | /*Initialize the radio_ack. This is the ack received for every transmitted packet.*/ 69 | //static bool radio_ack_pending = false; 70 | 71 | //The maximum size of a packet is 64 bytes. 72 | #define MAX_TX_BUFF 64 73 | static uint8_t tx_buff[MAX_TX_BUFF]; 74 | static uint8_t tx_buffer_len = 0; 75 | 76 | #define MAX_RX_BUFF 64 77 | 78 | static uint8_t rx_buff[MAX_RX_BUFF+1]; 79 | static uint8_t rx_buffer_len = 0; 80 | static uint8_t *p_before = &rx_buff[0] ; 81 | static uint8_t *p_back = &rx_buff[0]; 82 | 83 | static unsigned char is_connected = 0; 84 | 85 | uint8_t reqn_pin = DEFAULT_REQN; 86 | uint8_t rdyn_pin = DEFAULT_RDYN; 87 | 88 | static unsigned char spi_old; 89 | 90 | static void process_events(); 91 | 92 | /* Define how assert should function in the BLE library */ 93 | void __ble_assert(const char *file, uint16_t line) 94 | { 95 | RBL_LOG("ERROR "); 96 | RBL_LOG(file); 97 | RBL_LOG(": "); 98 | RBL_LOG(line); 99 | RBL_LOG("\n"); 100 | while(1); 101 | } 102 | 103 | void ble_set_pins(uint8_t reqn, uint8_t rdyn) 104 | { 105 | #if defined(BLEND_MICRO) 106 | return; 107 | #else 108 | reqn_pin = reqn; 109 | rdyn_pin = rdyn; 110 | #endif 111 | } 112 | 113 | void ble_begin() 114 | { 115 | #if ( !defined(__SAM3X8E__) && !defined(__PIC32MX__) ) 116 | spi_old = SPCR; 117 | SPI.setBitOrder(LSBFIRST); 118 | SPI.setClockDivider(SPI_CLOCK_DIV8); 119 | SPI.setDataMode(SPI_MODE0); 120 | #endif 121 | 122 | memset(bd_addr_own, 0x00, BTLE_DEVICE_ADDRESS_SIZE); 123 | 124 | /* Point ACI data structures to the the setup data that the nRFgo studio generated for the nRF8001 */ 125 | if (NULL != services_pipe_type_mapping) 126 | { 127 | aci_state.aci_setup_info.services_pipe_type_mapping = &services_pipe_type_mapping[0]; 128 | } 129 | else 130 | { 131 | aci_state.aci_setup_info.services_pipe_type_mapping = NULL; 132 | } 133 | aci_state.aci_setup_info.number_of_pipes = NUMBER_OF_PIPES; 134 | aci_state.aci_setup_info.setup_msgs = (hal_aci_data_t*)setup_msgs; 135 | aci_state.aci_setup_info.num_setup_msgs = NB_SETUP_MESSAGES; 136 | 137 | /* 138 | Tell the ACI library, the MCU to nRF8001 pin connections. 139 | The Active pin is optional and can be marked UNUSED 140 | */ 141 | aci_state.aci_pins.board_name = REDBEARLAB_SHIELD_V2; //See board.h for details 142 | aci_state.aci_pins.reqn_pin = reqn_pin; 143 | aci_state.aci_pins.rdyn_pin = rdyn_pin; 144 | aci_state.aci_pins.mosi_pin = MOSI; 145 | aci_state.aci_pins.miso_pin = MISO; 146 | aci_state.aci_pins.sck_pin = SCK; 147 | 148 | #if defined(__SAM3X8E__) 149 | aci_state.aci_pins.spi_clock_divider = 84; 150 | #else 151 | aci_state.aci_pins.spi_clock_divider = SPI_CLOCK_DIV8; 152 | #endif 153 | 154 | aci_state.aci_pins.reset_pin = UNUSED; 155 | aci_state.aci_pins.active_pin = UNUSED; 156 | aci_state.aci_pins.optional_chip_sel_pin = UNUSED; 157 | 158 | aci_state.aci_pins.interface_is_interrupt = false; 159 | aci_state.aci_pins.interrupt_number = 4;//1; 160 | 161 | //We reset the nRF8001 here by toggling the RESET line connected to the nRF8001 162 | //If the RESET line is not available we call the ACI Radio Reset to soft reset the nRF8001 163 | //then we initialize the data structures required to setup the nRF8001 164 | //The second parameter is for turning debug printing on for the ACI Commands and Events so they be printed on the Serial 165 | lib_aci_init(&aci_state, false); 166 | 167 | #if ( !defined(__SAM3X8E__) && !defined(__PIC32MX__) ) 168 | #if (ARDUINO < 150) 169 | SPCR = spi_old; 170 | SPI.begin(); 171 | #endif 172 | #endif 173 | } 174 | 175 | static volatile byte ack = 0; 176 | 177 | void ble_write(unsigned char data) 178 | { 179 | if(tx_buffer_len == MAX_TX_BUFF) 180 | { 181 | return; 182 | } 183 | tx_buff[tx_buffer_len] = data; 184 | tx_buffer_len++; 185 | } 186 | 187 | void ble_write_bytes(unsigned char *data, uint8_t len) 188 | { 189 | for (int i = 0; i < len; i++) 190 | ble_write(data[i]); 191 | } 192 | 193 | int ble_read() 194 | { 195 | int data; 196 | if(rx_buffer_len == 0) return -1; 197 | if(p_before == &rx_buff[MAX_RX_BUFF]) 198 | { 199 | p_before = &rx_buff[0]; 200 | } 201 | data = *p_before; 202 | p_before ++; 203 | rx_buffer_len--; 204 | return data; 205 | } 206 | 207 | unsigned char ble_available() 208 | { 209 | return rx_buffer_len; 210 | } 211 | 212 | unsigned char ble_connected() 213 | { 214 | return is_connected; 215 | } 216 | 217 | void ble_set_name(char *name) 218 | { 219 | unsigned char len=0; 220 | 221 | len = strlen(name); 222 | if(len > 10) 223 | { 224 | RBL_LOG("the new name is too long"); 225 | } 226 | else 227 | { 228 | strcpy(device_name, name); 229 | } 230 | } 231 | 232 | unsigned char ble_busy() 233 | { 234 | if(digitalRead(reqn_pin) == HIGH) 235 | { 236 | return 0; 237 | } 238 | else 239 | { 240 | return 1; 241 | } 242 | } 243 | 244 | void ble_reset(uint8_t reset_pin) 245 | { 246 | pinMode(reset_pin, OUTPUT); 247 | digitalWrite(reset_pin, HIGH); 248 | digitalWrite(reset_pin, LOW); 249 | digitalWrite(reset_pin, HIGH); 250 | } 251 | 252 | void ble_disconnect(void) 253 | { 254 | lib_aci_disconnect(&aci_state, ACI_REASON_TERMINATE); 255 | } 256 | 257 | void ble_get_mac_addr(uint8_t *bd_addr) 258 | { 259 | if(!addr_get) 260 | { 261 | lib_aci_get_address(); // Get device's MAC address and address type 262 | while(!addr_get) 263 | { 264 | process_events(); 265 | } 266 | } 267 | 268 | memcpy(bd_addr, bd_addr_own, BTLE_DEVICE_ADDRESS_SIZE); 269 | } 270 | 271 | static void process_events() 272 | { 273 | static bool setup_required = false; 274 | // We enter the if statement only when there is a ACI event available to be processed 275 | if (lib_aci_event_get(&aci_state, &aci_data)) 276 | { 277 | aci_evt_t *aci_evt; 278 | aci_evt = &aci_data.evt; 279 | switch(aci_evt->evt_opcode) 280 | { 281 | /* As soon as you reset the nRF8001 you will get an ACI Device Started Event */ 282 | case ACI_EVT_DEVICE_STARTED: 283 | aci_state.data_credit_total = aci_evt->params.device_started.credit_available; 284 | switch(aci_evt->params.device_started.device_mode) 285 | { 286 | case ACI_DEVICE_SETUP: 287 | /* When the device is in the setup mode*/ 288 | RBL_LOGLN(F("Evt Device Started: Setup")); 289 | setup_required = true; 290 | break; 291 | case ACI_DEVICE_STANDBY: 292 | RBL_LOGLN(F("Evt Device Started: Standby")); 293 | //Looking for an iPhone by sending radio advertisements 294 | //When an iPhone connects to us we will get an ACI_EVT_CONNECTED event from the nRF8001 295 | if (aci_evt->params.device_started.hw_error) 296 | { 297 | delay(20); //Magic number used to make sure the HW error event is handled correctly. 298 | } 299 | else 300 | { 301 | lib_aci_set_local_data(&aci_state, PIPE_GAP_DEVICE_NAME_SET , (uint8_t *)&device_name , strlen(device_name)); 302 | lib_aci_connect(Adv_Timeout/* in seconds */, Adv_Interval /* advertising interval 50ms*/); 303 | RBL_LOGLN(F("Advertising started")); 304 | } 305 | break; 306 | } 307 | break; //ACI Device Started Event 308 | 309 | case ACI_EVT_CMD_RSP: 310 | //If an ACI command response event comes with an error -> stop 311 | if (ACI_STATUS_SUCCESS != aci_evt->params.cmd_rsp.cmd_status) 312 | { 313 | //ACI ReadDynamicData and ACI WriteDynamicData will have status codes of 314 | //TRANSACTION_CONTINUE and TRANSACTION_COMPLETE 315 | //all other ACI commands will have status code of ACI_STATUS_SCUCCESS for a successful command 316 | RBL_LOG(F("ACI Command ")); 317 | RBL_LOGLN(aci_evt->params.cmd_rsp.cmd_opcode, HEX); 318 | RBL_LOG(F("Evt Cmd respone: Status ")); 319 | RBL_LOGLN(aci_evt->params.cmd_rsp.cmd_status, HEX); 320 | } 321 | if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode) 322 | { 323 | //Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic 324 | lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET, 325 | (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t)); 326 | } 327 | else if (ACI_CMD_GET_DEVICE_ADDRESS == aci_evt->params.cmd_rsp.cmd_opcode) 328 | { 329 | memcpy(bd_addr_own, aci_evt->params.cmd_rsp.params.get_device_address.bd_addr_own, BTLE_DEVICE_ADDRESS_SIZE); 330 | bd_addr_type = aci_evt->params.cmd_rsp.params.get_device_address.bd_addr_type; 331 | addr_get = 1; 332 | 333 | RBL_LOG(F("Device address: ")); 334 | for(uint8_t i=0; i nRF8001 conf. -> GAP. 366 | // Used to increase or decrease bandwidth 367 | timing_change_done = true; 368 | } 369 | break; 370 | 371 | case ACI_EVT_TIMING: 372 | RBL_LOGLN(F("Evt link connection interval changed")); 373 | break; 374 | 375 | case ACI_EVT_DISCONNECTED: 376 | is_connected = 0; 377 | ack = 1; 378 | RBL_LOGLN(F("Evt Disconnected/Advertising timed out")); 379 | lib_aci_connect(Adv_Timeout/* in seconds */, Adv_Interval /* advertising interval 50ms*/); 380 | RBL_LOGLN(F("Advertising started")); 381 | break; 382 | 383 | case ACI_EVT_DATA_RECEIVED: 384 | RBL_LOG(F("Pipe Number: ")); 385 | RBL_LOGLN(aci_evt->params.data_received.rx_data.pipe_number, DEC); 386 | for(int i=0; ilen - 2; i++) 387 | { 388 | if(rx_buffer_len == MAX_RX_BUFF) 389 | { 390 | break; 391 | } 392 | else 393 | { 394 | if(p_back == &rx_buff[MAX_RX_BUFF]) 395 | { 396 | p_back = &rx_buff[0]; 397 | } 398 | *p_back = aci_evt->params.data_received.rx_data.aci_data[i]; 399 | rx_buffer_len++; 400 | p_back++; 401 | } 402 | } 403 | break; 404 | 405 | case ACI_EVT_DATA_CREDIT: 406 | aci_state.data_credit_available = aci_state.data_credit_available + aci_evt->params.data_credit.credit; 407 | RBL_LOG("ACI_EVT_DATA_CREDIT "); 408 | RBL_LOG("Data Credit available: "); 409 | RBL_LOGLN(aci_state.data_credit_available,DEC); 410 | ack=1; 411 | break; 412 | 413 | case ACI_EVT_PIPE_ERROR: 414 | //See the appendix in the nRF8001 Product Specication for details on the error codes 415 | RBL_LOG(F("ACI Evt Pipe Error: Pipe #:")); 416 | RBL_LOG(aci_evt->params.pipe_error.pipe_number, DEC); 417 | RBL_LOG(F(" Pipe Error Code: 0x")); 418 | RBL_LOGLN(aci_evt->params.pipe_error.error_code, HEX); 419 | 420 | //Increment the credit available as the data packet was not sent. 421 | //The pipe error also represents the Attribute protocol Error Response sent from the peer and that should not be counted 422 | //for the credit. 423 | if (ACI_STATUS_ERROR_PEER_ATT_ERROR != aci_evt->params.pipe_error.error_code) 424 | { 425 | aci_state.data_credit_available++; 426 | } 427 | RBL_LOG("Data Credit available: "); 428 | RBL_LOGLN(aci_state.data_credit_available,DEC); 429 | break; 430 | 431 | case ACI_EVT_HW_ERROR: 432 | RBL_LOG(F("HW error: ")); 433 | RBL_LOGLN(aci_evt->params.hw_error.line_num, DEC); 434 | 435 | for(uint8_t counter = 0; counter <= (aci_evt->len - 3); counter++) 436 | { 437 | Serial.write(aci_evt->params.hw_error.file_name[counter]); //uint8_t file_name[20]; 438 | } 439 | RBL_LOGLN(); 440 | lib_aci_connect(Adv_Timeout/* in seconds */, Adv_Interval /* advertising interval 50ms*/); 441 | RBL_LOGLN(F("Advertising started")); 442 | break; 443 | } 444 | } 445 | else 446 | { 447 | //RBL_LOGLN(F("No ACI Events available")); 448 | // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep 449 | // Arduino can go to sleep now 450 | // Wakeup from sleep from the RDYN line 451 | } 452 | /* setup_required is set to true when the device starts up and enters setup mode. 453 | * It indicates that do_aci_setup() should be called. The flag should be cleared if 454 | * do_aci_setup() returns ACI_STATUS_TRANSACTION_COMPLETE. 455 | */ 456 | if(setup_required) 457 | { 458 | if (SETUP_SUCCESS == do_aci_setup(&aci_state)) 459 | { 460 | setup_required = false; 461 | } 462 | } 463 | } 464 | 465 | void ble_do_events() 466 | { 467 | #if ( !defined(__SAM3X8E__) && !defined(__PIC32MX__) ) 468 | spi_old = SPCR; 469 | SPI.setBitOrder(LSBFIRST); 470 | SPI.setClockDivider(SPI_CLOCK_DIV8); 471 | SPI.setDataMode(SPI_MODE0); 472 | #endif 473 | 474 | if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)) 475 | { 476 | if(tx_buffer_len > 0) 477 | { 478 | unsigned char Index = 0; 479 | while(tx_buffer_len > 20) 480 | { 481 | if(true == lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, &tx_buff[Index], 20)) 482 | { 483 | RBL_LOG("data transmmit success! Length: "); 484 | RBL_LOG(20, DEC); 485 | RBL_LOG(" "); 486 | } 487 | else 488 | { 489 | RBL_LOGLN("data transmmit fail !"); 490 | } 491 | tx_buffer_len -= 20; 492 | Index += 20; 493 | aci_state.data_credit_available--; 494 | RBL_LOG("Data Credit available: "); 495 | RBL_LOGLN(aci_state.data_credit_available,DEC); 496 | ack = 0; 497 | while (!ack) 498 | process_events(); 499 | } 500 | 501 | if(true == lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX,& tx_buff[Index], tx_buffer_len)) 502 | { 503 | RBL_LOG("data transmmit success! Length: "); 504 | RBL_LOG(tx_buffer_len, DEC); 505 | RBL_LOG(" "); 506 | } 507 | else 508 | { 509 | RBL_LOGLN("data transmmit fail !"); 510 | } 511 | tx_buffer_len = 0; 512 | aci_state.data_credit_available--; 513 | RBL_LOG("Data Credit available: "); 514 | RBL_LOGLN(aci_state.data_credit_available,DEC); 515 | ack = 0; 516 | while (!ack) 517 | process_events(); 518 | } 519 | } 520 | process_events(); 521 | 522 | #if ( !defined(__SAM3X8E__) && !defined(__PIC32MX__) ) 523 | SPCR = spi_old; 524 | #endif 525 | } 526 | 527 | -------------------------------------------------------------------------------- /src/RBL_nRF8001.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (c) 2012, 2013 RedBearLab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #ifndef _RBL_NRF8001_H 14 | #define _RBL_NRF8001_H 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #if ( !defined(__SAM3X8E__) && !defined(__PIC32MX__) ) 21 | #include 22 | #include 23 | #endif 24 | 25 | /* Put the nRF8001 setup in the RAM of the nRF8001.*/ 26 | #include "RBL_services.h" 27 | /* Include the services_lock.h to put the setup in the OTP memory of the nRF8001. 28 | This would mean that the setup cannot be changed once put in. 29 | However this removes the need to do the setup of the nRF8001 on every reset.*/ 30 | 31 | #if defined(BLEND_MICRO) 32 | #define DEFAULT_REQN 6 33 | #define DEFAULT_RDYN 7 34 | #else 35 | #define DEFAULT_REQN 9 36 | #define DEFAULT_RDYN 8 37 | #endif 38 | 39 | void ble_begin(); 40 | void ble_set_name(char *name); 41 | void ble_write(unsigned char data); 42 | void ble_write_bytes(unsigned char *data, unsigned char len); 43 | void ble_do_events(); 44 | int ble_read(); 45 | unsigned char ble_available(); 46 | unsigned char ble_connected(void); 47 | void ble_set_pins(uint8_t reqn, uint8_t rdyn); 48 | unsigned char ble_busy(); 49 | void ble_reset(uint8_t reset_pin); 50 | void ble_disconnect(void); 51 | void ble_get_mac_addr(uint8_t *bd_addr); 52 | 53 | #ifdef RBL_ENABLE_LOGGING 54 | # define RBL_LOG(...) Serial.print(__VA_ARGS__) 55 | # define RBL_LOGLN(...) Serial.println(__VA_ARGS__) 56 | #else 57 | # define RBL_LOG(...) 58 | # define RBL_LOGLN(...) 59 | #endif // RBL_ENABLE_LOGGING 60 | 61 | #endif 62 | 63 | -------------------------------------------------------------------------------- /src/RBL_nRF8001.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0 5 | nRF8001_Dx 6 | 7 | UART over BTLE 8 | 0000 9 | 10 | UART RX 11 | 0003 12 | 13 | 0 14 | 20 15 | 2 16 | false 17 | false 18 | 19 | true 20 | false 21 | false 22 | false 23 | false 24 | 25 | false 26 | false 27 | 28 | 0 29 | 30 | 31 | 32 | UART TX 33 | 0002 34 | 35 | 0 36 | 20 37 | 2 38 | false 39 | false 40 | 41 | false 42 | false 43 | true 44 | false 45 | false 46 | 47 | false 48 | false 49 | 50 | 0 51 | 52 | 53 | 54 | 55 | Device Information 56 | 180a 57 | 58 | Hardware Revision String 59 | 2a27 60 | 0A 61 | 0 62 | 9 63 | 2 64 | false 65 | false 66 | 67 | false 68 | false 69 | false 70 | false 71 | false 72 | 73 | true 74 | false 75 | 76 | 0 77 | 78 | 79 | 80 | 81 | BLE Shield 82 | 10 83 | true 84 | 0 85 | 0000 86 | 0 87 | 0 88 | 0 89 | 600 90 | 0 91 | 7 92 | 16 93 | 10 94 | 10 95 | 10 96 | 0 97 | 1a 98 | a 99 | 0 100 | 0 101 | 0 102 | 0 103 | 0 104 | 0 105 | 0 106 | 6 107 | 18 108 | 0 109 | 10 110 | true 111 | true 112 | 5 113 | 114 | 0000 115 | 116 | 117 | 118 | 19 119 | 0000 120 | 121 | 122 | 18 123 | 124 | 125 | 126 | 127 | 128 | 1 129 | 1 130 | 3 131 | 0 132 | 0 133 | 0 134 | 0 135 | false 136 | 137 | 138 | 220 139 | 10 140 | 1000 141 | 10 142 | 10 143 | 1280 144 | 145 | 146 | -------------------------------------------------------------------------------- /src/RBL_services.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is autogenerated by nRFgo Studio 1.17.0.3211 3 | */ 4 | 5 | #ifndef SETUP_MESSAGES_H__ 6 | #define SETUP_MESSAGES_H__ 7 | 8 | #include "hal_platform.h" 9 | #include "aci.h" 10 | 11 | 12 | #define SETUP_ID 0 13 | #define SETUP_FORMAT 3 /** nRF8001 D */ 14 | #define ACI_DYNAMIC_DATA_SIZE 197 15 | 16 | /* Service: Gap - Characteristic: Device name - Pipe: SET */ 17 | #define PIPE_GAP_DEVICE_NAME_SET 1 18 | #define PIPE_GAP_DEVICE_NAME_SET_MAX_SIZE 10 19 | 20 | /* Service: GATT - Characteristic: Service Changed - Pipe: TX_ACK */ 21 | #define PIPE_GATT_SERVICE_CHANGED_TX_ACK 2 22 | #define PIPE_GATT_SERVICE_CHANGED_TX_ACK_MAX_SIZE 4 23 | 24 | /* Service: UART over BTLE - Characteristic: UART RX - Pipe: RX */ 25 | #define PIPE_UART_OVER_BTLE_UART_RX_RX 3 26 | #define PIPE_UART_OVER_BTLE_UART_RX_RX_MAX_SIZE 20 27 | 28 | /* Service: UART over BTLE - Characteristic: UART TX - Pipe: TX */ 29 | #define PIPE_UART_OVER_BTLE_UART_TX_TX 4 30 | #define PIPE_UART_OVER_BTLE_UART_TX_TX_MAX_SIZE 20 31 | 32 | /* Service: Device Information - Characteristic: Hardware Revision String - Pipe: SET */ 33 | #define PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET 5 34 | #define PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET_MAX_SIZE 9 35 | 36 | 37 | #define NUMBER_OF_PIPES 5 38 | 39 | #define SERVICES_PIPE_TYPE_MAPPING_CONTENT {\ 40 | {ACI_STORE_LOCAL, ACI_SET}, \ 41 | {ACI_STORE_LOCAL, ACI_TX_ACK}, \ 42 | {ACI_STORE_LOCAL, ACI_RX}, \ 43 | {ACI_STORE_LOCAL, ACI_TX}, \ 44 | {ACI_STORE_LOCAL, ACI_SET}, \ 45 | } 46 | 47 | #define GAP_PPCP_MAX_CONN_INT 0x12 /**< Maximum connection interval as a multiple of 1.25 msec , 0xFFFF means no specific value requested */ 48 | #define GAP_PPCP_MIN_CONN_INT 0x6 /**< Minimum connection interval as a multiple of 1.25 msec , 0xFFFF means no specific value requested */ 49 | #define GAP_PPCP_SLAVE_LATENCY 0 50 | #define GAP_PPCP_CONN_TIMEOUT 0xa /** Connection Supervision timeout multiplier as a multiple of 10msec, 0xFFFF means no specific value requested */ 51 | 52 | #define NB_SETUP_MESSAGES 23 53 | #define SETUP_MESSAGES_CONTENT {\ 54 | {0x00,\ 55 | {\ 56 | 0x07,0x06,0x00,0x00,0x03,0x02,0x42,0x07,\ 57 | },\ 58 | },\ 59 | {0x00,\ 60 | {\ 61 | 0x1f,0x06,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x05,0x01,0x01,0x00,0x00,0x06,0x00,0x00,\ 62 | 0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ 63 | },\ 64 | },\ 65 | {0x00,\ 66 | {\ 67 | 0x1f,0x06,0x10,0x1c,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ 68 | 0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x03,0x90,0x01,0xff,\ 69 | },\ 70 | },\ 71 | {0x00,\ 72 | {\ 73 | 0x1f,0x06,0x10,0x38,0xff,0xff,0x02,0x58,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x00,0x00,\ 74 | 0x00,0x10,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,\ 75 | },\ 76 | },\ 77 | {0x00,\ 78 | {\ 79 | 0x05,0x06,0x10,0x54,0x00,0x00,\ 80 | },\ 81 | },\ 82 | {0x00,\ 83 | {\ 84 | 0x1f,0x06,0x20,0x00,0x04,0x04,0x02,0x02,0x00,0x01,0x28,0x00,0x01,0x00,0x18,0x04,0x04,0x05,0x05,0x00,\ 85 | 0x02,0x28,0x03,0x01,0x0e,0x03,0x00,0x00,0x2a,0x04,0x14,0x0a,\ 86 | },\ 87 | },\ 88 | {0x00,\ 89 | {\ 90 | 0x1f,0x06,0x20,0x1c,0x0a,0x00,0x03,0x2a,0x00,0x01,0x42,0x4c,0x45,0x20,0x53,0x68,0x69,0x65,0x6c,0x64,\ 91 | 0x04,0x04,0x05,0x05,0x00,0x04,0x28,0x03,0x01,0x02,0x05,0x00,\ 92 | },\ 93 | },\ 94 | {0x00,\ 95 | {\ 96 | 0x1f,0x06,0x20,0x38,0x01,0x2a,0x06,0x04,0x03,0x02,0x00,0x05,0x2a,0x01,0x01,0x00,0x00,0x04,0x04,0x05,\ 97 | 0x05,0x00,0x06,0x28,0x03,0x01,0x02,0x07,0x00,0x04,0x2a,0x06,\ 98 | },\ 99 | },\ 100 | {0x00,\ 101 | {\ 102 | 0x1f,0x06,0x20,0x54,0x04,0x09,0x08,0x00,0x07,0x2a,0x04,0x01,0x06,0x00,0x12,0x00,0x00,0x00,0x0a,0x00,\ 103 | 0x04,0x04,0x02,0x02,0x00,0x08,0x28,0x00,0x01,0x01,0x18,0x04,\ 104 | },\ 105 | },\ 106 | {0x00,\ 107 | {\ 108 | 0x1f,0x06,0x20,0x70,0x04,0x05,0x05,0x00,0x09,0x28,0x03,0x01,0x22,0x0a,0x00,0x05,0x2a,0x26,0x04,0x05,\ 109 | 0x04,0x00,0x0a,0x2a,0x05,0x01,0x00,0x00,0x00,0x00,0x46,0x14,\ 110 | },\ 111 | },\ 112 | {0x00,\ 113 | {\ 114 | 0x1f,0x06,0x20,0x8c,0x03,0x02,0x00,0x0b,0x29,0x02,0x01,0x00,0x00,0x04,0x04,0x10,0x10,0x00,0x0c,0x28,\ 115 | 0x00,0x01,0x1e,0x94,0x8d,0xf1,0x48,0x31,0x94,0xba,0x75,0x4c,\ 116 | },\ 117 | },\ 118 | {0x00,\ 119 | {\ 120 | 0x1f,0x06,0x20,0xa8,0x3e,0x50,0x00,0x00,0x3d,0x71,0x04,0x04,0x13,0x13,0x00,0x0d,0x28,0x03,0x01,0x04,\ 121 | 0x0e,0x00,0x1e,0x94,0x8d,0xf1,0x48,0x31,0x94,0xba,0x75,0x4c,\ 122 | },\ 123 | },\ 124 | {0x00,\ 125 | {\ 126 | 0x1f,0x06,0x20,0xc4,0x3e,0x50,0x03,0x00,0x3d,0x71,0x44,0x10,0x14,0x00,0x00,0x0e,0x00,0x03,0x02,0x00,\ 127 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ 128 | },\ 129 | },\ 130 | {0x00,\ 131 | {\ 132 | 0x1f,0x06,0x20,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x13,0x13,0x00,0x0f,0x28,0x03,0x01,\ 133 | 0x10,0x10,0x00,0x1e,0x94,0x8d,0xf1,0x48,0x31,0x94,0xba,0x75,\ 134 | },\ 135 | },\ 136 | {0x00,\ 137 | {\ 138 | 0x1f,0x06,0x20,0xfc,0x4c,0x3e,0x50,0x02,0x00,0x3d,0x71,0x14,0x00,0x14,0x00,0x00,0x10,0x00,0x02,0x02,\ 139 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ 140 | },\ 141 | },\ 142 | {0x00,\ 143 | {\ 144 | 0x1f,0x06,0x21,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x14,0x03,0x02,0x00,0x11,0x29,0x02,\ 145 | 0x01,0x00,0x00,0x04,0x04,0x02,0x02,0x00,0x12,0x28,0x00,0x01,\ 146 | },\ 147 | },\ 148 | {0x00,\ 149 | {\ 150 | 0x1f,0x06,0x21,0x34,0x0a,0x18,0x04,0x04,0x05,0x05,0x00,0x13,0x28,0x03,0x01,0x02,0x14,0x00,0x27,0x2a,\ 151 | 0x04,0x04,0x09,0x01,0x00,0x14,0x2a,0x27,0x01,0x0a,0x00,0x00,\ 152 | },\ 153 | },\ 154 | {0x00,\ 155 | {\ 156 | 0x0a,0x06,0x21,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ 157 | },\ 158 | },\ 159 | {0x00,\ 160 | {\ 161 | 0x1f,0x06,0x40,0x00,0x2a,0x00,0x01,0x00,0x80,0x04,0x00,0x03,0x00,0x00,0x2a,0x05,0x01,0x00,0x04,0x04,\ 162 | 0x00,0x0a,0x00,0x0b,0x00,0x03,0x02,0x00,0x08,0x04,0x00,0x0e,\ 163 | },\ 164 | },\ 165 | {0x00,\ 166 | {\ 167 | 0x19,0x06,0x40,0x1c,0x00,0x00,0x00,0x02,0x02,0x00,0x02,0x04,0x00,0x10,0x00,0x11,0x2a,0x27,0x01,0x00,\ 168 | 0x80,0x04,0x00,0x14,0x00,0x00,\ 169 | },\ 170 | },\ 171 | {0x00,\ 172 | {\ 173 | 0x13,0x06,0x50,0x00,0x1e,0x94,0x8d,0xf1,0x48,0x31,0x94,0xba,0x75,0x4c,0x3e,0x50,0x00,0x00,0x3d,0x71,\ 174 | },\ 175 | },\ 176 | {0x00,\ 177 | {\ 178 | 0x12,0x06,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ 179 | },\ 180 | },\ 181 | {0x00,\ 182 | {\ 183 | 0x06,0x06,0xf0,0x00,0x03,0x3d,0x6c,\ 184 | },\ 185 | },\ 186 | } 187 | 188 | #endif 189 | -------------------------------------------------------------------------------- /src/run_me_compile_xml_to_nRF8001_setup.bat: -------------------------------------------------------------------------------- 1 | del services.h 2 | del services_lock.h 3 | del ublue_setup.gen.out.txt 4 | 5 | "%NRFGOSTUDIOPATH%"\nrfgostudio.exe -nrf8001 -g RBL_nRF8001.xml -codeGenVersion 1 -o . --------------------------------------------------------------------------------