#include "cfg.h"

// Includes
#include "eeprom.h"
#include "tools.h"
#include "term.h"
#include "rf.h"

// ============================================================================
//                                   GLOBALS
// ============================================================================

cfg_t cfg;

// ============================================================================
//                                PROTOTYPES
// ============================================================================


// ============================================================================
//                                 FUNCTION
// ============================================================================

void cfg_init()
{
    uint32_t crc;

    // Init eeprom
    eeprom_init();

    // FACTORY
    // -------

    // Loading factory
    eeprom_read(CFG_FACTORY_ADDR, (uint8_t*)&cfg.factory, sizeof(cfg_factory_t) );
    // Compute CRC
    crc = crc32((uint8_t *)&cfg.factory, sizeof(cfg_factory_t) - 4);
    // Check integrity
    if ((cfg.factory.magic != CFG_FACTORY_MAGIC) || (cfg.factory.crc != crc)){
        // Defaulting
        cfg.factory.addr = 0;
        cfg_write_factory();
    }

    // USER
    // -------

    // Loading factory
    eeprom_read(CFG_USER_ADDR, (uint8_t*)&cfg.user, sizeof(cfg_user_t) );
    // Compute CRC
    crc = crc32((uint8_t *)&cfg.user, sizeof(cfg_user_t) - 4);
    // Check integrity
    if ((cfg.user.magic != CFG_USER_MAGIC) || (cfg.user.crc != crc)){
        // Defaulting
        cfg_user_reset();
    }

    term_out_str("CFG\r\n");
    term_field_uint("addr      ", cfg.factory.addr);
    term_field_uint("ack       ", cfg.user.is_ack);
    term_field_uint("autosave  ", cfg.user.is_autosave);
    term_field_uint("led_count ", cfg.user.led_count);
    term_field_uint("bright    ", cfg.user.brightness);
    term_field_uint("boot      ", cfg.user.boot);
    term_field_uint("flash_on  ", cfg.user.flash_on_ms);
    term_field_uint("flash_off ", cfg.user.flash_off_ms);
    term_field_uint("glow_a2b  ", cfg.user.glow_a2b_ms);
    term_field_uint("glow_b2q  ", cfg.user.glow_b2a_ms);
    // Group
    term_out_str(" group      : 0");

    int ngrp = 1;
    for(int grp = 1; grp < 256; grp++){
        if (cfg_group_is_member(grp)){
            if (ngrp > 0) term_out_str(", ");
            term_out_uint(grp);
            ngrp++;
        }
    }
    if (ngrp > 0) term_out_str("  ");
    term_out_str("(");
    term_out_uint(ngrp);
    term_out_str(")\r\n");
    // Sequences
    term_out_str(" sequence   : ");
    int nseq = 0;
    for(int seq = 1; seq < 64; seq++){
        if (cfg.user.seq[seq].type != RF_SEQ_TYPE_NONE){
            if (nseq > 0) term_out_str(", ");
            term_out_uint(seq);
            nseq++;
        }
    }
    if (nseq > 0) term_out_str("  ");
    term_out_str("(");
    term_out_uint(nseq);
    term_out_str(")\r\n");

}

void cfg_user_reset()
{
    cfg.user.is_ack         = 1;
    cfg.user.is_autosave    = 1;
    cfg.user.led_count      = 6;
    cfg.user.brightness     = 50;
    cfg.user.boot           = CFG_BOOT_AUTO;
    cfg.user.flash_on_ms    = 100;
    cfg.user.flash_off_ms   = 200;
    cfg.user.glow_a2b_ms    = 1000;
    cfg.user.glow_b2a_ms    = 1000;
    cfg_group_clear();
    cfg_sequence_clear();
    cfg_write_user();
}


uint32_t cfg_write_factory()
{
    cfg.factory.magic = CFG_FACTORY_MAGIC;
    cfg.factory.crc = crc32((uint8_t *)&cfg.factory, sizeof(cfg_factory_t) - 4);
    return eeprom_write(CFG_FACTORY_ADDR, (uint8_t*)&cfg.factory, sizeof(cfg_factory_t) );

}


uint32_t cfg_write_user()
{
    cfg.user.magic = CFG_USER_MAGIC;
    cfg.user.crc = crc32((uint8_t *)&cfg.user, sizeof(cfg_user_t) - 4);
    return eeprom_write(CFG_USER_ADDR, (uint8_t*)&cfg.user, sizeof(cfg_user_t) );

}


uint8_t cfg_group_is_member(uint8_t group)
{
    //if (group == 0) return true; // Handle a upper level
    uint8_t ibyte   = group >> 5;
    uint8_t ibit    = group & 0x1F;
    return (cfg.user.groups[ibyte] & (1UL << ibit)) != 0;
}

void cfg_group_join(uint8_t group)
{
    cfg.user.groups[group >> 5] |= (1UL << (group & 0x1F));
}

void cfg_group_leave(uint8_t group)
{
    cfg.user.groups[group >> 5] &= ~(1UL << (group & 0x1F));
}

void cfg_group_clear()
{
    for(int i = 0; i < 8; i++) cfg.user.groups[i] = 0x00000000;
}



void cfg_sequence_clear()
{
    for(int i = 0; i < 64; i++) cfg.user.seq[i].type = RF_SEQ_TYPE_NONE;
}
