diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index c7988bb344..509314dbb7 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -233,6 +233,7 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no file.read((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89 file.read((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 90 file.read((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 121 + file.read((uint8_t *)&_prefs.display_rotation, sizeof(_prefs.display_rotation)); // 137 file.close(); } @@ -273,6 +274,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_ file.write((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89 file.write((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 90 file.write((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 121 + file.write((uint8_t *)&_prefs.display_rotation, sizeof(_prefs.display_rotation)); // 137 file.close(); } diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index e8c1914bad..f00c5fbcac 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -876,6 +876,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe _prefs.rx_boosted_gain = 1; // enabled by default #endif #endif + _prefs.display_rotation = 3; // matches prior hardcoded E213/E290 default } void MyMesh::begin(bool has_display) { @@ -1981,6 +1982,15 @@ void MyMesh::checkCLIRescueCmd() { _prefs.ble_pin = atoi(&config[4]); savePrefs(); Serial.printf(" > pin is now %06d\n", _prefs.ble_pin); + } else if (memcmp(config, "display.rotation ", 17) == 0) { + uint8_t r = atoi(&config[17]); + if (r > 3) { + Serial.printf(" Error: display.rotation must be 0-3\n"); + } else { + _prefs.display_rotation = r; + savePrefs(); + Serial.printf(" > display.rotation is now %d\n", _prefs.display_rotation); + } } else { Serial.printf(" Error: unknown config: %s\n", config); } diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 48c381ceaf..99d48c9d77 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -34,4 +34,5 @@ struct NodePrefs { // persisted to file uint8_t autoadd_max_hops; // 0 = no limit, 1 = direct (0 hops), N = up to N-1 hops (max 64) char default_scope_name[31]; uint8_t default_scope_key[16]; + uint8_t display_rotation; // 0-3; forwarded to display driver setRotation(); default 3 }; \ No newline at end of file diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 876dc9c33c..6191fbaa71 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -218,6 +218,9 @@ void setup() { #endif #ifdef DISPLAY_CLASS + if (disp != NULL) { + disp->setRotation(the_mesh.getNodePrefs()->display_rotation); + } ui_task.begin(disp, &sensors, the_mesh.getNodePrefs()); // still want to pass this in as dependency, as prefs might be moved #endif } diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 666f79fc5c..7232ce0f20 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -911,6 +911,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc _prefs.rx_boosted_gain = 1; // enabled by default; #endif #endif + _prefs.display_rotation = 3; // matches prior hardcoded E213/E290 default pending_discover_tag = 0; pending_discover_until = 0; diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index e37078ce5f..0f4d3e1b25 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -96,6 +96,7 @@ void setup() { the_mesh.begin(fs); #ifdef DISPLAY_CLASS + display.setRotation(the_mesh.getNodePrefs()->display_rotation); ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION); #endif diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index 145fb0fd9f..b43f336c1a 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -652,6 +652,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc _prefs.gps_enabled = 0; _prefs.gps_interval = 0; _prefs.advert_loc_policy = ADVERT_LOC_PREFS; + _prefs.display_rotation = 3; // matches prior hardcoded E213/E290 default next_post_idx = 0; next_client_idx = 0; diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 825fb007d5..c62d17e4a2 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -73,6 +73,7 @@ void setup() { the_mesh.begin(fs); #ifdef DISPLAY_CLASS + display.setRotation(the_mesh.getNodePrefs()->display_rotation); ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION); #endif diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index b71afc72e2..7342f90ad0 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -89,7 +89,8 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166 file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170 file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290 - // next: 291 + file.read((uint8_t *)&_prefs->display_rotation, sizeof(_prefs->display_rotation)); // 291 + // next: 292 // sanitise bad pref values _prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f); @@ -119,6 +120,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { // sanitise settings _prefs->rx_boosted_gain = constrain(_prefs->rx_boosted_gain, 0, 1); // boolean + _prefs->display_rotation = constrain(_prefs->display_rotation, 0, 3); file.close(); } @@ -180,7 +182,8 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) { file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166 file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170 file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290 - // next: 291 + file.write((uint8_t *)&_prefs->display_rotation, sizeof(_prefs->display_rotation)); // 291 + // next: 292 file.close(); } @@ -494,6 +497,15 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep _prefs->multi_acks = atoi(&config[11]); savePrefs(); strcpy(reply, "OK"); + } else if (memcmp(config, "display.rotation ", 17) == 0) { + uint8_t r = atoi(&config[17]); + if (r > 3) { + strcpy(reply, "Error, display.rotation must be 0-3"); + } else { + _prefs->display_rotation = r; + savePrefs(); + strcpy(reply, "OK - reboot to apply"); + } } else if (memcmp(config, "allow.read.only ", 16) == 0) { _prefs->allow_read_only = memcmp(&config[16], "on", 2) == 0; savePrefs(); @@ -748,6 +760,8 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep sprintf(reply, "> %d", ((uint32_t) _prefs->agc_reset_interval) * 4); } else if (memcmp(config, "multi.acks", 10) == 0) { sprintf(reply, "> %d", (uint32_t) _prefs->multi_acks); + } else if (memcmp(config, "display.rotation", 16) == 0) { + sprintf(reply, "> %d", (uint32_t) _prefs->display_rotation); } else if (memcmp(config, "allow.read.only", 15) == 0) { sprintf(reply, "> %s", _prefs->allow_read_only ? "on" : "off"); } else if (memcmp(config, "flood.advert.interval", 21) == 0) { diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index ffdc7c6536..53a79d4b06 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -61,6 +61,7 @@ struct NodePrefs { // persisted to file uint8_t rx_boosted_gain; // power settings uint8_t path_hash_mode; // which path mode to use when sending uint8_t loop_detect; + uint8_t display_rotation; // 0-3; forwarded to display driver setRotation(); default 3 }; class CommonCLICallbacks { diff --git a/src/helpers/ui/DisplayDriver.h b/src/helpers/ui/DisplayDriver.h index ec63c19123..464635050f 100644 --- a/src/helpers/ui/DisplayDriver.h +++ b/src/helpers/ui/DisplayDriver.h @@ -13,6 +13,11 @@ class DisplayDriver { int width() const { return _w; } int height() const { return _h; } + // Rotation 0-3, same semantics as Arduino GFX setRotation(). + // Default no-op lets main.cpp call this uniformly across boards that + // don't honor runtime rotation. Concrete drivers override as needed. + virtual void setRotation(uint8_t r) { (void)r; } + virtual bool isOn() = 0; virtual void turnOn() = 0; virtual void turnOff() = 0; diff --git a/src/helpers/ui/E213Display.cpp b/src/helpers/ui/E213Display.cpp index 814693a06b..9ed757e064 100644 --- a/src/helpers/ui/E213Display.cpp +++ b/src/helpers/ui/E213Display.cpp @@ -46,8 +46,7 @@ bool E213Display::begin() { display = detectEInk(); } display->begin(); - // Set to landscape mode rotated 180 degrees - display->setRotation(3); + display->setRotation(_rotation); _init = true; _isOn = true; @@ -58,6 +57,14 @@ bool E213Display::begin() { return true; } +void E213Display::setRotation(uint8_t r) { + if (r > 3) return; // ignore invalid values; CLI validates but belt-and-braces + _rotation = r; + if (_init && display != NULL) { + display->setRotation(_rotation); + } +} + void E213Display::powerOn() { if (_periph_power) { _periph_power->claim(); diff --git a/src/helpers/ui/E213Display.h b/src/helpers/ui/E213Display.h index 420792c8a3..73e2956ccb 100644 --- a/src/helpers/ui/E213Display.h +++ b/src/helpers/ui/E213Display.h @@ -13,6 +13,7 @@ class E213Display : public DisplayDriver { BaseDisplay* display=NULL; bool _init = false; bool _isOn = false; + uint8_t _rotation = 3; // default matches prior hardcoded value; overridden via setRotation() RefCountedDigitalPin* _periph_power; CRC32 display_crc; uint32_t last_display_crc_value = 0; @@ -25,6 +26,7 @@ class E213Display : public DisplayDriver { } } bool begin(); + void setRotation(uint8_t r) override; bool isOn() override { return _isOn; } void turnOn() override; void turnOff() override;