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:
atc1441
2024-02-10 23:02:34 +01:00
parent edb874029e
commit aca1dfc7a3
10 changed files with 659 additions and 0 deletions

View 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
}

View 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" ]
}
}
}

View 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 ]
}
}
}

View 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

View File

@@ -0,0 +1,6 @@
#pragma once
#ifdef HAS_BLE_WRITER
void BLETask(void* parameter);
#endif

View File

@@ -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

View 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

View 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

View File

@@ -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);

View File

@@ -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