User Tools

Site Tools


project:gba:code

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

project:gba:code [2007/04/27 00:21] (current)
Line 1: Line 1:
 +====== Code ======
 +The project is complete, all code was tidied and presented in the project report (available on the [[:​project]] page), and instructions on its use was added along with pre-compiled versions and //all// libraries necessary to do compilation. Note that if you are only interested in using the GBA serial port, you might do better to look at my [[:​project:​gba]] page, which includes pre-compiled versions of ''​CommsProbe''​ and ''​RS232 Terminal''​ programs, along with their relevant instructions.
  
 +===== Random snippets of code =====
 +
 +==== BitTest ====
 +
 +<code cpp>
 +// BitTest - initialize two variables and output the
 +// results of applying the ~, &, | and ^
 +// operations
 +
 +#include <​iostream.h>​
 +
 +char* toBinary(int n){
 + static char sResult[(sizeof(n)*8)];​ //​ static so the return doesn'​t point to a local var
 +
 + // Use bit-wise AND to check if the LSB of n is set, and place into
 + // our string accordingly (filling right->​left due to numerical significance)
 + for(int i=sizeof(sResult);​ i>=0; i--){
 + sResult[i] = (n & 1) ? '​1'​ : '​0'​ ;
 + n >>= 1;
 + }
 +
 + return sResult; // Return a pointer
 +}
 +
 +int main(int nArg, char* pszArgs[]){
 +
 + //​initialize two arguments
 + int nArg1 = 0x0f0f;
 + int nArg2 = 0xf0f0;
 +
 + //now perform each operation in turn
 + //first the unary NOT operator
 + cout << "​nArg1 = b" << toBinary(nArg1) << endl;
 + cout << "​nArg2 = b" << toBinary(nArg2) << endl;
 + cout << "​~nArg1 = b" << toBinary(~nArg1) << endl;
 + cout << "​~nArg2 = b" << toBinary(~nArg2) << endl;
 +
 + //now the binary operators
 + cout << "nArg1 & nArg2 = b" << toBinary(nArg1 & nArg2) << endl;
 + cout << "nArg1 | nArg2 = b" << toBinary(nArg1 | nArg2) << endl;
 + cout << "nArg1 ^ nArg2 = b" << toBinary(nArg1 ^ nArg2) << endl;
 +}
 +
 +</​code>​
 +
 +==== CommsProbe ====
 +
 +<code cpp>
 +#define false 0
 +#define true 1
 +
 +#include <​mygba.h>​
 +#include "​general-purpose-comms.h"​
 +
 +short SC, SD, SI, SO, IO;
 +int data;
 +
 +MULTIBOOT
 +int main(void)
 +{
 +    ham_Init();
 +    ham_InitText(0);​
 +
 +    SC = SD = SI = SO = IO = 0;
 +    while(1)
 +    {
 +        if(F_CTRLINPUT_LEFT_PRESSED) SC=(SC+1)%2;​
 +        if(F_CTRLINPUT_RIGHT_PRESSED) SD=(SD+1)%2;​
 +        if(F_CTRLINPUT_B_PRESSED) SI=(SI+1)%2;​
 +        if(F_CTRLINPUT_A_PRESSED) SO=(SO+1)%2;​
 +        ​
 +        if(F_CTRLINPUT_L_PRESSED) IO=1;
 +        if(F_CTRLINPUT_R_PRESSED) IO=0;
 +
 +        set_comms(SC,​ SD, SI, SO, IO);
 +        ​
 +        int i=0;
 +        while(i<​250000)i++;​
 +    }
 +}
 +</​code>​
 +Where ''​mygba.h''​ is the [[http://​www.ngine.de|Ham]] library function and ''​general-purpose-comm.h''​ is as follows:
 +<code cpp>
 +#ifndef SIO_MULTIPLAYER_H
 +#define SIO_MULTIPLAYER_H 1
 +
 +//RCNT is used for mode selection
 +#define R_RCNT ​ *(volatile u16*) 0x4000134
 +
 +#include <​stdio.h>​
 +
 +/* GBAtek 1.4:
 +134h - RCNT (R) - SIO Mode, usage in GENERAL-PURPOSE Mode (R/W)
 +Interrupts can be requested when SI changes from HIGH to LOW, as General Purpose mode does
 +not require a serial shift clock, this interrupt may be produced even when the GBA is in
 +Stop (low power standby) state.
 +
 +  Bit   Expl.
 +  0     SC Data Bit         ​(0=Low,​ 1=High)
 +  1     SD Data Bit         ​(0=Low,​ 1=High)
 +  2     SI Data Bit         ​(0=Low,​ 1=High)
 +  3     SO Data Bit         ​(0=Low,​ 1=High)
 +  4     SC Direction ​       (0=Input, 1=Output)
 +  5     SD Direction ​       (0=Input, 1=Output)
 +  6     SI Direction ​       (0=Input, 1=Output, but see below)
 +  7     SO Direction ​       (0=Input, 1=Output)
 +  8     ​Interrupt Request ​  ​(0=Disable,​ 1=Enable)
 +  9-13  Not used
 +  14    Must be "​0"​ for General-Purpose Mode
 +  15    Must be "​1"​ for General-Purpose or JOYBUS Mode
 +
 +SI should be always used as Input to avoid problems with other hardware which does not
 +expect data to be output there.
 +*/
 +
 +// Accept a string input of 0 and 1 chars
 +void set_comms(short SC, short SD, short SI, short SO, short IO){
 +    u16 data;
 +    data = (1*SC) + (2*SD) + (4*SI) + (8*SO);
 +    data = data + (IO * 0xf0); ​ // Set all pins to IO (1=Out, 0=In)
 +    data = data + 0x8000; ​      // Set general purpose mode ('​10'​ MSB-LSB)
 +
 +    R_RCNT = data;
 +
 +    char st[100];
 +    sprintf(st,"​[%04x]",​R_RCNT);​
 +    ham_DrawText(1,​1,​ st);
 +
 +    if(IO) ham_DrawText(1,​2,​ "​Output"​);​ else ham_DrawText(1,​2,​ "Input ");
 +
 +    if(0x1 & R_RCNT) ham_DrawText(1,​11,"​SC"​);​ else ham_DrawText(1,​11,"​--"​);​
 +    if(0x2 & R_RCNT) ham_DrawText(5,​11,"​SD"​);​ else ham_DrawText(5,​11,"​--"​);​
 +    if(0x4 & R_RCNT) ham_DrawText(10,​11,"​SI"​);​ else ham_DrawText(10,​11,"​--"​);​
 +    if(0x8 & R_RCNT) ham_DrawText(15,​11,"​SO"​);​ else ham_DrawText(15,​11,"​--"​);​
 +}
 +
 +#endif
 +</​code>​
 +
 +
 +==== SuspendTest ====
 +NB, has occasional problems with interrupt-driven progress indicator at present, so it's been disabled.
 +
 +<code cpp>
 +#include "​mygba.h"​
 +
 +MULTIBOOT
 +
 +u32 count=0;
 +
 +void interrupt();​
 +char* toBinary(u8 n);
 +
 +int main(void)
 +{
 +    ham_Init();
 +    ham_InitText(0);​
 +    ham_InitPad();​
 +
 +
 +    // Setup the keypad interrupt register
 +    R_CTRLINT=
 +        256+    // Button R
 +        512+    // Button L
 +        4+      // Select
 +        16384+ ​ // Enable interrupt flag
 +        32768   // Enable logical AND mdoe (all button required)
 +        ;
 +
 +    // Enable keypad interrupt handling
 +    ham_StartIntHandler(INT_TYPE_KEY,&​interrupt);​
 +    ​
 +    ham_DrawText(1,​1,"​Press A to sleep"​);​
 +    ham_DrawText(1,​2,"​Press L & R & Select to wake"​);​
 +
 +    while(1)
 +    {
 +        ham_UpdatePad();​
 +        ​
 +        if(Pad.Pressed.A)
 +        {
 +            // BIOS '​Stop'​ command (turn everything off until interrupted)
 +            asm volatile("​swi 0x30000"​);​
 +        }
 +    }
 +
 +    return 0;
 +}
 +
 +
 +void interrupt()
 +{
 +   ​count++;​
 +   ​ham_DrawText(1,​3,"​%d",​count);​
 +   ​return;​
 +}
 +
 +char* toBinary(u8 n){
 + static char sResult[(sizeof(n)*8)];​ //​ static so the return doesn'​t point to a local var
 +
 + // Use bit-wise AND to check if the LSB of n is set, and place into
 + // our string accordingly (filling right->​left due to numerical significance)
 + int i=sizeof(sResult);​
 +    while(i>​=0){
 + sResult[i] = (n & 1) ? '​1'​ : '​0'​ ;
 + n >>= 1;
 + i--;
 + }
 +
 + return sResult; // Return a pointer
 +}
 +</​code>​
 +
 +==== SRAM Backup ====
 +Written to solve problems with my brother'​s GBA cart (which was losing his save game to Fire Emblam because he plays too quickly).
 +
 +This is designed to use a [[http://​www.devrs.com/​gba/​files/​mbv2faqs.php|Multi-Boot v2 cable]] (often shortened to MBv2) and copies to/from the PC as well as displaying a menu on the PC which requires user input to proceed.
 +
 +<code cpp>
 +#include <​mygba.h>​
 +#include "​mbv2lib.c"​
 +
 +MULTIBOOT
 +
 +int i = 0;
 +const int SRAM_size = 65536;
 +
 +void displayProgress();​
 +
 +int main (void)
 +{
 +    ham_Init();
 +    ham_InitText(0);​
 +    ham_DrawText(1,​1,"​Program started\n"​);​
 +
 +    char c;
 +    int l = 1;
 +    FILE fp = 0;
 +
 +    dprintf("​Program Started.\n"​);​
 +    dprintf("​Choose:​\n"​);​
 +    dprintf("​c : Complete (GBA->​before.bin,​ sram.bin->​GBA,​ verify, GBA->​after.bin)\n"​);​
 +    dprintf("​b : Backup (to sram.bin) and verify\n"​);​
 +    dprintf("​B : Backup (to sram.bin)\n"​);​
 +    dprintf("​v : Verify (against sram.bin)\n"​);​
 +    dprintf("​r : Restore (from sram.bin) and verify\n"​);​
 +    dprintf("​R : Restore (from sram.bin)\n"​);​
 +    dprintf("​\n"​);​
 +
 +    // Get character from PC keyboard
 +    c = dgetch ();
 +    ​
 +    dprintf("​Setting SRAM waitstate\n"​);​
 +    R_WAITCNT = 3;  // Set SRAM wait state for reliable reading/​writing
 +    ​
 +    // Setup a timer and interrupt for displaying progress indicators
 +    M_TIM0CNT_SPEED_SELECT_SET(1); ​    // increment timer count every 3,841ms
 +    M_TIM0COUNT_SET(3); ​                // Count up to this number
 +    M_TIM0CNT_TIMER_START;​
 +    M_TIM0CNT_IRQ_ENABLE; ​              // This timer can trigger interrupts
 +    ​
 +    // Disabled as it's randomly causing the program to hang
 +    //​ham_StartIntHandler(INT_TYPE_TIM0,&​displayProgress);​
 +
 +    // Backup
 +    if(c == '​c'​ || c == '​b'​)
 +    {
 +        // Copy SRAM or Flash backup to PC
 +        switch(c){
 +            case '​c':​
 +                ham_DrawText(1,​++l,"​Backing up SRAM (before.bin)"​);​
 +                dprintf("​\nCopying SRAM to before.bin\n"​);​
 +                fp = dfopen("​before.bin","​wb"​);​
 +                break;
 +            case '​B':​
 +            case '​b':​
 +                ham_DrawText(1,​++l,"​Backing up SRAM (sram.bin)"​);​
 +                dprintf("​\nCopying SRAM to sram.bin\n"​);​
 +                fp = dfopen("​sram.bin","​wb"​);​
 +                break;
 +        }
 +        for (i = 0; i != SRAM_size; i++)
 +        {
 +           ​dfputc(*(unsigned char *)(i + 0xE000000), fp);
 +        }
 +        ham_DrawText(1,​++l,​ "​Done"​);​
 +        dfclose(fp);​
 +        dprintf("​Done.\n"​);​
 +    }
 +
 +    // Restore
 +    if(c == '​c'​ || c == '​r'​ || c == '​R'​)
 +    {
 +        // Copy PC to SRAM
 +        ham_DrawText(1,​++l,"​Restoring SRAM (sram.bin)"​);​
 +        dprintf("​\nWriting sram.bin to GBA...\n"​);​
 +        dprintf("​Opening file..."​);​
 +        fp = dfopen("​sram.bin","​rb"​);​
 +        dprintf("​ Done.\n"​);​
 +        dprintf("​Entering loop.\n"​);​
 +
 +        for (i = 0; i != SRAM_size; i++)
 +        {
 +            *(unsigned char *)(i + 0xE000000) = dfgetc (fp);
 +        }
 +        dprintf("​End of loop, closing file..."​);​
 +        dfclose(fp);​
 +        dprintf("​Done.\n"​);​
 +        dprintf("​Writing phase complete.\n"​);​
 +        ham_DrawText(1,​++l,"​Done"​);​
 +    }
 +
 +    // Verify
 +    if(c == '​c'​ || c == '​b'​ || c == '​r'​ || c == '​v'​)
 +    {
 +        ham_DrawText(1,​++l,"​Verifying SRAM (sram.bin)"​);​
 +        dprintf("​\nVerifying SRAM against sram.bin\n"​);​
 +        dprintf("​Opening file..."​);​
 +        fp = dfopen("​sram.bin","​rb"​);​
 +        dprintf("​ Done.\n"​);​
 +        dprintf("​Entering loop.\n"​);​
 +
 +        int errors = 0;
 +        for (i = 0; i != SRAM_size; i++)
 +        {
 +            // File char != SRAM char
 +            if(dfgetc (fp) != *(unsigned char *)(i+0xE000000))
 +            {
 +                errors++;
 +            }
 +       }
 +       ​dprintf("​End of loop, closing file..."​);​
 +       ​dfclose(fp);​
 +       ​dprintf("​Done.\n"​);​
 +
 +       ​if(errors)
 +       {
 +            ham_DrawText(1,​++l,"​%d bytes failed verification",​errors);​
 +            dprintf("​%d bytes failed verification.\n",​ errors);
 +       }
 +       else
 +       {
 +            ham_DrawText(1,​++l,"​Verify OK!");
 +            dprintf("​Verify OK!\n"​);​
 +       }
 +    }
 +
 +    // Backup to after.bin
 +    if(c == '​c'​)
 +    {
 +        ham_DrawText(1,​++l,"​Backing up SRAM (after.bin)"​);​
 +        dprintf("​\nCopying current SRAM to after.bin\n"​);​
 +        fp = dfopen("​after.bin","​wb"​);​
 +        for (i = 0; i != SRAM_size; i++)
 +        {
 +           ​dfputc(*(unsigned char *)(i + 0xE000000), fp);
 +        }
 +        ham_DrawText(1,​++l,​ "Done backing up SRAM"​);​
 +        dfclose(fp);​
 +        dprintf("​Done.\n"​);​
 +    }
 +    ​
 +    // Remove interrupt to ensure clean restart
 +    ham_StopIntHandler(INT_TYPE_TIM0);​
 +    M_TIM0CNT_TIMER_STOP;​
 +    M_TIM0CNT_IRQ_DISABLE;​
 +
 +    displayProgress(); ​ // Avoid the progress showing '98 percent done' etc
 +
 +    ham_DrawText(1,​++l,"​Program completed"​);​
 +    dprintf("​\nProgram complete. Press any key to restart\n\n\n"​);​
 +    dgetch ();
 +
 +    return 0;
 +}
 +
 +void displayProgress()
 +{
 +    M_INTMST_DISABLE; ​  // Disable interrupts
 +
 +    ham_DrawText(1,​19,"​%d percent done.  ", i / (SRAM_size/​100));​
 +
 +    M_INTMST_ENABLE; ​   // Re-Enable interrupts
 +}
 +</​code>​
 +
 +where mbv2lib.c is
 +<code cpp>
 +
 +#define __ANSI_NAMES 0
 +//
 +// v1.40 - Initial release.
 +// v1.41 - Put received keyboard & file data in separate buffers
 +//         to prevent mixing of data during simultaneous use.
 +//         Added dfprintf library function.
 +// v1.42 - Fixed bug in dfputc() where escape characters caused
 +//         ​character 0x01 to be sent to console. Thanks to
 +//         Tim Schuerewegen for finding this bug.
 +//
 +//  MB v1.41 or later pc software is required to use this library
 +// software.
 +//
 +// NOTE: THIS LIBRARY USES GLOBAL INITIALIZED DATA SO YOU MUST USE
 +// A CRT0.S AND A LINKER SCRIPT THAT SUPPORTS THIS AS WELL. GET
 +// CRTLS V1.1 OR LATER FROM HTTP://​www.devrs.com/​gba FOR PROPER SUPPORT.
 +//
 +// The following library functions are supported:
 +//
 +// Library name   ​Standard Name      Function
 +//   ​dprintf ​       printf ​      Print a string on PC console.
 +//   ​dputchar ​      ​putchar ​     Print a char on PC console.
 +//   ​dgetch ​        ​getch ​       Get a char from PC keyboard.
 +//   ​dkbhit ​        ​kbhit ​       Return 1 if PC keyboard char is ready.
 +//
 +//   ​dfopen ​        ​fopen ​       Open PC file.
 +//   ​dfclose ​       fclose ​      Close PC file.
 +//   ​dfprintf ​      ​fprintf ​     Print a string to PC file.
 +//   ​dfgetc ​        ​fgetc ​       Get char from PC file.
 +//   ​dfputc ​        ​fputc ​       Write a char to PC file.
 +//   ​drewind ​       rewind ​      Set file pointer to start of file.
 +//
 +// If you wish to use the standard naming conventions
 +// rather than the library names then change "​__ANSI_NAMES 0"
 +// to "​__ANSI_NAMES 1" instead.
 +//
 +// Notes:
 +//
 +//  Currently only ONE file may be open at a time.
 +//
 +//  If you are sending raw binary data to a PC file, use
 +//  dfputc instead of dfprintf. Dfprintf will insert
 +//  carriage return characters before linefeed characters
 +//  on the PC side if the PC console software is running on
 +//  dos/windows for proper text formatting.
 +//
 +//  If you are missing some .h files during compile than get
 +// '​arminc.zip'​ from http://​www.devrs.com/​gba in the
 +//  Apps / C Compilers section.
 +//
 +// Example command line:
 +//    mb -s file.mb -c -w 50 -x 255 -m
 +//
 +//  In this example, after transferring "​file.mb"​ to the GBA,
 +// the PC goes into console/​file server mode (-c) and also
 +// shows all of the file open/file close/​fgetc/​fputc commands
 +// (-m) on screen. The -w value should be a large enough value
 +// where the -s is reliable and the -x value should be a large
 +// enough value where the -c is reliable with the GBA.
 +//
 +//      [Sending a file & console mode each have
 +//       their own delay settings because they
 +//       each use a different method for transferring
 +//       data. Each method is about ideal for it's
 +//       ​application.]
 +//
 +// Example GBA Code:
 +//
 +//  #include "​mbv2lib.c"​
 +//
 +//  int main (void)
 +//    {
 +//
 +//    int i,j,k;
 +//    FILE fp;
 +//
 +//    dprintf ("​Hello world!"​);​
 +//
 +//    // Get character from PC keyboard
 +//    i = dgetch ();
 +//
 +//    // Copy SRAM or Flash backup to PC
 +//    fp = dfopen("​sram.bin","​wb"​);​
 +//    for (i = 0; i != 0x8000; i++)
 +//       ​dfputc(*(unsigned char *)(i + 0xE000000), fp);
 +//    dfclose(fp);​
 +//
 +//    // Copy PC to SRAM
 +//    fp = dfopen("​sram.bin","​rb"​);​
 +//    for (i = 0; i != 0x8000; i++)
 +//       ​*(unsigned char *)(i + 0xE000000) = dfgetc (fp);
 +//    dfclose(fp);​
 +
 +//    // Read data from file
 +//    fp = dfopen ("​foo.bin",​ "​rb"​);​
 +//    i = dfgetc (fp);
 +//    j = dfgetc (fp);
 +//    k = dfgetc (fp);
 +//    dfclose (fp);
 +//
 +//    }
 +
 +// Data transfer format
 +// --------------------
 +//
 +// PC -> GBA Comms:
 +// Raw data is PC File read data.
 +// ESCCHR 0x00 = nada (used for input polling)
 +// ESCCHR 0x01 = Escape character from PC file read
 +// ESCCHR 0x08 0x?? = Keyboard read data
 +//
 +//
 +// GBA -> PC comms
 +// Raw data is console print data.
 +// ESCCHR = escape sequence
 +// ESCCHR 0x00 = nada (used for input polling)
 +// ESCCHR 0x01 = Escape character for console print
 +// ESCCHR 0x02 = file open (gba -> PC)
 +// ESCCHR 0x03 = file close (gba -> PC)
 +// ESCCHR 0x04 = fgetc (gba -> PC)
 +// ESCCHR 0x05 0x?? = fputc (gba -> PC)
 +// ESCCHR 0x06 = rewind (gba -> PC)
 +// ESCCHR 0x07 = fputc processed (gba -> pC) (Add CR before LF char if win/DOS machine)
 +
 +#define FILE int
 +
 +// Uncomment the following line to define the following types if needed
 +//#define INC_SHORT_NAME_TYPES 1
 +
 +#ifdef INC_SHORT_NAME_TYPES
 + ​typedef ​    ​volatile unsigned char           vu8;
 + ​typedef ​    ​volatile unsigned short int      vu16;
 + ​typedef ​    ​volatile unsigned int            vu32;
 + ​typedef ​    ​volatile unsigned long long int  vu64;
 +
 + ​typedef ​    ​unsigned char           u8;
 + ​typedef ​    ​unsigned short int      u16;
 + ​typedef ​    ​unsigned int            u32;
 + ​typedef ​    ​unsigned long long int  u64;
 +
 + ​typedef ​    ​signed char             s8;
 + ​typedef ​    ​signed short int        s16;
 + ​typedef ​    ​signed int              s32;
 + ​typedef ​    ​signed long long int    s64;
 +#endif
 +
 +#ifdef INC_REG_DEFS
 + #​define REG_BASE ​       0x4000000
 + #​define REG_SIOCNT ​     (REG_BASE + 0x128) ​ // Serial Communication Control
 + #​define REG_SIODATA8 ​   (REG_BASE + 0x12a) ​ // 8bit Serial Communication Data
 + #​define REG_RCNT ​       (REG_BASE + 0x134) ​ // General Input/​Output Control
 +#endif
 +
 +#include "​vsprintf.c"​
 +
 +#define __DOUTBUFSIZE 256
 +#define __FINBUFSIZE 256  //Must be a multiple of 2! (ex: 32,​64,​128,​256,​512..)
 +#define __KINBUFSIZE 64   //​Must be a multiple of 2! (ex: 32,​64,​128,​256,​512..)
 +#define __ESCCHR 27
 +
 +#define __ESC_NADA ​  0
 +#define __ESC_ESCCHR 1
 +#define __ESC_FOPEN ​ 2
 +#define __ESC_FCLOSE 3
 +#define __ESC_FGETC ​ 4
 +#define __ESC_FPUTC ​ 5
 +#define __ESC_REWIND 6
 +#define __ESC_FPUTC_PROCESSED 7         // PC side add CR before LF if DOS machine
 +#define __ESC_KBDCHR 8
 +
 +unsigned char __outstr[__DOUTBUFSIZE];​
 +unsigned char __finstr[__FINBUFSIZE];​
 +unsigned char __kinstr[__KINBUFSIZE];​
 +int finptr = 0;
 +int foutptr = 0;
 +int kinptr = 0;
 +int koutptr = 0;
 +
 +int __dputchar (int c)
 +   {
 +   int rcv;
 +   ​static int LastChar = 0;
 +   ​static int KbdCharNext = 0;
 +
 +   // Set non-general purpose comms mode
 +   *(u16 *)REG_RCNT = 0;
 +
 +   // Init normal comms, 8 bit transfer, receive clocking
 +   *(u16 *)REG_SIODATA8 = c;
 +   *(u16 *)REG_SIOCNT = 0x80;
 +
 +   // Wait until transfer is complete
 +   while (*(vu16 *)REG_SIOCNT & 0x80) {}
 +
 +   // Wait until SC is low
 +   while (*(vu16 *)REG_RCNT & 1) {}
 +
 +   // Force SD high
 +   *(u16 *)REG_RCNT = 0x8022;
 +
 +   // Wait until SC is high
 +   while ((*(vu16 *)REG_RCNT & 1)==0) {}
 +
 +   rcv = *(vu16 *)REG_SIODATA8;​
 +
 +   if (KbdCharNext)
 +      {
 +      // Put into keyboard buffer
 +      __kinstr[kinptr++] = rcv;
 +      kinptr &= (__KINBUFSIZE-1);​
 +
 +      KbdCharNext = 0;
 +
 +      // Make received char look like a NADA character
 +      // so that it won't be buffered elsewhere.
 +      LastChar = __ESCCHR;
 +      rcv = __ESC_NADA;
 +      }
 +
 +   if (LastChar == __ESCCHR)
 +      {
 +      // Process escape character
 +      switch (rcv)
 +         {
 +         case __ESC_ESCCHR:​
 +            __finstr[finptr++] = __ESCCHR;
 +            finptr &= (__FINBUFSIZE-1);​
 +            break;
 +         case __ESC_KBDCHR:​
 +            KbdCharNext = 1;
 +            break;
 +         }
 +      LastChar = 0;
 +      }
 +   else
 +      {
 +      if (rcv == __ESCCHR)
 +         ​LastChar = __ESCCHR;
 +      else
 +         {
 +         // If char received from PC then save in receive FIFO
 +         ​__finstr[finptr++] = rcv;
 +         ​finptr &= (__FINBUFSIZE-1);​
 +         }
 +      }
 +   ​return(1);​
 +   }
 +
 +int dputchar (int c)
 +   {
 +   ​(void) __dputchar(c);​
 +   if (c == __ESCCHR)
 +      (void) __dputchar(__ESC_ESCCHR);​
 +   ​return (1);
 +   }
 +
 +void __PrintStr (char *str)
 +   {
 +   while (*str)
 +      (void) dputchar(*str++);​
 +   }
 +
 +int dgetch (void)
 +   {
 +   int c;
 +
 +   // If no character is in FIFO then wait for one.
 +   while (kinptr == koutptr)
 +      {
 +      __dputchar(__ESCCHR);​
 +      __dputchar(__ESC_NADA);​
 +      }
 +
 +   c = __kinstr[koutptr++];​
 +   ​koutptr &= (__KINBUFSIZE-1);​
 +
 +   ​return (c);
 +   }
 +
 +int dfgetch (void)
 +   {
 +   int c;
 +
 +   // If no character is in FIFO then wait for one.
 +   while (finptr == foutptr)
 +      {
 +      __dputchar(__ESCCHR);​
 +      __dputchar(__ESC_NADA);​
 +      }
 +
 +   c = __finstr[foutptr++];​
 +   ​foutptr &= (__FINBUFSIZE-1);​
 +
 +   ​return (c);
 +   }
 +
 +int dkbhit (void)
 +   {
 +   ​return(kinptr != koutptr);
 +   }
 +
 +FILE dfopen (const char *file, const char *type)
 +   {
 +   ​__dputchar(__ESCCHR);​
 +   ​__dputchar(__ESC_FOPEN);​
 +
 +   while (*file)
 +      (void) dputchar(*file++);​
 +   ​dputchar(0);​
 +
 +   while (*type)
 +      (void) dputchar(*type++);​
 +   ​dputchar(0);​
 +
 +   ​return(1);​
 +   }
 +
 +int dfclose (FILE fp)
 +   {
 +   ​__dputchar(__ESCCHR);​
 +   ​__dputchar(__ESC_FCLOSE);​
 +
 +   ​return(1);​
 +   }
 +
 +int dfgetc (FILE fp)
 +   {
 +   ​__dputchar(__ESCCHR);​
 +   ​__dputchar(__ESC_FGETC);​
 +
 +   ​return(dfgetch());​
 +   }
 +
 +int dfputc (int ch, FILE fp)
 +   {
 +   ​__dputchar(__ESCCHR);​
 +   ​__dputchar(__ESC_FPUTC);​
 +
 +   ​__dputchar(ch); ​                /* Bug fix. Was:  dputchar(ch);​ */
 +
 +   ​return(1);​
 +   }
 +
 +void drewind (FILE fp)
 +   {
 +   ​__dputchar(__ESCCHR);​
 +   ​__dputchar(__ESC_REWIND);​
 +   }
 +
 +void __PrintStrToFile (FILE fp, char *str)
 +   {
 +   while (*str)
 +      {
 +      __dputchar(__ESCCHR);​
 +      __dputchar(__ESC_FPUTC_PROCESSED);​
 +
 +      dputchar(*str++);​
 +      }
 +   }
 +
 +#ifndef dprintf
 + #define dprintf(x...) ({ dsprintf(__outstr,​ x); __PrintStr(__outstr);​ })
 +#endif
 +#define dfprintf(y,​x...) ({ dsprintf(__outstr,​ x); __PrintStrToFile(y,​__outstr);​ })
 +
 +#ifdef __ANSI_NAMES
 +  #define printf ​ dprintf
 +  #define fprintf dfprintf
 +  #define putchar dputchar
 +  #define getch   ​dgetch
 +  #define kbhit   ​dkbhit
 +
 +  #define fopen   ​dfopen
 +  #define fclose ​ dfclose
 +  #define fgetc   ​dfgetc
 +  #define fputc   ​dfputc
 +  #define rewind ​ drewind
 +#endif
 +</​code>​
 +
 +==== RS232 Terminal ====
 +Adapted from [[http://​www.fivemouse.com.com/​gba]] to compile with HAM and echo sent characters locally, the code is spread accross multiple files, so I've just compressed the files into a .rar file. 
 +
 +[[http://​robmeerman.co.uk/​downloads/​GBA%20RS232%20Terminal.rar]]
project/gba/code.txt · Last modified: 2007/04/27 00:21 (external edit)