Adding Pico W AIO and USB Host to BLE project code
Adding Arduino code for two projects: Pico W DVI AIO display and the USB host featherwing to BLE
This commit is contained in:
parent
56fd748b19
commit
1afc27f9b1
6 changed files with 666 additions and 0 deletions
0
PicoW_DVI_AIO_Display/.pico_rp2040.test.only
Normal file
0
PicoW_DVI_AIO_Display/.pico_rp2040.test.only
Normal file
193
PicoW_DVI_AIO_Display/PicoW_DVI_AIO_Display.ino
Normal file
193
PicoW_DVI_AIO_Display/PicoW_DVI_AIO_Display.ino
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
// SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/************************** Configuration ***********************************/
|
||||
|
||||
// edit the config.h tab and enter your Adafruit IO credentials
|
||||
// and any additional configuration needed for WiFi, cellular,
|
||||
// or ethernet clients.
|
||||
#include "config.h"
|
||||
#include "sprites.h"
|
||||
#include <PicoDVI.h> // Core display & graphics library
|
||||
#include <Fonts/FreeSansBold18pt7b.h> // A custom font
|
||||
#include <Fonts/FreeSans9pt7b.h> // A custom font
|
||||
|
||||
// put your four feed names here!
|
||||
|
||||
AdafruitIO_Feed *temp = io.feed("temperature-feed");
|
||||
AdafruitIO_Feed *humid = io.feed("humidity-feed");
|
||||
AdafruitIO_Feed *bat = io.feed("battery-feed");
|
||||
AdafruitIO_Feed *aqi = io.feed("aqi-feed");
|
||||
|
||||
#define IO_LOOP_DELAY 5000
|
||||
unsigned long lastUpdate = 0;
|
||||
float temp_data;
|
||||
float humid_data;
|
||||
int bat_data;
|
||||
int aqi_data;
|
||||
|
||||
struct outline {
|
||||
int16_t x, y; // Top-left corner
|
||||
};
|
||||
|
||||
outline greenOutline = {159, 35};
|
||||
outline yellowOutline = {204, 35};
|
||||
outline redOutline = {250, 35};
|
||||
|
||||
DVIGFX8 display(DVI_RES_320x240p60, false, adafruit_dvibell_cfg);
|
||||
|
||||
void setup() {
|
||||
|
||||
// start the serial connection
|
||||
Serial.begin(115200);
|
||||
|
||||
// wait for serial monitor to open
|
||||
//while ( !Serial ) delay(10);
|
||||
|
||||
Serial.print("Connecting to Adafruit IO");
|
||||
|
||||
// start connection to io.adafruit.com
|
||||
io.connect();
|
||||
|
||||
// set up a message handler for the count feed.
|
||||
// the handleMessage function (defined below)
|
||||
// will be called whenever a message is
|
||||
// received from adafruit io.
|
||||
temp->onMessage(tempMessage);
|
||||
humid->onMessage(humidMessage);
|
||||
bat->onMessage(batMessage);
|
||||
aqi->onMessage(aqiMessage);
|
||||
|
||||
// wait for a connection
|
||||
while(io.status() < AIO_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(500);
|
||||
}
|
||||
// we are connected
|
||||
Serial.println();
|
||||
Serial.println(io.statusText());
|
||||
|
||||
// Because Adafruit IO doesn't support the MQTT retain flag, we can use the
|
||||
// get() function to ask IO to resend the last value for this feed to just
|
||||
// this MQTT client after the io client is connected.
|
||||
temp->get();
|
||||
humid->get();
|
||||
bat->get();
|
||||
aqi->get();
|
||||
|
||||
Serial.println("starting picodvi..");
|
||||
if (!display.begin()) { // Blink LED if insufficient RAM
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
for (;;) digitalWrite(LED_BUILTIN, (millis() / 500) & 1);
|
||||
}
|
||||
Serial.println("picodvi good to go");
|
||||
|
||||
// Set up color palette
|
||||
display.setColor(0, 0x0000); // black
|
||||
display.setColor(1, 0x057D); // blue
|
||||
display.setColor(2, 0xB77F); // light blue
|
||||
display.setColor(3, 0xE8E4); // red
|
||||
display.setColor(4, 0x3DA9); // green
|
||||
display.setColor(5, 0xFF80); // yellow
|
||||
display.setColor(6, 0xFFFF); // white
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// io.run(); is required for all sketches.
|
||||
// it should always be present at the top of your loop
|
||||
// function. it keeps the client connected to
|
||||
// io.adafruit.com, and processes any incoming data.
|
||||
io.run();
|
||||
|
||||
if (millis() > (lastUpdate + IO_LOOP_DELAY)) {
|
||||
display.fillScreen(0);
|
||||
display.drawBitmap(38, 35, airBitmap, airWidth, airHeight, 2);
|
||||
display.drawBitmap(47, 132, tempBitmap, tempWidth, tempHeight, 3);
|
||||
display.drawBitmap(145, 132, waterBitmap, waterWidth, waterHeight, 1);
|
||||
display.drawBitmap(248, 132, batBitmap, batWidth, batHeight, 6);
|
||||
drawBatterySquare(bat_data);
|
||||
displayAQI(aqi_data);
|
||||
display.setFont(&FreeSansBold18pt7b);
|
||||
display.setTextColor(6);
|
||||
display.setCursor(38 + airWidth + 15, 38 + airHeight - 10);
|
||||
display.println(aqi_data);
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
display.setCursor(47 - 9, 130 + tempHeight + 25);
|
||||
display.print(temp_data, 2);
|
||||
display.println(" F");
|
||||
display.setCursor(145 - 9, 130 + tempHeight + 25);
|
||||
display.print(humid_data, 2);
|
||||
display.println("%");
|
||||
display.setCursor(248 - 5, 130 + tempHeight + 25);
|
||||
display.print(bat_data);
|
||||
display.println("%");
|
||||
// store the current time
|
||||
lastUpdate = millis();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void humidMessage(AdafruitIO_Data *data) {
|
||||
//Serial.print("received <- ");
|
||||
Serial.println(data->value());
|
||||
String h = data->value();
|
||||
humid_data = h.toFloat();
|
||||
}
|
||||
|
||||
void tempMessage(AdafruitIO_Data *data) {
|
||||
//Serial.print("received <- ");
|
||||
Serial.println(data->value());
|
||||
String d = data->value();
|
||||
temp_data = d.toFloat();
|
||||
}
|
||||
|
||||
void batMessage(AdafruitIO_Data *data) {
|
||||
//Serial.print("received <- ");
|
||||
Serial.println(data->value());
|
||||
String b = data->value();
|
||||
bat_data = b.toInt();
|
||||
}
|
||||
|
||||
void aqiMessage(AdafruitIO_Data *data) {
|
||||
//Serial.print("received <- ");
|
||||
Serial.println(data->value());
|
||||
String a = data->value();
|
||||
aqi_data = a.toInt();
|
||||
}
|
||||
|
||||
void displayAQI(int data) {
|
||||
display.fillRoundRect(164, 40, 30, 30, 4, 4);
|
||||
display.fillRoundRect(209, 40, 30, 30, 4, 5);
|
||||
display.fillRoundRect(255, 40, 30, 30, 4, 3);
|
||||
if (data <= 12) { // Good
|
||||
display.drawRoundRect(greenOutline.x, greenOutline.y, 40, 40, 4, 6);
|
||||
} else if (data <= 35) { // Bad
|
||||
display.drawRoundRect(yellowOutline.x, yellowOutline.y, 40, 40, 4, 6);
|
||||
} else { // Dangerous
|
||||
display.drawRoundRect(redOutline.x, redOutline.y, 40, 40, 4, 6);
|
||||
}
|
||||
}
|
||||
|
||||
void drawBatterySquare(int data) {
|
||||
int BASE_SQUARE_X = 252; // Base X position
|
||||
int BASE_SQUARE_Y = 140; // Base Y position
|
||||
int SQUARE_WIDTH = 21; // Width is constant
|
||||
int MAX_SQUARE_HEIGHT = 35; // Maximum height for 100% charge
|
||||
// Map battery percentage to square height
|
||||
int height = map(data, 0, 100, 0, MAX_SQUARE_HEIGHT);
|
||||
// Choose color based on battery percentage
|
||||
uint16_t color;
|
||||
if (data >= 70) {
|
||||
color = 4;
|
||||
} else if (data >= 40) {
|
||||
color = 5;
|
||||
} else {
|
||||
color = 3;
|
||||
}
|
||||
// Calculate Y position based on height to draw from bottom up
|
||||
int yPos = BASE_SQUARE_Y + (MAX_SQUARE_HEIGHT - height);
|
||||
// Draw the battery square
|
||||
display.fillRect(BASE_SQUARE_X, yPos, SQUARE_WIDTH, height, color);
|
||||
}
|
||||
76
PicoW_DVI_AIO_Display/config.h
Normal file
76
PicoW_DVI_AIO_Display/config.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/************************ Adafruit IO Config *******************************/
|
||||
|
||||
// visit io.adafruit.com if you need to create an account,
|
||||
// or if you need your Adafruit IO key.
|
||||
#define IO_USERNAME "YOUR-AIO-USERNAME"
|
||||
#define IO_KEY "YOUR-AIO-KEY"
|
||||
|
||||
/******************************* WIFI **************************************/
|
||||
|
||||
// the AdafruitIO_WiFi client will work with the following boards:
|
||||
// - HUZZAH ESP8266 Breakout -> https://www.adafruit.com/products/2471
|
||||
// - Feather HUZZAH ESP8266 -> https://www.adafruit.com/products/2821
|
||||
// - Feather HUZZAH ESP32 -> https://www.adafruit.com/product/3405
|
||||
// - Feather M0 WiFi -> https://www.adafruit.com/products/3010
|
||||
// - Feather WICED -> https://www.adafruit.com/products/3056
|
||||
// - Adafruit PyPortal -> https://www.adafruit.com/product/4116
|
||||
// - Adafruit Metro M4 Express AirLift Lite ->
|
||||
// https://www.adafruit.com/product/4000
|
||||
// - Adafruit AirLift Breakout -> https://www.adafruit.com/product/4201
|
||||
// - Adafruit AirLift Shield -> https://www.adafruit.com/product/4285
|
||||
// - Adafruit AirLift FeatherWing -> https://www.adafruit.com/product/4264
|
||||
|
||||
#define WIFI_SSID "YOUR-WIFI-SSID"
|
||||
#define WIFI_PASS "YOUR-WIFI-SSID-PASSWORD"
|
||||
|
||||
// uncomment the following line if you are using airlift
|
||||
// #define USE_AIRLIFT
|
||||
|
||||
// uncomment the following line if you are using winc1500
|
||||
// #define USE_WINC1500
|
||||
|
||||
// uncomment the following line if you are using mrk1010 or nano 33 iot
|
||||
//#define ARDUINO_SAMD_MKR1010
|
||||
|
||||
// comment out the following lines if you are using fona or ethernet
|
||||
#include "AdafruitIO_WiFi.h"
|
||||
|
||||
#if defined(USE_AIRLIFT) || defined(ADAFRUIT_METRO_M4_AIRLIFT_LITE) || \
|
||||
defined(ADAFRUIT_PYPORTAL)
|
||||
// Configure the pins used for the ESP32 connection
|
||||
#if !defined(SPIWIFI_SS) // if the wifi definition isnt in the board variant
|
||||
// Don't change the names of these #define's! they match the variant ones
|
||||
#define SPIWIFI SPI
|
||||
#define SPIWIFI_SS 10 // Chip select pin
|
||||
#define NINA_ACK 9 // a.k.a BUSY or READY pin
|
||||
#define NINA_RESETN 6 // Reset pin
|
||||
#define NINA_GPIO0 -1 // Not connected
|
||||
#endif
|
||||
AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS, SPIWIFI_SS,
|
||||
NINA_ACK, NINA_RESETN, NINA_GPIO0, &SPIWIFI);
|
||||
#else
|
||||
AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);
|
||||
#endif
|
||||
/******************************* FONA **************************************/
|
||||
|
||||
// the AdafruitIO_FONA client will work with the following boards:
|
||||
// - Feather 32u4 FONA -> https://www.adafruit.com/product/3027
|
||||
|
||||
// uncomment the following two lines for 32u4 FONA,
|
||||
// and comment out the AdafruitIO_WiFi client in the WIFI section
|
||||
// #include "AdafruitIO_FONA.h"
|
||||
// AdafruitIO_FONA io(IO_USERNAME, IO_KEY);
|
||||
|
||||
/**************************** ETHERNET ************************************/
|
||||
|
||||
// the AdafruitIO_Ethernet client will work with the following boards:
|
||||
// - Ethernet FeatherWing -> https://www.adafruit.com/products/3201
|
||||
|
||||
// uncomment the following two lines for ethernet,
|
||||
// and comment out the AdafruitIO_WiFi client in the WIFI section
|
||||
// #include "AdafruitIO_Ethernet.h"
|
||||
// AdafruitIO_Ethernet io(IO_USERNAME, IO_KEY);
|
||||
81
PicoW_DVI_AIO_Display/sprites.h
Normal file
81
PicoW_DVI_AIO_Display/sprites.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
// SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#define airWidth 31
|
||||
#define airHeight 38
|
||||
const uint8_t PROGMEM airBitmap[] = {
|
||||
0x00, 0x00, 0x01, 0x80, 0x00, 0x38, 0x03, 0xC0, 0x00, 0x10, 0x07, 0xC0, 0x07,
|
||||
0x00, 0xC7, 0xC0, 0x0F, 0x81, 0xE3, 0xC0, 0x0F, 0x81, 0xE0, 0x00, 0x0F, 0x81,
|
||||
0xE0, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0F,
|
||||
0x00, 0x00, 0x1E, 0x1F, 0x80, 0x00, 0x3E, 0x3F, 0xC0, 0x00, 0x1E, 0x3F, 0xC0,
|
||||
0x00, 0x1C, 0x3F, 0xC0, 0x18, 0x00, 0x3F, 0xC0, 0x38, 0x00, 0x1F, 0xC0, 0x10,
|
||||
0x00, 0x0F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3F,
|
||||
0xE0, 0x38, 0x00, 0xFF, 0xF8, 0x38, 0x01, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFC,
|
||||
0x00, 0x03, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, 0xE0,
|
||||
0x1F, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0x7F,
|
||||
0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF,
|
||||
0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF,
|
||||
0xF8, 0x1F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xC0
|
||||
};
|
||||
|
||||
#define batWidth 29
|
||||
#define batHeight 46
|
||||
const uint8_t PROGMEM batBitmap[] = {
|
||||
0x00, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x01,
|
||||
0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x3F, 0xFF,
|
||||
0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0xF0, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00,
|
||||
0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70,
|
||||
0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70,
|
||||
0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00,
|
||||
0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00,
|
||||
0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70,
|
||||
0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70,
|
||||
0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00,
|
||||
0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00,
|
||||
0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70,
|
||||
0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x70, 0x70,
|
||||
0x00, 0x00, 0x70, 0x7F, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF,
|
||||
0xFF, 0xC0
|
||||
};
|
||||
|
||||
#define tempWidth 29
|
||||
#define tempHeight 47
|
||||
const uint8_t PROGMEM tempBitmap[] = {
|
||||
0x00, 0x0F, 0x80, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x01,
|
||||
0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x07, 0xFF,
|
||||
0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF,
|
||||
0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00,
|
||||
0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07,
|
||||
0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF,
|
||||
0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF,
|
||||
0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00,
|
||||
0x0F, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0xE0, 0x3F,
|
||||
0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF,
|
||||
0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF,
|
||||
0xF8, 0x7F, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xF0,
|
||||
0x3F, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xC0, 0x0F,
|
||||
0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x7F,
|
||||
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
#define waterWidth 31
|
||||
#define waterHeight 49
|
||||
const uint8_t PROGMEM waterBitmap[] = {
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x00,
|
||||
0x0F, 0xE0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x3F,
|
||||
0xF0, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x7F, 0xFC,
|
||||
0x00, 0x00, 0x7F, 0xFC, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFE, 0x00,
|
||||
0x01, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x03,
|
||||
0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF,
|
||||
0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF,
|
||||
0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xF8,
|
||||
0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0xFF,
|
||||
0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF,
|
||||
0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
||||
0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC,
|
||||
0x7F, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xF8, 0x1F,
|
||||
0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xC0, 0x03, 0xFF,
|
||||
0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x07, 0xC0,
|
||||
0x00
|
||||
};
|
||||
0
USB_Host_to_BLE_Arduino/.feather_esp32s3_tft.test.only
Normal file
0
USB_Host_to_BLE_Arduino/.feather_esp32s3_tft.test.only
Normal file
316
USB_Host_to_BLE_Arduino/USB_Host_to_BLE_Arduino.ino
Normal file
316
USB_Host_to_BLE_Arduino/USB_Host_to_BLE_Arduino.ino
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
// SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Uses the Adafruit ESP32-S3 TFT with the MAX3421E FeatherWing
|
||||
// Acts as a USB keyboard to BLE converter
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
#include "BLEDevice.h"
|
||||
#include "BLEHIDDevice.h"
|
||||
#include "HIDTypes.h"
|
||||
#include "HIDKeyboardTypes.h"
|
||||
#include "Adafruit_MAX1704X.h"
|
||||
#include "Adafruit_LC709203F.h"
|
||||
#include <Adafruit_ST7789.h>
|
||||
#include <Fonts/FreeSans12pt7b.h>
|
||||
|
||||
Adafruit_USBH_Host USBHost(&SPI, 10, 9);
|
||||
|
||||
#define US_KEYBOARD 1
|
||||
#define DEVICE_NAME "ESP32 Keyboard"
|
||||
#define BLE_MANUFACTURER "TinyUSB"
|
||||
|
||||
Adafruit_LC709203F lc_bat;
|
||||
Adafruit_MAX17048 max_bat;
|
||||
|
||||
Adafruit_ST7789 display = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
|
||||
BLEHIDDevice* hid;
|
||||
BLECharacteristic* input;
|
||||
BLECharacteristic* output;
|
||||
String keyInput = "";
|
||||
|
||||
GFXcanvas16 canvas(240, 135);
|
||||
|
||||
bool maxfound = false;
|
||||
bool lcfound = false;
|
||||
bool isBleConnected = false;
|
||||
|
||||
unsigned long previousMillis = 0;
|
||||
const long interval = 500;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
// while ( !Serial ) delay(10); // wait for native usb
|
||||
// turn on the TFT / I2C power supply
|
||||
pinMode(TFT_I2C_POWER, OUTPUT);
|
||||
digitalWrite(TFT_I2C_POWER, HIGH);
|
||||
pinMode(TFT_BACKLITE, OUTPUT);
|
||||
digitalWrite(TFT_BACKLITE, HIGH);
|
||||
display.init(135, 240); // Init ST7789 240x135
|
||||
display.setRotation(3);
|
||||
canvas.setFont(&FreeSans12pt7b);
|
||||
canvas.setTextColor(ST77XX_WHITE);
|
||||
canvas.fillScreen(ST77XX_BLACK);
|
||||
canvas.setCursor(0, 25);
|
||||
canvas.println("Connecting to BLE..");
|
||||
display.drawRGBBitmap(0, 0, canvas.getBuffer(), 240, 135);
|
||||
// start Bluetooth task
|
||||
xTaskCreate(bluetoothTask, "bluetooth", 20000, NULL, 5, NULL);
|
||||
canvas.fillScreen(ST77XX_BLACK);
|
||||
canvas.setCursor(0, 25);
|
||||
canvas.println("BLE Connected!");
|
||||
canvas.println("Finding USB device..");
|
||||
display.drawRGBBitmap(0, 0, canvas.getBuffer(), 240, 135);
|
||||
// init host stack on controller (rhport) 1
|
||||
USBHost.begin(1);
|
||||
Serial.println("TinyUSB Dual: HID Device to ESP BLE Keyboard");
|
||||
canvas.fillScreen(ST77XX_BLACK);
|
||||
canvas.setCursor(0, 25);
|
||||
canvas.println("BLE Connected!");
|
||||
canvas.println("USB Connected!");
|
||||
display.drawRGBBitmap(0, 0, canvas.getBuffer(), 240, 135);
|
||||
|
||||
if (lc_bat.begin()) {
|
||||
Serial.println("Found LC709203F");
|
||||
Serial.print("Version: 0x"); Serial.println(lc_bat.getICversion(), HEX);
|
||||
lc_bat.setPackSize(LC709203F_APA_500MAH);
|
||||
lcfound = true;
|
||||
}
|
||||
else {
|
||||
Serial.println(F("Couldnt find Adafruit LC709203F?\nChecking for Adafruit MAX1704X.."));
|
||||
delay(200);
|
||||
if (!max_bat.begin()) {
|
||||
Serial.println(F("Couldnt find Adafruit MAX1704X?\nMake sure a battery is plugged in!"));
|
||||
while (1) delay(10);
|
||||
}
|
||||
Serial.print(F("Found MAX17048"));
|
||||
Serial.print(F(" with Chip ID: 0x"));
|
||||
Serial.println(max_bat.getChipID(), HEX);
|
||||
maxfound = true;
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
unsigned long currentMillis = millis();
|
||||
USBHost.task();
|
||||
//Serial.flush();
|
||||
if (currentMillis - previousMillis >= interval) {
|
||||
previousMillis = currentMillis;
|
||||
canvas.fillScreen(ST77XX_BLACK);
|
||||
canvas.setCursor(0, 25);
|
||||
canvas.setTextColor(ST77XX_RED);
|
||||
canvas.println("Adafruit Feather");
|
||||
canvas.setTextColor(ST77XX_YELLOW);
|
||||
canvas.println("USB Host -> BLE");
|
||||
canvas.setTextColor(ST77XX_GREEN);
|
||||
canvas.print("Battery: ");
|
||||
canvas.setTextColor(ST77XX_WHITE);
|
||||
if (lcfound == true) {
|
||||
canvas.print(lc_bat.cellVoltage(), 1);
|
||||
canvas.print(" V / ");
|
||||
canvas.print(lc_bat.cellPercent(), 0);
|
||||
canvas.println("%");
|
||||
hid->setBatteryLevel(lc_bat.cellPercent());
|
||||
} else {
|
||||
canvas.print(max_bat.cellVoltage(), 1);
|
||||
canvas.print(" V / ");
|
||||
canvas.print(max_bat.cellPercent(), 0);
|
||||
canvas.println("%");
|
||||
hid->setBatteryLevel(max_bat.cellPercent());
|
||||
}
|
||||
canvas.setTextColor(ST77XX_BLUE);
|
||||
canvas.print("Sent: ");
|
||||
canvas.setTextColor(ST77XX_WHITE);
|
||||
canvas.println(keyInput);
|
||||
display.drawRGBBitmap(0, 0, canvas.getBuffer(), 240, 135);
|
||||
|
||||
}
|
||||
}
|
||||
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *msg, uint16_t len);
|
||||
|
||||
|
||||
// Message (report) sent when a key is pressed or released
|
||||
struct InputReport {
|
||||
uint8_t modifiers; // bitmask: CTRL = 1, SHIFT = 2, ALT = 4
|
||||
uint8_t reserved; // must be 0
|
||||
uint8_t pressedKeys[6]; // up to six concurrenlty pressed keys
|
||||
};
|
||||
|
||||
// The report map describes the HID device (a keyboard in this case) and
|
||||
// the messages (reports in HID terms) sent and received.
|
||||
static const uint8_t REPORT_MAP[] = {
|
||||
USAGE_PAGE(1), 0x01, // Generic Desktop Controls
|
||||
USAGE(1), 0x06, // Keyboard
|
||||
COLLECTION(1), 0x01, // Application
|
||||
REPORT_ID(1), 0x01, // Report ID (1)
|
||||
USAGE_PAGE(1), 0x07, // Keyboard/Keypad
|
||||
USAGE_MINIMUM(1), 0xE0, // Keyboard Left Control
|
||||
USAGE_MAXIMUM(1), 0xE7, // Keyboard Right Control
|
||||
LOGICAL_MINIMUM(1), 0x00, // Each bit is either 0 or 1
|
||||
LOGICAL_MAXIMUM(1), 0x01,
|
||||
REPORT_COUNT(1), 0x08, // 8 bits for the modifier keys
|
||||
REPORT_SIZE(1), 0x01,
|
||||
HIDINPUT(1), 0x02, // Data, Var, Abs
|
||||
REPORT_COUNT(1), 0x01, // 1 byte (unused)
|
||||
REPORT_SIZE(1), 0x08,
|
||||
HIDINPUT(1), 0x01, // Const, Array, Abs
|
||||
REPORT_COUNT(1), 0x06, // 6 bytes (for up to 6 concurrently pressed keys)
|
||||
REPORT_SIZE(1), 0x08,
|
||||
LOGICAL_MINIMUM(1), 0x00,
|
||||
LOGICAL_MAXIMUM(1), 0x65, // 101 keys
|
||||
USAGE_MINIMUM(1), 0x00,
|
||||
USAGE_MAXIMUM(1), 0x65,
|
||||
HIDINPUT(1), 0x00, // Data, Array, Abs
|
||||
REPORT_COUNT(1), 0x05, // 5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana)
|
||||
REPORT_SIZE(1), 0x01,
|
||||
USAGE_PAGE(1), 0x08, // LEDs
|
||||
USAGE_MINIMUM(1), 0x01, // Num Lock
|
||||
USAGE_MAXIMUM(1), 0x05, // Kana
|
||||
LOGICAL_MINIMUM(1), 0x00,
|
||||
LOGICAL_MAXIMUM(1), 0x01,
|
||||
HIDOUTPUT(1), 0x02, // Data, Var, Abs
|
||||
REPORT_COUNT(1), 0x01, // 3 bits (Padding)
|
||||
REPORT_SIZE(1), 0x03,
|
||||
HIDOUTPUT(1), 0x01, // Const, Array, Abs
|
||||
END_COLLECTION(0) // End application collection
|
||||
};
|
||||
|
||||
const InputReport NO_KEY_PRESSED = { };
|
||||
|
||||
/*
|
||||
* Callbacks related to BLE connection
|
||||
*/
|
||||
class BleKeyboardCallbacks : public BLEServerCallbacks {
|
||||
|
||||
void onConnect(BLEServer* server) {
|
||||
isBleConnected = true;
|
||||
|
||||
// Allow notifications for characteristics
|
||||
BLE2902* cccDesc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
|
||||
cccDesc->setNotifications(true);
|
||||
|
||||
Serial.println("Client has connected");
|
||||
}
|
||||
|
||||
void onDisconnect(BLEServer* server) {
|
||||
isBleConnected = false;
|
||||
|
||||
// Disallow notifications for characteristics
|
||||
BLE2902* cccDesc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
|
||||
cccDesc->setNotifications(false);
|
||||
|
||||
Serial.println("Client has disconnected");
|
||||
}
|
||||
};
|
||||
|
||||
void bluetoothTask(void*) {
|
||||
|
||||
BLEDevice::init(DEVICE_NAME);
|
||||
BLEServer* server = BLEDevice::createServer();
|
||||
server->setCallbacks(new BleKeyboardCallbacks());
|
||||
|
||||
// create an HID device
|
||||
hid = new BLEHIDDevice(server);
|
||||
input = hid->inputReport(1); // report ID
|
||||
|
||||
// set manufacturer name
|
||||
hid->manufacturer()->setValue(BLE_MANUFACTURER);
|
||||
// set USB vendor and product ID
|
||||
hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
|
||||
// information about HID device: device is not localized, device can be connected
|
||||
hid->hidInfo(0x00, 0x02);
|
||||
// Security: device requires bonding
|
||||
BLESecurity* security = new BLESecurity();
|
||||
security->setAuthenticationMode(ESP_LE_AUTH_BOND);
|
||||
|
||||
// set report map
|
||||
hid->reportMap((uint8_t*)REPORT_MAP, sizeof(REPORT_MAP));
|
||||
hid->startServices();
|
||||
|
||||
// set battery level to 100%
|
||||
hid->setBatteryLevel(100);
|
||||
|
||||
// advertise the services
|
||||
BLEAdvertising* advertising = server->getAdvertising();
|
||||
advertising->setAppearance(HID_KEYBOARD);
|
||||
advertising->addServiceUUID(hid->hidService()->getUUID());
|
||||
advertising->addServiceUUID(hid->deviceInfo()->getUUID());
|
||||
advertising->addServiceUUID(hid->batteryService()->getUUID());
|
||||
advertising->start();
|
||||
|
||||
Serial.println("BLE ready");
|
||||
delay(portMAX_DELAY);
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Invoked when device with hid interface is mounted
|
||||
// Report descriptor is also available for use.
|
||||
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
|
||||
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
||||
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
||||
|
||||
(void) desc_report;
|
||||
(void) desc_len;
|
||||
uint16_t vid, pid;
|
||||
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||
|
||||
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
|
||||
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
|
||||
hid->pnp(0x02, vid, 0xa111, pid);
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
Serial.printf("Error: cannot request to receive report\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when device with hid interface is un-mounted
|
||||
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||||
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
||||
}
|
||||
|
||||
// Invoked when received report from device via interrupt endpoint
|
||||
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *msg, uint16_t len) {
|
||||
// continue to request to receive report
|
||||
//unsigned long a = millis();
|
||||
if (!isBleConnected) return;
|
||||
//Serial.println(messageLength);
|
||||
if (msg[2] != 0) {
|
||||
for (uint8_t i = 2; i < len; i++) {
|
||||
// translate character to key combination
|
||||
// Assuming your USB message fits the format required by the BLE keyboard
|
||||
// You might need to adjust this depending on your actual USB message format
|
||||
|
||||
InputReport report = {
|
||||
.modifiers = msg[0], // No modifier for now
|
||||
.reserved = 0,
|
||||
.pressedKeys = {msg[i], 0, 0, 0, 0, 0}
|
||||
};
|
||||
input->setValue((uint8_t*)&report, sizeof(report));
|
||||
input->notify();
|
||||
delay(1);
|
||||
// release all keys between two characters; otherwise two identical
|
||||
// consecutive characters are treated as just one key press
|
||||
input->setValue((uint8_t*)&NO_KEY_PRESSED, sizeof(NO_KEY_PRESSED));
|
||||
input->notify();
|
||||
delay(1);
|
||||
}
|
||||
char formattedString[6]; // Large enough for "0x" + 2 hex digits + null terminator
|
||||
sprintf(formattedString, "0x%02X", msg[2]);
|
||||
//if (strcmp(formattedString, "0x00") != 0) {
|
||||
keyInput = "";
|
||||
keyInput = formattedString;
|
||||
//Serial.println(keyInput);
|
||||
//}
|
||||
}
|
||||
//sendUSBMessageOverBLE(report, len);
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
Serial.printf("Error: cannot request to receive report\r\n");
|
||||
}
|
||||
//unsigned long b = millis();
|
||||
//Serial.println(b-a);
|
||||
}
|
||||
|
||||
} // extern C
|
||||
Loading…
Reference in a new issue