limited.c 7.55 KB
#include "ultra64.h"
#include "os_bb.h"
#include "bcp.h"
#include "bbskapi.h"

#include "libfb.h"
#include "limited.h"


//#define VIDEO_PRINT
#define DMA_QUEUE_SIZE	200
#ifdef VIDEO_PRINT
static int ypos = 2, xpos = 2;
#define PRINTF(args...)		fbPrintf(fbWhite, xpos, ypos++, args);osWritebackDCacheAll()
#else
#define PRINTF			osSyncPrintf
#endif

/*
 * Thread and stack structures
 */
char   bootStack[STACKSIZE] __attribute__ ((aligned (8)));

static OSThread idleThread;
static char     idleThreadStack[STACKSIZE] __attribute__ ((aligned (8)));

static OSThread mainThread;
static char     mainThreadStack[STACKSIZE] __attribute__ ((aligned (8)));


/*
 * Message queues and message buffers used by this app 
 */
static OSMesg           PiMessages[DMA_QUEUE_SIZE], dmaMessageBuf;
static OSMesgQueue      PiMessageQ, dmaMessageQ;

static OSMesg           SiMessages[DMA_QUEUE_SIZE];
static OSMesgQueue      SiMessageQ, contMessageQ;

/*
 * Local variables and routines
 */

static void		idleproc(char *);
static void		mainproc(char *);

void
boot(void)
{
    osInitialize();
    osCreateThread(&idleThread, 1, (void(*)(void *))idleproc, (void *)0,
                   idleThreadStack+STACKSIZE, 8);
    osStartThread(&idleThread);
}


//#define SCREEN_LOW
#ifdef SCREEN_LOW
static u16 cfb[2][320*240] __attribute__((aligned(64)));
#else
static u16 cfb[2][640*480] __attribute__((aligned(64)));
#endif

static void
idleproc(char *argv)		/* priority 8 */
{
    osCreateViManager(OS_PRIORITY_VIMGR);
#ifdef SCREEN_LOW
    fbInit(FB_LOW_RES);
#else
    fbInit(FB_HIGH_RES);
#endif

    /*
     * Start PI Mgr for access to cartridge - start before the debugger
     */
    osCreatePiManager((OSPri) OS_PRIORITY_PIMGR, &PiMessageQ, PiMessages,
            DMA_QUEUE_SIZE);

    osCreateMesgQueue(&dmaMessageQ, &dmaMessageBuf, 1);
    osCreateMesgQueue(&SiMessageQ, SiMessages, DMA_QUEUE_SIZE);
    osSetEventMesg(OS_EVENT_SI, &SiMessageQ, (OSMesg)DMA_QUEUE_SIZE);

    /*
     * The main thread's priority must be the same or lower than the original
     * idle's thread priority. This allows the idle thread to change its
     * priority to 0 before the main thread starts execution.
     */
    osCreateThread(&mainThread, 3, (void(*)(void *))mainproc, argv,
           mainThreadStack+STACKSIZE/8, (OSPri)7);
    osStartThread(&mainThread);

    osSetThreadPri(0, OS_PRIORITY_IDLE);
    for(;;);                                    /* idle thread */
}

static OSMesgQueue	retraceMessageQ;
static OSMesg		dummyMessage, retraceMessageBuf;

OSContStatus statusData[MAXCONTROLLERS];
OSContPad controllerData[MAXCONTROLLERS];
static u16 lastbutton[MAXCONTROLLERS];

static int no_controller = 1;
static void
initController(void)
{
    int i;
    u8 pattern;

    osCreateMesgQueue(&contMessageQ, &dummyMessage, 1);
    osSetEventMesg(OS_EVENT_SI, &contMessageQ, (OSMesg) 0);

    osContInit(&contMessageQ, &pattern, &statusData[0]);

    for (i = 0; i < MAXCONTROLLERS; i++) {
        if ((pattern & (1 << i)) &&
            !(statusData[i].errno & CONT_NO_RESPONSE_ERROR)) {
            no_controller = 0;
        }
    }
}


int window_reset = 0;

static void
processButton(u16 button, int lastbutton)
{
    if (button & D_JPAD && !(lastbutton & D_JPAD)) {
    }

    if (button & U_JPAD && !(lastbutton & U_JPAD)) {
    }

    if (button & R_JPAD && !(lastbutton & R_JPAD)) {
    }

    if (button & L_JPAD && !(lastbutton & L_JPAD)) {
    }

    if (button & R_TRIG && !(lastbutton & R_TRIG)) {
	if (skAdvanceTicketWindow() < 0)
	    osSyncPrintf("skAdvancedTicketWindow failed\n");
	window_reset = 0;
	fbClear();
    }

    if (button & B_BUTTON && !(lastbutton & B_BUTTON)) {
    }

    if (button & A_BUTTON && !(lastbutton & A_BUTTON)) {
    }

    if (button & START_BUTTON && !(lastbutton & START_BUTTON)) {
	skExit();
    }

    if ((button & Z_TRIG) && !(lastbutton & Z_TRIG)) {
	if (!window_reset) {
	    skResetWindow();
	    window_reset = 1;
	    fbClear();
	}
    }
}

static void
readControllers(void)
{
    int i;
    OSContPad *pad;

    osRecvMesg(&contMessageQ, &dummyMessage, OS_MESG_BLOCK); 
    osContGetReadData(controllerData);

    for (i = 0; i < MAXCONTROLLERS; ++i) {
        pad = &controllerData[i];
        if (pad->button) {
            processButton(pad->button, lastbutton[i]);
        }
        lastbutton[i] = pad->button;
    }
}

#define fbhBlue		GPACK_RGBA5551(0,0,80,1)
#define fbhGreen	GPACK_RGBA5551(0,80,0,1)
#define fbhRed		GPACK_RGBA5551(80,0,0,1)
#define fbhYellow	GPACK_RGBA5551(80,80,0,1)
#define fbhMagenta	GPACK_RGBA5551(80,0,80,1)
#define fbhCyan		GPACK_RGBA5551(0,80,80,1)

#define fbLemonChiffon		GPACK_RGBA5551(255,250,205,1)
#define fbLightSlateBlue	GPACK_RGBA5551(132,112,255,1)
#define fbLightPink1		GPACK_RGBA5551(255,174,185,1)
#define fbThistle2		GPACK_RGBA5551(238,210,238,1)
#define fbSeaGreen4		GPACK_RGBA5551(105,139,105,1)
#define fbTomato1		GPACK_RGBA5551(255,99,71,1)
#define fbTurquoise2		GPACK_RGBA5551(0,229,238,1)
#define fbSienna4		GPACK_RGBA5551(139,71,38,1)

#if 0
#define skResetWindow()
#define skGetId(x)
#define skGetConsumption(x,y)
#endif

void
testproc(void) {
    int i;
    u16 window, cc[BB_MAX_CC];
    BbId id;
    skGetId(&id);
    PRINTF("bbid %x\n", id);
    window = 0x55aa;
    for(i = 0; i < BB_MAX_CC; i++)
	cc[i] = 0xaa55;
    skGetConsumption(&window, cc);
    for(i = 0; i < BB_MAX_CC/2; i++) {
	PRINTF("  %4d %4d     %4d %4d\n", window+i, cc[i], window+BB_MAX_CC/2+i, cc[BB_MAX_CC/2+i]);
    }
    if (window_reset)
	PRINTF("window reset\n");
}

static void fill_cc(u16* window, u16 cc[BB_MAX_CC]) {
    int i;
    *window = 0xbabe;
    for(i = 0; i < BB_MAX_CC; i++) {
	cc[i] = 0xff|+i;
    }
}

static void 
mainproc(char *argv)		{
    int which, i;
    u16 window, cc[BB_MAX_CC];
    osCreateMesgQueue(&retraceMessageQ, &retraceMessageBuf, 1);
    osViSetEvent(&retraceMessageQ, dummyMessage, 1);
    osViBlack(1);
    osViSwapBuffer(cfb);
    initController();
    fbSetBg(fbBlack);
    fbClear();
    osViBlack(0);
    osWritebackDCacheAll();
    osViSwapBuffer(cfb[which = 1]);
    fbClear();

#define TEST
#ifdef TEST
    if (skGetConsumption((void*)100, cc) >= 0) 
	PRINTF("ERROR: skGetConsumption pointer check failed (window)\n");
    if (skGetConsumption((void*)K0BASE+0x800000-1, cc) >= 0) 
	PRINTF("ERROR: skGetConsumption pointer check failed (window)\n");
    if (skGetConsumption(&window, (void*)100) >= 0) 
	PRINTF("ERROR: skGetConsumption pointer check failed (cc)\n");
    if (skGetConsumption(&window, (void*)K0BASE+0x800000-2) >= 0) 
	PRINTF("ERROR: skGetConsumption pointer check failed (cc)\n");
    skResetWindow();
    fill_cc(&window, cc);
    skGetConsumption(&window, cc);
    if (window != 0)
	PRINTF("ERROR: window not reset 0x%x\n", window);
    for(i = 0; i < BB_MAX_CC; i++) {
	if (cc[i] != 0)
	    PRINTF("ERROR: cc[%d] not reset 0x%x\n", i, cc[i]);
    }

    for(i = 0; i < 10; i++) {
	skAdvanceTicketWindow();
    }
    fill_cc(&window, cc);
    skGetConsumption(&window, cc);
    if (window != 10)
	PRINTF("ERROR: window not advanced 0x%x\n", window);
    for(i = 0; i < BB_MAX_CC; i++) {
	if (cc[i] != 0)
	    PRINTF("ERROR: cc[%d] changed 0x%x\n", i, cc[i]);
    }
    /* since ticket is still in place after launch, SetLimit will succeed */
    if (skSetLimit(0, 0) < 0) {
	PRINTF("ERROR: SetLimit failed\n");
    }
    testproc();
    /* power off */
    IO_WRITE(PI_GPIO_REG, 0|(1 << PI_GPIO_ENABLE_SHIFT));
    skExit();
#endif
    for(;;) {
        osRecvMesg(&retraceMessageQ, NULL, OS_MESG_BLOCK);
        osContStartReadData(&contMessageQ);
#ifdef VIDEO_PRINT
	ypos = 2;
#endif
        readControllers();
	testproc();
	osWritebackDCacheAll();
	osViSwapBuffer(cfb[which]);
	which ^= 1;
    }
}