├── 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 .
--------------------------------------------------------------------------------