PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)

Dependents:   YATTT sd_map_test cPong SnowDemo ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PokittoCookie.cpp Source File

PokittoCookie.cpp

Go to the documentation of this file.
00001 /**************************************************************************/
00002 /*!
00003     @file     PokittoCookie.cpp
00004     @author   Jonne Valola
00005 
00006     @section LICENSE
00007 
00008     Software License Agreement (BSD License)
00009 
00010     Copyright (c) 2018, Jonne Valola
00011     All rights reserved.
00012 
00013     Redistribution and use in source and binary forms, with or without
00014     modification, are permitted provided that the following conditions are met:
00015     1. Redistributions of source code must retain the above copyright
00016     notice, this list of conditions and the following disclaimer.
00017     2. Redistributions in binary form must reproduce the above copyright
00018     notice, this list of conditions and the following disclaimer in the
00019     documentation and/or other materials provided with the distribution.
00020     3. Neither the name of the copyright holders nor the
00021     names of its contributors may be used to endorse or promote products
00022     derived from this software without specific prior written permission.
00023 
00024     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
00025     EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00026     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
00028     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00033     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 */
00035 /**************************************************************************/
00036 
00037 #include "Pokitto_settings.h "
00038 #include "Pokitto.h "
00039 #include "PokittoCookie.h "
00040 
00041 #ifndef POK_SIM
00042 #else
00043 #include "PokittoSimulator.h"
00044 #endif
00045 
00046 using namespace Pokitto;
00047 
00048 //char Cookie::_key[SBKEYSIZE];
00049 //char Cookie::_keyorder;
00050 //bool Cookie::_status;
00051 
00052 #define HARDCODEDOFFSET 25 //bypasses Cookie parent instance general data (that does not need to be saved in EEPROM)
00053 
00054 Cookie::Cookie() {
00055     _status = false;
00056     _keyorder = SBINVALIDSLOT;
00057 }
00058 
00059 int Cookie::initialize() {
00060     //initialize is called from begin() and can be called several times during program run
00061     int datasize = _datasize;
00062     // check if key already exists
00063     _keyorder = exists(_key);
00064     if (_keyorder < SBMAXKEYS) {
00065             // key already exists
00066             // check amount of existing storage reserved for cookie
00067             datasize -= getAssignedBlocks()*SBBLOCKSIZE;
00068             if (datasize<=0) {
00069                 // the size of data matches the size requested
00070                 // therefore retrieve data from storage
00071                 _status = true; //were good to go
00072                 loadCookie();
00073             } else {
00074             // if that does not cover the whole size (maybe a newer version of program, who knows)
00075             // then do not load but reserve more blocks and store a new version
00076                 while (datasize>0) {
00077                     if(reserveBlock()) datasize -= SBBLOCKSIZE;
00078                     else return SBNOTENOUGHBLOCKSFREE; //no space to allocate
00079                 }
00080                 _status = true; //were good to go
00081                 eraseKeytableEntry(_keyorder);
00082                 writeKeyToKeytable(_key,_keyorder); // write the key in the key table in EEPROM
00083                 saveCookie();
00084             }
00085     } else {
00086             // new key needed
00087             // check if we have free keyslots
00088             _keyorder = getFreeKeytableSlot();
00089             if (_keyorder>=SBMAXKEYS) return SBNOMOREKEYS; //no space for key
00090             // check if we have free storage blocks
00091             if (getFreeBlocks()*SBBLOCKSIZE<datasize) return SBNOTENOUGHBLOCKSFREE; //no space to allocate
00092             while (datasize>0) {
00093                 //reserve enough blocks for the data until all data can fit
00094                 if(reserveBlock()) datasize -= SBBLOCKSIZE;
00095                 else return SBNOTENOUGHBLOCKSFREE; //no space to allocate
00096             }
00097     }
00098     _status = true; //were good to go
00099     eraseKeytableEntry(_keyorder);
00100     writeKeyToKeytable(_key,_keyorder); // write the key in the key table in EEPROM
00101     return 0;
00102 }
00103 
00104 int Cookie::begin(const char* idkey, int datasize, char* ptr) {
00105     _status=false;
00106     _datasize=datasize-HARDCODEDOFFSET;// warning! hardcoded! sizeof(this); //do not include the data of the parent Cookie instance
00107     _pointer = ptr + HARDCODEDOFFSET;// warning! hardcoded! sizeof(this); //point to the beginning of the inherited instance
00108     char _idkey[8];
00109     // make _idkey exactly 8 readable characters long
00110     for (int t = 0 ; t < 8 ; t++) _idkey[t]=' ';
00111     for (int t = 0 ; t < 8 ; t++) {if (idkey[t]==0) break; _idkey[t]=idkey[t];}
00112     // clean Keytable of keys with no storage
00113     cleanKeytable();
00114     memcpy(_key, _idkey, SBKEYSIZE); //store name of key
00115     initialize();
00116     return 0; //success
00117 }
00118 
00119 bool Cookie::saveCookie() {
00120     if (!_status || !_pointer) return false; //return if not initialized
00121     char* p = _pointer;
00122     _head=0;
00123     _block=0;
00124     _block=findMyNextBlock();
00125     for (int i=0; i<_datasize; i++) writeQueue(*p++);
00126     #if POK_ENABLE_SOUND
00127     Pokitto::soundInit(true); //re-init sound
00128     #endif
00129     return true;
00130 }
00131 
00132 bool Cookie::loadCookie() {
00133     if (!_status || !_pointer) return false;
00134     char* p = _pointer;
00135     _head=0;
00136     _block=0;
00137     _block=findMyNextBlock();
00138     for (int i=0; i<_datasize; i++) *p++ = readQueue();
00139     return true;
00140 }
00141 
00142 void Cookie::deleteCookie() {
00143     if (!_status) return;
00144     // free all blocks held by Cookie
00145     for (int i=0; i<SBMAXBLOCKS; i++) {
00146             if (isMyBlock(i)) freeBlock(i);
00147     }
00148     // erase Cookie entry from keytable
00149     eraseKeytableEntry(_keyorder);
00150     // set status to deleted
00151     _status = false;
00152 }
00153 
00154 int Cookie::exists(const char* idkey) {
00155     for (int i=0; i< SBMAXKEYS; i++) {
00156 
00157             if(eeprom_read_byte((uint16_t*)(i*SBKEYSIZE))==idkey[0]) {
00158                     int total=0;
00159                     for (int j=0; j<SBKEYSIZE;j++) {
00160                         if(eeprom_read_byte((uint16_t*)(i*SBKEYSIZE+j))==idkey[j]) total++;
00161                     }
00162                     if (total==SBKEYSIZE) return i; // return the keyslot number where key exists
00163             }
00164 
00165     }
00166     return SBINVALIDSLOT; //not found
00167 }
00168 
00169 int Cookie::getFreeKeytableSlot() {
00170     int freeslot=SBINVALIDSLOT;
00171     for (int i=0; i<SBMAXKEYS; i++) {
00172 
00173     if (eeprom_read_byte((uint16_t*)(i*SBKEYSIZE))==0) {freeslot=i; break;}
00174 
00175     }
00176     return freeslot;
00177 }
00178 
00179 int Cookie::getAssignedBlocks() {
00180     int assignedblocks=0;
00181     for (int i=0;i<SBMAXBLOCKS;i++) {
00182         if (isMyBlock(i)) assignedblocks++;
00183     }
00184     return assignedblocks;
00185 }
00186 
00187 int Cookie::getFreeBlocks() {
00188     int freeblocks=0;
00189     for (int i=0;i<SBMAXBLOCKS;i++) {
00190         if (isFreeBlock(i)) freeblocks++;
00191     }
00192     return freeblocks;
00193 }
00194 
00195 bool Cookie::isFreeBlock(int n) {
00196     if (n>=SBMAXBLOCKS) return false;
00197 
00198     if (!(eeprom_read_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+n))&0x80)) return true; //highest bit 0, its free
00199 
00200     return false; //its not free
00201 }
00202 
00203 bool Cookie::isMyBlock(int n) {
00204     if (n>=SBMAXBLOCKS) return false;
00205     if (isFreeBlock(n)) return false; //"free" blocks can not be "reserved" at the same time!
00206 
00207     char temp; int address;
00208     address = (SBMAXKEYS*SBKEYSIZE+n);
00209     temp = eeprom_read_byte((uint16_t*)address);
00210     if ((temp&0x7F) ==_keyorder) return true;
00211 
00212     return false; //its not your block
00213 }
00214 
00215 bool Cookie::blockIsOwnedBy(int n, int k) {
00216     if (n>=SBMAXBLOCKS) return false;
00217     if (k>=SBMAXKEYS) return false;
00218     if (isFreeBlock(n)) return false; //"free" blocks can not be "owned" by anyone
00219 
00220     char temp; int address;
00221     address = (SBMAXKEYS*SBKEYSIZE+n);
00222     temp = eeprom_read_byte((uint16_t*)address);
00223     if ((temp&0x7F) == k) return true;
00224 
00225     return false; //its not your block
00226 }
00227 
00228 void Cookie::writeKeyToKeytable(const char* key, int slot) {
00229     for (int i=0; i<SBKEYSIZE; i++) {
00230 
00231     if (key[i]) eeprom_write_byte((uint16_t*)(slot*SBKEYSIZE+i),key[i]);
00232     else eeprom_write_byte((uint16_t*)(slot*SBKEYSIZE+i),0);
00233 
00234     }
00235 }
00236 
00237 void Cookie::readKeytableEntry(int n, char* answer) {
00238     answer[8]=0;
00239     if (n >= SBMAXKEYS) n=SBMAXKEYS-1;
00240     for (int i=0; i<SBKEYSIZE; i++) {
00241 
00242         answer[i] = eeprom_read_byte((uint16_t*)(n*SBKEYSIZE+i));
00243 
00244     }
00245 }
00246 
00247 char Cookie::getBlockTableEntry(int n) {
00248     if (n>=SBMAXBLOCKS) return 0x80; // out of bounds will return a reserved block marker
00249 
00250         return eeprom_read_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+n));
00251 
00252     return 0x80;
00253 }
00254 
00255 void Cookie::readBlock(int n, char* data) {
00256     for (int i=0; i<SBBLOCKSIZE; i++) {
00257     data[i]=0;
00258 
00259         if (n < SBMAXBLOCKS) data[i] = eeprom_read_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+SBMAXBLOCKS+n*SBBLOCKSIZE+i));
00260 
00261     }
00262 }
00263 
00264 void Cookie::formatKeytable() {
00265     for (int j=0; j<SBMAXKEYS; j++) {
00266     for (int i=0; i<SBKEYSIZE; i++) {
00267 
00268         eeprom_write_byte((uint16_t*)(j*SBKEYSIZE+i),0);
00269 
00270     }
00271     }
00272 }
00273 
00274 void Cookie::freeBlock(int n) {
00275     if (n >= SBMAXBLOCKS) return; //out of bounds
00276 
00277         // delete entry from blocktable
00278         eeprom_write_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+n),0);
00279 
00280     for (int i=0; i<SBBLOCKSIZE;i++) {
00281 
00282         // wipe data in the block
00283         eeprom_write_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+SBMAXBLOCKS+n*SBBLOCKSIZE+i),0);
00284 
00285     }
00286 }
00287 
00288 bool Cookie::reserveBlock() {
00289     for (int i=0; i<SBMAXBLOCKS;i++) {
00290 
00291         // reserve block from blocktable
00292         if (isFreeBlock(i)) {
00293                 //free block found, mark it for us in the blocktable
00294                 eeprom_write_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+i),_keyorder | 0x80);
00295                 return true;
00296         }
00297 
00298     }
00299     return false; // no free block found
00300 }
00301 
00302 void Cookie::eraseKeytableEntry(int n) {
00303     if (n >= SBMAXKEYS) n=SBMAXKEYS-1;
00304     for (int i=0; i<SBKEYSIZE; i++) {
00305 
00306         eeprom_write_byte((uint16_t*)(n*SBKEYSIZE+i),0);
00307 
00308     }
00309 }
00310 
00311 void Cookie::cleanKeytable() {
00312     //Remove any keys without blocks
00313     for (int entry=0; entry<SBMAXKEYS; entry++) {
00314             if (eeprom_read_byte((uint16_t*)(entry*SBKEYSIZE))) {
00315                 bool isEmpty=true;
00316                 for (int block=0; block<SBMAXBLOCKS; block++) if (blockIsOwnedBy(block,entry)) {isEmpty=false;break;}
00317                 //this entry has no blocks reserved, so lets clean it from the keytable
00318                 if (isEmpty) eraseKeytableEntry(entry);
00319             }
00320     }
00321     for (int block=0;block<SBMAXBLOCKS;block++) {
00322             int blockentry = eeprom_read_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+block));
00323             if (blockentry&0x80) {
00324                     blockentry &= 0x7F;
00325                     bool isEmpty=true;
00326                     for (int key=0;key<SBMAXKEYS;key++) {
00327                             if (eeprom_read_byte((uint16_t*)(key*SBKEYSIZE))) {isEmpty=false;break;}
00328                     }
00329                     if (isEmpty) eeprom_write_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+block),0);
00330             }
00331     }
00332 }
00333 
00334 char Cookie::readQueue() {
00335     char data=0;
00336 
00337     int address;
00338     address = SBMAXKEYS*SBKEYSIZE+SBMAXBLOCKS+SBBLOCKSIZE*_block+_head%SBBLOCKSIZE;
00339     data=eeprom_read_byte((uint16_t*)address);
00340 
00341     _head++;
00342     if (_head%SBBLOCKSIZE==0 && _head) {
00343             _block++;
00344             _block=findMyNextBlock();
00345     }
00346     return data;
00347 }
00348 
00349 void Cookie::writeQueue(char data) {
00350 
00351     eeprom_write_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+SBMAXBLOCKS+SBBLOCKSIZE*_block+_head%SBBLOCKSIZE),data);
00352 
00353     _head++;
00354     if (_head%SBBLOCKSIZE==0 && _head) {
00355             _block++;
00356             _block=findMyNextBlock();
00357     }
00358 }
00359 
00360 int Cookie::findMyNextBlock() {
00361     if (!_status) return SBINVALIDBLOCK;
00362     for (int i=_block; i<SBMAXBLOCKS;i++) if (isMyBlock(i)) return i;
00363     return SBINVALIDBLOCK;
00364 }
00365 
00366 
00367