From 09b77cd918b9d78fa72e0fac8bf638c0cbc6abc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 09:30:55 +0300 Subject: [PATCH 01/15] Channel: decompile utility and WiiConnect24 targets --- config/HAFE/splits.txt | 40 ++ config/HAFE/symbols.txt | 193 +++++--- configure.py | 12 + include/channel/WiiConnect24.h | 60 ++- src/ChannelMathData.cpp | 20 + src/DragScroll.cpp | 91 ++++ src/MtxUtil.cpp | 39 ++ src/WeatherUtil.cpp | 283 +++++++++++ src/WiiConnect24.cpp | 173 +++++++ src/WiiConnect24Code.cpp | 14 + src/WiiConnect24Download.cpp | 870 +++++++++++++++++++++++++++++++++ src/WiiConnect24Heap.cpp | 13 + src/WiiConnect24Init.cpp | 31 ++ src/WiiConnect24Shutdown.cpp | 18 + src/WiiConnect24Update.cpp | 19 + src/WiiConnect24_bss.cpp | 29 ++ 16 files changed, 1818 insertions(+), 87 deletions(-) create mode 100644 src/ChannelMathData.cpp create mode 100644 src/DragScroll.cpp create mode 100644 src/MtxUtil.cpp create mode 100644 src/WeatherUtil.cpp create mode 100644 src/WiiConnect24.cpp create mode 100644 src/WiiConnect24Code.cpp create mode 100644 src/WiiConnect24Download.cpp create mode 100644 src/WiiConnect24Heap.cpp create mode 100644 src/WiiConnect24Init.cpp create mode 100644 src/WiiConnect24Shutdown.cpp create mode 100644 src/WiiConnect24Update.cpp create mode 100644 src/WiiConnect24_bss.cpp diff --git a/config/HAFE/splits.txt b/config/HAFE/splits.txt index 3c65b94..43c0af2 100644 --- a/config/HAFE/splits.txt +++ b/config/HAFE/splits.txt @@ -233,6 +233,46 @@ System.cpp: .sbss start:0x80330AD0 end:0x80330B78 .sdata2 start:0x80331F00 end:0x80331F78 +ChannelMathData.cpp: + .sdata2 start:0x80331F78 end:0x80331FC0 + +WiiConnect24_bss.cpp: + .bss start:0x801D99E0 end:0x801F6B28 + .sbss start:0x80330B78 end:0x80330B98 + +WiiConnect24Init.cpp: + .text start:0x80032610 end:0x800326BC + +WiiConnect24Update.cpp: + .text start:0x800326BC end:0x8003271C + +WiiConnect24Shutdown.cpp: + .text start:0x8003271C end:0x800327AC + +WiiConnect24.cpp: + .text start:0x800327AC end:0x80033C80 + +WiiConnect24Download.cpp: + .text start:0x80033C80 end:0x80035B70 + .data start:0x8019BD08 end:0x8019C189 + .sdata start:0x80330170 end:0x80330190 + +WiiConnect24Heap.cpp: + .text start:0x80035B70 end:0x80035B8C + +WiiConnect24Code.cpp: + .text start:0x80035B8C end:0x80035BA8 + +DragScroll.cpp: + .text start:0x80035BA8 end:0x80035DC4 + +WeatherUtil.cpp: + .text start:0x80035DC4 end:0x800367F4 + .rodata start:0x8018F4D0 end:0x8018F4E6 + +MtxUtil.cpp: + .text start:0x800367F4 end:0x80036978 + Tween.cpp: .text start:0x80036994 end:0x800369F4 .sdata2 start:0x80331FC0 end:0x80331FC8 diff --git a/config/HAFE/symbols.txt b/config/HAFE/symbols.txt index 09f913c..06a332e 100644 --- a/config/HAFE/symbols.txt +++ b/config/HAFE/symbols.txt @@ -781,14 +781,14 @@ downloadWeatherShort__13CWiiConnect24FPvPxPUlUl = .text:0x80033010; // type:func setWeather__13CWiiConnect24FPCcPCcUlUlUl = .text:0x80033430; // type:function size:0x448 deleteWeather__13CWiiConnect24Fv = .text:0x80033878; // type:function size:0x408 DownloaderThread = .text:0x80033C80; // type:function size:0x8E4 -fn_80034564 = .text:0x80034564; // type:function size:0x614 -fn_80034B78 = .text:0x80034B78; // type:function size:0x9D4 -fn_8003554C = .text:0x8003554C; // type:function size:0x180 -fn_800356CC = .text:0x800356CC; // type:function size:0x1DC -fn_800358A8 = .text:0x800358A8; // type:function size:0xF0 -fn_80035998 = .text:0x80035998; // type:function size:0x1D8 -fn_80035B70 = .text:0x80035B70; // type:function size:0x1C -fn_80035B8C = .text:0x80035B8C; // type:function size:0x1C +DownloadFiles = .text:0x80034564; // type:function size:0x614 +CreateDownloadTasks = .text:0x80034B78; // type:function size:0x9D4 +ExecuteDownloadTask = .text:0x8003554C; // type:function size:0x180 +DeleteTaskFiles = .text:0x800356CC; // type:function size:0x1DC +MapDownloadError = .text:0x800358A8; // type:function size:0xF0 +ReadCompressedFile = .text:0x80035998; // type:function size:0x1D8 +WC24Alloc = .text:0x80035B70; // type:function size:0x1C +WC24Free = .text:0x80035B8C; // type:function size:0x1C __ct__10DragScrollFv = .text:0x80035BA8; // type:function size:0x40 Reset__10DragScrollFv = .text:0x80035BE8; // type:function size:0x40 UpdateChan__10DragScrollFl = .text:0x80035C28; // type:function size:0x110 @@ -798,7 +798,7 @@ WrapHourTo24__FPl = .text:0x80035DF0; // type:function size:0x2C SmoothApproach__FPfffff = .text:0x80035E1C; // type:function size:0xB4 SmoothApproachAngle__FPfffff = .text:0x80035ED0; // type:function size:0x128 EaseCos__FUs = .text:0x80035FF8; // type:function size:0x3C -fn_80036034 = .text:0x80036034; // type:function size:0x2A4 +FormatDigits = .text:0x80036034; // type:function size:0x2A4 scope:global FormatNumber__FlPwli = .text:0x800362D8; // type:function size:0xFC FormatInt__FlPw = .text:0x800363D4; // type:function size:0x104 MinutesToCalendarTime__FUlP14OSCalendarTime = .text:0x800364D8; // type:function size:0x18C @@ -1489,8 +1489,8 @@ VFi_nanddrv_init_drv_tbl = .text:0x800662B8; // type:function size:0x18 scope:gl nanddrv_physical_read = .text:0x800662D0; // type:function size:0x1A0 scope:local nanddrv_physical_write = .text:0x80066470; // type:function size:0x194 scope:local VFi_InitSDWrok = .text:0x80066604; // type:function size:0x4 -fn_80066608 = .text:0x80066608; // type:function size:0x1C8 -fn_800667D0 = .text:0x800667D0; // type:function size:0xC +SOInit = .text:0x80066608; // type:function size:0x1C8 +SOStartup = .text:0x800667D0; // type:function size:0xC fn_800667DC = .text:0x800667DC; // type:function size:0x428 fn_80066C04 = .text:0x80066C04; // type:function size:0x1B0 fn_80066DB4 = .text:0x80066DB4; // type:function size:0xE8 @@ -1509,7 +1509,7 @@ fn_80067B70 = .text:0x80067B70; // type:function size:0xF0 NETGetUniversalCalendar = .text:0x80067C60; // type:function size:0xE4 scope:global NETCalcCRC32 = .text:0x80067D44; // type:function size:0x134 fn_80067E78 = .text:0x80067E78; // type:function size:0x278 -fn_800680F0 = .text:0x800680F0; // type:function size:0x80 +SOGetLastError = .text:0x800680F0; // type:function size:0x80 fn_80068170 = .text:0x80068170; // type:function size:0x178 fn_800682E8 = .text:0x800682E8; // type:function size:0x8 STD_strnlen = .text:0x800682F0; // type:function size:0x30 scope:global @@ -1598,31 +1598,31 @@ NWC24iIoctlResourceManager = .text:0x8006DCBC; // type:function size:0x48 scope: NWC24iIoctlResourceManagerAsync = .text:0x8006DD04; // type:function size:0x5C scope:global NWC24iIsAsyncRequestPending = .text:0x8006DD60; // type:function size:0x8 scope:global CallbackAsyncIpc = .text:0x8006DD68; // type:function size:0x1C scope:local -fn_8006DD84 = .text:0x8006DD84; // type:function size:0x240 -fn_8006DFC4 = .text:0x8006DFC4; // type:function size:0xA0 -fn_8006E064 = .text:0x8006E064; // type:function size:0x9C -fn_8006E100 = .text:0x8006E100; // type:function size:0x108 -fn_8006E208 = .text:0x8006E208; // type:function size:0x24C -fn_8006E454 = .text:0x8006E454; // type:function size:0x8C -fn_8006E4E0 = .text:0x8006E4E0; // type:function size:0x154 -fn_8006E634 = .text:0x8006E634; // type:function size:0x1B4 -fn_8006E7E8 = .text:0x8006E7E8; // type:function size:0xC -fn_8006E7F4 = .text:0x8006E7F4; // type:function size:0x16C -fn_8006E960 = .text:0x8006E960; // type:function size:0x160 -fn_8006EAC0 = .text:0x8006EAC0; // type:function size:0x100 -fn_8006EBC0 = .text:0x8006EBC0; // type:function size:0x154 -fn_8006ED14 = .text:0x8006ED14; // type:function size:0x98 -fn_8006EDAC = .text:0x8006EDAC; // type:function size:0x70 +NWC24InitDlTask = .text:0x8006DD84; // type:function size:0x240 +NWC24SetDlId = .text:0x8006DFC4; // type:function size:0xA0 +NWC24GetDlId = .text:0x8006E064; // type:function size:0x9C +NWC24SetDlPriority = .text:0x8006E100; // type:function size:0x108 +NWC24SetDlInterval = .text:0x8006E208; // type:function size:0x24C +NWC24GetDlInterval = .text:0x8006E454; // type:function size:0x8C +NWC24SetDlRetryMargin = .text:0x8006E4E0; // type:function size:0x154 +NWC24SetDlUrl = .text:0x8006E634; // type:function size:0x1B4 +NWC24GetDlUrl = .text:0x8006E7E8; // type:function size:0xC +NWC24SetDlFlags = .text:0x8006E7F4; // type:function size:0x16C +NWC24SetDlFilename = .text:0x8006E960; // type:function size:0x160 +NWC24GetDlFilename = .text:0x8006EAC0; // type:function size:0x100 +NWC24SetDlCount = .text:0x8006EBC0; // type:function size:0x154 +NWC24GetDlLastUpdate = .text:0x8006ED14; // type:function size:0x98 +NWC24iCheckDlTask = .text:0x8006EDAC; // type:function size:0x70 fn_8006EE1C = .text:0x8006EE1C; // type:function size:0x13C fn_8006EF58 = .text:0x8006EF58; // type:function size:0x244 -fn_8006F19C = .text:0x8006F19C; // type:function size:0x3F4 -fn_8006F590 = .text:0x8006F590; // type:function size:0x1A4 -fn_8006F734 = .text:0x8006F734; // type:function size:0x23C +NWC24UpdateDlTask = .text:0x8006F19C; // type:function size:0x3F4 +NWC24DeleteDlTask = .text:0x8006F590; // type:function size:0x1A4 +NWC24AddDlTask = .text:0x8006F734; // type:function size:0x23C NWC24GetDlTask = .text:0x8006F970; // type:function size:0x170 scope:global -fn_8006FAE0 = .text:0x8006FAE0; // type:function size:0x16C +NWC24GetDlNextTime = .text:0x8006FAE0; // type:function size:0x16C fn_8006FC4C = .text:0x8006FC4C; // type:function size:0x2C0 -fn_8006FF0C = .text:0x8006FF0C; // type:function size:0x1A4 -fn_800700B0 = .text:0x800700B0; // type:function size:0x26C +NWC24GetDlVfName = .text:0x8006FF0C; // type:function size:0x1A4 +NWC24CreateDlVf = .text:0x800700B0; // type:function size:0x26C NWC24iOpenDlTaskList = .text:0x8007031C; // type:function size:0x5C scope:global NWC24iCloseDlTaskList = .text:0x80070378; // type:function size:0x8 scope:global fn_80070380 = .text:0x80070380; // type:function size:0x350 @@ -5976,7 +5976,7 @@ gGlobeDotPositions = .rodata:0x8017B508; // type:object size:0x8E20 gGlobeDotSizes = .rodata:0x80184328; // type:object size:0x2388 data:byte gGlobeDotColorIndices = .rodata:0x801866B0; // type:object size:0x2388 data:byte gGlobeDotColors = .rodata:0x80188A38; // type:object size:0x6A98 -lbl_8018F4D0 = .rodata:0x8018F4D0; // type:object size:0x16 data:wstring +sWeatherDigits = .rodata:0x8018F4D0; // type:object size:0x16 data:wstring sGlyphTextureIds = .rodata:0x8018F4E8; // type:object size:0x164 scope:local data:4byte sLanguageTextures = .rodata:0x8018F64C; // type:object size:0x1C scope:local sDateGlyphs = .rodata:0x8018F668; // type:object size:0x24 scope:local data:2byte @@ -6729,7 +6729,48 @@ lbl_8019BC98 = .data:0x8019BC98; // type:object size:0x1C data:wstring lbl_8019BCB4 = .data:0x8019BCB4; // type:object size:0x1A data:wstring lbl_8019BCD0 = .data:0x8019BCD0; // type:object size:0x1A data:wstring gLastUpdatedPrefixes = .data:0x8019BCEC; // type:object size:0x1C -lbl_8019BD08 = .data:0x8019BD08; // type:object size:0x488 +@2291 = .data:0x8019BD08; // type:object size:0x17 scope:local data:string +@2292 = .data:0x8019BD20; // type:object size:0x9 scope:local align:4 data:string +@2293 = .data:0x8019BD2C; // type:object size:0x15 scope:local align:4 data:string +@2294 = .data:0x8019BD48; // type:object size:0x18 scope:local align:8 data:string +@2476 = .data:0x8019BD60; // type:object size:0x19 scope:local data:string +@2477 = .data:0x8019BD80; // type:object size:0x18 scope:local align:8 data:string +@2478 = .data:0x8019BD98; // type:object size:0x11 scope:local data:string +@2479 = .data:0x8019BDAC; // type:object size:0x1B scope:local align:4 data:string +@2480 = .data:0x8019BDC8; // type:object size:0x20 scope:local align:4 data:string +@2481 = .data:0x8019BDE8; // type:object size:0x11 scope:local data:string +@2482 = .data:0x8019BE00; // type:object size:0x10 scope:local align:8 data:string +@2483 = .data:0x8019BE10; // type:object size:0x1D scope:local data:string +@2484 = .data:0x8019BE30; // type:object size:0x15 scope:local align:4 data:string +@2485 = .data:0x8019BE48; // type:object size:0x19 scope:local align:4 data:string +@2486 = .data:0x8019BE64; // type:object size:0x16 scope:local align:4 data:string +@2487 = .data:0x8019BE7C; // type:object size:0x1F scope:local align:4 data:string +@2488 = .data:0x8019BE9C; // type:object size:0x1D scope:local align:4 data:string +@2489 = .data:0x8019BEBC; // type:object size:0x19 scope:local align:4 data:string +@2777 = .data:0x8019BED8; // type:object size:0x1D scope:local align:4 data:string +@2778 = .data:0x8019BEF8; // type:object size:0x1A scope:local align:4 data:string +@2779 = .data:0x8019BF14; // type:object size:0x17 scope:local align:4 data:string +@2780 = .data:0x8019BF2C; // type:object size:0x15 scope:local align:4 data:string +@2781 = .data:0x8019BF44; // type:object size:0x1A scope:local align:4 data:string +@2782 = .data:0x8019BF60; // type:object size:0x18 scope:local align:4 data:string +@2783 = .data:0x8019BF78; // type:object size:0x1D scope:local data:string +@2784 = .data:0x8019BF98; // type:object size:0x1A scope:local align:4 data:string +@2785 = .data:0x8019BFB4; // type:object size:0x1D scope:local align:4 data:string +@2786 = .data:0x8019BFD8; // type:object size:0x20 scope:local align:8 data:string +@2787 = .data:0x8019BFF8; // type:object size:0x1D scope:local data:string +@2788 = .data:0x8019C018; // type:object size:0x1A scope:local align:4 data:string +@2789 = .data:0x8019C034; // type:object size:0x19 scope:local align:4 data:string +@2790 = .data:0x8019C050; // type:object size:0x1C scope:local align:4 data:string +@2791 = .data:0x8019C06C; // type:object size:0x17 scope:local data:string +@2823 = .data:0x8019C084; // type:object size:0x11 scope:local align:4 data:string +@2824 = .data:0x8019C098; // type:object size:0x14 scope:local align:4 data:string +@2825 = .data:0x8019C0B0; // type:object size:0x20 scope:local align:8 data:string +@2884 = .data:0x8019C0D0; // type:object size:0x16 scope:local data:string +@2885 = .data:0x8019C0E8; // type:object size:0x1C scope:local align:4 data:string +@2956 = .data:0x8019C104; // type:object size:0x15 scope:local data:string +@2957 = .data:0x8019C11C; // type:object size:0x27 scope:local align:4 data:string +@2958 = .data:0x8019C144; // type:object size:0x22 scope:local align:4 data:string +@2959 = .data:0x8019C168; // type:object size:0x21 scope:local align:4 data:string lbl_8019C190 = .data:0x8019C190; // type:object size:0xC data:4byte lbl_8019C19C = .data:0x8019C19C; // type:object size:0xC data:4byte lbl_8019C1A8 = .data:0x8019C1A8; // type:object size:0xC data:4byte @@ -8513,14 +8554,14 @@ gMotorCooldown = .bss:0x801D9840; // type:object size:0x10 scope:global data:4by gMotorPattern = .bss:0x801D9850; // type:object size:0x10 scope:global data:4byte gMotorPatternPos = .bss:0x801D9860; // type:object size:0x10 scope:global data:4byte gContentHandles = .bss:0x801D9870; // type:object size:0x168 scope:global -lbl_801D99E0 = .bss:0x801D99E0; // type:object size:0x4000 -lbl_801DD9E0 = .bss:0x801DD9E0; // type:object size:0x20 -lbl_801DDA00 = .bss:0x801DDA00; // type:object size:0x40 -lbl_801DDA40 = .bss:0x801DDA40; // type:object size:0x318 -lbl_801DDD58 = .bss:0x801DDD58; // type:object size:0x8000 -lbl_801E5D58 = .bss:0x801E5D58; // type:object size:0x10000 data:byte +gNWC24Work = .bss:0x801D99E0; // type:object size:0x4000 +gWC24Queue = .bss:0x801DD9E0; // type:object size:0x20 +gWC24QueueBuffer = .bss:0x801DDA00; // type:object size:0x40 +gWC24Thread = .bss:0x801DDA40; // type:object size:0x318 +gWC24ThreadStack = .bss:0x801DDD58; // type:object size:0x8000 +gWC24FileBuffer = .bss:0x801E5D58; // type:object size:0x10000 data:byte gWC24Tasks = .bss:0x801F5D58; // type:object size:0xDC0 -lbl_801F6B18 = .bss:0x801F6B18; // type:object size:0x10 +gWC24Spare = .bss:0x801F6B18; // type:object size:0x10 gModelMtx = .bss:0x801F6B28; // type:object size:0x30 data:4byte lbl_801F6B58 = .bss:0x801F6B58; // type:object size:0x10 lbl_801F6B68 = .bss:0x801F6B68; // type:object size:0xF0 data:byte @@ -9243,12 +9284,12 @@ lbl_80330158 = .sdata:0x80330158; // type:object size:0x2 data:string gUnblackNextFrame = .sdata:0x8033015A; // type:object size:0x1 scope:global data:byte lbl_80330160 = .sdata:0x80330160; // type:object size:0x8 data:wstring lbl_80330168 = .sdata:0x80330168; // type:object size:0x8 data:wstring -lbl_80330170 = .sdata:0x80330170; // type:object size:0x4 data:string -lbl_80330174 = .sdata:0x80330174; // type:object size:0x7 data:string -lbl_8033017C = .sdata:0x8033017C; // type:object size:0x2 data:string -lbl_80330180 = .sdata:0x80330180; // type:object size:0x7 data:string -lbl_80330188 = .sdata:0x80330188; // type:object size:0x4 data:string -lbl_8033018C = .sdata:0x8033018C; // type:object size:0x4 data:string +sVfDriveName = .sdata:0x80330170; // type:object size:0x4 data:string +sVfRootPath = .sdata:0x80330174; // type:object size:0x7 data:string +sVfReadMode = .sdata:0x8033017C; // type:object size:0x2 align:4 data:string +sBinNameFormat = .sdata:0x80330180; // type:object size:0x7 align:4 data:string +sForecastFileSuffix = .sdata:0x80330188; // type:object size:0x4 align:4 data:string +sShortFileSuffix = .sdata:0x8033018C; // type:object size:0x4 data:string lbl_80330190 = .sdata:0x80330190; // type:object size:0x4 data:string lbl_80330194 = .sdata:0x80330194; // type:object size:0x5 data:string lbl_8033019C = .sdata:0x8033019C; // type:object size:0x4 data:string @@ -9690,16 +9731,16 @@ gCursor = .sbss:0x80330B68; // type:object size:0x4 scope:global data:4byte gWeatherScene = .sbss:0x80330B6C; // type:object size:0x4 scope:global data:4byte gFatalScene = .sbss:0x80330B70; // type:object size:0x4 scope:global data:4byte gUnk80330B74 = .sbss:0x80330B74; // type:object size:0x4 scope:global data:4byte -lbl_80330B78 = .sbss:0x80330B78; // type:object size:0x1 data:byte -lbl_80330B79 = .sbss:0x80330B79; // type:object size:0x1 data:byte -lbl_80330B7A = .sbss:0x80330B7A; // type:object size:0x1 data:byte -lbl_80330B7B = .sbss:0x80330B7B; // type:object size:0x1 data:byte -lbl_80330B7C = .sbss:0x80330B7C; // type:object size:0x1 data:byte -lbl_80330B80 = .sbss:0x80330B80; // type:object size:0x4 data:4byte -lbl_80330B84 = .sbss:0x80330B84; // type:object size:0x4 data:4byte -lbl_80330B88 = .sbss:0x80330B88; // type:object size:0x4 data:4byte -lbl_80330B8C = .sbss:0x80330B8C; // type:object size:0x4 data:4byte -lbl_80330B90 = .sbss:0x80330B90; // type:object size:0x8 data:4byte +gNWC24LibOpened = .sbss:0x80330B78; // type:object size:0x1 data:byte +gWC24DownloadComplete = .sbss:0x80330B79; // type:object size:0x1 data:byte +gWC24ShutdownFlag1 = .sbss:0x80330B7A; // type:object size:0x1 data:byte +gWC24NetInitialized = .sbss:0x80330B7B; // type:object size:0x1 data:byte +gWC24ShutdownFlag2 = .sbss:0x80330B7C; // type:object size:0x1 data:byte +gWC24DownloadIndex = .sbss:0x80330B80; // type:object size:0x4 data:4byte +gWC24QueueIndex = .sbss:0x80330B84; // type:object size:0x4 data:4byte +gWC24TaskCount = .sbss:0x80330B88; // type:object size:0x4 data:4byte +gWC24HeapBlock = .sbss:0x80330B8C; // type:object size:0x4 data:4byte +gWC24Heap = .sbss:0x80330B90; // type:object size:0x4 data:4byte lbl_80330B98 = .sbss:0x80330B98; // type:object size:0x4 data:byte gHomeButton = .sbss:0x80330BA0; // type:object size:0x4 data:4byte gUnkSceneFloat = .sbss:0x80330BA4; // type:object size:0x4 align:4 data:float @@ -10843,24 +10884,24 @@ lbl_80331F68 = .sdata2:0x80331F68; // type:object size:0x4 align:4 data:float lbl_80331F6C = .sdata2:0x80331F6C; // type:object size:0x4 align:4 data:float lbl_80331F70 = .sdata2:0x80331F70; // type:object size:0x4 align:4 data:float lbl_80331F74 = .sdata2:0x80331F74; // type:object size:0x4 data:byte -lbl_80331F78 = .sdata2:0x80331F78; // type:object size:0x4 align:4 data:float -lbl_80331F7C = .sdata2:0x80331F7C; // type:object size:0x4 align:4 data:float -lbl_80331F80 = .sdata2:0x80331F80; // type:object size:0x4 align:4 data:float -lbl_80331F84 = .sdata2:0x80331F84; // type:object size:0x4 align:4 data:float -lbl_80331F88 = .sdata2:0x80331F88; // type:object size:0x4 align:4 data:float -lbl_80331F8C = .sdata2:0x80331F8C; // type:object size:0x4 align:4 data:float -lbl_80331F90 = .sdata2:0x80331F90; // type:object size:0x4 align:4 data:float -lbl_80331F94 = .sdata2:0x80331F94; // type:object size:0x4 align:4 data:float -lbl_80331F98 = .sdata2:0x80331F98; // type:object size:0x4 align:4 data:float -lbl_80331F9C = .sdata2:0x80331F9C; // type:object size:0x4 align:4 data:float -lbl_80331FA0 = .sdata2:0x80331FA0; // type:object size:0x4 align:4 data:float -lbl_80331FA4 = .sdata2:0x80331FA4; // type:object size:0x4 align:4 data:float -lbl_80331FA8 = .sdata2:0x80331FA8; // type:object size:0x4 align:4 data:float -lbl_80331FAC = .sdata2:0x80331FAC; // type:object size:0x4 align:4 data:float -lbl_80331FB0 = .sdata2:0x80331FB0; // type:object size:0x4 align:4 data:float -lbl_80331FB4 = .sdata2:0x80331FB4; // type:object size:0x4 align:4 data:float -lbl_80331FB8 = .sdata2:0x80331FB8; // type:object size:0x4 align:4 data:float -lbl_80331FBC = .sdata2:0x80331FBC; // type:object size:0x4 align:4 data:float +sDragScrollZero = .sdata2:0x80331F78; // type:object size:0x4 align:4 data:float +sDragScrollOffset = .sdata2:0x80331F7C; // type:object size:0x4 align:4 data:float +sDragScrollThreshold = .sdata2:0x80331F80; // type:object size:0x4 align:4 data:float +sDragScrollNegThreshold = .sdata2:0x80331F84; // type:object size:0x4 align:4 data:float +sDragScrollMax = .sdata2:0x80331F88; // type:object size:0x4 align:4 data:float +sDragScrollAngleScale = .sdata2:0x80331F8C; // type:object size:0x4 align:4 data:float +sDragScrollHalfPi = .sdata2:0x80331F90; // type:object size:0x4 align:4 data:float +sDragScrollTimerScale = .sdata2:0x80331F94; // type:object size:0x4 align:4 data:float +sSmoothEpsilon = .sdata2:0x80331F98; // type:object size:0x4 align:4 data:float +sSmoothEpsilonNeg = .sdata2:0x80331F9C; // type:object size:0x4 align:4 data:float +sAngleZero = .sdata2:0x80331FA0; // type:object size:0x4 align:4 data:float +sAngleFull = .sdata2:0x80331FA4; // type:object size:0x4 align:4 data:float +sAngleHalfNeg = .sdata2:0x80331FA8; // type:object size:0x4 align:4 data:float +sAngleHalf = .sdata2:0x80331FAC; // type:object size:0x4 align:4 data:float +sIdxToFIdx = .sdata2:0x80331FB0; // type:object size:0x4 align:4 data:float +sHalf = .sdata2:0x80331FB4; // type:object size:0x4 align:4 data:float +sDegToRad = .sdata2:0x80331FB8; // type:object size:0x4 align:4 data:float +sDegToFIdx = .sdata2:0x80331FBC; // type:object size:0x4 align:4 data:float lbl_80331FC0 = .sdata2:0x80331FC0; // type:object size:0x8 align:4 data:float lbl_80331FC8 = .sdata2:0x80331FC8; // type:object size:0x4 align:4 data:float lbl_80331FCC = .sdata2:0x80331FCC; // type:object size:0x4 align:4 data:float diff --git a/configure.py b/configure.py index 6ae4df5..a06a3f7 100755 --- a/configure.py +++ b/configure.py @@ -1099,6 +1099,18 @@ def MatchingFor(*versions): Object(Matching, "main.cpp"), Object(Matching, "DrawUtil.cpp"), Object(Matching, "GlobeDots.cpp"), + Object(Matching, "WiiConnect24_bss.cpp"), + Object(Matching, "WiiConnect24Init.cpp"), + Object(Matching, "WiiConnect24Shutdown.cpp"), + Object(Matching, "WiiConnect24Update.cpp"), + Object(Matching, "WiiConnect24Code.cpp"), + Object(Matching, "WiiConnect24.cpp"), + Object(Matching, "WiiConnect24Download.cpp"), + Object(Matching, "WiiConnect24Heap.cpp"), + Object(Matching, "WeatherUtil.cpp"), + Object(Matching, "ChannelMathData.cpp"), + Object(Matching, "DragScroll.cpp"), + Object(Matching, "MtxUtil.cpp"), Object(Matching, "System.cpp"), Object(Matching, "Tween.cpp"), Object(NonMatching, "LayoutButton.cpp"), diff --git a/include/channel/WiiConnect24.h b/include/channel/WiiConnect24.h index 2896064..cb3450e 100644 --- a/include/channel/WiiConnect24.h +++ b/include/channel/WiiConnect24.h @@ -2,14 +2,51 @@ #define CHANNEL_WII_CONNECT24_H #include -// A WiiConnect24 request running on the worker thread (size 0x1B8) +// A pair of buffers/timestamps/sizes used by a WiiConnect24 download task. +// Each pair occupies 0x60 bytes; the remaining words are reserved and are +// only ever copied as part of the whole task. +struct WC24BufferSet { + void* forecast; // at 0x000 + void* shortForecast; // at 0x004 + u32 unk08[22]; // at 0x008 +}; + +struct WC24TimeSet { + s64* forecast; // at 0x000 + s64* shortForecast; // at 0x004 + u32 unk08[22]; // at 0x008 +}; + +struct WC24SizeSet { + u32* forecast; // at 0x000 + u32* shortForecast; // at 0x004 + u32 unk08[22]; // at 0x008 +}; + +// A request queued for the WiiConnect24 worker thread (size 0x1B8) struct WC24Task { - u8 unk0[0x164]; // at 0x0 - s32 mState; // at 0x164 - s32 mResult; // at 0x168 - s32 mErrorCode; // at 0x16C - s32 mNwc24Result; // at 0x170 - u8 unk174[0x1B8 - 0x174]; + u32 mType; // at 0x000 + u16 mTaskId; // at 0x004 + u16 mSubTaskId; // at 0x006 + u32 unk008; // at 0x008 + u32 unk00C; // at 0x00C + u32 unk010; // at 0x010 + WC24BufferSet mBuffers; // at 0x014 + WC24TimeSet mTimes; // at 0x074 + WC24SizeSet mSizes; // at 0x0D4 + s64 mNextDownloadTimes[2]; // at 0x138 + const char* mForecastUrl; // at 0x148 + const char* mShortUrl; // at 0x14C + u32 mForecastBufferSize; // at 0x150 + u32 mBufferSizes[2]; // at 0x154 + u16 mDownloadInterval; // at 0x15C + u16 mDownloadCount; // at 0x15E + u8 mRedownload; // at 0x160 + s32 mState; // at 0x164 + s32 mResult; // at 0x168 + s32 mErrorCode; // at 0x16C + s32 mNwc24Result; // at 0x170 + char mMessage[0x40]; // at 0x174 }; extern WC24Task gWC24Tasks[]; @@ -17,13 +54,14 @@ extern WC24Task gWC24Tasks[]; // WiiConnect24.cpp: weather download tasks class CWiiConnect24 { public: - static s32 getWeather(void* forecastBuf, s64* forecastTime, u32* forecastSize, void* shortBuf, - s64* shortTime, u32* shortSize, const char* forecastUrl, const char* shortUrl, + static s32 getWeather(void* forecastBuf, s64* forecastTime, u32* forecastSize, + void* shortBuf, s64* shortTime, u32* shortSize, + const char* forecastUrl, const char* shortUrl, u32 forecastBufSize, u32 forecastMaxSize, u32 shortBufSize); static s32 downloadWeatherForecast(void* buf, s64* time, u32* size, u32 bufSize); static s32 downloadWeatherShort(void* buf, s64* time, u32* size, u32 bufSize); - static s32 setWeather(const char* forecastUrl, const char* shortUrl, u32 forecastBufSize, u32 arg3, - u32 arg4); + static s32 setWeather(const char* forecastUrl, const char* shortUrl, u32 forecastBufSize, + u32 redownload, u32 interval); static s32 deleteWeather(); }; diff --git a/src/ChannelMathData.cpp b/src/ChannelMathData.cpp new file mode 100644 index 0000000..595b946 --- /dev/null +++ b/src/ChannelMathData.cpp @@ -0,0 +1,20 @@ +#include + +extern "C" const f32 sDragScrollZero = 0.0f; +extern "C" const f32 sDragScrollOffset = 228.0f; +extern "C" const f32 sDragScrollThreshold = 20.0f; +extern "C" const f32 sDragScrollNegThreshold = -20.0f; +extern "C" const f32 sDragScrollMax = 185.2f; +extern "C" const f32 sDragScrollAngleScale = 40.743664f; +extern "C" const f32 sDragScrollHalfPi = 1.5707964f; +extern "C" const f32 sDragScrollTimerScale = 23.0f; +extern "C" const f32 sSmoothEpsilon = 0.0008f; +extern "C" const f32 sSmoothEpsilonNeg = -0.0008f; +extern "C" const f32 sAngleZero = 0.0f; +extern "C" const f32 sAngleFull = 360.0f; +extern "C" const f32 sAngleHalfNeg = -180.0f; +extern "C" const f32 sAngleHalf = 180.0f; +extern "C" const f32 sIdxToFIdx = 0.00390625f; +extern "C" const f32 sHalf = 0.5f; +extern "C" const f32 sDegToRad = 0.017453292f; +extern "C" const f32 sDegToFIdx = 0.7111111f; diff --git a/src/DragScroll.cpp b/src/DragScroll.cpp new file mode 100644 index 0000000..12e820b --- /dev/null +++ b/src/DragScroll.cpp @@ -0,0 +1,91 @@ +#include +#include + +extern "C" const f32 sDragScrollZero; +extern "C" const f32 sDragScrollOffset; +extern "C" const f32 sDragScrollThreshold; +extern "C" const f32 sDragScrollNegThreshold; +extern "C" const f32 sDragScrollMax; +extern "C" const f32 sDragScrollAngleScale; +extern "C" const f32 sDragScrollHalfPi; +extern "C" const f32 sDragScrollTimerScale; + +// Layout matches gDragScroll in SceneBase.cpp (size 0x34). +struct DragScroll { + DragScroll(); + void Reset(); + void Update(); + void UpdateChan(s32 chan); + + f32 mScroll[4]; // at 0x00 + s32 mTimer[4]; // at 0x10 + s32 mState[4]; // at 0x20 + u8 mActive; // at 0x30 + u8 unk31[3]; // at 0x31 +}; + +DragScroll::DragScroll() { + for (int i = 0; i < 4; i++) { + mScroll[i] = sDragScrollZero; + mTimer[i] = 0; + mState[i] = 0; + } + mActive = 0; +} + +void DragScroll::Reset() { + for (int i = 0; i < 4; i++) { + mScroll[i] = sDragScrollZero; + mTimer[i] = 0; + mState[i] = 0; + } + mActive = 0; +} + +void DragScroll::UpdateChan(s32 chan) { + f32* pScroll = &mScroll[chan]; + s32* pTimer = &mTimer[chan]; + s32* pState = &mState[chan]; + + f32 scroll = sDragScrollOffset - gPointerY[chan][0]; + *pScroll = scroll; + + BOOL zero = scroll < sDragScrollThreshold && scroll > sDragScrollNegThreshold; + if (zero) { + *pScroll = sDragScrollZero; + return; + } + + if (*pTimer > 0) + (*pTimer)--; + + if (*pTimer != 0) + return; + + *pState = *pScroll > sDragScrollZero ? 1 : 2; + + f32 max = sDragScrollMax; + f32 amount = __fabsf(*pScroll) - sDragScrollThreshold; + if (amount > max) + amount = max; + + f32 angle = sDragScrollAngleScale * (sDragScrollHalfPi * amount / max); + *pTimer = (s32)(sDragScrollTimerScale * nw4r::math::CosFIdx(angle)) + 1; +} + +void DragScroll::Update() { + s32* pTimer = mTimer; + s32* pState = mState; + int i; + + for (i = 0; i < 4; i++, pState++, pTimer++) { + *pState = 0; + + if (gHold[i] & 0x400) { // WPAD_BUTTON_B + mActive = TRUE; + UpdateChan(i); + } else { + *pTimer = 0; + } + } +} diff --git a/src/MtxUtil.cpp b/src/MtxUtil.cpp new file mode 100644 index 0000000..f78e623 --- /dev/null +++ b/src/MtxUtil.cpp @@ -0,0 +1,39 @@ +#include +#include + +extern "C" const f32 sDegToRad; +extern "C" const f32 sDegToFIdx; + +void TranslateMtx(nw4r::math::MTX34* m, f32 x, f32 y, f32 z) { + Mtx trans; + PSMTXTrans(trans, x, y, z); + PSMTXConcat(trans, m->mtx, m->mtx); +} + +void RotateX(Mtx m, f32 degrees) { + Mtx rot; + PSMTXRotRad(rot, 'x', sDegToRad * degrees); + PSMTXConcat(rot, m, m); +} + +void RotateY(Mtx m, f32 degrees) { + Mtx rot; + PSMTXRotRad(rot, 'y', sDegToRad * degrees); + PSMTXConcat(rot, m, m); +} + +void RotateZ(Mtx m, f32 degrees) { + Mtx rot; + PSMTXRotRad(rot, 'z', sDegToRad * degrees); + PSMTXConcat(rot, m, m); +} + +void RotateMtxDeg(nw4r::math::MTX34* m, f32 x, f32 y, f32 z) { + nw4r::math::MTX34 rot; + nw4r::math::MTX34RotXYZFIdx(&rot, sDegToFIdx * x, sDegToFIdx * y, sDegToFIdx * z); + PSMTXConcat(rot.mtx, m->mtx, m->mtx); +} + +void SetRotateZ(Mtx m, f32 degrees) { + PSMTXRotRad(m, 'z', sDegToRad * degrees); +} diff --git a/src/WeatherUtil.cpp b/src/WeatherUtil.cpp new file mode 100644 index 0000000..fdf2827 --- /dev/null +++ b/src/WeatherUtil.cpp @@ -0,0 +1,283 @@ +#include +#include +#include +#include + +extern "C" const f32 sSmoothEpsilon; +extern "C" const f32 sSmoothEpsilonNeg; +extern "C" const f32 sAngleZero; +extern "C" const f32 sAngleFull; +extern "C" const f32 sAngleHalfNeg; +extern "C" const f32 sAngleHalf; +extern "C" const f32 sIdxToFIdx; +extern "C" const f32 sHalf; + +extern "C" const wchar_t sWeatherDigits[] = L"0123456789"; + +void WrapHour(s32* pHour) { + *pHour %= 24; +} + +void WrapHourTo24(s32* pHour) { + *pHour %= 25; +} + +f32 SmoothApproach(f32* value, f32 target, f32 rate, f32 maxStep, f32 minStep) { + if (*value != target) { + f32 diff = *value - target; + + if (__fabsf(diff) < minStep) { + *value = target; + } else { + f32 absDiff = __fabsf(diff); + f32 scaled = absDiff * rate; + diff *= rate; + + BOOL small = scaled < sSmoothEpsilon && scaled > sSmoothEpsilonNeg; + if (small) { + *value = target; + } else { + if (scaled > maxStep) { + if (diff < sAngleZero) + maxStep = -maxStep; + diff = maxStep; + } else if (scaled < minStep) { + if (diff < sAngleZero) + minStep = -minStep; + diff = minStep; + } + + *value -= diff; + } + } + } + + return __fabsf(*value - target); +} + +f32 SmoothApproachAngle(f32* value, f32 target, f32 rate, f32 maxStep, f32 minStep) { + f32 angle = *value; + if (angle < sAngleZero) + *value += sAngleFull; + else if (angle >= sAngleFull) + *value -= sAngleFull; + + if (target < sAngleZero) + target += sAngleFull; + else if (target >= sAngleFull) + target -= sAngleFull; + + if (*value != target) { + f32 diff = *value - target; + if (diff < sAngleHalfNeg) + diff += sAngleFull; + else if (diff > sAngleHalf) + diff -= sAngleFull; + + diff *= rate; + f32 scaled = __fabsf(diff); + + if (scaled <= minStep) { + *value = target; + } else { + if (scaled > maxStep) { + if (diff < sAngleZero) + maxStep = -maxStep; + diff = maxStep; + } + + *value -= diff; + + angle = *value; + if (angle < sAngleZero) + *value += sAngleFull; + else if (angle >= sAngleFull) + *value -= sAngleFull; + } + } + + return __fabsf(*value - target); +} + +f32 EaseCos(u16 t) { + return sHalf - sHalf * nw4r::math::CosFIdx(nw4r::math::U16ToF32(t) * sIdxToFIdx); +} + +extern "C" s32 FormatDigits(s32 value, s32* digits, s32 maxDigits) { + s32 i; + s32 count = 0; + s32 v = value; + + while (v != 0) { + count++; + v /= 10; + } + + if (count > maxDigits) + count = maxDigits; + + i = 0; + for (; i < count; i++) { + digits[i] = value % 10; + value /= 10; + } + for (; i < maxDigits; i++) + digits[i] = 0; + + return count; +} + +wchar_t* FormatNumber(s32 value, wchar_t* pBuf, s32 digits, BOOL zeroPad) { + s32 digitBuf[10]; + s32* p; + s32 i; + + if (digits > 10) + digits = 10; + + if (value < 0) { + *pBuf++ = L'-'; + value -= value * 2; + } + + FormatDigits(value, digitBuf, digits); + + i = digits - 1; + p = &digitBuf[i]; + for (; i >= 0; p--, i--) { + if (!zeroPad && i != 0) { + if (*p != 0) { + zeroPad = TRUE; + *pBuf++ = sWeatherDigits[*p]; + } + } else { + zeroPad = TRUE; + *pBuf++ = sWeatherDigits[*p]; + } + } + + *pBuf = 0; + return pBuf; +} + +wchar_t* FormatInt(s32 value, wchar_t* pBuf) { + s32 hundreds; + s32 rest; + s32 tens; + s32 ones; + if (value < 0) { + *pBuf++ = L'-'; + value -= value * 2; + } + hundreds = value / 100; + rest = value % 100; + ones = rest % 10; + tens = rest / 10; + if (hundreds != 0) { + *pBuf++ = sWeatherDigits[hundreds]; + *pBuf++ = sWeatherDigits[tens]; + *pBuf++ = sWeatherDigits[ones]; + } else if (tens != 0) { + *pBuf++ = sWeatherDigits[tens]; + *pBuf++ = sWeatherDigits[ones]; + } else { + *pBuf++ = sWeatherDigits[ones]; + } + *pBuf = 0; + return pBuf; +} + +static inline BOOL IsLeapYear(s32 year) { + return year % 4 == 0; +} + +static inline s32 GetDaysInMonth(s32 month, s32 year) { + if (month == 4 || month == 6 || month == 9 || month == 11) + return 30; + if (month == 2) { + if (IsLeapYear(year)) + return 29; + return 28; + } + return 31; +} + +void MinutesToCalendarTime(u32 minutes, OSCalendarTime* time) { + s32 len; + s32 year; + s32 month; + s32 days; + s32 yday; + s32 totalDays; + s32 hours; + + hours = minutes / 60; + days = hours / 24; + totalDays = days; + year = 0; + month = 1; + for (;;) { + len = IsLeapYear(year) ? 366 : 365; + if (days < len) + break; + days -= len; + year++; + } + yday = days; + + for (;;) { + len = GetDaysInMonth(month, year); + if (days < len) + break; + days -= len; + month++; + } + + time->sec = 0; + time->min = minutes % 60; + time->hour = hours % 24; + time->mday = days + 1; + time->month = month - 1; + time->year = year + 2000; + time->wday = (totalDays + 6) % 7; + time->yday = yday; + time->msec = 0; + time->usec = 0; +} + +u32 GetUniversalMinutes() { + OSCalendarTime time; + s32 year; + s32 month; + s32 days; + s32 hour; + s32 min; + s32 i; + s32 j; + + NETGetUniversalCalendar(&time); + + year = time.year; + month = time.month + 1; + days = time.mday; + hour = time.hour; + min = time.min; + + days += (year - 2000) * 365; + for (j = 0; j < year - 2000; j += 4) + days++; + for (i = 1; i < month; i++) { + if (i == 4 || i == 6 || i == 9 || i == 11) { + days += 30; + } else if (i == 2) { + if (((year - 2000) & 3) == 0) + days += 29; + else + days += 28; + } else { + days += 31; + } + } + + return min + hour * 60 + (days - 1) * 1440; +} diff --git a/src/WiiConnect24.cpp b/src/WiiConnect24.cpp new file mode 100644 index 0000000..8d11b81 --- /dev/null +++ b/src/WiiConnect24.cpp @@ -0,0 +1,173 @@ +#include +#include +#include + +extern "C" OSMessageQueue gWC24Queue; +extern "C" volatile s32 gWC24QueueIndex; +extern "C" volatile s32 gWC24TaskCount; + +s32 CWiiConnect24::getWeather(void* forecastBuf, s64* forecastTime, u32* forecastSize, + void* shortBuf, s64* shortTime, u32* shortSize, + const char* forecastUrl, const char* shortUrl, + u32 forecastBufSize, u32 forecastMaxSize, u32 shortBufSize) { + WC24Task task; + task.mType = 0; + task.mTaskId = 3; + task.mSubTaskId = 4; + task.mBuffers.forecast = forecastBuf; + task.mBuffers.shortForecast = shortBuf; + task.mTimes.forecast = forecastTime; + task.mTimes.shortForecast = shortTime; + task.mSizes.forecast = forecastSize; + task.mSizes.shortForecast = shortSize; + task.mForecastUrl = forecastUrl; + task.mShortUrl = shortUrl; + task.mForecastBufferSize = forecastBufSize; + task.mBufferSizes[0] = forecastMaxSize; + task.mBufferSizes[1] = shortBufSize; + + s32 result = -1; + if (gWC24TaskCount < 8) { + gWC24Tasks[gWC24QueueIndex] = task; + gWC24Tasks[gWC24QueueIndex].mState = 1; + gWC24Tasks[gWC24QueueIndex].mErrorCode = 0; + gWC24Tasks[gWC24QueueIndex].mMessage[0] = 0; + + if (OSSendMessage(&gWC24Queue, &gWC24Tasks[gWC24QueueIndex], 0)) { + result = gWC24QueueIndex; + gWC24QueueIndex++; + gWC24TaskCount++; + + if (gWC24QueueIndex >= gWC24TaskCount) + gWC24QueueIndex = 0; + } + } + + return result; +} + +s32 CWiiConnect24::downloadWeatherForecast(void* buf, s64* time, u32* size, u32 bufSize) { + WC24Task task; + task.mType = 1; + task.mTaskId = 3; + task.mSubTaskId = 0; + task.mBuffers.forecast = buf; + task.mTimes.forecast = time; + task.mBufferSizes[0] = bufSize; + task.mSizes.forecast = size; + task.mForecastUrl = NULL; + + s32 result = -1; + if (gWC24TaskCount < 8) { + gWC24Tasks[gWC24QueueIndex] = task; + gWC24Tasks[gWC24QueueIndex].mState = 1; + gWC24Tasks[gWC24QueueIndex].mErrorCode = 0; + gWC24Tasks[gWC24QueueIndex].mMessage[0] = 0; + + if (OSSendMessage(&gWC24Queue, &gWC24Tasks[gWC24QueueIndex], 0)) { + result = gWC24QueueIndex; + gWC24QueueIndex++; + gWC24TaskCount++; + + if (gWC24QueueIndex >= gWC24TaskCount) + gWC24QueueIndex = 0; + } + } + + return result; +} + +s32 CWiiConnect24::downloadWeatherShort(void* buf, s64* time, u32* size, u32 bufSize) { + WC24Task task; + task.mType = 1; + task.mTaskId = 4; + task.mSubTaskId = 0; + task.mBuffers.forecast = buf; + task.mTimes.forecast = time; + task.mBufferSizes[0] = bufSize; + task.mSizes.forecast = size; + task.mForecastUrl = NULL; + + s32 result = -1; + if (gWC24TaskCount < 8) { + gWC24Tasks[gWC24QueueIndex] = task; + gWC24Tasks[gWC24QueueIndex].mState = 1; + gWC24Tasks[gWC24QueueIndex].mErrorCode = 0; + gWC24Tasks[gWC24QueueIndex].mMessage[0] = 0; + + if (OSSendMessage(&gWC24Queue, &gWC24Tasks[gWC24QueueIndex], 0)) { + result = gWC24QueueIndex; + gWC24QueueIndex++; + gWC24TaskCount++; + + if (gWC24QueueIndex >= gWC24TaskCount) + gWC24QueueIndex = 0; + } + } + + return result; +} + +s32 CWiiConnect24::setWeather(const char* forecastUrl, const char* shortUrl, u32 forecastBufSize, + u32 redownload, u32 interval) { + WC24Task task; + WC24Task* pTask = &task; + pTask->mType = 2; + pTask->mTaskId = 3; + pTask->mSubTaskId = 4; + pTask->mForecastUrl = forecastUrl; + pTask->mShortUrl = shortUrl; + pTask->mForecastBufferSize = forecastBufSize; + pTask->mRedownload = redownload; + if (interval == 0) + pTask->mDownloadInterval = 30; + else + pTask->mDownloadInterval = interval; + pTask->mDownloadCount = 60; + + s32 result = -1; + if (gWC24TaskCount < 8) { + gWC24Tasks[gWC24QueueIndex] = *pTask; + gWC24Tasks[gWC24QueueIndex].mState = 1; + gWC24Tasks[gWC24QueueIndex].mErrorCode = 0; + gWC24Tasks[gWC24QueueIndex].mMessage[0] = 0; + + if (OSSendMessage(&gWC24Queue, &gWC24Tasks[gWC24QueueIndex], 0)) { + result = gWC24QueueIndex; + gWC24QueueIndex++; + gWC24TaskCount++; + + if (gWC24QueueIndex >= gWC24TaskCount) + gWC24QueueIndex = 0; + } + } + + return result; +} + +s32 CWiiConnect24::deleteWeather() { + WC24Task task; + WC24Task* pTask = &task; + pTask->mType = 3; + pTask->mTaskId = 3; + pTask->mSubTaskId = 4; + + s32 result = -1; + if (gWC24TaskCount < 8) { + gWC24Tasks[gWC24QueueIndex] = *pTask; + gWC24Tasks[gWC24QueueIndex].mState = 1; + gWC24Tasks[gWC24QueueIndex].mErrorCode = 0; + gWC24Tasks[gWC24QueueIndex].mMessage[0] = 0; + + if (OSSendMessage(&gWC24Queue, &gWC24Tasks[gWC24QueueIndex], 0)) { + result = gWC24QueueIndex; + gWC24QueueIndex++; + gWC24TaskCount++; + + if (gWC24QueueIndex >= gWC24TaskCount) + gWC24QueueIndex = 0; + } + } + + return result; +} diff --git a/src/WiiConnect24Code.cpp b/src/WiiConnect24Code.cpp new file mode 100644 index 0000000..49685a2 --- /dev/null +++ b/src/WiiConnect24Code.cpp @@ -0,0 +1,14 @@ +#include +#include + +extern "C" MEMiHeapHead* gWC24Heap; + +extern "C" void WC24Free(void* unused, void* block, s32 size) { + if (block == NULL) + return; + + if (size <= 0) + return; + + MEMFreeToExpHeap(gWC24Heap, block); +} diff --git a/src/WiiConnect24Download.cpp b/src/WiiConnect24Download.cpp new file mode 100644 index 0000000..b595baf --- /dev/null +++ b/src/WiiConnect24Download.cpp @@ -0,0 +1,870 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" OSMessageQueue gWC24Queue; +extern "C" u8 gWC24FileBuffer[]; +extern "C" volatile u8 gWC24DownloadComplete; +extern "C" volatile u8 gWC24NetInitialized; +extern "C" volatile u8 gWC24ShutdownFlag1; +extern "C" volatile u8 gWC24ShutdownFlag2; +extern "C" void* WC24Alloc(u32 unused, s32 size); +extern "C" void WC24Free(void* unused, void* block, s32 size); +extern "C" s32 SOInit(void* init); +extern "C" s32 SOStartup(); +extern "C" s32 SOGetLastError(); +extern "C" s32 NWC24ExecDownloadTask(s32 mode, u16 taskId, s32 flags); +extern "C" NWC24Work gNWC24Work; +extern "C" volatile u8 gNWC24LibOpened; + +extern "C" char sVfDriveName[] = "@24"; +extern "C" char sVfRootPath[] = "@24:/*"; +extern "C" char sVfReadMode[] = "r"; +extern "C" char sBinNameFormat[] = "%d.bin"; +extern "C" char sForecastFileSuffix[] = "%sB"; +extern "C" char sShortFileSuffix[] = "%sR"; + +extern "C" s32 NWC24GetDlUrl(NWC24DlTask* pTask, char* url, u32 len); +extern "C" s32 NWC24GetDlVfName(NWC24DlTask* pTask, char* name, u32 len); +extern "C" s32 NWC24GetDlFilename(NWC24DlTask* pTask, char* name, u32 len); +extern "C" s32 NWC24DeleteDlTask(NWC24DlTask* pTask); +extern "C" s32 NWC24InitDlTask(NWC24DlTask* pTask, u32 type); +extern "C" s32 NWC24SetDlId(NWC24DlTask* pTask, u16 id); +extern "C" s32 NWC24GetDlId(NWC24DlTask* pTask, u32* pId); +extern "C" s32 NWC24GetDlInterval(NWC24DlTask* pTask, u16* pInterval); +extern "C" s32 NWC24SetDlInterval(NWC24DlTask* pTask, u16 interval); +extern "C" s32 NWC24SetDlPriority(NWC24DlTask* pTask, s32 priority); +extern "C" s32 NWC24SetDlFlags(NWC24DlTask* pTask, u32 flags); +extern "C" s32 NWC24SetDlRetryMargin(NWC24DlTask* pTask, s32 margin); +extern "C" s32 NWC24SetDlUrl(NWC24DlTask* pTask, const char* url); +extern "C" s32 NWC24SetDlFilename(NWC24DlTask* pTask, const char* name); +extern "C" s32 NWC24SetDlCount(NWC24DlTask* pTask, s16 count); +extern "C" s32 NWC24AddDlTask(NWC24DlTask* pTask); +extern "C" s32 NWC24UpdateDlTask(NWC24DlTask* pTask); +extern "C" s32 NWC24CreateDlVf(NWC24DlTask* pTask, u32 size); +extern "C" s32 NWC24iCheckDlTask(NWC24DlTask* pTask); +extern "C" s32 NWC24GetDlLastUpdate(NWC24DlTask* pTask, s64* time); +extern "C" s32 NWC24GetDlNextTime(NWC24DlTask* pTask, s64* time); + +extern "C" s32 MapDownloadError(s32 error); +extern "C" s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort); +extern "C" s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, + u16 newInterval, u16 count, u32* idOut); +extern "C" s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2); +extern "C" s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort); +extern "C" s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, + u32* outSize); + +struct WC24IdleMode { + u8 wc24; + u8 slotLight; +}; +// The SDK header declares this as void, but the channel uses the result. +extern "C" BOOL SCGetIdleMode(WC24IdleMode* mode); + +static inline void SetTaskMessage(WC24Task* task, const char* msg, s32 code, s32 result) { + task->mErrorCode = code; + task->mNwc24Result = result; + sprintf(task->mMessage, "%s %d %d", msg, code, result); +} + +// A macro, not an inline: the message literal must reach SetTaskMessage directly. +// Passing it through another inline parameter keeps it live across +// NWC24GetErrorCode() in a callee-saved register, which the original does not do. +#define SetTaskError(task, msg, result) (SetTaskMessage(task, msg, NWC24GetErrorCode(), result), MapDownloadError(result)) + +static inline s32 OpenLib(WC24Task* task, s64 retry) { + s32 error; + + for (;;) { + error = NWC24OpenLib(&gNWC24Work); + + if (error != -0x16 && error != -0x1A && error != -0x1D) + break; + + OSSleepTicks(OS_MSEC_TO_TICKS(100 * (retry + 1))); + } + + if (error != 0) + return SetTaskError(task, "NWC24OpenLib() failed.", error); + + gNWC24LibOpened = 1; + return 0; +} + +static inline s32 CheckLib(WC24Task* task) { + s32 error = NWC24Check(2); + + if (error != 0) + return SetTaskError(task, "NWC24Check() failed.", error); + + WC24IdleMode idle; + if (SCGetIdleMode(&idle) == 0 || idle.wc24 != 1) + return -3; + + return 0; +} + +static inline s32 CloseLib(WC24Task* task) { + s32 error = NWC24CloseLib(); + + if (error != 0) + return SetTaskError(task, "NWC24CloseLib() failed.", error); + + gNWC24LibOpened = 0; + return 0; +} + +extern "C" void* DownloaderThread(void* unused) { + WC24Task* task; + void* message; + s64 retry = 0; + s32 result; + u8 opened; + s32 attempts; + u8 done; + + for (;;) { + done = FALSE; + OSReceiveMessage(&gWC24Queue, &message, 1); + + task = (WC24Task*)message; + if (task == NULL) + break; + + switch (task->mType) { + case 0: + opened = FALSE; + attempts = 0; + + for (;;) { + task->mState = 2; + task->mResult = OpenLib(task, retry); + if (task->mResult != 0) + break; + + opened = TRUE; + + task->mResult = CheckLib(task); + if (task->mResult != 0) + break; + + task->mState = 3; + if ((task->mResult = DownloadFiles(task, 1, 1)) == 0) + break; + if (task->mResult == -1 && attempts != 1) { + task->mState = 6; + task->mResult = CreateDownloadTasks(task, 1, 1, 1, 0x1E, 0x3C, 0); + if (task->mResult == 0) { + task->mState = 2; + task->mResult = CloseLib(task); + opened = FALSE; + if (task->mResult == 0) { + task->mState = 5; + task->mResult = ExecuteDownloadTask(task, 0, 0xFFFFFF, 0xFFFF); + if (task->mResult == 0) { + task->mResult = ExecuteDownloadTask(task, 1, 0xFFFFFF, 0xFFFF); + if (task->mResult == 0) { + attempts++; + continue; + } + } + } + } + } + break; + } + + if (opened) { + task->mState = 2; + result = CloseLib(task); + if (task->mResult == 0) + task->mResult = result; + } + task->mState = 0; + break; + + case 1: + task->mState = 5; + task->mResult = ExecuteDownloadTask(task, 0, 0xFFFFFF, 0xFFFF); + if (task->mResult == 0) { + task->mState = 2; + task->mResult = OpenLib(task, retry); + if (task->mResult == 0) { + task->mResult = CheckLib(task); + if (task->mResult == 0) { + task->mState = 3; + switch (task->mTaskId) { + case 3: + task->mResult = DownloadFiles(task, 1, 0); + break; + case 4: + task->mResult = DownloadFiles(task, 1, 0); + break; + } + } + task->mState = 2; + result = CloseLib(task); + if (task->mResult == 0) + task->mResult = result; + } + } + task->mState = 0; + break; + + case 2: + task->mState = 2; + task->mResult = OpenLib(task, retry); + if (task->mResult == 0) { + task->mResult = CheckLib(task); + if (task->mResult == 0) { + task->mState = 6; + task->mResult = CreateDownloadTasks(task, 1, 1, task->mRedownload, task->mDownloadInterval, + task->mDownloadCount, 0); + } + task->mState = 2; + result = CloseLib(task); + if (task->mResult == 0) + task->mResult = result; + } + task->mState = 0; + break; + + case 3: + task->mState = 2; + task->mResult = OpenLib(task, retry); + if (task->mResult == 0) { + task->mResult = CheckLib(task); + if (task->mResult == 0) { + task->mState = 7; + task->mResult = DeleteTaskFiles(task, 1, 1); + } + task->mState = 2; + result = CloseLib(task); + if (task->mResult == 0) + task->mResult = result; + } + task->mState = 0; + break; + + case 4: + done = TRUE; + break; + } + + if (!done) + continue; + break; + } + + return NULL; +} + +extern "C" s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { + NWC24DlTask dlTasks[2]; + u8 dta[0x448]; + char url[0x100]; + char vfName[0x50]; + char fileName[0x10]; + void* buffers[2]; + s64* times[2]; + u32* sizes[2]; + u16 ids[2]; + u32 outSize; + + s32 error; + BOOL found = FALSE; + + if (doForecast != 0) { + ids[0] = task->mTaskId; + buffers[0] = task->mBuffers.forecast; + times[0] = task->mTimes.forecast; + sizes[0] = task->mSizes.forecast; + } else { + ids[0] = 0; + buffers[0] = NULL; + times[0] = NULL; + sizes[0] = NULL; + } + + if (doShort != 0) { + ids[1] = task->mSubTaskId; + buffers[1] = task->mBuffers.shortForecast; + times[1] = task->mTimes.shortForecast; + sizes[1] = task->mSizes.shortForecast; + } else { + ids[1] = 0; + buffers[1] = NULL; + times[1] = NULL; + sizes[1] = NULL; + } + + // The loops below address the same task through dlTasks and through a + // second pointer to it; the original keeps one induction pointer for each. + NWC24DlTask* urlTask = dlTasks; + for (s32 i = 0; i < 2; i++) { + if (buffers[i] == NULL) + continue; + + error = NWC24GetDlTask(&dlTasks[i], ids[i]); + if (error == -0xD) { + SetTaskMessage(task, "NWC24GetDlTask() failed.", NWC24GetErrorCode(), error); + return -1; + } + + if (error != 0) { + return SetTaskError(task, "NWC24GetDlTask() failed.", error); + } + + error = NWC24GetDlUrl(&urlTask[i], url, 0xFF); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlUrl() failed.", error); + } + + if ((&task->mForecastUrl)[i] != NULL) { + u32 j = 0; + while (j < 0xFF && url[j] != 0) { + if (url[j] != (&task->mForecastUrl)[i][j]) { + SetTaskMessage(task, "URL is not same.", 0, 0); + return -1; + } + + j++; + } + } + } + + for (s32 i = 0; i < 2; i++) { + if (buffers[i] == NULL) + continue; + + error = NWC24GetDlVfName(&dlTasks[i], vfName, 0x50); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlVfName() failed.", error); + } + + error = VFMountDriveNANDFlashEx(sVfDriveName, vfName); + if (error != 0) { + SetTaskMessage(task, "VFMountDriveNANDFlash() failed.", 0, error); + return -1; + } + + s32 searchResult = VFFileSearchFirst(dta, sVfRootPath, 0x7F); + while (searchResult == 0) + searchResult = VFFileSearchNext(dta); + + found = TRUE; + break; + } + + if (!found) + OSPanic("WiiConnect24.cpp", 0x4B1, "VF Load Failed."); + + NWC24DlTask* pTask = dlTasks; + for (s32 i = 0; i < 2; i++) { + if (buffers[i] == NULL) + continue; + + error = NWC24GetDlFilename(&dlTasks[i], fileName, 0x10); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlFilename() failed.", error); + } + + void* file = VFOpenFile(fileName, sVfReadMode, 0); + if (file == NULL) { + SetTaskMessage(task, "VFOpenFile() failed.", NWC24GetErrorCode(), 0); + + error = VFUnmountDrive(sVfDriveName); + if (error != 0) { + SetTaskMessage(task, "VFUnmountDrive() failed.", 0, error); + return -7; + } + return -1; + } + + error = ReadCompressedFile(task, file, buffers[i], task->mBufferSizes[i], &outSize); + if (error != 0) + return error; + + *sizes[i] = outSize; + + // Pads the size to a multiple of 4, but writes into the task itself + // rather than into the downloaded buffer. + char* p; + u32 size = outSize; + p = (char*)&task->mBuffers + size; + while (size < ((outSize + 3) & ~3)) { + *p++ = 0; + size++; + } + + error = VFCloseFile(file); + if (error != 0) { + SetTaskMessage(task, "VFCloseFile() failed.", 0, error); + VFUnmountDrive(sVfDriveName); + return -7; + } + + error = NWC24GetDlLastUpdate(&dlTasks[i], times[i]); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlLastUpdate() failed.", error); + } + + error = NWC24GetDlNextTime(&pTask[i], &task->mNextDownloadTimes[i]); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlNextTime() failed.", error); + } + } + + error = VFUnmountDrive(sVfDriveName); + if (error != 0) { + SetTaskMessage(task, "VFUnmoundDrive() failed.", 0, error); + return -7; + } + + return 0; +} + +extern "C" s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, + u16 newInterval, u16 count, u32* idOut) { + NWC24DlTask dlTasks[2]; + u8 search[0x448]; + char url[0x100]; + char vfName[0x50]; + char vfName2[0x50]; + char fileName[0x10]; + char nameBuf[0x10]; + const char* urls[2]; + u16 ids[2]; + u16 interval; + + s32 error; + BOOL redo = redownload; + BOOL init = redownload; + BOOL mounted = FALSE; + + if (doForecast != 0) { + ids[0] = task->mTaskId; + urls[0] = task->mForecastUrl; + } else { + ids[0] = 0; + urls[0] = NULL; + } + + if (doShort != 0) { + ids[1] = task->mSubTaskId; + urls[1] = task->mShortUrl; + } else { + ids[1] = 0; + urls[1] = NULL; + } + + NWC24DlTask* pTask = dlTasks; + for (s32 i = 0; i < 2; i++) { + if (ids[i] == 0) + continue; + + if (redo != 0) + goto firstDone; + + error = NWC24GetDlTask(&dlTasks[i], ids[i]); + if (error == -0xD) { + redo = TRUE; + init = TRUE; + goto firstDone; + } + + if (error != 0) + return SetTaskError(task, "NWC24GetDlTask() failed.", error); + + error = NWC24GetDlVfName(&pTask[i], vfName, 0x50); + if (error != 0) + return SetTaskError(task, "NWC24GetDlVfName() failed.", error); + + if (!mounted) { + error = VFMountDriveNANDFlashEx(sVfDriveName, vfName); + if (error == 2 || error == 0xB001) { + redo = TRUE; + init = TRUE; + goto firstDone; + } + + if (error != 0) { + SetTaskMessage(task, "VFMountDriveNANDFlash() failed.", 0, error); + return -7; + } + + mounted = TRUE; + s32 searchResult = VFFileSearchFirst(search, sVfRootPath, 0x7F); + while (searchResult == 0) + searchResult = VFFileSearchNext(search); + } + + if (!mounted) + continue; + + switch (ids[i]) { + case 3: + case 4: { + error = NWC24GetDlFilename(&pTask[i], fileName, 0x10); + if (error != 0) + return SetTaskError(task, "NWC24GetDlFilename() failed.", error); + + void* file = VFOpenFile(fileName, sVfReadMode, 0); + if (file == NULL) { + redo = TRUE; + init = TRUE; + continue; + } + + error = VFCloseFile(file); + if (error != 0) { + SetTaskMessage(task, "VFCloseFile() failed.", 0, error); + VFUnmountDrive(sVfDriveName); + return -7; + } + break; + } + } + } + +firstDone: + if (mounted) { + error = VFUnmountDrive(sVfDriveName); + if (error != 0) { + SetTaskMessage(task, "VFUnmountDrive() failed.", 0, error); + return -7; + } + } + + if (!redo) { + for (s32 i = 0; i < 2; i++) { + if (ids[i] == 0) + continue; + + error = NWC24GetDlUrl(&dlTasks[i], url, 0xFF); + if (error != 0) + return SetTaskError(task, "NWC24GetDlUrl() failed.", error); + + const char* p = url; + u32 j = 0; + while (j < 0xFF && *p != 0) { + if (*p != urls[i][j]) { + redo = TRUE; + init = TRUE; + break; + } + p++; + j++; + } + + error = NWC24GetDlInterval(&dlTasks[i], &interval); + if (error != 0) + return SetTaskError(task, "NWC24GetDlInterval() failed.", error); + + if (newInterval != interval) + redo = TRUE; + } + } + + if (redo) { + BOOL created = FALSE; + NWC24DlTask* pTask2 = dlTasks; + + for (s32 i = 0; i < 2; i++) { + if (ids[i] == 0) + continue; + + if (init) { + error = NWC24InitDlTask(&dlTasks[i], 1); + if (error != 0) + return SetTaskError(task, "NWC24InitDlTask() failed.", error); + + error = NWC24SetDlId(&dlTasks[i], ids[i]); + if (error != 0) + return SetTaskError(task, "NWC24SetDlId() failed.", error); + + error = NWC24GetDlVfName(&pTask2[i], vfName2, 0x50); + if (error != 0) + return SetTaskError(task, "NWC24GetDlVfName() failed.", error); + + if (!created) { + error = NANDDelete(vfName2); + if (error != -0xC && error != 0) { + SetTaskMessage(task, "NANDDelete() failed.", 0, error); + return -8; + } + + error = NWC24CreateDlVf(&pTask2[i], task->mForecastBufferSize); + if (error != 0) + return SetTaskError(task, "NWC24CreateDlVf() failed.", error); + + created = TRUE; + } + } + + error = NWC24SetDlUrl(&dlTasks[i], urls[i]); + if (error != 0) + return SetTaskError(task, "NWC24SetDlUrl() failed.", error); + + s32 priority; + s32 margin; + switch (ids[i]) { + case 3: + priority = 100; + margin = 0x2D0; + break; + case 4: + priority = 100; + margin = 0x2D0; + break; + } + + error = NWC24SetDlPriority(&dlTasks[i], priority); + if (error != 0) + return SetTaskError(task, "NWC24SetDlPriority() failed.", error); + + error = NWC24SetDlFlags(&dlTasks[i], 0x40000000); + if (error != 0) + return SetTaskError(task, "NWC24SetDlFlags() failed.", error); + + error = NWC24SetDlInterval(&dlTasks[i], newInterval); + if (error != 0) + return SetTaskError(task, "NWC24SetDlInterval() failed.", error); + + error = NWC24SetDlRetryMargin(&dlTasks[i], margin); + if (error != 0) + return SetTaskError(task, "NWC24SetDlRetryMargin() failed.", error); + + sprintf(nameBuf, sBinNameFormat, ids[i]); + error = NWC24SetDlFilename(&dlTasks[i], nameBuf); + if (error != 0) + return SetTaskError(task, "NWC24SetDlFilename() failed.", error); + } + } + + NWC24DlTask* pTask3 = dlTasks; + for (s32 i = 0; i < 2; i++) { + if (ids[i] == 0) + continue; + + error = NWC24SetDlCount(&dlTasks[i], (s16)count); + if (error != 0) + return SetTaskError(task, "NWC24SetDlCount() failed.", error); + + if (redo) { + error = NWC24AddDlTask(&dlTasks[i]); + if (error != 0) + return SetTaskError(task, "NWC24AddDlTask() failed.", error); + } else { + error = NWC24UpdateDlTask(&dlTasks[i]); + if (error != 0) + return SetTaskError(task, "NWC24UpdateDlTask() failed.", error); + } + + if (idOut != NULL) { + error = NWC24GetDlId(&pTask3[i], idOut); + if (error != 0) + return SetTaskError(task, "NWC24GetDlId() failed.", error); + } + + NWC24iCheckDlTask(&pTask3[i]); + } + + gWC24DownloadComplete = 1; + return 0; +} + +struct WC24SOConfig { + void* alloc; + void* free; +}; + +extern "C" s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2) { + s32 initResult; + s32 startupResult; + s32 error; + s32 taskId; + WC24SOConfig config; + + taskId = (&task->mTaskId)[index]; + + if (!gWC24NetInitialized) { + gWC24ShutdownFlag2 = 1; + config.alloc = (void*)WC24Alloc; + config.free = (void*)WC24Free; + + initResult = SOInit(&config); + if (initResult < 0) { + SetTaskMessage(task, "SOInit() failed.", 0, initResult); + gWC24ShutdownFlag2 = 0; + return -9; + } + + startupResult = SOStartup(); + if (startupResult < 0) { + SetTaskMessage(task, "SOStartup() failed.", SOGetLastError(), startupResult); + gWC24ShutdownFlag2 = 0; + return -9; + } + + gWC24NetInitialized = 1; + gWC24ShutdownFlag2 = 0; + } + + switch (taskId) { + case 3: + case 4: + gWC24ShutdownFlag1 = 1; + error = NWC24ExecDownloadTask(2, taskId, 0); + gWC24ShutdownFlag1 = 0; + + if (error != 0) { + SetTaskMessage(task, "NWC24ExecDownloadTask() failed.", NWC24GetErrorCode(), error); + return MapDownloadError(error); + } + break; + } + return 0; +} + +extern "C" s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort) { + NWC24DlTask dlTask; + char vfName[0x50]; + u16 ids[2]; + u8 found; + + found = FALSE; + + if (doForecast != 0) + ids[0] = task->mTaskId; + else + ids[0] = 0; + + if (doShort != 0) + ids[1] = task->mSubTaskId; + else + ids[1] = 0; + + for (s32 i = 0; i < 2; i++) { + if (ids[i] == 0) + continue; + + s32 error = NWC24GetDlTask(&dlTask, ids[i]); + if (error == -0xD) + continue; + + if (error != 0) { + return SetTaskError(task, "NWC24GetDl*() failed.", error); + } + + if (!found) { + found = TRUE; + error = NWC24GetDlVfName(&dlTask, vfName, 0x50); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlVfName() failed.", error); + } + } + + error = NWC24DeleteDlTask(&dlTask); + if (error != 0) { + return SetTaskError(task, "NWC24DeleteDlTask() failed.", error); + } + } + + if (found) { + s32 error = NANDDelete(vfName); + if (error != -0xC && error != 0) { + SetTaskMessage(task, "NANDDelete() failed.", 0, error); + return -8; + } + } + + return 0; +} + +extern "C" s32 MapDownloadError(s32 error) { + s32 mapped = -6; + + if ((error <= -0x10 && error >= -0x15) || error == -0x26 || error == -0x29 || error == -0x2B || + error == -0x2E) { + mapped = -0xB; + } else if (error == -0x31) { + mapped = -0xC; + } else if (error == -1 || error == -0xB || error == -0x2A) { + mapped = -2; + } else if ((u32)(NWC24GetErrorCode() + 0x20000) == 0x55CE) { + mapped = -5; + } else { + switch (error) { + case -0x27: + mapped = -3; + break; + + case -0x1F: + mapped = -4; + break; + + case -0x20: + mapped = -5; + break; + } + } + + return mapped; +} + +extern "C" s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, + u32* outSize) { + u32 fileSize = VFGetFileSizeByFd(fd); + u32 uncompSize = 0; + CXUncompContextLZ ctx; + + CXInitUncompContextLZ(&ctx, dest); + + u32 offset = 0; + while (offset < fileSize) { + u32 chunk = fileSize - offset; + if (chunk > 0x10000) + chunk = 0x10000; + + s32 error = VFReadFile(fd, gWC24FileBuffer, chunk, NULL); + if (error != 0) { + SetTaskMessage(task, "VFReadFile() failed.", 0, error); + return -7; + } + + if (offset == 0) { + if ((gWC24FileBuffer[0] & 0xF0) != 0x10) { + SetTaskMessage(task, "CXGetCompressionType() data is not LZ.", 0, 0); + return -5; + } + + uncompSize = CXGetUncompressedSize(gWC24FileBuffer); + if (uncompSize > destSize) { + SetTaskMessage(task, "CXGetUncompressedSize() overflow.", 0, 0); + return -5; + } + } + + CXReadUncompLZ(&ctx, gWC24FileBuffer, chunk); + offset += 0x10000; + } + + // Equivalent to !CXIsFinishedUncompLZ(&ctx). + BOOL notFinished = ctx.destCount > 0 || ctx.headerSize > 0; + if (notFinished) { + SetTaskMessage(task, "CXIsFinisiedUncompLZ() is false.", 0, 0); + return -0xA; + } + + *outSize = uncompSize; + return 0; +} diff --git a/src/WiiConnect24Heap.cpp b/src/WiiConnect24Heap.cpp new file mode 100644 index 0000000..700b1ec --- /dev/null +++ b/src/WiiConnect24Heap.cpp @@ -0,0 +1,13 @@ +#include +#include + +extern "C" MEMiHeapHead* gWC24Heap; + +extern "C" void* WC24Alloc(u32 unused, s32 size) { + void* block = NULL; + + if (size > 0) + block = MEMAllocFromExpHeapEx(gWC24Heap, size, 0x20); + + return block; +} diff --git a/src/WiiConnect24Init.cpp b/src/WiiConnect24Init.cpp new file mode 100644 index 0000000..2482843 --- /dev/null +++ b/src/WiiConnect24Init.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +extern "C" OSMessageQueue gWC24Queue; +extern "C" OSMessage gWC24QueueBuffer[16]; +extern "C" OSThread gWC24Thread; +extern "C" u8 gWC24ThreadStack[]; +extern "C" void* gWC24HeapBlock; +extern "C" MEMiHeapHead* gWC24Heap; +extern "C" volatile s32 gWC24DownloadIndex; +extern "C" volatile s32 gWC24QueueIndex; +extern "C" volatile s32 gWC24TaskCount; +extern "C" void* DownloaderThread(void*); + +extern "C" void InitDownloader(void) { + void* block = MEM2Alloc(0x10000, 0x20); + gWC24HeapBlock = block; + gWC24Heap = MEMCreateExpHeapEx(block, 0x10000, 4); + + OSThread* thread = &gWC24Thread; + OSInitMessageQueue(&gWC24Queue, gWC24QueueBuffer, 0x10); + OSCreateThread(thread, (OSThreadFunc)DownloaderThread, NULL, gWC24ThreadStack + 0x8000, + 0x8000, 8, 1); + OSResumeThread(thread); + + gWC24DownloadIndex = 0; + gWC24QueueIndex = 0; + gWC24TaskCount = 0; +} diff --git a/src/WiiConnect24Shutdown.cpp b/src/WiiConnect24Shutdown.cpp new file mode 100644 index 0000000..36419a4 --- /dev/null +++ b/src/WiiConnect24Shutdown.cpp @@ -0,0 +1,18 @@ +#include +#include + +extern "C" OSThread gWC24Thread; +extern "C" volatile u8 gWC24ShutdownFlag1; +extern "C" volatile u8 gWC24ShutdownFlag2; +extern "C" int NWC24iRequestShutdown(u32 event); + +extern "C" void ShutdownDownloader(s32 event) { + int i = 0; + while (i < 10 && (gWC24ShutdownFlag1 || gWC24ShutdownFlag2)) { + NWC24iRequestShutdown(event); + OSSleepTicks(OS_TIME_SPEED); + i++; + } + + OSJoinThread(&gWC24Thread, NULL); +} diff --git a/src/WiiConnect24Update.cpp b/src/WiiConnect24Update.cpp new file mode 100644 index 0000000..ae39ad5 --- /dev/null +++ b/src/WiiConnect24Update.cpp @@ -0,0 +1,19 @@ +#include +#include + +extern "C" volatile s32 gWC24DownloadIndex; +extern "C" volatile s32 gWC24TaskCount; + +extern "C" void UpdateDownloader(void) { + if (gWC24TaskCount <= 0) + return; + + if (gWC24Tasks[gWC24DownloadIndex].mState != 0) + return; + + gWC24DownloadIndex++; + gWC24TaskCount--; + + if (gWC24DownloadIndex >= gWC24TaskCount) + gWC24DownloadIndex = 0; +} diff --git a/src/WiiConnect24_bss.cpp b/src/WiiConnect24_bss.cpp new file mode 100644 index 0000000..43f88b5 --- /dev/null +++ b/src/WiiConnect24_bss.cpp @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include + +extern "C" { +NWC24Work gNWC24Work; +OSMessageQueue gWC24Queue; +OSMessage gWC24QueueBuffer[16]; +OSThread gWC24Thread; +u8 gWC24ThreadStack[0x8000]; +u8 gWC24FileBuffer[0x10000]; +} +WC24Task gWC24Tasks[8]; +extern "C" { +u8 gWC24Spare[0x10]; + +volatile u8 gNWC24LibOpened; +volatile u8 gWC24DownloadComplete; +volatile u8 gWC24ShutdownFlag1; +volatile u8 gWC24NetInitialized; +volatile u8 gWC24ShutdownFlag2; +volatile s32 gWC24DownloadIndex; +volatile s32 gWC24QueueIndex; +volatile s32 gWC24TaskCount; +void* gWC24HeapBlock; +MEMiHeapHead* gWC24Heap; +} From 97f1550e8a6424f04100830a318c8a2446701b2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 10:35:38 +0300 Subject: [PATCH 02/15] Channel: drop unneeded extern "C" from WiiConnect24 and utility code CodeWarrior doesn't mangle global variable names, so extern "C" on the channel's globals did nothing. Variables are now plain (extern const for the shared float constants, which need external linkage in C++). Game functions get normal C++ linkage; symbols.txt now uses their mangled names (FormatDigits__FlPll, WC24Alloc__FUll, ...), and the callers in System.cpp and SceneBase.cpp are updated. extern "C" stays only on the locally declared SDK C functions (SO*, NWC24*, SCGetIdleMode). Also note that SmoothApproach/SmoothApproachAngle are the addCalc idiom. The DOL still matches and no function regressed. Co-Authored-By: Claude Opus 5.5 --- config/HAFE/symbols.txt | 26 ++++++++-------- src/ChannelMathData.cpp | 36 +++++++++++----------- src/DragScroll.cpp | 16 +++++----- src/MtxUtil.cpp | 4 +-- src/SceneBase.cpp | 2 +- src/System.cpp | 4 +-- src/WeatherUtil.cpp | 24 ++++++++------- src/WiiConnect24.cpp | 6 ++-- src/WiiConnect24Code.cpp | 4 +-- src/WiiConnect24Download.cpp | 58 ++++++++++++++++++------------------ src/WiiConnect24Heap.cpp | 4 +-- src/WiiConnect24Init.cpp | 22 +++++++------- src/WiiConnect24Shutdown.cpp | 8 ++--- src/WiiConnect24Update.cpp | 6 ++-- src/WiiConnect24_bss.cpp | 4 --- 15 files changed, 112 insertions(+), 112 deletions(-) diff --git a/config/HAFE/symbols.txt b/config/HAFE/symbols.txt index 06a332e..27bbe9d 100644 --- a/config/HAFE/symbols.txt +++ b/config/HAFE/symbols.txt @@ -772,23 +772,23 @@ __nw__FUll = .text:0x800325D4; // type:function size:0x14 scope:global __nwa__FUl = .text:0x800325E8; // type:function size:0x10 scope:global __dl__FPv = .text:0x800325F8; // type:function size:0xC scope:global __dla__FPv = .text:0x80032604; // type:function size:0xC scope:global -InitDownloader = .text:0x80032610; // type:function size:0xAC -UpdateDownloader = .text:0x800326BC; // type:function size:0x60 -ShutdownDownloader = .text:0x8003271C; // type:function size:0x90 +InitDownloader__Fv = .text:0x80032610; // type:function size:0xAC +UpdateDownloader__Fv = .text:0x800326BC; // type:function size:0x60 +ShutdownDownloader__Fl = .text:0x8003271C; // type:function size:0x90 getWeather__13CWiiConnect24FPvPxPUlPvPxPUlPCcPCcUlUlUl = .text:0x800327AC; // type:function size:0x444 downloadWeatherForecast__13CWiiConnect24FPvPxPUlUl = .text:0x80032BF0; // type:function size:0x420 downloadWeatherShort__13CWiiConnect24FPvPxPUlUl = .text:0x80033010; // type:function size:0x420 setWeather__13CWiiConnect24FPCcPCcUlUlUl = .text:0x80033430; // type:function size:0x448 deleteWeather__13CWiiConnect24Fv = .text:0x80033878; // type:function size:0x408 -DownloaderThread = .text:0x80033C80; // type:function size:0x8E4 -DownloadFiles = .text:0x80034564; // type:function size:0x614 -CreateDownloadTasks = .text:0x80034B78; // type:function size:0x9D4 -ExecuteDownloadTask = .text:0x8003554C; // type:function size:0x180 -DeleteTaskFiles = .text:0x800356CC; // type:function size:0x1DC -MapDownloadError = .text:0x800358A8; // type:function size:0xF0 -ReadCompressedFile = .text:0x80035998; // type:function size:0x1D8 -WC24Alloc = .text:0x80035B70; // type:function size:0x1C -WC24Free = .text:0x80035B8C; // type:function size:0x1C +DownloaderThread__FPv = .text:0x80033C80; // type:function size:0x8E4 +DownloadFiles__FP8WC24TaskUlUl = .text:0x80034564; // type:function size:0x614 +CreateDownloadTasks__FP8WC24TaskUlUlUcUsUsPUl = .text:0x80034B78; // type:function size:0x9D4 +ExecuteDownloadTask__FP8WC24TasklUlUs = .text:0x8003554C; // type:function size:0x180 +DeleteTaskFiles__FP8WC24TaskUlUl = .text:0x800356CC; // type:function size:0x1DC +MapDownloadError__Fl = .text:0x800358A8; // type:function size:0xF0 +ReadCompressedFile__FP8WC24TaskPvPvUlPUl = .text:0x80035998; // type:function size:0x1D8 +WC24Alloc__FUll = .text:0x80035B70; // type:function size:0x1C +WC24Free__FPvPvl = .text:0x80035B8C; // type:function size:0x1C __ct__10DragScrollFv = .text:0x80035BA8; // type:function size:0x40 Reset__10DragScrollFv = .text:0x80035BE8; // type:function size:0x40 UpdateChan__10DragScrollFl = .text:0x80035C28; // type:function size:0x110 @@ -798,7 +798,7 @@ WrapHourTo24__FPl = .text:0x80035DF0; // type:function size:0x2C SmoothApproach__FPfffff = .text:0x80035E1C; // type:function size:0xB4 SmoothApproachAngle__FPfffff = .text:0x80035ED0; // type:function size:0x128 EaseCos__FUs = .text:0x80035FF8; // type:function size:0x3C -FormatDigits = .text:0x80036034; // type:function size:0x2A4 scope:global +FormatDigits__FlPll = .text:0x80036034; // type:function size:0x2A4 scope:global FormatNumber__FlPwli = .text:0x800362D8; // type:function size:0xFC FormatInt__FlPw = .text:0x800363D4; // type:function size:0x104 MinutesToCalendarTime__FUlP14OSCalendarTime = .text:0x800364D8; // type:function size:0x18C diff --git a/src/ChannelMathData.cpp b/src/ChannelMathData.cpp index 595b946..521807d 100644 --- a/src/ChannelMathData.cpp +++ b/src/ChannelMathData.cpp @@ -1,20 +1,20 @@ #include -extern "C" const f32 sDragScrollZero = 0.0f; -extern "C" const f32 sDragScrollOffset = 228.0f; -extern "C" const f32 sDragScrollThreshold = 20.0f; -extern "C" const f32 sDragScrollNegThreshold = -20.0f; -extern "C" const f32 sDragScrollMax = 185.2f; -extern "C" const f32 sDragScrollAngleScale = 40.743664f; -extern "C" const f32 sDragScrollHalfPi = 1.5707964f; -extern "C" const f32 sDragScrollTimerScale = 23.0f; -extern "C" const f32 sSmoothEpsilon = 0.0008f; -extern "C" const f32 sSmoothEpsilonNeg = -0.0008f; -extern "C" const f32 sAngleZero = 0.0f; -extern "C" const f32 sAngleFull = 360.0f; -extern "C" const f32 sAngleHalfNeg = -180.0f; -extern "C" const f32 sAngleHalf = 180.0f; -extern "C" const f32 sIdxToFIdx = 0.00390625f; -extern "C" const f32 sHalf = 0.5f; -extern "C" const f32 sDegToRad = 0.017453292f; -extern "C" const f32 sDegToFIdx = 0.7111111f; +extern const f32 sDragScrollZero = 0.0f; +extern const f32 sDragScrollOffset = 228.0f; +extern const f32 sDragScrollThreshold = 20.0f; +extern const f32 sDragScrollNegThreshold = -20.0f; +extern const f32 sDragScrollMax = 185.2f; +extern const f32 sDragScrollAngleScale = 40.743664f; +extern const f32 sDragScrollHalfPi = 1.5707964f; +extern const f32 sDragScrollTimerScale = 23.0f; +extern const f32 sSmoothEpsilon = 0.0008f; +extern const f32 sSmoothEpsilonNeg = -0.0008f; +extern const f32 sAngleZero = 0.0f; +extern const f32 sAngleFull = 360.0f; +extern const f32 sAngleHalfNeg = -180.0f; +extern const f32 sAngleHalf = 180.0f; +extern const f32 sIdxToFIdx = 0.00390625f; +extern const f32 sHalf = 0.5f; +extern const f32 sDegToRad = 0.017453292f; +extern const f32 sDegToFIdx = 0.7111111f; diff --git a/src/DragScroll.cpp b/src/DragScroll.cpp index 12e820b..8d403a5 100644 --- a/src/DragScroll.cpp +++ b/src/DragScroll.cpp @@ -1,14 +1,14 @@ #include #include -extern "C" const f32 sDragScrollZero; -extern "C" const f32 sDragScrollOffset; -extern "C" const f32 sDragScrollThreshold; -extern "C" const f32 sDragScrollNegThreshold; -extern "C" const f32 sDragScrollMax; -extern "C" const f32 sDragScrollAngleScale; -extern "C" const f32 sDragScrollHalfPi; -extern "C" const f32 sDragScrollTimerScale; +extern const f32 sDragScrollZero; +extern const f32 sDragScrollOffset; +extern const f32 sDragScrollThreshold; +extern const f32 sDragScrollNegThreshold; +extern const f32 sDragScrollMax; +extern const f32 sDragScrollAngleScale; +extern const f32 sDragScrollHalfPi; +extern const f32 sDragScrollTimerScale; // Layout matches gDragScroll in SceneBase.cpp (size 0x34). struct DragScroll { diff --git a/src/MtxUtil.cpp b/src/MtxUtil.cpp index f78e623..6457564 100644 --- a/src/MtxUtil.cpp +++ b/src/MtxUtil.cpp @@ -1,8 +1,8 @@ #include #include -extern "C" const f32 sDegToRad; -extern "C" const f32 sDegToFIdx; +extern const f32 sDegToRad; +extern const f32 sDegToFIdx; void TranslateMtx(nw4r::math::MTX34* m, f32 x, f32 y, f32 z) { Mtx trans; diff --git a/src/SceneBase.cpp b/src/SceneBase.cpp index eae3ffe..37b3236 100644 --- a/src/SceneBase.cpp +++ b/src/SceneBase.cpp @@ -24,7 +24,7 @@ #include #include -extern "C" void ShutdownDownloader(s32 event); +void ShutdownDownloader(s32 event); wchar_t* FormatNumber(s32 value, wchar_t* pBuf, s32 digits, BOOL zeroPad); void WrapHour(s32* pHour); diff --git a/src/System.cpp b/src/System.cpp index 29fc773..4459686 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -10,8 +10,8 @@ #include // Not yet decompiled (channel) -extern "C" void InitDownloader(void); -extern "C" void UpdateDownloader(void); +void InitDownloader(void); +void UpdateDownloader(void); // Not yet decompiled (libraries) extern "C" void VFInit(void); diff --git a/src/WeatherUtil.cpp b/src/WeatherUtil.cpp index fdf2827..711673e 100644 --- a/src/WeatherUtil.cpp +++ b/src/WeatherUtil.cpp @@ -3,16 +3,16 @@ #include #include -extern "C" const f32 sSmoothEpsilon; -extern "C" const f32 sSmoothEpsilonNeg; -extern "C" const f32 sAngleZero; -extern "C" const f32 sAngleFull; -extern "C" const f32 sAngleHalfNeg; -extern "C" const f32 sAngleHalf; -extern "C" const f32 sIdxToFIdx; -extern "C" const f32 sHalf; +extern const f32 sSmoothEpsilon; +extern const f32 sSmoothEpsilonNeg; +extern const f32 sAngleZero; +extern const f32 sAngleFull; +extern const f32 sAngleHalfNeg; +extern const f32 sAngleHalf; +extern const f32 sIdxToFIdx; +extern const f32 sHalf; -extern "C" const wchar_t sWeatherDigits[] = L"0123456789"; +extern const wchar_t sWeatherDigits[] = L"0123456789"; void WrapHour(s32* pHour) { *pHour %= 24; @@ -22,6 +22,8 @@ void WrapHourTo24(s32* pHour) { *pHour %= 25; } +// Nintendo's usual addCalc idiom (cf. cLib_addCalc): step *value toward target +// by rate * distance, clamped to [minStep, maxStep]; returns the distance left. f32 SmoothApproach(f32* value, f32 target, f32 rate, f32 maxStep, f32 minStep) { if (*value != target) { f32 diff = *value - target; @@ -55,6 +57,8 @@ f32 SmoothApproach(f32* value, f32 target, f32 rate, f32 maxStep, f32 minStep) { return __fabsf(*value - target); } +// addCalc for angles in degrees: like SmoothApproach, but takes the short way +// around, wraps into [0, 360), has no minimum step and snaps once the step <= minStep. f32 SmoothApproachAngle(f32* value, f32 target, f32 rate, f32 maxStep, f32 minStep) { f32 angle = *value; if (angle < sAngleZero) @@ -103,7 +107,7 @@ f32 EaseCos(u16 t) { return sHalf - sHalf * nw4r::math::CosFIdx(nw4r::math::U16ToF32(t) * sIdxToFIdx); } -extern "C" s32 FormatDigits(s32 value, s32* digits, s32 maxDigits) { +s32 FormatDigits(s32 value, s32* digits, s32 maxDigits) { s32 i; s32 count = 0; s32 v = value; diff --git a/src/WiiConnect24.cpp b/src/WiiConnect24.cpp index 8d11b81..0056124 100644 --- a/src/WiiConnect24.cpp +++ b/src/WiiConnect24.cpp @@ -2,9 +2,9 @@ #include #include -extern "C" OSMessageQueue gWC24Queue; -extern "C" volatile s32 gWC24QueueIndex; -extern "C" volatile s32 gWC24TaskCount; +extern OSMessageQueue gWC24Queue; +extern volatile s32 gWC24QueueIndex; +extern volatile s32 gWC24TaskCount; s32 CWiiConnect24::getWeather(void* forecastBuf, s64* forecastTime, u32* forecastSize, void* shortBuf, s64* shortTime, u32* shortSize, diff --git a/src/WiiConnect24Code.cpp b/src/WiiConnect24Code.cpp index 49685a2..83ccf66 100644 --- a/src/WiiConnect24Code.cpp +++ b/src/WiiConnect24Code.cpp @@ -1,9 +1,9 @@ #include #include -extern "C" MEMiHeapHead* gWC24Heap; +extern MEMiHeapHead* gWC24Heap; -extern "C" void WC24Free(void* unused, void* block, s32 size) { +void WC24Free(void* unused, void* block, s32 size) { if (block == NULL) return; diff --git a/src/WiiConnect24Download.cpp b/src/WiiConnect24Download.cpp index b595baf..57d0943 100644 --- a/src/WiiConnect24Download.cpp +++ b/src/WiiConnect24Download.cpp @@ -9,27 +9,27 @@ #include #include -extern "C" OSMessageQueue gWC24Queue; -extern "C" u8 gWC24FileBuffer[]; -extern "C" volatile u8 gWC24DownloadComplete; -extern "C" volatile u8 gWC24NetInitialized; -extern "C" volatile u8 gWC24ShutdownFlag1; -extern "C" volatile u8 gWC24ShutdownFlag2; -extern "C" void* WC24Alloc(u32 unused, s32 size); -extern "C" void WC24Free(void* unused, void* block, s32 size); +extern OSMessageQueue gWC24Queue; +extern u8 gWC24FileBuffer[]; +extern volatile u8 gWC24DownloadComplete; +extern volatile u8 gWC24NetInitialized; +extern volatile u8 gWC24ShutdownFlag1; +extern volatile u8 gWC24ShutdownFlag2; +void* WC24Alloc(u32 unused, s32 size); +void WC24Free(void* unused, void* block, s32 size); extern "C" s32 SOInit(void* init); extern "C" s32 SOStartup(); extern "C" s32 SOGetLastError(); extern "C" s32 NWC24ExecDownloadTask(s32 mode, u16 taskId, s32 flags); -extern "C" NWC24Work gNWC24Work; -extern "C" volatile u8 gNWC24LibOpened; +extern NWC24Work gNWC24Work; +extern volatile u8 gNWC24LibOpened; -extern "C" char sVfDriveName[] = "@24"; -extern "C" char sVfRootPath[] = "@24:/*"; -extern "C" char sVfReadMode[] = "r"; -extern "C" char sBinNameFormat[] = "%d.bin"; -extern "C" char sForecastFileSuffix[] = "%sB"; -extern "C" char sShortFileSuffix[] = "%sR"; +char sVfDriveName[] = "@24"; +char sVfRootPath[] = "@24:/*"; +char sVfReadMode[] = "r"; +char sBinNameFormat[] = "%d.bin"; +char sForecastFileSuffix[] = "%sB"; +char sShortFileSuffix[] = "%sR"; extern "C" s32 NWC24GetDlUrl(NWC24DlTask* pTask, char* url, u32 len); extern "C" s32 NWC24GetDlVfName(NWC24DlTask* pTask, char* name, u32 len); @@ -53,13 +53,13 @@ extern "C" s32 NWC24iCheckDlTask(NWC24DlTask* pTask); extern "C" s32 NWC24GetDlLastUpdate(NWC24DlTask* pTask, s64* time); extern "C" s32 NWC24GetDlNextTime(NWC24DlTask* pTask, s64* time); -extern "C" s32 MapDownloadError(s32 error); -extern "C" s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort); -extern "C" s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, +s32 MapDownloadError(s32 error); +s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort); +s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, u16 newInterval, u16 count, u32* idOut); -extern "C" s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2); -extern "C" s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort); -extern "C" s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, +s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2); +s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort); +s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, u32* outSize); struct WC24IdleMode { @@ -122,7 +122,7 @@ static inline s32 CloseLib(WC24Task* task) { return 0; } -extern "C" void* DownloaderThread(void* unused) { +void* DownloaderThread(void* unused) { WC24Task* task; void* message; s64 retry = 0; @@ -267,7 +267,7 @@ extern "C" void* DownloaderThread(void* unused) { return NULL; } -extern "C" s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { +s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { NWC24DlTask dlTasks[2]; u8 dta[0x448]; char url[0x100]; @@ -432,7 +432,7 @@ extern "C" s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { return 0; } -extern "C" s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, +s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, u16 newInterval, u16 count, u32* idOut) { NWC24DlTask dlTasks[2]; u8 search[0x448]; @@ -687,7 +687,7 @@ struct WC24SOConfig { void* free; }; -extern "C" s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2) { +s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2) { s32 initResult; s32 startupResult; s32 error; @@ -735,7 +735,7 @@ extern "C" s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 un return 0; } -extern "C" s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort) { +s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort) { NWC24DlTask dlTask; char vfName[0x50]; u16 ids[2]; @@ -790,7 +790,7 @@ extern "C" s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort) { return 0; } -extern "C" s32 MapDownloadError(s32 error) { +s32 MapDownloadError(s32 error) { s32 mapped = -6; if ((error <= -0x10 && error >= -0x15) || error == -0x26 || error == -0x29 || error == -0x2B || @@ -821,7 +821,7 @@ extern "C" s32 MapDownloadError(s32 error) { return mapped; } -extern "C" s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, +s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, u32* outSize) { u32 fileSize = VFGetFileSizeByFd(fd); u32 uncompSize = 0; diff --git a/src/WiiConnect24Heap.cpp b/src/WiiConnect24Heap.cpp index 700b1ec..8986ca3 100644 --- a/src/WiiConnect24Heap.cpp +++ b/src/WiiConnect24Heap.cpp @@ -1,9 +1,9 @@ #include #include -extern "C" MEMiHeapHead* gWC24Heap; +extern MEMiHeapHead* gWC24Heap; -extern "C" void* WC24Alloc(u32 unused, s32 size) { +void* WC24Alloc(u32 unused, s32 size) { void* block = NULL; if (size > 0) diff --git a/src/WiiConnect24Init.cpp b/src/WiiConnect24Init.cpp index 2482843..c914795 100644 --- a/src/WiiConnect24Init.cpp +++ b/src/WiiConnect24Init.cpp @@ -3,18 +3,18 @@ #include #include -extern "C" OSMessageQueue gWC24Queue; -extern "C" OSMessage gWC24QueueBuffer[16]; -extern "C" OSThread gWC24Thread; -extern "C" u8 gWC24ThreadStack[]; -extern "C" void* gWC24HeapBlock; -extern "C" MEMiHeapHead* gWC24Heap; -extern "C" volatile s32 gWC24DownloadIndex; -extern "C" volatile s32 gWC24QueueIndex; -extern "C" volatile s32 gWC24TaskCount; -extern "C" void* DownloaderThread(void*); +extern OSMessageQueue gWC24Queue; +extern OSMessage gWC24QueueBuffer[16]; +extern OSThread gWC24Thread; +extern u8 gWC24ThreadStack[]; +extern void* gWC24HeapBlock; +extern MEMiHeapHead* gWC24Heap; +extern volatile s32 gWC24DownloadIndex; +extern volatile s32 gWC24QueueIndex; +extern volatile s32 gWC24TaskCount; +void* DownloaderThread(void*); -extern "C" void InitDownloader(void) { +void InitDownloader(void) { void* block = MEM2Alloc(0x10000, 0x20); gWC24HeapBlock = block; gWC24Heap = MEMCreateExpHeapEx(block, 0x10000, 4); diff --git a/src/WiiConnect24Shutdown.cpp b/src/WiiConnect24Shutdown.cpp index 36419a4..268dadf 100644 --- a/src/WiiConnect24Shutdown.cpp +++ b/src/WiiConnect24Shutdown.cpp @@ -1,12 +1,12 @@ #include #include -extern "C" OSThread gWC24Thread; -extern "C" volatile u8 gWC24ShutdownFlag1; -extern "C" volatile u8 gWC24ShutdownFlag2; +extern OSThread gWC24Thread; +extern volatile u8 gWC24ShutdownFlag1; +extern volatile u8 gWC24ShutdownFlag2; extern "C" int NWC24iRequestShutdown(u32 event); -extern "C" void ShutdownDownloader(s32 event) { +void ShutdownDownloader(s32 event) { int i = 0; while (i < 10 && (gWC24ShutdownFlag1 || gWC24ShutdownFlag2)) { NWC24iRequestShutdown(event); diff --git a/src/WiiConnect24Update.cpp b/src/WiiConnect24Update.cpp index ae39ad5..cf1f09c 100644 --- a/src/WiiConnect24Update.cpp +++ b/src/WiiConnect24Update.cpp @@ -1,10 +1,10 @@ #include #include -extern "C" volatile s32 gWC24DownloadIndex; -extern "C" volatile s32 gWC24TaskCount; +extern volatile s32 gWC24DownloadIndex; +extern volatile s32 gWC24TaskCount; -extern "C" void UpdateDownloader(void) { +void UpdateDownloader(void) { if (gWC24TaskCount <= 0) return; diff --git a/src/WiiConnect24_bss.cpp b/src/WiiConnect24_bss.cpp index 43f88b5..cc28d3b 100644 --- a/src/WiiConnect24_bss.cpp +++ b/src/WiiConnect24_bss.cpp @@ -4,16 +4,13 @@ #include #include -extern "C" { NWC24Work gNWC24Work; OSMessageQueue gWC24Queue; OSMessage gWC24QueueBuffer[16]; OSThread gWC24Thread; u8 gWC24ThreadStack[0x8000]; u8 gWC24FileBuffer[0x10000]; -} WC24Task gWC24Tasks[8]; -extern "C" { u8 gWC24Spare[0x10]; volatile u8 gNWC24LibOpened; @@ -26,4 +23,3 @@ volatile s32 gWC24QueueIndex; volatile s32 gWC24TaskCount; void* gWC24HeapBlock; MEMiHeapHead* gWC24Heap; -} From a6f826f68047c4553681501e04184f4012aebd90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 11:21:12 +0300 Subject: [PATCH 03/15] Channel: fold WiiConnect24 globals into WiiConnect24.cpp --- config/HAFE/splits.txt | 6 ++---- configure.py | 1 - src/WiiConnect24.cpp | 25 ++++++++++++++++++++++--- src/WiiConnect24_bss.cpp | 25 ------------------------- 4 files changed, 24 insertions(+), 33 deletions(-) delete mode 100644 src/WiiConnect24_bss.cpp diff --git a/config/HAFE/splits.txt b/config/HAFE/splits.txt index 43c0af2..119721d 100644 --- a/config/HAFE/splits.txt +++ b/config/HAFE/splits.txt @@ -236,10 +236,6 @@ System.cpp: ChannelMathData.cpp: .sdata2 start:0x80331F78 end:0x80331FC0 -WiiConnect24_bss.cpp: - .bss start:0x801D99E0 end:0x801F6B28 - .sbss start:0x80330B78 end:0x80330B98 - WiiConnect24Init.cpp: .text start:0x80032610 end:0x800326BC @@ -251,6 +247,8 @@ WiiConnect24Shutdown.cpp: WiiConnect24.cpp: .text start:0x800327AC end:0x80033C80 + .bss start:0x801D99E0 end:0x801F6B28 + .sbss start:0x80330B78 end:0x80330B98 WiiConnect24Download.cpp: .text start:0x80033C80 end:0x80035B70 diff --git a/configure.py b/configure.py index a06a3f7..8ff418b 100755 --- a/configure.py +++ b/configure.py @@ -1099,7 +1099,6 @@ def MatchingFor(*versions): Object(Matching, "main.cpp"), Object(Matching, "DrawUtil.cpp"), Object(Matching, "GlobeDots.cpp"), - Object(Matching, "WiiConnect24_bss.cpp"), Object(Matching, "WiiConnect24Init.cpp"), Object(Matching, "WiiConnect24Shutdown.cpp"), Object(Matching, "WiiConnect24Update.cpp"), diff --git a/src/WiiConnect24.cpp b/src/WiiConnect24.cpp index 0056124..c38c767 100644 --- a/src/WiiConnect24.cpp +++ b/src/WiiConnect24.cpp @@ -1,10 +1,29 @@ #include +#include +#include #include #include -extern OSMessageQueue gWC24Queue; -extern volatile s32 gWC24QueueIndex; -extern volatile s32 gWC24TaskCount; +NWC24Work gNWC24Work; +OSMessageQueue gWC24Queue; +OSMessage gWC24QueueBuffer[16]; +OSThread gWC24Thread; +u8 gWC24ThreadStack[0x8000]; +u8 gWC24FileBuffer[0x10000]; +WC24Task gWC24Tasks[8]; +u8 gWC24Spare[0x10]; + +volatile u8 gNWC24LibOpened; +volatile u8 gWC24DownloadComplete; +volatile u8 gWC24ShutdownFlag1; +volatile u8 gWC24NetInitialized; +volatile u8 gWC24ShutdownFlag2; +volatile s32 gWC24DownloadIndex; +volatile s32 gWC24QueueIndex; +volatile s32 gWC24TaskCount; +void* gWC24HeapBlock; +MEMiHeapHead* gWC24Heap; + s32 CWiiConnect24::getWeather(void* forecastBuf, s64* forecastTime, u32* forecastSize, void* shortBuf, s64* shortTime, u32* shortSize, diff --git a/src/WiiConnect24_bss.cpp b/src/WiiConnect24_bss.cpp deleted file mode 100644 index cc28d3b..0000000 --- a/src/WiiConnect24_bss.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include -#include -#include - -NWC24Work gNWC24Work; -OSMessageQueue gWC24Queue; -OSMessage gWC24QueueBuffer[16]; -OSThread gWC24Thread; -u8 gWC24ThreadStack[0x8000]; -u8 gWC24FileBuffer[0x10000]; -WC24Task gWC24Tasks[8]; -u8 gWC24Spare[0x10]; - -volatile u8 gNWC24LibOpened; -volatile u8 gWC24DownloadComplete; -volatile u8 gWC24ShutdownFlag1; -volatile u8 gWC24NetInitialized; -volatile u8 gWC24ShutdownFlag2; -volatile s32 gWC24DownloadIndex; -volatile s32 gWC24QueueIndex; -volatile s32 gWC24TaskCount; -void* gWC24HeapBlock; -MEMiHeapHead* gWC24Heap; From f37c87a474449b00b56d13580d0d1fd4e146a7f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 11:38:09 +0300 Subject: [PATCH 04/15] Channel: group downloader lifecycle functions --- config/HAFE/splits.txt | 10 ++---- configure.py | 4 +-- src/WiiConnect24Lifecycle.cpp | 61 +++++++++++++++++++++++++++++++++++ src/WiiConnect24Shutdown.cpp | 18 ----------- src/WiiConnect24Update.cpp | 19 ----------- 5 files changed, 64 insertions(+), 48 deletions(-) create mode 100644 src/WiiConnect24Lifecycle.cpp delete mode 100644 src/WiiConnect24Shutdown.cpp delete mode 100644 src/WiiConnect24Update.cpp diff --git a/config/HAFE/splits.txt b/config/HAFE/splits.txt index 119721d..38b4acd 100644 --- a/config/HAFE/splits.txt +++ b/config/HAFE/splits.txt @@ -236,14 +236,8 @@ System.cpp: ChannelMathData.cpp: .sdata2 start:0x80331F78 end:0x80331FC0 -WiiConnect24Init.cpp: - .text start:0x80032610 end:0x800326BC - -WiiConnect24Update.cpp: - .text start:0x800326BC end:0x8003271C - -WiiConnect24Shutdown.cpp: - .text start:0x8003271C end:0x800327AC +WiiConnect24Lifecycle.cpp: + .text start:0x80032610 end:0x800327AC WiiConnect24.cpp: .text start:0x800327AC end:0x80033C80 diff --git a/configure.py b/configure.py index 8ff418b..ec01c44 100755 --- a/configure.py +++ b/configure.py @@ -1099,9 +1099,7 @@ def MatchingFor(*versions): Object(Matching, "main.cpp"), Object(Matching, "DrawUtil.cpp"), Object(Matching, "GlobeDots.cpp"), - Object(Matching, "WiiConnect24Init.cpp"), - Object(Matching, "WiiConnect24Shutdown.cpp"), - Object(Matching, "WiiConnect24Update.cpp"), + Object(Matching, "WiiConnect24Lifecycle.cpp"), Object(Matching, "WiiConnect24Code.cpp"), Object(Matching, "WiiConnect24.cpp"), Object(Matching, "WiiConnect24Download.cpp"), diff --git a/src/WiiConnect24Lifecycle.cpp b/src/WiiConnect24Lifecycle.cpp new file mode 100644 index 0000000..65f4ebf --- /dev/null +++ b/src/WiiConnect24Lifecycle.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +extern OSMessageQueue gWC24Queue; +extern OSMessage gWC24QueueBuffer[16]; +extern OSThread gWC24Thread; +extern u8 gWC24ThreadStack[]; +extern void* gWC24HeapBlock; +extern MEMiHeapHead* gWC24Heap; +extern volatile s32 gWC24DownloadIndex; +extern volatile s32 gWC24QueueIndex; +extern volatile s32 gWC24TaskCount; +void* DownloaderThread(void*); + +void InitDownloader(void) { + void* block = MEM2Alloc(0x10000, 0x20); + gWC24HeapBlock = block; + gWC24Heap = MEMCreateExpHeapEx(block, 0x10000, 4); + + OSThread* thread = &gWC24Thread; + OSInitMessageQueue(&gWC24Queue, gWC24QueueBuffer, 0x10); + OSCreateThread(thread, (OSThreadFunc)DownloaderThread, NULL, gWC24ThreadStack + 0x8000, + 0x8000, 8, 1); + OSResumeThread(thread); + + gWC24DownloadIndex = 0; + gWC24QueueIndex = 0; + gWC24TaskCount = 0; +} + +void UpdateDownloader(void) { + if (gWC24TaskCount <= 0) + return; + + if (gWC24Tasks[gWC24DownloadIndex].mState != 0) + return; + + gWC24DownloadIndex++; + gWC24TaskCount--; + + if (gWC24DownloadIndex >= gWC24TaskCount) + gWC24DownloadIndex = 0; +} + +extern volatile u8 gWC24ShutdownFlag1; +extern volatile u8 gWC24ShutdownFlag2; +extern "C" int NWC24iRequestShutdown(u32 event); + +void ShutdownDownloader(s32 event) { + int i = 0; + while (i < 10 && (gWC24ShutdownFlag1 || gWC24ShutdownFlag2)) { + NWC24iRequestShutdown(event); + OSSleepTicks(OS_TIME_SPEED); + i++; + } + + OSJoinThread(&gWC24Thread, NULL); +} diff --git a/src/WiiConnect24Shutdown.cpp b/src/WiiConnect24Shutdown.cpp deleted file mode 100644 index 268dadf..0000000 --- a/src/WiiConnect24Shutdown.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include - -extern OSThread gWC24Thread; -extern volatile u8 gWC24ShutdownFlag1; -extern volatile u8 gWC24ShutdownFlag2; -extern "C" int NWC24iRequestShutdown(u32 event); - -void ShutdownDownloader(s32 event) { - int i = 0; - while (i < 10 && (gWC24ShutdownFlag1 || gWC24ShutdownFlag2)) { - NWC24iRequestShutdown(event); - OSSleepTicks(OS_TIME_SPEED); - i++; - } - - OSJoinThread(&gWC24Thread, NULL); -} diff --git a/src/WiiConnect24Update.cpp b/src/WiiConnect24Update.cpp deleted file mode 100644 index cf1f09c..0000000 --- a/src/WiiConnect24Update.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -extern volatile s32 gWC24DownloadIndex; -extern volatile s32 gWC24TaskCount; - -void UpdateDownloader(void) { - if (gWC24TaskCount <= 0) - return; - - if (gWC24Tasks[gWC24DownloadIndex].mState != 0) - return; - - gWC24DownloadIndex++; - gWC24TaskCount--; - - if (gWC24DownloadIndex >= gWC24TaskCount) - gWC24DownloadIndex = 0; -} From afbb9f9909d8a768c8da6168467b8448d67d39a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 11:40:03 +0300 Subject: [PATCH 05/15] Channel: share lifecycle declarations and name task enums --- include/channel/WiiConnect24.h | 18 ++++++++++++++++++ src/SceneBase.cpp | 2 +- src/System.cpp | 5 +---- src/WiiConnect24.cpp | 30 +++++++++++++++--------------- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/include/channel/WiiConnect24.h b/include/channel/WiiConnect24.h index cb3450e..9f3090c 100644 --- a/include/channel/WiiConnect24.h +++ b/include/channel/WiiConnect24.h @@ -51,6 +51,24 @@ struct WC24Task { extern WC24Task gWC24Tasks[]; +enum WC24TaskType { + WC24_TASK_GET_WEATHER = 0, + WC24_TASK_DOWNLOAD_WEATHER = 1, + WC24_TASK_SET_WEATHER = 2, + WC24_TASK_DELETE_WEATHER = 3, +}; + +enum WC24TaskId { + WC24_TASK_ID_NONE = 0, + WC24_TASK_ID_FORECAST = 3, + WC24_TASK_ID_SHORT = 4, +}; + +void InitDownloader(void); +void UpdateDownloader(void); +void ShutdownDownloader(s32 event); + + // WiiConnect24.cpp: weather download tasks class CWiiConnect24 { public: diff --git a/src/SceneBase.cpp b/src/SceneBase.cpp index 37b3236..896a4ee 100644 --- a/src/SceneBase.cpp +++ b/src/SceneBase.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,6 @@ #include #include -void ShutdownDownloader(s32 event); wchar_t* FormatNumber(s32 value, wchar_t* pBuf, s32 digits, BOOL zeroPad); void WrapHour(s32* pHour); diff --git a/src/System.cpp b/src/System.cpp index 4459686..8a3b2b2 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -1,5 +1,6 @@ #include "revolution/CNT/cnt.h" #include +#include #include #include @@ -9,10 +10,6 @@ #include #include -// Not yet decompiled (channel) -void InitDownloader(void); -void UpdateDownloader(void); - // Not yet decompiled (libraries) extern "C" void VFInit(void); extern "C" void OSRestart(u32 arg0); diff --git a/src/WiiConnect24.cpp b/src/WiiConnect24.cpp index c38c767..ea226ac 100644 --- a/src/WiiConnect24.cpp +++ b/src/WiiConnect24.cpp @@ -30,9 +30,9 @@ s32 CWiiConnect24::getWeather(void* forecastBuf, s64* forecastTime, u32* forecas const char* forecastUrl, const char* shortUrl, u32 forecastBufSize, u32 forecastMaxSize, u32 shortBufSize) { WC24Task task; - task.mType = 0; - task.mTaskId = 3; - task.mSubTaskId = 4; + task.mType = WC24_TASK_GET_WEATHER; + task.mTaskId = WC24_TASK_ID_FORECAST; + task.mSubTaskId = WC24_TASK_ID_SHORT; task.mBuffers.forecast = forecastBuf; task.mBuffers.shortForecast = shortBuf; task.mTimes.forecast = forecastTime; @@ -67,9 +67,9 @@ s32 CWiiConnect24::getWeather(void* forecastBuf, s64* forecastTime, u32* forecas s32 CWiiConnect24::downloadWeatherForecast(void* buf, s64* time, u32* size, u32 bufSize) { WC24Task task; - task.mType = 1; - task.mTaskId = 3; - task.mSubTaskId = 0; + task.mType = WC24_TASK_DOWNLOAD_WEATHER; + task.mTaskId = WC24_TASK_ID_FORECAST; + task.mSubTaskId = WC24_TASK_ID_NONE; task.mBuffers.forecast = buf; task.mTimes.forecast = time; task.mBufferSizes[0] = bufSize; @@ -98,9 +98,9 @@ s32 CWiiConnect24::downloadWeatherForecast(void* buf, s64* time, u32* size, u32 s32 CWiiConnect24::downloadWeatherShort(void* buf, s64* time, u32* size, u32 bufSize) { WC24Task task; - task.mType = 1; - task.mTaskId = 4; - task.mSubTaskId = 0; + task.mType = WC24_TASK_DOWNLOAD_WEATHER; + task.mTaskId = WC24_TASK_ID_SHORT; + task.mSubTaskId = WC24_TASK_ID_NONE; task.mBuffers.forecast = buf; task.mTimes.forecast = time; task.mBufferSizes[0] = bufSize; @@ -131,9 +131,9 @@ s32 CWiiConnect24::setWeather(const char* forecastUrl, const char* shortUrl, u32 u32 redownload, u32 interval) { WC24Task task; WC24Task* pTask = &task; - pTask->mType = 2; - pTask->mTaskId = 3; - pTask->mSubTaskId = 4; + pTask->mType = WC24_TASK_SET_WEATHER; + pTask->mTaskId = WC24_TASK_ID_FORECAST; + pTask->mSubTaskId = WC24_TASK_ID_SHORT; pTask->mForecastUrl = forecastUrl; pTask->mShortUrl = shortUrl; pTask->mForecastBufferSize = forecastBufSize; @@ -167,9 +167,9 @@ s32 CWiiConnect24::setWeather(const char* forecastUrl, const char* shortUrl, u32 s32 CWiiConnect24::deleteWeather() { WC24Task task; WC24Task* pTask = &task; - pTask->mType = 3; - pTask->mTaskId = 3; - pTask->mSubTaskId = 4; + pTask->mType = WC24_TASK_DELETE_WEATHER; + pTask->mTaskId = WC24_TASK_ID_FORECAST; + pTask->mSubTaskId = WC24_TASK_ID_SHORT; s32 result = -1; if (gWC24TaskCount < 8) { From 2e7f41b53c7c0135f470f3949150ea32dbdace7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 11:40:33 +0300 Subject: [PATCH 06/15] Channel: finish lifecycle split cleanup and add missing MSL wchar header --- include/MSL_C/include/wchar.h | 18 ++++++++++++++++++ src/WiiConnect24Init.cpp | 31 ------------------------------- 2 files changed, 18 insertions(+), 31 deletions(-) create mode 100644 include/MSL_C/include/wchar.h delete mode 100644 src/WiiConnect24Init.cpp diff --git a/include/MSL_C/include/wchar.h b/include/MSL_C/include/wchar.h new file mode 100644 index 0000000..cfee240 --- /dev/null +++ b/include/MSL_C/include/wchar.h @@ -0,0 +1,18 @@ +#ifndef WCHAR_H +#define WCHAR_H + +#include "size_t.h" +#include "wchar_t.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int wcscmp(const wchar_t* lhs, const wchar_t* rhs); +wchar_t* wcsncpy(wchar_t* dst, const wchar_t* src, size_t count); + +#ifdef __cplusplus +} +#endif + +#endif // WCHAR_H diff --git a/src/WiiConnect24Init.cpp b/src/WiiConnect24Init.cpp deleted file mode 100644 index c914795..0000000 --- a/src/WiiConnect24Init.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include -#include - -extern OSMessageQueue gWC24Queue; -extern OSMessage gWC24QueueBuffer[16]; -extern OSThread gWC24Thread; -extern u8 gWC24ThreadStack[]; -extern void* gWC24HeapBlock; -extern MEMiHeapHead* gWC24Heap; -extern volatile s32 gWC24DownloadIndex; -extern volatile s32 gWC24QueueIndex; -extern volatile s32 gWC24TaskCount; -void* DownloaderThread(void*); - -void InitDownloader(void) { - void* block = MEM2Alloc(0x10000, 0x20); - gWC24HeapBlock = block; - gWC24Heap = MEMCreateExpHeapEx(block, 0x10000, 4); - - OSThread* thread = &gWC24Thread; - OSInitMessageQueue(&gWC24Queue, gWC24QueueBuffer, 0x10); - OSCreateThread(thread, (OSThreadFunc)DownloaderThread, NULL, gWC24ThreadStack + 0x8000, - 0x8000, 8, 1); - OSResumeThread(thread); - - gWC24DownloadIndex = 0; - gWC24QueueIndex = 0; - gWC24TaskCount = 0; -} From 530d020afec3738e2e1c26f27c944210bc9fc2a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 11:42:55 +0300 Subject: [PATCH 07/15] Channel: share math constant declarations --- include/channel/ChannelMathData.h | 30 ++++++++++++++++++++++++++++++ src/ChannelMathData.cpp | 4 ++++ src/DragScroll.cpp | 9 +-------- src/MtxUtil.cpp | 3 +-- src/WeatherUtil.cpp | 9 +-------- 5 files changed, 37 insertions(+), 18 deletions(-) create mode 100644 include/channel/ChannelMathData.h diff --git a/include/channel/ChannelMathData.h b/include/channel/ChannelMathData.h new file mode 100644 index 0000000..ab88257 --- /dev/null +++ b/include/channel/ChannelMathData.h @@ -0,0 +1,30 @@ +#ifndef CHANNEL_CHANNEL_MATH_DATA_H +#define CHANNEL_CHANNEL_MATH_DATA_H + +#include + +// These constants are defined in ChannelMathData.cpp. The code units must see +// them as external objects: defining them alongside the functions lets MWCC +// fold them into anonymous local constants, which does not match the target. +extern const f32 sDragScrollZero; +extern const f32 sDragScrollOffset; +extern const f32 sDragScrollThreshold; +extern const f32 sDragScrollNegThreshold; +extern const f32 sDragScrollMax; +extern const f32 sDragScrollAngleScale; +extern const f32 sDragScrollHalfPi; +extern const f32 sDragScrollTimerScale; + +extern const f32 sSmoothEpsilon; +extern const f32 sSmoothEpsilonNeg; +extern const f32 sAngleZero; +extern const f32 sAngleFull; +extern const f32 sAngleHalfNeg; +extern const f32 sAngleHalf; +extern const f32 sIdxToFIdx; +extern const f32 sHalf; + +extern const f32 sDegToRad; +extern const f32 sDegToFIdx; + +#endif // CHANNEL_CHANNEL_MATH_DATA_H diff --git a/src/ChannelMathData.cpp b/src/ChannelMathData.cpp index 521807d..b7f4886 100644 --- a/src/ChannelMathData.cpp +++ b/src/ChannelMathData.cpp @@ -1,5 +1,9 @@ #include +// Definitions deliberately live in a separate TU from the functions that use +// them. This forces named external constants; same-TU definitions are folded +// by MWCC into anonymous locals and break the target match. + extern const f32 sDragScrollZero = 0.0f; extern const f32 sDragScrollOffset = 228.0f; extern const f32 sDragScrollThreshold = 20.0f; diff --git a/src/DragScroll.cpp b/src/DragScroll.cpp index 8d403a5..f3c00dd 100644 --- a/src/DragScroll.cpp +++ b/src/DragScroll.cpp @@ -1,14 +1,7 @@ #include +#include #include -extern const f32 sDragScrollZero; -extern const f32 sDragScrollOffset; -extern const f32 sDragScrollThreshold; -extern const f32 sDragScrollNegThreshold; -extern const f32 sDragScrollMax; -extern const f32 sDragScrollAngleScale; -extern const f32 sDragScrollHalfPi; -extern const f32 sDragScrollTimerScale; // Layout matches gDragScroll in SceneBase.cpp (size 0x34). struct DragScroll { diff --git a/src/MtxUtil.cpp b/src/MtxUtil.cpp index 6457564..fd487da 100644 --- a/src/MtxUtil.cpp +++ b/src/MtxUtil.cpp @@ -1,8 +1,7 @@ #include +#include #include -extern const f32 sDegToRad; -extern const f32 sDegToFIdx; void TranslateMtx(nw4r::math::MTX34* m, f32 x, f32 y, f32 z) { Mtx trans; diff --git a/src/WeatherUtil.cpp b/src/WeatherUtil.cpp index 711673e..c333c9b 100644 --- a/src/WeatherUtil.cpp +++ b/src/WeatherUtil.cpp @@ -1,16 +1,9 @@ #include +#include #include #include #include -extern const f32 sSmoothEpsilon; -extern const f32 sSmoothEpsilonNeg; -extern const f32 sAngleZero; -extern const f32 sAngleFull; -extern const f32 sAngleHalfNeg; -extern const f32 sAngleHalf; -extern const f32 sIdxToFIdx; -extern const f32 sHalf; extern const wchar_t sWeatherDigits[] = L"0123456789"; From e48c9739b6bc54f4dd400b7ec9c88b99cb4b1a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 12:58:02 +0300 Subject: [PATCH 08/15] Channel: rely on header extern for math constants --- src/ChannelMathData.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/ChannelMathData.cpp b/src/ChannelMathData.cpp index b7f4886..01621ca 100644 --- a/src/ChannelMathData.cpp +++ b/src/ChannelMathData.cpp @@ -1,24 +1,25 @@ #include +#include // Definitions deliberately live in a separate TU from the functions that use // them. This forces named external constants; same-TU definitions are folded // by MWCC into anonymous locals and break the target match. -extern const f32 sDragScrollZero = 0.0f; -extern const f32 sDragScrollOffset = 228.0f; -extern const f32 sDragScrollThreshold = 20.0f; -extern const f32 sDragScrollNegThreshold = -20.0f; -extern const f32 sDragScrollMax = 185.2f; -extern const f32 sDragScrollAngleScale = 40.743664f; -extern const f32 sDragScrollHalfPi = 1.5707964f; -extern const f32 sDragScrollTimerScale = 23.0f; -extern const f32 sSmoothEpsilon = 0.0008f; -extern const f32 sSmoothEpsilonNeg = -0.0008f; -extern const f32 sAngleZero = 0.0f; -extern const f32 sAngleFull = 360.0f; -extern const f32 sAngleHalfNeg = -180.0f; -extern const f32 sAngleHalf = 180.0f; -extern const f32 sIdxToFIdx = 0.00390625f; -extern const f32 sHalf = 0.5f; -extern const f32 sDegToRad = 0.017453292f; -extern const f32 sDegToFIdx = 0.7111111f; +const f32 sDragScrollZero = 0.0f; +const f32 sDragScrollOffset = 228.0f; +const f32 sDragScrollThreshold = 20.0f; +const f32 sDragScrollNegThreshold = -20.0f; +const f32 sDragScrollMax = 185.2f; +const f32 sDragScrollAngleScale = 40.743664f; +const f32 sDragScrollHalfPi = 1.5707964f; +const f32 sDragScrollTimerScale = 23.0f; +const f32 sSmoothEpsilon = 0.0008f; +const f32 sSmoothEpsilonNeg = -0.0008f; +const f32 sAngleZero = 0.0f; +const f32 sAngleFull = 360.0f; +const f32 sAngleHalfNeg = -180.0f; +const f32 sAngleHalf = 180.0f; +const f32 sIdxToFIdx = 0.00390625f; +const f32 sHalf = 0.5f; +const f32 sDegToRad = 0.017453292f; +const f32 sDegToFIdx = 0.7111111f; From 2b77f704d1bcf3a223d035e1fcc66e248d605d00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 13:17:28 +0300 Subject: [PATCH 09/15] Channel: use NWC24 error constants in downloader --- src/WiiConnect24Download.cpp | 73 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/src/WiiConnect24Download.cpp b/src/WiiConnect24Download.cpp index 57d0943..6b1fe31 100644 --- a/src/WiiConnect24Download.cpp +++ b/src/WiiConnect24Download.cpp @@ -80,46 +80,47 @@ static inline void SetTaskMessage(WC24Task* task, const char* msg, s32 code, s32 // NWC24GetErrorCode() in a callee-saved register, which the original does not do. #define SetTaskError(task, msg, result) (SetTaskMessage(task, msg, NWC24GetErrorCode(), result), MapDownloadError(result)) -static inline s32 OpenLib(WC24Task* task, s64 retry) { - s32 error; +static inline NWC24Err OpenLib(WC24Task* task, s64 retry) { + NWC24Err error; for (;;) { error = NWC24OpenLib(&gNWC24Work); - if (error != -0x16 && error != -0x1A && error != -0x1D) + if (error != NWC24_ERR_MUTEX && error != NWC24_ERR_BUSY && + error != NWC24_ERR_INPROGRESS) break; OSSleepTicks(OS_MSEC_TO_TICKS(100 * (retry + 1))); } - if (error != 0) - return SetTaskError(task, "NWC24OpenLib() failed.", error); + if (error != NWC24_OK) + return (NWC24Err)SetTaskError(task, "NWC24OpenLib() failed.", error); gNWC24LibOpened = 1; - return 0; + return NWC24_OK; } -static inline s32 CheckLib(WC24Task* task) { - s32 error = NWC24Check(2); +static inline NWC24Err CheckLib(WC24Task* task) { + NWC24Err error = NWC24Check(2); - if (error != 0) - return SetTaskError(task, "NWC24Check() failed.", error); + if (error != NWC24_OK) + return (NWC24Err)SetTaskError(task, "NWC24Check() failed.", error); WC24IdleMode idle; if (SCGetIdleMode(&idle) == 0 || idle.wc24 != 1) - return -3; + return NWC24_ERR_INVALID_VALUE; - return 0; + return NWC24_OK; } -static inline s32 CloseLib(WC24Task* task) { - s32 error = NWC24CloseLib(); +static inline NWC24Err CloseLib(WC24Task* task) { + NWC24Err error = NWC24CloseLib(); - if (error != 0) - return SetTaskError(task, "NWC24CloseLib() failed.", error); + if (error != NWC24_OK) + return (NWC24Err)SetTaskError(task, "NWC24CloseLib() failed.", error); gNWC24LibOpened = 0; - return 0; + return NWC24_OK; } void* DownloaderThread(void* unused) { @@ -147,31 +148,31 @@ void* DownloaderThread(void* unused) { for (;;) { task->mState = 2; task->mResult = OpenLib(task, retry); - if (task->mResult != 0) + if (task->mResult != NWC24_OK) break; opened = TRUE; task->mResult = CheckLib(task); - if (task->mResult != 0) + if (task->mResult != NWC24_OK) break; task->mState = 3; - if ((task->mResult = DownloadFiles(task, 1, 1)) == 0) + if ((task->mResult = DownloadFiles(task, 1, 1)) == NWC24_OK) break; - if (task->mResult == -1 && attempts != 1) { + if (task->mResult == NWC24_ERR_FATAL && attempts != 1) { task->mState = 6; task->mResult = CreateDownloadTasks(task, 1, 1, 1, 0x1E, 0x3C, 0); - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { task->mState = 2; task->mResult = CloseLib(task); opened = FALSE; - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { task->mState = 5; task->mResult = ExecuteDownloadTask(task, 0, 0xFFFFFF, 0xFFFF); - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { task->mResult = ExecuteDownloadTask(task, 1, 0xFFFFFF, 0xFFFF); - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { attempts++; continue; } @@ -185,7 +186,7 @@ void* DownloaderThread(void* unused) { if (opened) { task->mState = 2; result = CloseLib(task); - if (task->mResult == 0) + if (task->mResult == NWC24_OK) task->mResult = result; } task->mState = 0; @@ -194,12 +195,12 @@ void* DownloaderThread(void* unused) { case 1: task->mState = 5; task->mResult = ExecuteDownloadTask(task, 0, 0xFFFFFF, 0xFFFF); - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { task->mState = 2; task->mResult = OpenLib(task, retry); - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { task->mResult = CheckLib(task); - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { task->mState = 3; switch (task->mTaskId) { case 3: @@ -212,7 +213,7 @@ void* DownloaderThread(void* unused) { } task->mState = 2; result = CloseLib(task); - if (task->mResult == 0) + if (task->mResult == NWC24_OK) task->mResult = result; } } @@ -222,16 +223,16 @@ void* DownloaderThread(void* unused) { case 2: task->mState = 2; task->mResult = OpenLib(task, retry); - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { task->mResult = CheckLib(task); - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { task->mState = 6; task->mResult = CreateDownloadTasks(task, 1, 1, task->mRedownload, task->mDownloadInterval, task->mDownloadCount, 0); } task->mState = 2; result = CloseLib(task); - if (task->mResult == 0) + if (task->mResult == NWC24_OK) task->mResult = result; } task->mState = 0; @@ -240,15 +241,15 @@ void* DownloaderThread(void* unused) { case 3: task->mState = 2; task->mResult = OpenLib(task, retry); - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { task->mResult = CheckLib(task); - if (task->mResult == 0) { + if (task->mResult == NWC24_OK) { task->mState = 7; task->mResult = DeleteTaskFiles(task, 1, 1); } task->mState = 2; result = CloseLib(task); - if (task->mResult == 0) + if (task->mResult == NWC24_OK) task->mResult = result; } task->mState = 0; From 8130b97a2bc0971476ed4363617c2897c6cb4d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 14:18:32 +0300 Subject: [PATCH 10/15] NWC24: move download API declarations into headers --- include/revolution/NWC24/NWC24Download.h | 20 ++++++++++++++++ include/revolution/NWC24/NWC24Schedule.h | 1 + .../NWC24/internal/NWC24iDownload.h | 1 + src/WiiConnect24Download.cpp | 23 +------------------ 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/include/revolution/NWC24/NWC24Download.h b/include/revolution/NWC24/NWC24Download.h index f39ffda..8528841 100644 --- a/include/revolution/NWC24/NWC24Download.h +++ b/include/revolution/NWC24/NWC24Download.h @@ -42,6 +42,26 @@ typedef struct NWC24DlTask { NWC24Err NWC24CheckDlTask(NWC24DlTask* pTask); NWC24Err NWC24DeleteDlTaskForced(NWC24DlTask* pTask); NWC24Err NWC24GetDlTask(NWC24DlTask* pTask, u16 id); +NWC24Err NWC24InitDlTask(NWC24DlTask* pTask, u32 type); +NWC24Err NWC24SetDlId(NWC24DlTask* pTask, u16 id); +NWC24Err NWC24GetDlId(NWC24DlTask* pTask, u32* pId); +NWC24Err NWC24SetDlPriority(NWC24DlTask* pTask, s32 priority); +NWC24Err NWC24SetDlInterval(NWC24DlTask* pTask, u16 interval); +NWC24Err NWC24GetDlInterval(NWC24DlTask* pTask, u16* pInterval); +NWC24Err NWC24SetDlRetryMargin(NWC24DlTask* pTask, s32 margin); +NWC24Err NWC24SetDlUrl(NWC24DlTask* pTask, const char* url); +NWC24Err NWC24GetDlUrl(NWC24DlTask* pTask, char* url, u32 len); +NWC24Err NWC24SetDlFlags(NWC24DlTask* pTask, u32 flags); +NWC24Err NWC24SetDlFilename(NWC24DlTask* pTask, const char* name); +NWC24Err NWC24GetDlFilename(NWC24DlTask* pTask, char* name, u32 len); +NWC24Err NWC24SetDlCount(NWC24DlTask* pTask, s16 count); +NWC24Err NWC24GetDlLastUpdate(NWC24DlTask* pTask, s64* time); +NWC24Err NWC24UpdateDlTask(NWC24DlTask* pTask); +NWC24Err NWC24DeleteDlTask(NWC24DlTask* pTask); +NWC24Err NWC24AddDlTask(NWC24DlTask* pTask); +NWC24Err NWC24GetDlNextTime(NWC24DlTask* pTask, s64* time); +NWC24Err NWC24GetDlVfName(NWC24DlTask* pTask, char* name, u32 len); +NWC24Err NWC24CreateDlVf(NWC24DlTask* pTask, u32 size); #ifdef __cplusplus } diff --git a/include/revolution/NWC24/NWC24Schedule.h b/include/revolution/NWC24/NWC24Schedule.h index 618b89b..98c73fb 100644 --- a/include/revolution/NWC24/NWC24Schedule.h +++ b/include/revolution/NWC24/NWC24Schedule.h @@ -10,6 +10,7 @@ extern "C" { s32 NWC24SuspendScheduler(void); s32 NWC24ResumeScheduler(void); +NWC24Err NWC24ExecDownloadTask(s32 mode, u16 taskId, s32 flags); #ifdef __cplusplus } diff --git a/include/revolution/NWC24/internal/NWC24iDownload.h b/include/revolution/NWC24/internal/NWC24iDownload.h index 1662067..b33dd21 100644 --- a/include/revolution/NWC24/internal/NWC24iDownload.h +++ b/include/revolution/NWC24/internal/NWC24iDownload.h @@ -71,6 +71,7 @@ NWC24Err NWC24iCloseDlTaskList(void); NWC24iDlHeader* NWC24iGetCachedDlHeader(void); NWC24Err NWC24iCheckHeaderConsistency(NWC24iDlHeader* pHeader, BOOL clear) DECOMP_DONT_INLINE; +NWC24Err NWC24iCheckDlTask(NWC24DlTask* pTask); NWC24Err NWC24iLoadDlHeader(void); #ifdef __cplusplus diff --git a/src/WiiConnect24Download.cpp b/src/WiiConnect24Download.cpp index 6b1fe31..3156bd7 100644 --- a/src/WiiConnect24Download.cpp +++ b/src/WiiConnect24Download.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,6 @@ void WC24Free(void* unused, void* block, s32 size); extern "C" s32 SOInit(void* init); extern "C" s32 SOStartup(); extern "C" s32 SOGetLastError(); -extern "C" s32 NWC24ExecDownloadTask(s32 mode, u16 taskId, s32 flags); extern NWC24Work gNWC24Work; extern volatile u8 gNWC24LibOpened; @@ -31,27 +31,6 @@ char sBinNameFormat[] = "%d.bin"; char sForecastFileSuffix[] = "%sB"; char sShortFileSuffix[] = "%sR"; -extern "C" s32 NWC24GetDlUrl(NWC24DlTask* pTask, char* url, u32 len); -extern "C" s32 NWC24GetDlVfName(NWC24DlTask* pTask, char* name, u32 len); -extern "C" s32 NWC24GetDlFilename(NWC24DlTask* pTask, char* name, u32 len); -extern "C" s32 NWC24DeleteDlTask(NWC24DlTask* pTask); -extern "C" s32 NWC24InitDlTask(NWC24DlTask* pTask, u32 type); -extern "C" s32 NWC24SetDlId(NWC24DlTask* pTask, u16 id); -extern "C" s32 NWC24GetDlId(NWC24DlTask* pTask, u32* pId); -extern "C" s32 NWC24GetDlInterval(NWC24DlTask* pTask, u16* pInterval); -extern "C" s32 NWC24SetDlInterval(NWC24DlTask* pTask, u16 interval); -extern "C" s32 NWC24SetDlPriority(NWC24DlTask* pTask, s32 priority); -extern "C" s32 NWC24SetDlFlags(NWC24DlTask* pTask, u32 flags); -extern "C" s32 NWC24SetDlRetryMargin(NWC24DlTask* pTask, s32 margin); -extern "C" s32 NWC24SetDlUrl(NWC24DlTask* pTask, const char* url); -extern "C" s32 NWC24SetDlFilename(NWC24DlTask* pTask, const char* name); -extern "C" s32 NWC24SetDlCount(NWC24DlTask* pTask, s16 count); -extern "C" s32 NWC24AddDlTask(NWC24DlTask* pTask); -extern "C" s32 NWC24UpdateDlTask(NWC24DlTask* pTask); -extern "C" s32 NWC24CreateDlVf(NWC24DlTask* pTask, u32 size); -extern "C" s32 NWC24iCheckDlTask(NWC24DlTask* pTask); -extern "C" s32 NWC24GetDlLastUpdate(NWC24DlTask* pTask, s64* time); -extern "C" s32 NWC24GetDlNextTime(NWC24DlTask* pTask, s64* time); s32 MapDownloadError(s32 error); s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort); From f6e7040e323630a0a462617193c8708cc8067024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 14:21:05 +0300 Subject: [PATCH 11/15] Channel: merge downloader into WiiConnect24 TU --- config/HAFE/splits.txt | 9 +- configure.py | 1 - src/WiiConnect24.cpp | 840 +++++++++++++++++++++++++++++++++- src/WiiConnect24Download.cpp | 850 ----------------------------------- 4 files changed, 842 insertions(+), 858 deletions(-) delete mode 100644 src/WiiConnect24Download.cpp diff --git a/config/HAFE/splits.txt b/config/HAFE/splits.txt index 38b4acd..b5101c2 100644 --- a/config/HAFE/splits.txt +++ b/config/HAFE/splits.txt @@ -240,14 +240,11 @@ WiiConnect24Lifecycle.cpp: .text start:0x80032610 end:0x800327AC WiiConnect24.cpp: - .text start:0x800327AC end:0x80033C80 - .bss start:0x801D99E0 end:0x801F6B28 - .sbss start:0x80330B78 end:0x80330B98 - -WiiConnect24Download.cpp: - .text start:0x80033C80 end:0x80035B70 + .text start:0x800327AC end:0x80035B70 .data start:0x8019BD08 end:0x8019C189 + .bss start:0x801D99E0 end:0x801F6B28 .sdata start:0x80330170 end:0x80330190 + .sbss start:0x80330B78 end:0x80330B98 WiiConnect24Heap.cpp: .text start:0x80035B70 end:0x80035B8C diff --git a/configure.py b/configure.py index ec01c44..561974b 100755 --- a/configure.py +++ b/configure.py @@ -1102,7 +1102,6 @@ def MatchingFor(*versions): Object(Matching, "WiiConnect24Lifecycle.cpp"), Object(Matching, "WiiConnect24Code.cpp"), Object(Matching, "WiiConnect24.cpp"), - Object(Matching, "WiiConnect24Download.cpp"), Object(Matching, "WiiConnect24Heap.cpp"), Object(Matching, "WeatherUtil.cpp"), Object(Matching, "ChannelMathData.cpp"), diff --git a/src/WiiConnect24.cpp b/src/WiiConnect24.cpp index ea226ac..e416a09 100644 --- a/src/WiiConnect24.cpp +++ b/src/WiiConnect24.cpp @@ -1,9 +1,23 @@ #include #include -#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include + +void* WC24Alloc(u32 unused, s32 size); +void WC24Free(void* unused, void* block, s32 size); +extern "C" s32 SOInit(void* init); +extern "C" s32 SOStartup(); +extern "C" s32 SOGetLastError(); + NWC24Work gNWC24Work; OSMessageQueue gWC24Queue; OSMessage gWC24QueueBuffer[16]; @@ -190,3 +204,827 @@ s32 CWiiConnect24::deleteWeather() { return result; } + +char sVfDriveName[] = "@24"; +char sVfRootPath[] = "@24:/*"; +char sVfReadMode[] = "r"; +char sBinNameFormat[] = "%d.bin"; +char sForecastFileSuffix[] = "%sB"; +char sShortFileSuffix[] = "%sR"; + +s32 MapDownloadError(s32 error); +s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort); +s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, + u16 newInterval, u16 count, u32* idOut); +s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2); +s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort); +s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, + u32* outSize); + +struct WC24IdleMode { + u8 wc24; + u8 slotLight; +}; +// The SDK header declares this as void, but the channel uses the result. +extern "C" BOOL SCGetIdleMode(WC24IdleMode* mode); + +static inline void SetTaskMessage(WC24Task* task, const char* msg, s32 code, s32 result) { + task->mErrorCode = code; + task->mNwc24Result = result; + sprintf(task->mMessage, "%s %d %d", msg, code, result); +} + +// A macro, not an inline: the message literal must reach SetTaskMessage directly. +// Passing it through another inline parameter keeps it live across +// NWC24GetErrorCode() in a callee-saved register, which the original does not do. +#define SetTaskError(task, msg, result) (SetTaskMessage(task, msg, NWC24GetErrorCode(), result), MapDownloadError(result)) + +static inline NWC24Err OpenLib(WC24Task* task, s64 retry) { + NWC24Err error; + + for (;;) { + error = NWC24OpenLib(&gNWC24Work); + + if (error != NWC24_ERR_MUTEX && error != NWC24_ERR_BUSY && + error != NWC24_ERR_INPROGRESS) + break; + + OSSleepTicks(OS_MSEC_TO_TICKS(100 * (retry + 1))); + } + + if (error != NWC24_OK) + return (NWC24Err)SetTaskError(task, "NWC24OpenLib() failed.", error); + + gNWC24LibOpened = 1; + return NWC24_OK; +} + +static inline NWC24Err CheckLib(WC24Task* task) { + NWC24Err error = NWC24Check(2); + + if (error != NWC24_OK) + return (NWC24Err)SetTaskError(task, "NWC24Check() failed.", error); + + WC24IdleMode idle; + if (SCGetIdleMode(&idle) == 0 || idle.wc24 != 1) + return NWC24_ERR_INVALID_VALUE; + + return NWC24_OK; +} + +static inline NWC24Err CloseLib(WC24Task* task) { + NWC24Err error = NWC24CloseLib(); + + if (error != NWC24_OK) + return (NWC24Err)SetTaskError(task, "NWC24CloseLib() failed.", error); + + gNWC24LibOpened = 0; + return NWC24_OK; +} + +void* DownloaderThread(void* unused) { + WC24Task* task; + void* message; + s64 retry = 0; + s32 result; + u8 opened; + s32 attempts; + u8 done; + + for (;;) { + done = FALSE; + OSReceiveMessage(&gWC24Queue, &message, 1); + + task = (WC24Task*)message; + if (task == NULL) + break; + + switch (task->mType) { + case 0: + opened = FALSE; + attempts = 0; + + for (;;) { + task->mState = 2; + task->mResult = OpenLib(task, retry); + if (task->mResult != NWC24_OK) + break; + + opened = TRUE; + + task->mResult = CheckLib(task); + if (task->mResult != NWC24_OK) + break; + + task->mState = 3; + if ((task->mResult = DownloadFiles(task, 1, 1)) == NWC24_OK) + break; + if (task->mResult == NWC24_ERR_FATAL && attempts != 1) { + task->mState = 6; + task->mResult = CreateDownloadTasks(task, 1, 1, 1, 0x1E, 0x3C, 0); + if (task->mResult == NWC24_OK) { + task->mState = 2; + task->mResult = CloseLib(task); + opened = FALSE; + if (task->mResult == NWC24_OK) { + task->mState = 5; + task->mResult = ExecuteDownloadTask(task, 0, 0xFFFFFF, 0xFFFF); + if (task->mResult == NWC24_OK) { + task->mResult = ExecuteDownloadTask(task, 1, 0xFFFFFF, 0xFFFF); + if (task->mResult == NWC24_OK) { + attempts++; + continue; + } + } + } + } + } + break; + } + + if (opened) { + task->mState = 2; + result = CloseLib(task); + if (task->mResult == NWC24_OK) + task->mResult = result; + } + task->mState = 0; + break; + + case 1: + task->mState = 5; + task->mResult = ExecuteDownloadTask(task, 0, 0xFFFFFF, 0xFFFF); + if (task->mResult == NWC24_OK) { + task->mState = 2; + task->mResult = OpenLib(task, retry); + if (task->mResult == NWC24_OK) { + task->mResult = CheckLib(task); + if (task->mResult == NWC24_OK) { + task->mState = 3; + switch (task->mTaskId) { + case 3: + task->mResult = DownloadFiles(task, 1, 0); + break; + case 4: + task->mResult = DownloadFiles(task, 1, 0); + break; + } + } + task->mState = 2; + result = CloseLib(task); + if (task->mResult == NWC24_OK) + task->mResult = result; + } + } + task->mState = 0; + break; + + case 2: + task->mState = 2; + task->mResult = OpenLib(task, retry); + if (task->mResult == NWC24_OK) { + task->mResult = CheckLib(task); + if (task->mResult == NWC24_OK) { + task->mState = 6; + task->mResult = CreateDownloadTasks(task, 1, 1, task->mRedownload, task->mDownloadInterval, + task->mDownloadCount, 0); + } + task->mState = 2; + result = CloseLib(task); + if (task->mResult == NWC24_OK) + task->mResult = result; + } + task->mState = 0; + break; + + case 3: + task->mState = 2; + task->mResult = OpenLib(task, retry); + if (task->mResult == NWC24_OK) { + task->mResult = CheckLib(task); + if (task->mResult == NWC24_OK) { + task->mState = 7; + task->mResult = DeleteTaskFiles(task, 1, 1); + } + task->mState = 2; + result = CloseLib(task); + if (task->mResult == NWC24_OK) + task->mResult = result; + } + task->mState = 0; + break; + + case 4: + done = TRUE; + break; + } + + if (!done) + continue; + break; + } + + return NULL; +} + +s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { + NWC24DlTask dlTasks[2]; + u8 dta[0x448]; + char url[0x100]; + char vfName[0x50]; + char fileName[0x10]; + void* buffers[2]; + s64* times[2]; + u32* sizes[2]; + u16 ids[2]; + u32 outSize; + + s32 error; + BOOL found = FALSE; + + if (doForecast != 0) { + ids[0] = task->mTaskId; + buffers[0] = task->mBuffers.forecast; + times[0] = task->mTimes.forecast; + sizes[0] = task->mSizes.forecast; + } else { + ids[0] = 0; + buffers[0] = NULL; + times[0] = NULL; + sizes[0] = NULL; + } + + if (doShort != 0) { + ids[1] = task->mSubTaskId; + buffers[1] = task->mBuffers.shortForecast; + times[1] = task->mTimes.shortForecast; + sizes[1] = task->mSizes.shortForecast; + } else { + ids[1] = 0; + buffers[1] = NULL; + times[1] = NULL; + sizes[1] = NULL; + } + + // The loops below address the same task through dlTasks and through a + // second pointer to it; the original keeps one induction pointer for each. + NWC24DlTask* urlTask = dlTasks; + for (s32 i = 0; i < 2; i++) { + if (buffers[i] == NULL) + continue; + + error = NWC24GetDlTask(&dlTasks[i], ids[i]); + if (error == -0xD) { + SetTaskMessage(task, "NWC24GetDlTask() failed.", NWC24GetErrorCode(), error); + return -1; + } + + if (error != 0) { + return SetTaskError(task, "NWC24GetDlTask() failed.", error); + } + + error = NWC24GetDlUrl(&urlTask[i], url, 0xFF); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlUrl() failed.", error); + } + + if ((&task->mForecastUrl)[i] != NULL) { + u32 j = 0; + while (j < 0xFF && url[j] != 0) { + if (url[j] != (&task->mForecastUrl)[i][j]) { + SetTaskMessage(task, "URL is not same.", 0, 0); + return -1; + } + + j++; + } + } + } + + for (s32 i = 0; i < 2; i++) { + if (buffers[i] == NULL) + continue; + + error = NWC24GetDlVfName(&dlTasks[i], vfName, 0x50); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlVfName() failed.", error); + } + + error = VFMountDriveNANDFlashEx(sVfDriveName, vfName); + if (error != 0) { + SetTaskMessage(task, "VFMountDriveNANDFlash() failed.", 0, error); + return -1; + } + + s32 searchResult = VFFileSearchFirst(dta, sVfRootPath, 0x7F); + while (searchResult == 0) + searchResult = VFFileSearchNext(dta); + + found = TRUE; + break; + } + + if (!found) + OSPanic("WiiConnect24.cpp", 0x4B1, "VF Load Failed."); + + NWC24DlTask* pTask = dlTasks; + for (s32 i = 0; i < 2; i++) { + if (buffers[i] == NULL) + continue; + + error = NWC24GetDlFilename(&dlTasks[i], fileName, 0x10); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlFilename() failed.", error); + } + + void* file = VFOpenFile(fileName, sVfReadMode, 0); + if (file == NULL) { + SetTaskMessage(task, "VFOpenFile() failed.", NWC24GetErrorCode(), 0); + + error = VFUnmountDrive(sVfDriveName); + if (error != 0) { + SetTaskMessage(task, "VFUnmountDrive() failed.", 0, error); + return -7; + } + return -1; + } + + error = ReadCompressedFile(task, file, buffers[i], task->mBufferSizes[i], &outSize); + if (error != 0) + return error; + + *sizes[i] = outSize; + + // Pads the size to a multiple of 4, but writes into the task itself + // rather than into the downloaded buffer. + char* p; + u32 size = outSize; + p = (char*)&task->mBuffers + size; + while (size < ((outSize + 3) & ~3)) { + *p++ = 0; + size++; + } + + error = VFCloseFile(file); + if (error != 0) { + SetTaskMessage(task, "VFCloseFile() failed.", 0, error); + VFUnmountDrive(sVfDriveName); + return -7; + } + + error = NWC24GetDlLastUpdate(&dlTasks[i], times[i]); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlLastUpdate() failed.", error); + } + + error = NWC24GetDlNextTime(&pTask[i], &task->mNextDownloadTimes[i]); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlNextTime() failed.", error); + } + } + + error = VFUnmountDrive(sVfDriveName); + if (error != 0) { + SetTaskMessage(task, "VFUnmoundDrive() failed.", 0, error); + return -7; + } + + return 0; +} + +s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, + u16 newInterval, u16 count, u32* idOut) { + NWC24DlTask dlTasks[2]; + u8 search[0x448]; + char url[0x100]; + char vfName[0x50]; + char vfName2[0x50]; + char fileName[0x10]; + char nameBuf[0x10]; + const char* urls[2]; + u16 ids[2]; + u16 interval; + + s32 error; + BOOL redo = redownload; + BOOL init = redownload; + BOOL mounted = FALSE; + + if (doForecast != 0) { + ids[0] = task->mTaskId; + urls[0] = task->mForecastUrl; + } else { + ids[0] = 0; + urls[0] = NULL; + } + + if (doShort != 0) { + ids[1] = task->mSubTaskId; + urls[1] = task->mShortUrl; + } else { + ids[1] = 0; + urls[1] = NULL; + } + + NWC24DlTask* pTask = dlTasks; + for (s32 i = 0; i < 2; i++) { + if (ids[i] == 0) + continue; + + if (redo != 0) + goto firstDone; + + error = NWC24GetDlTask(&dlTasks[i], ids[i]); + if (error == -0xD) { + redo = TRUE; + init = TRUE; + goto firstDone; + } + + if (error != 0) + return SetTaskError(task, "NWC24GetDlTask() failed.", error); + + error = NWC24GetDlVfName(&pTask[i], vfName, 0x50); + if (error != 0) + return SetTaskError(task, "NWC24GetDlVfName() failed.", error); + + if (!mounted) { + error = VFMountDriveNANDFlashEx(sVfDriveName, vfName); + if (error == 2 || error == 0xB001) { + redo = TRUE; + init = TRUE; + goto firstDone; + } + + if (error != 0) { + SetTaskMessage(task, "VFMountDriveNANDFlash() failed.", 0, error); + return -7; + } + + mounted = TRUE; + s32 searchResult = VFFileSearchFirst(search, sVfRootPath, 0x7F); + while (searchResult == 0) + searchResult = VFFileSearchNext(search); + } + + if (!mounted) + continue; + + switch (ids[i]) { + case 3: + case 4: { + error = NWC24GetDlFilename(&pTask[i], fileName, 0x10); + if (error != 0) + return SetTaskError(task, "NWC24GetDlFilename() failed.", error); + + void* file = VFOpenFile(fileName, sVfReadMode, 0); + if (file == NULL) { + redo = TRUE; + init = TRUE; + continue; + } + + error = VFCloseFile(file); + if (error != 0) { + SetTaskMessage(task, "VFCloseFile() failed.", 0, error); + VFUnmountDrive(sVfDriveName); + return -7; + } + break; + } + } + } + +firstDone: + if (mounted) { + error = VFUnmountDrive(sVfDriveName); + if (error != 0) { + SetTaskMessage(task, "VFUnmountDrive() failed.", 0, error); + return -7; + } + } + + if (!redo) { + for (s32 i = 0; i < 2; i++) { + if (ids[i] == 0) + continue; + + error = NWC24GetDlUrl(&dlTasks[i], url, 0xFF); + if (error != 0) + return SetTaskError(task, "NWC24GetDlUrl() failed.", error); + + const char* p = url; + u32 j = 0; + while (j < 0xFF && *p != 0) { + if (*p != urls[i][j]) { + redo = TRUE; + init = TRUE; + break; + } + p++; + j++; + } + + error = NWC24GetDlInterval(&dlTasks[i], &interval); + if (error != 0) + return SetTaskError(task, "NWC24GetDlInterval() failed.", error); + + if (newInterval != interval) + redo = TRUE; + } + } + + if (redo) { + BOOL created = FALSE; + NWC24DlTask* pTask2 = dlTasks; + + for (s32 i = 0; i < 2; i++) { + if (ids[i] == 0) + continue; + + if (init) { + error = NWC24InitDlTask(&dlTasks[i], 1); + if (error != 0) + return SetTaskError(task, "NWC24InitDlTask() failed.", error); + + error = NWC24SetDlId(&dlTasks[i], ids[i]); + if (error != 0) + return SetTaskError(task, "NWC24SetDlId() failed.", error); + + error = NWC24GetDlVfName(&pTask2[i], vfName2, 0x50); + if (error != 0) + return SetTaskError(task, "NWC24GetDlVfName() failed.", error); + + if (!created) { + error = NANDDelete(vfName2); + if (error != -0xC && error != 0) { + SetTaskMessage(task, "NANDDelete() failed.", 0, error); + return -8; + } + + error = NWC24CreateDlVf(&pTask2[i], task->mForecastBufferSize); + if (error != 0) + return SetTaskError(task, "NWC24CreateDlVf() failed.", error); + + created = TRUE; + } + } + + error = NWC24SetDlUrl(&dlTasks[i], urls[i]); + if (error != 0) + return SetTaskError(task, "NWC24SetDlUrl() failed.", error); + + s32 priority; + s32 margin; + switch (ids[i]) { + case 3: + priority = 100; + margin = 0x2D0; + break; + case 4: + priority = 100; + margin = 0x2D0; + break; + } + + error = NWC24SetDlPriority(&dlTasks[i], priority); + if (error != 0) + return SetTaskError(task, "NWC24SetDlPriority() failed.", error); + + error = NWC24SetDlFlags(&dlTasks[i], 0x40000000); + if (error != 0) + return SetTaskError(task, "NWC24SetDlFlags() failed.", error); + + error = NWC24SetDlInterval(&dlTasks[i], newInterval); + if (error != 0) + return SetTaskError(task, "NWC24SetDlInterval() failed.", error); + + error = NWC24SetDlRetryMargin(&dlTasks[i], margin); + if (error != 0) + return SetTaskError(task, "NWC24SetDlRetryMargin() failed.", error); + + sprintf(nameBuf, sBinNameFormat, ids[i]); + error = NWC24SetDlFilename(&dlTasks[i], nameBuf); + if (error != 0) + return SetTaskError(task, "NWC24SetDlFilename() failed.", error); + } + } + + NWC24DlTask* pTask3 = dlTasks; + for (s32 i = 0; i < 2; i++) { + if (ids[i] == 0) + continue; + + error = NWC24SetDlCount(&dlTasks[i], (s16)count); + if (error != 0) + return SetTaskError(task, "NWC24SetDlCount() failed.", error); + + if (redo) { + error = NWC24AddDlTask(&dlTasks[i]); + if (error != 0) + return SetTaskError(task, "NWC24AddDlTask() failed.", error); + } else { + error = NWC24UpdateDlTask(&dlTasks[i]); + if (error != 0) + return SetTaskError(task, "NWC24UpdateDlTask() failed.", error); + } + + if (idOut != NULL) { + error = NWC24GetDlId(&pTask3[i], idOut); + if (error != 0) + return SetTaskError(task, "NWC24GetDlId() failed.", error); + } + + NWC24iCheckDlTask(&pTask3[i]); + } + + gWC24DownloadComplete = 1; + return 0; +} + +struct WC24SOConfig { + void* alloc; + void* free; +}; + +s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2) { + s32 initResult; + s32 startupResult; + s32 error; + s32 taskId; + WC24SOConfig config; + + taskId = (&task->mTaskId)[index]; + + if (!gWC24NetInitialized) { + gWC24ShutdownFlag2 = 1; + config.alloc = (void*)WC24Alloc; + config.free = (void*)WC24Free; + + initResult = SOInit(&config); + if (initResult < 0) { + SetTaskMessage(task, "SOInit() failed.", 0, initResult); + gWC24ShutdownFlag2 = 0; + return -9; + } + + startupResult = SOStartup(); + if (startupResult < 0) { + SetTaskMessage(task, "SOStartup() failed.", SOGetLastError(), startupResult); + gWC24ShutdownFlag2 = 0; + return -9; + } + + gWC24NetInitialized = 1; + gWC24ShutdownFlag2 = 0; + } + + switch (taskId) { + case 3: + case 4: + gWC24ShutdownFlag1 = 1; + error = NWC24ExecDownloadTask(2, taskId, 0); + gWC24ShutdownFlag1 = 0; + + if (error != 0) { + SetTaskMessage(task, "NWC24ExecDownloadTask() failed.", NWC24GetErrorCode(), error); + return MapDownloadError(error); + } + break; + } + return 0; +} + +s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort) { + NWC24DlTask dlTask; + char vfName[0x50]; + u16 ids[2]; + u8 found; + + found = FALSE; + + if (doForecast != 0) + ids[0] = task->mTaskId; + else + ids[0] = 0; + + if (doShort != 0) + ids[1] = task->mSubTaskId; + else + ids[1] = 0; + + for (s32 i = 0; i < 2; i++) { + if (ids[i] == 0) + continue; + + s32 error = NWC24GetDlTask(&dlTask, ids[i]); + if (error == -0xD) + continue; + + if (error != 0) { + return SetTaskError(task, "NWC24GetDl*() failed.", error); + } + + if (!found) { + found = TRUE; + error = NWC24GetDlVfName(&dlTask, vfName, 0x50); + if (error != 0) { + return SetTaskError(task, "NWC24GetDlVfName() failed.", error); + } + } + + error = NWC24DeleteDlTask(&dlTask); + if (error != 0) { + return SetTaskError(task, "NWC24DeleteDlTask() failed.", error); + } + } + + if (found) { + s32 error = NANDDelete(vfName); + if (error != -0xC && error != 0) { + SetTaskMessage(task, "NANDDelete() failed.", 0, error); + return -8; + } + } + + return 0; +} + +s32 MapDownloadError(s32 error) { + s32 mapped = -6; + + if ((error <= -0x10 && error >= -0x15) || error == -0x26 || error == -0x29 || error == -0x2B || + error == -0x2E) { + mapped = -0xB; + } else if (error == -0x31) { + mapped = -0xC; + } else if (error == -1 || error == -0xB || error == -0x2A) { + mapped = -2; + } else if ((u32)(NWC24GetErrorCode() + 0x20000) == 0x55CE) { + mapped = -5; + } else { + switch (error) { + case -0x27: + mapped = -3; + break; + + case -0x1F: + mapped = -4; + break; + + case -0x20: + mapped = -5; + break; + } + } + + return mapped; +} + +s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, + u32* outSize) { + u32 fileSize = VFGetFileSizeByFd(fd); + u32 uncompSize = 0; + CXUncompContextLZ ctx; + + CXInitUncompContextLZ(&ctx, dest); + + u32 offset = 0; + while (offset < fileSize) { + u32 chunk = fileSize - offset; + if (chunk > 0x10000) + chunk = 0x10000; + + s32 error = VFReadFile(fd, gWC24FileBuffer, chunk, NULL); + if (error != 0) { + SetTaskMessage(task, "VFReadFile() failed.", 0, error); + return -7; + } + + if (offset == 0) { + if ((gWC24FileBuffer[0] & 0xF0) != 0x10) { + SetTaskMessage(task, "CXGetCompressionType() data is not LZ.", 0, 0); + return -5; + } + + uncompSize = CXGetUncompressedSize(gWC24FileBuffer); + if (uncompSize > destSize) { + SetTaskMessage(task, "CXGetUncompressedSize() overflow.", 0, 0); + return -5; + } + } + + CXReadUncompLZ(&ctx, gWC24FileBuffer, chunk); + offset += 0x10000; + } + + // Equivalent to !CXIsFinishedUncompLZ(&ctx). + BOOL notFinished = ctx.destCount > 0 || ctx.headerSize > 0; + if (notFinished) { + SetTaskMessage(task, "CXIsFinisiedUncompLZ() is false.", 0, 0); + return -0xA; + } + + *outSize = uncompSize; + return 0; +} diff --git a/src/WiiConnect24Download.cpp b/src/WiiConnect24Download.cpp deleted file mode 100644 index 3156bd7..0000000 --- a/src/WiiConnect24Download.cpp +++ /dev/null @@ -1,850 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern OSMessageQueue gWC24Queue; -extern u8 gWC24FileBuffer[]; -extern volatile u8 gWC24DownloadComplete; -extern volatile u8 gWC24NetInitialized; -extern volatile u8 gWC24ShutdownFlag1; -extern volatile u8 gWC24ShutdownFlag2; -void* WC24Alloc(u32 unused, s32 size); -void WC24Free(void* unused, void* block, s32 size); -extern "C" s32 SOInit(void* init); -extern "C" s32 SOStartup(); -extern "C" s32 SOGetLastError(); -extern NWC24Work gNWC24Work; -extern volatile u8 gNWC24LibOpened; - -char sVfDriveName[] = "@24"; -char sVfRootPath[] = "@24:/*"; -char sVfReadMode[] = "r"; -char sBinNameFormat[] = "%d.bin"; -char sForecastFileSuffix[] = "%sB"; -char sShortFileSuffix[] = "%sR"; - - -s32 MapDownloadError(s32 error); -s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort); -s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, - u16 newInterval, u16 count, u32* idOut); -s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2); -s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort); -s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, - u32* outSize); - -struct WC24IdleMode { - u8 wc24; - u8 slotLight; -}; -// The SDK header declares this as void, but the channel uses the result. -extern "C" BOOL SCGetIdleMode(WC24IdleMode* mode); - -static inline void SetTaskMessage(WC24Task* task, const char* msg, s32 code, s32 result) { - task->mErrorCode = code; - task->mNwc24Result = result; - sprintf(task->mMessage, "%s %d %d", msg, code, result); -} - -// A macro, not an inline: the message literal must reach SetTaskMessage directly. -// Passing it through another inline parameter keeps it live across -// NWC24GetErrorCode() in a callee-saved register, which the original does not do. -#define SetTaskError(task, msg, result) (SetTaskMessage(task, msg, NWC24GetErrorCode(), result), MapDownloadError(result)) - -static inline NWC24Err OpenLib(WC24Task* task, s64 retry) { - NWC24Err error; - - for (;;) { - error = NWC24OpenLib(&gNWC24Work); - - if (error != NWC24_ERR_MUTEX && error != NWC24_ERR_BUSY && - error != NWC24_ERR_INPROGRESS) - break; - - OSSleepTicks(OS_MSEC_TO_TICKS(100 * (retry + 1))); - } - - if (error != NWC24_OK) - return (NWC24Err)SetTaskError(task, "NWC24OpenLib() failed.", error); - - gNWC24LibOpened = 1; - return NWC24_OK; -} - -static inline NWC24Err CheckLib(WC24Task* task) { - NWC24Err error = NWC24Check(2); - - if (error != NWC24_OK) - return (NWC24Err)SetTaskError(task, "NWC24Check() failed.", error); - - WC24IdleMode idle; - if (SCGetIdleMode(&idle) == 0 || idle.wc24 != 1) - return NWC24_ERR_INVALID_VALUE; - - return NWC24_OK; -} - -static inline NWC24Err CloseLib(WC24Task* task) { - NWC24Err error = NWC24CloseLib(); - - if (error != NWC24_OK) - return (NWC24Err)SetTaskError(task, "NWC24CloseLib() failed.", error); - - gNWC24LibOpened = 0; - return NWC24_OK; -} - -void* DownloaderThread(void* unused) { - WC24Task* task; - void* message; - s64 retry = 0; - s32 result; - u8 opened; - s32 attempts; - u8 done; - - for (;;) { - done = FALSE; - OSReceiveMessage(&gWC24Queue, &message, 1); - - task = (WC24Task*)message; - if (task == NULL) - break; - - switch (task->mType) { - case 0: - opened = FALSE; - attempts = 0; - - for (;;) { - task->mState = 2; - task->mResult = OpenLib(task, retry); - if (task->mResult != NWC24_OK) - break; - - opened = TRUE; - - task->mResult = CheckLib(task); - if (task->mResult != NWC24_OK) - break; - - task->mState = 3; - if ((task->mResult = DownloadFiles(task, 1, 1)) == NWC24_OK) - break; - if (task->mResult == NWC24_ERR_FATAL && attempts != 1) { - task->mState = 6; - task->mResult = CreateDownloadTasks(task, 1, 1, 1, 0x1E, 0x3C, 0); - if (task->mResult == NWC24_OK) { - task->mState = 2; - task->mResult = CloseLib(task); - opened = FALSE; - if (task->mResult == NWC24_OK) { - task->mState = 5; - task->mResult = ExecuteDownloadTask(task, 0, 0xFFFFFF, 0xFFFF); - if (task->mResult == NWC24_OK) { - task->mResult = ExecuteDownloadTask(task, 1, 0xFFFFFF, 0xFFFF); - if (task->mResult == NWC24_OK) { - attempts++; - continue; - } - } - } - } - } - break; - } - - if (opened) { - task->mState = 2; - result = CloseLib(task); - if (task->mResult == NWC24_OK) - task->mResult = result; - } - task->mState = 0; - break; - - case 1: - task->mState = 5; - task->mResult = ExecuteDownloadTask(task, 0, 0xFFFFFF, 0xFFFF); - if (task->mResult == NWC24_OK) { - task->mState = 2; - task->mResult = OpenLib(task, retry); - if (task->mResult == NWC24_OK) { - task->mResult = CheckLib(task); - if (task->mResult == NWC24_OK) { - task->mState = 3; - switch (task->mTaskId) { - case 3: - task->mResult = DownloadFiles(task, 1, 0); - break; - case 4: - task->mResult = DownloadFiles(task, 1, 0); - break; - } - } - task->mState = 2; - result = CloseLib(task); - if (task->mResult == NWC24_OK) - task->mResult = result; - } - } - task->mState = 0; - break; - - case 2: - task->mState = 2; - task->mResult = OpenLib(task, retry); - if (task->mResult == NWC24_OK) { - task->mResult = CheckLib(task); - if (task->mResult == NWC24_OK) { - task->mState = 6; - task->mResult = CreateDownloadTasks(task, 1, 1, task->mRedownload, task->mDownloadInterval, - task->mDownloadCount, 0); - } - task->mState = 2; - result = CloseLib(task); - if (task->mResult == NWC24_OK) - task->mResult = result; - } - task->mState = 0; - break; - - case 3: - task->mState = 2; - task->mResult = OpenLib(task, retry); - if (task->mResult == NWC24_OK) { - task->mResult = CheckLib(task); - if (task->mResult == NWC24_OK) { - task->mState = 7; - task->mResult = DeleteTaskFiles(task, 1, 1); - } - task->mState = 2; - result = CloseLib(task); - if (task->mResult == NWC24_OK) - task->mResult = result; - } - task->mState = 0; - break; - - case 4: - done = TRUE; - break; - } - - if (!done) - continue; - break; - } - - return NULL; -} - -s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { - NWC24DlTask dlTasks[2]; - u8 dta[0x448]; - char url[0x100]; - char vfName[0x50]; - char fileName[0x10]; - void* buffers[2]; - s64* times[2]; - u32* sizes[2]; - u16 ids[2]; - u32 outSize; - - s32 error; - BOOL found = FALSE; - - if (doForecast != 0) { - ids[0] = task->mTaskId; - buffers[0] = task->mBuffers.forecast; - times[0] = task->mTimes.forecast; - sizes[0] = task->mSizes.forecast; - } else { - ids[0] = 0; - buffers[0] = NULL; - times[0] = NULL; - sizes[0] = NULL; - } - - if (doShort != 0) { - ids[1] = task->mSubTaskId; - buffers[1] = task->mBuffers.shortForecast; - times[1] = task->mTimes.shortForecast; - sizes[1] = task->mSizes.shortForecast; - } else { - ids[1] = 0; - buffers[1] = NULL; - times[1] = NULL; - sizes[1] = NULL; - } - - // The loops below address the same task through dlTasks and through a - // second pointer to it; the original keeps one induction pointer for each. - NWC24DlTask* urlTask = dlTasks; - for (s32 i = 0; i < 2; i++) { - if (buffers[i] == NULL) - continue; - - error = NWC24GetDlTask(&dlTasks[i], ids[i]); - if (error == -0xD) { - SetTaskMessage(task, "NWC24GetDlTask() failed.", NWC24GetErrorCode(), error); - return -1; - } - - if (error != 0) { - return SetTaskError(task, "NWC24GetDlTask() failed.", error); - } - - error = NWC24GetDlUrl(&urlTask[i], url, 0xFF); - if (error != 0) { - return SetTaskError(task, "NWC24GetDlUrl() failed.", error); - } - - if ((&task->mForecastUrl)[i] != NULL) { - u32 j = 0; - while (j < 0xFF && url[j] != 0) { - if (url[j] != (&task->mForecastUrl)[i][j]) { - SetTaskMessage(task, "URL is not same.", 0, 0); - return -1; - } - - j++; - } - } - } - - for (s32 i = 0; i < 2; i++) { - if (buffers[i] == NULL) - continue; - - error = NWC24GetDlVfName(&dlTasks[i], vfName, 0x50); - if (error != 0) { - return SetTaskError(task, "NWC24GetDlVfName() failed.", error); - } - - error = VFMountDriveNANDFlashEx(sVfDriveName, vfName); - if (error != 0) { - SetTaskMessage(task, "VFMountDriveNANDFlash() failed.", 0, error); - return -1; - } - - s32 searchResult = VFFileSearchFirst(dta, sVfRootPath, 0x7F); - while (searchResult == 0) - searchResult = VFFileSearchNext(dta); - - found = TRUE; - break; - } - - if (!found) - OSPanic("WiiConnect24.cpp", 0x4B1, "VF Load Failed."); - - NWC24DlTask* pTask = dlTasks; - for (s32 i = 0; i < 2; i++) { - if (buffers[i] == NULL) - continue; - - error = NWC24GetDlFilename(&dlTasks[i], fileName, 0x10); - if (error != 0) { - return SetTaskError(task, "NWC24GetDlFilename() failed.", error); - } - - void* file = VFOpenFile(fileName, sVfReadMode, 0); - if (file == NULL) { - SetTaskMessage(task, "VFOpenFile() failed.", NWC24GetErrorCode(), 0); - - error = VFUnmountDrive(sVfDriveName); - if (error != 0) { - SetTaskMessage(task, "VFUnmountDrive() failed.", 0, error); - return -7; - } - return -1; - } - - error = ReadCompressedFile(task, file, buffers[i], task->mBufferSizes[i], &outSize); - if (error != 0) - return error; - - *sizes[i] = outSize; - - // Pads the size to a multiple of 4, but writes into the task itself - // rather than into the downloaded buffer. - char* p; - u32 size = outSize; - p = (char*)&task->mBuffers + size; - while (size < ((outSize + 3) & ~3)) { - *p++ = 0; - size++; - } - - error = VFCloseFile(file); - if (error != 0) { - SetTaskMessage(task, "VFCloseFile() failed.", 0, error); - VFUnmountDrive(sVfDriveName); - return -7; - } - - error = NWC24GetDlLastUpdate(&dlTasks[i], times[i]); - if (error != 0) { - return SetTaskError(task, "NWC24GetDlLastUpdate() failed.", error); - } - - error = NWC24GetDlNextTime(&pTask[i], &task->mNextDownloadTimes[i]); - if (error != 0) { - return SetTaskError(task, "NWC24GetDlNextTime() failed.", error); - } - } - - error = VFUnmountDrive(sVfDriveName); - if (error != 0) { - SetTaskMessage(task, "VFUnmoundDrive() failed.", 0, error); - return -7; - } - - return 0; -} - -s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, - u16 newInterval, u16 count, u32* idOut) { - NWC24DlTask dlTasks[2]; - u8 search[0x448]; - char url[0x100]; - char vfName[0x50]; - char vfName2[0x50]; - char fileName[0x10]; - char nameBuf[0x10]; - const char* urls[2]; - u16 ids[2]; - u16 interval; - - s32 error; - BOOL redo = redownload; - BOOL init = redownload; - BOOL mounted = FALSE; - - if (doForecast != 0) { - ids[0] = task->mTaskId; - urls[0] = task->mForecastUrl; - } else { - ids[0] = 0; - urls[0] = NULL; - } - - if (doShort != 0) { - ids[1] = task->mSubTaskId; - urls[1] = task->mShortUrl; - } else { - ids[1] = 0; - urls[1] = NULL; - } - - NWC24DlTask* pTask = dlTasks; - for (s32 i = 0; i < 2; i++) { - if (ids[i] == 0) - continue; - - if (redo != 0) - goto firstDone; - - error = NWC24GetDlTask(&dlTasks[i], ids[i]); - if (error == -0xD) { - redo = TRUE; - init = TRUE; - goto firstDone; - } - - if (error != 0) - return SetTaskError(task, "NWC24GetDlTask() failed.", error); - - error = NWC24GetDlVfName(&pTask[i], vfName, 0x50); - if (error != 0) - return SetTaskError(task, "NWC24GetDlVfName() failed.", error); - - if (!mounted) { - error = VFMountDriveNANDFlashEx(sVfDriveName, vfName); - if (error == 2 || error == 0xB001) { - redo = TRUE; - init = TRUE; - goto firstDone; - } - - if (error != 0) { - SetTaskMessage(task, "VFMountDriveNANDFlash() failed.", 0, error); - return -7; - } - - mounted = TRUE; - s32 searchResult = VFFileSearchFirst(search, sVfRootPath, 0x7F); - while (searchResult == 0) - searchResult = VFFileSearchNext(search); - } - - if (!mounted) - continue; - - switch (ids[i]) { - case 3: - case 4: { - error = NWC24GetDlFilename(&pTask[i], fileName, 0x10); - if (error != 0) - return SetTaskError(task, "NWC24GetDlFilename() failed.", error); - - void* file = VFOpenFile(fileName, sVfReadMode, 0); - if (file == NULL) { - redo = TRUE; - init = TRUE; - continue; - } - - error = VFCloseFile(file); - if (error != 0) { - SetTaskMessage(task, "VFCloseFile() failed.", 0, error); - VFUnmountDrive(sVfDriveName); - return -7; - } - break; - } - } - } - -firstDone: - if (mounted) { - error = VFUnmountDrive(sVfDriveName); - if (error != 0) { - SetTaskMessage(task, "VFUnmountDrive() failed.", 0, error); - return -7; - } - } - - if (!redo) { - for (s32 i = 0; i < 2; i++) { - if (ids[i] == 0) - continue; - - error = NWC24GetDlUrl(&dlTasks[i], url, 0xFF); - if (error != 0) - return SetTaskError(task, "NWC24GetDlUrl() failed.", error); - - const char* p = url; - u32 j = 0; - while (j < 0xFF && *p != 0) { - if (*p != urls[i][j]) { - redo = TRUE; - init = TRUE; - break; - } - p++; - j++; - } - - error = NWC24GetDlInterval(&dlTasks[i], &interval); - if (error != 0) - return SetTaskError(task, "NWC24GetDlInterval() failed.", error); - - if (newInterval != interval) - redo = TRUE; - } - } - - if (redo) { - BOOL created = FALSE; - NWC24DlTask* pTask2 = dlTasks; - - for (s32 i = 0; i < 2; i++) { - if (ids[i] == 0) - continue; - - if (init) { - error = NWC24InitDlTask(&dlTasks[i], 1); - if (error != 0) - return SetTaskError(task, "NWC24InitDlTask() failed.", error); - - error = NWC24SetDlId(&dlTasks[i], ids[i]); - if (error != 0) - return SetTaskError(task, "NWC24SetDlId() failed.", error); - - error = NWC24GetDlVfName(&pTask2[i], vfName2, 0x50); - if (error != 0) - return SetTaskError(task, "NWC24GetDlVfName() failed.", error); - - if (!created) { - error = NANDDelete(vfName2); - if (error != -0xC && error != 0) { - SetTaskMessage(task, "NANDDelete() failed.", 0, error); - return -8; - } - - error = NWC24CreateDlVf(&pTask2[i], task->mForecastBufferSize); - if (error != 0) - return SetTaskError(task, "NWC24CreateDlVf() failed.", error); - - created = TRUE; - } - } - - error = NWC24SetDlUrl(&dlTasks[i], urls[i]); - if (error != 0) - return SetTaskError(task, "NWC24SetDlUrl() failed.", error); - - s32 priority; - s32 margin; - switch (ids[i]) { - case 3: - priority = 100; - margin = 0x2D0; - break; - case 4: - priority = 100; - margin = 0x2D0; - break; - } - - error = NWC24SetDlPriority(&dlTasks[i], priority); - if (error != 0) - return SetTaskError(task, "NWC24SetDlPriority() failed.", error); - - error = NWC24SetDlFlags(&dlTasks[i], 0x40000000); - if (error != 0) - return SetTaskError(task, "NWC24SetDlFlags() failed.", error); - - error = NWC24SetDlInterval(&dlTasks[i], newInterval); - if (error != 0) - return SetTaskError(task, "NWC24SetDlInterval() failed.", error); - - error = NWC24SetDlRetryMargin(&dlTasks[i], margin); - if (error != 0) - return SetTaskError(task, "NWC24SetDlRetryMargin() failed.", error); - - sprintf(nameBuf, sBinNameFormat, ids[i]); - error = NWC24SetDlFilename(&dlTasks[i], nameBuf); - if (error != 0) - return SetTaskError(task, "NWC24SetDlFilename() failed.", error); - } - } - - NWC24DlTask* pTask3 = dlTasks; - for (s32 i = 0; i < 2; i++) { - if (ids[i] == 0) - continue; - - error = NWC24SetDlCount(&dlTasks[i], (s16)count); - if (error != 0) - return SetTaskError(task, "NWC24SetDlCount() failed.", error); - - if (redo) { - error = NWC24AddDlTask(&dlTasks[i]); - if (error != 0) - return SetTaskError(task, "NWC24AddDlTask() failed.", error); - } else { - error = NWC24UpdateDlTask(&dlTasks[i]); - if (error != 0) - return SetTaskError(task, "NWC24UpdateDlTask() failed.", error); - } - - if (idOut != NULL) { - error = NWC24GetDlId(&pTask3[i], idOut); - if (error != 0) - return SetTaskError(task, "NWC24GetDlId() failed.", error); - } - - NWC24iCheckDlTask(&pTask3[i]); - } - - gWC24DownloadComplete = 1; - return 0; -} - -struct WC24SOConfig { - void* alloc; - void* free; -}; - -s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2) { - s32 initResult; - s32 startupResult; - s32 error; - s32 taskId; - WC24SOConfig config; - - taskId = (&task->mTaskId)[index]; - - if (!gWC24NetInitialized) { - gWC24ShutdownFlag2 = 1; - config.alloc = (void*)WC24Alloc; - config.free = (void*)WC24Free; - - initResult = SOInit(&config); - if (initResult < 0) { - SetTaskMessage(task, "SOInit() failed.", 0, initResult); - gWC24ShutdownFlag2 = 0; - return -9; - } - - startupResult = SOStartup(); - if (startupResult < 0) { - SetTaskMessage(task, "SOStartup() failed.", SOGetLastError(), startupResult); - gWC24ShutdownFlag2 = 0; - return -9; - } - - gWC24NetInitialized = 1; - gWC24ShutdownFlag2 = 0; - } - - switch (taskId) { - case 3: - case 4: - gWC24ShutdownFlag1 = 1; - error = NWC24ExecDownloadTask(2, taskId, 0); - gWC24ShutdownFlag1 = 0; - - if (error != 0) { - SetTaskMessage(task, "NWC24ExecDownloadTask() failed.", NWC24GetErrorCode(), error); - return MapDownloadError(error); - } - break; - } - return 0; -} - -s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort) { - NWC24DlTask dlTask; - char vfName[0x50]; - u16 ids[2]; - u8 found; - - found = FALSE; - - if (doForecast != 0) - ids[0] = task->mTaskId; - else - ids[0] = 0; - - if (doShort != 0) - ids[1] = task->mSubTaskId; - else - ids[1] = 0; - - for (s32 i = 0; i < 2; i++) { - if (ids[i] == 0) - continue; - - s32 error = NWC24GetDlTask(&dlTask, ids[i]); - if (error == -0xD) - continue; - - if (error != 0) { - return SetTaskError(task, "NWC24GetDl*() failed.", error); - } - - if (!found) { - found = TRUE; - error = NWC24GetDlVfName(&dlTask, vfName, 0x50); - if (error != 0) { - return SetTaskError(task, "NWC24GetDlVfName() failed.", error); - } - } - - error = NWC24DeleteDlTask(&dlTask); - if (error != 0) { - return SetTaskError(task, "NWC24DeleteDlTask() failed.", error); - } - } - - if (found) { - s32 error = NANDDelete(vfName); - if (error != -0xC && error != 0) { - SetTaskMessage(task, "NANDDelete() failed.", 0, error); - return -8; - } - } - - return 0; -} - -s32 MapDownloadError(s32 error) { - s32 mapped = -6; - - if ((error <= -0x10 && error >= -0x15) || error == -0x26 || error == -0x29 || error == -0x2B || - error == -0x2E) { - mapped = -0xB; - } else if (error == -0x31) { - mapped = -0xC; - } else if (error == -1 || error == -0xB || error == -0x2A) { - mapped = -2; - } else if ((u32)(NWC24GetErrorCode() + 0x20000) == 0x55CE) { - mapped = -5; - } else { - switch (error) { - case -0x27: - mapped = -3; - break; - - case -0x1F: - mapped = -4; - break; - - case -0x20: - mapped = -5; - break; - } - } - - return mapped; -} - -s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, - u32* outSize) { - u32 fileSize = VFGetFileSizeByFd(fd); - u32 uncompSize = 0; - CXUncompContextLZ ctx; - - CXInitUncompContextLZ(&ctx, dest); - - u32 offset = 0; - while (offset < fileSize) { - u32 chunk = fileSize - offset; - if (chunk > 0x10000) - chunk = 0x10000; - - s32 error = VFReadFile(fd, gWC24FileBuffer, chunk, NULL); - if (error != 0) { - SetTaskMessage(task, "VFReadFile() failed.", 0, error); - return -7; - } - - if (offset == 0) { - if ((gWC24FileBuffer[0] & 0xF0) != 0x10) { - SetTaskMessage(task, "CXGetCompressionType() data is not LZ.", 0, 0); - return -5; - } - - uncompSize = CXGetUncompressedSize(gWC24FileBuffer); - if (uncompSize > destSize) { - SetTaskMessage(task, "CXGetUncompressedSize() overflow.", 0, 0); - return -5; - } - } - - CXReadUncompLZ(&ctx, gWC24FileBuffer, chunk); - offset += 0x10000; - } - - // Equivalent to !CXIsFinishedUncompLZ(&ctx). - BOOL notFinished = ctx.destCount > 0 || ctx.headerSize > 0; - if (notFinished) { - SetTaskMessage(task, "CXIsFinisiedUncompLZ() is false.", 0, 0); - return -0xA; - } - - *outSize = uncompSize; - return 0; -} From b3105535a08d7e804198629e25d3fd64b370d054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 14:29:39 +0300 Subject: [PATCH 12/15] Channel: align WiiConnect24 local symbol table --- config/HAFE/symbols.txt | 86 +++++++++++++++++++++-------------------- src/WiiConnect24.cpp | 2 + 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/config/HAFE/symbols.txt b/config/HAFE/symbols.txt index 27bbe9d..3d83304 100644 --- a/config/HAFE/symbols.txt +++ b/config/HAFE/symbols.txt @@ -6729,48 +6729,48 @@ lbl_8019BC98 = .data:0x8019BC98; // type:object size:0x1C data:wstring lbl_8019BCB4 = .data:0x8019BCB4; // type:object size:0x1A data:wstring lbl_8019BCD0 = .data:0x8019BCD0; // type:object size:0x1A data:wstring gLastUpdatedPrefixes = .data:0x8019BCEC; // type:object size:0x1C -@2291 = .data:0x8019BD08; // type:object size:0x17 scope:local data:string -@2292 = .data:0x8019BD20; // type:object size:0x9 scope:local align:4 data:string -@2293 = .data:0x8019BD2C; // type:object size:0x15 scope:local align:4 data:string -@2294 = .data:0x8019BD48; // type:object size:0x18 scope:local align:8 data:string -@2476 = .data:0x8019BD60; // type:object size:0x19 scope:local data:string -@2477 = .data:0x8019BD80; // type:object size:0x18 scope:local align:8 data:string -@2478 = .data:0x8019BD98; // type:object size:0x11 scope:local data:string -@2479 = .data:0x8019BDAC; // type:object size:0x1B scope:local align:4 data:string -@2480 = .data:0x8019BDC8; // type:object size:0x20 scope:local align:4 data:string -@2481 = .data:0x8019BDE8; // type:object size:0x11 scope:local data:string -@2482 = .data:0x8019BE00; // type:object size:0x10 scope:local align:8 data:string -@2483 = .data:0x8019BE10; // type:object size:0x1D scope:local data:string -@2484 = .data:0x8019BE30; // type:object size:0x15 scope:local align:4 data:string -@2485 = .data:0x8019BE48; // type:object size:0x19 scope:local align:4 data:string -@2486 = .data:0x8019BE64; // type:object size:0x16 scope:local align:4 data:string -@2487 = .data:0x8019BE7C; // type:object size:0x1F scope:local align:4 data:string -@2488 = .data:0x8019BE9C; // type:object size:0x1D scope:local align:4 data:string -@2489 = .data:0x8019BEBC; // type:object size:0x19 scope:local align:4 data:string -@2777 = .data:0x8019BED8; // type:object size:0x1D scope:local align:4 data:string -@2778 = .data:0x8019BEF8; // type:object size:0x1A scope:local align:4 data:string -@2779 = .data:0x8019BF14; // type:object size:0x17 scope:local align:4 data:string -@2780 = .data:0x8019BF2C; // type:object size:0x15 scope:local align:4 data:string -@2781 = .data:0x8019BF44; // type:object size:0x1A scope:local align:4 data:string -@2782 = .data:0x8019BF60; // type:object size:0x18 scope:local align:4 data:string -@2783 = .data:0x8019BF78; // type:object size:0x1D scope:local data:string -@2784 = .data:0x8019BF98; // type:object size:0x1A scope:local align:4 data:string -@2785 = .data:0x8019BFB4; // type:object size:0x1D scope:local align:4 data:string -@2786 = .data:0x8019BFD8; // type:object size:0x20 scope:local align:8 data:string -@2787 = .data:0x8019BFF8; // type:object size:0x1D scope:local data:string -@2788 = .data:0x8019C018; // type:object size:0x1A scope:local align:4 data:string -@2789 = .data:0x8019C034; // type:object size:0x19 scope:local align:4 data:string -@2790 = .data:0x8019C050; // type:object size:0x1C scope:local align:4 data:string -@2791 = .data:0x8019C06C; // type:object size:0x17 scope:local data:string -@2823 = .data:0x8019C084; // type:object size:0x11 scope:local align:4 data:string -@2824 = .data:0x8019C098; // type:object size:0x14 scope:local align:4 data:string -@2825 = .data:0x8019C0B0; // type:object size:0x20 scope:local align:8 data:string -@2884 = .data:0x8019C0D0; // type:object size:0x16 scope:local data:string -@2885 = .data:0x8019C0E8; // type:object size:0x1C scope:local align:4 data:string -@2956 = .data:0x8019C104; // type:object size:0x15 scope:local data:string -@2957 = .data:0x8019C11C; // type:object size:0x27 scope:local align:4 data:string -@2958 = .data:0x8019C144; // type:object size:0x22 scope:local align:4 data:string -@2959 = .data:0x8019C168; // type:object size:0x21 scope:local align:4 data:string +@2608 = .data:0x8019BD08; // type:object size:0x17 scope:local data:string +@2609 = .data:0x8019BD20; // type:object size:0x9 scope:local align:4 data:string +@2610 = .data:0x8019BD2C; // type:object size:0x15 scope:local align:4 data:string +@2611 = .data:0x8019BD48; // type:object size:0x18 scope:local align:8 data:string +@2793 = .data:0x8019BD60; // type:object size:0x19 scope:local data:string +@2794 = .data:0x8019BD80; // type:object size:0x18 scope:local align:8 data:string +@2795 = .data:0x8019BD98; // type:object size:0x11 scope:local data:string +@2796 = .data:0x8019BDAC; // type:object size:0x1B scope:local align:4 data:string +@2797 = .data:0x8019BDC8; // type:object size:0x20 scope:local align:4 data:string +@2798 = .data:0x8019BDE8; // type:object size:0x11 scope:local data:string +@2799 = .data:0x8019BE00; // type:object size:0x10 scope:local align:8 data:string +@2800 = .data:0x8019BE10; // type:object size:0x1D scope:local data:string +@2801 = .data:0x8019BE30; // type:object size:0x15 scope:local align:4 data:string +@2802 = .data:0x8019BE48; // type:object size:0x19 scope:local align:4 data:string +@2803 = .data:0x8019BE64; // type:object size:0x16 scope:local align:4 data:string +@2804 = .data:0x8019BE7C; // type:object size:0x1F scope:local align:4 data:string +@2805 = .data:0x8019BE9C; // type:object size:0x1D scope:local align:4 data:string +@2806 = .data:0x8019BEBC; // type:object size:0x19 scope:local align:4 data:string +@3094 = .data:0x8019BED8; // type:object size:0x1D scope:local align:4 data:string +@3095 = .data:0x8019BEF8; // type:object size:0x1A scope:local align:4 data:string +@3096 = .data:0x8019BF14; // type:object size:0x17 scope:local align:4 data:string +@3097 = .data:0x8019BF2C; // type:object size:0x15 scope:local align:4 data:string +@3098 = .data:0x8019BF44; // type:object size:0x1A scope:local align:4 data:string +@3099 = .data:0x8019BF60; // type:object size:0x18 scope:local align:4 data:string +@3100 = .data:0x8019BF78; // type:object size:0x1D scope:local data:string +@3101 = .data:0x8019BF98; // type:object size:0x1A scope:local align:4 data:string +@3102 = .data:0x8019BFB4; // type:object size:0x1D scope:local align:4 data:string +@3103 = .data:0x8019BFD8; // type:object size:0x20 scope:local align:8 data:string +@3104 = .data:0x8019BFF8; // type:object size:0x1D scope:local data:string +@3105 = .data:0x8019C018; // type:object size:0x1A scope:local align:4 data:string +@3106 = .data:0x8019C034; // type:object size:0x19 scope:local align:4 data:string +@3107 = .data:0x8019C050; // type:object size:0x1C scope:local align:4 data:string +@3108 = .data:0x8019C06C; // type:object size:0x17 scope:local data:string +@3140 = .data:0x8019C084; // type:object size:0x11 scope:local align:4 data:string +@3141 = .data:0x8019C098; // type:object size:0x14 scope:local align:4 data:string +@3142 = .data:0x8019C0B0; // type:object size:0x20 scope:local align:8 data:string +@3201 = .data:0x8019C0D0; // type:object size:0x16 scope:local data:string +@3202 = .data:0x8019C0E8; // type:object size:0x1C scope:local align:4 data:string +@3273 = .data:0x8019C104; // type:object size:0x15 scope:local data:string +@3274 = .data:0x8019C11C; // type:object size:0x27 scope:local align:4 data:string +@3275 = .data:0x8019C144; // type:object size:0x22 scope:local align:4 data:string +@3276 = .data:0x8019C168; // type:object size:0x21 scope:local align:4 data:string lbl_8019C190 = .data:0x8019C190; // type:object size:0xC data:4byte lbl_8019C19C = .data:0x8019C19C; // type:object size:0xC data:4byte lbl_8019C1A8 = .data:0x8019C1A8; // type:object size:0xC data:4byte @@ -9736,11 +9736,13 @@ gWC24DownloadComplete = .sbss:0x80330B79; // type:object size:0x1 data:byte gWC24ShutdownFlag1 = .sbss:0x80330B7A; // type:object size:0x1 data:byte gWC24NetInitialized = .sbss:0x80330B7B; // type:object size:0x1 data:byte gWC24ShutdownFlag2 = .sbss:0x80330B7C; // type:object size:0x1 data:byte +gWC24ShutdownPadding = .sbss:0x80330B7D; // type:object size:0x3 gWC24DownloadIndex = .sbss:0x80330B80; // type:object size:0x4 data:4byte gWC24QueueIndex = .sbss:0x80330B84; // type:object size:0x4 data:4byte gWC24TaskCount = .sbss:0x80330B88; // type:object size:0x4 data:4byte gWC24HeapBlock = .sbss:0x80330B8C; // type:object size:0x4 data:4byte gWC24Heap = .sbss:0x80330B90; // type:object size:0x4 data:4byte +gWC24HeapPadding = .sbss:0x80330B94; // type:object size:0x4 lbl_80330B98 = .sbss:0x80330B98; // type:object size:0x4 data:byte gHomeButton = .sbss:0x80330BA0; // type:object size:0x4 data:4byte gUnkSceneFloat = .sbss:0x80330BA4; // type:object size:0x4 align:4 data:float diff --git a/src/WiiConnect24.cpp b/src/WiiConnect24.cpp index e416a09..773650d 100644 --- a/src/WiiConnect24.cpp +++ b/src/WiiConnect24.cpp @@ -32,11 +32,13 @@ volatile u8 gWC24DownloadComplete; volatile u8 gWC24ShutdownFlag1; volatile u8 gWC24NetInitialized; volatile u8 gWC24ShutdownFlag2; +u8 gWC24ShutdownPadding[3]; volatile s32 gWC24DownloadIndex; volatile s32 gWC24QueueIndex; volatile s32 gWC24TaskCount; void* gWC24HeapBlock; MEMiHeapHead* gWC24Heap; +u8 gWC24HeapPadding[4]; s32 CWiiConnect24::getWeather(void* forecastBuf, s64* forecastTime, u32* forecastSize, From 9a456b2a4ea83e343ab1bc2865adfb4bc2a0cc8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 21:04:57 +0300 Subject: [PATCH 13/15] Channel: centralize WiiConnect24 declarations and fix SC/NWC24 signatures --- config/HAFE/symbols.txt | 86 +++++++++---------- include/channel/WiiConnect24Internal.h | 40 +++++++++ .../revolution/NWC24/internal/NWC24iSystem.h | 2 +- include/revolution/SC/scapi.h | 2 +- src/WiiConnect24.cpp | 16 +--- src/WiiConnect24Code.cpp | 2 +- src/WiiConnect24Heap.cpp | 2 +- src/WiiConnect24Lifecycle.cpp | 17 +--- src/revolution/NWC24/NWC24System.c | 27 ++++-- src/revolution/SC/scapi.c | 4 +- 10 files changed, 115 insertions(+), 83 deletions(-) create mode 100644 include/channel/WiiConnect24Internal.h diff --git a/config/HAFE/symbols.txt b/config/HAFE/symbols.txt index 3d83304..f3ea8c9 100644 --- a/config/HAFE/symbols.txt +++ b/config/HAFE/symbols.txt @@ -6729,48 +6729,48 @@ lbl_8019BC98 = .data:0x8019BC98; // type:object size:0x1C data:wstring lbl_8019BCB4 = .data:0x8019BCB4; // type:object size:0x1A data:wstring lbl_8019BCD0 = .data:0x8019BCD0; // type:object size:0x1A data:wstring gLastUpdatedPrefixes = .data:0x8019BCEC; // type:object size:0x1C -@2608 = .data:0x8019BD08; // type:object size:0x17 scope:local data:string -@2609 = .data:0x8019BD20; // type:object size:0x9 scope:local align:4 data:string -@2610 = .data:0x8019BD2C; // type:object size:0x15 scope:local align:4 data:string -@2611 = .data:0x8019BD48; // type:object size:0x18 scope:local align:8 data:string -@2793 = .data:0x8019BD60; // type:object size:0x19 scope:local data:string -@2794 = .data:0x8019BD80; // type:object size:0x18 scope:local align:8 data:string -@2795 = .data:0x8019BD98; // type:object size:0x11 scope:local data:string -@2796 = .data:0x8019BDAC; // type:object size:0x1B scope:local align:4 data:string -@2797 = .data:0x8019BDC8; // type:object size:0x20 scope:local align:4 data:string -@2798 = .data:0x8019BDE8; // type:object size:0x11 scope:local data:string -@2799 = .data:0x8019BE00; // type:object size:0x10 scope:local align:8 data:string -@2800 = .data:0x8019BE10; // type:object size:0x1D scope:local data:string -@2801 = .data:0x8019BE30; // type:object size:0x15 scope:local align:4 data:string -@2802 = .data:0x8019BE48; // type:object size:0x19 scope:local align:4 data:string -@2803 = .data:0x8019BE64; // type:object size:0x16 scope:local align:4 data:string -@2804 = .data:0x8019BE7C; // type:object size:0x1F scope:local align:4 data:string -@2805 = .data:0x8019BE9C; // type:object size:0x1D scope:local align:4 data:string -@2806 = .data:0x8019BEBC; // type:object size:0x19 scope:local align:4 data:string -@3094 = .data:0x8019BED8; // type:object size:0x1D scope:local align:4 data:string -@3095 = .data:0x8019BEF8; // type:object size:0x1A scope:local align:4 data:string -@3096 = .data:0x8019BF14; // type:object size:0x17 scope:local align:4 data:string -@3097 = .data:0x8019BF2C; // type:object size:0x15 scope:local align:4 data:string -@3098 = .data:0x8019BF44; // type:object size:0x1A scope:local align:4 data:string -@3099 = .data:0x8019BF60; // type:object size:0x18 scope:local align:4 data:string -@3100 = .data:0x8019BF78; // type:object size:0x1D scope:local data:string -@3101 = .data:0x8019BF98; // type:object size:0x1A scope:local align:4 data:string -@3102 = .data:0x8019BFB4; // type:object size:0x1D scope:local align:4 data:string -@3103 = .data:0x8019BFD8; // type:object size:0x20 scope:local align:8 data:string -@3104 = .data:0x8019BFF8; // type:object size:0x1D scope:local data:string -@3105 = .data:0x8019C018; // type:object size:0x1A scope:local align:4 data:string -@3106 = .data:0x8019C034; // type:object size:0x19 scope:local align:4 data:string -@3107 = .data:0x8019C050; // type:object size:0x1C scope:local align:4 data:string -@3108 = .data:0x8019C06C; // type:object size:0x17 scope:local data:string -@3140 = .data:0x8019C084; // type:object size:0x11 scope:local align:4 data:string -@3141 = .data:0x8019C098; // type:object size:0x14 scope:local align:4 data:string -@3142 = .data:0x8019C0B0; // type:object size:0x20 scope:local align:8 data:string -@3201 = .data:0x8019C0D0; // type:object size:0x16 scope:local data:string -@3202 = .data:0x8019C0E8; // type:object size:0x1C scope:local align:4 data:string -@3273 = .data:0x8019C104; // type:object size:0x15 scope:local data:string -@3274 = .data:0x8019C11C; // type:object size:0x27 scope:local align:4 data:string -@3275 = .data:0x8019C144; // type:object size:0x22 scope:local align:4 data:string -@3276 = .data:0x8019C168; // type:object size:0x21 scope:local align:4 data:string +@4009 = .data:0x8019BD08; // type:object size:0x17 scope:local data:string +@4010 = .data:0x8019BD20; // type:object size:0x9 scope:local align:4 data:string +@4011 = .data:0x8019BD2C; // type:object size:0x15 scope:local align:4 data:string +@4012 = .data:0x8019BD48; // type:object size:0x18 scope:local align:8 data:string +@4194 = .data:0x8019BD60; // type:object size:0x19 scope:local data:string +@4195 = .data:0x8019BD80; // type:object size:0x18 scope:local align:8 data:string +@4196 = .data:0x8019BD98; // type:object size:0x11 scope:local data:string +@4197 = .data:0x8019BDAC; // type:object size:0x1B scope:local align:4 data:string +@4198 = .data:0x8019BDC8; // type:object size:0x20 scope:local align:4 data:string +@4199 = .data:0x8019BDE8; // type:object size:0x11 scope:local data:string +@4200 = .data:0x8019BE00; // type:object size:0x10 scope:local align:8 data:string +@4201 = .data:0x8019BE10; // type:object size:0x1D scope:local data:string +@4202 = .data:0x8019BE30; // type:object size:0x15 scope:local align:4 data:string +@4203 = .data:0x8019BE48; // type:object size:0x19 scope:local align:4 data:string +@4204 = .data:0x8019BE64; // type:object size:0x16 scope:local align:4 data:string +@4205 = .data:0x8019BE7C; // type:object size:0x1F scope:local align:4 data:string +@4206 = .data:0x8019BE9C; // type:object size:0x1D scope:local align:4 data:string +@4207 = .data:0x8019BEBC; // type:object size:0x19 scope:local align:4 data:string +@4495 = .data:0x8019BED8; // type:object size:0x1D scope:local align:4 data:string +@4496 = .data:0x8019BEF8; // type:object size:0x1A scope:local align:4 data:string +@4497 = .data:0x8019BF14; // type:object size:0x17 scope:local align:4 data:string +@4498 = .data:0x8019BF2C; // type:object size:0x15 scope:local align:4 data:string +@4499 = .data:0x8019BF44; // type:object size:0x1A scope:local align:4 data:string +@4500 = .data:0x8019BF60; // type:object size:0x18 scope:local align:4 data:string +@4501 = .data:0x8019BF78; // type:object size:0x1D scope:local data:string +@4502 = .data:0x8019BF98; // type:object size:0x1A scope:local align:4 data:string +@4503 = .data:0x8019BFB4; // type:object size:0x1D scope:local align:4 data:string +@4504 = .data:0x8019BFD8; // type:object size:0x20 scope:local align:8 data:string +@4505 = .data:0x8019BFF8; // type:object size:0x1D scope:local data:string +@4506 = .data:0x8019C018; // type:object size:0x1A scope:local align:4 data:string +@4507 = .data:0x8019C034; // type:object size:0x19 scope:local align:4 data:string +@4508 = .data:0x8019C050; // type:object size:0x1C scope:local align:4 data:string +@4509 = .data:0x8019C06C; // type:object size:0x17 scope:local data:string +@4541 = .data:0x8019C084; // type:object size:0x11 scope:local align:4 data:string +@4542 = .data:0x8019C098; // type:object size:0x14 scope:local align:4 data:string +@4543 = .data:0x8019C0B0; // type:object size:0x20 scope:local align:8 data:string +@4602 = .data:0x8019C0D0; // type:object size:0x16 scope:local data:string +@4603 = .data:0x8019C0E8; // type:object size:0x1C scope:local align:4 data:string +@4674 = .data:0x8019C104; // type:object size:0x15 scope:local data:string +@4675 = .data:0x8019C11C; // type:object size:0x27 scope:local align:4 data:string +@4676 = .data:0x8019C144; // type:object size:0x22 scope:local align:4 data:string +@4677 = .data:0x8019C168; // type:object size:0x21 scope:local align:4 data:string lbl_8019C190 = .data:0x8019C190; // type:object size:0xC data:4byte lbl_8019C19C = .data:0x8019C19C; // type:object size:0xC data:4byte lbl_8019C1A8 = .data:0x8019C1A8; // type:object size:0xC data:4byte @@ -8115,7 +8115,7 @@ lbl_801D2BD8 = .data:0x801D2BD8; // type:object size:0x25 scope:local data:strin lbl_801D2C00 = .data:0x801D2C00; // type:object size:0x21 scope:local data:string lbl_801D2C24 = .data:0x801D2C24; // type:object size:0x1C scope:local data:string @2473 = .data:0x801D2C40; // type:object size:0x15 scope:local data:string -@2610 = .data:0x801D2C58; // type:object size:0x27 scope:local data:string +@4011 = .data:0x801D2C58; // type:object size:0x27 scope:local data:string @2626 = .data:0x801D2C80; // type:object size:0x1D scope:local data:string @2627 = .data:0x801D2CA0; // type:object size:0x30 scope:local data:string gap_conn_trace_unexpected_addr = .data:0x801D2CD0; // type:object size:0x44 data:string diff --git a/include/channel/WiiConnect24Internal.h b/include/channel/WiiConnect24Internal.h new file mode 100644 index 0000000..2075211 --- /dev/null +++ b/include/channel/WiiConnect24Internal.h @@ -0,0 +1,40 @@ +#ifndef CHANNEL_WII_CONNECT24_INTERNAL_H +#define CHANNEL_WII_CONNECT24_INTERNAL_H +#include + +#include +#include + +#include + +extern OSMessageQueue gWC24Queue; +extern OSMessage gWC24QueueBuffer[16]; +extern OSThread gWC24Thread; +extern u8 gWC24ThreadStack[]; +extern u8 gWC24FileBuffer[]; +extern volatile u8 gWC24DownloadComplete; +extern volatile u8 gWC24NetInitialized; +extern volatile u8 gWC24ShutdownFlag1; +extern volatile u8 gWC24ShutdownFlag2; +extern volatile s32 gWC24DownloadIndex; +extern volatile s32 gWC24QueueIndex; +extern volatile s32 gWC24TaskCount; +extern void* gWC24HeapBlock; +extern MEMiHeapHead* gWC24Heap; + +// The SO block is not split yet; keep the dependency declarations together. +#ifdef __cplusplus +extern "C" { +#endif +s32 SOInit(void* init); +s32 SOStartup(void); +s32 SOGetLastError(void); +#ifdef __cplusplus +} +#endif + +void* DownloaderThread(void* pArg); +void* WC24Alloc(u32 unused, s32 size); +void WC24Free(void* unused, void* pBlock, s32 size); + +#endif diff --git a/include/revolution/NWC24/internal/NWC24iSystem.h b/include/revolution/NWC24/internal/NWC24iSystem.h index 09f770b..9948ac7 100644 --- a/include/revolution/NWC24/internal/NWC24iSystem.h +++ b/include/revolution/NWC24/internal/NWC24iSystem.h @@ -8,7 +8,7 @@ extern "C" { #endif NWC24Err NWC24iPrepareShutdown(void); -NWC24Err NWC24iRequestShutdown(u32 event, NWC24Err* pResult); +NWC24Err NWC24iRequestShutdown(u32 event); #ifdef __cplusplus } diff --git a/include/revolution/SC/scapi.h b/include/revolution/SC/scapi.h index deda3be..2acc29b 100644 --- a/include/revolution/SC/scapi.h +++ b/include/revolution/SC/scapi.h @@ -116,7 +116,7 @@ typedef struct SCSimpleAddress { u8 SCGetAspectRatio(void); s8 SCGetDisplayOffsetH(void); u8 SCGetEuRgb60Mode(void); -void SCGetIdleMode(SCIdleModeInfo* mode); +BOOL SCGetIdleMode(SCIdleModeInfo* mode); u8 SCGetLanguage(void); BOOL SCSetLanguage(u8 language); BOOL SCGetParentalControl(SCParentalControlsInfo* pcInfo); diff --git a/src/WiiConnect24.cpp b/src/WiiConnect24.cpp index 773650d..d2ead33 100644 --- a/src/WiiConnect24.cpp +++ b/src/WiiConnect24.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -8,15 +9,11 @@ #include #include #include +#include #include #include -void* WC24Alloc(u32 unused, s32 size); -void WC24Free(void* unused, void* block, s32 size); -extern "C" s32 SOInit(void* init); -extern "C" s32 SOStartup(); -extern "C" s32 SOGetLastError(); NWC24Work gNWC24Work; OSMessageQueue gWC24Queue; @@ -223,13 +220,6 @@ s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort); s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, u32* outSize); -struct WC24IdleMode { - u8 wc24; - u8 slotLight; -}; -// The SDK header declares this as void, but the channel uses the result. -extern "C" BOOL SCGetIdleMode(WC24IdleMode* mode); - static inline void SetTaskMessage(WC24Task* task, const char* msg, s32 code, s32 result) { task->mErrorCode = code; task->mNwc24Result = result; @@ -267,7 +257,7 @@ static inline NWC24Err CheckLib(WC24Task* task) { if (error != NWC24_OK) return (NWC24Err)SetTaskError(task, "NWC24Check() failed.", error); - WC24IdleMode idle; + SCIdleModeInfo idle; if (SCGetIdleMode(&idle) == 0 || idle.wc24 != 1) return NWC24_ERR_INVALID_VALUE; diff --git a/src/WiiConnect24Code.cpp b/src/WiiConnect24Code.cpp index 83ccf66..c7f02ee 100644 --- a/src/WiiConnect24Code.cpp +++ b/src/WiiConnect24Code.cpp @@ -1,7 +1,7 @@ #include #include -extern MEMiHeapHead* gWC24Heap; +#include void WC24Free(void* unused, void* block, s32 size) { if (block == NULL) diff --git a/src/WiiConnect24Heap.cpp b/src/WiiConnect24Heap.cpp index 8986ca3..79012a2 100644 --- a/src/WiiConnect24Heap.cpp +++ b/src/WiiConnect24Heap.cpp @@ -1,7 +1,7 @@ #include #include -extern MEMiHeapHead* gWC24Heap; +#include void* WC24Alloc(u32 unused, s32 size) { void* block = NULL; diff --git a/src/WiiConnect24Lifecycle.cpp b/src/WiiConnect24Lifecycle.cpp index 65f4ebf..201d6dd 100644 --- a/src/WiiConnect24Lifecycle.cpp +++ b/src/WiiConnect24Lifecycle.cpp @@ -2,19 +2,10 @@ #include #include #include +#include +#include #include -extern OSMessageQueue gWC24Queue; -extern OSMessage gWC24QueueBuffer[16]; -extern OSThread gWC24Thread; -extern u8 gWC24ThreadStack[]; -extern void* gWC24HeapBlock; -extern MEMiHeapHead* gWC24Heap; -extern volatile s32 gWC24DownloadIndex; -extern volatile s32 gWC24QueueIndex; -extern volatile s32 gWC24TaskCount; -void* DownloaderThread(void*); - void InitDownloader(void) { void* block = MEM2Alloc(0x10000, 0x20); gWC24HeapBlock = block; @@ -45,10 +36,6 @@ void UpdateDownloader(void) { gWC24DownloadIndex = 0; } -extern volatile u8 gWC24ShutdownFlag1; -extern volatile u8 gWC24ShutdownFlag2; -extern "C" int NWC24iRequestShutdown(u32 event); - void ShutdownDownloader(s32 event) { int i = 0; while (i < 10 && (gWC24ShutdownFlag1 || gWC24ShutdownFlag2)) { diff --git a/src/revolution/NWC24/NWC24System.c b/src/revolution/NWC24/NWC24System.c index 2890414..954cba2 100644 --- a/src/revolution/NWC24/NWC24System.c +++ b/src/revolution/NWC24/NWC24System.c @@ -56,15 +56,30 @@ NWC24Err NWC24iPrepareShutdown(void) { return result; } -NWC24Err NWC24iRequestShutdown(u32 event, NWC24Err* pResult) { +NWC24Err NWC24iRequestShutdown(u32 event) { static u8 shtBuffer[32] ALIGN(32); static u8 shtResult[32] ALIGN(32); + NWC24Err result; *(u32*)shtBuffer = event; - return NWC24_IOCTL_DEVICE_ASYNC(nwc24ShtFd, NWC24_IOCTL_SHUTDOWN, // - shtBuffer, sizeof(shtBuffer), // - shtResult, sizeof(shtResult), // - pResult); + result = NWC24_IOCTL_DEVICE_ASYNC(nwc24ShtFd, NWC24_IOCTL_SHUTDOWN, // + shtBuffer, sizeof(shtBuffer), // + shtResult, sizeof(shtResult), // + &result); + + if (result < 0) { + return result; + } + + while (NWC24iIsAsyncRequestPending()) { + OSSleepTicks(OS_TIME_SPEED); + } + + if (*(NWC24Err*)shtResult < 0) { + return NWC24_ERR_FAILED; + } + + return NWC24_OK; } BOOL NWC24Shutdown(BOOL final, u32 event) { @@ -90,7 +105,7 @@ BOOL NWC24Shutdown(BOOL final, u32 event) { } else { return TRUE; } - } else if (NWC24iRequestShutdown(event, &result) >= 0) { + } else if ((result = NWC24iRequestShutdown(event)) >= 0) { shuttingdown = TRUE; } diff --git a/src/revolution/SC/scapi.c b/src/revolution/SC/scapi.c index 183ca89..71c3103 100644 --- a/src/revolution/SC/scapi.c +++ b/src/revolution/SC/scapi.c @@ -47,8 +47,8 @@ u8 SCGetEuRgb60Mode(void) { return item; } -void SCGetIdleMode(SCIdleModeInfo* mode) { - SCFindByteArrayItem(mode, sizeof(SCIdleModeInfo), SC_ITEM_IPL_IDL); +BOOL SCGetIdleMode(SCIdleModeInfo* mode) { + return SCFindByteArrayItem(mode, sizeof(SCIdleModeInfo), SC_ITEM_IPL_IDL); } u8 SCGetLanguage(void) { From 48e37a118f87798f3b591af794a61d0957571834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 23:37:40 +0300 Subject: [PATCH 14/15] Channel: merge the downloader lifecycle, allocator and main WC24 code into one TU WiiConnect24Lifecycle.cpp, WiiConnect24Heap.cpp and WiiConnect24Code.cpp were arbitrary splits of the same translation unit as WiiConnect24.cpp. Merge them: WiiConnect24.cpp .text 0x80032610-0x80035BA8 (was four units) InitDownloader, UpdateDownloader, ShutdownDownloader, CWiiConnect24 methods, DownloaderThread, DownloadFiles, CreateDownloadTasks, ExecuteDownloadTask, DeleteTaskFiles, MapDownloadError, ReadCompressedFile, WC24Alloc, WC24Free Proof that they share a TU: the merged unit still matches 100 % (17/17 functions, 13720/13720 bytes) and the DOL still matches. Matching subtlety found while doing it: the globals must be *defined after* the functions (extern declarations before them). With the definitions at the top, MWCC's IPA addresses the .bss globals through one base register, which shrank InitDownloader from 172 to 164 bytes and broke the DOL. MapDownloadError is an NWC24Err function: the local is an NWC24Err from the start and the mapping is written with the NWC24_ERR_* enumerators instead of raw negative numbers, so no cast is needed at the return. The parameter stays s32 because the target symbol is MapDownloadError__Fl and an enum parameter would mangle as __F9NWC24Err. --- config/HAFE/splits.txt | 11 +-- configure.py | 3 - src/WiiConnect24.cpp | 166 +++++++++++++++++++++++++--------- src/WiiConnect24Code.cpp | 14 --- src/WiiConnect24Heap.cpp | 13 --- src/WiiConnect24Lifecycle.cpp | 48 ---------- 6 files changed, 126 insertions(+), 129 deletions(-) delete mode 100644 src/WiiConnect24Code.cpp delete mode 100644 src/WiiConnect24Heap.cpp delete mode 100644 src/WiiConnect24Lifecycle.cpp diff --git a/config/HAFE/splits.txt b/config/HAFE/splits.txt index b5101c2..3b02b44 100644 --- a/config/HAFE/splits.txt +++ b/config/HAFE/splits.txt @@ -236,22 +236,13 @@ System.cpp: ChannelMathData.cpp: .sdata2 start:0x80331F78 end:0x80331FC0 -WiiConnect24Lifecycle.cpp: - .text start:0x80032610 end:0x800327AC - WiiConnect24.cpp: - .text start:0x800327AC end:0x80035B70 + .text start:0x80032610 end:0x80035BA8 .data start:0x8019BD08 end:0x8019C189 .bss start:0x801D99E0 end:0x801F6B28 .sdata start:0x80330170 end:0x80330190 .sbss start:0x80330B78 end:0x80330B98 -WiiConnect24Heap.cpp: - .text start:0x80035B70 end:0x80035B8C - -WiiConnect24Code.cpp: - .text start:0x80035B8C end:0x80035BA8 - DragScroll.cpp: .text start:0x80035BA8 end:0x80035DC4 diff --git a/configure.py b/configure.py index 561974b..1268544 100755 --- a/configure.py +++ b/configure.py @@ -1099,10 +1099,7 @@ def MatchingFor(*versions): Object(Matching, "main.cpp"), Object(Matching, "DrawUtil.cpp"), Object(Matching, "GlobeDots.cpp"), - Object(Matching, "WiiConnect24Lifecycle.cpp"), - Object(Matching, "WiiConnect24Code.cpp"), Object(Matching, "WiiConnect24.cpp"), - Object(Matching, "WiiConnect24Heap.cpp"), Object(Matching, "WeatherUtil.cpp"), Object(Matching, "ChannelMathData.cpp"), Object(Matching, "DragScroll.cpp"), diff --git a/src/WiiConnect24.cpp b/src/WiiConnect24.cpp index d2ead33..34bb132 100644 --- a/src/WiiConnect24.cpp +++ b/src/WiiConnect24.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -9,34 +10,74 @@ #include #include #include +#include #include #include #include +extern NWC24Work gNWC24Work; +extern OSMessageQueue gWC24Queue; +extern OSMessage gWC24QueueBuffer[16]; +extern OSThread gWC24Thread; +extern u8 gWC24ThreadStack[0x8000]; +extern u8 gWC24FileBuffer[0x10000]; +extern WC24Task gWC24Tasks[8]; +extern u8 gWC24Spare[0x10]; +extern volatile u8 gNWC24LibOpened; +extern volatile u8 gWC24DownloadComplete; +extern volatile u8 gWC24ShutdownFlag1; +extern volatile u8 gWC24NetInitialized; +extern volatile u8 gWC24ShutdownFlag2; +extern u8 gWC24ShutdownPadding[3]; +extern volatile s32 gWC24DownloadIndex; +extern volatile s32 gWC24QueueIndex; +extern volatile s32 gWC24TaskCount; +extern void* gWC24HeapBlock; +extern MEMiHeapHead* gWC24Heap; +extern u8 gWC24HeapPadding[4]; + +void* DownloaderThread(void* unused); + +void InitDownloader(void) { + void* block = MEM2Alloc(0x10000, 0x20); + gWC24HeapBlock = block; + gWC24Heap = MEMCreateExpHeapEx(block, 0x10000, 4); + + OSThread* thread = &gWC24Thread; + OSInitMessageQueue(&gWC24Queue, gWC24QueueBuffer, 0x10); + OSCreateThread(thread, (OSThreadFunc)DownloaderThread, NULL, gWC24ThreadStack + 0x8000, + 0x8000, 8, 1); + OSResumeThread(thread); + + gWC24DownloadIndex = 0; + gWC24QueueIndex = 0; + gWC24TaskCount = 0; +} +void UpdateDownloader(void) { + if (gWC24TaskCount <= 0) + return; -NWC24Work gNWC24Work; -OSMessageQueue gWC24Queue; -OSMessage gWC24QueueBuffer[16]; -OSThread gWC24Thread; -u8 gWC24ThreadStack[0x8000]; -u8 gWC24FileBuffer[0x10000]; -WC24Task gWC24Tasks[8]; -u8 gWC24Spare[0x10]; + if (gWC24Tasks[gWC24DownloadIndex].mState != 0) + return; -volatile u8 gNWC24LibOpened; -volatile u8 gWC24DownloadComplete; -volatile u8 gWC24ShutdownFlag1; -volatile u8 gWC24NetInitialized; -volatile u8 gWC24ShutdownFlag2; -u8 gWC24ShutdownPadding[3]; -volatile s32 gWC24DownloadIndex; -volatile s32 gWC24QueueIndex; -volatile s32 gWC24TaskCount; -void* gWC24HeapBlock; -MEMiHeapHead* gWC24Heap; -u8 gWC24HeapPadding[4]; + gWC24DownloadIndex++; + gWC24TaskCount--; + + if (gWC24DownloadIndex >= gWC24TaskCount) + gWC24DownloadIndex = 0; +} + +void ShutdownDownloader(s32 event) { + int i = 0; + while (i < 10 && (gWC24ShutdownFlag1 || gWC24ShutdownFlag2)) { + NWC24iRequestShutdown(event); + OSSleepTicks(OS_TIME_SPEED); + i++; + } + OSJoinThread(&gWC24Thread, NULL); +} s32 CWiiConnect24::getWeather(void* forecastBuf, s64* forecastTime, u32* forecastSize, void* shortBuf, s64* shortTime, u32* shortSize, @@ -211,7 +252,7 @@ char sBinNameFormat[] = "%d.bin"; char sForecastFileSuffix[] = "%sB"; char sShortFileSuffix[] = "%sR"; -s32 MapDownloadError(s32 error); +NWC24Err MapDownloadError(s32 error); s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort); s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, u16 newInterval, u16 count, u32* idOut); @@ -245,7 +286,7 @@ static inline NWC24Err OpenLib(WC24Task* task, s64 retry) { } if (error != NWC24_OK) - return (NWC24Err)SetTaskError(task, "NWC24OpenLib() failed.", error); + return SetTaskError(task, "NWC24OpenLib() failed.", error); gNWC24LibOpened = 1; return NWC24_OK; @@ -255,7 +296,7 @@ static inline NWC24Err CheckLib(WC24Task* task) { NWC24Err error = NWC24Check(2); if (error != NWC24_OK) - return (NWC24Err)SetTaskError(task, "NWC24Check() failed.", error); + return SetTaskError(task, "NWC24Check() failed.", error); SCIdleModeInfo idle; if (SCGetIdleMode(&idle) == 0 || idle.wc24 != 1) @@ -268,7 +309,7 @@ static inline NWC24Err CloseLib(WC24Task* task) { NWC24Err error = NWC24CloseLib(); if (error != NWC24_OK) - return (NWC24Err)SetTaskError(task, "NWC24CloseLib() failed.", error); + return SetTaskError(task, "NWC24CloseLib() failed.", error); gNWC24LibOpened = 0; return NWC24_OK; @@ -942,30 +983,32 @@ s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort) { return 0; } -s32 MapDownloadError(s32 error) { - s32 mapped = -6; - - if ((error <= -0x10 && error >= -0x15) || error == -0x26 || error == -0x29 || error == -0x2B || - error == -0x2E) { - mapped = -0xB; - } else if (error == -0x31) { - mapped = -0xC; - } else if (error == -1 || error == -0xB || error == -0x2A) { - mapped = -2; +NWC24Err MapDownloadError(s32 error) { + NWC24Err mapped = NWC24_ERR_FULL; + + if ((error <= NWC24_ERR_FILE_OPEN && error >= NWC24_ERR_FILE_OTHER) || + error == NWC24_ERR_NAND_CORRUPT || error == NWC24_ERR_FILE_EXISTS || + error == NWC24_ERR_INTERNAL_VF || error == NWC24_ERR_FILE_BROKEN) { + mapped = NWC24_ERR_NOMEM; + } else if (error == NWC24_ERR_OLD_SYSTEM) { + mapped = NWC24_ERR_CONFIG; + } else if (error == NWC24_ERR_FATAL || error == NWC24_ERR_NOMEM || + error == NWC24_ERR_INTERNAL_IPC) { + mapped = NWC24_ERR_FAILED; } else if ((u32)(NWC24GetErrorCode() + 0x20000) == 0x55CE) { - mapped = -5; + mapped = NWC24_ERR_NULL; } else { switch (error) { - case -0x27: - mapped = -3; + case NWC24_ERR_DISABLED: + mapped = NWC24_ERR_INVALID_VALUE; break; - case -0x1F: - mapped = -4; + case NWC24_ERR_NETWORK: + mapped = NWC24_ERR_NOT_SUPPORTED; break; - case -0x20: - mapped = -5; + case NWC24_ERR_SERVER: + mapped = NWC24_ERR_NULL; break; } } @@ -1020,3 +1063,44 @@ s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, *outSize = uncompSize; return 0; } + +void* WC24Alloc(u32 unused, s32 size) { + void* block = NULL; + + if (size > 0) + block = MEMAllocFromExpHeapEx(gWC24Heap, size, 0x20); + + return block; +} + +void WC24Free(void* unused, void* block, s32 size) { + if (block == NULL) + return; + + if (size <= 0) + return; + + MEMFreeToExpHeap(gWC24Heap, block); +} + +NWC24Work gNWC24Work; +OSMessageQueue gWC24Queue; +OSMessage gWC24QueueBuffer[16]; +OSThread gWC24Thread; +u8 gWC24ThreadStack[0x8000]; +u8 gWC24FileBuffer[0x10000]; +WC24Task gWC24Tasks[8]; +u8 gWC24Spare[0x10]; + +volatile u8 gNWC24LibOpened; +volatile u8 gWC24DownloadComplete; +volatile u8 gWC24ShutdownFlag1; +volatile u8 gWC24NetInitialized; +volatile u8 gWC24ShutdownFlag2; +u8 gWC24ShutdownPadding[3]; +volatile s32 gWC24DownloadIndex; +volatile s32 gWC24QueueIndex; +volatile s32 gWC24TaskCount; +void* gWC24HeapBlock; +MEMiHeapHead* gWC24Heap; +u8 gWC24HeapPadding[4]; diff --git a/src/WiiConnect24Code.cpp b/src/WiiConnect24Code.cpp deleted file mode 100644 index c7f02ee..0000000 --- a/src/WiiConnect24Code.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -#include - -void WC24Free(void* unused, void* block, s32 size) { - if (block == NULL) - return; - - if (size <= 0) - return; - - MEMFreeToExpHeap(gWC24Heap, block); -} diff --git a/src/WiiConnect24Heap.cpp b/src/WiiConnect24Heap.cpp deleted file mode 100644 index 79012a2..0000000 --- a/src/WiiConnect24Heap.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - -#include - -void* WC24Alloc(u32 unused, s32 size) { - void* block = NULL; - - if (size > 0) - block = MEMAllocFromExpHeapEx(gWC24Heap, size, 0x20); - - return block; -} diff --git a/src/WiiConnect24Lifecycle.cpp b/src/WiiConnect24Lifecycle.cpp deleted file mode 100644 index 201d6dd..0000000 --- a/src/WiiConnect24Lifecycle.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -void InitDownloader(void) { - void* block = MEM2Alloc(0x10000, 0x20); - gWC24HeapBlock = block; - gWC24Heap = MEMCreateExpHeapEx(block, 0x10000, 4); - - OSThread* thread = &gWC24Thread; - OSInitMessageQueue(&gWC24Queue, gWC24QueueBuffer, 0x10); - OSCreateThread(thread, (OSThreadFunc)DownloaderThread, NULL, gWC24ThreadStack + 0x8000, - 0x8000, 8, 1); - OSResumeThread(thread); - - gWC24DownloadIndex = 0; - gWC24QueueIndex = 0; - gWC24TaskCount = 0; -} - -void UpdateDownloader(void) { - if (gWC24TaskCount <= 0) - return; - - if (gWC24Tasks[gWC24DownloadIndex].mState != 0) - return; - - gWC24DownloadIndex++; - gWC24TaskCount--; - - if (gWC24DownloadIndex >= gWC24TaskCount) - gWC24DownloadIndex = 0; -} - -void ShutdownDownloader(s32 event) { - int i = 0; - while (i < 10 && (gWC24ShutdownFlag1 || gWC24ShutdownFlag2)) { - NWC24iRequestShutdown(event); - OSSleepTicks(OS_TIME_SPEED); - i++; - } - - OSJoinThread(&gWC24Thread, NULL); -} From b6dc3717a95a080109d4c685dfbad492f7322a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1dvan=20San?= Date: Wed, 21 Oct 2026 23:58:56 +0300 Subject: [PATCH 15/15] Channel: spell the WiiConnect24 error paths with NWC24Err codes The WC24 download helpers returned raw s32 codes that are, value for value, the NWC24Err codes, and MapDownloadError was typed on s32 even though it maps one NWC24 error to another. Untangle the two error domains: - MapDownloadError takes and returns NWC24Err (the symbol is now MapDownloadError__F8NWC24Err) and its mapping is written with the NWC24_ERR_* enumerators. - DownloadFiles, CreateDownloadTasks, ExecuteDownloadTask, DeleteTaskFiles and ReadCompressedFile return NWC24Err, and their results are NWC24_OK / NWC24_ERR_* instead of -1/-5/-7/-8/-9/-0xA. - NWC24 API results live in NWC24Err locals. Driver errors that used to share those locals now have their own s32 vfError / nandResult, and the NAND checks use NAND_RESULT_NOEXISTS / NAND_RESULT_OK. - The NWC24 comparisons use NWC24_ERR_NOT_FOUND and NWC24_OK, so SetTaskError no longer needs a cast. No instruction changed: the unit is still 17/17 functions and 13720/13720 bytes at 100 %, and the DOL still matches. --- config/HAFE/symbols.txt | 2 +- src/WiiConnect24.cpp | 212 ++++++++++++++++++++-------------------- 2 files changed, 108 insertions(+), 106 deletions(-) diff --git a/config/HAFE/symbols.txt b/config/HAFE/symbols.txt index f3ea8c9..873c3b2 100644 --- a/config/HAFE/symbols.txt +++ b/config/HAFE/symbols.txt @@ -785,7 +785,7 @@ DownloadFiles__FP8WC24TaskUlUl = .text:0x80034564; // type:function size:0x614 CreateDownloadTasks__FP8WC24TaskUlUlUcUsUsPUl = .text:0x80034B78; // type:function size:0x9D4 ExecuteDownloadTask__FP8WC24TasklUlUs = .text:0x8003554C; // type:function size:0x180 DeleteTaskFiles__FP8WC24TaskUlUl = .text:0x800356CC; // type:function size:0x1DC -MapDownloadError__Fl = .text:0x800358A8; // type:function size:0xF0 +MapDownloadError__F8NWC24Err = .text:0x800358A8; // type:function size:0xF0 ReadCompressedFile__FP8WC24TaskPvPvUlPUl = .text:0x80035998; // type:function size:0x1D8 WC24Alloc__FUll = .text:0x80035B70; // type:function size:0x1C WC24Free__FPvPvl = .text:0x80035B8C; // type:function size:0x1C diff --git a/src/WiiConnect24.cpp b/src/WiiConnect24.cpp index 34bb132..819a8a0 100644 --- a/src/WiiConnect24.cpp +++ b/src/WiiConnect24.cpp @@ -252,13 +252,13 @@ char sBinNameFormat[] = "%d.bin"; char sForecastFileSuffix[] = "%sB"; char sShortFileSuffix[] = "%sR"; -NWC24Err MapDownloadError(s32 error); -s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort); -s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, +NWC24Err MapDownloadError(NWC24Err error); +NWC24Err DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort); +NWC24Err CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, u16 newInterval, u16 count, u32* idOut); -s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2); -s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort); -s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, +NWC24Err ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2); +NWC24Err DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort); +NWC24Err ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, u32* outSize); static inline void SetTaskMessage(WC24Task* task, const char* msg, s32 code, s32 result) { @@ -460,7 +460,7 @@ void* DownloaderThread(void* unused) { return NULL; } -s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { +NWC24Err DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { NWC24DlTask dlTasks[2]; u8 dta[0x448]; char url[0x100]; @@ -472,7 +472,8 @@ s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { u16 ids[2]; u32 outSize; - s32 error; + NWC24Err error; + s32 vfError; BOOL found = FALSE; if (doForecast != 0) { @@ -507,17 +508,17 @@ s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { continue; error = NWC24GetDlTask(&dlTasks[i], ids[i]); - if (error == -0xD) { + if (error == NWC24_ERR_NOT_FOUND) { SetTaskMessage(task, "NWC24GetDlTask() failed.", NWC24GetErrorCode(), error); - return -1; + return NWC24_ERR_FATAL; } - if (error != 0) { + if (error != NWC24_OK) { return SetTaskError(task, "NWC24GetDlTask() failed.", error); } error = NWC24GetDlUrl(&urlTask[i], url, 0xFF); - if (error != 0) { + if (error != NWC24_OK) { return SetTaskError(task, "NWC24GetDlUrl() failed.", error); } @@ -526,7 +527,7 @@ s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { while (j < 0xFF && url[j] != 0) { if (url[j] != (&task->mForecastUrl)[i][j]) { SetTaskMessage(task, "URL is not same.", 0, 0); - return -1; + return NWC24_ERR_FATAL; } j++; @@ -539,14 +540,14 @@ s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { continue; error = NWC24GetDlVfName(&dlTasks[i], vfName, 0x50); - if (error != 0) { + if (error != NWC24_OK) { return SetTaskError(task, "NWC24GetDlVfName() failed.", error); } - error = VFMountDriveNANDFlashEx(sVfDriveName, vfName); - if (error != 0) { - SetTaskMessage(task, "VFMountDriveNANDFlash() failed.", 0, error); - return -1; + vfError = VFMountDriveNANDFlashEx(sVfDriveName, vfName); + if (vfError != 0) { + SetTaskMessage(task, "VFMountDriveNANDFlash() failed.", 0, vfError); + return NWC24_ERR_FATAL; } s32 searchResult = VFFileSearchFirst(dta, sVfRootPath, 0x7F); @@ -566,7 +567,7 @@ s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { continue; error = NWC24GetDlFilename(&dlTasks[i], fileName, 0x10); - if (error != 0) { + if (error != NWC24_OK) { return SetTaskError(task, "NWC24GetDlFilename() failed.", error); } @@ -574,17 +575,17 @@ s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { if (file == NULL) { SetTaskMessage(task, "VFOpenFile() failed.", NWC24GetErrorCode(), 0); - error = VFUnmountDrive(sVfDriveName); - if (error != 0) { - SetTaskMessage(task, "VFUnmountDrive() failed.", 0, error); - return -7; + vfError = VFUnmountDrive(sVfDriveName); + if (vfError != 0) { + SetTaskMessage(task, "VFUnmountDrive() failed.", 0, vfError); + return NWC24_ERR_PROTECTED; } - return -1; + return NWC24_ERR_FATAL; } - error = ReadCompressedFile(task, file, buffers[i], task->mBufferSizes[i], &outSize); - if (error != 0) - return error; + NWC24Err result = ReadCompressedFile(task, file, buffers[i], task->mBufferSizes[i], &outSize); + if (result != NWC24_OK) + return result; *sizes[i] = outSize; @@ -598,34 +599,34 @@ s32 DownloadFiles(WC24Task* task, u32 doForecast, u32 doShort) { size++; } - error = VFCloseFile(file); - if (error != 0) { - SetTaskMessage(task, "VFCloseFile() failed.", 0, error); + vfError = VFCloseFile(file); + if (vfError != 0) { + SetTaskMessage(task, "VFCloseFile() failed.", 0, vfError); VFUnmountDrive(sVfDriveName); - return -7; + return NWC24_ERR_PROTECTED; } error = NWC24GetDlLastUpdate(&dlTasks[i], times[i]); - if (error != 0) { + if (error != NWC24_OK) { return SetTaskError(task, "NWC24GetDlLastUpdate() failed.", error); } error = NWC24GetDlNextTime(&pTask[i], &task->mNextDownloadTimes[i]); - if (error != 0) { + if (error != NWC24_OK) { return SetTaskError(task, "NWC24GetDlNextTime() failed.", error); } } - error = VFUnmountDrive(sVfDriveName); - if (error != 0) { - SetTaskMessage(task, "VFUnmoundDrive() failed.", 0, error); - return -7; + vfError = VFUnmountDrive(sVfDriveName); + if (vfError != 0) { + SetTaskMessage(task, "VFUnmoundDrive() failed.", 0, vfError); + return NWC24_ERR_PROTECTED; } - return 0; + return NWC24_OK; } -s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, +NWC24Err CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownload, u16 newInterval, u16 count, u32* idOut) { NWC24DlTask dlTasks[2]; u8 search[0x448]; @@ -638,7 +639,8 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo u16 ids[2]; u16 interval; - s32 error; + NWC24Err error; + s32 vfError; BOOL redo = redownload; BOOL init = redownload; BOOL mounted = FALSE; @@ -668,30 +670,30 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo goto firstDone; error = NWC24GetDlTask(&dlTasks[i], ids[i]); - if (error == -0xD) { + if (error == NWC24_ERR_NOT_FOUND) { redo = TRUE; init = TRUE; goto firstDone; } - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24GetDlTask() failed.", error); error = NWC24GetDlVfName(&pTask[i], vfName, 0x50); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24GetDlVfName() failed.", error); if (!mounted) { - error = VFMountDriveNANDFlashEx(sVfDriveName, vfName); - if (error == 2 || error == 0xB001) { + vfError = VFMountDriveNANDFlashEx(sVfDriveName, vfName); + if (vfError == 2 || vfError == 0xB001) { redo = TRUE; init = TRUE; goto firstDone; } - if (error != 0) { - SetTaskMessage(task, "VFMountDriveNANDFlash() failed.", 0, error); - return -7; + if (vfError != 0) { + SetTaskMessage(task, "VFMountDriveNANDFlash() failed.", 0, vfError); + return NWC24_ERR_PROTECTED; } mounted = TRUE; @@ -707,7 +709,7 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo case 3: case 4: { error = NWC24GetDlFilename(&pTask[i], fileName, 0x10); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24GetDlFilename() failed.", error); void* file = VFOpenFile(fileName, sVfReadMode, 0); @@ -717,11 +719,11 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo continue; } - error = VFCloseFile(file); - if (error != 0) { - SetTaskMessage(task, "VFCloseFile() failed.", 0, error); + vfError = VFCloseFile(file); + if (vfError != 0) { + SetTaskMessage(task, "VFCloseFile() failed.", 0, vfError); VFUnmountDrive(sVfDriveName); - return -7; + return NWC24_ERR_PROTECTED; } break; } @@ -730,10 +732,10 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo firstDone: if (mounted) { - error = VFUnmountDrive(sVfDriveName); - if (error != 0) { - SetTaskMessage(task, "VFUnmountDrive() failed.", 0, error); - return -7; + vfError = VFUnmountDrive(sVfDriveName); + if (vfError != 0) { + SetTaskMessage(task, "VFUnmountDrive() failed.", 0, vfError); + return NWC24_ERR_PROTECTED; } } @@ -743,7 +745,7 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo continue; error = NWC24GetDlUrl(&dlTasks[i], url, 0xFF); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24GetDlUrl() failed.", error); const char* p = url; @@ -759,7 +761,7 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo } error = NWC24GetDlInterval(&dlTasks[i], &interval); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24GetDlInterval() failed.", error); if (newInterval != interval) @@ -777,26 +779,26 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo if (init) { error = NWC24InitDlTask(&dlTasks[i], 1); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24InitDlTask() failed.", error); error = NWC24SetDlId(&dlTasks[i], ids[i]); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24SetDlId() failed.", error); error = NWC24GetDlVfName(&pTask2[i], vfName2, 0x50); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24GetDlVfName() failed.", error); if (!created) { - error = NANDDelete(vfName2); - if (error != -0xC && error != 0) { - SetTaskMessage(task, "NANDDelete() failed.", 0, error); - return -8; + s32 nandResult = NANDDelete(vfName2); + if (nandResult != NAND_RESULT_NOEXISTS && nandResult != NAND_RESULT_OK) { + SetTaskMessage(task, "NANDDelete() failed.", 0, nandResult); + return NWC24_ERR_OVERFLOW; } error = NWC24CreateDlVf(&pTask2[i], task->mForecastBufferSize); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24CreateDlVf() failed.", error); created = TRUE; @@ -804,7 +806,7 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo } error = NWC24SetDlUrl(&dlTasks[i], urls[i]); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24SetDlUrl() failed.", error); s32 priority; @@ -821,24 +823,24 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo } error = NWC24SetDlPriority(&dlTasks[i], priority); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24SetDlPriority() failed.", error); error = NWC24SetDlFlags(&dlTasks[i], 0x40000000); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24SetDlFlags() failed.", error); error = NWC24SetDlInterval(&dlTasks[i], newInterval); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24SetDlInterval() failed.", error); error = NWC24SetDlRetryMargin(&dlTasks[i], margin); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24SetDlRetryMargin() failed.", error); sprintf(nameBuf, sBinNameFormat, ids[i]); error = NWC24SetDlFilename(&dlTasks[i], nameBuf); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24SetDlFilename() failed.", error); } } @@ -849,22 +851,22 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo continue; error = NWC24SetDlCount(&dlTasks[i], (s16)count); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24SetDlCount() failed.", error); if (redo) { error = NWC24AddDlTask(&dlTasks[i]); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24AddDlTask() failed.", error); } else { error = NWC24UpdateDlTask(&dlTasks[i]); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24UpdateDlTask() failed.", error); } if (idOut != NULL) { error = NWC24GetDlId(&pTask3[i], idOut); - if (error != 0) + if (error != NWC24_OK) return SetTaskError(task, "NWC24GetDlId() failed.", error); } @@ -872,7 +874,7 @@ s32 CreateDownloadTasks(WC24Task* task, u32 doForecast, u32 doShort, u8 redownlo } gWC24DownloadComplete = 1; - return 0; + return NWC24_OK; } struct WC24SOConfig { @@ -880,10 +882,10 @@ struct WC24SOConfig { void* free; }; -s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2) { +NWC24Err ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2) { s32 initResult; s32 startupResult; - s32 error; + NWC24Err error; s32 taskId; WC24SOConfig config; @@ -898,14 +900,14 @@ s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2) { if (initResult < 0) { SetTaskMessage(task, "SOInit() failed.", 0, initResult); gWC24ShutdownFlag2 = 0; - return -9; + return NWC24_ERR_LIB_NOT_OPENED; } startupResult = SOStartup(); if (startupResult < 0) { SetTaskMessage(task, "SOStartup() failed.", SOGetLastError(), startupResult); gWC24ShutdownFlag2 = 0; - return -9; + return NWC24_ERR_LIB_NOT_OPENED; } gWC24NetInitialized = 1; @@ -919,16 +921,16 @@ s32 ExecuteDownloadTask(WC24Task* task, s32 index, u32 unused, u16 unused2) { error = NWC24ExecDownloadTask(2, taskId, 0); gWC24ShutdownFlag1 = 0; - if (error != 0) { + if (error != NWC24_OK) { SetTaskMessage(task, "NWC24ExecDownloadTask() failed.", NWC24GetErrorCode(), error); return MapDownloadError(error); } break; } - return 0; + return NWC24_OK; } -s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort) { +NWC24Err DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort) { NWC24DlTask dlTask; char vfName[0x50]; u16 ids[2]; @@ -950,40 +952,40 @@ s32 DeleteTaskFiles(WC24Task* task, u32 doForecast, u32 doShort) { if (ids[i] == 0) continue; - s32 error = NWC24GetDlTask(&dlTask, ids[i]); - if (error == -0xD) + NWC24Err error = NWC24GetDlTask(&dlTask, ids[i]); + if (error == NWC24_ERR_NOT_FOUND) continue; - if (error != 0) { + if (error != NWC24_OK) { return SetTaskError(task, "NWC24GetDl*() failed.", error); } if (!found) { found = TRUE; error = NWC24GetDlVfName(&dlTask, vfName, 0x50); - if (error != 0) { + if (error != NWC24_OK) { return SetTaskError(task, "NWC24GetDlVfName() failed.", error); } } error = NWC24DeleteDlTask(&dlTask); - if (error != 0) { + if (error != NWC24_OK) { return SetTaskError(task, "NWC24DeleteDlTask() failed.", error); } } if (found) { - s32 error = NANDDelete(vfName); - if (error != -0xC && error != 0) { - SetTaskMessage(task, "NANDDelete() failed.", 0, error); - return -8; + s32 nandResult = NANDDelete(vfName); + if (nandResult != NAND_RESULT_NOEXISTS && nandResult != NAND_RESULT_OK) { + SetTaskMessage(task, "NANDDelete() failed.", 0, nandResult); + return NWC24_ERR_OVERFLOW; } } - return 0; + return NWC24_OK; } -NWC24Err MapDownloadError(s32 error) { +NWC24Err MapDownloadError(NWC24Err error) { NWC24Err mapped = NWC24_ERR_FULL; if ((error <= NWC24_ERR_FILE_OPEN && error >= NWC24_ERR_FILE_OTHER) || @@ -1016,7 +1018,7 @@ NWC24Err MapDownloadError(s32 error) { return mapped; } -s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, +NWC24Err ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, u32* outSize) { u32 fileSize = VFGetFileSizeByFd(fd); u32 uncompSize = 0; @@ -1030,22 +1032,22 @@ s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, if (chunk > 0x10000) chunk = 0x10000; - s32 error = VFReadFile(fd, gWC24FileBuffer, chunk, NULL); - if (error != 0) { - SetTaskMessage(task, "VFReadFile() failed.", 0, error); - return -7; + s32 vfError = VFReadFile(fd, gWC24FileBuffer, chunk, NULL); + if (vfError != 0) { + SetTaskMessage(task, "VFReadFile() failed.", 0, vfError); + return NWC24_ERR_PROTECTED; } if (offset == 0) { if ((gWC24FileBuffer[0] & 0xF0) != 0x10) { SetTaskMessage(task, "CXGetCompressionType() data is not LZ.", 0, 0); - return -5; + return NWC24_ERR_NULL; } uncompSize = CXGetUncompressedSize(gWC24FileBuffer); if (uncompSize > destSize) { SetTaskMessage(task, "CXGetUncompressedSize() overflow.", 0, 0); - return -5; + return NWC24_ERR_NULL; } } @@ -1057,11 +1059,11 @@ s32 ReadCompressedFile(WC24Task* task, void* fd, void* dest, u32 destSize, BOOL notFinished = ctx.destCount > 0 || ctx.headerSize > 0; if (notFinished) { SetTaskMessage(task, "CXIsFinisiedUncompLZ() is false.", 0, 0); - return -0xA; + return NWC24_ERR_LIB_OPENED; } *outSize = uncompSize; - return 0; + return NWC24_OK; } void* WC24Alloc(u32 unused, s32 size) {