/ EyeLights_Bluetooth_Scroller / EyeLights_Bluetooth_Scroller.ino
EyeLights_Bluetooth_Scroller.ino
1 // SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries 2 // 3 // SPDX-License-Identifier: MIT 4 5 /* 6 BLUETOOTH SCROLLING MESSAGE for Adafruit EyeLights (LED Glasses + Driver). 7 Use BLUEFRUIT CONNECT app on iOS or Android to connect to LED glasses. 8 Use the app's UART input to enter a new message. 9 Use the app's Color Picker (under "Controller") to change text color. 10 This is based on the glassesdemo-3-smooth example from the 11 Adafruit_IS31FL3741 library, with Bluetooth additions on top. If this 12 code all seems a bit too much, you can start with that example (or the two 13 that precede it) to gain an understanding of the LED glasses basics, then 14 return here to see what the extra Bluetooth layers do. 15 */ 16 17 #include <Adafruit_IS31FL3741.h> // For LED driver 18 #include <bluefruit.h> // For Bluetooth communication 19 #include <EyeLightsCanvasFont.h> // Smooth scrolly font for glasses 20 21 // These items are over in the packetParser.cpp tab: 22 extern uint8_t packetbuffer[]; 23 extern uint8_t readPacket(BLEUart *ble, uint16_t timeout); 24 extern int8_t packetType(uint8_t *buf, uint8_t len); 25 extern float parsefloat(uint8_t *buffer); 26 extern void printHex(const uint8_t * data, const uint32_t numBytes); 27 28 // GLOBAL VARIABLES ------- 29 30 // 'Buffered' glasses for buttery animation, 31 // 'true' to allocate a drawing canvas for smooth graphics: 32 Adafruit_EyeLights_buffered glasses(true); 33 GFXcanvas16 *canvas; // Pointer to glasses' canvas object 34 // Because 'canvas' is a pointer, always use -> when calling 35 // drawing functions there. 'glasses' is an object in itself, 36 // so . is used when calling its functions. 37 38 char message[51] = "Run Bluefruit Connect app"; // Scrolling message 39 int16_t text_x; // Message position on canvas 40 int16_t text_min; // Leftmost position before restarting scroll 41 42 BLEUart bleuart; // Bluetooth low energy UART 43 44 int8_t last_packet_type = 99; // Last BLE packet type, init to nonsense value 45 46 // ONE-TIME SETUP --------- 47 48 void setup() { // Runs once at program start... 49 50 Serial.begin(115200); 51 //while(!Serial); 52 53 // Configure and start the BLE UART service 54 Bluefruit.begin(); 55 Bluefruit.setTxPower(4); 56 bleuart.begin(); 57 startAdv(); // Set up and start advertising 58 59 if (!glasses.begin()) err("IS3741 not found", 2); 60 61 canvas = glasses.getCanvas(); 62 if (!canvas) err("Can't allocate canvas", 5); 63 64 // Configure glasses for full brightness and enable output 65 glasses.setLEDscaling(0xFF); 66 glasses.setGlobalCurrent(0xFF); 67 glasses.enable(true); 68 69 // Set up for scrolling text, initialize color and position 70 canvas->setFont(&EyeLightsCanvasFont); 71 canvas->setTextWrap(false); // Allow text to extend off edges 72 canvas->setTextColor(glasses.color565(0x303030)); // Dim white to start 73 reposition_text(); // Sets up initial position & scroll limit 74 } 75 76 // Crude error handler, prints message to Serial console, flashes LED 77 void err(char *str, uint8_t hz) { 78 Serial.println(str); 79 pinMode(LED_BUILTIN, OUTPUT); 80 for (;;) digitalWrite(LED_BUILTIN, (millis() * hz / 500) & 1); 81 } 82 83 // Set up, start BLE advertising 84 void startAdv(void) { 85 // Advertising packet 86 Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); 87 Bluefruit.Advertising.addTxPower(); 88 89 // Include the BLE UART (AKA 'NUS') 128-bit UUID 90 Bluefruit.Advertising.addService(bleuart); 91 92 // Secondary Scan Response packet (optional) 93 // Since there is no room for 'Name' in Advertising packet 94 Bluefruit.ScanResponse.addName(); 95 96 // Start Advertising 97 // - Enable auto advertising if disconnected 98 // - Interval: fast mode = 20 ms, slow mode = 152.5 ms 99 // - Timeout for fast mode is 30 seconds 100 // - Start(timeout) with timeout = 0 will advertise forever (until connected) 101 // 102 // For recommended advertising interval 103 // https://developer.apple.com/library/content/qa/qa1931/_index.html 104 Bluefruit.Advertising.restartOnDisconnect(true); 105 Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms 106 Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode 107 Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds 108 } 109 110 // MAIN LOOP -------------- 111 112 void loop() { // Repeat forever... 113 // The packet read timeout (9 ms here) also determines the text 114 // scrolling speed -- if no data is received over BLE in that time, 115 // the function exits and returns here with len=0. 116 uint8_t len = readPacket(&bleuart, 9); 117 if (len) { 118 int8_t type = packetType(packetbuffer, len); 119 // The Bluefruit Connect app can return a variety of data from 120 // a phone's sensors. To keep this example relatively simple, 121 // we'll only look at color and text, but here's where others 122 // would go if we were to extend this. See Bluefruit library 123 // examples for the packet data formats. packetParser.cpp 124 // has a couple functions not used in this code but that may be 125 // helpful in interpreting these other packet types. 126 switch(type) { 127 case 0: // Accelerometer 128 Serial.println("Accel"); 129 break; 130 case 1: // Gyro: 131 Serial.println("Gyro"); 132 break; 133 case 2: // Magnetometer 134 Serial.println("Mag"); 135 break; 136 case 3: // Quaternion 137 Serial.println("Quat"); 138 break; 139 case 4: // Button 140 Serial.println("Button"); 141 break; 142 case 5: // Color 143 Serial.println("Color"); 144 // packetbuffer[2] through [4] contain R, G, B byte values. 145 // Because the drawing canvas uses lower-precision '565' color, 146 // and because glasses.scale() applies gamma correction and may 147 // quantize the dimmest colors to 0, set a brightness floor here 148 // so text isn't invisible. 149 for (uint8_t i=2; i<=4; i++) { 150 if (packetbuffer[i] < 0x20) packetbuffer[i] = 0x20; 151 } 152 canvas->setTextColor(glasses.color565(glasses.Color( 153 packetbuffer[2], packetbuffer[3], packetbuffer[4]))); 154 break; 155 case 6: // Location 156 Serial.println("Location"); 157 break; 158 default: // -1 159 // Packet is not one of the Bluefruit Connect types. Most programs 160 // will ignore/reject it as not valud, but in this case we accept 161 // it as a freeform string for the scrolling message. 162 if (last_packet_type != -1) { 163 // If prior data was a packet, this is a new freeform string, 164 // initialize the message string with it... 165 strncpy(message, (char *)packetbuffer, 20); 166 } else { 167 // If prior data was also a freeform string, concatenate this onto 168 // the message (up to the max message length). BLE packets can only 169 // be so large, so long strings are broken into multiple packets. 170 uint8_t message_len = strlen(message); 171 uint8_t max_append = sizeof message - 1 - message_len; 172 strncpy(&message[message_len], (char *)packetbuffer, max_append); 173 len = message_len + max_append; 174 } 175 message[len] = 0; // End of string NUL char 176 Serial.println(message); 177 reposition_text(); // Reset text off right edge of canvas 178 } 179 last_packet_type = type; // Save packet type for next pass 180 } else { 181 last_packet_type = 99; // BLE read timeout, reset last type to nonsense 182 } 183 184 canvas->fillScreen(0); // Clear the whole drawing canvas 185 // Update text to new position, and draw on canvas 186 if (--text_x < text_min) { // If text scrolls off left edge, 187 text_x = canvas->width(); // reset position off right edge 188 } 189 canvas->setCursor(text_x, canvas->height()); 190 canvas->print(message); 191 glasses.scale(); // 1:3 downsample canvas to LED matrix 192 glasses.show(); // MUST call show() to update matrix 193 } 194 195 // When new message text is assigned, call this to reset its position 196 // off the right edge and calculate column where scrolling resets. 197 void reposition_text() { 198 uint16_t w, h, ignore; 199 canvas->getTextBounds(message, 0, 0, (int16_t *)&ignore, (int16_t *)&ignore, &w, &ignore); 200 text_x = canvas->width(); 201 text_min = -w; // Off left edge this many pixels 202 }