- finished implementing protocol

- some changes and cleanup
This commit is contained in:
Dorian Zedler 2020-10-14 23:54:54 +02:00
parent ce6d436c85
commit d74da783b3
Signed by: dorian
GPG key ID: D3B255CB8BC7CD37
9 changed files with 506 additions and 353 deletions

View file

@ -5,6 +5,8 @@
"deque": "cpp",
"string": "cpp",
"vector": "cpp",
"unordered_map": "cpp"
"unordered_map": "cpp",
"random": "cpp",
"memory": "cpp"
}
}

View file

@ -9,6 +9,42 @@
class BluetoothLeUartServerCallbacks;
/*!
* \brief The BluetoothLeUartServer class can be used to connect to another Bluetooth LE device (like an Android phone) effordlessly.
*
* Example use
* \code
* #include <Arduino.h>
* #include "OmobiLedDisplay.h"
*
* BluetoothLeUartServer* server;
*
* class MyCallbacks : public BluetoothLeUartServerCallbacks
* {
* virtual void onDeviceConnectedChanged(bool deviceConnected)
* {
* Serial.println("Device connected changed");
* };
* virtual void onDataReceived(String data)
* {
* Serial.println("Got some data: " + data);
* };
* };
*
* void setup()
* {
* server = new BluetoothLeUartServer("OmobiLedDisplay1", "6e400001-b5a3-f393-e0a9-e50e24dcca9e", "6e400002-b5a3-f393-e0a9-e50e24dcca9e", "6e400003-b5a3-f393-e0a9-e50e24dcca9e");
* server->setCallbacks(new MyCallbacks());
* }
*
* void loop()
* {
* if(server->getDeviceConnected())
* server->sendData("PING");
* delay(1000);
* }
* \endcode
*/
class BluetoothLeUartServer : protected BLEServerCallbacks, protected BLECharacteristicCallbacks
{
@ -34,15 +70,18 @@ protected:
void onWrite(BLECharacteristic *rxCharacteristic) override;
private:
// service and characteristic UUIDs
const char *uartServiceUUID;
const char *rxUUID;
const char *txUUID;
// BLE Objects
BLEServer *bleServer;
BLEService *bleService;
BLECharacteristic *txCharacteristic;
BLECharacteristic *rxCharacteristic;
// helpers
bool deviceConnected = false;
BluetoothLeUartServerCallbacks *callbacks;
};

View file

@ -11,87 +11,105 @@
class LedDisplayController
{
public:
explicit LedDisplayController(const byte pin);
explicit LedDisplayController(Adafruit_NeoMatrix *matrix);
~LedDisplayController();
enum text_align_t
{
TEXTLEFT,
TEXTCENTER,
TEXTRIGHT
AlignLeft,
AlignCenter,
AlignRight
};
enum set_param_index_t
enum DisplayTextSetParameter
{
PTEXT,
PTIME,
PCOLOR,
PALIGN,
PSCROLL,
PSCROLL_RUNS,
PACTIVE
TextParameter = 0,
ActiveParameter,
RuntimeParameter,
ColorParameter,
AlignmentParameter,
ScrollParameter,
ScrollSpeedParameter,
ScrollCountParameter,
IndexParameter,
DisplayTextSetParameterCount
};
static const uint16_t text_nr_sets = 2;
static const uint16_t MAX_TXT_LENGTH = 256;
static const int nr_param_names = 7;
typedef struct text_set_t
enum GetSetTextSetParameterExitCode
{
char text[MAX_TXT_LENGTH];
uint16_t time_ms;
uint16_t color;
text_align_t align;
bool text_scroll;
uint16_t text_scroll_pass;
bool active;
} text_set_t;
Success,
InvalidParameterError,
ParameterNotWritableError,
ValueOutOfRangeError,
IndexOutOfRangeError,
ValueIsNullptrError,
InternalError
};
typedef struct sets_t
{
text_set_t sets[text_nr_sets];
char valid[3];
} sets_t;
static const uint16_t MaximumTextSets = 6;
static const uint16_t MaximumTextLength = 256;
void disp_update();
void loop();
void setTexts(sets_t texts);
sets_t getTexts();
// modifiers for the internal text sets
String getTextSetParameter(int index, DisplayTextSetParameter parameter);
GetSetTextSetParameterExitCode setTextSetParameter(int index, DisplayTextSetParameter parameter, String value);
uint16_t Color(uint8_t r, uint8_t g, uint8_t b);
// brightness control
int getBrightness();
bool setBrightness(int brightness);
private:
// matrix objects
TaskHandle_t displayUpdateTask;
Adafruit_NeoMatrix *matrix;
const String set_param_name[nr_param_names] = {"text_", "time_", "color_", "align_", "scroll_", "scroll_runs_", "active_"};
const uint16_t DISP_STRUCT_SIZE = sizeof(sets_t);
sets_t text_sets;
// matrix variables
uint16_t text_curr_nr;
uint32_t text_set_starttime;
int text_pos;
unsigned int text_pass;
unsigned int textpixel;
int disp_brightness;
bool disp_show;
void storeDisplaySet();
bool loadDisplaySet();
void disp_scroll_text();
void disp_switch_text();
void disp_start_set();
// matrix control
void disp_init();
void show_matrix(const char *text, int pos, uint16_t color);
String get_paramstring_from_struct(String name);
void set_param_to_struct(String name, String value);
String getset_param_at_struct(String name, String value, bool set);
void disp_start_set();
void disp_scroll_text();
void show_matrix(const char *text, int pos, const char *color);
uint16_t colorFromHex(String hex);
// storage structs
typedef struct text_set_t
{
char text[MaximumTextLength];
bool active;
uint16_t runtime;
char color[7];
text_align_t alignment;
bool scroll;
int scrollSpeed;
uint16_t scrollCount;
} text_set_t;
typedef struct sets_t
{
text_set_t sets[MaximumTextSets];
char valid[3];
} sets_t;
// storage variables
sets_t text_sets;
// storage control
GetSetTextSetParameterExitCode getSetTextSetParameter(int index, DisplayTextSetParameter parameter, String *value, bool set = false);
void storeTextSets();
bool loadTextSets();
};
// function for updater task on core 0
void updateDisplayGlobal(void *);
extern LedDisplayController *ledDisplayControllerGlobal;

View file

@ -6,10 +6,11 @@
#include "BluetoothLeUartServer.h"
#include "LedDisplayController.h"
class OmobiLedDisplay : protected BluetoothLeUartServerCallbacks {
class OmobiLedDisplay : protected BluetoothLeUartServerCallbacks
{
public:
explicit OmobiLedDisplay(String deviceName, const byte ledPin);
explicit OmobiLedDisplay(String deviceName, Adafruit_NeoMatrix *ledDisplayMatrix);
// befriend for callbacks
friend class BluetoothLeUartServer;
@ -20,6 +21,22 @@ protected:
void onDataReceived(String data) override;
private:
enum OmobiDisplayCommand
{
GetAllTextSetsCommand = 10,
GetTextSetParameterCommand = 11,
GetDisplayBrightnessCommand = 12,
SetTextSetParameterCommand = 20,
SetDisplayBrightnessCommand = 21
};
enum OmobiDisplayStatusCode
{
Success = 200,
InternalError = 500,
DisplayControllerError = 501
};
LedDisplayController *ledDisplayController;
BluetoothLeUartServer *bleServer;
};

View file

@ -57,7 +57,8 @@ void BluetoothLeUartServer::sendData(String data)
void BluetoothLeUartServer::onConnect(BLEServer *pServer)
{
this->deviceConnected = true;
if (this->callbacks != nullptr) {
if (this->callbacks != nullptr)
{
this->callbacks->onDeviceConnectedChanged(this->deviceConnected);
}
}

View file

@ -2,15 +2,12 @@
LedDisplayController *ledDisplayControllerGlobal = nullptr;
LedDisplayController::LedDisplayController(const byte pin)
LedDisplayController::LedDisplayController(Adafruit_NeoMatrix *matrix)
{
ledDisplayControllerGlobal = this;
this->loadTextSets();
this->matrix = new Adafruit_NeoMatrix(8, 8, 1, 1, pin,
NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_PROGRESSIVE +
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_TILE_PROGRESSIVE,
NEO_GRB + NEO_KHZ800);
this->matrix = matrix;
this->matrix->begin();
this->matrix->setTextWrap(false);
this->matrix->setBrightness(40);
@ -19,6 +16,7 @@ LedDisplayController::LedDisplayController(const byte pin)
text_set_starttime = 0;
text_pass = 0;
textpixel = 0;
disp_brightness = 5;
disp_show = false;
this->disp_init();
@ -27,7 +25,11 @@ LedDisplayController::LedDisplayController(const byte pin)
xTaskCreatePinnedToCore(updateDisplayGlobal, "DisplayUpdateTask", 10000, NULL, 1, &displayUpdateTask, 0);
}
void LedDisplayController::disp_update()
// --------------------
// - Public functions -
// --------------------
void LedDisplayController::loop()
{
if (this->disp_show)
{
@ -36,7 +38,7 @@ void LedDisplayController::disp_update()
{
if (text_sets.sets[text_curr_nr].text != '\0')
{
if (text_sets.sets[text_curr_nr].text_scroll)
if (text_sets.sets[text_curr_nr].scroll)
{
disp_scroll_text();
}
@ -45,6 +47,39 @@ void LedDisplayController::disp_update()
}
}
String LedDisplayController::getTextSetParameter(int index, DisplayTextSetParameter parameter)
{
if (index < 0 || index > this->MaximumTextSets || parameter < 0 || parameter >= DisplayTextSetParameterCount)
return "";
String value = "";
this->getSetTextSetParameter(index, parameter, &value);
return value;
}
LedDisplayController::GetSetTextSetParameterExitCode LedDisplayController::setTextSetParameter(int index, DisplayTextSetParameter parameter, String value)
{
return this->getSetTextSetParameter(index, parameter, &value, true);
}
int LedDisplayController::getBrightness()
{
return this->disp_brightness;
}
bool LedDisplayController::setBrightness(int brightness)
{
if (brightness < 0 || brightness > 10)
return false;
this->disp_brightness = brightness;
return true;
}
// ------------------
// - Matrix control -
// ------------------
void LedDisplayController::disp_init()
{
text_curr_nr = 0;
@ -54,6 +89,50 @@ void LedDisplayController::disp_init()
disp_show = true;
}
void LedDisplayController::disp_start_set()
{
if ((0 == text_set_starttime) ||
(text_sets.sets[text_curr_nr].text == '\0') ||
text_sets.sets[text_curr_nr].active == false ||
((text_sets.sets[text_curr_nr].scroll == false) && (text_sets.sets[text_curr_nr].runtime > 0) && ((millis() - text_set_starttime) >= text_sets.sets[text_curr_nr].runtime)) ||
((text_sets.sets[text_curr_nr].scroll == true) && (text_sets.sets[text_curr_nr].scrollCount > 0) && (text_pass >= text_sets.sets[text_curr_nr].scrollCount)) ||
(((text_sets.sets[text_curr_nr].scrollCount == 0) || text_sets.sets[text_curr_nr].scroll == false) && (text_sets.sets[text_curr_nr].runtime == 0) && ((millis() - text_set_starttime) >= 10000)))
{
//Serial.printf("[%lu] Meet start set condition. Curr set is %d. \n", millis(), text_curr_nr);
if (0 < text_set_starttime || text_sets.sets[text_curr_nr].text == '\0' || text_sets.sets[text_curr_nr].active == false)
text_curr_nr++;
if (text_curr_nr == MaximumTextSets)
text_curr_nr = 0;
text_pass = 0;
if (text_sets.sets[text_curr_nr].text != '\0' && text_sets.sets[text_curr_nr].active == true)
{
//Serial.printf("[%lu] Set %d. Runtime %d. Text:'%s'\n", millis(), text_curr_nr, text_sets.sets[text_curr_nr].runtime, text_sets.sets[text_curr_nr].text);
this->matrix->fillScreen(0);
textpixel = 6 * strlen(text_sets.sets[text_curr_nr].text);
switch (text_sets.sets[text_curr_nr].alignment)
{
case AlignLeft:
text_pos = 0;
break;
case AlignRight:
text_pos = this->matrix->width();
break;
case AlignCenter:
text_pos = this->matrix->width() - textpixel;
text_pos = text_pos / 2;
break;
}
show_matrix(text_sets.sets[text_curr_nr].text, text_pos, text_sets.sets[text_curr_nr].color);
text_set_starttime = millis();
}
}
else
{
//Serial.printf("[%lu] Don't meet start set condition. Text is: %s. Active is: %d\n", millis(), text_sets.sets[text_curr_nr].text, text_sets.sets[text_curr_nr].active);
}
}
void LedDisplayController::disp_scroll_text()
{
this->matrix->fillScreen(0);
@ -63,58 +142,15 @@ void LedDisplayController::disp_scroll_text()
{
text_pos = this->matrix->width();
text_pass++;
Serial.printf("Pass[%d] - set nr %d, Text: '%s' \n", text_pass, text_curr_nr, text_sets.sets[text_curr_nr].text);
//Serial.printf("Pass[%d] - set nr %d, Text: '%s' \n", text_pass, text_curr_nr, text_sets.sets[text_curr_nr].text);
}
delay(100);
}
void LedDisplayController::disp_start_set()
void LedDisplayController::show_matrix(const char *text, int pos, const char *color)
{
if ((0 == text_set_starttime) ||
(text_sets.sets[text_curr_nr].text == '\0') ||
text_sets.sets[text_curr_nr].active == false ||
((text_sets.sets[text_curr_nr].text_scroll == false) && (text_sets.sets[text_curr_nr].time_ms > 0) && ((millis() - text_set_starttime) >= text_sets.sets[text_curr_nr].time_ms)) ||
((text_sets.sets[text_curr_nr].text_scroll == true) && (text_sets.sets[text_curr_nr].text_scroll_pass > 0) && (text_pass >= text_sets.sets[text_curr_nr].text_scroll_pass)) ||
(((text_sets.sets[text_curr_nr].text_scroll_pass == 0) || text_sets.sets[text_curr_nr].text_scroll == false) && (text_sets.sets[text_curr_nr].time_ms == 0) && ((millis() - text_set_starttime) >= 10000)))
{
//Serial.printf("[%lu] Meet start set condition. Curr set is %d. \n", millis(), text_curr_nr);
if (0 < text_set_starttime || text_sets.sets[text_curr_nr].text == '\0' || text_sets.sets[text_curr_nr].active == false)
text_curr_nr++;
if (text_curr_nr == text_nr_sets)
text_curr_nr = 0;
text_pass = 0;
if (text_sets.sets[text_curr_nr].text != '\0' && text_sets.sets[text_curr_nr].active == true)
{
Serial.printf("[%lu] Set %d. Runtime %d. Text:'%s'\n", millis(), text_curr_nr, text_sets.sets[text_curr_nr].time_ms, text_sets.sets[text_curr_nr].text);
this->matrix->fillScreen(0);
textpixel = 6 * strlen(text_sets.sets[text_curr_nr].text);
switch (text_sets.sets[text_curr_nr].align)
{
case TEXTLEFT:
text_pos = 0;
break;
case TEXTRIGHT:
text_pos = this->matrix->width();
break;
case TEXTCENTER:
text_pos = this->matrix->width() - textpixel;
text_pos = text_pos / 2;
break;
}
show_matrix(text_sets.sets[text_curr_nr].text, text_pos, text_sets.sets[text_curr_nr].color);
text_set_starttime = millis();
}
}
else {
//Serial.printf("[%lu] Don't meet start set condition. Text is: %s. Active is: %d\n", millis(), text_sets.sets[text_curr_nr].text, text_sets.sets[text_curr_nr].active);
}
}
void LedDisplayController::show_matrix(const char *text, int pos, uint16_t color)
{
Serial.printf("TEXT: %s (pos=%d, color=%d)\n", text, pos, color);
this->matrix->setTextColor(color);
//Serial.printf("TEXT: %s (pos=%d, color=%d)\n", text, pos, this->colorFromHex(String(color)));
this->matrix->setTextColor(this->colorFromHex(String(color)));
this->matrix->setCursor(pos, 0);
this->matrix->print(text);
portDISABLE_INTERRUPTS();
@ -122,10 +158,135 @@ void LedDisplayController::show_matrix(const char *text, int pos, uint16_t color
portENABLE_INTERRUPTS();
}
void LedDisplayController::storeDisplaySet()
uint16_t LedDisplayController::colorFromHex(String hex)
{
hex.replace("#", "");
long number = (long)strtol(&hex[0], NULL, 16);
int r = number >> 16;
int g = number >> 8 & 0xFF;
int b = number & 0xFF;
//Serial.println("Color is: " + hex + " rgb are: r: " + r + " b: " + b + " g: " + g);
return this->matrix->Color(r, g, b);
}
// -------------------
// - Storage control -
// -------------------
LedDisplayController::GetSetTextSetParameterExitCode LedDisplayController::getSetTextSetParameter(int index, DisplayTextSetParameter parameter, String *value, bool set)
{
if (parameter < 0 || parameter >= DisplayTextSetParameterCount)
return InvalidParameterError;
else if (index < 0 || index >= this->MaximumTextSets)
return IndexOutOfRangeError;
else if (value == nullptr)
return ValueIsNullptrError;
else if (strcmp(this->text_sets.valid, "OK") != 0)
return InternalError;
text_set_t *currentTextSet = &this->text_sets.sets[index];
String returnValue = "";
switch (parameter)
{
case TextParameter:
if (set)
strncpy(currentTextSet->text, value->c_str(), sizeof(currentTextSet->text));
else
returnValue = String(currentTextSet->text);
break;
case ActiveParameter:
if (set)
currentTextSet->active = *value == "true";
else
returnValue = currentTextSet->active ? "true" : "false";
break;
case RuntimeParameter:
if (set)
currentTextSet->runtime = value->toInt();
else
returnValue = String(currentTextSet->runtime);
break;
case ColorParameter:
if (set)
strncpy(currentTextSet->color, value->c_str(), sizeof(currentTextSet->color));
else
returnValue = String(currentTextSet->color);
break;
case AlignmentParameter:
if (set)
{
if (value->toInt() < 0 || value->toInt() > AlignRight)
return ValueOutOfRangeError;
currentTextSet->alignment = text_align_t(value->toInt());
}
else
returnValue = String(currentTextSet->alignment);
break;
case ScrollParameter:
if (set)
currentTextSet->scroll = *value == "true";
else
returnValue = currentTextSet->scroll ? "true" : "false";
break;
case ScrollSpeedParameter:
if (set)
{
if (value->toInt() < 0 || value->toInt() > 10)
return ValueOutOfRangeError;
currentTextSet->scrollSpeed = value->toInt();
}
else
returnValue = String(currentTextSet->scrollSpeed);
break;
case ScrollCountParameter:
if (set)
{
if (value->toInt() < 0)
return ValueOutOfRangeError;
currentTextSet->scrollCount = value->toInt();
}
else
returnValue = String(currentTextSet->scrollCount);
break;
case IndexParameter:
if (set)
return ParameterNotWritableError;
else
returnValue = String(index);
break;
default:
break;
}
if (set)
{
this->storeTextSets();
return Success;
}
else
{
*value = returnValue;
return Success;
}
}
void LedDisplayController::storeTextSets()
{
// write conf to EEPROM
EEPROM.begin(DISP_STRUCT_SIZE);
EEPROM.begin(sizeof(sets_t));
//for (size_t i = 0 ; i < DISP_STRUCT_SIZE ; i++)
//{
// EEPROM.write(i, 0);
@ -136,12 +297,12 @@ void LedDisplayController::storeDisplaySet()
EEPROM.end();
}
bool LedDisplayController::loadDisplaySet()
bool LedDisplayController::loadTextSets()
{
bool rc = false;
sets_t buf = {};
// read conf from EEPROM
EEPROM.begin(DISP_STRUCT_SIZE);
EEPROM.begin(sizeof(sets_t));
EEPROM.get(0, buf);
EEPROM.end();
if (strcmp(buf.valid, "OK") == 0)
@ -151,108 +312,44 @@ bool LedDisplayController::loadDisplaySet()
}
else
{
memset(&text_sets, 0, sizeof(text_sets));
// There was an error reading the sets -> rebuild with default values!
sets_t defaultTextSets;
strncpy(defaultTextSets.valid, "OK", sizeof(defaultTextSets.valid));
for (int i = 0; i < this->MaximumTextSets; i++)
{
text_set_t defaultTextSet{
"",
false,
0,
"",
AlignCenter,
false,
0,
0};
defaultTextSets.sets[i] = defaultTextSet;
}
this->text_sets = defaultTextSets;
this->storeTextSets();
}
return rc;
}
String LedDisplayController::get_paramstring_from_struct(String name)
{
return (getset_param_at_struct(name, "", false));
}
void LedDisplayController::set_param_to_struct(String name, String value)
{
getset_param_at_struct(name, value, true);
}
String LedDisplayController::getset_param_at_struct(String name, String value, bool set)
{
String name_value = "";
int name_setnr_index = name.lastIndexOf("_");
int name_setnr = -1;
int name_index = -1;
String name_name = "unknown";
if (name_setnr_index > 0)
{
name_setnr = name.substring(name_setnr_index + 1).toInt();
name_name = name.substring(0, name_setnr_index + 1);
for (int pnr = 0; pnr < nr_param_names; pnr++)
{
if (name_name == set_param_name[pnr])
{
name_index = pnr;
break;
}
}
//Serial.printf("Param: (name=%s,set=%d, index=%d) %s = %s \n", name_name.c_str(), name_setnr, name_index, name.c_str(), value.c_str());
if (name_index != -1 && name_setnr != -1 && name_name != "unknown")
{
name_value += name_name + String(name_setnr) + "=";
switch (name_index)
{
case PCOLOR:
//if (true == set)
//text_sets.sets[name_setnr].color = (unint16_t)value.toInt();
name_value += String(text_sets.sets[name_setnr].color);
break;
case PTEXT:
if (true == set)
snprintf((char *)text_sets.sets[name_setnr].text, MAX_TXT_LENGTH, value.c_str());
name_value += String(text_sets.sets[name_setnr].text);
break;
case PTIME:
if (true == set)
text_sets.sets[name_setnr].time_ms = value.toInt() * 1000;
name_value += String(text_sets.sets[name_setnr].time_ms / 1000);
break;
case PSCROLL:
if (true == set)
text_sets.sets[name_setnr].text_scroll = (value == "true") ? true : false;
name_value += String(text_sets.sets[name_setnr].text_scroll);
break;
case PACTIVE:
if (true == set)
text_sets.sets[name_setnr].active = (value == "true") ? true : false;
name_value += String(text_sets.sets[name_setnr].active);
break;
case PALIGN:
if (true == set)
text_sets.sets[name_setnr].align = (text_align_t)value.toInt();
name_value += String(text_sets.sets[name_setnr].align);
break;
case PSCROLL_RUNS:
if (true == set)
text_sets.sets[name_setnr].text_scroll_pass = value.toInt();
name_value += String(text_sets.sets[name_setnr].text_scroll_pass);
break;
}
//Serial.printf("get/set %s\n", name_value.c_str());
}
}
return (name_value);
}
void LedDisplayController::setTexts(sets_t texts) {
this->text_sets = texts;
this->storeDisplaySet();
}
LedDisplayController::sets_t LedDisplayController::getTexts() {
return this->text_sets;
}
uint16_t LedDisplayController::Color(uint8_t r, uint8_t g, uint8_t b) {
return this->matrix->Color(r,g,b);
}
// ----------
// - Extern -
// ----------
void updateDisplayGlobal(void *)
{
for(;;) {
for (;;)
{
esp_task_wdt_reset();
delay(1);
ledDisplayControllerGlobal->disp_update();
ledDisplayControllerGlobal->loop();
}
}

View file

@ -1,17 +1,12 @@
#include "OmobiLedDisplay.h"
OmobiLedDisplay::OmobiLedDisplay(String deviceName, const byte ledPin)
OmobiLedDisplay::OmobiLedDisplay(String deviceName, Adafruit_NeoMatrix *ledDisplayMatrix)
{
this->ledDisplayController = new LedDisplayController(ledPin);
this->ledDisplayController->setTexts(LedDisplayController::sets_t{
{// TEXT , SHOWTIME, COLOR, ALIGNMENT, SCROLL, SCROLLNR, ACTIVE
{"itsblue", 5000, ledDisplayController->Color(0, 0, 255), LedDisplayController::TEXTCENTER, false, 1, true},
{"", 0, ledDisplayController->Color(0, 0, 255), LedDisplayController::TEXTCENTER, false, 4, false}
},
"OK"});
// init led display controller
this->ledDisplayController = new LedDisplayController(ledDisplayMatrix);
this->ledDisplayController->setTextSetParameter(0, LedDisplayController::ActiveParameter, "true");
// init ble server
this->bleServer = new BluetoothLeUartServer(deviceName, "6e400001-b5a3-f393-e0a9-e50e24dcca9e", "6e400002-b5a3-f393-e0a9-e50e24dcca9e", "6e400003-b5a3-f393-e0a9-e50e24dcca9e");
this->bleServer->setCallbacks(this);
}
@ -20,121 +15,109 @@ void OmobiLedDisplay::onDeviceConnectedChanged(bool deviceConnected)
{
if (deviceConnected)
Serial.println("Device connected");
else
Serial.println("Device disconnected");
}
void OmobiLedDisplay::onDataReceived(String data)
void OmobiLedDisplay::onDataReceived(String dataString)
{
if (data.startsWith("GET_TEXTS"))
// process JSON
const size_t capacity = JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 200;
DynamicJsonDocument requestDoc(capacity);
DeserializationError error = deserializeJson(requestDoc, dataString);
// return on error
if(error != DeserializationError::Ok)
return;
// get reuqest data
OmobiDisplayCommand requestHeader = requestDoc["header"];
JsonObject requestData = requestDoc["data"];
// prepare reply data
DynamicJsonDocument replyDoc(capacity);
replyDoc["header"] = requestHeader;
OmobiDisplayStatusCode replyStatus = InternalError;
JsonObject replyData = replyDoc.createNestedObject("data");
switch (requestHeader)
{
const size_t capacity = JSON_ARRAY_SIZE(LedDisplayController::text_nr_sets) + LedDisplayController::text_nr_sets * (JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(8));
case GetAllTextSetsCommand:
{
// cycle through all text sets
for (int textSetIndex = 0; textSetIndex < LedDisplayController::MaximumTextSets; textSetIndex++)
{
if (this->ledDisplayController->getTextSetParameter(textSetIndex, LedDisplayController::TextParameter) == "")
continue;
//Serial.println("Adding index " + String(textSetIndex) + " with text: " + this->ledDisplayController->getTextSetParameter(textSetIndex, LedDisplayController::TextParameter));
// if a set isn't empty, go through all parameters
for (int textSetParameter = 0; textSetParameter < LedDisplayController::DisplayTextSetParameterCount; textSetParameter++)
{
// send each parameter to the client
const size_t capacity = JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 200;
DynamicJsonDocument doc(capacity);
for (int i = 0; i < LedDisplayController::text_nr_sets; i++)
{
LedDisplayController::text_set_t textSet = this->ledDisplayController->getTexts().sets[i];
JsonObject doc_0 = doc.createNestedObject();
doc_0["active"] = textSet.active;
doc_0["alignment"] = textSet.align;
doc["header"] = GetTextSetParameterCommand;
JsonObject doc_0_color = doc_0.createNestedObject("color");
doc_0_color["r"] = 0;
doc_0_color["g"] = 0;
doc_0_color["b"] = 0;
doc_0["runtime"] = textSet.time_ms;
doc_0["scroll"] = textSet.text_scroll;
doc_0["scrollCount"] = textSet.text_scroll_pass;
doc_0["scrollSpeed"] = 5;
doc_0["text"] = textSet.text;
}
JsonObject data = doc.createNestedObject("data");
data["index"] = textSetIndex;
data["parameter"] = textSetParameter;
data["value"] = this->ledDisplayController->getTextSetParameter(
textSetIndex,
LedDisplayController::DisplayTextSetParameter(textSetParameter));
String json;
serializeJson(doc, json);
this->bleServer->sendData("GET_TEXTS:" + json);
this->bleServer->sendData(json);
}
}
else if (data.startsWith("SET_TEXTS:"))
{
const size_t capacity = JSON_ARRAY_SIZE(LedDisplayController::text_nr_sets) + LedDisplayController::text_nr_sets * JSON_OBJECT_SIZE(8) + 270;
DynamicJsonDocument doc(capacity);
data.replace("SET_TEXTS:", "");
Serial.println("Got new SET TEXT:" + data);
// TODO: handle Error!
DeserializationError err = deserializeJson(doc, data);
replyStatus = Success;
replyData["maximumTextSets"] = LedDisplayController::MaximumTextSets;
replyData["maximumTextLength"] = LedDisplayController::MaximumTextLength;
Serial.println("deserialization result: " + String(err.c_str()));
if(err != DeserializationError::Ok)
return;
JsonArray textsArray = doc.as<JsonArray>();
LedDisplayController::sets_t textSets;
strncpy(textSets.valid, "OK", sizeof(textSets.valid));
for (int i = 0; i < textsArray.size(); i++)
{
Serial.println(" | Processing index " + String(i));
if (i >= LedDisplayController::text_nr_sets)
break;
JsonObject textObject = textsArray[i].as<JsonObject>();
if(
!textObject.containsKey("text") ||
!textObject.containsKey("runtime") ||
//!textObject.containsKey("color") ||
!textObject.containsKey("scroll") ||
!textObject.containsKey("scrollCount") ||
!textObject.containsKey("active") ||
!textObject.containsKey("alignment")
)
continue;
LedDisplayController::text_set_t textSet;
const char* text = textObject["text"];
strncpy(textSet.text, text, sizeof(textSet.text));
uint16_t runtime = textObject["runtime"];
textSet.time_ms = runtime;
//JsonObject colorObject = textObject["color"].as<JsonObject>();
//uint16_t color = this->ledDisplayController->Color(colorObject["r"], colorObject["color"]["g"], colorObject["color"]["b"]);
//textSet.color = color;
bool scroll = textObject["scroll"];
textSet.text_scroll = scroll;
uint16_t scrollCount = textObject["scrollCount"];
textSet.text_scroll_pass = scrollCount;
bool active = textObject["active"];
textSet.active = active;
int alignment = textObject["alignment"];
textSet.align = LedDisplayController::text_align_t(alignment);
Serial.println(
" | Got set: text: " + String(textSet.text) +
" time: " + String(textSet.time_ms) +
" color: " + String(textSet.color) +
" scroll: " + String(textSet.text_scroll) +
" scrollCount: " + String(textSet.text_scroll_pass) +
" active: " + String(textSet.active)
);
textSets.sets[i] = textSet;
}
case GetDisplayBrightnessCommand:
{
replyData["displayBrightness"] = this->ledDisplayController->getBrightness();
replyStatus = Success;
break;
}
this->ledDisplayController->setTexts(textSets);
case SetTextSetParameterCommand:
{
int index = requestData["index"];
int parameter = requestData["parameter"];
String value = requestData["value"];
this->bleServer->sendData("SET_TEXTS:OK");
LedDisplayController::GetSetTextSetParameterExitCode res = this->ledDisplayController->setTextSetParameter(index, LedDisplayController::DisplayTextSetParameter(parameter), value);
if (res == LedDisplayController::Success)
replyStatus = Success;
else
{
replyStatus = DisplayControllerError;
replyData["displayControllerError"] = res;
}
else if (data.startsWith("GET_BRIGHTNESS"))
this->bleServer->sendData("GET_BRIGHTNESS:5");
else if (data.startsWith("SET_BRIGHTNESS:"))
this->bleServer->sendData("SET_BRIGHTNESS:OK");
break;
}
case SetDisplayBrightnessCommand:
{
this->ledDisplayController->setBrightness(requestData["displayBrightness"]);
replyStatus = Success;
break;
}
default:
break;
}
// reply to the client
replyDoc["status"] = replyStatus;
String json;
serializeJson(replyDoc, json);
this->bleServer->sendData(json);
}

View file

@ -1,33 +1,31 @@
#include <Arduino.h>
//#include "BluetoothLeUartServer.h"
#include "OmobiLedDisplay.h"
#define PIN 4
OmobiLedDisplay *display;
class MyCallbacks : public BluetoothLeUartServerCallbacks {
virtual void onDeviceConnectedChanged(bool deviceConnected) {
Serial.println("Device connected changed");
};
virtual void onDataReceived(String data) {
Serial.println("Got some data: " + data);
};
};
//BluetoothLeUartServer* server;
void setup()
{
Serial.begin(115200);
Serial.printf("Los\n");
display = new OmobiLedDisplay("OmobiLedDisplay1", PIN);
//server = new BluetoothLeUartServer("OmobiLedDisplay1", "6e400001-b5a3-f393-e0a9-e50e24dcca9e", "6e400002-b5a3-f393-e0a9-e50e24dcca9e", "6e400003-b5a3-f393-e0a9-e50e24dcca9e");
//server->setCallbacks(new MyCallbacks());
Adafruit_NeoMatrix *displayMatrix = new Adafruit_NeoMatrix(
8,
8,
1,
1,
PIN,
NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_PROGRESSIVE +
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_TILE_PROGRESSIVE,
NEO_GRB + NEO_KHZ800);
// create our display
display = new OmobiLedDisplay("OmobiLedDisplay1", displayMatrix);
}
void loop()
{
// nothing to do in loop
delay(1000);
}