#ifndef _LCE_H
#define _LCE_H

#include "types.h"

#if !defined(_GBA) && !defined(_SC)
#pragma pack(push, 4)
#endif

// Emulation modes
//
#define  LCE_NORMAL_MODE        0   // normal mode
#define  LCE_TS_SYNC_MODE       1   // time-shifted sync comm.
#define  LCE_TS_ASYNC_MODE      2   // time-shifted async comm.
#define  LCE_TS_STREAM_MODE     3   // time-shifted data stream

#define LCE_OPTS_FILE "/tmp/lce_opts"
#define LCE_DEBUG_FILE "/lce_debug"

typedef struct {
    u32 delay;
} lce_opts;

typedef struct {
    /* GBA write space */
    vu32 reg_ie_if;
    vu32 timer_counter;
    vu32 timer_counter_limit;
    vu32 frame_intr_skipped;
    vu32 timer_intr_skipped;
    vu32 vcount_intr_skipped;
    vu32 siocnt;
    vu32 siomulti_send;
    vu32 main_loop_done;
    vu32 game_mode;
    vu32 tmp;
    vu32 tmp2;
    /* NC write space */
    vu32 emulated_intr;
    vu32 frame_counter;
    vu32 frame_counter_limit;
    vu32 mode;
    vu32 delay;
    vu32 siomulti0;
    vu32 siomulti1;
    vu32 siomulti2;
    vu32 siomulti3;
    vu32 enable;
    vu32 linkid;
    vu32 pad;
} lce_type;

// Return pointer to LCE shared buffer
lce_type* getLCEDataArea();

// Initialize LCE library
//   LCE_Init should be called by viewer before launching 
//   multiplayer game.
//   The LCE is initialized to LCE_NORMAL_MODE by default.
//
void LCE_Init();

// Specify dummy data to initialize delay queue.
//   buf: Pointer to 1 frame of dummy data.
//
void LCE_SetDummyData(unsigned short int* buf[4][2]);

// Set length of delay queue in frames for TS mode.
//   ignored in RT mode
//
void LCE_SetDelay(int delay);

// Specify number of 16-bit transfers per frame.  This must
// be exact.
//   size: # of transfers between VBLANKS.
void LCE_SetFrameLen(int size);

// Enable/disable use of LCE
//   Enable when player selects link play from game menu.
//   Disable when player exits multiplayer mode.
//   This is needed to stop frame syncing when link is no longer needed.
//
void LCE_Enable();
void LCE_Disable();

// Switch LCE emulation mode
//   can only be called by master.
//
//   mode:  LCE_NORMAL_MODE or LCE_TS_MODE
//
void LCE_SwitchMode(int mode);


// Trigger data exchange among players.  Updates Shadow registers before
// exchange, updates SIO registers after.
//  - invoked by master when SIOCNT SIO_START is enabled
//  - invoked by slave on receive of emulated SIO Interrupt
//
void LCE_Trigger();


// Ask LCE to schedule a sequence of SIO interrupts to deliver
// the data for the current frame
//   - usually called at VBLANK intr
//
void LCE_SchedSIOIntr();

// Notify LCE of VBLANK interrupt
void LCE_Vblank();


#if !defined(_GBA) && !defined(_SC)
#pragma pack(pop)
#endif

#endif /* _LCE_H */

