mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 03:04:25 +01:00
Added Gicisky / PICKSMART BLE E-Paper Display support. Can be activated via the -D HAS_BLE_WRITER definition in the platformio.ini
This enables direct BLE Image upload from the Main ESP32 SoC via BLE and allows an OEPL usage without soldering/flashing or extra ZigBee interface. Currently tested on the 2.9" BW and 4.2" BWR version, tagtypes need to be added for more versions Demo video: https://youtu.be/_efgMQUA1F4 Official description of the BLE Protocol here: https://zhuanlan.zhihu.com/p/633113543 Thanks to these wonderful guys for such a good overview: https://github.com/fpoli/gicisky-tag https://github.com/Cabalist/gicisky_image_notes
This commit is contained in:
16
ESP32_AP-Flasher/data/tagtypes/B2.json
Normal file
16
ESP32_AP-Flasher/data/tagtypes/B2.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Gicisky BLE EPD BW 2.9\"",
|
||||
"width": 296,
|
||||
"height": 128,
|
||||
"rotatebuffer": 1,
|
||||
"bpp": 1,
|
||||
"colors": 2,
|
||||
"colortable": {
|
||||
"white": [255, 255, 255],
|
||||
"black": [0, 0, 0]
|
||||
},
|
||||
"shortlut": 0,
|
||||
"options": ["button", "customlut"],
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21 ],
|
||||
"usetemplate": 1
|
||||
}
|
||||
81
ESP32_AP-Flasher/data/tagtypes/B3.json
Normal file
81
ESP32_AP-Flasher/data/tagtypes/B3.json
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "Gicisky BLE EPD BWR 2.9\"",
|
||||
"width": 296,
|
||||
"height": 128,
|
||||
"rotatebuffer": 1,
|
||||
"bpp": 2,
|
||||
"colors": 3,
|
||||
"colortable": {
|
||||
"white": [255, 255, 255],
|
||||
"black": [0, 0, 0],
|
||||
"red": [255, 0, 0],
|
||||
"gray": [150, 150, 150]
|
||||
},
|
||||
"contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21, 27 ],
|
||||
"template": {
|
||||
"1": {
|
||||
"weekday": [ 148, -3, "Signika-SB.ttf", 60 ],
|
||||
"date": [ 148, 65, "Signika-SB.ttf", 48 ]
|
||||
},
|
||||
"2": {
|
||||
"fonts": [ "Signika-SB.ttf", 150, 150, 150, 120, 100, 80 ],
|
||||
"xy": [ 148, 53 ]
|
||||
},
|
||||
"16": {
|
||||
"location": [ 5, 5, "fonts/bahnschrift30" ],
|
||||
"title": [ 247, 11, "glasstown_nbp_tf" ],
|
||||
"cols": [ 1, 125, 12, "glasstown_nbp_tf" ],
|
||||
"bars": [ 5, 111, 10 ]
|
||||
},
|
||||
"4": {
|
||||
"location": [5, 5, "fonts/bahnschrift30"],
|
||||
"wind": [280, 5, "fonts/bahnschrift30"],
|
||||
"temp": [5, 65, "fonts/bahnschrift70"],
|
||||
"icon": [285, 20, 70, 2],
|
||||
"dir": [235, -12, 40],
|
||||
"umbrella": [190, -50, 25]
|
||||
},
|
||||
"8": {
|
||||
"location": [5, 12, "t0_14b_tf"],
|
||||
"column": [5, 59],
|
||||
"day": [30, 18, "fonts/twcondensed20", 41, 108],
|
||||
"icon": [30, 55, 30],
|
||||
"wind": [18, 26],
|
||||
"line": [20, 128]
|
||||
},
|
||||
"9": {
|
||||
"title": [ 2, 0, "bahnschrift20.vlw", 25 ],
|
||||
"items": 8,
|
||||
"line": [ 1, 25, "REFSAN12.vlw" ],
|
||||
"desc": [ 0, 5, "", 1 ]
|
||||
},
|
||||
"10": {
|
||||
"title": [149, 5, "fonts/bahnschrift20"],
|
||||
"pos": [149, 27]
|
||||
},
|
||||
"11": {
|
||||
"mode": 0,
|
||||
"days": 1,
|
||||
"title": [5, 2, "fonts/bahnschrift20"],
|
||||
"date": [290, 2],
|
||||
"items": 7,
|
||||
"red": [0, 21, 296, 14],
|
||||
"line": [5, 32, 15, "t0_14b_tf", 50]
|
||||
},
|
||||
"21": [
|
||||
{ "text": [ 5, 5, "OpenEpaperLink AP", "bahnschrift20", 1, 0, 0 ] },
|
||||
{ "text": [ 5, 50, "IP address:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 120, 50, "{ap_ip}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 5, 70, "Channel:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 120, 70, "{ap_ch}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 5, 90, "Tag count:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 120, 90, "{ap_tagcount}", "t0_14b_tf", 1, 0, 0 ] }
|
||||
],
|
||||
"27": {
|
||||
"bars": [ 9, 288, 90, 10 ],
|
||||
"time": [ "BellCent10.vlw" ],
|
||||
"yaxis": [ "BellCent10.vlw", 0, 6 ],
|
||||
"head": [ "calibrib30.vlw" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
55
ESP32_AP-Flasher/data/tagtypes/B5.json
Normal file
55
ESP32_AP-Flasher/data/tagtypes/B5.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "Gicisky BLE EPD BWR 4.2\"",
|
||||
"width": 400,
|
||||
"height": 300,
|
||||
"rotatebuffer": 0,
|
||||
"bpp": 2,
|
||||
"colors": 3,
|
||||
"colortable": {
|
||||
"white": [255, 255, 255],
|
||||
"black": [0, 0, 0],
|
||||
"red": [255, 0, 0],
|
||||
"gray": [150, 150, 150]
|
||||
},
|
||||
"contentids": [ 22, 23, 1, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20],
|
||||
"template": {
|
||||
"1": {
|
||||
"weekday": [ 200, 0, "Signika-SB.ttf", 70 ],
|
||||
"month": [ 200, 210, "Signika-SB.ttf", 70 ],
|
||||
"day": [ 200, 45, "Signika-SB.ttf", 170 ]
|
||||
},
|
||||
"4": {
|
||||
"location": [ 20, 20, "fonts/calibrib30" ],
|
||||
"wind": [ 90, 83, "fonts/calibrib50" ],
|
||||
"temp": [ 20, 170, "fonts/calibrib100" ],
|
||||
"icon": [ 385, 0, 100, 2 ],
|
||||
"dir": [ 40, 50, 80 ],
|
||||
"umbrella": [ 325, 155, 78 ]
|
||||
},
|
||||
"8": {
|
||||
"location": [ 10, 10, "fonts/calibrib30" ],
|
||||
"column": [ 6, 66 ],
|
||||
"day": [ 33, 60, "fonts/bahnschrift20", 104, 230 ],
|
||||
"rain": [ 34, 260 ],
|
||||
"icon": [ 32, 145, 30 ],
|
||||
"wind": [ 17, 90 ],
|
||||
"line": [ 50, 300 ]
|
||||
},
|
||||
"9": {
|
||||
"title": [ 6, 0, "Signika-SB.ttf", 25 ],
|
||||
"items": 4,
|
||||
"line": [ 9, 40, "calibrib16.vlw" ],
|
||||
"desc": [ 2, 8, "REFSAN12.vlw", 1.2 ]
|
||||
},
|
||||
"10": {
|
||||
"title": [ 200, 10, "fonts/bahnschrift20" ],
|
||||
"pos": [ 200, 35 ]
|
||||
},
|
||||
"11": {
|
||||
"rotate": 0,
|
||||
"mode": 1,
|
||||
"days": 4,
|
||||
"gridparam": [ 5, 17, 20, "calibrib16.vlw", "BellCent10.vlw", 14 ]
|
||||
}
|
||||
}
|
||||
}
|
||||
10
ESP32_AP-Flasher/include/ble_filter.h
Normal file
10
ESP32_AP-Flasher/include/ble_filter.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#ifdef HAS_BLE_WRITER
|
||||
#include "BLEDevice.h"
|
||||
|
||||
uint8_t gicToOEPLtype(uint8_t gicType);
|
||||
bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice);
|
||||
bool BLE_is_image_pending(uint8_t address[8]);
|
||||
uint32_t compress_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len);
|
||||
|
||||
#endif
|
||||
6
ESP32_AP-Flasher/include/ble_writer.h
Normal file
6
ESP32_AP-Flasher/include/ble_writer.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#ifdef HAS_BLE_WRITER
|
||||
|
||||
void BLETask(void* parameter);
|
||||
|
||||
#endif
|
||||
@@ -279,6 +279,7 @@ lib_deps =
|
||||
build_flags =
|
||||
-std=gnu++17
|
||||
${env.build_flags}
|
||||
-D HAS_BLE_WRITER
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
-D ARDUINO_USB_CDC_ON_BOOT
|
||||
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||
|
||||
209
ESP32_AP-Flasher/src/ble_filter.cpp
Normal file
209
ESP32_AP-Flasher/src/ble_filter.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
#ifdef HAS_BLE_WRITER
|
||||
#include <Arduino.h>
|
||||
#include <FS.h>
|
||||
|
||||
#include "BLEDevice.h"
|
||||
#include "newproto.h"
|
||||
#include "serialap.h"
|
||||
#include "settings.h"
|
||||
#include "storage.h"
|
||||
#include "system.h"
|
||||
#include "tag_db.h"
|
||||
#include "tagdata.h"
|
||||
#include "udp.h"
|
||||
#include "util.h"
|
||||
#include "web.h"
|
||||
|
||||
uint8_t gicToOEPLtype(uint8_t gicType) {
|
||||
switch (gicType) {
|
||||
case 0x08:
|
||||
return GICI_BLE_EPD_21_BW;
|
||||
break;
|
||||
case 0x0B:
|
||||
return GICI_BLE_EPD_21_BWR;
|
||||
break;
|
||||
case 0x28:
|
||||
case 0x30:
|
||||
return GICI_BLE_EPD_29_BW;
|
||||
break;
|
||||
case 0x2B:
|
||||
return GICI_BLE_EPD_29_BWR;
|
||||
break;
|
||||
case 0x33:
|
||||
return GICI_BLE_EPD_29_BWR1;
|
||||
break;
|
||||
case 0x48:
|
||||
return GICI_BLE_EPD_BW_42;
|
||||
break;
|
||||
case 0x4B:
|
||||
return GICI_BLE_EPD_BWR_42;
|
||||
break;
|
||||
case 0x40:
|
||||
return GICI_BLE_TFT_BW_42;
|
||||
break;
|
||||
case 0x42:
|
||||
return GICI_BLE_TFT_BWR_42;
|
||||
break;
|
||||
case 0x68:
|
||||
return GICI_BLE_EPD_BW_74;
|
||||
break;
|
||||
case 0x6A:
|
||||
return GICI_BLE_EPD_BWR_74;
|
||||
break;
|
||||
default:
|
||||
return GICI_BLE_UNKNOWN; // Should never happen, return 1.54"
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
|
||||
if (advertisedDevice.haveManufacturerData()) {
|
||||
int manuDatalen = advertisedDevice.getManufacturerData().length();
|
||||
uint8_t manuData[100];
|
||||
if (manuDatalen > sizeof(manuData))
|
||||
return false; // Manu data too big, could never happen but better make sure here
|
||||
memcpy(&manuData, (uint8_t*)advertisedDevice.getManufacturerData().data(), manuDatalen);
|
||||
if (manuDatalen == 7 && manuData[0] == 0x53 && manuData[1] == 0x50) {
|
||||
Serial.print("BLE Advertised Device found: ");
|
||||
Serial.println(advertisedDevice.toString().c_str());
|
||||
Serial.printf(" Address type: %02X Manu data: ", advertisedDevice.getAddressType());
|
||||
for (int i = 0; i < advertisedDevice.getManufacturerData().length(); i++)
|
||||
Serial.printf("%02X", manuData[i]);
|
||||
Serial.printf("\r\n");
|
||||
|
||||
struct espAvailDataReq theAdvData;
|
||||
memset((uint8_t*)&theAdvData, 0x00, sizeof(espAvailDataReq));
|
||||
|
||||
uint8_t macReversed[6];
|
||||
memcpy(&macReversed, (uint8_t*)advertisedDevice.getAddress().getNative(), 6);
|
||||
theAdvData.src[0] = macReversed[5];
|
||||
theAdvData.src[1] = macReversed[4];
|
||||
theAdvData.src[2] = macReversed[3];
|
||||
theAdvData.src[3] = macReversed[2];
|
||||
theAdvData.src[4] = macReversed[1];
|
||||
theAdvData.src[5] = macReversed[0];
|
||||
theAdvData.src[6] = manuData[2]; // We use this do find out what type of display we got for compression^^
|
||||
theAdvData.src[7] = 0x00;
|
||||
theAdvData.adr.batteryMv = manuData[3] * 100;
|
||||
theAdvData.adr.lastPacketRSSI = advertisedDevice.getRSSI();
|
||||
theAdvData.adr.hwType = gicToOEPLtype(manuData[2]);
|
||||
theAdvData.adr.tagSoftwareVersion = manuData[4] << 8 | manuData[5];
|
||||
theAdvData.adr.capabilities = 0x00;
|
||||
|
||||
processDataReq(&theAdvData, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BLE_is_image_pending(uint8_t address[8]) {
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
tagRecord* taginfo = tagDB.at(c);
|
||||
if (taginfo->pendingCount > 0 && taginfo->version == 0 && (taginfo->hwType & 0xB0)) {
|
||||
memcpy(address, taginfo->mac, 8);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t compress_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len) {
|
||||
uint32_t t = millis();
|
||||
PendingItem* queueItem = getQueueItem(address, 0);
|
||||
if (queueItem == nullptr) {
|
||||
prepareCancelPending(address);
|
||||
Serial.printf("blockrequest: couldn't find taginfo %02X%02X%02X%02X%02X%02X%02X%02X\n", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]);
|
||||
return 0;
|
||||
}
|
||||
if (queueItem->data == nullptr) {
|
||||
fs::File file = contentFS->open(queueItem->filename);
|
||||
if (!file) {
|
||||
Serial.print("No current file. " + String(queueItem->filename) + " Canceling request\n");
|
||||
prepareCancelPending(address);
|
||||
return 0;
|
||||
}
|
||||
queueItem->data = getDataForFile(file);
|
||||
Serial.println("Reading file " + String(queueItem->filename) + " in " + String(millis() - t) + "ms");
|
||||
file.close();
|
||||
}
|
||||
|
||||
uint8_t giciType = address[6]; // here we "extract" the display info again
|
||||
|
||||
bool extra_color = false;
|
||||
uint16_t width_display = 104;
|
||||
uint16_t height_display = 212;
|
||||
switch ((giciType >> 5) & 7) // Resolution
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
width_display = 104;
|
||||
height_display = 212;
|
||||
break;
|
||||
case 1:
|
||||
width_display = 296;
|
||||
height_display = 128;
|
||||
break;
|
||||
case 2:
|
||||
width_display = 300;
|
||||
height_display = 400;
|
||||
break;
|
||||
case 3:
|
||||
width_display = 384;
|
||||
height_display = 640;
|
||||
break;
|
||||
}
|
||||
switch ((giciType >> 1) & 3) // Extra color
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
extra_color = false;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
extra_color = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Yeah, this is no real compression, but maybe it will be solved in the future to the "real" RLE Compression
|
||||
uint32_t len_compressed = 4;
|
||||
uint32_t curr_input_posi = 0;
|
||||
uint32_t byte_per_line = (height_display / 8);
|
||||
for (int i = 0; i < width_display; i++) {
|
||||
buffer[len_compressed++] = 0x75;
|
||||
buffer[len_compressed++] = byte_per_line + 7;
|
||||
buffer[len_compressed++] = byte_per_line;
|
||||
buffer[len_compressed++] = 0x00;
|
||||
buffer[len_compressed++] = 0x00;
|
||||
buffer[len_compressed++] = 0x00;
|
||||
buffer[len_compressed++] = 0x00;
|
||||
for (int b = 0; b < byte_per_line; b++) {
|
||||
buffer[len_compressed++] = ~queueItem->data[curr_input_posi++];
|
||||
}
|
||||
}
|
||||
if (extra_color) {
|
||||
for (int i = 0; i < width_display; i++) {
|
||||
buffer[len_compressed++] = 0x75;
|
||||
buffer[len_compressed++] = byte_per_line + 7;
|
||||
buffer[len_compressed++] = byte_per_line;
|
||||
buffer[len_compressed++] = 0x00;
|
||||
buffer[len_compressed++] = 0x00;
|
||||
buffer[len_compressed++] = 0x00;
|
||||
buffer[len_compressed++] = 0x00;
|
||||
for (int b = 0; b < byte_per_line; b++) {
|
||||
if (queueItem->len <= curr_input_posi)
|
||||
buffer[len_compressed++] = 0x00;
|
||||
else
|
||||
buffer[len_compressed++] = queueItem->data[curr_input_posi++];
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer[0] = len_compressed & 0xff;
|
||||
buffer[1] = (len_compressed >> 8) & 0xff;
|
||||
buffer[2] = (len_compressed >> 16) & 0xff;
|
||||
buffer[3] = (len_compressed >> 24) & 0xff;
|
||||
return len_compressed;
|
||||
}
|
||||
|
||||
#endif
|
||||
262
ESP32_AP-Flasher/src/ble_writer.cpp
Normal file
262
ESP32_AP-Flasher/src/ble_writer.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
#ifdef HAS_BLE_WRITER
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "BLEDevice.h"
|
||||
#include "ble_filter.h"
|
||||
#include "newproto.h"
|
||||
|
||||
#define INTERVAL_BLE_SCANNING_SECONDS 60
|
||||
#define INTERVAL_HANDLE_PENDING_SECONDS 10
|
||||
|
||||
#define BUFFER_MAX_SIZE_COMPRESSING 100000
|
||||
|
||||
#define BLE_MAIN_STATE_IDLE 0
|
||||
#define BLE_MAIN_STATE_PREPARE 1
|
||||
#define BLE_MAIN_STATE_CONNECT 2
|
||||
#define BLE_MAIN_STATE_UPLOAD 3
|
||||
|
||||
int ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
uint32_t last_ble_scan = 0;
|
||||
|
||||
#define BLE_UPLOAD_STATE_INIT 0
|
||||
#define BLE_UPLOAD_STATE_SIZE 1
|
||||
#define BLE_UPLOAD_STATE_START 2
|
||||
#define BLE_UPLOAD_STATE_UPLOAD 5
|
||||
int BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
||||
|
||||
bool BLE_connected = false;
|
||||
bool BLE_new_notify = false;
|
||||
|
||||
static BLEUUID gicServiceUUID((uint16_t)0xfef0);
|
||||
static BLEUUID gicCtrlUUID((uint16_t)0xfef1);
|
||||
static BLEUUID gicImgUUID((uint16_t)0xfef2);
|
||||
|
||||
BLERemoteCharacteristic* ctrlChar;
|
||||
BLERemoteCharacteristic* imgChar;
|
||||
BLEAdvertisedDevice* myDevice;
|
||||
|
||||
BLEClient* pClient;
|
||||
|
||||
uint8_t BLE_notify_buffer[255] = {0};
|
||||
|
||||
uint32_t curr_part = 0;
|
||||
uint8_t BLE_buff[255];
|
||||
|
||||
uint32_t BLE_last_notify = 0;
|
||||
uint32_t BLE_last_pending_check = 0;
|
||||
uint8_t BLE_curr_address[8] = {0};
|
||||
|
||||
uint32_t compressed_len = 0;
|
||||
uint8_t* buffer;
|
||||
|
||||
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: ");
|
||||
for (int i = 0; i < length; i++) {
|
||||
Serial.printf("%02X", pData[i]);
|
||||
BLE_notify_buffer[1 + i] = pData[i];
|
||||
}
|
||||
BLE_notify_buffer[0] = length;
|
||||
Serial.println();
|
||||
BLE_new_notify = true;
|
||||
}
|
||||
|
||||
class MyClientCallback : public BLEClientCallbacks {
|
||||
void onConnect(BLEClient* pclient) {
|
||||
Serial.println("BLE onConnect");
|
||||
BLE_connected = true;
|
||||
}
|
||||
|
||||
void onDisconnect(BLEClient* pclient) {
|
||||
Serial.println("BLE onDisconnect");
|
||||
pclient->disconnect();
|
||||
BLE_connected = false;
|
||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
}
|
||||
};
|
||||
|
||||
bool BLE_connect(uint8_t addr[8]) {
|
||||
uint8_t temp_Address[] = {addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]};
|
||||
Serial.printf("BLE Connecting to: %02X:%02X:%02X:%02X:%02X:%02X\r\n", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
|
||||
pClient = BLEDevice::createClient();
|
||||
pClient->setClientCallbacks(new MyClientCallback());
|
||||
if (!pClient->connect(BLEAddress(temp_Address))) {
|
||||
Serial.printf("BLE connection failed\r\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
if (!BLE_connected)
|
||||
return false;
|
||||
Serial.printf("BLE starting to get service\r\n");
|
||||
BLERemoteService* pRemoteService = pClient->getService(gicServiceUUID);
|
||||
if (pRemoteService == nullptr) {
|
||||
Serial.printf("BLE Service failed\r\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
imgChar = pRemoteService->getCharacteristic(gicImgUUID);
|
||||
if (imgChar == nullptr) {
|
||||
Serial.printf("BLE IMG Char failed\r\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
ctrlChar = pRemoteService->getCharacteristic(gicCtrlUUID);
|
||||
if (ctrlChar == nullptr) {
|
||||
Serial.printf("BLE ctrl Char failed\r\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
if (ctrlChar->canNotify()) {
|
||||
ctrlChar->registerForNotify(notifyCallback);
|
||||
} else {
|
||||
Serial.printf("BLE Notify failed\r\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
if (pClient->setMTU(255) == false) {
|
||||
Serial.printf("BLE MTU failed\r\n");
|
||||
pClient->disconnect();
|
||||
return false;
|
||||
}
|
||||
Serial.printf("BLE Connected fully to: %02X:%02X:%02X:%02X:%02X:%02X\r\n", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
|
||||
void onResult(BLEAdvertisedDevice advertisedDevice) {
|
||||
BLE_filter_add_device(advertisedDevice);
|
||||
}
|
||||
};
|
||||
|
||||
void BLE_startScan(uint32_t timeout) {
|
||||
BLEScan* pBLEScan = BLEDevice::getScan();
|
||||
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||
pBLEScan->setInterval(1349);
|
||||
pBLEScan->setWindow(449);
|
||||
pBLEScan->setActiveScan(true);
|
||||
pBLEScan->start(timeout, false);
|
||||
}
|
||||
|
||||
void BLETask(void* parameter) {
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
BLEDevice::init("");
|
||||
while (1) {
|
||||
switch (ble_main_state) {
|
||||
default:
|
||||
case BLE_MAIN_STATE_IDLE:
|
||||
if (millis() - last_ble_scan > (INTERVAL_BLE_SCANNING_SECONDS * 1000)) {
|
||||
last_ble_scan = millis();
|
||||
Serial.println("Doing the BLE Scan");
|
||||
BLE_startScan(5); // timeout in seconds, this is blocking but only for this thread!
|
||||
}
|
||||
if (millis() - BLE_last_pending_check >= (INTERVAL_HANDLE_PENDING_SECONDS * 1000)) {
|
||||
if (BLE_is_image_pending(BLE_curr_address)) {
|
||||
delay(4000); // We better wait here, since the pending image needs to be created first
|
||||
Serial.println("BLE Image is pending");
|
||||
// Here we create the compressed buffer
|
||||
buffer = (uint8_t*)malloc(BUFFER_MAX_SIZE_COMPRESSING);
|
||||
if (buffer == nullptr) {
|
||||
Serial.println("BLE Could not create buffer!");
|
||||
compressed_len = 0;
|
||||
} else {
|
||||
compressed_len = compress_image(BLE_curr_address, buffer, BUFFER_MAX_SIZE_COMPRESSING);
|
||||
Serial.printf("BLE Compressed Length: %i\r\n", compressed_len);
|
||||
// then we connect to BLE to send the compressed data
|
||||
if (compressed_len && BLE_connect(BLE_curr_address)) {
|
||||
curr_part = 0;
|
||||
memset(BLE_notify_buffer, 0x00, sizeof(BLE_notify_buffer));
|
||||
BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
||||
ble_main_state = BLE_MAIN_STATE_UPLOAD;
|
||||
BLE_new_notify = true; // trigger the upload here
|
||||
} else {
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
BLE_last_pending_check = millis();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BLE_MAIN_STATE_UPLOAD: {
|
||||
if (BLE_connected && BLE_new_notify) {
|
||||
BLE_new_notify = false;
|
||||
BLE_last_notify = millis();
|
||||
BLE_upload_state = BLE_notify_buffer[1];
|
||||
|
||||
switch (BLE_upload_state) {
|
||||
default:
|
||||
case BLE_UPLOAD_STATE_INIT:
|
||||
BLE_buff[0] = 1;
|
||||
ctrlChar->writeValue(BLE_buff, 1);
|
||||
break;
|
||||
case BLE_UPLOAD_STATE_SIZE:
|
||||
BLE_buff[0] = 0x02;
|
||||
BLE_buff[1] = compressed_len & 0xff;
|
||||
BLE_buff[2] = (compressed_len >> 8) & 0xff;
|
||||
BLE_buff[3] = (compressed_len >> 16) & 0xff;
|
||||
BLE_buff[4] = (compressed_len >> 24) & 0xff;
|
||||
BLE_buff[5] = 0x00;
|
||||
ctrlChar->writeValue(BLE_buff, 6);
|
||||
break;
|
||||
case BLE_UPLOAD_STATE_START:
|
||||
BLE_buff[0] = 0x03;
|
||||
ctrlChar->writeValue(BLE_buff, 1);
|
||||
break;
|
||||
case BLE_UPLOAD_STATE_UPLOAD:
|
||||
if (BLE_notify_buffer[2] == 0x08) {
|
||||
free(buffer);
|
||||
pClient->disconnect();
|
||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
BLE_last_pending_check = millis();
|
||||
// Done and the image is refreshing now
|
||||
struct espXferComplete reportStruct;
|
||||
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
|
||||
processXferComplete(&reportStruct, true);
|
||||
curr_part = 0;
|
||||
} else {
|
||||
uint32_t req_curr_part = (BLE_notify_buffer[6] << 24) | (BLE_notify_buffer[5] << 24) | (BLE_notify_buffer[4] << 24) | BLE_notify_buffer[3];
|
||||
if (req_curr_part != curr_part) {
|
||||
Serial.printf("Something went wrong, expected req part: %i but got: %i we better abort here.\r\n", req_curr_part, curr_part);
|
||||
free(buffer);
|
||||
pClient->disconnect();
|
||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
BLE_last_pending_check = millis();
|
||||
}
|
||||
uint32_t curr_len = 240;
|
||||
if (compressed_len - (curr_part * 240) < 240)
|
||||
curr_len = compressed_len - (curr_part * 240);
|
||||
BLE_buff[0] = curr_part & 0xff;
|
||||
BLE_buff[1] = (curr_part >> 8) & 0xff;
|
||||
BLE_buff[2] = (curr_part >> 16) & 0xff;
|
||||
BLE_buff[3] = (curr_part >> 24) & 0xff;
|
||||
memcpy((uint8_t*)&BLE_buff[4], (uint8_t*)&buffer[curr_part * 240], curr_len);
|
||||
imgChar->writeValue(BLE_buff, curr_len + 4);
|
||||
Serial.printf("BLE sending part: %i\r\n", curr_part);
|
||||
curr_part++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (millis() - BLE_last_notify > 30000) { // Something odd, better reset connection!
|
||||
Serial.println("BLE err going back to IDLE");
|
||||
free(buffer);
|
||||
pClient->disconnect();
|
||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||
BLE_last_pending_check = millis();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
vTaskDelay(15 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "udp.h"
|
||||
#include "util.h"
|
||||
#include "web.h"
|
||||
#include "ble_writer.h"
|
||||
|
||||
util::Timer intervalContentRunner(seconds(1));
|
||||
util::Timer intervalSysinfo(seconds(5));
|
||||
@@ -134,6 +135,10 @@ void setup() {
|
||||
xTaskCreate(APTask, "AP Process", 6000, NULL, 5, NULL);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
#ifdef HAS_BLE_WRITER
|
||||
xTaskCreate(BLETask, "BLE Writer", 12000, NULL, 5, NULL);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_USB
|
||||
// We'll need to start the 'usbflasher' task for boards with a second (USB) port. This can be used as a 'flasher' interface, using a python script on the host
|
||||
xTaskCreate(usbFlasherTask, "usbflasher", 10000, NULL, 5, NULL);
|
||||
|
||||
@@ -55,6 +55,20 @@
|
||||
#define HS_NEBULAR_BWR_35 0x61
|
||||
#define HS_NEBULAR_BW_35 0x62
|
||||
|
||||
// Gicisky / PICKSMART BLE Types
|
||||
#define GICI_BLE_EPD_21_BW 0xB0
|
||||
#define GICI_BLE_EPD_21_BWR 0xB1
|
||||
#define GICI_BLE_EPD_29_BW 0xB2
|
||||
#define GICI_BLE_EPD_29_BWR 0xB3
|
||||
#define GICI_BLE_EPD_29_BWR1 0xB3
|
||||
#define GICI_BLE_EPD_BW_42 0xB4
|
||||
#define GICI_BLE_EPD_BWR_42 0xB5
|
||||
#define GICI_BLE_TFT_BW_42 0xB6
|
||||
#define GICI_BLE_TFT_BWR_42 0xB7
|
||||
#define GICI_BLE_EPD_BW_74 0xB8
|
||||
#define GICI_BLE_EPD_BWR_74 0xB9
|
||||
#define GICI_BLE_UNKNOWN 0xBF
|
||||
|
||||
// Solum types - customer data byte 16 in M3 (nRF) UICR
|
||||
#define STYPE_SIZE_016 0x40
|
||||
#define STYPE_SIZE_022 0x41
|
||||
|
||||
Reference in New Issue
Block a user