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

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) initialize(); //reinitialize if needed
00121     if (!_status || !_pointer) return false; //return if initialize still failed
00122     char* p = _pointer;
00123     _head=0;
00124     _block=0;
00125     _block=findMyNextBlock();
00126     for (int i=0; i<_datasize; i++) writeQueue(*p++);
00127     return true;
00128 }
00129 
00130 bool Cookie::loadCookie() {
00131     if (!_status || !_pointer) return false;
00132     char* p = _pointer;
00133     _head=0;
00134     _block=0;
00135     _block=findMyNextBlock();
00136     for (int i=0; i<_datasize; i++) *p++ = readQueue();
00137     return true;
00138 }
00139 
00140 void Cookie::deleteCookie() {
00141     if (!_status) return;
00142     // free all blocks held by Cookie
00143     for (int i=0; i<SBMAXBLOCKS; i++) {
00144             if (isMyBlock(i)) freeBlock(i);
00145     }
00146     // erase Cookie entry from keytable
00147     eraseKeytableEntry(_keyorder);
00148     // set status to deleted
00149     _status = false;
00150 }
00151 
00152 int Cookie::exists(const char* idkey) {
00153     for (int i=0; i< SBMAXKEYS; i++) {
00154         #ifndef POK_SIM
00155             if(eeprom_read_byte((uint16_t*)(i*SBKEYSIZE))==idkey[0]) {
00156                     int total=0;
00157                     for (int j=0; j<SBKEYSIZE;j++) {
00158                         if(eeprom_read_byte((uint16_t*)(i*SBKEYSIZE+j))==idkey[j]) total++;
00159                     }
00160                     if (total==SBKEYSIZE) return i; // return the keyslot number where key exists
00161             }
00162         #endif
00163     }
00164     return SBINVALIDSLOT; //not found
00165 }
00166 
00167 int Cookie::getFreeKeytableSlot() {
00168     int freeslot=SBINVALIDSLOT;
00169     for (int i=0; i<SBMAXKEYS; i++) {
00170     #ifndef POK_SIM
00171     if (eeprom_read_byte((uint16_t*)(i*SBKEYSIZE))==0) {freeslot=i; break;}
00172     #endif
00173     }
00174     return freeslot;
00175 }
00176 
00177 int Cookie::getAssignedBlocks() {
00178     int assignedblocks=0;
00179     for (int i=0;i<SBMAXBLOCKS;i++) {
00180         if (isMyBlock(i)) assignedblocks++;
00181     }
00182     return assignedblocks;
00183 }
00184 
00185 int Cookie::getFreeBlocks() {
00186     int freeblocks=0;
00187     for (int i=0;i<SBMAXBLOCKS;i++) {
00188         if (isFreeBlock(i)) freeblocks++;
00189     }
00190     return freeblocks;
00191 }
00192 
00193 bool Cookie::isFreeBlock(int n) {
00194     if (n>=SBMAXBLOCKS) return false;
00195     #ifndef POK_SIM
00196     if (!(eeprom_read_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+n))&0x80)) return true; //highest bit 0, its free
00197     #endif
00198     return false; //its not free
00199 }
00200 
00201 bool Cookie::isMyBlock(int n) {
00202     if (n>=SBMAXBLOCKS) return false;
00203     if (isFreeBlock(n)) return false; //"free" blocks can not be "reserved" at the same time!
00204     #ifndef POK_SIM
00205     char temp; int address;
00206     address = (SBMAXKEYS*SBKEYSIZE+n);
00207     temp = eeprom_read_byte((uint16_t*)address);
00208     if ((temp&0x7F) ==_keyorder) return true;
00209     #endif
00210     return false; //its not your block
00211 }
00212 
00213 bool Cookie::blockIsOwnedBy(int n, int k) {
00214     if (n>=SBMAXBLOCKS) return false;
00215     if (k>=SBMAXKEYS) return false;
00216     if (isFreeBlock(n)) return false; //"free" blocks can not be "owned" by anyone
00217     #ifndef POK_SIM
00218     char temp; int address;
00219     address = (SBMAXKEYS*SBKEYSIZE+n);
00220     temp = eeprom_read_byte((uint16_t*)address);
00221     if ((temp&0x7F) == k) return true;
00222     #endif
00223     return false; //its not your block
00224 }
00225 
00226 void Cookie::writeKeyToKeytable(const char* key, int slot) {
00227     for (int i=0; i<SBKEYSIZE; i++) {
00228     #ifndef POK_SIM
00229     if (key[i]) eeprom_write_byte((uint16_t*)(slot*SBKEYSIZE+i),key[i]);
00230     else eeprom_write_byte((uint16_t*)(slot*SBKEYSIZE+i),0);
00231     #endif
00232     }
00233 }
00234 
00235 void Cookie::readKeytableEntry(int n, char* answer) {
00236     answer[8]=0;
00237     if (n >= SBMAXKEYS) n=SBMAXKEYS-1;
00238     for (int i=0; i<SBKEYSIZE; i++) {
00239         #ifndef POK_SIM
00240         answer[i] = eeprom_read_byte((uint16_t*)(n*SBKEYSIZE+i));
00241         #endif
00242     }
00243 }
00244 
00245 char Cookie::getBlockTableEntry(int n) {
00246     if (n>=SBMAXBLOCKS) return 0x80; // out of bounds will return a reserved block marker
00247     #ifndef POK_SIM
00248         return eeprom_read_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+n));
00249     #endif
00250     //return 0x80;
00251 }
00252 
00253 void Cookie::readBlock(int n, char* data) {
00254     for (int i=0; i<SBBLOCKSIZE; i++) {
00255     data[i]=0;
00256     #ifndef POK_SIM
00257         if (n < SBMAXBLOCKS) data[i] = eeprom_read_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+SBMAXBLOCKS+n*SBBLOCKSIZE+i));
00258     #endif
00259     }
00260 }
00261 
00262 void Cookie::formatKeytable() {
00263     for (int j=0; j<SBMAXKEYS; j++) {
00264     for (int i=0; i<SBKEYSIZE; i++) {
00265         #ifndef POK_SIM
00266         eeprom_write_byte((uint16_t*)(j*SBKEYSIZE+i),0);
00267         #endif
00268     }
00269     }
00270 }
00271 
00272 void Cookie::freeBlock(int n) {
00273     if (n >= SBMAXBLOCKS) return; //out of bounds
00274     #ifndef POK_SIM
00275         // delete entry from blocktable
00276         eeprom_write_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+n),0);
00277     #endif
00278     for (int i=0; i<SBBLOCKSIZE;i++) {
00279     #ifndef POK_SIM
00280         // wipe data in the block
00281         eeprom_write_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+SBMAXBLOCKS+n*SBBLOCKSIZE+i),0);
00282     #endif
00283     }
00284 }
00285 
00286 bool Cookie::reserveBlock() {
00287     for (int i=0; i<SBMAXBLOCKS;i++) {
00288     #ifndef POK_SIM
00289         // reserve block from blocktable
00290         if (isFreeBlock(i)) {
00291                 //free block found, mark it for us in the blocktable
00292                 eeprom_write_byte((uint16_t*)(SBKEYSIZE*SBMAXKEYS+i),_keyorder | 0x80);
00293                 return true;
00294         }
00295     #endif
00296     }
00297     return false; // no free block found
00298 }
00299 
00300 void Cookie::eraseKeytableEntry(int n) {
00301     if (n >= SBMAXKEYS) n=SBMAXKEYS-1;
00302     for (int i=0; i<SBKEYSIZE; i++) {
00303         #ifndef POK_SIM
00304         eeprom_write_byte((uint16_t*)(n*SBKEYSIZE+i),0);
00305         #endif
00306     }
00307 }
00308 
00309 void Cookie::cleanKeytable() {
00310     //Remove any keys without blocks
00311     for (int entry=0; entry<SBMAXKEYS; entry++) {
00312             if (eeprom_read_byte((uint16_t*)(entry*SBKEYSIZE))) {
00313                 bool isEmpty=true;
00314                 for (int block=0; block<SBMAXBLOCKS; block++) if (blockIsOwnedBy(block,entry)) {isEmpty=false;break;}
00315                 //this entry has no blocks reserved, so lets clean it from the keytable
00316                 if (isEmpty) eraseKeytableEntry(entry);
00317             }
00318     }
00319     for (int block=0;block<SBMAXBLOCKS;block++) {
00320             int blockentry = eeprom_read_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+block));
00321             if (blockentry&0x80) {
00322                     blockentry &= 0x7F;
00323                     bool isEmpty=true;
00324                     for (int key=0;key<SBMAXKEYS;key++) {
00325                             if (eeprom_read_byte((uint16_t*)(key*SBKEYSIZE))) {isEmpty=false;break;}
00326                     }
00327                     if (isEmpty) eeprom_write_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+block),0);
00328             }
00329     }
00330 }
00331 
00332 char Cookie::readQueue() {
00333     char data=0;
00334     #ifndef POK_SIM
00335     int address;
00336     address = SBMAXKEYS*SBKEYSIZE+SBMAXBLOCKS+SBBLOCKSIZE*_block+_head%SBBLOCKSIZE;
00337     data=eeprom_read_byte((uint16_t*)address);
00338     #endif
00339     _head++;
00340     if (_head%SBBLOCKSIZE==0 && _head) {
00341             _block++;
00342             _block=findMyNextBlock();
00343     }
00344     return data;
00345 }
00346 
00347 void Cookie::writeQueue(char data) {
00348     #ifndef POK_SIM
00349     eeprom_write_byte((uint16_t*)(SBMAXKEYS*SBKEYSIZE+SBMAXBLOCKS+SBBLOCKSIZE*_block+_head%SBBLOCKSIZE),data);
00350     #endif
00351     _head++;
00352     if (_head%SBBLOCKSIZE==0 && _head) {
00353             _block++;
00354             _block=findMyNextBlock();
00355     }
00356 }
00357 
00358 int Cookie::findMyNextBlock() {
00359     if (!_status) return SBINVALIDBLOCK;
00360     for (int i=_block; i<SBMAXBLOCKS;i++) if (isMyBlock(i)) return i;
00361     return SBINVALIDBLOCK;
00362 }
00363 
00364 
00365