esp_arduino_stuff
This commit is contained in:
335
arduino_stepper/arduino_stepper.ino
Normal file
335
arduino_stepper/arduino_stepper.ino
Normal file
@@ -0,0 +1,335 @@
|
||||
|
||||
/*
|
||||
Stepper Motor Control - one revolution
|
||||
|
||||
This program drives a unipolar or bipolar stepper motor.
|
||||
The motor is attached to digital pins 8 - 11 of the Arduino.
|
||||
|
||||
The motor should revolve one revolution in one direction, then
|
||||
one revolution in the other direction.
|
||||
|
||||
|
||||
Created 11 Mar. 2007
|
||||
Modified 30 Nov. 2009
|
||||
by Tom Igoe
|
||||
|
||||
*/
|
||||
|
||||
#include <Stepper.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
const int stepsPerRevolution = 2*2*1600; // change this to fit the number of steps per revolution
|
||||
// for your motor
|
||||
const float lead = 3.0; // Steigung in mm
|
||||
|
||||
// PINs
|
||||
const int stepper_1_a_gpio = 25;
|
||||
const int stepper_1_b_gpio = 33;
|
||||
|
||||
const int butten_down_up_analog_read = 34;
|
||||
const int led_gpio = 32;
|
||||
const int button_down_gpio = 35;
|
||||
const int button_up_gpio = 34;
|
||||
const int relais_gpio = 13;
|
||||
const int wifi_btn_gpio = 14;
|
||||
|
||||
const int power_led_gpio = 27;
|
||||
|
||||
|
||||
long power_off_timer = 0;
|
||||
const long power_off_timeout = 5*1000; // switch off power after 3 seconds
|
||||
|
||||
bool power_enabled = false;
|
||||
|
||||
|
||||
// Replace with your network credentials
|
||||
const char* ssid = "ESP32-Access-Point";
|
||||
const char* password = "123456789";
|
||||
|
||||
// Set web server port number to 80
|
||||
WiFiServer server(80);
|
||||
|
||||
// Variable to store the HTTP request
|
||||
String header;
|
||||
|
||||
|
||||
// Auxiliar variables to store the current output state
|
||||
String output26State = "off";
|
||||
String output27State = "off";
|
||||
|
||||
// Assign output variables to GPIO pins
|
||||
const int output26 = 26;
|
||||
const int output27 = 27;
|
||||
|
||||
|
||||
// initialize the stepper library on pins 8 through 11:
|
||||
//Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);
|
||||
Stepper myStepper(stepsPerRevolution, stepper_1_a_gpio, stepper_1_b_gpio);
|
||||
|
||||
void setup() {
|
||||
// set the speed at 60 rpm:
|
||||
pinMode(led_gpio, OUTPUT);
|
||||
pinMode(power_led_gpio, OUTPUT);
|
||||
//pinMode(button_down_gpio, INPUT_PULLDOWN); // for analog read not required
|
||||
//pinMode(button_up_gpio, INPUT_PULLDOWN); // for analog read not required
|
||||
pinMode(relais_gpio, OUTPUT);
|
||||
pinMode(wifi_btn_gpio, INPUT);
|
||||
disable_power();
|
||||
myStepper.setSpeed(120);
|
||||
// initialize the serial port:
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
|
||||
void do_test(){
|
||||
Serial.print("Setting LED to LOW");
|
||||
digitalWrite(power_led_gpio, LOW);
|
||||
delay(5000);
|
||||
Serial.print("Setting LED to HIGH");
|
||||
digitalWrite(power_led_gpio, HIGH);
|
||||
delay(5000);
|
||||
|
||||
}
|
||||
|
||||
void setup_wifi_ap(){
|
||||
// Connect to Wi-Fi network with SSID and password
|
||||
Serial.print("Setting AP (Access Point)…");
|
||||
// Remove the password parameter, if you want the AP (Access Point) to be open
|
||||
WiFi.softAP(ssid, password);
|
||||
|
||||
IPAddress IP = WiFi.softAPIP();
|
||||
Serial.print("AP IP address: ");
|
||||
Serial.println(IP);
|
||||
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void move_x_mm(int x) {
|
||||
digitalWrite(led_gpio, HIGH);
|
||||
Serial.println(x);
|
||||
Serial.println(x/lead);
|
||||
myStepper.step(x/lead*stepsPerRevolution);
|
||||
digitalWrite(led_gpio, LOW);
|
||||
}
|
||||
|
||||
void enable_power() {
|
||||
if(!power_enabled) {
|
||||
digitalWrite(relais_gpio, HIGH);
|
||||
digitalWrite(power_led_gpio, HIGH);
|
||||
Serial.println("enable relais");
|
||||
delay(500);
|
||||
power_enabled = true;
|
||||
}
|
||||
power_off_timer = millis();
|
||||
}
|
||||
void disable_power() {
|
||||
Serial.println("disable relais");
|
||||
digitalWrite(relais_gpio, LOW);
|
||||
digitalWrite(power_led_gpio, LOW);
|
||||
power_enabled = false;
|
||||
}
|
||||
|
||||
void _test_stepper(){
|
||||
//Wdo_test();
|
||||
//listen_for_wifi_client();
|
||||
//enable_power();
|
||||
//delay(2000);
|
||||
move_x_mm(10*3);
|
||||
//disable_power();
|
||||
delay(3000);
|
||||
move_x_mm(-3*10);
|
||||
delay(3000);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//_test_stepper();
|
||||
//return;
|
||||
|
||||
|
||||
if(millis() > power_off_timer + power_off_timeout && power_enabled){
|
||||
disable_power();
|
||||
}
|
||||
|
||||
int up_down_btn_val = analogRead(butten_down_up_analog_read);
|
||||
|
||||
|
||||
//delay(100);
|
||||
if (up_down_btn_val > 150 && up_down_btn_val < 300) {
|
||||
enable_power();
|
||||
move_x_mm(2);
|
||||
}
|
||||
else if (up_down_btn_val > 1800 && up_down_btn_val < 2050) {
|
||||
enable_power();
|
||||
move_x_mm(-2);
|
||||
}
|
||||
else if (up_down_btn_val > 0) {
|
||||
char format[] = "Btn Val=\"%d\"";
|
||||
char txt[50] = "";
|
||||
sprintf(txt,format,up_down_btn_val);
|
||||
Serial.println(txt);
|
||||
}
|
||||
|
||||
int up_button_state = digitalRead(button_up_gpio);
|
||||
//Serial.println(up_button_state);
|
||||
if ( up_button_state == HIGH )
|
||||
{
|
||||
enable_power();
|
||||
move_x_mm(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//disable_power();
|
||||
}
|
||||
int down_button_state = digitalRead(button_down_gpio);
|
||||
//Serial.println(down_button_state);
|
||||
if ( down_button_state == HIGH )
|
||||
{
|
||||
enable_power();
|
||||
move_x_mm(-2);
|
||||
}
|
||||
else
|
||||
{
|
||||
//disable_power();
|
||||
}
|
||||
//delay(10);
|
||||
|
||||
/*
|
||||
Serial.println("on");
|
||||
digitalWrite(led_gpio, HIGH); // turn the LED on (HIGH is the voltage level)
|
||||
delay(1000); // wait for a second
|
||||
Serial.println("off");
|
||||
digitalWrite(led_gpio, LOW); // turn the LED off by making the voltage LOW
|
||||
delay(1000); // wait for a second
|
||||
*/
|
||||
|
||||
/*
|
||||
// step one revolution in one direction:
|
||||
Serial.println("clockwise");
|
||||
//myStepper.step(3*stepsPerRevolution);
|
||||
move_x_mm(10);
|
||||
delay(2500);
|
||||
|
||||
// step one revolution in the other direction:
|
||||
Serial.println("counterclockwise");
|
||||
//myStepper.step(-stepsPerRevolution);
|
||||
move_x_mm(-10);
|
||||
delay(2500);
|
||||
*/
|
||||
|
||||
/*
|
||||
int wifi_btn_state = digitalRead(wifi_btn_gpio);
|
||||
if ( wifi_btn_state == HIGH )
|
||||
{
|
||||
digitalWrite(led_gpio, HIGH);
|
||||
delay(200);
|
||||
digitalWrite(led_gpio, LOW);
|
||||
delay(200);
|
||||
digitalWrite(led_gpio, HIGH);
|
||||
delay(200);
|
||||
digitalWrite(led_gpio, LOW);
|
||||
delay(200);
|
||||
digitalWrite(led_gpio, HIGH);
|
||||
delay(200);
|
||||
digitalWrite(led_gpio, LOW);
|
||||
setup_wifi_ap();
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void listen_for_wifi_client(){
|
||||
WiFiClient client = server.available(); // Listen for incoming clients
|
||||
|
||||
if (client) { // If a new client connects,
|
||||
Serial.println("New Client."); // print a message out in the serial port
|
||||
String currentLine = ""; // make a String to hold incoming data from the client
|
||||
while (client.connected()) { // loop while the client's connected
|
||||
if (client.available()) { // if there's bytes to read from the client,
|
||||
char c = client.read(); // read a byte, then
|
||||
Serial.write(c); // print it out the serial monitor
|
||||
header += c;
|
||||
if (c == '\n') { // if the byte is a newline character
|
||||
// if the current line is blank, you got two newline characters in a row.
|
||||
// that's the end of the client HTTP request, so send a response:
|
||||
if (currentLine.length() == 0) {
|
||||
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
|
||||
// and a content-type so the client knows what's coming, then a blank line:
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-type:text/html");
|
||||
client.println("Connection: close");
|
||||
client.println();
|
||||
|
||||
// turns the GPIOs on and off
|
||||
if (header.indexOf("GET /26/on") >= 0) {
|
||||
Serial.println("GPIO 26 on");
|
||||
output26State = "on";
|
||||
digitalWrite(output26, HIGH);
|
||||
} else if (header.indexOf("GET /26/off") >= 0) {
|
||||
Serial.println("GPIO 26 off");
|
||||
output26State = "off";
|
||||
digitalWrite(output26, LOW);
|
||||
} else if (header.indexOf("GET /27/on") >= 0) {
|
||||
Serial.println("GPIO 27 on");
|
||||
output27State = "on";
|
||||
digitalWrite(output27, HIGH);
|
||||
} else if (header.indexOf("GET /27/off") >= 0) {
|
||||
Serial.println("GPIO 27 off");
|
||||
output27State = "off";
|
||||
digitalWrite(output27, LOW);
|
||||
}
|
||||
|
||||
// Display the HTML web page
|
||||
client.println("<!DOCTYPE html><html>");
|
||||
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
|
||||
client.println("<link rel=\"icon\" href=\"data:,\">");
|
||||
// CSS to style the on/off buttons
|
||||
// Feel free to change the background-color and font-size attributes to fit your preferences
|
||||
client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
|
||||
client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
|
||||
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
|
||||
client.println(".button2 {background-color: #555555;}</style></head>");
|
||||
|
||||
// Web Page Heading
|
||||
client.println("<body><h1>ESP32 Web Server</h1>");
|
||||
|
||||
// Display current state, and ON/OFF buttons for GPIO 26
|
||||
client.println("<p>GPIO 26 - State " + output26State + "</p>");
|
||||
// If the output26State is off, it displays the ON button
|
||||
if (output26State=="off") {
|
||||
client.println("<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>");
|
||||
} else {
|
||||
client.println("<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>");
|
||||
}
|
||||
|
||||
// Display current state, and ON/OFF buttons for GPIO 27
|
||||
client.println("<p>GPIO 27 - State " + output27State + "</p>");
|
||||
// If the output27State is off, it displays the ON button
|
||||
if (output27State=="off") {
|
||||
client.println("<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>");
|
||||
} else {
|
||||
client.println("<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>");
|
||||
}
|
||||
client.println("</body></html>");
|
||||
|
||||
// The HTTP response ends with another blank line
|
||||
client.println();
|
||||
// Break out of the while loop
|
||||
break;
|
||||
} else { // if you got a newline, then clear currentLine
|
||||
currentLine = "";
|
||||
}
|
||||
} else if (c != '\r') { // if you got anything else but a carriage return character,
|
||||
currentLine += c; // add it to the end of the currentLine
|
||||
}
|
||||
}
|
||||
}
|
||||
// Clear the header variable
|
||||
header = "";
|
||||
// Close the connection
|
||||
client.stop();
|
||||
Serial.println("Client disconnected.");
|
||||
Serial.println("");
|
||||
}
|
||||
}
|
||||
28
basic_relay_test/basic_relay_test.ino
Normal file
28
basic_relay_test/basic_relay_test.ino
Normal file
@@ -0,0 +1,28 @@
|
||||
/*********
|
||||
Rui Santos
|
||||
Complete project details at https://RandomNerdTutorials.com/esp8266-relay-module-ac-web-server/
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
*********/
|
||||
|
||||
const int relay = 5;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
pinMode(relay, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Normally Open configuration, send LOW signal to let current flow
|
||||
// (if you're usong Normally Closed configuration send HIGH signal)
|
||||
digitalWrite(relay, LOW);
|
||||
Serial.println("Current Flowing");
|
||||
delay(5000);
|
||||
|
||||
// Normally Open configuration, send HIGH signal stop current flow
|
||||
// (if you're usong Normally Closed configuration send LOW signal)
|
||||
digitalWrite(relay, HIGH);
|
||||
Serial.println("Current not Flowing");
|
||||
delay(5000);
|
||||
}
|
||||
19
bluetooth_esp32/bluetooth_esp32.ino
Normal file
19
bluetooth_esp32/bluetooth_esp32.ino
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
SerialBT.begin("ESP32test"); //Name des ESP32
|
||||
Serial.println("Der ESP32 ist bereit. Verbinde dich nun über Bluetooth.");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (Serial.available()) {
|
||||
SerialBT.write(Serial.read());
|
||||
}
|
||||
if (SerialBT.available()) {
|
||||
Serial.write(SerialBT.read());
|
||||
}
|
||||
delay(25);
|
||||
}
|
||||
411
hvst_multi_stepper/hvst_multi_stepper.ino
Normal file
411
hvst_multi_stepper/hvst_multi_stepper.ino
Normal file
@@ -0,0 +1,411 @@
|
||||
|
||||
/*
|
||||
Stepper Motor Control - one revolution
|
||||
|
||||
This program drives a unipolar or bipolar stepper motor.
|
||||
The motor is attached to digital pins 8 - 11 of the Arduino.
|
||||
|
||||
The motor should revolve one revolution in one direction, then
|
||||
one revolution in the other direction.
|
||||
|
||||
|
||||
Created 11 Mar. 2007
|
||||
Modified 30 Nov. 2009
|
||||
by Tom Igoe
|
||||
|
||||
*/
|
||||
|
||||
#include <Preferences.h>
|
||||
#include <AccelStepper.h>
|
||||
#include <MultiStepper.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
|
||||
const int stepsPerRevolution = 2*2*1600; // change this to fit the number of steps per revolution
|
||||
// for your motor
|
||||
const float lead = 3.0; // Steigung in mm
|
||||
|
||||
// PINs
|
||||
const unsigned int STEPPER_1_PULSE_GPIO = 25;
|
||||
const unsigned int STEPPER_1_DIR_GPIO = 33;
|
||||
|
||||
const unsigned int STEPPER_2_PULSE_GPIO = 99;
|
||||
const unsigned int STEPPER_2_DIR_GPIO = 99;
|
||||
|
||||
const int butten_down_up_analog_read = 34;
|
||||
const int led_gpio = 32;
|
||||
const int button_down_gpio = 35;
|
||||
const int button_up_gpio = 34;
|
||||
const int relais_gpio = 13;
|
||||
const int wifi_btn_gpio = 14;
|
||||
|
||||
const int power_led_gpio = 27;
|
||||
|
||||
// power relais control
|
||||
long power_off_timer = 0;
|
||||
const long power_off_timeout = 5*1000; // switch off power after 3 seconds
|
||||
|
||||
bool power_enabled = false;
|
||||
|
||||
|
||||
// stepper positions / dir / endstops
|
||||
long current_stepper_position = 0; // must be loaded from persisted data; reseted by endstop(s)
|
||||
|
||||
|
||||
////////// WIFI Krempel
|
||||
// Replace with your network credentials
|
||||
const char* ssid = "ESP32-Access-Point";
|
||||
const char* password = "123456789";
|
||||
|
||||
// Set web server port number to 80
|
||||
WiFiServer server(80);
|
||||
|
||||
// Variable to store the HTTP request
|
||||
String header;
|
||||
|
||||
|
||||
// Auxiliar variables to store the current output state
|
||||
String output26State = "off";
|
||||
String output27State = "off";
|
||||
|
||||
// Assign output variables to GPIO pins
|
||||
const int output26 = 26;
|
||||
const int output27 = 27;
|
||||
////////// WIFI Krempel
|
||||
|
||||
|
||||
///// Persisted Data (Preferences)
|
||||
Preferences preferences;
|
||||
|
||||
|
||||
|
||||
//struct PersistedData{
|
||||
// long last_position;
|
||||
// int initialized_magic_number; // set to a predifend value AFTER initialization of memory was done, indicating successfull initialization
|
||||
// char ssid[64];
|
||||
// char wifi_pw[32];
|
||||
//};
|
||||
|
||||
|
||||
void load_persisted_data(){
|
||||
|
||||
//EEPROM.get( eeAddress, p_data );
|
||||
Serial.println( "Read custom object from EEPROM: " );
|
||||
Serial.println( preferences.getLong("last_position") );
|
||||
Serial.println( preferences.getInt("initialized_magic_number") );
|
||||
Serial.println( preferences.getString("ssid") );
|
||||
Serial.println( preferences.getString("wifi_pw") );
|
||||
}
|
||||
|
||||
void calibrate(){
|
||||
|
||||
}
|
||||
|
||||
// initialize the stepper library on pins 8 through 11:
|
||||
//Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);
|
||||
//Stepper myStepper(stepsPerRevolution, stepper_1_pulse_gpio, stepper_1_dir_gpio);
|
||||
|
||||
AccelStepper stepper1(AccelStepper::DRIVER, STEPPER_1_PULSE_GPIO, STEPPER_1_DIR_GPIO);
|
||||
AccelStepper stepper2(AccelStepper::DRIVER, STEPPER_2_PULSE_GPIO, STEPPER_2_DIR_GPIO);
|
||||
// Up to 10 steppers can be handled as a group by MultiStepper
|
||||
MultiStepper steppers;
|
||||
|
||||
void setup_steppers(){
|
||||
// set the speed at 60 rpm:
|
||||
//myStepper.setSpeed(120);
|
||||
|
||||
// Configure each stepper
|
||||
stepper1.setMaxSpeed(stepsPerRevolution);
|
||||
stepper2.setMaxSpeed(stepsPerRevolution);
|
||||
// Then give them to MultiStepper to manage
|
||||
steppers.addStepper(stepper1);
|
||||
steppers.addStepper(stepper2);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
preferences.begin("hvst", false);
|
||||
load_persisted_data();
|
||||
setup_steppers();
|
||||
pinMode(led_gpio, OUTPUT);
|
||||
pinMode(power_led_gpio, OUTPUT);
|
||||
//pinMode(button_down_gpio, INPUT_PULLDOWN); // for analog read not required
|
||||
//pinMode(button_up_gpio, INPUT_PULLDOWN); // for analog read not required
|
||||
pinMode(relais_gpio, OUTPUT);
|
||||
pinMode(wifi_btn_gpio, INPUT);
|
||||
disable_power();
|
||||
|
||||
// initialize the serial port:
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
|
||||
void do_test(){
|
||||
Serial.print("Setting LED to LOW");
|
||||
digitalWrite(power_led_gpio, LOW);
|
||||
delay(5000);
|
||||
Serial.print("Setting LED to HIGH");
|
||||
digitalWrite(power_led_gpio, HIGH);
|
||||
delay(5000);
|
||||
|
||||
}
|
||||
|
||||
void setup_wifi_ap(){
|
||||
// Connect to Wi-Fi network with SSID and password
|
||||
Serial.print("Setting AP (Access Point)…");
|
||||
// Remove the password parameter, if you want the AP (Access Point) to be open
|
||||
WiFi.softAP(ssid, password);
|
||||
|
||||
IPAddress IP = WiFi.softAPIP();
|
||||
Serial.print("AP IP address: ");
|
||||
Serial.println(IP);
|
||||
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void move_x_mm(int x) {
|
||||
digitalWrite(led_gpio, HIGH);
|
||||
Serial.println(x);
|
||||
Serial.println(x/lead);
|
||||
//myStepper.step(x/lead*stepsPerRevolution);
|
||||
long steps = x/lead*stepsPerRevolution;
|
||||
current_stepper_position + steps;
|
||||
long positions[2];
|
||||
positions[0] = current_stepper_position;
|
||||
positions[1] = current_stepper_position;
|
||||
steppers.moveTo(positions);
|
||||
steppers.runSpeedToPosition(); // blocking call; alternative might be just run...
|
||||
digitalWrite(led_gpio, LOW);
|
||||
}
|
||||
|
||||
void enable_power() {
|
||||
if(!power_enabled) {
|
||||
digitalWrite(relais_gpio, HIGH);
|
||||
digitalWrite(power_led_gpio, HIGH);
|
||||
Serial.println("enable relais");
|
||||
delay(500);
|
||||
power_enabled = true;
|
||||
}
|
||||
power_off_timer = millis();
|
||||
}
|
||||
void disable_power() {
|
||||
Serial.println("disable relais");
|
||||
digitalWrite(relais_gpio, LOW);
|
||||
digitalWrite(power_led_gpio, LOW);
|
||||
power_enabled = false;
|
||||
}
|
||||
|
||||
void _test_stepper(){
|
||||
//Wdo_test();
|
||||
//listen_for_wifi_client();
|
||||
//enable_power();
|
||||
//delay(2000);
|
||||
move_x_mm(10*3);
|
||||
//disable_power();
|
||||
delay(3000);
|
||||
move_x_mm(-3*10);
|
||||
delay(3000);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.println("load_persisted_data();");
|
||||
load_persisted_data();
|
||||
Serial.println("data loaded;");
|
||||
delay(1000);
|
||||
//_test_stepper();
|
||||
|
||||
long positions[2]; // Array of desired stepper positions
|
||||
|
||||
positions[0] = 1000;
|
||||
positions[1] = 50;
|
||||
steppers.moveTo(positions);
|
||||
steppers.runSpeedToPosition(); // Blocks until all are in position
|
||||
delay(1000);
|
||||
|
||||
|
||||
if(millis() > power_off_timer + power_off_timeout && power_enabled){
|
||||
disable_power();
|
||||
}
|
||||
|
||||
int up_down_btn_val = analogRead(butten_down_up_analog_read);
|
||||
|
||||
|
||||
//delay(100);
|
||||
if (up_down_btn_val > 150 && up_down_btn_val < 300) {
|
||||
enable_power();
|
||||
move_x_mm(2);
|
||||
}
|
||||
else if (up_down_btn_val > 1800 && up_down_btn_val < 2050) {
|
||||
enable_power();
|
||||
move_x_mm(-2);
|
||||
}
|
||||
else if (up_down_btn_val > 0) {
|
||||
char format[] = "Btn Val=\"%d\"";
|
||||
char txt[50] = "";
|
||||
sprintf(txt,format,up_down_btn_val);
|
||||
Serial.println(txt);
|
||||
}
|
||||
|
||||
int up_button_state = digitalRead(button_up_gpio);
|
||||
//Serial.println(up_button_state);
|
||||
if ( up_button_state == HIGH )
|
||||
{
|
||||
enable_power();
|
||||
move_x_mm(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//disable_power();
|
||||
}
|
||||
int down_button_state = digitalRead(button_down_gpio);
|
||||
//Serial.println(down_button_state);
|
||||
if ( down_button_state == HIGH )
|
||||
{
|
||||
enable_power();
|
||||
move_x_mm(-2);
|
||||
}
|
||||
else
|
||||
{
|
||||
//disable_power();
|
||||
}
|
||||
//delay(10);
|
||||
|
||||
/*
|
||||
Serial.println("on");
|
||||
digitalWrite(led_gpio, HIGH); // turn the LED on (HIGH is the voltage level)
|
||||
delay(1000); // wait for a second
|
||||
Serial.println("off");
|
||||
digitalWrite(led_gpio, LOW); // turn the LED off by making the voltage LOW
|
||||
delay(1000); // wait for a second
|
||||
*/
|
||||
|
||||
/*
|
||||
// step one revolution in one direction:
|
||||
Serial.println("clockwise");
|
||||
//myStepper.step(3*stepsPerRevolution);
|
||||
move_x_mm(10);
|
||||
delay(2500);
|
||||
|
||||
// step one revolution in the other direction:
|
||||
Serial.println("counterclockwise");
|
||||
//myStepper.step(-stepsPerRevolution);
|
||||
move_x_mm(-10);
|
||||
delay(2500);
|
||||
*/
|
||||
|
||||
/*
|
||||
int wifi_btn_state = digitalRead(wifi_btn_gpio);
|
||||
if ( wifi_btn_state == HIGH )
|
||||
{
|
||||
digitalWrite(led_gpio, HIGH);
|
||||
delay(200);
|
||||
digitalWrite(led_gpio, LOW);
|
||||
delay(200);
|
||||
digitalWrite(led_gpio, HIGH);
|
||||
delay(200);
|
||||
digitalWrite(led_gpio, LOW);
|
||||
delay(200);
|
||||
digitalWrite(led_gpio, HIGH);
|
||||
delay(200);
|
||||
digitalWrite(led_gpio, LOW);
|
||||
setup_wifi_ap();
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void listen_for_wifi_client(){
|
||||
WiFiClient client = server.available(); // Listen for incoming clients
|
||||
|
||||
if (client) { // If a new client connects,
|
||||
Serial.println("New Client."); // print a message out in the serial port
|
||||
String currentLine = ""; // make a String to hold incoming data from the client
|
||||
while (client.connected()) { // loop while the client's connected
|
||||
if (client.available()) { // if there's bytes to read from the client,
|
||||
char c = client.read(); // read a byte, then
|
||||
Serial.write(c); // print it out the serial monitor
|
||||
header += c;
|
||||
if (c == '\n') { // if the byte is a newline character
|
||||
// if the current line is blank, you got two newline characters in a row.
|
||||
// that's the end of the client HTTP request, so send a response:
|
||||
if (currentLine.length() == 0) {
|
||||
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
|
||||
// and a content-type so the client knows what's coming, then a blank line:
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-type:text/html");
|
||||
client.println("Connection: close");
|
||||
client.println();
|
||||
|
||||
// turns the GPIOs on and off
|
||||
if (header.indexOf("GET /26/on") >= 0) {
|
||||
Serial.println("GPIO 26 on");
|
||||
output26State = "on";
|
||||
digitalWrite(output26, HIGH);
|
||||
} else if (header.indexOf("GET /26/off") >= 0) {
|
||||
Serial.println("GPIO 26 off");
|
||||
output26State = "off";
|
||||
digitalWrite(output26, LOW);
|
||||
} else if (header.indexOf("GET /27/on") >= 0) {
|
||||
Serial.println("GPIO 27 on");
|
||||
output27State = "on";
|
||||
digitalWrite(output27, HIGH);
|
||||
} else if (header.indexOf("GET /27/off") >= 0) {
|
||||
Serial.println("GPIO 27 off");
|
||||
output27State = "off";
|
||||
digitalWrite(output27, LOW);
|
||||
}
|
||||
|
||||
// Display the HTML web page
|
||||
client.println("<!DOCTYPE html><html>");
|
||||
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
|
||||
client.println("<link rel=\"icon\" href=\"data:,\">");
|
||||
// CSS to style the on/off buttons
|
||||
// Feel free to change the background-color and font-size attributes to fit your preferences
|
||||
client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
|
||||
client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
|
||||
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
|
||||
client.println(".button2 {background-color: #555555;}</style></head>");
|
||||
|
||||
// Web Page Heading
|
||||
client.println("<body><h1>ESP32 Web Server</h1>");
|
||||
|
||||
// Display current state, and ON/OFF buttons for GPIO 26
|
||||
client.println("<p>GPIO 26 - State " + output26State + "</p>");
|
||||
// If the output26State is off, it displays the ON button
|
||||
if (output26State=="off") {
|
||||
client.println("<p><a href=\"/26/on\"><button class=\"button\">ON</button></a></p>");
|
||||
} else {
|
||||
client.println("<p><a href=\"/26/off\"><button class=\"button button2\">OFF</button></a></p>");
|
||||
}
|
||||
|
||||
// Display current state, and ON/OFF buttons for GPIO 27
|
||||
client.println("<p>GPIO 27 - State " + output27State + "</p>");
|
||||
// If the output27State is off, it displays the ON button
|
||||
if (output27State=="off") {
|
||||
client.println("<p><a href=\"/27/on\"><button class=\"button\">ON</button></a></p>");
|
||||
} else {
|
||||
client.println("<p><a href=\"/27/off\"><button class=\"button button2\">OFF</button></a></p>");
|
||||
}
|
||||
client.println("</body></html>");
|
||||
|
||||
// The HTTP response ends with another blank line
|
||||
client.println();
|
||||
// Break out of the while loop
|
||||
break;
|
||||
} else { // if you got a newline, then clear currentLine
|
||||
currentLine = "";
|
||||
}
|
||||
} else if (c != '\r') { // if you got anything else but a carriage return character,
|
||||
currentLine += c; // add it to the end of the currentLine
|
||||
}
|
||||
}
|
||||
}
|
||||
// Clear the header variable
|
||||
header = "";
|
||||
// Close the connection
|
||||
client.stop();
|
||||
Serial.println("Client disconnected.");
|
||||
Serial.println("");
|
||||
}
|
||||
}
|
||||
17
libraries/AccelStepper/LICENSE
Normal file
17
libraries/AccelStepper/LICENSE
Normal file
@@ -0,0 +1,17 @@
|
||||
This software is Copyright (C) 2008 Mike McCauley. Use is subject to license
|
||||
conditions. The main licensing options available are GPL V3 or Commercial:
|
||||
|
||||
Open Source Licensing GPL V3
|
||||
|
||||
This is the appropriate option if you want to share the source code of your
|
||||
application with everyone you distribute it to, and you also want to give them
|
||||
the right to share who uses it. If you wish to use this software under Open
|
||||
Source Licensing, you must contribute all your source code to the open source
|
||||
community in accordance with the GPL Version 3 when your application is
|
||||
distributed. See http://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
Commercial Licensing
|
||||
|
||||
This is the appropriate option if you are creating proprietary applications
|
||||
and you are not prepared to distribute and share the source code of your
|
||||
application. Contact info@open.com.au for details.
|
||||
22
libraries/AccelStepper/README.md
Normal file
22
libraries/AccelStepper/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
This fork follows the [upstream version](http://www.airspayce.com/mikem/arduino/AccelStepper/). Files are slightly reorganized to follow Arduino library conventions to allow for inclusion into the Arduino IDE library manager.
|
||||
|
||||
Please direct questions and discussion to http://groups.google.com/group/accelstepper
|
||||
|
||||
---
|
||||
|
||||
This is the Arduino AccelStepper library. It provides an object-oriented interface for 2, 3 or 4 pin stepper motors and motor drivers.
|
||||
|
||||
The standard Arduino IDE includes the Stepper library (http://arduino.cc/en/Reference/Stepper) for stepper motors. It is perfectly adequate for simple, single motor applications.
|
||||
|
||||
AccelStepper significantly improves on the standard Arduino Stepper library in several ways:
|
||||
|
||||
- Supports acceleration and deceleration
|
||||
- Supports multiple simultaneous steppers, with independent concurrent stepping on each stepper
|
||||
- API functions never delay() or block
|
||||
- Supports 2, 3 and 4 wire steppers, plus 3 and 4 wire half steppers.
|
||||
- Supports alternate stepping functions to enable support of AFMotor (https://github.com/adafruit/Adafruit-Motor-Shield-library)
|
||||
- Supports stepper drivers such as the Sparkfun EasyDriver (based on 3967 driver chip)
|
||||
- Very slow speeds are supported
|
||||
- Extensive API
|
||||
- Subclass support
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// AFMotor_ConstantSpeed.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Shows how to run AccelStepper in the simplest,
|
||||
// fixed speed mode with no accelerations
|
||||
// Requires the AFMotor library
|
||||
// (https://github.com/adafruit/Adafruit-Motor-Shield-library)
|
||||
// Caution, does not work with Adafruit Motor Shield V2
|
||||
// See https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library
|
||||
// for examples that work with Adafruit Motor Shield V2.
|
||||
|
||||
#include <AccelStepper.h>
|
||||
#include <AFMotor.h>
|
||||
|
||||
AF_Stepper motor1(200, 1);
|
||||
|
||||
|
||||
// you can change these to DOUBLE or INTERLEAVE or MICROSTEP!
|
||||
void forwardstep() {
|
||||
motor1.onestep(FORWARD, SINGLE);
|
||||
}
|
||||
void backwardstep() {
|
||||
motor1.onestep(BACKWARD, SINGLE);
|
||||
}
|
||||
|
||||
AccelStepper stepper(forwardstep, backwardstep); // use functions to step
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600); // set up Serial library at 9600 bps
|
||||
Serial.println("Stepper test!");
|
||||
|
||||
stepper.setMaxSpeed(50);
|
||||
stepper.setSpeed(50);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
stepper.runSpeed();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// AFMotor_MultiStepper.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Control both Stepper motors at the same time with different speeds
|
||||
// and accelerations.
|
||||
// Requires the AFMotor library (https://github.com/adafruit/Adafruit-Motor-Shield-library)
|
||||
// Caution, does not work with Adafruit Motor Shield V2
|
||||
// See https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library
|
||||
// for examples that work with Adafruit Motor Shield V2.
|
||||
|
||||
#include <AccelStepper.h>
|
||||
#include <AFMotor.h>
|
||||
|
||||
// two stepper motors one on each port
|
||||
AF_Stepper motor1(200, 1);
|
||||
AF_Stepper motor2(200, 2);
|
||||
|
||||
// you can change these to DOUBLE or INTERLEAVE or MICROSTEP!
|
||||
// wrappers for the first motor!
|
||||
void forwardstep1() {
|
||||
motor1.onestep(FORWARD, SINGLE);
|
||||
}
|
||||
void backwardstep1() {
|
||||
motor1.onestep(BACKWARD, SINGLE);
|
||||
}
|
||||
// wrappers for the second motor!
|
||||
void forwardstep2() {
|
||||
motor2.onestep(FORWARD, SINGLE);
|
||||
}
|
||||
void backwardstep2() {
|
||||
motor2.onestep(BACKWARD, SINGLE);
|
||||
}
|
||||
|
||||
// Motor shield has two motor ports, now we'll wrap them in an AccelStepper object
|
||||
AccelStepper stepper1(forwardstep1, backwardstep1);
|
||||
AccelStepper stepper2(forwardstep2, backwardstep2);
|
||||
|
||||
void setup()
|
||||
{
|
||||
stepper1.setMaxSpeed(200.0);
|
||||
stepper1.setAcceleration(100.0);
|
||||
stepper1.moveTo(24);
|
||||
|
||||
stepper2.setMaxSpeed(300.0);
|
||||
stepper2.setAcceleration(100.0);
|
||||
stepper2.moveTo(1000000);
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Change direction at the limits
|
||||
if (stepper1.distanceToGo() == 0)
|
||||
stepper1.moveTo(-stepper1.currentPosition());
|
||||
stepper1.run();
|
||||
stepper2.run();
|
||||
}
|
||||
28
libraries/AccelStepper/examples/Blocking/Blocking.pde
Normal file
28
libraries/AccelStepper/examples/Blocking/Blocking.pde
Normal file
@@ -0,0 +1,28 @@
|
||||
// Blocking.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Shows how to use the blocking call runToNewPosition
|
||||
// Which sets a new target position and then waits until the stepper has
|
||||
// achieved it.
|
||||
//
|
||||
// Copyright (C) 2009 Mike McCauley
|
||||
// $Id: Blocking.pde,v 1.1 2011/01/05 01:51:01 mikem Exp mikem $
|
||||
|
||||
#include <AccelStepper.h>
|
||||
|
||||
// Define a stepper and the pins it will use
|
||||
AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
|
||||
|
||||
void setup()
|
||||
{
|
||||
stepper.setMaxSpeed(200.0);
|
||||
stepper.setAcceleration(100.0);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
stepper.runToNewPosition(0);
|
||||
stepper.runToNewPosition(500);
|
||||
stepper.runToNewPosition(100);
|
||||
stepper.runToNewPosition(120);
|
||||
}
|
||||
29
libraries/AccelStepper/examples/Bounce/Bounce.pde
Normal file
29
libraries/AccelStepper/examples/Bounce/Bounce.pde
Normal file
@@ -0,0 +1,29 @@
|
||||
// Bounce.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Make a single stepper bounce from one limit to another
|
||||
//
|
||||
// Copyright (C) 2012 Mike McCauley
|
||||
// $Id: Random.pde,v 1.1 2011/01/05 01:51:01 mikem Exp mikem $
|
||||
|
||||
#include <AccelStepper.h>
|
||||
|
||||
// Define a stepper and the pins it will use
|
||||
AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Change these to suit your stepper if you want
|
||||
stepper.setMaxSpeed(100);
|
||||
stepper.setAcceleration(20);
|
||||
stepper.moveTo(500);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// If at the end of travel go to the other end
|
||||
if (stepper.distanceToGo() == 0)
|
||||
stepper.moveTo(-stepper.currentPosition());
|
||||
|
||||
stepper.run();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// ConstantSpeed.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Shows how to run AccelStepper in the simplest,
|
||||
// fixed speed mode with no accelerations
|
||||
/// \author Mike McCauley (mikem@airspayce.com)
|
||||
// Copyright (C) 2009 Mike McCauley
|
||||
// $Id: ConstantSpeed.pde,v 1.1 2011/01/05 01:51:01 mikem Exp mikem $
|
||||
|
||||
#include <AccelStepper.h>
|
||||
|
||||
AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
|
||||
|
||||
void setup()
|
||||
{
|
||||
stepper.setMaxSpeed(1000);
|
||||
stepper.setSpeed(50);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
stepper.runSpeed();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// DualMotorShield.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Shows how to run 2 simultaneous steppers
|
||||
// using the Itead Studio Arduino Dual Stepper Motor Driver Shield
|
||||
// model IM120417015
|
||||
// This shield is capable of driving 2 steppers at
|
||||
// currents of up to 750mA
|
||||
// and voltages up to 30V
|
||||
// Runs both steppers forwards and backwards, accelerating and decelerating
|
||||
// at the limits.
|
||||
//
|
||||
// Copyright (C) 2014 Mike McCauley
|
||||
// $Id: $
|
||||
|
||||
#include <AccelStepper.h>
|
||||
|
||||
// The X Stepper pins
|
||||
#define STEPPER1_DIR_PIN 3
|
||||
#define STEPPER1_STEP_PIN 2
|
||||
// The Y stepper pins
|
||||
#define STEPPER2_DIR_PIN 7
|
||||
#define STEPPER2_STEP_PIN 6
|
||||
|
||||
// Define some steppers and the pins the will use
|
||||
AccelStepper stepper1(AccelStepper::DRIVER, STEPPER1_STEP_PIN, STEPPER1_DIR_PIN);
|
||||
AccelStepper stepper2(AccelStepper::DRIVER, STEPPER2_STEP_PIN, STEPPER2_DIR_PIN);
|
||||
|
||||
void setup()
|
||||
{
|
||||
stepper1.setMaxSpeed(200.0);
|
||||
stepper1.setAcceleration(200.0);
|
||||
stepper1.moveTo(100);
|
||||
|
||||
stepper2.setMaxSpeed(100.0);
|
||||
stepper2.setAcceleration(100.0);
|
||||
stepper2.moveTo(100);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Change direction at the limits
|
||||
if (stepper1.distanceToGo() == 0)
|
||||
stepper1.moveTo(-stepper1.currentPosition());
|
||||
if (stepper2.distanceToGo() == 0)
|
||||
stepper2.moveTo(-stepper2.currentPosition());
|
||||
stepper1.run();
|
||||
stepper2.run();
|
||||
}
|
||||
103
libraries/AccelStepper/examples/MotorShield/MotorShield.pde
Normal file
103
libraries/AccelStepper/examples/MotorShield/MotorShield.pde
Normal file
@@ -0,0 +1,103 @@
|
||||
// AFMotor_ConstantSpeed.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Shows how to use AccelStepper to control a 3-phase motor, such as a HDD spindle motor
|
||||
// using the Adafruit Motor Shield
|
||||
// http://www.ladyada.net/make/mshield/index.html.
|
||||
// Create a subclass of AccelStepper which controls the motor pins via the
|
||||
// Motor Shield serial-to-parallel interface
|
||||
|
||||
#include <AccelStepper.h>
|
||||
|
||||
// Arduino pin names for interface to 74HCT595 latch
|
||||
// on Adafruit Motor Shield
|
||||
#define MOTORLATCH 12
|
||||
#define MOTORCLK 4
|
||||
#define MOTORENABLE 7
|
||||
#define MOTORDATA 8
|
||||
|
||||
// PWM pins, also used to enable motor outputs
|
||||
#define PWM0A 5
|
||||
#define PWM0B 6
|
||||
#define PWM1A 9
|
||||
#define PWM1B 10
|
||||
#define PWM2A 11
|
||||
#define PWM2B 3
|
||||
|
||||
|
||||
// The main purpose of this class is to override setOutputPins to work with Adafruit Motor Shield
|
||||
class AFMotorShield : public AccelStepper
|
||||
{
|
||||
public:
|
||||
AFMotorShield(uint8_t interface = AccelStepper::FULL4WIRE, uint8_t pin1 = 2, uint8_t pin2 = 3, uint8_t pin3 = 4, uint8_t pin4 = 5);
|
||||
|
||||
virtual void setOutputPins(uint8_t mask);
|
||||
};
|
||||
|
||||
|
||||
AFMotorShield::AFMotorShield(uint8_t interface, uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4)
|
||||
: AccelStepper(interface, pin1, pin2, pin3, pin4)
|
||||
{
|
||||
// Enable motor control serial to parallel latch
|
||||
pinMode(MOTORLATCH, OUTPUT);
|
||||
pinMode(MOTORENABLE, OUTPUT);
|
||||
pinMode(MOTORDATA, OUTPUT);
|
||||
pinMode(MOTORCLK, OUTPUT);
|
||||
digitalWrite(MOTORENABLE, LOW);
|
||||
|
||||
// enable both H bridges on motor 1
|
||||
pinMode(PWM2A, OUTPUT);
|
||||
pinMode(PWM2B, OUTPUT);
|
||||
pinMode(PWM0A, OUTPUT);
|
||||
pinMode(PWM0B, OUTPUT);
|
||||
digitalWrite(PWM2A, HIGH);
|
||||
digitalWrite(PWM2B, HIGH);
|
||||
digitalWrite(PWM0A, HIGH);
|
||||
digitalWrite(PWM0B, HIGH);
|
||||
|
||||
setOutputPins(0); // Reset
|
||||
};
|
||||
|
||||
// Use the AF Motor Shield serial-to-parallel to set the state of the motor pins
|
||||
// Caution: the mapping of AccelStepper pins to AF motor outputs is not
|
||||
// obvious:
|
||||
// AccelStepper Motor Shield output
|
||||
// pin1 M4A
|
||||
// pin2 M1A
|
||||
// pin3 M2A
|
||||
// pin4 M3A
|
||||
// Caution this is pretty slow and limits the max speed of the motor to about 500/3 rpm
|
||||
void AFMotorShield::setOutputPins(uint8_t mask)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
digitalWrite(MOTORLATCH, LOW);
|
||||
digitalWrite(MOTORDATA, LOW);
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
digitalWrite(MOTORCLK, LOW);
|
||||
|
||||
if (mask & _BV(7-i))
|
||||
digitalWrite(MOTORDATA, HIGH);
|
||||
else
|
||||
digitalWrite(MOTORDATA, LOW);
|
||||
|
||||
digitalWrite(MOTORCLK, HIGH);
|
||||
}
|
||||
digitalWrite(MOTORLATCH, HIGH);
|
||||
}
|
||||
|
||||
AFMotorShield stepper(AccelStepper::HALF3WIRE, 0, 0, 0, 0); // 3 phase HDD spindle drive
|
||||
|
||||
void setup()
|
||||
{
|
||||
stepper.setMaxSpeed(500); // divide by 3 to get rpm
|
||||
stepper.setAcceleration(80);
|
||||
stepper.moveTo(10000000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
stepper.run();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// MultiStepper.pde
|
||||
// -*- mode: C++ -*-
|
||||
// Use MultiStepper class to manage multiple steppers and make them all move to
|
||||
// the same position at the same time for linear 2d (or 3d) motion.
|
||||
|
||||
#include <AccelStepper.h>
|
||||
#include <MultiStepper.h>
|
||||
|
||||
// EG X-Y position bed driven by 2 steppers
|
||||
// Alas its not possible to build an array of these with different pins for each :-(
|
||||
AccelStepper stepper1(AccelStepper::FULL4WIRE, 2, 3, 4, 5);
|
||||
AccelStepper stepper2(AccelStepper::FULL4WIRE, 8, 9, 10, 11);
|
||||
|
||||
// Up to 10 steppers can be handled as a group by MultiStepper
|
||||
MultiStepper steppers;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// Configure each stepper
|
||||
stepper1.setMaxSpeed(100);
|
||||
stepper2.setMaxSpeed(100);
|
||||
|
||||
// Then give them to MultiStepper to manage
|
||||
steppers.addStepper(stepper1);
|
||||
steppers.addStepper(stepper2);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
long positions[2]; // Array of desired stepper positions
|
||||
|
||||
positions[0] = 1000;
|
||||
positions[1] = 50;
|
||||
steppers.moveTo(positions);
|
||||
steppers.runSpeedToPosition(); // Blocks until all are in position
|
||||
delay(1000);
|
||||
|
||||
// Move to a different coordinate
|
||||
positions[0] = -100;
|
||||
positions[1] = 100;
|
||||
steppers.moveTo(positions);
|
||||
steppers.runSpeedToPosition(); // Blocks until all are in position
|
||||
delay(1000);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// MultiStepper.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Shows how to multiple simultaneous steppers
|
||||
// Runs one stepper forwards and backwards, accelerating and decelerating
|
||||
// at the limits. Runs other steppers at the same time
|
||||
//
|
||||
// Copyright (C) 2009 Mike McCauley
|
||||
// $Id: MultiStepper.pde,v 1.1 2011/01/05 01:51:01 mikem Exp mikem $
|
||||
|
||||
#include <AccelStepper.h>
|
||||
|
||||
// Define some steppers and the pins the will use
|
||||
AccelStepper stepper1; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
|
||||
AccelStepper stepper2(AccelStepper::FULL4WIRE, 6, 7, 8, 9);
|
||||
AccelStepper stepper3(AccelStepper::FULL2WIRE, 10, 11);
|
||||
|
||||
void setup()
|
||||
{
|
||||
stepper1.setMaxSpeed(200.0);
|
||||
stepper1.setAcceleration(100.0);
|
||||
stepper1.moveTo(24);
|
||||
|
||||
stepper2.setMaxSpeed(300.0);
|
||||
stepper2.setAcceleration(100.0);
|
||||
stepper2.moveTo(1000000);
|
||||
|
||||
stepper3.setMaxSpeed(300.0);
|
||||
stepper3.setAcceleration(100.0);
|
||||
stepper3.moveTo(1000000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Change direction at the limits
|
||||
if (stepper1.distanceToGo() == 0)
|
||||
stepper1.moveTo(-stepper1.currentPosition());
|
||||
stepper1.run();
|
||||
stepper2.run();
|
||||
stepper3.run();
|
||||
}
|
||||
28
libraries/AccelStepper/examples/Overshoot/Overshoot.pde
Normal file
28
libraries/AccelStepper/examples/Overshoot/Overshoot.pde
Normal file
@@ -0,0 +1,28 @@
|
||||
// Overshoot.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Check overshoot handling
|
||||
// which sets a new target position and then waits until the stepper has
|
||||
// achieved it. This is used for testing the handling of overshoots
|
||||
//
|
||||
// Copyright (C) 2009 Mike McCauley
|
||||
// $Id: Overshoot.pde,v 1.1 2011/01/05 01:51:01 mikem Exp mikem $
|
||||
|
||||
#include <AccelStepper.h>
|
||||
|
||||
// Define a stepper and the pins it will use
|
||||
AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
|
||||
|
||||
void setup()
|
||||
{
|
||||
stepper.setMaxSpeed(150);
|
||||
stepper.setAcceleration(100);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
stepper.moveTo(500);
|
||||
while (stepper.currentPosition() != 300) // Full speed up to 300
|
||||
stepper.run();
|
||||
stepper.runToNewPosition(0); // Cause an overshoot then back to 0
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// ProportionalControl.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Make a single stepper follow the analog value read from a pot or whatever
|
||||
// The stepper will move at a constant speed to each newly set posiiton,
|
||||
// depending on the value of the pot.
|
||||
//
|
||||
// Copyright (C) 2012 Mike McCauley
|
||||
// $Id: ProportionalControl.pde,v 1.1 2011/01/05 01:51:01 mikem Exp mikem $
|
||||
|
||||
#include <AccelStepper.h>
|
||||
|
||||
// Define a stepper and the pins it will use
|
||||
AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
|
||||
|
||||
// This defines the analog input pin for reading the control voltage
|
||||
// Tested with a 10k linear pot between 5v and GND
|
||||
#define ANALOG_IN A0
|
||||
|
||||
void setup()
|
||||
{
|
||||
stepper.setMaxSpeed(1000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Read new position
|
||||
int analog_in = analogRead(ANALOG_IN);
|
||||
stepper.moveTo(analog_in);
|
||||
stepper.setSpeed(100);
|
||||
stepper.runSpeedToPosition();
|
||||
}
|
||||
40
libraries/AccelStepper/examples/Quickstop/Quickstop.pde
Normal file
40
libraries/AccelStepper/examples/Quickstop/Quickstop.pde
Normal file
@@ -0,0 +1,40 @@
|
||||
// Quickstop.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Check stop handling.
|
||||
// Calls stop() while the stepper is travelling at full speed, causing
|
||||
// the stepper to stop as quickly as possible, within the constraints of the
|
||||
// current acceleration.
|
||||
//
|
||||
// Copyright (C) 2012 Mike McCauley
|
||||
// $Id: $
|
||||
|
||||
#include <AccelStepper.h>
|
||||
|
||||
// Define a stepper and the pins it will use
|
||||
AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
|
||||
|
||||
void setup()
|
||||
{
|
||||
stepper.setMaxSpeed(150);
|
||||
stepper.setAcceleration(100);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
stepper.moveTo(500);
|
||||
while (stepper.currentPosition() != 300) // Full speed up to 300
|
||||
stepper.run();
|
||||
stepper.stop(); // Stop as fast as possible: sets new target
|
||||
stepper.runToPosition();
|
||||
// Now stopped after quickstop
|
||||
|
||||
// Now go backwards
|
||||
stepper.moveTo(-500);
|
||||
while (stepper.currentPosition() != 0) // Full speed basck to 0
|
||||
stepper.run();
|
||||
stepper.stop(); // Stop as fast as possible: sets new target
|
||||
stepper.runToPosition();
|
||||
// Now stopped after quickstop
|
||||
|
||||
}
|
||||
30
libraries/AccelStepper/examples/Random/Random.pde
Normal file
30
libraries/AccelStepper/examples/Random/Random.pde
Normal file
@@ -0,0 +1,30 @@
|
||||
// Random.pde
|
||||
// -*- mode: C++ -*-
|
||||
//
|
||||
// Make a single stepper perform random changes in speed, position and acceleration
|
||||
//
|
||||
// Copyright (C) 2009 Mike McCauley
|
||||
// $Id: Random.pde,v 1.1 2011/01/05 01:51:01 mikem Exp mikem $
|
||||
|
||||
#include <AccelStepper.h>
|
||||
|
||||
// Define a stepper and the pins it will use
|
||||
AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
|
||||
|
||||
void setup()
|
||||
{
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (stepper.distanceToGo() == 0)
|
||||
{
|
||||
// Random change to speed, position and acceleration
|
||||
// Make sure we dont get 0 speed or accelerations
|
||||
delay(1000);
|
||||
stepper.moveTo(rand() % 200);
|
||||
stepper.setMaxSpeed((rand() % 200) + 1);
|
||||
stepper.setAcceleration((rand() % 200) + 1);
|
||||
}
|
||||
stepper.run();
|
||||
}
|
||||
420
libraries/AccelStepper/extras/doc/AccelStepper_8h-source.html
Normal file
420
libraries/AccelStepper/extras/doc/AccelStepper_8h-source.html
Normal file
@@ -0,0 +1,420 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
||||
<title>AccelStepper: AccelStepper.h Source File</title>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css">
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css">
|
||||
</head><body>
|
||||
<!-- Generated by Doxygen 1.5.6 -->
|
||||
<div class="navigation" id="top">
|
||||
<div class="tabs">
|
||||
<ul>
|
||||
<li><a href="index.html"><span>Main Page</span></a></li>
|
||||
<li><a href="annotated.html"><span>Classes</span></a></li>
|
||||
<li class="current"><a href="files.html"><span>Files</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<h1>AccelStepper.h</h1><div class="fragment"><pre class="fragment"><a name="l00001"></a>00001 <span class="comment">// AccelStepper.h</span>
|
||||
<a name="l00002"></a>00002 <span class="comment">//</span><span class="comment"></span>
|
||||
<a name="l00003"></a>00003 <span class="comment">/// \mainpage AccelStepper library for Arduino</span>
|
||||
<a name="l00004"></a>00004 <span class="comment">///</span>
|
||||
<a name="l00005"></a>00005 <span class="comment">/// This is the Arduino AccelStepper library.</span>
|
||||
<a name="l00006"></a>00006 <span class="comment">/// It provides an object-oriented interface for 2 or 4 pin stepper motors.</span>
|
||||
<a name="l00007"></a>00007 <span class="comment">///</span>
|
||||
<a name="l00008"></a>00008 <span class="comment">/// The standard Arduino IDE includes the Stepper library</span>
|
||||
<a name="l00009"></a>00009 <span class="comment">/// (http://arduino.cc/en/Reference/Stepper) for stepper motors. It is</span>
|
||||
<a name="l00010"></a>00010 <span class="comment">/// perfectly adequate for simple, single motor applications.</span>
|
||||
<a name="l00011"></a>00011 <span class="comment">///</span>
|
||||
<a name="l00012"></a>00012 <span class="comment">/// AccelStepper significantly improves on the standard Arduino Stepper library in several ways:</span>
|
||||
<a name="l00013"></a>00013 <span class="comment">/// \li Supports acceleration and deceleration</span>
|
||||
<a name="l00014"></a>00014 <span class="comment">/// \li Supports multiple simultaneous steppers, with independent concurrent stepping on each stepper</span>
|
||||
<a name="l00015"></a>00015 <span class="comment">/// \li API functions never delay() or block</span>
|
||||
<a name="l00016"></a>00016 <span class="comment">/// \li Supports 2 and 4 wire steppers, plus 4 wire half steppers.</span>
|
||||
<a name="l00017"></a>00017 <span class="comment">/// \li Supports alternate stepping functions to enable support of AFMotor (https://github.com/adafruit/Adafruit-Motor-Shield-library)</span>
|
||||
<a name="l00018"></a>00018 <span class="comment">/// \li Supports stepper drivers such as the Sparkfun EasyDriver (based on 3967 driver chip)</span>
|
||||
<a name="l00019"></a>00019 <span class="comment">/// \li Very slow speeds are supported</span>
|
||||
<a name="l00020"></a>00020 <span class="comment">/// \li Extensive API</span>
|
||||
<a name="l00021"></a>00021 <span class="comment">/// \li Subclass support</span>
|
||||
<a name="l00022"></a>00022 <span class="comment">///</span>
|
||||
<a name="l00023"></a>00023 <span class="comment">/// The latest version of this documentation can be downloaded from </span>
|
||||
<a name="l00024"></a>00024 <span class="comment">/// http://www.open.com.au/mikem/arduino/AccelStepper</span>
|
||||
<a name="l00025"></a>00025 <span class="comment">///</span>
|
||||
<a name="l00026"></a>00026 <span class="comment">/// Example Arduino programs are included to show the main modes of use.</span>
|
||||
<a name="l00027"></a>00027 <span class="comment">///</span>
|
||||
<a name="l00028"></a>00028 <span class="comment">/// The version of the package that this documentation refers to can be downloaded </span>
|
||||
<a name="l00029"></a>00029 <span class="comment">/// from http://www.open.com.au/mikem/arduino/AccelStepper/AccelStepper-1.11.zip</span>
|
||||
<a name="l00030"></a>00030 <span class="comment">/// You can find the latest version at http://www.open.com.au/mikem/arduino/AccelStepper</span>
|
||||
<a name="l00031"></a>00031 <span class="comment">///</span>
|
||||
<a name="l00032"></a>00032 <span class="comment">/// Tested on Arduino Diecimila and Mega with arduino-0018 & arduino-0021 </span>
|
||||
<a name="l00033"></a>00033 <span class="comment">/// on OpenSuSE 11.1 and avr-libc-1.6.1-1.15,</span>
|
||||
<a name="l00034"></a>00034 <span class="comment">/// cross-avr-binutils-2.19-9.1, cross-avr-gcc-4.1.3_20080612-26.5.</span>
|
||||
<a name="l00035"></a>00035 <span class="comment">///</span>
|
||||
<a name="l00036"></a>00036 <span class="comment">/// \par Installation</span>
|
||||
<a name="l00037"></a>00037 <span class="comment">/// Install in the usual way: unzip the distribution zip file to the libraries</span>
|
||||
<a name="l00038"></a>00038 <span class="comment">/// sub-folder of your sketchbook. </span>
|
||||
<a name="l00039"></a>00039 <span class="comment">///</span>
|
||||
<a name="l00040"></a>00040 <span class="comment">/// This software is Copyright (C) 2010 Mike McCauley. Use is subject to license</span>
|
||||
<a name="l00041"></a>00041 <span class="comment">/// conditions. The main licensing options available are GPL V2 or Commercial:</span>
|
||||
<a name="l00042"></a>00042 <span class="comment">/// </span>
|
||||
<a name="l00043"></a>00043 <span class="comment">/// \par Open Source Licensing GPL V2</span>
|
||||
<a name="l00044"></a>00044 <span class="comment">/// This is the appropriate option if you want to share the source code of your</span>
|
||||
<a name="l00045"></a>00045 <span class="comment">/// application with everyone you distribute it to, and you also want to give them</span>
|
||||
<a name="l00046"></a>00046 <span class="comment">/// the right to share who uses it. If you wish to use this software under Open</span>
|
||||
<a name="l00047"></a>00047 <span class="comment">/// Source Licensing, you must contribute all your source code to the open source</span>
|
||||
<a name="l00048"></a>00048 <span class="comment">/// community in accordance with the GPL Version 2 when your application is</span>
|
||||
<a name="l00049"></a>00049 <span class="comment">/// distributed. See http://www.gnu.org/copyleft/gpl.html</span>
|
||||
<a name="l00050"></a>00050 <span class="comment">/// </span>
|
||||
<a name="l00051"></a>00051 <span class="comment">/// \par Commercial Licensing</span>
|
||||
<a name="l00052"></a>00052 <span class="comment">/// This is the appropriate option if you are creating proprietary applications</span>
|
||||
<a name="l00053"></a>00053 <span class="comment">/// and you are not prepared to distribute and share the source code of your</span>
|
||||
<a name="l00054"></a>00054 <span class="comment">/// application. Contact info@open.com.au for details.</span>
|
||||
<a name="l00055"></a>00055 <span class="comment">///</span>
|
||||
<a name="l00056"></a>00056 <span class="comment">/// \par Revision History</span>
|
||||
<a name="l00057"></a>00057 <span class="comment">/// \version 1.0 Initial release</span>
|
||||
<a name="l00058"></a>00058 <span class="comment">///</span>
|
||||
<a name="l00059"></a>00059 <span class="comment">/// \version 1.1 Added speed() function to get the current speed.</span>
|
||||
<a name="l00060"></a>00060 <span class="comment">/// \version 1.2 Added runSpeedToPosition() submitted by Gunnar Arndt.</span>
|
||||
<a name="l00061"></a>00061 <span class="comment">/// \version 1.3 Added support for stepper drivers (ie with Step and Direction inputs) with _pins == 1</span>
|
||||
<a name="l00062"></a>00062 <span class="comment">/// \version 1.4 Added functional contructor to support AFMotor, contributed by Limor, with example sketches.</span>
|
||||
<a name="l00063"></a>00063 <span class="comment">/// \version 1.5 Improvements contributed by Peter Mousley: Use of microsecond steps and other speed improvements</span>
|
||||
<a name="l00064"></a>00064 <span class="comment">/// to increase max stepping speed to about 4kHz. New option for user to set the min allowed pulse width.</span>
|
||||
<a name="l00065"></a>00065 <span class="comment">/// Added checks for already running at max speed and skip further calcs if so. </span>
|
||||
<a name="l00066"></a>00066 <span class="comment">/// \version 1.6 Fixed a problem with wrapping of microsecond stepping that could cause stepping to hang. </span>
|
||||
<a name="l00067"></a>00067 <span class="comment">/// Reported by Sandy Noble.</span>
|
||||
<a name="l00068"></a>00068 <span class="comment">/// Removed redundant _lastRunTime member.</span>
|
||||
<a name="l00069"></a>00069 <span class="comment">/// \version 1.7 Fixed a bug where setCurrentPosition() did always work as expected. Reported by Peter Linhart.</span>
|
||||
<a name="l00070"></a>00070 <span class="comment">/// Reported by Sandy Noble.</span>
|
||||
<a name="l00071"></a>00071 <span class="comment">/// Removed redundant _lastRunTime member.</span>
|
||||
<a name="l00072"></a>00072 <span class="comment">/// \version 1.8 Added support for 4 pin half-steppers, requested by Harvey Moon</span>
|
||||
<a name="l00073"></a>00073 <span class="comment">/// \version 1.9 setCurrentPosition() now also sets motor speed to 0.</span>
|
||||
<a name="l00074"></a>00074 <span class="comment">/// \version 1.10 Builds on Arduino 1.0</span>
|
||||
<a name="l00075"></a>00075 <span class="comment">/// \version 1.11 Improvments from Michael Ellison:</span>
|
||||
<a name="l00076"></a>00076 <span class="comment">/// Added optional enable line support for stepper drivers</span>
|
||||
<a name="l00077"></a>00077 <span class="comment">/// Added inversion for step/direction/enable lines for stepper drivers</span>
|
||||
<a name="l00078"></a>00078 <span class="comment">///</span>
|
||||
<a name="l00079"></a>00079 <span class="comment">/// \author Mike McCauley (mikem@open.com.au)</span>
|
||||
<a name="l00080"></a>00080 <span class="comment"></span><span class="comment">// Copyright (C) 2009 Mike McCauley</span>
|
||||
<a name="l00081"></a>00081 <span class="comment">// $Id: AccelStepper.h,v 1.5 2011/03/21 00:42:15 mikem Exp mikem $</span>
|
||||
<a name="l00082"></a>00082
|
||||
<a name="l00083"></a>00083 <span class="preprocessor">#ifndef AccelStepper_h</span>
|
||||
<a name="l00084"></a>00084 <span class="preprocessor"></span><span class="preprocessor">#define AccelStepper_h</span>
|
||||
<a name="l00085"></a>00085 <span class="preprocessor"></span>
|
||||
<a name="l00086"></a>00086 <span class="preprocessor">#include <stdlib.h></span>
|
||||
<a name="l00087"></a>00087 <span class="preprocessor">#if ARDUINO >= 100</span>
|
||||
<a name="l00088"></a>00088 <span class="preprocessor"></span><span class="preprocessor">#include <Arduino.h></span>
|
||||
<a name="l00089"></a>00089 <span class="preprocessor">#else</span>
|
||||
<a name="l00090"></a>00090 <span class="preprocessor"></span><span class="preprocessor">#include <wiring.h></span>
|
||||
<a name="l00091"></a>00091 <span class="preprocessor">#endif</span>
|
||||
<a name="l00092"></a>00092 <span class="preprocessor"></span>
|
||||
<a name="l00093"></a>00093 <span class="comment">// These defs cause trouble on some versions of Arduino</span>
|
||||
<a name="l00094"></a>00094 <span class="preprocessor">#undef round</span>
|
||||
<a name="l00095"></a>00095 <span class="preprocessor"></span><span class="comment"></span>
|
||||
<a name="l00096"></a>00096 <span class="comment">/////////////////////////////////////////////////////////////////////</span>
|
||||
<a name="l00097"></a>00097 <span class="comment">/// \class AccelStepper AccelStepper.h <AccelStepper.h></span>
|
||||
<a name="l00098"></a>00098 <span class="comment">/// \brief Support for stepper motors with acceleration etc.</span>
|
||||
<a name="l00099"></a>00099 <span class="comment">///</span>
|
||||
<a name="l00100"></a>00100 <span class="comment">/// This defines a single 2 or 4 pin stepper motor, or stepper moter with fdriver chip, with optional</span>
|
||||
<a name="l00101"></a>00101 <span class="comment">/// acceleration, deceleration, absolute positioning commands etc. Multiple</span>
|
||||
<a name="l00102"></a>00102 <span class="comment">/// simultaneous steppers are supported, all moving </span>
|
||||
<a name="l00103"></a>00103 <span class="comment">/// at different speeds and accelerations. </span>
|
||||
<a name="l00104"></a>00104 <span class="comment">///</span>
|
||||
<a name="l00105"></a>00105 <span class="comment">/// \par Operation</span>
|
||||
<a name="l00106"></a>00106 <span class="comment">/// This module operates by computing a step time in microseconds. The step</span>
|
||||
<a name="l00107"></a>00107 <span class="comment">/// time is recomputed after each step and after speed and acceleration</span>
|
||||
<a name="l00108"></a>00108 <span class="comment">/// parameters are changed by the caller. The time of each step is recorded in</span>
|
||||
<a name="l00109"></a>00109 <span class="comment">/// microseconds. The run() function steps the motor if a new step is due.</span>
|
||||
<a name="l00110"></a>00110 <span class="comment">/// The run() function must be called frequently until the motor is in the</span>
|
||||
<a name="l00111"></a>00111 <span class="comment">/// desired position, after which time run() will do nothing.</span>
|
||||
<a name="l00112"></a>00112 <span class="comment">///</span>
|
||||
<a name="l00113"></a>00113 <span class="comment">/// \par Positioning</span>
|
||||
<a name="l00114"></a>00114 <span class="comment">/// Positions are specified by a signed long integer. At</span>
|
||||
<a name="l00115"></a>00115 <span class="comment">/// construction time, the current position of the motor is consider to be 0. Positive</span>
|
||||
<a name="l00116"></a>00116 <span class="comment">/// positions are clockwise from the initial position; negative positions are</span>
|
||||
<a name="l00117"></a>00117 <span class="comment">/// anticlockwise. The curent position can be altered for instance after</span>
|
||||
<a name="l00118"></a>00118 <span class="comment">/// initialization positioning.</span>
|
||||
<a name="l00119"></a>00119 <span class="comment">///</span>
|
||||
<a name="l00120"></a>00120 <span class="comment">/// \par Caveats</span>
|
||||
<a name="l00121"></a>00121 <span class="comment">/// This is an open loop controller: If the motor stalls or is oversped,</span>
|
||||
<a name="l00122"></a>00122 <span class="comment">/// AccelStepper will not have a correct </span>
|
||||
<a name="l00123"></a>00123 <span class="comment">/// idea of where the motor really is (since there is no feedback of the motor's</span>
|
||||
<a name="l00124"></a>00124 <span class="comment">/// real position. We only know where we _think_ it is, relative to the</span>
|
||||
<a name="l00125"></a>00125 <span class="comment">/// initial starting point).</span>
|
||||
<a name="l00126"></a>00126 <span class="comment">///</span>
|
||||
<a name="l00127"></a>00127 <span class="comment">/// The fastest motor speed that can be reliably supported is 4000 steps per</span>
|
||||
<a name="l00128"></a>00128 <span class="comment">/// second (4 kHz) at a clock frequency of 16 MHz. However, any speed less than that</span>
|
||||
<a name="l00129"></a>00129 <span class="comment">/// down to very slow speeds (much less than one per second) are also supported,</span>
|
||||
<a name="l00130"></a>00130 <span class="comment">/// provided the run() function is called frequently enough to step the motor</span>
|
||||
<a name="l00131"></a>00131 <span class="comment">/// whenever required for the speed set.</span>
|
||||
<a name="l00132"></a><a class="code" href="classAccelStepper.html">00132</a> <span class="comment"></span><span class="keyword">class </span><a class="code" href="classAccelStepper.html" title="Support for stepper motors with acceleration etc.">AccelStepper</a>
|
||||
<a name="l00133"></a>00133 {
|
||||
<a name="l00134"></a>00134 <span class="keyword">public</span>:<span class="comment"></span>
|
||||
<a name="l00135"></a>00135 <span class="comment"> /// Constructor. You can have multiple simultaneous steppers, all moving</span>
|
||||
<a name="l00136"></a>00136 <span class="comment"> /// at different speeds and accelerations, provided you call their run()</span>
|
||||
<a name="l00137"></a>00137 <span class="comment"> /// functions at frequent enough intervals. Current Position is set to 0, target</span>
|
||||
<a name="l00138"></a>00138 <span class="comment"> /// position is set to 0. MaxSpeed and Acceleration default to 1.0.</span>
|
||||
<a name="l00139"></a>00139 <span class="comment"> /// The motor pins will be initialised to OUTPUT mode during the</span>
|
||||
<a name="l00140"></a>00140 <span class="comment"> /// constructor by a call to enableOutputs().</span>
|
||||
<a name="l00141"></a>00141 <span class="comment"> /// \param[in] pins Number of pins to interface to. 1, 2 or 4 are</span>
|
||||
<a name="l00142"></a>00142 <span class="comment"> /// supported. 1 means a stepper driver (with Step and Direction pins).</span>
|
||||
<a name="l00143"></a>00143 <span class="comment"> /// If an enable line is also needed, call setEnablePin() after construction.</span>
|
||||
<a name="l00144"></a>00144 <span class="comment"> /// You may also invert the pins using setPinsInverted().</span>
|
||||
<a name="l00145"></a>00145 <span class="comment"> /// 2 means a 2 wire stepper. 4 means a 4 wire stepper. 8 means a 4 wire half stepper</span>
|
||||
<a name="l00146"></a>00146 <span class="comment"> /// Defaults to 4 pins.</span>
|
||||
<a name="l00147"></a>00147 <span class="comment"> /// \param[in] pin1 Arduino digital pin number for motor pin 1. Defaults</span>
|
||||
<a name="l00148"></a>00148 <span class="comment"> /// to pin 2. For a driver (pins==1), this is the Step input to the driver. Low to high transition means to step)</span>
|
||||
<a name="l00149"></a>00149 <span class="comment"> /// \param[in] pin2 Arduino digital pin number for motor pin 2. Defaults</span>
|
||||
<a name="l00150"></a>00150 <span class="comment"> /// to pin 3. For a driver (pins==1), this is the Direction input the driver. High means forward.</span>
|
||||
<a name="l00151"></a>00151 <span class="comment"> /// \param[in] pin3 Arduino digital pin number for motor pin 3. Defaults</span>
|
||||
<a name="l00152"></a>00152 <span class="comment"> /// to pin 4.</span>
|
||||
<a name="l00153"></a>00153 <span class="comment"> /// \param[in] pin4 Arduino digital pin number for motor pin 4. Defaults</span>
|
||||
<a name="l00154"></a>00154 <span class="comment"> /// to pin 5.</span>
|
||||
<a name="l00155"></a>00155 <span class="comment"></span> <a class="code" href="classAccelStepper.html#a1290897df35915069e5eca9d034038c">AccelStepper</a>(uint8_t pins = 4, uint8_t pin1 = 2, uint8_t pin2 = 3, uint8_t pin3 = 4, uint8_t pin4 = 5);
|
||||
<a name="l00156"></a>00156 <span class="comment"></span>
|
||||
<a name="l00157"></a>00157 <span class="comment"> /// Alternate Constructor which will call your own functions for forward and backward steps. </span>
|
||||
<a name="l00158"></a>00158 <span class="comment"> /// You can have multiple simultaneous steppers, all moving</span>
|
||||
<a name="l00159"></a>00159 <span class="comment"> /// at different speeds and accelerations, provided you call their run()</span>
|
||||
<a name="l00160"></a>00160 <span class="comment"> /// functions at frequent enough intervals. Current Position is set to 0, target</span>
|
||||
<a name="l00161"></a>00161 <span class="comment"> /// position is set to 0. MaxSpeed and Acceleration default to 1.0.</span>
|
||||
<a name="l00162"></a>00162 <span class="comment"> /// Any motor initialization should happen before hand, no pins are used or initialized.</span>
|
||||
<a name="l00163"></a>00163 <span class="comment"> /// \param[in] forward void-returning procedure that will make a forward step</span>
|
||||
<a name="l00164"></a>00164 <span class="comment"> /// \param[in] backward void-returning procedure that will make a backward step</span>
|
||||
<a name="l00165"></a>00165 <span class="comment"></span> <a class="code" href="classAccelStepper.html#a1290897df35915069e5eca9d034038c">AccelStepper</a>(<span class="keywordtype">void</span> (*forward)(), <span class="keywordtype">void</span> (*backward)());
|
||||
<a name="l00166"></a>00166 <span class="comment"></span>
|
||||
<a name="l00167"></a>00167 <span class="comment"> /// Set the target position. The run() function will try to move the motor</span>
|
||||
<a name="l00168"></a>00168 <span class="comment"> /// from the current position to the target position set by the most</span>
|
||||
<a name="l00169"></a>00169 <span class="comment"> /// recent call to this function.</span>
|
||||
<a name="l00170"></a>00170 <span class="comment"> /// \param[in] absolute The desired absolute position. Negative is</span>
|
||||
<a name="l00171"></a>00171 <span class="comment"> /// anticlockwise from the 0 position.</span>
|
||||
<a name="l00172"></a>00172 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#ce236ede35f87c63d18da25810ec9736">moveTo</a>(<span class="keywordtype">long</span> absolute);
|
||||
<a name="l00173"></a>00173 <span class="comment"></span>
|
||||
<a name="l00174"></a>00174 <span class="comment"> /// Set the target position relative to the current position</span>
|
||||
<a name="l00175"></a>00175 <span class="comment"> /// \param[in] relative The desired position relative to the current position. Negative is</span>
|
||||
<a name="l00176"></a>00176 <span class="comment"> /// anticlockwise from the current position.</span>
|
||||
<a name="l00177"></a>00177 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#68942c66e78fb7f7b5f0cdade6eb7f06">move</a>(<span class="keywordtype">long</span> relative);
|
||||
<a name="l00178"></a>00178 <span class="comment"></span>
|
||||
<a name="l00179"></a>00179 <span class="comment"> /// Poll the motor and step it if a step is due, implementing</span>
|
||||
<a name="l00180"></a>00180 <span class="comment"> /// accelerations and decelerations to achive the ratget position. You must call this as</span>
|
||||
<a name="l00181"></a>00181 <span class="comment"> /// fequently as possible, but at least once per minimum step interval,</span>
|
||||
<a name="l00182"></a>00182 <span class="comment"> /// preferably in your main loop.</span>
|
||||
<a name="l00183"></a>00183 <span class="comment"> /// \return true if the motor is at the target position.</span>
|
||||
<a name="l00184"></a>00184 <span class="comment"></span> <span class="keywordtype">boolean</span> <a class="code" href="classAccelStepper.html#608b2395b64ac15451d16d0371fe13ce">run</a>();
|
||||
<a name="l00185"></a>00185 <span class="comment"></span>
|
||||
<a name="l00186"></a>00186 <span class="comment"> /// Poll the motor and step it if a step is due, implmenting a constant</span>
|
||||
<a name="l00187"></a>00187 <span class="comment"> /// speed as set by the most recent call to setSpeed().</span>
|
||||
<a name="l00188"></a>00188 <span class="comment"> /// \return true if the motor was stepped.</span>
|
||||
<a name="l00189"></a>00189 <span class="comment"></span> <span class="keywordtype">boolean</span> <a class="code" href="classAccelStepper.html#a4a6bdf99f698284faaeb5542b0b7514">runSpeed</a>();
|
||||
<a name="l00190"></a>00190 <span class="comment"></span>
|
||||
<a name="l00191"></a>00191 <span class="comment"> /// Sets the maximum permitted speed. the run() function will accelerate</span>
|
||||
<a name="l00192"></a>00192 <span class="comment"> /// up to the speed set by this function.</span>
|
||||
<a name="l00193"></a>00193 <span class="comment"> /// \param[in] speed The desired maximum speed in steps per second. Must</span>
|
||||
<a name="l00194"></a>00194 <span class="comment"> /// be > 0. Speeds of more than 1000 steps per second are unreliable. </span>
|
||||
<a name="l00195"></a>00195 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#bee8d466229b87accba33d6ec929c18f">setMaxSpeed</a>(<span class="keywordtype">float</span> <a class="code" href="classAccelStepper.html#4f0989d0ae264e7eadfe1fa720769fb6">speed</a>);
|
||||
<a name="l00196"></a>00196 <span class="comment"></span>
|
||||
<a name="l00197"></a>00197 <span class="comment"> /// Sets the acceleration and deceleration parameter.</span>
|
||||
<a name="l00198"></a>00198 <span class="comment"> /// \param[in] acceleration The desired acceleration in steps per second</span>
|
||||
<a name="l00199"></a>00199 <span class="comment"> /// per second. Must be > 0.</span>
|
||||
<a name="l00200"></a>00200 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#dfb19e3cd2a028a1fe78131787604fd1">setAcceleration</a>(<span class="keywordtype">float</span> acceleration);
|
||||
<a name="l00201"></a>00201 <span class="comment"></span>
|
||||
<a name="l00202"></a>00202 <span class="comment"> /// Sets the desired constant speed for use with runSpeed().</span>
|
||||
<a name="l00203"></a>00203 <span class="comment"> /// \param[in] speed The desired constant speed in steps per</span>
|
||||
<a name="l00204"></a>00204 <span class="comment"> /// second. Positive is clockwise. Speeds of more than 1000 steps per</span>
|
||||
<a name="l00205"></a>00205 <span class="comment"> /// second are unreliable. Very slow speeds may be set (eg 0.00027777 for</span>
|
||||
<a name="l00206"></a>00206 <span class="comment"> /// once per hour, approximately. Speed accuracy depends on the Arduino</span>
|
||||
<a name="l00207"></a>00207 <span class="comment"> /// crystal. Jitter depends on how frequently you call the runSpeed() function.</span>
|
||||
<a name="l00208"></a>00208 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#e79c49ad69d5ccc9da0ee691fa4ca235">setSpeed</a>(<span class="keywordtype">float</span> speed);
|
||||
<a name="l00209"></a>00209 <span class="comment"></span>
|
||||
<a name="l00210"></a>00210 <span class="comment"> /// The most recently set speed</span>
|
||||
<a name="l00211"></a>00211 <span class="comment"> /// \return the most recent speed in steps per second</span>
|
||||
<a name="l00212"></a>00212 <span class="comment"></span> <span class="keywordtype">float</span> <a class="code" href="classAccelStepper.html#4f0989d0ae264e7eadfe1fa720769fb6">speed</a>();
|
||||
<a name="l00213"></a>00213 <span class="comment"></span>
|
||||
<a name="l00214"></a>00214 <span class="comment"> /// The distance from the current position to the target position.</span>
|
||||
<a name="l00215"></a>00215 <span class="comment"> /// \return the distance from the current position to the target position</span>
|
||||
<a name="l00216"></a>00216 <span class="comment"> /// in steps. Positive is clockwise from the current position.</span>
|
||||
<a name="l00217"></a>00217 <span class="comment"></span> <span class="keywordtype">long</span> <a class="code" href="classAccelStepper.html#748665c3962e66fbc0e9373eb14c69c1">distanceToGo</a>();
|
||||
<a name="l00218"></a>00218 <span class="comment"></span>
|
||||
<a name="l00219"></a>00219 <span class="comment"> /// The most recently set target position.</span>
|
||||
<a name="l00220"></a>00220 <span class="comment"> /// \return the target position</span>
|
||||
<a name="l00221"></a>00221 <span class="comment"> /// in steps. Positive is clockwise from the 0 position.</span>
|
||||
<a name="l00222"></a>00222 <span class="comment"></span> <span class="keywordtype">long</span> <a class="code" href="classAccelStepper.html#96685e0945b7cf75d5959da679cd911e">targetPosition</a>();
|
||||
<a name="l00223"></a>00223
|
||||
<a name="l00224"></a>00224 <span class="comment"></span>
|
||||
<a name="l00225"></a>00225 <span class="comment"> /// The currently motor position.</span>
|
||||
<a name="l00226"></a>00226 <span class="comment"> /// \return the current motor position</span>
|
||||
<a name="l00227"></a>00227 <span class="comment"> /// in steps. Positive is clockwise from the 0 position.</span>
|
||||
<a name="l00228"></a>00228 <span class="comment"></span> <span class="keywordtype">long</span> <a class="code" href="classAccelStepper.html#5dce13ab2a1b02b8f443318886bf6fc5">currentPosition</a>();
|
||||
<a name="l00229"></a>00229 <span class="comment"></span>
|
||||
<a name="l00230"></a>00230 <span class="comment"> /// Resets the current position of the motor, so that wherever the motor</span>
|
||||
<a name="l00231"></a>00231 <span class="comment"> /// happens to be right now is considered to be the new 0 position. Useful</span>
|
||||
<a name="l00232"></a>00232 <span class="comment"> /// for setting a zero position on a stepper after an initial hardware</span>
|
||||
<a name="l00233"></a>00233 <span class="comment"> /// positioning move.</span>
|
||||
<a name="l00234"></a>00234 <span class="comment"> /// Has the side effect of setting the current motor speed to 0.</span>
|
||||
<a name="l00235"></a>00235 <span class="comment"> /// \param[in] position The position in steps of wherever the motor</span>
|
||||
<a name="l00236"></a>00236 <span class="comment"> /// happens to be right now.</span>
|
||||
<a name="l00237"></a>00237 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#9d917f014317fb9d3b5dc14e66f6c689">setCurrentPosition</a>(<span class="keywordtype">long</span> position);
|
||||
<a name="l00238"></a>00238 <span class="comment"></span>
|
||||
<a name="l00239"></a>00239 <span class="comment"> /// Moves the motor to the target position and blocks until it is at</span>
|
||||
<a name="l00240"></a>00240 <span class="comment"> /// position. Dont use this in event loops, since it blocks.</span>
|
||||
<a name="l00241"></a>00241 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#344f58fef8cc34ac5aa75ba4b665d21c">runToPosition</a>();
|
||||
<a name="l00242"></a>00242 <span class="comment"></span>
|
||||
<a name="l00243"></a>00243 <span class="comment"> /// Runs at the currently selected speed until the target position is reached</span>
|
||||
<a name="l00244"></a>00244 <span class="comment"> /// Does not implement accelerations.</span>
|
||||
<a name="l00245"></a>00245 <span class="comment"></span> <span class="keywordtype">boolean</span> <a class="code" href="classAccelStepper.html#9270d20336e76ac1fd5bcd5b9c34f301">runSpeedToPosition</a>();
|
||||
<a name="l00246"></a>00246 <span class="comment"></span>
|
||||
<a name="l00247"></a>00247 <span class="comment"> /// Moves the motor to the new target position and blocks until it is at</span>
|
||||
<a name="l00248"></a>00248 <span class="comment"> /// position. Dont use this in event loops, since it blocks.</span>
|
||||
<a name="l00249"></a>00249 <span class="comment"> /// \param[in] position The new target position.</span>
|
||||
<a name="l00250"></a>00250 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#176c5d2e4c2f21e9e92b12e39a6f0e67">runToNewPosition</a>(<span class="keywordtype">long</span> position);
|
||||
<a name="l00251"></a>00251 <span class="comment"></span>
|
||||
<a name="l00252"></a>00252 <span class="comment"> /// Disable motor pin outputs by setting them all LOW</span>
|
||||
<a name="l00253"></a>00253 <span class="comment"> /// Depending on the design of your electronics this may turn off</span>
|
||||
<a name="l00254"></a>00254 <span class="comment"> /// the power to the motor coils, saving power.</span>
|
||||
<a name="l00255"></a>00255 <span class="comment"> /// This is useful to support Arduino low power modes: disable the outputs</span>
|
||||
<a name="l00256"></a>00256 <span class="comment"> /// during sleep and then reenable with enableOutputs() before stepping</span>
|
||||
<a name="l00257"></a>00257 <span class="comment"> /// again.</span>
|
||||
<a name="l00258"></a>00258 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#3591e29a236e2935afd7f64ff6c22006">disableOutputs</a>();
|
||||
<a name="l00259"></a>00259 <span class="comment"></span>
|
||||
<a name="l00260"></a>00260 <span class="comment"> /// Enable motor pin outputs by setting the motor pins to OUTPUT</span>
|
||||
<a name="l00261"></a>00261 <span class="comment"> /// mode. Called automatically by the constructor.</span>
|
||||
<a name="l00262"></a>00262 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#a279a50d30d0413f570c692cff071643">enableOutputs</a>();
|
||||
<a name="l00263"></a>00263 <span class="comment"></span>
|
||||
<a name="l00264"></a>00264 <span class="comment"> /// Sets the minimum pulse width allowed by the stepper driver.</span>
|
||||
<a name="l00265"></a>00265 <span class="comment"> /// \param[in] minWidth The minimum pulse width in microseconds.</span>
|
||||
<a name="l00266"></a>00266 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#f4d3818e691dad5dc518308796ccf154">setMinPulseWidth</a>(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> minWidth);
|
||||
<a name="l00267"></a>00267 <span class="comment"></span>
|
||||
<a name="l00268"></a>00268 <span class="comment"> /// Sets the enable pin number for stepper drivers.</span>
|
||||
<a name="l00269"></a>00269 <span class="comment"> /// 0xFF indicates unused (default).</span>
|
||||
<a name="l00270"></a>00270 <span class="comment"> /// Otherwise, if a pin is set, the pin will be turned on when </span>
|
||||
<a name="l00271"></a>00271 <span class="comment"> /// enableOutputs() is called and switched off when disableOutputs() </span>
|
||||
<a name="l00272"></a>00272 <span class="comment"> /// is called.</span>
|
||||
<a name="l00273"></a>00273 <span class="comment"> /// \param[in] enablePin Arduino digital pin number for motor enable</span>
|
||||
<a name="l00274"></a>00274 <span class="comment"> /// \sa setPinsInverted</span>
|
||||
<a name="l00275"></a>00275 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#56a81c5f00d02ca19646718e88e974c0">setEnablePin</a>(uint8_t enablePin = 0xff);
|
||||
<a name="l00276"></a>00276 <span class="comment"></span>
|
||||
<a name="l00277"></a>00277 <span class="comment"> /// Sets the inversion for stepper driver pins</span>
|
||||
<a name="l00278"></a>00278 <span class="comment"> /// \param[in] direction True for inverted direction pin, false for non-inverted</span>
|
||||
<a name="l00279"></a>00279 <span class="comment"> /// \param[in] step True for inverted step pin, false for non-inverted</span>
|
||||
<a name="l00280"></a>00280 <span class="comment"> /// \param[in] enable True for inverted enable pin, false (default) for non-inverted</span>
|
||||
<a name="l00281"></a>00281 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#797b4bdb580d4ca7a1cfeabe3df0de35">setPinsInverted</a>(<span class="keywordtype">bool</span> direction, <span class="keywordtype">bool</span> <a class="code" href="classAccelStepper.html#3c9a220819d2451f79ff8a0c0a395b9f">step</a>, <span class="keywordtype">bool</span> enable = <span class="keyword">false</span>);
|
||||
<a name="l00282"></a>00282
|
||||
<a name="l00283"></a>00283 <span class="keyword">protected</span>:
|
||||
<a name="l00284"></a>00284 <span class="comment"></span>
|
||||
<a name="l00285"></a>00285 <span class="comment"> /// Forces the library to compute a new instantaneous speed and set that as</span>
|
||||
<a name="l00286"></a>00286 <span class="comment"> /// the current speed. Calls</span>
|
||||
<a name="l00287"></a>00287 <span class="comment"> /// desiredSpeed(), which can be overridden by subclasses. It is called by</span>
|
||||
<a name="l00288"></a>00288 <span class="comment"> /// the library:</span>
|
||||
<a name="l00289"></a>00289 <span class="comment"> /// \li after each step</span>
|
||||
<a name="l00290"></a>00290 <span class="comment"> /// \li after change to maxSpeed through setMaxSpeed()</span>
|
||||
<a name="l00291"></a>00291 <span class="comment"> /// \li after change to acceleration through setAcceleration()</span>
|
||||
<a name="l00292"></a>00292 <span class="comment"> /// \li after change to target position (relative or absolute) through</span>
|
||||
<a name="l00293"></a>00293 <span class="comment"> /// move() or moveTo()</span>
|
||||
<a name="l00294"></a>00294 <span class="comment"></span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#ffbee789b5c19165846cf0409860ae79">computeNewSpeed</a>();
|
||||
<a name="l00295"></a>00295 <span class="comment"></span>
|
||||
<a name="l00296"></a>00296 <span class="comment"> /// Called to execute a step. Only called when a new step is</span>
|
||||
<a name="l00297"></a>00297 <span class="comment"> /// required. Subclasses may override to implement new stepping</span>
|
||||
<a name="l00298"></a>00298 <span class="comment"> /// interfaces. The default calls step1(), step2(), step4() or step8() depending on the</span>
|
||||
<a name="l00299"></a>00299 <span class="comment"> /// number of pins defined for the stepper.</span>
|
||||
<a name="l00300"></a>00300 <span class="comment"> /// \param[in] step The current step phase number (0 to 7)</span>
|
||||
<a name="l00301"></a>00301 <span class="comment"></span> <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#3c9a220819d2451f79ff8a0c0a395b9f">step</a>(uint8_t step);
|
||||
<a name="l00302"></a>00302 <span class="comment"></span>
|
||||
<a name="l00303"></a>00303 <span class="comment"> /// Called to execute a step using stepper functions (pins = 0) Only called when a new step is</span>
|
||||
<a name="l00304"></a>00304 <span class="comment"> /// required. Calls _forward() or _backward() to perform the step</span>
|
||||
<a name="l00305"></a>00305 <span class="comment"></span> <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#889f109756aa4c0a2feefebd8081a337">step0</a>(<span class="keywordtype">void</span>);
|
||||
<a name="l00306"></a>00306 <span class="comment"></span>
|
||||
<a name="l00307"></a>00307 <span class="comment"> /// Called to execute a step on a stepper drover (ie where pins == 1). Only called when a new step is</span>
|
||||
<a name="l00308"></a>00308 <span class="comment"> /// required. Subclasses may override to implement new stepping</span>
|
||||
<a name="l00309"></a>00309 <span class="comment"> /// interfaces. The default sets or clears the outputs of Step pin1 to step, </span>
|
||||
<a name="l00310"></a>00310 <span class="comment"> /// and sets the output of _pin2 to the desired direction. The Step pin (_pin1) is pulsed for 1 microsecond</span>
|
||||
<a name="l00311"></a>00311 <span class="comment"> /// which is the minimum STEP pulse width for the 3967 driver.</span>
|
||||
<a name="l00312"></a>00312 <span class="comment"> /// \param[in] step The current step phase number (0 to 7)</span>
|
||||
<a name="l00313"></a>00313 <span class="comment"></span> <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#cc64254ea242b53588e948335fd9305f">step1</a>(uint8_t step);
|
||||
<a name="l00314"></a>00314 <span class="comment"></span>
|
||||
<a name="l00315"></a>00315 <span class="comment"> /// Called to execute a step on a 2 pin motor. Only called when a new step is</span>
|
||||
<a name="l00316"></a>00316 <span class="comment"> /// required. Subclasses may override to implement new stepping</span>
|
||||
<a name="l00317"></a>00317 <span class="comment"> /// interfaces. The default sets or clears the outputs of pin1 and pin2</span>
|
||||
<a name="l00318"></a>00318 <span class="comment"> /// \param[in] step The current step phase number (0 to 7)</span>
|
||||
<a name="l00319"></a>00319 <span class="comment"></span> <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#88f11bf6361fe002585f731d34fe2e8b">step2</a>(uint8_t step);
|
||||
<a name="l00320"></a>00320 <span class="comment"></span>
|
||||
<a name="l00321"></a>00321 <span class="comment"> /// Called to execute a step on a 4 pin motor. Only called when a new step is</span>
|
||||
<a name="l00322"></a>00322 <span class="comment"> /// required. Subclasses may override to implement new stepping</span>
|
||||
<a name="l00323"></a>00323 <span class="comment"> /// interfaces. The default sets or clears the outputs of pin1, pin2,</span>
|
||||
<a name="l00324"></a>00324 <span class="comment"> /// pin3, pin4.</span>
|
||||
<a name="l00325"></a>00325 <span class="comment"> /// \param[in] step The current step phase number (0 to 7)</span>
|
||||
<a name="l00326"></a>00326 <span class="comment"></span> <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#49e448d179bbe4e0f8003a3f9993789d">step4</a>(uint8_t step);
|
||||
<a name="l00327"></a>00327 <span class="comment"></span>
|
||||
<a name="l00328"></a>00328 <span class="comment"> /// Called to execute a step on a 4 pin half-steper motor. Only called when a new step is</span>
|
||||
<a name="l00329"></a>00329 <span class="comment"> /// required. Subclasses may override to implement new stepping</span>
|
||||
<a name="l00330"></a>00330 <span class="comment"> /// interfaces. The default sets or clears the outputs of pin1, pin2,</span>
|
||||
<a name="l00331"></a>00331 <span class="comment"> /// pin3, pin4.</span>
|
||||
<a name="l00332"></a>00332 <span class="comment"> /// \param[in] step The current step phase number (0 to 7)</span>
|
||||
<a name="l00333"></a>00333 <span class="comment"></span> <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classAccelStepper.html#5b33d1088e2beaf2176c42b08fb675ea">step8</a>(uint8_t step);
|
||||
<a name="l00334"></a>00334 <span class="comment"></span>
|
||||
<a name="l00335"></a>00335 <span class="comment"> /// Compute and return the desired speed. The default algorithm uses</span>
|
||||
<a name="l00336"></a>00336 <span class="comment"> /// maxSpeed, acceleration and the current speed to set a new speed to</span>
|
||||
<a name="l00337"></a>00337 <span class="comment"> /// move the motor from teh current position to the target</span>
|
||||
<a name="l00338"></a>00338 <span class="comment"> /// position. Subclasses may override this to provide an alternate</span>
|
||||
<a name="l00339"></a>00339 <span class="comment"> /// algorithm (but do not block). Called by computeNewSpeed whenever a new speed neds to be</span>
|
||||
<a name="l00340"></a>00340 <span class="comment"> /// computed. </span>
|
||||
<a name="l00341"></a>00341 <span class="comment"></span> <span class="keyword">virtual</span> <span class="keywordtype">float</span> <a class="code" href="classAccelStepper.html#6e4bd79c395e69beee31d76d0d3287e4">desiredSpeed</a>();
|
||||
<a name="l00342"></a>00342
|
||||
<a name="l00343"></a>00343 <span class="keyword">private</span>:<span class="comment"></span>
|
||||
<a name="l00344"></a>00344 <span class="comment"> /// Number of pins on the stepper motor. Permits 2 or 4. 2 pins is a</span>
|
||||
<a name="l00345"></a>00345 <span class="comment"> /// bipolar, and 4 pins is a unipolar.</span>
|
||||
<a name="l00346"></a>00346 <span class="comment"></span> uint8_t _pins; <span class="comment">// 2 or 4</span>
|
||||
<a name="l00347"></a>00347 <span class="comment"></span>
|
||||
<a name="l00348"></a>00348 <span class="comment"> /// Arduino pin number for the 2 or 4 pins required to interface to the</span>
|
||||
<a name="l00349"></a>00349 <span class="comment"> /// stepper motor.</span>
|
||||
<a name="l00350"></a>00350 <span class="comment"></span> uint8_t _pin1, _pin2, _pin3, _pin4;
|
||||
<a name="l00351"></a>00351 <span class="comment"></span>
|
||||
<a name="l00352"></a>00352 <span class="comment"> /// The current absolution position in steps.</span>
|
||||
<a name="l00353"></a>00353 <span class="comment"></span> <span class="keywordtype">long</span> _currentPos; <span class="comment">// Steps</span>
|
||||
<a name="l00354"></a>00354 <span class="comment"></span>
|
||||
<a name="l00355"></a>00355 <span class="comment"> /// The target position in steps. The AccelStepper library will move the</span>
|
||||
<a name="l00356"></a>00356 <span class="comment"> /// motor from the _currentPos to the _targetPos, taking into account the</span>
|
||||
<a name="l00357"></a>00357 <span class="comment"> /// max speed, acceleration and deceleration</span>
|
||||
<a name="l00358"></a>00358 <span class="comment"></span> <span class="keywordtype">long</span> _targetPos; <span class="comment">// Steps</span>
|
||||
<a name="l00359"></a>00359 <span class="comment"></span>
|
||||
<a name="l00360"></a>00360 <span class="comment"> /// The current motos speed in steps per second</span>
|
||||
<a name="l00361"></a>00361 <span class="comment"> /// Positive is clockwise</span>
|
||||
<a name="l00362"></a>00362 <span class="comment"></span> <span class="keywordtype">float</span> _speed; <span class="comment">// Steps per second</span>
|
||||
<a name="l00363"></a>00363 <span class="comment"></span>
|
||||
<a name="l00364"></a>00364 <span class="comment"> /// The maximum permitted speed in steps per second. Must be > 0.</span>
|
||||
<a name="l00365"></a>00365 <span class="comment"></span> <span class="keywordtype">float</span> _maxSpeed;
|
||||
<a name="l00366"></a>00366 <span class="comment"></span>
|
||||
<a name="l00367"></a>00367 <span class="comment"> /// The acceleration to use to accelerate or decelerate the motor in steps</span>
|
||||
<a name="l00368"></a>00368 <span class="comment"> /// per second per second. Must be > 0</span>
|
||||
<a name="l00369"></a>00369 <span class="comment"></span> <span class="keywordtype">float</span> _acceleration;
|
||||
<a name="l00370"></a>00370 <span class="comment"></span>
|
||||
<a name="l00371"></a>00371 <span class="comment"> /// The current interval between steps in microseconds</span>
|
||||
<a name="l00372"></a>00372 <span class="comment"></span> <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> _stepInterval;
|
||||
<a name="l00373"></a>00373 <span class="comment"></span>
|
||||
<a name="l00374"></a>00374 <span class="comment"> /// The last step time in microseconds</span>
|
||||
<a name="l00375"></a>00375 <span class="comment"></span> <span class="keywordtype">unsigned</span> <span class="keywordtype">long</span> _lastStepTime;
|
||||
<a name="l00376"></a>00376 <span class="comment"></span>
|
||||
<a name="l00377"></a>00377 <span class="comment"> /// The minimum allowed pulse width in microseconds</span>
|
||||
<a name="l00378"></a>00378 <span class="comment"></span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> _minPulseWidth;
|
||||
<a name="l00379"></a>00379 <span class="comment"></span>
|
||||
<a name="l00380"></a>00380 <span class="comment"> /// Is the direction pin inverted?</span>
|
||||
<a name="l00381"></a>00381 <span class="comment"></span> <span class="keywordtype">bool</span> _dirInverted;
|
||||
<a name="l00382"></a>00382 <span class="comment"></span>
|
||||
<a name="l00383"></a>00383 <span class="comment"> /// Is the step pin inverted?</span>
|
||||
<a name="l00384"></a>00384 <span class="comment"></span> <span class="keywordtype">bool</span> _stepInverted;
|
||||
<a name="l00385"></a>00385 <span class="comment"></span>
|
||||
<a name="l00386"></a>00386 <span class="comment"> /// Is the enable pin inverted?</span>
|
||||
<a name="l00387"></a>00387 <span class="comment"></span> <span class="keywordtype">bool</span> _enableInverted;
|
||||
<a name="l00388"></a>00388 <span class="comment"></span>
|
||||
<a name="l00389"></a>00389 <span class="comment"> /// Enable pin for stepper driver, or 0xFF if unused.</span>
|
||||
<a name="l00390"></a>00390 <span class="comment"></span> uint8_t _enablePin;
|
||||
<a name="l00391"></a>00391
|
||||
<a name="l00392"></a>00392 <span class="comment">// The pointer to a forward-step procedure</span>
|
||||
<a name="l00393"></a>00393 void (*_forward)();
|
||||
<a name="l00394"></a>00394
|
||||
<a name="l00395"></a>00395 <span class="comment">// The pointer to a backward-step procedure</span>
|
||||
<a name="l00396"></a>00396 void (*_backward)();
|
||||
<a name="l00397"></a>00397 };
|
||||
<a name="l00398"></a>00398
|
||||
<a name="l00399"></a>00399 <span class="preprocessor">#endif </span>
|
||||
</pre></div></div>
|
||||
<hr size="1"><address style="text-align: right;"><small>Generated on Sun Jan 8 17:27:41 2012 for AccelStepper by
|
||||
<a href="http://www.doxygen.org/index.html">
|
||||
<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.6 </small></address>
|
||||
</body>
|
||||
</html>
|
||||
58
libraries/AccelStepper/extras/doc/annotated.html
Normal file
58
libraries/AccelStepper/extras/doc/annotated.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.13"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>AccelStepper: Class List</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">AccelStepper
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.13 -->
|
||||
<script type="text/javascript" src="menudata.js"></script>
|
||||
<script type="text/javascript" src="menu.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
initMenu('',false,false,'search.php','Search');
|
||||
});
|
||||
</script>
|
||||
<div id="main-nav"></div>
|
||||
</div><!-- top -->
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">Class List</div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock">Here are the classes, structs, unions and interfaces with brief descriptions:</div><div class="directory">
|
||||
<table class="directory">
|
||||
<tr id="row_0_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><span class="icona"><span class="icon">C</span></span><a class="el" href="classAccelStepper.html" target="_self">AccelStepper</a></td><td class="desc">Support for stepper motors with acceleration etc </td></tr>
|
||||
<tr id="row_1_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><span class="icona"><span class="icon">C</span></span><a class="el" href="classMultiStepper.html" target="_self">MultiStepper</a></td><td class="desc">Operate multiple AccelSteppers in a co-ordinated fashion </td></tr>
|
||||
</table>
|
||||
</div><!-- directory -->
|
||||
</div><!-- contents -->
|
||||
<!-- start footer part -->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated by  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||
</a> 1.8.13
|
||||
</small></address>
|
||||
</body>
|
||||
</html>
|
||||
103
libraries/AccelStepper/extras/doc/classAccelStepper-members.html
Normal file
103
libraries/AccelStepper/extras/doc/classAccelStepper-members.html
Normal file
@@ -0,0 +1,103 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.13"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>AccelStepper: Member List</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">AccelStepper
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.13 -->
|
||||
<script type="text/javascript" src="menudata.js"></script>
|
||||
<script type="text/javascript" src="menu.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
initMenu('',false,false,'search.php','Search');
|
||||
});
|
||||
</script>
|
||||
<div id="main-nav"></div>
|
||||
</div><!-- top -->
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">AccelStepper Member List</div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
|
||||
<p>This is the complete list of members for <a class="el" href="classAccelStepper.html">AccelStepper</a>, including all inherited members.</p>
|
||||
<table class="directory">
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a35162cdf8ed9a98f98984c177d5ade58">_direction</a></td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a3bc75bd6571b98a6177838ca81ac39ab">AccelStepper</a>(uint8_t interface=AccelStepper::FULL4WIRE, uint8_t pin1=2, uint8_t pin2=3, uint8_t pin3=4, uint8_t pin4=5, bool enable=true)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#afa3061ce813303a8f2fa206ee8d012bd">AccelStepper</a>(void(*forward)(), void(*backward)())</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#affbee789b5c19165846cf0409860ae79">computeNewSpeed</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a5dce13ab2a1b02b8f443318886bf6fc5">currentPosition</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a7468f91a925c689c3ba250f8d074d228">Direction</a> enum name</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a7468f91a925c689c3ba250f8d074d228a6959a4549f734bd771d418f995ba4fb4">DIRECTION_CCW</a> enum value</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a7468f91a925c689c3ba250f8d074d228ad604e0047f7cb47662c5a1cf6999337c">DIRECTION_CW</a> enum value</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a3591e29a236e2935afd7f64ff6c22006">disableOutputs</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a748665c3962e66fbc0e9373eb14c69c1">distanceToGo</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5ac3523e4cf6763ba518d16fec3708ef23">DRIVER</a> enum value</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#aa279a50d30d0413f570c692cff071643">enableOutputs</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">virtual</span></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5a62a305b52f749ff8c89138273fbb012d">FULL2WIRE</a> enum value</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5a0b8eea5cf0f8ce70b1959d2977ccc996">FULL3WIRE</a> enum value</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5adedd394a375190a3df8d4519c0d4dc2f">FULL4WIRE</a> enum value</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5af5bb99ad9d67ad2d85f840e3abcfe068">FUNCTION</a> enum value</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5a00c2387a5af43d8e97639699ab7a5c7f">HALF3WIRE</a> enum value</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5aecc0900c55b777d2e885581b8c434b07">HALF4WIRE</a> enum value</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a3a60cc0b962f8ceb81ee1e6f36443ceb">isRunning</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a6123a1dfb4495d8bd2646288eae60d7f">maxSpeed</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5">MotorInterfaceType</a> enum name</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a68942c66e78fb7f7b5f0cdade6eb7f06">move</a>(long relative)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#ace236ede35f87c63d18da25810ec9736">moveTo</a>(long absolute)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a608b2395b64ac15451d16d0371fe13ce">run</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#aa4a6bdf99f698284faaeb5542b0b7514">runSpeed</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a9270d20336e76ac1fd5bcd5b9c34f301">runSpeedToPosition</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a176c5d2e4c2f21e9e92b12e39a6f0e67">runToNewPosition</a>(long position)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a344f58fef8cc34ac5aa75ba4b665d21c">runToPosition</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#adfb19e3cd2a028a1fe78131787604fd1">setAcceleration</a>(float acceleration)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a9d917f014317fb9d3b5dc14e66f6c689">setCurrentPosition</a>(long position)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a56a81c5f00d02ca19646718e88e974c0">setEnablePin</a>(uint8_t enablePin=0xff)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#abee8d466229b87accba33d6ec929c18f">setMaxSpeed</a>(float speed)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#af4d3818e691dad5dc518308796ccf154">setMinPulseWidth</a>(unsigned int minWidth)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#af3c2516b6ce7c1ecbc2004107bb2a9ce">setOutputPins</a>(uint8_t mask)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#ac62cae590c2f9c303519a3a1c4adc8ab">setPinsInverted</a>(bool directionInvert=false, bool stepInvert=false, bool enableInvert=false)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a38298ac2dd852fb22259f6c4bbe08c94">setPinsInverted</a>(bool pin1Invert, bool pin2Invert, bool pin3Invert, bool pin4Invert, bool enableInvert)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#ae79c49ad69d5ccc9da0ee691fa4ca235">setSpeed</a>(float speed)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a4f0989d0ae264e7eadfe1fa720769fb6">speed</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a8a419121702399d8ac66df4cc47481f4">step</a>(long step)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#aa2913db789e6fa05756579ff82fe6e7e">step0</a>(long step)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a63ef416bc039da539294e84a41e7d7dc">step1</a>(long step)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a674e48a6bf99e7ad1f013c1e4414565a">step2</a>(long step)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#ad73c61aade2e10243dfb02aefa7ab8fd">step3</a>(long step)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a8910bd9218a54dfb7e2372a6d0bcca0c">step4</a>(long step)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a4b0faf1ebc0c584ab606c0c0f66986b0">step6</a>(long step)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#aa909c6c3fcd3ea4b3ee1aa8b4d0f7e87">step8</a>(long step)</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"><span class="mlabel">protected</span><span class="mlabel">virtual</span></td></tr>
|
||||
<tr class="even"><td class="entry"><a class="el" href="classAccelStepper.html#a638817b85aed9d5cd15c76a76c00aced">stop</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
<tr><td class="entry"><a class="el" href="classAccelStepper.html#a96685e0945b7cf75d5959da679cd911e">targetPosition</a>()</td><td class="entry"><a class="el" href="classAccelStepper.html">AccelStepper</a></td><td class="entry"></td></tr>
|
||||
</table></div><!-- contents -->
|
||||
<!-- start footer part -->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated by  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||
</a> 1.8.13
|
||||
</small></address>
|
||||
</body>
|
||||
</html>
|
||||
1346
libraries/AccelStepper/extras/doc/classAccelStepper.html
Normal file
1346
libraries/AccelStepper/extras/doc/classAccelStepper.html
Normal file
File diff suppressed because it is too large
Load Diff
1596
libraries/AccelStepper/extras/doc/doxygen.css
Normal file
1596
libraries/AccelStepper/extras/doc/doxygen.css
Normal file
File diff suppressed because it is too large
Load Diff
BIN
libraries/AccelStepper/extras/doc/doxygen.png
Normal file
BIN
libraries/AccelStepper/extras/doc/doxygen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
58
libraries/AccelStepper/extras/doc/files.html
Normal file
58
libraries/AccelStepper/extras/doc/files.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.13"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>AccelStepper: File List</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">AccelStepper
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.13 -->
|
||||
<script type="text/javascript" src="menudata.js"></script>
|
||||
<script type="text/javascript" src="menu.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
initMenu('',false,false,'search.php','Search');
|
||||
});
|
||||
</script>
|
||||
<div id="main-nav"></div>
|
||||
</div><!-- top -->
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">File List</div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock">Here is a list of all documented files with brief descriptions:</div><div class="directory">
|
||||
<table class="directory">
|
||||
<tr id="row_0_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a href="AccelStepper_8h_source.html"><span class="icondoc"></span></a><b>AccelStepper.h</b></td><td class="desc"></td></tr>
|
||||
<tr id="row_1_"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a href="MultiStepper_8h_source.html"><span class="icondoc"></span></a><b>MultiStepper.h</b></td><td class="desc"></td></tr>
|
||||
</table>
|
||||
</div><!-- directory -->
|
||||
</div><!-- contents -->
|
||||
<!-- start footer part -->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated by  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||
</a> 1.8.13
|
||||
</small></address>
|
||||
</body>
|
||||
</html>
|
||||
243
libraries/AccelStepper/extras/doc/functions.html
Normal file
243
libraries/AccelStepper/extras/doc/functions.html
Normal file
@@ -0,0 +1,243 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.13"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>AccelStepper: Class Members</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">AccelStepper
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.13 -->
|
||||
<script type="text/javascript" src="menudata.js"></script>
|
||||
<script type="text/javascript" src="menu.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
initMenu('',false,false,'search.php','Search');
|
||||
});
|
||||
</script>
|
||||
<div id="main-nav"></div>
|
||||
</div><!-- top -->
|
||||
<div class="contents">
|
||||
<div class="textblock">Here is a list of all documented class members with links to the class documentation for each member:</div>
|
||||
|
||||
<h3><a id="index__"></a>- _ -</h3><ul>
|
||||
<li>_direction
|
||||
: <a class="el" href="classAccelStepper.html#a35162cdf8ed9a98f98984c177d5ade58">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_a"></a>- a -</h3><ul>
|
||||
<li>AccelStepper()
|
||||
: <a class="el" href="classAccelStepper.html#a3bc75bd6571b98a6177838ca81ac39ab">AccelStepper</a>
|
||||
</li>
|
||||
<li>addStepper()
|
||||
: <a class="el" href="classMultiStepper.html#a383d8486e17ad9de9f1bafcbd9aa52ee">MultiStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_c"></a>- c -</h3><ul>
|
||||
<li>computeNewSpeed()
|
||||
: <a class="el" href="classAccelStepper.html#affbee789b5c19165846cf0409860ae79">AccelStepper</a>
|
||||
</li>
|
||||
<li>currentPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a5dce13ab2a1b02b8f443318886bf6fc5">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_d"></a>- d -</h3><ul>
|
||||
<li>Direction
|
||||
: <a class="el" href="classAccelStepper.html#a7468f91a925c689c3ba250f8d074d228">AccelStepper</a>
|
||||
</li>
|
||||
<li>DIRECTION_CCW
|
||||
: <a class="el" href="classAccelStepper.html#a7468f91a925c689c3ba250f8d074d228a6959a4549f734bd771d418f995ba4fb4">AccelStepper</a>
|
||||
</li>
|
||||
<li>DIRECTION_CW
|
||||
: <a class="el" href="classAccelStepper.html#a7468f91a925c689c3ba250f8d074d228ad604e0047f7cb47662c5a1cf6999337c">AccelStepper</a>
|
||||
</li>
|
||||
<li>disableOutputs()
|
||||
: <a class="el" href="classAccelStepper.html#a3591e29a236e2935afd7f64ff6c22006">AccelStepper</a>
|
||||
</li>
|
||||
<li>distanceToGo()
|
||||
: <a class="el" href="classAccelStepper.html#a748665c3962e66fbc0e9373eb14c69c1">AccelStepper</a>
|
||||
</li>
|
||||
<li>DRIVER
|
||||
: <a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5ac3523e4cf6763ba518d16fec3708ef23">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_e"></a>- e -</h3><ul>
|
||||
<li>enableOutputs()
|
||||
: <a class="el" href="classAccelStepper.html#aa279a50d30d0413f570c692cff071643">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_f"></a>- f -</h3><ul>
|
||||
<li>FULL2WIRE
|
||||
: <a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5a62a305b52f749ff8c89138273fbb012d">AccelStepper</a>
|
||||
</li>
|
||||
<li>FULL3WIRE
|
||||
: <a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5a0b8eea5cf0f8ce70b1959d2977ccc996">AccelStepper</a>
|
||||
</li>
|
||||
<li>FULL4WIRE
|
||||
: <a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5adedd394a375190a3df8d4519c0d4dc2f">AccelStepper</a>
|
||||
</li>
|
||||
<li>FUNCTION
|
||||
: <a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5af5bb99ad9d67ad2d85f840e3abcfe068">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_h"></a>- h -</h3><ul>
|
||||
<li>HALF3WIRE
|
||||
: <a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5a00c2387a5af43d8e97639699ab7a5c7f">AccelStepper</a>
|
||||
</li>
|
||||
<li>HALF4WIRE
|
||||
: <a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5aecc0900c55b777d2e885581b8c434b07">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_i"></a>- i -</h3><ul>
|
||||
<li>isRunning()
|
||||
: <a class="el" href="classAccelStepper.html#a3a60cc0b962f8ceb81ee1e6f36443ceb">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_m"></a>- m -</h3><ul>
|
||||
<li>maxSpeed()
|
||||
: <a class="el" href="classAccelStepper.html#a6123a1dfb4495d8bd2646288eae60d7f">AccelStepper</a>
|
||||
</li>
|
||||
<li>MotorInterfaceType
|
||||
: <a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5">AccelStepper</a>
|
||||
</li>
|
||||
<li>move()
|
||||
: <a class="el" href="classAccelStepper.html#a68942c66e78fb7f7b5f0cdade6eb7f06">AccelStepper</a>
|
||||
</li>
|
||||
<li>moveTo()
|
||||
: <a class="el" href="classAccelStepper.html#ace236ede35f87c63d18da25810ec9736">AccelStepper</a>
|
||||
, <a class="el" href="classMultiStepper.html#a291fec32a79390b6eb00296cffac49ee">MultiStepper</a>
|
||||
</li>
|
||||
<li>MultiStepper()
|
||||
: <a class="el" href="classMultiStepper.html#a14c0c1c0f55e5bbdc4971730e32304c2">MultiStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_r"></a>- r -</h3><ul>
|
||||
<li>run()
|
||||
: <a class="el" href="classAccelStepper.html#a608b2395b64ac15451d16d0371fe13ce">AccelStepper</a>
|
||||
, <a class="el" href="classMultiStepper.html#a26c2f53b1e7ddf5d5dfb333f6fb7fb92">MultiStepper</a>
|
||||
</li>
|
||||
<li>runSpeed()
|
||||
: <a class="el" href="classAccelStepper.html#aa4a6bdf99f698284faaeb5542b0b7514">AccelStepper</a>
|
||||
</li>
|
||||
<li>runSpeedToPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a9270d20336e76ac1fd5bcd5b9c34f301">AccelStepper</a>
|
||||
, <a class="el" href="classMultiStepper.html#a2592f55864ce3ace125944db624317bc">MultiStepper</a>
|
||||
</li>
|
||||
<li>runToNewPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a176c5d2e4c2f21e9e92b12e39a6f0e67">AccelStepper</a>
|
||||
</li>
|
||||
<li>runToPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a344f58fef8cc34ac5aa75ba4b665d21c">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_s"></a>- s -</h3><ul>
|
||||
<li>setAcceleration()
|
||||
: <a class="el" href="classAccelStepper.html#adfb19e3cd2a028a1fe78131787604fd1">AccelStepper</a>
|
||||
</li>
|
||||
<li>setCurrentPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a9d917f014317fb9d3b5dc14e66f6c689">AccelStepper</a>
|
||||
</li>
|
||||
<li>setEnablePin()
|
||||
: <a class="el" href="classAccelStepper.html#a56a81c5f00d02ca19646718e88e974c0">AccelStepper</a>
|
||||
</li>
|
||||
<li>setMaxSpeed()
|
||||
: <a class="el" href="classAccelStepper.html#abee8d466229b87accba33d6ec929c18f">AccelStepper</a>
|
||||
</li>
|
||||
<li>setMinPulseWidth()
|
||||
: <a class="el" href="classAccelStepper.html#af4d3818e691dad5dc518308796ccf154">AccelStepper</a>
|
||||
</li>
|
||||
<li>setOutputPins()
|
||||
: <a class="el" href="classAccelStepper.html#af3c2516b6ce7c1ecbc2004107bb2a9ce">AccelStepper</a>
|
||||
</li>
|
||||
<li>setPinsInverted()
|
||||
: <a class="el" href="classAccelStepper.html#ac62cae590c2f9c303519a3a1c4adc8ab">AccelStepper</a>
|
||||
</li>
|
||||
<li>setSpeed()
|
||||
: <a class="el" href="classAccelStepper.html#ae79c49ad69d5ccc9da0ee691fa4ca235">AccelStepper</a>
|
||||
</li>
|
||||
<li>speed()
|
||||
: <a class="el" href="classAccelStepper.html#a4f0989d0ae264e7eadfe1fa720769fb6">AccelStepper</a>
|
||||
</li>
|
||||
<li>step()
|
||||
: <a class="el" href="classAccelStepper.html#a8a419121702399d8ac66df4cc47481f4">AccelStepper</a>
|
||||
</li>
|
||||
<li>step0()
|
||||
: <a class="el" href="classAccelStepper.html#aa2913db789e6fa05756579ff82fe6e7e">AccelStepper</a>
|
||||
</li>
|
||||
<li>step1()
|
||||
: <a class="el" href="classAccelStepper.html#a63ef416bc039da539294e84a41e7d7dc">AccelStepper</a>
|
||||
</li>
|
||||
<li>step2()
|
||||
: <a class="el" href="classAccelStepper.html#a674e48a6bf99e7ad1f013c1e4414565a">AccelStepper</a>
|
||||
</li>
|
||||
<li>step3()
|
||||
: <a class="el" href="classAccelStepper.html#ad73c61aade2e10243dfb02aefa7ab8fd">AccelStepper</a>
|
||||
</li>
|
||||
<li>step4()
|
||||
: <a class="el" href="classAccelStepper.html#a8910bd9218a54dfb7e2372a6d0bcca0c">AccelStepper</a>
|
||||
</li>
|
||||
<li>step6()
|
||||
: <a class="el" href="classAccelStepper.html#a4b0faf1ebc0c584ab606c0c0f66986b0">AccelStepper</a>
|
||||
</li>
|
||||
<li>step8()
|
||||
: <a class="el" href="classAccelStepper.html#aa909c6c3fcd3ea4b3ee1aa8b4d0f7e87">AccelStepper</a>
|
||||
</li>
|
||||
<li>stop()
|
||||
: <a class="el" href="classAccelStepper.html#a638817b85aed9d5cd15c76a76c00aced">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_t"></a>- t -</h3><ul>
|
||||
<li>targetPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a96685e0945b7cf75d5959da679cd911e">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div><!-- contents -->
|
||||
<!-- start footer part -->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated by  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||
</a> 1.8.13
|
||||
</small></address>
|
||||
</body>
|
||||
</html>
|
||||
195
libraries/AccelStepper/extras/doc/functions_func.html
Normal file
195
libraries/AccelStepper/extras/doc/functions_func.html
Normal file
@@ -0,0 +1,195 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.13"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>AccelStepper: Class Members - Functions</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">AccelStepper
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.13 -->
|
||||
<script type="text/javascript" src="menudata.js"></script>
|
||||
<script type="text/javascript" src="menu.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
initMenu('',false,false,'search.php','Search');
|
||||
});
|
||||
</script>
|
||||
<div id="main-nav"></div>
|
||||
</div><!-- top -->
|
||||
<div class="contents">
|
||||
 
|
||||
|
||||
<h3><a id="index_a"></a>- a -</h3><ul>
|
||||
<li>AccelStepper()
|
||||
: <a class="el" href="classAccelStepper.html#a3bc75bd6571b98a6177838ca81ac39ab">AccelStepper</a>
|
||||
</li>
|
||||
<li>addStepper()
|
||||
: <a class="el" href="classMultiStepper.html#a383d8486e17ad9de9f1bafcbd9aa52ee">MultiStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_c"></a>- c -</h3><ul>
|
||||
<li>computeNewSpeed()
|
||||
: <a class="el" href="classAccelStepper.html#affbee789b5c19165846cf0409860ae79">AccelStepper</a>
|
||||
</li>
|
||||
<li>currentPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a5dce13ab2a1b02b8f443318886bf6fc5">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_d"></a>- d -</h3><ul>
|
||||
<li>disableOutputs()
|
||||
: <a class="el" href="classAccelStepper.html#a3591e29a236e2935afd7f64ff6c22006">AccelStepper</a>
|
||||
</li>
|
||||
<li>distanceToGo()
|
||||
: <a class="el" href="classAccelStepper.html#a748665c3962e66fbc0e9373eb14c69c1">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_e"></a>- e -</h3><ul>
|
||||
<li>enableOutputs()
|
||||
: <a class="el" href="classAccelStepper.html#aa279a50d30d0413f570c692cff071643">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_i"></a>- i -</h3><ul>
|
||||
<li>isRunning()
|
||||
: <a class="el" href="classAccelStepper.html#a3a60cc0b962f8ceb81ee1e6f36443ceb">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_m"></a>- m -</h3><ul>
|
||||
<li>maxSpeed()
|
||||
: <a class="el" href="classAccelStepper.html#a6123a1dfb4495d8bd2646288eae60d7f">AccelStepper</a>
|
||||
</li>
|
||||
<li>move()
|
||||
: <a class="el" href="classAccelStepper.html#a68942c66e78fb7f7b5f0cdade6eb7f06">AccelStepper</a>
|
||||
</li>
|
||||
<li>moveTo()
|
||||
: <a class="el" href="classAccelStepper.html#ace236ede35f87c63d18da25810ec9736">AccelStepper</a>
|
||||
, <a class="el" href="classMultiStepper.html#a291fec32a79390b6eb00296cffac49ee">MultiStepper</a>
|
||||
</li>
|
||||
<li>MultiStepper()
|
||||
: <a class="el" href="classMultiStepper.html#a14c0c1c0f55e5bbdc4971730e32304c2">MultiStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_r"></a>- r -</h3><ul>
|
||||
<li>run()
|
||||
: <a class="el" href="classAccelStepper.html#a608b2395b64ac15451d16d0371fe13ce">AccelStepper</a>
|
||||
, <a class="el" href="classMultiStepper.html#a26c2f53b1e7ddf5d5dfb333f6fb7fb92">MultiStepper</a>
|
||||
</li>
|
||||
<li>runSpeed()
|
||||
: <a class="el" href="classAccelStepper.html#aa4a6bdf99f698284faaeb5542b0b7514">AccelStepper</a>
|
||||
</li>
|
||||
<li>runSpeedToPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a9270d20336e76ac1fd5bcd5b9c34f301">AccelStepper</a>
|
||||
, <a class="el" href="classMultiStepper.html#a2592f55864ce3ace125944db624317bc">MultiStepper</a>
|
||||
</li>
|
||||
<li>runToNewPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a176c5d2e4c2f21e9e92b12e39a6f0e67">AccelStepper</a>
|
||||
</li>
|
||||
<li>runToPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a344f58fef8cc34ac5aa75ba4b665d21c">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_s"></a>- s -</h3><ul>
|
||||
<li>setAcceleration()
|
||||
: <a class="el" href="classAccelStepper.html#adfb19e3cd2a028a1fe78131787604fd1">AccelStepper</a>
|
||||
</li>
|
||||
<li>setCurrentPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a9d917f014317fb9d3b5dc14e66f6c689">AccelStepper</a>
|
||||
</li>
|
||||
<li>setEnablePin()
|
||||
: <a class="el" href="classAccelStepper.html#a56a81c5f00d02ca19646718e88e974c0">AccelStepper</a>
|
||||
</li>
|
||||
<li>setMaxSpeed()
|
||||
: <a class="el" href="classAccelStepper.html#abee8d466229b87accba33d6ec929c18f">AccelStepper</a>
|
||||
</li>
|
||||
<li>setMinPulseWidth()
|
||||
: <a class="el" href="classAccelStepper.html#af4d3818e691dad5dc518308796ccf154">AccelStepper</a>
|
||||
</li>
|
||||
<li>setOutputPins()
|
||||
: <a class="el" href="classAccelStepper.html#af3c2516b6ce7c1ecbc2004107bb2a9ce">AccelStepper</a>
|
||||
</li>
|
||||
<li>setPinsInverted()
|
||||
: <a class="el" href="classAccelStepper.html#a38298ac2dd852fb22259f6c4bbe08c94">AccelStepper</a>
|
||||
</li>
|
||||
<li>setSpeed()
|
||||
: <a class="el" href="classAccelStepper.html#ae79c49ad69d5ccc9da0ee691fa4ca235">AccelStepper</a>
|
||||
</li>
|
||||
<li>speed()
|
||||
: <a class="el" href="classAccelStepper.html#a4f0989d0ae264e7eadfe1fa720769fb6">AccelStepper</a>
|
||||
</li>
|
||||
<li>step()
|
||||
: <a class="el" href="classAccelStepper.html#a8a419121702399d8ac66df4cc47481f4">AccelStepper</a>
|
||||
</li>
|
||||
<li>step0()
|
||||
: <a class="el" href="classAccelStepper.html#aa2913db789e6fa05756579ff82fe6e7e">AccelStepper</a>
|
||||
</li>
|
||||
<li>step1()
|
||||
: <a class="el" href="classAccelStepper.html#a63ef416bc039da539294e84a41e7d7dc">AccelStepper</a>
|
||||
</li>
|
||||
<li>step2()
|
||||
: <a class="el" href="classAccelStepper.html#a674e48a6bf99e7ad1f013c1e4414565a">AccelStepper</a>
|
||||
</li>
|
||||
<li>step3()
|
||||
: <a class="el" href="classAccelStepper.html#ad73c61aade2e10243dfb02aefa7ab8fd">AccelStepper</a>
|
||||
</li>
|
||||
<li>step4()
|
||||
: <a class="el" href="classAccelStepper.html#a8910bd9218a54dfb7e2372a6d0bcca0c">AccelStepper</a>
|
||||
</li>
|
||||
<li>step6()
|
||||
: <a class="el" href="classAccelStepper.html#a4b0faf1ebc0c584ab606c0c0f66986b0">AccelStepper</a>
|
||||
</li>
|
||||
<li>step8()
|
||||
: <a class="el" href="classAccelStepper.html#aa909c6c3fcd3ea4b3ee1aa8b4d0f7e87">AccelStepper</a>
|
||||
</li>
|
||||
<li>stop()
|
||||
: <a class="el" href="classAccelStepper.html#a638817b85aed9d5cd15c76a76c00aced">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3><a id="index_t"></a>- t -</h3><ul>
|
||||
<li>targetPosition()
|
||||
: <a class="el" href="classAccelStepper.html#a96685e0945b7cf75d5959da679cd911e">AccelStepper</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div><!-- contents -->
|
||||
<!-- start footer part -->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated by  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||
</a> 1.8.13
|
||||
</small></address>
|
||||
</body>
|
||||
</html>
|
||||
226
libraries/AccelStepper/extras/doc/index.html
Normal file
226
libraries/AccelStepper/extras/doc/index.html
Normal file
@@ -0,0 +1,226 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||||
<meta name="generator" content="Doxygen 1.8.13"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<title>AccelStepper: AccelStepper library for Arduino</title>
|
||||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div id="titlearea">
|
||||
<table cellspacing="0" cellpadding="0">
|
||||
<tbody>
|
||||
<tr style="height: 56px;">
|
||||
<td id="projectalign" style="padding-left: 0.5em;">
|
||||
<div id="projectname">AccelStepper
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.13 -->
|
||||
<script type="text/javascript" src="menudata.js"></script>
|
||||
<script type="text/javascript" src="menu.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
initMenu('',false,false,'search.php','Search');
|
||||
});
|
||||
</script>
|
||||
<div id="main-nav"></div>
|
||||
</div><!-- top -->
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title"><a class="el" href="classAccelStepper.html" title="Support for stepper motors with acceleration etc. ">AccelStepper</a> library for Arduino </div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock"><p>This is the Arduino <a class="el" href="classAccelStepper.html" title="Support for stepper motors with acceleration etc. ">AccelStepper</a> library. It provides an object-oriented interface for 2, 3 or 4 pin stepper motors and motor drivers.</p>
|
||||
<p>The standard Arduino IDE includes the Stepper library (<a href="http://arduino.cc/en/Reference/Stepper">http://arduino.cc/en/Reference/Stepper</a>) for stepper motors. It is perfectly adequate for simple, single motor applications.</p>
|
||||
<p><a class="el" href="classAccelStepper.html" title="Support for stepper motors with acceleration etc. ">AccelStepper</a> significantly improves on the standard Arduino Stepper library in several ways: </p><ul>
|
||||
<li>Supports acceleration and deceleration </li>
|
||||
<li>Supports multiple simultaneous steppers, with independent concurrent stepping on each stepper </li>
|
||||
<li>Most API functions never delay() or block (unless otherwise stated) </li>
|
||||
<li>Supports 2, 3 and 4 wire steppers, plus 3 and 4 wire half steppers. </li>
|
||||
<li>Supports alternate stepping functions to enable support of AFMotor (<a href="https://github.com/adafruit/Adafruit-Motor-Shield-library">https://github.com/adafruit/Adafruit-Motor-Shield-library</a>) </li>
|
||||
<li>Supports stepper drivers such as the Sparkfun EasyDriver (based on 3967 driver chip) </li>
|
||||
<li>Very slow speeds are supported </li>
|
||||
<li>Extensive API </li>
|
||||
<li>Subclass support</li>
|
||||
</ul>
|
||||
<p>The latest version of this documentation can be downloaded from <a href="http://www.airspayce.com/mikem/arduino/AccelStepper">http://www.airspayce.com/mikem/arduino/AccelStepper</a> The version of the package that this documentation refers to can be downloaded from <a href="http://www.airspayce.com/mikem/arduino/AccelStepper/AccelStepper-1.61.zip">http://www.airspayce.com/mikem/arduino/AccelStepper/AccelStepper-1.61.zip</a></p>
|
||||
<p>Example Arduino programs are included to show the main modes of use.</p>
|
||||
<p>You can also find online help and discussion at <a href="http://groups.google.com/group/accelstepper">http://groups.google.com/group/accelstepper</a> Please use that group for all questions and discussions on this topic. Do not contact the author directly, unless it is to discuss commercial licensing. Before asking a question or reporting a bug, please read</p><ul>
|
||||
<li><a href="http://en.wikipedia.org/wiki/Wikipedia:Reference_desk/How_to_ask_a_software_question">http://en.wikipedia.org/wiki/Wikipedia:Reference_desk/How_to_ask_a_software_question</a></li>
|
||||
<li><a href="http://www.catb.org/esr/faqs/smart-questions.html">http://www.catb.org/esr/faqs/smart-questions.html</a></li>
|
||||
<li><a href="http://www.chiark.greenend.org.uk/~shgtatham/bugs.html">http://www.chiark.greenend.org.uk/~shgtatham/bugs.html</a></li>
|
||||
</ul>
|
||||
<p>Tested on Arduino Diecimila and Mega with arduino-0018 & arduino-0021 on OpenSuSE 11.1 and avr-libc-1.6.1-1.15, cross-avr-binutils-2.19-9.1, cross-avr-gcc-4.1.3_20080612-26.5. Tested on Teensy <a href="http://www.pjrc.com/teensy">http://www.pjrc.com/teensy</a> including Teensy 3.1 built using Arduino IDE 1.0.5 with teensyduino addon 1.18 and later.</p>
|
||||
<dl class="section user"><dt>Installation</dt><dd></dd></dl>
|
||||
<p>Install in the usual way: unzip the distribution zip file to the libraries sub-folder of your sketchbook.</p>
|
||||
<dl class="section user"><dt>Theory</dt><dd></dd></dl>
|
||||
<p>This code uses speed calculations as described in "Generate stepper-motor speed profiles in real time" by David Austin <a href="http://fab.cba.mit.edu/classes/MIT/961.09/projects/i0/Stepper_Motor_Speed_Profile.pdf">http://fab.cba.mit.edu/classes/MIT/961.09/projects/i0/Stepper_Motor_Speed_Profile.pdf</a> or <a href="http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time">http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time</a> or <a href="http://web.archive.org/web/20140705143928/http://fab.cba.mit.edu/classes/MIT/961.09/projects/i0/Stepper_Motor_Speed_Profile.pdf">http://web.archive.org/web/20140705143928/http://fab.cba.mit.edu/classes/MIT/961.09/projects/i0/Stepper_Motor_Speed_Profile.pdf</a> with the exception that <a class="el" href="classAccelStepper.html" title="Support for stepper motors with acceleration etc. ">AccelStepper</a> uses steps per second rather than radians per second (because we dont know the step angle of the motor) An initial step interval is calculated for the first step, based on the desired acceleration On subsequent steps, shorter step intervals are calculated based on the previous step until max speed is achieved.</p>
|
||||
<dl class="section user"><dt>Adafruit Motor Shield V2</dt><dd></dd></dl>
|
||||
<p>The included examples AFMotor_* are for Adafruit Motor Shield V1 and do not work with Adafruit Motor Shield V2. See <a href="https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library">https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library</a> for examples that work with Adafruit Motor Shield V2.</p>
|
||||
<dl class="section user"><dt>Donations</dt><dd></dd></dl>
|
||||
<p>This library is offered under a free GPL license for those who want to use it that way. We try hard to keep it up to date, fix bugs and to provide free support. If this library has helped you save time or money, please consider donating at <a href="http://www.airspayce.com">http://www.airspayce.com</a> or here:</p>
|
||||
<p> <form action="https://www.paypal.com/cgi-bin/webscr" method="post"><input type="hidden" name="cmd" value="_donations" /> <input type="hidden" name="business" value="mikem@airspayce.com" /> <input type="hidden" name="lc" value="AU" /> <input type="hidden" name="item_name" value="Airspayce" /> <input type="hidden" name="item_number" value="AccelStepper" /> <input type="hidden" name="currency_code" value="USD" /> <input type="hidden" name="bn" value="PP-DonationsBF:btn_donateCC_LG.gif:NonHosted" /> <input type="image" alt="PayPal — The safer, easier way to pay online." name="submit" src="https://www.paypalobjects.com/en_AU/i/btn/btn_donateCC_LG.gif" /> <img alt="" src="https://www.paypalobjects.com/en_AU/i/scr/pixel.gif" width="1" height="1" border="0" /></form> </p>
|
||||
<dl class="section user"><dt>Trademarks</dt><dd></dd></dl>
|
||||
<p><a class="el" href="classAccelStepper.html" title="Support for stepper motors with acceleration etc. ">AccelStepper</a> is a trademark of AirSpayce Pty Ltd. The <a class="el" href="classAccelStepper.html" title="Support for stepper motors with acceleration etc. ">AccelStepper</a> mark was first used on April 26 2010 for international trade, and is used only in relation to motor control hardware and software. It is not to be confused with any other similar marks covering other goods and services.</p>
|
||||
<dl class="section user"><dt>Copyright</dt><dd></dd></dl>
|
||||
<p>This software is Copyright (C) 2010-2018 Mike McCauley. Use is subject to license conditions. The main licensing options available are GPL V3 or Commercial:</p>
|
||||
<dl class="section user"><dt>Open Source Licensing GPL V3</dt><dd>This is the appropriate option if you want to share the source code of your application with everyone you distribute it to, and you also want to give them the right to share who uses it. If you wish to use this software under Open Source Licensing, you must contribute all your source code to the open source community in accordance with the GPL Version 23 when your application is distributed. See <a href="https://www.gnu.org/licenses/gpl-3.0.html">https://www.gnu.org/licenses/gpl-3.0.html</a></dd></dl>
|
||||
<dl class="section user"><dt>Commercial Licensing</dt><dd>This is the appropriate option if you are creating proprietary applications and you are not prepared to distribute and share the source code of your application. To purchase a commercial license, contact <a href="#" onclick="location.href='mai'+'lto:'+'inf'+'o@'+'air'+'sp'+'ayc'+'e.'+'com'; return false;">info@<span style="display: none;">.nosp@m.</span>airs<span style="display: none;">.nosp@m.</span>payce<span style="display: none;">.nosp@m.</span>.com</a></dd></dl>
|
||||
<dl class="section user"><dt>Revision History</dt><dd></dd></dl>
|
||||
<dl class="section version"><dt>Version</dt><dd>1.0 Initial release</dd>
|
||||
<dd>
|
||||
1.1 Added speed() function to get the current speed. </dd>
|
||||
<dd>
|
||||
1.2 Added runSpeedToPosition() submitted by Gunnar Arndt. </dd>
|
||||
<dd>
|
||||
1.3 Added support for stepper drivers (ie with Step and Direction inputs) with _pins == 1 </dd>
|
||||
<dd>
|
||||
1.4 Added functional contructor to support AFMotor, contributed by Limor, with example sketches. </dd>
|
||||
<dd>
|
||||
1.5 Improvements contributed by Peter Mousley: Use of microsecond steps and other speed improvements to increase max stepping speed to about 4kHz. New option for user to set the min allowed pulse width. Added checks for already running at max speed and skip further calcs if so. </dd>
|
||||
<dd>
|
||||
1.6 Fixed a problem with wrapping of microsecond stepping that could cause stepping to hang. Reported by Sandy Noble. Removed redundant _lastRunTime member. </dd>
|
||||
<dd>
|
||||
1.7 Fixed a bug where setCurrentPosition() did not always work as expected. Reported by Peter Linhart. </dd>
|
||||
<dd>
|
||||
1.8 Added support for 4 pin half-steppers, requested by Harvey Moon </dd>
|
||||
<dd>
|
||||
1.9 setCurrentPosition() now also sets motor speed to 0. </dd>
|
||||
<dd>
|
||||
1.10 Builds on Arduino 1.0 </dd>
|
||||
<dd>
|
||||
1.11 Improvments from Michael Ellison: Added optional enable line support for stepper drivers Added inversion for step/direction/enable lines for stepper drivers </dd>
|
||||
<dd>
|
||||
1.12 Announce Google Group </dd>
|
||||
<dd>
|
||||
1.13 Improvements to speed calculation. Cost of calculation is now less in the worst case, and more or less constant in all cases. This should result in slightly beter high speed performance, and reduce anomalous speed glitches when other steppers are accelerating. However, its hard to see how to replace the sqrt() required at the very first step from 0 speed. </dd>
|
||||
<dd>
|
||||
1.14 Fixed a problem with compiling under arduino 0021 reported by EmbeddedMan </dd>
|
||||
<dd>
|
||||
1.15 Fixed a problem with runSpeedToPosition which did not correctly handle running backwards to a smaller target position. Added examples </dd>
|
||||
<dd>
|
||||
1.16 Fixed some cases in the code where abs() was used instead of fabs(). </dd>
|
||||
<dd>
|
||||
1.17 Added example ProportionalControl </dd>
|
||||
<dd>
|
||||
1.18 Fixed a problem: If one calls the funcion runSpeed() when Speed is zero, it makes steps without counting. reported by Friedrich, Klappenbach. </dd>
|
||||
<dd>
|
||||
1.19 Added MotorInterfaceType and symbolic names for the number of pins to use for the motor interface. Updated examples to suit. Replaced individual pin assignment variables _pin1, _pin2 etc with array _pin[4]. _pins member changed to _interface. Added _pinInverted array to simplify pin inversion operations. Added new function setOutputPins() which sets the motor output pins. It can be overridden in order to provide, say, serial output instead of parallel output Some refactoring and code size reduction. </dd>
|
||||
<dd>
|
||||
1.20 Improved documentation and examples to show need for correctly specifying <a class="el" href="classAccelStepper.html#a73bdecf1273d98d8c5fbcb764cabeea5adedd394a375190a3df8d4519c0d4dc2f" title="4 wire full stepper, 4 motor pins required ">AccelStepper::FULL4WIRE</a> and friends. </dd>
|
||||
<dd>
|
||||
1.21 Fixed a problem where desiredSpeed could compute the wrong step acceleration when _speed was small but non-zero. Reported by Brian Schmalz. Precompute sqrt_twoa to improve performance and max possible stepping speed </dd>
|
||||
<dd>
|
||||
1.22 Added Bounce.pde example Fixed a problem where calling moveTo(), setMaxSpeed(), setAcceleration() more frequently than the step time, even with the same values, would interfere with speed calcs. Now a new speed is computed only if there was a change in the set value. Reported by Brian Schmalz. </dd>
|
||||
<dd>
|
||||
1.23 Rewrite of the speed algorithms in line with <a href="http://fab.cba.mit.edu/classes/MIT/961.09/projects/i0/Stepper_Motor_Speed_Profile.pdf">http://fab.cba.mit.edu/classes/MIT/961.09/projects/i0/Stepper_Motor_Speed_Profile.pdf</a> Now expect smoother and more linear accelerations and decelerations. The desiredSpeed() function was removed. </dd>
|
||||
<dd>
|
||||
1.24 Fixed a problem introduced in 1.23: with runToPosition, which did never returned </dd>
|
||||
<dd>
|
||||
1.25 Now ignore attempts to set acceleration to 0.0 </dd>
|
||||
<dd>
|
||||
1.26 Fixed a problem where certina combinations of speed and accelration could cause oscillation about the target position. </dd>
|
||||
<dd>
|
||||
1.27 Added stop() function to stop as fast as possible with current acceleration parameters. Also added new Quickstop example showing its use. </dd>
|
||||
<dd>
|
||||
1.28 Fixed another problem where certain combinations of speed and acceleration could cause oscillation about the target position. Added support for 3 wire full and half steppers such as Hard Disk Drive spindle. Contributed by Yuri Ivatchkovitch. </dd>
|
||||
<dd>
|
||||
1.29 Fixed a problem that could cause a DRIVER stepper to continually step with some sketches. Reported by Vadim. </dd>
|
||||
<dd>
|
||||
1.30 Fixed a problem that could cause stepper to back up a few steps at the end of accelerated travel with certain speeds. Reported and patched by jolo. </dd>
|
||||
<dd>
|
||||
1.31 Updated author and distribution location details to airspayce.com </dd>
|
||||
<dd>
|
||||
1.32 Fixed a problem with enableOutputs() and setEnablePin on Arduino Due that prevented the enable pin changing stae correctly. Reported by Duane Bishop. </dd>
|
||||
<dd>
|
||||
1.33 Fixed an error in example AFMotor_ConstantSpeed.pde did not setMaxSpeed(); Fixed a problem that caused incorrect pin sequencing of FULL3WIRE and HALF3WIRE. Unfortunately this meant changing the signature for all step*() functions. Added example MotorShield, showing how to use AdaFruit Motor Shield to control a 3 phase motor such as a HDD spindle motor (and without using the AFMotor library. </dd>
|
||||
<dd>
|
||||
1.34 Added setPinsInverted(bool pin1Invert, bool pin2Invert, bool pin3Invert, bool pin4Invert, bool enableInvert) to allow inversion of 2, 3 and 4 wire stepper pins. Requested by Oleg. </dd>
|
||||
<dd>
|
||||
1.35 Removed default args from setPinsInverted(bool, bool, bool, bool, bool) to prevent ambiguity with setPinsInverted(bool, bool, bool). Reported by Mac Mac. </dd>
|
||||
<dd>
|
||||
1.36 Changed enableOutputs() and disableOutputs() to be virtual so can be overridden. Added new optional argument 'enable' to constructor, which allows you toi disable the automatic enabling of outputs at construction time. Suggested by Guido. </dd>
|
||||
<dd>
|
||||
1.37 Fixed a problem with step1 that could cause a rogue step in the wrong direction (or not, depending on the setup-time requirements of the connected hardware). Reported by Mark Tillotson. </dd>
|
||||
<dd>
|
||||
1.38 run() function incorrectly always returned true. Updated function and doc so it returns true if the motor is still running to the target position. </dd>
|
||||
<dd>
|
||||
1.39 Updated typos in keywords.txt, courtesey Jon Magill. </dd>
|
||||
<dd>
|
||||
1.40 Updated documentation, including testing on Teensy 3.1 </dd>
|
||||
<dd>
|
||||
1.41 Fixed an error in the acceleration calculations, resulting in acceleration of haldf the intended value </dd>
|
||||
<dd>
|
||||
1.42 Improved support for FULL3WIRE and HALF3WIRE output pins. These changes were in Yuri's original contribution but did not make it into production.<br />
|
||||
</dd>
|
||||
<dd>
|
||||
1.43 Added DualMotorShield example. Shows how to use <a class="el" href="classAccelStepper.html" title="Support for stepper motors with acceleration etc. ">AccelStepper</a> to control 2 x 2 phase steppers using the Itead Studio Arduino Dual Stepper Motor Driver Shield model IM120417015.<br />
|
||||
</dd>
|
||||
<dd>
|
||||
1.44 examples/DualMotorShield/DualMotorShield.ino examples/DualMotorShield/DualMotorShield.pde was missing from the distribution.<br />
|
||||
</dd>
|
||||
<dd>
|
||||
1.45 Fixed a problem where if setAcceleration was not called, there was no default acceleration. Reported by Michael Newman.<br />
|
||||
</dd>
|
||||
<dd>
|
||||
1.45 Fixed inaccuracy in acceleration rate by using Equation 15, suggested by Sebastian Gracki.<br />
|
||||
Performance improvements in runSpeed suggested by Jaakko Fagerlund.<br />
|
||||
</dd>
|
||||
<dd>
|
||||
1.46 Fixed error in documentation for runToPosition(). Reinstated time calculations in runSpeed() since new version is reported not to work correctly under some circumstances. Reported by Oleg V Gavva.<br />
|
||||
</dd>
|
||||
<dd>
|
||||
1.48 2015-08-25 Added new class <a class="el" href="classMultiStepper.html" title="Operate multiple AccelSteppers in a co-ordinated fashion. ">MultiStepper</a> that can manage multiple AccelSteppers, and cause them all to move to selected positions at such a (constant) speed that they all arrive at their target position at the same time. Suitable for X-Y flatbeds etc.<br />
|
||||
Added new method maxSpeed() to <a class="el" href="classAccelStepper.html" title="Support for stepper motors with acceleration etc. ">AccelStepper</a> to return the currently configured maxSpeed.<br />
|
||||
</dd>
|
||||
<dd>
|
||||
1.49 2016-01-02 Testing with VID28 series instrument stepper motors and EasyDriver. OK, although with light pointers and slow speeds like 180 full steps per second the motor movement can be erratic, probably due to some mechanical resonance. Best to accelerate through this speed.<br />
|
||||
Added isRunning().<br />
|
||||
</dd>
|
||||
<dd>
|
||||
1.50 2016-02-25 <a class="el" href="classAccelStepper.html#a3591e29a236e2935afd7f64ff6c22006">AccelStepper::disableOutputs</a> now sets the enable pion to OUTPUT mode if the enable pin is defined. Patch from Piet De Jong.<br />
|
||||
Added notes about the fact that AFMotor_* examples do not work with Adafruit Motor Shield V2.<br />
|
||||
</dd>
|
||||
<dd>
|
||||
1.51 2016-03-24 Fixed a problem reported by gregor: when resetting the stepper motor position using setCurrentPosition() the stepper speed is reset by setting _stepInterval to 0, but _speed is not reset. this results in the stepper motor not starting again when calling setSpeed() with the same speed the stepper was set to before. </dd>
|
||||
<dd>
|
||||
1.52 2016-08-09 Added <a class="el" href="classMultiStepper.html" title="Operate multiple AccelSteppers in a co-ordinated fashion. ">MultiStepper</a> to keywords.txt. Improvements to efficiency of <a class="el" href="classAccelStepper.html#aa4a6bdf99f698284faaeb5542b0b7514">AccelStepper::runSpeed()</a> as suggested by David Grayson. Improvements to speed accuracy as suggested by David Grayson. </dd>
|
||||
<dd>
|
||||
1.53 2016-08-14 Backed out Improvements to speed accuracy from 1.52 as it did not work correctly. </dd>
|
||||
<dd>
|
||||
1.54 2017-01-24 Fixed some warnings about unused arguments. </dd>
|
||||
<dd>
|
||||
1.55 2017-01-25 Fixed another warning in MultiStepper.cpp </dd>
|
||||
<dd>
|
||||
1.56 2017-02-03 Fixed minor documentation error with DIRECTION_CCW and DIRECTION_CW. Reported by David Mutterer. Added link to Binpress commercial license purchasing. </dd>
|
||||
<dd>
|
||||
1.57 2017-03-28 _direction moved to protected at the request of Rudy Ercek. setMaxSpeed() and setAcceleration() now correct negative values to be positive. </dd>
|
||||
<dd>
|
||||
1.58 2018-04-13 Add initialisation for _enableInverted in constructor. </dd>
|
||||
<dd>
|
||||
1.59 2018-08-28 Update commercial licensing, remove binpress. </dd>
|
||||
<dd>
|
||||
1.60 2020-03-07 Release under GPL V3 </dd>
|
||||
<dd>
|
||||
1.61 2020-04-20 Added yield() call in runToPosition(), so that platforms like esp8266 dont hang/crash during long runs.</dd></dl>
|
||||
<dl class="section author"><dt>Author</dt><dd>Mike McCauley (<a href="#" onclick="location.href='mai'+'lto:'+'mik'+'em'+'@ai'+'rs'+'pay'+'ce'+'.co'+'m'; return false;">mikem<span style="display: none;">.nosp@m.</span>@air<span style="display: none;">.nosp@m.</span>spayc<span style="display: none;">.nosp@m.</span>e.co<span style="display: none;">.nosp@m.</span>m</a>) DO NOT CONTACT THE AUTHOR DIRECTLY: USE THE LISTS </dd></dl>
|
||||
</div></div><!-- contents -->
|
||||
<!-- start footer part -->
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated by  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||
</a> 1.8.13
|
||||
</small></address>
|
||||
</body>
|
||||
</html>
|
||||
BIN
libraries/AccelStepper/extras/doc/tab_b.gif
Normal file
BIN
libraries/AccelStepper/extras/doc/tab_b.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 B |
BIN
libraries/AccelStepper/extras/doc/tab_l.gif
Normal file
BIN
libraries/AccelStepper/extras/doc/tab_l.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 706 B |
BIN
libraries/AccelStepper/extras/doc/tab_r.gif
Normal file
BIN
libraries/AccelStepper/extras/doc/tab_r.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
1
libraries/AccelStepper/extras/doc/tabs.css
Normal file
1
libraries/AccelStepper/extras/doc/tabs.css
Normal file
File diff suppressed because one or more lines are too long
41
libraries/AccelStepper/keywords.txt
Normal file
41
libraries/AccelStepper/keywords.txt
Normal file
@@ -0,0 +1,41 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For AccelStepper
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
AccelStepper KEYWORD1
|
||||
MultiStepper KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
moveTo KEYWORD2
|
||||
move KEYWORD2
|
||||
run KEYWORD2
|
||||
runSpeed KEYWORD2
|
||||
setMaxSpeed KEYWORD2
|
||||
setAcceleration KEYWORD2
|
||||
setSpeed KEYWORD2
|
||||
speed KEYWORD2
|
||||
distanceToGo KEYWORD2
|
||||
targetPosition KEYWORD2
|
||||
currentPosition KEYWORD2
|
||||
setCurrentPosition KEYWORD2
|
||||
runToPosition KEYWORD2
|
||||
runSpeedToPosition KEYWORD2
|
||||
runToNewPosition KEYWORD2
|
||||
stop KEYWORD2
|
||||
disableOutputs KEYWORD2
|
||||
enableOutputs KEYWORD2
|
||||
setMinPulseWidth KEYWORD2
|
||||
setEnablePin KEYWORD2
|
||||
setPinsInverted KEYWORD2
|
||||
maxSpeed KEYWORD2
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
9
libraries/AccelStepper/library.properties
Normal file
9
libraries/AccelStepper/library.properties
Normal file
@@ -0,0 +1,9 @@
|
||||
name=AccelStepper
|
||||
version=1.61
|
||||
author=Mike McCauley <mikem@airspayce.com>
|
||||
maintainer=Patrick Wasp <patrickwasp@gmail.com>
|
||||
sentence=Allows Arduino boards to control a variety of stepper motors.
|
||||
paragraph=Provides an object-oriented interface for 2, 3 or 4 pin stepper motors and motor drivers.
|
||||
category=Device Control
|
||||
url=http://www.airspayce.com/mikem/arduino/AccelStepper/
|
||||
architectures=*
|
||||
652
libraries/AccelStepper/src/AccelStepper.cpp
Normal file
652
libraries/AccelStepper/src/AccelStepper.cpp
Normal file
@@ -0,0 +1,652 @@
|
||||
// AccelStepper.cpp
|
||||
//
|
||||
// Copyright (C) 2009-2013 Mike McCauley
|
||||
// $Id: AccelStepper.cpp,v 1.24 2020/04/20 00:15:03 mikem Exp mikem $
|
||||
|
||||
#include "AccelStepper.h"
|
||||
|
||||
#if 0
|
||||
// Some debugging assistance
|
||||
void dump(uint8_t* p, int l)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < l; i++)
|
||||
{
|
||||
Serial.print(p[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println("");
|
||||
}
|
||||
#endif
|
||||
|
||||
void AccelStepper::moveTo(long absolute)
|
||||
{
|
||||
if (_targetPos != absolute)
|
||||
{
|
||||
_targetPos = absolute;
|
||||
computeNewSpeed();
|
||||
// compute new n?
|
||||
}
|
||||
}
|
||||
|
||||
void AccelStepper::move(long relative)
|
||||
{
|
||||
moveTo(_currentPos + relative);
|
||||
}
|
||||
|
||||
// Implements steps according to the current step interval
|
||||
// You must call this at least once per step
|
||||
// returns true if a step occurred
|
||||
boolean AccelStepper::runSpeed()
|
||||
{
|
||||
// Dont do anything unless we actually have a step interval
|
||||
if (!_stepInterval)
|
||||
return false;
|
||||
|
||||
unsigned long time = micros();
|
||||
if (time - _lastStepTime >= _stepInterval)
|
||||
{
|
||||
if (_direction == DIRECTION_CW)
|
||||
{
|
||||
// Clockwise
|
||||
_currentPos += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Anticlockwise
|
||||
_currentPos -= 1;
|
||||
}
|
||||
step(_currentPos);
|
||||
|
||||
_lastStepTime = time; // Caution: does not account for costs in step()
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
long AccelStepper::distanceToGo()
|
||||
{
|
||||
return _targetPos - _currentPos;
|
||||
}
|
||||
|
||||
long AccelStepper::targetPosition()
|
||||
{
|
||||
return _targetPos;
|
||||
}
|
||||
|
||||
long AccelStepper::currentPosition()
|
||||
{
|
||||
return _currentPos;
|
||||
}
|
||||
|
||||
// Useful during initialisations or after initial positioning
|
||||
// Sets speed to 0
|
||||
void AccelStepper::setCurrentPosition(long position)
|
||||
{
|
||||
_targetPos = _currentPos = position;
|
||||
_n = 0;
|
||||
_stepInterval = 0;
|
||||
_speed = 0.0;
|
||||
}
|
||||
|
||||
void AccelStepper::computeNewSpeed()
|
||||
{
|
||||
long distanceTo = distanceToGo(); // +ve is clockwise from curent location
|
||||
|
||||
long stepsToStop = (long)((_speed * _speed) / (2.0 * _acceleration)); // Equation 16
|
||||
|
||||
if (distanceTo == 0 && stepsToStop <= 1)
|
||||
{
|
||||
// We are at the target and its time to stop
|
||||
_stepInterval = 0;
|
||||
_speed = 0.0;
|
||||
_n = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (distanceTo > 0)
|
||||
{
|
||||
// We are anticlockwise from the target
|
||||
// Need to go clockwise from here, maybe decelerate now
|
||||
if (_n > 0)
|
||||
{
|
||||
// Currently accelerating, need to decel now? Or maybe going the wrong way?
|
||||
if ((stepsToStop >= distanceTo) || _direction == DIRECTION_CCW)
|
||||
_n = -stepsToStop; // Start deceleration
|
||||
}
|
||||
else if (_n < 0)
|
||||
{
|
||||
// Currently decelerating, need to accel again?
|
||||
if ((stepsToStop < distanceTo) && _direction == DIRECTION_CW)
|
||||
_n = -_n; // Start accceleration
|
||||
}
|
||||
}
|
||||
else if (distanceTo < 0)
|
||||
{
|
||||
// We are clockwise from the target
|
||||
// Need to go anticlockwise from here, maybe decelerate
|
||||
if (_n > 0)
|
||||
{
|
||||
// Currently accelerating, need to decel now? Or maybe going the wrong way?
|
||||
if ((stepsToStop >= -distanceTo) || _direction == DIRECTION_CW)
|
||||
_n = -stepsToStop; // Start deceleration
|
||||
}
|
||||
else if (_n < 0)
|
||||
{
|
||||
// Currently decelerating, need to accel again?
|
||||
if ((stepsToStop < -distanceTo) && _direction == DIRECTION_CCW)
|
||||
_n = -_n; // Start accceleration
|
||||
}
|
||||
}
|
||||
|
||||
// Need to accelerate or decelerate
|
||||
if (_n == 0)
|
||||
{
|
||||
// First step from stopped
|
||||
_cn = _c0;
|
||||
_direction = (distanceTo > 0) ? DIRECTION_CW : DIRECTION_CCW;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Subsequent step. Works for accel (n is +_ve) and decel (n is -ve).
|
||||
_cn = _cn - ((2.0 * _cn) / ((4.0 * _n) + 1)); // Equation 13
|
||||
_cn = max(_cn, _cmin);
|
||||
}
|
||||
_n++;
|
||||
_stepInterval = _cn;
|
||||
_speed = 1000000.0 / _cn;
|
||||
if (_direction == DIRECTION_CCW)
|
||||
_speed = -_speed;
|
||||
|
||||
#if 0
|
||||
Serial.println(_speed);
|
||||
Serial.println(_acceleration);
|
||||
Serial.println(_cn);
|
||||
Serial.println(_c0);
|
||||
Serial.println(_n);
|
||||
Serial.println(_stepInterval);
|
||||
Serial.println(distanceTo);
|
||||
Serial.println(stepsToStop);
|
||||
Serial.println("-----");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Run the motor to implement speed and acceleration in order to proceed to the target position
|
||||
// You must call this at least once per step, preferably in your main loop
|
||||
// If the motor is in the desired position, the cost is very small
|
||||
// returns true if the motor is still running to the target position.
|
||||
boolean AccelStepper::run()
|
||||
{
|
||||
if (runSpeed())
|
||||
computeNewSpeed();
|
||||
return _speed != 0.0 || distanceToGo() != 0;
|
||||
}
|
||||
|
||||
AccelStepper::AccelStepper(uint8_t interface, uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4, bool enable)
|
||||
{
|
||||
_interface = interface;
|
||||
_currentPos = 0;
|
||||
_targetPos = 0;
|
||||
_speed = 0.0;
|
||||
_maxSpeed = 1.0;
|
||||
_acceleration = 0.0;
|
||||
_sqrt_twoa = 1.0;
|
||||
_stepInterval = 0;
|
||||
_minPulseWidth = 1;
|
||||
_enablePin = 0xff;
|
||||
_lastStepTime = 0;
|
||||
_pin[0] = pin1;
|
||||
_pin[1] = pin2;
|
||||
_pin[2] = pin3;
|
||||
_pin[3] = pin4;
|
||||
_enableInverted = false;
|
||||
|
||||
// NEW
|
||||
_n = 0;
|
||||
_c0 = 0.0;
|
||||
_cn = 0.0;
|
||||
_cmin = 1.0;
|
||||
_direction = DIRECTION_CCW;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
_pinInverted[i] = 0;
|
||||
if (enable)
|
||||
enableOutputs();
|
||||
// Some reasonable default
|
||||
setAcceleration(1);
|
||||
}
|
||||
|
||||
AccelStepper::AccelStepper(void (*forward)(), void (*backward)())
|
||||
{
|
||||
_interface = 0;
|
||||
_currentPos = 0;
|
||||
_targetPos = 0;
|
||||
_speed = 0.0;
|
||||
_maxSpeed = 1.0;
|
||||
_acceleration = 0.0;
|
||||
_sqrt_twoa = 1.0;
|
||||
_stepInterval = 0;
|
||||
_minPulseWidth = 1;
|
||||
_enablePin = 0xff;
|
||||
_lastStepTime = 0;
|
||||
_pin[0] = 0;
|
||||
_pin[1] = 0;
|
||||
_pin[2] = 0;
|
||||
_pin[3] = 0;
|
||||
_forward = forward;
|
||||
_backward = backward;
|
||||
|
||||
// NEW
|
||||
_n = 0;
|
||||
_c0 = 0.0;
|
||||
_cn = 0.0;
|
||||
_cmin = 1.0;
|
||||
_direction = DIRECTION_CCW;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
_pinInverted[i] = 0;
|
||||
// Some reasonable default
|
||||
setAcceleration(1);
|
||||
}
|
||||
|
||||
void AccelStepper::setMaxSpeed(float speed)
|
||||
{
|
||||
if (speed < 0.0)
|
||||
speed = -speed;
|
||||
if (_maxSpeed != speed)
|
||||
{
|
||||
_maxSpeed = speed;
|
||||
_cmin = 1000000.0 / speed;
|
||||
// Recompute _n from current speed and adjust speed if accelerating or cruising
|
||||
if (_n > 0)
|
||||
{
|
||||
_n = (long)((_speed * _speed) / (2.0 * _acceleration)); // Equation 16
|
||||
computeNewSpeed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float AccelStepper::maxSpeed()
|
||||
{
|
||||
return _maxSpeed;
|
||||
}
|
||||
|
||||
void AccelStepper::setAcceleration(float acceleration)
|
||||
{
|
||||
if (acceleration == 0.0)
|
||||
return;
|
||||
if (acceleration < 0.0)
|
||||
acceleration = -acceleration;
|
||||
if (_acceleration != acceleration)
|
||||
{
|
||||
// Recompute _n per Equation 17
|
||||
_n = _n * (_acceleration / acceleration);
|
||||
// New c0 per Equation 7, with correction per Equation 15
|
||||
_c0 = 0.676 * sqrt(2.0 / acceleration) * 1000000.0; // Equation 15
|
||||
_acceleration = acceleration;
|
||||
computeNewSpeed();
|
||||
}
|
||||
}
|
||||
|
||||
void AccelStepper::setSpeed(float speed)
|
||||
{
|
||||
if (speed == _speed)
|
||||
return;
|
||||
speed = constrain(speed, -_maxSpeed, _maxSpeed);
|
||||
if (speed == 0.0)
|
||||
_stepInterval = 0;
|
||||
else
|
||||
{
|
||||
_stepInterval = fabs(1000000.0 / speed);
|
||||
_direction = (speed > 0.0) ? DIRECTION_CW : DIRECTION_CCW;
|
||||
}
|
||||
_speed = speed;
|
||||
}
|
||||
|
||||
float AccelStepper::speed()
|
||||
{
|
||||
return _speed;
|
||||
}
|
||||
|
||||
// Subclasses can override
|
||||
void AccelStepper::step(long step)
|
||||
{
|
||||
switch (_interface)
|
||||
{
|
||||
case FUNCTION:
|
||||
step0(step);
|
||||
break;
|
||||
|
||||
case DRIVER:
|
||||
step1(step);
|
||||
break;
|
||||
|
||||
case FULL2WIRE:
|
||||
step2(step);
|
||||
break;
|
||||
|
||||
case FULL3WIRE:
|
||||
step3(step);
|
||||
break;
|
||||
|
||||
case FULL4WIRE:
|
||||
step4(step);
|
||||
break;
|
||||
|
||||
case HALF3WIRE:
|
||||
step6(step);
|
||||
break;
|
||||
|
||||
case HALF4WIRE:
|
||||
step8(step);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// You might want to override this to implement eg serial output
|
||||
// bit 0 of the mask corresponds to _pin[0]
|
||||
// bit 1 of the mask corresponds to _pin[1]
|
||||
// ....
|
||||
void AccelStepper::setOutputPins(uint8_t mask)
|
||||
{
|
||||
uint8_t numpins = 2;
|
||||
if (_interface == FULL4WIRE || _interface == HALF4WIRE)
|
||||
numpins = 4;
|
||||
else if (_interface == FULL3WIRE || _interface == HALF3WIRE)
|
||||
numpins = 3;
|
||||
uint8_t i;
|
||||
for (i = 0; i < numpins; i++)
|
||||
digitalWrite(_pin[i], (mask & (1 << i)) ? (HIGH ^ _pinInverted[i]) : (LOW ^ _pinInverted[i]));
|
||||
}
|
||||
|
||||
// 0 pin step function (ie for functional usage)
|
||||
void AccelStepper::step0(long step)
|
||||
{
|
||||
(void)(step); // Unused
|
||||
if (_speed > 0)
|
||||
_forward();
|
||||
else
|
||||
_backward();
|
||||
}
|
||||
|
||||
// 1 pin step function (ie for stepper drivers)
|
||||
// This is passed the current step number (0 to 7)
|
||||
// Subclasses can override
|
||||
void AccelStepper::step1(long step)
|
||||
{
|
||||
(void)(step); // Unused
|
||||
|
||||
// _pin[0] is step, _pin[1] is direction
|
||||
setOutputPins(_direction ? 0b10 : 0b00); // Set direction first else get rogue pulses
|
||||
setOutputPins(_direction ? 0b11 : 0b01); // step HIGH
|
||||
// Caution 200ns setup time
|
||||
// Delay the minimum allowed pulse width
|
||||
delayMicroseconds(_minPulseWidth);
|
||||
setOutputPins(_direction ? 0b10 : 0b00); // step LOW
|
||||
}
|
||||
|
||||
|
||||
// 2 pin step function
|
||||
// This is passed the current step number (0 to 7)
|
||||
// Subclasses can override
|
||||
void AccelStepper::step2(long step)
|
||||
{
|
||||
switch (step & 0x3)
|
||||
{
|
||||
case 0: /* 01 */
|
||||
setOutputPins(0b10);
|
||||
break;
|
||||
|
||||
case 1: /* 11 */
|
||||
setOutputPins(0b11);
|
||||
break;
|
||||
|
||||
case 2: /* 10 */
|
||||
setOutputPins(0b01);
|
||||
break;
|
||||
|
||||
case 3: /* 00 */
|
||||
setOutputPins(0b00);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 3 pin step function
|
||||
// This is passed the current step number (0 to 7)
|
||||
// Subclasses can override
|
||||
void AccelStepper::step3(long step)
|
||||
{
|
||||
switch (step % 3)
|
||||
{
|
||||
case 0: // 100
|
||||
setOutputPins(0b100);
|
||||
break;
|
||||
|
||||
case 1: // 001
|
||||
setOutputPins(0b001);
|
||||
break;
|
||||
|
||||
case 2: //010
|
||||
setOutputPins(0b010);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 4 pin step function for half stepper
|
||||
// This is passed the current step number (0 to 7)
|
||||
// Subclasses can override
|
||||
void AccelStepper::step4(long step)
|
||||
{
|
||||
switch (step & 0x3)
|
||||
{
|
||||
case 0: // 1010
|
||||
setOutputPins(0b0101);
|
||||
break;
|
||||
|
||||
case 1: // 0110
|
||||
setOutputPins(0b0110);
|
||||
break;
|
||||
|
||||
case 2: //0101
|
||||
setOutputPins(0b1010);
|
||||
break;
|
||||
|
||||
case 3: //1001
|
||||
setOutputPins(0b1001);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3 pin half step function
|
||||
// This is passed the current step number (0 to 7)
|
||||
// Subclasses can override
|
||||
void AccelStepper::step6(long step)
|
||||
{
|
||||
switch (step % 6)
|
||||
{
|
||||
case 0: // 100
|
||||
setOutputPins(0b100);
|
||||
break;
|
||||
|
||||
case 1: // 101
|
||||
setOutputPins(0b101);
|
||||
break;
|
||||
|
||||
case 2: // 001
|
||||
setOutputPins(0b001);
|
||||
break;
|
||||
|
||||
case 3: // 011
|
||||
setOutputPins(0b011);
|
||||
break;
|
||||
|
||||
case 4: // 010
|
||||
setOutputPins(0b010);
|
||||
break;
|
||||
|
||||
case 5: // 011
|
||||
setOutputPins(0b110);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 4 pin half step function
|
||||
// This is passed the current step number (0 to 7)
|
||||
// Subclasses can override
|
||||
void AccelStepper::step8(long step)
|
||||
{
|
||||
switch (step & 0x7)
|
||||
{
|
||||
case 0: // 1000
|
||||
setOutputPins(0b0001);
|
||||
break;
|
||||
|
||||
case 1: // 1010
|
||||
setOutputPins(0b0101);
|
||||
break;
|
||||
|
||||
case 2: // 0010
|
||||
setOutputPins(0b0100);
|
||||
break;
|
||||
|
||||
case 3: // 0110
|
||||
setOutputPins(0b0110);
|
||||
break;
|
||||
|
||||
case 4: // 0100
|
||||
setOutputPins(0b0010);
|
||||
break;
|
||||
|
||||
case 5: //0101
|
||||
setOutputPins(0b1010);
|
||||
break;
|
||||
|
||||
case 6: // 0001
|
||||
setOutputPins(0b1000);
|
||||
break;
|
||||
|
||||
case 7: //1001
|
||||
setOutputPins(0b1001);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevents power consumption on the outputs
|
||||
void AccelStepper::disableOutputs()
|
||||
{
|
||||
if (! _interface) return;
|
||||
|
||||
setOutputPins(0); // Handles inversion automatically
|
||||
if (_enablePin != 0xff)
|
||||
{
|
||||
pinMode(_enablePin, OUTPUT);
|
||||
digitalWrite(_enablePin, LOW ^ _enableInverted);
|
||||
}
|
||||
}
|
||||
|
||||
void AccelStepper::enableOutputs()
|
||||
{
|
||||
if (! _interface)
|
||||
return;
|
||||
|
||||
pinMode(_pin[0], OUTPUT);
|
||||
pinMode(_pin[1], OUTPUT);
|
||||
if (_interface == FULL4WIRE || _interface == HALF4WIRE)
|
||||
{
|
||||
pinMode(_pin[2], OUTPUT);
|
||||
pinMode(_pin[3], OUTPUT);
|
||||
}
|
||||
else if (_interface == FULL3WIRE || _interface == HALF3WIRE)
|
||||
{
|
||||
pinMode(_pin[2], OUTPUT);
|
||||
}
|
||||
|
||||
if (_enablePin != 0xff)
|
||||
{
|
||||
pinMode(_enablePin, OUTPUT);
|
||||
digitalWrite(_enablePin, HIGH ^ _enableInverted);
|
||||
}
|
||||
}
|
||||
|
||||
void AccelStepper::setMinPulseWidth(unsigned int minWidth)
|
||||
{
|
||||
_minPulseWidth = minWidth;
|
||||
}
|
||||
|
||||
void AccelStepper::setEnablePin(uint8_t enablePin)
|
||||
{
|
||||
_enablePin = enablePin;
|
||||
|
||||
// This happens after construction, so init pin now.
|
||||
if (_enablePin != 0xff)
|
||||
{
|
||||
pinMode(_enablePin, OUTPUT);
|
||||
digitalWrite(_enablePin, HIGH ^ _enableInverted);
|
||||
}
|
||||
}
|
||||
|
||||
void AccelStepper::setPinsInverted(bool directionInvert, bool stepInvert, bool enableInvert)
|
||||
{
|
||||
_pinInverted[0] = stepInvert;
|
||||
_pinInverted[1] = directionInvert;
|
||||
_enableInverted = enableInvert;
|
||||
}
|
||||
|
||||
void AccelStepper::setPinsInverted(bool pin1Invert, bool pin2Invert, bool pin3Invert, bool pin4Invert, bool enableInvert)
|
||||
{
|
||||
_pinInverted[0] = pin1Invert;
|
||||
_pinInverted[1] = pin2Invert;
|
||||
_pinInverted[2] = pin3Invert;
|
||||
_pinInverted[3] = pin4Invert;
|
||||
_enableInverted = enableInvert;
|
||||
}
|
||||
|
||||
// Blocks until the target position is reached and stopped
|
||||
void AccelStepper::runToPosition()
|
||||
{
|
||||
while (run())
|
||||
YIELD; // Let system housekeeping occur
|
||||
}
|
||||
|
||||
boolean AccelStepper::runSpeedToPosition()
|
||||
{
|
||||
if (_targetPos == _currentPos)
|
||||
return false;
|
||||
if (_targetPos >_currentPos)
|
||||
_direction = DIRECTION_CW;
|
||||
else
|
||||
_direction = DIRECTION_CCW;
|
||||
return runSpeed();
|
||||
}
|
||||
|
||||
// Blocks until the new target position is reached
|
||||
void AccelStepper::runToNewPosition(long position)
|
||||
{
|
||||
moveTo(position);
|
||||
runToPosition();
|
||||
}
|
||||
|
||||
void AccelStepper::stop()
|
||||
{
|
||||
if (_speed != 0.0)
|
||||
{
|
||||
long stepsToStop = (long)((_speed * _speed) / (2.0 * _acceleration)) + 1; // Equation 16 (+integer rounding)
|
||||
if (_speed > 0)
|
||||
move(stepsToStop);
|
||||
else
|
||||
move(-stepsToStop);
|
||||
}
|
||||
}
|
||||
|
||||
bool AccelStepper::isRunning()
|
||||
{
|
||||
return !(_speed == 0.0 && _targetPos == _currentPos);
|
||||
}
|
||||
749
libraries/AccelStepper/src/AccelStepper.h
Normal file
749
libraries/AccelStepper/src/AccelStepper.h
Normal file
@@ -0,0 +1,749 @@
|
||||
// AccelStepper.h
|
||||
//
|
||||
/// \mainpage AccelStepper library for Arduino
|
||||
///
|
||||
/// This is the Arduino AccelStepper library.
|
||||
/// It provides an object-oriented interface for 2, 3 or 4 pin stepper motors and motor drivers.
|
||||
///
|
||||
/// The standard Arduino IDE includes the Stepper library
|
||||
/// (http://arduino.cc/en/Reference/Stepper) for stepper motors. It is
|
||||
/// perfectly adequate for simple, single motor applications.
|
||||
///
|
||||
/// AccelStepper significantly improves on the standard Arduino Stepper library in several ways:
|
||||
/// \li Supports acceleration and deceleration
|
||||
/// \li Supports multiple simultaneous steppers, with independent concurrent stepping on each stepper
|
||||
/// \li Most API functions never delay() or block (unless otherwise stated)
|
||||
/// \li Supports 2, 3 and 4 wire steppers, plus 3 and 4 wire half steppers.
|
||||
/// \li Supports alternate stepping functions to enable support of AFMotor (https://github.com/adafruit/Adafruit-Motor-Shield-library)
|
||||
/// \li Supports stepper drivers such as the Sparkfun EasyDriver (based on 3967 driver chip)
|
||||
/// \li Very slow speeds are supported
|
||||
/// \li Extensive API
|
||||
/// \li Subclass support
|
||||
///
|
||||
/// The latest version of this documentation can be downloaded from
|
||||
/// http://www.airspayce.com/mikem/arduino/AccelStepper
|
||||
/// The version of the package that this documentation refers to can be downloaded
|
||||
/// from http://www.airspayce.com/mikem/arduino/AccelStepper/AccelStepper-1.61.zip
|
||||
///
|
||||
/// Example Arduino programs are included to show the main modes of use.
|
||||
///
|
||||
/// You can also find online help and discussion at http://groups.google.com/group/accelstepper
|
||||
/// Please use that group for all questions and discussions on this topic.
|
||||
/// Do not contact the author directly, unless it is to discuss commercial licensing.
|
||||
/// Before asking a question or reporting a bug, please read
|
||||
/// - http://en.wikipedia.org/wiki/Wikipedia:Reference_desk/How_to_ask_a_software_question
|
||||
/// - http://www.catb.org/esr/faqs/smart-questions.html
|
||||
/// - http://www.chiark.greenend.org.uk/~shgtatham/bugs.html
|
||||
///
|
||||
/// Tested on Arduino Diecimila and Mega with arduino-0018 & arduino-0021
|
||||
/// on OpenSuSE 11.1 and avr-libc-1.6.1-1.15,
|
||||
/// cross-avr-binutils-2.19-9.1, cross-avr-gcc-4.1.3_20080612-26.5.
|
||||
/// Tested on Teensy http://www.pjrc.com/teensy including Teensy 3.1 built using Arduino IDE 1.0.5 with
|
||||
/// teensyduino addon 1.18 and later.
|
||||
///
|
||||
/// \par Installation
|
||||
///
|
||||
/// Install in the usual way: unzip the distribution zip file to the libraries
|
||||
/// sub-folder of your sketchbook.
|
||||
///
|
||||
/// \par Theory
|
||||
///
|
||||
/// This code uses speed calculations as described in
|
||||
/// "Generate stepper-motor speed profiles in real time" by David Austin
|
||||
/// http://fab.cba.mit.edu/classes/MIT/961.09/projects/i0/Stepper_Motor_Speed_Profile.pdf or
|
||||
/// http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time or
|
||||
/// http://web.archive.org/web/20140705143928/http://fab.cba.mit.edu/classes/MIT/961.09/projects/i0/Stepper_Motor_Speed_Profile.pdf
|
||||
/// with the exception that AccelStepper uses steps per second rather than radians per second
|
||||
/// (because we dont know the step angle of the motor)
|
||||
/// An initial step interval is calculated for the first step, based on the desired acceleration
|
||||
/// On subsequent steps, shorter step intervals are calculated based
|
||||
/// on the previous step until max speed is achieved.
|
||||
///
|
||||
/// \par Adafruit Motor Shield V2
|
||||
///
|
||||
/// The included examples AFMotor_* are for Adafruit Motor Shield V1 and do not work with Adafruit Motor Shield V2.
|
||||
/// See https://github.com/adafruit/Adafruit_Motor_Shield_V2_Library for examples that work with Adafruit Motor Shield V2.
|
||||
///
|
||||
/// \par Donations
|
||||
///
|
||||
/// This library is offered under a free GPL license for those who want to use it that way.
|
||||
/// We try hard to keep it up to date, fix bugs
|
||||
/// and to provide free support. If this library has helped you save time or money, please consider donating at
|
||||
/// http://www.airspayce.com or here:
|
||||
///
|
||||
/// \htmlonly <form action="https://www.paypal.com/cgi-bin/webscr" method="post"><input type="hidden" name="cmd" value="_donations" /> <input type="hidden" name="business" value="mikem@airspayce.com" /> <input type="hidden" name="lc" value="AU" /> <input type="hidden" name="item_name" value="Airspayce" /> <input type="hidden" name="item_number" value="AccelStepper" /> <input type="hidden" name="currency_code" value="USD" /> <input type="hidden" name="bn" value="PP-DonationsBF:btn_donateCC_LG.gif:NonHosted" /> <input type="image" alt="PayPal — The safer, easier way to pay online." name="submit" src="https://www.paypalobjects.com/en_AU/i/btn/btn_donateCC_LG.gif" /> <img alt="" src="https://www.paypalobjects.com/en_AU/i/scr/pixel.gif" width="1" height="1" border="0" /></form> \endhtmlonly
|
||||
///
|
||||
/// \par Trademarks
|
||||
///
|
||||
/// AccelStepper is a trademark of AirSpayce Pty Ltd. The AccelStepper mark was first used on April 26 2010 for
|
||||
/// international trade, and is used only in relation to motor control hardware and software.
|
||||
/// It is not to be confused with any other similar marks covering other goods and services.
|
||||
///
|
||||
/// \par Copyright
|
||||
///
|
||||
/// This software is Copyright (C) 2010-2018 Mike McCauley. Use is subject to license
|
||||
/// conditions. The main licensing options available are GPL V3 or Commercial:
|
||||
///
|
||||
/// \par Open Source Licensing GPL V3
|
||||
/// This is the appropriate option if you want to share the source code of your
|
||||
/// application with everyone you distribute it to, and you also want to give them
|
||||
/// the right to share who uses it. If you wish to use this software under Open
|
||||
/// Source Licensing, you must contribute all your source code to the open source
|
||||
/// community in accordance with the GPL Version 23 when your application is
|
||||
/// distributed. See https://www.gnu.org/licenses/gpl-3.0.html
|
||||
///
|
||||
/// \par Commercial Licensing
|
||||
/// This is the appropriate option if you are creating proprietary applications
|
||||
/// and you are not prepared to distribute and share the source code of your
|
||||
/// application. To purchase a commercial license, contact info@airspayce.com
|
||||
///
|
||||
/// \par Revision History
|
||||
/// \version 1.0 Initial release
|
||||
///
|
||||
/// \version 1.1 Added speed() function to get the current speed.
|
||||
/// \version 1.2 Added runSpeedToPosition() submitted by Gunnar Arndt.
|
||||
/// \version 1.3 Added support for stepper drivers (ie with Step and Direction inputs) with _pins == 1
|
||||
/// \version 1.4 Added functional contructor to support AFMotor, contributed by Limor, with example sketches.
|
||||
/// \version 1.5 Improvements contributed by Peter Mousley: Use of microsecond steps and other speed improvements
|
||||
/// to increase max stepping speed to about 4kHz. New option for user to set the min allowed pulse width.
|
||||
/// Added checks for already running at max speed and skip further calcs if so.
|
||||
/// \version 1.6 Fixed a problem with wrapping of microsecond stepping that could cause stepping to hang.
|
||||
/// Reported by Sandy Noble.
|
||||
/// Removed redundant _lastRunTime member.
|
||||
/// \version 1.7 Fixed a bug where setCurrentPosition() did not always work as expected.
|
||||
/// Reported by Peter Linhart.
|
||||
/// \version 1.8 Added support for 4 pin half-steppers, requested by Harvey Moon
|
||||
/// \version 1.9 setCurrentPosition() now also sets motor speed to 0.
|
||||
/// \version 1.10 Builds on Arduino 1.0
|
||||
/// \version 1.11 Improvments from Michael Ellison:
|
||||
/// Added optional enable line support for stepper drivers
|
||||
/// Added inversion for step/direction/enable lines for stepper drivers
|
||||
/// \version 1.12 Announce Google Group
|
||||
/// \version 1.13 Improvements to speed calculation. Cost of calculation is now less in the worst case,
|
||||
/// and more or less constant in all cases. This should result in slightly beter high speed performance, and
|
||||
/// reduce anomalous speed glitches when other steppers are accelerating.
|
||||
/// However, its hard to see how to replace the sqrt() required at the very first step from 0 speed.
|
||||
/// \version 1.14 Fixed a problem with compiling under arduino 0021 reported by EmbeddedMan
|
||||
/// \version 1.15 Fixed a problem with runSpeedToPosition which did not correctly handle
|
||||
/// running backwards to a smaller target position. Added examples
|
||||
/// \version 1.16 Fixed some cases in the code where abs() was used instead of fabs().
|
||||
/// \version 1.17 Added example ProportionalControl
|
||||
/// \version 1.18 Fixed a problem: If one calls the funcion runSpeed() when Speed is zero, it makes steps
|
||||
/// without counting. reported by Friedrich, Klappenbach.
|
||||
/// \version 1.19 Added MotorInterfaceType and symbolic names for the number of pins to use
|
||||
/// for the motor interface. Updated examples to suit.
|
||||
/// Replaced individual pin assignment variables _pin1, _pin2 etc with array _pin[4].
|
||||
/// _pins member changed to _interface.
|
||||
/// Added _pinInverted array to simplify pin inversion operations.
|
||||
/// Added new function setOutputPins() which sets the motor output pins.
|
||||
/// It can be overridden in order to provide, say, serial output instead of parallel output
|
||||
/// Some refactoring and code size reduction.
|
||||
/// \version 1.20 Improved documentation and examples to show need for correctly
|
||||
/// specifying AccelStepper::FULL4WIRE and friends.
|
||||
/// \version 1.21 Fixed a problem where desiredSpeed could compute the wrong step acceleration
|
||||
/// when _speed was small but non-zero. Reported by Brian Schmalz.
|
||||
/// Precompute sqrt_twoa to improve performance and max possible stepping speed
|
||||
/// \version 1.22 Added Bounce.pde example
|
||||
/// Fixed a problem where calling moveTo(), setMaxSpeed(), setAcceleration() more
|
||||
/// frequently than the step time, even
|
||||
/// with the same values, would interfere with speed calcs. Now a new speed is computed
|
||||
/// only if there was a change in the set value. Reported by Brian Schmalz.
|
||||
/// \version 1.23 Rewrite of the speed algorithms in line with
|
||||
/// http://fab.cba.mit.edu/classes/MIT/961.09/projects/i0/Stepper_Motor_Speed_Profile.pdf
|
||||
/// Now expect smoother and more linear accelerations and decelerations. The desiredSpeed()
|
||||
/// function was removed.
|
||||
/// \version 1.24 Fixed a problem introduced in 1.23: with runToPosition, which did never returned
|
||||
/// \version 1.25 Now ignore attempts to set acceleration to 0.0
|
||||
/// \version 1.26 Fixed a problem where certina combinations of speed and accelration could cause
|
||||
/// oscillation about the target position.
|
||||
/// \version 1.27 Added stop() function to stop as fast as possible with current acceleration parameters.
|
||||
/// Also added new Quickstop example showing its use.
|
||||
/// \version 1.28 Fixed another problem where certain combinations of speed and acceleration could cause
|
||||
/// oscillation about the target position.
|
||||
/// Added support for 3 wire full and half steppers such as Hard Disk Drive spindle.
|
||||
/// Contributed by Yuri Ivatchkovitch.
|
||||
/// \version 1.29 Fixed a problem that could cause a DRIVER stepper to continually step
|
||||
/// with some sketches. Reported by Vadim.
|
||||
/// \version 1.30 Fixed a problem that could cause stepper to back up a few steps at the end of
|
||||
/// accelerated travel with certain speeds. Reported and patched by jolo.
|
||||
/// \version 1.31 Updated author and distribution location details to airspayce.com
|
||||
/// \version 1.32 Fixed a problem with enableOutputs() and setEnablePin on Arduino Due that
|
||||
/// prevented the enable pin changing stae correctly. Reported by Duane Bishop.
|
||||
/// \version 1.33 Fixed an error in example AFMotor_ConstantSpeed.pde did not setMaxSpeed();
|
||||
/// Fixed a problem that caused incorrect pin sequencing of FULL3WIRE and HALF3WIRE.
|
||||
/// Unfortunately this meant changing the signature for all step*() functions.
|
||||
/// Added example MotorShield, showing how to use AdaFruit Motor Shield to control
|
||||
/// a 3 phase motor such as a HDD spindle motor (and without using the AFMotor library.
|
||||
/// \version 1.34 Added setPinsInverted(bool pin1Invert, bool pin2Invert, bool pin3Invert, bool pin4Invert, bool enableInvert)
|
||||
/// to allow inversion of 2, 3 and 4 wire stepper pins. Requested by Oleg.
|
||||
/// \version 1.35 Removed default args from setPinsInverted(bool, bool, bool, bool, bool) to prevent ambiguity with
|
||||
/// setPinsInverted(bool, bool, bool). Reported by Mac Mac.
|
||||
/// \version 1.36 Changed enableOutputs() and disableOutputs() to be virtual so can be overridden.
|
||||
/// Added new optional argument 'enable' to constructor, which allows you toi disable the
|
||||
/// automatic enabling of outputs at construction time. Suggested by Guido.
|
||||
/// \version 1.37 Fixed a problem with step1 that could cause a rogue step in the
|
||||
/// wrong direction (or not,
|
||||
/// depending on the setup-time requirements of the connected hardware).
|
||||
/// Reported by Mark Tillotson.
|
||||
/// \version 1.38 run() function incorrectly always returned true. Updated function and doc so it returns true
|
||||
/// if the motor is still running to the target position.
|
||||
/// \version 1.39 Updated typos in keywords.txt, courtesey Jon Magill.
|
||||
/// \version 1.40 Updated documentation, including testing on Teensy 3.1
|
||||
/// \version 1.41 Fixed an error in the acceleration calculations, resulting in acceleration of haldf the intended value
|
||||
/// \version 1.42 Improved support for FULL3WIRE and HALF3WIRE output pins. These changes were in Yuri's original
|
||||
/// contribution but did not make it into production.<br>
|
||||
/// \version 1.43 Added DualMotorShield example. Shows how to use AccelStepper to control 2 x 2 phase steppers using the
|
||||
/// Itead Studio Arduino Dual Stepper Motor Driver Shield model IM120417015.<br>
|
||||
/// \version 1.44 examples/DualMotorShield/DualMotorShield.ino examples/DualMotorShield/DualMotorShield.pde
|
||||
/// was missing from the distribution.<br>
|
||||
/// \version 1.45 Fixed a problem where if setAcceleration was not called, there was no default
|
||||
/// acceleration. Reported by Michael Newman.<br>
|
||||
/// \version 1.45 Fixed inaccuracy in acceleration rate by using Equation 15, suggested by Sebastian Gracki.<br>
|
||||
/// Performance improvements in runSpeed suggested by Jaakko Fagerlund.<br>
|
||||
/// \version 1.46 Fixed error in documentation for runToPosition().
|
||||
/// Reinstated time calculations in runSpeed() since new version is reported
|
||||
/// not to work correctly under some circumstances. Reported by Oleg V Gavva.<br>
|
||||
/// \version 1.48 2015-08-25
|
||||
/// Added new class MultiStepper that can manage multiple AccelSteppers,
|
||||
/// and cause them all to move
|
||||
/// to selected positions at such a (constant) speed that they all arrive at their
|
||||
/// target position at the same time. Suitable for X-Y flatbeds etc.<br>
|
||||
/// Added new method maxSpeed() to AccelStepper to return the currently configured maxSpeed.<br>
|
||||
/// \version 1.49 2016-01-02
|
||||
/// Testing with VID28 series instrument stepper motors and EasyDriver.
|
||||
/// OK, although with light pointers
|
||||
/// and slow speeds like 180 full steps per second the motor movement can be erratic,
|
||||
/// probably due to some mechanical resonance. Best to accelerate through this speed.<br>
|
||||
/// Added isRunning().<br>
|
||||
/// \version 1.50 2016-02-25
|
||||
/// AccelStepper::disableOutputs now sets the enable pion to OUTPUT mode if the enable pin is defined.
|
||||
/// Patch from Piet De Jong.<br>
|
||||
/// Added notes about the fact that AFMotor_* examples do not work with Adafruit Motor Shield V2.<br>
|
||||
/// \version 1.51 2016-03-24
|
||||
/// Fixed a problem reported by gregor: when resetting the stepper motor position using setCurrentPosition() the
|
||||
/// stepper speed is reset by setting _stepInterval to 0, but _speed is not
|
||||
/// reset. this results in the stepper motor not starting again when calling
|
||||
/// setSpeed() with the same speed the stepper was set to before.
|
||||
/// \version 1.52 2016-08-09
|
||||
/// Added MultiStepper to keywords.txt.
|
||||
/// Improvements to efficiency of AccelStepper::runSpeed() as suggested by David Grayson.
|
||||
/// Improvements to speed accuracy as suggested by David Grayson.
|
||||
/// \version 1.53 2016-08-14
|
||||
/// Backed out Improvements to speed accuracy from 1.52 as it did not work correctly.
|
||||
/// \version 1.54 2017-01-24
|
||||
/// Fixed some warnings about unused arguments.
|
||||
/// \version 1.55 2017-01-25
|
||||
/// Fixed another warning in MultiStepper.cpp
|
||||
/// \version 1.56 2017-02-03
|
||||
/// Fixed minor documentation error with DIRECTION_CCW and DIRECTION_CW. Reported by David Mutterer.
|
||||
/// Added link to Binpress commercial license purchasing.
|
||||
/// \version 1.57 2017-03-28
|
||||
/// _direction moved to protected at the request of Rudy Ercek.
|
||||
/// setMaxSpeed() and setAcceleration() now correct negative values to be positive.
|
||||
/// \version 1.58 2018-04-13
|
||||
/// Add initialisation for _enableInverted in constructor.
|
||||
/// \version 1.59 2018-08-28
|
||||
/// Update commercial licensing, remove binpress.
|
||||
/// \version 1.60 2020-03-07
|
||||
/// Release under GPL V3
|
||||
/// \version 1.61 2020-04-20
|
||||
/// Added yield() call in runToPosition(), so that platforms like esp8266 dont hang/crash
|
||||
/// during long runs.
|
||||
///
|
||||
/// \author Mike McCauley (mikem@airspayce.com) DO NOT CONTACT THE AUTHOR DIRECTLY: USE THE LISTS
|
||||
// Copyright (C) 2009-2013 Mike McCauley
|
||||
// $Id: AccelStepper.h,v 1.28 2020/04/20 00:15:03 mikem Exp mikem $
|
||||
|
||||
#ifndef AccelStepper_h
|
||||
#define AccelStepper_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#if ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <wiring.h>
|
||||
#endif
|
||||
|
||||
// These defs cause trouble on some versions of Arduino
|
||||
#undef round
|
||||
|
||||
// Use the system yield() whenever possoible, since some platforms require it for housekeeping, especially
|
||||
// ESP8266
|
||||
#if (defined(ARDUINO) && ARDUINO >= 155) || defined(ESP8266)
|
||||
#define YIELD yield();
|
||||
#else
|
||||
#define YIELD
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/// \class AccelStepper AccelStepper.h <AccelStepper.h>
|
||||
/// \brief Support for stepper motors with acceleration etc.
|
||||
///
|
||||
/// This defines a single 2 or 4 pin stepper motor, or stepper moter with fdriver chip, with optional
|
||||
/// acceleration, deceleration, absolute positioning commands etc. Multiple
|
||||
/// simultaneous steppers are supported, all moving
|
||||
/// at different speeds and accelerations.
|
||||
///
|
||||
/// \par Operation
|
||||
/// This module operates by computing a step time in microseconds. The step
|
||||
/// time is recomputed after each step and after speed and acceleration
|
||||
/// parameters are changed by the caller. The time of each step is recorded in
|
||||
/// microseconds. The run() function steps the motor once if a new step is due.
|
||||
/// The run() function must be called frequently until the motor is in the
|
||||
/// desired position, after which time run() will do nothing.
|
||||
///
|
||||
/// \par Positioning
|
||||
/// Positions are specified by a signed long integer. At
|
||||
/// construction time, the current position of the motor is consider to be 0. Positive
|
||||
/// positions are clockwise from the initial position; negative positions are
|
||||
/// anticlockwise. The current position can be altered for instance after
|
||||
/// initialization positioning.
|
||||
///
|
||||
/// \par Caveats
|
||||
/// This is an open loop controller: If the motor stalls or is oversped,
|
||||
/// AccelStepper will not have a correct
|
||||
/// idea of where the motor really is (since there is no feedback of the motor's
|
||||
/// real position. We only know where we _think_ it is, relative to the
|
||||
/// initial starting point).
|
||||
///
|
||||
/// \par Performance
|
||||
/// The fastest motor speed that can be reliably supported is about 4000 steps per
|
||||
/// second at a clock frequency of 16 MHz on Arduino such as Uno etc.
|
||||
/// Faster processors can support faster stepping speeds.
|
||||
/// However, any speed less than that
|
||||
/// down to very slow speeds (much less than one per second) are also supported,
|
||||
/// provided the run() function is called frequently enough to step the motor
|
||||
/// whenever required for the speed set.
|
||||
/// Calling setAcceleration() is expensive,
|
||||
/// since it requires a square root to be calculated.
|
||||
///
|
||||
/// Gregor Christandl reports that with an Arduino Due and a simple test program,
|
||||
/// he measured 43163 steps per second using runSpeed(),
|
||||
/// and 16214 steps per second using run();
|
||||
class AccelStepper
|
||||
{
|
||||
public:
|
||||
/// \brief Symbolic names for number of pins.
|
||||
/// Use this in the pins argument the AccelStepper constructor to
|
||||
/// provide a symbolic name for the number of pins
|
||||
/// to use.
|
||||
typedef enum
|
||||
{
|
||||
FUNCTION = 0, ///< Use the functional interface, implementing your own driver functions (internal use only)
|
||||
DRIVER = 1, ///< Stepper Driver, 2 driver pins required
|
||||
FULL2WIRE = 2, ///< 2 wire stepper, 2 motor pins required
|
||||
FULL3WIRE = 3, ///< 3 wire stepper, such as HDD spindle, 3 motor pins required
|
||||
FULL4WIRE = 4, ///< 4 wire full stepper, 4 motor pins required
|
||||
HALF3WIRE = 6, ///< 3 wire half stepper, such as HDD spindle, 3 motor pins required
|
||||
HALF4WIRE = 8 ///< 4 wire half stepper, 4 motor pins required
|
||||
} MotorInterfaceType;
|
||||
|
||||
/// Constructor. You can have multiple simultaneous steppers, all moving
|
||||
/// at different speeds and accelerations, provided you call their run()
|
||||
/// functions at frequent enough intervals. Current Position is set to 0, target
|
||||
/// position is set to 0. MaxSpeed and Acceleration default to 1.0.
|
||||
/// The motor pins will be initialised to OUTPUT mode during the
|
||||
/// constructor by a call to enableOutputs().
|
||||
/// \param[in] interface Number of pins to interface to. Integer values are
|
||||
/// supported, but it is preferred to use the \ref MotorInterfaceType symbolic names.
|
||||
/// AccelStepper::DRIVER (1) means a stepper driver (with Step and Direction pins).
|
||||
/// If an enable line is also needed, call setEnablePin() after construction.
|
||||
/// You may also invert the pins using setPinsInverted().
|
||||
/// Caution: DRIVER implements a blocking delay of minPulseWidth microseconds (default 1us) for each step.
|
||||
/// You can change this with setMinPulseWidth().
|
||||
/// AccelStepper::FULL2WIRE (2) means a 2 wire stepper (2 pins required).
|
||||
/// AccelStepper::FULL3WIRE (3) means a 3 wire stepper, such as HDD spindle (3 pins required).
|
||||
/// AccelStepper::FULL4WIRE (4) means a 4 wire stepper (4 pins required).
|
||||
/// AccelStepper::HALF3WIRE (6) means a 3 wire half stepper, such as HDD spindle (3 pins required)
|
||||
/// AccelStepper::HALF4WIRE (8) means a 4 wire half stepper (4 pins required)
|
||||
/// Defaults to AccelStepper::FULL4WIRE (4) pins.
|
||||
/// \param[in] pin1 Arduino digital pin number for motor pin 1. Defaults
|
||||
/// to pin 2. For a AccelStepper::DRIVER (interface==1),
|
||||
/// this is the Step input to the driver. Low to high transition means to step)
|
||||
/// \param[in] pin2 Arduino digital pin number for motor pin 2. Defaults
|
||||
/// to pin 3. For a AccelStepper::DRIVER (interface==1),
|
||||
/// this is the Direction input the driver. High means forward.
|
||||
/// \param[in] pin3 Arduino digital pin number for motor pin 3. Defaults
|
||||
/// to pin 4.
|
||||
/// \param[in] pin4 Arduino digital pin number for motor pin 4. Defaults
|
||||
/// to pin 5.
|
||||
/// \param[in] enable If this is true (the default), enableOutputs() will be called to enable
|
||||
/// the output pins at construction time.
|
||||
AccelStepper(uint8_t interface = AccelStepper::FULL4WIRE, uint8_t pin1 = 2, uint8_t pin2 = 3, uint8_t pin3 = 4, uint8_t pin4 = 5, bool enable = true);
|
||||
|
||||
/// Alternate Constructor which will call your own functions for forward and backward steps.
|
||||
/// You can have multiple simultaneous steppers, all moving
|
||||
/// at different speeds and accelerations, provided you call their run()
|
||||
/// functions at frequent enough intervals. Current Position is set to 0, target
|
||||
/// position is set to 0. MaxSpeed and Acceleration default to 1.0.
|
||||
/// Any motor initialization should happen before hand, no pins are used or initialized.
|
||||
/// \param[in] forward void-returning procedure that will make a forward step
|
||||
/// \param[in] backward void-returning procedure that will make a backward step
|
||||
AccelStepper(void (*forward)(), void (*backward)());
|
||||
|
||||
/// Set the target position. The run() function will try to move the motor (at most one step per call)
|
||||
/// from the current position to the target position set by the most
|
||||
/// recent call to this function. Caution: moveTo() also recalculates the speed for the next step.
|
||||
/// If you are trying to use constant speed movements, you should call setSpeed() after calling moveTo().
|
||||
/// \param[in] absolute The desired absolute position. Negative is
|
||||
/// anticlockwise from the 0 position.
|
||||
void moveTo(long absolute);
|
||||
|
||||
/// Set the target position relative to the current position.
|
||||
/// \param[in] relative The desired position relative to the current position. Negative is
|
||||
/// anticlockwise from the current position.
|
||||
void move(long relative);
|
||||
|
||||
/// Poll the motor and step it if a step is due, implementing
|
||||
/// accelerations and decelerations to achieve the target position. You must call this as
|
||||
/// frequently as possible, but at least once per minimum step time interval,
|
||||
/// preferably in your main loop. Note that each call to run() will make at most one step, and then only when a step is due,
|
||||
/// based on the current speed and the time since the last step.
|
||||
/// \return true if the motor is still running to the target position.
|
||||
boolean run();
|
||||
|
||||
/// Poll the motor and step it if a step is due, implementing a constant
|
||||
/// speed as set by the most recent call to setSpeed(). You must call this as
|
||||
/// frequently as possible, but at least once per step interval,
|
||||
/// \return true if the motor was stepped.
|
||||
boolean runSpeed();
|
||||
|
||||
/// Sets the maximum permitted speed. The run() function will accelerate
|
||||
/// up to the speed set by this function.
|
||||
/// Caution: the maximum speed achievable depends on your processor and clock speed.
|
||||
/// The default maxSpeed is 1.0 steps per second.
|
||||
/// \param[in] speed The desired maximum speed in steps per second. Must
|
||||
/// be > 0. Caution: Speeds that exceed the maximum speed supported by the processor may
|
||||
/// Result in non-linear accelerations and decelerations.
|
||||
void setMaxSpeed(float speed);
|
||||
|
||||
/// Returns the maximum speed configured for this stepper
|
||||
/// that was previously set by setMaxSpeed();
|
||||
/// \return The currently configured maximum speed
|
||||
float maxSpeed();
|
||||
|
||||
/// Sets the acceleration/deceleration rate.
|
||||
/// \param[in] acceleration The desired acceleration in steps per second
|
||||
/// per second. Must be > 0.0. This is an expensive call since it requires a square
|
||||
/// root to be calculated. Dont call more ofthen than needed
|
||||
void setAcceleration(float acceleration);
|
||||
|
||||
/// Sets the desired constant speed for use with runSpeed().
|
||||
/// \param[in] speed The desired constant speed in steps per
|
||||
/// second. Positive is clockwise. Speeds of more than 1000 steps per
|
||||
/// second are unreliable. Very slow speeds may be set (eg 0.00027777 for
|
||||
/// once per hour, approximately. Speed accuracy depends on the Arduino
|
||||
/// crystal. Jitter depends on how frequently you call the runSpeed() function.
|
||||
/// The speed will be limited by the current value of setMaxSpeed()
|
||||
void setSpeed(float speed);
|
||||
|
||||
/// The most recently set speed.
|
||||
/// \return the most recent speed in steps per second
|
||||
float speed();
|
||||
|
||||
/// The distance from the current position to the target position.
|
||||
/// \return the distance from the current position to the target position
|
||||
/// in steps. Positive is clockwise from the current position.
|
||||
long distanceToGo();
|
||||
|
||||
/// The most recently set target position.
|
||||
/// \return the target position
|
||||
/// in steps. Positive is clockwise from the 0 position.
|
||||
long targetPosition();
|
||||
|
||||
/// The current motor position.
|
||||
/// \return the current motor position
|
||||
/// in steps. Positive is clockwise from the 0 position.
|
||||
long currentPosition();
|
||||
|
||||
/// Resets the current position of the motor, so that wherever the motor
|
||||
/// happens to be right now is considered to be the new 0 position. Useful
|
||||
/// for setting a zero position on a stepper after an initial hardware
|
||||
/// positioning move.
|
||||
/// Has the side effect of setting the current motor speed to 0.
|
||||
/// \param[in] position The position in steps of wherever the motor
|
||||
/// happens to be right now.
|
||||
void setCurrentPosition(long position);
|
||||
|
||||
/// Moves the motor (with acceleration/deceleration)
|
||||
/// to the target position and blocks until it is at
|
||||
/// position. Dont use this in event loops, since it blocks.
|
||||
void runToPosition();
|
||||
|
||||
/// Runs at the currently selected speed until the target position is reached.
|
||||
/// Does not implement accelerations.
|
||||
/// \return true if it stepped
|
||||
boolean runSpeedToPosition();
|
||||
|
||||
/// Moves the motor (with acceleration/deceleration)
|
||||
/// to the new target position and blocks until it is at
|
||||
/// position. Dont use this in event loops, since it blocks.
|
||||
/// \param[in] position The new target position.
|
||||
void runToNewPosition(long position);
|
||||
|
||||
/// Sets a new target position that causes the stepper
|
||||
/// to stop as quickly as possible, using the current speed and acceleration parameters.
|
||||
void stop();
|
||||
|
||||
/// Disable motor pin outputs by setting them all LOW
|
||||
/// Depending on the design of your electronics this may turn off
|
||||
/// the power to the motor coils, saving power.
|
||||
/// This is useful to support Arduino low power modes: disable the outputs
|
||||
/// during sleep and then reenable with enableOutputs() before stepping
|
||||
/// again.
|
||||
/// If the enable Pin is defined, sets it to OUTPUT mode and clears the pin to disabled.
|
||||
virtual void disableOutputs();
|
||||
|
||||
/// Enable motor pin outputs by setting the motor pins to OUTPUT
|
||||
/// mode. Called automatically by the constructor.
|
||||
/// If the enable Pin is defined, sets it to OUTPUT mode and sets the pin to enabled.
|
||||
virtual void enableOutputs();
|
||||
|
||||
/// Sets the minimum pulse width allowed by the stepper driver. The minimum practical pulse width is
|
||||
/// approximately 20 microseconds. Times less than 20 microseconds
|
||||
/// will usually result in 20 microseconds or so.
|
||||
/// \param[in] minWidth The minimum pulse width in microseconds.
|
||||
void setMinPulseWidth(unsigned int minWidth);
|
||||
|
||||
/// Sets the enable pin number for stepper drivers.
|
||||
/// 0xFF indicates unused (default).
|
||||
/// Otherwise, if a pin is set, the pin will be turned on when
|
||||
/// enableOutputs() is called and switched off when disableOutputs()
|
||||
/// is called.
|
||||
/// \param[in] enablePin Arduino digital pin number for motor enable
|
||||
/// \sa setPinsInverted
|
||||
void setEnablePin(uint8_t enablePin = 0xff);
|
||||
|
||||
/// Sets the inversion for stepper driver pins
|
||||
/// \param[in] directionInvert True for inverted direction pin, false for non-inverted
|
||||
/// \param[in] stepInvert True for inverted step pin, false for non-inverted
|
||||
/// \param[in] enableInvert True for inverted enable pin, false (default) for non-inverted
|
||||
void setPinsInverted(bool directionInvert = false, bool stepInvert = false, bool enableInvert = false);
|
||||
|
||||
/// Sets the inversion for 2, 3 and 4 wire stepper pins
|
||||
/// \param[in] pin1Invert True for inverted pin1, false for non-inverted
|
||||
/// \param[in] pin2Invert True for inverted pin2, false for non-inverted
|
||||
/// \param[in] pin3Invert True for inverted pin3, false for non-inverted
|
||||
/// \param[in] pin4Invert True for inverted pin4, false for non-inverted
|
||||
/// \param[in] enableInvert True for inverted enable pin, false (default) for non-inverted
|
||||
void setPinsInverted(bool pin1Invert, bool pin2Invert, bool pin3Invert, bool pin4Invert, bool enableInvert);
|
||||
|
||||
/// Checks to see if the motor is currently running to a target
|
||||
/// \return true if the speed is not zero or not at the target position
|
||||
bool isRunning();
|
||||
|
||||
protected:
|
||||
|
||||
/// \brief Direction indicator
|
||||
/// Symbolic names for the direction the motor is turning
|
||||
typedef enum
|
||||
{
|
||||
DIRECTION_CCW = 0, ///< Counter-Clockwise
|
||||
DIRECTION_CW = 1 ///< Clockwise
|
||||
} Direction;
|
||||
|
||||
/// Forces the library to compute a new instantaneous speed and set that as
|
||||
/// the current speed. It is called by
|
||||
/// the library:
|
||||
/// \li after each step
|
||||
/// \li after change to maxSpeed through setMaxSpeed()
|
||||
/// \li after change to acceleration through setAcceleration()
|
||||
/// \li after change to target position (relative or absolute) through
|
||||
/// move() or moveTo()
|
||||
void computeNewSpeed();
|
||||
|
||||
/// Low level function to set the motor output pins
|
||||
/// bit 0 of the mask corresponds to _pin[0]
|
||||
/// bit 1 of the mask corresponds to _pin[1]
|
||||
/// You can override this to impment, for example serial chip output insted of using the
|
||||
/// output pins directly
|
||||
virtual void setOutputPins(uint8_t mask);
|
||||
|
||||
/// Called to execute a step. Only called when a new step is
|
||||
/// required. Subclasses may override to implement new stepping
|
||||
/// interfaces. The default calls step1(), step2(), step4() or step8() depending on the
|
||||
/// number of pins defined for the stepper.
|
||||
/// \param[in] step The current step phase number (0 to 7)
|
||||
virtual void step(long step);
|
||||
|
||||
/// Called to execute a step using stepper functions (pins = 0) Only called when a new step is
|
||||
/// required. Calls _forward() or _backward() to perform the step
|
||||
/// \param[in] step The current step phase number (0 to 7)
|
||||
virtual void step0(long step);
|
||||
|
||||
/// Called to execute a step on a stepper driver (ie where pins == 1). Only called when a new step is
|
||||
/// required. Subclasses may override to implement new stepping
|
||||
/// interfaces. The default sets or clears the outputs of Step pin1 to step,
|
||||
/// and sets the output of _pin2 to the desired direction. The Step pin (_pin1) is pulsed for 1 microsecond
|
||||
/// which is the minimum STEP pulse width for the 3967 driver.
|
||||
/// \param[in] step The current step phase number (0 to 7)
|
||||
virtual void step1(long step);
|
||||
|
||||
/// Called to execute a step on a 2 pin motor. Only called when a new step is
|
||||
/// required. Subclasses may override to implement new stepping
|
||||
/// interfaces. The default sets or clears the outputs of pin1 and pin2
|
||||
/// \param[in] step The current step phase number (0 to 7)
|
||||
virtual void step2(long step);
|
||||
|
||||
/// Called to execute a step on a 3 pin motor, such as HDD spindle. Only called when a new step is
|
||||
/// required. Subclasses may override to implement new stepping
|
||||
/// interfaces. The default sets or clears the outputs of pin1, pin2,
|
||||
/// pin3
|
||||
/// \param[in] step The current step phase number (0 to 7)
|
||||
virtual void step3(long step);
|
||||
|
||||
/// Called to execute a step on a 4 pin motor. Only called when a new step is
|
||||
/// required. Subclasses may override to implement new stepping
|
||||
/// interfaces. The default sets or clears the outputs of pin1, pin2,
|
||||
/// pin3, pin4.
|
||||
/// \param[in] step The current step phase number (0 to 7)
|
||||
virtual void step4(long step);
|
||||
|
||||
/// Called to execute a step on a 3 pin motor, such as HDD spindle. Only called when a new step is
|
||||
/// required. Subclasses may override to implement new stepping
|
||||
/// interfaces. The default sets or clears the outputs of pin1, pin2,
|
||||
/// pin3
|
||||
/// \param[in] step The current step phase number (0 to 7)
|
||||
virtual void step6(long step);
|
||||
|
||||
/// Called to execute a step on a 4 pin half-steper motor. Only called when a new step is
|
||||
/// required. Subclasses may override to implement new stepping
|
||||
/// interfaces. The default sets or clears the outputs of pin1, pin2,
|
||||
/// pin3, pin4.
|
||||
/// \param[in] step The current step phase number (0 to 7)
|
||||
virtual void step8(long step);
|
||||
|
||||
/// Current direction motor is spinning in
|
||||
/// Protected because some peoples subclasses need it to be so
|
||||
boolean _direction; // 1 == CW
|
||||
|
||||
private:
|
||||
/// Number of pins on the stepper motor. Permits 2 or 4. 2 pins is a
|
||||
/// bipolar, and 4 pins is a unipolar.
|
||||
uint8_t _interface; // 0, 1, 2, 4, 8, See MotorInterfaceType
|
||||
|
||||
/// Arduino pin number assignments for the 2 or 4 pins required to interface to the
|
||||
/// stepper motor or driver
|
||||
uint8_t _pin[4];
|
||||
|
||||
/// Whether the _pins is inverted or not
|
||||
uint8_t _pinInverted[4];
|
||||
|
||||
/// The current absolution position in steps.
|
||||
long _currentPos; // Steps
|
||||
|
||||
/// The target position in steps. The AccelStepper library will move the
|
||||
/// motor from the _currentPos to the _targetPos, taking into account the
|
||||
/// max speed, acceleration and deceleration
|
||||
long _targetPos; // Steps
|
||||
|
||||
/// The current motos speed in steps per second
|
||||
/// Positive is clockwise
|
||||
float _speed; // Steps per second
|
||||
|
||||
/// The maximum permitted speed in steps per second. Must be > 0.
|
||||
float _maxSpeed;
|
||||
|
||||
/// The acceleration to use to accelerate or decelerate the motor in steps
|
||||
/// per second per second. Must be > 0
|
||||
float _acceleration;
|
||||
float _sqrt_twoa; // Precomputed sqrt(2*_acceleration)
|
||||
|
||||
/// The current interval between steps in microseconds.
|
||||
/// 0 means the motor is currently stopped with _speed == 0
|
||||
unsigned long _stepInterval;
|
||||
|
||||
/// The last step time in microseconds
|
||||
unsigned long _lastStepTime;
|
||||
|
||||
/// The minimum allowed pulse width in microseconds
|
||||
unsigned int _minPulseWidth;
|
||||
|
||||
/// Is the direction pin inverted?
|
||||
///bool _dirInverted; /// Moved to _pinInverted[1]
|
||||
|
||||
/// Is the step pin inverted?
|
||||
///bool _stepInverted; /// Moved to _pinInverted[0]
|
||||
|
||||
/// Is the enable pin inverted?
|
||||
bool _enableInverted;
|
||||
|
||||
/// Enable pin for stepper driver, or 0xFF if unused.
|
||||
uint8_t _enablePin;
|
||||
|
||||
/// The pointer to a forward-step procedure
|
||||
void (*_forward)();
|
||||
|
||||
/// The pointer to a backward-step procedure
|
||||
void (*_backward)();
|
||||
|
||||
/// The step counter for speed calculations
|
||||
long _n;
|
||||
|
||||
/// Initial step size in microseconds
|
||||
float _c0;
|
||||
|
||||
/// Last step size in microseconds
|
||||
float _cn;
|
||||
|
||||
/// Min step size in microseconds based on maxSpeed
|
||||
float _cmin; // at max speed
|
||||
|
||||
};
|
||||
|
||||
/// @example Random.pde
|
||||
/// Make a single stepper perform random changes in speed, position and acceleration
|
||||
|
||||
/// @example Overshoot.pde
|
||||
/// Check overshoot handling
|
||||
/// which sets a new target position and then waits until the stepper has
|
||||
/// achieved it. This is used for testing the handling of overshoots
|
||||
|
||||
/// @example MultipleSteppers.pde
|
||||
/// Shows how to multiple simultaneous steppers
|
||||
/// Runs one stepper forwards and backwards, accelerating and decelerating
|
||||
/// at the limits. Runs other steppers at the same time
|
||||
|
||||
/// @example ConstantSpeed.pde
|
||||
/// Shows how to run AccelStepper in the simplest,
|
||||
/// fixed speed mode with no accelerations
|
||||
|
||||
/// @example Blocking.pde
|
||||
/// Shows how to use the blocking call runToNewPosition
|
||||
/// Which sets a new target position and then waits until the stepper has
|
||||
/// achieved it.
|
||||
|
||||
/// @example AFMotor_MultiStepper.pde
|
||||
/// Control both Stepper motors at the same time with different speeds
|
||||
/// and accelerations.
|
||||
|
||||
/// @example AFMotor_ConstantSpeed.pde
|
||||
/// Shows how to run AccelStepper in the simplest,
|
||||
/// fixed speed mode with no accelerations
|
||||
|
||||
/// @example ProportionalControl.pde
|
||||
/// Make a single stepper follow the analog value read from a pot or whatever
|
||||
/// The stepper will move at a constant speed to each newly set posiiton,
|
||||
/// depending on the value of the pot.
|
||||
|
||||
/// @example Bounce.pde
|
||||
/// Make a single stepper bounce from one limit to another, observing
|
||||
/// accelrations at each end of travel
|
||||
|
||||
/// @example Quickstop.pde
|
||||
/// Check stop handling.
|
||||
/// Calls stop() while the stepper is travelling at full speed, causing
|
||||
/// the stepper to stop as quickly as possible, within the constraints of the
|
||||
/// current acceleration.
|
||||
|
||||
/// @example MotorShield.pde
|
||||
/// Shows how to use AccelStepper to control a 3-phase motor, such as a HDD spindle motor
|
||||
/// using the Adafruit Motor Shield http://www.ladyada.net/make/mshield/index.html.
|
||||
|
||||
/// @example DualMotorShield.pde
|
||||
/// Shows how to use AccelStepper to control 2 x 2 phase steppers using the
|
||||
/// Itead Studio Arduino Dual Stepper Motor Driver Shield
|
||||
/// model IM120417015
|
||||
|
||||
#endif
|
||||
86
libraries/AccelStepper/src/MultiStepper.cpp
Normal file
86
libraries/AccelStepper/src/MultiStepper.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// MultiStepper.cpp
|
||||
//
|
||||
// Copyright (C) 2015 Mike McCauley
|
||||
// $Id: MultiStepper.cpp,v 1.3 2020/04/20 00:15:03 mikem Exp mikem $
|
||||
|
||||
#include "MultiStepper.h"
|
||||
#include "AccelStepper.h"
|
||||
|
||||
MultiStepper::MultiStepper()
|
||||
: _num_steppers(0)
|
||||
{
|
||||
}
|
||||
|
||||
boolean MultiStepper::addStepper(AccelStepper& stepper)
|
||||
{
|
||||
if (_num_steppers >= MULTISTEPPER_MAX_STEPPERS)
|
||||
return false; // No room for more
|
||||
_steppers[_num_steppers++] = &stepper;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MultiStepper::moveTo(long absolute[])
|
||||
{
|
||||
// First find the stepper that will take the longest time to move
|
||||
float longestTime = 0.0;
|
||||
|
||||
uint8_t i;
|
||||
for (i = 0; i < _num_steppers; i++)
|
||||
{
|
||||
long thisDistance = absolute[i] - _steppers[i]->currentPosition();
|
||||
float thisTime = abs(thisDistance) / _steppers[i]->maxSpeed();
|
||||
|
||||
if (thisTime > longestTime)
|
||||
longestTime = thisTime;
|
||||
}
|
||||
|
||||
if (longestTime > 0.0)
|
||||
{
|
||||
// Now work out a new max speed for each stepper so they will all
|
||||
// arrived at the same time of longestTime
|
||||
for (i = 0; i < _num_steppers; i++)
|
||||
{
|
||||
long thisDistance = absolute[i] - _steppers[i]->currentPosition();
|
||||
float thisSpeed = thisDistance / longestTime;
|
||||
_steppers[i]->moveTo(absolute[i]); // New target position (resets speed)
|
||||
_steppers[i]->setSpeed(thisSpeed); // New speed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if any motor is still running to the target position.
|
||||
boolean MultiStepper::run()
|
||||
{
|
||||
uint8_t i;
|
||||
boolean ret = false;
|
||||
for (i = 0; i < _num_steppers; i++)
|
||||
{
|
||||
if ( _steppers[i]->distanceToGo() != 0)
|
||||
{
|
||||
_steppers[i]->runSpeed();
|
||||
ret = true;
|
||||
}
|
||||
// Caution: it has een reported that if any motor is used with acceleration outside of
|
||||
// MultiStepper, this code is necessary, you get
|
||||
// strange results where it moves in the wrong direction for a while then
|
||||
// slams back the correct way.
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
// Need to call this to clear _stepInterval, _speed and _n
|
||||
otherwise future calls will fail.
|
||||
_steppers[i]->setCurrentPosition(_steppers[i]->currentPosition());
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Blocks until all steppers reach their target position and are stopped
|
||||
void MultiStepper::runSpeedToPosition()
|
||||
{
|
||||
while (run())
|
||||
;
|
||||
}
|
||||
|
||||
78
libraries/AccelStepper/src/MultiStepper.h
Normal file
78
libraries/AccelStepper/src/MultiStepper.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// MultiStepper.h
|
||||
|
||||
#ifndef MultiStepper_h
|
||||
#define MultiStepper_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#if ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <wiring.h>
|
||||
#endif
|
||||
|
||||
#define MULTISTEPPER_MAX_STEPPERS 10
|
||||
|
||||
class AccelStepper;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/// \class MultiStepper MultiStepper.h <MultiStepper.h>
|
||||
/// \brief Operate multiple AccelSteppers in a co-ordinated fashion
|
||||
///
|
||||
/// This class can manage multiple AccelSteppers (up to MULTISTEPPER_MAX_STEPPERS = 10),
|
||||
/// and cause them all to move
|
||||
/// to selected positions at such a (constant) speed that they all arrive at their
|
||||
/// target position at the same time. This can be used to support devices with multiple steppers
|
||||
/// on say multiple axes to cause linear diagonal motion. Suitable for use with X-Y plotters, flatbeds,
|
||||
/// 3D printers etc
|
||||
/// to get linear straight line movement between arbitrary 2d (or 3d or ...) positions.
|
||||
///
|
||||
/// Caution: only constant speed stepper motion is supported: acceleration and deceleration is not supported
|
||||
/// All the steppers managed by MultiStepper will step at a constant speed to their
|
||||
/// target (albeit perhaps different speeds for each stepper).
|
||||
class MultiStepper
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
MultiStepper();
|
||||
|
||||
/// Add a stepper to the set of managed steppers
|
||||
/// There is an upper limit of MULTISTEPPER_MAX_STEPPERS = 10 to the number of steppers that can be managed
|
||||
/// \param[in] stepper Reference to a stepper to add to the managed list
|
||||
/// \return true if successful. false if the number of managed steppers would exceed MULTISTEPPER_MAX_STEPPERS
|
||||
boolean addStepper(AccelStepper& stepper);
|
||||
|
||||
/// Set the target positions of all managed steppers
|
||||
/// according to a coordinate array.
|
||||
/// New speeds will be computed for each stepper so they will all arrive at their
|
||||
/// respective targets at very close to the same time.
|
||||
/// \param[in] absolute An array of desired absolute stepper positions. absolute[0] will be used to set
|
||||
/// the absolute position of the first stepper added by addStepper() etc. The array must be at least as long as
|
||||
/// the number of steppers that have been added by addStepper, else results are undefined.
|
||||
void moveTo(long absolute[]);
|
||||
|
||||
/// Calls runSpeed() on all the managed steppers
|
||||
/// that have not acheived their target position.
|
||||
/// \return true if any stepper is still in the process of running to its target position.
|
||||
boolean run();
|
||||
|
||||
/// Runs all managed steppers until they acheived their target position.
|
||||
/// Blocks until all that position is acheived. If you dont
|
||||
/// want blocking consider using run() instead.
|
||||
void runSpeedToPosition();
|
||||
|
||||
private:
|
||||
/// Array of pointers to the steppers we are controlling.
|
||||
/// Fills from 0 onwards
|
||||
AccelStepper* _steppers[MULTISTEPPER_MAX_STEPPERS];
|
||||
|
||||
/// Number of steppers we are controlling and the number
|
||||
/// of steppers in _steppers[]
|
||||
uint8_t _num_steppers;
|
||||
};
|
||||
|
||||
/// @example MultiStepper.pde
|
||||
/// Use MultiStepper class to manage multiple steppers and make them all move to
|
||||
/// the same position at the same time for linear 2d (or 3d) motion.
|
||||
|
||||
#endif
|
||||
15
libraries/ESP32_BLE_Arduino/README.md
Normal file
15
libraries/ESP32_BLE_Arduino/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# ESP32 BLE for Arduino
|
||||
The Arduino IDE provides an excellent library package manager where versions of libraries can be downloaded and installed. This Github project provides the repository for the ESP32 BLE support for Arduino.
|
||||
|
||||
The actual source of the project which is being maintained can be found here:
|
||||
|
||||
https://github.com/nkolban/esp32-snippets
|
||||
|
||||
Issues and questions should be raised here:
|
||||
|
||||
https://github.com/nkolban/esp32-snippets/issues
|
||||
|
||||
|
||||
Documentation for using the library can be found here:
|
||||
|
||||
https://github.com/nkolban/esp32-snippets/tree/master/Documentation
|
||||
160
libraries/ESP32_BLE_Arduino/examples/BLE_client/BLE_client.ino
Normal file
160
libraries/ESP32_BLE_Arduino/examples/BLE_client/BLE_client.ino
Normal file
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* A BLE client example that is rich in capabilities.
|
||||
* There is a lot new capabilities implemented.
|
||||
* author unknown
|
||||
* updated by chegewara
|
||||
*/
|
||||
|
||||
#include "BLEDevice.h"
|
||||
//#include "BLEScan.h"
|
||||
|
||||
// The remote service we wish to connect to.
|
||||
static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
|
||||
// The characteristic of the remote service we are interested in.
|
||||
static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");
|
||||
|
||||
static boolean doConnect = false;
|
||||
static boolean connected = false;
|
||||
static boolean doScan = false;
|
||||
static BLERemoteCharacteristic* pRemoteCharacteristic;
|
||||
static BLEAdvertisedDevice* myDevice;
|
||||
|
||||
static void notifyCallback(
|
||||
BLERemoteCharacteristic* pBLERemoteCharacteristic,
|
||||
uint8_t* pData,
|
||||
size_t length,
|
||||
bool isNotify) {
|
||||
Serial.print("Notify callback for characteristic ");
|
||||
Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
|
||||
Serial.print(" of data length ");
|
||||
Serial.println(length);
|
||||
Serial.print("data: ");
|
||||
Serial.println((char*)pData);
|
||||
}
|
||||
|
||||
class MyClientCallback : public BLEClientCallbacks {
|
||||
void onConnect(BLEClient* pclient) {
|
||||
}
|
||||
|
||||
void onDisconnect(BLEClient* pclient) {
|
||||
connected = false;
|
||||
Serial.println("onDisconnect");
|
||||
}
|
||||
};
|
||||
|
||||
bool connectToServer() {
|
||||
Serial.print("Forming a connection to ");
|
||||
Serial.println(myDevice->getAddress().toString().c_str());
|
||||
|
||||
BLEClient* pClient = BLEDevice::createClient();
|
||||
Serial.println(" - Created client");
|
||||
|
||||
pClient->setClientCallbacks(new MyClientCallback());
|
||||
|
||||
// Connect to the remove BLE Server.
|
||||
pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
|
||||
Serial.println(" - Connected to server");
|
||||
|
||||
// Obtain a reference to the service we are after in the remote BLE server.
|
||||
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
|
||||
if (pRemoteService == nullptr) {
|
||||
Serial.print("Failed to find our service UUID: ");
|
||||
Serial.println(serviceUUID.toString().c_str());
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
Serial.println(" - Found our service");
|
||||
|
||||
|
||||
// Obtain a reference to the characteristic in the service of the remote BLE server.
|
||||
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
|
||||
if (pRemoteCharacteristic == nullptr) {
|
||||
Serial.print("Failed to find our characteristic UUID: ");
|
||||
Serial.println(charUUID.toString().c_str());
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
Serial.println(" - Found our characteristic");
|
||||
|
||||
// Read the value of the characteristic.
|
||||
if(pRemoteCharacteristic->canRead()) {
|
||||
std::string value = pRemoteCharacteristic->readValue();
|
||||
Serial.print("The characteristic value was: ");
|
||||
Serial.println(value.c_str());
|
||||
}
|
||||
|
||||
if(pRemoteCharacteristic->canNotify())
|
||||
pRemoteCharacteristic->registerForNotify(notifyCallback);
|
||||
|
||||
connected = true;
|
||||
}
|
||||
/**
|
||||
* Scan for BLE servers and find the first one that advertises the service we are looking for.
|
||||
*/
|
||||
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||
/**
|
||||
* Called for each advertising BLE server.
|
||||
*/
|
||||
void onResult(BLEAdvertisedDevice advertisedDevice) {
|
||||
Serial.print("BLE Advertised Device found: ");
|
||||
Serial.println(advertisedDevice.toString().c_str());
|
||||
|
||||
// We have found a device, let us now see if it contains the service we are looking for.
|
||||
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
|
||||
|
||||
BLEDevice::getScan()->stop();
|
||||
myDevice = new BLEAdvertisedDevice(advertisedDevice);
|
||||
doConnect = true;
|
||||
doScan = true;
|
||||
|
||||
} // Found our server
|
||||
} // onResult
|
||||
}; // MyAdvertisedDeviceCallbacks
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Starting Arduino BLE Client application...");
|
||||
BLEDevice::init("");
|
||||
|
||||
// Retrieve a Scanner and set the callback we want to use to be informed when we
|
||||
// have detected a new device. Specify that we want active scanning and start the
|
||||
// scan to run for 5 seconds.
|
||||
BLEScan* pBLEScan = BLEDevice::getScan();
|
||||
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||
pBLEScan->setInterval(1349);
|
||||
pBLEScan->setWindow(449);
|
||||
pBLEScan->setActiveScan(true);
|
||||
pBLEScan->start(5, false);
|
||||
} // End of setup.
|
||||
|
||||
|
||||
// This is the Arduino main loop function.
|
||||
void loop() {
|
||||
|
||||
// If the flag "doConnect" is true then we have scanned for and found the desired
|
||||
// BLE Server with which we wish to connect. Now we connect to it. Once we are
|
||||
// connected we set the connected flag to be true.
|
||||
if (doConnect == true) {
|
||||
if (connectToServer()) {
|
||||
Serial.println("We are now connected to the BLE Server.");
|
||||
} else {
|
||||
Serial.println("We have failed to connect to the server; there is nothin more we will do.");
|
||||
}
|
||||
doConnect = false;
|
||||
}
|
||||
|
||||
// If we are connected to a peer BLE Server, update the characteristic each time we are reached
|
||||
// with the current time since boot.
|
||||
if (connected) {
|
||||
String newValue = "Time since boot: " + String(millis()/1000);
|
||||
Serial.println("Setting new characteristic value to \"" + newValue + "\"");
|
||||
|
||||
// Set the characteristic's value to be the array of bytes that is actually a string.
|
||||
pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
|
||||
}else if(doScan){
|
||||
BLEDevice::getScan()->start(0); // this is just eample to start scan after disconnect, most likely there is better way to do it in arduino
|
||||
}
|
||||
|
||||
delay(1000); // Delay a second between loops.
|
||||
} // End of loop
|
||||
103
libraries/ESP32_BLE_Arduino/examples/BLE_iBeacon/BLE_iBeacon.ino
Normal file
103
libraries/ESP32_BLE_Arduino/examples/BLE_iBeacon/BLE_iBeacon.ino
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
|
||||
Ported to Arduino ESP32 by pcbreflux
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Create a BLE server that will send periodic iBeacon frames.
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create advertising data
|
||||
3. Start advertising.
|
||||
4. wait
|
||||
5. Stop advertising.
|
||||
6. deep sleep
|
||||
|
||||
*/
|
||||
#include "sys/time.h"
|
||||
|
||||
#include "BLEDevice.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "BLEBeacon.h"
|
||||
#include "esp_sleep.h"
|
||||
|
||||
#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up
|
||||
RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory
|
||||
RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint8_t temprature_sens_read();
|
||||
//uint8_t g_phyFuns;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
BLEAdvertising *pAdvertising;
|
||||
struct timeval now;
|
||||
|
||||
#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)
|
||||
|
||||
void setBeacon() {
|
||||
|
||||
BLEBeacon oBeacon = BLEBeacon();
|
||||
oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!)
|
||||
oBeacon.setProximityUUID(BLEUUID(BEACON_UUID));
|
||||
oBeacon.setMajor((bootcount & 0xFFFF0000) >> 16);
|
||||
oBeacon.setMinor(bootcount&0xFFFF);
|
||||
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
|
||||
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
|
||||
|
||||
oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04
|
||||
|
||||
std::string strServiceData = "";
|
||||
|
||||
strServiceData += (char)26; // Len
|
||||
strServiceData += (char)0xFF; // Type
|
||||
strServiceData += oBeacon.getData();
|
||||
oAdvertisementData.addData(strServiceData);
|
||||
|
||||
pAdvertising->setAdvertisementData(oAdvertisementData);
|
||||
pAdvertising->setScanResponseData(oScanResponseData);
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
|
||||
Serial.begin(115200);
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
Serial.printf("start ESP32 %d\n",bootcount++);
|
||||
|
||||
Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n",now.tv_sec,now.tv_sec-last);
|
||||
|
||||
last = now.tv_sec;
|
||||
|
||||
// Create the BLE Device
|
||||
BLEDevice::init("");
|
||||
|
||||
// Create the BLE Server
|
||||
// BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage
|
||||
|
||||
pAdvertising = BLEDevice::getAdvertising();
|
||||
|
||||
setBeacon();
|
||||
// Start advertising
|
||||
pAdvertising->start();
|
||||
Serial.println("Advertizing started...");
|
||||
delay(100);
|
||||
pAdvertising->stop();
|
||||
Serial.printf("enter deep sleep\n");
|
||||
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
|
||||
Serial.printf("in deep sleep\n");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
110
libraries/ESP32_BLE_Arduino/examples/BLE_notify/BLE_notify.ino
Normal file
110
libraries/ESP32_BLE_Arduino/examples/BLE_notify/BLE_notify.ino
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
updated by chegewara
|
||||
|
||||
Create a BLE server that, once we receive a connection, will send periodic notifications.
|
||||
The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b
|
||||
And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8
|
||||
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create a BLE Service
|
||||
3. Create a BLE Characteristic on the Service
|
||||
4. Create a BLE Descriptor on the characteristic
|
||||
5. Start the service.
|
||||
6. Start advertising.
|
||||
|
||||
A connect hander associated with the server starts a background task that performs notification
|
||||
every couple of seconds.
|
||||
*/
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
|
||||
BLEServer* pServer = NULL;
|
||||
BLECharacteristic* pCharacteristic = NULL;
|
||||
bool deviceConnected = false;
|
||||
bool oldDeviceConnected = false;
|
||||
uint32_t value = 0;
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
|
||||
|
||||
class MyServerCallbacks: public BLEServerCallbacks {
|
||||
void onConnect(BLEServer* pServer) {
|
||||
deviceConnected = true;
|
||||
};
|
||||
|
||||
void onDisconnect(BLEServer* pServer) {
|
||||
deviceConnected = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Create the BLE Device
|
||||
BLEDevice::init("ESP32");
|
||||
|
||||
// Create the BLE Server
|
||||
pServer = BLEDevice::createServer();
|
||||
pServer->setCallbacks(new MyServerCallbacks());
|
||||
|
||||
// Create the BLE Service
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
|
||||
// Create a BLE Characteristic
|
||||
pCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_WRITE |
|
||||
BLECharacteristic::PROPERTY_NOTIFY |
|
||||
BLECharacteristic::PROPERTY_INDICATE
|
||||
);
|
||||
|
||||
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
|
||||
// Create a BLE Descriptor
|
||||
pCharacteristic->addDescriptor(new BLE2902());
|
||||
|
||||
// Start the service
|
||||
pService->start();
|
||||
|
||||
// Start advertising
|
||||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(false);
|
||||
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
|
||||
BLEDevice::startAdvertising();
|
||||
Serial.println("Waiting a client connection to notify...");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// notify changed value
|
||||
if (deviceConnected) {
|
||||
pCharacteristic->setValue((uint8_t*)&value, 4);
|
||||
pCharacteristic->notify();
|
||||
value++;
|
||||
delay(3); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
|
||||
}
|
||||
// disconnecting
|
||||
if (!deviceConnected && oldDeviceConnected) {
|
||||
delay(500); // give the bluetooth stack the chance to get things ready
|
||||
pServer->startAdvertising(); // restart advertising
|
||||
Serial.println("start advertising");
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
// connecting
|
||||
if (deviceConnected && !oldDeviceConnected) {
|
||||
// do stuff here on connecting
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
}
|
||||
40
libraries/ESP32_BLE_Arduino/examples/BLE_scan/BLE_scan.ino
Normal file
40
libraries/ESP32_BLE_Arduino/examples/BLE_scan/BLE_scan.ino
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
*/
|
||||
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLEScan.h>
|
||||
#include <BLEAdvertisedDevice.h>
|
||||
|
||||
int scanTime = 5; //In seconds
|
||||
BLEScan* pBLEScan;
|
||||
|
||||
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
||||
void onResult(BLEAdvertisedDevice advertisedDevice) {
|
||||
Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Scanning...");
|
||||
|
||||
BLEDevice::init("");
|
||||
pBLEScan = BLEDevice::getScan(); //create new scan
|
||||
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
|
||||
pBLEScan->setInterval(100);
|
||||
pBLEScan->setWindow(99); // less or equal setInterval value
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
|
||||
Serial.print("Devices found: ");
|
||||
Serial.println(foundDevices.getCount());
|
||||
Serial.println("Scan done!");
|
||||
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
|
||||
delay(2000);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
updates by chegewara
|
||||
*/
|
||||
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLEServer.h>
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Starting BLE work!");
|
||||
|
||||
BLEDevice::init("Long name works now");
|
||||
BLEServer *pServer = BLEDevice::createServer();
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
);
|
||||
|
||||
pCharacteristic->setValue("Hello World says Neil");
|
||||
pService->start();
|
||||
// BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility
|
||||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(true);
|
||||
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
|
||||
pAdvertising->setMinPreferred(0x12);
|
||||
BLEDevice::startAdvertising();
|
||||
Serial.println("Characteristic defined! Now you can read it in your phone!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
delay(2000);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
updated by chegewara
|
||||
|
||||
Create a BLE server that, once we receive a connection, will send periodic notifications.
|
||||
The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b
|
||||
And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8
|
||||
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create a BLE Service
|
||||
3. Create a BLE Characteristic on the Service
|
||||
4. Create a BLE Descriptor on the characteristic
|
||||
5. Start the service.
|
||||
6. Start advertising.
|
||||
|
||||
A connect hander associated with the server starts a background task that performs notification
|
||||
every couple of seconds.
|
||||
*/
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
|
||||
BLEServer* pServer = NULL;
|
||||
BLECharacteristic* pCharacteristic = NULL;
|
||||
bool deviceConnected = false;
|
||||
bool oldDeviceConnected = false;
|
||||
uint32_t value = 0;
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
|
||||
|
||||
class MyServerCallbacks: public BLEServerCallbacks {
|
||||
void onConnect(BLEServer* pServer) {
|
||||
deviceConnected = true;
|
||||
BLEDevice::startAdvertising();
|
||||
};
|
||||
|
||||
void onDisconnect(BLEServer* pServer) {
|
||||
deviceConnected = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Create the BLE Device
|
||||
BLEDevice::init("ESP32");
|
||||
|
||||
// Create the BLE Server
|
||||
pServer = BLEDevice::createServer();
|
||||
pServer->setCallbacks(new MyServerCallbacks());
|
||||
|
||||
// Create the BLE Service
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
|
||||
// Create a BLE Characteristic
|
||||
pCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_WRITE |
|
||||
BLECharacteristic::PROPERTY_NOTIFY |
|
||||
BLECharacteristic::PROPERTY_INDICATE
|
||||
);
|
||||
|
||||
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
|
||||
// Create a BLE Descriptor
|
||||
pCharacteristic->addDescriptor(new BLE2902());
|
||||
|
||||
// Start the service
|
||||
pService->start();
|
||||
|
||||
// Start advertising
|
||||
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID(SERVICE_UUID);
|
||||
pAdvertising->setScanResponse(false);
|
||||
pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter
|
||||
BLEDevice::startAdvertising();
|
||||
Serial.println("Waiting a client connection to notify...");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// notify changed value
|
||||
if (deviceConnected) {
|
||||
pCharacteristic->setValue((uint8_t*)&value, 4);
|
||||
pCharacteristic->notify();
|
||||
value++;
|
||||
delay(10); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
|
||||
}
|
||||
// disconnecting
|
||||
if (!deviceConnected && oldDeviceConnected) {
|
||||
delay(500); // give the bluetooth stack the chance to get things ready
|
||||
pServer->startAdvertising(); // restart advertising
|
||||
Serial.println("start advertising");
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
// connecting
|
||||
if (deviceConnected && !oldDeviceConnected) {
|
||||
// do stuff here on connecting
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
}
|
||||
125
libraries/ESP32_BLE_Arduino/examples/BLE_uart/BLE_uart.ino
Normal file
125
libraries/ESP32_BLE_Arduino/examples/BLE_uart/BLE_uart.ino
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
|
||||
Create a BLE server that, once we receive a connection, will send periodic notifications.
|
||||
The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
|
||||
Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE"
|
||||
Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY"
|
||||
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create a BLE Service
|
||||
3. Create a BLE Characteristic on the Service
|
||||
4. Create a BLE Descriptor on the characteristic
|
||||
5. Start the service.
|
||||
6. Start advertising.
|
||||
|
||||
In this example rxValue is the data received (only accessible inside that function).
|
||||
And txValue is the data to be sent, in this example just a byte incremented every second.
|
||||
*/
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
|
||||
BLEServer *pServer = NULL;
|
||||
BLECharacteristic * pTxCharacteristic;
|
||||
bool deviceConnected = false;
|
||||
bool oldDeviceConnected = false;
|
||||
uint8_t txValue = 0;
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
|
||||
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
|
||||
|
||||
class MyServerCallbacks: public BLEServerCallbacks {
|
||||
void onConnect(BLEServer* pServer) {
|
||||
deviceConnected = true;
|
||||
};
|
||||
|
||||
void onDisconnect(BLEServer* pServer) {
|
||||
deviceConnected = false;
|
||||
}
|
||||
};
|
||||
|
||||
class MyCallbacks: public BLECharacteristicCallbacks {
|
||||
void onWrite(BLECharacteristic *pCharacteristic) {
|
||||
std::string rxValue = pCharacteristic->getValue();
|
||||
|
||||
if (rxValue.length() > 0) {
|
||||
Serial.println("*********");
|
||||
Serial.print("Received Value: ");
|
||||
for (int i = 0; i < rxValue.length(); i++)
|
||||
Serial.print(rxValue[i]);
|
||||
|
||||
Serial.println();
|
||||
Serial.println("*********");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Create the BLE Device
|
||||
BLEDevice::init("UART Service");
|
||||
|
||||
// Create the BLE Server
|
||||
pServer = BLEDevice::createServer();
|
||||
pServer->setCallbacks(new MyServerCallbacks());
|
||||
|
||||
// Create the BLE Service
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
|
||||
// Create a BLE Characteristic
|
||||
pTxCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID_TX,
|
||||
BLECharacteristic::PROPERTY_NOTIFY
|
||||
);
|
||||
|
||||
pTxCharacteristic->addDescriptor(new BLE2902());
|
||||
|
||||
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID_RX,
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
);
|
||||
|
||||
pRxCharacteristic->setCallbacks(new MyCallbacks());
|
||||
|
||||
// Start the service
|
||||
pService->start();
|
||||
|
||||
// Start advertising
|
||||
pServer->getAdvertising()->start();
|
||||
Serial.println("Waiting a client connection to notify...");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
if (deviceConnected) {
|
||||
pTxCharacteristic->setValue(&txValue, 1);
|
||||
pTxCharacteristic->notify();
|
||||
txValue++;
|
||||
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
|
||||
}
|
||||
|
||||
// disconnecting
|
||||
if (!deviceConnected && oldDeviceConnected) {
|
||||
delay(500); // give the bluetooth stack the chance to get things ready
|
||||
pServer->startAdvertising(); // restart advertising
|
||||
Serial.println("start advertising");
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
// connecting
|
||||
if (deviceConnected && !oldDeviceConnected) {
|
||||
// do stuff here on connecting
|
||||
oldDeviceConnected = deviceConnected;
|
||||
}
|
||||
}
|
||||
65
libraries/ESP32_BLE_Arduino/examples/BLE_write/BLE_write.ino
Normal file
65
libraries/ESP32_BLE_Arduino/examples/BLE_write/BLE_write.ino
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleWrite.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
*/
|
||||
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLEServer.h>
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
|
||||
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
|
||||
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
|
||||
|
||||
class MyCallbacks: public BLECharacteristicCallbacks {
|
||||
void onWrite(BLECharacteristic *pCharacteristic) {
|
||||
std::string value = pCharacteristic->getValue();
|
||||
|
||||
if (value.length() > 0) {
|
||||
Serial.println("*********");
|
||||
Serial.print("New value: ");
|
||||
for (int i = 0; i < value.length(); i++)
|
||||
Serial.print(value[i]);
|
||||
|
||||
Serial.println();
|
||||
Serial.println("*********");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println("1- Download and install an BLE scanner app in your phone");
|
||||
Serial.println("2- Scan for BLE devices in the app");
|
||||
Serial.println("3- Connect to MyESP32");
|
||||
Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something");
|
||||
Serial.println("5- See the magic =)");
|
||||
|
||||
BLEDevice::init("MyESP32");
|
||||
BLEServer *pServer = BLEDevice::createServer();
|
||||
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
|
||||
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
BLECharacteristic::PROPERTY_READ |
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
);
|
||||
|
||||
pCharacteristic->setCallbacks(new MyCallbacks());
|
||||
|
||||
pCharacteristic->setValue("Hello World");
|
||||
pService->start();
|
||||
|
||||
BLEAdvertising *pAdvertising = pServer->getAdvertising();
|
||||
pAdvertising->start();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
delay(2000);
|
||||
}
|
||||
10
libraries/ESP32_BLE_Arduino/library.properties
Normal file
10
libraries/ESP32_BLE_Arduino/library.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
name=ESP32 BLE Arduino
|
||||
version=1.0.1
|
||||
author=Neil Kolban <kolban1@kolban.com>
|
||||
maintainer=Dariusz Krempa <esp32@esp32.eu.org>
|
||||
sentence=BLE functions for ESP32
|
||||
paragraph=This library provides an implementation Bluetooth Low Energy support for the ESP32 using the Arduino platform.
|
||||
category=Communication
|
||||
url=https://github.com/nkolban/ESP32_BLE_Arduino
|
||||
architectures=esp32
|
||||
includes=BLEDevice.h, BLEUtils.h, BLEScan.h, BLEAdvertisedDevice.h
|
||||
62
libraries/ESP32_BLE_Arduino/src/BLE2902.cpp
Normal file
62
libraries/ESP32_BLE_Arduino/src/BLE2902.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* BLE2902.cpp
|
||||
*
|
||||
* Created on: Jun 25, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
/*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLE2902.h"
|
||||
|
||||
BLE2902::BLE2902() : BLEDescriptor(BLEUUID((uint16_t) 0x2902)) {
|
||||
uint8_t data[2] = { 0, 0 };
|
||||
setValue(data, 2);
|
||||
} // BLE2902
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the notifications value.
|
||||
* @return The notifications value. True if notifications are enabled and false if not.
|
||||
*/
|
||||
bool BLE2902::getNotifications() {
|
||||
return (getValue()[0] & (1 << 0)) != 0;
|
||||
} // getNotifications
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the indications value.
|
||||
* @return The indications value. True if indications are enabled and false if not.
|
||||
*/
|
||||
bool BLE2902::getIndications() {
|
||||
return (getValue()[0] & (1 << 1)) != 0;
|
||||
} // getIndications
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the indications flag.
|
||||
* @param [in] flag The indications flag.
|
||||
*/
|
||||
void BLE2902::setIndications(bool flag) {
|
||||
uint8_t *pValue = getValue();
|
||||
if (flag) pValue[0] |= 1 << 1;
|
||||
else pValue[0] &= ~(1 << 1);
|
||||
} // setIndications
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the notifications flag.
|
||||
* @param [in] flag The notifications flag.
|
||||
*/
|
||||
void BLE2902::setNotifications(bool flag) {
|
||||
uint8_t *pValue = getValue();
|
||||
if (flag) pValue[0] |= 1 << 0;
|
||||
else pValue[0] &= ~(1 << 0);
|
||||
} // setNotifications
|
||||
|
||||
#endif
|
||||
34
libraries/ESP32_BLE_Arduino/src/BLE2902.h
Normal file
34
libraries/ESP32_BLE_Arduino/src/BLE2902.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* BLE2902.h
|
||||
*
|
||||
* Created on: Jun 25, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLE2902_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLE2902_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLEDescriptor.h"
|
||||
|
||||
/**
|
||||
* @brief Descriptor for Client Characteristic Configuration.
|
||||
*
|
||||
* This is a convenience descriptor for the Client Characteristic Configuration which has a UUID of 0x2902.
|
||||
*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
|
||||
*/
|
||||
class BLE2902: public BLEDescriptor {
|
||||
public:
|
||||
BLE2902();
|
||||
bool getNotifications();
|
||||
bool getIndications();
|
||||
void setNotifications(bool flag);
|
||||
void setIndications(bool flag);
|
||||
|
||||
}; // BLE2902
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLE2902_H_ */
|
||||
74
libraries/ESP32_BLE_Arduino/src/BLE2904.cpp
Normal file
74
libraries/ESP32_BLE_Arduino/src/BLE2904.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* BLE2904.cpp
|
||||
*
|
||||
* Created on: Dec 23, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
/*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLE2904.h"
|
||||
|
||||
|
||||
BLE2904::BLE2904() : BLEDescriptor(BLEUUID((uint16_t) 0x2904)) {
|
||||
m_data.m_format = 0;
|
||||
m_data.m_exponent = 0;
|
||||
m_data.m_namespace = 1; // 1 = Bluetooth SIG Assigned Numbers
|
||||
m_data.m_unit = 0;
|
||||
m_data.m_description = 0;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // BLE2902
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the description.
|
||||
*/
|
||||
void BLE2904::setDescription(uint16_t description) {
|
||||
m_data.m_description = description;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the exponent.
|
||||
*/
|
||||
void BLE2904::setExponent(int8_t exponent) {
|
||||
m_data.m_exponent = exponent;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setExponent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the format.
|
||||
*/
|
||||
void BLE2904::setFormat(uint8_t format) {
|
||||
m_data.m_format = format;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setFormat
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the namespace.
|
||||
*/
|
||||
void BLE2904::setNamespace(uint8_t namespace_value) {
|
||||
m_data.m_namespace = namespace_value;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setNamespace
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the units for this value. It should be one of the encoded values defined here:
|
||||
* https://www.bluetooth.com/specifications/assigned-numbers/units
|
||||
* @param [in] unit The type of units of this characteristic as defined by assigned numbers.
|
||||
*/
|
||||
void BLE2904::setUnit(uint16_t unit) {
|
||||
m_data.m_unit = unit;
|
||||
setValue((uint8_t*) &m_data, sizeof(m_data));
|
||||
} // setUnit
|
||||
|
||||
#endif
|
||||
74
libraries/ESP32_BLE_Arduino/src/BLE2904.h
Normal file
74
libraries/ESP32_BLE_Arduino/src/BLE2904.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* BLE2904.h
|
||||
*
|
||||
* Created on: Dec 23, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLE2904_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLE2904_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLEDescriptor.h"
|
||||
|
||||
struct BLE2904_Data {
|
||||
uint8_t m_format;
|
||||
int8_t m_exponent;
|
||||
uint16_t m_unit; // See https://www.bluetooth.com/specifications/assigned-numbers/units
|
||||
uint8_t m_namespace;
|
||||
uint16_t m_description;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* @brief Descriptor for Characteristic Presentation Format.
|
||||
*
|
||||
* This is a convenience descriptor for the Characteristic Presentation Format which has a UUID of 0x2904.
|
||||
*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
|
||||
*/
|
||||
class BLE2904: public BLEDescriptor {
|
||||
public:
|
||||
BLE2904();
|
||||
static const uint8_t FORMAT_BOOLEAN = 1;
|
||||
static const uint8_t FORMAT_UINT2 = 2;
|
||||
static const uint8_t FORMAT_UINT4 = 3;
|
||||
static const uint8_t FORMAT_UINT8 = 4;
|
||||
static const uint8_t FORMAT_UINT12 = 5;
|
||||
static const uint8_t FORMAT_UINT16 = 6;
|
||||
static const uint8_t FORMAT_UINT24 = 7;
|
||||
static const uint8_t FORMAT_UINT32 = 8;
|
||||
static const uint8_t FORMAT_UINT48 = 9;
|
||||
static const uint8_t FORMAT_UINT64 = 10;
|
||||
static const uint8_t FORMAT_UINT128 = 11;
|
||||
static const uint8_t FORMAT_SINT8 = 12;
|
||||
static const uint8_t FORMAT_SINT12 = 13;
|
||||
static const uint8_t FORMAT_SINT16 = 14;
|
||||
static const uint8_t FORMAT_SINT24 = 15;
|
||||
static const uint8_t FORMAT_SINT32 = 16;
|
||||
static const uint8_t FORMAT_SINT48 = 17;
|
||||
static const uint8_t FORMAT_SINT64 = 18;
|
||||
static const uint8_t FORMAT_SINT128 = 19;
|
||||
static const uint8_t FORMAT_FLOAT32 = 20;
|
||||
static const uint8_t FORMAT_FLOAT64 = 21;
|
||||
static const uint8_t FORMAT_SFLOAT16 = 22;
|
||||
static const uint8_t FORMAT_SFLOAT32 = 23;
|
||||
static const uint8_t FORMAT_IEEE20601 = 24;
|
||||
static const uint8_t FORMAT_UTF8 = 25;
|
||||
static const uint8_t FORMAT_UTF16 = 26;
|
||||
static const uint8_t FORMAT_OPAQUE = 27;
|
||||
|
||||
void setDescription(uint16_t);
|
||||
void setExponent(int8_t exponent);
|
||||
void setFormat(uint8_t format);
|
||||
void setNamespace(uint8_t namespace_value);
|
||||
void setUnit(uint16_t unit);
|
||||
|
||||
private:
|
||||
BLE2904_Data m_data;
|
||||
}; // BLE2904
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLE2904_H_ */
|
||||
95
libraries/ESP32_BLE_Arduino/src/BLEAddress.cpp
Normal file
95
libraries/ESP32_BLE_Arduino/src/BLEAddress.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* BLEAddress.cpp
|
||||
*
|
||||
* Created on: Jul 2, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLEAddress.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-log.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create an address from the native ESP32 representation.
|
||||
* @param [in] address The native representation.
|
||||
*/
|
||||
BLEAddress::BLEAddress(esp_bd_addr_t address) {
|
||||
memcpy(m_address, address, ESP_BD_ADDR_LEN);
|
||||
} // BLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create an address from a hex string
|
||||
*
|
||||
* A hex string is of the format:
|
||||
* ```
|
||||
* 00:00:00:00:00:00
|
||||
* ```
|
||||
* which is 17 characters in length.
|
||||
*
|
||||
* @param [in] stringAddress The hex representation of the address.
|
||||
*/
|
||||
BLEAddress::BLEAddress(std::string stringAddress) {
|
||||
if (stringAddress.length() != 17) return;
|
||||
|
||||
int data[6];
|
||||
sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5]);
|
||||
m_address[0] = (uint8_t) data[0];
|
||||
m_address[1] = (uint8_t) data[1];
|
||||
m_address[2] = (uint8_t) data[2];
|
||||
m_address[3] = (uint8_t) data[3];
|
||||
m_address[4] = (uint8_t) data[4];
|
||||
m_address[5] = (uint8_t) data[5];
|
||||
} // BLEAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Determine if this address equals another.
|
||||
* @param [in] otherAddress The other address to compare against.
|
||||
* @return True if the addresses are equal.
|
||||
*/
|
||||
bool BLEAddress::equals(BLEAddress otherAddress) {
|
||||
return memcmp(otherAddress.getNative(), m_address, 6) == 0;
|
||||
} // equals
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the native representation of the address.
|
||||
* @return The native representation of the address.
|
||||
*/
|
||||
esp_bd_addr_t *BLEAddress::getNative() {
|
||||
return &m_address;
|
||||
} // getNative
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert a BLE address to a string.
|
||||
*
|
||||
* A string representation of an address is in the format:
|
||||
*
|
||||
* ```
|
||||
* xx:xx:xx:xx:xx:xx
|
||||
* ```
|
||||
*
|
||||
* @return The string representation of the address.
|
||||
*/
|
||||
std::string BLEAddress::toString() {
|
||||
std::stringstream stream;
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[0] << ':';
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[1] << ':';
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[2] << ':';
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[3] << ':';
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[4] << ':';
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[5];
|
||||
return stream.str();
|
||||
} // toString
|
||||
#endif
|
||||
34
libraries/ESP32_BLE_Arduino/src/BLEAddress.h
Normal file
34
libraries/ESP32_BLE_Arduino/src/BLEAddress.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* BLEAddress.h
|
||||
*
|
||||
* Created on: Jul 2, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEADDRESS_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEADDRESS_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_gap_ble_api.h> // ESP32 BLE
|
||||
#include <string>
|
||||
|
||||
|
||||
/**
|
||||
* @brief A %BLE device address.
|
||||
*
|
||||
* Every %BLE device has a unique address which can be used to identify it and form connections.
|
||||
*/
|
||||
class BLEAddress {
|
||||
public:
|
||||
BLEAddress(esp_bd_addr_t address);
|
||||
BLEAddress(std::string stringAddress);
|
||||
bool equals(BLEAddress otherAddress);
|
||||
esp_bd_addr_t* getNative();
|
||||
std::string toString();
|
||||
|
||||
private:
|
||||
esp_bd_addr_t m_address;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEADDRESS_H_ */
|
||||
529
libraries/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp
Normal file
529
libraries/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
* BLEAdvertisedDevice.cpp
|
||||
*
|
||||
* During the scanning procedure, we will be finding advertised BLE devices. This class
|
||||
* models a found device.
|
||||
*
|
||||
*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
|
||||
*
|
||||
* Created on: Jul 3, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <sstream>
|
||||
#include "BLEAdvertisedDevice.h"
|
||||
#include "BLEUtils.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG="BLEAdvertisedDevice";
|
||||
#endif
|
||||
|
||||
BLEAdvertisedDevice::BLEAdvertisedDevice() {
|
||||
m_adFlag = 0;
|
||||
m_appearance = 0;
|
||||
m_deviceType = 0;
|
||||
m_manufacturerData = "";
|
||||
m_name = "";
|
||||
m_rssi = -9999;
|
||||
m_serviceData = "";
|
||||
m_txPower = 0;
|
||||
m_pScan = nullptr;
|
||||
|
||||
m_haveAppearance = false;
|
||||
m_haveManufacturerData = false;
|
||||
m_haveName = false;
|
||||
m_haveRSSI = false;
|
||||
m_haveServiceData = false;
|
||||
m_haveServiceUUID = false;
|
||||
m_haveTXPower = false;
|
||||
|
||||
} // BLEAdvertisedDevice
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the address.
|
||||
*
|
||||
* Every %BLE device exposes an address that is used to identify it and subsequently connect to it.
|
||||
* Call this function to obtain the address of the advertised device.
|
||||
*
|
||||
* @return The address of the advertised device.
|
||||
*/
|
||||
BLEAddress BLEAdvertisedDevice::getAddress() {
|
||||
return m_address;
|
||||
} // getAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the appearance.
|
||||
*
|
||||
* A %BLE device can declare its own appearance. The appearance is how it would like to be shown to an end user
|
||||
* typcially in the form of an icon.
|
||||
*
|
||||
* @return The appearance of the advertised device.
|
||||
*/
|
||||
uint16_t BLEAdvertisedDevice::getAppearance() {
|
||||
return m_appearance;
|
||||
} // getAppearance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the manufacturer data.
|
||||
* @return The manufacturer data of the advertised device.
|
||||
*/
|
||||
std::string BLEAdvertisedDevice::getManufacturerData() {
|
||||
return m_manufacturerData;
|
||||
} // getManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the name.
|
||||
* @return The name of the advertised device.
|
||||
*/
|
||||
std::string BLEAdvertisedDevice::getName() {
|
||||
return m_name;
|
||||
} // getName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the RSSI.
|
||||
* @return The RSSI of the advertised device.
|
||||
*/
|
||||
int BLEAdvertisedDevice::getRSSI() {
|
||||
return m_rssi;
|
||||
} // getRSSI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the scan object that created this advertisement.
|
||||
* @return The scan object.
|
||||
*/
|
||||
BLEScan* BLEAdvertisedDevice::getScan() {
|
||||
return m_pScan;
|
||||
} // getScan
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service data.
|
||||
* @return The ServiceData of the advertised device.
|
||||
*/
|
||||
std::string BLEAdvertisedDevice::getServiceData() {
|
||||
return m_serviceData;
|
||||
} //getServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service data UUID.
|
||||
* @return The service data UUID.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceDataUUID() {
|
||||
return m_serviceDataUUID;
|
||||
} // getServiceDataUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the Service UUID.
|
||||
* @return The Service UUID of the advertised device.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceUUID() { //TODO Remove it eventually, is no longer useful
|
||||
return m_serviceUUIDs[0];
|
||||
} // getServiceUUID
|
||||
|
||||
/**
|
||||
* @brief Check advertised serviced for existence required UUID
|
||||
* @return Return true if service is advertised
|
||||
*/
|
||||
bool BLEAdvertisedDevice::isAdvertisingService(BLEUUID uuid){
|
||||
for (int i = 0; i < m_serviceUUIDs.size(); i++) {
|
||||
if (m_serviceUUIDs[i].equals(uuid)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the TX Power.
|
||||
* @return The TX Power of the advertised device.
|
||||
*/
|
||||
int8_t BLEAdvertisedDevice::getTXPower() {
|
||||
return m_txPower;
|
||||
} // getTXPower
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have an appearance value?
|
||||
* @return True if there is an appearance value present.
|
||||
*/
|
||||
bool BLEAdvertisedDevice::haveAppearance() {
|
||||
return m_haveAppearance;
|
||||
} // haveAppearance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have manufacturer data?
|
||||
* @return True if there is manufacturer data present.
|
||||
*/
|
||||
bool BLEAdvertisedDevice::haveManufacturerData() {
|
||||
return m_haveManufacturerData;
|
||||
} // haveManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a name value?
|
||||
* @return True if there is a name value present.
|
||||
*/
|
||||
bool BLEAdvertisedDevice::haveName() {
|
||||
return m_haveName;
|
||||
} // haveName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a signal strength value?
|
||||
* @return True if there is a signal strength value present.
|
||||
*/
|
||||
bool BLEAdvertisedDevice::haveRSSI() {
|
||||
return m_haveRSSI;
|
||||
} // haveRSSI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a service data value?
|
||||
* @return True if there is a service data value present.
|
||||
*/
|
||||
bool BLEAdvertisedDevice::haveServiceData() {
|
||||
return m_haveServiceData;
|
||||
} // haveServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a service UUID value?
|
||||
* @return True if there is a service UUID value present.
|
||||
*/
|
||||
bool BLEAdvertisedDevice::haveServiceUUID() {
|
||||
return m_haveServiceUUID;
|
||||
} // haveServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does this advertisement have a transmission power value?
|
||||
* @return True if there is a transmission power value present.
|
||||
*/
|
||||
bool BLEAdvertisedDevice::haveTXPower() {
|
||||
return m_haveTXPower;
|
||||
} // haveTXPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse the advertising pay load.
|
||||
*
|
||||
* The pay load is a buffer of bytes that is either 31 bytes long or terminated by
|
||||
* a 0 length value. Each entry in the buffer has the format:
|
||||
* [length][type][data...]
|
||||
*
|
||||
* The length does not include itself but does include everything after it until the next record. A record
|
||||
* with a length value of 0 indicates a terminator.
|
||||
*
|
||||
* https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
|
||||
*/
|
||||
void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len) {
|
||||
uint8_t length;
|
||||
uint8_t ad_type;
|
||||
uint8_t sizeConsumed = 0;
|
||||
bool finished = false;
|
||||
m_payload = payload;
|
||||
m_payloadLength = total_len;
|
||||
|
||||
while(!finished) {
|
||||
length = *payload; // Retrieve the length of the record.
|
||||
payload++; // Skip to type
|
||||
sizeConsumed += 1 + length; // increase the size consumed.
|
||||
|
||||
if (length != 0) { // A length of 0 indicates that we have reached the end.
|
||||
ad_type = *payload;
|
||||
payload++;
|
||||
length--;
|
||||
|
||||
char* pHex = BLEUtils::buildHexData(nullptr, payload, length);
|
||||
ESP_LOGD(LOG_TAG, "Type: 0x%.2x (%s), length: %d, data: %s",
|
||||
ad_type, BLEUtils::advTypeToString(ad_type), length, pHex);
|
||||
free(pHex);
|
||||
|
||||
switch(ad_type) {
|
||||
case ESP_BLE_AD_TYPE_NAME_CMPL: { // Adv Data Type: 0x09
|
||||
setName(std::string(reinterpret_cast<char*>(payload), length));
|
||||
break;
|
||||
} // ESP_BLE_AD_TYPE_NAME_CMPL
|
||||
|
||||
case ESP_BLE_AD_TYPE_TX_PWR: { // Adv Data Type: 0x0A
|
||||
setTXPower(*payload);
|
||||
break;
|
||||
} // ESP_BLE_AD_TYPE_TX_PWR
|
||||
|
||||
case ESP_BLE_AD_TYPE_APPEARANCE: { // Adv Data Type: 0x19
|
||||
setAppearance(*reinterpret_cast<uint16_t*>(payload));
|
||||
break;
|
||||
} // ESP_BLE_AD_TYPE_APPEARANCE
|
||||
|
||||
case ESP_BLE_AD_TYPE_FLAG: { // Adv Data Type: 0x01
|
||||
setAdFlag(*payload);
|
||||
break;
|
||||
} // ESP_BLE_AD_TYPE_FLAG
|
||||
|
||||
case ESP_BLE_AD_TYPE_16SRV_CMPL:
|
||||
case ESP_BLE_AD_TYPE_16SRV_PART: { // Adv Data Type: 0x02
|
||||
for (int var = 0; var < length/2; ++var) {
|
||||
setServiceUUID(BLEUUID(*reinterpret_cast<uint16_t*>(payload + var * 2)));
|
||||
}
|
||||
break;
|
||||
} // ESP_BLE_AD_TYPE_16SRV_PART
|
||||
|
||||
case ESP_BLE_AD_TYPE_32SRV_CMPL:
|
||||
case ESP_BLE_AD_TYPE_32SRV_PART: { // Adv Data Type: 0x04
|
||||
for (int var = 0; var < length/4; ++var) {
|
||||
setServiceUUID(BLEUUID(*reinterpret_cast<uint32_t*>(payload + var * 4)));
|
||||
}
|
||||
break;
|
||||
} // ESP_BLE_AD_TYPE_32SRV_PART
|
||||
|
||||
case ESP_BLE_AD_TYPE_128SRV_CMPL: { // Adv Data Type: 0x07
|
||||
setServiceUUID(BLEUUID(payload, 16, false));
|
||||
break;
|
||||
} // ESP_BLE_AD_TYPE_128SRV_CMPL
|
||||
|
||||
case ESP_BLE_AD_TYPE_128SRV_PART: { // Adv Data Type: 0x06
|
||||
setServiceUUID(BLEUUID(payload, 16, false));
|
||||
break;
|
||||
} // ESP_BLE_AD_TYPE_128SRV_PART
|
||||
|
||||
// See CSS Part A 1.4 Manufacturer Specific Data
|
||||
case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: {
|
||||
setManufacturerData(std::string(reinterpret_cast<char*>(payload), length));
|
||||
break;
|
||||
} // ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE
|
||||
|
||||
case ESP_BLE_AD_TYPE_SERVICE_DATA: { // Adv Data Type: 0x16 (Service Data) - 2 byte UUID
|
||||
if (length < 2) {
|
||||
ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_SERVICE_DATA");
|
||||
break;
|
||||
}
|
||||
uint16_t uuid = *(uint16_t*)payload;
|
||||
setServiceDataUUID(BLEUUID(uuid));
|
||||
if (length > 2) {
|
||||
setServiceData(std::string(reinterpret_cast<char*>(payload + 2), length - 2));
|
||||
}
|
||||
break;
|
||||
} //ESP_BLE_AD_TYPE_SERVICE_DATA
|
||||
|
||||
case ESP_BLE_AD_TYPE_32SERVICE_DATA: { // Adv Data Type: 0x20 (Service Data) - 4 byte UUID
|
||||
if (length < 4) {
|
||||
ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_32SERVICE_DATA");
|
||||
break;
|
||||
}
|
||||
uint32_t uuid = *(uint32_t*) payload;
|
||||
setServiceDataUUID(BLEUUID(uuid));
|
||||
if (length > 4) {
|
||||
setServiceData(std::string(reinterpret_cast<char*>(payload + 4), length - 4));
|
||||
}
|
||||
break;
|
||||
} //ESP_BLE_AD_TYPE_32SERVICE_DATA
|
||||
|
||||
case ESP_BLE_AD_TYPE_128SERVICE_DATA: { // Adv Data Type: 0x21 (Service Data) - 16 byte UUID
|
||||
if (length < 16) {
|
||||
ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_128SERVICE_DATA");
|
||||
break;
|
||||
}
|
||||
|
||||
setServiceDataUUID(BLEUUID(payload, (size_t)16, false));
|
||||
if (length > 16) {
|
||||
setServiceData(std::string(reinterpret_cast<char*>(payload + 16), length - 16));
|
||||
}
|
||||
break;
|
||||
} //ESP_BLE_AD_TYPE_32SERVICE_DATA
|
||||
|
||||
default: {
|
||||
ESP_LOGD(LOG_TAG, "Unhandled type: adType: %d - 0x%.2x", ad_type, ad_type);
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
payload += length;
|
||||
} // Length <> 0
|
||||
|
||||
|
||||
if (sizeConsumed >= total_len)
|
||||
finished = true;
|
||||
|
||||
} // !finished
|
||||
} // parseAdvertisement
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the address of the advertised device.
|
||||
* @param [in] address The address of the advertised device.
|
||||
*/
|
||||
void BLEAdvertisedDevice::setAddress(BLEAddress address) {
|
||||
m_address = address;
|
||||
} // setAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the adFlag for this device.
|
||||
* @param [in] The discovered adFlag.
|
||||
*/
|
||||
void BLEAdvertisedDevice::setAdFlag(uint8_t adFlag) {
|
||||
m_adFlag = adFlag;
|
||||
} // setAdFlag
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the appearance for this device.
|
||||
* @param [in] The discovered appearance.
|
||||
*/
|
||||
void BLEAdvertisedDevice::setAppearance(uint16_t appearance) {
|
||||
m_appearance = appearance;
|
||||
m_haveAppearance = true;
|
||||
ESP_LOGD(LOG_TAG, "- appearance: %d", m_appearance);
|
||||
} // setAppearance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the manufacturer data for this device.
|
||||
* @param [in] The discovered manufacturer data.
|
||||
*/
|
||||
void BLEAdvertisedDevice::setManufacturerData(std::string manufacturerData) {
|
||||
m_manufacturerData = manufacturerData;
|
||||
m_haveManufacturerData = true;
|
||||
char* pHex = BLEUtils::buildHexData(nullptr, (uint8_t*) m_manufacturerData.data(), (uint8_t) m_manufacturerData.length());
|
||||
ESP_LOGD(LOG_TAG, "- manufacturer data: %s", pHex);
|
||||
free(pHex);
|
||||
} // setManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the name for this device.
|
||||
* @param [in] name The discovered name.
|
||||
*/
|
||||
void BLEAdvertisedDevice::setName(std::string name) {
|
||||
m_name = name;
|
||||
m_haveName = true;
|
||||
ESP_LOGD(LOG_TAG, "- setName(): name: %s", m_name.c_str());
|
||||
} // setName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the RSSI for this device.
|
||||
* @param [in] rssi The discovered RSSI.
|
||||
*/
|
||||
void BLEAdvertisedDevice::setRSSI(int rssi) {
|
||||
m_rssi = rssi;
|
||||
m_haveRSSI = true;
|
||||
ESP_LOGD(LOG_TAG, "- setRSSI(): rssi: %d", m_rssi);
|
||||
} // setRSSI
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Scan that created this advertised device.
|
||||
* @param pScan The Scan that created this advertised device.
|
||||
*/
|
||||
void BLEAdvertisedDevice::setScan(BLEScan* pScan) {
|
||||
m_pScan = pScan;
|
||||
} // setScan
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Service UUID for this device.
|
||||
* @param [in] serviceUUID The discovered serviceUUID
|
||||
*/
|
||||
void BLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) {
|
||||
return setServiceUUID(BLEUUID(serviceUUID));
|
||||
} // setServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Service UUID for this device.
|
||||
* @param [in] serviceUUID The discovered serviceUUID
|
||||
*/
|
||||
void BLEAdvertisedDevice::setServiceUUID(BLEUUID serviceUUID) {
|
||||
m_serviceUUIDs.push_back(serviceUUID);
|
||||
m_haveServiceUUID = true;
|
||||
ESP_LOGD(LOG_TAG, "- addServiceUUID(): serviceUUID: %s", serviceUUID.toString().c_str());
|
||||
} // setServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the ServiceData value.
|
||||
* @param [in] data ServiceData value.
|
||||
*/
|
||||
void BLEAdvertisedDevice::setServiceData(std::string serviceData) {
|
||||
m_haveServiceData = true; // Set the flag that indicates we have service data.
|
||||
m_serviceData = serviceData; // Save the service data that we received.
|
||||
} //setServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the ServiceDataUUID value.
|
||||
* @param [in] data ServiceDataUUID value.
|
||||
*/
|
||||
void BLEAdvertisedDevice::setServiceDataUUID(BLEUUID uuid) {
|
||||
m_haveServiceData = true; // Set the flag that indicates we have service data.
|
||||
m_serviceDataUUID = uuid;
|
||||
} // setServiceDataUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the power level for this device.
|
||||
* @param [in] txPower The discovered power level.
|
||||
*/
|
||||
void BLEAdvertisedDevice::setTXPower(int8_t txPower) {
|
||||
m_txPower = txPower;
|
||||
m_haveTXPower = true;
|
||||
ESP_LOGD(LOG_TAG, "- txPower: %d", m_txPower);
|
||||
} // setTXPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of this device.
|
||||
* @return A string representation of this device.
|
||||
*/
|
||||
std::string BLEAdvertisedDevice::toString() {
|
||||
std::stringstream ss;
|
||||
ss << "Name: " << getName() << ", Address: " << getAddress().toString();
|
||||
if (haveAppearance()) {
|
||||
ss << ", appearance: " << getAppearance();
|
||||
}
|
||||
if (haveManufacturerData()) {
|
||||
char *pHex = BLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length());
|
||||
ss << ", manufacturer data: " << pHex;
|
||||
free(pHex);
|
||||
}
|
||||
if (haveServiceUUID()) {
|
||||
ss << ", serviceUUID: " << getServiceUUID().toString();
|
||||
}
|
||||
if (haveTXPower()) {
|
||||
ss << ", txPower: " << (int)getTXPower();
|
||||
}
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
uint8_t* BLEAdvertisedDevice::getPayload() {
|
||||
return m_payload;
|
||||
}
|
||||
|
||||
esp_ble_addr_type_t BLEAdvertisedDevice::getAddressType() {
|
||||
return m_addressType;
|
||||
}
|
||||
|
||||
void BLEAdvertisedDevice::setAddressType(esp_ble_addr_type_t type) {
|
||||
m_addressType = type;
|
||||
}
|
||||
|
||||
size_t BLEAdvertisedDevice::getPayloadLength() {
|
||||
return m_payloadLength;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
|
||||
123
libraries/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h
Normal file
123
libraries/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* BLEAdvertisedDevice.h
|
||||
*
|
||||
* Created on: Jul 3, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_gattc_api.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "BLEAddress.h"
|
||||
#include "BLEScan.h"
|
||||
#include "BLEUUID.h"
|
||||
|
||||
|
||||
class BLEScan;
|
||||
/**
|
||||
* @brief A representation of a %BLE advertised device found by a scan.
|
||||
*
|
||||
* When we perform a %BLE scan, the result will be a set of devices that are advertising. This
|
||||
* class provides a model of a detected device.
|
||||
*/
|
||||
class BLEAdvertisedDevice {
|
||||
public:
|
||||
BLEAdvertisedDevice();
|
||||
|
||||
BLEAddress getAddress();
|
||||
uint16_t getAppearance();
|
||||
std::string getManufacturerData();
|
||||
std::string getName();
|
||||
int getRSSI();
|
||||
BLEScan* getScan();
|
||||
std::string getServiceData();
|
||||
BLEUUID getServiceDataUUID();
|
||||
BLEUUID getServiceUUID();
|
||||
int8_t getTXPower();
|
||||
uint8_t* getPayload();
|
||||
size_t getPayloadLength();
|
||||
esp_ble_addr_type_t getAddressType();
|
||||
void setAddressType(esp_ble_addr_type_t type);
|
||||
|
||||
|
||||
bool isAdvertisingService(BLEUUID uuid);
|
||||
bool haveAppearance();
|
||||
bool haveManufacturerData();
|
||||
bool haveName();
|
||||
bool haveRSSI();
|
||||
bool haveServiceData();
|
||||
bool haveServiceUUID();
|
||||
bool haveTXPower();
|
||||
|
||||
std::string toString();
|
||||
|
||||
private:
|
||||
friend class BLEScan;
|
||||
|
||||
void parseAdvertisement(uint8_t* payload, size_t total_len=62);
|
||||
void setAddress(BLEAddress address);
|
||||
void setAdFlag(uint8_t adFlag);
|
||||
void setAdvertizementResult(uint8_t* payload);
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setManufacturerData(std::string manufacturerData);
|
||||
void setName(std::string name);
|
||||
void setRSSI(int rssi);
|
||||
void setScan(BLEScan* pScan);
|
||||
void setServiceData(std::string data);
|
||||
void setServiceDataUUID(BLEUUID uuid);
|
||||
void setServiceUUID(const char* serviceUUID);
|
||||
void setServiceUUID(BLEUUID serviceUUID);
|
||||
void setTXPower(int8_t txPower);
|
||||
|
||||
bool m_haveAppearance;
|
||||
bool m_haveManufacturerData;
|
||||
bool m_haveName;
|
||||
bool m_haveRSSI;
|
||||
bool m_haveServiceData;
|
||||
bool m_haveServiceUUID;
|
||||
bool m_haveTXPower;
|
||||
|
||||
|
||||
BLEAddress m_address = BLEAddress((uint8_t*)"\0\0\0\0\0\0");
|
||||
uint8_t m_adFlag;
|
||||
uint16_t m_appearance;
|
||||
int m_deviceType;
|
||||
std::string m_manufacturerData;
|
||||
std::string m_name;
|
||||
BLEScan* m_pScan;
|
||||
int m_rssi;
|
||||
std::vector<BLEUUID> m_serviceUUIDs;
|
||||
int8_t m_txPower;
|
||||
std::string m_serviceData;
|
||||
BLEUUID m_serviceDataUUID;
|
||||
uint8_t* m_payload;
|
||||
size_t m_payloadLength = 0;
|
||||
esp_ble_addr_type_t m_addressType;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A callback handler for callbacks associated device scanning.
|
||||
*
|
||||
* When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising
|
||||
* has been found. This class can be sub-classed and registered such that when a scan is performed and
|
||||
* a new advertised device has been found, we will be called back to be notified.
|
||||
*/
|
||||
class BLEAdvertisedDeviceCallbacks {
|
||||
public:
|
||||
virtual ~BLEAdvertisedDeviceCallbacks() {}
|
||||
/**
|
||||
* @brief Called when a new scan result is detected.
|
||||
*
|
||||
* As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the
|
||||
* device that was found. During any individual scan, a device will only be detected one time.
|
||||
*/
|
||||
virtual void onResult(BLEAdvertisedDevice advertisedDevice) = 0;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ */
|
||||
505
libraries/ESP32_BLE_Arduino/src/BLEAdvertising.cpp
Normal file
505
libraries/ESP32_BLE_Arduino/src/BLEAdvertising.cpp
Normal file
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* BLEAdvertising.cpp
|
||||
*
|
||||
* This class encapsulates advertising a BLE Server.
|
||||
* Created on: Jun 21, 2017
|
||||
* Author: kolban
|
||||
*
|
||||
* The ESP-IDF provides a framework for BLE advertising. It has determined that there are a common set
|
||||
* of properties that are advertised and has built a data structure that can be populated by the programmer.
|
||||
* This means that the programmer doesn't have to "mess with" the low level construction of a low level
|
||||
* BLE advertising frame. Many of the fields are determined for us while others we can set before starting
|
||||
* to advertise.
|
||||
*
|
||||
* Should we wish to construct our own payload, we can use the BLEAdvertisementData class and call the setters
|
||||
* upon it. Once it is populated, we can then associate it with the advertising and what ever the programmer
|
||||
* set in the data will be advertised.
|
||||
*
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include "BLEAdvertising.h"
|
||||
#include <esp_err.h>
|
||||
#include "BLEUtils.h"
|
||||
#include "GeneralUtils.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEAdvertising";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a default advertising object.
|
||||
*
|
||||
*/
|
||||
BLEAdvertising::BLEAdvertising() {
|
||||
m_advData.set_scan_rsp = false;
|
||||
m_advData.include_name = true;
|
||||
m_advData.include_txpower = true;
|
||||
m_advData.min_interval = 0x20;
|
||||
m_advData.max_interval = 0x40;
|
||||
m_advData.appearance = 0x00;
|
||||
m_advData.manufacturer_len = 0;
|
||||
m_advData.p_manufacturer_data = nullptr;
|
||||
m_advData.service_data_len = 0;
|
||||
m_advData.p_service_data = nullptr;
|
||||
m_advData.service_uuid_len = 0;
|
||||
m_advData.p_service_uuid = nullptr;
|
||||
m_advData.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT);
|
||||
|
||||
m_advParams.adv_int_min = 0x20;
|
||||
m_advParams.adv_int_max = 0x40;
|
||||
m_advParams.adv_type = ADV_TYPE_IND;
|
||||
m_advParams.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
|
||||
m_advParams.channel_map = ADV_CHNL_ALL;
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
|
||||
m_advParams.peer_addr_type = BLE_ADDR_TYPE_PUBLIC;
|
||||
|
||||
m_customAdvData = false; // No custom advertising data
|
||||
m_customScanResponseData = false; // No custom scan response data
|
||||
} // BLEAdvertising
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a service uuid to exposed list of services.
|
||||
* @param [in] serviceUUID The UUID of the service to expose.
|
||||
*/
|
||||
void BLEAdvertising::addServiceUUID(BLEUUID serviceUUID) {
|
||||
m_serviceUUIDs.push_back(serviceUUID);
|
||||
} // addServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a service uuid to exposed list of services.
|
||||
* @param [in] serviceUUID The string representation of the service to expose.
|
||||
*/
|
||||
void BLEAdvertising::addServiceUUID(const char* serviceUUID) {
|
||||
addServiceUUID(BLEUUID(serviceUUID));
|
||||
} // addServiceUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the device appearance in the advertising data.
|
||||
* The appearance attribute is of type 0x19. The codes for distinct appearances can be found here:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml.
|
||||
* @param [in] appearance The appearance of the device in the advertising data.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEAdvertising::setAppearance(uint16_t appearance) {
|
||||
m_advData.appearance = appearance;
|
||||
} // setAppearance
|
||||
|
||||
void BLEAdvertising::setMinInterval(uint16_t mininterval) {
|
||||
m_advParams.adv_int_min = mininterval;
|
||||
} // setMinInterval
|
||||
|
||||
void BLEAdvertising::setMaxInterval(uint16_t maxinterval) {
|
||||
m_advParams.adv_int_max = maxinterval;
|
||||
} // setMaxInterval
|
||||
|
||||
void BLEAdvertising::setMinPreferred(uint16_t mininterval) {
|
||||
m_advData.min_interval = mininterval;
|
||||
} //
|
||||
|
||||
void BLEAdvertising::setMaxPreferred(uint16_t maxinterval) {
|
||||
m_advData.max_interval = maxinterval;
|
||||
} //
|
||||
|
||||
void BLEAdvertising::setScanResponse(bool set) {
|
||||
m_scanResp = set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the filtering for the scan filter.
|
||||
* @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list.
|
||||
* @param [in] connectWhitelistOnly If true, only allow connections from those on the white list.
|
||||
*/
|
||||
void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) {
|
||||
ESP_LOGD(LOG_TAG, ">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly);
|
||||
if (!scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
if (scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
if (!scanRequestWhitelistOnly && connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
if (scanRequestWhitelistOnly && connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
} // setScanFilter
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement data that is to be published in a regular advertisement.
|
||||
* @param [in] advertisementData The data to be advertised.
|
||||
*/
|
||||
void BLEAdvertising::setAdvertisementData(BLEAdvertisementData& advertisementData) {
|
||||
ESP_LOGD(LOG_TAG, ">> setAdvertisementData");
|
||||
esp_err_t errRc = ::esp_ble_gap_config_adv_data_raw(
|
||||
(uint8_t*)advertisementData.getPayload().data(),
|
||||
advertisementData.getPayload().length());
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_config_adv_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
m_customAdvData = true; // Set the flag that indicates we are using custom advertising data.
|
||||
ESP_LOGD(LOG_TAG, "<< setAdvertisementData");
|
||||
} // setAdvertisementData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement data that is to be published in a scan response.
|
||||
* @param [in] advertisementData The data to be advertised.
|
||||
*/
|
||||
void BLEAdvertising::setScanResponseData(BLEAdvertisementData& advertisementData) {
|
||||
ESP_LOGD(LOG_TAG, ">> setScanResponseData");
|
||||
esp_err_t errRc = ::esp_ble_gap_config_scan_rsp_data_raw(
|
||||
(uint8_t*)advertisementData.getPayload().data(),
|
||||
advertisementData.getPayload().length());
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_config_scan_rsp_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data.
|
||||
ESP_LOGD(LOG_TAG, "<< setScanResponseData");
|
||||
} // setScanResponseData
|
||||
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
* Start advertising.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEAdvertising::start() {
|
||||
ESP_LOGD(LOG_TAG, ">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData);
|
||||
|
||||
// We have a vector of service UUIDs that we wish to advertise. In order to use the
|
||||
// ESP-IDF framework, these must be supplied in a contiguous array of their 128bit (16 byte)
|
||||
// representations. If we have 1 or more services to advertise then we allocate enough
|
||||
// storage to host them and then copy them in one at a time into the contiguous storage.
|
||||
int numServices = m_serviceUUIDs.size();
|
||||
if (numServices > 0) {
|
||||
m_advData.service_uuid_len = 16 * numServices;
|
||||
m_advData.p_service_uuid = new uint8_t[m_advData.service_uuid_len];
|
||||
uint8_t* p = m_advData.p_service_uuid;
|
||||
for (int i = 0; i < numServices; i++) {
|
||||
ESP_LOGD(LOG_TAG, "- advertising service: %s", m_serviceUUIDs[i].toString().c_str());
|
||||
BLEUUID serviceUUID128 = m_serviceUUIDs[i].to128();
|
||||
memcpy(p, serviceUUID128.getNative()->uuid.uuid128, 16);
|
||||
p += 16;
|
||||
}
|
||||
} else {
|
||||
m_advData.service_uuid_len = 0;
|
||||
ESP_LOGD(LOG_TAG, "- no services advertised");
|
||||
}
|
||||
|
||||
esp_err_t errRc;
|
||||
|
||||
if (!m_customAdvData) {
|
||||
// Set the configuration for advertising.
|
||||
m_advData.set_scan_rsp = false;
|
||||
m_advData.include_name = !m_scanResp;
|
||||
m_advData.include_txpower = !m_scanResp;
|
||||
errRc = ::esp_ble_gap_config_adv_data(&m_advData);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_customScanResponseData && m_scanResp) {
|
||||
m_advData.set_scan_rsp = true;
|
||||
m_advData.include_name = m_scanResp;
|
||||
m_advData.include_txpower = m_scanResp;
|
||||
errRc = ::esp_ble_gap_config_adv_data(&m_advData);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we had services to advertise then we previously allocated some storage for them.
|
||||
// Here we release that storage.
|
||||
if (m_advData.service_uuid_len > 0) {
|
||||
delete[] m_advData.p_service_uuid;
|
||||
m_advData.p_service_uuid = nullptr;
|
||||
}
|
||||
|
||||
// Start advertising.
|
||||
errRc = ::esp_ble_gap_start_advertising(&m_advParams);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< start");
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop advertising.
|
||||
* Stop advertising.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEAdvertising::stop() {
|
||||
ESP_LOGD(LOG_TAG, ">> stop");
|
||||
esp_err_t errRc = ::esp_ble_gap_stop_advertising();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< stop");
|
||||
} // stop
|
||||
|
||||
/**
|
||||
* @brief Add data to the payload to be advertised.
|
||||
* @param [in] data The data to be added to the payload.
|
||||
*/
|
||||
void BLEAdvertisementData::addData(std::string data) {
|
||||
if ((m_payload.length() + data.length()) > ESP_BLE_ADV_DATA_LEN_MAX) {
|
||||
return;
|
||||
}
|
||||
m_payload.append(data);
|
||||
} // addData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the appearance.
|
||||
* @param [in] appearance The appearance code value.
|
||||
*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml
|
||||
*/
|
||||
void BLEAdvertisementData::setAppearance(uint16_t appearance) {
|
||||
char cdata[2];
|
||||
cdata[0] = 3;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_APPEARANCE; // 0x19
|
||||
addData(std::string(cdata, 2) + std::string((char*) &appearance, 2));
|
||||
} // setAppearance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the complete services.
|
||||
* @param [in] uuid The single service to advertise.
|
||||
*/
|
||||
void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) {
|
||||
char cdata[2];
|
||||
switch (uuid.bitSize()) {
|
||||
case 16: {
|
||||
// [Len] [0x02] [LL] [HH]
|
||||
cdata[0] = 3;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_16SRV_CMPL; // 0x03
|
||||
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid16, 2));
|
||||
break;
|
||||
}
|
||||
|
||||
case 32: {
|
||||
// [Len] [0x04] [LL] [LL] [HH] [HH]
|
||||
cdata[0] = 5;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_32SRV_CMPL; // 0x05
|
||||
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid32, 4));
|
||||
break;
|
||||
}
|
||||
|
||||
case 128: {
|
||||
// [Len] [0x04] [0] [1] ... [15]
|
||||
cdata[0] = 17;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_128SRV_CMPL; // 0x07
|
||||
addData(std::string(cdata, 2) + std::string((char*) uuid.getNative()->uuid.uuid128, 16));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} // setCompleteServices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement flags.
|
||||
* @param [in] The flags to be set in the advertisement.
|
||||
*
|
||||
* * ESP_BLE_ADV_FLAG_LIMIT_DISC
|
||||
* * ESP_BLE_ADV_FLAG_GEN_DISC
|
||||
* * ESP_BLE_ADV_FLAG_BREDR_NOT_SPT
|
||||
* * ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT
|
||||
* * ESP_BLE_ADV_FLAG_DMT_HOST_SPT
|
||||
* * ESP_BLE_ADV_FLAG_NON_LIMIT_DISC
|
||||
*/
|
||||
void BLEAdvertisementData::setFlags(uint8_t flag) {
|
||||
char cdata[3];
|
||||
cdata[0] = 2;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_FLAG; // 0x01
|
||||
cdata[2] = flag;
|
||||
addData(std::string(cdata, 3));
|
||||
} // setFlag
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set manufacturer specific data.
|
||||
* @param [in] data Manufacturer data.
|
||||
*/
|
||||
void BLEAdvertisementData::setManufacturerData(std::string data) {
|
||||
ESP_LOGD("BLEAdvertisementData", ">> setManufacturerData");
|
||||
char cdata[2];
|
||||
cdata[0] = data.length() + 1;
|
||||
cdata[1] = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE; // 0xff
|
||||
addData(std::string(cdata, 2) + data);
|
||||
ESP_LOGD("BLEAdvertisementData", "<< setManufacturerData");
|
||||
} // setManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the name.
|
||||
* @param [in] The complete name of the device.
|
||||
*/
|
||||
void BLEAdvertisementData::setName(std::string name) {
|
||||
ESP_LOGD("BLEAdvertisementData", ">> setName: %s", name.c_str());
|
||||
char cdata[2];
|
||||
cdata[0] = name.length() + 1;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_NAME_CMPL; // 0x09
|
||||
addData(std::string(cdata, 2) + name);
|
||||
ESP_LOGD("BLEAdvertisementData", "<< setName");
|
||||
} // setName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the partial services.
|
||||
* @param [in] uuid The single service to advertise.
|
||||
*/
|
||||
void BLEAdvertisementData::setPartialServices(BLEUUID uuid) {
|
||||
char cdata[2];
|
||||
switch (uuid.bitSize()) {
|
||||
case 16: {
|
||||
// [Len] [0x02] [LL] [HH]
|
||||
cdata[0] = 3;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_16SRV_PART; // 0x02
|
||||
addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid16, 2));
|
||||
break;
|
||||
}
|
||||
|
||||
case 32: {
|
||||
// [Len] [0x04] [LL] [LL] [HH] [HH]
|
||||
cdata[0] = 5;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_32SRV_PART; // 0x04
|
||||
addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid32, 4));
|
||||
break;
|
||||
}
|
||||
|
||||
case 128: {
|
||||
// [Len] [0x04] [0] [1] ... [15]
|
||||
cdata[0] = 17;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_128SRV_PART; // 0x06
|
||||
addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid128, 16));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} // setPartialServices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the service data (UUID + data)
|
||||
* @param [in] uuid The UUID to set with the service data. Size of UUID will be used.
|
||||
* @param [in] data The data to be associated with the service data advert.
|
||||
*/
|
||||
void BLEAdvertisementData::setServiceData(BLEUUID uuid, std::string data) {
|
||||
char cdata[2];
|
||||
switch (uuid.bitSize()) {
|
||||
case 16: {
|
||||
// [Len] [0x16] [UUID16] data
|
||||
cdata[0] = data.length() + 3;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_SERVICE_DATA; // 0x16
|
||||
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid16, 2) + data);
|
||||
break;
|
||||
}
|
||||
|
||||
case 32: {
|
||||
// [Len] [0x20] [UUID32] data
|
||||
cdata[0] = data.length() + 5;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_32SERVICE_DATA; // 0x20
|
||||
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid32, 4) + data);
|
||||
break;
|
||||
}
|
||||
|
||||
case 128: {
|
||||
// [Len] [0x21] [UUID128] data
|
||||
cdata[0] = data.length() + 17;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_128SERVICE_DATA; // 0x21
|
||||
addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid128, 16) + data);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} // setServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the short name.
|
||||
* @param [in] The short name of the device.
|
||||
*/
|
||||
void BLEAdvertisementData::setShortName(std::string name) {
|
||||
ESP_LOGD("BLEAdvertisementData", ">> setShortName: %s", name.c_str());
|
||||
char cdata[2];
|
||||
cdata[0] = name.length() + 1;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_NAME_SHORT; // 0x08
|
||||
addData(std::string(cdata, 2) + name);
|
||||
ESP_LOGD("BLEAdvertisementData", "<< setShortName");
|
||||
} // setShortName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the payload that is to be advertised.
|
||||
* @return The payload that is to be advertised.
|
||||
*/
|
||||
std::string BLEAdvertisementData::getPayload() {
|
||||
return m_payload;
|
||||
} // getPayload
|
||||
|
||||
void BLEAdvertising::handleGAPEvent(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param) {
|
||||
|
||||
ESP_LOGD(LOG_TAG, "handleGAPEvent [event no: %d]", (int)event);
|
||||
|
||||
switch(event) {
|
||||
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: {
|
||||
// m_semaphoreSetAdv.give();
|
||||
break;
|
||||
}
|
||||
case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: {
|
||||
// m_semaphoreSetAdv.give();
|
||||
break;
|
||||
}
|
||||
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: {
|
||||
// m_semaphoreSetAdv.give();
|
||||
break;
|
||||
}
|
||||
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: {
|
||||
ESP_LOGI(LOG_TAG, "STOP advertising");
|
||||
start();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
78
libraries/ESP32_BLE_Arduino/src/BLEAdvertising.h
Normal file
78
libraries/ESP32_BLE_Arduino/src/BLEAdvertising.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* BLEAdvertising.h
|
||||
*
|
||||
* Created on: Jun 21, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEADVERTISING_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEADVERTISING_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include "BLEUUID.h"
|
||||
#include <vector>
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
/**
|
||||
* @brief Advertisement data set by the programmer to be published by the %BLE server.
|
||||
*/
|
||||
class BLEAdvertisementData {
|
||||
// Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will
|
||||
// be exposed on demand/request or as time permits.
|
||||
//
|
||||
public:
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setCompleteServices(BLEUUID uuid);
|
||||
void setFlags(uint8_t);
|
||||
void setManufacturerData(std::string data);
|
||||
void setName(std::string name);
|
||||
void setPartialServices(BLEUUID uuid);
|
||||
void setServiceData(BLEUUID uuid, std::string data);
|
||||
void setShortName(std::string name);
|
||||
void addData(std::string data); // Add data to the payload.
|
||||
std::string getPayload(); // Retrieve the current advert payload.
|
||||
|
||||
private:
|
||||
friend class BLEAdvertising;
|
||||
std::string m_payload; // The payload of the advertisement.
|
||||
}; // BLEAdvertisementData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Perform and manage %BLE advertising.
|
||||
*
|
||||
* A %BLE server will want to perform advertising in order to make itself known to %BLE clients.
|
||||
*/
|
||||
class BLEAdvertising {
|
||||
public:
|
||||
BLEAdvertising();
|
||||
void addServiceUUID(BLEUUID serviceUUID);
|
||||
void addServiceUUID(const char* serviceUUID);
|
||||
void start();
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setMaxInterval(uint16_t maxinterval);
|
||||
void setMinInterval(uint16_t mininterval);
|
||||
void setAdvertisementData(BLEAdvertisementData& advertisementData);
|
||||
void setScanFilter(bool scanRequertWhitelistOnly, bool connectWhitelistOnly);
|
||||
void setScanResponseData(BLEAdvertisementData& advertisementData);
|
||||
void setPrivateAddress(esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM);
|
||||
|
||||
void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param);
|
||||
void setMinPreferred(uint16_t);
|
||||
void setMaxPreferred(uint16_t);
|
||||
void setScanResponse(bool);
|
||||
|
||||
private:
|
||||
esp_ble_adv_data_t m_advData;
|
||||
esp_ble_adv_params_t m_advParams;
|
||||
std::vector<BLEUUID> m_serviceUUIDs;
|
||||
bool m_customAdvData = false; // Are we using custom advertising data?
|
||||
bool m_customScanResponseData = false; // Are we using custom scan response data?
|
||||
FreeRTOS::Semaphore m_semaphoreSetAdv = FreeRTOS::Semaphore("startAdvert");
|
||||
bool m_scanResp = true;
|
||||
|
||||
};
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */
|
||||
89
libraries/ESP32_BLE_Arduino/src/BLEBeacon.cpp
Normal file
89
libraries/ESP32_BLE_Arduino/src/BLEBeacon.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* BLEBeacon.cpp
|
||||
*
|
||||
* Created on: Jan 4, 2018
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string.h>
|
||||
#include "BLEBeacon.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEBeacon";
|
||||
#endif
|
||||
|
||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
|
||||
|
||||
|
||||
BLEBeacon::BLEBeacon() {
|
||||
m_beaconData.manufacturerId = 0x4c00;
|
||||
m_beaconData.subType = 0x02;
|
||||
m_beaconData.subTypeLength = 0x15;
|
||||
m_beaconData.major = 0;
|
||||
m_beaconData.minor = 0;
|
||||
m_beaconData.signalPower = 0;
|
||||
memset(m_beaconData.proximityUUID, 0, sizeof(m_beaconData.proximityUUID));
|
||||
} // BLEBeacon
|
||||
|
||||
std::string BLEBeacon::getData() {
|
||||
return std::string((char*) &m_beaconData, sizeof(m_beaconData));
|
||||
} // getData
|
||||
|
||||
uint16_t BLEBeacon::getMajor() {
|
||||
return m_beaconData.major;
|
||||
}
|
||||
|
||||
uint16_t BLEBeacon::getManufacturerId() {
|
||||
return m_beaconData.manufacturerId;
|
||||
}
|
||||
|
||||
uint16_t BLEBeacon::getMinor() {
|
||||
return m_beaconData.minor;
|
||||
}
|
||||
|
||||
BLEUUID BLEBeacon::getProximityUUID() {
|
||||
return BLEUUID(m_beaconData.proximityUUID, 16, false);
|
||||
}
|
||||
|
||||
int8_t BLEBeacon::getSignalPower() {
|
||||
return m_beaconData.signalPower;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the raw data for the beacon record.
|
||||
*/
|
||||
void BLEBeacon::setData(std::string data) {
|
||||
if (data.length() != sizeof(m_beaconData)) {
|
||||
ESP_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_beaconData));
|
||||
return;
|
||||
}
|
||||
memcpy(&m_beaconData, data.data(), sizeof(m_beaconData));
|
||||
} // setData
|
||||
|
||||
void BLEBeacon::setMajor(uint16_t major) {
|
||||
m_beaconData.major = ENDIAN_CHANGE_U16(major);
|
||||
} // setMajor
|
||||
|
||||
void BLEBeacon::setManufacturerId(uint16_t manufacturerId) {
|
||||
m_beaconData.manufacturerId = ENDIAN_CHANGE_U16(manufacturerId);
|
||||
} // setManufacturerId
|
||||
|
||||
void BLEBeacon::setMinor(uint16_t minor) {
|
||||
m_beaconData.minor = ENDIAN_CHANGE_U16(minor);
|
||||
} // setMinior
|
||||
|
||||
void BLEBeacon::setProximityUUID(BLEUUID uuid) {
|
||||
uuid = uuid.to128();
|
||||
memcpy(m_beaconData.proximityUUID, uuid.getNative()->uuid.uuid128, 16);
|
||||
} // setProximityUUID
|
||||
|
||||
void BLEBeacon::setSignalPower(int8_t signalPower) {
|
||||
m_beaconData.signalPower = signalPower;
|
||||
} // setSignalPower
|
||||
|
||||
|
||||
#endif
|
||||
43
libraries/ESP32_BLE_Arduino/src/BLEBeacon.h
Normal file
43
libraries/ESP32_BLE_Arduino/src/BLEBeacon.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* BLEBeacon2.h
|
||||
*
|
||||
* Created on: Jan 4, 2018
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEBEACON_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEBEACON_H_
|
||||
#include "BLEUUID.h"
|
||||
/**
|
||||
* @brief Representation of a beacon.
|
||||
* See:
|
||||
* * https://en.wikipedia.org/wiki/IBeacon
|
||||
*/
|
||||
class BLEBeacon {
|
||||
private:
|
||||
struct {
|
||||
uint16_t manufacturerId;
|
||||
uint8_t subType;
|
||||
uint8_t subTypeLength;
|
||||
uint8_t proximityUUID[16];
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
int8_t signalPower;
|
||||
} __attribute__((packed)) m_beaconData;
|
||||
public:
|
||||
BLEBeacon();
|
||||
std::string getData();
|
||||
uint16_t getMajor();
|
||||
uint16_t getMinor();
|
||||
uint16_t getManufacturerId();
|
||||
BLEUUID getProximityUUID();
|
||||
int8_t getSignalPower();
|
||||
void setData(std::string data);
|
||||
void setMajor(uint16_t major);
|
||||
void setMinor(uint16_t minor);
|
||||
void setManufacturerId(uint16_t manufacturerId);
|
||||
void setProximityUUID(BLEUUID uuid);
|
||||
void setSignalPower(int8_t signalPower);
|
||||
}; // BLEBeacon
|
||||
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEBEACON_H_ */
|
||||
760
libraries/ESP32_BLE_Arduino/src/BLECharacteristic.cpp
Normal file
760
libraries/ESP32_BLE_Arduino/src/BLECharacteristic.cpp
Normal file
@@ -0,0 +1,760 @@
|
||||
/*
|
||||
* BLECharacteristic.cpp
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include <iomanip>
|
||||
#include <stdlib.h>
|
||||
#include "sdkconfig.h"
|
||||
#include <esp_err.h>
|
||||
#include "BLECharacteristic.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLEDevice.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "BLE2902.h"
|
||||
#include "GeneralUtils.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLECharacteristic";
|
||||
#endif
|
||||
|
||||
#define NULL_HANDLE (0xffff)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a characteristic
|
||||
* @param [in] uuid - UUID (const char*) for the characteristic.
|
||||
* @param [in] properties - Properties for the characteristic.
|
||||
*/
|
||||
BLECharacteristic::BLECharacteristic(const char* uuid, uint32_t properties) : BLECharacteristic(BLEUUID(uuid), properties) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a characteristic
|
||||
* @param [in] uuid - UUID for the characteristic.
|
||||
* @param [in] properties - Properties for the characteristic.
|
||||
*/
|
||||
BLECharacteristic::BLECharacteristic(BLEUUID uuid, uint32_t properties) {
|
||||
m_bleUUID = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_properties = (esp_gatt_char_prop_t)0;
|
||||
m_pCallbacks = nullptr;
|
||||
|
||||
setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0);
|
||||
setReadProperty((properties & PROPERTY_READ) != 0);
|
||||
setWriteProperty((properties & PROPERTY_WRITE) != 0);
|
||||
setNotifyProperty((properties & PROPERTY_NOTIFY) != 0);
|
||||
setIndicateProperty((properties & PROPERTY_INDICATE) != 0);
|
||||
setWriteNoResponseProperty((properties & PROPERTY_WRITE_NR) != 0);
|
||||
} // BLECharacteristic
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
BLECharacteristic::~BLECharacteristic() {
|
||||
//free(m_value.attr_value); // Release the storage for the value.
|
||||
} // ~BLECharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Associate a descriptor with this characteristic.
|
||||
* @param [in] pDescriptor
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLECharacteristic::addDescriptor(BLEDescriptor* pDescriptor) {
|
||||
ESP_LOGD(LOG_TAG, ">> addDescriptor(): Adding %s to %s", pDescriptor->toString().c_str(), toString().c_str());
|
||||
m_descriptorMap.setByUUID(pDescriptor->getUUID(), pDescriptor);
|
||||
ESP_LOGD(LOG_TAG, "<< addDescriptor()");
|
||||
} // addDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register a new characteristic with the ESP runtime.
|
||||
* @param [in] pService The service with which to associate this characteristic.
|
||||
*/
|
||||
void BLECharacteristic::executeCreate(BLEService* pService) {
|
||||
ESP_LOGD(LOG_TAG, ">> executeCreate()");
|
||||
|
||||
if (m_handle != NULL_HANDLE) {
|
||||
ESP_LOGE(LOG_TAG, "Characteristic already has a handle.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_pService = pService; // Save the service to which this characteristic belongs.
|
||||
|
||||
ESP_LOGD(LOG_TAG, "Registering characteristic (esp_ble_gatts_add_char): uuid: %s, service: %s",
|
||||
getUUID().toString().c_str(),
|
||||
m_pService->toString().c_str());
|
||||
|
||||
esp_attr_control_t control;
|
||||
control.auto_rsp = ESP_GATT_RSP_BY_APP;
|
||||
|
||||
m_semaphoreCreateEvt.take("executeCreate");
|
||||
esp_err_t errRc = ::esp_ble_gatts_add_char(
|
||||
m_pService->getHandle(),
|
||||
getUUID().getNative(),
|
||||
static_cast<esp_gatt_perm_t>(m_permissions),
|
||||
getProperties(),
|
||||
nullptr,
|
||||
&control); // Whether to auto respond or not.
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_add_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
m_semaphoreCreateEvt.wait("executeCreate");
|
||||
|
||||
BLEDescriptor* pDescriptor = m_descriptorMap.getFirst();
|
||||
while (pDescriptor != nullptr) {
|
||||
pDescriptor->executeCreate(this);
|
||||
pDescriptor = m_descriptorMap.getNext();
|
||||
} // End while
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< executeCreate");
|
||||
} // executeCreate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID if associated with this characteristic.
|
||||
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
|
||||
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
||||
*/
|
||||
BLEDescriptor* BLECharacteristic::getDescriptorByUUID(const char* descriptorUUID) {
|
||||
return m_descriptorMap.getByUUID(BLEUUID(descriptorUUID));
|
||||
} // getDescriptorByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the BLE Descriptor for the given UUID if associated with this characteristic.
|
||||
* @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve.
|
||||
* @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
|
||||
*/
|
||||
BLEDescriptor* BLECharacteristic::getDescriptorByUUID(BLEUUID descriptorUUID) {
|
||||
return m_descriptorMap.getByUUID(descriptorUUID);
|
||||
} // getDescriptorByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the handle of the characteristic.
|
||||
* @return The handle of the characteristic.
|
||||
*/
|
||||
uint16_t BLECharacteristic::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
void BLECharacteristic::setAccessPermissions(esp_gatt_perm_t perm) {
|
||||
m_permissions = perm;
|
||||
}
|
||||
|
||||
esp_gatt_char_prop_t BLECharacteristic::getProperties() {
|
||||
return m_properties;
|
||||
} // getProperties
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service associated with this characteristic.
|
||||
*/
|
||||
BLEService* BLECharacteristic::getService() {
|
||||
return m_pService;
|
||||
} // getService
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID of the characteristic.
|
||||
* @return The UUID of the characteristic.
|
||||
*/
|
||||
BLEUUID BLECharacteristic::getUUID() {
|
||||
return m_bleUUID;
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current value of the characteristic.
|
||||
* @return A pointer to storage containing the current characteristic value.
|
||||
*/
|
||||
std::string BLECharacteristic::getValue() {
|
||||
return m_value.getValue();
|
||||
} // getValue
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current raw data of the characteristic.
|
||||
* @return A pointer to storage containing the current characteristic data.
|
||||
*/
|
||||
uint8_t* BLECharacteristic::getData() {
|
||||
return m_value.getData();
|
||||
} // getData
|
||||
|
||||
|
||||
/**
|
||||
* Handle a GATT server event.
|
||||
*/
|
||||
void BLECharacteristic::handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param) {
|
||||
ESP_LOGD(LOG_TAG, ">> handleGATTServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str());
|
||||
|
||||
switch(event) {
|
||||
// Events handled:
|
||||
//
|
||||
// ESP_GATTS_ADD_CHAR_EVT
|
||||
// ESP_GATTS_CONF_EVT
|
||||
// ESP_GATTS_CONNECT_EVT
|
||||
// ESP_GATTS_DISCONNECT_EVT
|
||||
// ESP_GATTS_EXEC_WRITE_EVT
|
||||
// ESP_GATTS_READ_EVT
|
||||
// ESP_GATTS_WRITE_EVT
|
||||
|
||||
//
|
||||
// ESP_GATTS_EXEC_WRITE_EVT
|
||||
// When we receive this event it is an indication that a previous write long needs to be committed.
|
||||
//
|
||||
// exec_write:
|
||||
// - uint16_t conn_id
|
||||
// - uint32_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint8_t exec_write_flag - Either ESP_GATT_PREP_WRITE_EXEC or ESP_GATT_PREP_WRITE_CANCEL
|
||||
//
|
||||
case ESP_GATTS_EXEC_WRITE_EVT: {
|
||||
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
|
||||
m_value.commit();
|
||||
if (m_pCallbacks != nullptr) {
|
||||
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
|
||||
}
|
||||
} else {
|
||||
m_value.cancel();
|
||||
}
|
||||
// ???
|
||||
esp_err_t errRc = ::esp_ble_gatts_send_response(
|
||||
gatts_if,
|
||||
param->write.conn_id,
|
||||
param->write.trans_id, ESP_GATT_OK, nullptr);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_EXEC_WRITE_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service.
|
||||
// add_char:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t attr_handle
|
||||
// - uint16_t service_handle
|
||||
// - esp_bt_uuid_t char_uuid
|
||||
case ESP_GATTS_ADD_CHAR_EVT: {
|
||||
if (getHandle() == param->add_char.attr_handle) {
|
||||
// we have created characteristic, now we can create descriptors
|
||||
// BLEDescriptor* pDescriptor = m_descriptorMap.getFirst();
|
||||
// while (pDescriptor != nullptr) {
|
||||
// pDescriptor->executeCreate(this);
|
||||
// pDescriptor = m_descriptorMap.getNext();
|
||||
// } // End while
|
||||
m_semaphoreCreateEvt.give();
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_ADD_CHAR_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_WRITE_EVT - A request to write the value of a characteristic has arrived.
|
||||
//
|
||||
// write:
|
||||
// - uint16_t conn_id
|
||||
// - uint16_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
// - bool need_rsp
|
||||
// - bool is_prep
|
||||
// - uint16_t len
|
||||
// - uint8_t *value
|
||||
//
|
||||
case ESP_GATTS_WRITE_EVT: {
|
||||
// We check if this write request is for us by comparing the handles in the event. If it is for us
|
||||
// we save the new value. Next we look at the need_rsp flag which indicates whether or not we need
|
||||
// to send a response. If we do, then we formulate a response and send it.
|
||||
if (param->write.handle == m_handle) {
|
||||
if (param->write.is_prep) {
|
||||
m_value.addPart(param->write.value, param->write.len);
|
||||
} else {
|
||||
setValue(param->write.value, param->write.len);
|
||||
}
|
||||
|
||||
ESP_LOGD(LOG_TAG, " - Response to write event: New value: handle: %.2x, uuid: %s",
|
||||
getHandle(), getUUID().toString().c_str());
|
||||
|
||||
char* pHexData = BLEUtils::buildHexData(nullptr, param->write.value, param->write.len);
|
||||
ESP_LOGD(LOG_TAG, " - Data: length: %d, data: %s", param->write.len, pHexData);
|
||||
free(pHexData);
|
||||
|
||||
if (param->write.need_rsp) {
|
||||
esp_gatt_rsp_t rsp;
|
||||
|
||||
rsp.attr_value.len = param->write.len;
|
||||
rsp.attr_value.handle = m_handle;
|
||||
rsp.attr_value.offset = param->write.offset;
|
||||
rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
|
||||
memcpy(rsp.attr_value.value, param->write.value, param->write.len);
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gatts_send_response(
|
||||
gatts_if,
|
||||
param->write.conn_id,
|
||||
param->write.trans_id, ESP_GATT_OK, &rsp);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
} // Response needed
|
||||
|
||||
if (m_pCallbacks != nullptr && param->write.is_prep != true) {
|
||||
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
|
||||
}
|
||||
} // Match on handles.
|
||||
break;
|
||||
} // ESP_GATTS_WRITE_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived.
|
||||
//
|
||||
// read:
|
||||
// - uint16_t conn_id
|
||||
// - uint32_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
// - bool is_long
|
||||
// - bool need_rsp
|
||||
//
|
||||
case ESP_GATTS_READ_EVT: {
|
||||
if (param->read.handle == m_handle) {
|
||||
|
||||
|
||||
|
||||
// Here's an interesting thing. The read request has the option of saying whether we need a response
|
||||
// or not. What would it "mean" to receive a read request and NOT send a response back? That feels like
|
||||
// a very strange read.
|
||||
//
|
||||
// We have to handle the case where the data we wish to send back to the client is greater than the maximum
|
||||
// packet size of 22 bytes. In this case, we become responsible for chunking the data into units of 22 bytes.
|
||||
// The apparent algorithm is as follows:
|
||||
//
|
||||
// If the is_long flag is set then this is a follow on from an original read and we will already have sent at least 22 bytes.
|
||||
// If the is_long flag is not set then we need to check how much data we are going to send. If we are sending LESS than
|
||||
// 22 bytes, then we "just" send it and thats the end of the story.
|
||||
// If we are sending 22 bytes exactly, we just send it BUT we will get a follow on request.
|
||||
// If we are sending more than 22 bytes, we send the first 22 bytes and we will get a follow on request.
|
||||
// Because of follow on request processing, we need to maintain an offset of how much data we have already sent
|
||||
// so that when a follow on request arrives, we know where to start in the data to send the next sequence.
|
||||
// Note that the indication that the client will send a follow on request is that we sent exactly 22 bytes as a response.
|
||||
// If our payload is divisible by 22 then the last response will be a response of 0 bytes in length.
|
||||
//
|
||||
// The following code has deliberately not been factored to make it fewer statements because this would cloud the
|
||||
// the logic flow comprehension.
|
||||
//
|
||||
|
||||
// get mtu for peer device that we are sending read request to
|
||||
uint16_t maxOffset = getService()->getServer()->getPeerMTU(param->read.conn_id) - 1;
|
||||
ESP_LOGD(LOG_TAG, "mtu value: %d", maxOffset);
|
||||
if (param->read.need_rsp) {
|
||||
ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)");
|
||||
esp_gatt_rsp_t rsp;
|
||||
|
||||
if (param->read.is_long) {
|
||||
std::string value = m_value.getValue();
|
||||
|
||||
if (value.length() - m_value.getReadOffset() < maxOffset) {
|
||||
// This is the last in the chain
|
||||
rsp.attr_value.len = value.length() - m_value.getReadOffset();
|
||||
rsp.attr_value.offset = m_value.getReadOffset();
|
||||
memcpy(rsp.attr_value.value, value.data() + rsp.attr_value.offset, rsp.attr_value.len);
|
||||
m_value.setReadOffset(0);
|
||||
} else {
|
||||
// There will be more to come.
|
||||
rsp.attr_value.len = maxOffset;
|
||||
rsp.attr_value.offset = m_value.getReadOffset();
|
||||
memcpy(rsp.attr_value.value, value.data() + rsp.attr_value.offset, rsp.attr_value.len);
|
||||
m_value.setReadOffset(rsp.attr_value.offset + maxOffset);
|
||||
}
|
||||
} else { // read.is_long == false
|
||||
|
||||
std::string value = m_value.getValue();
|
||||
|
||||
if (value.length() + 1 > maxOffset) {
|
||||
// Too big for a single shot entry.
|
||||
m_value.setReadOffset(maxOffset);
|
||||
rsp.attr_value.len = maxOffset;
|
||||
rsp.attr_value.offset = 0;
|
||||
memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len);
|
||||
} else {
|
||||
// Will fit in a single packet with no callbacks required.
|
||||
rsp.attr_value.len = value.length();
|
||||
rsp.attr_value.offset = 0;
|
||||
memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len);
|
||||
}
|
||||
|
||||
if (m_pCallbacks != nullptr) { // If is.long is false then this is the first (or only) request to read data, so invoke the callback
|
||||
m_pCallbacks->onRead(this); // Invoke the read callback.
|
||||
}
|
||||
}
|
||||
rsp.attr_value.handle = param->read.handle;
|
||||
rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
|
||||
|
||||
char *pHexData = BLEUtils::buildHexData(nullptr, rsp.attr_value.value, rsp.attr_value.len);
|
||||
ESP_LOGD(LOG_TAG, " - Data: length=%d, data=%s, offset=%d", rsp.attr_value.len, pHexData, rsp.attr_value.offset);
|
||||
free(pHexData);
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gatts_send_response(
|
||||
gatts_if, param->read.conn_id,
|
||||
param->read.trans_id,
|
||||
ESP_GATT_OK,
|
||||
&rsp);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
} // Response needed
|
||||
} // Handle matches this characteristic.
|
||||
break;
|
||||
} // ESP_GATTS_READ_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_CONF_EVT
|
||||
//
|
||||
// conf:
|
||||
// - esp_gatt_status_t status – The status code.
|
||||
// - uint16_t conn_id – The connection used.
|
||||
//
|
||||
case ESP_GATTS_CONF_EVT: {
|
||||
// ESP_LOGD(LOG_TAG, "m_handle = %d, conf->handle = %d", m_handle, param->conf.handle);
|
||||
if(param->conf.conn_id == getService()->getServer()->getConnId()) // && param->conf.handle == m_handle) // bug in esp-idf and not implemented in arduino yet
|
||||
m_semaphoreConfEvt.give(param->conf.status);
|
||||
break;
|
||||
}
|
||||
|
||||
case ESP_GATTS_CONNECT_EVT: {
|
||||
break;
|
||||
}
|
||||
|
||||
case ESP_GATTS_DISCONNECT_EVT: {
|
||||
m_semaphoreConfEvt.give();
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
} // default
|
||||
|
||||
} // switch event
|
||||
|
||||
// Give each of the descriptors associated with this characteristic the opportunity to handle the
|
||||
// event.
|
||||
|
||||
m_descriptorMap.handleGATTServerEvent(event, gatts_if, param);
|
||||
ESP_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
||||
} // handleGATTServerEvent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send an indication.
|
||||
* An indication is a transmission of up to the first 20 bytes of the characteristic value. An indication
|
||||
* will block waiting a positive confirmation from the client.
|
||||
* @return N/A
|
||||
*/
|
||||
void BLECharacteristic::indicate() {
|
||||
|
||||
ESP_LOGD(LOG_TAG, ">> indicate: length: %d", m_value.getValue().length());
|
||||
notify(false);
|
||||
ESP_LOGD(LOG_TAG, "<< indicate");
|
||||
} // indicate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a notify.
|
||||
* A notification is a transmission of up to the first 20 bytes of the characteristic value. An notification
|
||||
* will not block; it is a fire and forget.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLECharacteristic::notify(bool is_notification) {
|
||||
ESP_LOGD(LOG_TAG, ">> notify: length: %d", m_value.getValue().length());
|
||||
|
||||
assert(getService() != nullptr);
|
||||
assert(getService()->getServer() != nullptr);
|
||||
|
||||
GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length());
|
||||
|
||||
if (getService()->getServer()->getConnectedCount() == 0) {
|
||||
ESP_LOGD(LOG_TAG, "<< notify: No connected clients.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Test to see if we have a 0x2902 descriptor. If we do, then check to see if notification is enabled
|
||||
// and, if not, prevent the notification.
|
||||
|
||||
BLE2902 *p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902);
|
||||
if(is_notification) {
|
||||
if (p2902 != nullptr && !p2902->getNotifications()) {
|
||||
ESP_LOGD(LOG_TAG, "<< notifications disabled; ignoring");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (p2902 != nullptr && !p2902->getIndications()) {
|
||||
ESP_LOGD(LOG_TAG, "<< indications disabled; ignoring");
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (auto &myPair : getService()->getServer()->getPeerDevices(false)) {
|
||||
uint16_t _mtu = (myPair.second.mtu);
|
||||
if (m_value.getValue().length() > _mtu - 3) {
|
||||
ESP_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
||||
}
|
||||
|
||||
size_t length = m_value.getValue().length();
|
||||
if(!is_notification)
|
||||
m_semaphoreConfEvt.take("indicate");
|
||||
esp_err_t errRc = ::esp_ble_gatts_send_indicate(
|
||||
getService()->getServer()->getGattsIf(),
|
||||
myPair.first,
|
||||
getHandle(), length, (uint8_t*)m_value.getValue().data(), !is_notification); // The need_confirm = false makes this a notify.
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_send_ %s: rc=%d %s",is_notification?"notify":"indicate", errRc, GeneralUtils::errorToString(errRc));
|
||||
m_semaphoreConfEvt.give();
|
||||
return;
|
||||
}
|
||||
if(!is_notification)
|
||||
m_semaphoreConfEvt.wait("indicate");
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< notify");
|
||||
} // Notify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the permission to broadcast.
|
||||
* A characteristics has properties associated with it which define what it is capable of doing.
|
||||
* One of these is the broadcast flag.
|
||||
* @param [in] value The flag value of the property.
|
||||
* @return N/A
|
||||
*/
|
||||
void BLECharacteristic::setBroadcastProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setBroadcastProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_BROADCAST);
|
||||
} else {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST);
|
||||
}
|
||||
} // setBroadcastProperty
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the callback handlers for this characteristic.
|
||||
* @param [in] pCallbacks An instance of a callbacks structure used to define any callbacks for the characteristic.
|
||||
*/
|
||||
void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) {
|
||||
ESP_LOGD(LOG_TAG, ">> setCallbacks: 0x%x", (uint32_t)pCallbacks);
|
||||
m_pCallbacks = pCallbacks;
|
||||
ESP_LOGD(LOG_TAG, "<< setCallbacks");
|
||||
} // setCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the BLE handle associated with this characteristic.
|
||||
* A user program will request that a characteristic be created against a service. When the characteristic has been
|
||||
* registered, the service will be given a "handle" that it knows the characteristic as. This handle is unique to the
|
||||
* server/service but it is told to the service, not the characteristic associated with the service. This internally
|
||||
* exposed function can be invoked by the service against this model of the characteristic to allow the characteristic
|
||||
* to learn its own handle. Once the characteristic knows its own handle, it will be able to see incoming GATT events
|
||||
* that will be propagated down to it which contain a handle value and now know that the event is destined for it.
|
||||
* @param [in] handle The handle associated with this characteristic.
|
||||
*/
|
||||
void BLECharacteristic::setHandle(uint16_t handle) {
|
||||
ESP_LOGD(LOG_TAG, ">> setHandle: handle=0x%.2x, characteristic uuid=%s", handle, getUUID().toString().c_str());
|
||||
m_handle = handle;
|
||||
ESP_LOGD(LOG_TAG, "<< setHandle");
|
||||
} // setHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Indicate property value.
|
||||
* @param [in] value Set to true if we are to allow indicate messages.
|
||||
*/
|
||||
void BLECharacteristic::setIndicateProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setIndicateProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_INDICATE);
|
||||
} else {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_INDICATE);
|
||||
}
|
||||
} // setIndicateProperty
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Notify property value.
|
||||
* @param [in] value Set to true if we are to allow notification messages.
|
||||
*/
|
||||
void BLECharacteristic::setNotifyProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setNotifyProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_NOTIFY);
|
||||
} else {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY);
|
||||
}
|
||||
} // setNotifyProperty
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Read property value.
|
||||
* @param [in] value Set to true if we are to allow reads.
|
||||
*/
|
||||
void BLECharacteristic::setReadProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setReadProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_READ);
|
||||
} else {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_READ);
|
||||
}
|
||||
} // setReadProperty
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the characteristic.
|
||||
* @param [in] data The data to set for the characteristic.
|
||||
* @param [in] length The length of the data in bytes.
|
||||
*/
|
||||
void BLECharacteristic::setValue(uint8_t* data, size_t length) {
|
||||
char* pHex = BLEUtils::buildHexData(nullptr, data, length);
|
||||
ESP_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
||||
free(pHex);
|
||||
if (length > ESP_GATT_MAX_ATTR_LEN) {
|
||||
ESP_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN);
|
||||
return;
|
||||
}
|
||||
m_value.setValue(data, length);
|
||||
ESP_LOGD(LOG_TAG, "<< setValue");
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the characteristic from string data.
|
||||
* We set the value of the characteristic from the bytes contained in the
|
||||
* string.
|
||||
* @param [in] Set the value of the characteristic.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLECharacteristic::setValue(std::string value) {
|
||||
setValue((uint8_t*)(value.data()), value.length());
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(uint16_t& data16) {
|
||||
uint8_t temp[2];
|
||||
temp[0] = data16;
|
||||
temp[1] = data16 >> 8;
|
||||
setValue(temp, 2);
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(uint32_t& data32) {
|
||||
uint8_t temp[4];
|
||||
temp[0] = data32;
|
||||
temp[1] = data32 >> 8;
|
||||
temp[2] = data32 >> 16;
|
||||
temp[3] = data32 >> 24;
|
||||
setValue(temp, 4);
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(int& data32) {
|
||||
uint8_t temp[4];
|
||||
temp[0] = data32;
|
||||
temp[1] = data32 >> 8;
|
||||
temp[2] = data32 >> 16;
|
||||
temp[3] = data32 >> 24;
|
||||
setValue(temp, 4);
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(float& data32) {
|
||||
uint8_t temp[4];
|
||||
*((float*)temp) = data32;
|
||||
setValue(temp, 4);
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(double& data64) {
|
||||
uint8_t temp[8];
|
||||
*((double*)temp) = data64;
|
||||
setValue(temp, 8);
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Write No Response property value.
|
||||
* @param [in] value Set to true if we are to allow writes with no response.
|
||||
*/
|
||||
void BLECharacteristic::setWriteNoResponseProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setWriteNoResponseProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
|
||||
} else {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
|
||||
}
|
||||
} // setWriteNoResponseProperty
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Write property value.
|
||||
* @param [in] value Set to true if we are to allow writes.
|
||||
*/
|
||||
void BLECharacteristic::setWriteProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setWriteProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE);
|
||||
} else {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_WRITE);
|
||||
}
|
||||
} // setWriteProperty
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the characteristic.
|
||||
* @return A string representation of the characteristic.
|
||||
*/
|
||||
std::string BLECharacteristic::toString() {
|
||||
std::stringstream stringstream;
|
||||
stringstream << std::hex << std::setfill('0');
|
||||
stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle;
|
||||
stringstream << " " <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_READ) ? "Read " : "") <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE) ? "Write " : "") <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE_NR) ? "WriteNoResponse " : "") <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_BROADCAST) ? "Broadcast " : "") <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY) ? "Notify " : "") <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_INDICATE) ? "Indicate " : "");
|
||||
return stringstream.str();
|
||||
} // toString
|
||||
|
||||
|
||||
BLECharacteristicCallbacks::~BLECharacteristicCallbacks() {}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a read request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
*/
|
||||
void BLECharacteristicCallbacks::onRead(BLECharacteristic* pCharacteristic) {
|
||||
ESP_LOGD("BLECharacteristicCallbacks", ">> onRead: default");
|
||||
ESP_LOGD("BLECharacteristicCallbacks", "<< onRead");
|
||||
} // onRead
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a write request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
*/
|
||||
void BLECharacteristicCallbacks::onWrite(BLECharacteristic* pCharacteristic) {
|
||||
ESP_LOGD("BLECharacteristicCallbacks", ">> onWrite: default");
|
||||
ESP_LOGD("BLECharacteristicCallbacks", "<< onWrite");
|
||||
} // onWrite
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
137
libraries/ESP32_BLE_Arduino/src/BLECharacteristic.h
Normal file
137
libraries/ESP32_BLE_Arduino/src/BLECharacteristic.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* BLECharacteristic.h
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "BLEUUID.h"
|
||||
#include <esp_gatts_api.h>
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include "BLEDescriptor.h"
|
||||
#include "BLEValue.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
class BLEService;
|
||||
class BLEDescriptor;
|
||||
class BLECharacteristicCallbacks;
|
||||
|
||||
/**
|
||||
* @brief A management structure for %BLE descriptors.
|
||||
*/
|
||||
class BLEDescriptorMap {
|
||||
public:
|
||||
void setByUUID(const char* uuid, BLEDescriptor* pDescriptor);
|
||||
void setByUUID(BLEUUID uuid, BLEDescriptor* pDescriptor);
|
||||
void setByHandle(uint16_t handle, BLEDescriptor* pDescriptor);
|
||||
BLEDescriptor* getByUUID(const char* uuid);
|
||||
BLEDescriptor* getByUUID(BLEUUID uuid);
|
||||
BLEDescriptor* getByHandle(uint16_t handle);
|
||||
std::string toString();
|
||||
void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param);
|
||||
BLEDescriptor* getFirst();
|
||||
BLEDescriptor* getNext();
|
||||
private:
|
||||
std::map<BLEDescriptor*, std::string> m_uuidMap;
|
||||
std::map<uint16_t, BLEDescriptor*> m_handleMap;
|
||||
std::map<BLEDescriptor*, std::string>::iterator m_iterator;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The model of a %BLE Characteristic.
|
||||
*
|
||||
* A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE server and
|
||||
* can be read and written to by a %BLE client.
|
||||
*/
|
||||
class BLECharacteristic {
|
||||
public:
|
||||
BLECharacteristic(const char* uuid, uint32_t properties = 0);
|
||||
BLECharacteristic(BLEUUID uuid, uint32_t properties = 0);
|
||||
virtual ~BLECharacteristic();
|
||||
|
||||
void addDescriptor(BLEDescriptor* pDescriptor);
|
||||
BLEDescriptor* getDescriptorByUUID(const char* descriptorUUID);
|
||||
BLEDescriptor* getDescriptorByUUID(BLEUUID descriptorUUID);
|
||||
BLEUUID getUUID();
|
||||
std::string getValue();
|
||||
uint8_t* getData();
|
||||
|
||||
void indicate();
|
||||
void notify(bool is_notification = true);
|
||||
void setBroadcastProperty(bool value);
|
||||
void setCallbacks(BLECharacteristicCallbacks* pCallbacks);
|
||||
void setIndicateProperty(bool value);
|
||||
void setNotifyProperty(bool value);
|
||||
void setReadProperty(bool value);
|
||||
void setValue(uint8_t* data, size_t size);
|
||||
void setValue(std::string value);
|
||||
void setValue(uint16_t& data16);
|
||||
void setValue(uint32_t& data32);
|
||||
void setValue(int& data32);
|
||||
void setValue(float& data32);
|
||||
void setValue(double& data64);
|
||||
void setWriteProperty(bool value);
|
||||
void setWriteNoResponseProperty(bool value);
|
||||
std::string toString();
|
||||
uint16_t getHandle();
|
||||
void setAccessPermissions(esp_gatt_perm_t perm);
|
||||
|
||||
static const uint32_t PROPERTY_READ = 1<<0;
|
||||
static const uint32_t PROPERTY_WRITE = 1<<1;
|
||||
static const uint32_t PROPERTY_NOTIFY = 1<<2;
|
||||
static const uint32_t PROPERTY_BROADCAST = 1<<3;
|
||||
static const uint32_t PROPERTY_INDICATE = 1<<4;
|
||||
static const uint32_t PROPERTY_WRITE_NR = 1<<5;
|
||||
|
||||
private:
|
||||
|
||||
friend class BLEServer;
|
||||
friend class BLEService;
|
||||
friend class BLEDescriptor;
|
||||
friend class BLECharacteristicMap;
|
||||
|
||||
BLEUUID m_bleUUID;
|
||||
BLEDescriptorMap m_descriptorMap;
|
||||
uint16_t m_handle;
|
||||
esp_gatt_char_prop_t m_properties;
|
||||
BLECharacteristicCallbacks* m_pCallbacks;
|
||||
BLEService* m_pService;
|
||||
BLEValue m_value;
|
||||
esp_gatt_perm_t m_permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
|
||||
|
||||
void handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param);
|
||||
|
||||
void executeCreate(BLEService* pService);
|
||||
esp_gatt_char_prop_t getProperties();
|
||||
BLEService* getService();
|
||||
void setHandle(uint16_t handle);
|
||||
FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreConfEvt = FreeRTOS::Semaphore("ConfEvt");
|
||||
}; // BLECharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks that can be associated with a %BLE characteristic to inform of events.
|
||||
*
|
||||
* When a server application creates a %BLE characteristic, we may wish to be informed when there is either
|
||||
* a read or write request to the characteristic's value. An application can register a
|
||||
* sub-classed instance of this class and will be notified when such an event happens.
|
||||
*/
|
||||
class BLECharacteristicCallbacks {
|
||||
public:
|
||||
virtual ~BLECharacteristicCallbacks();
|
||||
virtual void onRead(BLECharacteristic* pCharacteristic);
|
||||
virtual void onWrite(BLECharacteristic* pCharacteristic);
|
||||
};
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ */
|
||||
133
libraries/ESP32_BLE_Arduino/src/BLECharacteristicMap.cpp
Normal file
133
libraries/ESP32_BLE_Arduino/src/BLECharacteristicMap.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* BLECharacteristicMap.cpp
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include "BLEService.h"
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-log.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the characteristic by handle.
|
||||
* @param [in] handle The handle to look up the characteristic.
|
||||
* @return The characteristic.
|
||||
*/
|
||||
BLECharacteristic* BLECharacteristicMap::getByHandle(uint16_t handle) {
|
||||
return m_handleMap.at(handle);
|
||||
} // getByHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the characteristic by UUID.
|
||||
* @param [in] UUID The UUID to look up the characteristic.
|
||||
* @return The characteristic.
|
||||
*/
|
||||
BLECharacteristic* BLECharacteristicMap::getByUUID(const char* uuid) {
|
||||
return getByUUID(BLEUUID(uuid));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the characteristic by UUID.
|
||||
* @param [in] UUID The UUID to look up the characteristic.
|
||||
* @return The characteristic.
|
||||
*/
|
||||
BLECharacteristic* BLECharacteristicMap::getByUUID(BLEUUID uuid) {
|
||||
for (auto &myPair : m_uuidMap) {
|
||||
if (myPair.first->getUUID().equals(uuid)) {
|
||||
return myPair.first;
|
||||
}
|
||||
}
|
||||
//return m_uuidMap.at(uuid.toString());
|
||||
return nullptr;
|
||||
} // getByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the first characteristic in the map.
|
||||
* @return The first characteristic in the map.
|
||||
*/
|
||||
BLECharacteristic* BLECharacteristicMap::getFirst() {
|
||||
m_iterator = m_uuidMap.begin();
|
||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
||||
BLECharacteristic* pRet = m_iterator->first;
|
||||
m_iterator++;
|
||||
return pRet;
|
||||
} // getFirst
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the next characteristic in the map.
|
||||
* @return The next characteristic in the map.
|
||||
*/
|
||||
BLECharacteristic* BLECharacteristicMap::getNext() {
|
||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
||||
BLECharacteristic* pRet = m_iterator->first;
|
||||
m_iterator++;
|
||||
return pRet;
|
||||
} // getNext
|
||||
|
||||
|
||||
/**
|
||||
* @brief Pass the GATT server event onwards to each of the characteristics found in the mapping
|
||||
* @param [in] event
|
||||
* @param [in] gatts_if
|
||||
* @param [in] param
|
||||
*/
|
||||
void BLECharacteristicMap::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param) {
|
||||
// Invoke the handler for every Service we have.
|
||||
for (auto& myPair : m_uuidMap) {
|
||||
myPair.first->handleGATTServerEvent(event, gatts_if, param);
|
||||
}
|
||||
} // handleGATTServerEvent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the characteristic by handle.
|
||||
* @param [in] handle The handle of the characteristic.
|
||||
* @param [in] characteristic The characteristic to cache.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLECharacteristicMap::setByHandle(uint16_t handle, BLECharacteristic* characteristic) {
|
||||
m_handleMap.insert(std::pair<uint16_t, BLECharacteristic*>(handle, characteristic));
|
||||
} // setByHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the characteristic by UUID.
|
||||
* @param [in] uuid The uuid of the characteristic.
|
||||
* @param [in] characteristic The characteristic to cache.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLECharacteristicMap::setByUUID(BLECharacteristic* pCharacteristic, BLEUUID uuid) {
|
||||
m_uuidMap.insert(std::pair<BLECharacteristic*, std::string>(pCharacteristic, uuid.toString()));
|
||||
} // setByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the characteristic map.
|
||||
* @return A string representation of the characteristic map.
|
||||
*/
|
||||
std::string BLECharacteristicMap::toString() {
|
||||
std::stringstream stringStream;
|
||||
stringStream << std::hex << std::setfill('0');
|
||||
int count = 0;
|
||||
for (auto &myPair: m_uuidMap) {
|
||||
if (count > 0) {
|
||||
stringStream << "\n";
|
||||
}
|
||||
count++;
|
||||
stringStream << "handle: 0x" << std::setw(2) << myPair.first->getHandle() << ", uuid: " + myPair.first->getUUID().toString();
|
||||
}
|
||||
return stringStream.str();
|
||||
} // toString
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
536
libraries/ESP32_BLE_Arduino/src/BLEClient.cpp
Normal file
536
libraries/ESP32_BLE_Arduino/src/BLEClient.cpp
Normal file
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
* BLEDevice.cpp
|
||||
*
|
||||
* Created on: Mar 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_bt.h>
|
||||
#include <esp_bt_main.h>
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include <esp_gattc_api.h>
|
||||
#include "BLEClient.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "BLEService.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
#include "BLEDevice.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEClient";
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Design
|
||||
* ------
|
||||
* When we perform a searchService() requests, we are asking the BLE server to return each of the services
|
||||
* that it exposes. For each service, we received an ESP_GATTC_SEARCH_RES_EVT event which contains details
|
||||
* of the exposed service including its UUID.
|
||||
*
|
||||
* The objects we will invent for a BLEClient will be as follows:
|
||||
* * BLERemoteService - A model of a remote service.
|
||||
* * BLERemoteCharacteristic - A model of a remote characteristic
|
||||
* * BLERemoteDescriptor - A model of a remote descriptor.
|
||||
*
|
||||
* Since there is a hierarchical relationship here, we will have the idea that from a BLERemoteService will own
|
||||
* zero or more remote characteristics and a BLERemoteCharacteristic will own zero or more remote BLEDescriptors.
|
||||
*
|
||||
* We will assume that a BLERemoteService contains a map that maps BLEUUIDs to the set of owned characteristics
|
||||
* and that a BLECharacteristic contains a map that maps BLEUUIDs to the set of owned descriptors.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
BLEClient::BLEClient() {
|
||||
m_pClientCallbacks = nullptr;
|
||||
m_conn_id = ESP_GATT_IF_NONE;
|
||||
m_gattc_if = ESP_GATT_IF_NONE;
|
||||
m_haveServices = false;
|
||||
m_isConnected = false; // Initially, we are flagged as not connected.
|
||||
} // BLEClient
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
BLEClient::~BLEClient() {
|
||||
// We may have allocated service references associated with this client. Before we are finished
|
||||
// with the client, we must release resources.
|
||||
for (auto &myPair : m_servicesMap) {
|
||||
delete myPair.second;
|
||||
}
|
||||
m_servicesMap.clear();
|
||||
} // ~BLEClient
|
||||
|
||||
|
||||
/**
|
||||
* @brief Clear any existing services.
|
||||
*
|
||||
*/
|
||||
void BLEClient::clearServices() {
|
||||
ESP_LOGD(LOG_TAG, ">> clearServices");
|
||||
// Delete all the services.
|
||||
for (auto &myPair : m_servicesMap) {
|
||||
delete myPair.second;
|
||||
}
|
||||
m_servicesMap.clear();
|
||||
m_haveServices = false;
|
||||
ESP_LOGD(LOG_TAG, "<< clearServices");
|
||||
} // clearServices
|
||||
|
||||
/**
|
||||
* Add overloaded function to ease connect to peer device with not public address
|
||||
*/
|
||||
bool BLEClient::connect(BLEAdvertisedDevice* device) {
|
||||
BLEAddress address = device->getAddress();
|
||||
esp_ble_addr_type_t type = device->getAddressType();
|
||||
return connect(address, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connect to the partner (BLE Server).
|
||||
* @param [in] address The address of the partner.
|
||||
* @return True on success.
|
||||
*/
|
||||
bool BLEClient::connect(BLEAddress address, esp_ble_addr_type_t type) {
|
||||
ESP_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str());
|
||||
|
||||
// We need the connection handle that we get from registering the application. We register the app
|
||||
// and then block on its completion. When the event has arrived, we will have the handle.
|
||||
m_appId = BLEDevice::m_appId++;
|
||||
BLEDevice::addPeerDevice(this, true, m_appId);
|
||||
m_semaphoreRegEvt.take("connect");
|
||||
|
||||
// clearServices(); // we dont need to delete services since every client is unique?
|
||||
esp_err_t errRc = ::esp_ble_gattc_app_register(m_appId);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_semaphoreRegEvt.wait("connect");
|
||||
|
||||
m_peerAddress = address;
|
||||
|
||||
// Perform the open connection request against the target BLE Server.
|
||||
m_semaphoreOpenEvt.take("connect");
|
||||
errRc = ::esp_ble_gattc_open(
|
||||
m_gattc_if,
|
||||
*getPeerAddress().getNative(), // address
|
||||
type, // Note: This was added on 2018-04-03 when the latest ESP-IDF was detected to have changed the signature.
|
||||
1 // direct connection <-- maybe needs to be changed in case of direct indirect connection???
|
||||
);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete.
|
||||
ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK);
|
||||
return rc == ESP_GATT_OK;
|
||||
} // connect
|
||||
|
||||
|
||||
/**
|
||||
* @brief Disconnect from the peer.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEClient::disconnect() {
|
||||
ESP_LOGD(LOG_TAG, ">> disconnect()");
|
||||
esp_err_t errRc = ::esp_ble_gattc_close(getGattcIf(), getConnId());
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_close: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< disconnect()");
|
||||
} // disconnect
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle GATT Client events
|
||||
*/
|
||||
void BLEClient::gattClientEventHandler(
|
||||
esp_gattc_cb_event_t event,
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* evtParam) {
|
||||
|
||||
ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s",
|
||||
gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str());
|
||||
|
||||
// Execute handler code based on the type of event received.
|
||||
switch(event) {
|
||||
|
||||
case ESP_GATTC_SRVC_CHG_EVT:
|
||||
ESP_LOGI(LOG_TAG, "SERVICE CHANGED");
|
||||
break;
|
||||
|
||||
case ESP_GATTC_CLOSE_EVT: {
|
||||
// esp_ble_gattc_app_unregister(m_appId);
|
||||
// BLEDevice::removePeerDevice(m_gattc_if, true);
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// ESP_GATTC_DISCONNECT_EVT
|
||||
//
|
||||
// disconnect:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t conn_id
|
||||
// - esp_bd_addr_t remote_bda
|
||||
case ESP_GATTC_DISCONNECT_EVT: {
|
||||
// If we receive a disconnect event, set the class flag that indicates that we are
|
||||
// no longer connected.
|
||||
m_isConnected = false;
|
||||
if (m_pClientCallbacks != nullptr) {
|
||||
m_pClientCallbacks->onDisconnect(this);
|
||||
}
|
||||
BLEDevice::removePeerDevice(m_appId, true);
|
||||
esp_ble_gattc_app_unregister(m_gattc_if);
|
||||
m_semaphoreRssiCmplEvt.give();
|
||||
m_semaphoreSearchCmplEvt.give(1);
|
||||
break;
|
||||
} // ESP_GATTC_DISCONNECT_EVT
|
||||
|
||||
//
|
||||
// ESP_GATTC_OPEN_EVT
|
||||
//
|
||||
// open:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t conn_id
|
||||
// - esp_bd_addr_t remote_bda
|
||||
//
|
||||
case ESP_GATTC_OPEN_EVT: {
|
||||
m_conn_id = evtParam->open.conn_id;
|
||||
if (m_pClientCallbacks != nullptr) {
|
||||
m_pClientCallbacks->onConnect(this);
|
||||
}
|
||||
if (evtParam->open.status == ESP_GATT_OK) {
|
||||
m_isConnected = true; // Flag us as connected.
|
||||
}
|
||||
m_semaphoreOpenEvt.give(evtParam->open.status);
|
||||
break;
|
||||
} // ESP_GATTC_OPEN_EVT
|
||||
|
||||
|
||||
//
|
||||
// ESP_GATTC_REG_EVT
|
||||
//
|
||||
// reg:
|
||||
// esp_gatt_status_t status
|
||||
// uint16_t app_id
|
||||
//
|
||||
case ESP_GATTC_REG_EVT: {
|
||||
m_gattc_if = gattc_if;
|
||||
m_semaphoreRegEvt.give();
|
||||
break;
|
||||
} // ESP_GATTC_REG_EVT
|
||||
|
||||
case ESP_GATTC_CFG_MTU_EVT:
|
||||
if(evtParam->cfg_mtu.status != ESP_GATT_OK) {
|
||||
ESP_LOGE(LOG_TAG,"Config mtu failed");
|
||||
}
|
||||
m_mtu = evtParam->cfg_mtu.mtu;
|
||||
break;
|
||||
|
||||
case ESP_GATTC_CONNECT_EVT: {
|
||||
BLEDevice::updatePeerDevice(this, true, m_gattc_if);
|
||||
esp_err_t errRc = esp_ble_gattc_send_mtu_req(gattc_if, evtParam->connect.conn_id);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityLevel){
|
||||
esp_ble_set_encryption(evtParam->connect.remote_bda, BLEDevice::m_securityLevel);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
} // ESP_GATTC_CONNECT_EVT
|
||||
|
||||
//
|
||||
// ESP_GATTC_SEARCH_CMPL_EVT
|
||||
//
|
||||
// search_cmpl:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t conn_id
|
||||
//
|
||||
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||
esp_ble_gattc_cb_param_t* p_data = (esp_ble_gattc_cb_param_t*)evtParam;
|
||||
if (p_data->search_cmpl.status != ESP_GATT_OK){
|
||||
ESP_LOGE(LOG_TAG, "search service failed, error status = %x", p_data->search_cmpl.status);
|
||||
break;
|
||||
}
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
// commented out just for now to keep backward compatibility
|
||||
// if(p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_REMOTE_DEVICE) {
|
||||
// ESP_LOGI(LOG_TAG, "Get service information from remote device");
|
||||
// } else if (p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_NVS_FLASH) {
|
||||
// ESP_LOGI(LOG_TAG, "Get service information from flash");
|
||||
// } else {
|
||||
// ESP_LOGI(LOG_TAG, "unknown service source");
|
||||
// }
|
||||
#endif
|
||||
m_semaphoreSearchCmplEvt.give(0);
|
||||
break;
|
||||
} // ESP_GATTC_SEARCH_CMPL_EVT
|
||||
|
||||
|
||||
//
|
||||
// ESP_GATTC_SEARCH_RES_EVT
|
||||
//
|
||||
// search_res:
|
||||
// - uint16_t conn_id
|
||||
// - uint16_t start_handle
|
||||
// - uint16_t end_handle
|
||||
// - esp_gatt_id_t srvc_id
|
||||
//
|
||||
case ESP_GATTC_SEARCH_RES_EVT: {
|
||||
BLEUUID uuid = BLEUUID(evtParam->search_res.srvc_id);
|
||||
BLERemoteService* pRemoteService = new BLERemoteService(
|
||||
evtParam->search_res.srvc_id,
|
||||
this,
|
||||
evtParam->search_res.start_handle,
|
||||
evtParam->search_res.end_handle
|
||||
);
|
||||
m_servicesMap.insert(std::pair<std::string, BLERemoteService*>(uuid.toString(), pRemoteService));
|
||||
m_servicesMapByInstID.insert(std::pair<BLERemoteService *, uint16_t>(pRemoteService, evtParam->search_res.srvc_id.inst_id));
|
||||
break;
|
||||
} // ESP_GATTC_SEARCH_RES_EVT
|
||||
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
} // Switch
|
||||
|
||||
// Pass the request on to all services.
|
||||
for (auto &myPair : m_servicesMap) {
|
||||
myPair.second->gattClientEventHandler(event, gattc_if, evtParam);
|
||||
}
|
||||
|
||||
} // gattClientEventHandler
|
||||
|
||||
|
||||
uint16_t BLEClient::getConnId() {
|
||||
return m_conn_id;
|
||||
} // getConnId
|
||||
|
||||
|
||||
|
||||
esp_gatt_if_t BLEClient::getGattcIf() {
|
||||
return m_gattc_if;
|
||||
} // getGattcIf
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the address of the peer.
|
||||
*
|
||||
* Returns the Bluetooth device address of the %BLE peer to which this client is connected.
|
||||
*/
|
||||
BLEAddress BLEClient::getPeerAddress() {
|
||||
return m_peerAddress;
|
||||
} // getAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Ask the BLE server for the RSSI value.
|
||||
* @return The RSSI value.
|
||||
*/
|
||||
int BLEClient::getRssi() {
|
||||
ESP_LOGD(LOG_TAG, ">> getRssi()");
|
||||
if (!isConnected()) {
|
||||
ESP_LOGD(LOG_TAG, "<< getRssi(): Not connected");
|
||||
return 0;
|
||||
}
|
||||
// We make the API call to read the RSSI value which is an asynchronous operation. We expect to receive
|
||||
// an ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT to indicate completion.
|
||||
//
|
||||
m_semaphoreRssiCmplEvt.take("getRssi");
|
||||
esp_err_t rc = ::esp_ble_gap_read_rssi(*getPeerAddress().getNative());
|
||||
if (rc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< getRssi: esp_ble_gap_read_rssi: rc=%d %s", rc, GeneralUtils::errorToString(rc));
|
||||
return 0;
|
||||
}
|
||||
int rssiValue = m_semaphoreRssiCmplEvt.wait("getRssi");
|
||||
ESP_LOGD(LOG_TAG, "<< getRssi(): %d", rssiValue);
|
||||
return rssiValue;
|
||||
} // getRssi
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service BLE Remote Service instance corresponding to the uuid.
|
||||
* @param [in] uuid The UUID of the service being sought.
|
||||
* @return A reference to the Service or nullptr if don't know about it.
|
||||
*/
|
||||
BLERemoteService* BLEClient::getService(const char* uuid) {
|
||||
return getService(BLEUUID(uuid));
|
||||
} // getService
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the service object corresponding to the uuid.
|
||||
* @param [in] uuid The UUID of the service being sought.
|
||||
* @return A reference to the Service or nullptr if don't know about it.
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
BLERemoteService* BLEClient::getService(BLEUUID uuid) {
|
||||
ESP_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str());
|
||||
// Design
|
||||
// ------
|
||||
// We wish to retrieve the service given its UUID. It is possible that we have not yet asked the
|
||||
// device what services it has in which case we have nothing to match against. If we have not
|
||||
// asked the device about its services, then we do that now. Once we get the results we can then
|
||||
// examine the services map to see if it has the service we are looking for.
|
||||
if (!m_haveServices) {
|
||||
getServices();
|
||||
}
|
||||
std::string uuidStr = uuid.toString();
|
||||
for (auto &myPair : m_servicesMap) {
|
||||
if (myPair.first == uuidStr) {
|
||||
ESP_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str());
|
||||
return myPair.second;
|
||||
}
|
||||
} // End of each of the services.
|
||||
ESP_LOGD(LOG_TAG, "<< getService: not found");
|
||||
return nullptr;
|
||||
} // getService
|
||||
|
||||
|
||||
/**
|
||||
* @brief Ask the remote %BLE server for its services.
|
||||
* A %BLE Server exposes a set of services for its partners. Here we ask the server for its set of
|
||||
* services and wait until we have received them all.
|
||||
* @return N/A
|
||||
*/
|
||||
std::map<std::string, BLERemoteService*>* BLEClient::getServices() {
|
||||
/*
|
||||
* Design
|
||||
* ------
|
||||
* We invoke esp_ble_gattc_search_service. This will request a list of the service exposed by the
|
||||
* peer BLE partner to be returned as events. Each event will be an an instance of ESP_GATTC_SEARCH_RES_EVT
|
||||
* and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received.
|
||||
*/
|
||||
ESP_LOGD(LOG_TAG, ">> getServices");
|
||||
// TODO implement retrieving services from cache
|
||||
clearServices(); // Clear any services that may exist.
|
||||
|
||||
esp_err_t errRc = esp_ble_gattc_search_service(
|
||||
getGattcIf(),
|
||||
getConnId(),
|
||||
NULL // Filter UUID
|
||||
);
|
||||
|
||||
m_semaphoreSearchCmplEvt.take("getServices");
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return &m_servicesMap;
|
||||
}
|
||||
// If sucessfull, remember that we now have services.
|
||||
m_haveServices = (m_semaphoreSearchCmplEvt.wait("getServices") == 0);
|
||||
ESP_LOGD(LOG_TAG, "<< getServices");
|
||||
return &m_servicesMap;
|
||||
} // getServices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the value of a specific characteristic associated with a specific service.
|
||||
* @param [in] serviceUUID The service that owns the characteristic.
|
||||
* @param [in] characteristicUUID The characteristic whose value we wish to read.
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
std::string BLEClient::getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID) {
|
||||
ESP_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
std::string ret = getService(serviceUUID)->getCharacteristic(characteristicUUID)->readValue();
|
||||
ESP_LOGD(LOG_TAG, "<<getValue");
|
||||
return ret;
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle a received GAP event.
|
||||
*
|
||||
* @param [in] event
|
||||
* @param [in] param
|
||||
*/
|
||||
void BLEClient::handleGAPEvent(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param) {
|
||||
ESP_LOGD(LOG_TAG, "BLEClient ... handling GAP event!");
|
||||
switch (event) {
|
||||
//
|
||||
// ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT
|
||||
//
|
||||
// read_rssi_cmpl
|
||||
// - esp_bt_status_t status
|
||||
// - int8_t rssi
|
||||
// - esp_bd_addr_t remote_addr
|
||||
//
|
||||
case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: {
|
||||
m_semaphoreRssiCmplEvt.give((uint32_t) param->read_rssi_cmpl.rssi);
|
||||
break;
|
||||
} // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} // handleGAPEvent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Are we connected to a partner?
|
||||
* @return True if we are connected and false if we are not connected.
|
||||
*/
|
||||
bool BLEClient::isConnected() {
|
||||
return m_isConnected;
|
||||
} // isConnected
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the callbacks that will be invoked.
|
||||
*/
|
||||
void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks) {
|
||||
m_pClientCallbacks = pClientCallbacks;
|
||||
} // setClientCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of a specific characteristic associated with a specific service.
|
||||
* @param [in] serviceUUID The service that owns the characteristic.
|
||||
* @param [in] characteristicUUID The characteristic whose value we wish to write.
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
void BLEClient::setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) {
|
||||
ESP_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
getService(serviceUUID)->getCharacteristic(characteristicUUID)->writeValue(value);
|
||||
ESP_LOGD(LOG_TAG, "<< setValue");
|
||||
} // setValue
|
||||
|
||||
uint16_t BLEClient::getMTU() {
|
||||
return m_mtu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of this client.
|
||||
* @return A string representation of this client.
|
||||
*/
|
||||
std::string BLEClient::toString() {
|
||||
std::ostringstream ss;
|
||||
ss << "peer address: " << m_peerAddress.toString();
|
||||
ss << "\nServices:\n";
|
||||
for (auto &myPair : m_servicesMap) {
|
||||
ss << myPair.second->toString() << "\n";
|
||||
// myPair.second is the value
|
||||
}
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
103
libraries/ESP32_BLE_Arduino/src/BLEClient.h
Normal file
103
libraries/ESP32_BLE_Arduino/src/BLEClient.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* BLEDevice.h
|
||||
*
|
||||
* Created on: Mar 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_BLEDEVICE_H_
|
||||
#define MAIN_BLEDEVICE_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <esp_gattc_api.h>
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "BLEExceptions.h"
|
||||
#include "BLERemoteService.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLEAddress.h"
|
||||
#include "BLEAdvertisedDevice.h"
|
||||
|
||||
class BLERemoteService;
|
||||
class BLEClientCallbacks;
|
||||
class BLEAdvertisedDevice;
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE client.
|
||||
*/
|
||||
class BLEClient {
|
||||
public:
|
||||
BLEClient();
|
||||
~BLEClient();
|
||||
|
||||
bool connect(BLEAdvertisedDevice* device);
|
||||
bool connect(BLEAddress address, esp_ble_addr_type_t type = BLE_ADDR_TYPE_PUBLIC); // Connect to the remote BLE Server
|
||||
void disconnect(); // Disconnect from the remote BLE Server
|
||||
BLEAddress getPeerAddress(); // Get the address of the remote BLE Server
|
||||
int getRssi(); // Get the RSSI of the remote BLE Server
|
||||
std::map<std::string, BLERemoteService*>* getServices(); // Get a map of the services offered by the remote BLE Server
|
||||
BLERemoteService* getService(const char* uuid); // Get a reference to a specified service offered by the remote BLE server.
|
||||
BLERemoteService* getService(BLEUUID uuid); // Get a reference to a specified service offered by the remote BLE server.
|
||||
std::string getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID); // Get the value of a given characteristic at a given service.
|
||||
|
||||
|
||||
void handleGAPEvent(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param);
|
||||
|
||||
bool isConnected(); // Return true if we are connected.
|
||||
|
||||
void setClientCallbacks(BLEClientCallbacks *pClientCallbacks);
|
||||
void setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value); // Set the value of a given characteristic at a given service.
|
||||
|
||||
std::string toString(); // Return a string representation of this client.
|
||||
uint16_t getConnId();
|
||||
esp_gatt_if_t getGattcIf();
|
||||
uint16_t getMTU();
|
||||
|
||||
uint16_t m_appId;
|
||||
private:
|
||||
friend class BLEDevice;
|
||||
friend class BLERemoteService;
|
||||
friend class BLERemoteCharacteristic;
|
||||
friend class BLERemoteDescriptor;
|
||||
|
||||
void gattClientEventHandler(
|
||||
esp_gattc_cb_event_t event,
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* param);
|
||||
|
||||
BLEAddress m_peerAddress = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); // The BD address of the remote server.
|
||||
uint16_t m_conn_id;
|
||||
// int m_deviceType;
|
||||
esp_gatt_if_t m_gattc_if;
|
||||
bool m_haveServices = false; // Have we previously obtain the set of services from the remote server.
|
||||
bool m_isConnected = false; // Are we currently connected.
|
||||
|
||||
BLEClientCallbacks* m_pClientCallbacks;
|
||||
FreeRTOS::Semaphore m_semaphoreRegEvt = FreeRTOS::Semaphore("RegEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreRssiCmplEvt = FreeRTOS::Semaphore("RssiCmplEvt");
|
||||
std::map<std::string, BLERemoteService*> m_servicesMap;
|
||||
std::map<BLERemoteService*, uint16_t> m_servicesMapByInstID;
|
||||
void clearServices(); // Clear any existing services.
|
||||
uint16_t m_mtu = 23;
|
||||
}; // class BLEDevice
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks associated with a %BLE client.
|
||||
*/
|
||||
class BLEClientCallbacks {
|
||||
public:
|
||||
virtual ~BLEClientCallbacks() {};
|
||||
virtual void onConnect(BLEClient *pClient) = 0;
|
||||
virtual void onDisconnect(BLEClient *pClient) = 0;
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* MAIN_BLEDEVICE_H_ */
|
||||
296
libraries/ESP32_BLE_Arduino/src/BLEDescriptor.cpp
Normal file
296
libraries/ESP32_BLE_Arduino/src/BLEDescriptor.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* BLEDescriptor.cpp
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include <iomanip>
|
||||
#include <stdlib.h>
|
||||
#include "sdkconfig.h"
|
||||
#include <esp_err.h>
|
||||
#include "BLEService.h"
|
||||
#include "BLEDescriptor.h"
|
||||
#include "GeneralUtils.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEDescriptor";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#define NULL_HANDLE (0xffff)
|
||||
|
||||
|
||||
/**
|
||||
* @brief BLEDescriptor constructor.
|
||||
*/
|
||||
BLEDescriptor::BLEDescriptor(const char* uuid, uint16_t len) : BLEDescriptor(BLEUUID(uuid), len) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief BLEDescriptor constructor.
|
||||
*/
|
||||
BLEDescriptor::BLEDescriptor(BLEUUID uuid, uint16_t max_len) {
|
||||
m_bleUUID = uuid;
|
||||
m_value.attr_len = 0; // Initial length is 0.
|
||||
m_value.attr_max_len = max_len; // Maximum length of the data.
|
||||
m_handle = NULL_HANDLE; // Handle is initially unknown.
|
||||
m_pCharacteristic = nullptr; // No initial characteristic.
|
||||
m_pCallback = nullptr; // No initial callback.
|
||||
|
||||
m_value.attr_value = (uint8_t*) malloc(max_len); // Allocate storage for the value.
|
||||
} // BLEDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief BLEDescriptor destructor.
|
||||
*/
|
||||
BLEDescriptor::~BLEDescriptor() {
|
||||
free(m_value.attr_value); // Release the storage we created in the constructor.
|
||||
} // ~BLEDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Execute the creation of the descriptor with the BLE runtime in ESP.
|
||||
* @param [in] pCharacteristic The characteristic to which to register this descriptor.
|
||||
*/
|
||||
void BLEDescriptor::executeCreate(BLECharacteristic* pCharacteristic) {
|
||||
ESP_LOGD(LOG_TAG, ">> executeCreate(): %s", toString().c_str());
|
||||
|
||||
if (m_handle != NULL_HANDLE) {
|
||||
ESP_LOGE(LOG_TAG, "Descriptor already has a handle.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_pCharacteristic = pCharacteristic; // Save the characteristic associated with this service.
|
||||
|
||||
esp_attr_control_t control;
|
||||
control.auto_rsp = ESP_GATT_AUTO_RSP;
|
||||
m_semaphoreCreateEvt.take("executeCreate");
|
||||
esp_err_t errRc = ::esp_ble_gatts_add_char_descr(
|
||||
pCharacteristic->getService()->getHandle(),
|
||||
getUUID().getNative(),
|
||||
(esp_gatt_perm_t)m_permissions,
|
||||
&m_value,
|
||||
&control);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_add_char_descr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreCreateEvt.wait("executeCreate");
|
||||
ESP_LOGD(LOG_TAG, "<< executeCreate");
|
||||
} // executeCreate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the BLE handle for this descriptor.
|
||||
* @return The handle for this descriptor.
|
||||
*/
|
||||
uint16_t BLEDescriptor::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the length of the value of this descriptor.
|
||||
* @return The length (in bytes) of the value of this descriptor.
|
||||
*/
|
||||
size_t BLEDescriptor::getLength() {
|
||||
return m_value.attr_len;
|
||||
} // getLength
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID of the descriptor.
|
||||
*/
|
||||
BLEUUID BLEDescriptor::getUUID() {
|
||||
return m_bleUUID;
|
||||
} // getUUID
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the value of this descriptor.
|
||||
* @return A pointer to the value of this descriptor.
|
||||
*/
|
||||
uint8_t* BLEDescriptor::getValue() {
|
||||
return m_value.attr_value;
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle GATT server events for the descripttor.
|
||||
* @param [in] event
|
||||
* @param [in] gatts_if
|
||||
* @param [in] param
|
||||
*/
|
||||
void BLEDescriptor::handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param) {
|
||||
switch (event) {
|
||||
// ESP_GATTS_ADD_CHAR_DESCR_EVT
|
||||
//
|
||||
// add_char_descr:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t attr_handle
|
||||
// - uint16_t service_handle
|
||||
// - esp_bt_uuid_t char_uuid
|
||||
case ESP_GATTS_ADD_CHAR_DESCR_EVT: {
|
||||
if (m_pCharacteristic != nullptr &&
|
||||
m_bleUUID.equals(BLEUUID(param->add_char_descr.descr_uuid)) &&
|
||||
m_pCharacteristic->getService()->getHandle() == param->add_char_descr.service_handle &&
|
||||
m_pCharacteristic == m_pCharacteristic->getService()->getLastCreatedCharacteristic()) {
|
||||
setHandle(param->add_char_descr.attr_handle);
|
||||
m_semaphoreCreateEvt.give();
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_ADD_CHAR_DESCR_EVT
|
||||
|
||||
// ESP_GATTS_WRITE_EVT - A request to write the value of a descriptor has arrived.
|
||||
//
|
||||
// write:
|
||||
// - uint16_t conn_id
|
||||
// - uint16_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
// - bool need_rsp
|
||||
// - bool is_prep
|
||||
// - uint16_t len
|
||||
// - uint8_t *value
|
||||
case ESP_GATTS_WRITE_EVT: {
|
||||
if (param->write.handle == m_handle) {
|
||||
setValue(param->write.value, param->write.len); // Set the value of the descriptor.
|
||||
|
||||
if (m_pCallback != nullptr) { // We have completed the write, if there is a user supplied callback handler, invoke it now.
|
||||
m_pCallback->onWrite(this); // Invoke the onWrite callback handler.
|
||||
}
|
||||
} // End of ... this is our handle.
|
||||
|
||||
break;
|
||||
} // ESP_GATTS_WRITE_EVT
|
||||
|
||||
// ESP_GATTS_READ_EVT - A request to read the value of a descriptor has arrived.
|
||||
//
|
||||
// read:
|
||||
// - uint16_t conn_id
|
||||
// - uint32_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
// - bool is_long
|
||||
// - bool need_rsp
|
||||
//
|
||||
case ESP_GATTS_READ_EVT: {
|
||||
if (param->read.handle == m_handle) { // If this event is for this descriptor ... process it
|
||||
|
||||
if (m_pCallback != nullptr) { // If we have a user supplied callback, invoke it now.
|
||||
m_pCallback->onRead(this); // Invoke the onRead callback method in the callback handler.
|
||||
}
|
||||
|
||||
} // End of this is our handle
|
||||
break;
|
||||
} // ESP_GATTS_READ_EVT
|
||||
|
||||
default:
|
||||
break;
|
||||
} // switch event
|
||||
} // handleGATTServerEvent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the callback handlers for this descriptor.
|
||||
* @param [in] pCallbacks An instance of a callback structure used to define any callbacks for the descriptor.
|
||||
*/
|
||||
void BLEDescriptor::setCallbacks(BLEDescriptorCallbacks* pCallback) {
|
||||
ESP_LOGD(LOG_TAG, ">> setCallbacks: 0x%x", (uint32_t) pCallback);
|
||||
m_pCallback = pCallback;
|
||||
ESP_LOGD(LOG_TAG, "<< setCallbacks");
|
||||
} // setCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the handle of this descriptor.
|
||||
* Set the handle of this descriptor to be the supplied value.
|
||||
* @param [in] handle The handle to be associated with this descriptor.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEDescriptor::setHandle(uint16_t handle) {
|
||||
ESP_LOGD(LOG_TAG, ">> setHandle(0x%.2x): Setting descriptor handle to be 0x%.2x", handle, handle);
|
||||
m_handle = handle;
|
||||
ESP_LOGD(LOG_TAG, "<< setHandle()");
|
||||
} // setHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the descriptor.
|
||||
* @param [in] data The data to set for the descriptor.
|
||||
* @param [in] length The length of the data in bytes.
|
||||
*/
|
||||
void BLEDescriptor::setValue(uint8_t* data, size_t length) {
|
||||
if (length > ESP_GATT_MAX_ATTR_LEN) {
|
||||
ESP_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN);
|
||||
return;
|
||||
}
|
||||
m_value.attr_len = length;
|
||||
memcpy(m_value.attr_value, data, length);
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of the descriptor.
|
||||
* @param [in] value The value of the descriptor in string form.
|
||||
*/
|
||||
void BLEDescriptor::setValue(std::string value) {
|
||||
setValue((uint8_t*) value.data(), value.length());
|
||||
} // setValue
|
||||
|
||||
void BLEDescriptor::setAccessPermissions(esp_gatt_perm_t perm) {
|
||||
m_permissions = perm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the descriptor.
|
||||
* @return A string representation of the descriptor.
|
||||
*/
|
||||
std::string BLEDescriptor::toString() {
|
||||
std::stringstream stringstream;
|
||||
stringstream << std::hex << std::setfill('0');
|
||||
stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle;
|
||||
return stringstream.str();
|
||||
} // toString
|
||||
|
||||
|
||||
BLEDescriptorCallbacks::~BLEDescriptorCallbacks() {}
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a read request.
|
||||
* @param [in] pDescriptor The descriptor that is the source of the event.
|
||||
*/
|
||||
void BLEDescriptorCallbacks::onRead(BLEDescriptor* pDescriptor) {
|
||||
ESP_LOGD("BLEDescriptorCallbacks", ">> onRead: default");
|
||||
ESP_LOGD("BLEDescriptorCallbacks", "<< onRead");
|
||||
} // onRead
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a write request.
|
||||
* @param [in] pDescriptor The descriptor that is the source of the event.
|
||||
*/
|
||||
void BLEDescriptorCallbacks::onWrite(BLEDescriptor* pDescriptor) {
|
||||
ESP_LOGD("BLEDescriptorCallbacks", ">> onWrite: default");
|
||||
ESP_LOGD("BLEDescriptorCallbacks", "<< onWrite");
|
||||
} // onWrite
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
77
libraries/ESP32_BLE_Arduino/src/BLEDescriptor.h
Normal file
77
libraries/ESP32_BLE_Arduino/src/BLEDescriptor.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* BLEDescriptor.h
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string>
|
||||
#include "BLEUUID.h"
|
||||
#include "BLECharacteristic.h"
|
||||
#include <esp_gatts_api.h>
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
class BLEService;
|
||||
class BLECharacteristic;
|
||||
class BLEDescriptorCallbacks;
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE descriptor.
|
||||
*/
|
||||
class BLEDescriptor {
|
||||
public:
|
||||
BLEDescriptor(const char* uuid, uint16_t max_len = 100);
|
||||
BLEDescriptor(BLEUUID uuid, uint16_t max_len = 100);
|
||||
virtual ~BLEDescriptor();
|
||||
|
||||
uint16_t getHandle(); // Get the handle of the descriptor.
|
||||
size_t getLength(); // Get the length of the value of the descriptor.
|
||||
BLEUUID getUUID(); // Get the UUID of the descriptor.
|
||||
uint8_t* getValue(); // Get a pointer to the value of the descriptor.
|
||||
void handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param);
|
||||
|
||||
void setAccessPermissions(esp_gatt_perm_t perm); // Set the permissions of the descriptor.
|
||||
void setCallbacks(BLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor.
|
||||
void setValue(uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data.
|
||||
void setValue(std::string value); // Set the value of the descriptor as a data buffer.
|
||||
|
||||
std::string toString(); // Convert the descriptor to a string representation.
|
||||
|
||||
private:
|
||||
friend class BLEDescriptorMap;
|
||||
friend class BLECharacteristic;
|
||||
BLEUUID m_bleUUID;
|
||||
uint16_t m_handle;
|
||||
BLEDescriptorCallbacks* m_pCallback;
|
||||
BLECharacteristic* m_pCharacteristic;
|
||||
esp_gatt_perm_t m_permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
|
||||
FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt");
|
||||
esp_attr_value_t m_value;
|
||||
|
||||
void executeCreate(BLECharacteristic* pCharacteristic);
|
||||
void setHandle(uint16_t handle);
|
||||
}; // BLEDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks that can be associated with a %BLE descriptors to inform of events.
|
||||
*
|
||||
* When a server application creates a %BLE descriptor, we may wish to be informed when there is either
|
||||
* a read or write request to the descriptors value. An application can register a
|
||||
* sub-classed instance of this class and will be notified when such an event happens.
|
||||
*/
|
||||
class BLEDescriptorCallbacks {
|
||||
public:
|
||||
virtual ~BLEDescriptorCallbacks();
|
||||
virtual void onRead(BLEDescriptor* pDescriptor);
|
||||
virtual void onWrite(BLEDescriptor* pDescriptor);
|
||||
};
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ */
|
||||
147
libraries/ESP32_BLE_Arduino/src/BLEDescriptorMap.cpp
Normal file
147
libraries/ESP32_BLE_Arduino/src/BLEDescriptorMap.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* BLEDescriptorMap.cpp
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include "BLECharacteristic.h"
|
||||
#include "BLEDescriptor.h"
|
||||
#include <esp_gatts_api.h> // ESP32 BLE
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-log.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return the descriptor by UUID.
|
||||
* @param [in] UUID The UUID to look up the descriptor.
|
||||
* @return The descriptor. If not present, then nullptr is returned.
|
||||
*/
|
||||
BLEDescriptor* BLEDescriptorMap::getByUUID(const char* uuid) {
|
||||
return getByUUID(BLEUUID(uuid));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the descriptor by UUID.
|
||||
* @param [in] UUID The UUID to look up the descriptor.
|
||||
* @return The descriptor. If not present, then nullptr is returned.
|
||||
*/
|
||||
BLEDescriptor* BLEDescriptorMap::getByUUID(BLEUUID uuid) {
|
||||
for (auto &myPair : m_uuidMap) {
|
||||
if (myPair.first->getUUID().equals(uuid)) {
|
||||
return myPair.first;
|
||||
}
|
||||
}
|
||||
//return m_uuidMap.at(uuid.toString());
|
||||
return nullptr;
|
||||
} // getByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the descriptor by handle.
|
||||
* @param [in] handle The handle to look up the descriptor.
|
||||
* @return The descriptor.
|
||||
*/
|
||||
BLEDescriptor* BLEDescriptorMap::getByHandle(uint16_t handle) {
|
||||
return m_handleMap.at(handle);
|
||||
} // getByHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the descriptor by UUID.
|
||||
* @param [in] uuid The uuid of the descriptor.
|
||||
* @param [in] characteristic The descriptor to cache.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEDescriptorMap::setByUUID(const char* uuid, BLEDescriptor* pDescriptor){
|
||||
m_uuidMap.insert(std::pair<BLEDescriptor*, std::string>(pDescriptor, uuid));
|
||||
} // setByUUID
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the descriptor by UUID.
|
||||
* @param [in] uuid The uuid of the descriptor.
|
||||
* @param [in] characteristic The descriptor to cache.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEDescriptorMap::setByUUID(BLEUUID uuid, BLEDescriptor* pDescriptor) {
|
||||
m_uuidMap.insert(std::pair<BLEDescriptor*, std::string>(pDescriptor, uuid.toString()));
|
||||
} // setByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the descriptor by handle.
|
||||
* @param [in] handle The handle of the descriptor.
|
||||
* @param [in] descriptor The descriptor to cache.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEDescriptorMap::setByHandle(uint16_t handle, BLEDescriptor* pDescriptor) {
|
||||
m_handleMap.insert(std::pair<uint16_t, BLEDescriptor*>(handle, pDescriptor));
|
||||
} // setByHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the descriptor map.
|
||||
* @return A string representation of the descriptor map.
|
||||
*/
|
||||
std::string BLEDescriptorMap::toString() {
|
||||
std::stringstream stringStream;
|
||||
stringStream << std::hex << std::setfill('0');
|
||||
int count = 0;
|
||||
for (auto &myPair : m_uuidMap) {
|
||||
if (count > 0) {
|
||||
stringStream << "\n";
|
||||
}
|
||||
count++;
|
||||
stringStream << "handle: 0x" << std::setw(2) << myPair.first->getHandle() << ", uuid: " + myPair.first->getUUID().toString();
|
||||
}
|
||||
return stringStream.str();
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @breif Pass the GATT server event onwards to each of the descriptors found in the mapping
|
||||
* @param [in] event
|
||||
* @param [in] gatts_if
|
||||
* @param [in] param
|
||||
*/
|
||||
void BLEDescriptorMap::handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param) {
|
||||
// Invoke the handler for every descriptor we have.
|
||||
for (auto &myPair : m_uuidMap) {
|
||||
myPair.first->handleGATTServerEvent(event, gatts_if, param);
|
||||
}
|
||||
} // handleGATTServerEvent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the first descriptor in the map.
|
||||
* @return The first descriptor in the map.
|
||||
*/
|
||||
BLEDescriptor* BLEDescriptorMap::getFirst() {
|
||||
m_iterator = m_uuidMap.begin();
|
||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
||||
BLEDescriptor* pRet = m_iterator->first;
|
||||
m_iterator++;
|
||||
return pRet;
|
||||
} // getFirst
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the next descriptor in the map.
|
||||
* @return The next descriptor in the map.
|
||||
*/
|
||||
BLEDescriptor* BLEDescriptorMap::getNext() {
|
||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
||||
BLEDescriptor* pRet = m_iterator->first;
|
||||
m_iterator++;
|
||||
return pRet;
|
||||
} // getNext
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
646
libraries/ESP32_BLE_Arduino/src/BLEDevice.cpp
Normal file
646
libraries/ESP32_BLE_Arduino/src/BLEDevice.cpp
Normal file
@@ -0,0 +1,646 @@
|
||||
/*
|
||||
* BLE.cpp
|
||||
*
|
||||
* Created on: Mar 16, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/event_groups.h>
|
||||
#include <freertos/task.h>
|
||||
#include <esp_err.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <esp_bt.h> // ESP32 BLE
|
||||
#include <esp_bt_device.h> // ESP32 BLE
|
||||
#include <esp_bt_main.h> // ESP32 BLE
|
||||
#include <esp_gap_ble_api.h> // ESP32 BLE
|
||||
#include <esp_gatts_api.h> // ESP32 BLE
|
||||
#include <esp_gattc_api.h> // ESP32 BLE
|
||||
#include <esp_gatt_common_api.h>// ESP32 BLE
|
||||
#include <esp_err.h> // ESP32 ESP-IDF
|
||||
#include <map> // Part of C++ Standard library
|
||||
#include <sstream> // Part of C++ Standard library
|
||||
#include <iomanip> // Part of C++ Standard library
|
||||
|
||||
#include "BLEDevice.h"
|
||||
#include "BLEClient.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "GeneralUtils.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#include "esp32-hal-bt.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEDevice";
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Singletons for the BLEDevice.
|
||||
*/
|
||||
BLEServer* BLEDevice::m_pServer = nullptr;
|
||||
BLEScan* BLEDevice::m_pScan = nullptr;
|
||||
BLEClient* BLEDevice::m_pClient = nullptr;
|
||||
bool initialized = false;
|
||||
esp_ble_sec_act_t BLEDevice::m_securityLevel = (esp_ble_sec_act_t)0;
|
||||
BLESecurityCallbacks* BLEDevice::m_securityCallbacks = nullptr;
|
||||
uint16_t BLEDevice::m_localMTU = 23; // not sure if this variable is useful
|
||||
BLEAdvertising* BLEDevice::m_bleAdvertising = nullptr;
|
||||
uint16_t BLEDevice::m_appId = 0;
|
||||
std::map<uint16_t, conn_status_t> BLEDevice::m_connectedClientsMap;
|
||||
gap_event_handler BLEDevice::m_customGapHandler = nullptr;
|
||||
gattc_event_handler BLEDevice::m_customGattcHandler = nullptr;
|
||||
gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
|
||||
/**
|
||||
* @brief Create a new instance of a client.
|
||||
* @return A new instance of the client.
|
||||
*/
|
||||
/* STATIC */ BLEClient* BLEDevice::createClient() {
|
||||
ESP_LOGD(LOG_TAG, ">> createClient");
|
||||
#ifndef CONFIG_GATTC_ENABLE // Check that BLE GATTC is enabled in make menuconfig
|
||||
ESP_LOGE(LOG_TAG, "BLE GATTC is not enabled - CONFIG_GATTC_ENABLE not defined");
|
||||
abort();
|
||||
#endif // CONFIG_GATTC_ENABLE
|
||||
m_pClient = new BLEClient();
|
||||
ESP_LOGD(LOG_TAG, "<< createClient");
|
||||
return m_pClient;
|
||||
} // createClient
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new instance of a server.
|
||||
* @return A new instance of the server.
|
||||
*/
|
||||
/* STATIC */ BLEServer* BLEDevice::createServer() {
|
||||
ESP_LOGD(LOG_TAG, ">> createServer");
|
||||
#ifndef CONFIG_GATTS_ENABLE // Check that BLE GATTS is enabled in make menuconfig
|
||||
ESP_LOGE(LOG_TAG, "BLE GATTS is not enabled - CONFIG_GATTS_ENABLE not defined");
|
||||
abort();
|
||||
#endif // CONFIG_GATTS_ENABLE
|
||||
m_pServer = new BLEServer();
|
||||
m_pServer->createApp(m_appId++);
|
||||
ESP_LOGD(LOG_TAG, "<< createServer");
|
||||
return m_pServer;
|
||||
} // createServer
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle GATT server events.
|
||||
*
|
||||
* @param [in] event The event that has been newly received.
|
||||
* @param [in] gatts_if The connection to the GATT interface.
|
||||
* @param [in] param Parameters for the event.
|
||||
*/
|
||||
/* STATIC */ void BLEDevice::gattServerEventHandler(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param
|
||||
) {
|
||||
ESP_LOGD(LOG_TAG, "gattServerEventHandler [esp_gatt_if: %d] ... %s",
|
||||
gatts_if,
|
||||
BLEUtils::gattServerEventTypeToString(event).c_str());
|
||||
|
||||
BLEUtils::dumpGattServerEvent(event, gatts_if, param);
|
||||
|
||||
switch (event) {
|
||||
case ESP_GATTS_CONNECT_EVT: {
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityLevel){
|
||||
esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
} // ESP_GATTS_CONNECT_EVT
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
|
||||
|
||||
if (BLEDevice::m_pServer != nullptr) {
|
||||
BLEDevice::m_pServer->handleGATTServerEvent(event, gatts_if, param);
|
||||
}
|
||||
|
||||
if(m_customGattsHandler != nullptr) {
|
||||
m_customGattsHandler(event, gatts_if, param);
|
||||
}
|
||||
|
||||
} // gattServerEventHandler
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle GATT client events.
|
||||
*
|
||||
* Handler for the GATT client events.
|
||||
*
|
||||
* @param [in] event
|
||||
* @param [in] gattc_if
|
||||
* @param [in] param
|
||||
*/
|
||||
/* STATIC */ void BLEDevice::gattClientEventHandler(
|
||||
esp_gattc_cb_event_t event,
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* param) {
|
||||
|
||||
ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s",
|
||||
gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str());
|
||||
BLEUtils::dumpGattClientEvent(event, gattc_if, param);
|
||||
|
||||
switch(event) {
|
||||
case ESP_GATTC_CONNECT_EVT: {
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityLevel){
|
||||
esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
} // ESP_GATTS_CONNECT_EVT
|
||||
|
||||
default:
|
||||
break;
|
||||
} // switch
|
||||
for(auto &myPair : BLEDevice::getPeerDevices(true)) {
|
||||
conn_status_t conn_status = (conn_status_t)myPair.second;
|
||||
if(((BLEClient*)conn_status.peer_device)->getGattcIf() == gattc_if || ((BLEClient*)conn_status.peer_device)->getGattcIf() == ESP_GATT_IF_NONE || gattc_if == ESP_GATT_IF_NONE){
|
||||
((BLEClient*)conn_status.peer_device)->gattClientEventHandler(event, gattc_if, param);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_customGattcHandler != nullptr) {
|
||||
m_customGattcHandler(event, gattc_if, param);
|
||||
}
|
||||
|
||||
|
||||
} // gattClientEventHandler
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle GAP events.
|
||||
*/
|
||||
/* STATIC */ void BLEDevice::gapEventHandler(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t *param) {
|
||||
|
||||
BLEUtils::dumpGapEvent(event, param);
|
||||
|
||||
switch(event) {
|
||||
|
||||
case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_OOB_REQ_EVT");
|
||||
break;
|
||||
case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_IR_EVT");
|
||||
break;
|
||||
case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_ER_EVT");
|
||||
break;
|
||||
case ESP_GAP_BLE_NC_REQ_EVT: /* NUMERIC CONFIRMATION */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_NC_REQ_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks != nullptr){
|
||||
esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onConfirmPIN(param->ble_security.key_notif.passkey));
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT: ");
|
||||
// esp_log_buffer_hex(LOG_TAG, m_remote_bda, sizeof(m_remote_bda));
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks != nullptr){
|
||||
esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, BLEDevice::m_securityCallbacks->onPassKeyRequest());
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
/*
|
||||
* TODO should we add white/black list comparison?
|
||||
*/
|
||||
case ESP_GAP_BLE_SEC_REQ_EVT:
|
||||
/* send the positive(true) security response to the peer device to accept the security request.
|
||||
If not accept the security request, should sent the security response with negative(false) accept value*/
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_SEC_REQ_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks!=nullptr){
|
||||
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onSecurityRequest());
|
||||
}
|
||||
else{
|
||||
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
/*
|
||||
*
|
||||
*/
|
||||
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: //the app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
|
||||
//display the passkey number to the user to input it in the peer deivce within 30 seconds
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_NOTIF_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
ESP_LOGI(LOG_TAG, "passKey = %d", param->ble_security.key_notif.passkey);
|
||||
if(BLEDevice::m_securityCallbacks!=nullptr){
|
||||
BLEDevice::m_securityCallbacks->onPassKeyNotify(param->ble_security.key_notif.passkey);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
case ESP_GAP_BLE_KEY_EVT:
|
||||
//shows the ble key type info share with peer device to the user.
|
||||
ESP_LOGD(LOG_TAG, "ESP_GAP_BLE_KEY_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
ESP_LOGI(LOG_TAG, "key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type));
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
case ESP_GAP_BLE_AUTH_CMPL_EVT:
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_AUTH_CMPL_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks != nullptr){
|
||||
BLEDevice::m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
|
||||
if (BLEDevice::m_pClient != nullptr) {
|
||||
BLEDevice::m_pClient->handleGAPEvent(event, param);
|
||||
}
|
||||
|
||||
if (BLEDevice::m_pScan != nullptr) {
|
||||
BLEDevice::getScan()->handleGAPEvent(event, param);
|
||||
}
|
||||
|
||||
if(m_bleAdvertising != nullptr) {
|
||||
BLEDevice::getAdvertising()->handleGAPEvent(event, param);
|
||||
}
|
||||
|
||||
if(m_customGapHandler != nullptr) {
|
||||
BLEDevice::m_customGapHandler(event, param);
|
||||
}
|
||||
|
||||
} // gapEventHandler
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the BLE device address.
|
||||
* @return The BLE device address.
|
||||
*/
|
||||
/* STATIC*/ BLEAddress BLEDevice::getAddress() {
|
||||
const uint8_t* bdAddr = esp_bt_dev_get_address();
|
||||
esp_bd_addr_t addr;
|
||||
memcpy(addr, bdAddr, sizeof(addr));
|
||||
return BLEAddress(addr);
|
||||
} // getAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the Scan object that we use for scanning.
|
||||
* @return The scanning object reference. This is a singleton object. The caller should not
|
||||
* try and release/delete it.
|
||||
*/
|
||||
/* STATIC */ BLEScan* BLEDevice::getScan() {
|
||||
//ESP_LOGD(LOG_TAG, ">> getScan");
|
||||
if (m_pScan == nullptr) {
|
||||
m_pScan = new BLEScan();
|
||||
//ESP_LOGD(LOG_TAG, " - creating a new scan object");
|
||||
}
|
||||
//ESP_LOGD(LOG_TAG, "<< getScan: Returning object at 0x%x", (uint32_t)m_pScan);
|
||||
return m_pScan;
|
||||
} // getScan
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the value of a characteristic of a service on a remote device.
|
||||
* @param [in] bdAddress
|
||||
* @param [in] serviceUUID
|
||||
* @param [in] characteristicUUID
|
||||
*/
|
||||
/* STATIC */ std::string BLEDevice::getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID) {
|
||||
ESP_LOGD(LOG_TAG, ">> getValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
BLEClient* pClient = createClient();
|
||||
pClient->connect(bdAddress);
|
||||
std::string ret = pClient->getValue(serviceUUID, characteristicUUID);
|
||||
pClient->disconnect();
|
||||
ESP_LOGD(LOG_TAG, "<< getValue");
|
||||
return ret;
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize the %BLE environment.
|
||||
* @param deviceName The device name of the device.
|
||||
*/
|
||||
/* STATIC */ void BLEDevice::init(std::string deviceName) {
|
||||
if(!initialized){
|
||||
initialized = true; // Set the initialization flag to ensure we are only initialized once.
|
||||
|
||||
esp_err_t errRc = ESP_OK;
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
if (!btStart()) {
|
||||
errRc = ESP_FAIL;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
errRc = ::nvs_flash_init();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef CLASSIC_BT_ENABLED
|
||||
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
#endif
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
errRc = esp_bt_controller_init(&bt_cfg);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef CLASSIC_BT_ENABLED
|
||||
errRc = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
errRc = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
esp_bluedroid_status_t bt_state = esp_bluedroid_get_status();
|
||||
if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED) {
|
||||
errRc = esp_bluedroid_init();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (bt_state != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
errRc = esp_bluedroid_enable();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
errRc = esp_ble_gap_register_callback(BLEDevice::gapEventHandler);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GATTC_ENABLE // Check that BLE client is configured in make menuconfig
|
||||
errRc = esp_ble_gattc_register_callback(BLEDevice::gattClientEventHandler);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
#endif // CONFIG_GATTC_ENABLE
|
||||
|
||||
#ifdef CONFIG_GATTS_ENABLE // Check that BLE server is configured in make menuconfig
|
||||
errRc = esp_ble_gatts_register_callback(BLEDevice::gattServerEventHandler);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
#endif // CONFIG_GATTS_ENABLE
|
||||
|
||||
errRc = ::esp_ble_gap_set_device_name(deviceName.c_str());
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_set_device_name: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE;
|
||||
errRc = ::esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_set_security_param: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
};
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
}
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS); // Delay for 200 msecs as a workaround to an apparent Arduino environment issue.
|
||||
} // init
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the transmission power.
|
||||
* The power level can be one of:
|
||||
* * ESP_PWR_LVL_N14
|
||||
* * ESP_PWR_LVL_N11
|
||||
* * ESP_PWR_LVL_N8
|
||||
* * ESP_PWR_LVL_N5
|
||||
* * ESP_PWR_LVL_N2
|
||||
* * ESP_PWR_LVL_P1
|
||||
* * ESP_PWR_LVL_P4
|
||||
* * ESP_PWR_LVL_P7
|
||||
* @param [in] powerLevel.
|
||||
*/
|
||||
/* STATIC */ void BLEDevice::setPower(esp_power_level_t powerLevel) {
|
||||
ESP_LOGD(LOG_TAG, ">> setPower: %d", powerLevel);
|
||||
esp_err_t errRc = ::esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, powerLevel);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
};
|
||||
ESP_LOGD(LOG_TAG, "<< setPower");
|
||||
} // setPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of a characteristic of a service on a remote device.
|
||||
* @param [in] bdAddress
|
||||
* @param [in] serviceUUID
|
||||
* @param [in] characteristicUUID
|
||||
*/
|
||||
/* STATIC */ void BLEDevice::setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) {
|
||||
ESP_LOGD(LOG_TAG, ">> setValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
BLEClient* pClient = createClient();
|
||||
pClient->connect(bdAddress);
|
||||
pClient->setValue(serviceUUID, characteristicUUID, value);
|
||||
pClient->disconnect();
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the nature of this device.
|
||||
* @return A string representation of the nature of this device.
|
||||
*/
|
||||
/* STATIC */ std::string BLEDevice::toString() {
|
||||
std::ostringstream oss;
|
||||
oss << "BD Address: " << getAddress().toString();
|
||||
return oss.str();
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add an entry to the BLE white list.
|
||||
* @param [in] address The address to add to the white list.
|
||||
*/
|
||||
void BLEDevice::whiteListAdd(BLEAddress address) {
|
||||
ESP_LOGD(LOG_TAG, ">> whiteListAdd: %s", address.toString().c_str());
|
||||
esp_err_t errRc = esp_ble_gap_update_whitelist(true, *address.getNative()); // True to add an entry.
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< whiteListAdd");
|
||||
} // whiteListAdd
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove an entry from the BLE white list.
|
||||
* @param [in] address The address to remove from the white list.
|
||||
*/
|
||||
void BLEDevice::whiteListRemove(BLEAddress address) {
|
||||
ESP_LOGD(LOG_TAG, ">> whiteListRemove: %s", address.toString().c_str());
|
||||
esp_err_t errRc = esp_ble_gap_update_whitelist(false, *address.getNative()); // False to remove an entry.
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< whiteListRemove");
|
||||
} // whiteListRemove
|
||||
|
||||
/*
|
||||
* @brief Set encryption level that will be negotiated with peer device durng connection
|
||||
* @param [in] level Requested encryption level
|
||||
*/
|
||||
void BLEDevice::setEncryptionLevel(esp_ble_sec_act_t level) {
|
||||
BLEDevice::m_securityLevel = level;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Set callbacks that will be used to handle encryption negotiation events and authentication events
|
||||
* @param [in] cllbacks Pointer to BLESecurityCallbacks class callback
|
||||
*/
|
||||
void BLEDevice::setSecurityCallbacks(BLESecurityCallbacks* callbacks) {
|
||||
BLEDevice::m_securityCallbacks = callbacks;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Setup local mtu that will be used to negotiate mtu during request from client peer
|
||||
* @param [in] mtu Value to set local mtu, should be larger than 23 and lower or equal to 517
|
||||
*/
|
||||
esp_err_t BLEDevice::setMTU(uint16_t mtu) {
|
||||
ESP_LOGD(LOG_TAG, ">> setLocalMTU: %d", mtu);
|
||||
esp_err_t err = esp_ble_gatt_set_local_mtu(mtu);
|
||||
if (err == ESP_OK) {
|
||||
m_localMTU = mtu;
|
||||
} else {
|
||||
ESP_LOGE(LOG_TAG, "can't set local mtu value: %d", mtu);
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< setLocalMTU");
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Get local MTU value set during mtu request or default value
|
||||
*/
|
||||
uint16_t BLEDevice::getMTU() {
|
||||
return m_localMTU;
|
||||
}
|
||||
|
||||
bool BLEDevice::getInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
BLEAdvertising* BLEDevice::getAdvertising() {
|
||||
if(m_bleAdvertising == nullptr) {
|
||||
m_bleAdvertising = new BLEAdvertising();
|
||||
ESP_LOGI(LOG_TAG, "create advertising");
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "get advertising");
|
||||
return m_bleAdvertising;
|
||||
}
|
||||
|
||||
void BLEDevice::startAdvertising() {
|
||||
ESP_LOGD(LOG_TAG, ">> startAdvertising");
|
||||
getAdvertising()->start();
|
||||
ESP_LOGD(LOG_TAG, "<< startAdvertising");
|
||||
} // startAdvertising
|
||||
|
||||
/* multi connect support */
|
||||
/* requires a little more work */
|
||||
std::map<uint16_t, conn_status_t> BLEDevice::getPeerDevices(bool _client) {
|
||||
return m_connectedClientsMap;
|
||||
}
|
||||
|
||||
BLEClient* BLEDevice::getClientByGattIf(uint16_t conn_id) {
|
||||
return (BLEClient*)m_connectedClientsMap.find(conn_id)->second.peer_device;
|
||||
}
|
||||
|
||||
void BLEDevice::updatePeerDevice(void* peer, bool _client, uint16_t conn_id) {
|
||||
ESP_LOGD(LOG_TAG, "update conn_id: %d, GATT role: %s", conn_id, _client? "client":"server");
|
||||
std::map<uint16_t, conn_status_t>::iterator it = m_connectedClientsMap.find(ESP_GATT_IF_NONE);
|
||||
if (it != m_connectedClientsMap.end()) {
|
||||
std::swap(m_connectedClientsMap[conn_id], it->second);
|
||||
m_connectedClientsMap.erase(it);
|
||||
}else{
|
||||
it = m_connectedClientsMap.find(conn_id);
|
||||
if (it != m_connectedClientsMap.end()) {
|
||||
conn_status_t _st = it->second;
|
||||
_st.peer_device = peer;
|
||||
std::swap(m_connectedClientsMap[conn_id], _st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BLEDevice::addPeerDevice(void* peer, bool _client, uint16_t conn_id) {
|
||||
ESP_LOGI(LOG_TAG, "add conn_id: %d, GATT role: %s", conn_id, _client? "client":"server");
|
||||
conn_status_t status = {
|
||||
.peer_device = peer,
|
||||
.connected = true,
|
||||
.mtu = 23
|
||||
};
|
||||
|
||||
m_connectedClientsMap.insert(std::pair<uint16_t, conn_status_t>(conn_id, status));
|
||||
}
|
||||
|
||||
void BLEDevice::removePeerDevice(uint16_t conn_id, bool _client) {
|
||||
ESP_LOGI(LOG_TAG, "remove: %d, GATT role %s", conn_id, _client?"client":"server");
|
||||
if(m_connectedClientsMap.find(conn_id) != m_connectedClientsMap.end())
|
||||
m_connectedClientsMap.erase(conn_id);
|
||||
}
|
||||
|
||||
/* multi connect support */
|
||||
|
||||
/**
|
||||
* @brief de-Initialize the %BLE environment.
|
||||
* @param release_memory release the internal BT stack memory
|
||||
*/
|
||||
/* STATIC */ void BLEDevice::deinit(bool release_memory) {
|
||||
if (!initialized) return;
|
||||
|
||||
esp_bluedroid_disable();
|
||||
esp_bluedroid_deinit();
|
||||
esp_bt_controller_disable();
|
||||
esp_bt_controller_deinit();
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
if (release_memory) {
|
||||
esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); // <-- require tests because we released classic BT memory and this can cause crash (most likely not, esp-idf takes care of it)
|
||||
} else {
|
||||
initialized = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BLEDevice::setCustomGapHandler(gap_event_handler handler) {
|
||||
m_customGapHandler = handler;
|
||||
}
|
||||
|
||||
void BLEDevice::setCustomGattcHandler(gattc_event_handler handler) {
|
||||
m_customGattcHandler = handler;
|
||||
}
|
||||
|
||||
void BLEDevice::setCustomGattsHandler(gatts_event_handler handler) {
|
||||
m_customGattsHandler = handler;
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
99
libraries/ESP32_BLE_Arduino/src/BLEDevice.h
Normal file
99
libraries/ESP32_BLE_Arduino/src/BLEDevice.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* BLEDevice.h
|
||||
*
|
||||
* Created on: Mar 16, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef MAIN_BLEDevice_H_
|
||||
#define MAIN_BLEDevice_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_gap_ble_api.h> // ESP32 BLE
|
||||
#include <esp_gattc_api.h> // ESP32 BLE
|
||||
#include <map> // Part of C++ STL
|
||||
#include <string>
|
||||
#include <esp_bt.h>
|
||||
|
||||
#include "BLEServer.h"
|
||||
#include "BLEClient.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "BLEScan.h"
|
||||
#include "BLEAddress.h"
|
||||
|
||||
/**
|
||||
* @brief BLE functions.
|
||||
*/
|
||||
typedef void (*gap_event_handler)(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param);
|
||||
typedef void (*gattc_event_handler)(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* param);
|
||||
typedef void (*gatts_event_handler)(esp_gatts_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gatts_cb_param_t* param);
|
||||
|
||||
class BLEDevice {
|
||||
public:
|
||||
|
||||
static BLEClient* createClient(); // Create a new BLE client.
|
||||
static BLEServer* createServer(); // Cretae a new BLE server.
|
||||
static BLEAddress getAddress(); // Retrieve our own local BD address.
|
||||
static BLEScan* getScan(); // Get the scan object
|
||||
static std::string getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID); // Get the value of a characteristic of a service on a server.
|
||||
static void init(std::string deviceName); // Initialize the local BLE environment.
|
||||
static void setPower(esp_power_level_t powerLevel); // Set our power level.
|
||||
static void setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value); // Set the value of a characteristic on a service on a server.
|
||||
static std::string toString(); // Return a string representation of our device.
|
||||
static void whiteListAdd(BLEAddress address); // Add an entry to the BLE white list.
|
||||
static void whiteListRemove(BLEAddress address); // Remove an entry from the BLE white list.
|
||||
static void setEncryptionLevel(esp_ble_sec_act_t level);
|
||||
static void setSecurityCallbacks(BLESecurityCallbacks* pCallbacks);
|
||||
static esp_err_t setMTU(uint16_t mtu);
|
||||
static uint16_t getMTU();
|
||||
static bool getInitialized(); // Returns the state of the device, is it initialized or not?
|
||||
/* move advertising to BLEDevice for saving ram and flash in beacons */
|
||||
static BLEAdvertising* getAdvertising();
|
||||
static void startAdvertising();
|
||||
static uint16_t m_appId;
|
||||
/* multi connect */
|
||||
static std::map<uint16_t, conn_status_t> getPeerDevices(bool client);
|
||||
static void addPeerDevice(void* peer, bool is_client, uint16_t conn_id);
|
||||
static void updatePeerDevice(void* peer, bool _client, uint16_t conn_id);
|
||||
static void removePeerDevice(uint16_t conn_id, bool client);
|
||||
static BLEClient* getClientByGattIf(uint16_t conn_id);
|
||||
static void setCustomGapHandler(gap_event_handler handler);
|
||||
static void setCustomGattcHandler(gattc_event_handler handler);
|
||||
static void setCustomGattsHandler(gatts_event_handler handler);
|
||||
static void deinit(bool release_memory = false);
|
||||
static uint16_t m_localMTU;
|
||||
static esp_ble_sec_act_t m_securityLevel;
|
||||
|
||||
private:
|
||||
static BLEServer* m_pServer;
|
||||
static BLEScan* m_pScan;
|
||||
static BLEClient* m_pClient;
|
||||
static BLESecurityCallbacks* m_securityCallbacks;
|
||||
static BLEAdvertising* m_bleAdvertising;
|
||||
static esp_gatt_if_t getGattcIF();
|
||||
static std::map<uint16_t, conn_status_t> m_connectedClientsMap;
|
||||
|
||||
static void gattClientEventHandler(
|
||||
esp_gattc_cb_event_t event,
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* param);
|
||||
|
||||
static void gattServerEventHandler(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param);
|
||||
|
||||
static void gapEventHandler(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param);
|
||||
|
||||
public:
|
||||
/* custom gap and gatt handlers for flexibility */
|
||||
static gap_event_handler m_customGapHandler;
|
||||
static gattc_event_handler m_customGattcHandler;
|
||||
static gatts_event_handler m_customGattsHandler;
|
||||
|
||||
}; // class BLE
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* MAIN_BLEDevice_H_ */
|
||||
150
libraries/ESP32_BLE_Arduino/src/BLEEddystoneTLM.cpp
Normal file
150
libraries/ESP32_BLE_Arduino/src/BLEEddystoneTLM.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* BLEEddystoneTLM.cpp
|
||||
*
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
#include <esp_log.h>
|
||||
#include "BLEEddystoneTLM.h"
|
||||
|
||||
static const char LOG_TAG[] = "BLEEddystoneTLM";
|
||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
|
||||
#define ENDIAN_CHANGE_U32(x) ((((x)&0xFF000000)>>24) + (((x)&0x00FF0000)>>8)) + ((((x)&0xFF00)<<8) + (((x)&0xFF)<<24))
|
||||
|
||||
BLEEddystoneTLM::BLEEddystoneTLM() {
|
||||
beaconUUID = 0xFEAA;
|
||||
m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE;
|
||||
m_eddystoneData.version = 0;
|
||||
m_eddystoneData.volt = 3300; // 3300mV = 3.3V
|
||||
m_eddystoneData.temp = (uint16_t) ((float) 23.00);
|
||||
m_eddystoneData.advCount = 0;
|
||||
m_eddystoneData.tmil = 0;
|
||||
} // BLEEddystoneTLM
|
||||
|
||||
std::string BLEEddystoneTLM::getData() {
|
||||
return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData));
|
||||
} // getData
|
||||
|
||||
BLEUUID BLEEddystoneTLM::getUUID() {
|
||||
return BLEUUID(beaconUUID);
|
||||
} // getUUID
|
||||
|
||||
uint8_t BLEEddystoneTLM::getVersion() {
|
||||
return m_eddystoneData.version;
|
||||
} // getVersion
|
||||
|
||||
uint16_t BLEEddystoneTLM::getVolt() {
|
||||
return m_eddystoneData.volt;
|
||||
} // getVolt
|
||||
|
||||
float BLEEddystoneTLM::getTemp() {
|
||||
return (float)m_eddystoneData.temp;
|
||||
} // getTemp
|
||||
|
||||
uint32_t BLEEddystoneTLM::getCount() {
|
||||
return m_eddystoneData.advCount;
|
||||
} // getCount
|
||||
|
||||
uint32_t BLEEddystoneTLM::getTime() {
|
||||
return m_eddystoneData.tmil;
|
||||
} // getTime
|
||||
|
||||
std::string BLEEddystoneTLM::toString() {
|
||||
std::stringstream ss;
|
||||
std::string out = "";
|
||||
uint32_t rawsec;
|
||||
ss << "Version ";
|
||||
ss << std::dec << m_eddystoneData.version;
|
||||
ss << "\n";
|
||||
|
||||
ss << "Battery Voltage ";
|
||||
ss << std::dec << ENDIAN_CHANGE_U16(m_eddystoneData.volt);
|
||||
ss << " mV\n";
|
||||
|
||||
ss << "Temperature ";
|
||||
ss << (float) m_eddystoneData.temp;
|
||||
ss << " °C\n";
|
||||
|
||||
ss << "Adv. Count ";
|
||||
ss << std::dec << ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
|
||||
|
||||
ss << "\n";
|
||||
|
||||
ss << "Time ";
|
||||
|
||||
rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil);
|
||||
std::stringstream buffstream;
|
||||
buffstream << "0000";
|
||||
buffstream << std::dec << rawsec / 864000;
|
||||
std::string buff = buffstream.str();
|
||||
|
||||
ss << buff.substr(buff.length() - 4, buff.length());
|
||||
ss << ".";
|
||||
|
||||
buffstream.str("");
|
||||
buffstream.clear();
|
||||
buffstream << "00";
|
||||
buffstream << std::dec << (rawsec / 36000) % 24;
|
||||
buff = buffstream.str();
|
||||
ss << buff.substr(buff.length()-2, buff.length());
|
||||
ss << ":";
|
||||
|
||||
buffstream.str("");
|
||||
buffstream.clear();
|
||||
buffstream << "00";
|
||||
buffstream << std::dec << (rawsec / 600) % 60;
|
||||
buff = buffstream.str();
|
||||
ss << buff.substr(buff.length() - 2, buff.length());
|
||||
ss << ":";
|
||||
|
||||
buffstream.str("");
|
||||
buffstream.clear();
|
||||
buffstream << "00";
|
||||
buffstream << std::dec << (rawsec / 10) % 60;
|
||||
buff = buffstream.str();
|
||||
ss << buff.substr(buff.length() - 2, buff.length());
|
||||
ss << "\n";
|
||||
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
/**
|
||||
* Set the raw data for the beacon record.
|
||||
*/
|
||||
void BLEEddystoneTLM::setData(std::string data) {
|
||||
if (data.length() != sizeof(m_eddystoneData)) {
|
||||
ESP_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_eddystoneData));
|
||||
return;
|
||||
}
|
||||
memcpy(&m_eddystoneData, data.data(), data.length());
|
||||
} // setData
|
||||
|
||||
void BLEEddystoneTLM::setUUID(BLEUUID l_uuid) {
|
||||
beaconUUID = l_uuid.getNative()->uuid.uuid16;
|
||||
} // setUUID
|
||||
|
||||
void BLEEddystoneTLM::setVersion(uint8_t version) {
|
||||
m_eddystoneData.version = version;
|
||||
} // setVersion
|
||||
|
||||
void BLEEddystoneTLM::setVolt(uint16_t volt) {
|
||||
m_eddystoneData.volt = volt;
|
||||
} // setVolt
|
||||
|
||||
void BLEEddystoneTLM::setTemp(float temp) {
|
||||
m_eddystoneData.temp = (uint16_t)temp;
|
||||
} // setTemp
|
||||
|
||||
void BLEEddystoneTLM::setCount(uint32_t advCount) {
|
||||
m_eddystoneData.advCount = advCount;
|
||||
} // setCount
|
||||
|
||||
void BLEEddystoneTLM::setTime(uint32_t tmil) {
|
||||
m_eddystoneData.tmil = tmil;
|
||||
} // setTime
|
||||
|
||||
#endif
|
||||
51
libraries/ESP32_BLE_Arduino/src/BLEEddystoneTLM.h
Normal file
51
libraries/ESP32_BLE_Arduino/src/BLEEddystoneTLM.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* BLEEddystoneTLM.cpp
|
||||
*
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
*/
|
||||
|
||||
#ifndef _BLEEddystoneTLM_H_
|
||||
#define _BLEEddystoneTLM_H_
|
||||
#include "BLEUUID.h"
|
||||
|
||||
#define EDDYSTONE_TLM_FRAME_TYPE 0x20
|
||||
|
||||
/**
|
||||
* @brief Representation of a beacon.
|
||||
* See:
|
||||
* * https://github.com/google/eddystone
|
||||
*/
|
||||
class BLEEddystoneTLM {
|
||||
public:
|
||||
BLEEddystoneTLM();
|
||||
std::string getData();
|
||||
BLEUUID getUUID();
|
||||
uint8_t getVersion();
|
||||
uint16_t getVolt();
|
||||
float getTemp();
|
||||
uint32_t getCount();
|
||||
uint32_t getTime();
|
||||
std::string toString();
|
||||
void setData(std::string data);
|
||||
void setUUID(BLEUUID l_uuid);
|
||||
void setVersion(uint8_t version);
|
||||
void setVolt(uint16_t volt);
|
||||
void setTemp(float temp);
|
||||
void setCount(uint32_t advCount);
|
||||
void setTime(uint32_t tmil);
|
||||
|
||||
private:
|
||||
uint16_t beaconUUID;
|
||||
struct {
|
||||
uint8_t frameType;
|
||||
uint8_t version;
|
||||
uint16_t volt;
|
||||
uint16_t temp;
|
||||
uint32_t advCount;
|
||||
uint32_t tmil;
|
||||
} __attribute__((packed)) m_eddystoneData;
|
||||
|
||||
}; // BLEEddystoneTLM
|
||||
|
||||
#endif /* _BLEEddystoneTLM_H_ */
|
||||
148
libraries/ESP32_BLE_Arduino/src/BLEEddystoneURL.cpp
Normal file
148
libraries/ESP32_BLE_Arduino/src/BLEEddystoneURL.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* BLEEddystoneURL.cpp
|
||||
*
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include "BLEEddystoneURL.h"
|
||||
|
||||
static const char LOG_TAG[] = "BLEEddystoneURL";
|
||||
|
||||
BLEEddystoneURL::BLEEddystoneURL() {
|
||||
beaconUUID = 0xFEAA;
|
||||
lengthURL = 0;
|
||||
m_eddystoneData.frameType = EDDYSTONE_URL_FRAME_TYPE;
|
||||
m_eddystoneData.advertisedTxPower = 0;
|
||||
memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url));
|
||||
} // BLEEddystoneURL
|
||||
|
||||
std::string BLEEddystoneURL::getData() {
|
||||
return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData));
|
||||
} // getData
|
||||
|
||||
BLEUUID BLEEddystoneURL::getUUID() {
|
||||
return BLEUUID(beaconUUID);
|
||||
} // getUUID
|
||||
|
||||
int8_t BLEEddystoneURL::getPower() {
|
||||
return m_eddystoneData.advertisedTxPower;
|
||||
} // getPower
|
||||
|
||||
std::string BLEEddystoneURL::getURL() {
|
||||
return std::string((char*) &m_eddystoneData.url, sizeof(m_eddystoneData.url));
|
||||
} // getURL
|
||||
|
||||
std::string BLEEddystoneURL::getDecodedURL() {
|
||||
std::string decodedURL = "";
|
||||
|
||||
switch (m_eddystoneData.url[0]) {
|
||||
case 0x00:
|
||||
decodedURL += "http://www.";
|
||||
break;
|
||||
case 0x01:
|
||||
decodedURL += "https://www.";
|
||||
break;
|
||||
case 0x02:
|
||||
decodedURL += "http://";
|
||||
break;
|
||||
case 0x03:
|
||||
decodedURL += "https://";
|
||||
break;
|
||||
default:
|
||||
decodedURL += m_eddystoneData.url[0];
|
||||
}
|
||||
|
||||
for (int i = 1; i < lengthURL; i++) {
|
||||
if (m_eddystoneData.url[i] > 33 && m_eddystoneData.url[i] < 127) {
|
||||
decodedURL += m_eddystoneData.url[i];
|
||||
} else {
|
||||
switch (m_eddystoneData.url[i]) {
|
||||
case 0x00:
|
||||
decodedURL += ".com/";
|
||||
break;
|
||||
case 0x01:
|
||||
decodedURL += ".org/";
|
||||
break;
|
||||
case 0x02:
|
||||
decodedURL += ".edu/";
|
||||
break;
|
||||
case 0x03:
|
||||
decodedURL += ".net/";
|
||||
break;
|
||||
case 0x04:
|
||||
decodedURL += ".info/";
|
||||
break;
|
||||
case 0x05:
|
||||
decodedURL += ".biz/";
|
||||
break;
|
||||
case 0x06:
|
||||
decodedURL += ".gov/";
|
||||
break;
|
||||
case 0x07:
|
||||
decodedURL += ".com";
|
||||
break;
|
||||
case 0x08:
|
||||
decodedURL += ".org";
|
||||
break;
|
||||
case 0x09:
|
||||
decodedURL += ".edu";
|
||||
break;
|
||||
case 0x0A:
|
||||
decodedURL += ".net";
|
||||
break;
|
||||
case 0x0B:
|
||||
decodedURL += ".info";
|
||||
break;
|
||||
case 0x0C:
|
||||
decodedURL += ".biz";
|
||||
break;
|
||||
case 0x0D:
|
||||
decodedURL += ".gov";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return decodedURL;
|
||||
} // getDecodedURL
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the raw data for the beacon record.
|
||||
*/
|
||||
void BLEEddystoneURL::setData(std::string data) {
|
||||
if (data.length() > sizeof(m_eddystoneData)) {
|
||||
ESP_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and max expected %d", data.length(), sizeof(m_eddystoneData));
|
||||
return;
|
||||
}
|
||||
memset(&m_eddystoneData, 0, sizeof(m_eddystoneData));
|
||||
memcpy(&m_eddystoneData, data.data(), data.length());
|
||||
lengthURL = data.length() - (sizeof(m_eddystoneData) - sizeof(m_eddystoneData.url));
|
||||
} // setData
|
||||
|
||||
void BLEEddystoneURL::setUUID(BLEUUID l_uuid) {
|
||||
beaconUUID = l_uuid.getNative()->uuid.uuid16;
|
||||
} // setUUID
|
||||
|
||||
void BLEEddystoneURL::setPower(int8_t advertisedTxPower) {
|
||||
m_eddystoneData.advertisedTxPower = advertisedTxPower;
|
||||
} // setPower
|
||||
|
||||
void BLEEddystoneURL::setURL(std::string url) {
|
||||
if (url.length() > sizeof(m_eddystoneData.url)) {
|
||||
ESP_LOGE(LOG_TAG, "Unable to set the url ... length passed in was %d and max expected %d", url.length(), sizeof(m_eddystoneData.url));
|
||||
return;
|
||||
}
|
||||
memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url));
|
||||
memcpy(m_eddystoneData.url, url.data(), url.length());
|
||||
lengthURL = url.length();
|
||||
} // setURL
|
||||
|
||||
|
||||
#endif
|
||||
43
libraries/ESP32_BLE_Arduino/src/BLEEddystoneURL.h
Normal file
43
libraries/ESP32_BLE_Arduino/src/BLEEddystoneURL.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* BLEEddystoneURL.cpp
|
||||
*
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
*/
|
||||
|
||||
#ifndef _BLEEddystoneURL_H_
|
||||
#define _BLEEddystoneURL_H_
|
||||
#include "BLEUUID.h"
|
||||
|
||||
#define EDDYSTONE_URL_FRAME_TYPE 0x10
|
||||
|
||||
/**
|
||||
* @brief Representation of a beacon.
|
||||
* See:
|
||||
* * https://github.com/google/eddystone
|
||||
*/
|
||||
class BLEEddystoneURL {
|
||||
public:
|
||||
BLEEddystoneURL();
|
||||
std::string getData();
|
||||
BLEUUID getUUID();
|
||||
int8_t getPower();
|
||||
std::string getURL();
|
||||
std::string getDecodedURL();
|
||||
void setData(std::string data);
|
||||
void setUUID(BLEUUID l_uuid);
|
||||
void setPower(int8_t advertisedTxPower);
|
||||
void setURL(std::string url);
|
||||
|
||||
private:
|
||||
uint16_t beaconUUID;
|
||||
uint8_t lengthURL;
|
||||
struct {
|
||||
uint8_t frameType;
|
||||
int8_t advertisedTxPower;
|
||||
uint8_t url[16];
|
||||
} __attribute__((packed)) m_eddystoneData;
|
||||
|
||||
}; // BLEEddystoneURL
|
||||
|
||||
#endif /* _BLEEddystoneURL_H_ */
|
||||
9
libraries/ESP32_BLE_Arduino/src/BLEExceptions.cpp
Normal file
9
libraries/ESP32_BLE_Arduino/src/BLEExceptions.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* BLExceptions.cpp
|
||||
*
|
||||
* Created on: Nov 27, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "BLEExceptions.h"
|
||||
|
||||
31
libraries/ESP32_BLE_Arduino/src/BLEExceptions.h
Normal file
31
libraries/ESP32_BLE_Arduino/src/BLEExceptions.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* BLExceptions.h
|
||||
*
|
||||
* Created on: Nov 27, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_CXX_EXCEPTIONS != 1
|
||||
#error "C++ exception handling must be enabled within make menuconfig. See Compiler Options > Enable C++ Exceptions."
|
||||
#endif
|
||||
|
||||
#include <exception>
|
||||
|
||||
|
||||
class BLEDisconnectedException : public std::exception {
|
||||
const char* what() const throw () {
|
||||
return "BLE Disconnected";
|
||||
}
|
||||
};
|
||||
|
||||
class BLEUuidNotFoundException : public std::exception {
|
||||
const char* what() const throw () {
|
||||
return "No such UUID";
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_ */
|
||||
243
libraries/ESP32_BLE_Arduino/src/BLEHIDDevice.cpp
Normal file
243
libraries/ESP32_BLE_Arduino/src/BLEHIDDevice.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* BLEHIDDevice.cpp
|
||||
*
|
||||
* Created on: Jan 03, 2018
|
||||
* Author: chegewara
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLEHIDDevice.h"
|
||||
#include "BLE2904.h"
|
||||
|
||||
|
||||
BLEHIDDevice::BLEHIDDevice(BLEServer* server) {
|
||||
/*
|
||||
* Here we create mandatory services described in bluetooth specification
|
||||
*/
|
||||
m_deviceInfoService = server->createService(BLEUUID((uint16_t) 0x180a));
|
||||
m_hidService = server->createService(BLEUUID((uint16_t) 0x1812), 40);
|
||||
m_batteryService = server->createService(BLEUUID((uint16_t) 0x180f));
|
||||
|
||||
/*
|
||||
* Mandatory characteristic for device info service
|
||||
*/
|
||||
m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a50, BLECharacteristic::PROPERTY_READ);
|
||||
|
||||
/*
|
||||
* Mandatory characteristics for HID service
|
||||
*/
|
||||
m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4a, BLECharacteristic::PROPERTY_READ);
|
||||
m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4b, BLECharacteristic::PROPERTY_READ);
|
||||
m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4c, BLECharacteristic::PROPERTY_WRITE_NR);
|
||||
m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4e, BLECharacteristic::PROPERTY_WRITE_NR | BLECharacteristic::PROPERTY_READ);
|
||||
|
||||
/*
|
||||
* Mandatory battery level characteristic with notification and presence descriptor
|
||||
*/
|
||||
BLE2904* batteryLevelDescriptor = new BLE2904();
|
||||
batteryLevelDescriptor->setFormat(BLE2904::FORMAT_UINT8);
|
||||
batteryLevelDescriptor->setNamespace(1);
|
||||
batteryLevelDescriptor->setUnit(0x27ad);
|
||||
|
||||
m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
|
||||
m_batteryLevelCharacteristic->addDescriptor(batteryLevelDescriptor);
|
||||
m_batteryLevelCharacteristic->addDescriptor(new BLE2902());
|
||||
|
||||
/*
|
||||
* This value is setup here because its default value in most usage cases, its very rare to use boot mode
|
||||
* and we want to simplify library using as much as possible
|
||||
*/
|
||||
const uint8_t pMode[] = { 0x01 };
|
||||
protocolMode()->setValue((uint8_t*) pMode, 1);
|
||||
}
|
||||
|
||||
BLEHIDDevice::~BLEHIDDevice() {
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void BLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
|
||||
m_reportMapCharacteristic->setValue(map, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief This function suppose to be called at the end, when we have created all characteristics we need to build HID service
|
||||
*/
|
||||
void BLEHIDDevice::startServices() {
|
||||
m_deviceInfoService->start();
|
||||
m_hidService->start();
|
||||
m_batteryService->start();
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create manufacturer characteristic (this characteristic is optional)
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::manufacturer() {
|
||||
m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, BLECharacteristic::PROPERTY_READ);
|
||||
return m_manufacturerCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Set manufacturer name
|
||||
* @param [in] name manufacturer name
|
||||
*/
|
||||
void BLEHIDDevice::manufacturer(std::string name) {
|
||||
m_manufacturerCharacteristic->setValue(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void BLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
|
||||
uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
|
||||
m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void BLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
|
||||
uint8_t info[] = { 0x11, 0x1, country, flags };
|
||||
m_hidInfoCharacteristic->setValue(info, sizeof(info));
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create input report characteristic that need to be saved as new characteristic object so can be further used
|
||||
* @param [in] reportID input report ID, the same as in report map for input object related to created characteristic
|
||||
* @return pointer to new input report characteristic
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::inputReport(uint8_t reportID) {
|
||||
BLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
|
||||
BLEDescriptor* inputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908));
|
||||
BLE2902* p2902 = new BLE2902();
|
||||
inputReportCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
|
||||
inputReportDescriptor->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
|
||||
p2902->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x01 };
|
||||
inputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
inputReportCharacteristic->addDescriptor(p2902);
|
||||
inputReportCharacteristic->addDescriptor(inputReportDescriptor);
|
||||
|
||||
return inputReportCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create output report characteristic that need to be saved as new characteristic object so can be further used
|
||||
* @param [in] reportID Output report ID, the same as in report map for output object related to created characteristic
|
||||
* @return Pointer to new output report characteristic
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::outputReport(uint8_t reportID) {
|
||||
BLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
|
||||
BLEDescriptor* outputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908));
|
||||
outputReportCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
|
||||
outputReportDescriptor->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x02 };
|
||||
outputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
outputReportCharacteristic->addDescriptor(outputReportDescriptor);
|
||||
|
||||
return outputReportCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create feature report characteristic that need to be saved as new characteristic object so can be further used
|
||||
* @param [in] reportID Feature report ID, the same as in report map for feature object related to created characteristic
|
||||
* @return Pointer to new feature report characteristic
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::featureReport(uint8_t reportID) {
|
||||
BLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);
|
||||
BLEDescriptor* featureReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908));
|
||||
|
||||
featureReportCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
|
||||
featureReportDescriptor->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
|
||||
|
||||
uint8_t desc1_val[] = { reportID, 0x03 };
|
||||
featureReportDescriptor->setValue((uint8_t*) desc1_val, 2);
|
||||
featureReportCharacteristic->addDescriptor(featureReportDescriptor);
|
||||
|
||||
return featureReportCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::bootInput() {
|
||||
BLECharacteristic* bootInputCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a22, BLECharacteristic::PROPERTY_NOTIFY);
|
||||
bootInputCharacteristic->addDescriptor(new BLE2902());
|
||||
|
||||
return bootInputCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::bootOutput() {
|
||||
return m_hidService->createCharacteristic((uint16_t) 0x2a32, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::hidControl() {
|
||||
return m_hidControlCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::protocolMode() {
|
||||
return m_protocolModeCharacteristic;
|
||||
}
|
||||
|
||||
void BLEHIDDevice::setBatteryLevel(uint8_t level) {
|
||||
m_batteryLevelCharacteristic->setValue(&level, 1);
|
||||
}
|
||||
/*
|
||||
* @brief Returns battery level characteristic
|
||||
* @ return battery level characteristic
|
||||
*//*
|
||||
BLECharacteristic* BLEHIDDevice::batteryLevel() {
|
||||
return m_batteryLevelCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::reportMap() {
|
||||
return m_reportMapCharacteristic;
|
||||
}
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::pnp() {
|
||||
return m_pnpCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::hidInfo() {
|
||||
return m_hidInfoCharacteristic;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLEService* BLEHIDDevice::deviceInfo() {
|
||||
return m_deviceInfoService;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLEService* BLEHIDDevice::hidService() {
|
||||
return m_hidService;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLEService* BLEHIDDevice::batteryService() {
|
||||
return m_batteryService;
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
|
||||
75
libraries/ESP32_BLE_Arduino/src/BLEHIDDevice.h
Normal file
75
libraries/ESP32_BLE_Arduino/src/BLEHIDDevice.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* BLEHIDDevice.h
|
||||
*
|
||||
* Created on: Jan 03, 2018
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#ifndef _BLEHIDDEVICE_H_
|
||||
#define _BLEHIDDEVICE_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLECharacteristic.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLEDescriptor.h"
|
||||
#include "BLE2902.h"
|
||||
#include "HIDTypes.h"
|
||||
|
||||
#define GENERIC_HID 0x03C0
|
||||
#define HID_KEYBOARD 0x03C1
|
||||
#define HID_MOUSE 0x03C2
|
||||
#define HID_JOYSTICK 0x03C3
|
||||
#define HID_GAMEPAD 0x03C4
|
||||
#define HID_TABLET 0x03C5
|
||||
#define HID_CARD_READER 0x03C6
|
||||
#define HID_DIGITAL_PEN 0x03C7
|
||||
#define HID_BARCODE 0x03C8
|
||||
|
||||
class BLEHIDDevice {
|
||||
public:
|
||||
BLEHIDDevice(BLEServer*);
|
||||
virtual ~BLEHIDDevice();
|
||||
|
||||
void reportMap(uint8_t* map, uint16_t);
|
||||
void startServices();
|
||||
|
||||
BLEService* deviceInfo();
|
||||
BLEService* hidService();
|
||||
BLEService* batteryService();
|
||||
|
||||
BLECharacteristic* manufacturer();
|
||||
void manufacturer(std::string name);
|
||||
//BLECharacteristic* pnp();
|
||||
void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version);
|
||||
//BLECharacteristic* hidInfo();
|
||||
void hidInfo(uint8_t country, uint8_t flags);
|
||||
//BLECharacteristic* batteryLevel();
|
||||
void setBatteryLevel(uint8_t level);
|
||||
|
||||
|
||||
//BLECharacteristic* reportMap();
|
||||
BLECharacteristic* hidControl();
|
||||
BLECharacteristic* inputReport(uint8_t reportID);
|
||||
BLECharacteristic* outputReport(uint8_t reportID);
|
||||
BLECharacteristic* featureReport(uint8_t reportID);
|
||||
BLECharacteristic* protocolMode();
|
||||
BLECharacteristic* bootInput();
|
||||
BLECharacteristic* bootOutput();
|
||||
|
||||
private:
|
||||
BLEService* m_deviceInfoService; //0x180a
|
||||
BLEService* m_hidService; //0x1812
|
||||
BLEService* m_batteryService = 0; //0x180f
|
||||
|
||||
BLECharacteristic* m_manufacturerCharacteristic; //0x2a29
|
||||
BLECharacteristic* m_pnpCharacteristic; //0x2a50
|
||||
BLECharacteristic* m_hidInfoCharacteristic; //0x2a4a
|
||||
BLECharacteristic* m_reportMapCharacteristic; //0x2a4b
|
||||
BLECharacteristic* m_hidControlCharacteristic; //0x2a4c
|
||||
BLECharacteristic* m_protocolModeCharacteristic; //0x2a4e
|
||||
BLECharacteristic* m_batteryLevelCharacteristic; //0x2a19
|
||||
};
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* _BLEHIDDEVICE_H_ */
|
||||
588
libraries/ESP32_BLE_Arduino/src/BLERemoteCharacteristic.cpp
Normal file
588
libraries/ESP32_BLE_Arduino/src/BLERemoteCharacteristic.cpp
Normal file
@@ -0,0 +1,588 @@
|
||||
/*
|
||||
* BLERemoteCharacteristic.cpp
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "BLERemoteCharacteristic.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <esp_gattc_api.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
#include <sstream>
|
||||
#include "BLEExceptions.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include "BLERemoteDescriptor.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLERemoteCharacteristic"; // The logging tag for this class.
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* @param [in] handle The BLE server side handle of this characteristic.
|
||||
* @param [in] uuid The UUID of this characteristic.
|
||||
* @param [in] charProp The properties of this characteristic.
|
||||
* @param [in] pRemoteService A reference to the remote service to which this remote characteristic pertains.
|
||||
*/
|
||||
BLERemoteCharacteristic::BLERemoteCharacteristic(
|
||||
uint16_t handle,
|
||||
BLEUUID uuid,
|
||||
esp_gatt_char_prop_t charProp,
|
||||
BLERemoteService* pRemoteService) {
|
||||
ESP_LOGD(LOG_TAG, ">> BLERemoteCharacteristic: handle: %d 0x%d, uuid: %s", handle, handle, uuid.toString().c_str());
|
||||
m_handle = handle;
|
||||
m_uuid = uuid;
|
||||
m_charProp = charProp;
|
||||
m_pRemoteService = pRemoteService;
|
||||
m_notifyCallback = nullptr;
|
||||
|
||||
retrieveDescriptors(); // Get the descriptors for this characteristic
|
||||
ESP_LOGD(LOG_TAG, "<< BLERemoteCharacteristic");
|
||||
} // BLERemoteCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
*@brief Destructor.
|
||||
*/
|
||||
BLERemoteCharacteristic::~BLERemoteCharacteristic() {
|
||||
removeDescriptors(); // Release resources for any descriptor information we may have allocated.
|
||||
} // ~BLERemoteCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support broadcasting?
|
||||
* @return True if the characteristic supports broadcasting.
|
||||
*/
|
||||
bool BLERemoteCharacteristic::canBroadcast() {
|
||||
return (m_charProp & ESP_GATT_CHAR_PROP_BIT_BROADCAST) != 0;
|
||||
} // canBroadcast
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support indications?
|
||||
* @return True if the characteristic supports indications.
|
||||
*/
|
||||
bool BLERemoteCharacteristic::canIndicate() {
|
||||
return (m_charProp & ESP_GATT_CHAR_PROP_BIT_INDICATE) != 0;
|
||||
} // canIndicate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support notifications?
|
||||
* @return True if the characteristic supports notifications.
|
||||
*/
|
||||
bool BLERemoteCharacteristic::canNotify() {
|
||||
return (m_charProp & ESP_GATT_CHAR_PROP_BIT_NOTIFY) != 0;
|
||||
} // canNotify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support reading?
|
||||
* @return True if the characteristic supports reading.
|
||||
*/
|
||||
bool BLERemoteCharacteristic::canRead() {
|
||||
return (m_charProp & ESP_GATT_CHAR_PROP_BIT_READ) != 0;
|
||||
} // canRead
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support writing?
|
||||
* @return True if the characteristic supports writing.
|
||||
*/
|
||||
bool BLERemoteCharacteristic::canWrite() {
|
||||
return (m_charProp & ESP_GATT_CHAR_PROP_BIT_WRITE) != 0;
|
||||
} // canWrite
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the characteristic support writing with no response?
|
||||
* @return True if the characteristic supports writing with no response.
|
||||
*/
|
||||
bool BLERemoteCharacteristic::canWriteNoResponse() {
|
||||
return (m_charProp & ESP_GATT_CHAR_PROP_BIT_WRITE_NR) != 0;
|
||||
} // canWriteNoResponse
|
||||
|
||||
|
||||
/*
|
||||
static bool compareSrvcId(esp_gatt_srvc_id_t id1, esp_gatt_srvc_id_t id2) {
|
||||
if (id1.id.inst_id != id2.id.inst_id) {
|
||||
return false;
|
||||
}
|
||||
if (!BLEUUID(id1.id.uuid).equals(BLEUUID(id2.id.uuid))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // compareSrvcId
|
||||
*/
|
||||
|
||||
/*
|
||||
static bool compareGattId(esp_gatt_id_t id1, esp_gatt_id_t id2) {
|
||||
if (id1.inst_id != id2.inst_id) {
|
||||
return false;
|
||||
}
|
||||
if (!BLEUUID(id1.uuid).equals(BLEUUID(id2.uuid))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // compareCharId
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle GATT Client events.
|
||||
* When an event arrives for a GATT client we give this characteristic the opportunity to
|
||||
* take a look at it to see if there is interest in it.
|
||||
* @param [in] event The type of event.
|
||||
* @param [in] gattc_if The interface on which the event was received.
|
||||
* @param [in] evtParam Payload data for the event.
|
||||
* @returns N/A
|
||||
*/
|
||||
void BLERemoteCharacteristic::gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam) {
|
||||
switch(event) {
|
||||
// ESP_GATTC_NOTIFY_EVT
|
||||
//
|
||||
// notify
|
||||
// - uint16_t conn_id - The connection identifier of the server.
|
||||
// - esp_bd_addr_t remote_bda - The device address of the BLE server.
|
||||
// - uint16_t handle - The handle of the characteristic for which the event is being received.
|
||||
// - uint16_t value_len - The length of the received data.
|
||||
// - uint8_t* value - The received data.
|
||||
// - bool is_notify - True if this is a notify, false if it is an indicate.
|
||||
//
|
||||
// We have received a notification event which means that the server wishes us to know about a notification
|
||||
// piece of data. What we must now do is find the characteristic with the associated handle and then
|
||||
// invoke its notification callback (if it has one).
|
||||
case ESP_GATTC_NOTIFY_EVT: {
|
||||
if (evtParam->notify.handle != getHandle()) break;
|
||||
if (m_notifyCallback != nullptr) {
|
||||
ESP_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", toString().c_str());
|
||||
m_notifyCallback(this, evtParam->notify.value, evtParam->notify.value_len, evtParam->notify.is_notify);
|
||||
} // End we have a callback function ...
|
||||
break;
|
||||
} // ESP_GATTC_NOTIFY_EVT
|
||||
|
||||
// ESP_GATTC_READ_CHAR_EVT
|
||||
// This event indicates that the server has responded to the read request.
|
||||
//
|
||||
// read:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t conn_id
|
||||
// - uint16_t handle
|
||||
// - uint8_t* value
|
||||
// - uint16_t value_len
|
||||
case ESP_GATTC_READ_CHAR_EVT: {
|
||||
// If this event is not for us, then nothing further to do.
|
||||
if (evtParam->read.handle != getHandle()) break;
|
||||
|
||||
// At this point, we have determined that the event is for us, so now we save the value
|
||||
// and unlock the semaphore to ensure that the requestor of the data can continue.
|
||||
if (evtParam->read.status == ESP_GATT_OK) {
|
||||
m_value = std::string((char*) evtParam->read.value, evtParam->read.value_len);
|
||||
if(m_rawData != nullptr) free(m_rawData);
|
||||
m_rawData = (uint8_t*) calloc(evtParam->read.value_len, sizeof(uint8_t));
|
||||
memcpy(m_rawData, evtParam->read.value, evtParam->read.value_len);
|
||||
} else {
|
||||
m_value = "";
|
||||
}
|
||||
|
||||
m_semaphoreReadCharEvt.give();
|
||||
break;
|
||||
} // ESP_GATTC_READ_CHAR_EVT
|
||||
|
||||
// ESP_GATTC_REG_FOR_NOTIFY_EVT
|
||||
//
|
||||
// reg_for_notify:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t handle
|
||||
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
|
||||
// If the request is not for this BLERemoteCharacteristic then move on to the next.
|
||||
if (evtParam->reg_for_notify.handle != getHandle()) break;
|
||||
|
||||
// We have processed the notify registration and can unlock the semaphore.
|
||||
m_semaphoreRegForNotifyEvt.give();
|
||||
break;
|
||||
} // ESP_GATTC_REG_FOR_NOTIFY_EVT
|
||||
|
||||
// ESP_GATTC_UNREG_FOR_NOTIFY_EVT
|
||||
//
|
||||
// unreg_for_notify:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t handle
|
||||
case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: {
|
||||
if (evtParam->unreg_for_notify.handle != getHandle()) break;
|
||||
// We have processed the notify un-registration and can unlock the semaphore.
|
||||
m_semaphoreRegForNotifyEvt.give();
|
||||
break;
|
||||
} // ESP_GATTC_UNREG_FOR_NOTIFY_EVT:
|
||||
|
||||
// ESP_GATTC_WRITE_CHAR_EVT
|
||||
//
|
||||
// write:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t conn_id
|
||||
// - uint16_t handle
|
||||
case ESP_GATTC_WRITE_CHAR_EVT: {
|
||||
// Determine if this event is for us and, if not, pass onwards.
|
||||
if (evtParam->write.handle != getHandle()) break;
|
||||
|
||||
// There is nothing further we need to do here. This is merely an indication
|
||||
// that the write has completed and we can unlock the caller.
|
||||
m_semaphoreWriteCharEvt.give();
|
||||
break;
|
||||
} // ESP_GATTC_WRITE_CHAR_EVT
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
} // End switch
|
||||
}; // gattClientEventHandler
|
||||
|
||||
|
||||
/**
|
||||
* @brief Populate the descriptors (if any) for this characteristic.
|
||||
*/
|
||||
void BLERemoteCharacteristic::retrieveDescriptors() {
|
||||
ESP_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str());
|
||||
|
||||
removeDescriptors(); // Remove any existing descriptors.
|
||||
|
||||
// Loop over each of the descriptors within the service associated with this characteristic.
|
||||
// For each descriptor we find, create a BLERemoteDescriptor instance.
|
||||
uint16_t offset = 0;
|
||||
esp_gattc_descr_elem_t result;
|
||||
while(true) {
|
||||
uint16_t count = 10;
|
||||
esp_gatt_status_t status = ::esp_ble_gattc_get_all_descr(
|
||||
getRemoteService()->getClient()->getGattcIf(),
|
||||
getRemoteService()->getClient()->getConnId(),
|
||||
getHandle(),
|
||||
&result,
|
||||
&count,
|
||||
offset
|
||||
);
|
||||
|
||||
if (status == ESP_GATT_INVALID_OFFSET) { // We have reached the end of the entries.
|
||||
break;
|
||||
}
|
||||
|
||||
if (status != ESP_GATT_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_all_descr: %s", BLEUtils::gattStatusToString(status).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
if (count == 0) break;
|
||||
|
||||
ESP_LOGD(LOG_TAG, "Found a descriptor: Handle: %d, UUID: %s", result.handle, BLEUUID(result.uuid).toString().c_str());
|
||||
|
||||
// We now have a new characteristic ... let us add that to our set of known characteristics
|
||||
BLERemoteDescriptor* pNewRemoteDescriptor = new BLERemoteDescriptor(
|
||||
result.handle,
|
||||
BLEUUID(result.uuid),
|
||||
this
|
||||
);
|
||||
|
||||
m_descriptorMap.insert(std::pair<std::string, BLERemoteDescriptor*>(pNewRemoteDescriptor->getUUID().toString(), pNewRemoteDescriptor));
|
||||
|
||||
offset++;
|
||||
} // while true
|
||||
//m_haveCharacteristics = true; // Remember that we have received the characteristics.
|
||||
ESP_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", offset);
|
||||
} // getDescriptors
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the map of descriptors keyed by UUID.
|
||||
*/
|
||||
std::map<std::string, BLERemoteDescriptor*>* BLERemoteCharacteristic::getDescriptors() {
|
||||
return &m_descriptorMap;
|
||||
} // getDescriptors
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the handle for this characteristic.
|
||||
* @return The handle for this characteristic.
|
||||
*/
|
||||
uint16_t BLERemoteCharacteristic::getHandle() {
|
||||
//ESP_LOGD(LOG_TAG, ">> getHandle: Characteristic: %s", getUUID().toString().c_str());
|
||||
//ESP_LOGD(LOG_TAG, "<< getHandle: %d 0x%.2x", m_handle, m_handle);
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the descriptor instance with the given UUID that belongs to this characteristic.
|
||||
* @param [in] uuid The UUID of the descriptor to find.
|
||||
* @return The Remote descriptor (if present) or null if not present.
|
||||
*/
|
||||
BLERemoteDescriptor* BLERemoteCharacteristic::getDescriptor(BLEUUID uuid) {
|
||||
ESP_LOGD(LOG_TAG, ">> getDescriptor: uuid: %s", uuid.toString().c_str());
|
||||
std::string v = uuid.toString();
|
||||
for (auto &myPair : m_descriptorMap) {
|
||||
if (myPair.first == v) {
|
||||
ESP_LOGD(LOG_TAG, "<< getDescriptor: found");
|
||||
return myPair.second;
|
||||
}
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< getDescriptor: Not found");
|
||||
return nullptr;
|
||||
} // getDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the remote service associated with this characteristic.
|
||||
* @return The remote service associated with this characteristic.
|
||||
*/
|
||||
BLERemoteService* BLERemoteCharacteristic::getRemoteService() {
|
||||
return m_pRemoteService;
|
||||
} // getRemoteService
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID for this characteristic.
|
||||
* @return The UUID for this characteristic.
|
||||
*/
|
||||
BLEUUID BLERemoteCharacteristic::getUUID() {
|
||||
return m_uuid;
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read an unsigned 16 bit value
|
||||
* @return The unsigned 16 bit value.
|
||||
*/
|
||||
uint16_t BLERemoteCharacteristic::readUInt16() {
|
||||
std::string value = readValue();
|
||||
if (value.length() >= 2) {
|
||||
return *(uint16_t*)(value.data());
|
||||
}
|
||||
return 0;
|
||||
} // readUInt16
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read an unsigned 32 bit value.
|
||||
* @return the unsigned 32 bit value.
|
||||
*/
|
||||
uint32_t BLERemoteCharacteristic::readUInt32() {
|
||||
std::string value = readValue();
|
||||
if (value.length() >= 4) {
|
||||
return *(uint32_t*)(value.data());
|
||||
}
|
||||
return 0;
|
||||
} // readUInt32
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read a byte value
|
||||
* @return The value as a byte
|
||||
*/
|
||||
uint8_t BLERemoteCharacteristic::readUInt8() {
|
||||
std::string value = readValue();
|
||||
if (value.length() >= 1) {
|
||||
return (uint8_t)value[0];
|
||||
}
|
||||
return 0;
|
||||
} // readUInt8
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read the value of the remote characteristic.
|
||||
* @return The value of the remote characteristic.
|
||||
*/
|
||||
std::string BLERemoteCharacteristic::readValue() {
|
||||
ESP_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x", getUUID().toString().c_str(), getHandle(), getHandle());
|
||||
|
||||
// Check to see that we are connected.
|
||||
if (!getRemoteService()->getClient()->isConnected()) {
|
||||
ESP_LOGE(LOG_TAG, "Disconnected");
|
||||
throw BLEDisconnectedException();
|
||||
}
|
||||
|
||||
m_semaphoreReadCharEvt.take("readValue");
|
||||
|
||||
// Ask the BLE subsystem to retrieve the value for the remote hosted characteristic.
|
||||
// This is an asynchronous request which means that we must block waiting for the response
|
||||
// to become available.
|
||||
esp_err_t errRc = ::esp_ble_gattc_read_char(
|
||||
m_pRemoteService->getClient()->getGattcIf(),
|
||||
m_pRemoteService->getClient()->getConnId(), // The connection ID to the BLE server
|
||||
getHandle(), // The handle of this characteristic
|
||||
ESP_GATT_AUTH_REQ_NONE); // Security
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return "";
|
||||
}
|
||||
|
||||
// Block waiting for the event that indicates that the read has completed. When it has, the std::string found
|
||||
// in m_value will contain our data.
|
||||
m_semaphoreReadCharEvt.wait("readValue");
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< readValue(): length: %d", m_value.length());
|
||||
return m_value;
|
||||
} // readValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register for notifications.
|
||||
* @param [in] notifyCallback A callback to be invoked for a notification. If NULL is provided then we are
|
||||
* unregistering a notification.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback, bool notifications) {
|
||||
ESP_LOGD(LOG_TAG, ">> registerForNotify(): %s", toString().c_str());
|
||||
|
||||
m_notifyCallback = notifyCallback; // Save the notification callback.
|
||||
|
||||
m_semaphoreRegForNotifyEvt.take("registerForNotify");
|
||||
|
||||
if (notifyCallback != nullptr) { // If we have a callback function, then this is a registration.
|
||||
esp_err_t errRc = ::esp_ble_gattc_register_for_notify(
|
||||
m_pRemoteService->getClient()->getGattcIf(),
|
||||
*m_pRemoteService->getClient()->getPeerAddress().getNative(),
|
||||
getHandle()
|
||||
);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_for_notify: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
|
||||
uint8_t val[] = {0x01, 0x00};
|
||||
if(!notifications) val[0] = 0x02;
|
||||
BLERemoteDescriptor* desc = getDescriptor(BLEUUID((uint16_t)0x2902));
|
||||
desc->writeValue(val, 2);
|
||||
} // End Register
|
||||
else { // If we weren't passed a callback function, then this is an unregistration.
|
||||
esp_err_t errRc = ::esp_ble_gattc_unregister_for_notify(
|
||||
m_pRemoteService->getClient()->getGattcIf(),
|
||||
*m_pRemoteService->getClient()->getPeerAddress().getNative(),
|
||||
getHandle()
|
||||
);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_unregister_for_notify: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
|
||||
uint8_t val[] = {0x00, 0x00};
|
||||
BLERemoteDescriptor* desc = getDescriptor((uint16_t)0x2902);
|
||||
desc->writeValue(val, 2);
|
||||
} // End Unregister
|
||||
|
||||
m_semaphoreRegForNotifyEvt.wait("registerForNotify");
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< registerForNotify()");
|
||||
} // registerForNotify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete the descriptors in the descriptor map.
|
||||
* We maintain a map called m_descriptorMap that contains pointers to BLERemoteDescriptors
|
||||
* object references. Since we allocated these in this class, we are also responsible for deleteing
|
||||
* them. This method does just that.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLERemoteCharacteristic::removeDescriptors() {
|
||||
// Iterate through all the descriptors releasing their storage and erasing them from the map.
|
||||
for (auto &myPair : m_descriptorMap) {
|
||||
m_descriptorMap.erase(myPair.first);
|
||||
delete myPair.second;
|
||||
}
|
||||
m_descriptorMap.clear(); // Technically not neeeded, but just to be sure.
|
||||
} // removeCharacteristics
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert a BLERemoteCharacteristic to a string representation;
|
||||
* @return a String representation.
|
||||
*/
|
||||
std::string BLERemoteCharacteristic::toString() {
|
||||
std::ostringstream ss;
|
||||
ss << "Characteristic: uuid: " << m_uuid.toString() <<
|
||||
", handle: " << getHandle() << " 0x" << std::hex << getHandle() <<
|
||||
", props: " << BLEUtils::characteristicPropertiesToString(m_charProp);
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write the new value for the characteristic.
|
||||
* @param [in] newValue The new value to write.
|
||||
* @param [in] response Do we expect a response?
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLERemoteCharacteristic::writeValue(std::string newValue, bool response) {
|
||||
writeValue((uint8_t*)newValue.c_str(), strlen(newValue.c_str()), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write the new value for the characteristic.
|
||||
*
|
||||
* This is a convenience function. Many BLE characteristics are a single byte of data.
|
||||
* @param [in] newValue The new byte value to write.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLERemoteCharacteristic::writeValue(uint8_t newValue, bool response) {
|
||||
writeValue(&newValue, 1, response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write the new value for the characteristic from a data buffer.
|
||||
* @param [in] data A pointer to a data buffer.
|
||||
* @param [in] length The length of the data in the data buffer.
|
||||
* @param [in] response Whether we require a response from the write.
|
||||
*/
|
||||
void BLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool response) {
|
||||
// writeValue(std::string((char*)data, length), response);
|
||||
ESP_LOGD(LOG_TAG, ">> writeValue(), length: %d", length);
|
||||
|
||||
// Check to see that we are connected.
|
||||
if (!getRemoteService()->getClient()->isConnected()) {
|
||||
ESP_LOGE(LOG_TAG, "Disconnected");
|
||||
throw BLEDisconnectedException();
|
||||
}
|
||||
|
||||
m_semaphoreWriteCharEvt.take("writeValue");
|
||||
// Invoke the ESP-IDF API to perform the write.
|
||||
esp_err_t errRc = ::esp_ble_gattc_write_char(
|
||||
m_pRemoteService->getClient()->getGattcIf(),
|
||||
m_pRemoteService->getClient()->getConnId(),
|
||||
getHandle(),
|
||||
length,
|
||||
data,
|
||||
response?ESP_GATT_WRITE_TYPE_RSP:ESP_GATT_WRITE_TYPE_NO_RSP,
|
||||
ESP_GATT_AUTH_REQ_NONE
|
||||
);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_write_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreWriteCharEvt.wait("writeValue");
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< writeValue");
|
||||
} // writeValue
|
||||
|
||||
/**
|
||||
* @brief Read raw data from remote characteristic as hex bytes
|
||||
* @return return pointer data read
|
||||
*/
|
||||
uint8_t* BLERemoteCharacteristic::readRawData() {
|
||||
return m_rawData;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
84
libraries/ESP32_BLE_Arduino/src/BLERemoteCharacteristic.h
Normal file
84
libraries/ESP32_BLE_Arduino/src/BLERemoteCharacteristic.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* BLERemoteCharacteristic.h
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <esp_gattc_api.h>
|
||||
|
||||
#include "BLERemoteService.h"
|
||||
#include "BLERemoteDescriptor.h"
|
||||
#include "BLEUUID.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
class BLERemoteService;
|
||||
class BLERemoteDescriptor;
|
||||
typedef void (*notify_callback)(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify);
|
||||
|
||||
/**
|
||||
* @brief A model of a remote %BLE characteristic.
|
||||
*/
|
||||
class BLERemoteCharacteristic {
|
||||
public:
|
||||
~BLERemoteCharacteristic();
|
||||
|
||||
// Public member functions
|
||||
bool canBroadcast();
|
||||
bool canIndicate();
|
||||
bool canNotify();
|
||||
bool canRead();
|
||||
bool canWrite();
|
||||
bool canWriteNoResponse();
|
||||
BLERemoteDescriptor* getDescriptor(BLEUUID uuid);
|
||||
std::map<std::string, BLERemoteDescriptor*>* getDescriptors();
|
||||
uint16_t getHandle();
|
||||
BLEUUID getUUID();
|
||||
std::string readValue();
|
||||
uint8_t readUInt8();
|
||||
uint16_t readUInt16();
|
||||
uint32_t readUInt32();
|
||||
void registerForNotify(notify_callback _callback, bool notifications = true);
|
||||
void writeValue(uint8_t* data, size_t length, bool response = false);
|
||||
void writeValue(std::string newValue, bool response = false);
|
||||
void writeValue(uint8_t newValue, bool response = false);
|
||||
std::string toString();
|
||||
uint8_t* readRawData();
|
||||
|
||||
private:
|
||||
BLERemoteCharacteristic(uint16_t handle, BLEUUID uuid, esp_gatt_char_prop_t charProp, BLERemoteService* pRemoteService);
|
||||
friend class BLEClient;
|
||||
friend class BLERemoteService;
|
||||
friend class BLERemoteDescriptor;
|
||||
|
||||
// Private member functions
|
||||
void gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam);
|
||||
|
||||
BLERemoteService* getRemoteService();
|
||||
void removeDescriptors();
|
||||
void retrieveDescriptors();
|
||||
|
||||
// Private properties
|
||||
BLEUUID m_uuid;
|
||||
esp_gatt_char_prop_t m_charProp;
|
||||
uint16_t m_handle;
|
||||
BLERemoteService* m_pRemoteService;
|
||||
FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreRegForNotifyEvt = FreeRTOS::Semaphore("RegForNotifyEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt");
|
||||
std::string m_value;
|
||||
uint8_t *m_rawData;
|
||||
notify_callback m_notifyCallback;
|
||||
|
||||
// We maintain a map of descriptors owned by this characteristic keyed by a string representation of the UUID.
|
||||
std::map<std::string, BLERemoteDescriptor*> m_descriptorMap;
|
||||
}; // BLERemoteCharacteristic
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ */
|
||||
181
libraries/ESP32_BLE_Arduino/src/BLERemoteDescriptor.cpp
Normal file
181
libraries/ESP32_BLE_Arduino/src/BLERemoteDescriptor.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* BLERemoteDescriptor.cpp
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <sstream>
|
||||
#include "BLERemoteDescriptor.h"
|
||||
#include "GeneralUtils.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLERemoteDescriptor";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
BLERemoteDescriptor::BLERemoteDescriptor(
|
||||
uint16_t handle,
|
||||
BLEUUID uuid,
|
||||
BLERemoteCharacteristic* pRemoteCharacteristic) {
|
||||
|
||||
m_handle = handle;
|
||||
m_uuid = uuid;
|
||||
m_pRemoteCharacteristic = pRemoteCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the handle associated with this remote descriptor.
|
||||
* @return The handle associated with this remote descriptor.
|
||||
*/
|
||||
uint16_t BLERemoteDescriptor::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the characteristic that owns this descriptor.
|
||||
* @return The characteristic that owns this descriptor.
|
||||
*/
|
||||
BLERemoteCharacteristic* BLERemoteDescriptor::getRemoteCharacteristic() {
|
||||
return m_pRemoteCharacteristic;
|
||||
} // getRemoteCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the UUID associated this remote descriptor.
|
||||
* @return The UUID associated this remote descriptor.
|
||||
*/
|
||||
BLEUUID BLERemoteDescriptor::getUUID() {
|
||||
return m_uuid;
|
||||
} // getUUID
|
||||
|
||||
|
||||
std::string BLERemoteDescriptor::readValue() {
|
||||
ESP_LOGD(LOG_TAG, ">> readValue: %s", toString().c_str());
|
||||
|
||||
// Check to see that we are connected.
|
||||
if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) {
|
||||
ESP_LOGE(LOG_TAG, "Disconnected");
|
||||
throw BLEDisconnectedException();
|
||||
}
|
||||
|
||||
m_semaphoreReadDescrEvt.take("readValue");
|
||||
|
||||
// Ask the BLE subsystem to retrieve the value for the remote hosted characteristic.
|
||||
esp_err_t errRc = ::esp_ble_gattc_read_char_descr(
|
||||
m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(),
|
||||
m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(), // The connection ID to the BLE server
|
||||
getHandle(), // The handle of this characteristic
|
||||
ESP_GATT_AUTH_REQ_NONE); // Security
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return "";
|
||||
}
|
||||
|
||||
// Block waiting for the event that indicates that the read has completed. When it has, the std::string found
|
||||
// in m_value will contain our data.
|
||||
m_semaphoreReadDescrEvt.wait("readValue");
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< readValue(): length: %d", m_value.length());
|
||||
return m_value;
|
||||
} // readValue
|
||||
|
||||
|
||||
uint8_t BLERemoteDescriptor::readUInt8() {
|
||||
std::string value = readValue();
|
||||
if (value.length() >= 1) {
|
||||
return (uint8_t) value[0];
|
||||
}
|
||||
return 0;
|
||||
} // readUInt8
|
||||
|
||||
|
||||
uint16_t BLERemoteDescriptor::readUInt16() {
|
||||
std::string value = readValue();
|
||||
if (value.length() >= 2) {
|
||||
return *(uint16_t*) value.data();
|
||||
}
|
||||
return 0;
|
||||
} // readUInt16
|
||||
|
||||
|
||||
uint32_t BLERemoteDescriptor::readUInt32() {
|
||||
std::string value = readValue();
|
||||
if (value.length() >= 4) {
|
||||
return *(uint32_t*) value.data();
|
||||
}
|
||||
return 0;
|
||||
} // readUInt32
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of this BLE Remote Descriptor.
|
||||
* @retun A string representation of this BLE Remote Descriptor.
|
||||
*/
|
||||
std::string BLERemoteDescriptor::toString() {
|
||||
std::stringstream ss;
|
||||
ss << "handle: " << getHandle() << ", uuid: " << getUUID().toString();
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write data to the BLE Remote Descriptor.
|
||||
* @param [in] data The data to send to the remote descriptor.
|
||||
* @param [in] length The length of the data to send.
|
||||
* @param [in] response True if we expect a response.
|
||||
*/
|
||||
void BLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool response) {
|
||||
ESP_LOGD(LOG_TAG, ">> writeValue: %s", toString().c_str());
|
||||
// Check to see that we are connected.
|
||||
if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) {
|
||||
ESP_LOGE(LOG_TAG, "Disconnected");
|
||||
throw BLEDisconnectedException();
|
||||
}
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gattc_write_char_descr(
|
||||
m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(),
|
||||
m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(),
|
||||
getHandle(),
|
||||
length, // Data length
|
||||
data, // Data
|
||||
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP,
|
||||
ESP_GATT_AUTH_REQ_NONE
|
||||
);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_write_char_descr: %d", errRc);
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< writeValue");
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write data represented as a string to the BLE Remote Descriptor.
|
||||
* @param [in] newValue The data to send to the remote descriptor.
|
||||
* @param [in] response True if we expect a response.
|
||||
*/
|
||||
void BLERemoteDescriptor::writeValue(std::string newValue, bool response) {
|
||||
writeValue((uint8_t*) newValue.data(), newValue.length(), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write a byte value to the Descriptor.
|
||||
* @param [in] The single byte to write.
|
||||
* @param [in] True if we expect a response.
|
||||
*/
|
||||
void BLERemoteDescriptor::writeValue(uint8_t newValue, bool response) {
|
||||
writeValue(&newValue, 1, response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
55
libraries/ESP32_BLE_Arduino/src/BLERemoteDescriptor.h
Normal file
55
libraries/ESP32_BLE_Arduino/src/BLERemoteDescriptor.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* BLERemoteDescriptor.h
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string>
|
||||
|
||||
#include <esp_gattc_api.h>
|
||||
|
||||
#include "BLERemoteCharacteristic.h"
|
||||
#include "BLEUUID.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
class BLERemoteCharacteristic;
|
||||
/**
|
||||
* @brief A model of remote %BLE descriptor.
|
||||
*/
|
||||
class BLERemoteDescriptor {
|
||||
public:
|
||||
uint16_t getHandle();
|
||||
BLERemoteCharacteristic* getRemoteCharacteristic();
|
||||
BLEUUID getUUID();
|
||||
std::string readValue(void);
|
||||
uint8_t readUInt8(void);
|
||||
uint16_t readUInt16(void);
|
||||
uint32_t readUInt32(void);
|
||||
std::string toString(void);
|
||||
void writeValue(uint8_t* data, size_t length, bool response = false);
|
||||
void writeValue(std::string newValue, bool response = false);
|
||||
void writeValue(uint8_t newValue, bool response = false);
|
||||
|
||||
|
||||
private:
|
||||
friend class BLERemoteCharacteristic;
|
||||
BLERemoteDescriptor(
|
||||
uint16_t handle,
|
||||
BLEUUID uuid,
|
||||
BLERemoteCharacteristic* pRemoteCharacteristic
|
||||
);
|
||||
uint16_t m_handle; // Server handle of this descriptor.
|
||||
BLEUUID m_uuid; // UUID of this descriptor.
|
||||
std::string m_value; // Last received value of the descriptor.
|
||||
BLERemoteCharacteristic* m_pRemoteCharacteristic; // Reference to the Remote characteristic of which this descriptor is associated.
|
||||
FreeRTOS::Semaphore m_semaphoreReadDescrEvt = FreeRTOS::Semaphore("ReadDescrEvt");
|
||||
|
||||
|
||||
};
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ */
|
||||
340
libraries/ESP32_BLE_Arduino/src/BLERemoteService.cpp
Normal file
340
libraries/ESP32_BLE_Arduino/src/BLERemoteService.cpp
Normal file
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* BLERemoteService.cpp
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <sstream>
|
||||
#include "BLERemoteService.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include <esp_err.h>
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLERemoteService";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
BLERemoteService::BLERemoteService(
|
||||
esp_gatt_id_t srvcId,
|
||||
BLEClient* pClient,
|
||||
uint16_t startHandle,
|
||||
uint16_t endHandle
|
||||
) {
|
||||
|
||||
ESP_LOGD(LOG_TAG, ">> BLERemoteService()");
|
||||
m_srvcId = srvcId;
|
||||
m_pClient = pClient;
|
||||
m_uuid = BLEUUID(m_srvcId);
|
||||
m_haveCharacteristics = false;
|
||||
m_startHandle = startHandle;
|
||||
m_endHandle = endHandle;
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< BLERemoteService()");
|
||||
}
|
||||
|
||||
|
||||
BLERemoteService::~BLERemoteService() {
|
||||
removeCharacteristics();
|
||||
}
|
||||
|
||||
/*
|
||||
static bool compareSrvcId(esp_gatt_srvc_id_t id1, esp_gatt_srvc_id_t id2) {
|
||||
if (id1.id.inst_id != id2.id.inst_id) {
|
||||
return false;
|
||||
}
|
||||
if (!BLEUUID(id1.id.uuid).equals(BLEUUID(id2.id.uuid))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // compareSrvcId
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Handle GATT Client events
|
||||
*/
|
||||
void BLERemoteService::gattClientEventHandler(
|
||||
esp_gattc_cb_event_t event,
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* evtParam) {
|
||||
switch (event) {
|
||||
//
|
||||
// ESP_GATTC_GET_CHAR_EVT
|
||||
//
|
||||
// get_char:
|
||||
// - esp_gatt_status_t status
|
||||
// - uin1t6_t conn_id
|
||||
// - esp_gatt_srvc_id_t srvc_id
|
||||
// - esp_gatt_id_t char_id
|
||||
// - esp_gatt_char_prop_t char_prop
|
||||
//
|
||||
/*
|
||||
case ESP_GATTC_GET_CHAR_EVT: {
|
||||
// Is this event for this service? If yes, then the local srvc_id and the event srvc_id will be
|
||||
// the same.
|
||||
if (compareSrvcId(m_srvcId, evtParam->get_char.srvc_id) == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If the status is NOT OK then we have a problem and continue.
|
||||
if (evtParam->get_char.status != ESP_GATT_OK) {
|
||||
m_semaphoreGetCharEvt.give();
|
||||
break;
|
||||
}
|
||||
|
||||
// This is an indication that we now have the characteristic details for a characteristic owned
|
||||
// by this service so remember it.
|
||||
m_characteristicMap.insert(std::pair<std::string, BLERemoteCharacteristic*>(
|
||||
BLEUUID(evtParam->get_char.char_id.uuid).toString(),
|
||||
new BLERemoteCharacteristic(evtParam->get_char.char_id, evtParam->get_char.char_prop, this) ));
|
||||
|
||||
|
||||
// Now that we have received a characteristic, lets ask for the next one.
|
||||
esp_err_t errRc = ::esp_ble_gattc_get_characteristic(
|
||||
m_pClient->getGattcIf(),
|
||||
m_pClient->getConnId(),
|
||||
&m_srvcId,
|
||||
&evtParam->get_char.char_id);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_characteristic: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
break;
|
||||
}
|
||||
|
||||
//m_semaphoreGetCharEvt.give();
|
||||
break;
|
||||
} // ESP_GATTC_GET_CHAR_EVT
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
} // switch
|
||||
|
||||
// Send the event to each of the characteristics owned by this service.
|
||||
for (auto &myPair : m_characteristicMapByHandle) {
|
||||
myPair.second->gattClientEventHandler(event, gattc_if, evtParam);
|
||||
}
|
||||
} // gattClientEventHandler
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the remote characteristic object for the characteristic UUID.
|
||||
* @param [in] uuid Remote characteristic uuid.
|
||||
* @return Reference to the remote characteristic object.
|
||||
* @throws BLEUuidNotFoundException
|
||||
*/
|
||||
BLERemoteCharacteristic* BLERemoteService::getCharacteristic(const char* uuid) {
|
||||
return getCharacteristic(BLEUUID(uuid));
|
||||
} // getCharacteristic
|
||||
|
||||
/**
|
||||
* @brief Get the characteristic object for the UUID.
|
||||
* @param [in] uuid Characteristic uuid.
|
||||
* @return Reference to the characteristic object.
|
||||
* @throws BLEUuidNotFoundException
|
||||
*/
|
||||
BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid) {
|
||||
// Design
|
||||
// ------
|
||||
// We wish to retrieve the characteristic given its UUID. It is possible that we have not yet asked the
|
||||
// device what characteristics it has in which case we have nothing to match against. If we have not
|
||||
// asked the device about its characteristics, then we do that now. Once we get the results we can then
|
||||
// examine the characteristics map to see if it has the characteristic we are looking for.
|
||||
if (!m_haveCharacteristics) {
|
||||
retrieveCharacteristics();
|
||||
}
|
||||
std::string v = uuid.toString();
|
||||
for (auto &myPair : m_characteristicMap) {
|
||||
if (myPair.first == v) {
|
||||
return myPair.second;
|
||||
}
|
||||
}
|
||||
// throw new BLEUuidNotFoundException(); // <-- we dont want exception here, which will cause app crash, we want to search if any characteristic can be found one after another
|
||||
return nullptr;
|
||||
} // getCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve all the characteristics for this service.
|
||||
* This function will not return until we have all the characteristics.
|
||||
* @return N/A
|
||||
*/
|
||||
void BLERemoteService::retrieveCharacteristics() {
|
||||
ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||
|
||||
removeCharacteristics(); // Forget any previous characteristics.
|
||||
|
||||
uint16_t offset = 0;
|
||||
esp_gattc_char_elem_t result;
|
||||
while (true) {
|
||||
uint16_t count = 10; // this value is used as in parameter that allows to search max 10 chars with the same uuid
|
||||
esp_gatt_status_t status = ::esp_ble_gattc_get_all_char(
|
||||
getClient()->getGattcIf(),
|
||||
getClient()->getConnId(),
|
||||
m_startHandle,
|
||||
m_endHandle,
|
||||
&result,
|
||||
&count,
|
||||
offset
|
||||
);
|
||||
|
||||
if (status == ESP_GATT_INVALID_OFFSET) { // We have reached the end of the entries.
|
||||
break;
|
||||
}
|
||||
|
||||
if (status != ESP_GATT_OK) { // If we got an error, end.
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_all_char: %s", BLEUtils::gattStatusToString(status).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
if (count == 0) { // If we failed to get any new records, end.
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGD(LOG_TAG, "Found a characteristic: Handle: %d, UUID: %s", result.char_handle, BLEUUID(result.uuid).toString().c_str());
|
||||
|
||||
// We now have a new characteristic ... let us add that to our set of known characteristics
|
||||
BLERemoteCharacteristic *pNewRemoteCharacteristic = new BLERemoteCharacteristic(
|
||||
result.char_handle,
|
||||
BLEUUID(result.uuid),
|
||||
result.properties,
|
||||
this
|
||||
);
|
||||
|
||||
m_characteristicMap.insert(std::pair<std::string, BLERemoteCharacteristic*>(pNewRemoteCharacteristic->getUUID().toString(), pNewRemoteCharacteristic));
|
||||
m_characteristicMapByHandle.insert(std::pair<uint16_t, BLERemoteCharacteristic*>(result.char_handle, pNewRemoteCharacteristic));
|
||||
offset++; // Increment our count of number of descriptors found.
|
||||
} // Loop forever (until we break inside the loop).
|
||||
|
||||
m_haveCharacteristics = true; // Remember that we have received the characteristics.
|
||||
ESP_LOGD(LOG_TAG, "<< getCharacteristics()");
|
||||
} // getCharacteristics
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve a map of all the characteristics of this service.
|
||||
* @return A map of all the characteristics of this service.
|
||||
*/
|
||||
std::map<std::string, BLERemoteCharacteristic*>* BLERemoteService::getCharacteristics() {
|
||||
ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||
// If is possible that we have not read the characteristics associated with the service so do that
|
||||
// now. The request to retrieve the characteristics by calling "retrieveCharacteristics" is a blocking
|
||||
// call and does not return until all the characteristics are available.
|
||||
if (!m_haveCharacteristics) {
|
||||
retrieveCharacteristics();
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< getCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||
return &m_characteristicMap;
|
||||
} // getCharacteristics
|
||||
|
||||
/**
|
||||
* @brief This function is designed to get characteristics map when we have multiple characteristics with the same UUID
|
||||
*/
|
||||
void BLERemoteService::getCharacteristics(std::map<uint16_t, BLERemoteCharacteristic*>* pCharacteristicMap) {
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
|
||||
pCharacteristicMap = &m_characteristicMapByHandle;
|
||||
} // Get the characteristics map.
|
||||
|
||||
/**
|
||||
* @brief Get the client associated with this service.
|
||||
* @return A reference to the client associated with this service.
|
||||
*/
|
||||
BLEClient* BLERemoteService::getClient() {
|
||||
return m_pClient;
|
||||
} // getClient
|
||||
|
||||
|
||||
uint16_t BLERemoteService::getEndHandle() {
|
||||
return m_endHandle;
|
||||
} // getEndHandle
|
||||
|
||||
|
||||
esp_gatt_id_t* BLERemoteService::getSrvcId() {
|
||||
return &m_srvcId;
|
||||
} // getSrvcId
|
||||
|
||||
|
||||
uint16_t BLERemoteService::getStartHandle() {
|
||||
return m_startHandle;
|
||||
} // getStartHandle
|
||||
|
||||
|
||||
uint16_t BLERemoteService::getHandle() {
|
||||
ESP_LOGD(LOG_TAG, ">> getHandle: service: %s", getUUID().toString().c_str());
|
||||
ESP_LOGD(LOG_TAG, "<< getHandle: %d 0x%.2x", getStartHandle(), getStartHandle());
|
||||
return getStartHandle();
|
||||
} // getHandle
|
||||
|
||||
|
||||
BLEUUID BLERemoteService::getUUID() {
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the value of a characteristic associated with this service.
|
||||
*/
|
||||
std::string BLERemoteService::getValue(BLEUUID characteristicUuid) {
|
||||
ESP_LOGD(LOG_TAG, ">> readValue: uuid: %s", characteristicUuid.toString().c_str());
|
||||
std::string ret = getCharacteristic(characteristicUuid)->readValue();
|
||||
ESP_LOGD(LOG_TAG, "<< readValue");
|
||||
return ret;
|
||||
} // readValue
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete the characteristics in the characteristics map.
|
||||
* We maintain a map called m_characteristicsMap that contains pointers to BLERemoteCharacteristic
|
||||
* object references. Since we allocated these in this class, we are also responsible for deleteing
|
||||
* them. This method does just that.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLERemoteService::removeCharacteristics() {
|
||||
for (auto &myPair : m_characteristicMap) {
|
||||
delete myPair.second;
|
||||
//m_characteristicMap.erase(myPair.first); // Should be no need to delete as it will be deleted by the clear
|
||||
}
|
||||
m_characteristicMap.clear(); // Clear the map
|
||||
for (auto &myPair : m_characteristicMapByHandle) {
|
||||
delete myPair.second;
|
||||
}
|
||||
m_characteristicMapByHandle.clear(); // Clear the map
|
||||
} // removeCharacteristics
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of a characteristic.
|
||||
* @param [in] characteristicUuid The characteristic to set.
|
||||
* @param [in] value The value to set.
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
void BLERemoteService::setValue(BLEUUID characteristicUuid, std::string value) {
|
||||
ESP_LOGD(LOG_TAG, ">> setValue: uuid: %s", characteristicUuid.toString().c_str());
|
||||
getCharacteristic(characteristicUuid)->writeValue(value);
|
||||
ESP_LOGD(LOG_TAG, "<< setValue");
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of this remote service.
|
||||
* @return A string representation of this remote service.
|
||||
*/
|
||||
std::string BLERemoteService::toString() {
|
||||
std::ostringstream ss;
|
||||
ss << "Service: uuid: " + m_uuid.toString();
|
||||
ss << ", start_handle: " << std::dec << m_startHandle << " 0x" << std::hex << m_startHandle <<
|
||||
", end_handle: " << std::dec << m_endHandle << " 0x" << std::hex << m_endHandle;
|
||||
for (auto &myPair : m_characteristicMap) {
|
||||
ss << "\n" << myPair.second->toString();
|
||||
// myPair.second is the value
|
||||
}
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
85
libraries/ESP32_BLE_Arduino/src/BLERemoteService.h
Normal file
85
libraries/ESP32_BLE_Arduino/src/BLERemoteService.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* BLERemoteService.h
|
||||
*
|
||||
* Created on: Jul 8, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "BLEClient.h"
|
||||
#include "BLERemoteCharacteristic.h"
|
||||
#include "BLEUUID.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
class BLEClient;
|
||||
class BLERemoteCharacteristic;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A model of a remote %BLE service.
|
||||
*/
|
||||
class BLERemoteService {
|
||||
public:
|
||||
virtual ~BLERemoteService();
|
||||
|
||||
// Public methods
|
||||
BLERemoteCharacteristic* getCharacteristic(const char* uuid); // Get the specified characteristic reference.
|
||||
BLERemoteCharacteristic* getCharacteristic(BLEUUID uuid); // Get the specified characteristic reference.
|
||||
BLERemoteCharacteristic* getCharacteristic(uint16_t uuid); // Get the specified characteristic reference.
|
||||
std::map<std::string, BLERemoteCharacteristic*>* getCharacteristics();
|
||||
std::map<uint16_t, BLERemoteCharacteristic*>* getCharacteristicsByHandle(); // Get the characteristics map.
|
||||
void getCharacteristics(std::map<uint16_t, BLERemoteCharacteristic*>* pCharacteristicMap);
|
||||
|
||||
BLEClient* getClient(void); // Get a reference to the client associated with this service.
|
||||
uint16_t getHandle(); // Get the handle of this service.
|
||||
BLEUUID getUUID(void); // Get the UUID of this service.
|
||||
std::string getValue(BLEUUID characteristicUuid); // Get the value of a characteristic.
|
||||
void setValue(BLEUUID characteristicUuid, std::string value); // Set the value of a characteristic.
|
||||
std::string toString(void);
|
||||
|
||||
private:
|
||||
// Private constructor ... never meant to be created by a user application.
|
||||
BLERemoteService(esp_gatt_id_t srvcId, BLEClient* pClient, uint16_t startHandle, uint16_t endHandle);
|
||||
|
||||
// Friends
|
||||
friend class BLEClient;
|
||||
friend class BLERemoteCharacteristic;
|
||||
|
||||
// Private methods
|
||||
void retrieveCharacteristics(void); // Retrieve the characteristics from the BLE Server.
|
||||
esp_gatt_id_t* getSrvcId(void);
|
||||
uint16_t getStartHandle(); // Get the start handle for this service.
|
||||
uint16_t getEndHandle(); // Get the end handle for this service.
|
||||
|
||||
void gattClientEventHandler(
|
||||
esp_gattc_cb_event_t event,
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* evtParam);
|
||||
|
||||
void removeCharacteristics();
|
||||
|
||||
// Properties
|
||||
|
||||
// We maintain a map of characteristics owned by this service keyed by a string representation of the UUID.
|
||||
std::map<std::string, BLERemoteCharacteristic*> m_characteristicMap;
|
||||
|
||||
// We maintain a map of characteristics owned by this service keyed by a handle.
|
||||
std::map<uint16_t, BLERemoteCharacteristic*> m_characteristicMapByHandle;
|
||||
|
||||
bool m_haveCharacteristics; // Have we previously obtained the characteristics.
|
||||
BLEClient* m_pClient;
|
||||
FreeRTOS::Semaphore m_semaphoreGetCharEvt = FreeRTOS::Semaphore("GetCharEvt");
|
||||
esp_gatt_id_t m_srvcId;
|
||||
BLEUUID m_uuid; // The UUID of this service.
|
||||
uint16_t m_startHandle; // The starting handle of this service.
|
||||
uint16_t m_endHandle; // The ending handle of this service.
|
||||
}; // BLERemoteService
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ */
|
||||
331
libraries/ESP32_BLE_Arduino/src/BLEScan.cpp
Normal file
331
libraries/ESP32_BLE_Arduino/src/BLEScan.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* BLEScan.cpp
|
||||
*
|
||||
* Created on: Jul 1, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
|
||||
#include <esp_err.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "BLEAdvertisedDevice.h"
|
||||
#include "BLEScan.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "GeneralUtils.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEScan";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
BLEScan::BLEScan() {
|
||||
m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE; // Default is a passive scan.
|
||||
m_scan_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
|
||||
m_scan_params.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL;
|
||||
m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
m_stopped = true;
|
||||
m_wantDuplicates = false;
|
||||
setInterval(100);
|
||||
setWindow(100);
|
||||
} // BLEScan
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle GAP events related to scans.
|
||||
* @param [in] event The event type for this event.
|
||||
* @param [in] param Parameter data for this event.
|
||||
*/
|
||||
void BLEScan::handleGAPEvent(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param) {
|
||||
|
||||
switch(event) {
|
||||
|
||||
// ---------------------------
|
||||
// scan_rst:
|
||||
// esp_gap_search_evt_t search_evt
|
||||
// esp_bd_addr_t bda
|
||||
// esp_bt_dev_type_t dev_type
|
||||
// esp_ble_addr_type_t ble_addr_type
|
||||
// esp_ble_evt_type_t ble_evt_type
|
||||
// int rssi
|
||||
// uint8_t ble_adv[ESP_BLE_ADV_DATA_LEN_MAX]
|
||||
// int flag
|
||||
// int num_resps
|
||||
// uint8_t adv_data_len
|
||||
// uint8_t scan_rsp_len
|
||||
case ESP_GAP_BLE_SCAN_RESULT_EVT: {
|
||||
|
||||
switch(param->scan_rst.search_evt) {
|
||||
//
|
||||
// ESP_GAP_SEARCH_INQ_CMPL_EVT
|
||||
//
|
||||
// Event that indicates that the duration allowed for the search has completed or that we have been
|
||||
// asked to stop.
|
||||
case ESP_GAP_SEARCH_INQ_CMPL_EVT: {
|
||||
ESP_LOGW(LOG_TAG, "ESP_GAP_SEARCH_INQ_CMPL_EVT");
|
||||
m_stopped = true;
|
||||
m_semaphoreScanEnd.give();
|
||||
if (m_scanCompleteCB != nullptr) {
|
||||
m_scanCompleteCB(m_scanResults);
|
||||
}
|
||||
break;
|
||||
} // ESP_GAP_SEARCH_INQ_CMPL_EVT
|
||||
|
||||
//
|
||||
// ESP_GAP_SEARCH_INQ_RES_EVT
|
||||
//
|
||||
// Result that has arrived back from a Scan inquiry.
|
||||
case ESP_GAP_SEARCH_INQ_RES_EVT: {
|
||||
if (m_stopped) { // If we are not scanning, nothing to do with the extra results.
|
||||
break;
|
||||
}
|
||||
|
||||
// Examine our list of previously scanned addresses and, if we found this one already,
|
||||
// ignore it.
|
||||
BLEAddress advertisedAddress(param->scan_rst.bda);
|
||||
bool found = false;
|
||||
|
||||
if (m_scanResults.m_vectorAdvertisedDevices.count(advertisedAddress.toString()) != 0) {
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found && !m_wantDuplicates) { // If we found a previous entry AND we don't want duplicates, then we are done.
|
||||
ESP_LOGD(LOG_TAG, "Ignoring %s, already seen it.", advertisedAddress.toString().c_str());
|
||||
vTaskDelay(1); // <--- allow to switch task in case we scan infinity and dont have new devices to report, or we are blocked here
|
||||
break;
|
||||
}
|
||||
|
||||
// We now construct a model of the advertised device that we have just found for the first
|
||||
// time.
|
||||
// ESP_LOG_BUFFER_HEXDUMP(LOG_TAG, (uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len, ESP_LOG_DEBUG);
|
||||
// ESP_LOGW(LOG_TAG, "bytes length: %d + %d, addr type: %d", param->scan_rst.adv_data_len, param->scan_rst.scan_rsp_len, param->scan_rst.ble_addr_type);
|
||||
BLEAdvertisedDevice *advertisedDevice = new BLEAdvertisedDevice();
|
||||
advertisedDevice->setAddress(advertisedAddress);
|
||||
advertisedDevice->setRSSI(param->scan_rst.rssi);
|
||||
advertisedDevice->setAdFlag(param->scan_rst.flag);
|
||||
advertisedDevice->parseAdvertisement((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len);
|
||||
advertisedDevice->setScan(this);
|
||||
advertisedDevice->setAddressType(param->scan_rst.ble_addr_type);
|
||||
|
||||
if (!found) { // If we have previously seen this device, don't record it again.
|
||||
m_scanResults.m_vectorAdvertisedDevices.insert(std::pair<std::string, BLEAdvertisedDevice*>(advertisedAddress.toString(), advertisedDevice));
|
||||
}
|
||||
|
||||
if (m_pAdvertisedDeviceCallbacks) {
|
||||
m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice);
|
||||
}
|
||||
if(found)
|
||||
delete advertisedDevice;
|
||||
|
||||
break;
|
||||
} // ESP_GAP_SEARCH_INQ_RES_EVT
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
} // switch - search_evt
|
||||
|
||||
|
||||
break;
|
||||
} // ESP_GAP_BLE_SCAN_RESULT_EVT
|
||||
|
||||
default: {
|
||||
break;
|
||||
} // default
|
||||
} // End switch
|
||||
} // gapEventHandler
|
||||
|
||||
|
||||
/**
|
||||
* @brief Should we perform an active or passive scan?
|
||||
* The default is a passive scan. An active scan means that we will wish a scan response.
|
||||
* @param [in] active If true, we perform an active scan otherwise a passive scan.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEScan::setActiveScan(bool active) {
|
||||
if (active) {
|
||||
m_scan_params.scan_type = BLE_SCAN_TYPE_ACTIVE;
|
||||
} else {
|
||||
m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE;
|
||||
}
|
||||
} // setActiveScan
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the call backs to be invoked.
|
||||
* @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked.
|
||||
* @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false.
|
||||
*/
|
||||
void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates) {
|
||||
m_wantDuplicates = wantDuplicates;
|
||||
m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
|
||||
} // setAdvertisedDeviceCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the interval to scan.
|
||||
* @param [in] The interval in msecs.
|
||||
*/
|
||||
void BLEScan::setInterval(uint16_t intervalMSecs) {
|
||||
m_scan_params.scan_interval = intervalMSecs / 0.625;
|
||||
} // setInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the window to actively scan.
|
||||
* @param [in] windowMSecs How long to actively scan.
|
||||
*/
|
||||
void BLEScan::setWindow(uint16_t windowMSecs) {
|
||||
m_scan_params.scan_window = windowMSecs / 0.625;
|
||||
} // setWindow
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start scanning.
|
||||
* @param [in] duration The duration in seconds for which to scan.
|
||||
* @param [in] scanCompleteCB A function to be called when scanning has completed.
|
||||
* @param [in] are we continue scan (true) or we want to clear stored devices (false)
|
||||
* @return True if scan started or false if there was an error.
|
||||
*/
|
||||
bool BLEScan::start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults), bool is_continue) {
|
||||
ESP_LOGD(LOG_TAG, ">> start(duration=%d)", duration);
|
||||
|
||||
m_semaphoreScanEnd.take(std::string("start"));
|
||||
m_scanCompleteCB = scanCompleteCB; // Save the callback to be invoked when the scan completes.
|
||||
|
||||
// if we are connecting to devices that are advertising even after being connected, multiconnecting peripherals
|
||||
// then we should not clear map or we will connect the same device few times
|
||||
if(!is_continue) {
|
||||
for(auto _dev : m_scanResults.m_vectorAdvertisedDevices){
|
||||
delete _dev.second;
|
||||
}
|
||||
m_scanResults.m_vectorAdvertisedDevices.clear();
|
||||
}
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gap_set_scan_params(&m_scan_params);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_set_scan_params: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
m_semaphoreScanEnd.give();
|
||||
return false;
|
||||
}
|
||||
|
||||
errRc = ::esp_ble_gap_start_scanning(duration);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_start_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
m_semaphoreScanEnd.give();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_stopped = false;
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< start()");
|
||||
return true;
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start scanning and block until scanning has been completed.
|
||||
* @param [in] duration The duration in seconds for which to scan.
|
||||
* @return The BLEScanResults.
|
||||
*/
|
||||
BLEScanResults BLEScan::start(uint32_t duration, bool is_continue) {
|
||||
if(start(duration, nullptr, is_continue)) {
|
||||
m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release.
|
||||
}
|
||||
return m_scanResults;
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop an in progress scan.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEScan::stop() {
|
||||
ESP_LOGD(LOG_TAG, ">> stop()");
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gap_stop_scanning();
|
||||
|
||||
m_stopped = true;
|
||||
m_semaphoreScanEnd.give();
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_stop_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< stop()");
|
||||
} // stop
|
||||
|
||||
// delete peer device from cache after disconnecting, it is required in case we are connecting to devices with not public address
|
||||
void BLEScan::erase(BLEAddress address) {
|
||||
ESP_LOGI(LOG_TAG, "erase device: %s", address.toString().c_str());
|
||||
BLEAdvertisedDevice *advertisedDevice = m_scanResults.m_vectorAdvertisedDevices.find(address.toString())->second;
|
||||
m_scanResults.m_vectorAdvertisedDevices.erase(address.toString());
|
||||
delete advertisedDevice;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dump the scan results to the log.
|
||||
*/
|
||||
void BLEScanResults::dump() {
|
||||
ESP_LOGD(LOG_TAG, ">> Dump scan results:");
|
||||
for (int i=0; i<getCount(); i++) {
|
||||
ESP_LOGD(LOG_TAG, "- %s", getDevice(i).toString().c_str());
|
||||
}
|
||||
} // dump
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the count of devices found in the last scan.
|
||||
* @return The number of devices found in the last scan.
|
||||
*/
|
||||
int BLEScanResults::getCount() {
|
||||
return m_vectorAdvertisedDevices.size();
|
||||
} // getCount
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the specified device at the given index.
|
||||
* The index should be between 0 and getCount()-1.
|
||||
* @param [in] i The index of the device.
|
||||
* @return The device at the specified index.
|
||||
*/
|
||||
BLEAdvertisedDevice BLEScanResults::getDevice(uint32_t i) {
|
||||
uint32_t x = 0;
|
||||
BLEAdvertisedDevice dev = *m_vectorAdvertisedDevices.begin()->second;
|
||||
for (auto it = m_vectorAdvertisedDevices.begin(); it != m_vectorAdvertisedDevices.end(); it++) {
|
||||
dev = *it->second;
|
||||
if (x==i) break;
|
||||
x++;
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
BLEScanResults BLEScan::getResults() {
|
||||
return m_scanResults;
|
||||
}
|
||||
|
||||
void BLEScan::clearResults() {
|
||||
for(auto _dev : m_scanResults.m_vectorAdvertisedDevices){
|
||||
delete _dev.second;
|
||||
}
|
||||
m_scanResults.m_vectorAdvertisedDevices.clear();
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
83
libraries/ESP32_BLE_Arduino/src/BLEScan.h
Normal file
83
libraries/ESP32_BLE_Arduino/src/BLEScan.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* BLEScan.h
|
||||
*
|
||||
* Created on: Jul 1, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLESCAN_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLESCAN_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_gap_ble_api.h>
|
||||
|
||||
// #include <vector>
|
||||
#include <string>
|
||||
#include "BLEAdvertisedDevice.h"
|
||||
#include "BLEClient.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
class BLEAdvertisedDevice;
|
||||
class BLEAdvertisedDeviceCallbacks;
|
||||
class BLEClient;
|
||||
class BLEScan;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The result of having performed a scan.
|
||||
* When a scan completes, we have a set of found devices. Each device is described
|
||||
* by a BLEAdvertisedDevice object. The number of items in the set is given by
|
||||
* getCount(). We can retrieve a device by calling getDevice() passing in the
|
||||
* index (starting at 0) of the desired device.
|
||||
*/
|
||||
class BLEScanResults {
|
||||
public:
|
||||
void dump();
|
||||
int getCount();
|
||||
BLEAdvertisedDevice getDevice(uint32_t i);
|
||||
|
||||
private:
|
||||
friend BLEScan;
|
||||
std::map<std::string, BLEAdvertisedDevice*> m_vectorAdvertisedDevices;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Perform and manage %BLE scans.
|
||||
*
|
||||
* Scanning is associated with a %BLE client that is attempting to locate BLE servers.
|
||||
*/
|
||||
class BLEScan {
|
||||
public:
|
||||
void setActiveScan(bool active);
|
||||
void setAdvertisedDeviceCallbacks(
|
||||
BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks,
|
||||
bool wantDuplicates = false);
|
||||
void setInterval(uint16_t intervalMSecs);
|
||||
void setWindow(uint16_t windowMSecs);
|
||||
bool start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults), bool is_continue = false);
|
||||
BLEScanResults start(uint32_t duration, bool is_continue = false);
|
||||
void stop();
|
||||
void erase(BLEAddress address);
|
||||
BLEScanResults getResults();
|
||||
void clearResults();
|
||||
|
||||
private:
|
||||
BLEScan(); // One doesn't create a new instance instead one asks the BLEDevice for the singleton.
|
||||
friend class BLEDevice;
|
||||
void handleGAPEvent(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param);
|
||||
void parseAdvertisement(BLEClient* pRemoteDevice, uint8_t *payload);
|
||||
|
||||
|
||||
esp_ble_scan_params_t m_scan_params;
|
||||
BLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
bool m_stopped = true;
|
||||
FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd");
|
||||
BLEScanResults m_scanResults;
|
||||
bool m_wantDuplicates;
|
||||
void (*m_scanCompleteCB)(BLEScanResults scanResults);
|
||||
}; // BLEScan
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLESCAN_H_ */
|
||||
104
libraries/ESP32_BLE_Arduino/src/BLESecurity.cpp
Normal file
104
libraries/ESP32_BLE_Arduino/src/BLESecurity.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* BLESecurity.cpp
|
||||
*
|
||||
* Created on: Dec 17, 2017
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#include "BLESecurity.h"
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
BLESecurity::BLESecurity() {
|
||||
}
|
||||
|
||||
BLESecurity::~BLESecurity() {
|
||||
}
|
||||
/*
|
||||
* @brief Set requested authentication mode
|
||||
*/
|
||||
void BLESecurity::setAuthenticationMode(esp_ble_auth_req_t auth_req) {
|
||||
m_authReq = auth_req;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &m_authReq, sizeof(uint8_t)); // <--- setup requested authentication mode
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set our device IO capability to let end user perform authorization
|
||||
* either by displaying or entering generated 6-digits pin code
|
||||
*/
|
||||
void BLESecurity::setCapability(esp_ble_io_cap_t iocap) {
|
||||
m_iocap = iocap;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
|
||||
} // setCapability
|
||||
|
||||
|
||||
/**
|
||||
* @brief Init encryption key by server
|
||||
* @param key_size is value between 7 and 16
|
||||
*/
|
||||
void BLESecurity::setInitEncryptionKey(uint8_t init_key) {
|
||||
m_initKey = init_key;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &m_initKey, sizeof(uint8_t));
|
||||
} // setInitEncryptionKey
|
||||
|
||||
|
||||
/**
|
||||
* @brief Init encryption key by client
|
||||
* @param key_size is value between 7 and 16
|
||||
*/
|
||||
void BLESecurity::setRespEncryptionKey(uint8_t resp_key) {
|
||||
m_respKey = resp_key;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &m_respKey, sizeof(uint8_t));
|
||||
} // setRespEncryptionKey
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
void BLESecurity::setKeySize(uint8_t key_size) {
|
||||
m_keySize = key_size;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &m_keySize, sizeof(uint8_t));
|
||||
} //setKeySize
|
||||
|
||||
|
||||
/**
|
||||
* @brief Debug function to display what keys are exchanged by peers
|
||||
*/
|
||||
char* BLESecurity::esp_key_type_to_str(esp_ble_key_type_t key_type) {
|
||||
char* key_str = nullptr;
|
||||
switch (key_type) {
|
||||
case ESP_LE_KEY_NONE:
|
||||
key_str = (char*) "ESP_LE_KEY_NONE";
|
||||
break;
|
||||
case ESP_LE_KEY_PENC:
|
||||
key_str = (char*) "ESP_LE_KEY_PENC";
|
||||
break;
|
||||
case ESP_LE_KEY_PID:
|
||||
key_str = (char*) "ESP_LE_KEY_PID";
|
||||
break;
|
||||
case ESP_LE_KEY_PCSRK:
|
||||
key_str = (char*) "ESP_LE_KEY_PCSRK";
|
||||
break;
|
||||
case ESP_LE_KEY_PLK:
|
||||
key_str = (char*) "ESP_LE_KEY_PLK";
|
||||
break;
|
||||
case ESP_LE_KEY_LLK:
|
||||
key_str = (char*) "ESP_LE_KEY_LLK";
|
||||
break;
|
||||
case ESP_LE_KEY_LENC:
|
||||
key_str = (char*) "ESP_LE_KEY_LENC";
|
||||
break;
|
||||
case ESP_LE_KEY_LID:
|
||||
key_str = (char*) "ESP_LE_KEY_LID";
|
||||
break;
|
||||
case ESP_LE_KEY_LCSRK:
|
||||
key_str = (char*) "ESP_LE_KEY_LCSRK";
|
||||
break;
|
||||
default:
|
||||
key_str = (char*) "INVALID BLE KEY TYPE";
|
||||
break;
|
||||
}
|
||||
return key_str;
|
||||
} // esp_key_type_to_str
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
72
libraries/ESP32_BLE_Arduino/src/BLESecurity.h
Normal file
72
libraries/ESP32_BLE_Arduino/src/BLESecurity.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* BLESecurity.h
|
||||
*
|
||||
* Created on: Dec 17, 2017
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLESECURITY_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLESECURITY_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <esp_gap_ble_api.h>
|
||||
|
||||
class BLESecurity {
|
||||
public:
|
||||
BLESecurity();
|
||||
virtual ~BLESecurity();
|
||||
void setAuthenticationMode(esp_ble_auth_req_t auth_req);
|
||||
void setCapability(esp_ble_io_cap_t iocap);
|
||||
void setInitEncryptionKey(uint8_t init_key);
|
||||
void setRespEncryptionKey(uint8_t resp_key);
|
||||
void setKeySize(uint8_t key_size = 16);
|
||||
static char* esp_key_type_to_str(esp_ble_key_type_t key_type);
|
||||
|
||||
private:
|
||||
esp_ble_auth_req_t m_authReq;
|
||||
esp_ble_io_cap_t m_iocap;
|
||||
uint8_t m_initKey;
|
||||
uint8_t m_respKey;
|
||||
uint8_t m_keySize;
|
||||
|
||||
}; // BLESecurity
|
||||
|
||||
|
||||
/*
|
||||
* @brief Callbacks to handle GAP events related to authorization
|
||||
*/
|
||||
class BLESecurityCallbacks {
|
||||
public:
|
||||
virtual ~BLESecurityCallbacks() {};
|
||||
|
||||
/**
|
||||
* @brief Its request from peer device to input authentication pin code displayed on peer device.
|
||||
* It requires that our device is capable to input 6-digits code by end user
|
||||
* @return Return 6-digits integer value from input device
|
||||
*/
|
||||
virtual uint32_t onPassKeyRequest() = 0;
|
||||
|
||||
/**
|
||||
* @brief Provide us 6-digits code to perform authentication.
|
||||
* It requires that our device is capable to display this code to end user
|
||||
* @param
|
||||
*/
|
||||
virtual void onPassKeyNotify(uint32_t pass_key) = 0;
|
||||
|
||||
/**
|
||||
* @brief Here we can make decision if we want to let negotiate authorization with peer device or not
|
||||
* return Return true if we accept this peer device request
|
||||
*/
|
||||
|
||||
virtual bool onSecurityRequest() = 0 ;
|
||||
/**
|
||||
* Provide us information when authentication process is completed
|
||||
*/
|
||||
virtual void onAuthenticationComplete(esp_ble_auth_cmpl_t) = 0;
|
||||
|
||||
virtual bool onConfirmPIN(uint32_t pin) = 0;
|
||||
}; // BLESecurityCallbacks
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif // COMPONENTS_CPP_UTILS_BLESECURITY_H_
|
||||
424
libraries/ESP32_BLE_Arduino/src/BLEServer.cpp
Normal file
424
libraries/ESP32_BLE_Arduino/src/BLEServer.cpp
Normal file
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* BLEServer.cpp
|
||||
*
|
||||
* Created on: Apr 16, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_bt.h>
|
||||
#include <esp_bt_main.h>
|
||||
#include "GeneralUtils.h"
|
||||
#include "BLEDevice.h"
|
||||
#include "BLEServer.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLEUtils.h"
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEServer";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a %BLE Server
|
||||
*
|
||||
* This class is not designed to be individually instantiated. Instead one should create a server by asking
|
||||
* the BLEDevice class.
|
||||
*/
|
||||
BLEServer::BLEServer() {
|
||||
m_appId = ESP_GATT_IF_NONE;
|
||||
m_gatts_if = ESP_GATT_IF_NONE;
|
||||
m_connectedCount = 0;
|
||||
m_connId = ESP_GATT_IF_NONE;
|
||||
m_pServerCallbacks = nullptr;
|
||||
} // BLEServer
|
||||
|
||||
|
||||
void BLEServer::createApp(uint16_t appId) {
|
||||
m_appId = appId;
|
||||
registerApp(appId);
|
||||
} // createApp
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a %BLE Service.
|
||||
*
|
||||
* With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition
|
||||
* of a new service. Every service must have a unique UUID.
|
||||
* @param [in] uuid The UUID of the new service.
|
||||
* @return A reference to the new service object.
|
||||
*/
|
||||
BLEService* BLEServer::createService(const char* uuid) {
|
||||
return createService(BLEUUID(uuid));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a %BLE Service.
|
||||
*
|
||||
* With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition
|
||||
* of a new service. Every service must have a unique UUID.
|
||||
* @param [in] uuid The UUID of the new service.
|
||||
* @param [in] numHandles The maximum number of handles associated with this service.
|
||||
* @param [in] inst_id With multiple services with the same UUID we need to provide inst_id value different for each service.
|
||||
* @return A reference to the new service object.
|
||||
*/
|
||||
BLEService* BLEServer::createService(BLEUUID uuid, uint32_t numHandles, uint8_t inst_id) {
|
||||
ESP_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
|
||||
m_semaphoreCreateEvt.take("createService");
|
||||
|
||||
// Check that a service with the supplied UUID does not already exist.
|
||||
if (m_serviceMap.getByUUID(uuid) != nullptr) {
|
||||
ESP_LOGW(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.",
|
||||
uuid.toString().c_str());
|
||||
}
|
||||
|
||||
BLEService* pService = new BLEService(uuid, numHandles);
|
||||
pService->m_instId = inst_id;
|
||||
m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server.
|
||||
pService->executeCreate(this); // Perform the API calls to actually create the service.
|
||||
|
||||
m_semaphoreCreateEvt.wait("createService");
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< createService");
|
||||
return pService;
|
||||
} // createService
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a %BLE Service by its UUID
|
||||
* @param [in] uuid The UUID of the new service.
|
||||
* @return A reference to the service object.
|
||||
*/
|
||||
BLEService* BLEServer::getServiceByUUID(const char* uuid) {
|
||||
return m_serviceMap.getByUUID(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a %BLE Service by its UUID
|
||||
* @param [in] uuid The UUID of the new service.
|
||||
* @return A reference to the service object.
|
||||
*/
|
||||
BLEService* BLEServer::getServiceByUUID(BLEUUID uuid) {
|
||||
return m_serviceMap.getByUUID(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
|
||||
*
|
||||
* @return An advertising object.
|
||||
*/
|
||||
BLEAdvertising* BLEServer::getAdvertising() {
|
||||
return BLEDevice::getAdvertising();
|
||||
}
|
||||
|
||||
uint16_t BLEServer::getConnId() {
|
||||
return m_connId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the number of connected clients.
|
||||
* @return The number of connected clients.
|
||||
*/
|
||||
uint32_t BLEServer::getConnectedCount() {
|
||||
return m_connectedCount;
|
||||
} // getConnectedCount
|
||||
|
||||
|
||||
uint16_t BLEServer::getGattsIf() {
|
||||
return m_gatts_if;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle a GATT Server Event.
|
||||
*
|
||||
* @param [in] event
|
||||
* @param [in] gatts_if
|
||||
* @param [in] param
|
||||
*
|
||||
*/
|
||||
void BLEServer::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param) {
|
||||
ESP_LOGD(LOG_TAG, ">> handleGATTServerEvent: %s",
|
||||
BLEUtils::gattServerEventTypeToString(event).c_str());
|
||||
|
||||
switch(event) {
|
||||
// ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service.
|
||||
// add_char:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t attr_handle
|
||||
// - uint16_t service_handle
|
||||
// - esp_bt_uuid_t char_uuid
|
||||
//
|
||||
case ESP_GATTS_ADD_CHAR_EVT: {
|
||||
break;
|
||||
} // ESP_GATTS_ADD_CHAR_EVT
|
||||
|
||||
case ESP_GATTS_MTU_EVT:
|
||||
updatePeerMTU(param->mtu.conn_id, param->mtu.mtu);
|
||||
break;
|
||||
|
||||
// ESP_GATTS_CONNECT_EVT
|
||||
// connect:
|
||||
// - uint16_t conn_id
|
||||
// - esp_bd_addr_t remote_bda
|
||||
//
|
||||
case ESP_GATTS_CONNECT_EVT: {
|
||||
m_connId = param->connect.conn_id;
|
||||
addPeerDevice((void*)this, false, m_connId);
|
||||
if (m_pServerCallbacks != nullptr) {
|
||||
m_pServerCallbacks->onConnect(this);
|
||||
m_pServerCallbacks->onConnect(this, param);
|
||||
}
|
||||
m_connectedCount++; // Increment the number of connected devices count.
|
||||
break;
|
||||
} // ESP_GATTS_CONNECT_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_CREATE_EVT
|
||||
// Called when a new service is registered as having been created.
|
||||
//
|
||||
// create:
|
||||
// * esp_gatt_status_t status
|
||||
// * uint16_t service_handle
|
||||
// * esp_gatt_srvc_id_t service_id
|
||||
//
|
||||
case ESP_GATTS_CREATE_EVT: {
|
||||
BLEService* pService = m_serviceMap.getByUUID(param->create.service_id.id.uuid, param->create.service_id.id.inst_id); // <--- very big bug for multi services with the same uuid
|
||||
m_serviceMap.setByHandle(param->create.service_handle, pService);
|
||||
m_semaphoreCreateEvt.give();
|
||||
break;
|
||||
} // ESP_GATTS_CREATE_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_DISCONNECT_EVT
|
||||
//
|
||||
// disconnect
|
||||
// - uint16_t conn_id
|
||||
// - esp_bd_addr_t remote_bda
|
||||
// - esp_gatt_conn_reason_t reason
|
||||
//
|
||||
// If we receive a disconnect event then invoke the callback for disconnects (if one is present).
|
||||
// we also want to start advertising again.
|
||||
case ESP_GATTS_DISCONNECT_EVT: {
|
||||
m_connectedCount--; // Decrement the number of connected devices count.
|
||||
if (m_pServerCallbacks != nullptr) { // If we have callbacks, call now.
|
||||
m_pServerCallbacks->onDisconnect(this);
|
||||
}
|
||||
startAdvertising(); //- do this with some delay from the loop()
|
||||
removePeerDevice(param->disconnect.conn_id, false);
|
||||
break;
|
||||
} // ESP_GATTS_DISCONNECT_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived.
|
||||
//
|
||||
// read:
|
||||
// - uint16_t conn_id
|
||||
// - uint32_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
// - bool is_long
|
||||
// - bool need_rsp
|
||||
//
|
||||
case ESP_GATTS_READ_EVT: {
|
||||
break;
|
||||
} // ESP_GATTS_READ_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_REG_EVT
|
||||
// reg:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t app_id
|
||||
//
|
||||
case ESP_GATTS_REG_EVT: {
|
||||
m_gatts_if = gatts_if;
|
||||
m_semaphoreRegisterAppEvt.give(); // Unlock the mutex waiting for the registration of the app.
|
||||
break;
|
||||
} // ESP_GATTS_REG_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_WRITE_EVT - A request to write the value of a characteristic has arrived.
|
||||
//
|
||||
// write:
|
||||
// - uint16_t conn_id
|
||||
// - uint16_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
// - bool need_rsp
|
||||
// - bool is_prep
|
||||
// - uint16_t len
|
||||
// - uint8_t* value
|
||||
//
|
||||
case ESP_GATTS_WRITE_EVT: {
|
||||
break;
|
||||
}
|
||||
|
||||
case ESP_GATTS_OPEN_EVT:
|
||||
m_semaphoreOpenEvt.give(param->open.status);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Invoke the handler for every Service we have.
|
||||
m_serviceMap.handleGATTServerEvent(event, gatts_if, param);
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
||||
} // handleGATTServerEvent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register the app.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
void BLEServer::registerApp(uint16_t m_appId) {
|
||||
ESP_LOGD(LOG_TAG, ">> registerApp - %d", m_appId);
|
||||
m_semaphoreRegisterAppEvt.take("registerApp"); // Take the mutex, will be released by ESP_GATTS_REG_EVT event.
|
||||
::esp_ble_gatts_app_register(m_appId);
|
||||
m_semaphoreRegisterAppEvt.wait("registerApp");
|
||||
ESP_LOGD(LOG_TAG, "<< registerApp");
|
||||
} // registerApp
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the server callbacks.
|
||||
*
|
||||
* As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client
|
||||
* disconnecting. This function can be called to register a callback handler that will be invoked when these
|
||||
* events are detected.
|
||||
*
|
||||
* @param [in] pCallbacks The callbacks to be invoked.
|
||||
*/
|
||||
void BLEServer::setCallbacks(BLEServerCallbacks* pCallbacks) {
|
||||
m_pServerCallbacks = pCallbacks;
|
||||
} // setCallbacks
|
||||
|
||||
/*
|
||||
* Remove service
|
||||
*/
|
||||
void BLEServer::removeService(BLEService* service) {
|
||||
service->stop();
|
||||
service->executeDelete();
|
||||
m_serviceMap.removeService(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
*
|
||||
* Start the server advertising its existence. This is a convenience function and is equivalent to
|
||||
* retrieving the advertising object and invoking start upon it.
|
||||
*/
|
||||
void BLEServer::startAdvertising() {
|
||||
ESP_LOGD(LOG_TAG, ">> startAdvertising");
|
||||
BLEDevice::startAdvertising();
|
||||
ESP_LOGD(LOG_TAG, "<< startAdvertising");
|
||||
} // startAdvertising
|
||||
|
||||
/**
|
||||
* Allow to connect GATT server to peer device
|
||||
* Probably can be used in ANCS for iPhone
|
||||
*/
|
||||
bool BLEServer::connect(BLEAddress address) {
|
||||
esp_bd_addr_t addr;
|
||||
memcpy(&addr, address.getNative(), 6);
|
||||
// Perform the open connection request against the target BLE Server.
|
||||
m_semaphoreOpenEvt.take("connect");
|
||||
esp_err_t errRc = ::esp_ble_gatts_open(
|
||||
getGattsIf(),
|
||||
addr, // address
|
||||
1 // direct connection
|
||||
);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete.
|
||||
ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK);
|
||||
return rc == ESP_GATT_OK;
|
||||
} // connect
|
||||
|
||||
|
||||
|
||||
void BLEServerCallbacks::onConnect(BLEServer* pServer) {
|
||||
ESP_LOGD("BLEServerCallbacks", ">> onConnect(): Default");
|
||||
ESP_LOGD("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str());
|
||||
ESP_LOGD("BLEServerCallbacks", "<< onConnect()");
|
||||
} // onConnect
|
||||
|
||||
void BLEServerCallbacks::onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t* param) {
|
||||
ESP_LOGD("BLEServerCallbacks", ">> onConnect(): Default");
|
||||
ESP_LOGD("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str());
|
||||
ESP_LOGD("BLEServerCallbacks", "<< onConnect()");
|
||||
} // onConnect
|
||||
|
||||
|
||||
void BLEServerCallbacks::onDisconnect(BLEServer* pServer) {
|
||||
ESP_LOGD("BLEServerCallbacks", ">> onDisconnect(): Default");
|
||||
ESP_LOGD("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str());
|
||||
ESP_LOGD("BLEServerCallbacks", "<< onDisconnect()");
|
||||
} // onDisconnect
|
||||
|
||||
/* multi connect support */
|
||||
/* TODO do some more tweaks */
|
||||
void BLEServer::updatePeerMTU(uint16_t conn_id, uint16_t mtu) {
|
||||
// set mtu in conn_status_t
|
||||
const std::map<uint16_t, conn_status_t>::iterator it = m_connectedServersMap.find(conn_id);
|
||||
if (it != m_connectedServersMap.end()) {
|
||||
it->second.mtu = mtu;
|
||||
std::swap(m_connectedServersMap[conn_id], it->second);
|
||||
}
|
||||
}
|
||||
|
||||
std::map<uint16_t, conn_status_t> BLEServer::getPeerDevices(bool _client) {
|
||||
return m_connectedServersMap;
|
||||
}
|
||||
|
||||
|
||||
uint16_t BLEServer::getPeerMTU(uint16_t conn_id) {
|
||||
return m_connectedServersMap.find(conn_id)->second.mtu;
|
||||
}
|
||||
|
||||
void BLEServer::addPeerDevice(void* peer, bool _client, uint16_t conn_id) {
|
||||
conn_status_t status = {
|
||||
.peer_device = peer,
|
||||
.connected = true,
|
||||
.mtu = 23
|
||||
};
|
||||
|
||||
m_connectedServersMap.insert(std::pair<uint16_t, conn_status_t>(conn_id, status));
|
||||
}
|
||||
|
||||
void BLEServer::removePeerDevice(uint16_t conn_id, bool _client) {
|
||||
m_connectedServersMap.erase(conn_id);
|
||||
}
|
||||
/* multi connect support */
|
||||
|
||||
/**
|
||||
* Update connection parameters can be called only after connection has been established
|
||||
*/
|
||||
void BLEServer::updateConnParams(esp_bd_addr_t remote_bda, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout) {
|
||||
esp_ble_conn_update_params_t conn_params;
|
||||
memcpy(conn_params.bda, remote_bda, sizeof(esp_bd_addr_t));
|
||||
conn_params.latency = latency;
|
||||
conn_params.max_int = maxInterval; // max_int = 0x20*1.25ms = 40ms
|
||||
conn_params.min_int = minInterval; // min_int = 0x10*1.25ms = 20ms
|
||||
conn_params.timeout = timeout; // timeout = 400*10ms = 4000ms
|
||||
esp_ble_gap_update_conn_params(&conn_params);
|
||||
}
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
140
libraries/ESP32_BLE_Arduino/src/BLEServer.h
Normal file
140
libraries/ESP32_BLE_Arduino/src/BLEServer.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* BLEServer.h
|
||||
*
|
||||
* Created on: Apr 16, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLESERVER_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLESERVER_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_gatts_api.h>
|
||||
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
// #include "BLEDevice.h"
|
||||
|
||||
#include "BLEUUID.h"
|
||||
#include "BLEAdvertising.h"
|
||||
#include "BLECharacteristic.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLESecurity.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "BLEAddress.h"
|
||||
|
||||
class BLEServerCallbacks;
|
||||
/* TODO possibly refactor this struct */
|
||||
typedef struct {
|
||||
void *peer_device; // peer device BLEClient or BLEServer - maybe its better to have 2 structures or union here
|
||||
bool connected; // do we need it?
|
||||
uint16_t mtu; // every peer device negotiate own mtu
|
||||
} conn_status_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A data structure that manages the %BLE servers owned by a BLE server.
|
||||
*/
|
||||
class BLEServiceMap {
|
||||
public:
|
||||
BLEService* getByHandle(uint16_t handle);
|
||||
BLEService* getByUUID(const char* uuid);
|
||||
BLEService* getByUUID(BLEUUID uuid, uint8_t inst_id = 0);
|
||||
void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param);
|
||||
void setByHandle(uint16_t handle, BLEService* service);
|
||||
void setByUUID(const char* uuid, BLEService* service);
|
||||
void setByUUID(BLEUUID uuid, BLEService* service);
|
||||
std::string toString();
|
||||
BLEService* getFirst();
|
||||
BLEService* getNext();
|
||||
void removeService(BLEService *service);
|
||||
int getRegisteredServiceCount();
|
||||
|
||||
private:
|
||||
std::map<uint16_t, BLEService*> m_handleMap;
|
||||
std::map<BLEService*, std::string> m_uuidMap;
|
||||
std::map<BLEService*, std::string>::iterator m_iterator;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The model of a %BLE server.
|
||||
*/
|
||||
class BLEServer {
|
||||
public:
|
||||
uint32_t getConnectedCount();
|
||||
BLEService* createService(const char* uuid);
|
||||
BLEService* createService(BLEUUID uuid, uint32_t numHandles=15, uint8_t inst_id=0);
|
||||
BLEAdvertising* getAdvertising();
|
||||
void setCallbacks(BLEServerCallbacks* pCallbacks);
|
||||
void startAdvertising();
|
||||
void removeService(BLEService* service);
|
||||
BLEService* getServiceByUUID(const char* uuid);
|
||||
BLEService* getServiceByUUID(BLEUUID uuid);
|
||||
bool connect(BLEAddress address);
|
||||
uint16_t m_appId;
|
||||
void updateConnParams(esp_bd_addr_t remote_bda, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout);
|
||||
|
||||
/* multi connection support */
|
||||
std::map<uint16_t, conn_status_t> getPeerDevices(bool client);
|
||||
void addPeerDevice(void* peer, bool is_client, uint16_t conn_id);
|
||||
void removePeerDevice(uint16_t conn_id, bool client);
|
||||
BLEServer* getServerByConnId(uint16_t conn_id);
|
||||
void updatePeerMTU(uint16_t connId, uint16_t mtu);
|
||||
uint16_t getPeerMTU(uint16_t conn_id);
|
||||
uint16_t getConnId();
|
||||
|
||||
|
||||
private:
|
||||
BLEServer();
|
||||
friend class BLEService;
|
||||
friend class BLECharacteristic;
|
||||
friend class BLEDevice;
|
||||
esp_ble_adv_data_t m_adv_data;
|
||||
// BLEAdvertising m_bleAdvertising;
|
||||
uint16_t m_connId;
|
||||
uint32_t m_connectedCount;
|
||||
uint16_t m_gatts_if;
|
||||
std::map<uint16_t, conn_status_t> m_connectedServersMap;
|
||||
|
||||
FreeRTOS::Semaphore m_semaphoreRegisterAppEvt = FreeRTOS::Semaphore("RegisterAppEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt");
|
||||
BLEServiceMap m_serviceMap;
|
||||
BLEServerCallbacks* m_pServerCallbacks = nullptr;
|
||||
|
||||
void createApp(uint16_t appId);
|
||||
uint16_t getGattsIf();
|
||||
void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
|
||||
void registerApp(uint16_t);
|
||||
}; // BLEServer
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks associated with the operation of a %BLE server.
|
||||
*/
|
||||
class BLEServerCallbacks {
|
||||
public:
|
||||
virtual ~BLEServerCallbacks() {};
|
||||
/**
|
||||
* @brief Handle a new client connection.
|
||||
*
|
||||
* When a new client connects, we are invoked.
|
||||
*
|
||||
* @param [in] pServer A reference to the %BLE server that received the client connection.
|
||||
*/
|
||||
virtual void onConnect(BLEServer* pServer);
|
||||
virtual void onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param);
|
||||
/**
|
||||
* @brief Handle an existing client disconnection.
|
||||
*
|
||||
* When an existing client disconnects, we are invoked.
|
||||
*
|
||||
* @param [in] pServer A reference to the %BLE server that received the existing client disconnection.
|
||||
*/
|
||||
virtual void onDisconnect(BLEServer* pServer);
|
||||
}; // BLEServerCallbacks
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLESERVER_H_ */
|
||||
418
libraries/ESP32_BLE_Arduino/src/BLEService.cpp
Normal file
418
libraries/ESP32_BLE_Arduino/src/BLEService.cpp
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* BLEService.cpp
|
||||
*
|
||||
* Created on: Mar 25, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
// A service is identified by a UUID. A service is also the container for one or more characteristics.
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_err.h>
|
||||
#include <esp_gatts_api.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "BLEServer.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "GeneralUtils.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEService"; // Tag for logging.
|
||||
#endif
|
||||
|
||||
#define NULL_HANDLE (0xffff)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct an instance of the BLEService
|
||||
* @param [in] uuid The UUID of the service.
|
||||
* @param [in] numHandles The maximum number of handles associated with the service.
|
||||
*/
|
||||
BLEService::BLEService(const char* uuid, uint16_t numHandles) : BLEService(BLEUUID(uuid), numHandles) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct an instance of the BLEService
|
||||
* @param [in] uuid The UUID of the service.
|
||||
* @param [in] numHandles The maximum number of handles associated with the service.
|
||||
*/
|
||||
BLEService::BLEService(BLEUUID uuid, uint16_t numHandles) {
|
||||
m_uuid = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_pServer = nullptr;
|
||||
//m_serializeMutex.setName("BLEService");
|
||||
m_lastCreatedCharacteristic = nullptr;
|
||||
m_numHandles = numHandles;
|
||||
} // BLEService
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create the service.
|
||||
* Create the service.
|
||||
* @param [in] gatts_if The handle of the GATT server interface.
|
||||
* @return N/A.
|
||||
*/
|
||||
|
||||
void BLEService::executeCreate(BLEServer* pServer) {
|
||||
ESP_LOGD(LOG_TAG, ">> executeCreate() - Creating service (esp_ble_gatts_create_service) service uuid: %s", getUUID().toString().c_str());
|
||||
m_pServer = pServer;
|
||||
m_semaphoreCreateEvt.take("executeCreate"); // Take the mutex and release at event ESP_GATTS_CREATE_EVT
|
||||
|
||||
esp_gatt_srvc_id_t srvc_id;
|
||||
srvc_id.is_primary = true;
|
||||
srvc_id.id.inst_id = m_instId;
|
||||
srvc_id.id.uuid = *m_uuid.getNative();
|
||||
esp_err_t errRc = ::esp_ble_gatts_create_service(getServer()->getGattsIf(), &srvc_id, m_numHandles); // The maximum number of handles associated with the service.
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_create_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreCreateEvt.wait("executeCreate");
|
||||
ESP_LOGD(LOG_TAG, "<< executeCreate");
|
||||
} // executeCreate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete the service.
|
||||
* Delete the service.
|
||||
* @return N/A.
|
||||
*/
|
||||
|
||||
void BLEService::executeDelete() {
|
||||
ESP_LOGD(LOG_TAG, ">> executeDelete()");
|
||||
m_semaphoreDeleteEvt.take("executeDelete"); // Take the mutex and release at event ESP_GATTS_DELETE_EVT
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gatts_delete_service(getHandle());
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_delete_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreDeleteEvt.wait("executeDelete");
|
||||
ESP_LOGD(LOG_TAG, "<< executeDelete");
|
||||
} // executeDelete
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dump details of this BLE GATT service.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEService::dump() {
|
||||
ESP_LOGD(LOG_TAG, "Service: uuid:%s, handle: 0x%.2x",
|
||||
m_uuid.toString().c_str(),
|
||||
m_handle);
|
||||
ESP_LOGD(LOG_TAG, "Characteristics:\n%s", m_characteristicMap.toString().c_str());
|
||||
} // dump
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the UUID of the service.
|
||||
* @return the UUID of the service.
|
||||
*/
|
||||
BLEUUID BLEService::getUUID() {
|
||||
return m_uuid;
|
||||
} // getUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start the service.
|
||||
* Here we wish to start the service which means that we will respond to partner requests about it.
|
||||
* Starting a service also means that we can create the corresponding characteristics.
|
||||
* @return Start the service.
|
||||
*/
|
||||
void BLEService::start() {
|
||||
// We ask the BLE runtime to start the service and then create each of the characteristics.
|
||||
// We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event
|
||||
// obtained as a result of calling esp_ble_gatts_create_service().
|
||||
//
|
||||
ESP_LOGD(LOG_TAG, ">> start(): Starting service (esp_ble_gatts_start_service): %s", toString().c_str());
|
||||
if (m_handle == NULL_HANDLE) {
|
||||
ESP_LOGE(LOG_TAG, "<< !!! We attempted to start a service but don't know its handle!");
|
||||
return;
|
||||
}
|
||||
|
||||
BLECharacteristic *pCharacteristic = m_characteristicMap.getFirst();
|
||||
|
||||
while (pCharacteristic != nullptr) {
|
||||
m_lastCreatedCharacteristic = pCharacteristic;
|
||||
pCharacteristic->executeCreate(this);
|
||||
|
||||
pCharacteristic = m_characteristicMap.getNext();
|
||||
}
|
||||
// Start each of the characteristics ... these are found in the m_characteristicMap.
|
||||
|
||||
m_semaphoreStartEvt.take("start");
|
||||
esp_err_t errRc = ::esp_ble_gatts_start_service(m_handle);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_start_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
m_semaphoreStartEvt.wait("start");
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< start()");
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop the service.
|
||||
*/
|
||||
void BLEService::stop() {
|
||||
// We ask the BLE runtime to start the service and then create each of the characteristics.
|
||||
// We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event
|
||||
// obtained as a result of calling esp_ble_gatts_create_service().
|
||||
ESP_LOGD(LOG_TAG, ">> stop(): Stopping service (esp_ble_gatts_stop_service): %s", toString().c_str());
|
||||
if (m_handle == NULL_HANDLE) {
|
||||
ESP_LOGE(LOG_TAG, "<< !!! We attempted to stop a service but don't know its handle!");
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreStopEvt.take("stop");
|
||||
esp_err_t errRc = ::esp_ble_gatts_stop_service(m_handle);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_stop_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
m_semaphoreStopEvt.wait("stop");
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< stop()");
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the handle associated with this service.
|
||||
* @param [in] handle The handle associated with the service.
|
||||
*/
|
||||
void BLEService::setHandle(uint16_t handle) {
|
||||
ESP_LOGD(LOG_TAG, ">> setHandle - Handle=0x%.2x, service UUID=%s)", handle, getUUID().toString().c_str());
|
||||
if (m_handle != NULL_HANDLE) {
|
||||
ESP_LOGE(LOG_TAG, "!!! Handle is already set %.2x", m_handle);
|
||||
return;
|
||||
}
|
||||
m_handle = handle;
|
||||
ESP_LOGD(LOG_TAG, "<< setHandle");
|
||||
} // setHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the handle associated with this service.
|
||||
* @return The handle associated with this service.
|
||||
*/
|
||||
uint16_t BLEService::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a characteristic to the service.
|
||||
* @param [in] pCharacteristic A pointer to the characteristic to be added.
|
||||
*/
|
||||
void BLEService::addCharacteristic(BLECharacteristic* pCharacteristic) {
|
||||
// We maintain a mapping of characteristics owned by this service. These are managed by the
|
||||
// BLECharacteristicMap class instance found in m_characteristicMap. We add the characteristic
|
||||
// to the map and then ask the service to add the characteristic at the BLE level (ESP-IDF).
|
||||
|
||||
ESP_LOGD(LOG_TAG, ">> addCharacteristic()");
|
||||
ESP_LOGD(LOG_TAG, "Adding characteristic: uuid=%s to service: %s",
|
||||
pCharacteristic->getUUID().toString().c_str(),
|
||||
toString().c_str());
|
||||
|
||||
// Check that we don't add the same characteristic twice.
|
||||
if (m_characteristicMap.getByUUID(pCharacteristic->getUUID()) != nullptr) {
|
||||
ESP_LOGW(LOG_TAG, "<< Adding a new characteristic with the same UUID as a previous one");
|
||||
//return;
|
||||
}
|
||||
|
||||
// Remember this characteristic in our map of characteristics. At this point, we can lookup by UUID
|
||||
// but not by handle. The handle is allocated to us on the ESP_GATTS_ADD_CHAR_EVT.
|
||||
m_characteristicMap.setByUUID(pCharacteristic, pCharacteristic->getUUID());
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< addCharacteristic()");
|
||||
} // addCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new BLE Characteristic associated with this service.
|
||||
* @param [in] uuid - The UUID of the characteristic.
|
||||
* @param [in] properties - The properties of the characteristic.
|
||||
* @return The new BLE characteristic.
|
||||
*/
|
||||
BLECharacteristic* BLEService::createCharacteristic(const char* uuid, uint32_t properties) {
|
||||
return createCharacteristic(BLEUUID(uuid), properties);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a new BLE Characteristic associated with this service.
|
||||
* @param [in] uuid - The UUID of the characteristic.
|
||||
* @param [in] properties - The properties of the characteristic.
|
||||
* @return The new BLE characteristic.
|
||||
*/
|
||||
BLECharacteristic* BLEService::createCharacteristic(BLEUUID uuid, uint32_t properties) {
|
||||
BLECharacteristic* pCharacteristic = new BLECharacteristic(uuid, properties);
|
||||
addCharacteristic(pCharacteristic);
|
||||
return pCharacteristic;
|
||||
} // createCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle a GATTS server event.
|
||||
*/
|
||||
void BLEService::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param) {
|
||||
switch (event) {
|
||||
// ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service.
|
||||
// add_char:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t attr_handle
|
||||
// - uint16_t service_handle
|
||||
// - esp_bt_uuid_t char_uuid
|
||||
|
||||
// If we have reached the correct service, then locate the characteristic and remember the handle
|
||||
// for that characteristic.
|
||||
case ESP_GATTS_ADD_CHAR_EVT: {
|
||||
if (m_handle == param->add_char.service_handle) {
|
||||
BLECharacteristic *pCharacteristic = getLastCreatedCharacteristic();
|
||||
if (pCharacteristic == nullptr) {
|
||||
ESP_LOGE(LOG_TAG, "Expected to find characteristic with UUID: %s, but didnt!",
|
||||
BLEUUID(param->add_char.char_uuid).toString().c_str());
|
||||
dump();
|
||||
break;
|
||||
}
|
||||
pCharacteristic->setHandle(param->add_char.attr_handle);
|
||||
m_characteristicMap.setByHandle(param->add_char.attr_handle, pCharacteristic);
|
||||
break;
|
||||
} // Reached the correct service.
|
||||
break;
|
||||
} // ESP_GATTS_ADD_CHAR_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_START_EVT
|
||||
//
|
||||
// start:
|
||||
// esp_gatt_status_t status
|
||||
// uint16_t service_handle
|
||||
case ESP_GATTS_START_EVT: {
|
||||
if (param->start.service_handle == getHandle()) {
|
||||
m_semaphoreStartEvt.give();
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_START_EVT
|
||||
|
||||
// ESP_GATTS_STOP_EVT
|
||||
//
|
||||
// stop:
|
||||
// esp_gatt_status_t status
|
||||
// uint16_t service_handle
|
||||
//
|
||||
case ESP_GATTS_STOP_EVT: {
|
||||
if (param->stop.service_handle == getHandle()) {
|
||||
m_semaphoreStopEvt.give();
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_STOP_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_CREATE_EVT
|
||||
// Called when a new service is registered as having been created.
|
||||
//
|
||||
// create:
|
||||
// * esp_gatt_status_t status
|
||||
// * uint16_t service_handle
|
||||
// * esp_gatt_srvc_id_t service_id
|
||||
// * - esp_gatt_id id
|
||||
// * - esp_bt_uuid uuid
|
||||
// * - uint8_t inst_id
|
||||
// * - bool is_primary
|
||||
//
|
||||
case ESP_GATTS_CREATE_EVT: {
|
||||
if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid)) && m_instId == param->create.service_id.id.inst_id) {
|
||||
setHandle(param->create.service_handle);
|
||||
m_semaphoreCreateEvt.give();
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_CREATE_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_DELETE_EVT
|
||||
// Called when a service is deleted.
|
||||
//
|
||||
// delete:
|
||||
// * esp_gatt_status_t status
|
||||
// * uint16_t service_handle
|
||||
//
|
||||
case ESP_GATTS_DELETE_EVT: {
|
||||
if (param->del.service_handle == getHandle()) {
|
||||
m_semaphoreDeleteEvt.give();
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_DELETE_EVT
|
||||
|
||||
default:
|
||||
break;
|
||||
} // Switch
|
||||
|
||||
// Invoke the GATTS handler in each of the associated characteristics.
|
||||
m_characteristicMap.handleGATTServerEvent(event, gatts_if, param);
|
||||
} // handleGATTServerEvent
|
||||
|
||||
|
||||
BLECharacteristic* BLEService::getCharacteristic(const char* uuid) {
|
||||
return getCharacteristic(BLEUUID(uuid));
|
||||
}
|
||||
|
||||
|
||||
BLECharacteristic* BLEService::getCharacteristic(BLEUUID uuid) {
|
||||
return m_characteristicMap.getByUUID(uuid);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of this service.
|
||||
* A service is defined by:
|
||||
* * Its UUID
|
||||
* * Its handle
|
||||
* @return A string representation of this service.
|
||||
*/
|
||||
std::string BLEService::toString() {
|
||||
std::stringstream stringStream;
|
||||
stringStream << "UUID: " << getUUID().toString() <<
|
||||
", handle: 0x" << std::hex << std::setfill('0') << std::setw(2) << getHandle();
|
||||
return stringStream.str();
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the last created characteristic.
|
||||
* It is lamentable that this function has to exist. It returns the last created characteristic.
|
||||
* We need this because the descriptor API is built around the notion that a new descriptor, when created,
|
||||
* is associated with the last characteristics created and we need that information.
|
||||
* @return The last created characteristic.
|
||||
*/
|
||||
BLECharacteristic* BLEService::getLastCreatedCharacteristic() {
|
||||
return m_lastCreatedCharacteristic;
|
||||
} // getLastCreatedCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the BLE server associated with this service.
|
||||
* @return The BLEServer associated with this service.
|
||||
*/
|
||||
BLEServer* BLEService::getServer() {
|
||||
return m_pServer;
|
||||
} // getServer
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
97
libraries/ESP32_BLE_Arduino/src/BLEService.h
Normal file
97
libraries/ESP32_BLE_Arduino/src/BLEService.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* BLEService.h
|
||||
*
|
||||
* Created on: Mar 25, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLESERVICE_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLESERVICE_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <esp_gatts_api.h>
|
||||
|
||||
#include "BLECharacteristic.h"
|
||||
#include "BLEServer.h"
|
||||
#include "BLEUUID.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
class BLEServer;
|
||||
|
||||
/**
|
||||
* @brief A data mapping used to manage the set of %BLE characteristics known to the server.
|
||||
*/
|
||||
class BLECharacteristicMap {
|
||||
public:
|
||||
void setByUUID(BLECharacteristic* pCharacteristic, const char* uuid);
|
||||
void setByUUID(BLECharacteristic* pCharacteristic, BLEUUID uuid);
|
||||
void setByHandle(uint16_t handle, BLECharacteristic* pCharacteristic);
|
||||
BLECharacteristic* getByUUID(const char* uuid);
|
||||
BLECharacteristic* getByUUID(BLEUUID uuid);
|
||||
BLECharacteristic* getByHandle(uint16_t handle);
|
||||
BLECharacteristic* getFirst();
|
||||
BLECharacteristic* getNext();
|
||||
std::string toString();
|
||||
void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param);
|
||||
|
||||
private:
|
||||
std::map<BLECharacteristic*, std::string> m_uuidMap;
|
||||
std::map<uint16_t, BLECharacteristic*> m_handleMap;
|
||||
std::map<BLECharacteristic*, std::string>::iterator m_iterator;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The model of a %BLE service.
|
||||
*
|
||||
*/
|
||||
class BLEService {
|
||||
public:
|
||||
void addCharacteristic(BLECharacteristic* pCharacteristic);
|
||||
BLECharacteristic* createCharacteristic(const char* uuid, uint32_t properties);
|
||||
BLECharacteristic* createCharacteristic(BLEUUID uuid, uint32_t properties);
|
||||
void dump();
|
||||
void executeCreate(BLEServer* pServer);
|
||||
void executeDelete();
|
||||
BLECharacteristic* getCharacteristic(const char* uuid);
|
||||
BLECharacteristic* getCharacteristic(BLEUUID uuid);
|
||||
BLEUUID getUUID();
|
||||
BLEServer* getServer();
|
||||
void start();
|
||||
void stop();
|
||||
std::string toString();
|
||||
uint16_t getHandle();
|
||||
uint8_t m_instId = 0;
|
||||
|
||||
private:
|
||||
BLEService(const char* uuid, uint16_t numHandles);
|
||||
BLEService(BLEUUID uuid, uint16_t numHandles);
|
||||
friend class BLEServer;
|
||||
friend class BLEServiceMap;
|
||||
friend class BLEDescriptor;
|
||||
friend class BLECharacteristic;
|
||||
friend class BLEDevice;
|
||||
|
||||
BLECharacteristicMap m_characteristicMap;
|
||||
uint16_t m_handle;
|
||||
BLECharacteristic* m_lastCreatedCharacteristic = nullptr;
|
||||
BLEServer* m_pServer = nullptr;
|
||||
BLEUUID m_uuid;
|
||||
|
||||
FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreDeleteEvt = FreeRTOS::Semaphore("DeleteEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreStartEvt = FreeRTOS::Semaphore("StartEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreStopEvt = FreeRTOS::Semaphore("StopEvt");
|
||||
|
||||
uint16_t m_numHandles;
|
||||
|
||||
BLECharacteristic* getLastCreatedCharacteristic();
|
||||
void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param);
|
||||
void setHandle(uint16_t handle);
|
||||
//void setService(esp_gatt_srvc_id_t srvc_id);
|
||||
}; // BLEService
|
||||
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLESERVICE_H_ */
|
||||
134
libraries/ESP32_BLE_Arduino/src/BLEServiceMap.cpp
Normal file
134
libraries/ESP32_BLE_Arduino/src/BLEServiceMap.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* BLEServiceMap.cpp
|
||||
*
|
||||
* Created on: Jun 22, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include "BLEService.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the service by UUID.
|
||||
* @param [in] UUID The UUID to look up the service.
|
||||
* @return The characteristic.
|
||||
*/
|
||||
BLEService* BLEServiceMap::getByUUID(const char* uuid) {
|
||||
return getByUUID(BLEUUID(uuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the service by UUID.
|
||||
* @param [in] UUID The UUID to look up the service.
|
||||
* @return The characteristic.
|
||||
*/
|
||||
BLEService* BLEServiceMap::getByUUID(BLEUUID uuid, uint8_t inst_id) {
|
||||
for (auto &myPair : m_uuidMap) {
|
||||
if (myPair.first->getUUID().equals(uuid)) {
|
||||
return myPair.first;
|
||||
}
|
||||
}
|
||||
//return m_uuidMap.at(uuid.toString());
|
||||
return nullptr;
|
||||
} // getByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the service by handle.
|
||||
* @param [in] handle The handle to look up the service.
|
||||
* @return The service.
|
||||
*/
|
||||
BLEService* BLEServiceMap::getByHandle(uint16_t handle) {
|
||||
return m_handleMap.at(handle);
|
||||
} // getByHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the service by UUID.
|
||||
* @param [in] uuid The uuid of the service.
|
||||
* @param [in] characteristic The service to cache.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEServiceMap::setByUUID(BLEUUID uuid, BLEService* service) {
|
||||
m_uuidMap.insert(std::pair<BLEService*, std::string>(service, uuid.toString()));
|
||||
} // setByUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the service by handle.
|
||||
* @param [in] handle The handle of the service.
|
||||
* @param [in] service The service to cache.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEServiceMap::setByHandle(uint16_t handle, BLEService* service) {
|
||||
m_handleMap.insert(std::pair<uint16_t, BLEService*>(handle, service));
|
||||
} // setByHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the service map.
|
||||
* @return A string representation of the service map.
|
||||
*/
|
||||
std::string BLEServiceMap::toString() {
|
||||
std::stringstream stringStream;
|
||||
stringStream << std::hex << std::setfill('0');
|
||||
for (auto &myPair: m_handleMap) {
|
||||
stringStream << "handle: 0x" << std::setw(2) << myPair.first << ", uuid: " + myPair.second->getUUID().toString() << "\n";
|
||||
}
|
||||
return stringStream.str();
|
||||
} // toString
|
||||
|
||||
void BLEServiceMap::handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param) {
|
||||
// Invoke the handler for every Service we have.
|
||||
for (auto &myPair : m_uuidMap) {
|
||||
myPair.first->handleGATTServerEvent(event, gatts_if, param);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the first service in the map.
|
||||
* @return The first service in the map.
|
||||
*/
|
||||
BLEService* BLEServiceMap::getFirst() {
|
||||
m_iterator = m_uuidMap.begin();
|
||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
||||
BLEService* pRet = m_iterator->first;
|
||||
m_iterator++;
|
||||
return pRet;
|
||||
} // getFirst
|
||||
|
||||
/**
|
||||
* @brief Get the next service in the map.
|
||||
* @return The next service in the map.
|
||||
*/
|
||||
BLEService* BLEServiceMap::getNext() {
|
||||
if (m_iterator == m_uuidMap.end()) return nullptr;
|
||||
BLEService* pRet = m_iterator->first;
|
||||
m_iterator++;
|
||||
return pRet;
|
||||
} // getNext
|
||||
|
||||
/**
|
||||
* @brief Removes service from maps.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEServiceMap::removeService(BLEService* service) {
|
||||
m_handleMap.erase(service->getHandle());
|
||||
m_uuidMap.erase(service);
|
||||
} // removeService
|
||||
|
||||
/**
|
||||
* @brief Returns the amount of registered services
|
||||
* @return amount of registered services
|
||||
*/
|
||||
int BLEServiceMap::getRegisteredServiceCount(){
|
||||
return m_handleMap.size();
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
407
libraries/ESP32_BLE_Arduino/src/BLEUUID.cpp
Normal file
407
libraries/ESP32_BLE_Arduino/src/BLEUUID.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* BLEUUID.cpp
|
||||
*
|
||||
* Created on: Jun 21, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "BLEUUID.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEUUID";
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Copy memory from source to target but in reverse order.
|
||||
*
|
||||
* When we move memory from one location it is normally:
|
||||
*
|
||||
* ```
|
||||
* [0][1][2]...[n] -> [0][1][2]...[n]
|
||||
* ```
|
||||
*
|
||||
* with this function, it is:
|
||||
*
|
||||
* ```
|
||||
* [0][1][2]...[n] -> [n][n-1][n-2]...[0]
|
||||
* ```
|
||||
*
|
||||
* @param [in] target The target of the copy
|
||||
* @param [in] source The source of the copy
|
||||
* @param [in] size The number of bytes to copy
|
||||
*/
|
||||
static void memrcpy(uint8_t* target, uint8_t* source, uint32_t size) {
|
||||
assert(size > 0);
|
||||
target += (size - 1); // Point target to the last byte of the target data
|
||||
while (size > 0) {
|
||||
*target = *source;
|
||||
target--;
|
||||
source++;
|
||||
size--;
|
||||
}
|
||||
} // memrcpy
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from a string.
|
||||
*
|
||||
* Create a UUID from a string. There will be two possible stories here. Either the string represents
|
||||
* a binary data field or the string represents a hex encoding of a UUID.
|
||||
* For the hex encoding, here is an example:
|
||||
*
|
||||
* ```
|
||||
* "beb5483e-36e1-4688-b7f5-ea07361b26a8"
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
* 12345678-90ab-cdef-1234-567890abcdef
|
||||
* ```
|
||||
*
|
||||
* This has a length of 36 characters. We need to parse this into 16 bytes.
|
||||
*
|
||||
* @param [in] value The string to build a UUID from.
|
||||
*/
|
||||
BLEUUID::BLEUUID(std::string value) {
|
||||
m_valueSet = true;
|
||||
if (value.length() == 4) {
|
||||
m_uuid.len = ESP_UUID_LEN_16;
|
||||
m_uuid.uuid.uuid16 = 0;
|
||||
for(int i=0;i<value.length();){
|
||||
uint8_t MSB = value.c_str()[i];
|
||||
uint8_t LSB = value.c_str()[i+1];
|
||||
|
||||
if(MSB > '9') MSB -= 7;
|
||||
if(LSB > '9') LSB -= 7;
|
||||
m_uuid.uuid.uuid16 += (((MSB&0x0F) <<4) | (LSB & 0x0F))<<(2-i)*4;
|
||||
i+=2;
|
||||
}
|
||||
}
|
||||
else if (value.length() == 8) {
|
||||
m_uuid.len = ESP_UUID_LEN_32;
|
||||
m_uuid.uuid.uuid32 = 0;
|
||||
for(int i=0;i<value.length();){
|
||||
uint8_t MSB = value.c_str()[i];
|
||||
uint8_t LSB = value.c_str()[i+1];
|
||||
|
||||
if(MSB > '9') MSB -= 7;
|
||||
if(LSB > '9') LSB -= 7;
|
||||
m_uuid.uuid.uuid32 += (((MSB&0x0F) <<4) | (LSB & 0x0F))<<(6-i)*4;
|
||||
i+=2;
|
||||
}
|
||||
}
|
||||
else if (value.length() == 16) { // how we can have 16 byte length string reprezenting 128 bit uuid??? needs to be investigated (lack of time)
|
||||
m_uuid.len = ESP_UUID_LEN_128;
|
||||
memrcpy(m_uuid.uuid.uuid128, (uint8_t*)value.data(), 16);
|
||||
}
|
||||
else if (value.length() == 36) {
|
||||
// If the length of the string is 36 bytes then we will assume it is a long hex string in
|
||||
// UUID format.
|
||||
m_uuid.len = ESP_UUID_LEN_128;
|
||||
int n = 0;
|
||||
for(int i=0;i<value.length();){
|
||||
if(value.c_str()[i] == '-')
|
||||
i++;
|
||||
uint8_t MSB = value.c_str()[i];
|
||||
uint8_t LSB = value.c_str()[i+1];
|
||||
|
||||
if(MSB > '9') MSB -= 7;
|
||||
if(LSB > '9') LSB -= 7;
|
||||
m_uuid.uuid.uuid128[15-n++] = ((MSB&0x0F) <<4) | (LSB & 0x0F);
|
||||
i+=2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ESP_LOGE(LOG_TAG, "ERROR: UUID value not 2, 4, 16 or 36 bytes");
|
||||
m_valueSet = false;
|
||||
}
|
||||
} //BLEUUID(std::string)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from 16 bytes of memory.
|
||||
*
|
||||
* @param [in] pData The pointer to the start of the UUID.
|
||||
* @param [in] size The size of the data.
|
||||
* @param [in] msbFirst Is the MSB first in pData memory?
|
||||
*/
|
||||
BLEUUID::BLEUUID(uint8_t* pData, size_t size, bool msbFirst) {
|
||||
if (size != 16) {
|
||||
ESP_LOGE(LOG_TAG, "ERROR: UUID length not 16 bytes");
|
||||
return;
|
||||
}
|
||||
m_uuid.len = ESP_UUID_LEN_128;
|
||||
if (msbFirst) {
|
||||
memrcpy(m_uuid.uuid.uuid128, pData, 16);
|
||||
} else {
|
||||
memcpy(m_uuid.uuid.uuid128, pData, 16);
|
||||
}
|
||||
m_valueSet = true;
|
||||
} // BLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from the 16bit value.
|
||||
*
|
||||
* @param [in] uuid The 16bit short form UUID.
|
||||
*/
|
||||
BLEUUID::BLEUUID(uint16_t uuid) {
|
||||
m_uuid.len = ESP_UUID_LEN_16;
|
||||
m_uuid.uuid.uuid16 = uuid;
|
||||
m_valueSet = true;
|
||||
} // BLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from the 32bit value.
|
||||
*
|
||||
* @param [in] uuid The 32bit short form UUID.
|
||||
*/
|
||||
BLEUUID::BLEUUID(uint32_t uuid) {
|
||||
m_uuid.len = ESP_UUID_LEN_32;
|
||||
m_uuid.uuid.uuid32 = uuid;
|
||||
m_valueSet = true;
|
||||
} // BLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from the native UUID.
|
||||
*
|
||||
* @param [in] uuid The native UUID.
|
||||
*/
|
||||
BLEUUID::BLEUUID(esp_bt_uuid_t uuid) {
|
||||
m_uuid = uuid;
|
||||
m_valueSet = true;
|
||||
} // BLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a UUID from the ESP32 esp_gat_id_t.
|
||||
*
|
||||
* @param [in] gattId The data to create the UUID from.
|
||||
*/
|
||||
BLEUUID::BLEUUID(esp_gatt_id_t gattId) : BLEUUID(gattId.uuid) {
|
||||
} // BLEUUID
|
||||
|
||||
|
||||
BLEUUID::BLEUUID() {
|
||||
m_valueSet = false;
|
||||
} // BLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the number of bits in this uuid.
|
||||
* @return The number of bits in the UUID. One of 16, 32 or 128.
|
||||
*/
|
||||
uint8_t BLEUUID::bitSize() {
|
||||
if (!m_valueSet) return 0;
|
||||
switch (m_uuid.len) {
|
||||
case ESP_UUID_LEN_16:
|
||||
return 16;
|
||||
case ESP_UUID_LEN_32:
|
||||
return 32;
|
||||
case ESP_UUID_LEN_128:
|
||||
return 128;
|
||||
default:
|
||||
ESP_LOGE(LOG_TAG, "Unknown UUID length: %d", m_uuid.len);
|
||||
return 0;
|
||||
} // End of switch
|
||||
} // bitSize
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compare a UUID against this UUID.
|
||||
*
|
||||
* @param [in] uuid The UUID to compare against.
|
||||
* @return True if the UUIDs are equal and false otherwise.
|
||||
*/
|
||||
bool BLEUUID::equals(BLEUUID uuid) {
|
||||
//ESP_LOGD(TAG, "Comparing: %s to %s", toString().c_str(), uuid.toString().c_str());
|
||||
if (!m_valueSet || !uuid.m_valueSet) return false;
|
||||
|
||||
if (uuid.m_uuid.len != m_uuid.len) {
|
||||
return uuid.toString() == toString();
|
||||
}
|
||||
|
||||
if (uuid.m_uuid.len == ESP_UUID_LEN_16) {
|
||||
return uuid.m_uuid.uuid.uuid16 == m_uuid.uuid.uuid16;
|
||||
}
|
||||
|
||||
if (uuid.m_uuid.len == ESP_UUID_LEN_32) {
|
||||
return uuid.m_uuid.uuid.uuid32 == m_uuid.uuid.uuid32;
|
||||
}
|
||||
|
||||
return memcmp(uuid.m_uuid.uuid.uuid128, m_uuid.uuid.uuid128, 16) == 0;
|
||||
} // equals
|
||||
|
||||
|
||||
/**
|
||||
* Create a BLEUUID from a string of the form:
|
||||
* 0xNNNN
|
||||
* 0xNNNNNNNN
|
||||
* 0x<UUID>
|
||||
* NNNN
|
||||
* NNNNNNNN
|
||||
* <UUID>
|
||||
*/
|
||||
BLEUUID BLEUUID::fromString(std::string _uuid) {
|
||||
uint8_t start = 0;
|
||||
if (strstr(_uuid.c_str(), "0x") != nullptr) { // If the string starts with 0x, skip those characters.
|
||||
start = 2;
|
||||
}
|
||||
uint8_t len = _uuid.length() - start; // Calculate the length of the string we are going to use.
|
||||
|
||||
if(len == 4) {
|
||||
uint16_t x = strtoul(_uuid.substr(start, len).c_str(), NULL, 16);
|
||||
return BLEUUID(x);
|
||||
} else if (len == 8) {
|
||||
uint32_t x = strtoul(_uuid.substr(start, len).c_str(), NULL, 16);
|
||||
return BLEUUID(x);
|
||||
} else if (len == 36) {
|
||||
return BLEUUID(_uuid);
|
||||
}
|
||||
return BLEUUID();
|
||||
} // fromString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the native UUID value.
|
||||
*
|
||||
* @return The native UUID value or NULL if not set.
|
||||
*/
|
||||
esp_bt_uuid_t* BLEUUID::getNative() {
|
||||
//ESP_LOGD(TAG, ">> getNative()")
|
||||
if (m_valueSet == false) {
|
||||
ESP_LOGD(LOG_TAG, "<< Return of un-initialized UUID!");
|
||||
return nullptr;
|
||||
}
|
||||
//ESP_LOGD(TAG, "<< getNative()");
|
||||
return &m_uuid;
|
||||
} // getNative
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert a UUID to its 128 bit representation.
|
||||
*
|
||||
* A UUID can be internally represented as 16bit, 32bit or the full 128bit. This method
|
||||
* will convert 16 or 32 bit representations to the full 128bit.
|
||||
*/
|
||||
BLEUUID BLEUUID::to128() {
|
||||
//ESP_LOGD(LOG_TAG, ">> toFull() - %s", toString().c_str());
|
||||
|
||||
// If we either don't have a value or are already a 128 bit UUID, nothing further to do.
|
||||
if (!m_valueSet || m_uuid.len == ESP_UUID_LEN_128) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If we are 16 bit or 32 bit, then set the 4 bytes of the variable part of the UUID.
|
||||
if (m_uuid.len == ESP_UUID_LEN_16) {
|
||||
uint16_t temp = m_uuid.uuid.uuid16;
|
||||
m_uuid.uuid.uuid128[15] = 0;
|
||||
m_uuid.uuid.uuid128[14] = 0;
|
||||
m_uuid.uuid.uuid128[13] = (temp >> 8) & 0xff;
|
||||
m_uuid.uuid.uuid128[12] = temp & 0xff;
|
||||
|
||||
}
|
||||
else if (m_uuid.len == ESP_UUID_LEN_32) {
|
||||
uint32_t temp = m_uuid.uuid.uuid32;
|
||||
m_uuid.uuid.uuid128[15] = (temp >> 24) & 0xff;
|
||||
m_uuid.uuid.uuid128[14] = (temp >> 16) & 0xff;
|
||||
m_uuid.uuid.uuid128[13] = (temp >> 8) & 0xff;
|
||||
m_uuid.uuid.uuid128[12] = temp & 0xff;
|
||||
}
|
||||
|
||||
// Set the fixed parts of the UUID.
|
||||
m_uuid.uuid.uuid128[11] = 0x00;
|
||||
m_uuid.uuid.uuid128[10] = 0x00;
|
||||
|
||||
m_uuid.uuid.uuid128[9] = 0x10;
|
||||
m_uuid.uuid.uuid128[8] = 0x00;
|
||||
|
||||
m_uuid.uuid.uuid128[7] = 0x80;
|
||||
m_uuid.uuid.uuid128[6] = 0x00;
|
||||
|
||||
m_uuid.uuid.uuid128[5] = 0x00;
|
||||
m_uuid.uuid.uuid128[4] = 0x80;
|
||||
m_uuid.uuid.uuid128[3] = 0x5f;
|
||||
m_uuid.uuid.uuid128[2] = 0x9b;
|
||||
m_uuid.uuid.uuid128[1] = 0x34;
|
||||
m_uuid.uuid.uuid128[0] = 0xfb;
|
||||
|
||||
m_uuid.len = ESP_UUID_LEN_128;
|
||||
//ESP_LOGD(TAG, "<< toFull <- %s", toString().c_str());
|
||||
return *this;
|
||||
} // to128
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a string representation of the UUID.
|
||||
*
|
||||
* The format of a string is:
|
||||
* 01234567 8901 2345 6789 012345678901
|
||||
* 0000180d-0000-1000-8000-00805f9b34fb
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
*
|
||||
* @return A string representation of the UUID.
|
||||
*/
|
||||
std::string BLEUUID::toString() {
|
||||
if (!m_valueSet) return "<NULL>"; // If we have no value, nothing to format.
|
||||
|
||||
// If the UUIDs are 16 or 32 bit, pad correctly.
|
||||
std::stringstream ss;
|
||||
|
||||
if (m_uuid.len == ESP_UUID_LEN_16) { // If the UUID is 16bit, pad correctly.
|
||||
ss << "0000" <<
|
||||
std::hex <<
|
||||
std::setfill('0') <<
|
||||
std::setw(4) <<
|
||||
m_uuid.uuid.uuid16 <<
|
||||
"-0000-1000-8000-00805f9b34fb";
|
||||
return ss.str(); // Return the string
|
||||
} // End 16bit UUID
|
||||
|
||||
if (m_uuid.len == ESP_UUID_LEN_32) { // If the UUID is 32bit, pad correctly.
|
||||
ss << std::hex <<
|
||||
std::setfill('0') <<
|
||||
std::setw(8) <<
|
||||
m_uuid.uuid.uuid32 <<
|
||||
"-0000-1000-8000-00805f9b34fb";
|
||||
return ss.str(); // return the string
|
||||
} // End 32bit UUID
|
||||
|
||||
// The UUID is not 16bit or 32bit which means that it is 128bit.
|
||||
//
|
||||
// UUID string format:
|
||||
// AABBCCDD-EEFF-GGHH-IIJJ-KKLLMMNNOOPP
|
||||
ss << std::hex << std::setfill('0') <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[15] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[14] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[13] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[12] << "-" <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[11] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[10] << "-" <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[9] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[8] << "-" <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[7] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[6] << "-" <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[5] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[4] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[3] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[2] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[1] <<
|
||||
std::setw(2) << (int) m_uuid.uuid.uuid128[0];
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
39
libraries/ESP32_BLE_Arduino/src/BLEUUID.h
Normal file
39
libraries/ESP32_BLE_Arduino/src/BLEUUID.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* BLEUUID.h
|
||||
*
|
||||
* Created on: Jun 21, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEUUID_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEUUID_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_gatt_defs.h>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief A model of a %BLE UUID.
|
||||
*/
|
||||
class BLEUUID {
|
||||
public:
|
||||
BLEUUID(std::string uuid);
|
||||
BLEUUID(uint16_t uuid);
|
||||
BLEUUID(uint32_t uuid);
|
||||
BLEUUID(esp_bt_uuid_t uuid);
|
||||
BLEUUID(uint8_t* pData, size_t size, bool msbFirst);
|
||||
BLEUUID(esp_gatt_id_t gattId);
|
||||
BLEUUID();
|
||||
uint8_t bitSize(); // Get the number of bits in this uuid.
|
||||
bool equals(BLEUUID uuid);
|
||||
esp_bt_uuid_t* getNative();
|
||||
BLEUUID to128();
|
||||
std::string toString();
|
||||
static BLEUUID fromString(std::string uuid); // Create a BLEUUID from a string
|
||||
|
||||
private:
|
||||
esp_bt_uuid_t m_uuid; // The underlying UUID structure that this class wraps.
|
||||
bool m_valueSet = false; // Is there a value set for this instance.
|
||||
}; // BLEUUID
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEUUID_H_ */
|
||||
2033
libraries/ESP32_BLE_Arduino/src/BLEUtils.cpp
Normal file
2033
libraries/ESP32_BLE_Arduino/src/BLEUtils.cpp
Normal file
File diff suppressed because it is too large
Load Diff
63
libraries/ESP32_BLE_Arduino/src/BLEUtils.h
Normal file
63
libraries/ESP32_BLE_Arduino/src/BLEUtils.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* BLEUtils.h
|
||||
*
|
||||
* Created on: Mar 25, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEUTILS_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEUTILS_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_gattc_api.h> // ESP32 BLE
|
||||
#include <esp_gatts_api.h> // ESP32 BLE
|
||||
#include <esp_gap_ble_api.h> // ESP32 BLE
|
||||
#include <string>
|
||||
#include "BLEClient.h"
|
||||
|
||||
/**
|
||||
* @brief A set of general %BLE utilities.
|
||||
*/
|
||||
class BLEUtils {
|
||||
public:
|
||||
static const char* addressTypeToString(esp_ble_addr_type_t type);
|
||||
static std::string adFlagsToString(uint8_t adFlags);
|
||||
static const char* advTypeToString(uint8_t advType);
|
||||
static char* buildHexData(uint8_t* target, uint8_t* source, uint8_t length);
|
||||
static std::string buildPrintData(uint8_t* source, size_t length);
|
||||
static std::string characteristicPropertiesToString(esp_gatt_char_prop_t prop);
|
||||
static const char* devTypeToString(esp_bt_dev_type_t type);
|
||||
static esp_gatt_id_t buildGattId(esp_bt_uuid_t uuid, uint8_t inst_id = 0);
|
||||
static esp_gatt_srvc_id_t buildGattSrvcId(esp_gatt_id_t gattId, bool is_primary = true);
|
||||
static void dumpGapEvent(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param);
|
||||
static void dumpGattClientEvent(
|
||||
esp_gattc_cb_event_t event,
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* evtParam);
|
||||
static void dumpGattServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* evtParam);
|
||||
static const char* eventTypeToString(esp_ble_evt_type_t eventType);
|
||||
static BLEClient* findByAddress(BLEAddress address);
|
||||
static BLEClient* findByConnId(uint16_t conn_id);
|
||||
static const char* gapEventToString(uint32_t eventType);
|
||||
static std::string gattCharacteristicUUIDToString(uint32_t characteristicUUID);
|
||||
static std::string gattClientEventTypeToString(esp_gattc_cb_event_t eventType);
|
||||
static std::string gattCloseReasonToString(esp_gatt_conn_reason_t reason);
|
||||
static std::string gattcServiceElementToString(esp_gattc_service_elem_t* pGATTCServiceElement);
|
||||
static std::string gattDescriptorUUIDToString(uint32_t descriptorUUID);
|
||||
static std::string gattServerEventTypeToString(esp_gatts_cb_event_t eventType);
|
||||
static std::string gattServiceIdToString(esp_gatt_srvc_id_t srvcId);
|
||||
static std::string gattServiceToString(uint32_t serviceId);
|
||||
static std::string gattStatusToString(esp_gatt_status_t status);
|
||||
static std::string getMember(uint32_t memberId);
|
||||
static void registerByAddress(BLEAddress address, BLEClient* pDevice);
|
||||
static void registerByConnId(uint16_t conn_id, BLEClient* pDevice);
|
||||
static const char* searchEventTypeToString(esp_gap_search_evt_t searchEvt);
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEUTILS_H_ */
|
||||
139
libraries/ESP32_BLE_Arduino/src/BLEValue.cpp
Normal file
139
libraries/ESP32_BLE_Arduino/src/BLEValue.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* BLEValue.cpp
|
||||
*
|
||||
* Created on: Jul 17, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include "BLEValue.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG="BLEValue";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
BLEValue::BLEValue() {
|
||||
m_accumulation = "";
|
||||
m_value = "";
|
||||
m_readOffset = 0;
|
||||
} // BLEValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a message part to the accumulation.
|
||||
* The accumulation is a growing set of data that is added to until a commit or cancel.
|
||||
* @param [in] part A message part being added.
|
||||
*/
|
||||
void BLEValue::addPart(std::string part) {
|
||||
ESP_LOGD(LOG_TAG, ">> addPart: length=%d", part.length());
|
||||
m_accumulation += part;
|
||||
} // addPart
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a message part to the accumulation.
|
||||
* The accumulation is a growing set of data that is added to until a commit or cancel.
|
||||
* @param [in] pData A message part being added.
|
||||
* @param [in] length The number of bytes being added.
|
||||
*/
|
||||
void BLEValue::addPart(uint8_t* pData, size_t length) {
|
||||
ESP_LOGD(LOG_TAG, ">> addPart: length=%d", length);
|
||||
m_accumulation += std::string((char*) pData, length);
|
||||
} // addPart
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cancel the current accumulation.
|
||||
*/
|
||||
void BLEValue::cancel() {
|
||||
ESP_LOGD(LOG_TAG, ">> cancel");
|
||||
m_accumulation = "";
|
||||
m_readOffset = 0;
|
||||
} // cancel
|
||||
|
||||
|
||||
/**
|
||||
* @brief Commit the current accumulation.
|
||||
* When writing a value, we may find that we write it in "parts" meaning that the writes come in in pieces
|
||||
* of the overall message. After the last part has been received, we may perform a commit which means that
|
||||
* we now have the complete message and commit the change as a unit.
|
||||
*/
|
||||
void BLEValue::commit() {
|
||||
ESP_LOGD(LOG_TAG, ">> commit");
|
||||
// If there is nothing to commit, do nothing.
|
||||
if (m_accumulation.length() == 0) return;
|
||||
setValue(m_accumulation);
|
||||
m_accumulation = "";
|
||||
m_readOffset = 0;
|
||||
} // commit
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the data.
|
||||
* @return A pointer to the data.
|
||||
*/
|
||||
uint8_t* BLEValue::getData() {
|
||||
return (uint8_t*) m_value.data();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the length of the data in bytes.
|
||||
* @return The length of the data in bytes.
|
||||
*/
|
||||
size_t BLEValue::getLength() {
|
||||
return m_value.length();
|
||||
} // getLength
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the read offset.
|
||||
* @return The read offset into the read.
|
||||
*/
|
||||
uint16_t BLEValue::getReadOffset() {
|
||||
return m_readOffset;
|
||||
} // getReadOffset
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the current value.
|
||||
*/
|
||||
std::string BLEValue::getValue() {
|
||||
return m_value;
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the read offset
|
||||
* @param [in] readOffset The offset into the read.
|
||||
*/
|
||||
void BLEValue::setReadOffset(uint16_t readOffset) {
|
||||
m_readOffset = readOffset;
|
||||
} // setReadOffset
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the current value.
|
||||
*/
|
||||
void BLEValue::setValue(std::string value) {
|
||||
m_value = value;
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the current value.
|
||||
* @param [in] pData The data for the current value.
|
||||
* @param [in] The length of the new current value.
|
||||
*/
|
||||
void BLEValue::setValue(uint8_t* pData, size_t length) {
|
||||
m_value = std::string((char*) pData, length);
|
||||
} // setValue
|
||||
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
39
libraries/ESP32_BLE_Arduino/src/BLEValue.h
Normal file
39
libraries/ESP32_BLE_Arduino/src/BLEValue.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* BLEValue.h
|
||||
*
|
||||
* Created on: Jul 17, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEVALUE_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEVALUE_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief The model of a %BLE value.
|
||||
*/
|
||||
class BLEValue {
|
||||
public:
|
||||
BLEValue();
|
||||
void addPart(std::string part);
|
||||
void addPart(uint8_t* pData, size_t length);
|
||||
void cancel();
|
||||
void commit();
|
||||
uint8_t* getData();
|
||||
size_t getLength();
|
||||
uint16_t getReadOffset();
|
||||
std::string getValue();
|
||||
void setReadOffset(uint16_t readOffset);
|
||||
void setValue(std::string value);
|
||||
void setValue(uint8_t* pData, size_t length);
|
||||
|
||||
private:
|
||||
std::string m_accumulation;
|
||||
uint16_t m_readOffset;
|
||||
std::string m_value;
|
||||
|
||||
};
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEVALUE_H_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user