PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)
Dependents: YATTT sd_map_test cPong SnowDemo ... more
PokittoLib
Library for programming Pokitto hardware
How to Use
- Import this library to online compiler (see button "import" on the right hand side
- DO NOT import mbed-src anymore, a better version is now included inside PokittoLib
- Change My_settings.h according to your project
- Start coding!
Diff: POKITTO_CORE/PokittoCookie.cpp
- Revision:
- 51:113b1d84c34f
- Child:
- 58:5f58a2846a20
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/POKITTO_CORE/PokittoCookie.cpp Sun Jul 01 06:32:10 2018 +0000 @@ -0,0 +1,362 @@ +/**************************************************************************/ +/*! + @file PokittoCookie.cpp + @author Jonne Valola + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Jonne Valola + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "Pokitto_settings.h" +#include "Pokitto.h" +#include "PokittoCookie.h" + +#ifndef POK_SIM +#else +#include "PokittoSimulator.h" +#endif + +using namespace Pokitto; + +//char Cookie::_key[SBKEYSIZE]; +//char Cookie::_keyorder; +//bool Cookie::_status; + +#define HARDCODEDOFFSET 25 //bypasses Cookie parent instance general data (that does not need to be saved in EEPROM) + +Cookie::Cookie() { + _status = false; + _keyorder = SBINVALIDSLOT; +} + +int Cookie::initialize() { + //initialize is called from begin() and can be called several times during program run + int datasize = _datasize; + // check if key already exists + _keyorder = exists(_key); + if (_keyorder < SBMAXKEYS) { + // key already exists + // check amount of existing storage reserved for cookie + datasize -= getAssignedBlocks()*SBBLOCKSIZE; + if (datasize<=0) { + // the size of data matches the size requested + // therefore retrieve data from storage + _status = true; //were good to go + loadCookie(); + } else { + // if that does not cover the whole size (maybe a newer version of program, who knows) + // then do not load but reserve more blocks and store a new version + while (datasize>0) { + if(reserveBlock()) datasize -= SBBLOCKSIZE; + else return SBNOTENOUGHBLOCKSFREE; //no space to allocate + } + _status = true; //were good to go + eraseKeytableEntry(_keyorder); + writeKeyToKeytable(_key,_keyorder); // write the key in the key table in EEPROM + saveCookie(); + } + } else { + // new key needed + // check if we have free keyslots + _keyorder = getFreeKeytableSlot(); + if (_keyorder>=SBMAXKEYS) return SBNOMOREKEYS; //no space for key + // check if we have free storage blocks + if (getFreeBlocks()*SBBLOCKSIZE<datasize) return SBNOTENOUGHBLOCKSFREE; //no space to allocate + while (datasize>0) { + //reserve enough blocks for the data until all data can fit + if(reserveBlock()) datasize -= SBBLOCKSIZE; + else return SBNOTENOUGHBLOCKSFREE; //no space to allocate + } + } + _status = true; //were good to go + eraseKeytableEntry(_keyorder); + writeKeyToKeytable(_key,_keyorder); // write the key in the key table in EEPROM + return 0; +} + +int Cookie::begin(const char* idkey, int datasize, char* ptr) { + _status=false; + _datasize=datasize-HARDCODEDOFFSET;// warning! hardcoded! sizeof(this); //do not include the data of the parent Cookie instance + _pointer = ptr + HARDCODEDOFFSET;// warning! hardcoded! sizeof(this); //point to the beginning of the inherited instance + char _idkey[8]; + // make _idkey exactly 8 readable characters long + for (int t = 0 ; t < 8 ; t++) _idkey[t]=' '; + for (int t = 0 ; t < 8 ; t++) {if (idkey[t]==0) break; _idkey[t]=idkey[t];} + // clean Keytable of keys with no storage + cleanKeytable(); + memcpy(_key, _idkey, SBKEYSIZE); //store name of key + initialize(); + return 0; //success +} + +bool Cookie::saveCookie() { + if (!_status || !_pointer) initialize(); //reinitialize if needed + if (!_status || !_pointer) return false; //return if initialize still failed + char* p = _pointer; + _head=0; + _block=0; + _block=findMyNextBlock(); + for (int i=0; i<_datasize; i++) writeQueue(*p++); +} + +bool Cookie::loadCookie() { + if (!_status || !_pointer) return false; + char* p = _pointer; + _head=0; + _block=0; + _block=findMyNextBlock(); + for (int i=0; i<_datasize; i++) *p++ = readQueue(); +} + +void Cookie::deleteCookie() { + if (!_status) return; + // free all blocks held by Cookie + for (int i=0; i<SBMAXBLOCKS; i++) { + if (isMyBlock(i)) freeBlock(i); + } + // erase Cookie entry from keytable + eraseKeytableEntry(_keyorder); + // set status to deleted + _status = false; +} + +int Cookie::exists(const char* idkey) { + for (int i=0; i< SBMAXKEYS; i++) { + #ifndef POK_SIM + if(eeprom_read_byte((uint16_t*)(i*SBKEYSIZE))==idkey[0]) { + int total=0; + for (int j=0; j<SBKEYSIZE;j++) { + if(eeprom_read_byte((uint16_t*)(i*SBKEYSIZE+j))==idkey[j]) total++; + } + if (total==SBKEYSIZE) return i; // return the keyslot number where key exists + } + #endif + } + return SBINVALIDSLOT; //not found +} + +int Cookie::getFreeKeytableSlot() { + int freeslot=SBINVALIDSLOT; + for (int i=0; i<SBMAXKEYS; i++) { + #ifndef POK_SIM + if (eeprom_read_byte((uint16_t*)(i*SBKEYSIZE))==0) {freeslot=i; break;} + #endif + } + return freeslot; +} + +int Cookie::getAssignedBlocks() { + int assignedblocks=0; + for (int i=0;i<SBMAXBLOCKS;i++) { + if (isMyBlock(i)) assignedblocks++; + } + return assignedblocks; +} + +int Cookie::getFreeBlocks() { + int freeblocks=0; + for (int i=0;i<SBMAXBLOCKS;i++) { + if (isFreeBlock(i)) freeblocks++; + } + return freeblocks; +} + +bool Cookie::isFreeBlock(int n) { + if (n>=SBMAXBLOCKS) return false; + #ifndef POK_SIM + if (!(eeprom_read_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+n))&0x80)) return true; //highest bit 0, its free + #endif + return false; //its not free +} + +bool Cookie::isMyBlock(int n) { + if (n>=SBMAXBLOCKS) return false; + if (isFreeBlock(n)) return false; //"free" blocks can not be "reserved" at the same time! + #ifndef POK_SIM + char temp; int address; + address = (SBMAXKEYS*SBKEYSIZE+n); + temp = eeprom_read_byte((uint16_t*)address); + if ((temp&0x7F) ==_keyorder) return true; + #endif + return false; //its not your block +} + +bool Cookie::blockIsOwnedBy(int n, int k) { + if (n>=SBMAXBLOCKS) return false; + if (k>=SBMAXKEYS) return false; + if (isFreeBlock(n)) return false; //"free" blocks can not be "owned" by anyone + #ifndef POK_SIM + char temp; int address; + address = (SBMAXKEYS*SBKEYSIZE+n); + temp = eeprom_read_byte((uint16_t*)address); + if ((temp&0x7F) == k) return true; + #endif + return false; //its not your block +} + +void Cookie::writeKeyToKeytable(const char* key, int slot) { + for (int i=0; i<SBKEYSIZE; i++) { + #ifndef POK_SIM + if (key[i]) eeprom_write_byte((uint16_t*)(slot*SBKEYSIZE+i),key[i]); + else eeprom_write_byte((uint16_t*)(slot*SBKEYSIZE+i),0); + #endif + } +} + +void Cookie::readKeytableEntry(int n, char* answer) { + answer[8]=0; + if (n >= SBMAXKEYS) n=SBMAXKEYS-1; + for (int i=0; i<SBKEYSIZE; i++) { + #ifndef POK_SIM + answer[i] = eeprom_read_byte((uint16_t*)(n*SBKEYSIZE+i)); + #endif + } +} + +char Cookie::getBlockTableEntry(int n) { + if (n>=SBMAXBLOCKS) return 0x80; // out of bounds will return a reserved block marker + #ifndef POK_SIM + return eeprom_read_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+n)); + #endif + return 0x80; +} + +void Cookie::readBlock(int n, char* data) { + for (int i=0; i<SBBLOCKSIZE; i++) { + data[i]=0; + #ifndef POK_SIM + if (n < SBMAXBLOCKS) data[i] = eeprom_read_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+SBMAXBLOCKS+n*SBBLOCKSIZE+i)); + #endif + } +} + +void Cookie::formatKeytable() { + for (int j=0; j<SBMAXKEYS; j++) { + for (int i=0; i<SBKEYSIZE; i++) { + #ifndef POK_SIM + eeprom_write_byte((uint16_t*)(j*SBKEYSIZE+i),0); + #endif + } + } +} + +void Cookie::freeBlock(int n) { + if (n >= SBMAXBLOCKS) return; //out of bounds + #ifndef POK_SIM + // delete entry from blocktable + eeprom_write_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+n),0); + #endif + for (int i=0; i<SBBLOCKSIZE;i++) { + #ifndef POK_SIM + // wipe data in the block + eeprom_write_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+SBMAXBLOCKS+n*SBBLOCKSIZE+i),0); + #endif + } +} + +bool Cookie::reserveBlock() { + for (int i=0; i<SBMAXBLOCKS;i++) { + #ifndef POK_SIM + // reserve block from blocktable + if (isFreeBlock(i)) { + //free block found, mark it for us in the blocktable + eeprom_write_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+i),_keyorder | 0x80); + return true; + } + #endif + } + return false; // no free block found +} + +void Cookie::eraseKeytableEntry(int n) { + if (n >= SBMAXKEYS) n=SBMAXKEYS-1; + for (int i=0; i<SBKEYSIZE; i++) { + #ifndef POK_SIM + eeprom_write_byte((uint16_t*)(n*SBKEYSIZE+i),0); + #endif + } +} + +void Cookie::cleanKeytable() { + //Remove any keys without blocks + for (int entry=0; entry<SBMAXKEYS; entry++) { + if (eeprom_read_byte((uint16_t*)(entry*SBKEYSIZE))) { + bool isEmpty=true; + for (int block=0; block<SBMAXBLOCKS; block++) if (blockIsOwnedBy(block,entry)) {isEmpty=false;break;} + //this entry has no blocks reserved, so lets clean it from the keytable + if (isEmpty) eraseKeytableEntry(entry); + } + } + for (int block=0;block<SBMAXBLOCKS;block++) { + int blockentry = eeprom_read_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+block)); + if (blockentry&0x80) { + blockentry &= 0x7F; + bool isEmpty=true; + for (int key=0;key<SBMAXKEYS;key++) { + if (eeprom_read_byte((uint16_t*)(key*SBKEYSIZE))) {isEmpty=false;break;} + } + if (isEmpty) eeprom_write_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+block),0); + } + } +} + +char Cookie::readQueue() { + char data=0; + #ifndef POK_SIM + int address; + address = SBMAXKEYS*SBKEYSIZE+SBMAXBLOCKS+SBBLOCKSIZE*_block+_head%SBBLOCKSIZE; + data=eeprom_read_byte((uint16_t*)address); + #endif + _head++; + if (_head%SBBLOCKSIZE==0 && _head) { + _block++; + _block=findMyNextBlock(); + } + return data; +} + +void Cookie::writeQueue(char data) { + #ifndef POK_SIM + eeprom_write_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+SBMAXBLOCKS+SBBLOCKSIZE*_block+_head%SBBLOCKSIZE),data); + #endif + _head++; + if (_head%SBBLOCKSIZE==0 && _head) { + _block++; + _block=findMyNextBlock(); + } +} + +int Cookie::findMyNextBlock() { + if (!_status) return SBINVALIDBLOCK; + for (int i=_block; i<SBMAXBLOCKS;i++) if (isMyBlock(i)) return i; +} + + +