segatools/platform/system.c

182 lines
4.4 KiB
C
Raw Normal View History

2023-07-13 22:41:23 +00:00
#include <windows.h>
#include <ntstatus.h>
#include <assert.h>
#include <string.h>
#include "platform/system.h"
2023-07-13 22:41:23 +00:00
#include "platform/vfs.h"
#include "util/dprintf.h"
#include "util/str.h"
#include "util/crc.h"
#define DATA_SIZE 503
#define BLOCK_SIZE (sizeof(uint32_t) + 4 + 1 + DATA_SIZE)
#pragma pack(push, 1)
typedef struct
{
uint32_t checksum;
2023-12-03 21:22:17 +00:00
char padding[6];
uint8_t freeplay;
char data[DATA_SIZE - 2];
} CreditBlock;
typedef struct
{
uint32_t checksum;
char padding[4];
2023-07-13 22:41:23 +00:00
uint8_t dip_switches;
char data[DATA_SIZE];
} DipSwBlock;
2023-07-13 22:41:23 +00:00
typedef struct
{
2023-12-03 21:22:17 +00:00
CreditBlock credit_block;
DipSwBlock dip_switch_block;
2023-07-13 22:41:23 +00:00
char *data;
2023-12-03 21:22:17 +00:00
} SystemInfo;
2023-07-13 22:41:23 +00:00
#pragma pack(pop)
2023-12-03 21:22:17 +00:00
static SystemInfo system_info;
2023-07-13 22:41:23 +00:00
static struct system_config system_config;
2023-07-13 22:41:23 +00:00
static struct vfs_config vfs_config;
static void system_read_sysfile(const wchar_t *sys_file);
static void system_save_sysfile(const wchar_t *sys_file);
2023-07-13 22:41:23 +00:00
HRESULT system_init(const struct system_config *cfg, const struct vfs_config *vfs_cfg)
2023-07-13 22:41:23 +00:00
{
HRESULT hr;
wchar_t sys_file_path[MAX_PATH];
assert(cfg != NULL);
assert(vfs_cfg != NULL);
if (!cfg->enable)
{
return S_FALSE;
}
memcpy(&system_config, cfg, sizeof(*cfg));
2023-07-13 22:41:23 +00:00
sys_file_path[0] = L'\0';
// concatenate vfs_config.amfs with L"sysfile.dat"
wcsncpy(sys_file_path, vfs_cfg->amfs, MAX_PATH);
wcsncat(sys_file_path, L"\\sysfile.dat", MAX_PATH);
system_read_sysfile(sys_file_path);
2023-07-13 22:41:23 +00:00
// now write the system_config.system to the dip_switch_block
system_save_sysfile(sys_file_path);
2023-07-13 22:41:23 +00:00
return S_OK;
}
static void system_read_sysfile(const wchar_t *sys_file)
2023-07-13 22:41:23 +00:00
{
FILE *f = _wfopen(sys_file, L"r");
if (f == NULL)
{
dprintf("System: First run detected, system settings can only be applied AFTER the first run\n");
2023-07-13 22:41:23 +00:00
return;
}
fseek(f, 0, SEEK_END);
long file_size = ftell(f);
fseek(f, 0, SEEK_SET);
if (file_size != 0x6000)
{
dprintf("System: Invalid sysfile.dat file size\n");
2023-07-13 22:41:23 +00:00
fclose(f);
return;
}
2023-12-03 21:22:17 +00:00
system_info.data = malloc(file_size);
fread(system_info.data, 1, file_size, f);
2023-07-13 22:41:23 +00:00
fclose(f);
2023-12-03 21:22:17 +00:00
// copy the credit_block and dip_switch_block from the sysfile.dat
memcpy(&system_info.credit_block, system_info.data, BLOCK_SIZE);
memcpy(&system_info.dip_switch_block, system_info.data + 0x2800, BLOCK_SIZE);
2023-07-13 22:41:23 +00:00
}
static void system_save_sysfile(const wchar_t *sys_file)
2023-07-13 22:41:23 +00:00
{
2023-12-03 21:22:17 +00:00
char block[BLOCK_SIZE];
uint8_t system = 0;
2023-12-03 21:22:17 +00:00
uint8_t freeplay = 0;
2023-07-13 22:41:23 +00:00
// open the sysfile.dat for writing in bytes mode
FILE *f = _wfopen(sys_file, L"rb+");
if (f == NULL)
{
return;
}
// write the system_config.system to the dip_switch_block
2023-07-13 22:41:23 +00:00
for (int i = 0; i < 8; i++)
{
if (system_config.dipsw[i])
2023-07-13 22:41:23 +00:00
{
// print which system is enabled
dprintf("System: DipSw%d=1 set\n", i + 1);
system |= (1 << i);
2023-07-13 22:41:23 +00:00
}
}
if (system_config.freeplay)
2023-12-03 21:22:17 +00:00
{
// print that freeplay is enabled
dprintf("System: Freeplay enabled\n");
2023-12-03 21:22:17 +00:00
freeplay = 1;
}
// set the new credit block
system_info.credit_block.freeplay = freeplay;
// set the new dip_switch_block
system_info.dip_switch_block.dip_switches = system;
2023-07-13 22:41:23 +00:00
// calculate the new checksum, skip the old crc32 value
// which is at the beginning of the block, thats's why the +4
// conver the struct to chars in order for the crc32 calculation to work
2023-12-03 21:22:17 +00:00
system_info.credit_block.checksum = crc32(
(char *)&system_info.credit_block + 4, BLOCK_SIZE - 4, 0);
system_info.dip_switch_block.checksum = crc32(
(char *)&system_info.dip_switch_block + 4, BLOCK_SIZE - 4, 0);
// build the new credit block
memcpy(block, (char *)&system_info.credit_block, BLOCK_SIZE);
memcpy(system_info.data, block, BLOCK_SIZE);
memcpy(system_info.data + 0x3000, block, BLOCK_SIZE);
2023-07-13 22:41:23 +00:00
// build the new dip switch block
2023-12-03 21:22:17 +00:00
memcpy(block, (char *)&system_info.dip_switch_block, BLOCK_SIZE);
2023-07-13 22:41:23 +00:00
2023-12-03 21:22:17 +00:00
memcpy(system_info.data + 0x2800, block, BLOCK_SIZE);
memcpy(system_info.data + 0x5800, block, BLOCK_SIZE);
2023-07-13 22:41:23 +00:00
// print the dip_switch_block in hex
/*
dprintf("System Block: ");
2023-07-13 22:41:23 +00:00
for (size_t i = 0; i < BLOCK_SIZE; i++)
{
2023-12-03 21:22:17 +00:00
dprintf("%02X ", ((uint8_t *)&system_info.dip_switch_block)[i]);
2023-07-13 22:41:23 +00:00
}
dprintf("\n");
*/
2023-12-03 21:22:17 +00:00
fwrite(system_info.data, 1, 0x6000, f);
2023-07-13 22:41:23 +00:00
fclose(f);
}