/* *****************************************************************************
 * FX gameState example v1.01 by Mr.Blinky       Jan-Feb.2023 licenced under CC0
 * *****************************************************************************
 * 
 * This is a example showing how you can save and load game data to the FX flash 
 * chip.
 * 
 * Before this example sketch is uploaded and run on the Arduboy FX, make sure 
 * the fxdata of this sketch has been built and uploaded to the Arduboy FX. 
 * 
 * If the Arduboy FX Arduino plugin has been installed you can simply choose the 
 * 'Build and upload Arduboy FX data' from the Arduino IDE Tools menu. Since the
 * data has already been prebuild for this demo you may alsu choose the 'upload
 * existing Arduboy FX data' option.
 * 
 * Alternatively the fxdata.txt script file can be build using the fxdata-build.py 
 * Python script and the fxdata.bin file can be uploaded using the 
 * fxdata-upload.py, uploader-gui.py, or flash-writer.py (using the -d switch)
 * Python scripts.
 * 
 * *****************************************************************************
 * 
 * The FX library has two functions for saving and loading game data:
 * 
 * uint8_t FX::loadGameState(Type gameState)
 * 
 * void FX::saveGameState(Type gameState)
 * 
 * loadGameState 
 * -------------
 * 
 * Loads previously saved game data. It returns 0 if there was no data to load
 * or 1 if the data was successfully loaded.
 * 
 * gameState is an object structure in RAM to where the game data will be loaded.
 * If the size of the object in ram differes from the size of previously saved 
 * data, no data will be loaded.
 * 
 * When no game data loaded (result 0), the contents of the gameState structure
 * remains unchanged.
 * 
 * saveGameState 
 * -------------
 * 
 * Saves game data into a 4K flash block that is uniquely assigned to a program. 
 * On the first save, data is saved at the beginning of the block. Any save 
 * after that will be appended after previously saved data as a simple method to 
 * reduce flash wear. Once the new data doesn't fit into the 4K block, the block 
 * is erased and the new data is stored at the beginning of the block again.
 * when an erase is necessary this function takes a bit longer to execute.
 * This process is fully transparent and you do not need to worry about it. 
 * It just explains why sometimes this function may take a bit more time then usual.
 * 
 * gameState is an object structure in RAM which will be saved to external flash memory.
 * 
 * initilizing FX chip when using save capabilities
 * ------------------------------------------------
 * 
 * To let the FX library know your sketch makes use of save data the FX library
 * must be initialized in setup with the following line:
 * 
 * FX::begin(FX_DATA_PAGE, FX_SAVE_PAGE); 
 * 
 * The FX_DATA_PAGE, FX_SAVE_PAGE defines are defined in the fxdata.h file that
 * will be created by the fxdata-build tool.
 * 
 * creating a save data block
 * --------------------------
 * 
 * In order to use the loadGameState and saveGameState functions, a save section
 * must be added to the fxdata.txt file located in the fxdata folder in your
 * sketch folder. this save section can be added by typing the word 'savesection'
 * (without the quotes)on a line  at the end of the fxdata.txt file.
 * Any data defined after that will be written into the default save data file.

 * A minimum blank save data file can be generated by adding just two lines:
 * 
 *      savesection
 *      uint16_t 0xFFFF // No saved game state / end of game state
 *      
 * Example of a predefined save data with 5 high scores:
 * 
 *      savesection
 *      uint16_t 30     //size of save data excluding length bytes
 *      uint16_t 50000  //high scores
 *      string "KVN"
 *      uint16_t 40000      
 *      string "MRB"
 *      uint16_t 30000
 *      string "FLM"
 *      uint16_t 20000      
 *      string "VMP"
 *      uint16_t 10000      
 *      string "ADB"
 *      uint16_t 0xFFFF //end of save data / beginning of free space
 *                      //not included in the save data length
 * 
 * when there is a savesection in a fxdata.txt file, the fxbuild.by tool will 
 * generate 3 files:
 * 
 *  fxdata.bin        this file is uploaded during development, when uploading
 *                    a sketch through the Arduino IDE or using a emulator. 
 *                    It contains both the data and save sections.
 *                    
 *  fxdata-data.bin   contains only the data. This file is used when the sketch
 *                    hexfile is made part of a flash image file.
 *  fxdata-save.bin   contains only the save data. This file is used when the 
 *                    sketch hexfile is made part of a flash image file.
 * 
  ******************************************************************************/
  
#include <Arduboy2.h>
#include <ArduboyFX.h>
#include "fxdata/fxdata.h" //created by the fxdata-build.py python script.

Arduboy2 arduboy;

// First we create a structure that will contain all the relevant game data that
// needs to be saved.

struct GameState
{
  char     name[20]; // space for a text string
  uint16_t count;    // A counter that counts the number of times this sketch was
};                   // run (and saved data)

GameState gameState; // This creates the actual gameState in ram.

void setup() {
  arduboy.begin(); // initialize Arduboy.
  
  FX::begin(FX_DATA_PAGE, FX_SAVE_PAGE);  // Initialize FX chip. When using FX save data,
                                          // FX_SAVE_PAGE must also be passed on in FX::begin.

  if (!FX::loadGameState(gameState)) // Load saveState from the 4K FX save data block. '(uint8_t*) &' is used 
                                     // here to cast a uint8_t pointer to the saveState structure. 
  {
    // This code gets executed only when the function didn't load a saveState (function returned 0)
    strcpy(gameState.name, "Hello World !!!"); // copy some introductory text to saveState.name
    gameState.count = 1; // set count to 1 for 1st time this sketch is run.
  }
  else
  { 
    // A previously saved gameState was loaded.
    strcpy(gameState.name, "Save state loaded"); // change text
    gameState.count ++;                          // increase the number of times this sketch was run.
  }
  
  FX::saveGameState(gameState); //Save the game state to 4K FX save block
  
  arduboy.clear();
  arduboy.setCursor(0,32 - 8);
  arduboy.print(gameState.name);
  arduboy.setCursor(0,32 + 8);
  arduboy.print("Number of times this\nsketch is run: ");
  arduboy.print(gameState.count);
  FX::display();
}

void loop() {
  
  if (!arduboy.nextFrame()) return; //waint for next frame
  
  if (arduboy.buttonsState()) arduboy.exitToBootloader(); // exit to bootloader.
  
}
