/* ***************************************************************************** * FX gameState example v1.00 by Mr.Blinky Jan.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(uint8_t* gameState, size_t size) * * void FX::saveGameState(uint8_t* gameState, size_t size) * * 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 a pointer to an uint8_t array or to a structure in RAM containing * your game data. When using a structure for the game data, the structure must be * cast to an uint8_t array by putting (uint8_t*)& in front of the structures name. * * size is the size of the uint8_t array or structure in RAM and is usually * determined by using the sizeof() operator. * * When there is 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 and size are the same parameters as for the loadSaveData function. * * 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 #include #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((uint8_t*) &gameState, sizeof(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((uint8_t*) &gameState, sizeof(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. }