├── README.md
├── arduino
├── README.MD
└── libraries
│ ├── AltSoftSerial
│ ├── AltSoftSerial.cpp
│ ├── AltSoftSerial.h
│ ├── config
│ │ ├── known_boards.h
│ │ └── known_timers.h
│ ├── examples
│ │ └── Test
│ │ │ └── Test.pde
│ └── keywords.txt
│ └── BLEHCI
│ ├── ble_hci.cpp
│ ├── ble_hci.h
│ ├── central.cpp
│ ├── central.h
│ ├── examples
│ ├── BLE_HCI_BLEShieldCentral
│ │ ├── BLEShield_Central.cpp
│ │ ├── BLEShield_Central.h
│ │ └── BLE_HCI_BLEShieldCentral.ino
│ ├── BLE_HCI_BiscuitCentral
│ │ ├── BLE_HCI_BiscuitCentral.ino
│ │ ├── biscuit_central.cpp
│ │ └── biscuit_central.h
│ └── BiscuitPeripheral
│ │ └── BiscuitPeripheral.ino
│ └── typedef.h
├── cc2540_hci_fw
├── HCI_UART_115200bps_20130429.bin.zip
├── HCI_UART_57600bps_20130502.bin.zip
├── HCI_USBCDC_115200_20130429.bin.zip
└── UBL-1.3.hex.zip
├── drivers
├── ccxxxx_usb_cdc.cat
└── ccxxxx_usb_cdc.inf
└── python
├── BLEMini
├── Biscuit_Central_HCI.py
└── Biscuit_Peripheral.py
├── BLEShield
└── BLEShield_Central_HCI.py
└── SensorTag
└── SensorTag_Central_HCI.py
/README.md:
--------------------------------------------------------------------------------
1 | BLE_HCI
2 | =======
3 |
4 | Allows external systems or MCUs to control BLE chip (CC2540) using Bluetooth HCI mode such as Windows/Linux/Mac, Arduino (AVR), Teensy 3.0 (ARM Cortex-M4), Respberry Pi (ARM11), etc.
5 |
6 | This library was written for Python (Tested on Windows, Linux and Mac OSX) and Arduino platforms.
7 |
8 | This is in beta and still a work in progress, not all HCI commands and events have been implemented or fully tested.
9 |
10 | The HCI firmware is built from TI CC254x SDK, refer to the HostTestApp project if you want to study the firmware code.
11 |
12 | You can use it to connect to other BLE devices such as our BLE Mini and BLE Shield. Note that, it is also possible to connect to other BLE devices but modify the source code is required.
13 |
14 | To learn more about HCI mode, you can refer to BTool in TI CC254x SDK.
15 |
16 | Example 1
17 | =========
18 |
19 | PC/Mac as BLE central role and via the BLE link, connecting to BLE Mini running Biscuit firmware as peripheral role
20 |
21 | Typical connections:
22 | 1. PC <-> USB <-> BLE Mini (HCI) <----- BLE Link ------> BLE Mini (Biscuit) <-> Serial <-> Ardino
23 | 2. Mac <-> USB <-> BLE Mini (HCI) <----- BLE Link ------> BLE Mini (Biscuit) <-> USB <-> Raspberry Pi
24 | 3. Raspberry Pi <-> USB <-> BLE Mini (HCI) <----- BLE Link -----> BLE Mini (Biscuit) <-> Serial <-> Arduino
25 |
26 | Requirements:
27 | 1. A PC running Windows, Linux or a Mac running Mac OS X
28 | 2. Raspberry Pi with Linux is also possible
29 | 3. HCI firmware (USB) and Biscuit firmware (USB or Serial)
30 | 4. Two BLE Mini boards, first one running the HCI firmware, another one running the Biscuit firmware
31 | 5. Install Python 2.7.2 32-bit
32 | 6. Install PySerial 2.5
33 | 7. For Windows, install USB CDC driver
34 | 8. Biscuit central Python script
35 |
36 | How it works:
37 | When you connect the BLE Mini (HCI) to your PC via the USB port, it will function as an USB CDC (Virtual COM Port). On Windows, it will ask for a device driver, so you need to install the USB CDC driver. It shows as a COM port (e.g. COM5). For Linux or Mac OS X, it will work as a tty device (e.g. ttyACM0 or tty.usbmodem1311).
38 |
39 | The Biscuit central Python script controls the virtual COM port, sending BLE command over the port, and listening to the HCI events.
40 |
41 | You need to change the following lines to match your COM port and bardrate:
42 | ```python
43 | if os.name == 'posix':
44 | TX.port = '/dev/tty.usbmodem1431'
45 | else:
46 | TX.port = 'COM5'
47 | TX.baudrate = 115200
48 | ```
49 |
50 | Press 'd' to start discovery, it will show if any device is found, and then press 'e' to establish a BLE link with the device, you need then enable the notification before you can receive data from the device.
51 |
52 | Press '1', it will send a string 'Hello World!' to the device and press '2' will send 'I love BLE!'.
53 |
54 | You can do many other interesting things as you want with BLE.
55 |
56 | Supported systems:
57 | 1. Windows
58 | 2. Linux (includes Raspberry Pi)
59 | 3. Mac OS X
60 |
61 | Example 2
62 | =========
63 |
64 | Arduino as BLE central role and via the BLE link, connecting to BLE Mini running Biscuit firmware as peripheral role
65 |
66 | Typical connections:
67 | 1. Arduino (A) <-> Serial <-> BLE Mini (A) <----- BLE Link -----> BLE Mini (B) <-> Serial <-> Arduino (B)
68 | 2. Arduino (A) <-> Serial <-> BLE Mini (A) <----- BLE Link -----> BLE Mini (C) <-> USB <-> Raspberry Pi
69 |
70 | * Suggest to use Arduino Leonardo or other boards with more than one serial to try this example.
71 | * We use the USB CDC serial for debug/UI and one for connecting to the BLE Mini on Leonardo board.
72 | * Uno has only one serial and we do not use SoftwareSerial because sometimes data recevied incorrectly.
73 | -> We used AltSoftSerial, so Uno works now, but the baudrate limited to 57600bps.
74 | -> http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
75 | * Tested with Uno (use pin 8, 9), Leonardo (use pin 0, 1), Mega 2560 (use TX1, RX1)
76 |
77 | Requirements:
78 | 1. BLE HCI library for Arduino
79 | 2. Arduino (A) running HCI library
80 | 3. AltSoftSerial (requred for Arduino Uno)
81 | 4. BLE Mini (A) running HCI firmware (Serial)
82 | 5. BLE Mini (B or C) running Biscuit firmware (Serial or USB)
83 |
84 | How it works:
85 | Similar to the Example 1, the Arduino will keep tracks of HCI events from the serial port. You can see those events and send command using the Arduino IDE's Serial Monitor.
86 |
87 | Supported Arduino boards or compatible:
88 | 1. Arduino UNO (R3)
89 | 2. Arduino Leonardo (R3)
90 | 3. Arduino Mega 2560 (R3)
91 | 4. Seeeduino V3.0 (Atmega 328P)
92 | 5. Teensy 3.0
93 | Write to us if any other boards you tested.
94 |
--------------------------------------------------------------------------------
/arduino/README.MD:
--------------------------------------------------------------------------------
1 |
2 | Arduino
3 | -------
4 |
5 | This folder contains Arduino library and examples.
6 |
7 | The BLE_HCI_BiscuitCentral is for BLE Mini (Central) to connect to BLE Mini (Peripheral).
8 |
9 | The BLE_HCI_BLEShieldCentral is for BLE Mini (Central) to connect to BLE Shield (Peripheral).
10 |
11 | This example will send data to the BLE Shield and turn on the LED connected to Arduino UNO pin 7.
12 | You need to load the BLEFirmata to the UNO board.
13 |
14 | Use the Serial Monitor on Leonardo board, and press 'd' for discovery, after it shows 1 device discovered, press 'e' for establish a link to the BLE Shield, after that press '1' or '2' to trun on or off the LED.
15 |
16 | The connection is:
17 | Arduino Leonardo <-> UART <-> BLE Mini <--- BLE Link ---> BLE Shield <-> SPI <-> Arduino UNO
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/arduino/libraries/AltSoftSerial/AltSoftSerial.cpp:
--------------------------------------------------------------------------------
1 | /* An Alternative Software Serial Library
2 | * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
3 | * Copyright (c) 2012 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | * THE SOFTWARE.
22 | */
23 |
24 | #include "AltSoftSerial.h"
25 | #include "config/known_boards.h"
26 | #include "config/known_timers.h"
27 |
28 | /****************************************/
29 | /** Initialization **/
30 | /****************************************/
31 |
32 | static uint16_t ticks_per_bit=0;
33 | bool AltSoftSerial::timing_error=false;
34 |
35 | //#define MAX_RX_EVENTS 10
36 | //static volatile uint8_t rx_count=0;
37 | //static uint16_t rx_event[MAX_RX_EVENTS];
38 | static uint8_t rx_state;
39 | static uint8_t rx_byte;
40 | static uint8_t rx_bit = 0;
41 | static uint16_t rx_target;
42 | static uint16_t rx_stop_ticks=0;
43 | static volatile uint8_t rx_buffer_head;
44 | static volatile uint8_t rx_buffer_tail;
45 | #define RX_BUFFER_SIZE 80
46 | static volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
47 |
48 | static volatile uint8_t tx_state=0;
49 | static uint8_t tx_byte;
50 | static uint8_t tx_bit;
51 | static volatile uint8_t tx_buffer_head;
52 | static volatile uint8_t tx_buffer_tail;
53 | #define TX_BUFFER_SIZE 68
54 | static volatile uint8_t tx_buffer[RX_BUFFER_SIZE];
55 |
56 |
57 | #ifndef INPUT_PULLUP
58 | #define INPUT_PULLUP INPUT
59 | #endif
60 |
61 | void AltSoftSerial::init(uint32_t cycles_per_bit)
62 | {
63 | if (cycles_per_bit < 7085) {
64 | CONFIG_TIMER_NOPRESCALE();
65 | } else {
66 | cycles_per_bit /= 8;
67 | if (cycles_per_bit < 7085) {
68 | CONFIG_TIMER_PRESCALE_8();
69 | } else {
70 | return; // minimum 283 baud at 16 MHz clock
71 | }
72 | }
73 | ticks_per_bit = cycles_per_bit;
74 | rx_stop_ticks = cycles_per_bit * 37 / 4;
75 | pinMode(INPUT_CAPTURE_PIN, INPUT_PULLUP);
76 | digitalWrite(OUTPUT_COMPARE_A_PIN, HIGH);
77 | pinMode(OUTPUT_COMPARE_A_PIN, OUTPUT);
78 | //rx_count = 0;
79 | rx_state = 0;
80 | rx_buffer_head = 0;
81 | rx_buffer_tail = 0;
82 | tx_state = 0;
83 | tx_buffer_head = 0;
84 | tx_buffer_tail = 0;
85 | ENABLE_INT_INPUT_CAPTURE();
86 | }
87 |
88 | void AltSoftSerial::end(void)
89 | {
90 | DISABLE_INT_COMPARE_B();
91 | DISABLE_INT_INPUT_CAPTURE();
92 | flushInput();
93 | flushOutput();
94 | DISABLE_INT_COMPARE_A();
95 | // TODO: restore timer to original settings?
96 | }
97 |
98 |
99 | /****************************************/
100 | /** Transmission **/
101 | /****************************************/
102 |
103 | void AltSoftSerial::writeByte(uint8_t b)
104 | {
105 | uint8_t intr_state, head;
106 |
107 | head = tx_buffer_head + 1;
108 | if (head >= TX_BUFFER_SIZE) head = 0;
109 | while (tx_buffer_tail == head) ; // wait until space in buffer
110 | intr_state = SREG;
111 | cli();
112 | if (tx_state) {
113 | tx_buffer[head] = b;
114 | tx_buffer_head = head;
115 | } else {
116 | tx_state = 1;
117 | tx_byte = b;
118 | tx_bit = 0;
119 | ENABLE_INT_COMPARE_A();
120 | CONFIG_MATCH_CLEAR();
121 | SET_COMPARE_A(GET_TIMER_COUNT() + 16);
122 | }
123 | SREG = intr_state;
124 | }
125 |
126 |
127 | ISR(COMPARE_A_INTERRUPT)
128 | {
129 | uint8_t state, byte, bit, head, tail;
130 | uint16_t target;
131 |
132 | state = tx_state;
133 | byte = tx_byte;
134 | target = GET_COMPARE_A();
135 | while (state < 9) {
136 | target += ticks_per_bit;
137 | bit = byte & 1;
138 | byte >>= 1;
139 | state++;
140 | if (bit != tx_bit) {
141 | if (bit) {
142 | CONFIG_MATCH_SET();
143 | } else {
144 | CONFIG_MATCH_CLEAR();
145 | }
146 | SET_COMPARE_A(target);
147 | tx_bit = bit;
148 | tx_byte = byte;
149 | tx_state = state;
150 | // TODO: how to detect timing_error?
151 | return;
152 | }
153 | }
154 | if (state == 9) {
155 | tx_state = 10;
156 | CONFIG_MATCH_SET();
157 | SET_COMPARE_A(target + ticks_per_bit);
158 | return;
159 | }
160 | head = tx_buffer_head;
161 | tail = tx_buffer_tail;
162 | if (head == tail) {
163 | tx_state = 0;
164 | CONFIG_MATCH_NORMAL();
165 | DISABLE_INT_COMPARE_A();
166 | } else {
167 | tx_state = 1;
168 | if (++tail >= TX_BUFFER_SIZE) tail = 0;
169 | tx_buffer_tail = tail;
170 | tx_byte = tx_buffer[tail];
171 | tx_bit = 0;
172 | CONFIG_MATCH_CLEAR();
173 | SET_COMPARE_A(target + ticks_per_bit);
174 | // TODO: how to detect timing_error?
175 | }
176 | }
177 |
178 | void AltSoftSerial::flushOutput(void)
179 | {
180 | while (tx_state) /* wait */ ;
181 | }
182 |
183 |
184 | /****************************************/
185 | /** Reception **/
186 | /****************************************/
187 |
188 |
189 | #if 1
190 | ISR(CAPTURE_INTERRUPT)
191 | {
192 | uint8_t state, bit, head;
193 | uint16_t capture, target;
194 | int16_t offset;
195 |
196 | //PORTD |= 1;
197 | capture = GET_INPUT_CAPTURE();
198 | bit = rx_bit;
199 | if (bit) {
200 | CONFIG_CAPTURE_FALLING_EDGE();
201 | rx_bit = 0;
202 | } else {
203 | CONFIG_CAPTURE_RISING_EDGE();
204 | rx_bit = 0x80;
205 | }
206 | state = rx_state;
207 | if (state == 0) {
208 | if (!bit) {
209 | SET_COMPARE_B(capture + rx_stop_ticks);
210 | ENABLE_INT_COMPARE_B();
211 | rx_target = capture + ticks_per_bit + ticks_per_bit/2;
212 | rx_state = 1;
213 | }
214 | } else {
215 | target = rx_target;
216 | while (1) {
217 | offset = capture - target;
218 | if (offset < 0) break;
219 | //PORTD |= 1;
220 | rx_byte = (rx_byte >> 1) | rx_bit;
221 | target += ticks_per_bit;
222 | //PORTD &= ~1;
223 | state++;
224 | if (state >= 9) {
225 | DISABLE_INT_COMPARE_B();
226 | head = rx_buffer_head + 1;
227 | if (head >= RX_BUFFER_SIZE) head = 0;
228 | if (head != rx_buffer_tail) {
229 | rx_buffer[head] = rx_byte;
230 | rx_buffer_head = head;
231 | }
232 | CONFIG_CAPTURE_FALLING_EDGE();
233 | rx_bit = 0;
234 | rx_state = 0;
235 | return;
236 | }
237 | }
238 | rx_target = target;
239 | rx_state = state;
240 | }
241 | //if (GET_TIMER_COUNT() - capture > ticks_per_bit) AltSoftSerial::timing_error = true;
242 | //PORTD &= ~1;
243 | }
244 |
245 | ISR(COMPARE_B_INTERRUPT)
246 | {
247 | uint8_t head, state, bit;
248 |
249 | //PORTD |= 1;
250 | DISABLE_INT_COMPARE_B();
251 | CONFIG_CAPTURE_FALLING_EDGE();
252 | state = rx_state;
253 | bit = rx_bit ^ 0x80;
254 | while (state < 9) {
255 | rx_byte = (rx_byte >> 1) | bit;
256 | state++;
257 | }
258 | head = rx_buffer_head + 1;
259 | if (head >= RX_BUFFER_SIZE) head = 0;
260 | if (head != rx_buffer_tail) {
261 | rx_buffer[head] = rx_byte;
262 | rx_buffer_head = head;
263 | }
264 | rx_state = 0;
265 | CONFIG_CAPTURE_FALLING_EDGE();
266 | rx_bit = 0;
267 | //PORTD &= ~1;
268 | }
269 | #endif
270 |
271 |
272 |
273 | #if 0
274 |
275 | // Original receive code... this doesn't work at 57600.
276 | // Leaving all the analysis until the stop bit causes
277 | // us to sometimes miss the falling edge of the next
278 | // start bit.
279 |
280 | ISR(CAPTURE_INTERRUPT)
281 | {
282 | uint8_t count;
283 | uint16_t capture, current;
284 |
285 | PORTD |= 1;
286 | capture = GET_INPUT_CAPTURE();
287 | count = rx_count;
288 | if (count & 1) {
289 | CONFIG_CAPTURE_FALLING_EDGE();
290 | } else {
291 | CONFIG_CAPTURE_RISING_EDGE();
292 | }
293 | if (count == 0) {
294 | SET_COMPARE_B(capture + rx_stop_ticks);
295 | ENABLE_INT_COMPARE_B();
296 | rx_event[0] = capture;
297 | } else if (count < MAX_RX_EVENTS) {
298 | rx_event[count] = capture;
299 | }
300 | rx_count = count + 1;
301 | if (GET_TIMER_COUNT() - capture > ticks_per_bit) {
302 | AltSoftSerial::timing_error = true;
303 | }
304 | PORTD &= ~1;
305 | }
306 |
307 | static inline uint8_t analyze(uint8_t count)
308 | {
309 | const uint16_t *p = rx_event;
310 | uint8_t out=0xFF, mask=0x01, state=0;
311 | uint16_t begin, tmp, target, now=0;
312 |
313 | if (count > MAX_RX_EVENTS) count = MAX_RX_EVENTS;
314 | begin = *p++;
315 | target = ticks_per_bit + ticks_per_bit / 2;
316 | while (--count > 0) {
317 | tmp = *p++;
318 | now += tmp - begin;
319 | begin = tmp;
320 | while (now >= target) {
321 | if (state == 0) out &= ~mask;
322 | mask <<= 1;
323 | target += ticks_per_bit;
324 | }
325 | state ^= 1;
326 | }
327 | return out;
328 | }
329 |
330 | ISR(COMPARE_B_INTERRUPT)
331 | {
332 | uint8_t head;
333 |
334 | PORTD |= 1;
335 | DISABLE_INT_COMPARE_B();
336 | CONFIG_CAPTURE_FALLING_EDGE();
337 | head = rx_buffer_head + 1;
338 | if (head >= RX_BUFFER_SIZE) head = 0;
339 | if (head != rx_buffer_tail) {
340 | rx_buffer[head] = analyze(rx_count);
341 | rx_buffer_head = head;
342 | }
343 | rx_count = 0;
344 | PORTD &= ~1;
345 | }
346 | #endif
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 | int AltSoftSerial::read(void)
355 | {
356 | uint8_t head, tail, out;
357 |
358 | head = rx_buffer_head;
359 | tail = rx_buffer_tail;
360 | if (head == tail) return -1;
361 | if (++tail >= RX_BUFFER_SIZE) tail = 0;
362 | out = rx_buffer[tail];
363 | rx_buffer_tail = tail;
364 | return out;
365 | }
366 |
367 | int AltSoftSerial::peek(void)
368 | {
369 | uint8_t head, tail;
370 |
371 | head = rx_buffer_head;
372 | tail = rx_buffer_tail;
373 | if (head == tail) return -1;
374 | return rx_buffer[tail];
375 | }
376 |
377 | int AltSoftSerial::available(void)
378 | {
379 | uint8_t head, tail;
380 |
381 | head = rx_buffer_head;
382 | tail = rx_buffer_tail;
383 | if (head >= tail) return head - tail;
384 | return RX_BUFFER_SIZE + head - tail;
385 | }
386 |
387 | void AltSoftSerial::flushInput(void)
388 | {
389 | rx_buffer_head = rx_buffer_tail;
390 | }
391 |
392 |
393 |
394 |
--------------------------------------------------------------------------------
/arduino/libraries/AltSoftSerial/AltSoftSerial.h:
--------------------------------------------------------------------------------
1 | /* An Alternative Software Serial Library
2 | * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
3 | * Copyright (c) 2012 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | * THE SOFTWARE.
22 | */
23 |
24 | #ifndef AltSoftSerial_h
25 | #define AltSoftSerial_h
26 |
27 | #include
28 |
29 | #if ARDUINO >= 100
30 | #include "Arduino.h"
31 | #else
32 | #include "WProgram.h"
33 | #include "pins_arduino.h"
34 | #endif
35 |
36 | class AltSoftSerial : public Stream
37 | {
38 | public:
39 | AltSoftSerial() { }
40 | ~AltSoftSerial() { end(); }
41 | static void begin(uint32_t baud) { init((F_CPU + baud / 2) / baud); }
42 | static void end();
43 | int peek();
44 | int read();
45 | int available();
46 | #if ARDUINO >= 100
47 | size_t write(uint8_t byte) { writeByte(byte); return 1; }
48 | void flush() { flushOutput(); }
49 | #else
50 | void write(uint8_t byte) { writeByte(byte); }
51 | void flush() { flushInput(); }
52 | #endif
53 | using Print::write;
54 | static void flushInput();
55 | static void flushOutput();
56 | // for drop-in compatibility with NewSoftSerial, rxPin & txPin ignored
57 | AltSoftSerial(uint8_t rxPin, uint8_t txPin, bool inverse = false) { }
58 | bool listen() { return false; }
59 | bool isListening() { return true; }
60 | bool overflow() { bool r = timing_error; timing_error = false; return r; }
61 | static int library_version() { return 1; }
62 | static void enable_timer0(bool enable) { }
63 | static bool timing_error;
64 | private:
65 | static void init(uint32_t cycles_per_bit);
66 | static void writeByte(uint8_t byte);
67 | };
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/arduino/libraries/AltSoftSerial/config/known_boards.h:
--------------------------------------------------------------------------------
1 |
2 |
3 | // Teensy 2.0
4 | //
5 | #if defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)
6 |
7 | //#define ALTSS_USE_TIMER1
8 | //#define INPUT_CAPTURE_PIN 22 // receive
9 | //#define OUTPUT_COMPARE_A_PIN 14 // transmit
10 | //#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
11 | //#define OUTPUT_COMPARE_C_PIN 4 // unusable PWM
12 |
13 | #define ALTSS_USE_TIMER3
14 | #define INPUT_CAPTURE_PIN 10 // receive
15 | #define OUTPUT_COMPARE_A_PIN 9 // transmit
16 |
17 |
18 |
19 | // Teensy++ 2.0
20 | //
21 | #elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY)
22 |
23 | #define ALTSS_USE_TIMER1
24 | #define INPUT_CAPTURE_PIN 4 // receive
25 | #define OUTPUT_COMPARE_A_PIN 25 // transmit
26 | #define OUTPUT_COMPARE_B_PIN 26 // unusable PWM
27 | #define OUTPUT_COMPARE_C_PIN 27 // unusable PWM
28 |
29 | //#define ALTSS_USE_TIMER3
30 | //#define INPUT_CAPTURE_PIN 17 // receive
31 | //#define OUTPUT_COMPARE_A_PIN 16 // transmit
32 | //#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM
33 | //#define OUTPUT_COMPARE_C_PIN 14 // unusable PWM
34 |
35 |
36 | // Leonardo
37 | //
38 | #elif defined(__AVR_ATmega32U4__)
39 |
40 | #define ALTSS_USE_TIMER3
41 | #define INPUT_CAPTURE_PIN 10 // receive
42 | #define OUTPUT_COMPARE_A_PIN 9 // transmit
43 |
44 |
45 |
46 | // Wiring-S
47 | //
48 | #elif defined(__AVR_ATmega644P__) && defined(WIRING)
49 |
50 | #define ALTSS_USE_TIMER1
51 | #define INPUT_CAPTURE_PIN 6 // receive
52 | #define OUTPUT_COMPARE_A_PIN 5 // transmit
53 | #define OUTPUT_COMPARE_B_PIN 4 // unusable PWM
54 |
55 |
56 |
57 | // Arduino Uno, Duemilanove, LilyPad, etc
58 | //
59 | #elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega328P__)
60 |
61 | #define ALTSS_USE_TIMER1
62 | #define INPUT_CAPTURE_PIN 8 // receive
63 | #define OUTPUT_COMPARE_A_PIN 9 // transmit
64 | #define OUTPUT_COMPARE_B_PIN 10 // unusable PWM
65 |
66 |
67 |
68 | // Arduino Mega
69 | //
70 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
71 |
72 | //#define ALTSS_USE_TIMER4
73 | //#define INPUT_CAPTURE_PIN 49 // receive
74 | //#define OUTPUT_COMPARE_A_PIN 6 // transmit
75 | //#define OUTPUT_COMPARE_B_PIN 7 // unusable PWM
76 | //#define OUTPUT_COMPARE_C_PIN 8 // unusable PWM
77 |
78 | #define ALTSS_USE_TIMER5
79 | #define INPUT_CAPTURE_PIN 48 // receive
80 | #define OUTPUT_COMPARE_A_PIN 46 // transmit
81 | #define OUTPUT_COMPARE_B_PIN 45 // unusable PWM
82 | #define OUTPUT_COMPARE_C_PIN 44 // unusable PWM
83 |
84 |
85 |
86 | // Sanguino
87 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
88 |
89 | #define ALTSS_USE_TIMER1
90 | #define INPUT_CAPTURE_PIN 14 // receive
91 | #define OUTPUT_COMPARE_A_PIN 13 // transmit
92 | #define OUTPUT_COMPARE_B_PIN 12 // unusable PWM
93 |
94 |
95 | // Unknown board
96 | #else
97 | #error "Please define your board timer and pins"
98 | #endif
99 |
100 |
--------------------------------------------------------------------------------
/arduino/libraries/AltSoftSerial/config/known_timers.h:
--------------------------------------------------------------------------------
1 |
2 | #if defined(ALTSS_USE_TIMER1)
3 | #define CONFIG_TIMER_NOPRESCALE() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1<
2 |
3 | // AltSoftSerial always uses these pins:
4 | //
5 | // Board Transmit Receive PWM Unusable
6 | // ----- -------- ------- ------------
7 | // Teensy 2.0 9 10 (none)
8 | // Teensy++ 2.0 25 4 26, 27
9 | // Arduino Uno 9 8 10
10 | // Arduino Mega 46 48 44, 45
11 | // Wiring-S 5 6 4
12 | // Sanguino 13 14 12
13 |
14 | AltSoftSerial altSerial;
15 |
16 | void setup() {
17 | Serial.begin(9600);
18 | Serial.println("AltSoftSerial Test Begin");
19 | altSerial.begin(9600);
20 | altSerial.println("Hello World");
21 | }
22 |
23 | void loop() {
24 | char c;
25 |
26 | if (Serial.available()) {
27 | c = Serial.read();
28 | altSerial.print(c);
29 | }
30 | if (altSerial.available()) {
31 | c = altSerial.read();
32 | Serial.print(c);
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/arduino/libraries/AltSoftSerial/keywords.txt:
--------------------------------------------------------------------------------
1 | AltSoftSerial KEYWORD1
2 | active KEYWORD2
3 | overflow KEYWORD2
4 | library_version KEYWORD2
5 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/ble_hci.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "typedef.h"
3 | #include "ble_hci.h"
4 |
5 | #if defined(__AVR_ATmega328P__)
6 | #include
7 | AltSoftSerial *TX;
8 | uint8 ble_hci_init(AltSoftSerial *ser)
9 | {
10 | TX = ser;
11 | }
12 | #else
13 | uint8 ble_hci_init()
14 | {
15 | }
16 | #endif
17 |
18 | bStatus_t GAP_DeviceInit( uint8 taskID, uint8 profileRole, uint8 maxScanResponses, uint8 *pIRK, uint8 *pSRK, uint32 *pSignCounter )
19 | {
20 | uint8 buf[42];
21 | uint8 len = 0;
22 |
23 | buf[len++] = 0x01; // -Type : 0x01 (Command)
24 | buf[len++] = 0x00; // -Opcode : 0xFE00 (GAP_DeviceInit)
25 | buf[len++] = 0xFE;
26 |
27 | buf[len++] = 0x26; // -Data Length
28 | buf[len++] = profileRole; // Profile Role
29 | buf[len++] = maxScanResponses; // MaxScanRsps
30 | memcpy(&buf[len], pIRK, 16); // IRK
31 | len += 16;
32 | memcpy(&buf[len], pSRK, 16); // SRK
33 | len += 16;
34 | memcpy(&buf[len], pSignCounter, 4); // SignCounter
35 | len += 4;
36 |
37 | #if defined(__AVR_ATmega328P__)
38 | (*TX).write(buf, len);
39 | #else
40 | Serial1.write(buf, len);
41 | #endif
42 |
43 | return 1;
44 | }
45 |
46 | bStatus_t GAP_DeviceDiscoveryRequest( gapDevDiscReq_t *pParams )
47 | {
48 | uint8 buf[20];
49 | uint8 len = 0;
50 |
51 | buf[len++] = 0x01; // -Type : 0x01 (Command)
52 | buf[len++] = 0x04; // -Opcode : 0xFE04 (GAP_DeviceDiscoveryRequest)
53 | buf[len++] = 0xFE;
54 |
55 | buf[len++] = 0x03; // -Data Length
56 | buf[len++] = pParams->mode; // Mode
57 | buf[len++] = pParams->activeScan; // ActiveScan
58 | buf[len++] = pParams->whiteList; // WhiteList
59 |
60 | // hci_tl_write(buf, len);
61 | // hci_tl_wait_for_response();
62 |
63 | #if defined(__AVR_ATmega328P__)
64 | (*TX).write(buf, len);
65 | #else
66 | Serial1.write(buf, len);
67 | #endif
68 |
69 | return 1;
70 | }
71 |
72 | bStatus_t GAP_EstablishLinkReq( gapEstLinkReq_t *pParams )
73 | {
74 | uint8 buf[20];
75 | uint8 len = 0;
76 |
77 | buf[len++] = 0x01;
78 | memcpy(&buf[len], "\x09\xFE", 2);
79 | len += 2;
80 |
81 | buf[len++] = 0x03 + B_ADDR_LEN;
82 |
83 | buf[len++] = pParams->highDutyCycle;
84 | buf[len++] = pParams->whiteList;
85 | buf[len++] = pParams->addrTypePeer;
86 | memcpy(&buf[len], pParams->peerAddr, B_ADDR_LEN);
87 | len+=B_ADDR_LEN;
88 |
89 | #if defined(__AVR_ATmega328P__)
90 | (*TX).write(buf, len);
91 | #else
92 | Serial1.write(buf, len);
93 | #endif
94 |
95 | return 1;
96 | }
97 |
98 | bStatus_t GATT_WriteCharValue( uint16 connHandle, attWriteReq_t *pReq, uint8 taskId )
99 | {
100 | uint8 buf[20];
101 | uint8 len = 0;
102 |
103 | buf[len++] = 0x01;
104 | memcpy(&buf[len], "\x92\xFD", 2);
105 | len += 2;
106 |
107 | buf[len++] = 0x04 + pReq->len;
108 |
109 | memcpy(&buf[len], &connHandle, 2);
110 | len += 2;
111 | memcpy(&buf[len], &pReq->handle, 2);
112 | len += 2;
113 | memcpy(&buf[len], pReq->value, pReq->len);
114 | len += pReq->len;
115 |
116 | #if defined(__AVR_ATmega328P__)
117 | (*TX).write(buf, len);
118 | #else
119 | Serial1.write(buf, len);
120 | #endif
121 |
122 | return 1;
123 | }
124 |
125 | bStatus_t GATT_WriteNoRsp( uint16 connHandle, attWriteReq_t *pReq, uint8 taskId )
126 | {
127 | uint8 buf[20];
128 | uint8 len = 0;
129 |
130 | buf[len++] = 0x01;
131 | memcpy(&buf[len], "\xB6\xFD", 2);
132 | len += 2;
133 |
134 | buf[len++] = 0x04 + pReq->len;
135 |
136 | memcpy(&buf[len], &connHandle, 2);
137 | len += 2;
138 | memcpy(&buf[len], &pReq->handle, 2);
139 | len += 2;
140 | memcpy(&buf[len], pReq->value, pReq->len);
141 | len += pReq->len;
142 |
143 | #if defined(__AVR_ATmega328P__)
144 | (*TX).write(buf, len);
145 | #else
146 | Serial1.write(buf, len);
147 | #endif
148 |
149 | return 1;
150 | }
151 |
152 | /*
153 | bStatus_t GAP_TerminateLinkReq( uint8 taskID, uint16 connectionHandle )
154 | {
155 | }
156 | */
157 |
158 |
159 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/ble_hci.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef BLE_HCI_H
3 | #define BLE_HCI_H
4 |
5 | #include "typedef.h"
6 |
7 | #if defined(__AVR_ATmega328P__)
8 | #include
9 | uint8 ble_hci_init(AltSoftSerial *ser);
10 | #else
11 | uint8 ble_hci_init();
12 | #endif
13 |
14 | bStatus_t GAP_DeviceInit( uint8 taskID, uint8 profileRole, uint8 maxScanResponses, uint8 *pIRK, uint8 *pSRK, uint32 *pSignCounter );
15 | bStatus_t GAP_DeviceDiscoveryRequest( gapDevDiscReq_t *pParams );
16 | bStatus_t GAP_EstablishLinkReq( gapEstLinkReq_t *pParams );
17 | bStatus_t GATT_WriteCharValue( uint16 connHandle, attWriteReq_t *pReq, uint8 taskId );
18 | bStatus_t GATT_WriteNoRsp( uint16 connHandle, attWriteReq_t *pReq, uint8 taskId );
19 |
20 | #endif /* BLE_HCI_H */
21 |
22 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/central.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "typedef.h"
3 | #include "ble_hci.h"
4 |
5 | static uint8 gapCentralRoleTaskId = 0;
6 |
7 | static uint8 gapCentralRoleIRK[KEYLEN] = {0};
8 | static uint8 gapCentralRoleSRK[KEYLEN] = {0};
9 | static uint32 gapCentralRoleSignCounter = 1;
10 | static uint8 gapCentralRoleBdAddr[B_ADDR_LEN];
11 | static uint8 gapCentralRoleMaxScanRes = 5;
12 |
13 | bStatus_t GAPCentralRole_StartDevice()
14 | {
15 | return GAP_DeviceInit( gapCentralRoleTaskId, GAP_PROFILE_CENTRAL,
16 | gapCentralRoleMaxScanRes, gapCentralRoleIRK,
17 | gapCentralRoleSRK, &gapCentralRoleSignCounter );
18 | }
19 |
20 | bStatus_t GAPCentralRole_EstablishLink( uint8 highDutyCycle, uint8 whiteList,
21 | uint8 addrTypePeer, uint8 *peerAddr )
22 | {
23 | gapEstLinkReq_t params;
24 |
25 | params.taskID = gapCentralRoleTaskId;
26 | params.highDutyCycle = highDutyCycle;
27 | params.whiteList = whiteList;
28 | params.addrTypePeer = addrTypePeer;
29 | memcpy( params.peerAddr, peerAddr, B_ADDR_LEN );
30 |
31 | return GAP_EstablishLinkReq( ¶ms );
32 | }
33 |
34 | bStatus_t GAPCentralRole_StartDiscovery( uint8 mode, uint8 activeScan, uint8 whiteList )
35 | {
36 | gapDevDiscReq_t params;
37 |
38 | params.taskID = gapCentralRoleTaskId;
39 | params.mode = mode;
40 | params.activeScan = activeScan;
41 | params.whiteList = whiteList;
42 |
43 | return GAP_DeviceDiscoveryRequest( ¶ms );
44 | }
45 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/central.h:
--------------------------------------------------------------------------------
1 |
2 | #include "typedef.h"
3 |
4 | bStatus_t GAPCentralRole_StartDevice();
5 | bStatus_t GAPCentralRole_EstablishLink( uint8 highDutyCycle, uint8 whiteList,
6 | uint8 addrTypePeer, uint8 *peerAddr );
7 | bStatus_t GAPCentralRole_StartDiscovery( uint8 mode, uint8 activeScan, uint8 whiteList );
8 |
9 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/examples/BLE_HCI_BLEShieldCentral/BLEShield_Central.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 |
5 | // Discovey mode (limited, general, all)
6 | #define DEFAULT_DISCOVERY_MODE DEVDISC_MODE_ALL
7 |
8 | // TRUE to use active scan
9 | #define DEFAULT_DISCOVERY_ACTIVE_SCAN TRUE
10 |
11 | // TRUE to use white list during discovery
12 | #define DEFAULT_DISCOVERY_WHITE_LIST FALSE
13 |
14 | // TRUE to use high scan duty cycle when creating link
15 | #define DEFAULT_LINK_HIGH_DUTY_CYCLE FALSE
16 |
17 | // TRUE to use white list when creating link
18 | #define DEFAULT_LINK_WHITE_LIST FALSE
19 |
20 | void bleshield_central_init()
21 | {
22 | GAPCentralRole_StartDevice();
23 | }
24 |
25 | void bleshield_central_start_discovery()
26 | {
27 | GAPCentralRole_StartDiscovery( DEFAULT_DISCOVERY_MODE,
28 | DEFAULT_DISCOVERY_ACTIVE_SCAN,
29 | DEFAULT_DISCOVERY_WHITE_LIST );
30 | }
31 |
32 | void bleshield_central_connect(uint8 *address)
33 | {
34 | GAPCentralRole_EstablishLink( DEFAULT_LINK_HIGH_DUTY_CYCLE,
35 | DEFAULT_LINK_WHITE_LIST,
36 | 1, address );
37 | }
38 |
39 | void bleshield_central_write_bytes(uint8 *buf, uint8 len)
40 | {
41 | attWriteReq_t writeReq;
42 |
43 | writeReq.handle = 0x000b;
44 | writeReq.len = len;
45 | memcpy(writeReq.value, buf, len);
46 |
47 | GATT_WriteNoRsp( 0x0000, &writeReq, 0 );
48 | }
49 |
50 | void bleshield_central_enable_notification()
51 | {
52 | attWriteReq_t writeReq;
53 |
54 | writeReq.handle = 0x000e;
55 | writeReq.len = 2;
56 | writeReq.value[0] = 0x01;
57 | writeReq.value[1] = 0x00;
58 |
59 | GATT_WriteCharValue( 0x0000, &writeReq, 0 );
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/examples/BLE_HCI_BLEShieldCentral/BLEShield_Central.h:
--------------------------------------------------------------------------------
1 |
2 | void bleshield_central_init();
3 | void bleshield_central_start_discovery();
4 | void bleshield_central_connect(uint8 *);
5 | void bleshield_central_enable_notification();
6 | void bleshield_central_write_bytes(uint8 *buf, uint8 len);
7 |
8 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/examples/BLE_HCI_BLEShieldCentral/BLE_HCI_BLEShieldCentral.ino:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include "typedef.h"
4 | #include "bleshield_central.h"
5 | #include "ble_hci.h"
6 |
7 | #if defined(__AVR_ATmega328P__) // Arduino UNO?
8 | #include
9 | AltSoftSerial Serial1;
10 | // Refer to this: http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
11 | #endif
12 |
13 | uint8_t found_address[6];
14 |
15 | void p(char *fmt, ... )
16 | {
17 | char tmp[128]; // resulting string limited to 128 chars
18 | va_list args;
19 | va_start (args, fmt );
20 | vsnprintf(tmp, 128, fmt, args);
21 | va_end (args);
22 | Serial.print(tmp);
23 | }
24 |
25 | void ble_event_poll()
26 | {
27 | }
28 |
29 | byte ble_event_available()
30 | {
31 | return Serial1.available();
32 | }
33 |
34 | byte ble_event_process()
35 | {
36 | uint8_t type, event_code, data_len, status1;
37 | uint16_t event;
38 | uint8_t buf[64];
39 |
40 | type = Serial1.read();
41 | delay(35);
42 | event_code = Serial1.read();
43 | data_len = Serial1.read();
44 |
45 | p("-----------------------------\r\n");
46 | p("-Type : 0x%02X\r\n", type);
47 | p("-EventCode : 0x%02X\r\n", event_code);
48 | p("-Data Length : 0x%02X\r\n", data_len);
49 |
50 | for (int i = 0; i < data_len; i++)
51 | buf[i] = Serial1.read();
52 |
53 | event = BUILD_UINT16(buf[0], buf[1]);
54 | status1 = buf[2];
55 |
56 | p(" Event : 0x%04X\r\n", event);
57 | p(" Status : 0x%02X\r\n", status1);
58 |
59 | switch (event)
60 | {
61 | case 0x0601: // GAP_DeviceDiscoveryDone
62 | {
63 | p("GAP_DeviceDiscoveryDone\r\n");
64 |
65 | uint8_t num_devs = buf[3];
66 | p(" NumDevs : 0x%02X\r\n", num_devs);
67 |
68 | if (num_devs > 0)
69 | memcpy(found_address, &buf[6], 6); // store 1 device address only in this demo
70 | }
71 | break;
72 |
73 | case 0x051B: // ATT_HandleValueNotification
74 | {
75 | p("ATT_HandleValueNotification\r\n");
76 |
77 | uint8_t data[21] = {0};
78 | uint8_t len = data_len - 8;
79 |
80 | if (len > 20)
81 | len = 20;
82 |
83 | memcpy(data, &buf[8], len);
84 |
85 | p(" -------------> Received from Biscuit peripheral: %s\r\n", data);
86 | }
87 | break;
88 |
89 | default:
90 | p(" -> Not handled yet.\r\n");
91 | }
92 | }
93 |
94 | void setup()
95 | {
96 | #if defined(__AVR_ATmega328P__)
97 | Serial1.begin(57600);
98 | Serial.begin(57600);
99 |
100 | ble_hci_init(&Serial1);
101 | #else
102 | Serial1.begin(57600);
103 | Serial.begin(115200);
104 | while (!Serial);
105 |
106 | ble_hci_init();
107 | #endif
108 |
109 | bleshield_central_init();
110 | }
111 |
112 | void loop()
113 | {
114 | while (ble_event_available())
115 | ble_event_process();
116 |
117 | while (Serial.available())
118 | {
119 | byte cmd = Serial.read();
120 | switch(cmd)
121 | {
122 | case 'D':
123 | case 'd':
124 | p(" -> Start discovery...\r\n");
125 | bleshield_central_start_discovery();
126 | break;
127 |
128 | case 'E':
129 | case 'e':
130 | p(" -> Connecting to Biscuit peripheral...\r\n");
131 | bleshield_central_connect(found_address);
132 | break;
133 |
134 | case 'N':
135 | case 'n':
136 | p(" -> Enable notification to receive data...\r\n");
137 | bleshield_central_enable_notification();
138 | break;
139 |
140 | case '1':
141 | {
142 | byte buf[] = {0x90, 0x00, 0x01};
143 | p(" -> Send 'On' to the BLE Shield\r\n");
144 | bleshield_central_write_bytes(buf, 3);
145 | }
146 | break;
147 |
148 | case '2':
149 | {
150 | byte buf[] = {0x90, 0x00, 0x00};
151 | p(" -> Send 'Off' to the BLE Shield\r\n");
152 | bleshield_central_write_bytes(buf, 3);
153 | }
154 | break;
155 |
156 | default:
157 | p(" -> Invalid command.\r\n");
158 | }
159 | }
160 | }
161 |
162 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/examples/BLE_HCI_BiscuitCentral/BLE_HCI_BiscuitCentral.ino:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include "typedef.h"
4 | #include "biscuit_central.h"
5 | #include "ble_hci.h"
6 |
7 | #if defined(__AVR_ATmega328P__) // Arduino UNO?
8 | #include
9 | AltSoftSerial Serial1;
10 | // Refer to this: http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html
11 | #endif
12 |
13 | uint8_t found_address[6];
14 |
15 | void p(char *fmt, ... )
16 | {
17 | char tmp[128]; // resulting string limited to 128 chars
18 | va_list args;
19 | va_start (args, fmt );
20 | vsnprintf(tmp, 128, fmt, args);
21 | va_end (args);
22 | Serial.print(tmp);
23 | }
24 |
25 | void ble_event_poll()
26 | {
27 | }
28 |
29 | byte ble_event_available()
30 | {
31 | return Serial1.available();
32 | }
33 |
34 | byte ble_event_process()
35 | {
36 | uint8_t type, event_code, data_len, status1;
37 | uint16_t event;
38 | uint8_t buf[64];
39 |
40 | type = Serial1.read();
41 | delay(35);
42 | event_code = Serial1.read();
43 | data_len = Serial1.read();
44 |
45 | p("-----------------------------\r\n");
46 | p("-Type : 0x%02X\r\n", type);
47 | p("-EventCode : 0x%02X\r\n", event_code);
48 | p("-Data Length : 0x%02X\r\n", data_len);
49 |
50 | for (int i = 0; i < data_len; i++)
51 | buf[i] = Serial1.read();
52 |
53 | event = BUILD_UINT16(buf[0], buf[1]);
54 | status1 = buf[2];
55 |
56 | p(" Event : 0x%04X\r\n", event);
57 | p(" Status : 0x%02X\r\n", status1);
58 |
59 | switch (event)
60 | {
61 | case 0x060D: // GAP_DeviceInformation
62 | {
63 | p("GAP_DeviceInformation\r\n");
64 |
65 | int8_t rssi = buf[11];
66 | p("RSSI: %d\r\n", rssi);
67 |
68 | p("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\r\n", buf[10], buf[9], buf[8], buf[7], buf[6], buf[5]);
69 | }
70 | break;
71 |
72 | case 0x0601: // GAP_DeviceDiscoveryDone
73 | {
74 | p("GAP_DeviceDiscoveryDone\r\n");
75 |
76 | uint8_t num_devs = buf[3];
77 | p(" NumDevs : 0x%02X\r\n", num_devs);
78 |
79 | if (num_devs > 0)
80 | memcpy(found_address, &buf[6], 6); // store 1 device address only in this demo
81 | }
82 | break;
83 |
84 | case 0x051B: // ATT_HandleValueNotification
85 | {
86 | p("ATT_HandleValueNotification\r\n");
87 |
88 | uint8_t data[21] = {0};
89 | uint8_t len = data_len - 8;
90 |
91 | if (len > 20)
92 | len = 20;
93 |
94 | memcpy(data, &buf[8], len);
95 |
96 | p(" -------------> Received from Biscuit peripheral: %s\r\n", data);
97 | }
98 | break;
99 |
100 | default:
101 | p(" -> Not handled yet.\r\n");
102 | }
103 | }
104 |
105 | void setup()
106 | {
107 | #if defined(__AVR_ATmega328P__)
108 | Serial1.begin(57600);
109 | Serial.begin(57600);
110 |
111 | ble_hci_init(&Serial1);
112 | #else
113 | Serial1.begin(57600);
114 | Serial.begin(115200);
115 | while (!Serial);
116 |
117 | ble_hci_init();
118 | #endif
119 |
120 | biscuit_central_init();
121 | }
122 |
123 | void loop()
124 | {
125 | while (ble_event_available())
126 | ble_event_process();
127 |
128 | while (Serial.available())
129 | {
130 | byte cmd = Serial.read();
131 | switch(cmd)
132 | {
133 | case 'D':
134 | case 'd':
135 | p(" -> Start discovery...\r\n");
136 | biscuit_central_start_discovery();
137 | break;
138 |
139 | case 'E':
140 | case 'e':
141 | p(" -> Connecting to Biscuit peripheral...\r\n");
142 | biscuit_central_connect(found_address);
143 | break;
144 |
145 | case 'N':
146 | case 'n':
147 | p(" -> Enable notification to receive data...\r\n");
148 | biscuit_central_enable_notification();
149 | break;
150 |
151 | case '1':
152 | p(" -> Send \"Hello World!\" to the Biscuit peripheral...\r\n");
153 | biscuit_central_write_bytes((uint8 *)"Hello World!\r\n", 14);
154 | break;
155 |
156 | case '2':
157 | p(" -> Send \"I love BLE!\" to the Biscuit peripheral...\r\n");
158 | biscuit_central_write_bytes((uint8 *)"I love BLE!\r\n", 13);
159 | break;
160 |
161 | default:
162 | p(" -> Invalid command.\r\n");
163 | }
164 | }
165 | }
166 |
167 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/examples/BLE_HCI_BiscuitCentral/biscuit_central.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 |
5 | // Discovey mode (limited, general, all)
6 | #define DEFAULT_DISCOVERY_MODE DEVDISC_MODE_ALL
7 |
8 | // TRUE to use active scan
9 | #define DEFAULT_DISCOVERY_ACTIVE_SCAN TRUE
10 |
11 | // TRUE to use white list during discovery
12 | #define DEFAULT_DISCOVERY_WHITE_LIST FALSE
13 |
14 | // TRUE to use high scan duty cycle when creating link
15 | #define DEFAULT_LINK_HIGH_DUTY_CYCLE FALSE
16 |
17 | // TRUE to use white list when creating link
18 | #define DEFAULT_LINK_WHITE_LIST FALSE
19 |
20 | void biscuit_central_init()
21 | {
22 | GAPCentralRole_StartDevice();
23 | }
24 |
25 | void biscuit_central_start_discovery()
26 | {
27 | GAPCentralRole_StartDiscovery( DEFAULT_DISCOVERY_MODE,
28 | DEFAULT_DISCOVERY_ACTIVE_SCAN,
29 | DEFAULT_DISCOVERY_WHITE_LIST );
30 | }
31 |
32 | void biscuit_central_connect(uint8 *address)
33 | {
34 | GAPCentralRole_EstablishLink( DEFAULT_LINK_HIGH_DUTY_CYCLE,
35 | DEFAULT_LINK_WHITE_LIST,
36 | 0, address );
37 | }
38 |
39 | void biscuit_central_write_bytes(uint8 *buf, uint8 len)
40 | {
41 | attWriteReq_t writeReq;
42 |
43 | writeReq.handle = 0x0016;
44 | writeReq.len = len;
45 | memcpy(writeReq.value, buf, len);
46 |
47 | GATT_WriteCharValue( 0x0000, &writeReq, 0 );
48 | }
49 |
50 | void biscuit_central_enable_notification()
51 | {
52 | attWriteReq_t writeReq;
53 |
54 | writeReq.handle = 0x0013;
55 | writeReq.len = 2;
56 | writeReq.value[0] = 0x01;
57 | writeReq.value[1] = 0x00;
58 |
59 | GATT_WriteCharValue( 0x0000, &writeReq, 0 );
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/examples/BLE_HCI_BiscuitCentral/biscuit_central.h:
--------------------------------------------------------------------------------
1 |
2 | void biscuit_central_init();
3 | void biscuit_central_start_discovery();
4 | void biscuit_central_connect(uint8 *);
5 | void biscuit_central_enable_notification();
6 | void biscuit_central_write_bytes(uint8 *buf, uint8 len);
7 |
8 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/examples/BiscuitPeripheral/BiscuitPeripheral.ino:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | This example reads data from or sends data to BLE Mini
4 | (running the Biscuit firmware) using software serial.
5 |
6 | */
7 |
8 | #include
9 |
10 | SoftwareSerial mySerial(10, 11); // RX, TX
11 |
12 | void setup()
13 | {
14 | // Open serial communications and wait for port to open:
15 | Serial.begin(57600);
16 | while (!Serial) {
17 | ; // wait for serial port to connect. Needed for Leonardo only
18 | }
19 |
20 | // set the data rate for the SoftwareSerial port
21 | mySerial.begin(57600);
22 | }
23 |
24 | void loop() // run over and over
25 | {
26 | // Forward data between hardware and software serial ports
27 | if (mySerial.available())
28 | Serial.write(mySerial.read());
29 | if (Serial.available())
30 | mySerial.write(Serial.read());
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/arduino/libraries/BLEHCI/typedef.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef TYPEDEF_H
3 | #define TYPEDEF_H
4 |
5 | #include "Arduino.h"
6 |
7 | /* ------------------------------------------------------------------------------------------------
8 | * Standard Defines
9 | * ------------------------------------------------------------------------------------------------
10 | */
11 | #ifndef TRUE
12 | #define TRUE 1
13 | #endif
14 |
15 | #ifndef FALSE
16 | #define FALSE 0
17 | #endif
18 |
19 | #ifndef NULL
20 | #define NULL 0
21 | #endif
22 |
23 | #define BUILD_UINT32(Byte0, Byte1, Byte2, Byte3) \
24 | ((uint32)((uint32)((Byte0) & 0x00FF) \
25 | + ((uint32)((Byte1) & 0x00FF) << 8) \
26 | + ((uint32)((Byte2) & 0x00FF) << 16) \
27 | + ((uint32)((Byte3) & 0x00FF) << 24)))
28 |
29 | #define BUILD_UINT16(loByte, hiByte) \
30 | ((uint16)(((loByte) & 0x00FF) + (((hiByte) & 0x00FF) << 8)))
31 |
32 | #define HI_UINT16(a) (((a) >> 8) & 0xFF)
33 | #define LO_UINT16(a) ((a) & 0xFF)
34 |
35 | #define BUILD_UINT8(hiByte, loByte) \
36 | ((uint8)(((loByte) & 0x0F) + (((hiByte) & 0x0F) << 4)))
37 |
38 | #define HI_UINT8(a) (((a) >> 4) & 0x0F)
39 | #define LO_UINT8(a) ((a) & 0x0F)
40 |
41 | /** @defgroup GAP_DEVDISC_MODE_DEFINES GAP Device Discovery Modes
42 | * @{
43 | */
44 | #define DEVDISC_MODE_NONDISCOVERABLE 0x00 //!< No discoverable setting
45 | #define DEVDISC_MODE_GENERAL 0x01 //!< General Discoverable devices
46 | #define DEVDISC_MODE_LIMITED 0x02 //!< Limited Discoverable devices
47 | #define DEVDISC_MODE_ALL 0x03 //!< Not filtered
48 | /** @} End GAP_DEVDISC_MODE_DEFINES */
49 |
50 | /** @defgroup GAP_PROFILE_ROLE_DEFINES GAP Profile Roles
51 | * Bit mask values
52 | * @{
53 | */
54 | #define GAP_PROFILE_BROADCASTER 0x01 //!< A device that sends advertising events only.
55 | #define GAP_PROFILE_OBSERVER 0x02 //!< A device that receives advertising events only.
56 | #define GAP_PROFILE_PERIPHERAL 0x04 //!< A device that accepts the establishment of an LE physical link using the connection establishment procedure
57 | #define GAP_PROFILE_CENTRAL 0x08 //!< A device that supports the Central role initiates the establishment of a physical connection
58 | /** @} End GAP_PROFILE_ROLE_DEFINES */
59 |
60 | //! Default key length
61 | #define KEYLEN 16
62 |
63 | #define B_ADDR_LEN 6
64 |
65 | // Minimum supported information payload for the Basic information frame (B-frame)
66 | #define L2CAP_MTU_SIZE 23
67 |
68 | // The Exchanging MTU Size is defined as the maximum size of any packet
69 | // transmitted between a client and a server. A higher layer specification
70 | // defines the default ATT MTU value. The ATT MTU value should be within
71 | // the range 23 to 517 inclusive.
72 | #define ATT_MTU_SIZE L2CAP_MTU_SIZE //!< Minimum ATT MTU size
73 | #define ATT_MAX_MTU_SIZE 517 //!< Maximum ATT MTU size
74 |
75 | // Size of 16-bit Bluetooth UUID
76 | #define ATT_BT_UUID_SIZE 2
77 |
78 | // Size of 128-bit UUID
79 | #define ATT_UUID_SIZE 16
80 |
81 | typedef uint8_t uint8;
82 | typedef uint16_t uint16;
83 | typedef uint32_t uint32;
84 |
85 | typedef uint8 Status_t;
86 | typedef Status_t bStatus_t;
87 |
88 | /**
89 | * Type of device discovery (Scan) to perform.
90 | */
91 | typedef struct
92 | {
93 | uint8 taskID; //!< Requesting App's Task ID, used to return results
94 | uint8 mode; //!< Discovery Mode: @ref GAP_DEVDISC_MODE_DEFINES
95 | uint8 activeScan; //!< TRUE for active scanning
96 | uint8 whiteList; //!< TRUE to only allow advertisements from devices in the white list.
97 | } gapDevDiscReq_t;
98 |
99 | /**
100 | * Establish Link Request parameters
101 | */
102 | typedef struct
103 | {
104 | uint8 taskID; //!< Requesting App/Profile's Task ID
105 | uint8 highDutyCycle; //!< TRUE to high duty cycle scan, FALSE if not.
106 | uint8 whiteList; //!< Determines use of the white list: @ref GAP_WHITELIST_DEFINES
107 | uint8 addrTypePeer; //!< Address type of the advertiser: @ref GAP_ADDR_TYPE_DEFINES
108 | uint8 peerAddr[B_ADDR_LEN]; //!< Advertiser's address
109 | } gapEstLinkReq_t;
110 |
111 | /**
112 | * Attribute Type format (2 or 16 octet UUID).
113 | */
114 | typedef struct
115 | {
116 | uint8 len; //!< Length of UUID
117 | uint8 uuid[ATT_UUID_SIZE]; //!< 16 or 128 bit UUID
118 | } attAttrType_t;
119 |
120 | /**
121 | * Read By Type Request format.
122 | */
123 | typedef struct
124 | {
125 | uint16 startHandle; //!< First requested handle number (must be first field)
126 | uint16 endHandle; //!< Last requested handle number
127 | attAttrType_t type; //!< Requested type (2 or 16 octet UUID)
128 | } attReadByTypeReq_t;
129 |
130 | /**
131 | * Write Request format.
132 | */
133 | typedef struct
134 | {
135 | uint16 handle; //!< Handle of the attribute to be written (must be first field)
136 | uint8 len; //!< Length of value
137 | uint8 value[ATT_MTU_SIZE-3]; //!< Value of the attribute to be written
138 | uint8 sig; //!< Authentication Signature status (not included (0), valid (1), invalid (2))
139 | uint8 cmd; //!< Command Flag
140 | } attWriteReq_t;
141 |
142 | #endif /* TYPEDEF_H */
143 |
144 |
--------------------------------------------------------------------------------
/cc2540_hci_fw/HCI_UART_115200bps_20130429.bin.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samyk/BLE_HCI/20b53636ebef162a20c772073d8af29bbc2e97c1/cc2540_hci_fw/HCI_UART_115200bps_20130429.bin.zip
--------------------------------------------------------------------------------
/cc2540_hci_fw/HCI_UART_57600bps_20130502.bin.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samyk/BLE_HCI/20b53636ebef162a20c772073d8af29bbc2e97c1/cc2540_hci_fw/HCI_UART_57600bps_20130502.bin.zip
--------------------------------------------------------------------------------
/cc2540_hci_fw/HCI_USBCDC_115200_20130429.bin.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samyk/BLE_HCI/20b53636ebef162a20c772073d8af29bbc2e97c1/cc2540_hci_fw/HCI_USBCDC_115200_20130429.bin.zip
--------------------------------------------------------------------------------
/cc2540_hci_fw/UBL-1.3.hex.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samyk/BLE_HCI/20b53636ebef162a20c772073d8af29bbc2e97c1/cc2540_hci_fw/UBL-1.3.hex.zip
--------------------------------------------------------------------------------
/drivers/ccxxxx_usb_cdc.cat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samyk/BLE_HCI/20b53636ebef162a20c772073d8af29bbc2e97c1/drivers/ccxxxx_usb_cdc.cat
--------------------------------------------------------------------------------
/drivers/ccxxxx_usb_cdc.inf:
--------------------------------------------------------------------------------
1 | ;
2 | ; Texas Instruments CCxxxx USB Serial Port Setup File
3 | ;
4 | ; Based on Windows USB CDC ACM Setup File
5 | ; Copyright (c) 2000 Microsoft Corporation
6 | ; Copyright (c) 2013 Texas Instruments Inc
7 |
8 | [Version]
9 | Signature="$Windows NT$"
10 | Class=Ports
11 | ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
12 | Provider=%PROVIDER%
13 | DriverVer=04/05/2013,1.2.0.0
14 | CatalogFile=ccxxxx_usb_cdc.cat
15 |
16 | [Manufacturer]
17 | %MFGNAME%=DeviceList,NTx86,NTamd64
18 |
19 |
20 | [DeviceList.NTx86]
21 | %DESC_SRFEB% = DriverInstall, USB\VID_0451&PID_16B6
22 | %DESC_CC2511% = DriverInstall, USB\VID_0451&PID_16A4
23 | %DESC_CC1111% = DriverInstall, USB\VID_0451&PID_16A6
24 | %DESC_CC2531% = DriverInstall, USB\VID_0451&PID_16A8
25 | %DESC_CC2540% = DriverInstall, USB\VID_0451&PID_16AA
26 | %DESC_CC2544% = DriverInstall, USB\VID_0451&PID_16C5
27 | %DESC_CC2538% = DriverInstall, USB\VID_0451&PID_16C8
28 | %DESC_CCXXXXBL% = DriverInstall, USB\VID_0451&PID_16C7
29 | %DESC_REMOTINP% = DriverInstall, USB\VID_0451&PID_16B1
30 |
31 | [DeviceList.NTamd64]
32 | %DESC_SRFEB% = DriverInstall, USB\VID_0451&PID_16B6
33 | %DESC_CC2511% = DriverInstall, USB\VID_0451&PID_16A4
34 | %DESC_CC1111% = DriverInstall, USB\VID_0451&PID_16A6
35 | %DESC_CC2531% = DriverInstall, USB\VID_0451&PID_16A8
36 | %DESC_CC2540% = DriverInstall, USB\VID_0451&PID_16AA
37 | %DESC_CC2544% = DriverInstall, USB\VID_0451&PID_16C5
38 | %DESC_CC2538% = DriverInstall, USB\VID_0451&PID_16C8
39 | %DESC_CCXXXXBL% = DriverInstall, USB\VID_0451&PID_16C7
40 | %DESC_REMOTINP% = DriverInstall, USB\VID_0451&PID_16B1
41 |
42 |
43 | ;------------------------------------------------------------------------------
44 | ; Windows 32-bit sections
45 | ;------------------------------------------------------------------------------
46 |
47 | [DriverInstall.NTx86]
48 | include=mdmcpq.inf
49 | CopyFiles=FakeModemCopyFileSection
50 | AddReg=DriverRegistryKeys
51 |
52 | [DriverInstall.NTx86.Services]
53 | AddService=usbser, 0x00000002, DriverService
54 |
55 |
56 | ;------------------------------------------------------------------------------
57 | ; Windows 64-bit sections
58 | ;------------------------------------------------------------------------------
59 |
60 | [DriverInstall.NTamd64]
61 | include=mdmcpq.inf
62 | CopyFiles=FakeModemCopyFileSection
63 | AddReg=DriverRegistryKeys
64 |
65 | [DriverInstall.NTamd64.Services]
66 | AddService=usbser, 0x00000002, DriverService
67 |
68 |
69 | ;------------------------------------------------------------------------------
70 | ;
71 | ;------------------------------------------------------------------------------
72 |
73 | [DriverRegistryKeys]
74 | HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
75 |
76 | [DriverService]
77 | DisplayName = %SERVICE%
78 | ServiceType = 1
79 | StartType = 3
80 | ErrorControl = 1
81 | ServiceBinary = %12%\usbser.sys
82 |
83 |
84 | ;------------------------------------------------------------------------------
85 | ; String Definitions
86 | ;------------------------------------------------------------------------------
87 |
88 | [Strings]
89 | PROVIDER = "Texas Instruments"
90 | MFGNAME = "Texas Instruments"
91 | SERVICE = "TI USB CDC Driver"
92 | DESC_SRFEB = "TI SmartRFEB USB CDC Serial Port"
93 | DESC_CC1111 = "TI CC1111 USB CDC Serial Port"
94 | DESC_CC2511 = "TI CC2511 USB CDC Serial Port"
95 | DESC_CC2531 = "TI CC2531 USB CDC Serial Port"
96 | DESC_CC2538 = "TI CC2538 USB CDC Serial Port"
97 | DESC_CC2540 = "TI CC2540 USB CDC Serial Port"
98 | DESC_CC2544 = "TI CC2544 USB CDC Serial Port"
99 | DESC_CCXXXXBL = "TI CCxxxx Generic USB CDC Boot Loader"
100 | DESC_REMOTINP = "RemoTI Network Processor"
101 |
--------------------------------------------------------------------------------
/python/BLEMini/Biscuit_Central_HCI.py:
--------------------------------------------------------------------------------
1 | import serial
2 | import os, sys
3 | import struct
4 | from select import select
5 |
6 | # not posix system, we need msvcrt library for kbhit
7 | # for posix, we need termios and atexit
8 | if os.name <> 'posix':
9 | import msvcrt
10 | else:
11 | import atexit
12 | import termios
13 |
14 | #
15 | # Structures
16 | #
17 |
18 | class KB:
19 |
20 | def __init__(self):
21 | '''Creates a KBHit object that you can call to do various keyboard things.
22 | '''
23 |
24 | if os.name == 'nt':
25 | pass
26 |
27 | else:
28 |
29 | # Save the terminal settings
30 | self.fd = sys.stdin.fileno()
31 | self.new_term = termios.tcgetattr(self.fd)
32 | self.old_term = termios.tcgetattr(self.fd)
33 |
34 | # New terminal setting unbuffered
35 | self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
36 | termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)
37 |
38 | # Support normal-terminal reset at exit
39 | atexit.register(self.set_normal_term)
40 |
41 |
42 | def set_normal_term(self):
43 | ''' Resets to normal terminal. On Windows this is a no-op.
44 | '''
45 |
46 | if os.name == 'nt':
47 | pass
48 |
49 | else:
50 | termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)
51 |
52 |
53 | def getch(self):
54 | ''' Returns a keyboard character after kbhit() has been called.
55 | Should not be called in the same program as getarrow().
56 | '''
57 |
58 | s = ''
59 |
60 | if os.name == 'nt':
61 | return msvcrt.getch().decode('utf-8')
62 |
63 | else:
64 | return sys.stdin.read(1)
65 |
66 |
67 | def getarrow(self):
68 | ''' Returns an arrow-key code after kbhit() has been called. Codes are
69 | 0 : up
70 | 1 : right
71 | 2 : down
72 | 3 : left
73 | Should not be called in the same program as getch().
74 | '''
75 |
76 | if os.name == 'nt':
77 | msvcrt.getch() # skip 0xE0
78 | c = msvcrt.getch()
79 | vals = [72, 77, 80, 75]
80 |
81 | else:
82 | c = sys.stdin.read(3)[2]
83 | vals = [65, 67, 66, 68]
84 |
85 | return vals.index(ord(c.decode('utf-8')))
86 |
87 |
88 | def kbhit(self):
89 | ''' Returns True if keyboard character was hit, False otherwise.
90 | '''
91 | if os.name == 'nt':
92 | return msvcrt.kbhit()
93 |
94 | else:
95 | dr,dw,de = select([sys.stdin], [], [], 0)
96 | return dr != []
97 |
98 | class gapDevDiscReq_t:
99 | taskID = None
100 | mode = None
101 | activeScan = None
102 | whiteList = None
103 |
104 | class gapEstLinkReq_t:
105 | taskID = None
106 | highDutyCycle = None
107 | whiteList = None
108 | addrTypePeer = None
109 | peerAddr = None
110 |
111 | class attWriteReq_t:
112 | handle = None # Handle of the attribute to be written (must be first field)
113 | len = None # Length of value
114 | value = None # Value of the attribute to be written
115 | sig = None # Authentication Signature status (not included (0), valid (1), invalid (2))
116 | cmd = None # Command Flag
117 |
118 | #
119 | # Constants
120 | #
121 |
122 | GAP_PROFILE_CENTRAL = '\x08'
123 |
124 | DEVDISC_MODE_NONDISCOVERABLE = '\x00'
125 | DEVDISC_MODE_GENERAL = '\x01'
126 | DEVDISC_MODE_LIMITED = '\x02'
127 | DEVDISC_MODE_ALL = '\x03'
128 |
129 | # Discovey mode (limited, general, all)
130 | DEFAULT_DISCOVERY_MODE = DEVDISC_MODE_ALL
131 |
132 | # TRUE to use active scan
133 | DEFAULT_DISCOVERY_ACTIVE_SCAN = '\x01' # True
134 |
135 | # TRUE to use white list during discovery
136 | DEFAULT_DISCOVERY_WHITE_LIST = '\x00' # False
137 |
138 | # TRUE to use high scan duty cycle when creating link
139 | DEFAULT_LINK_HIGH_DUTY_CYCLE = '\x00' # False
140 |
141 | # TRUE to use white list when creating link
142 | DEFAULT_LINK_WHITE_LIST = '\x00' # False
143 |
144 | #
145 | # Global
146 | #
147 |
148 | # our transport layer will be serial port
149 | TX = serial.Serial()
150 |
151 | # store the address found
152 | found_address = None
153 |
154 | #
155 | is_connected = False
156 |
157 | #
158 | # Defines the BLE GAP command APIs
159 | #
160 |
161 | def GAP_DeviceInit( taskID, profileRole, maxScanResponses, irk, srk, signCounter ):
162 | buf = ''
163 |
164 | buf += '\x01' # -Type : 0x01 (Command)
165 | buf += '\x00' # -Opcode : 0xFE00 (GAP_DeviceInit)
166 | buf += '\xFE'
167 |
168 | buf += '\x26' # -Data Length
169 | buf += profileRole # Profile Role
170 | buf += maxScanResponses # MaxScanRsps
171 | buf += irk #
172 | buf += srk #
173 | buf += signCounter #
174 |
175 | TX.write(buf)
176 |
177 | # ToDo: here should wait for command status
178 | return True
179 |
180 | def GAP_DeviceDiscoveryRequest( params ):
181 | buf = ''
182 |
183 | buf += '\x01' # -Type : 0x01 (Command)
184 | buf += '\x04' # -Opcode : 0xFE04 (GAP_DeviceDiscoveryRequest)
185 | buf += '\xFE'
186 |
187 | buf += '\x03' # -Data Length
188 | buf += params.mode # Mode
189 | buf += params.activeScan # ActiveScan
190 | buf += params.whiteList # WhiteList
191 |
192 | TX.write(buf)
193 |
194 | # ToDo: here should wait for command status
195 | return True
196 |
197 | def GAP_EstablishLinkReq( params ):
198 | buf = ''
199 |
200 | buf += '\x01'
201 | buf += '\x09\xFE'
202 |
203 | buf += struct.pack('B', 3 + 6) # 6 is B_ADDR_LEN
204 |
205 | buf += params.highDutyCycle
206 | buf += params.whiteList
207 | buf += params.addrTypePeer
208 |
209 | buf += params.peerAddr
210 |
211 | TX.write(buf)
212 |
213 | # ToDo: here should wait for command status
214 | return True;
215 |
216 | #
217 | # Defines the BLE GATT command APIs
218 | #
219 |
220 | def GATT_WriteCharValue( connHandle, req, taskId ):
221 | buf = ''
222 |
223 | buf += '\x01'
224 | buf += '\x92\xFD'
225 |
226 | buf += struct.pack('B', 4 + ord(req.len))
227 |
228 | buf += connHandle
229 | buf += req.handle
230 | buf += req.value
231 |
232 | TX.write(buf)
233 |
234 | # ToDo: here should wait for command status
235 | return True
236 |
237 | #
238 | # Defines the BLE GAP Central Role APIs
239 | #
240 |
241 | gapCentralRoleTaskId = '\x00'
242 | gapCentralRoleIRK = struct.pack('16s', '\x00')
243 | gapCentralRoleSRK = struct.pack('16s', '\x00')
244 | gapCentralRoleSignCounter = '\x01'
245 | gapCentralRoleMaxScanRes = '\x05'
246 |
247 | def GAPCentralRole_StartDevice():
248 | return GAP_DeviceInit( gapCentralRoleTaskId, GAP_PROFILE_CENTRAL,
249 | gapCentralRoleMaxScanRes, gapCentralRoleIRK,
250 | gapCentralRoleSRK, gapCentralRoleSignCounter )
251 |
252 | def GAPCentralRole_EstablishLink( highDutyCycle, whiteList, addrTypePeer, peerAddr ):
253 | params = gapEstLinkReq_t
254 |
255 | params.taskID = gapCentralRoleTaskId
256 | params.highDutyCycle = highDutyCycle
257 | params.whiteList = whiteList
258 | params.addrTypePeer = addrTypePeer
259 | params.peerAddr = peerAddr
260 |
261 | return GAP_EstablishLinkReq( params )
262 |
263 | def GAPCentralRole_StartDiscovery( mode, activeScan, whiteList ):
264 | params = gapDevDiscReq_t
265 |
266 | params.taskID = gapCentralRoleTaskId
267 | params.mode = mode
268 | params.activeScan = activeScan
269 | params.whiteList = whiteList
270 |
271 | return GAP_DeviceDiscoveryRequest( params )
272 |
273 | #
274 | #
275 | #
276 |
277 | def ble_enable_notification():
278 | writeReq = attWriteReq_t
279 |
280 | writeReq.handle = '\x13\x00'
281 | writeReq.len = '\x02'
282 | writeReq.value = '\x01\x00'
283 |
284 | GATT_WriteCharValue( '\x00\x00', writeReq, '\x00' );
285 |
286 | def ble_write_bytes(buf):
287 | writeReq = attWriteReq_t
288 |
289 | writeReq.handle = '\x16\x00'
290 | writeReq.len = struct.pack('b', len(buf))
291 | writeReq.value = buf
292 |
293 | GATT_WriteCharValue( '\x00\x00', writeReq, '\x00' )
294 |
295 | def ble_event_available():
296 | return TX.inWaiting()
297 |
298 | def ble_event_process():
299 | global found_address
300 | global is_connected
301 |
302 | type = ord(TX.read(1));
303 | event_code = ord(TX.read(1));
304 | data_len = ord(TX.read(1));
305 |
306 | print '-----------------------------'
307 | print '-Type : 0x%02X' % (type)
308 | print '-EventCode : 0x%02X' % (event_code)
309 | print '-Data Length : 0x%02X' % (data_len)
310 |
311 | buf = TX.read(data_len)
312 |
313 | # if event_code == '\x0E':
314 | # p(" Packets : 0x%02X\r\n", buf[0]);
315 | # p(" Opcode : 0x%02X%02X\r\n", buf[2], buf[1]);
316 | # byte rssi = buf[6];
317 | # p(" RSSI : %d\r\n", rssi-255);
318 |
319 | # if (rssi-255) > -100:
320 | # print rssi
321 |
322 | # return True
323 |
324 | event = struct.unpack('H', buf[0]+buf[1])[0]
325 | status = ord(buf[2]);
326 |
327 | print ' Event : 0x%04X' % event
328 | print ' Status : 0x%02X' % status
329 |
330 | if event == 0x0601: # GAP_DeviceDiscoveryDone
331 | print 'GAP_DeviceDiscoveryDone'
332 |
333 | num_devs = ord(buf[3])
334 | print ' NumDevs : 0x%02X' % num_devs
335 |
336 | # Store address so that we can link it up
337 | # only store first discovered device only in this demo
338 | if num_devs > 0:
339 | found_address = buf[6] + buf[7] + buf[8] + buf[9] + buf[10] + buf[11]
340 |
341 | print 'Address found: ' + hex(ord(found_address[0])) + ':' + hex(ord(found_address[1])) + ':' + hex(ord(found_address[2])) + ':' + hex(ord(found_address[3])) + ':' + hex(ord(found_address[4])) + ':' + hex(ord(found_address[5]))
342 | else:
343 | print 'No device found'
344 |
345 | elif event == 0x067F:
346 | print 'GAP_HCI_ExtentionCommandStatus'
347 | print ' OpCode : 0x%02X%02X' % (ord(buf[4]), ord(buf[3]))
348 |
349 | elif event == 0x0605:
350 | print 'GAP_EstablishLink'
351 | is_connected = True;
352 |
353 | elif event == 0x0606:
354 | print 'GAP_TerminateLink'
355 | is_connected = False;
356 | found = 0;
357 |
358 | elif event == 0x060D:
359 | print 'GAP_DeviceInformation'
360 | event_type = ord(buf[3])
361 | if event_type == 0x04:
362 | print 'Scan Response'
363 | if buf[15] == 0x1E:
364 | if buf[16] == 0x94:
365 | # found_address = buf[5] + buf[6] + buf[7] + buf[8] + buf[9] + buf[10]
366 | found = 1;
367 | # GAP_DeviceDiscoveryCancel()
368 |
369 | elif event == 0x051B:
370 | print 'ATT_HandleValueNotification'
371 |
372 | n = data_len - 7
373 | s = ''
374 | for i in xrange(n):
375 | s += buf[i+7]
376 |
377 | print ' -------------> Data: ' + s
378 |
379 | else:
380 | print ' -> Not handled yet.'
381 |
382 | #
383 | # Start our demo here
384 | #
385 |
386 | if os.name == 'posix':
387 | TX.port = '/dev/tty.usbmodem1431'
388 | else:
389 | TX.port = 'COM5'
390 | TX.baudrate = 115200
391 | TX.open()
392 |
393 | print 'Biscuit Central via HCI'
394 | GAPCentralRole_StartDevice()
395 |
396 | str = ''
397 | kb = KB()
398 |
399 | while True:
400 | if ble_event_available():
401 | ble_event_process()
402 |
403 | if kb.kbhit():
404 | ch = kb.getch()
405 |
406 | if ch == 'd':
407 | print 'Discovery...'
408 | GAPCentralRole_StartDiscovery( DEFAULT_DISCOVERY_MODE,
409 | DEFAULT_DISCOVERY_ACTIVE_SCAN,
410 | DEFAULT_DISCOVERY_WHITE_LIST )
411 | elif ch == 'e':
412 | print 'Establish Link...'
413 | print 'Connecting to: ' + hex(ord(found_address[0])) + ':' + hex(ord(found_address[1])) + ':' + hex(ord(found_address[2])) + ':' + hex(ord(found_address[3])) + ':' + hex(ord(found_address[4])) + ':' + hex(ord(found_address[5]))
414 |
415 | GAPCentralRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
416 | DEFAULT_LINK_WHITE_LIST,
417 | '\x00', found_address )
418 |
419 | elif ch == 'n':
420 | print 'Enable Notification...'
421 | ble_enable_notification()
422 |
423 | elif ch == 'q':
424 | print 'Quit'
425 | TX.close()
426 | break
427 |
428 | elif ch == '1':
429 | print 'Send -> Hello World!'
430 | ble_write_bytes('Hello World!\r\n')
431 |
432 | elif ch == '2':
433 | print 'Send -> I love BLE!'
434 | ble_write_bytes('I love BLE!\r\n')
435 |
436 | else:
437 | print 'Invalid command.'
438 |
--------------------------------------------------------------------------------
/python/BLEMini/Biscuit_Peripheral.py:
--------------------------------------------------------------------------------
1 | import serial
2 | import os
3 |
4 | TX = serial.Serial()
5 |
6 | if os.name == 'posix':
7 | TX.port = '/dev/tty.usbmodem1431'
8 | else:
9 | TX.port = 'COM5'
10 | TX.baudrate = 115200
11 | TX.open()
12 |
13 | print 'Waiting for data from Biscuit central...'
14 | while 1:
15 | print TX.readline()
16 |
--------------------------------------------------------------------------------
/python/BLEShield/BLEShield_Central_HCI.py:
--------------------------------------------------------------------------------
1 | import serial
2 | import os, sys
3 | import struct
4 | from select import select
5 |
6 | # not posix system, we need msvcrt library for kbhit
7 | # for posix, we need termios and atexit
8 | if os.name <> 'posix':
9 | import msvcrt
10 | else:
11 | import atexit
12 | import termios
13 |
14 | #
15 | # Structures
16 | #
17 |
18 | class KB:
19 |
20 | def __init__(self):
21 | '''Creates a KBHit object that you can call to do various keyboard things.
22 | '''
23 |
24 | if os.name == 'nt':
25 | pass
26 |
27 | else:
28 |
29 | # Save the terminal settings
30 | self.fd = sys.stdin.fileno()
31 | self.new_term = termios.tcgetattr(self.fd)
32 | self.old_term = termios.tcgetattr(self.fd)
33 |
34 | # New terminal setting unbuffered
35 | self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
36 | termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)
37 |
38 | # Support normal-terminal reset at exit
39 | atexit.register(self.set_normal_term)
40 |
41 |
42 | def set_normal_term(self):
43 | ''' Resets to normal terminal. On Windows this is a no-op.
44 | '''
45 |
46 | if os.name == 'nt':
47 | pass
48 |
49 | else:
50 | termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)
51 |
52 |
53 | def getch(self):
54 | ''' Returns a keyboard character after kbhit() has been called.
55 | Should not be called in the same program as getarrow().
56 | '''
57 |
58 | s = ''
59 |
60 | if os.name == 'nt':
61 | return msvcrt.getch().decode('utf-8')
62 |
63 | else:
64 | return sys.stdin.read(1)
65 |
66 |
67 | def getarrow(self):
68 | ''' Returns an arrow-key code after kbhit() has been called. Codes are
69 | 0 : up
70 | 1 : right
71 | 2 : down
72 | 3 : left
73 | Should not be called in the same program as getch().
74 | '''
75 |
76 | if os.name == 'nt':
77 | msvcrt.getch() # skip 0xE0
78 | c = msvcrt.getch()
79 | vals = [72, 77, 80, 75]
80 |
81 | else:
82 | c = sys.stdin.read(3)[2]
83 | vals = [65, 67, 66, 68]
84 |
85 | return vals.index(ord(c.decode('utf-8')))
86 |
87 |
88 | def kbhit(self):
89 | ''' Returns True if keyboard character was hit, False otherwise.
90 | '''
91 | if os.name == 'nt':
92 | return msvcrt.kbhit()
93 |
94 | else:
95 | dr,dw,de = select([sys.stdin], [], [], 0)
96 | return dr != []
97 |
98 | class gapDevDiscReq_t:
99 | taskID = None
100 | mode = None
101 | activeScan = None
102 | whiteList = None
103 |
104 | class gapEstLinkReq_t:
105 | taskID = None
106 | highDutyCycle = None
107 | whiteList = None
108 | addrTypePeer = None
109 | peerAddr = None
110 |
111 | class attWriteReq_t:
112 | handle = None # Handle of the attribute to be written (must be first field)
113 | len = None # Length of value
114 | value = None # Value of the attribute to be written
115 | sig = None # Authentication Signature status (not included (0), valid (1), invalid (2))
116 | cmd = None # Command Flag
117 |
118 | #
119 | # Constants
120 | #
121 |
122 | GAP_PROFILE_CENTRAL = '\x08'
123 |
124 | DEVDISC_MODE_NONDISCOVERABLE = '\x00'
125 | DEVDISC_MODE_GENERAL = '\x01'
126 | DEVDISC_MODE_LIMITED = '\x02'
127 | DEVDISC_MODE_ALL = '\x03'
128 |
129 | # Discovey mode (limited, general, all)
130 | DEFAULT_DISCOVERY_MODE = DEVDISC_MODE_ALL
131 |
132 | # TRUE to use active scan
133 | DEFAULT_DISCOVERY_ACTIVE_SCAN = '\x01' # True
134 |
135 | # TRUE to use white list during discovery
136 | DEFAULT_DISCOVERY_WHITE_LIST = '\x00' # False
137 |
138 | # TRUE to use high scan duty cycle when creating link
139 | DEFAULT_LINK_HIGH_DUTY_CYCLE = '\x00' # False
140 |
141 | # TRUE to use white list when creating link
142 | DEFAULT_LINK_WHITE_LIST = '\x00' # False
143 |
144 | #
145 | # Global
146 | #
147 |
148 | # our transport layer will be serial port
149 | TX = serial.Serial()
150 |
151 | # store the address found
152 | found_address = None
153 |
154 | #
155 | is_connected = False
156 |
157 | #
158 | # Defines the BLE GAP command APIs
159 | #
160 |
161 | def GAP_DeviceInit( taskID, profileRole, maxScanResponses, irk, srk, signCounter ):
162 | buf = ''
163 |
164 | buf += '\x01' # -Type : 0x01 (Command)
165 | buf += '\x00' # -Opcode : 0xFE00 (GAP_DeviceInit)
166 | buf += '\xFE'
167 |
168 | buf += '\x26' # -Data Length
169 | buf += profileRole # Profile Role
170 | buf += maxScanResponses # MaxScanRsps
171 | buf += irk #
172 | buf += srk #
173 | buf += signCounter #
174 |
175 | TX.write(buf)
176 |
177 | # ToDo: here should wait for command status
178 | return True
179 |
180 | def GAP_DeviceDiscoveryRequest( params ):
181 | buf = ''
182 |
183 | buf += '\x01' # -Type : 0x01 (Command)
184 | buf += '\x04' # -Opcode : 0xFE04 (GAP_DeviceDiscoveryRequest)
185 | buf += '\xFE'
186 |
187 | buf += '\x03' # -Data Length
188 | buf += params.mode # Mode
189 | buf += params.activeScan # ActiveScan
190 | buf += params.whiteList # WhiteList
191 |
192 | TX.write(buf)
193 |
194 | # ToDo: here should wait for command status
195 | return True
196 |
197 | def GAP_EstablishLinkReq( params ):
198 | buf = ''
199 |
200 | buf += '\x01'
201 | buf += '\x09\xFE'
202 |
203 | buf += struct.pack('B', 3 + 6) # 6 is B_ADDR_LEN
204 |
205 | buf += params.highDutyCycle
206 | buf += params.whiteList
207 | buf += params.addrTypePeer
208 |
209 | buf += params.peerAddr
210 |
211 | TX.write(buf)
212 |
213 | # ToDo: here should wait for command status
214 | return True;
215 |
216 | #
217 | # Defines the BLE GATT command APIs
218 | #
219 |
220 | def GATT_WriteNoRsp( connHandle, req, taskId ):
221 | buf = ''
222 |
223 | buf += '\x01'
224 | buf += '\xB6\xFD'
225 |
226 | buf += struct.pack('B', 4 + ord(req.len))
227 |
228 | buf += connHandle
229 | buf += req.handle
230 | buf += req.value
231 |
232 | TX.write(buf)
233 |
234 | # ToDo: here should wait for command status
235 | return True
236 |
237 | def GATT_WriteCharValue( connHandle, req, taskId ):
238 | buf = ''
239 |
240 | buf += '\x01'
241 | buf += '\x92\xFD'
242 |
243 | buf += struct.pack('B', 4 + ord(req.len))
244 |
245 | buf += connHandle
246 | buf += req.handle
247 | buf += req.value
248 |
249 | TX.write(buf)
250 |
251 | # ToDo: here should wait for command status
252 | return True
253 |
254 | #
255 | # Defines the BLE GAP Central Role APIs
256 | #
257 |
258 | gapCentralRoleTaskId = '\x00'
259 | gapCentralRoleIRK = struct.pack('16s', '\x00')
260 | gapCentralRoleSRK = struct.pack('16s', '\x00')
261 | gapCentralRoleSignCounter = '\x01'
262 | gapCentralRoleMaxScanRes = '\x05'
263 |
264 | def GAPCentralRole_StartDevice():
265 | return GAP_DeviceInit( gapCentralRoleTaskId, GAP_PROFILE_CENTRAL,
266 | gapCentralRoleMaxScanRes, gapCentralRoleIRK,
267 | gapCentralRoleSRK, gapCentralRoleSignCounter )
268 |
269 | def GAPCentralRole_EstablishLink( highDutyCycle, whiteList, addrTypePeer, peerAddr ):
270 | params = gapEstLinkReq_t
271 |
272 | params.taskID = gapCentralRoleTaskId
273 | params.highDutyCycle = highDutyCycle
274 | params.whiteList = whiteList
275 | params.addrTypePeer = addrTypePeer
276 | params.peerAddr = peerAddr
277 |
278 | return GAP_EstablishLinkReq( params )
279 |
280 | def GAPCentralRole_StartDiscovery( mode, activeScan, whiteList ):
281 | params = gapDevDiscReq_t
282 |
283 | params.taskID = gapCentralRoleTaskId
284 | params.mode = mode
285 | params.activeScan = activeScan
286 | params.whiteList = whiteList
287 |
288 | return GAP_DeviceDiscoveryRequest( params )
289 |
290 | #
291 | #
292 | #
293 |
294 | def ble_enable_notification():
295 | writeReq = attWriteReq_t
296 |
297 | writeReq.handle = '\x0e\x00'
298 | writeReq.len = '\x02'
299 | writeReq.value = '\x01\x00'
300 |
301 | GATT_WriteCharValue( '\x00\x00', writeReq, '\x00' );
302 |
303 | def ble_write_bytes(buf):
304 | writeReq = attWriteReq_t
305 |
306 | writeReq.handle = '\x0b\x00'
307 | writeReq.len = struct.pack('b', len(buf))
308 | writeReq.value = buf
309 |
310 | GATT_WriteNoRsp( '\x00\x00', writeReq, '\x00' )
311 |
312 | def ble_event_available():
313 | return TX.inWaiting()
314 |
315 | def ble_event_process():
316 | global found_address
317 | global is_connected
318 |
319 | type = ord(TX.read(1));
320 | event_code = ord(TX.read(1));
321 | data_len = ord(TX.read(1));
322 |
323 | print '-----------------------------'
324 | print '-Type : 0x%02X' % (type)
325 | print '-EventCode : 0x%02X' % (event_code)
326 | print '-Data Length : 0x%02X' % (data_len)
327 |
328 | buf = TX.read(data_len)
329 |
330 | # if event_code == '\x0E':
331 | # p(" Packets : 0x%02X\r\n", buf[0]);
332 | # p(" Opcode : 0x%02X%02X\r\n", buf[2], buf[1]);
333 | # byte rssi = buf[6];
334 | # p(" RSSI : %d\r\n", rssi-255);
335 |
336 | # if (rssi-255) > -100:
337 | # print rssi
338 |
339 | # return True
340 |
341 | event = struct.unpack('H', buf[0]+buf[1])[0]
342 | status = ord(buf[2]);
343 |
344 | print ' Event : 0x%04X' % event
345 | print ' Status : 0x%02X' % status
346 |
347 | if event == 0x0601: # GAP_DeviceDiscoveryDone
348 | print 'GAP_DeviceDiscoveryDone'
349 |
350 | num_devs = ord(buf[3])
351 | print ' NumDevs : 0x%02X' % num_devs
352 |
353 | # Store address so that we can link it up
354 | # only store first discovered device only in this demo
355 | if num_devs > 0:
356 | found_address = buf[6] + buf[7] + buf[8] + buf[9] + buf[10] + buf[11]
357 |
358 | print 'Address found: ' + hex(ord(found_address[0])) + ':' + hex(ord(found_address[1])) + ':' + hex(ord(found_address[2])) + ':' + hex(ord(found_address[3])) + ':' + hex(ord(found_address[4])) + ':' + hex(ord(found_address[5]))
359 | else:
360 | print 'No device found'
361 |
362 | elif event == 0x067F:
363 | print 'GAP_HCI_ExtentionCommandStatus'
364 | print ' OpCode : 0x%02X%02X' % (ord(buf[4]), ord(buf[3]))
365 |
366 | elif event == 0x0605:
367 | print 'GAP_EstablishLink'
368 | is_connected = True;
369 |
370 | elif event == 0x0606:
371 | print 'GAP_TerminateLink'
372 | is_connected = False;
373 | found = 0;
374 |
375 | elif event == 0x060D:
376 | print 'GAP_DeviceInformation'
377 | event_type = ord(buf[3])
378 | if event_type == 0x04:
379 | print 'Scan Response'
380 | if buf[15] == 0x1E:
381 | if buf[16] == 0x94:
382 | # found_address = buf[5] + buf[6] + buf[7] + buf[8] + buf[9] + buf[10]
383 | found = 1;
384 | # GAP_DeviceDiscoveryCancel()
385 |
386 | elif event == 0x051B:
387 | print 'ATT_HandleValueNotification'
388 |
389 | n = data_len - 7
390 | s = ''
391 | for i in xrange(n):
392 | s += buf[i+7]
393 |
394 | print ' -------------> Data: ' + s
395 |
396 | else:
397 | print ' -> Not handled yet.'
398 |
399 | #
400 | # Start our demo here
401 | #
402 |
403 | if os.name == 'posix':
404 | TX.port = '/dev/tty.usbmodem1431'
405 | else:
406 | TX.port = 'COM5'
407 | TX.baudrate = 115200
408 | TX.open()
409 |
410 | print 'Biscuit Central via HCI'
411 | GAPCentralRole_StartDevice()
412 |
413 | str = ''
414 | kb = KB()
415 |
416 | while True:
417 | if ble_event_available():
418 | ble_event_process()
419 |
420 | if kb.kbhit():
421 | ch = kb.getch()
422 |
423 | if ch == 'd':
424 | print 'Discovery...'
425 | GAPCentralRole_StartDiscovery( DEFAULT_DISCOVERY_MODE,
426 | DEFAULT_DISCOVERY_ACTIVE_SCAN,
427 | DEFAULT_DISCOVERY_WHITE_LIST )
428 | elif ch == 'e':
429 | print 'Establish Link...'
430 | print 'Connecting to: ' + hex(ord(found_address[0])) + ':' + hex(ord(found_address[1])) + ':' + hex(ord(found_address[2])) + ':' + hex(ord(found_address[3])) + ':' + hex(ord(found_address[4])) + ':' + hex(ord(found_address[5]))
431 |
432 | GAPCentralRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
433 | DEFAULT_LINK_WHITE_LIST,
434 | '\x01', found_address )
435 |
436 | elif ch == 'n':
437 | print 'Enable Notification...'
438 | ble_enable_notification()
439 |
440 | elif ch == 'q':
441 | print 'Quit'
442 | TX.close()
443 | break
444 |
445 | elif ch == '1':
446 | print 'Send "ON" to the BLE Shield'
447 | ble_write_bytes('\x90\x00\x01')
448 |
449 | elif ch == '2':
450 | print 'Send "OFF" to the BLE Shield'
451 | ble_write_bytes('\x90\x00\x00')
452 |
453 | elif ch == '3':
454 | print 'Send "HELLO" to the BLE Shield'
455 | ble_write_bytes('HELLO');
456 |
457 | else:
458 | print 'Invalid command.'
459 |
--------------------------------------------------------------------------------
/python/SensorTag/SensorTag_Central_HCI.py:
--------------------------------------------------------------------------------
1 | import serial
2 | import os, sys
3 | import struct
4 | from select import select
5 |
6 | # not posix system, we need msvcrt library for kbhit
7 | # for posix, we need termios and atexit
8 | if os.name <> 'posix':
9 | import msvcrt
10 | else:
11 | import atexit
12 | import termios
13 |
14 | #
15 | # Structures
16 | #
17 |
18 | class KB:
19 |
20 | def __init__(self):
21 | '''Creates a KBHit object that you can call to do various keyboard things.
22 | '''
23 |
24 | if os.name == 'nt':
25 | pass
26 |
27 | else:
28 |
29 | # Save the terminal settings
30 | self.fd = sys.stdin.fileno()
31 | self.new_term = termios.tcgetattr(self.fd)
32 | self.old_term = termios.tcgetattr(self.fd)
33 |
34 | # New terminal setting unbuffered
35 | self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
36 | termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)
37 |
38 | # Support normal-terminal reset at exit
39 | atexit.register(self.set_normal_term)
40 |
41 |
42 | def set_normal_term(self):
43 | ''' Resets to normal terminal. On Windows this is a no-op.
44 | '''
45 |
46 | if os.name == 'nt':
47 | pass
48 |
49 | else:
50 | termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)
51 |
52 |
53 | def getch(self):
54 | ''' Returns a keyboard character after kbhit() has been called.
55 | Should not be called in the same program as getarrow().
56 | '''
57 |
58 | s = ''
59 |
60 | if os.name == 'nt':
61 | return msvcrt.getch().decode('utf-8')
62 |
63 | else:
64 | return sys.stdin.read(1)
65 |
66 |
67 | def getarrow(self):
68 | ''' Returns an arrow-key code after kbhit() has been called. Codes are
69 | 0 : up
70 | 1 : right
71 | 2 : down
72 | 3 : left
73 | Should not be called in the same program as getch().
74 | '''
75 |
76 | if os.name == 'nt':
77 | msvcrt.getch() # skip 0xE0
78 | c = msvcrt.getch()
79 | vals = [72, 77, 80, 75]
80 |
81 | else:
82 | c = sys.stdin.read(3)[2]
83 | vals = [65, 67, 66, 68]
84 |
85 | return vals.index(ord(c.decode('utf-8')))
86 |
87 |
88 | def kbhit(self):
89 | ''' Returns True if keyboard character was hit, False otherwise.
90 | '''
91 | if os.name == 'nt':
92 | return msvcrt.kbhit()
93 |
94 | else:
95 | dr,dw,de = select([sys.stdin], [], [], 0)
96 | return dr != []
97 |
98 | class gapDevDiscReq_t:
99 | taskID = None
100 | mode = None
101 | activeScan = None
102 | whiteList = None
103 |
104 | class gapEstLinkReq_t:
105 | taskID = None
106 | highDutyCycle = None
107 | whiteList = None
108 | addrTypePeer = None
109 | peerAddr = None
110 |
111 | class attWriteReq_t:
112 | handle = None # Handle of the attribute to be written (must be first field)
113 | len = None # Length of value
114 | value = None # Value of the attribute to be written
115 | sig = None # Authentication Signature status (not included (0), valid (1), invalid (2))
116 | cmd = None # Command Flag
117 |
118 | #
119 | # Constants
120 | #
121 |
122 | GAP_PROFILE_CENTRAL = '\x08'
123 |
124 | DEVDISC_MODE_NONDISCOVERABLE = '\x00'
125 | DEVDISC_MODE_GENERAL = '\x01'
126 | DEVDISC_MODE_LIMITED = '\x02'
127 | DEVDISC_MODE_ALL = '\x03'
128 |
129 | # Discovey mode (limited, general, all)
130 | DEFAULT_DISCOVERY_MODE = DEVDISC_MODE_ALL
131 |
132 | # TRUE to use active scan
133 | DEFAULT_DISCOVERY_ACTIVE_SCAN = '\x01' # True
134 |
135 | # TRUE to use white list during discovery
136 | DEFAULT_DISCOVERY_WHITE_LIST = '\x00' # False
137 |
138 | # TRUE to use high scan duty cycle when creating link
139 | DEFAULT_LINK_HIGH_DUTY_CYCLE = '\x00' # False
140 |
141 | # TRUE to use white list when creating link
142 | DEFAULT_LINK_WHITE_LIST = '\x00' # False
143 |
144 | #
145 | # Global
146 | #
147 |
148 | # our transport layer will be serial port
149 | TX = serial.Serial()
150 |
151 | # store the address found
152 | found_address = None
153 |
154 | #
155 | is_connected = False
156 |
157 | #
158 | # Defines the BLE GAP command APIs
159 | #
160 |
161 | def GAP_DeviceInit( taskID, profileRole, maxScanResponses, irk, srk, signCounter ):
162 | buf = ''
163 |
164 | buf += '\x01' # -Type : 0x01 (Command)
165 | buf += '\x00' # -Opcode : 0xFE00 (GAP_DeviceInit)
166 | buf += '\xFE'
167 |
168 | buf += '\x26' # -Data Length
169 | buf += profileRole # Profile Role
170 | buf += maxScanResponses # MaxScanRsps
171 | buf += irk #
172 | buf += srk #
173 | buf += signCounter #
174 |
175 | TX.write(buf)
176 |
177 | # ToDo: here should wait for command status
178 | return True
179 |
180 | def GAP_DeviceDiscoveryRequest( params ):
181 | buf = ''
182 |
183 | buf += '\x01' # -Type : 0x01 (Command)
184 | buf += '\x04' # -Opcode : 0xFE04 (GAP_DeviceDiscoveryRequest)
185 | buf += '\xFE'
186 |
187 | buf += '\x03' # -Data Length
188 | buf += params.mode # Mode
189 | buf += params.activeScan # ActiveScan
190 | buf += params.whiteList # WhiteList
191 |
192 | TX.write(buf)
193 |
194 | # ToDo: here should wait for command status
195 | return True
196 |
197 | def GAP_EstablishLinkReq( params ):
198 | buf = ''
199 |
200 | buf += '\x01'
201 | buf += '\x09\xFE'
202 |
203 | buf += struct.pack('B', 3 + 6) # 6 is B_ADDR_LEN
204 |
205 | buf += params.highDutyCycle
206 | buf += params.whiteList
207 | buf += params.addrTypePeer
208 |
209 | buf += params.peerAddr
210 |
211 | TX.write(buf)
212 |
213 | # ToDo: here should wait for command status
214 | return True;
215 |
216 | #
217 | # Defines the BLE GATT command APIs
218 | #
219 |
220 | def GATT_WriteCharValue( connHandle, req, taskId ):
221 | buf = ''
222 |
223 | buf += '\x01'
224 | buf += '\x92\xFD'
225 |
226 | buf += struct.pack('B', 4 + ord(req.len))
227 |
228 | buf += connHandle
229 | buf += req.handle
230 | buf += req.value
231 |
232 | TX.write(buf)
233 |
234 | # ToDo: here should wait for command status
235 | return True
236 |
237 | #
238 | # Defines the BLE GAP Central Role APIs
239 | #
240 |
241 | gapCentralRoleTaskId = '\x00'
242 | gapCentralRoleIRK = struct.pack('16s', '\x00')
243 | gapCentralRoleSRK = struct.pack('16s', '\x00')
244 | gapCentralRoleSignCounter = '\x01'
245 | gapCentralRoleMaxScanRes = '\x05'
246 |
247 | def GAPCentralRole_StartDevice():
248 | return GAP_DeviceInit( gapCentralRoleTaskId, GAP_PROFILE_CENTRAL,
249 | gapCentralRoleMaxScanRes, gapCentralRoleIRK,
250 | gapCentralRoleSRK, gapCentralRoleSignCounter )
251 |
252 | def GAPCentralRole_EstablishLink( highDutyCycle, whiteList, addrTypePeer, peerAddr ):
253 | params = gapEstLinkReq_t
254 |
255 | params.taskID = gapCentralRoleTaskId
256 | params.highDutyCycle = highDutyCycle
257 | params.whiteList = whiteList
258 | params.addrTypePeer = addrTypePeer
259 | params.peerAddr = peerAddr
260 |
261 | return GAP_EstablishLinkReq( params )
262 |
263 | def GAPCentralRole_StartDiscovery( mode, activeScan, whiteList ):
264 | params = gapDevDiscReq_t
265 |
266 | params.taskID = gapCentralRoleTaskId
267 | params.mode = mode
268 | params.activeScan = activeScan
269 | params.whiteList = whiteList
270 |
271 | return GAP_DeviceDiscoveryRequest( params )
272 |
273 | #
274 | #
275 | #
276 |
277 | def ble_enable_notification():
278 | writeReq = attWriteReq_t
279 |
280 | writeReq.handle = '\x6C\x00' # this is the handle of button in SensorTag, got from BTool
281 | writeReq.len = '\x02'
282 | writeReq.value = '\x01\x00'
283 |
284 | GATT_WriteCharValue( '\x00\x00', writeReq, '\x00' );
285 |
286 | def ble_write_bytes(buf):
287 | writeReq = attWriteReq_t
288 |
289 | writeReq.handle = '\x16\x00'
290 | writeReq.len = struct.pack('b', len(buf))
291 | writeReq.value = buf
292 |
293 | GATT_WriteCharValue( '\x00\x00', writeReq, '\x00' )
294 |
295 | def ble_event_available():
296 | return TX.inWaiting()
297 |
298 | def ble_event_process():
299 | global found_address
300 | global is_connected
301 |
302 | type = ord(TX.read(1));
303 | event_code = ord(TX.read(1));
304 | data_len = ord(TX.read(1));
305 |
306 | print '-----------------------------'
307 | print '-Type : 0x%02X' % (type)
308 | print '-EventCode : 0x%02X' % (event_code)
309 | print '-Data Length : 0x%02X' % (data_len)
310 |
311 | buf = TX.read(data_len)
312 |
313 | # if event_code == '\x0E':
314 | # p(" Packets : 0x%02X\r\n", buf[0]);
315 | # p(" Opcode : 0x%02X%02X\r\n", buf[2], buf[1]);
316 | # byte rssi = buf[6];
317 | # p(" RSSI : %d\r\n", rssi-255);
318 |
319 | # if (rssi-255) > -100:
320 | # print rssi
321 |
322 | # return True
323 |
324 | event = struct.unpack('H', buf[0]+buf[1])[0]
325 | status = ord(buf[2]);
326 |
327 | print ' Event : 0x%04X' % event
328 | print ' Status : 0x%02X' % status
329 |
330 | if event == 0x0601: # GAP_DeviceDiscoveryDone
331 | print 'GAP_DeviceDiscoveryDone'
332 |
333 | num_devs = ord(buf[3])
334 | print ' NumDevs : 0x%02X' % num_devs
335 |
336 | # Store address so that we can link it up
337 | # only store first discovered device only in this demo
338 | if num_devs > 0:
339 | found_address = buf[6] + buf[7] + buf[8] + buf[9] + buf[10] + buf[11]
340 |
341 | print 'Address found: ' + hex(ord(found_address[0])) + ':' + hex(ord(found_address[1])) + ':' + hex(ord(found_address[2])) + ':' + hex(ord(found_address[3])) + ':' + hex(ord(found_address[4])) + ':' + hex(ord(found_address[5]))
342 | else:
343 | print 'No device found'
344 |
345 | elif event == 0x067F:
346 | print 'GAP_HCI_ExtentionCommandStatus'
347 | print ' OpCode : 0x%02X%02X' % (ord(buf[4]), ord(buf[3]))
348 |
349 | elif event == 0x0605:
350 | print 'GAP_EstablishLink'
351 | is_connected = True;
352 |
353 | elif event == 0x0606:
354 | print 'GAP_TerminateLink'
355 | is_connected = False;
356 | found = 0;
357 |
358 | elif event == 0x060D:
359 | print 'GAP_DeviceInformation'
360 | event_type = ord(buf[3])
361 | if event_type == 0x04:
362 | print 'Scan Response'
363 | if buf[15] == 0x1E:
364 | if buf[16] == 0x94:
365 | # found_address = buf[5] + buf[6] + buf[7] + buf[8] + buf[9] + buf[10]
366 | found = 1;
367 | # GAP_DeviceDiscoveryCancel()
368 |
369 | elif event == 0x051B:
370 | print 'ATT_HandleValueNotification'
371 |
372 | if ord(buf[6]) == 0x6B:
373 | print ' -------------> Button: ' + hex(ord(buf[8]))
374 |
375 | else:
376 | print ' -> Not handled yet.'
377 |
378 | #
379 | # Start our demo here
380 | #
381 |
382 | if os.name == 'posix':
383 | TX.port = '/dev/tty.usbmodem1431'
384 | else:
385 | TX.port = 'COM5'
386 | TX.baudrate = 115200
387 | TX.open()
388 |
389 | print 'Biscuit Central via HCI'
390 | GAPCentralRole_StartDevice()
391 |
392 | str = ''
393 | kb = KB()
394 |
395 | while True:
396 | if ble_event_available():
397 | ble_event_process()
398 |
399 | if kb.kbhit():
400 | ch = kb.getch()
401 |
402 | if ch == 'd':
403 | print 'Discovery...'
404 | GAPCentralRole_StartDiscovery( DEFAULT_DISCOVERY_MODE,
405 | DEFAULT_DISCOVERY_ACTIVE_SCAN,
406 | DEFAULT_DISCOVERY_WHITE_LIST )
407 | elif ch == 'e':
408 | print 'Establish Link...'
409 | print 'Connecting to: ' + hex(ord(found_address[0])) + ':' + hex(ord(found_address[1])) + ':' + hex(ord(found_address[2])) + ':' + hex(ord(found_address[3])) + ':' + hex(ord(found_address[4])) + ':' + hex(ord(found_address[5]))
410 |
411 | GAPCentralRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
412 | DEFAULT_LINK_WHITE_LIST,
413 | '\x00', found_address )
414 |
415 | elif ch == 'n':
416 | print 'Enable Notification...'
417 | ble_enable_notification()
418 |
419 | elif ch == 'q':
420 | print 'Quit'
421 | TX.close()
422 | break
423 |
424 | else:
425 | print 'Invalid command.'
426 |
--------------------------------------------------------------------------------