Version of Robotron arcade game using LPC1768, a Gameduino shield, a serial EEPROM (for high scores), two microswitch joysticks and two buttons plus a box to put it in. 20 levels of mayhem.

Dependencies:   25LCxxx_SPI CommonTypes Gameduino mbed

Files at this revision

API Documentation at this revision

Comitter:
RichardE
Date:
Fri Jun 07 20:29:59 2013 +0000
Parent:
2:bb0f631a6068
Child:
4:673eb9735d44
Commit message:
Abandoned writing serial EEPROM class and used Ser25LCxxx library instead. HighScoreTable class appears to be reading and writing correctly to EEPROM and high scores are displayed correctly.

Changed in this revision

25LCxxx_SPI.lib Show annotated file Show diff for this revision Revisions of this file
GameRobotRic.cpp Show annotated file Show diff for this revision Revisions of this file
HighScoreTable.cpp Show annotated file Show diff for this revision Revisions of this file
HighScoreTable.h Show annotated file Show diff for this revision Revisions of this file
Level0.cpp Show annotated file Show diff for this revision Revisions of this file
SPIEEPROM.cpp Show diff for this revision Revisions of this file
SPIEEPROM.h Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/25LCxxx_SPI.lib	Fri Jun 07 20:29:59 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/hlipka/code/25LCxxx_SPI/#3a3404dbd3eb
--- a/GameRobotRic.cpp	Thu Jun 06 20:11:28 2013 +0000
+++ b/GameRobotRic.cpp	Fri Jun 07 20:29:59 2013 +0000
@@ -18,6 +18,9 @@
     #include "HighScoreEntry.h"                 // for getting player's name for high score table
 #endif
 
+// Define following for debugging messages to serial port.
+#define CHATTY
+
 // Number of lives player starts with.
 #define START_LIVES 5
 
@@ -29,6 +32,9 @@
 // Address of EEPROM set using A0, A1 and A2 pins.
 #define ADDRESS_OF_EEPROM 0
 
+// Serial link to PC over USB cable. Globally accessible.
+Serial pc( USBTX, USBRX );
+
 /**************************/
 /* CHECK FOR A HIGH SCORE */
 /**************************/
@@ -55,12 +61,12 @@
 /*****************/
 // This NEVER exits.
 void GameRobotRic::Play( void ) {
+    #ifdef CHATTY
+        pc.puts( "Program has restarted!\r\n" );
+    #endif
     // Make a digital output for use as the Gameduino chip select pin. Deselect it.
     DigitalOut gameduinoCS( p8 );
     gameduinoCS = 1;
-    // Make a digital output for use as the Gameduino chip select pin. Deselect it.
-    DigitalOut eepromCS( p14 );
-    eepromCS = 1;
     // Initialise an SPI link for communications with Gameduino and the serial EEPROM.
     // This is different from how the Maple version of RobotRic did it. It used an
     // I2C EEPROM.
@@ -72,7 +78,7 @@
     spi.frequency( 8000000 );
     // Set SPI format to use.
     // Use 8 bits per SPI frame.
-    // Use SPI mode 0.
+    // Use SPI mode 0. Clock normally low. Data captured on rising edge.
     spi.format( 8, 0 );
     // Make a Gameduino and pass SPI link and digital output for chip select.
     Gameduino gd( &spi, &gameduinoCS );
@@ -94,7 +100,7 @@
     // enemies are both J type and so collisions between players and enemies are not detected.
     gd.wr( Gameduino::JK_MODE, 0 );
     // Initialise serial EEPROM object which is on same SPI bus as the Gameduino.
-    SPIEEPROM eeprom( &spi, &eepromCS );
+    Ser25LCxxx eeprom( &spi, p14, 32768, 64 );
     // Create a high score table that uses the EEPROM.
     HighScoreTable highScores( &eeprom );
     // Start on the attract level.
@@ -125,9 +131,9 @@
       // Refetch level.
       level = levels.GetLevel( levelNumber );
     }
-#if 0
     // Pass reference to high score table.
     level->SetHighScores( &highScores );
+#if 0
     // Set player that is playing the level.
     level->SetPlayer( &player );
 #endif
--- a/HighScoreTable.cpp	Thu Jun 06 20:11:28 2013 +0000
+++ b/HighScoreTable.cpp	Fri Jun 07 20:29:59 2013 +0000
@@ -47,13 +47,21 @@
  *
  */
 
+// Define this for debugging messages to be sent to serial port.
+#undef CHATTY
+
+#ifdef CHATTY
+    #include "mbed.h"
+    extern Serial pc;
+#endif
+
 #include "HighScoreTable.h"
 
 /***************/
 /* CONSTRUCTOR */
 /***************/
 // Pass pointer to an SPI EEPROM which contains the high scores.
-HighScoreTable::HighScoreTable( SPIEEPROM *e ) :
+HighScoreTable::HighScoreTable( Ser25LCxxx *e ) :
     eeprom( e )
 {
 }
@@ -115,15 +123,15 @@
     // a single byte a whole page is written so might as well
     // write a whole page in one go. Only drawback is more RAM
     // is required.
-    UInt8 buffer[ memoryUsed ];
-    if( eeprom->ReadBytes( eepromAddress, buffer, memoryUsed ) ) {
+    char *buffer = eeprom->read( eepromAddress, memoryUsed );
+    if( buffer != NULL ) {
         // Fetch index for lowest score in the table.
         UInt8 index = buffer[ capacity - 1 ];
         // Make sure index is within range.
         if( index < capacity ) {
             // Point to section of buffer that contains name and score for
             // lowest score.
-            UInt8 *address = buffer + capacity + ( index << 3 );
+            UInt8 *address = (UInt8*)( buffer + capacity + ( index << 3 ) );
             // Copy characters of name into buffer.
             for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
                 *address++ = name->Name[ i ];
@@ -139,7 +147,9 @@
             // Insert index of newly written record at insertion point.
             buffer[ pos ] = index;
             // Write the buffer back to EEPROM.
-            eeprom->WriteBytes( eepromAddress, buffer, memoryUsed ); 
+            eeprom->write( eepromAddress, memoryUsed, buffer );
+            // Free memory used by buffer.
+            free( buffer );
         }
     }
 }
@@ -151,27 +161,37 @@
 // Player name is returned in object pointed to by name.
 // Player score is returned in integer pointed to by score.
 void HighScoreTable::Get( UInt8 pos, PlayerName *name, UInt32 *score ) const {
-    // Write default values to name and score.
+  // Write default values to name and score.
   for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
     name->Name[ i ] = (UInt8)'X';
   }
   name->Name[ PlayerName::Length ] = 0;
-    *score = 0;
+  *score = 0;
   // Fetch index from EEPROM.
-  UInt8 index;
-    if( ! eeprom->ReadBytes( eepromAddress + pos, &index, 1 ) ) {
+  UInt8 *index = (UInt8*)eeprom->read( eepromAddress + pos, 1 );
+  if( index == NULL ) {
         return;
-    }
+  }
   // Point to appropriate part of data table.
-  UInt16 address = eepromAddress + capacity + ( index << 3 );
+  UInt16 address = eepromAddress + capacity + ( *index << 3 );
+  // Free buffer containing index.
+  free( index );
   // Read out characters and store in name.
-    if( ! eeprom->ReadBytes( address, (UInt8*)name->Name, PlayerName::Length ) ) {
-        return;
-    }
+  char *rawName = eeprom->read( address, PlayerName::Length );
+  if( rawName == NULL ) {
+    return;
+  }
+  memcpy( name->Name, rawName, PlayerName::Length );
   name->Name[ PlayerName::Length ] = 0;
-    address += PlayerName::Length;
+  address += PlayerName::Length;
+  free( rawName );
   // Read out score.
-    eeprom->ReadBytes( address, (UInt8*)score, 4 );
+  char *rawScore = eeprom->read( address, 4 );
+  if( rawScore == NULL ) {
+    return;
+  }
+  *score = *((UInt32*)rawScore);
+  free( rawScore );
 }
 
 /********************************/
@@ -179,53 +199,84 @@
 /********************************/
 // Returns true if EEPROM is valid.
 bool HighScoreTable::EEPROMValid( void ) {
+  #ifdef CHATTY
+    pc.printf( "Checking validity.\r\n" );
+  #endif
   UInt8 b, b2;
+  // Read index from EEPROM.
+  char *index = eeprom->read( eepromAddress, capacity );
+  if( index == NULL ) {
+    return false;
+  }
   // Check all entries in the index are within range and are unique.
   for( UInt8 i = 0; i < capacity; ++i ) {
-    // Read byte from EEPROM.
-        if( ! eeprom->ReadBytes( eepromAddress + i, &b, 1 ) ) {
-            return false;
-        }
-    // Check index read is less than capacity.
+    b = index[ i ];
+    #ifdef CHATTY
+      pc.printf( "index[ %u ] = %u\r\n", (unsigned)i, (unsigned)b );
+    #endif
     if( b >= capacity ) {
+      free( index );
       return false;
     }
     // Check if any of the following bytes in the index have
     // the same value.
     for( UInt8 j = i + 1; j < capacity; ++j ) {
-            if( ! eeprom->ReadBytes( eepromAddress + j, &b2, 1 ) ) {
-                return false;
-            }
+      b2 = index [ j ];
       if( b == b2 ) {
+        #ifdef CHATTY
+            pc.printf( "index[ %u ] has the same value!\r\n", (unsigned)j );
+        #endif
+        free( index );
         return false;
       }
     }
   }
+  // Free memory used by index.
+  free( index );
   // Check all entries in the data part of the table are valid.
   UInt16 address = eepromAddress + capacity;
   for( UInt8 i = 0; i < capacity; ++i ) {
+    // Read name and score.
+    char *entry = eeprom->read( address, 8 );
+    if( entry == NULL ) {
+      return false;
+    }
+    #ifdef CHATTY
+        pc.printf( "Checking entry %u.\r\n", i );
+        pc.puts( "Name:" );
+    #endif
     // Check name consists only of uppercase letters.
     for( UInt8 j = 0; j < PlayerName::Length; ++j ) {
-            // Read byte from EEPROM.
-            if( ! eeprom->ReadBytes( address++, &b, 1 ) ) {
-                return false;
-            }
+      b = (UInt8)entry[ j ];
+      #ifdef CHATTY
+        pc.putc( b );
+      #endif
       if( ( b < PlayerName::MinChar ) || ( b > PlayerName::MaxChar ) ) {
+        free( entry );
         return false;
       }
     }
+    #ifdef CHATTY
+        pc.puts( "\r\nScore:" );
+    #endif
     // Check score consists only of valid BCD numbers.
-    for( UInt8 j = 0; j < 4; ++j ) {
-            // Read byte from EEPROM.
-            if( ! eeprom->ReadBytes( address++, &b, 1 ) ) {
-                return false;
-            }
+    for( UInt8 j = PlayerName::Length; j < PlayerName::Length + 4; ++j ) {
+      b = (UInt8)entry[ j ];
+      #ifdef CHATTY
+        pc.printf( "%02X ", (int)b );
+      #endif
       if( ( ( b & 0x0F ) > 0x09 ) || ( ( b & 0xF0 ) > 0x90 ) ) {
+        free( entry );
         return false;
       }
     }
-    // Skip over unused byte.
-    address++;
+    #ifdef CHATTY
+        pc.puts( "\r\n" );
+    #endif
+    // Finished with name and score.
+    free( entry );
+    // Skip to next entry.
+    address += 8;
   }
   // EEPROM is valid
   return true;
@@ -236,9 +287,9 @@
 /****************************/
 // This may take a second or two to execute!
 void HighScoreTable::WriteEEPROMDefaults( void ) {
-    UInt8 buffer[ memoryUsed ];
+  UInt8 buffer[ memoryUsed ];
   // Write index with ascending integers.
-    UInt8 *ptr = buffer;
+  UInt8 *ptr = buffer;
   for( UInt8 i = 0; i < capacity; ++i ) {
     *ptr++ =  i;
   }
@@ -246,14 +297,14 @@
   for( UInt8 i = 0; i < capacity; ++i ) {
     // Write a name of "AAA".
     for( UInt8 j = 0; j < PlayerName::Length; ++j ) {
-            *ptr++ = (UInt8)'A';
+      *ptr++ = (UInt8)'A';
     }
-        // Write a score of zero.
+    // Write a score of zero.
     *((UInt32*)ptr) = 0;
-        ptr += 4;
-        // Write zero to unused byte.
-        *ptr++ = 0;    
-    }
-    // Write the buffer to EEPROM.
-    eeprom->WriteBytes( eepromAddress, buffer, memoryUsed ); 
+    ptr += 4;
+    // Write zero to unused byte.
+    *ptr++ = 0;    
+  }
+  // Write the buffer to EEPROM.
+  eeprom->write( eepromAddress, memoryUsed, (char*)buffer ); 
 }
--- a/HighScoreTable.h	Thu Jun 06 20:11:28 2013 +0000
+++ b/HighScoreTable.h	Fri Jun 07 20:29:59 2013 +0000
@@ -12,7 +12,7 @@
 
   #include "Types.h"
   #include "PlayerName.h"
-  #include "SPIEEPROM.h"
+  #include "Ser25lcxxx.h"       // serial EEPROM routines. Also work for 25AAxxx EEPROMs.
   
   class HighScoreTable {
 
@@ -21,8 +21,8 @@
     /***************/
     /* CONSTRUCTOR */
     /***************/
-        // Pass pointer to an SPI EEPROM which contains the high scores.
-    HighScoreTable( SPIEEPROM *e );
+    // Pass pointer to an SPI EEPROM which contains the high scores.
+    HighScoreTable( Ser25LCxxx *e );
 
     /**************/
     /* DESTRUCTOR */
@@ -32,7 +32,7 @@
     /***************************************/
     /* GET EEPROM USED BY HIGH SCORE TABLE */
     /***************************************/
-    SPIEEPROM *GetEEPROM( void ) const {
+    Ser25LCxxx *GetEEPROM( void ) const {
         return eeprom;
     }
         
@@ -50,7 +50,7 @@
     // Returns true if EEPROM is valid.
     bool EEPROMValid( void );
     
-  /*************************/
+    /*************************/
     /* GET CAPACITY OF TABLE */
     /*************************/
     // Returns capacity of table.
@@ -96,7 +96,7 @@
     };
 
     // Pointer to EEPROM that holds high scores.
-    SPIEEPROM *eeprom;
+    Ser25LCxxx *eeprom;
         
     /****************************/
     /* WRITE DEFAULTS TO EEPROM */
--- a/Level0.cpp	Thu Jun 06 20:11:28 2013 +0000
+++ b/Level0.cpp	Fri Jun 07 20:29:59 2013 +0000
@@ -37,19 +37,17 @@
 /* DRAW HIGH SCORES */
 /********************/
 void Level0::DrawHighScores( void ) {
-#if 0
   // Draw high score table.
-  GDExtra::WriteProgString( 16, 11, StringData::HighScoresString );
+  GDExtra::WriteProgString( gd, 16, 11, StringData::HighScoresString );
   PlayerName name;
   UInt32 score;
   UInt8 y = 13;
   for( UInt8 i = 0; i < highScores->GetCapacity(); ++i ) {
     highScores->Get( i, &name, &score );
-    GD.putstr( 18, y, name.Name );
-    GDExtra::WriteBCDNumber( 22, y, score, 8 );
+    gd->putstr( 18, y, name.Name );
+    GDExtra::WriteBCDNumber( gd, 22, y, score, 8 );
     y += 2;
   }
-#endif
 }
 
 /*************/
--- a/SPIEEPROM.cpp	Thu Jun 06 20:11:28 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/*
- * SOURCE FILE : SPIEEPROM.cpp
- *
- * Definition of class SPIEEPROM.
- * Rountines for communicating with a serial EEPROM over an SPI link.
- * EEPROM in question is a Microchip 24AA512.
- * Remember you need pullup resistors on the SCL, SDA and WP lines.
- *
- */
-
-#include "SPIEEPROM.h"
-
-// Instruction set codes for use with EEPROM.
-#define READ 0x03       // read data beginning at selected address
-#define WRITE 0x02      // write data beginning at selected address
-#define WRDI 0x04       // disable write operations
-#define WREN 0x06       // enable write operations
-#define RDSR 0x05       // read status register
-#define WRSR 0x01       // write status register
-
-/***************/
-/* CONSTRUCTOR */
-/***************/
-// Pass pointer to an SPI object in spiLink.
-// Pass pointer to output used as chip select in chipSelect.
-SPIEEPROM::SPIEEPROM( SPI *spiLink, DigitalOut *chipSelect ) :
-    spi( spiLink ),
-    cs( chipSelect )
-{
-}
-
-/**************/
-/* DESTRUCTOR */
-/**************/
-SPIEEPROM::~SPIEEPROM() {
-}
-
-/*************************************/
-/* ATTEMPT TO READ A NUMBER OF BYTES */
-/*************************************/
-// Pass address within EEPROM in address.
-// Pass pointer to buffer for bytes read in buffer.
-// Returns false if a failure occurred whilst reading EEPROM.
-// Pass number of bytes to read in count.
-// Returns true if successful, false if not.
-bool SPIEEPROM::ReadBytes( UInt16 address, UInt8 *buffer, UInt16 count ) {
-    *cs = 0;                                // Select the EEPROM.
-    spi->write( READ );                     // Send read instruction.
-    spi->write( ( address >> 8 ) & 0xFF );  // Send MSB of address.
-    spi->write( address & 0xFF );           // Send LSB of address.
-    // Read back the correct number of bytes by writing zero bytes.
-    // and storing what comes back in the buffer.
-    while( count > 0 ) {
-        *buffer++ = (UInt8)( spi->write( 0 ) );
-        count--;
-    }
-    *cs = 1;                                // Deselect the EEPROM.
-    return true;                            // Always succeeds.
-}
-
-/**************************************/
-/* ATTEMPT TO WRITE A CHUNK TO EEPROM */
-/**************************************/
-// Pass address within EEPROM in address.
-// Pass pointer to buffer of bytes to write in buffer.
-// Pass number of bytes to write in count.
-// Returns true if successful, false if not.
-// The number of bytes written must not exceed CHUNK_SIZE.
-bool SPIEEPROM::WriteChunk( UInt16 address, const UInt8 *buffer, UInt8 count ) {
-#if 0
-  // First send address you want to write to.
-  wire->beginTransmission( slaveAddress );
-  // Add high byte of EEPROM address to write to.
-  wire->send( ( address >> 8 ) & 0xFF );
-  // Add low byte of EEPROM address to write to.
-  wire->send( address & 0xFF );
-    // Add buffer bytes.
-    wire->send( (uint8*)buffer, count );
-  // Send the packet.
-    // Return true if successful.
-  return ( wire->endTransmission() == SUCCESS );
-#else
-  return false;
-#endif
-}
-
-/**************************************/
-/* ATTEMPT TO WRITE A NUMBER OF BYTES */
-/**************************************/
-// Pass address within EEPROM in address.
-// Pass pointer to buffer of bytes to write in buffer.
-// Pass number of bytes to write in count.
-// Returns true if successful, false if not.
-bool SPIEEPROM::WriteBytes( UInt16 address, const UInt8 *buffer, UInt16 count ) {
-#if 0
-    bool ok = true;
-    // Write enable EEPROM and wait a bit.
-    digitalWrite( wp, LOW );
-    delay( 1 );
-    // Keep writing chunks until all bytes written.
-    while( ( count > 0 ) && ok ) {
-        if( count > CHUNK_SIZE ) {
-            ok = WriteChunk( address, buffer, (UInt8)CHUNK_SIZE );
-            address += CHUNK_SIZE;
-            buffer += CHUNK_SIZE;
-            count -= CHUNK_SIZE;
-        }
-        else {
-            ok = WriteChunk( address, buffer, (UInt8)count );
-            count = 0;
-        }
-        // Wait a lot to allow page to be written.
-        delay( 6 );
-    }
-    // Write protect EEPROM.
-    digitalWrite( wp, HIGH );
-    // Return true on success.
-    return ok;
-#else
-  return false;
-#endif
-}
--- a/SPIEEPROM.h	Thu Jun 06 20:11:28 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * SOURCE FILE : SPIEEPROM.h
- *
- * Definition of class SPIEEPROM.
- * Rountines for communicating with a serial EEPROM over an SPI link.
- * EEPROM in question is a Microchip 25AA256.
- *
- */
-
-#ifndef SPIEEPROMDefined
-
-  #define SPIEEPROMDefined
-
-  #include "Types.h"
-  #include "mbed.h"     // for SPI
-    
-  class SPIEEPROM {
-
-  public :
-
-    /***************/
-    /* CONSTRUCTOR */
-    /***************/
-    // Pass pointer to an SPI object in spiLink.
-    // Pass pointer to output used as chip select in chipSelect.
-    SPIEEPROM( SPI *spi, DigitalOut *cs );
-        
-    /**************/
-    /* DESTRUCTOR */
-    /**************/
-    virtual ~SPIEEPROM();
-
-    /*************************************/
-    /* ATTEMPT TO READ A NUMBER OF BYTES */
-    /*************************************/
-    // Pass address within EEPROM in address.
-    // Pass pointer to buffer for bytes read in buffer.
-    // Pass number of bytes to read in count.
-    // Returns true if successful, false if not.
-    bool ReadBytes( UInt16 address, UInt8 *buffer, UInt16 count );
-
-    /**************************************/
-    /* ATTEMPT TO WRITE A NUMBER OF BYTES */
-    /**************************************/
-    // Pass address within EEPROM in address.
-    // Pass pointer to buffer of bytes to write in buffer.
-    // Pass number of bytes to write in count.
-    // Returns true if successful, false if not.
-    bool WriteBytes( UInt16 address, const UInt8 *buffer, UInt16 count );
-        
-private :
-
-    // Pointer to SPI object used for communication.
-    SPI *spi;
-    
-    // Pointer to digital output used as chip select.
-    DigitalOut *cs;
-    
-    /**************************************/
-    /* ATTEMPT TO WRITE A CHUNK TO EEPROM */
-    /**************************************/
-    // Pass address within EEPROM in address.
-    // Pass pointer to buffer of bytes to write in buffer.
-    // Pass number of bytes to write in count.
-    // Returns true if successful, false if not.
-    // The number of bytes written must not exceed WIRE_BUFSIZ - 2.
-    bool WriteChunk( UInt16 address, const UInt8 *buffer, UInt8 count );
-
-};
-
-#endif
-
-/* END of SPIEEPROM.h */
-