/****************************************************************************/
/* Copyright 2012 MBARI.                                                    */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/

#include "config.h"
#include "flash_mem.h"
#include "sys_defs.h"

#include <string.h>

typedef struct {
    ConfigData config;
    unsigned int checksum;
} ConfigBlock;

unsigned int calcCheckSum(char* buff, int size);

/****************************************************************************/
/*                             Config functions                             */
/****************************************************************************/
int cfgCheck(ConfigData* config) {
    if (config->bootFlag != CFG_DEFAULT_BOOT_FLAG)
        return -2;


    switch (config->inst0Baud) {
        case CFG_INST_BAUD_4800: break;
        case CFG_INST_BAUD_9600: break;
        case CFG_INST_BAUD_14400: break;
        case CFG_INST_BAUD_19200: break;
        case CFG_INST_BAUD_38400: break;
        case CFG_INST_BAUD_57600: break;
        case CFG_INST_BAUD_115200: break;
        default: return -3;
    }

    switch (config->inst1Baud) {
        case CFG_INST_BAUD_4800: break;
        case CFG_INST_BAUD_9600: break;
        case CFG_INST_BAUD_14400: break;
        case CFG_INST_BAUD_19200: break;
        case CFG_INST_BAUD_38400: break;
        case CFG_INST_BAUD_57600: break;
        case CFG_INST_BAUD_115200: break;
        default: return -4;
    }

    switch (config->inst0Parity) {
        case CFG_INST_PAR_8NONE: break;
        case CFG_INST_PAR_8EVEN: break;
        case CFG_INST_PAR_8ODD: break;
        case CFG_INST_PAR_9NONE: break;
        default: return -7;
    }

    switch (config->inst1Parity) {
        case CFG_INST_PAR_8NONE: break;
        case CFG_INST_PAR_8EVEN: break;
        case CFG_INST_PAR_8ODD: break;
        case CFG_INST_PAR_9NONE: break;
        default: return -8;
    }

    switch (config->inst0Stop) {
        case CFG_INST_STOP_ONE: break;
        case CFG_INST_STOP_TWO: break;
        default: return -9;
    }

    switch (config->inst1Stop) {
        case CFG_INST_STOP_ONE: break;
        case CFG_INST_STOP_TWO: break;
        default: return -10;
    }


    return 0;
}

int cfgRead(ConfigData* config) {
    ConfigBlock cb;
    unsigned int cs_calc;

    /* read the configuation struct from memory */
    memRead((char*) &cb, sizeof (cb));

    cs_calc = calcCheckSum((char*) &cb.config, sizeof (ConfigData));

    if (cs_calc != cb.checksum)
        return -1;

    /* assign stored data to the config data struct */
    config->bootFlag = cb.config.bootFlag;
    config->inst0Baud = cb.config.inst0Baud;
    config->inst0Parity = cb.config.inst0Parity;
    config->inst0Stop = cb.config.inst0Stop;
    config->inst1Baud = cb.config.inst1Baud;
    config->inst1Parity = cb.config.inst1Parity;
    config->inst1Stop = cb.config.inst1Stop;
    config->debugBits = cb.config.debugBits;

    return cfgCheck(config);
}

int cfgWrite(ConfigData* config) {
    ConfigBlock cb;

    /* if config params are not in a valid range, don't write it */
    if (cfgCheck(config) != 0)
        return -1;

    /* assign stored data to the config data struct */
    cb.config.bootFlag = config->bootFlag;
    cb.config.inst0Baud = config->inst0Baud;
    cb.config.inst0Parity = config->inst0Parity;
    cb.config.inst0Stop = config->inst0Stop;
    cb.config.inst1Baud = config->inst1Baud;
    cb.config.inst1Parity = config->inst1Parity;
    cb.config.inst1Stop = config->inst1Stop;
    cb.config.debugBits = config->debugBits;

    /* calc and assign the checksum */
    cb.checksum = calcCheckSum((char*) &cb.config, sizeof (ConfigData));

    /* erase the old config */
    memErase();

    /* write the new config */
    memWrite((char*) &cb, sizeof (cb));

    return 0;
}

int cfgDefault() {
    ConfigBlock cb;

    /* assign stored data to the config data struct */
    cb.config.bootFlag = CFG_DEFAULT_BOOT_FLAG;

    cb.config.inst0Baud = CFG_INST_BAUD_DEF;
    cb.config.inst0Parity = CFG_INST_PAR_DEF;
    cb.config.inst0Stop = CFG_INST_STOP_DEF;
    cb.config.inst1Baud = CFG_INST_BAUD_DEF;
    cb.config.inst1Parity = CFG_INST_PAR_DEF;
    cb.config.inst1Stop = CFG_INST_STOP_DEF;

    cb.config.debugBits = CFG_DEBUG_BITS_DEF;

    /* calc and assign the checksum */
    cb.checksum = calcCheckSum((char*) &cb.config, sizeof (ConfigData));

    /* erase the old config */
    memErase();

    /* write the new config */
    memWrite((char*) &cb, sizeof (cb));

    return 0;
}

int cfgSetBootFlag() {
    ConfigBlock cb;

    /* clear out the config block */
    memset((char*) &cb, 0, sizeof (ConfigBlock));

    /* set the boot flag */
    cb.config.bootFlag = CFG_ACTIVE_BOOT_FLAG;

    /* calc and assign the checksum */
    cb.checksum = calcCheckSum((char*) &cb.config, sizeof (ConfigData));

    /* erase the old config */
    memErase();

    /* write the new config */
    memWrite((char*) &cb, sizeof (cb));

    return 0;
}

unsigned int calcCheckSum(char* buff, int size) {
    int i;
    unsigned int cs = 0;

    for (i = 0; i < size; i++)
        cs += buff[i];

    return cs;
}

