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