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

  1. Import this library to online compiler (see button "import" on the right hand side
  2. DO NOT import mbed-src anymore, a better version is now included inside PokittoLib
  3. Change My_settings.h according to your project
  4. Start coding!
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;
+}
+
+
+