#include "LedDisplayController.h" // -------------------- // - Public functions - // -------------------- void LedDisplayController::loop() { //Serial.printf("Ligth: %d \n" , analogRead(36)); storeDataToEEPROM(); if (this->disp_show) { measureBrightnessEnv(); disp_start_set(); if (true == text_sets.sets[text_curr_nr].active) { if (text_sets.sets[text_curr_nr].text[0] != '\0') { if (text_sets.sets[text_curr_nr].scroll) { disp_scroll_text(); } } } } } bool LedDisplayController::storeDataToEEPROM() { if(millis() - this->setsModiefiedLastTime_ms > this->msToWaitBeforeModifyGetsInactive) { if(true == this->setModifyingActive) { this->setModifyingActive = false; Serial.println("Sets are not longer modified by external data ..."); Serial.println("Storing Text Sets To EEPROM now..."); 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; } } return true; } 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; this->matrix->SetBrightness( adjustBrightnessToEnv() ); this->matrix->Show(); this->storeTextSets(); return true; } bool LedDisplayController::getAutomaticBrightnessAdjustment() { return this->text_sets.disp_automatic_brightness_adjustment; } void LedDisplayController::setAutomaticBrightnessAdjustment(bool automaticBrightnessAdjustment) { this->text_sets.disp_automatic_brightness_adjustment = automaticBrightnessAdjustment; this->storeTextSets(); brightness_init(); measureBrightnessEnv(); } // ------------------ // - Matrix control - // ------------------ void LedDisplayController::brightness_init() { for(uint8_t i = 0; i < meas_slots; i++) this->brightness_levels[i] = analogRead(LDR_PIN); this->current_meas_slot = 0; this->last_brightness_meas = millis(); measureBrightnessEnv(); } 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] == '\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) { if(0 == text_sets.sets[text_curr_nr].scrollDirection) text_pos = this->matrix->width(); else text_pos = 0 - textpixel; } else { switch (text_sets.sets[text_curr_nr].alignment) { case AlignLeft: text_pos = 0; break; case AlignRight: text_pos = this->matrix->width() - textpixel; 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 && text_sets.sets[text_curr_nr].scrollSpeed != 0) { 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); if(0==text_sets.sets[text_curr_nr].scrollDirection) { (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); } } else { (int)text_pos++; if (text_pos > this->matrix->width()) { text_pos = 0 - textpixel; 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( adjustBrightnessToEnv() ); this->matrix->setTextColor(this->colorFromHex(String(color))); this->matrix->setCursor(pos, 0); this->matrix->print(text); //portDISABLE_INTERRUPTS(); this->matrix->Show(); //portENABLE_INTERRUPTS(); } uint8_t LedDisplayController::adjustBrightnessToEnv( void ) { uint8_t brightness = ( pow (2, (this->text_sets.disp_brightness / RFade)) ) ; uint8_t brightness_adj = brightness * this->brightness_adjust ; //Serial.printf("brightness without adjust : %d . Adjust is: %f. Brightness with adjust : %d .\n", brightness, this->brightness_adjust, brightness_adj); if(brightness_adj < 1) brightness_adj = 1; return brightness_adj; } void LedDisplayController::measureBrightnessEnv( void ) { if(true == this->text_sets.disp_automatic_brightness_adjustment) { if( millis() - this->last_brightness_meas > 1000) { this->brightness_levels[this->current_meas_slot] = analogRead(LDR_PIN); //Serial.printf("brightness last measured value = %d\n", brightness_levels[current_meas_slot]); this->current_meas_slot = this->current_meas_slot+1>=this->meas_slots? 0 : this->current_meas_slot+1; this->last_brightness_meas = millis(); uint16_t smallest = brightness_levels[0]; uint16_t biggest = brightness_levels[0]; uint64_t sum = brightness_levels[0]; for(uint8_t i = 1; i < this->meas_slots; i++) { sum = sum + this->brightness_levels[i] ; if( this->brightness_levels[i] < smallest ) smallest = this->brightness_levels[i]; else { if( this->brightness_levels[i] > biggest ) biggest = this->brightness_levels[i]; } } sum = sum - smallest - biggest; sum = sum / (this->meas_slots - 2); //Serial.printf("brightness median value = %llu \n", sum); float adjust = ( ( ( ( 100.0/ ( 4095.0 / 2.0 ) ) * (float)sum ) ) / 100.0 ); adjust = adjust > 1.0 ? 1.0 : adjust ; adjust = adjust < 0.2 ? 0.1 : adjust ; this->brightness_adjust = adjust; Serial.printf("brightness_adjust = %f\n", this->brightness_adjust); } } else { this->brightness_adjust = 1.0; } } 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 Serial.println("Deleting: " + String(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((int)round(currentTextSet->runtime / 1000)); //Serial.printf("Runtime 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("Text Sets where modified ..."); this->setsModiefiedLastTime_ms = millis(); this->setModifyingActive = true; 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 = 70; text_sets.disp_automatic_brightness_adjustment = false; return this->storeTextSets(); } } // ---------- // - Extern - // ---------- void updateDisplayGlobal(void *object) { for (;;) { esp_task_wdt_reset(); delay(1); ((LedDisplayController *)(object))->loop(); } }