get this started: refactor SPI in OOP
This commit is contained in:
parent
70c6750561
commit
440b356674
11
src/DSi.cpp
11
src/DSi.cpp
|
@ -403,6 +403,7 @@ void SetupDirectBoot()
|
||||||
NDSHeader& header = NDSCart::Cart->GetHeader();
|
NDSHeader& header = NDSCart::Cart->GetHeader();
|
||||||
const u8* cartrom = NDSCart::Cart->GetROM();
|
const u8* cartrom = NDSCart::Cart->GetROM();
|
||||||
u32 cartid = NDSCart::Cart->ID();
|
u32 cartid = NDSCart::Cart->ID();
|
||||||
|
DSi_TSC* tsc = (DSi_TSC*)NDS::SPI->GetTSC();
|
||||||
|
|
||||||
// TODO: add controls for forcing DS or DSi mode?
|
// TODO: add controls for forcing DS or DSi mode?
|
||||||
if (!(header.UnitCode & 0x02))
|
if (!(header.UnitCode & 0x02))
|
||||||
|
@ -429,7 +430,7 @@ void SetupDirectBoot()
|
||||||
|
|
||||||
NDS::MapSharedWRAM(3);
|
NDS::MapSharedWRAM(3);
|
||||||
|
|
||||||
DSi_SPI_TSC::SetMode(0x00);
|
tsc->SetMode(0x00);
|
||||||
Set_SCFG_Clock9(0x0000);
|
Set_SCFG_Clock9(0x0000);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -481,7 +482,7 @@ void SetupDirectBoot()
|
||||||
NDS::MapSharedWRAM(mbk[11] >> 24);
|
NDS::MapSharedWRAM(mbk[11] >> 24);
|
||||||
|
|
||||||
if (!(header.AppFlags & (1<<0)))
|
if (!(header.AppFlags & (1<<0)))
|
||||||
DSi_SPI_TSC::SetMode(0x00);
|
tsc->SetMode(0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup main RAM data
|
// setup main RAM data
|
||||||
|
@ -552,12 +553,12 @@ void SetupDirectBoot()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::WifiBoard nwifiver = SPI_Firmware::GetFirmware()->Header().WifiBoard;
|
Firmware::WifiBoard nwifiver = NDS::SPI->GetFirmware()->GetHeader().WifiBoard;
|
||||||
ARM9Write8(0x020005E0, static_cast<u8>(nwifiver));
|
ARM9Write8(0x020005E0, static_cast<u8>(nwifiver));
|
||||||
|
|
||||||
// TODO: these should be taken from the wifi firmware in NAND
|
// TODO: these should be taken from the wifi firmware in NAND
|
||||||
// but, hey, this works too.
|
// but, hey, this works too.
|
||||||
if (nwifiver == SPI_Firmware::WifiBoard::W015)
|
if (nwifiver == Firmware::WifiBoard::W015)
|
||||||
{
|
{
|
||||||
ARM9Write16(0x020005E2, 0xB57E);
|
ARM9Write16(0x020005E2, 0xB57E);
|
||||||
ARM9Write32(0x020005E4, 0x00500400);
|
ARM9Write32(0x020005E4, 0x00500400);
|
||||||
|
@ -642,7 +643,7 @@ void SetupDirectBoot()
|
||||||
|
|
||||||
NDS::ARM7BIOSProt = 0x20;
|
NDS::ARM7BIOSProt = 0x20;
|
||||||
|
|
||||||
SPI_Firmware::SetupDirectBoot(true);
|
NDS::SPI->GetFirmwareMem()->SetupDirectBoot(true);
|
||||||
|
|
||||||
NDS::ARM9->CP15Write(0x100, 0x00056078);
|
NDS::ARM9->CP15Write(0x100, 0x00056078);
|
||||||
NDS::ARM9->CP15Write(0x200, 0x0000004A);
|
NDS::ARM9->CP15Write(0x200, 0x0000004A);
|
||||||
|
|
|
@ -144,7 +144,7 @@ u8 GetBatteryLevel() { return Registers[0x20] & 0xF; }
|
||||||
void SetBatteryLevel(u8 batteryLevel)
|
void SetBatteryLevel(u8 batteryLevel)
|
||||||
{
|
{
|
||||||
Registers[0x20] = ((Registers[0x20] & 0xF0) | (batteryLevel & 0x0F));
|
Registers[0x20] = ((Registers[0x20] & 0xF0) | (batteryLevel & 0x0F));
|
||||||
SPI_Powerman::SetBatteryLevelOkay(batteryLevel > batteryLevel_Low ? true : false);
|
//SPI_Powerman::SetBatteryLevelOkay(batteryLevel > batteryLevel_Low ? true : false);
|
||||||
|
|
||||||
if (batteryLevel <= 1)
|
if (batteryLevel <= 1)
|
||||||
{
|
{
|
||||||
|
|
|
@ -161,7 +161,7 @@ union DSiFirmwareSystemSettings
|
||||||
u32 ConfigFlags;
|
u32 ConfigFlags;
|
||||||
u8 Zero02;
|
u8 Zero02;
|
||||||
u8 CountryCode;
|
u8 CountryCode;
|
||||||
SPI_Firmware::Language Language;
|
Firmware::Language Language;
|
||||||
u8 RTCYear;
|
u8 RTCYear;
|
||||||
u32 RTCOffset;
|
u32 RTCOffset;
|
||||||
u8 Zero3[4];
|
u8 Zero3[4];
|
||||||
|
|
|
@ -145,7 +145,6 @@ DSi_NWifi::~DSi_NWifi()
|
||||||
|
|
||||||
void DSi_NWifi::Reset()
|
void DSi_NWifi::Reset()
|
||||||
{
|
{
|
||||||
using namespace SPI_Firmware;
|
|
||||||
TransferCmd = 0xFFFFFFFF;
|
TransferCmd = 0xFFFFFFFF;
|
||||||
RemSize = 0;
|
RemSize = 0;
|
||||||
|
|
||||||
|
@ -162,26 +161,28 @@ void DSi_NWifi::Reset()
|
||||||
for (int i = 0; i < 9; i++)
|
for (int i = 0; i < 9; i++)
|
||||||
Mailbox[i].Clear();
|
Mailbox[i].Clear();
|
||||||
|
|
||||||
MacAddress mac = GetFirmware()->Header().MacAddress;
|
const Firmware* fw = NDS::SPI->GetFirmware();
|
||||||
|
|
||||||
|
MacAddress mac = fw->GetHeader().MacAddress;
|
||||||
Log(LogLevel::Info, "NWifi MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
Log(LogLevel::Info, "NWifi MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
|
|
||||||
WifiBoard type = GetFirmware()->Header().WifiBoard;
|
Firmware::WifiBoard type = fw->GetHeader().WifiBoard;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case WifiBoard::W015: // AR6002
|
case Firmware::WifiBoard::W015: // AR6002
|
||||||
ROMID = 0x20000188;
|
ROMID = 0x20000188;
|
||||||
ChipID = 0x02000001;
|
ChipID = 0x02000001;
|
||||||
HostIntAddr = 0x00500400;
|
HostIntAddr = 0x00500400;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WifiBoard::W024: // AR6013
|
case Firmware::WifiBoard::W024: // AR6013
|
||||||
ROMID = 0x23000024;
|
ROMID = 0x23000024;
|
||||||
ChipID = 0x0D000000;
|
ChipID = 0x0D000000;
|
||||||
HostIntAddr = 0x00520000;
|
HostIntAddr = 0x00520000;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WifiBoard::W028: // AR6014 (3DS)
|
case Firmware::WifiBoard::W028: // AR6014 (3DS)
|
||||||
ROMID = 0x2300006F;
|
ROMID = 0x2300006F;
|
||||||
ChipID = 0x0D000001;
|
ChipID = 0x0D000001;
|
||||||
HostIntAddr = 0x00520000;
|
HostIntAddr = 0x00520000;
|
||||||
|
@ -893,9 +894,8 @@ void DSi_NWifi::HTC_Command()
|
||||||
|
|
||||||
case 0x0004: // setup complete
|
case 0x0004: // setup complete
|
||||||
{
|
{
|
||||||
SPI_Firmware::MacAddress mac = SPI_Firmware::GetFirmware()->Header().MacAddress;
|
|
||||||
u8 ready_evt[12];
|
u8 ready_evt[12];
|
||||||
memcpy(&ready_evt[0], &mac, mac.size());
|
memcpy(&ready_evt[0], &EEPROM[0xA], 6); // MAC address
|
||||||
ready_evt[6] = 0x02;
|
ready_evt[6] = 0x02;
|
||||||
ready_evt[7] = 0;
|
ready_evt[7] = 0;
|
||||||
*(u32*)&ready_evt[8] = 0x2300006C;
|
*(u32*)&ready_evt[8] = 0x2300006C;
|
||||||
|
|
|
@ -19,38 +19,25 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "DSi.h"
|
#include "DSi.h"
|
||||||
#include "SPI.h"
|
|
||||||
#include "DSi_SPI_TSC.h"
|
#include "DSi_SPI_TSC.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
|
||||||
using Platform::Log;
|
using Platform::Log;
|
||||||
using Platform::LogLevel;
|
using Platform::LogLevel;
|
||||||
|
|
||||||
namespace DSi_SPI_TSC
|
|
||||||
{
|
|
||||||
|
|
||||||
u32 DataPos;
|
DSi_TSC::DSi_TSC(SPIHost* host) : TSC(host)
|
||||||
u8 Index;
|
|
||||||
u8 Bank;
|
|
||||||
u8 Data;
|
|
||||||
|
|
||||||
u8 Bank3Regs[0x80];
|
|
||||||
u8 TSCMode;
|
|
||||||
|
|
||||||
u16 TouchX, TouchY;
|
|
||||||
|
|
||||||
|
|
||||||
bool Init()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeInit()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset()
|
DSi_TSC::~DSi_TSC()
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSi_TSC::Reset()
|
||||||
|
{
|
||||||
|
TSC::Reset();
|
||||||
|
|
||||||
DataPos = 0;
|
DataPos = 0;
|
||||||
|
|
||||||
Bank = 0;
|
Bank = 0;
|
||||||
|
@ -72,8 +59,10 @@ void Reset()
|
||||||
TSCMode = 0x01; // DSi mode
|
TSCMode = 0x01; // DSi mode
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoSavestate(Savestate* file)
|
void DSi_TSC::DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
|
TSC::DoSavestate(file);
|
||||||
|
|
||||||
file->Section("SPTi");
|
file->Section("SPTi");
|
||||||
|
|
||||||
file->Var32(&DataPos);
|
file->Var32(&DataPos);
|
||||||
|
@ -85,19 +74,14 @@ void DoSavestate(Savestate* file)
|
||||||
file->Var8(&TSCMode);
|
file->Var8(&TSCMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetMode(u8 mode)
|
void DSi_TSC::SetMode(u8 mode)
|
||||||
{
|
{
|
||||||
TSCMode = mode;
|
TSCMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTouchCoords(u16 x, u16 y)
|
void DSi_TSC::SetTouchCoords(u16 x, u16 y)
|
||||||
{
|
{
|
||||||
if (TSCMode == 0x00)
|
if (TSCMode == 0x00) return TSC::SetTouchCoords(x, y);
|
||||||
{
|
|
||||||
if (y == 0xFFF) NDS::KeyInput |= (1 << (16+6));
|
|
||||||
else NDS::KeyInput &= ~(1 << (16+6));
|
|
||||||
return SPI_TSC::SetTouchCoords(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
TouchX = x;
|
TouchX = x;
|
||||||
TouchY = y;
|
TouchY = y;
|
||||||
|
@ -135,24 +119,17 @@ void SetTouchCoords(u16 x, u16 y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicInputFrame(s16* data, int samples)
|
void DSi_TSC::MicInputFrame(s16* data, int samples)
|
||||||
{
|
{
|
||||||
if (TSCMode == 0x00) return SPI_TSC::MicInputFrame(data, samples);
|
if (TSCMode == 0x00) return TSC::MicInputFrame(data, samples);
|
||||||
|
|
||||||
// otherwise we don't handle mic input
|
// otherwise we don't handle mic input
|
||||||
// TODO: handle it where it needs to be
|
// TODO: handle it where it needs to be
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Read()
|
void DSi_TSC::Write(u8 val)
|
||||||
{
|
{
|
||||||
if (TSCMode == 0x00) return SPI_TSC::Read();
|
if (TSCMode == 0x00) return TSC::Write(val);
|
||||||
|
|
||||||
return Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Write(u8 val, u32 hold)
|
|
||||||
{
|
|
||||||
if (TSCMode == 0x00) return SPI_TSC::Write(val, hold);
|
|
||||||
|
|
||||||
#define READWRITE(var) { if (Index & 0x01) Data = var; else var = val; }
|
#define READWRITE(var) { if (Index & 0x01) Data = var; else var = val; }
|
||||||
|
|
||||||
|
@ -233,8 +210,12 @@ void Write(u8 val, u32 hold)
|
||||||
Index += (1<<1); // increment index
|
Index += (1<<1); // increment index
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hold) DataPos++;
|
DataPos++;
|
||||||
else DataPos = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DSi_TSC::Release()
|
||||||
|
{
|
||||||
|
if (TSCMode == 0x00) return TSC::Release();
|
||||||
|
|
||||||
|
DataPos = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,26 +21,33 @@
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "Savestate.h"
|
#include "Savestate.h"
|
||||||
|
#include "SPI.h"
|
||||||
|
|
||||||
namespace DSi_SPI_TSC
|
class DSi_TSC : public TSC
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
DSi_TSC(SPIHost* host);
|
||||||
|
~DSi_TSC() override;
|
||||||
|
|
||||||
extern u32 DataPos;
|
void Reset() override;
|
||||||
|
|
||||||
bool Init();
|
void DoSavestate(Savestate* file) override;
|
||||||
void DeInit();
|
|
||||||
void Reset();
|
|
||||||
void DoSavestate(Savestate* file);
|
|
||||||
|
|
||||||
// 00=DS-mode 01=normal
|
// 00=DS-mode 01=normal
|
||||||
void SetMode(u8 mode);
|
void SetMode(u8 mode);
|
||||||
|
|
||||||
void SetTouchCoords(u16 x, u16 y);
|
void SetTouchCoords(u16 x, u16 y) override;
|
||||||
void MicInputFrame(s16* data, int samples);
|
void MicInputFrame(s16* data, int samples) override;
|
||||||
|
|
||||||
u8 Read();
|
void Write(u8 val) override;
|
||||||
void Write(u8 val, u32 hold);
|
void Release() override;
|
||||||
|
|
||||||
}
|
private:
|
||||||
|
u8 Index;
|
||||||
|
u8 Bank;
|
||||||
|
|
||||||
|
u8 Bank3Regs[0x80];
|
||||||
|
u8 TSCMode;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // DSI_SPI_TSC
|
#endif // DSI_SPI_TSC
|
||||||
|
|
57
src/NDS.cpp
57
src/NDS.cpp
|
@ -178,6 +178,8 @@ u32 KeyInput;
|
||||||
u16 KeyCnt[2];
|
u16 KeyCnt[2];
|
||||||
u16 RCnt;
|
u16 RCnt;
|
||||||
|
|
||||||
|
SPIHost* SPI;
|
||||||
|
|
||||||
bool Running;
|
bool Running;
|
||||||
|
|
||||||
bool RunningGame;
|
bool RunningGame;
|
||||||
|
@ -215,11 +217,12 @@ bool Init()
|
||||||
DMAs[6] = new DMA(1, 2);
|
DMAs[6] = new DMA(1, 2);
|
||||||
DMAs[7] = new DMA(1, 3);
|
DMAs[7] = new DMA(1, 3);
|
||||||
|
|
||||||
|
SPI = new SPIHost();
|
||||||
|
|
||||||
if (!NDSCart::Init()) return false;
|
if (!NDSCart::Init()) return false;
|
||||||
if (!GBACart::Init()) return false;
|
if (!GBACart::Init()) return false;
|
||||||
if (!GPU::Init()) return false;
|
if (!GPU::Init()) return false;
|
||||||
if (!SPU::Init()) return false;
|
if (!SPU::Init()) return false;
|
||||||
if (!SPI::Init()) return false;
|
|
||||||
if (!RTC::Init()) return false;
|
if (!RTC::Init()) return false;
|
||||||
if (!Wifi::Init()) return false;
|
if (!Wifi::Init()) return false;
|
||||||
|
|
||||||
|
@ -248,11 +251,13 @@ void DeInit()
|
||||||
DMAs[i] = nullptr;
|
DMAs[i] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete SPI;
|
||||||
|
SPI = nullptr;
|
||||||
|
|
||||||
NDSCart::DeInit();
|
NDSCart::DeInit();
|
||||||
GBACart::DeInit();
|
GBACart::DeInit();
|
||||||
GPU::DeInit();
|
GPU::DeInit();
|
||||||
SPU::DeInit();
|
SPU::DeInit();
|
||||||
SPI::DeInit();
|
|
||||||
RTC::DeInit();
|
RTC::DeInit();
|
||||||
Wifi::DeInit();
|
Wifi::DeInit();
|
||||||
|
|
||||||
|
@ -389,7 +394,7 @@ bool NeedsDirectBoot()
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// DSi/3DS firmwares aren't bootable
|
// DSi/3DS firmwares aren't bootable
|
||||||
if (!SPI_Firmware::GetFirmware()->IsBootable())
|
if (!SPI->GetFirmware()->IsBootable())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -465,7 +470,7 @@ void SetupDirectBoot(const std::string& romname)
|
||||||
|
|
||||||
ARM7BIOSProt = 0x1204;
|
ARM7BIOSProt = 0x1204;
|
||||||
|
|
||||||
SPI_Firmware::SetupDirectBoot(false);
|
SPI->GetFirmwareMem()->SetupDirectBoot(false);
|
||||||
|
|
||||||
ARM9->CP15Write(0x100, 0x00012078);
|
ARM9->CP15Write(0x100, 0x00012078);
|
||||||
ARM9->CP15Write(0x200, 0x00000042);
|
ARM9->CP15Write(0x200, 0x00000042);
|
||||||
|
@ -641,7 +646,7 @@ void Reset()
|
||||||
GBACart::Reset();
|
GBACart::Reset();
|
||||||
GPU::Reset();
|
GPU::Reset();
|
||||||
SPU::Reset();
|
SPU::Reset();
|
||||||
SPI::Reset();
|
SPI->Reset();
|
||||||
RTC::Reset();
|
RTC::Reset();
|
||||||
Wifi::Reset();
|
Wifi::Reset();
|
||||||
|
|
||||||
|
@ -843,7 +848,7 @@ bool DoSavestate(Savestate* file)
|
||||||
GBACart::DoSavestate(file);
|
GBACart::DoSavestate(file);
|
||||||
GPU::DoSavestate(file);
|
GPU::DoSavestate(file);
|
||||||
SPU::DoSavestate(file);
|
SPU::DoSavestate(file);
|
||||||
SPI::DoSavestate(file);
|
SPI->DoSavestate(file);
|
||||||
RTC::DoSavestate(file);
|
RTC::DoSavestate(file);
|
||||||
Wifi::DoSavestate(file);
|
Wifi::DoSavestate(file);
|
||||||
|
|
||||||
|
@ -1279,28 +1284,12 @@ void CancelEvent(u32 id)
|
||||||
|
|
||||||
void TouchScreen(u16 x, u16 y)
|
void TouchScreen(u16 x, u16 y)
|
||||||
{
|
{
|
||||||
if (ConsoleType == 1)
|
SPI->GetTSC()->SetTouchCoords(x, y);
|
||||||
{
|
|
||||||
DSi_SPI_TSC::SetTouchCoords(x, y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SPI_TSC::SetTouchCoords(x, y);
|
|
||||||
KeyInput &= ~(1 << (16+6));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseScreen()
|
void ReleaseScreen()
|
||||||
{
|
{
|
||||||
if (ConsoleType == 1)
|
SPI->GetTSC()->SetTouchCoords(0x000, 0xFFF);
|
||||||
{
|
|
||||||
DSi_SPI_TSC::SetTouchCoords(0x000, 0xFFF);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SPI_TSC::SetTouchCoords(0x000, 0xFFF);
|
|
||||||
KeyInput |= (1 << (16+6));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1383,7 +1372,7 @@ void CamInputFrame(int cam, u32* data, int width, int height, bool rgb)
|
||||||
|
|
||||||
void MicInputFrame(s16* data, int samples)
|
void MicInputFrame(s16* data, int samples)
|
||||||
{
|
{
|
||||||
return SPI_TSC::MicInputFrame(data, samples);
|
return SPI->GetTSC()->MicInputFrame(data, samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*int ImportSRAM(u8* data, u32 length)
|
/*int ImportSRAM(u8* data, u32 length)
|
||||||
|
@ -3917,7 +3906,7 @@ u8 ARM7IORead8(u32 addr)
|
||||||
return NDSCart::ROMCommand[7];
|
return NDSCart::ROMCommand[7];
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 0x040001C2: return SPI::ReadData();
|
case 0x040001C2: return SPI->ReadData();
|
||||||
|
|
||||||
case 0x04000208: return IME[1];
|
case 0x04000208: return IME[1];
|
||||||
|
|
||||||
|
@ -4005,8 +3994,8 @@ u16 ARM7IORead16(u32 addr)
|
||||||
(NDSCart::ROMCommand[7] << 8);
|
(NDSCart::ROMCommand[7] << 8);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 0x040001C0: return SPI::Cnt;
|
case 0x040001C0: return SPI->ReadCnt();
|
||||||
case 0x040001C2: return SPI::ReadData();
|
case 0x040001C2: return SPI->ReadData();
|
||||||
|
|
||||||
case 0x04000204: return ExMemCnt[1];
|
case 0x04000204: return ExMemCnt[1];
|
||||||
case 0x04000206:
|
case 0x04000206:
|
||||||
|
@ -4088,7 +4077,7 @@ u32 ARM7IORead32(u32 addr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 0x040001C0:
|
case 0x040001C0:
|
||||||
return SPI::Cnt | (SPI::ReadData() << 16);
|
return SPI->ReadCnt() | (SPI->ReadData() << 16);
|
||||||
|
|
||||||
case 0x04000208: return IME[1];
|
case 0x04000208: return IME[1];
|
||||||
case 0x04000210: return IE[1];
|
case 0x04000210: return IE[1];
|
||||||
|
@ -4181,7 +4170,7 @@ void ARM7IOWrite8(u32 addr, u8 val)
|
||||||
case 0x040001AF: if (ExMemCnt[0] & (1<<11)) NDSCart::ROMCommand[7] = val; return;
|
case 0x040001AF: if (ExMemCnt[0] & (1<<11)) NDSCart::ROMCommand[7] = val; return;
|
||||||
|
|
||||||
case 0x040001C2:
|
case 0x040001C2:
|
||||||
SPI::WriteData(val);
|
SPI->WriteData(val);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x04000208: IME[1] = val & 0x1; UpdateIRQ(1); return;
|
case 0x04000208: IME[1] = val & 0x1; UpdateIRQ(1); return;
|
||||||
|
@ -4309,10 +4298,10 @@ void ARM7IOWrite16(u32 addr, u16 val)
|
||||||
case 0x040001BA: ROMSeed1[12] = val & 0x7F; return;
|
case 0x040001BA: ROMSeed1[12] = val & 0x7F; return;
|
||||||
|
|
||||||
case 0x040001C0:
|
case 0x040001C0:
|
||||||
SPI::WriteCnt(val);
|
SPI->WriteCnt(val);
|
||||||
return;
|
return;
|
||||||
case 0x040001C2:
|
case 0x040001C2:
|
||||||
SPI::WriteData(val & 0xFF);
|
SPI->WriteData(val & 0xFF);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x04000204:
|
case 0x04000204:
|
||||||
|
@ -4462,8 +4451,8 @@ void ARM7IOWrite32(u32 addr, u32 val)
|
||||||
case 0x040001B4: *(u32*)&ROMSeed1[8] = val; return;
|
case 0x040001B4: *(u32*)&ROMSeed1[8] = val; return;
|
||||||
|
|
||||||
case 0x040001C0:
|
case 0x040001C0:
|
||||||
SPI::WriteCnt(val & 0xFFFF);
|
SPI->WriteCnt(val & 0xFFFF);
|
||||||
SPI::WriteData((val >> 16) & 0xFF);
|
SPI->WriteData((val >> 16) & 0xFF);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x04000208: IME[1] = val & 0x1; UpdateIRQ(1); return;
|
case 0x04000208: IME[1] = val & 0x1; UpdateIRQ(1); return;
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
// with this enabled, to make sure it doesn't desync
|
// with this enabled, to make sure it doesn't desync
|
||||||
//#define DEBUG_CHECK_DESYNC
|
//#define DEBUG_CHECK_DESYNC
|
||||||
|
|
||||||
|
class SPIHost;
|
||||||
|
|
||||||
namespace NDS
|
namespace NDS
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -246,6 +248,8 @@ extern MemRegion SWRAM_ARM7;
|
||||||
extern u32 KeyInput;
|
extern u32 KeyInput;
|
||||||
extern u16 RCnt;
|
extern u16 RCnt;
|
||||||
|
|
||||||
|
extern SPIHost* SPI;
|
||||||
|
|
||||||
const u32 ARM7WRAMSize = 0x10000;
|
const u32 ARM7WRAMSize = 0x10000;
|
||||||
extern u8* ARM7WRAM;
|
extern u8* ARM7WRAM;
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace SPI_Firmware
|
class Firmware;
|
||||||
{
|
|
||||||
class Firmware;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
|
@ -335,7 +332,7 @@ void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen
|
||||||
/// @param firmware The firmware that was just written.
|
/// @param firmware The firmware that was just written.
|
||||||
/// @param writeoffset The offset of the first byte that was written to firmware.
|
/// @param writeoffset The offset of the first byte that was written to firmware.
|
||||||
/// @param writelen The number of bytes that were written to firmware.
|
/// @param writelen The number of bytes that were written to firmware.
|
||||||
void WriteFirmware(const SPI_Firmware::Firmware& firmware, u32 writeoffset, u32 writelen);
|
void WriteFirmware(const Firmware& firmware, u32 writeoffset, u32 writelen);
|
||||||
|
|
||||||
// called when the RTC date/time is changed and the frontend might need to take it into account
|
// called when the RTC date/time is changed and the frontend might need to take it into account
|
||||||
void WriteDateTime(int year, int month, int day, int hour, int minute, int second);
|
void WriteDateTime(int year, int month, int day, int hour, int minute, int second);
|
||||||
|
|
358
src/SPI.cpp
358
src/SPI.cpp
|
@ -29,18 +29,6 @@
|
||||||
|
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
|
|
||||||
namespace SPI_Firmware
|
|
||||||
{
|
|
||||||
|
|
||||||
std::unique_ptr<Firmware> Firmware;
|
|
||||||
|
|
||||||
u32 Hold;
|
|
||||||
u8 CurCmd;
|
|
||||||
u32 DataPos;
|
|
||||||
u8 Data;
|
|
||||||
|
|
||||||
u8 StatusReg;
|
|
||||||
u32 Addr;
|
|
||||||
|
|
||||||
u16 CRC16(const u8* data, u32 len, u32 start)
|
u16 CRC16(const u8* data, u32 len, u32 start)
|
||||||
{
|
{
|
||||||
|
@ -65,7 +53,9 @@ u16 CRC16(const u8* data, u32 len, u32 start)
|
||||||
return start & 0xFFFF;
|
return start & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset)
|
|
||||||
|
|
||||||
|
bool FirmwareMem::VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset)
|
||||||
{
|
{
|
||||||
u16 crc_stored = *(u16*)&Firmware->Buffer()[crcoffset];
|
u16 crc_stored = *(u16*)&Firmware->Buffer()[crcoffset];
|
||||||
u16 crc_calced = CRC16(&Firmware->Buffer()[offset], len, start);
|
u16 crc_calced = CRC16(&Firmware->Buffer()[offset], len, start);
|
||||||
|
@ -73,40 +63,16 @@ bool VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Init()
|
FirmwareMem::FirmwareMem(SPIHost* host) : SPIDevice(host)
|
||||||
{
|
{
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeInit()
|
FirmwareMem::~FirmwareMem()
|
||||||
{
|
{
|
||||||
RemoveFirmware();
|
RemoveFirmware();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 FixFirmwareLength(u32 originalLength)
|
void FirmwareMem::Reset()
|
||||||
{
|
|
||||||
if (originalLength != 0x20000 && originalLength != 0x40000 && originalLength != 0x80000)
|
|
||||||
{
|
|
||||||
Log(LogLevel::Warn, "Bad firmware size %d, ", originalLength);
|
|
||||||
|
|
||||||
// pick the nearest power-of-two length
|
|
||||||
originalLength |= (originalLength >> 1);
|
|
||||||
originalLength |= (originalLength >> 2);
|
|
||||||
originalLength |= (originalLength >> 4);
|
|
||||||
originalLength |= (originalLength >> 8);
|
|
||||||
originalLength |= (originalLength >> 16);
|
|
||||||
originalLength++;
|
|
||||||
|
|
||||||
// ensure it's a sane length
|
|
||||||
if (originalLength > 0x80000) originalLength = 0x80000;
|
|
||||||
else if (originalLength < 0x20000) originalLength = 0x20000;
|
|
||||||
|
|
||||||
Log(LogLevel::Debug, "assuming %d\n", originalLength);
|
|
||||||
}
|
|
||||||
return originalLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset()
|
|
||||||
{
|
{
|
||||||
if (!Firmware)
|
if (!Firmware)
|
||||||
{
|
{
|
||||||
|
@ -115,7 +81,7 @@ void Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix touchscreen coords
|
// fix touchscreen coords
|
||||||
for (UserData& u : Firmware->UserData())
|
for (auto& u : Firmware->GetUserData())
|
||||||
{
|
{
|
||||||
u.TouchCalibrationADC1[0] = 0;
|
u.TouchCalibrationADC1[0] = 0;
|
||||||
u.TouchCalibrationADC1[1] = 0;
|
u.TouchCalibrationADC1[1] = 0;
|
||||||
|
@ -132,7 +98,7 @@ void Reset()
|
||||||
// disable autoboot
|
// disable autoboot
|
||||||
//Firmware[userdata+0x64] &= 0xBF;
|
//Firmware[userdata+0x64] &= 0xBF;
|
||||||
|
|
||||||
MacAddress mac = Firmware->Header().MacAddress;
|
MacAddress mac = Firmware->GetHeader().MacAddress;
|
||||||
Log(LogLevel::Info, "MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
Log(LogLevel::Info, "MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||||
|
|
||||||
// verify shit
|
// verify shit
|
||||||
|
@ -150,14 +116,14 @@ void Reset()
|
||||||
StatusReg = 0x00;
|
StatusReg = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoSavestate(Savestate* file)
|
void FirmwareMem::DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
file->Section("SPFW");
|
file->Section("SPFW");
|
||||||
|
|
||||||
// CHECKME/TODO: trust the firmware to stay the same?????
|
// CHECKME/TODO: trust the firmware to stay the same?????
|
||||||
// embedding the whole firmware in the savestate would be derpo tho??
|
// embedding the whole firmware in the savestate would be derpo tho??
|
||||||
|
|
||||||
file->Var32(&Hold);
|
file->Bool32(&Hold);
|
||||||
file->Var8(&CurCmd);
|
file->Var8(&CurCmd);
|
||||||
file->Var32(&DataPos);
|
file->Var32(&DataPos);
|
||||||
file->Var8(&Data);
|
file->Var8(&Data);
|
||||||
|
@ -166,10 +132,10 @@ void DoSavestate(Savestate* file)
|
||||||
file->Var32(&Addr);
|
file->Var32(&Addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupDirectBoot(bool dsi)
|
void FirmwareMem::SetupDirectBoot(bool dsi)
|
||||||
{
|
{
|
||||||
const FirmwareHeader& header = Firmware->Header();
|
const auto& header = Firmware->GetHeader();
|
||||||
const UserData& userdata = Firmware->EffectiveUserData();
|
const auto& userdata = Firmware->GetEffectiveUserData();
|
||||||
if (dsi)
|
if (dsi)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < 6; i += 2)
|
for (u32 i = 0; i < 6; i += 2)
|
||||||
|
@ -194,17 +160,17 @@ void SetupDirectBoot(bool dsi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const class Firmware* GetFirmware()
|
const class Firmware* FirmwareMem::GetFirmware()
|
||||||
{
|
{
|
||||||
return Firmware.get();
|
return Firmware.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsLoadedFirmwareBuiltIn()
|
bool FirmwareMem::IsLoadedFirmwareBuiltIn()
|
||||||
{
|
{
|
||||||
return Firmware->Header().Identifier == GENERATED_FIRMWARE_IDENTIFIER;
|
return Firmware->GetHeader().Identifier == GENERATED_FIRMWARE_IDENTIFIER;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstallFirmware(class Firmware&& firmware)
|
bool FirmwareMem::InstallFirmware(class Firmware&& firmware)
|
||||||
{
|
{
|
||||||
if (!firmware.Buffer())
|
if (!firmware.Buffer())
|
||||||
{
|
{
|
||||||
|
@ -214,13 +180,13 @@ bool InstallFirmware(class Firmware&& firmware)
|
||||||
|
|
||||||
Firmware = std::make_unique<class Firmware>(std::move(firmware));
|
Firmware = std::make_unique<class Firmware>(std::move(firmware));
|
||||||
|
|
||||||
FirmwareIdentifier id = Firmware->Header().Identifier;
|
FirmwareIdentifier id = Firmware->GetHeader().Identifier;
|
||||||
Log(LogLevel::Debug, "Installed firmware (Identifier: %c%c%c%c)\n", id[0], id[1], id[2], id[3]);
|
Log(LogLevel::Debug, "Installed firmware (Identifier: %c%c%c%c)\n", id[0], id[1], id[2], id[3]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstallFirmware(std::unique_ptr<class Firmware>&& firmware)
|
bool FirmwareMem::InstallFirmware(std::unique_ptr<class Firmware>&& firmware)
|
||||||
{
|
{
|
||||||
if (!firmware)
|
if (!firmware)
|
||||||
{
|
{
|
||||||
|
@ -236,40 +202,42 @@ bool InstallFirmware(std::unique_ptr<class Firmware>&& firmware)
|
||||||
|
|
||||||
Firmware = std::move(firmware);
|
Firmware = std::move(firmware);
|
||||||
|
|
||||||
FirmwareIdentifier id = Firmware->Header().Identifier;
|
FirmwareIdentifier id = Firmware->GetHeader().Identifier;
|
||||||
Log(LogLevel::Debug, "Installed firmware (Identifier: %c%c%c%c)\n", id[0], id[1], id[2], id[3]);
|
Log(LogLevel::Debug, "Installed firmware (Identifier: %c%c%c%c)\n", id[0], id[1], id[2], id[3]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveFirmware()
|
void FirmwareMem::RemoveFirmware()
|
||||||
{
|
{
|
||||||
Firmware.reset();
|
Firmware.reset();
|
||||||
Log(LogLevel::Debug, "Removed installed firmware (if any)\n");
|
Log(LogLevel::Debug, "Removed installed firmware (if any)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Read()
|
void FirmwareMem::Write(u8 val)
|
||||||
{
|
{
|
||||||
return Data;
|
if (!Hold)
|
||||||
}
|
|
||||||
|
|
||||||
void Write(u8 val, u32 hold)
|
|
||||||
{
|
|
||||||
if (!hold)
|
|
||||||
{
|
|
||||||
if (!Hold) // commands with no paramters
|
|
||||||
CurCmd = val;
|
|
||||||
|
|
||||||
Hold = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hold && (!Hold))
|
|
||||||
{
|
{
|
||||||
CurCmd = val;
|
CurCmd = val;
|
||||||
Hold = 1;
|
Hold = true;
|
||||||
Data = 0;
|
Data = 0;
|
||||||
DataPos = 1;
|
DataPos = 1;
|
||||||
Addr = 0;
|
Addr = 0;
|
||||||
|
|
||||||
|
// handle commands with no parameters
|
||||||
|
switch (CurCmd)
|
||||||
|
{
|
||||||
|
case 0x04: // write disable
|
||||||
|
StatusReg &= ~(1<<1);
|
||||||
|
Data = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x06: // write enable
|
||||||
|
StatusReg |= (1<<1);
|
||||||
|
Data = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,20 +261,10 @@ void Write(u8 val, u32 hold)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x04: // write disable
|
|
||||||
StatusReg &= ~(1<<1);
|
|
||||||
Data = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x05: // read status reg
|
case 0x05: // read status reg
|
||||||
Data = StatusReg;
|
Data = StatusReg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x06: // write enable
|
|
||||||
StatusReg |= (1<<1);
|
|
||||||
Data = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x0A: // write
|
case 0x0A: // write
|
||||||
{
|
{
|
||||||
// TODO: what happens if you write too many bytes? (max 256, they say)
|
// TODO: what happens if you write too many bytes? (max 256, they say)
|
||||||
|
@ -345,45 +303,38 @@ void Write(u8 val, u32 hold)
|
||||||
Data = 0xFF;
|
Data = 0xFF;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!hold && (CurCmd == 0x02 || CurCmd == 0x0A))
|
void FirmwareMem::Release()
|
||||||
|
{
|
||||||
|
if (CurCmd == 0x02 || CurCmd == 0x0A)
|
||||||
{ // If the SPI firmware chip just finished a write...
|
{ // If the SPI firmware chip just finished a write...
|
||||||
// We only notify the frontend of changes to the Wi-fi/userdata settings region
|
// We only notify the frontend of changes to the Wi-fi/userdata settings region
|
||||||
// (although it might still decide to flush the whole thing)
|
// (although it might still decide to flush the whole thing)
|
||||||
u32 wifioffset = Firmware->WifiAccessPointOffset();
|
u32 wifioffset = Firmware->GetWifiAccessPointOffset();
|
||||||
|
|
||||||
// Request that the start of the Wi-fi/userdata settings region
|
// Request that the start of the Wi-fi/userdata settings region
|
||||||
// through the end of the firmware blob be flushed to disk
|
// through the end of the firmware blob be flushed to disk
|
||||||
Platform::WriteFirmware(*Firmware, wifioffset, Firmware->Length() - wifioffset);
|
Platform::WriteFirmware(*Firmware, wifioffset, Firmware->Length() - wifioffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SPIDevice::Release();
|
||||||
|
CurCmd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace SPI_Powerman
|
|
||||||
{
|
|
||||||
|
|
||||||
u32 Hold;
|
|
||||||
u32 DataPos;
|
|
||||||
u8 Index;
|
|
||||||
u8 Data;
|
|
||||||
|
|
||||||
u8 Registers[8];
|
|
||||||
u8 RegMasks[8];
|
|
||||||
|
|
||||||
|
|
||||||
bool Init()
|
PowerMan::PowerMan(SPIHost* host) : SPIDevice(host)
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeInit()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset()
|
PowerMan::~PowerMan()
|
||||||
{
|
{
|
||||||
Hold = 0;
|
}
|
||||||
|
|
||||||
|
void PowerMan::Reset()
|
||||||
|
{
|
||||||
|
Hold = false;
|
||||||
Index = 0;
|
Index = 0;
|
||||||
Data = 0;
|
Data = 0;
|
||||||
|
|
||||||
|
@ -399,14 +350,11 @@ void Reset()
|
||||||
RegMasks[4] = 0x0F;
|
RegMasks[4] = 0x0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetBatteryLevelOkay() { return !Registers[1]; }
|
void PowerMan::DoSavestate(Savestate* file)
|
||||||
void SetBatteryLevelOkay(bool okay) { Registers[1] = okay ? 0x00 : 0x01; }
|
|
||||||
|
|
||||||
void DoSavestate(Savestate* file)
|
|
||||||
{
|
{
|
||||||
file->Section("SPPW");
|
file->Section("SPPW");
|
||||||
|
|
||||||
file->Var32(&Hold);
|
file->Bool32(&Hold);
|
||||||
file->Var32(&DataPos);
|
file->Var32(&DataPos);
|
||||||
file->Var8(&Index);
|
file->Var8(&Index);
|
||||||
file->Var8(&Data);
|
file->Var8(&Data);
|
||||||
|
@ -415,22 +363,15 @@ void DoSavestate(Savestate* file)
|
||||||
file->VarArray(RegMasks, 8); // is that needed??
|
file->VarArray(RegMasks, 8); // is that needed??
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Read()
|
bool PowerMan::GetBatteryLevelOkay() { return !Registers[1]; }
|
||||||
{
|
void PowerMan::SetBatteryLevelOkay(bool okay) { Registers[1] = okay ? 0x00 : 0x01; }
|
||||||
return Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Write(u8 val, u32 hold)
|
void PowerMan::Write(u8 val)
|
||||||
{
|
{
|
||||||
if (!hold)
|
if (!Hold)
|
||||||
{
|
|
||||||
Hold = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hold && (!Hold))
|
|
||||||
{
|
{
|
||||||
Index = val;
|
Index = val;
|
||||||
Hold = 1;
|
Hold = true;
|
||||||
Data = 0;
|
Data = 0;
|
||||||
DataPos = 1;
|
DataPos = 1;
|
||||||
return;
|
return;
|
||||||
|
@ -465,35 +406,19 @@ void Write(u8 val, u32 hold)
|
||||||
Data = 0;
|
Data = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace SPI_TSC
|
TSC::TSC(SPIHost* host) : SPIDevice(host)
|
||||||
{
|
|
||||||
|
|
||||||
u32 DataPos;
|
|
||||||
u8 ControlByte;
|
|
||||||
u8 Data;
|
|
||||||
|
|
||||||
u16 ConvResult;
|
|
||||||
|
|
||||||
u16 TouchX, TouchY;
|
|
||||||
|
|
||||||
s16 MicBuffer[1024];
|
|
||||||
int MicBufferLen;
|
|
||||||
|
|
||||||
|
|
||||||
bool Init()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeInit()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset()
|
TSC::~TSC()
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TSC::Reset()
|
||||||
|
{
|
||||||
|
Hold = false;
|
||||||
ControlByte = 0;
|
ControlByte = 0;
|
||||||
Data = 0;
|
Data = 0;
|
||||||
|
|
||||||
|
@ -502,7 +427,7 @@ void Reset()
|
||||||
MicBufferLen = 0;
|
MicBufferLen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoSavestate(Savestate* file)
|
void TSC::DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
file->Section("SPTS");
|
file->Section("SPTS");
|
||||||
|
|
||||||
|
@ -513,7 +438,7 @@ void DoSavestate(Savestate* file)
|
||||||
file->Var16(&ConvResult);
|
file->Var16(&ConvResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTouchCoords(u16 x, u16 y)
|
void TSC::SetTouchCoords(u16 x, u16 y)
|
||||||
{
|
{
|
||||||
// scr.x = (adc.x-adc.x1) * (scr.x2-scr.x1) / (adc.x2-adc.x1) + (scr.x1-1)
|
// scr.x = (adc.x-adc.x1) * (scr.x2-scr.x1) / (adc.x2-adc.x1) + (scr.x1-1)
|
||||||
// scr.y = (adc.y-adc.y1) * (scr.y2-scr.y1) / (adc.y2-adc.y1) + (scr.y1-1)
|
// scr.y = (adc.y-adc.y1) * (scr.y2-scr.y1) / (adc.y2-adc.y1) + (scr.y1-1)
|
||||||
|
@ -522,13 +447,19 @@ void SetTouchCoords(u16 x, u16 y)
|
||||||
TouchX = x;
|
TouchX = x;
|
||||||
TouchY = y;
|
TouchY = y;
|
||||||
|
|
||||||
if (y == 0xFFF) return;
|
if (y == 0xFFF)
|
||||||
|
{
|
||||||
|
// released
|
||||||
|
NDS::KeyInput |= (1 << (16+6));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TouchX <<= 4;
|
TouchX <<= 4;
|
||||||
TouchY <<= 4;
|
TouchY <<= 4;
|
||||||
|
NDS::KeyInput &= ~(1 << (16+6));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicInputFrame(s16* data, int samples)
|
void TSC::MicInputFrame(s16* data, int samples)
|
||||||
{
|
{
|
||||||
if (!data)
|
if (!data)
|
||||||
{
|
{
|
||||||
|
@ -541,12 +472,7 @@ void MicInputFrame(s16* data, int samples)
|
||||||
MicBufferLen = samples;
|
MicBufferLen = samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Read()
|
void TSC::Write(u8 val)
|
||||||
{
|
|
||||||
return Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Write(u8 val, u32 hold)
|
|
||||||
{
|
{
|
||||||
if (DataPos == 1)
|
if (DataPos == 1)
|
||||||
Data = (ConvResult >> 5) & 0xFF;
|
Data = (ConvResult >> 5) & 0xFF;
|
||||||
|
@ -599,79 +525,71 @@ void Write(u8 val, u32 hold)
|
||||||
DataPos++;
|
DataPos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SPIHost::SPIHost()
|
||||||
|
{
|
||||||
|
NDS::RegisterEventFunc(NDS::Event_SPITransfer, 0, MemberEventFunc(SPIHost, TransferDone));
|
||||||
|
|
||||||
|
Devices[SPIDevice_FirmwareMem] = new FirmwareMem(this);
|
||||||
|
Devices[SPIDevice_PowerMan] = new PowerMan(this);
|
||||||
|
Devices[SPIDevice_TSC] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SPIHost::~SPIHost()
|
||||||
namespace SPI
|
|
||||||
{
|
{
|
||||||
|
for (int i = 0; i < SPIDevice_MAX; i++)
|
||||||
|
{
|
||||||
|
if (Devices[i])
|
||||||
|
delete Devices[i];
|
||||||
|
|
||||||
u16 Cnt;
|
Devices[i] = nullptr;
|
||||||
|
}
|
||||||
u32 CurDevice; // remove me
|
|
||||||
|
|
||||||
|
|
||||||
bool Init()
|
|
||||||
{
|
|
||||||
NDS::RegisterEventFunc(NDS::Event_SPITransfer, 0, TransferDone);
|
|
||||||
|
|
||||||
if (!SPI_Firmware::Init()) return false;
|
|
||||||
if (!SPI_Powerman::Init()) return false;
|
|
||||||
if (!SPI_TSC::Init()) return false;
|
|
||||||
if (!DSi_SPI_TSC::Init()) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeInit()
|
|
||||||
{
|
|
||||||
SPI_Firmware::DeInit();
|
|
||||||
SPI_Powerman::DeInit();
|
|
||||||
SPI_TSC::DeInit();
|
|
||||||
DSi_SPI_TSC::DeInit();
|
|
||||||
|
|
||||||
NDS::UnregisterEventFunc(NDS::Event_SPITransfer, 0);
|
NDS::UnregisterEventFunc(NDS::Event_SPITransfer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset()
|
void SPIHost::Reset()
|
||||||
{
|
{
|
||||||
Cnt = 0;
|
Cnt = 0;
|
||||||
|
|
||||||
SPI_Firmware::Reset();
|
if (Devices[SPIDevice_TSC])
|
||||||
SPI_Powerman::Reset();
|
delete Devices[SPIDevice_TSC];
|
||||||
SPI_TSC::Reset();
|
|
||||||
if (NDS::ConsoleType == 1) DSi_SPI_TSC::Reset();
|
if (NDS::ConsoleType == 1)
|
||||||
|
Devices[SPIDevice_TSC] = new DSi_TSC(this);
|
||||||
|
else
|
||||||
|
Devices[SPIDevice_TSC] = new TSC(this);
|
||||||
|
|
||||||
|
for (int i = 0; i < SPIDevice_MAX; i++)
|
||||||
|
{
|
||||||
|
Devices[i]->Reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoSavestate(Savestate* file)
|
void SPIHost::DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
file->Section("SPIG");
|
file->Section("SPIG");
|
||||||
|
|
||||||
file->Var16(&Cnt);
|
file->Var16(&Cnt);
|
||||||
file->Var32(&CurDevice);
|
|
||||||
|
|
||||||
SPI_Firmware::DoSavestate(file);
|
for (int i = 0; i < SPIDevice_MAX; i++)
|
||||||
SPI_Powerman::DoSavestate(file);
|
{
|
||||||
SPI_TSC::DoSavestate(file);
|
Devices[i]->DoSavestate(file);
|
||||||
if (NDS::ConsoleType == 1) DSi_SPI_TSC::DoSavestate(file);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WriteCnt(u16 val)
|
void SPIHost::WriteCnt(u16 val)
|
||||||
{
|
{
|
||||||
// turning it off should clear chipselect
|
// turning it off should clear chipselect
|
||||||
// TODO: confirm on hardware. libnds expects this, though.
|
// TODO: confirm on hardware. libnds expects this, though.
|
||||||
if ((Cnt & (1<<15)) && !(val & (1<<15)))
|
if ((Cnt & (1<<15)) && !(val & (1<<15)))
|
||||||
{
|
{
|
||||||
switch (Cnt & 0x0300)
|
int dev = (Cnt >> 8) & 0x3;
|
||||||
|
if (dev < SPIDevice_MAX)
|
||||||
{
|
{
|
||||||
case 0x0000: SPI_Powerman::Hold = 0; break;
|
Devices[dev]->Release();
|
||||||
case 0x0100: SPI_Firmware::Hold = 0; break;
|
|
||||||
case 0x0200:
|
|
||||||
if (NDS::ConsoleType == 1)
|
|
||||||
DSi_SPI_TSC::DataPos = 0;
|
|
||||||
else
|
|
||||||
SPI_TSC::DataPos = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,7 +600,7 @@ void WriteCnt(u16 val)
|
||||||
if (Cnt & (1<<7)) Log(LogLevel::Warn, "!! CHANGING SPICNT DURING TRANSFER: %04X\n", val);
|
if (Cnt & (1<<7)) Log(LogLevel::Warn, "!! CHANGING SPICNT DURING TRANSFER: %04X\n", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransferDone(u32 param)
|
void SPIHost::TransferDone(u32 param)
|
||||||
{
|
{
|
||||||
Cnt &= ~(1<<7);
|
Cnt &= ~(1<<7);
|
||||||
|
|
||||||
|
@ -690,46 +608,40 @@ void TransferDone(u32 param)
|
||||||
NDS::SetIRQ(1, NDS::IRQ_SPI);
|
NDS::SetIRQ(1, NDS::IRQ_SPI);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 ReadData()
|
u8 SPIHost::ReadData()
|
||||||
{
|
{
|
||||||
if (!(Cnt & (1<<15))) return 0;
|
if (!(Cnt & (1<<15))) return 0;
|
||||||
if (Cnt & (1<<7)) return 0; // checkme
|
if (Cnt & (1<<7)) return 0; // checkme
|
||||||
|
|
||||||
switch (Cnt & 0x0300)
|
int dev = (Cnt >> 8) & 0x3;
|
||||||
|
if (dev < SPIDevice_MAX)
|
||||||
{
|
{
|
||||||
case 0x0000: return SPI_Powerman::Read();
|
return Devices[dev]->Read();
|
||||||
case 0x0100: return SPI_Firmware::Read();
|
|
||||||
case 0x0200:
|
|
||||||
if (NDS::ConsoleType == 1)
|
|
||||||
return DSi_SPI_TSC::Read();
|
|
||||||
else
|
|
||||||
return SPI_TSC::Read();
|
|
||||||
default: return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteData(u8 val)
|
void SPIHost::WriteData(u8 val)
|
||||||
{
|
{
|
||||||
if (!(Cnt & (1<<15))) return;
|
if (!(Cnt & (1<<15))) return;
|
||||||
if (Cnt & (1<<7)) return;
|
if (Cnt & (1<<7)) return;
|
||||||
|
|
||||||
Cnt |= (1<<7);
|
Cnt |= (1<<7);
|
||||||
switch (Cnt & 0x0300)
|
|
||||||
|
int dev = (Cnt >> 8) & 0x3;
|
||||||
|
if (dev < SPIDevice_MAX)
|
||||||
{
|
{
|
||||||
case 0x0000: SPI_Powerman::Write(val, Cnt&(1<<11)); break;
|
Devices[dev]->Write(val);
|
||||||
case 0x0100: SPI_Firmware::Write(val, Cnt&(1<<11)); break;
|
if (!(Cnt & (1<<11))) // release chipselect
|
||||||
case 0x0200:
|
Devices[dev]->Release();
|
||||||
if (NDS::ConsoleType == 1)
|
}
|
||||||
DSi_SPI_TSC::Write(val, Cnt&(1<<11));
|
else
|
||||||
else
|
{
|
||||||
SPI_TSC::Write(val, Cnt&(1<<11));
|
Log(LogLevel::Warn, "SPI to unknown device %04X %02X\n", Cnt, val);
|
||||||
break;
|
|
||||||
default: Log(LogLevel::Warn, "SPI to unknown device %04X %02X\n", Cnt, val); break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI transfers one bit per cycle -> 8 cycles per byte
|
// SPI transfers one bit per cycle -> 8 cycles per byte
|
||||||
u32 delay = 8 * (8 << (Cnt & 0x3));
|
u32 delay = 8 * (8 << (Cnt & 0x3));
|
||||||
NDS::ScheduleEvent(NDS::Event_SPITransfer, false, delay, 0, 0);
|
NDS::ScheduleEvent(NDS::Event_SPITransfer, false, delay, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
159
src/SPI.h
159
src/SPI.h
|
@ -28,61 +28,150 @@
|
||||||
#include "Savestate.h"
|
#include "Savestate.h"
|
||||||
#include "SPI_Firmware.h"
|
#include "SPI_Firmware.h"
|
||||||
|
|
||||||
namespace SPI_Firmware
|
enum
|
||||||
{
|
{
|
||||||
|
SPIDevice_PowerMan = 0,
|
||||||
|
SPIDevice_FirmwareMem,
|
||||||
|
SPIDevice_TSC,
|
||||||
|
|
||||||
|
SPIDevice_MAX
|
||||||
|
};
|
||||||
|
|
||||||
u16 CRC16(const u8* data, u32 len, u32 start);
|
u16 CRC16(const u8* data, u32 len, u32 start);
|
||||||
void SetupDirectBoot(bool dsi);
|
|
||||||
|
|
||||||
u32 FixFirmwareLength(u32 originalLength);
|
class SPIHost;
|
||||||
|
|
||||||
/// @return A pointer to the installed firmware blob if one exists, otherwise \c nullptr.
|
class SPIDevice
|
||||||
/// @warning The pointer refers to memory that melonDS owns. Do not deallocate it yourself.
|
|
||||||
/// @see InstallFirmware
|
|
||||||
const Firmware* GetFirmware();
|
|
||||||
|
|
||||||
bool IsLoadedFirmwareBuiltIn();
|
|
||||||
bool InstallFirmware(Firmware&& firmware);
|
|
||||||
bool InstallFirmware(std::unique_ptr<Firmware>&& firmware);
|
|
||||||
void RemoveFirmware();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace SPI_Powerman
|
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
SPIDevice(SPIHost* host) : Host(host), Hold(false), DataPos(0) {}
|
||||||
|
virtual ~SPIDevice() {}
|
||||||
|
|
||||||
bool GetBatteryLevelOkay();
|
virtual void Reset() = 0;
|
||||||
void SetBatteryLevelOkay(bool okay);
|
|
||||||
|
|
||||||
}
|
virtual void DoSavestate(Savestate* file) = 0;
|
||||||
|
|
||||||
namespace SPI_TSC
|
virtual u8 Read() { return Data; }
|
||||||
|
virtual void Write(u8 val) = 0;
|
||||||
|
virtual void Release() { Hold = false; DataPos = 0; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SPIHost* Host;
|
||||||
|
|
||||||
|
bool Hold;
|
||||||
|
u32 DataPos;
|
||||||
|
u8 Data;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FirmwareMem : public SPIDevice
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
FirmwareMem(SPIHost* host);
|
||||||
|
~FirmwareMem() override;
|
||||||
|
|
||||||
void SetTouchCoords(u16 x, u16 y);
|
void Reset() override;
|
||||||
void MicInputFrame(s16* data, int samples);
|
|
||||||
|
|
||||||
u8 Read();
|
void DoSavestate(Savestate* file) override;
|
||||||
void Write(u8 val, u32 hold);
|
|
||||||
|
|
||||||
}
|
void SetupDirectBoot(bool dsi);
|
||||||
|
|
||||||
namespace SPI
|
const class Firmware* GetFirmware();
|
||||||
|
bool IsLoadedFirmwareBuiltIn();
|
||||||
|
bool InstallFirmware(class Firmware&& firmware);
|
||||||
|
bool InstallFirmware(std::unique_ptr<class Firmware>&& firmware);
|
||||||
|
void RemoveFirmware();
|
||||||
|
|
||||||
|
void Write(u8 val) override;
|
||||||
|
void Release() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Firmware> Firmware;
|
||||||
|
|
||||||
|
u8 CurCmd;
|
||||||
|
|
||||||
|
u8 StatusReg;
|
||||||
|
u32 Addr;
|
||||||
|
|
||||||
|
bool VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset);
|
||||||
|
};
|
||||||
|
|
||||||
|
class PowerMan : public SPIDevice
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
PowerMan(SPIHost* host);
|
||||||
|
~PowerMan() override;
|
||||||
|
|
||||||
extern u16 Cnt;
|
void Reset() override;
|
||||||
|
|
||||||
bool Init();
|
void DoSavestate(Savestate* file) override;
|
||||||
void DeInit();
|
|
||||||
void Reset();
|
|
||||||
void DoSavestate(Savestate* file);
|
|
||||||
|
|
||||||
void WriteCnt(u16 val);
|
bool GetBatteryLevelOkay();
|
||||||
|
void SetBatteryLevelOkay(bool okay);
|
||||||
|
|
||||||
u8 ReadData();
|
void Write(u8 val) override;
|
||||||
void WriteData(u8 val);
|
|
||||||
|
|
||||||
void TransferDone(u32 param);
|
private:
|
||||||
|
u8 Index;
|
||||||
|
|
||||||
}
|
u8 Registers[8];
|
||||||
|
u8 RegMasks[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
class TSC : public SPIDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TSC(SPIHost* host);
|
||||||
|
virtual ~TSC() override;
|
||||||
|
|
||||||
|
virtual void Reset() override;
|
||||||
|
|
||||||
|
virtual void DoSavestate(Savestate* file) override;
|
||||||
|
|
||||||
|
virtual void SetTouchCoords(u16 x, u16 y);
|
||||||
|
virtual void MicInputFrame(s16* data, int samples);
|
||||||
|
|
||||||
|
virtual void Write(u8 val) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
u8 ControlByte;
|
||||||
|
|
||||||
|
u16 ConvResult;
|
||||||
|
|
||||||
|
u16 TouchX, TouchY;
|
||||||
|
|
||||||
|
s16 MicBuffer[1024];
|
||||||
|
int MicBufferLen;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SPIHost
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SPIHost();
|
||||||
|
~SPIHost();
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
|
FirmwareMem* GetFirmwareMem() { return (FirmwareMem*)Devices[SPIDevice_FirmwareMem]; }
|
||||||
|
PowerMan* GetPowerMan() { return (PowerMan*)Devices[SPIDevice_PowerMan]; }
|
||||||
|
TSC* GetTSC() { return (TSC*)Devices[SPIDevice_TSC]; }
|
||||||
|
|
||||||
|
const Firmware* GetFirmware() { return GetFirmwareMem()->GetFirmware(); }
|
||||||
|
|
||||||
|
u16 ReadCnt() { return Cnt; }
|
||||||
|
void WriteCnt(u16 val);
|
||||||
|
|
||||||
|
u8 ReadData();
|
||||||
|
void WriteData(u8 val);
|
||||||
|
|
||||||
|
void TransferDone(u32 param);
|
||||||
|
|
||||||
|
private:
|
||||||
|
u16 Cnt;
|
||||||
|
|
||||||
|
SPIDevice* Devices[3];
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
#include "SPI_Firmware.h"
|
#include "SPI_Firmware.h"
|
||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
|
#include "Platform.h"
|
||||||
|
|
||||||
|
using Platform::Log;
|
||||||
|
using Platform::LogLevel;
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -49,7 +53,7 @@ constexpr u8 CHANDATA[0x3C]
|
||||||
|
|
||||||
constexpr u8 DEFAULT_UNUSED3[6] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
|
constexpr u8 DEFAULT_UNUSED3[6] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
|
||||||
|
|
||||||
SPI_Firmware::WifiAccessPoint::WifiAccessPoint()
|
Firmware::WifiAccessPoint::WifiAccessPoint()
|
||||||
{
|
{
|
||||||
memset(Bytes, 0, sizeof(Bytes));
|
memset(Bytes, 0, sizeof(Bytes));
|
||||||
Status = AccessPointStatus::NotConfigured;
|
Status = AccessPointStatus::NotConfigured;
|
||||||
|
@ -57,7 +61,7 @@ SPI_Firmware::WifiAccessPoint::WifiAccessPoint()
|
||||||
UpdateChecksum();
|
UpdateChecksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::WifiAccessPoint::WifiAccessPoint(int consoletype)
|
Firmware::WifiAccessPoint::WifiAccessPoint(int consoletype)
|
||||||
{
|
{
|
||||||
memset(Bytes, 0, sizeof(Bytes));
|
memset(Bytes, 0, sizeof(Bytes));
|
||||||
strncpy(SSID, DEFAULT_SSID, sizeof(SSID));
|
strncpy(SSID, DEFAULT_SSID, sizeof(SSID));
|
||||||
|
@ -67,25 +71,25 @@ SPI_Firmware::WifiAccessPoint::WifiAccessPoint(int consoletype)
|
||||||
UpdateChecksum();
|
UpdateChecksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPI_Firmware::WifiAccessPoint::UpdateChecksum()
|
void Firmware::WifiAccessPoint::UpdateChecksum()
|
||||||
{
|
{
|
||||||
Checksum = CRC16(Bytes, 0xFE, 0x0000);
|
Checksum = CRC16(Bytes, 0xFE, 0x0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::ExtendedWifiAccessPoint::ExtendedWifiAccessPoint()
|
Firmware::ExtendedWifiAccessPoint::ExtendedWifiAccessPoint()
|
||||||
{
|
{
|
||||||
Data.Base = WifiAccessPoint();
|
Data.Base = WifiAccessPoint();
|
||||||
|
|
||||||
UpdateChecksum();
|
UpdateChecksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPI_Firmware::ExtendedWifiAccessPoint::UpdateChecksum()
|
void Firmware::ExtendedWifiAccessPoint::UpdateChecksum()
|
||||||
{
|
{
|
||||||
Data.Base.UpdateChecksum();
|
Data.Base.UpdateChecksum();
|
||||||
Data.ExtendedChecksum = CRC16(&Bytes[0x100], 0xFE, 0x0000);
|
Data.ExtendedChecksum = CRC16(&Bytes[0x100], 0xFE, 0x0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::FirmwareHeader::FirmwareHeader(int consoletype)
|
Firmware::FirmwareHeader::FirmwareHeader(int consoletype)
|
||||||
{
|
{
|
||||||
if (consoletype == 1)
|
if (consoletype == 1)
|
||||||
{
|
{
|
||||||
|
@ -143,12 +147,12 @@ SPI_Firmware::FirmwareHeader::FirmwareHeader(int consoletype)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SPI_Firmware::FirmwareHeader::UpdateChecksum()
|
void Firmware::FirmwareHeader::UpdateChecksum()
|
||||||
{
|
{
|
||||||
WifiConfigChecksum = SPI_Firmware::CRC16(&Bytes[0x2C], WifiConfigLength, 0x0000);
|
WifiConfigChecksum = CRC16(&Bytes[0x2C], WifiConfigLength, 0x0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::UserData::UserData()
|
Firmware::UserData::UserData()
|
||||||
{
|
{
|
||||||
memset(Bytes, 0, 0x74);
|
memset(Bytes, 0, 0x74);
|
||||||
Version = 5;
|
Version = 5;
|
||||||
|
@ -160,7 +164,7 @@ SPI_Firmware::UserData::UserData()
|
||||||
Checksum = CRC16(Bytes, 0x70, 0xFFFF);
|
Checksum = CRC16(Bytes, 0x70, 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPI_Firmware::UserData::UpdateChecksum()
|
void Firmware::UserData::UpdateChecksum()
|
||||||
{
|
{
|
||||||
Checksum = CRC16(Bytes, 0x70, 0xFFFF);
|
Checksum = CRC16(Bytes, 0x70, 0xFFFF);
|
||||||
if (ExtendedSettings.Unknown0 == 0x01)
|
if (ExtendedSettings.Unknown0 == 0x01)
|
||||||
|
@ -169,7 +173,30 @@ void SPI_Firmware::UserData::UpdateChecksum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::Firmware::Firmware(int consoletype)
|
u32 Firmware::FixFirmwareLength(u32 originalLength)
|
||||||
|
{
|
||||||
|
if (originalLength != 0x20000 && originalLength != 0x40000 && originalLength != 0x80000)
|
||||||
|
{
|
||||||
|
Log(LogLevel::Warn, "Bad firmware size %d, ", originalLength);
|
||||||
|
|
||||||
|
// pick the nearest power-of-two length
|
||||||
|
originalLength |= (originalLength >> 1);
|
||||||
|
originalLength |= (originalLength >> 2);
|
||||||
|
originalLength |= (originalLength >> 4);
|
||||||
|
originalLength |= (originalLength >> 8);
|
||||||
|
originalLength |= (originalLength >> 16);
|
||||||
|
originalLength++;
|
||||||
|
|
||||||
|
// ensure it's a sane length
|
||||||
|
if (originalLength > 0x80000) originalLength = 0x80000;
|
||||||
|
else if (originalLength < 0x20000) originalLength = 0x20000;
|
||||||
|
|
||||||
|
Log(LogLevel::Debug, "assuming %d\n", originalLength);
|
||||||
|
}
|
||||||
|
return originalLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
Firmware::Firmware(int consoletype)
|
||||||
{
|
{
|
||||||
FirmwareBufferLength = DEFAULT_FIRMWARE_LENGTH;
|
FirmwareBufferLength = DEFAULT_FIRMWARE_LENGTH;
|
||||||
FirmwareBuffer = new u8[FirmwareBufferLength];
|
FirmwareBuffer = new u8[FirmwareBufferLength];
|
||||||
|
@ -184,16 +211,16 @@ SPI_Firmware::Firmware::Firmware(int consoletype)
|
||||||
// user data
|
// user data
|
||||||
header.UserSettingsOffset = (0x7FE00 & FirmwareMask) >> 3;
|
header.UserSettingsOffset = (0x7FE00 & FirmwareMask) >> 3;
|
||||||
|
|
||||||
std::array<union UserData, 2>& settings = *reinterpret_cast<std::array<union UserData, 2>*>(UserDataPosition());
|
std::array<UserData, 2>& settings = *reinterpret_cast<std::array<UserData, 2>*>(GetUserDataPosition());
|
||||||
settings = {
|
settings = {
|
||||||
SPI_Firmware::UserData(),
|
UserData(),
|
||||||
SPI_Firmware::UserData(),
|
UserData(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// wifi access points
|
// wifi access points
|
||||||
// TODO: WFC ID??
|
// TODO: WFC ID??
|
||||||
|
|
||||||
std::array<WifiAccessPoint, 3>& accesspoints = *reinterpret_cast<std::array<WifiAccessPoint, 3>*>(WifiAccessPointPosition());
|
std::array<WifiAccessPoint, 3>& accesspoints = *reinterpret_cast<std::array<WifiAccessPoint, 3>*>(GetWifiAccessPointPosition());
|
||||||
|
|
||||||
accesspoints = {
|
accesspoints = {
|
||||||
WifiAccessPoint(consoletype),
|
WifiAccessPoint(consoletype),
|
||||||
|
@ -203,7 +230,7 @@ SPI_Firmware::Firmware::Firmware(int consoletype)
|
||||||
|
|
||||||
if (consoletype == 1)
|
if (consoletype == 1)
|
||||||
{
|
{
|
||||||
std::array<ExtendedWifiAccessPoint, 3>& extendedaccesspoints = *reinterpret_cast<std::array<ExtendedWifiAccessPoint, 3>*>(ExtendedAccessPointPosition());
|
std::array<ExtendedWifiAccessPoint, 3>& extendedaccesspoints = *reinterpret_cast<std::array<ExtendedWifiAccessPoint, 3>*>(GetExtendedAccessPointPosition());
|
||||||
|
|
||||||
extendedaccesspoints = {
|
extendedaccesspoints = {
|
||||||
ExtendedWifiAccessPoint(),
|
ExtendedWifiAccessPoint(),
|
||||||
|
@ -213,7 +240,7 @@ SPI_Firmware::Firmware::Firmware(int consoletype)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::Firmware::Firmware(Platform::FileHandle* file) : FirmwareBuffer(nullptr), FirmwareBufferLength(0), FirmwareMask(0)
|
Firmware::Firmware(Platform::FileHandle* file) : FirmwareBuffer(nullptr), FirmwareBufferLength(0), FirmwareMask(0)
|
||||||
{
|
{
|
||||||
if (file)
|
if (file)
|
||||||
{
|
{
|
||||||
|
@ -239,7 +266,7 @@ SPI_Firmware::Firmware::Firmware(Platform::FileHandle* file) : FirmwareBuffer(nu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::Firmware::Firmware(const u8* data, u32 length) : FirmwareBuffer(nullptr), FirmwareBufferLength(FixFirmwareLength(length))
|
Firmware::Firmware(const u8* data, u32 length) : FirmwareBuffer(nullptr), FirmwareBufferLength(FixFirmwareLength(length))
|
||||||
{
|
{
|
||||||
if (data)
|
if (data)
|
||||||
{
|
{
|
||||||
|
@ -249,14 +276,14 @@ SPI_Firmware::Firmware::Firmware(const u8* data, u32 length) : FirmwareBuffer(nu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::Firmware::Firmware(const Firmware& other) : FirmwareBuffer(nullptr), FirmwareBufferLength(other.FirmwareBufferLength)
|
Firmware::Firmware(const Firmware& other) : FirmwareBuffer(nullptr), FirmwareBufferLength(other.FirmwareBufferLength)
|
||||||
{
|
{
|
||||||
FirmwareBuffer = new u8[FirmwareBufferLength];
|
FirmwareBuffer = new u8[FirmwareBufferLength];
|
||||||
memcpy(FirmwareBuffer, other.FirmwareBuffer, FirmwareBufferLength);
|
memcpy(FirmwareBuffer, other.FirmwareBuffer, FirmwareBufferLength);
|
||||||
FirmwareMask = other.FirmwareMask;
|
FirmwareMask = other.FirmwareMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::Firmware::Firmware(Firmware&& other) noexcept
|
Firmware::Firmware(Firmware&& other) noexcept
|
||||||
{
|
{
|
||||||
FirmwareBuffer = other.FirmwareBuffer;
|
FirmwareBuffer = other.FirmwareBuffer;
|
||||||
FirmwareBufferLength = other.FirmwareBufferLength;
|
FirmwareBufferLength = other.FirmwareBufferLength;
|
||||||
|
@ -266,7 +293,7 @@ SPI_Firmware::Firmware::Firmware(Firmware&& other) noexcept
|
||||||
other.FirmwareMask = 0;
|
other.FirmwareMask = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::Firmware& SPI_Firmware::Firmware::operator=(const Firmware& other)
|
Firmware& Firmware::operator=(const Firmware& other)
|
||||||
{
|
{
|
||||||
if (this != &other)
|
if (this != &other)
|
||||||
{
|
{
|
||||||
|
@ -280,7 +307,7 @@ SPI_Firmware::Firmware& SPI_Firmware::Firmware::operator=(const Firmware& other)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::Firmware& SPI_Firmware::Firmware::operator=(Firmware&& other) noexcept
|
Firmware& Firmware::operator=(Firmware&& other) noexcept
|
||||||
{
|
{
|
||||||
if (this != &other)
|
if (this != &other)
|
||||||
{
|
{
|
||||||
|
@ -296,21 +323,21 @@ SPI_Firmware::Firmware& SPI_Firmware::Firmware::operator=(Firmware&& other) noex
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::Firmware::~Firmware()
|
Firmware::~Firmware()
|
||||||
{
|
{
|
||||||
delete[] FirmwareBuffer;
|
delete[] FirmwareBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SPI_Firmware::Firmware::IsBootable() const
|
bool Firmware::IsBootable() const
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
FirmwareBufferLength != DEFAULT_FIRMWARE_LENGTH &&
|
FirmwareBufferLength != DEFAULT_FIRMWARE_LENGTH &&
|
||||||
Header().Identifier != GENERATED_FIRMWARE_IDENTIFIER
|
GetHeader().Identifier != GENERATED_FIRMWARE_IDENTIFIER
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SPI_Firmware::UserData& SPI_Firmware::Firmware::EffectiveUserData() const {
|
const Firmware::UserData& Firmware::GetEffectiveUserData() const {
|
||||||
const std::array<union UserData, 2>& userdata = UserData();
|
const std::array<union UserData, 2>& userdata = GetUserData();
|
||||||
bool userdata0ChecksumOk = userdata[0].ChecksumValid();
|
bool userdata0ChecksumOk = userdata[0].ChecksumValid();
|
||||||
bool userdata1ChecksumOk = userdata[1].ChecksumValid();
|
bool userdata1ChecksumOk = userdata[1].ChecksumValid();
|
||||||
|
|
||||||
|
@ -332,8 +359,8 @@ const SPI_Firmware::UserData& SPI_Firmware::Firmware::EffectiveUserData() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SPI_Firmware::UserData& SPI_Firmware::Firmware::EffectiveUserData() {
|
Firmware::UserData& Firmware::GetEffectiveUserData() {
|
||||||
std::array<union UserData, 2>& userdata = UserData();
|
std::array<union UserData, 2>& userdata = GetUserData();
|
||||||
bool userdata0ChecksumOk = userdata[0].ChecksumValid();
|
bool userdata0ChecksumOk = userdata[0].ChecksumValid();
|
||||||
bool userdata1ChecksumOk = userdata[1].ChecksumValid();
|
bool userdata1ChecksumOk = userdata[1].ChecksumValid();
|
||||||
|
|
||||||
|
@ -355,25 +382,25 @@ SPI_Firmware::UserData& SPI_Firmware::Firmware::EffectiveUserData() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPI_Firmware::Firmware::UpdateChecksums()
|
void Firmware::UpdateChecksums()
|
||||||
{
|
{
|
||||||
Header().UpdateChecksum();
|
GetHeader().UpdateChecksum();
|
||||||
|
|
||||||
for (SPI_Firmware::WifiAccessPoint& ap : AccessPoints())
|
for (auto& ap : GetAccessPoints())
|
||||||
{
|
{
|
||||||
ap.UpdateChecksum();
|
ap.UpdateChecksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Header().ConsoleType == FirmwareConsoleType::DSi)
|
if (GetHeader().ConsoleType == FirmwareConsoleType::DSi)
|
||||||
{
|
{
|
||||||
for (SPI_Firmware::ExtendedWifiAccessPoint& eap : ExtendedAccessPoints())
|
for (auto& eap : GetExtendedAccessPoints())
|
||||||
{
|
{
|
||||||
eap.UpdateChecksum();
|
eap.UpdateChecksum();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SPI_Firmware::UserData& u : UserData())
|
for (auto& u : GetUserData())
|
||||||
{
|
{
|
||||||
u.UpdateChecksum();
|
u.UpdateChecksum();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,10 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
|
||||||
namespace SPI_Firmware
|
|
||||||
{
|
|
||||||
|
|
||||||
u16 CRC16(const u8* data, u32 len, u32 start);
|
u16 CRC16(const u8* data, u32 len, u32 start);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using MacAddress = std::array<u8, 6>;
|
using MacAddress = std::array<u8, 6>;
|
||||||
using IpAddress = std::array<u8, 4>;
|
using IpAddress = std::array<u8, 4>;
|
||||||
|
|
||||||
|
@ -44,382 +44,384 @@ constexpr const char* const DEFAULT_SSID = "melonAP";
|
||||||
*/
|
*/
|
||||||
constexpr int EXTENDED_WIFI_SETTINGS_OFFSET = -0xA00;
|
constexpr int EXTENDED_WIFI_SETTINGS_OFFSET = -0xA00;
|
||||||
|
|
||||||
enum class WepMode : u8
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Hex5 = 1,
|
|
||||||
Hex13 = 2,
|
|
||||||
Hex16 = 3,
|
|
||||||
Ascii5 = 5,
|
|
||||||
Ascii13 = 6,
|
|
||||||
Ascii16 = 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class WpaMode : u8
|
|
||||||
{
|
|
||||||
Normal = 0,
|
|
||||||
WPA_WPA2 = 0x10,
|
|
||||||
WPS_WPA = 0x13,
|
|
||||||
Unused = 0xff,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class WpaSecurity : u8
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
WPA_TKIP = 4,
|
|
||||||
WPA2_TKIP = 5,
|
|
||||||
WPA_AES = 6,
|
|
||||||
WPA2_AES = 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class AccessPointStatus : u8
|
|
||||||
{
|
|
||||||
Normal = 0,
|
|
||||||
Aoss = 1,
|
|
||||||
NotConfigured = 0xff
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see https://problemkaputt.de/gbatek.htm#dsfirmwarewifiinternetaccesspoints
|
|
||||||
*/
|
|
||||||
union WifiAccessPoint
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Constructs an unconfigured access point.
|
|
||||||
*/
|
|
||||||
WifiAccessPoint();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an access point configured with melonDS's defaults.
|
|
||||||
*/
|
|
||||||
explicit WifiAccessPoint(int consoletype);
|
|
||||||
void UpdateChecksum();
|
|
||||||
u8 Bytes[256];
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char ProxyUsername[32];
|
|
||||||
char ProxyPassword[32];
|
|
||||||
char SSID[32];
|
|
||||||
char SSIDWEP64[32];
|
|
||||||
u8 WEPKey1[16];
|
|
||||||
u8 WEPKey2[16];
|
|
||||||
u8 WEPKey3[16];
|
|
||||||
u8 WEPKey4[16];
|
|
||||||
IpAddress Address;
|
|
||||||
IpAddress Gateway;
|
|
||||||
IpAddress PrimaryDns;
|
|
||||||
IpAddress SecondaryDns;
|
|
||||||
u8 SubnetMask;
|
|
||||||
u8 Unknown0[21];
|
|
||||||
enum WepMode WepMode;
|
|
||||||
AccessPointStatus Status;
|
|
||||||
u8 SSIDLength;
|
|
||||||
u8 Unknown1;
|
|
||||||
u16 Mtu;
|
|
||||||
u8 Unknown2[3];
|
|
||||||
u8 ConnectionConfigured;
|
|
||||||
u8 NintendoWFCID[6];
|
|
||||||
u8 Unknown3[8];
|
|
||||||
u16 Checksum;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(WifiAccessPoint) == 256, "WifiAccessPoint should be 256 bytes");
|
|
||||||
|
|
||||||
union ExtendedWifiAccessPoint
|
|
||||||
{
|
|
||||||
ExtendedWifiAccessPoint();
|
|
||||||
void UpdateChecksum();
|
|
||||||
u8 Bytes[512];
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
WifiAccessPoint Base;
|
|
||||||
|
|
||||||
// DSi-specific entries now
|
|
||||||
u8 PrecomputedPSK[32];
|
|
||||||
char WPAPassword[64];
|
|
||||||
char Unused0[33];
|
|
||||||
WpaSecurity Security;
|
|
||||||
bool ProxyEnabled;
|
|
||||||
bool ProxyAuthentication;
|
|
||||||
char ProxyName[48];
|
|
||||||
u8 Unused1[52];
|
|
||||||
u16 ProxyPort;
|
|
||||||
u8 Unused2[20];
|
|
||||||
u16 ExtendedChecksum;
|
|
||||||
} Data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(ExtendedWifiAccessPoint) == 512, "WifiAccessPoint should be 512 bytes");
|
|
||||||
|
|
||||||
|
|
||||||
enum class FirmwareConsoleType : u8
|
|
||||||
{
|
|
||||||
DS = 0xFF,
|
|
||||||
DSLite = 0x20,
|
|
||||||
DSi = 0x57,
|
|
||||||
iQueDS = 0x43,
|
|
||||||
iQueDSLite = 0x63,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class WifiVersion : u8
|
|
||||||
{
|
|
||||||
V1_4 = 0,
|
|
||||||
V5 = 3,
|
|
||||||
V6_7 = 5,
|
|
||||||
W006 = 6,
|
|
||||||
W015 = 15,
|
|
||||||
W024 = 24,
|
|
||||||
N3DS = 34,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RFChipType : u8
|
|
||||||
{
|
|
||||||
Type2 = 0x2,
|
|
||||||
Type3 = 0x3,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class WifiBoard : u8
|
|
||||||
{
|
|
||||||
W015 = 0x1,
|
|
||||||
W024 = 0x2,
|
|
||||||
W028 = 0x3,
|
|
||||||
Unused = 0xff,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Language : u8
|
|
||||||
{
|
|
||||||
Japanese = 0,
|
|
||||||
English = 1,
|
|
||||||
French = 2,
|
|
||||||
German = 3,
|
|
||||||
Italian = 4,
|
|
||||||
Spanish = 5,
|
|
||||||
Chinese = 6,
|
|
||||||
Reserved = 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum GBAScreen : u8
|
|
||||||
{
|
|
||||||
Upper = 0,
|
|
||||||
Lower = (1 << 3),
|
|
||||||
};
|
|
||||||
|
|
||||||
enum BacklightLevel : u8
|
|
||||||
{
|
|
||||||
Low = 0,
|
|
||||||
Medium = 1 << 4,
|
|
||||||
High = 2 << 4,
|
|
||||||
Max = 3 << 4
|
|
||||||
};
|
|
||||||
|
|
||||||
enum BootMenu : u8
|
|
||||||
{
|
|
||||||
Manual = 0,
|
|
||||||
Autostart = 1 << 6,
|
|
||||||
};
|
|
||||||
|
|
||||||
using FirmwareIdentifier = std::array<u8, 4>;
|
using FirmwareIdentifier = std::array<u8, 4>;
|
||||||
using MacAddress = std::array<u8, 6>;
|
using MacAddress = std::array<u8, 6>;
|
||||||
|
|
||||||
constexpr FirmwareIdentifier GENERATED_FIRMWARE_IDENTIFIER = {'M', 'E', 'L', 'N'};
|
constexpr FirmwareIdentifier GENERATED_FIRMWARE_IDENTIFIER = {'M', 'E', 'L', 'N'};
|
||||||
|
|
||||||
/**
|
|
||||||
* @note GBATek says the header is actually 511 bytes;
|
|
||||||
* this header struct is 512 bytes due to padding,
|
|
||||||
* but the last byte is just the first byte of the firmware's code.
|
|
||||||
* It doesn't affect the offset of any of the fields,
|
|
||||||
* so leaving that last byte in there is harmless.
|
|
||||||
* @see https://problemkaputt.de/gbatek.htm#dsfirmwareheader
|
|
||||||
* @see https://problemkaputt.de/gbatek.htm#dsfirmwarewificalibrationdata
|
|
||||||
*/
|
|
||||||
union FirmwareHeader
|
|
||||||
{
|
|
||||||
explicit FirmwareHeader(int consoletype);
|
|
||||||
void UpdateChecksum();
|
|
||||||
u8 Bytes[512];
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
u16 ARM9GUICodeOffset;
|
|
||||||
u16 ARM7WifiCodeOffset;
|
|
||||||
u16 GUIWifiCodeChecksum;
|
|
||||||
u16 BootCodeChecksum;
|
|
||||||
|
|
||||||
FirmwareIdentifier Identifier;
|
|
||||||
|
|
||||||
u16 ARM9BootCodeROMAddress;
|
|
||||||
u16 ARM9BootCodeRAMAddress;
|
|
||||||
u16 ARM7BootCodeRAMAddress;
|
|
||||||
u16 ARM7BootCodeROMAddress;
|
|
||||||
u16 ShiftAmounts;
|
|
||||||
u16 DataGfxRomAddress;
|
|
||||||
|
|
||||||
u8 BuildMinute;
|
|
||||||
u8 BuildHour;
|
|
||||||
u8 BuildDay;
|
|
||||||
u8 BuildMonth;
|
|
||||||
u8 BuildYear;
|
|
||||||
|
|
||||||
FirmwareConsoleType ConsoleType;
|
|
||||||
|
|
||||||
u8 Unused0[2];
|
|
||||||
|
|
||||||
u16 UserSettingsOffset;
|
|
||||||
u8 Unknown0[2];
|
|
||||||
u8 Unknown1[2];
|
|
||||||
u16 DataGfxChecksum;
|
|
||||||
u8 Unused2[2];
|
|
||||||
|
|
||||||
// Begin wi-fi settings
|
|
||||||
u16 WifiConfigChecksum;
|
|
||||||
u16 WifiConfigLength;
|
|
||||||
u8 Unused1;
|
|
||||||
enum WifiVersion WifiVersion;
|
|
||||||
|
|
||||||
u8 Unused3[6];
|
|
||||||
|
|
||||||
SPI_Firmware::MacAddress MacAddress;
|
|
||||||
|
|
||||||
u16 EnabledChannels;
|
|
||||||
|
|
||||||
u8 Unknown2[2];
|
|
||||||
|
|
||||||
enum RFChipType RFChipType;
|
|
||||||
u8 RFBitsPerEntry;
|
|
||||||
u8 RFEntries;
|
|
||||||
u8 Unknown3;
|
|
||||||
|
|
||||||
u8 InitialValues[32];
|
|
||||||
u8 InitialBBValues[105];
|
|
||||||
u8 Unused4;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
u8 InitialRFValues[36];
|
|
||||||
u8 InitialRF56Values[84];
|
|
||||||
u8 InitialBB1EValues[14];
|
|
||||||
u8 InitialRf9Values[14];
|
|
||||||
} Type2Config;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
u8 InitialRFValues[41];
|
|
||||||
u8 BBIndicesPerChannel;
|
|
||||||
u8 BBIndex1;
|
|
||||||
u8 BBData1[14];
|
|
||||||
u8 BBIndex2;
|
|
||||||
u8 BBData2[14];
|
|
||||||
u8 RFIndex1;
|
|
||||||
u8 RFData1[14];
|
|
||||||
u8 RFIndex2;
|
|
||||||
u8 RFData2[14];
|
|
||||||
u8 Unused0[46];
|
|
||||||
} Type3Config;
|
|
||||||
};
|
|
||||||
|
|
||||||
u8 Unknown4;
|
|
||||||
u8 Unused5;
|
|
||||||
u8 Unused6[153];
|
|
||||||
enum WifiBoard WifiBoard;
|
|
||||||
u8 WifiFlash;
|
|
||||||
u8 Unused7;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(FirmwareHeader) == 512, "FirmwareHeader should be 512 bytes");
|
|
||||||
|
|
||||||
struct ExtendedUserSettings
|
|
||||||
{
|
|
||||||
char ID[8];
|
|
||||||
u16 Checksum;
|
|
||||||
u16 ChecksumLength;
|
|
||||||
u8 Version;
|
|
||||||
u8 UpdateCount;
|
|
||||||
u8 BootMenuFlags;
|
|
||||||
u8 GBABorder;
|
|
||||||
u16 TemperatureCalibration0;
|
|
||||||
u16 TemperatureCalibration1;
|
|
||||||
u16 TemperatureCalibrationDegrees;
|
|
||||||
u8 TemperatureFlags;
|
|
||||||
u8 BacklightIntensity;
|
|
||||||
u32 DateCenturyOffset;
|
|
||||||
u8 DateMonthRecovery;
|
|
||||||
u8 DateDayRecovery;
|
|
||||||
u8 DateYearRecovery;
|
|
||||||
u8 DateTimeFlags;
|
|
||||||
char DateSeparator;
|
|
||||||
char TimeSeparator;
|
|
||||||
char DecimalSeparator;
|
|
||||||
char ThousandsSeparator;
|
|
||||||
u8 DaylightSavingsTimeNth;
|
|
||||||
u8 DaylightSavingsTimeDay;
|
|
||||||
u8 DaylightSavingsTimeOfMonth;
|
|
||||||
u8 DaylightSavingsTimeFlags;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(sizeof(ExtendedUserSettings) == 0x28, "ExtendedUserSettings should be 40 bytes");
|
|
||||||
|
|
||||||
union UserData
|
|
||||||
{
|
|
||||||
UserData();
|
|
||||||
void UpdateChecksum();
|
|
||||||
[[nodiscard]] bool ChecksumValid() const
|
|
||||||
{
|
|
||||||
bool baseChecksumOk = Checksum == CRC16(Bytes, 0x70, 0xFFFF);
|
|
||||||
bool extendedChecksumOk = Bytes[0x74] != 1 || ExtendedSettings.Checksum == CRC16(Bytes + 0x74, 0x8A, 0xFFFF);
|
|
||||||
// For our purposes, the extended checksum is OK if we're not using extended data
|
|
||||||
|
|
||||||
return baseChecksumOk && extendedChecksumOk;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 Bytes[256];
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
u16 Version;
|
|
||||||
u8 FavoriteColor;
|
|
||||||
u8 BirthdayMonth;
|
|
||||||
u8 BirthdayDay;
|
|
||||||
u8 Unused0;
|
|
||||||
char16_t Nickname[10];
|
|
||||||
u16 NameLength;
|
|
||||||
char16_t Message[26];
|
|
||||||
u16 MessageLength;
|
|
||||||
u8 AlarmHour;
|
|
||||||
u8 AlarmMinute;
|
|
||||||
u8 Unknown0[2];
|
|
||||||
u8 AlarmFlags;
|
|
||||||
u8 Unused1;
|
|
||||||
u16 TouchCalibrationADC1[2];
|
|
||||||
u8 TouchCalibrationPixel1[2];
|
|
||||||
u16 TouchCalibrationADC2[2];
|
|
||||||
u8 TouchCalibrationPixel2[2];
|
|
||||||
u16 Settings;
|
|
||||||
u8 Year;
|
|
||||||
u8 RTCClockAdjust;
|
|
||||||
u32 RTCOffset;
|
|
||||||
u8 Unused2[4];
|
|
||||||
u16 UpdateCounter;
|
|
||||||
u16 Checksum;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
u8 Unused3[0x8C];
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
u8 Unknown0;
|
|
||||||
Language ExtendedLanguage; // padded
|
|
||||||
u16 SupportedLanguageMask;
|
|
||||||
u8 Unused0[0x86];
|
|
||||||
u16 Checksum;
|
|
||||||
} ExtendedSettings;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
static_assert(sizeof(UserData) == 256, "UserData should be 256 bytes");
|
|
||||||
|
|
||||||
class Firmware
|
class Firmware
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum class WepMode : u8
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Hex5 = 1,
|
||||||
|
Hex13 = 2,
|
||||||
|
Hex16 = 3,
|
||||||
|
Ascii5 = 5,
|
||||||
|
Ascii13 = 6,
|
||||||
|
Ascii16 = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class WpaMode : u8
|
||||||
|
{
|
||||||
|
Normal = 0,
|
||||||
|
WPA_WPA2 = 0x10,
|
||||||
|
WPS_WPA = 0x13,
|
||||||
|
Unused = 0xff,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class WpaSecurity : u8
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
WPA_TKIP = 4,
|
||||||
|
WPA2_TKIP = 5,
|
||||||
|
WPA_AES = 6,
|
||||||
|
WPA2_AES = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AccessPointStatus : u8
|
||||||
|
{
|
||||||
|
Normal = 0,
|
||||||
|
Aoss = 1,
|
||||||
|
NotConfigured = 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://problemkaputt.de/gbatek.htm#dsfirmwarewifiinternetaccesspoints
|
||||||
|
*/
|
||||||
|
union WifiAccessPoint
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs an unconfigured access point.
|
||||||
|
*/
|
||||||
|
WifiAccessPoint();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an access point configured with melonDS's defaults.
|
||||||
|
*/
|
||||||
|
explicit WifiAccessPoint(int consoletype);
|
||||||
|
void UpdateChecksum();
|
||||||
|
u8 Bytes[256];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
char ProxyUsername[32];
|
||||||
|
char ProxyPassword[32];
|
||||||
|
char SSID[32];
|
||||||
|
char SSIDWEP64[32];
|
||||||
|
u8 WEPKey1[16];
|
||||||
|
u8 WEPKey2[16];
|
||||||
|
u8 WEPKey3[16];
|
||||||
|
u8 WEPKey4[16];
|
||||||
|
IpAddress Address;
|
||||||
|
IpAddress Gateway;
|
||||||
|
IpAddress PrimaryDns;
|
||||||
|
IpAddress SecondaryDns;
|
||||||
|
u8 SubnetMask;
|
||||||
|
u8 Unknown0[21];
|
||||||
|
enum WepMode WepMode;
|
||||||
|
AccessPointStatus Status;
|
||||||
|
u8 SSIDLength;
|
||||||
|
u8 Unknown1;
|
||||||
|
u16 Mtu;
|
||||||
|
u8 Unknown2[3];
|
||||||
|
u8 ConnectionConfigured;
|
||||||
|
u8 NintendoWFCID[6];
|
||||||
|
u8 Unknown3[8];
|
||||||
|
u16 Checksum;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(WifiAccessPoint) == 256, "WifiAccessPoint should be 256 bytes");
|
||||||
|
|
||||||
|
union ExtendedWifiAccessPoint
|
||||||
|
{
|
||||||
|
ExtendedWifiAccessPoint();
|
||||||
|
void UpdateChecksum();
|
||||||
|
u8 Bytes[512];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
WifiAccessPoint Base;
|
||||||
|
|
||||||
|
// DSi-specific entries now
|
||||||
|
u8 PrecomputedPSK[32];
|
||||||
|
char WPAPassword[64];
|
||||||
|
char Unused0[33];
|
||||||
|
WpaSecurity Security;
|
||||||
|
bool ProxyEnabled;
|
||||||
|
bool ProxyAuthentication;
|
||||||
|
char ProxyName[48];
|
||||||
|
u8 Unused1[52];
|
||||||
|
u16 ProxyPort;
|
||||||
|
u8 Unused2[20];
|
||||||
|
u16 ExtendedChecksum;
|
||||||
|
} Data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(ExtendedWifiAccessPoint) == 512, "WifiAccessPoint should be 512 bytes");
|
||||||
|
|
||||||
|
|
||||||
|
enum class FirmwareConsoleType : u8
|
||||||
|
{
|
||||||
|
DS = 0xFF,
|
||||||
|
DSLite = 0x20,
|
||||||
|
DSi = 0x57,
|
||||||
|
iQueDS = 0x43,
|
||||||
|
iQueDSLite = 0x63,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class WifiVersion : u8
|
||||||
|
{
|
||||||
|
V1_4 = 0,
|
||||||
|
V5 = 3,
|
||||||
|
V6_7 = 5,
|
||||||
|
W006 = 6,
|
||||||
|
W015 = 15,
|
||||||
|
W024 = 24,
|
||||||
|
N3DS = 34,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RFChipType : u8
|
||||||
|
{
|
||||||
|
Type2 = 0x2,
|
||||||
|
Type3 = 0x3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class WifiBoard : u8
|
||||||
|
{
|
||||||
|
W015 = 0x1,
|
||||||
|
W024 = 0x2,
|
||||||
|
W028 = 0x3,
|
||||||
|
Unused = 0xff,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Language : u8
|
||||||
|
{
|
||||||
|
Japanese = 0,
|
||||||
|
English = 1,
|
||||||
|
French = 2,
|
||||||
|
German = 3,
|
||||||
|
Italian = 4,
|
||||||
|
Spanish = 5,
|
||||||
|
Chinese = 6,
|
||||||
|
Reserved = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum GBAScreen : u8
|
||||||
|
{
|
||||||
|
Upper = 0,
|
||||||
|
Lower = (1 << 3),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BacklightLevel : u8
|
||||||
|
{
|
||||||
|
Low = 0,
|
||||||
|
Medium = 1 << 4,
|
||||||
|
High = 2 << 4,
|
||||||
|
Max = 3 << 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BootMenu : u8
|
||||||
|
{
|
||||||
|
Manual = 0,
|
||||||
|
Autostart = 1 << 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note GBATek says the header is actually 511 bytes;
|
||||||
|
* this header struct is 512 bytes due to padding,
|
||||||
|
* but the last byte is just the first byte of the firmware's code.
|
||||||
|
* It doesn't affect the offset of any of the fields,
|
||||||
|
* so leaving that last byte in there is harmless.
|
||||||
|
* @see https://problemkaputt.de/gbatek.htm#dsfirmwareheader
|
||||||
|
* @see https://problemkaputt.de/gbatek.htm#dsfirmwarewificalibrationdata
|
||||||
|
*/
|
||||||
|
union FirmwareHeader
|
||||||
|
{
|
||||||
|
explicit FirmwareHeader(int consoletype);
|
||||||
|
void UpdateChecksum();
|
||||||
|
u8 Bytes[512];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u16 ARM9GUICodeOffset;
|
||||||
|
u16 ARM7WifiCodeOffset;
|
||||||
|
u16 GUIWifiCodeChecksum;
|
||||||
|
u16 BootCodeChecksum;
|
||||||
|
|
||||||
|
FirmwareIdentifier Identifier;
|
||||||
|
|
||||||
|
u16 ARM9BootCodeROMAddress;
|
||||||
|
u16 ARM9BootCodeRAMAddress;
|
||||||
|
u16 ARM7BootCodeRAMAddress;
|
||||||
|
u16 ARM7BootCodeROMAddress;
|
||||||
|
u16 ShiftAmounts;
|
||||||
|
u16 DataGfxRomAddress;
|
||||||
|
|
||||||
|
u8 BuildMinute;
|
||||||
|
u8 BuildHour;
|
||||||
|
u8 BuildDay;
|
||||||
|
u8 BuildMonth;
|
||||||
|
u8 BuildYear;
|
||||||
|
|
||||||
|
FirmwareConsoleType ConsoleType;
|
||||||
|
|
||||||
|
u8 Unused0[2];
|
||||||
|
|
||||||
|
u16 UserSettingsOffset;
|
||||||
|
u8 Unknown0[2];
|
||||||
|
u8 Unknown1[2];
|
||||||
|
u16 DataGfxChecksum;
|
||||||
|
u8 Unused2[2];
|
||||||
|
|
||||||
|
// Begin wi-fi settings
|
||||||
|
u16 WifiConfigChecksum;
|
||||||
|
u16 WifiConfigLength;
|
||||||
|
u8 Unused1;
|
||||||
|
enum WifiVersion WifiVersion;
|
||||||
|
|
||||||
|
u8 Unused3[6];
|
||||||
|
|
||||||
|
MacAddress MacAddress;
|
||||||
|
|
||||||
|
u16 EnabledChannels;
|
||||||
|
|
||||||
|
u8 Unknown2[2];
|
||||||
|
|
||||||
|
enum RFChipType RFChipType;
|
||||||
|
u8 RFBitsPerEntry;
|
||||||
|
u8 RFEntries;
|
||||||
|
u8 Unknown3;
|
||||||
|
|
||||||
|
u8 InitialValues[32];
|
||||||
|
u8 InitialBBValues[105];
|
||||||
|
u8 Unused4;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u8 InitialRFValues[36];
|
||||||
|
u8 InitialRF56Values[84];
|
||||||
|
u8 InitialBB1EValues[14];
|
||||||
|
u8 InitialRf9Values[14];
|
||||||
|
} Type2Config;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u8 InitialRFValues[41];
|
||||||
|
u8 BBIndicesPerChannel;
|
||||||
|
u8 BBIndex1;
|
||||||
|
u8 BBData1[14];
|
||||||
|
u8 BBIndex2;
|
||||||
|
u8 BBData2[14];
|
||||||
|
u8 RFIndex1;
|
||||||
|
u8 RFData1[14];
|
||||||
|
u8 RFIndex2;
|
||||||
|
u8 RFData2[14];
|
||||||
|
u8 Unused0[46];
|
||||||
|
} Type3Config;
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 Unknown4;
|
||||||
|
u8 Unused5;
|
||||||
|
u8 Unused6[153];
|
||||||
|
enum WifiBoard WifiBoard;
|
||||||
|
u8 WifiFlash;
|
||||||
|
u8 Unused7;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(FirmwareHeader) == 512, "FirmwareHeader should be 512 bytes");
|
||||||
|
|
||||||
|
struct ExtendedUserSettings
|
||||||
|
{
|
||||||
|
char ID[8];
|
||||||
|
u16 Checksum;
|
||||||
|
u16 ChecksumLength;
|
||||||
|
u8 Version;
|
||||||
|
u8 UpdateCount;
|
||||||
|
u8 BootMenuFlags;
|
||||||
|
u8 GBABorder;
|
||||||
|
u16 TemperatureCalibration0;
|
||||||
|
u16 TemperatureCalibration1;
|
||||||
|
u16 TemperatureCalibrationDegrees;
|
||||||
|
u8 TemperatureFlags;
|
||||||
|
u8 BacklightIntensity;
|
||||||
|
u32 DateCenturyOffset;
|
||||||
|
u8 DateMonthRecovery;
|
||||||
|
u8 DateDayRecovery;
|
||||||
|
u8 DateYearRecovery;
|
||||||
|
u8 DateTimeFlags;
|
||||||
|
char DateSeparator;
|
||||||
|
char TimeSeparator;
|
||||||
|
char DecimalSeparator;
|
||||||
|
char ThousandsSeparator;
|
||||||
|
u8 DaylightSavingsTimeNth;
|
||||||
|
u8 DaylightSavingsTimeDay;
|
||||||
|
u8 DaylightSavingsTimeOfMonth;
|
||||||
|
u8 DaylightSavingsTimeFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(ExtendedUserSettings) == 0x28, "ExtendedUserSettings should be 40 bytes");
|
||||||
|
|
||||||
|
union UserData
|
||||||
|
{
|
||||||
|
UserData();
|
||||||
|
void UpdateChecksum();
|
||||||
|
[[nodiscard]] bool ChecksumValid() const
|
||||||
|
{
|
||||||
|
bool baseChecksumOk = Checksum == CRC16(Bytes, 0x70, 0xFFFF);
|
||||||
|
bool extendedChecksumOk = Bytes[0x74] != 1 || ExtendedSettings.Checksum == CRC16(Bytes + 0x74, 0x8A, 0xFFFF);
|
||||||
|
// For our purposes, the extended checksum is OK if we're not using extended data
|
||||||
|
|
||||||
|
return baseChecksumOk && extendedChecksumOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 Bytes[256];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u16 Version;
|
||||||
|
u8 FavoriteColor;
|
||||||
|
u8 BirthdayMonth;
|
||||||
|
u8 BirthdayDay;
|
||||||
|
u8 Unused0;
|
||||||
|
char16_t Nickname[10];
|
||||||
|
u16 NameLength;
|
||||||
|
char16_t Message[26];
|
||||||
|
u16 MessageLength;
|
||||||
|
u8 AlarmHour;
|
||||||
|
u8 AlarmMinute;
|
||||||
|
u8 Unknown0[2];
|
||||||
|
u8 AlarmFlags;
|
||||||
|
u8 Unused1;
|
||||||
|
u16 TouchCalibrationADC1[2];
|
||||||
|
u8 TouchCalibrationPixel1[2];
|
||||||
|
u16 TouchCalibrationADC2[2];
|
||||||
|
u8 TouchCalibrationPixel2[2];
|
||||||
|
u16 Settings;
|
||||||
|
u8 Year;
|
||||||
|
u8 RTCClockAdjust;
|
||||||
|
u32 RTCOffset;
|
||||||
|
u8 Unused2[4];
|
||||||
|
u16 UpdateCounter;
|
||||||
|
u16 Checksum;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u8 Unused3[0x8C];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u8 Unknown0;
|
||||||
|
Language ExtendedLanguage; // padded
|
||||||
|
u16 SupportedLanguageMask;
|
||||||
|
u8 Unused0[0x86];
|
||||||
|
u16 Checksum;
|
||||||
|
} ExtendedSettings;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(UserData) == 256, "UserData should be 256 bytes");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a default firmware blob
|
* Constructs a default firmware blob
|
||||||
* filled with data necessary for booting and configuring NDS games.
|
* filled with data necessary for booting and configuring NDS games.
|
||||||
|
@ -449,28 +451,28 @@ public:
|
||||||
Firmware& operator=(Firmware&& other) noexcept;
|
Firmware& operator=(Firmware&& other) noexcept;
|
||||||
~Firmware();
|
~Firmware();
|
||||||
|
|
||||||
[[nodiscard]] FirmwareHeader& Header() { return *reinterpret_cast<FirmwareHeader*>(FirmwareBuffer); }
|
[[nodiscard]] FirmwareHeader& GetHeader() { return *reinterpret_cast<FirmwareHeader*>(FirmwareBuffer); }
|
||||||
[[nodiscard]] const FirmwareHeader& Header() const { return *reinterpret_cast<const FirmwareHeader*>(FirmwareBuffer); }
|
[[nodiscard]] const FirmwareHeader& GetHeader() const { return *reinterpret_cast<const FirmwareHeader*>(FirmwareBuffer); }
|
||||||
|
|
||||||
/// @return The offset of the first basic Wi-fi settings block in the firmware
|
/// @return The offset of the first basic Wi-fi settings block in the firmware
|
||||||
/// (not the extended Wi-fi settings block used by the DSi).
|
/// (not the extended Wi-fi settings block used by the DSi).
|
||||||
/// @see WifiAccessPointPosition
|
/// @see WifiAccessPointPosition
|
||||||
[[nodiscard]] u32 WifiAccessPointOffset() const { return UserDataOffset() - 0x400; }
|
[[nodiscard]] u32 GetWifiAccessPointOffset() const { return GetUserDataOffset() - 0x400; }
|
||||||
|
|
||||||
/// @return The address of the first basic Wi-fi settings block in the firmware.
|
/// @return The address of the first basic Wi-fi settings block in the firmware.
|
||||||
[[nodiscard]] u8* WifiAccessPointPosition() { return FirmwareBuffer + WifiAccessPointOffset(); }
|
[[nodiscard]] u8* GetWifiAccessPointPosition() { return FirmwareBuffer + GetWifiAccessPointOffset(); }
|
||||||
[[nodiscard]] const u8* WifiAccessPointPosition() const { return FirmwareBuffer + WifiAccessPointOffset(); }
|
[[nodiscard]] const u8* GetWifiAccessPointPosition() const { return FirmwareBuffer + GetWifiAccessPointOffset(); }
|
||||||
|
|
||||||
[[nodiscard]] const std::array<WifiAccessPoint, 3>& AccessPoints() const
|
[[nodiscard]] const std::array<WifiAccessPoint, 3>& GetAccessPoints() const
|
||||||
{
|
{
|
||||||
// An std::array is a wrapper around a C array, so this cast is fine.
|
// An std::array is a wrapper around a C array, so this cast is fine.
|
||||||
return *reinterpret_cast<const std::array<WifiAccessPoint, 3>*>(WifiAccessPointPosition());
|
return *reinterpret_cast<const std::array<WifiAccessPoint, 3>*>(GetWifiAccessPointPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::array<WifiAccessPoint, 3>& AccessPoints()
|
[[nodiscard]] std::array<WifiAccessPoint, 3>& GetAccessPoints()
|
||||||
{
|
{
|
||||||
// An std::array is a wrapper around a C array, so this cast is fine.
|
// An std::array is a wrapper around a C array, so this cast is fine.
|
||||||
return *reinterpret_cast<std::array<WifiAccessPoint, 3>*>(WifiAccessPointPosition());
|
return *reinterpret_cast<std::array<WifiAccessPoint, 3>*>(GetWifiAccessPointPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns \c true if this firmware image contains bootable code.
|
/// @returns \c true if this firmware image contains bootable code.
|
||||||
|
@ -481,20 +483,20 @@ public:
|
||||||
|
|
||||||
/// @return The address of the first extended Wi-fi settings block in the firmware.
|
/// @return The address of the first extended Wi-fi settings block in the firmware.
|
||||||
/// @warning Only meaningful if this is DSi firmware.
|
/// @warning Only meaningful if this is DSi firmware.
|
||||||
[[nodiscard]] u32 ExtendedAccessPointOffset() const { return UserDataOffset() + EXTENDED_WIFI_SETTINGS_OFFSET; }
|
[[nodiscard]] u32 GetExtendedAccessPointOffset() const { return GetUserDataOffset() + EXTENDED_WIFI_SETTINGS_OFFSET; }
|
||||||
[[nodiscard]] u8* ExtendedAccessPointPosition() { return FirmwareBuffer + ExtendedAccessPointOffset(); }
|
[[nodiscard]] u8* GetExtendedAccessPointPosition() { return FirmwareBuffer + GetExtendedAccessPointOffset(); }
|
||||||
[[nodiscard]] const u8* ExtendedAccessPointPosition() const { return FirmwareBuffer + ExtendedAccessPointOffset(); }
|
[[nodiscard]] const u8* GetExtendedAccessPointPosition() const { return FirmwareBuffer + GetExtendedAccessPointOffset(); }
|
||||||
|
|
||||||
[[nodiscard]] const std::array<ExtendedWifiAccessPoint, 3>& ExtendedAccessPoints() const
|
[[nodiscard]] const std::array<ExtendedWifiAccessPoint, 3>& GetExtendedAccessPoints() const
|
||||||
{
|
{
|
||||||
// An std::array is a wrapper around a C array, so this cast is fine.
|
// An std::array is a wrapper around a C array, so this cast is fine.
|
||||||
return *reinterpret_cast<const std::array<ExtendedWifiAccessPoint, 3>*>(ExtendedAccessPointPosition());
|
return *reinterpret_cast<const std::array<ExtendedWifiAccessPoint, 3>*>(GetExtendedAccessPointPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::array<ExtendedWifiAccessPoint, 3>& ExtendedAccessPoints()
|
[[nodiscard]] std::array<ExtendedWifiAccessPoint, 3>& GetExtendedAccessPoints()
|
||||||
{
|
{
|
||||||
// An std::array is a wrapper around a C array, so this cast is fine.
|
// An std::array is a wrapper around a C array, so this cast is fine.
|
||||||
return *reinterpret_cast<std::array<ExtendedWifiAccessPoint, 3>*>(ExtendedAccessPointPosition());
|
return *reinterpret_cast<std::array<ExtendedWifiAccessPoint, 3>*>(GetExtendedAccessPointPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return The pointer to the firmware buffer,
|
/// @return The pointer to the firmware buffer,
|
||||||
|
@ -508,21 +510,21 @@ public:
|
||||||
|
|
||||||
/// @return The offset of the first user data section in the firmware.
|
/// @return The offset of the first user data section in the firmware.
|
||||||
/// @see UserDataPosition
|
/// @see UserDataPosition
|
||||||
[[nodiscard]] u32 UserDataOffset() const { return Header().UserSettingsOffset << 3; }
|
[[nodiscard]] u32 GetUserDataOffset() const { return GetHeader().UserSettingsOffset << 3; }
|
||||||
|
|
||||||
/// @return The address of the first user data section in the firmware.
|
/// @return The address of the first user data section in the firmware.
|
||||||
/// @see UserDataOffset
|
/// @see UserDataOffset
|
||||||
[[nodiscard]] u8* UserDataPosition() { return FirmwareBuffer + UserDataOffset(); }
|
[[nodiscard]] u8* GetUserDataPosition() { return FirmwareBuffer + GetUserDataOffset(); }
|
||||||
[[nodiscard]] const u8* UserDataPosition() const { return FirmwareBuffer + UserDataOffset(); }
|
[[nodiscard]] const u8* GetUserDataPosition() const { return FirmwareBuffer + GetUserDataOffset(); }
|
||||||
|
|
||||||
|
|
||||||
/// @return Reference to the two user data sections.
|
/// @return Reference to the two user data sections.
|
||||||
/// @note Either \c UserData object could be the "effective" one,
|
/// @note Either \c UserData object could be the "effective" one,
|
||||||
/// so prefer using \c EffectiveUserData() if you're not modifying both.
|
/// so prefer using \c EffectiveUserData() if you're not modifying both.
|
||||||
[[nodiscard]] const std::array<union UserData, 2>& UserData() const
|
[[nodiscard]] const std::array<union UserData, 2>& GetUserData() const
|
||||||
{
|
{
|
||||||
// An std::array is a wrapper around a C array, so this cast is fine.
|
// An std::array is a wrapper around a C array, so this cast is fine.
|
||||||
return *reinterpret_cast<const std::array<union UserData, 2>*>(UserDataPosition());
|
return *reinterpret_cast<const std::array<union UserData, 2>*>(GetUserDataPosition());
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -531,10 +533,10 @@ public:
|
||||||
* so prefer using \c EffectiveUserData() if you're not modifying both.
|
* so prefer using \c EffectiveUserData() if you're not modifying both.
|
||||||
* @warning Remember to call UserData::UpdateChecksum() after modifying any of its fields.
|
* @warning Remember to call UserData::UpdateChecksum() after modifying any of its fields.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::array<union UserData, 2>& UserData()
|
[[nodiscard]] std::array<union UserData, 2>& GetUserData()
|
||||||
{
|
{
|
||||||
// An std::array is a wrapper around a C array, so this cast is fine.
|
// An std::array is a wrapper around a C array, so this cast is fine.
|
||||||
return *reinterpret_cast<std::array<union UserData, 2>*>(UserDataPosition());
|
return *reinterpret_cast<std::array<union UserData, 2>*>(GetUserDataPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -543,13 +545,16 @@ public:
|
||||||
* Specifically, the firmware will use whichever one has the valid checksum
|
* Specifically, the firmware will use whichever one has the valid checksum
|
||||||
* (or the newer one if they're both valid).
|
* (or the newer one if they're both valid).
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] const union UserData& EffectiveUserData() const;
|
[[nodiscard]] const union UserData& GetEffectiveUserData() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Reference to whichever of the two user data sections
|
* @return Reference to whichever of the two user data sections
|
||||||
* has the highest update counter.
|
* has the highest update counter.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] union UserData& EffectiveUserData();
|
[[nodiscard]] union UserData& GetEffectiveUserData();
|
||||||
|
|
||||||
|
/// Fix the given firmware length to an acceptable length
|
||||||
|
u32 FixFirmwareLength(u32 originalLength);
|
||||||
|
|
||||||
/// Updates the checksums of all used sections of the firmware.
|
/// Updates the checksums of all used sections of the firmware.
|
||||||
void UpdateChecksums();
|
void UpdateChecksums();
|
||||||
|
@ -558,6 +563,5 @@ private:
|
||||||
u32 FirmwareBufferLength;
|
u32 FirmwareBufferLength;
|
||||||
u32 FirmwareMask;
|
u32 FirmwareMask;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
#endif //MELONDS_SPI_FIRMWARE_H
|
#endif //MELONDS_SPI_FIRMWARE_H
|
||||||
|
|
13
src/Wifi.cpp
13
src/Wifi.cpp
|
@ -180,7 +180,6 @@ void DeInit()
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
using namespace SPI_Firmware;
|
|
||||||
memset(RAM, 0, 0x2000);
|
memset(RAM, 0, 0x2000);
|
||||||
memset(IO, 0, 0x1000);
|
memset(IO, 0, 0x1000);
|
||||||
|
|
||||||
|
@ -220,15 +219,17 @@ void Reset()
|
||||||
}
|
}
|
||||||
#undef BBREG_FIXED
|
#undef BBREG_FIXED
|
||||||
|
|
||||||
RFVersion = GetFirmware()->Header().RFChipType;
|
const Firmware* fw = NDS::SPI->GetFirmware();
|
||||||
|
|
||||||
|
RFVersion = fw->GetHeader().RFChipType;
|
||||||
memset(RFRegs, 0, 4*0x40);
|
memset(RFRegs, 0, 4*0x40);
|
||||||
|
|
||||||
FirmwareConsoleType console = GetFirmware()->Header().ConsoleType;
|
Firmware::FirmwareConsoleType console = fw->GetHeader().ConsoleType;
|
||||||
if (console == FirmwareConsoleType::DS)
|
if (console == Firmware::FirmwareConsoleType::DS)
|
||||||
IOPORT(0x000) = 0x1440;
|
IOPORT(0x000) = 0x1440;
|
||||||
else if (console == FirmwareConsoleType::DSLite)
|
else if (console == Firmware::FirmwareConsoleType::DSLite)
|
||||||
IOPORT(0x000) = 0xC340;
|
IOPORT(0x000) = 0xC340;
|
||||||
else if (NDS::ConsoleType == 1 && console == FirmwareConsoleType::DSi)
|
else if (NDS::ConsoleType == 1 && console == Firmware::FirmwareConsoleType::DSi)
|
||||||
IOPORT(0x000) = 0xC340; // DSi has the modern DS-wifi variant
|
IOPORT(0x000) = 0xC340; // DSi has the modern DS-wifi variant
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -580,31 +580,31 @@ void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen
|
||||||
ROMManager::GBASave->RequestFlush(savedata, savelen, writeoffset, writelen);
|
ROMManager::GBASave->RequestFlush(savedata, savelen, writeoffset, writelen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteFirmware(const SPI_Firmware::Firmware& firmware, u32 writeoffset, u32 writelen)
|
void WriteFirmware(const Firmware& firmware, u32 writeoffset, u32 writelen)
|
||||||
{
|
{
|
||||||
if (!ROMManager::FirmwareSave)
|
if (!ROMManager::FirmwareSave)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (firmware.Header().Identifier != SPI_Firmware::GENERATED_FIRMWARE_IDENTIFIER)
|
if (firmware.GetHeader().Identifier != GENERATED_FIRMWARE_IDENTIFIER)
|
||||||
{ // If this is not the default built-in firmware...
|
{ // If this is not the default built-in firmware...
|
||||||
// ...then write the whole thing back.
|
// ...then write the whole thing back.
|
||||||
ROMManager::FirmwareSave->RequestFlush(firmware.Buffer(), firmware.Length(), writeoffset, writelen);
|
ROMManager::FirmwareSave->RequestFlush(firmware.Buffer(), firmware.Length(), writeoffset, writelen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 eapstart = firmware.ExtendedAccessPointOffset();
|
u32 eapstart = firmware.GetExtendedAccessPointOffset();
|
||||||
u32 eapend = eapstart + sizeof(firmware.ExtendedAccessPoints());
|
u32 eapend = eapstart + sizeof(firmware.GetExtendedAccessPoints());
|
||||||
|
|
||||||
u32 apstart = firmware.WifiAccessPointOffset();
|
u32 apstart = firmware.GetWifiAccessPointOffset();
|
||||||
u32 apend = apstart + sizeof(firmware.AccessPoints());
|
u32 apend = apstart + sizeof(firmware.GetAccessPoints());
|
||||||
|
|
||||||
// assert that the extended access points come just before the regular ones
|
// assert that the extended access points come just before the regular ones
|
||||||
assert(eapend == apstart);
|
assert(eapend == apstart);
|
||||||
|
|
||||||
if (eapstart <= writeoffset && writeoffset < apend)
|
if (eapstart <= writeoffset && writeoffset < apend)
|
||||||
{ // If we're writing to the access points...
|
{ // If we're writing to the access points...
|
||||||
const u8* buffer = firmware.ExtendedAccessPointPosition();
|
const u8* buffer = firmware.GetExtendedAccessPointPosition();
|
||||||
u32 length = sizeof(firmware.ExtendedAccessPoints()) + sizeof(firmware.AccessPoints());
|
u32 length = sizeof(firmware.GetExtendedAccessPoints()) + sizeof(firmware.GetAccessPoints());
|
||||||
ROMManager::FirmwareSave->RequestFlush(buffer, length, writeoffset - eapstart, writelen);
|
ROMManager::FirmwareSave->RequestFlush(buffer, length, writeoffset - eapstart, writelen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ PowerManagementDialog::PowerManagementDialog(QWidget* parent) : QDialog(parent),
|
||||||
{
|
{
|
||||||
ui->grpDSiBattery->setEnabled(false);
|
ui->grpDSiBattery->setEnabled(false);
|
||||||
|
|
||||||
oldDSBatteryLevel = SPI_Powerman::GetBatteryLevelOkay();
|
oldDSBatteryLevel = NDS::SPI->GetPowerMan()->GetBatteryLevelOkay();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDSBatteryLevelControls();
|
updateDSBatteryLevelControls();
|
||||||
|
@ -91,7 +91,7 @@ void PowerManagementDialog::done(int r)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Config::DSBatteryLevelOkay = SPI_Powerman::GetBatteryLevelOkay();
|
Config::DSBatteryLevelOkay = NDS::SPI->GetPowerMan()->GetBatteryLevelOkay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -103,7 +103,7 @@ void PowerManagementDialog::done(int r)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SPI_Powerman::SetBatteryLevelOkay(oldDSBatteryLevel);
|
NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(oldDSBatteryLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,17 +114,17 @@ void PowerManagementDialog::done(int r)
|
||||||
|
|
||||||
void PowerManagementDialog::on_rbDSBatteryLow_clicked()
|
void PowerManagementDialog::on_rbDSBatteryLow_clicked()
|
||||||
{
|
{
|
||||||
SPI_Powerman::SetBatteryLevelOkay(false);
|
NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerManagementDialog::on_rbDSBatteryOkay_clicked()
|
void PowerManagementDialog::on_rbDSBatteryOkay_clicked()
|
||||||
{
|
{
|
||||||
SPI_Powerman::SetBatteryLevelOkay(true);
|
NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerManagementDialog::updateDSBatteryLevelControls()
|
void PowerManagementDialog::updateDSBatteryLevelControls()
|
||||||
{
|
{
|
||||||
if (SPI_Powerman::GetBatteryLevelOkay())
|
if (NDS::SPI->GetPowerMan()->GetBatteryLevelOkay())
|
||||||
ui->rbDSBatteryOkay->setChecked(true);
|
ui->rbDSBatteryOkay->setChecked(true);
|
||||||
else
|
else
|
||||||
ui->rbDSBatteryLow->setChecked(true);
|
ui->rbDSBatteryLow->setChecked(true);
|
||||||
|
|
|
@ -588,7 +588,7 @@ void SetBatteryLevels()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SPI_Powerman::SetBatteryLevelOkay(Config::DSBatteryLevelOkay);
|
NDS::SPI->GetPowerMan()->SetBatteryLevelOkay(Config::DSBatteryLevelOkay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,10 +792,10 @@ void ClearBackupState()
|
||||||
|
|
||||||
// We want both the firmware object and the path that was used to load it,
|
// We want both the firmware object and the path that was used to load it,
|
||||||
// since we'll need to give it to the save manager later
|
// since we'll need to give it to the save manager later
|
||||||
pair<unique_ptr<SPI_Firmware::Firmware>, string> LoadFirmwareFromFile()
|
pair<unique_ptr<Firmware>, string> LoadFirmwareFromFile()
|
||||||
{
|
{
|
||||||
string loadedpath;
|
string loadedpath;
|
||||||
unique_ptr<SPI_Firmware::Firmware> firmware = nullptr;
|
unique_ptr<Firmware> firmware = nullptr;
|
||||||
string firmwarepath = Config::ConsoleType == 0 ? Config::FirmwarePath : Config::DSiFirmwarePath;
|
string firmwarepath = Config::ConsoleType == 0 ? Config::FirmwarePath : Config::DSiFirmwarePath;
|
||||||
|
|
||||||
Log(LogLevel::Debug, "SPI firmware: loading from file %s\n", firmwarepath.c_str());
|
Log(LogLevel::Debug, "SPI firmware: loading from file %s\n", firmwarepath.c_str());
|
||||||
|
@ -812,7 +812,7 @@ pair<unique_ptr<SPI_Firmware::Firmware>, string> LoadFirmwareFromFile()
|
||||||
|
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
firmware = make_unique<SPI_Firmware::Firmware>(f);
|
firmware = make_unique<Firmware>(f);
|
||||||
if (!firmware->Buffer())
|
if (!firmware->Buffer())
|
||||||
{
|
{
|
||||||
Log(LogLevel::Warn, "Couldn't read firmware file!\n");
|
Log(LogLevel::Warn, "Couldn't read firmware file!\n");
|
||||||
|
@ -826,9 +826,8 @@ pair<unique_ptr<SPI_Firmware::Firmware>, string> LoadFirmwareFromFile()
|
||||||
return std::make_pair(std::move(firmware), loadedpath);
|
return std::make_pair(std::move(firmware), loadedpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<unique_ptr<SPI_Firmware::Firmware>, string> GenerateDefaultFirmware()
|
pair<unique_ptr<Firmware>, string> GenerateDefaultFirmware()
|
||||||
{
|
{
|
||||||
using namespace SPI_Firmware;
|
|
||||||
// Construct the default firmware...
|
// Construct the default firmware...
|
||||||
string settingspath;
|
string settingspath;
|
||||||
std::unique_ptr<Firmware> firmware = std::make_unique<Firmware>(Config::ConsoleType);
|
std::unique_ptr<Firmware> firmware = std::make_unique<Firmware>(Config::ConsoleType);
|
||||||
|
@ -850,27 +849,27 @@ pair<unique_ptr<SPI_Firmware::Firmware>, string> GenerateDefaultFirmware()
|
||||||
// and if we didn't keep them then the player would have to reset them in each session.
|
// and if we didn't keep them then the player would have to reset them in each session.
|
||||||
if (f)
|
if (f)
|
||||||
{ // If we have Wi-fi settings to load...
|
{ // If we have Wi-fi settings to load...
|
||||||
constexpr unsigned TOTAL_WFC_SETTINGS_SIZE = 3 * (sizeof(WifiAccessPoint) + sizeof(ExtendedWifiAccessPoint));
|
constexpr unsigned TOTAL_WFC_SETTINGS_SIZE = 3 * (sizeof(Firmware::WifiAccessPoint) + sizeof(Firmware::ExtendedWifiAccessPoint));
|
||||||
|
|
||||||
// The access point and extended access point segments might
|
// The access point and extended access point segments might
|
||||||
// be in different locations depending on the firmware revision,
|
// be in different locations depending on the firmware revision,
|
||||||
// but our generated firmware always keeps them next to each other.
|
// but our generated firmware always keeps them next to each other.
|
||||||
// (Extended access points first, then regular ones.)
|
// (Extended access points first, then regular ones.)
|
||||||
|
|
||||||
if (!FileRead(firmware->ExtendedAccessPointPosition(), TOTAL_WFC_SETTINGS_SIZE, 1, f))
|
if (!FileRead(firmware->GetExtendedAccessPointPosition(), TOTAL_WFC_SETTINGS_SIZE, 1, f))
|
||||||
{ // If we couldn't read the Wi-fi settings from this file...
|
{ // If we couldn't read the Wi-fi settings from this file...
|
||||||
Platform::Log(Platform::LogLevel::Warn, "Failed to read Wi-fi settings from \"%s\"; using defaults instead\n", wfcsettingspath.c_str());
|
Platform::Log(Platform::LogLevel::Warn, "Failed to read Wi-fi settings from \"%s\"; using defaults instead\n", wfcsettingspath.c_str());
|
||||||
|
|
||||||
firmware->AccessPoints() = {
|
firmware->GetAccessPoints() = {
|
||||||
WifiAccessPoint(Config::ConsoleType),
|
Firmware::WifiAccessPoint(Config::ConsoleType),
|
||||||
WifiAccessPoint(),
|
Firmware::WifiAccessPoint(),
|
||||||
WifiAccessPoint(),
|
Firmware::WifiAccessPoint(),
|
||||||
};
|
};
|
||||||
|
|
||||||
firmware->ExtendedAccessPoints() = {
|
firmware->GetExtendedAccessPoints() = {
|
||||||
ExtendedWifiAccessPoint(),
|
Firmware::ExtendedWifiAccessPoint(),
|
||||||
ExtendedWifiAccessPoint(),
|
Firmware::ExtendedWifiAccessPoint(),
|
||||||
ExtendedWifiAccessPoint(),
|
Firmware::ExtendedWifiAccessPoint(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,10 +883,9 @@ pair<unique_ptr<SPI_Firmware::Firmware>, string> GenerateDefaultFirmware()
|
||||||
return std::make_pair(std::move(firmware), std::move(wfcsettingspath));
|
return std::make_pair(std::move(firmware), std::move(wfcsettingspath));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadUserSettingsFromConfig(SPI_Firmware::Firmware& firmware)
|
void LoadUserSettingsFromConfig(Firmware& firmware)
|
||||||
{
|
{
|
||||||
using namespace SPI_Firmware;
|
auto& currentData = firmware.GetEffectiveUserData();
|
||||||
UserData& currentData = firmware.EffectiveUserData();
|
|
||||||
|
|
||||||
// setting up username
|
// setting up username
|
||||||
std::string orig_username = Config::FirmwareUsername;
|
std::string orig_username = Config::FirmwareUsername;
|
||||||
|
@ -899,10 +897,10 @@ void LoadUserSettingsFromConfig(SPI_Firmware::Firmware& firmware)
|
||||||
memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto language = static_cast<Language>(Config::FirmwareLanguage);
|
auto language = static_cast<Firmware::Language>(Config::FirmwareLanguage);
|
||||||
if (language != Language::Reserved)
|
if (language != Firmware::Language::Reserved)
|
||||||
{ // If the frontend specifies a language (rather than using the existing value)...
|
{ // If the frontend specifies a language (rather than using the existing value)...
|
||||||
currentData.Settings &= ~Language::Reserved; // ..clear the existing language...
|
currentData.Settings &= ~Firmware::Language::Reserved; // ..clear the existing language...
|
||||||
currentData.Settings |= language; // ...and set the new one.
|
currentData.Settings |= language; // ...and set the new one.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -937,7 +935,7 @@ void LoadUserSettingsFromConfig(SPI_Firmware::Firmware& firmware)
|
||||||
|
|
||||||
MacAddress mac;
|
MacAddress mac;
|
||||||
bool rep = false;
|
bool rep = false;
|
||||||
auto& header = firmware.Header();
|
auto& header = firmware.GetHeader();
|
||||||
|
|
||||||
memcpy(&mac, header.MacAddress.data(), sizeof(MacAddress));
|
memcpy(&mac, header.MacAddress.data(), sizeof(MacAddress));
|
||||||
|
|
||||||
|
@ -1035,7 +1033,7 @@ bool InstallNAND(const u8* es_keyY)
|
||||||
memcpy(&settings.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
memcpy(&settings.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
||||||
|
|
||||||
// setting language
|
// setting language
|
||||||
settings.Language = static_cast<SPI_Firmware::Language>(Config::FirmwareLanguage);
|
settings.Language = static_cast<Firmware::Language>(Config::FirmwareLanguage);
|
||||||
|
|
||||||
// setting up color
|
// setting up color
|
||||||
settings.FavoriteColor = Config::FirmwareFavouriteColour;
|
settings.FavoriteColor = Config::FirmwareFavouriteColour;
|
||||||
|
@ -1074,7 +1072,6 @@ bool InstallNAND(const u8* es_keyY)
|
||||||
|
|
||||||
bool InstallFirmware()
|
bool InstallFirmware()
|
||||||
{
|
{
|
||||||
using namespace SPI_Firmware;
|
|
||||||
FirmwareSave.reset();
|
FirmwareSave.reset();
|
||||||
unique_ptr<Firmware> firmware;
|
unique_ptr<Firmware> firmware;
|
||||||
string firmwarepath;
|
string firmwarepath;
|
||||||
|
@ -1105,7 +1102,7 @@ bool InstallFirmware()
|
||||||
|
|
||||||
FirmwareSave = std::make_unique<SaveManager>(firmwarepath);
|
FirmwareSave = std::make_unique<SaveManager>(firmwarepath);
|
||||||
|
|
||||||
return InstallFirmware(std::move(firmware));
|
return NDS::SPI->GetFirmwareMem()->InstallFirmware(std::move(firmware));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadROM(QStringList filepath, bool reset)
|
bool LoadROM(QStringList filepath, bool reset)
|
||||||
|
|
Loading…
Reference in New Issue