From d74da783b32ad368dc96922e5ba12657e49ddae3 Mon Sep 17 00:00:00 2001 From: Dorian Zedler Date: Wed, 14 Oct 2020 23:54:54 +0200 Subject: [PATCH] - finished implementing protocol - some changes and cleanup --- .../.vscode/settings.json | 4 +- .../include/BluetoothLeUartServer.h | 43 +- .../include/LedDisplayController.h | 124 +++--- .../include/OmobiLedDisplay.h | 33 +- .../include/omobi_html.h | 2 - .../src/BluetoothLeUartServer.cpp | 3 +- .../src/LedDisplayController.cpp | 415 +++++++++++------- .../src/OmobiLedDisplay.cpp | 205 ++++----- vscode/OmobiLEDdisplayBluetooth/src/main.cpp | 30 +- 9 files changed, 506 insertions(+), 353 deletions(-) delete mode 100644 vscode/OmobiLEDdisplayBluetooth/include/omobi_html.h diff --git a/vscode/OmobiLEDdisplayBluetooth/.vscode/settings.json b/vscode/OmobiLEDdisplayBluetooth/.vscode/settings.json index f77b6a9..01232d4 100644 --- a/vscode/OmobiLEDdisplayBluetooth/.vscode/settings.json +++ b/vscode/OmobiLEDdisplayBluetooth/.vscode/settings.json @@ -5,6 +5,8 @@ "deque": "cpp", "string": "cpp", "vector": "cpp", - "unordered_map": "cpp" + "unordered_map": "cpp", + "random": "cpp", + "memory": "cpp" } } \ No newline at end of file diff --git a/vscode/OmobiLEDdisplayBluetooth/include/BluetoothLeUartServer.h b/vscode/OmobiLEDdisplayBluetooth/include/BluetoothLeUartServer.h index 87399bd..04928b3 100644 --- a/vscode/OmobiLEDdisplayBluetooth/include/BluetoothLeUartServer.h +++ b/vscode/OmobiLEDdisplayBluetooth/include/BluetoothLeUartServer.h @@ -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 + * #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; }; @@ -52,7 +91,7 @@ class BluetoothLeUartServerCallbacks public: virtual ~BluetoothLeUartServerCallbacks(){}; - const char* test = "testlol"; + const char *test = "testlol"; virtual void onDeviceConnectedChanged(bool deviceConnected); virtual void onDataReceived(String data); diff --git a/vscode/OmobiLEDdisplayBluetooth/include/LedDisplayController.h b/vscode/OmobiLEDdisplayBluetooth/include/LedDisplayController.h index a2741a5..9d8bee0 100644 --- a/vscode/OmobiLEDdisplayBluetooth/include/LedDisplayController.h +++ b/vscode/OmobiLEDdisplayBluetooth/include/LedDisplayController.h @@ -11,88 +11,106 @@ 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; - 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(); }; -void updateDisplayGlobal(void*); +// function for updater task on core 0 +void updateDisplayGlobal(void *); extern LedDisplayController *ledDisplayControllerGlobal; #endif // LED_DISPLAY_CONTROLLER \ No newline at end of file diff --git a/vscode/OmobiLEDdisplayBluetooth/include/OmobiLedDisplay.h b/vscode/OmobiLEDdisplayBluetooth/include/OmobiLedDisplay.h index 5b40435..9e897ea 100644 --- a/vscode/OmobiLEDdisplayBluetooth/include/OmobiLedDisplay.h +++ b/vscode/OmobiLEDdisplayBluetooth/include/OmobiLedDisplay.h @@ -6,22 +6,39 @@ #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; + // befriend for callbacks + friend class BluetoothLeUartServer; protected: -// calbacks for BluetoothLeUartServerCallbacks - void onDeviceConnectedChanged(bool deviceConnected) override; + // calbacks for BluetoothLeUartServerCallbacks + void onDeviceConnectedChanged(bool deviceConnected) override; void onDataReceived(String data) override; private: -LedDisplayController* ledDisplayController; -BluetoothLeUartServer * bleServer; + enum OmobiDisplayCommand + { + GetAllTextSetsCommand = 10, + GetTextSetParameterCommand = 11, + GetDisplayBrightnessCommand = 12, + SetTextSetParameterCommand = 20, + SetDisplayBrightnessCommand = 21 + }; + + enum OmobiDisplayStatusCode + { + Success = 200, + InternalError = 500, + DisplayControllerError = 501 + }; + + LedDisplayController *ledDisplayController; + BluetoothLeUartServer *bleServer; }; #endif // OMOBI_LED_DISPLAY \ No newline at end of file diff --git a/vscode/OmobiLEDdisplayBluetooth/include/omobi_html.h b/vscode/OmobiLEDdisplayBluetooth/include/omobi_html.h deleted file mode 100644 index 862edf6..0000000 --- a/vscode/OmobiLEDdisplayBluetooth/include/omobi_html.h +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/vscode/OmobiLEDdisplayBluetooth/src/BluetoothLeUartServer.cpp b/vscode/OmobiLEDdisplayBluetooth/src/BluetoothLeUartServer.cpp index 0dcf64d..f384f36 100644 --- a/vscode/OmobiLEDdisplayBluetooth/src/BluetoothLeUartServer.cpp +++ b/vscode/OmobiLEDdisplayBluetooth/src/BluetoothLeUartServer.cpp @@ -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); } } diff --git a/vscode/OmobiLEDdisplayBluetooth/src/LedDisplayController.cpp b/vscode/OmobiLEDdisplayBluetooth/src/LedDisplayController.cpp index a94eef2..5190722 100644 --- a/vscode/OmobiLEDdisplayBluetooth/src/LedDisplayController.cpp +++ b/vscode/OmobiLEDdisplayBluetooth/src/LedDisplayController.cpp @@ -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,24 +25,61 @@ 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) + if (this->disp_show) + { + disp_start_set(); + if (true == text_sets.sets[text_curr_nr].active) { - disp_start_set(); - if (true == text_sets.sets[text_curr_nr].active) + if (text_sets.sets[text_curr_nr].text != '\0') { - if (text_sets.sets[text_curr_nr].text != '\0') + if (text_sets.sets[text_curr_nr].scroll) { - if (text_sets.sets[text_curr_nr].text_scroll) - { - disp_scroll_text(); - } + disp_scroll_text(); } } } + } } +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(); } } \ No newline at end of file diff --git a/vscode/OmobiLEDdisplayBluetooth/src/OmobiLedDisplay.cpp b/vscode/OmobiLEDdisplayBluetooth/src/OmobiLedDisplay.cpp index 3eec35c..dbfa1dc 100644 --- a/vscode/OmobiLEDdisplayBluetooth/src/OmobiLedDisplay.cpp +++ b/vscode/OmobiLEDdisplayBluetooth/src/OmobiLedDisplay.cpp @@ -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)); - 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; - - 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; - } - - String json; - serializeJson(doc, json); - this->bleServer->sendData("GET_TEXTS:" + json); - } - else if (data.startsWith("SET_TEXTS:")) + case GetAllTextSetsCommand: { - 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); - - Serial.println("deserialization result: " + String(err.c_str())); - - if(err != DeserializationError::Ok) - return; - - JsonArray textsArray = doc.as(); - - LedDisplayController::sets_t textSets; - strncpy(textSets.valid, "OK", sizeof(textSets.valid)); - - for (int i = 0; i < textsArray.size(); i++) + // cycle through all text sets + for (int textSetIndex = 0; textSetIndex < LedDisplayController::MaximumTextSets; textSetIndex++) { - Serial.println(" | Processing index " + String(i)); - - if (i >= LedDisplayController::text_nr_sets) - break; - - JsonObject textObject = textsArray[i].as(); - - if( - !textObject.containsKey("text") || - !textObject.containsKey("runtime") || - //!textObject.containsKey("color") || - !textObject.containsKey("scroll") || - !textObject.containsKey("scrollCount") || - !textObject.containsKey("active") || - !textObject.containsKey("alignment") - ) + if (this->ledDisplayController->getTextSetParameter(textSetIndex, LedDisplayController::TextParameter) == "") continue; - LedDisplayController::text_set_t textSet; + //Serial.println("Adding index " + String(textSetIndex) + " with text: " + this->ledDisplayController->getTextSetParameter(textSetIndex, LedDisplayController::TextParameter)); - const char* text = textObject["text"]; - strncpy(textSet.text, text, sizeof(textSet.text)); + // 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); - uint16_t runtime = textObject["runtime"]; - textSet.time_ms = runtime; + doc["header"] = GetTextSetParameterCommand; - //JsonObject colorObject = textObject["color"].as(); - //uint16_t color = this->ledDisplayController->Color(colorObject["r"], colorObject["color"]["g"], colorObject["color"]["b"]); - //textSet.color = color; + JsonObject data = doc.createNestedObject("data"); + data["index"] = textSetIndex; + data["parameter"] = textSetParameter; + data["value"] = this->ledDisplayController->getTextSetParameter( + textSetIndex, + LedDisplayController::DisplayTextSetParameter(textSetParameter)); - 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; + String json; + serializeJson(doc, json); + this->bleServer->sendData(json); + } } - this->ledDisplayController->setTexts(textSets); + replyStatus = Success; + replyData["maximumTextSets"] = LedDisplayController::MaximumTextSets; + replyData["maximumTextLength"] = LedDisplayController::MaximumTextLength; - this->bleServer->sendData("SET_TEXTS:OK"); + break; } - else if (data.startsWith("GET_BRIGHTNESS")) - this->bleServer->sendData("GET_BRIGHTNESS:5"); - else if (data.startsWith("SET_BRIGHTNESS:")) - this->bleServer->sendData("SET_BRIGHTNESS:OK"); + case GetDisplayBrightnessCommand: + { + replyData["displayBrightness"] = this->ledDisplayController->getBrightness(); + replyStatus = Success; + break; + } + + case SetTextSetParameterCommand: + { + int index = requestData["index"]; + int parameter = requestData["parameter"]; + String value = requestData["value"]; + + LedDisplayController::GetSetTextSetParameterExitCode res = this->ledDisplayController->setTextSetParameter(index, LedDisplayController::DisplayTextSetParameter(parameter), value); + + if (res == LedDisplayController::Success) + replyStatus = Success; + else + { + replyStatus = DisplayControllerError; + replyData["displayControllerError"] = res; + } + + 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); } \ No newline at end of file diff --git a/vscode/OmobiLEDdisplayBluetooth/src/main.cpp b/vscode/OmobiLEDdisplayBluetooth/src/main.cpp index 4dc0fc3..93c673b 100644 --- a/vscode/OmobiLEDdisplayBluetooth/src/main.cpp +++ b/vscode/OmobiLEDdisplayBluetooth/src/main.cpp @@ -1,33 +1,31 @@ #include - -//#include "BluetoothLeUartServer.h" #include "OmobiLedDisplay.h" #define PIN 4 -OmobiLedDisplay* display; +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); } \ No newline at end of file