#include "LedDisplayController.h" LedDisplayController *ledDisplayControllerGlobal = nullptr; LedDisplayController::LedDisplayController(Adafruit_NeoMatrix *matrix) { ledDisplayControllerGlobal = this; this->loadTextSets(); this->matrix = matrix; this->matrix->begin(); this->matrix->setTextWrap(false); this->matrix->setBrightness(40); text_curr_nr = 0; text_set_starttime = 0; text_pass = 0; textpixel = 0; disp_brightness = 5; disp_show = false; this->disp_init(); // create updater task xTaskCreatePinnedToCore(updateDisplayGlobal, "DisplayUpdateTask", 10000, NULL, 1, &displayUpdateTask, 0); } // -------------------- // - Public functions - // -------------------- void LedDisplayController::loop() { if (this->disp_show) { 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].scroll) { 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; text_set_starttime = 0; text_pass = 0; text_pos = this->matrix->width(); 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); show_matrix(text_sets.sets[text_curr_nr].text, text_pos, text_sets.sets[text_curr_nr].color); (int)text_pos--; if (int(text_pos + textpixel) < 0) { 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); } delay(100); } void LedDisplayController::show_matrix(const char *text, int pos, const char *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(); this->matrix->show(); portENABLE_INTERRUPTS(); } 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(sizeof(sets_t)); //for (size_t i = 0 ; i < DISP_STRUCT_SIZE ; i++) //{ // EEPROM.write(i, 0); //} strncpy(text_sets.valid, "OK", sizeof(text_sets.valid)); EEPROM.put(0, text_sets); EEPROM.commit(); EEPROM.end(); } bool LedDisplayController::loadTextSets() { bool rc = false; sets_t buf = {}; // read conf from EEPROM EEPROM.begin(sizeof(sets_t)); EEPROM.get(0, buf); EEPROM.end(); if (strcmp(buf.valid, "OK") == 0) { rc = true; memcpy(&text_sets, &buf, sizeof(text_sets)); } else { // 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; } // ---------- // - Extern - // ---------- void updateDisplayGlobal(void *) { for (;;) { esp_task_wdt_reset(); delay(1); ledDisplayControllerGlobal->loop(); } }