Merge remote-tracking branch 'origin/keymindCascade' into keymindCascade
This commit is contained in:
commit
86ef1e890c
17 files changed
+324
-21
No files matched your search
@@ -1115,6 +1115,7 @@ jobs:
|
||||
python3 -B test/test_ssd1306_power.py -v
|
||||
python3 -B test/test_oled_display_probe.py -v
|
||||
python3 -B test/test_oled_controller_settings.py -v
|
||||
python3 -B test/test_upstream_auto_display_merge.py -v
|
||||
python3 -B test/test_companion_inbox.py
|
||||
python3 -B test/test_heltec_r8_external_power.py
|
||||
python3 -B test/test_bluetooth_mac_contract.py
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "esp32/WiFiRadioPolicy.h"
|
||||
#endif
|
||||
#if defined(ESP32_PLATFORM) && defined(ENABLE_OTA) && \
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID))
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID) || defined(ENABLE_WIFI_INTERFACE))
|
||||
#include "esp32/WiFiOtaSeeder.h"
|
||||
#endif
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
@@ -52,7 +52,7 @@ static uint32_t _atoi(const char* sp) {
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
static bool observerBluetoothWiFiCoexistenceRequired() {
|
||||
#if defined(BLE_PIN_CODE) && defined(WIFI_SSID)
|
||||
#if defined(BLE_PIN_CODE) && (defined(WIFI_SSID) || defined(ENABLE_WIFI_INTERFACE))
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
@@ -1129,7 +1129,7 @@ bool CommonCLI::handleObserverGetCmd(uint32_t sender_timestamp, const char* conf
|
||||
#endif
|
||||
}
|
||||
#if defined(ESP32_PLATFORM) && defined(ENABLE_OTA) && \
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID))
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID) || defined(ENABLE_WIFI_INTERFACE))
|
||||
mesh::ota::WiFiOtaSeeder::appendStatus(reply, 160);
|
||||
#endif
|
||||
} else if (memcmp(config, "wifi.powersave", 14) == 0) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "WiFiSetupPortal.h"
|
||||
|
||||
#if defined(ESP32_PLATFORM) && defined(WIFI_SSID)
|
||||
#if defined(ESP32_PLATFORM) && (defined(WIFI_SSID) || defined(ENABLE_WIFI_INTERFACE))
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <helpers/esp32/StaticHtml.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(ESP32_PLATFORM) && defined(WIFI_SSID)
|
||||
#if defined(ESP32_PLATFORM) && (defined(WIFI_SSID) || defined(ENABLE_WIFI_INTERFACE))
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
@@ -21,7 +21,7 @@ static_assert(sizeof(WEBCONFIG_AP_PREFIX) <= 28,
|
||||
#include <esp_heap_caps.h>
|
||||
|
||||
#if defined(ESP32_PLATFORM) && defined(ENABLE_OTA) && \
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID))
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID) || defined(ENABLE_WIFI_INTERFACE))
|
||||
#include <helpers/esp32/WiFiOtaSeeder.h>
|
||||
#endif
|
||||
|
||||
@@ -177,7 +177,7 @@ static bool bluetoothWiFiCoexistenceRequired() {
|
||||
// This server is never constructed on the exclusive profile's BLE boot.
|
||||
// Any running WebConfig instance therefore has no active Bluetooth stack.
|
||||
return false;
|
||||
#elif defined(BLE_PIN_CODE) && defined(WIFI_SSID)
|
||||
#elif defined(BLE_PIN_CODE) && (defined(WIFI_SSID) || defined(ENABLE_WIFI_INTERFACE))
|
||||
return mesh::wifi::activeCompanionMode()
|
||||
!= mesh::wifi::CompanionMode::WiFiOnly;
|
||||
#else
|
||||
@@ -307,7 +307,7 @@ static bool fixedTimeEquals(const char* a, const char* b, size_t max_len) {
|
||||
|
||||
static void appendOtaSeederStatus(char* reply, size_t reply_len) {
|
||||
#if defined(ESP32_PLATFORM) && defined(ENABLE_OTA) && \
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID))
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID) || defined(ENABLE_WIFI_INTERFACE))
|
||||
mesh::ota::WiFiOtaSeeder::appendStatus(reply, reply_len);
|
||||
#else
|
||||
(void)reply;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "WiFiOtaSeeder.h"
|
||||
|
||||
#if defined(ESP32_PLATFORM) && defined(ENABLE_OTA) && \
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID))
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID) || defined(ENABLE_WIFI_INTERFACE))
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(ESP32_PLATFORM) && defined(ENABLE_OTA) && \
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID))
|
||||
(defined(WIFI_OTA_SEEDER) || defined(WIFI_SSID) || defined(ENABLE_WIFI_INTERFACE))
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "AutoDetectDisplay.h"
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "SSD1306Display.h"
|
||||
|
||||
// Compatibility with upstream's driver name. OLED_AUTO_DETECT selects the
|
||||
// shared backend, including saved controller overrides, rotation and one
|
||||
// framebuffer. RAK profiles retain SSD1306Display for existing size accounting.
|
||||
using AutoDetectDisplay = SSD1306Display;
|
||||
@@ -21,15 +21,15 @@ bool SH1106Display::i2c_probe(TwoWire &wire, uint8_t addr)
|
||||
}
|
||||
|
||||
// Color scheme
|
||||
ColorVal UIColor::window_bkg = SH110X_BLACK;
|
||||
ColorVal UIColor::title_bkg = SH110X_BLACK;
|
||||
ColorVal UIColor::title_txt = SH110X_WHITE;
|
||||
ColorVal UIColor::primary_txt = SH110X_WHITE;
|
||||
ColorVal UIColor::secondary_txt = SH110X_WHITE;
|
||||
ColorVal UIColor::warning_txt = SH110X_WHITE;
|
||||
ColorVal UIColor::popup_bkg = SH110X_BLACK;
|
||||
ColorVal UIColor::popup_txt = SH110X_WHITE;
|
||||
ColorVal UIColor::corp_blue = SH110X_WHITE;
|
||||
__attribute__((weak)) ColorVal UIColor::window_bkg = SH110X_BLACK;
|
||||
__attribute__((weak)) ColorVal UIColor::title_bkg = SH110X_BLACK;
|
||||
__attribute__((weak)) ColorVal UIColor::title_txt = SH110X_WHITE;
|
||||
__attribute__((weak)) ColorVal UIColor::primary_txt = SH110X_WHITE;
|
||||
__attribute__((weak)) ColorVal UIColor::secondary_txt = SH110X_WHITE;
|
||||
__attribute__((weak)) ColorVal UIColor::warning_txt = SH110X_WHITE;
|
||||
__attribute__((weak)) ColorVal UIColor::popup_bkg = SH110X_BLACK;
|
||||
__attribute__((weak)) ColorVal UIColor::popup_txt = SH110X_WHITE;
|
||||
__attribute__((weak)) ColorVal UIColor::corp_blue = SH110X_WHITE;
|
||||
|
||||
bool SH1106Display::begin()
|
||||
{
|
||||
|
||||
+7
@@ -82,6 +82,13 @@ struct Canvas {
|
||||
void reset() { std::fill(pixels.begin(),pixels.end(),0); }
|
||||
};
|
||||
Canvas* Canvas::active=nullptr;
|
||||
// This fixture exercises direct panel geometry; the full buffered T-Deck
|
||||
// renderer and its PSRAM canvas run in test_tdeck_display_cooperation.py.
|
||||
class TDeckCanvas : public Canvas {
|
||||
public:
|
||||
int16_t getCursorX() const { return x; }
|
||||
int16_t getCursorY() const { return y; }
|
||||
};
|
||||
struct ST7789Spi : Canvas { template<class... T> ST7789Spi(T...) {} };
|
||||
struct Adafruit_ST7789 : Canvas { template<class... T> Adafruit_ST7789(T...) {} };
|
||||
struct GxEPD2_150_BN { static const int WIDTH=200,HEIGHT=200; template<class... T> GxEPD2_150_BN(T...) {} };
|
||||
|
||||
@@ -50,12 +50,17 @@ class NativeDisplaysTest(unittest.TestCase):
|
||||
source += driver[a:b]
|
||||
source += method(driver, cls, "drawChar")
|
||||
else:
|
||||
source += f"bool {cls}::begin() {{ return true; }}\n"
|
||||
awake = "_isOn=true; " if cls == "ST7789LCDDisplay" else ""
|
||||
source += f"bool {cls}::begin() {{ {awake}return true; }}\n"
|
||||
for name in ("turnOn", "turnOff", "clear", "endFrame"):
|
||||
source += f"void {cls}::{name}() {{}}\n"
|
||||
source += f"void {cls}::startFrame(ColorVal) {{}}\n"
|
||||
if cls == "ST7789LCDDisplay":
|
||||
source += f"void {cls}::setFlipped(bool) {{}}\n"
|
||||
if "LILYGO_TDECK" in defines:
|
||||
source += f"{cls}::~{cls}() {{}}\n"
|
||||
source += method(driver, cls, "isBufferedRendering")
|
||||
source += f"void {cls}::finishCanvasPrimitive(int,int,int,int) {{ assert(false); }}\n"
|
||||
names = ["setTextSize", "setColor", "setCursor", "print", "fillRect", "drawRect", "drawXbm", "getTextWidth"]
|
||||
if cls == "ST7789LCDDisplay":
|
||||
names += ["setRotationDegrees"]
|
||||
@@ -66,6 +71,9 @@ class NativeDisplaysTest(unittest.TestCase):
|
||||
source += r'''
|
||||
int main() {
|
||||
Driver d; d.begin(); d.setColor(1); d.setTextSize(1);
|
||||
#ifdef LILYGO_TDECK
|
||||
assert(!d.isBufferedRendering());
|
||||
#endif
|
||||
auto& c=*Canvas::active;
|
||||
assert(d.width()==EXPECTED_WIDTH && d.height()==EXPECTED_HEIGHT);
|
||||
assert(!d.useSmallMessageFont());
|
||||
|
||||
@@ -440,7 +440,8 @@ class Nrf52VariantContractsTest(unittest.TestCase):
|
||||
|
||||
self.assertIn("bool isBridgeRunning() const override", header)
|
||||
self.assertIn("if (isRs232BridgeRunning()) reply_data[8] |= 0x01", implementation)
|
||||
self.assertIn("if (isBridgeRunning()) reply_data[8] |= 0x03", implementation)
|
||||
self.assertIn("if (isEspNowBridgeRunning()) reply_data[8] |= 0x03", implementation)
|
||||
self.assertNotIn("if (isBridgeRunning()) reply_data[8] |= 0x03", implementation)
|
||||
boot_failure = implementation[
|
||||
implementation.index("if (!bridge || !beginRS232Bridge())"):
|
||||
implementation.index("#else", implementation.index(
|
||||
|
||||
@@ -5,12 +5,143 @@ import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from test_t114_autodisplay_recipes import defines
|
||||
from test_upstream_observer_recipes import Recipes
|
||||
from test_replay_reset_integration import extract_braced
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
COMPANION = ROOT / "examples/companion_radio"
|
||||
|
||||
|
||||
class DynamicWiFiBootContractTest(unittest.TestCase):
|
||||
def test_new_ble_wifi_recipes_keep_dynamic_setup_and_queue_capacity(self):
|
||||
recipes = Recipes()
|
||||
for name in (
|
||||
"heltec_v4_tft_companion_radio_ble_femon",
|
||||
"heltec_v4_3_tft_companion_radio_ble_femoff",
|
||||
"heltec_v4_expansionkit_tft_companion_radio_ble_femon",
|
||||
"heltec_v4_3_expansionkit_tft_companion_radio_ble_femoff",
|
||||
"T_Beam_S3_Supreme_SX1262_companion_radio_ble",
|
||||
"T_Beam_S3_Supreme_SX1262_companion_radio_ble_ps",
|
||||
):
|
||||
with self.subTest(target=name):
|
||||
section = "env:" + name
|
||||
flags = defines(recipes.value(section, "build_flags"))
|
||||
self.assertEqual(flags["ENABLE_WIFI_INTERFACE"], "1")
|
||||
self.assertEqual(flags["BLE_PIN_CODE"], "123456")
|
||||
self.assertEqual(flags["OFFLINE_QUEUE_SIZE"], "512")
|
||||
self.assertNotIn("WIFI_SSID", flags)
|
||||
self.assertNotIn("WIFI_PWD", flags)
|
||||
for source in ("helpers/wifi/SerialWifiInterface.cpp",
|
||||
"helpers/WiFiSetupPortal.cpp",
|
||||
"helpers/esp32/WiFiOtaSeeder.cpp"):
|
||||
self.assertTrue(recipes.includes(section, source), source)
|
||||
|
||||
def test_dynamic_wifi_helpers_link_without_companion_header_normalization(self):
|
||||
portal = (ROOT / "src/helpers/WiFiSetupPortal.cpp").read_text()
|
||||
seeder = (ROOT / "src/helpers/esp32/WiFiOtaSeeder.cpp").read_text()
|
||||
|
||||
def guard(source):
|
||||
lines = iter(source.splitlines())
|
||||
line = next(line for line in lines if line.startswith("#if "))
|
||||
result = line
|
||||
while line.endswith("\\"):
|
||||
line = next(lines)
|
||||
result += "\n" + line
|
||||
return result
|
||||
|
||||
helper_source = '''
|
||||
#include <helpers/WiFiSetupPortal.h>
|
||||
#include <helpers/esp32/WiFiOtaSeeder.h>
|
||||
#include <helpers/CLICommandUtils.h>
|
||||
#include <Preferences.h>
|
||||
#include <strings.h>
|
||||
@PORTAL_GUARD@
|
||||
@PORTAL_METHODS@
|
||||
#endif
|
||||
@SEEDER_GUARD@
|
||||
namespace mesh { namespace ota {
|
||||
static bool listener_active = true, tcp_folder_attached = false;
|
||||
@SEEDER_METHODS@
|
||||
} }
|
||||
#endif
|
||||
'''.replace("@PORTAL_GUARD@", guard(portal)).replace("@SEEDER_GUARD@", guard(seeder))
|
||||
helper_source = helper_source.replace("@PORTAL_METHODS@", "\n".join(
|
||||
extract_braced(portal, signature) for signature in (
|
||||
"bool WiFiSetupPortal::loadStoredCredentials(",
|
||||
"bool WiFiSetupPortal::isPlaceholderSSID(")))
|
||||
helper_source = helper_source.replace("@SEEDER_METHODS@", "\n".join(
|
||||
extract_braced(seeder, signature) for signature in (
|
||||
"bool WiFiOtaSeeder::isListening(", "bool WiFiOtaSeeder::isAttached(")))
|
||||
caller = '''
|
||||
#include <helpers/WiFiSetupPortal.h>
|
||||
#include <helpers/esp32/WiFiOtaSeeder.h>
|
||||
#include <Preferences.h>
|
||||
#include <cassert>
|
||||
#if @PORTAL@
|
||||
static void portalTest() {
|
||||
assert(WiFiSetupPortal::isPlaceholderSSID(""));
|
||||
assert(!WiFiSetupPortal::isPlaceholderSSID("mesh"));
|
||||
char ssid[32] = {}, password[65] = {};
|
||||
assert(!WiFiSetupPortal::loadStoredCredentials(ssid, sizeof(ssid), password, sizeof(password)));
|
||||
nvs_values["ssid"] = {PT_STR, "mesh", 0};
|
||||
nvs_values["password"] = {PT_STR, "password", 0};
|
||||
assert(WiFiSetupPortal::loadStoredCredentials(ssid, sizeof(ssid), password, sizeof(password)));
|
||||
}
|
||||
#else
|
||||
class WiFiSetupPortal {}; // disabled declarations must stay absent
|
||||
#endif
|
||||
#if @SEEDER@
|
||||
static void seederTest() {
|
||||
assert(mesh::ota::WiFiOtaSeeder::isListening());
|
||||
assert(!mesh::ota::WiFiOtaSeeder::isAttached());
|
||||
}
|
||||
#else
|
||||
namespace mesh { namespace ota { class WiFiOtaSeeder {}; } }
|
||||
#endif
|
||||
int main() {
|
||||
#if @PORTAL@
|
||||
portalTest();
|
||||
#endif
|
||||
#if @SEEDER@
|
||||
seederTest();
|
||||
#endif
|
||||
}
|
||||
'''
|
||||
cases = (
|
||||
(("ESP32_PLATFORM", "ENABLE_WIFI_INTERFACE", "ENABLE_OTA=1"), 1, 1),
|
||||
(("ESP32_PLATFORM", 'WIFI_SSID="legacy"', "ENABLE_OTA=1"), 1, 1),
|
||||
(("ESP32_PLATFORM", "ENABLE_OTA=1"), 0, 0),
|
||||
(("ESP32_PLATFORM", "ENABLE_WIFI_INTERFACE"), 1, 0),
|
||||
(("ESP32_PLATFORM", "WIFI_OTA_SEEDER", "ENABLE_OTA=1"), 0, 1),
|
||||
(("NRF52_PLATFORM", "ENABLE_WIFI_INTERFACE", "ENABLE_OTA=1"), 0, 0),
|
||||
)
|
||||
with tempfile.TemporaryDirectory(prefix="dynamic-wifi-helpers-") as temporary:
|
||||
folder = Path(temporary)
|
||||
(folder / "Arduino.h").write_text("#pragma once\n#include <stddef.h>\n#include <stdint.h>\n")
|
||||
(folder / "IPAddress.h").write_text(
|
||||
"#pragma once\nstruct IPAddress { IPAddress(int,int,int,int) {} };\n")
|
||||
(folder / "Preferences.h").write_text(
|
||||
(ROOT / "test/fixtures/wifi_credentials_preferences.h").read_text())
|
||||
helper = folder / "helpers.cpp"
|
||||
helper.write_text(helper_source)
|
||||
for index, (flags, has_portal, has_seeder) in enumerate(cases):
|
||||
with self.subTest(defines=flags):
|
||||
main = folder / "main.cpp"
|
||||
main.write_text(caller.replace("@PORTAL@", str(has_portal))
|
||||
.replace("@SEEDER@", str(has_seeder)))
|
||||
binary = folder / str(index)
|
||||
built = subprocess.run([
|
||||
"c++", "-std=c++17", "-Wall", "-Wextra", "-Werror",
|
||||
"-I", str(folder), "-I", str(ROOT / "src"),
|
||||
*["-D" + flag for flag in flags], str(helper), str(main),
|
||||
"-o", str(binary),
|
||||
], text=True, capture_output=True, timeout=30)
|
||||
self.assertEqual(built.returncode, 0, built.stderr)
|
||||
ran = subprocess.run([str(binary)], capture_output=True, text=True, timeout=10)
|
||||
self.assertEqual(ran.returncode, 0, ran.stderr)
|
||||
|
||||
def test_real_include_order_normalizes_before_feature_selection(self):
|
||||
mesh = (COMPANION / "MyMesh.h").read_text()
|
||||
abstract = (COMPANION / "AbstractUITask.h").read_text()
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
"""Keep upstream's display name on the existing single-buffer OLED backend."""
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import test_oled_display_probe as probe
|
||||
from test_upstream_power_policy_merge import Recipes
|
||||
|
||||
DRAWING = r'''
|
||||
uint8_t rotation = 0;
|
||||
void setRotation(uint8_t value) { rotation = last_rotation = value; }
|
||||
int16_t width() const { return rotation & 1 ? HEIGHT : WIDTH; }
|
||||
int16_t height() const { return rotation & 1 ? WIDTH : HEIGHT; }
|
||||
void setTextColor(uint16_t) {}
|
||||
void setTextSize(int) {}
|
||||
void setTextWrap(bool) {}
|
||||
void cp437(bool) {}
|
||||
void setCursor(int, int) {}
|
||||
void print(const char*) {}
|
||||
void fillRect(int, int, int, int, uint16_t) {}
|
||||
void drawRect(int, int, int, int, uint16_t) {}
|
||||
void drawBitmap(int, int, const uint8_t*, int, int, uint16_t) {}
|
||||
void getTextBounds(const char* text, int, int, int16_t* x, int16_t* y,
|
||||
uint16_t* width, uint16_t* height) {
|
||||
*x = *y = 0; *width = std::strlen(text) * 6; *height = 8;
|
||||
}
|
||||
'''
|
||||
|
||||
HARNESS = r'''
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <stdlib.h>
|
||||
#include <type_traits>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
static unsigned allocations = 0, active = 0;
|
||||
void* test_malloc(size_t size) {
|
||||
assert(size == 1024); ++allocations; ++active; return std::malloc(size);
|
||||
}
|
||||
void test_free(void* p) { if (p) { assert(active == 1); --active; std::free(p); } }
|
||||
#define malloc test_malloc
|
||||
#include <helpers/ui/AutoDetectDisplay.h>
|
||||
#include <helpers/ui/SSD1306Display.cpp>
|
||||
#undef malloc
|
||||
static_assert(std::is_same<AutoDetectDisplay, SSD1306Display>::value,
|
||||
"compatibility must preserve the single driver and framebuffer");
|
||||
namespace mesh { namespace ui {
|
||||
static OLEDControllerMode saved = OLEDControllerMode::Auto;
|
||||
OLEDControllerMode oledControllerMode() { return saved; }
|
||||
}}
|
||||
using mesh::ui::OLEDControllerMode;
|
||||
int main() {
|
||||
for (auto mode : {OLEDControllerMode::Auto, OLEDControllerMode::SSD1306,
|
||||
OLEDControllerMode::SH1106}) {
|
||||
for (int status : {0, 8}) {
|
||||
Wire = TwoWire{}; Wire.status[0x3C] = {status, status};
|
||||
mesh::ui::saved = mode;
|
||||
const unsigned before = allocations;
|
||||
{
|
||||
AutoDetectDisplay panel;
|
||||
DisplayDriver* ui = &panel;
|
||||
assert(ui->supportsRotation() && panel.begin() && ui->isOn());
|
||||
assert(allocations == before + 1 && active == 1);
|
||||
const bool sh = mode == OLEDControllerMode::SH1106 ||
|
||||
(mode == OLEDControllerMode::Auto && status == 8);
|
||||
// SSD1306 init has no payload in this vendor double. SH1106 performs
|
||||
// its real init and eight page writes through the actual backend.
|
||||
bool saw_page = false;
|
||||
for (const auto& tx : Wire.transactions)
|
||||
if (tx.data.size() == 4 && tx.data[1] == 0xB0) saw_page = true;
|
||||
assert(saw_page == sh);
|
||||
for (unsigned degrees : {0, 90, 180, 270}) {
|
||||
assert(ui->setRotationDegrees(degrees));
|
||||
assert(ui->width() == (degrees % 180 ? 64 : 128));
|
||||
assert(ui->height() == (degrees % 180 ? 128 : 64));
|
||||
ui->setFlipped(true); assert(last_rotation == ((degrees / 90 + 2) & 3));
|
||||
ui->setFlipped(false); assert(last_rotation == degrees / 90);
|
||||
}
|
||||
assert(!ui->setRotationDegrees(45));
|
||||
ui->setTextSize(2); assert(ui->textLineHeight() == 16);
|
||||
ui->startFrame(); assert(ui->textLineHeight() == 8);
|
||||
ui->turnOff(); assert(!ui->isOn()); ui->turnOn(); assert(ui->isOn());
|
||||
Wire.requests.clear();
|
||||
assert(panel.begin() && allocations == before + 1);
|
||||
}
|
||||
assert(active == 0);
|
||||
}
|
||||
}
|
||||
Wire = TwoWire{}; Wire.present[0x3C] = false;
|
||||
mesh::ui::saved = OLEDControllerMode::Auto;
|
||||
AutoDetectDisplay absent;
|
||||
const unsigned before = allocations;
|
||||
assert(!absent.begin() && !absent.isOn());
|
||||
absent.turnOn(); assert(!absent.isOn() && allocations == before);
|
||||
}
|
||||
'''
|
||||
|
||||
|
||||
class UpstreamAutoDisplayMergeTests(unittest.TestCase):
|
||||
def test_real_compatibility_driver_detection_settings_rotation_and_memory(self):
|
||||
vendor = probe.VENDOR.replace("class Adafruit_SSD1306 {",
|
||||
"inline unsigned last_rotation = 0;\nclass Adafruit_SSD1306 {")
|
||||
vendor = vendor.replace("public:\n", "public:\n" + DRAWING)
|
||||
vendor += "\n#define SSD1306_BLACK 0\n#define SSD1306_WHITE 1\n"
|
||||
vendor += "#define SSD1306_DISPLAYON 0xAF\n#define SSD1306_DISPLAYOFF 0xAE\n"
|
||||
mocks = {
|
||||
"Arduino.h": probe.ARDUINO + "\ninline int digitalRead(unsigned) { return 0; }\n",
|
||||
"Wire.h": probe.WIRE, "Adafruit_SSD1306.h": vendor, "Adafruit_GFX.h": "",
|
||||
"helpers/IdentityStore.h": "#pragma once\nstruct FakeFS;\n#define FILESYSTEM FakeFS\n",
|
||||
}
|
||||
# Existing helper writes only direct children; provide the one nested
|
||||
# header through a separate include directory in the same test scope.
|
||||
identity = mocks.pop("helpers/IdentityStore.h")
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
include = Path(directory)
|
||||
(include / "helpers").mkdir()
|
||||
(include / "helpers/IdentityStore.h").write_text(identity)
|
||||
probe.OledDisplayProbeTests.compile_run(
|
||||
self, HARNESS, ("-DOLED_AUTO_DETECT=1", "-DPIN_OLED_RESET=-1",
|
||||
"-Wno-unused-parameter", "-I", str(include)), mocks)
|
||||
|
||||
def test_every_rak_display_role_keeps_existing_detection_and_source_budget(self):
|
||||
recipes = Recipes()
|
||||
count = 0
|
||||
for section in recipes.config.sections():
|
||||
if not section.startswith("env:RAK_4631_"):
|
||||
continue
|
||||
flags = recipes.value(section, "build_flags")
|
||||
if "DISPLAY_CLASS=" not in flags:
|
||||
continue
|
||||
with self.subTest(role=section):
|
||||
self.assertIn("OLED_AUTO_DETECT=1", flags)
|
||||
self.assertIn("DISPLAY_CLASS=SSD1306Display", flags)
|
||||
sources = recipes.value(section, "build_src_filter")
|
||||
self.assertIn("helpers/ui/SSD1306Display.cpp", sources)
|
||||
self.assertNotIn("helpers/ui/SH1106Display.cpp", sources)
|
||||
self.assertNotIn("Adafruit SH110X", recipes.value(section, "lib_deps"))
|
||||
count += 1
|
||||
self.assertGreater(count, 15)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -743,12 +743,14 @@ build_flags =
|
||||
-D AUTO_SHUTDOWN_MILLIVOLTS=3400
|
||||
-D BLE_DEBUG_LOGGING=1
|
||||
-D OFFLINE_QUEUE_SIZE=512
|
||||
-D ENABLE_WIFI_INTERFACE
|
||||
; -D MESH_PACKET_LOGGING=1
|
||||
; -D MESH_DEBUG=1
|
||||
build_src_filter = ${heltec_v4_tft.build_src_filter}
|
||||
+<helpers/ui/ST7789LCDDisplay.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/wifi/*.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
lib_deps =
|
||||
|
||||
@@ -211,11 +211,13 @@ build_flags =
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D BLE_PIN_CODE=123456
|
||||
-D OFFLINE_QUEUE_SIZE=512
|
||||
-D ENABLE_WIFI_INTERFACE
|
||||
; -D BLE_DEBUG_LOGGING=1
|
||||
; -D MESH_PACKET_LOGGING=8
|
||||
; -D MESH_DEBUG=1
|
||||
build_src_filter = ${T_Beam_S3_Supreme_SX1262.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/wifi/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
|
||||
Reference in new issue
Block a user