From 1ed550fb92037c9dc3fe9162d44aaf9e1577ae59 Mon Sep 17 00:00:00 2001 From: Armel FAUVEAU Date: Thu, 7 May 2026 15:32:07 +0200 Subject: [PATCH] Add LOGO option to POnMsg menu --- App/CMakeLists.txt | 1 + App/driver/eeprom_compat.c | 5 +++++ App/settings.h | 5 ++++- App/ui/menu.c | 3 +++ App/ui/menu.h | 6 +++++- App/ui/welcome.c | 30 +++++++++++++++++++++++++++++- CMakePresets.json | 2 ++ archive/quansheng.stock.logo.png | Bin 0 -> 2058 bytes 8 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 archive/quansheng.stock.logo.png diff --git a/App/CMakeLists.txt b/App/CMakeLists.txt index 44fd71ed..0850f989 100644 --- a/App/CMakeLists.txt +++ b/App/CMakeLists.txt @@ -214,6 +214,7 @@ if(ENABLE_FEAT_F4HWN_BEAM AND NOT ENABLE_AIRCOPY) message(FATAL_ERROR "ENABLE_FEAT_F4HWN_BEAM requires ENABLE_AIRCOPY (it reuses g_FSK_Buffer, AIRCOPY_Obfuscate and the FSK packet plumbing).") endif() enable_feature(ENABLE_FEAT_F4HWN_QRCODE) +enable_feature(ENABLE_FEAT_F4HWN_LOGO) # ---- DEBUGGING ---- diff --git a/App/driver/eeprom_compat.c b/App/driver/eeprom_compat.c index 39dde9aa..b4cf7bf3 100644 --- a/App/driver/eeprom_compat.c +++ b/App/driver/eeprom_compat.c @@ -67,6 +67,11 @@ static const AddrMapping_t ADDR_MAPPINGS[] = { // Settings Version * 16 Bytes 0x00A160 -> 0x00A170 _MK_MAPPING(0x010000, 0x00B000, 0x00B200), // Calibration 512 Bytes!!! + + _MK_MAPPING(0x011000, 0x00C000, 0x00D000), // Boot Logo sector (4 KB): + // [0x00..0x07] 8-byte header (reserved) + // [0x08..0x407] 128x64 monochrome bitmap, 1024 Bytes + // ST7565-native: 8 pages * 128 columns, column-major LSB-top }; static void AddrTranslate(uint16_t EEPROM_Addr, uint16_t Size, uint32_t *PY25Q16_Addr_out, uint16_t *Size_out, bool *End_out); diff --git a/App/settings.h b/App/settings.h index 81ffa637..07884bae 100644 --- a/App/settings.h +++ b/App/settings.h @@ -34,7 +34,10 @@ enum POWER_OnDisplayMode_t { #endif POWER_ON_DISPLAY_MODE_MESSAGE, POWER_ON_DISPLAY_MODE_VOLTAGE, - POWER_ON_DISPLAY_MODE_NONE +#ifdef ENABLE_FEAT_F4HWN_LOGO + POWER_ON_DISPLAY_MODE_LOGO, +#endif + POWER_ON_DISPLAY_MODE_NONE, }; typedef enum POWER_OnDisplayMode_t POWER_OnDisplayMode_t; diff --git a/App/ui/menu.c b/App/ui/menu.c index 2b5156b6..e0737607 100644 --- a/App/ui/menu.c +++ b/App/ui/menu.c @@ -295,6 +295,9 @@ const char gSubMenu_PONMSG[][8] = #endif "MESSAGE", "VOLTAGE", +#ifdef ENABLE_FEAT_F4HWN_LOGO + "LOGO", +#endif "NONE" }; diff --git a/App/ui/menu.h b/App/ui/menu.h index 0ae007af..10e8b7ff 100644 --- a/App/ui/menu.h +++ b/App/ui/menu.h @@ -211,7 +211,11 @@ extern const char gSubMenu_D_RSP[4][11]; extern const char* const gSubMenu_PTT_ID[5]; #ifdef ENABLE_FEAT_F4HWN - extern const char gSubMenu_PONMSG[5][8]; + #ifdef ENABLE_FEAT_F4HWN_LOGO + extern const char gSubMenu_PONMSG[6][8]; + #else + extern const char gSubMenu_PONMSG[5][8]; + #endif #else extern const char gSubMenu_PONMSG[4][8]; #endif diff --git a/App/ui/welcome.c b/App/ui/welcome.c index 69520590..6dfd0518 100644 --- a/App/ui/welcome.c +++ b/App/ui/welcome.c @@ -33,6 +33,19 @@ #include "screenshot.h" #endif +#ifdef ENABLE_FEAT_F4HWN_LOGO +// Boot logo storage in PY25Q16 external flash, aligned on a 4 KB sector, +// placed past the calibration zone (0x010000-0x010200). +// +// Layout inside the sector starting at LOGO_FLASH_ADDR: +// [0x00..0x07] : 8-byte header (reserved for future magic/version/flags) +// [0x08..0x407]: 128x64 monochrome bitmap (1024 B) +// ST7565-native: 8 pages * 128 columns, column-major LSB-top +#define LOGO_FLASH_ADDR 0x011000 +#define LOGO_HEADER_SIZE 8 +#define LOGO_BITMAP_ADDR (LOGO_FLASH_ADDR + LOGO_HEADER_SIZE) +#endif + #ifdef ENABLE_FEAT_F4HWN_QRCODE // QR code (version 4, 33x33 modules, EC level L) encoding: // https://github.com/armel/uv-k1-k5v3-firmware-custom @@ -216,10 +229,25 @@ void UI_DisplayWelcome(void) #endif UI_DisplayClear(); +#ifdef ENABLE_FEAT_F4HWN_LOGO + if (gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_LOGO) { + // Skip 8-byte header, then read 128x64 bitmap (1024 B): + // page 0 -> gStatusLine, pages 1..7 -> gFrameBuffer. + PY25Q16_ReadBuffer(LOGO_BITMAP_ADDR, gStatusLine, sizeof(gStatusLine)); + PY25Q16_ReadBuffer(LOGO_BITMAP_ADDR + sizeof(gStatusLine), gFrameBuffer, sizeof(gFrameBuffer)); + ST7565_BlitStatusLine(); + ST7565_BlitFullScreen(); + #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT + SCREENSHOT_Update(true); + #endif + return; + } +#endif + #ifdef ENABLE_FEAT_F4HWN ST7565_BlitStatusLine(); ST7565_BlitFullScreen(); - + if (gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_NONE || gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_SOUND) { ST7565_FillScreen(0x00); } diff --git a/CMakePresets.json b/CMakePresets.json index 444f422d..22442849 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -71,6 +71,7 @@ "ENABLE_FEAT_F4HWN_SCAN_PROGRESS": false, "ENABLE_FEAT_F4HWN_SCAN_FASTER": false, "ENABLE_FEAT_F4HWN_BEAM": false, + "ENABLE_FEAT_F4HWN_LOGO": false, "ENABLE_AGC_SHOW_DATA": false, "ENABLE_UART_RW_BK_REGS": false, "ENABLE_SWD": false, @@ -200,6 +201,7 @@ "ENABLE_FEAT_F4HWN_BEAM": true, "ENABLE_FEAT_F4HWN_QRCODE": true, "ENABLE_FEAT_F4HWN_MEM": true, + "ENABLE_FEAT_F4HWN_LOGO": true, "ENABLE_SWD": true, "EDITION_STRING": "Fusion", "TARGET": "f4hwn.fusion" diff --git a/archive/quansheng.stock.logo.png b/archive/quansheng.stock.logo.png new file mode 100644 index 0000000000000000000000000000000000000000..fe3cc9e799d769e8e925a4706fc50c4017337a6d GIT binary patch literal 2058 zcmV+l2=(`gP)3{!y{=D@B{(XJ^y!8Y=3-H$0 z|Mm4*fX@QF`2^nl^*`SLp9OgH3B391f4%|UbOG|UUvdF}FL)j~q*s=wUjUe1w3qe$ zUv|DKKwfC%)b72ZC?Li65s~0EmHm2_k0>G*vFq zh?NIKY<0o(^7TP**3(W2W4@dK+JYE&Mx0^+fHqqPt^(5wg7E9x0_(su2S!`Jbs)~E zx;_CBubzJ8+0gw0z&L22ecE#94!i2wmjDbd7%x^5M&DXJSjHO%O!@&VcPezd0KjCp zPSv3+0mTHc@{v*??g!K4T!b=IHp*-2y-iE(e*jgW%In3G00N z_mmK4L3}F!?b7FGWbeS-)t%kd0zeGb0YVH<-KnL7;N@V{wf_PTXF^E(s;~!GzK48| z=w<;R2I`O?2AFzE7-Qs)!u-PLedvd=R~Yqq?9p}?3ji@72UiCI<04f4OnSZ(#5?xZ zdlw7fP#hG*kW#PG7$K*Gh*ke<0IR?IYag}G)T_T2{qO|<7PEl()msF5g5TAAj zC2TmQdSZ>MzBRwx7G#~2nUnS-(i$**&qwO~R?eXd;7d6m<=z0=?`dFjY2fah&Beb1 zf9qYpOF#T`*a84U(-5Ejfml(1hc5>rccpBj;JUvBJ@N43fuRD7`am9}9JTc3h0kvArs{q=CrSsPCfD9d^Irm^l{83<8 z^T&0!fcO&4xY2ES>Xj$TOCj|=ocC=^4fF2b^kp6nhpEa%Kq2R z112+vbsK^QhBCmzxfWS0fTREvlj4oI@_@*>60*q!QOBVPlVIeuuK^-<9s^9?2c~w7 z2depJI!w=n(au@e42=AmJ?G37bN=E2%mcNz0H%#?$*D0A`Pr;Kxc!$z<8Hy4BIDFW z+RsR!Ef<7*q!uuw&HG9_)*N*qFD@=X2BkFk7Ve3ywSZxGYkaK>)R0xZ z#;*o!AfK%PxBJ}C#^#VM{Q`?QUtECAC(i=6G%`yWOmjsN>HSaMk- z?LFkYCQQ$)XJo8Wqz~A<2sO|AY6DUYm2bq#qs9P350zgmfKE~CX^Z64#iMrSDYFhl zgK6u7<>dpqx&tr_*ybR5ukTZJV-oV>mTgSpR_xrLdCK%D7YiWyR{$nQ*&K|VwgIr@ zL%t*n5tcZfc#UmezYeS2eTy+aqE4zlW(nm0xO?UO!_(>LdywYSs+ zhGQTW0Yd7iHL9-fXdJo#`SLIwVDgvbr6Iyt=Th#yJY25{qaWhZVU&3ujB&~JAP--F zyiACpITW}(tjsgM0&eHl_-i_Bt7R{u)`G~Dhf%LFJ?MuofJ1OdN|8Fm(B$p~Jf53p z!R;C_UE1tDYgD`H>F+^yu>d&;m<}DLcE)Xy!0O))g}PYN(Fi8Mz5!)4SMeRCTkKYjYw04(Utf$*ih2<(*TdI6kS4iv5r z7~&GmfzWGi>eWBj(^gghZJ8=(Js}4uCJWk#6FjGR}6%aK5 z&EXry8jX0N$LSYfeivR+B7H#n>W1qw<1=5GT<`MH{$6eY>L9$pM^J0Ly8hA&@amVh z$NPO2V2>%DxW;DzPJDTLwEkIuJ*If#8lMF?@#XE&`ey<5nBs|Rd=}uumuKtG;(q`D o0RR8skhUcN000I_L_t&o0K|xE>Sn#+4FCWD07*qoM6N<$f(C`>{r~^~ literal 0 HcmV?d00001