IJFW - IchigoJamのBASICプログラムをメモリカード(MMCまたは互換カード)に保存したり読み出したりできるプログラム。メモリカードにファームウェアのファイルを置くだけで、電源ON時に自動的に書き換える機能も搭載(一応こちらがメイン)。LPC1114FN28専用。

Dependencies:   mbed

参考URL http://www.cyberchabudai.org/index.php/entry?tag=IJFW

I2c2mem/I2c2mem.cpp

Committer:
oks486
Date:
2016-08-21
Revision:
2:daf6c4719496
Parent:
1:11f73f269fdc

File content as of revision 2:daf6c4719496:

#include "I2c2mem.h"
#include "mbed.h"
#include "I2CSlave2.h"
#include "FatfsIjfwConfigurable.h"

const int PROGRAM_BYTES_MAX = 1024;
const int PROGRAM_NUM_MAX = 128;
const int DATA_BYTES_MAX = 512;
const char* DATA_FILENAME = "ijdata.dat";
const int DATA_FILENUM_MAX = 1023;

const int RETURN_NORMAL = 1;
const int RETURN_ERROR = 0;


I2c2mem::I2c2mem(I2CSlave2* _i2cs, FatfsIjfwConfigurable* _fs, DigitalOut* _ledcard)
    : i2cs(_i2cs), fs(_fs), ledcard(_ledcard) {
    buffer = new char[PROGRAM_BYTES_MAX];
    address = 0;    
    address_old = 0;    
    count = 0;
    dataBytesCount = 0;
    dataFileNum = 0;
}


I2c2mem::~I2c2mem(){
    delete [] buffer;
}


// Write a BASIC program to memory card
int I2c2mem::writeProgram(int flag){
    ledcard->write(1);

    // Receive I2C data (
    char bufi2c[36];
    int length = i2cs->read(bufi2c, 36) - 1;

    if (length == 2 || length == 34) {
        // Calculate memory address in EEPROM
        address = 0x10000 * flag;       // This flag expresses 64-127 block
        address |= (bufi2c[0] << 8) | bufi2c[1];

        // if command is "FILES"
        if (address != address_old + 32) {
            count = 0;
        }
        address_old = address;

        // BAS file name
        if (count == 0) {
            int filenum = ((address / PROGRAM_BYTES_MAX) % PROGRAM_NUM_MAX) + 100;
            sprintf(filename, "ij%03d.bas", filenum);
        }
    } else {    // Not match 2 nor 34
        i2cs->stop();
        count = 0;
        ledcard->write(0);
        return RETURN_ERROR;
    }

    if (length == 34) {
        for (int i = 0; i < 32; i++) {
            buffer[count + i] = bufi2c[i + 2];
        }
        count += 32;

        if (count >= PROGRAM_BYTES_MAX) {
            count = 0;
            fs->mount();
            int res = fs->openBas(filename, MODE_OVERWRITE);
            if (res != FR_OK) {
                ledcard->write(0);
                return RETURN_ERROR;
            }

            fs->write(buffer, PROGRAM_BYTES_MAX);
            fs->close();
        }
    }
    
    ledcard->write(0);
    return RETURN_NORMAL;
}


// Read a BASIC program from memory card
int I2c2mem::readProgram() {
    ledcard->write(1);

    if (count == 0) {
        fs->mount();
        int res = fs->openBas(filename, MODE_RO);
        if (res != FR_OK) {
            i2cs->stop();
            ledcard->write(0);
            return RETURN_ERROR;
        }
        if (fs->read(buffer, PROGRAM_BYTES_MAX) != PROGRAM_BYTES_MAX) {
            fs->close();
            i2cs->stop();
            ledcard->write(0);
            return RETURN_ERROR;
        }
        fs->close();
    }
    
    char bufi2c[32];
    for (int i = 0; i < 32; i++) {
        bufi2c[i] = buffer[count + i];
    }

    if (i2cs->write(bufi2c, 32) != 32) {
        i2cs->stop();
        count = 0;
        ledcard->write(0);
        return RETURN_ERROR;
    }
    count += 32;
    
    if (count >= PROGRAM_BYTES_MAX) {
        i2cs->stop();
        count = 0;
    }
    
    ledcard->write(0);
    return RETURN_NORMAL;
}


// Write a I2C data to memory card
int I2c2mem::writeData()
{
    ledcard->write(1);

    // Data from master
    char bufi2c[DATA_BYTES_MAX+2];
    int length = i2cs->read(bufi2c, DATA_BYTES_MAX+2) - 1;
    // The reason of "DATA_BYTES_MAX+2" is the one is "command byte" 
    // from IchigoJam and the other is caused by behavior of i2c_api

    if (length == 1) {      // when "i2cr" instruction
        count = 1;
        return RETURN_NORMAL;
    } else {
        count = 0;
    }

    length--;   // decresement the number of command bytes
    if (length > DATA_BYTES_MAX) {
        length = DATA_BYTES_MAX;
    }

    // Write data to memory card
    fs->mount();
    int res = fs->open(DATA_FILENAME, MODE_OVERWRITE);
    if (res != FR_OK) {
        ledcard->write(0);
        return RETURN_ERROR;
    }
    fs->write(&bufi2c[1], length);
    fs->close();
    
    ledcard->write(0);
    return RETURN_NORMAL;
}


// Read a I2C data to memory card
int I2c2mem::readData()
{
    ledcard->write(1);

    if (count != 1) {
        i2cs->stop();
        count = 0;
        ledcard->write(0);
        return RETURN_ERROR;
    }

    // Read data from memory card
    fs->mount();
    int res = fs->open(DATA_FILENAME, MODE_RO);
    if (res != FR_OK) {
        ledcard->write(0);
        return RETURN_ERROR;
    }

    int length = fs->filesize();
    if (length > DATA_BYTES_MAX) {
        length = DATA_BYTES_MAX;
    }

    char bufi2c[DATA_BYTES_MAX];
    if (fs->read(bufi2c, length) != length) {
        fs->close();
        ledcard->write(0);
        return RETURN_ERROR;
    }
    fs->close();

    // Send to master
    i2cs->write(bufi2c, length);

    count = 0;
    ledcard->write(0);
    return RETURN_NORMAL;
}


// Write a I2C data to memory card card (Continuous writting mode)
int I2c2mem::writeDataContinuous()
{
    // Data from master
    char bufi2c[DATA_BYTES_MAX+2];
    int length = i2cs->read(bufi2c, DATA_BYTES_MAX+2) - 1;

    length--;   // decresement the number of command bytes
    if (length > DATA_BYTES_MAX) {
        length = DATA_BYTES_MAX;
    }

    for (int i = 0; i < length; i++) {
        buffer[dataBytesCount + i] = bufi2c[i + 1];
    }
    
    dataBytesCount += length;
    if (dataBytesCount < DATA_BYTES_MAX) {
        return RETURN_NORMAL;
    }

    // Write data to memory card
    ledcard->write(1);
    fs->mount();
    fs->mkdir("data");

    sprintf(filename, "/data/%04d.dat", dataFileNum);
    int res = fs->open(filename, MODE_APPEND);
    if (res != FR_OK) {
        ledcard->write(0);
        return RETURN_ERROR;
    }

    int datafilesize = fs->filesize();
    if (datafilesize > 1024*1024) {
        fs->close();
        dataFileNum++;
        if (dataFileNum > DATA_FILENUM_MAX) {
            dataFileNum = 0;
        }
        sprintf(filename, "/data/%04d.dat", dataFileNum);
        res = fs->open(filename, MODE_OVERWRITE);
        if (res != FR_OK) {
            ledcard->write(0);
            return RETURN_ERROR;
        }
    }

    fs->write(buffer, dataBytesCount);
    fs->close();
    dataBytesCount = 0;
    ledcard->write(0);
    
    return RETURN_NORMAL;
}


int I2c2mem::reset()
{
    i2cs->stop();

    // If there is data remaining in the buffer, it is written to memory card.
    if (dataBytesCount != 0) {
        ledcard->write(1);
        fs->mount();

        sprintf(filename, "/data/%04d.dat", dataFileNum);
        int res = fs->open(filename, MODE_APPEND);
        if (res != FR_OK) {
            ledcard->write(0);
            return RETURN_ERROR;
        }

        int datafilesize = fs->filesize();
        if (datafilesize > 1024*1024) {
            fs->close();
            dataFileNum++;
            if (dataFileNum > DATA_FILENUM_MAX) {
                dataFileNum = 0;
            }
            sprintf(filename, "/data/%04d.dat", dataFileNum);
            res = fs->open(filename, MODE_OVERWRITE);
            if (res != FR_OK) {
                ledcard->write(0);
                return RETURN_ERROR;
            }
        }

        fs->write(buffer, dataBytesCount);
        fs->close();
        ledcard->write(0);
    }

    address = 0;    
    address_old = 0;    
    count = 0;
    dataBytesCount = 0;
    dataFileNum = 0;

    return RETURN_NORMAL;
}