[Demo]PokittoCookie - game data save/load system for EEPROM


#1

Introducing Pokitto::Cookie

What is it?

Pokitto::Cookie is a way to store game data (highscores) etc. into the EEPROM in a way that makes sure you do not interfere with other programs.

What is EEPROM?

EEPROM is a small (4kB) memory inside the Pokitto chip that can be used to store small things, like highscore tables and Pokitto settings.

  • EEPROM is inside the chip and works also when there is no SD card!
  • Saving / loading a file from SD card is a different thing!

Why do we need this system?

The problem with using EEPROM is that if you have many games and apps, they can accidentally write data on top of each other. A management system ensures other apps do not interfere with your app’s data and vice versa.

How does it work?

Users can create their own Cookies which contain the stuff they want to store. When the Cookie is saved, the data is written into the EEPROM. When the program restarts, the data is retrieved automatically from the EEPROM.

Details:

  • 48 cookies maximum at a time
  • each cookie has a key of 8 characters that is stored in the keytable
  • one program can create several cookies if needed
  • each cookie reserves at least 1 block of 32 bytes
  • a cookie can extend to as many blocks as needed to store the data, but:
  • there are exactly 112 blocks available (3584 bytes of data)

The system is already working very well, some minor bugs probably will still need to be ironed out

Demo binary of the system

savehi.bin (41.3 KB)

Source code in GitHub (not yet in mbed)

Minimal usage example

#include "Pokitto.h"
#include "PokittoCookie.h"

Pokitto::Core mygame;

class mycookie : public Pokitto::Cookie {
public:
    char initials[4] = {'A','D','A',0};
    int score=10;
};

/* create instance */
mycookie highscore;

int main () {

    highscore.begin("HISCTEST",sizeof(highscore),(char*)&highscore); //initialize cookie 

    mygame.begin(); //start game, only AFTER cookie is initialized

    while (mygame.isRunning()) {

        if (mygame.update()) {
            
	    /* display the random data */
            mygame.display.setFont(font5x7);
            mygame.display.color=1;
            mygame.display.println("Highscore Cookie test\n");
            mygame.display.color=2;
            mygame.display.println("Random \"data\":\n");
            mygame.display.color=3;
            mygame.display.setFont(fontZXSpec);
            mygame.display.fontSize=2;
            mygame.display.print((const char*)highscore.initials);
            mygame.display.print(" ");
            mygame.display.println((int)highscore.score);
            mygame.display.println("\n");
            mygame.display.fontSize=1;
            mygame.display.color=1;
            mygame.display.println("\n\nPress A to generate random highscore\nand store it ");
            
	    /*generate random data on A button press*/
			
	    if (mygame.buttons.pressed(BTN_A)) {
                //generate a random, but higher new highscore
                highscore.initials[0] = random(65,90);
                highscore.initials[1] = random(65,90);
                highscore.initials[2] = random(65,90);
                highscore.score += random(10);
                strcpy(highscore.rank,playerrank[random(0,3)]);
                highscore.playtime = (long)random(0,0xFFFF)*(long)random(0,0xFFFF);
                // save new highscore
                highscore.saveCookie();
            }
            
        } //update

        } //isrunning

return 0;
		
} // main


[WIP] Arduboy2 Implementation Overhaul
#2

I’m going to propose a few changes if everyone’s happy with them.

  • Add a templated version of begin that allows numbercookie.begin("NUMBERS", numbercookie); (idiomatic C++, typesafe) instead of numbercookie.begin("NUMBERS",sizeof(numbercookie),(char*)&numbercookie); (C-style, error prone)
  • Alter the example to use this new version
  • Change the int parameter to std::size_t because sizeof actually returns std::size_t, not int Might hold out on that one because some of the logic is oriented around signed numbers and it isn’t a straightforward changeover.

The PR:


Out of interest, how is HARDCODEDOFFSET calculated?
Because it’s not equal to sizeof(Cookie) and the comments in Cookie::begin imply that it should be (i…e sizeof(this);)


#3

@Pharap Thanks, merged. Going to test this for a while and implement changes also in mbed online


#4

NOW WORKS 100% ALSO IN SIMULATOR

Pokitto EEPROM simulation is now implemented in the simulator

It creates a 4kB file called EEP.ROM in the same directory where Pokitto_sim.exe runs

This file simulates exactly how the EEPROM works, including using the PokittoCookie class

When you store data in the EEPROM, you can use a hex-editor to see what is being written in the EEPROM and where:


#5

SaveHighscore demo added to simulator

This demo will show you, on both hardware and simulator, how the SAFE PokittoCookie storage system works.

No more conflicts between games saving highscores!


#6

#Please check this video…
…because then you will see that using PokittoCookie is really, really easy


#7

I don’t know if I’m missing something but it seems to return true when loading a cookie doesn’t exist. I’d like to load default data only if no cookie is found.