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

Revision:
2:bb0f631a6068
Parent:
0:5fa232ee5fdf
Child:
3:a6a0cd726ca0
--- a/HighScoreTable.cpp	Wed Jun 05 22:05:41 2013 +0000
+++ b/HighScoreTable.cpp	Thu Jun 06 20:11:28 2013 +0000
@@ -1,259 +1,259 @@
-/*
- * SOURCE FILE : HighScoreTable.cpp
- *
- * Definition of class HighScoreTable.
- * Maintains a table of high scores with a name and a score for each entry in the table.
- *
- * The table is stored in EEPROM at an address specified when you call the constructor.
- * The table is structured as follows. This shows a table with a capacity of 3.
- *
- * Byte offset      Usage
- * -----------      -----
- * 0                Index of highest score in data that follows
- * 1                Index of second highest score in data that follows
- * 2                Index of third highest score in data that follows
- *
- * 3                First character of player's name
- * 4                Second character of player's name
- * 5                Third character of player's name
- * 6                LSB of score (in BCD)
- * 7                Byte 1 of score (in BCD)
- * 8                Byte 2 of score (in BCD)
- * 9                MSB of score (in BCD)
- * 10               Unused
- *
- * 11               First character of player's name
- * 12               Second character of player's name
- * 13               Third character of player's name
- * 14               LSB of score (in BCD)
- * 15               Byte 1 of score (in BCD)
- * 16               Byte 2 of score (in BCD)
- * 17               MSB of score (in BCD)
- * 18               Unused
- *
- * 19               First character of player's name
- * 20               Second character of player's name
- * 21               Third character of player's name
- * 22               LSB of score (in BCD)
- * 23               Byte 1 of score (in BCD)
- * 24               Byte 2 of score (in BCD)
- * 25               MSB of score (in BCD)
- * 26               Unused
- *
- * So, assuming the capacity of the table is N, the first N bytes form an index which is used to locate
- * items in the remaining N*8 bytes that follow. This is done so that inserting a new entry only involves
- * overwriting one name/score record and updating the index. You don't have to re-write all the records
- * that move down the table to make room for the new one.
- *
- */
-
-#include "HighScoreTable.h"
-
-/***************/
-/* CONSTRUCTOR */
-/***************/
-// Pass pointer to an I2C EEPROM which contains the high scores.
-HighScoreTable::HighScoreTable( I2CEEPROM *e ) :
-    eeprom( e )
-{
-}
-
-/**************/
-/* DESTRUCTOR */
-/**************/
-HighScoreTable::~HighScoreTable() {
-}
-
-/****************************************/
-/* VALIDATE EEPROM USED FOR HIGH SCORES */
-/****************************************/
-// Checks EEPROM used for high scores and
-// if any of it looks like nonsense it
-// rewrites the whole table with defaults.
-void HighScoreTable::ValidateEEPROM( void ) {
-  // Check if contents of EEPROM make sense.
-  // If not then rewrite EEPROM with defaults.
-  if( ! EEPROMValid() ) {
-    WriteEEPROMDefaults();
-  }
-}
-
-/**********************************************/
-/* DETERMINE POSITION OF A SCORE IN THE TABLE */
-/**********************************************/
-// Pass score in score.
-// Returns position in table (0 is top score).
-// If position returned is >= capacity of table then score is not high
-// enough to place in table.
-UInt8 HighScoreTable::GetPositionInTable( UInt32 score ) const {
-  // Look through table for a score less than the one passed.
-  PlayerName name;
-  UInt32 tableScore = (UInt32)0;
-  for( UInt8 i = 0; i < capacity; ++i ) {
-    Get( i, &name, &tableScore );
-    if( tableScore < score ) {
-      // Found a score that is less.
-      // Return index at which it was found.
-      return i;
-    }
-  }
-  // No score found that is less than the one passed.
-  // Return capacity of table to indicate not found.
-  return capacity;
-}
-
-/*********************************/
-/* ADD ENTRY TO HIGH SCORE TABLE */
-/*********************************/
-// Pass position in table to put entry in pos.
-// Pass name of player in name.
-// Pass score in score.
-void HighScoreTable::Add( UInt8 pos, const PlayerName *name, UInt32 score ) {
-    // Read the entire index, high scores and names out of EEPROM.
-    // Going to do manipulations in RAM to minimise the number of
-    // writes we need to do to EEPROM. Remember every time we write
-    // 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 ) ) {
-        // 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 );
-            // Copy characters of name into buffer.
-            for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
-                *address++ = name->Name[ i ];
-            }
-            // Copy bytes of score into buffer.
-            *((UInt32*)address) = score;
-            address += 4;
-            // Move all entries in the index below insertion point down one
-            // to make room for new entry.
-            for( UInt8 i = capacity - 1; i > pos; --i ) {
-                buffer[ i ] = buffer[ i - 1 ];
-            }
-            // Insert index of newly written record at insertion point.
-            buffer[ pos ] = index;
-            // Write the buffer back to EEPROM.
-            eeprom->WriteBytes( eepromAddress, buffer, memoryUsed ); 
-        }
-    }
-}
-
-/****************************/
-/* GET ENTRY FROM THE TABLE */
-/****************************/
-// Pass position to fetch from in pos.
-// 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.
-  for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
-    name->Name[ i ] = (UInt8)'X';
-  }
-  name->Name[ PlayerName::Length ] = 0;
-    *score = 0;
-  // Fetch index from EEPROM.
-  UInt8 index;
-    if( ! eeprom->ReadBytes( eepromAddress + pos, &index, 1 ) ) {
-        return;
-    }
-  // Point to appropriate part of data table.
-  UInt16 address = eepromAddress + capacity + ( index << 3 );
-  // Read out characters and store in name.
-    if( ! eeprom->ReadBytes( address, (UInt8*)name->Name, PlayerName::Length ) ) {
-        return;
-    }
-  name->Name[ PlayerName::Length ] = 0;
-    address += PlayerName::Length;
-  // Read out score.
-    eeprom->ReadBytes( address, (UInt8*)score, 4 );
-}
-
-/********************************/
-/* DETERMINE IF EEPROM IS VALID */
-/********************************/
-// Returns true if EEPROM is valid.
-bool HighScoreTable::EEPROMValid( void ) {
-  UInt8 b, b2;
-  // 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.
-    if( b >= capacity ) {
-      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;
-            }
-      if( b == b2 ) {
-        return false;
-      }
-    }
-  }
-  // Check all entries in the data part of the table are valid.
-  UInt16 address = eepromAddress + capacity;
-  for( UInt8 i = 0; i < capacity; ++i ) {
-    // 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;
-            }
-      if( ( b < PlayerName::MinChar ) || ( b > PlayerName::MaxChar ) ) {
-        return false;
-      }
-    }
-    // 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;
-            }
-      if( ( ( b & 0x0F ) > 0x09 ) || ( ( b & 0xF0 ) > 0x90 ) ) {
-        return false;
-      }
-    }
-    // Skip over unused byte.
-    address++;
-  }
-  // EEPROM is valid
-  return true;
-}
-
-/****************************/
-/* WRITE DEFAULTS TO EEPROM */
-/****************************/
-// This may take a second or two to execute!
-void HighScoreTable::WriteEEPROMDefaults( void ) {
-    UInt8 buffer[ memoryUsed ];
-  // Write index with ascending integers.
-    UInt8 *ptr = buffer;
-  for( UInt8 i = 0; i < capacity; ++i ) {
-    *ptr++ =  i;
-  }
-  // Write data table with zero score entries.  
-  for( UInt8 i = 0; i < capacity; ++i ) {
-    // Write a name of "AAA".
-    for( UInt8 j = 0; j < PlayerName::Length; ++j ) {
-            *ptr++ = (UInt8)'A';
-    }
-        // 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 ); 
+/*
+ * SOURCE FILE : HighScoreTable.cpp
+ *
+ * Definition of class HighScoreTable.
+ * Maintains a table of high scores with a name and a score for each entry in the table.
+ *
+ * The table is stored in EEPROM at an address specified when you call the constructor.
+ * The table is structured as follows. This shows a table with a capacity of 3.
+ *
+ * Byte offset      Usage
+ * -----------      -----
+ * 0                Index of highest score in data that follows
+ * 1                Index of second highest score in data that follows
+ * 2                Index of third highest score in data that follows
+ *
+ * 3                First character of player's name
+ * 4                Second character of player's name
+ * 5                Third character of player's name
+ * 6                LSB of score (in BCD)
+ * 7                Byte 1 of score (in BCD)
+ * 8                Byte 2 of score (in BCD)
+ * 9                MSB of score (in BCD)
+ * 10               Unused
+ *
+ * 11               First character of player's name
+ * 12               Second character of player's name
+ * 13               Third character of player's name
+ * 14               LSB of score (in BCD)
+ * 15               Byte 1 of score (in BCD)
+ * 16               Byte 2 of score (in BCD)
+ * 17               MSB of score (in BCD)
+ * 18               Unused
+ *
+ * 19               First character of player's name
+ * 20               Second character of player's name
+ * 21               Third character of player's name
+ * 22               LSB of score (in BCD)
+ * 23               Byte 1 of score (in BCD)
+ * 24               Byte 2 of score (in BCD)
+ * 25               MSB of score (in BCD)
+ * 26               Unused
+ *
+ * So, assuming the capacity of the table is N, the first N bytes form an index which is used to locate
+ * items in the remaining N*8 bytes that follow. This is done so that inserting a new entry only involves
+ * overwriting one name/score record and updating the index. You don't have to re-write all the records
+ * that move down the table to make room for the new one.
+ *
+ */
+
+#include "HighScoreTable.h"
+
+/***************/
+/* CONSTRUCTOR */
+/***************/
+// Pass pointer to an SPI EEPROM which contains the high scores.
+HighScoreTable::HighScoreTable( SPIEEPROM *e ) :
+    eeprom( e )
+{
+}
+
+/**************/
+/* DESTRUCTOR */
+/**************/
+HighScoreTable::~HighScoreTable() {
+}
+
+/****************************************/
+/* VALIDATE EEPROM USED FOR HIGH SCORES */
+/****************************************/
+// Checks EEPROM used for high scores and
+// if any of it looks like nonsense it
+// rewrites the whole table with defaults.
+void HighScoreTable::ValidateEEPROM( void ) {
+  // Check if contents of EEPROM make sense.
+  // If not then rewrite EEPROM with defaults.
+  if( ! EEPROMValid() ) {
+    WriteEEPROMDefaults();
+  }
+}
+
+/**********************************************/
+/* DETERMINE POSITION OF A SCORE IN THE TABLE */
+/**********************************************/
+// Pass score in score.
+// Returns position in table (0 is top score).
+// If position returned is >= capacity of table then score is not high
+// enough to place in table.
+UInt8 HighScoreTable::GetPositionInTable( UInt32 score ) const {
+  // Look through table for a score less than the one passed.
+  PlayerName name;
+  UInt32 tableScore = (UInt32)0;
+  for( UInt8 i = 0; i < capacity; ++i ) {
+    Get( i, &name, &tableScore );
+    if( tableScore < score ) {
+      // Found a score that is less.
+      // Return index at which it was found.
+      return i;
+    }
+  }
+  // No score found that is less than the one passed.
+  // Return capacity of table to indicate not found.
+  return capacity;
 }
+
+/*********************************/
+/* ADD ENTRY TO HIGH SCORE TABLE */
+/*********************************/
+// Pass position in table to put entry in pos.
+// Pass name of player in name.
+// Pass score in score.
+void HighScoreTable::Add( UInt8 pos, const PlayerName *name, UInt32 score ) {
+    // Read the entire index, high scores and names out of EEPROM.
+    // Going to do manipulations in RAM to minimise the number of
+    // writes we need to do to EEPROM. Remember every time we write
+    // 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 ) ) {
+        // 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 );
+            // Copy characters of name into buffer.
+            for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
+                *address++ = name->Name[ i ];
+            }
+            // Copy bytes of score into buffer.
+            *((UInt32*)address) = score;
+            address += 4;
+            // Move all entries in the index below insertion point down one
+            // to make room for new entry.
+            for( UInt8 i = capacity - 1; i > pos; --i ) {
+                buffer[ i ] = buffer[ i - 1 ];
+            }
+            // Insert index of newly written record at insertion point.
+            buffer[ pos ] = index;
+            // Write the buffer back to EEPROM.
+            eeprom->WriteBytes( eepromAddress, buffer, memoryUsed ); 
+        }
+    }
+}
+
+/****************************/
+/* GET ENTRY FROM THE TABLE */
+/****************************/
+// Pass position to fetch from in pos.
+// 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.
+  for( UInt8 i = 0; i < PlayerName::Length; ++i ) {
+    name->Name[ i ] = (UInt8)'X';
+  }
+  name->Name[ PlayerName::Length ] = 0;
+    *score = 0;
+  // Fetch index from EEPROM.
+  UInt8 index;
+    if( ! eeprom->ReadBytes( eepromAddress + pos, &index, 1 ) ) {
+        return;
+    }
+  // Point to appropriate part of data table.
+  UInt16 address = eepromAddress + capacity + ( index << 3 );
+  // Read out characters and store in name.
+    if( ! eeprom->ReadBytes( address, (UInt8*)name->Name, PlayerName::Length ) ) {
+        return;
+    }
+  name->Name[ PlayerName::Length ] = 0;
+    address += PlayerName::Length;
+  // Read out score.
+    eeprom->ReadBytes( address, (UInt8*)score, 4 );
+}
+
+/********************************/
+/* DETERMINE IF EEPROM IS VALID */
+/********************************/
+// Returns true if EEPROM is valid.
+bool HighScoreTable::EEPROMValid( void ) {
+  UInt8 b, b2;
+  // 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.
+    if( b >= capacity ) {
+      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;
+            }
+      if( b == b2 ) {
+        return false;
+      }
+    }
+  }
+  // Check all entries in the data part of the table are valid.
+  UInt16 address = eepromAddress + capacity;
+  for( UInt8 i = 0; i < capacity; ++i ) {
+    // 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;
+            }
+      if( ( b < PlayerName::MinChar ) || ( b > PlayerName::MaxChar ) ) {
+        return false;
+      }
+    }
+    // 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;
+            }
+      if( ( ( b & 0x0F ) > 0x09 ) || ( ( b & 0xF0 ) > 0x90 ) ) {
+        return false;
+      }
+    }
+    // Skip over unused byte.
+    address++;
+  }
+  // EEPROM is valid
+  return true;
+}
+
+/****************************/
+/* WRITE DEFAULTS TO EEPROM */
+/****************************/
+// This may take a second or two to execute!
+void HighScoreTable::WriteEEPROMDefaults( void ) {
+    UInt8 buffer[ memoryUsed ];
+  // Write index with ascending integers.
+    UInt8 *ptr = buffer;
+  for( UInt8 i = 0; i < capacity; ++i ) {
+    *ptr++ =  i;
+  }
+  // Write data table with zero score entries.  
+  for( UInt8 i = 0; i < capacity; ++i ) {
+    // Write a name of "AAA".
+    for( UInt8 j = 0; j < PlayerName::Length; ++j ) {
+            *ptr++ = (UInt8)'A';
+    }
+        // 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 ); 
+}