#include "LedDisplayController.h" LedDisplayController *ledDisplayControllerGlobal = nullptr; static const uint8_t StepsFade = 255; static const float RFade = (StepsFade*log10(2))/log10(255); // -------------------- // - 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(); } } } } } bool LedDisplayController::registerEepromUnit(EepromManager *eepromManager) { if (this->eepromUnit != nullptr) return false; this->eepromUnit = eepromManager->registerEempromUnit(sizeof(sets_t)); return this->loadTextSets(); } 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->text_sets.disp_brightness; } bool LedDisplayController::setBrightness(int brightness) { if (brightness < 0 || brightness > 255) return false; this->text_sets.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; last_display_show_ms = 0; default_display_show_wait_ms = 200; display_show_wait_ms = 100; text_no_activ_legal_sets = true; } void LedDisplayController::disp_start_set() { bool legal_entry_setting = (0 == text_set_starttime) || // current entry is not scrolling: maximum of runtime is defined and runtime is over ((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))) || // current entry is scrolling: but maximum number of scrolls is defined and reached ((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))) ; bool illegal_entry_settings = // current entry is not active (text_sets.sets[text_curr_nr].active == false) || // current entry has no text defined (text_sets.sets[text_curr_nr].text == '\0') || // current entry is not scrolling: but no runtime is defined ((text_sets.sets[text_curr_nr].scroll == false) && (text_sets.sets[text_curr_nr].runtime == 0)) || // current entry is scrolling: but no scrollnumber defined ((text_sets.sets[text_curr_nr].scroll == true) && (text_sets.sets[text_curr_nr].scrollCount == 0)) ; if (legal_entry_setting || illegal_entry_settings //(((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; if(false == text_no_activ_legal_sets ) { this->matrix->fillScreen(0); this->matrix->Show(); } text_no_activ_legal_sets = false; } text_pass = 0; if (text_sets.sets[text_curr_nr].active && ( ((text_sets.sets[text_curr_nr].scroll == false) && (text_sets.sets[text_curr_nr].runtime > 0)) || ((text_sets.sets[text_curr_nr].scroll == true) && (text_sets.sets[text_curr_nr].scrollCount > 0)) ) ) { text_no_activ_legal_sets = 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); // scrolling text has always left or right allignment - depending on direction of scroll if(true == text_sets.sets[text_curr_nr].scroll) text_sets.sets[text_curr_nr].alignment = AlignRight; 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() { if(millis() - last_display_show_ms > display_show_wait_ms) { last_display_show_ms = millis(); display_show_wait_ms = ((2*default_display_show_wait_ms)/text_sets.sets[text_curr_nr].scrollSpeed); //Serial.printf("speed %d, waittime: %d' \n", text_sets.sets[text_curr_nr].scrollSpeed, display_show_wait_ms); 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); } } } 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->SetBrightness(pow (2, (this->text_sets.disp_brightness / RFade)) - 1); 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) { if (*value == "") // delete the index for (int i = index; i < this->maximumTextSets; i++) { if (i > this->maximumTextSets - 1) this->text_sets.sets[i] = this->text_sets.sets[i + 1]; else this->text_sets.sets[i] = this->defaultTextSet; } else 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()*1000; else returnValue = String(round(currentTextSet->runtime/1000)); //Serial.printf("Runtim is: %d \n", 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 ScrollDirectionParameter: if(set) currentTextSet->scrollDirection = value->toInt(); else returnValue = currentTextSet->scrollDirection; 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; } } bool LedDisplayController::storeTextSets() { Serial.println("Storing Text Sets..."); if (this->eepromUnit == nullptr) { Serial.println("ERROR"); return false; } strncpy(this->text_sets.valid, "OK", sizeof(this->text_sets.valid)); this->eepromUnit->write(this->text_sets); Serial.println("OK"); return true; } bool LedDisplayController::loadTextSets() { sets_t buf = {}; Serial.println("Loading Text Sets..."); if (this->eepromUnit != nullptr) { // read conf from EEPROM this->eepromUnit->read(buf); } Serial.println("Loaded text sets: valid: " + String(buf.valid)); if (strcmp(buf.valid, "OK") == 0) { memcpy(&text_sets, &buf, sizeof(sets_t)); //Serial.printf("OK: '%s\n", text_sets.sets[0].text); return true; } else { // There was an error reading the sets -> rebuild with default values! sets_t defaultTextSets; for (int i = 0; i < this->maximumTextSets; i++) { defaultTextSets.sets[i] = this->defaultTextSet; } memcpy(&text_sets, &defaultTextSets, sizeof(sets_t)); text_sets.disp_brightness = 100; return this->storeTextSets(); } } // ---------- // - Extern - // ---------- void updateDisplayGlobal(void* object) { for (;;) { esp_task_wdt_reset(); delay(1); ((LedDisplayController*)(object))->loop(); } }