Files
libretro-atari800/atari800/src/atari_ps2.c
T
2015-12-14 14:00:35 +01:00

1018 lines
22 KiB
C

/*
* atari_ps2.c - Sony PlayStation 2 port code
*
* Copyright (c) 2005 Troy Ayers and Piotr Fusik
* Copyright (c) 2005-2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
//TODO: map the following keys
//control <>: (suits)
//akey_clear
//AKEY_BREAK
//all ALT+key shortcut keys
//Atari OPTION key (temple of apshai, others?)
//keyboard repeat (when shift nor control pressed)
//mouse support
//autodetect pal vs ntsc
//allow user to map own keyboard keys to controller
//enable cdfs, hdd, mass, and host support.
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <tamtypes.h>
#include <loadfile.h>
#include <fileio.h>
#include <sifcmd.h>
#include <sifrpc.h>
#include <kernel.h>
#include <debug.h>
#include <libmc.h>
#include <libkbd.h>
#include <libpad.h>
#include <gsKit.h>
#include <dmaKit.h>
#include "atari.h"
#include "colours.h"
#include "input.h"
#include "akey.h"
#include "log.h"
#include "monitor.h"
#include "screen.h"
#include "ui.h"
#include "util.h"
//#ifdef SOUND
#include <audsrv.h>
#include "pokeysnd.h"
#include "sound.h"
extern unsigned char audsrv[];
extern unsigned int size_audsrv;
//#endif
// define to use T0 and T1 timers
#define USE_TIMERS
extern unsigned char usbd[];
extern unsigned int size_usbd;
extern unsigned char ps2kbd[];
extern unsigned int size_ps2kbd;
static GSGLOBAL *gsGlobal = NULL;
static int clut[256] __attribute__((aligned(16)));
//int PS2KbdCAPS = 0;
int PS2KbdSHIFT = 0;
int PS2KbdCONTROL = 0;
int PS2KbdALT = 0;
#define PAD_PORT 0
#define PAD_SLOT 0
static char padBuf[256] __attribute__((aligned(64)));
#ifdef USE_TIMERS
/* We use T0 for PLATFORM_Time() and T1 for PLATFORM_Sleep().
Note that both timers are just 16-bit. */
#define T0_COUNT (*(volatile unsigned long *) 0x10000000)
#define T0_MODE (*(volatile unsigned long *) 0x10000010)
#define T0_COMP (*(volatile unsigned long *) 0x10000020)
#define T1_COUNT (*(volatile unsigned long *) 0x10000800)
#define T1_MODE (*(volatile unsigned long *) 0x10000810)
#define T1_COMP (*(volatile unsigned long *) 0x10000820)
#define INTC_TIM0 9
#define INTC_TIM1 10
static int t0_interrupt_id = -1;
static int t1_interrupt_id = -1;
/* The range of int is enough for about 7 years
of continuous running. */
static volatile int timer_interrupt_ticks = 0;
static int sleeping_thread_id = 0;
static int t0_interrupt_handler(int ca)
{
timer_interrupt_ticks++;
T0_MODE |= 0x800; // clear overflow status
// __asm__ volatile("sync.l; ei"); // XXX: necessary?
return -1; // XXX: or 0? what does it mean?
}
static int t1_interrupt_handler(int ca)
{
iWakeupThread(sleeping_thread_id);
T1_MODE = 0; // disable
// __asm__ volatile("sync.l; ei"); // XXX: necessary?
return -1; // XXX: or 0? what does it mean?
}
static void timer_initialize(void)
{
T0_MODE = 0; // disable
t0_interrupt_id = AddIntcHandler(INTC_TIM0, t0_interrupt_handler, 0);
EnableIntc(INTC_TIM0);
T0_COUNT = 0;
T0_MODE = 0x002 // 576000 Hz clock
+ 0x080 // start counting
+ 0x200; // generate interrupt on overflow
T1_MODE = 0; // disable
t1_interrupt_id = AddIntcHandler(INTC_TIM1, t1_interrupt_handler, 0);
EnableIntc(INTC_TIM1);
}
static void timer_shutdown(void)
{
T0_MODE = 0;
if (t0_interrupt_id >= 0) {
DisableIntc(INTC_TIM0);
RemoveIntcHandler(INTC_TIM0, t0_interrupt_id);
t0_interrupt_id = -1;
}
T1_MODE = 0;
if (t1_interrupt_id >= 0) {
DisableIntc(INTC_TIM1);
RemoveIntcHandler(INTC_TIM1, t1_interrupt_id);
t1_interrupt_id = -1;
}
}
#endif /* USE_TIMERS */
double PLATFORM_Time(void)
{
#ifdef USE_TIMERS
/* AFAIK, multiplication is faster than division,
on every CPU architecture */
return (timer_interrupt_ticks * 65536.0 + T0_COUNT) * (1.0 / 576000);
#else
static double fake_timer = 0;
return fake_timer++;
#endif
}
/* this PLATFORM_Sleep() supports times only up to 0.11 sec,
which is enough for Atari800 purposes */
/* void PLATFORM_Sleep(double s)
{
#ifdef USE_TIMERS
unsigned long count = 65536 - (unsigned long) (s * 576000);
// do nothing if s is less than one T1 tick
if (count >= 65536)
return;
sleeping_thread_id = GetThreadId();
T1_COUNT = count;
T1_MODE = 0x002 // 576000 Hz clock
+ 0x080 // start counting
+ 0x200; // generate interrupt on overflow
// SleepThread();
#endif
}
*/
//volatile int locked = 1;
//void wakeup(s32 id, u16 time, void *arg)
//{
// locked = 0;
//}
//
//void PLATFORM_Sleep(double s)
//{
//
// /* 15734 is around 1 second on NTSC */
// /* is about 1ms? */
// SetAlarm(15734 * s, wakeup, 0);
// while (locked);
// locked = 1;
//}
void PLATFORM_Sleep(double s)
{
if (UI_is_active){
int i,ret;
for (i=0;i<s * 100.0;i++){
ee_sema_t sema;
sema.attr = 0;
sema.count = 0;
sema.init_count = 0;
sema.max_count = 1;
ret = CreateSema(&sema);
if (ret <= 0) {
//could not create sema, strange! continue anyway.
return;
}
iSignalSema(ret);
WaitSema(ret);
DeleteSema(ret);
}
}
}
void loadModules(void)
{
int ret;
//init_scr();
ret = SifLoadModule("rom0:SIO2MAN", 0, NULL);
if (ret < 0) {
Log_print("Sio2man loading failed: %d", ret);
SleepThread();
}
// Log_print("mcman");
SifLoadModule("rom0:MCMAN", 0, NULL);
// Log_print("mcserv");
SifLoadModule("rom0:MCSERV", 0, NULL);
// Log_print("padman");
ret = SifLoadModule("rom0:PADMAN", 0, NULL);
if (ret < 0) {
Log_print("Padman loading failed: %d", ret);
SleepThread();
}
mcInit(MC_TYPE_MC);
// cdinit(1);
SifInitRpc(0);
SifExecModuleBuffer(usbd, size_usbd, 0, NULL, &ret);
SifExecModuleBuffer(ps2kbd, size_ps2kbd, 0, NULL, &ret);
if (PS2KbdInit() == 0) {
Log_print("Failed to Init Keyboard.");
}
PS2KbdSetReadmode(PS2KBD_READMODE_RAW);
#ifdef SOUND
ret = SifLoadModule("rom0:LIBSD", 0, NULL);
ret = SifExecModuleBuffer(audsrv, size_audsrv, 0, NULL, &ret);
#endif
}
int PLATFORM_Initialise(int *argc, char *argv[])
{
// Swap Red and Blue components
int i;
for (i = 0; i < 256; i++) {
int c = Colours_table[i];
// clut[i] = (c >> 16) + (c & 0xff00) + ((c & 0xff) << 16);
// swap bits 3 and 4 to workaround a bug in gsKit
clut[(i ^ i * 2) & 16 ? i ^ 24 : i] = (c >> 16) + (c & 0xff00) + ((c & 0xff) << 16);
}
// Clear debug from screen
init_scr();
// Initialize graphics
gsGlobal = gsKit_init_global(GS_MODE_NTSC);
dmaKit_init(D_CTRL_RELE_ON, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC,
D_CTRL_STD_OFF, D_CTRL_RCYC_8);
dmaKit_chan_init(DMA_CHANNEL_GIF);
gsGlobal->PSM = GS_PSM_CT32;
gsGlobal->Test->ZTE = 0;
gsKit_init_screen(gsGlobal);
// Init joypad
padInit(0);
padPortOpen(PAD_PORT, PAD_SLOT, padBuf);
#ifdef USE_TIMERS
timer_initialize();
#endif
#ifdef SOUND
if (!Sound_Initialise(argc, argv))
return FALSE;
#endif
return TRUE;
}
int PLATFORM_Exit(int run_monitor)
{
// TODO: shutdown graphics mode
Log_flushlog();
#if 0
if (run_monitor && MONITOR_Run()) {
// TODO: reinitialize graphics mode
return TRUE;
}
#endif
#ifdef USE_TIMERS
timer_shutdown();
#endif
/* TODO Sound_Exit should not be called here! It only stays here now because
the next step restarts the PS2 without ever returning from this function to
Atari800_Exit, so the call to Sound_Exit located in the latter function is
never invoked. So, should the LoadExecPS2call below get removed, so should
this call to Sound_Exit. */
#ifdef SOUND
Sound_Exit();
#endif
//zzz temp exit procedure
//Hard coded to go back to ulaunch
fioExit();
SifExitRpc();
LoadExecPS2("mc0:/BOOT/BOOT.ELF", 0, NULL);
//zzz end
return FALSE;
}
void PLATFORM_DisplayScreen(void)
{
GSTEXTURE tex;
tex.Width = Screen_WIDTH;
tex.Height = Screen_HEIGHT;
tex.PSM = GS_PSM_T8;
tex.Mem = (UBYTE *) Screen_atari;
tex.Clut = clut;
tex.Vram = 0x200000;
tex.VramClut = 0x280000;
tex.Filter = GS_FILTER_LINEAR;
// TODO: upload clut just once
gsKit_texture_upload(gsGlobal, &tex);
gsKit_prim_sprite_texture(gsGlobal, &tex, 0, 0, 32, 0, 640, 480, 32 + 320, 240, 0, 0x80808080);
#if 0
gsKit_sync_flip(gsGlobal);
#else
// flip without vsync
// this is a copy of gsKit_sync_flip() code with just gsKit_vsync() call removed
GS_SET_DISPFB2(gsGlobal->ScreenBuffer[gsGlobal->ActiveBuffer & 1] / 8192,
gsGlobal->Width / 64, gsGlobal->PSM, 0, 0 );
gsGlobal->ActiveBuffer ^= 1;
gsGlobal->PrimContext ^= 1;
gsGlobal->EvenOrOdd = ((GSREG *) GS_CSR)->FIELD;
gsKit_setactive(gsGlobal);
#endif
}
static int PadButtons(void)
{
struct padButtonStatus buttons;
for (;;) {
int ret = padGetState(PAD_PORT, PAD_SLOT);
if (ret == PAD_STATE_STABLE || ret == PAD_STATE_FINDCTP1)
break;
if (ret == PAD_STATE_DISCONN)
return 0;
}
padRead(PAD_PORT, PAD_SLOT, &buttons);
return ~buttons.btns;
}
int PLATFORM_Keyboard(void)
{
int new_pad = PadButtons();
PS2KbdRawKey key;
INPUT_key_consol = INPUT_CONSOL_NONE;
if (UI_is_active) {
if (new_pad & PAD_CROSS)
return AKEY_RETURN;
if (new_pad & PAD_CIRCLE)
return AKEY_ESCAPE;
if (new_pad & PAD_LEFT)
return AKEY_LEFT;
if (new_pad & PAD_RIGHT)
return AKEY_RIGHT;
if (new_pad & PAD_UP)
return AKEY_UP;
if (new_pad & PAD_DOWN)
return AKEY_DOWN;
if (new_pad & PAD_L1)
return AKEY_COLDSTART;
if (new_pad & PAD_R1)
return AKEY_WARMSTART;
}
//PAD_CROSS is used for PLATFORM_TRIG().
if (new_pad & PAD_TRIANGLE)
return AKEY_UI;
if (new_pad & PAD_SQUARE)
return AKEY_SPACE;
if (new_pad & PAD_CIRCLE)
return AKEY_RETURN;
if (new_pad & PAD_L1)
return AKEY_COLDSTART;
if (new_pad & PAD_R1)
return AKEY_WARMSTART;
if (Atari800_machine_type == Atari800_MACHINE_5200) {
if (new_pad & PAD_START)
return AKEY_5200_START;
}
else {
if (new_pad & PAD_START)
INPUT_key_consol ^= INPUT_CONSOL_START;
if (new_pad & PAD_SELECT)
INPUT_key_consol ^= INPUT_CONSOL_SELECT;
if (new_pad & PAD_CROSS)
return AKEY_HELP;
}
if (Atari800_machine_type != Atari800_MACHINE_5200 || UI_is_active) {
while (PS2KbdReadRaw(&key) != 0) {
if (key.state == PS2KBD_RAWKEY_DOWN) {
switch (key.key) {
case EOF:
Atari800_Exit(FALSE);
exit(0);
break;
case 0x28:
return AKEY_RETURN;
case 0x29:
return AKEY_ESCAPE;
case 0x2A:
return AKEY_BACKSPACE;
case 0x2B:
return AKEY_TAB;
case 0x2C:
return AKEY_SPACE;
case 0x46://Print Screen Button
return AKEY_SCREENSHOT;
case 0x4F:
return AKEY_RIGHT;
case 0x50:
return AKEY_LEFT;
case 0x51:
return AKEY_DOWN;
case 0x52:
return AKEY_UP;
case 0x58:
return AKEY_RETURN;
case 0xE0:
PS2KbdCONTROL = 1;
return AKEY_NONE;
case 0xE4:
PS2KbdCONTROL = 1;
return AKEY_NONE;
case 0xE1:
PS2KbdSHIFT = 1;
return AKEY_NONE;
case 0xE2:
PS2KbdALT = 1;
return AKEY_NONE;
case 0xE5:
PS2KbdSHIFT = 1;
return AKEY_NONE;
case 0xE6:
PS2KbdALT = 1;
return AKEY_NONE;
default:
break;
}
}
if ((key.state == PS2KBD_RAWKEY_DOWN) && !PS2KbdSHIFT && !PS2KbdALT) {
switch (key.key) {
case 0x1E:
return AKEY_1;
case 0X1F:
return AKEY_2;
case 0x20:
return AKEY_3;
case 0x21:
return AKEY_4;
case 0x22:
return AKEY_5;
case 0x23:
return AKEY_6;
case 0x24:
return AKEY_7;
case 0x25:
return AKEY_8;
case 0x26:
return AKEY_9;
case 0x27:
return AKEY_0;
case 0x2D:
return AKEY_MINUS;
case 0x2E:
return AKEY_EQUAL;
case 0x2F:
return AKEY_BRACKETLEFT;
case 0x30:
return AKEY_BRACKETRIGHT;
case 0x31:
return AKEY_BACKSLASH;
case 0x33:
return AKEY_SEMICOLON;
case 0x34:
return AKEY_QUOTE;
case 0x35:
return AKEY_ATARI;
case 0x36:
return AKEY_COMMA;
case 0x37:
return AKEY_FULLSTOP;
case 0x38:
return AKEY_SLASH;
case 0x3A://F1
return AKEY_UI;
case 0x3E://F5
return AKEY_WARMSTART;
case 0x42://F9
return AKEY_EXIT;
case 0x43://F10
return AKEY_SCREENSHOT;
default:
break;
}
}
if ((key.state == PS2KBD_RAWKEY_DOWN) && PS2KbdSHIFT && !PS2KbdCONTROL && !PS2KbdALT) {
switch (key.key) {
case 0x4:
return AKEY_A;
case 0x5:
return AKEY_B;
case 0x6:
return AKEY_C;
case 0x7:
return AKEY_D;
case 0x8:
return AKEY_E;
case 0x9:
return AKEY_F;
case 0xA:
return AKEY_G;
case 0xB:
return AKEY_H;
case 0xC:
return AKEY_I;
case 0xD:
return AKEY_J;
case 0xE:
return AKEY_K;
case 0xF:
return AKEY_L;
case 0x10:
return AKEY_M;
case 0x11:
return AKEY_N;
case 0x12:
return AKEY_O;
case 0x13:
return AKEY_P;
case 0x14:
return AKEY_Q;
case 0x15:
return AKEY_R;
case 0x16:
return AKEY_S;
case 0x17:
return AKEY_T;
case 0x18:
return AKEY_U;
case 0x19:
return AKEY_V;
case 0x1A:
return AKEY_W;
case 0x1B:
return AKEY_X;
case 0x1C:
return AKEY_Y;
case 0x1D:
return AKEY_Z;
case 0x1E:
return AKEY_EXCLAMATION;
case 0X1F:
return AKEY_AT;
case 0x20:
return AKEY_HASH;
case 0x21:
return AKEY_DOLLAR;
case 0x22:
return AKEY_PERCENT;
case 0x23:
// return AKEY_CIRCUMFLEX;
return AKEY_CARET;
case 0x24:
return AKEY_AMPERSAND;
case 0x25:
return AKEY_ASTERISK;
case 0x26:
return AKEY_PARENLEFT;
case 0x27:
return AKEY_PARENRIGHT;
case 0x2B:
return AKEY_SETTAB;
case 0x2D:
return AKEY_UNDERSCORE;
case 0x2E:
return AKEY_PLUS;
case 0x31:
return AKEY_BAR;
case 0x33:
return AKEY_COLON;
case 0x34:
return AKEY_DBLQUOTE;
case 0x36:
return AKEY_LESS;
case 0x37:
return AKEY_GREATER;
case 0x38:
return AKEY_QUESTION;
case 0x3E://Shift+F5
return AKEY_COLDSTART;
case 0x43://Shift+F10
return AKEY_SCREENSHOT_INTERLACE;
case 0x49://Shift+Insert key
return AKEY_INSERT_LINE;
case 0x4C://Shift+Backspace Key
return AKEY_DELETE_LINE;
default:
break;
}
}
if ((key.state == PS2KBD_RAWKEY_DOWN) && !PS2KbdSHIFT && !PS2KbdCONTROL && !PS2KbdALT) {
switch (key.key) {
case 0x4:
return AKEY_a;
case 0x5:
return AKEY_b;
case 0x6:
return AKEY_c;
case 0x7:
return AKEY_d;
case 0x8:
return AKEY_e;
case 0x9:
return AKEY_f;
case 0xA:
return AKEY_g;
case 0xB:
return AKEY_h;
case 0xC:
return AKEY_i;
case 0xD:
return AKEY_j;
case 0xE:
return AKEY_k;
case 0xF:
return AKEY_l;
case 0x10:
return AKEY_m;
case 0x11:
return AKEY_n;
case 0x12:
return AKEY_o;
case 0x13:
return AKEY_p;
case 0x14:
return AKEY_q;
case 0x15:
return AKEY_r;
case 0x16:
return AKEY_s;
case 0x17:
return AKEY_t;
case 0x18:
return AKEY_u;
case 0x19:
return AKEY_v;
case 0x1A:
return AKEY_w;
case 0x1B:
return AKEY_x;
case 0x1C:
return AKEY_y;
case 0x1D:
return AKEY_z;
case 0x49:
return AKEY_INSERT_CHAR;
case 0x4C:
return AKEY_DELETE_CHAR;
default:
break;
}
}
if ((key.state == PS2KBD_RAWKEY_DOWN) && PS2KbdCONTROL && !PS2KbdALT) {
switch(key.key) {
case 0x4:
return AKEY_CTRL_a;
case 0x5:
return AKEY_CTRL_b;
case 0x6:
return AKEY_CTRL_c;
case 0x7:
return AKEY_CTRL_d;
case 0x8:
return AKEY_CTRL_e;
case 0x9:
return AKEY_CTRL_f;
case 0xA:
return AKEY_CTRL_g;
case 0xB:
return AKEY_CTRL_h;
case 0xC:
return AKEY_CTRL_i;
case 0xD:
return AKEY_CTRL_j;
case 0xE:
return AKEY_CTRL_k;
case 0xF:
return AKEY_CTRL_l;
case 0x10:
return AKEY_CTRL_m;
case 0x11:
return AKEY_CTRL_n;
case 0x12:
return AKEY_CTRL_o;
case 0x13:
return AKEY_CTRL_p;
case 0x14:
return AKEY_CTRL_q;
case 0x15:
return AKEY_CTRL_r;
case 0x16:
return AKEY_CTRL_s;
case 0x17:
return AKEY_CTRL_t;
case 0x18:
return AKEY_CTRL_u;
case 0x19:
return AKEY_CTRL_v;
case 0x1A:
return AKEY_CTRL_w;
case 0x1B:
return AKEY_CTRL_x;
case 0x1C:
return AKEY_CTRL_y;
case 0x1D:
return AKEY_CTRL_z;
case 0x1E:
return AKEY_CTRL_1;
case 0x1F:
return AKEY_CTRL_2;
case 0x20:
return AKEY_CTRL_3;
case 0x21:
return AKEY_CTRL_4;
case 0x22:
return AKEY_CTRL_5;
case 0x23:
return AKEY_CTRL_6;
case 0x24:
return AKEY_CTRL_7;
case 0x25:
return AKEY_CTRL_8;
case 0x26:
return AKEY_CTRL_9;
case 0x27:
return AKEY_CTRL_0;
case 0x2B:
return AKEY_CLRTAB;
case 0x33:
return AKEY_SEMICOLON | AKEY_CTRL;
case 0x36:
return AKEY_LESS | AKEY_CTRL;
case 0x37:
return AKEY_GREATER | AKEY_CTRL;
default:
break;
}
}
if ((key.state == PS2KBD_RAWKEY_DOWN) && PS2KbdALT) {
switch(key.key) {
//case dcr ylsa
case 0x7:
UI_alt_function = UI_MENU_DISK;
return AKEY_UI;
case 0x6:
UI_alt_function = UI_MENU_CARTRIDGE;
return AKEY_UI;
case 0x15:
UI_alt_function = UI_MENU_RUN;
return AKEY_UI;
case 0x1C:
UI_alt_function = UI_MENU_SYSTEM;
return AKEY_UI;
case 0xF:
UI_alt_function = UI_MENU_LOADSTATE;
return AKEY_UI;
case 0x16:
UI_alt_function = UI_MENU_SAVESTATE;
return AKEY_UI;
case 0x17:
UI_alt_function = UI_MENU_CASSETTE;
return AKEY_UI;
case 0x4:
UI_alt_function = UI_MENU_ABOUT;
return AKEY_UI;
default:
break;
}
}
if (key.state == PS2KBD_RAWKEY_UP) {
switch (key.key) {
case 0x39:
return AKEY_CAPSTOGGLE;
case 0xE0:
PS2KbdCONTROL = 0;
return AKEY_NONE;
case 0xE4:
PS2KbdCONTROL = 0;
return AKEY_NONE;
case 0xE1:
PS2KbdSHIFT = 0;
return AKEY_NONE;
case 0xE2:
PS2KbdALT = 0;
return AKEY_NONE;
case 0xE5:
PS2KbdSHIFT = 0;
return AKEY_NONE;
case 0xE6:
PS2KbdALT = 0;
return AKEY_NONE;
default:
break;
}
}
}
}
return AKEY_NONE;
}
int PLATFORM_PORT(int num)
{
int ret = 0xff;
if (num == 0) {
int pad = PadButtons();
if (pad & PAD_LEFT)
ret &= 0xf0 | INPUT_STICK_LEFT;
if (pad & PAD_RIGHT)
ret &= 0xf0 | INPUT_STICK_RIGHT;
if (pad & PAD_UP)
ret &= 0xf0 | INPUT_STICK_FORWARD;
if (pad & PAD_DOWN)
ret &= 0xf0 | INPUT_STICK_BACK;
}
return ret;
}
int PLATFORM_TRIG(int num)
{
if (num == 0 && PadButtons() & PAD_CROSS)
return 0;
return 1;
}
char dir_path[FILENAME_MAX];
static int dir_n;
static int dir_i;
// XXX: use followup calls to get directory entries one-by-one?
#define MAX_FILES_PER_DIR 1000
static mcTable mcDir[MAX_FILES_PER_DIR];
int Atari_OpenDir(const char *filename)
{
// TODO: support other devices
if (strncmp(filename, "mc0:/", 5) != 0)
return FALSE;
dir_n = mcGetDir(0, 0, filename + 4, 0 /* followup flag */, MAX_FILES_PER_DIR, mcDir);
mcSync(0,NULL,&dir_n);
if (dir_n < 0)
return FALSE;
dir_i = 0;
// XXX: does it know (and needs to know) that "mc0:/" is a root directory?
Util_splitpath(filename, dir_path, NULL);
return TRUE;
}
int Atari_ReadDir(char *fullpath, char *filename, int *isdir,
int *readonly, int *size, char *timetext)
{
const mcTable *p;
if (dir_i >= dir_n)
return FALSE;
p = mcDir + dir_i;
if (fullpath != NULL)
Util_catpath(fullpath, dir_path, p->name);
if (filename != NULL)
strcpy(filename, p->name);
if (isdir != NULL)
*isdir = (p->attrFile & MC_ATTR_SUBDIR) ? TRUE : FALSE;
if (readonly != NULL)
*readonly = (p->attrFile & MC_ATTR_WRITEABLE) ? FALSE : TRUE; // XXX: MC_ATTR_PROTECTED ?
if (size != NULL)
*size = (int) (p->fileSizeByte);
if (timetext != NULL) {
// FIXME: adjust from GMT to local time
int hour = p->_modify.hour;
char ampm = 'a';
if (hour >= 12) {
hour -= 12;
ampm = 'p';
}
if (hour == 0)
hour = 12;
sprintf(timetext, "%2d-%02d-%02d %2d:%02d%c",
p->_modify.month, p->_modify.day, p->_modify.year % 100, hour, p->_modify.sec, ampm);
}
dir_i++;
return TRUE;
}
#ifdef SOUND
int Sound_Initialise(int *argc, char *argv[])
{
if (audsrv_init() != 0)
Log_print("failed to initialize audsrv: %s", audsrv_get_error_string());
else {
struct audsrv_fmt_t format;
format.bits = 8;
format.freq = 44100;
format.channels = 1;
audsrv_set_format(&format);
audsrv_set_volume(MAX_VOLUME);
POKEYSND_Init(POKEYSND_FREQ_17_EXACT, 44100, 1, 0);
}
return TRUE;
}
void Sound_Exit(void)
{
audsrv_quit();
}
void Sound_Update(void)
{
static char buffer[44100 / 50];
unsigned int nsamples = (Atari800_tv_mode == Atari800_TV_NTSC) ? (44100 / 60) : (44100 / 50);
POKEYSND_Process(buffer, nsamples);
audsrv_wait_audio(nsamples);
audsrv_play_audio(buffer, nsamples);
}
void Sound_Pause(void)
{
audsrv_stop_audio();
}
void Sound_Continue(void)
{
if (audsrv_init() != 0)
Log_print("failed to initialize audsrv: %s", audsrv_get_error_string());
else {
struct audsrv_fmt_t format;
format.bits = 8;
format.freq = 44100;
format.channels = 1;
audsrv_set_format(&format);
audsrv_set_volume(MAX_VOLUME);
}
}
#endif /* SOUND */
int main(int argc, char **argv)
{
loadModules();
/* initialise Atari800 core */
if (!Atari800_Initialise(&argc, argv))
return 3;
/* main loop */
for (;;) {
INPUT_key_code = PLATFORM_Keyboard();
Atari800_Frame();
if (Atari800_display_screen){
PLATFORM_DisplayScreen();}
}
}