Skip to content
Snippets Groups Projects
i2c_impl.c 15.3 KiB
Newer Older
#include <atmel_start.h>
#include <stdlib.h>

#include <i2c_slave.h>
#include <flash_utils.h>
#include <float_utils.h>
#define STATUS_BYTE_CML_SHIFT 1

const char MFR_ID[] = "CERN (BE/CO)";
const char MFR_MDL[] = "DI/OT MoniMod";
#if defined MMRTSB
const char MFR_REV[] = "0.2p-RTSB";
#elif defined MMFANT
const char MFR_REV[] = "0.2p-FANT";
#elif defined MMRATO
const char MFR_REV[] = "0.2p-RATO";
#elif defined MMPROT
const char MFR_REV[] = "0.2p-PROT";
#else
const char MFR_REV[] = "0.2p-ERRO";
#error Exactly one of MMRTSB, MMFANT, MMRATO or MMPROT has to be defined
#endif
const char MFR_DAT[] = "211020";
const char MFR_SER[] = "123456789";
const char IC_DEVICE_REV[] = __GIT_VER__;
#ifdef USE_LINEAR16
const uint8_t vout_mode = 0x16; // linear mode, fixed 2^10 exponent
#else
const uint8_t vout_mode = 0xe0; // not compliant to the standard, set mode bits to (invalid) 3'b111
extern uint16_t use_pec __xMR;
uint8_t use_pec_tmp;
void read_status_b(void);
void get_status_cml(void);
void write_status_cml(void);
extern uint8_t status_b;
extern uint8_t status_cml;
static uint8_t status_cml_tmp;
void accvolt();
void acccurr();
void accpowr();
uint16_t curpage_volt;
uint16_t curpage_curr;
uint16_t curpage_powr;
uint8_t query_r;
#ifdef MMRTSB
#define MAX_PAGE 3
#else
#define MAX_PAGE 2
#endif

extern uint16_t volts_lin[MAX_PAGE+1];
extern uint16_t currs_lin[MAX_PAGE+1];
extern uint16_t powrs_lin[MAX_PAGE+1];
extern uint16_t frpms_lin[3];
void set_frpms();
uint16_t setfrpms_lin[3];
extern uint16_t setfrpms[3] __xMR;
uint16_t temp_curve_points_data[7];
extern float temp_curve_points_x[3][3] __xMR;
extern float temp_curve_points_y[3][3] __xMR;

void set_tc_matrix();
void set_tc_onoff();
uint16_t temp_matrix_row[3]; // these rows mix the 3 temps separately for each fan
extern float temp_matrix[3][3] __xMR;
extern uint16_t temp_control_on __xMR;
uint8_t fan_config_1_2;
uint8_t fan_config_3_4;
void fan_config();
extern uint16_t fan_installed[3] __xMR;
extern uint16_t fan_cmdrpm[3] __xMR;
extern uint16_t fan_ppr[3] __xMR;
enum {
        cmd_0x00 = 0,
        cmd_0x1A,
        cmd_0x20,
        cmd_0x3A,
        cmd_0x3B,
        cmd_0x3C,
        cmd_0x3D,
        cmd_0x3E,
        cmd_0x78,
        cmd_0x7E,
        cmd_0x8B,
        cmd_0x8C,
        cmd_0x8D,
        cmd_0x8E,
        cmd_0x8F,
        cmd_0x90,
        cmd_0x91,
        cmd_0x92,
        cmd_0x96,
        cmd_0x99,
        cmd_0x9A,
        cmd_0x9B,
        cmd_0x9C,
        cmd_0x9D,
        cmd_0x9E,
        cmd_0xAE,
        /* extended commands */
        cmd_0xFF05,
        cmd_0xFF06,
        cmd_0xFF10,
        cmd_0xFFA0,
        cmd_0xFFB0,
        cmd_0xFFC0,
        cmd_0xFFC1,
        cmd_0xFFC4,
};

/* "- 1" to avoid adding null char at the end of a string */
static const int8_t cmd_data_lengths[] = {
        [cmd_0x00] = 1,
        [cmd_0x1A] = -1,
        [cmd_0x20] = 1,
        [cmd_0x3A] = 1,
        [cmd_0x3B] = 2,
        [cmd_0x3C] = 2,
        [cmd_0x3D] = 1,
        [cmd_0x3E] = 2,
        [cmd_0x78] = 1,
        [cmd_0x7E] = 1,
        [cmd_0x8B] = 2,
        [cmd_0x8C] = 2,
        [cmd_0x8D] = 2,
        [cmd_0x8E] = 2,
        [cmd_0x8F] = 2,
        [cmd_0x90] = 2,
        [cmd_0x91] = 2,
        [cmd_0x92] = 2,
        [cmd_0x96] = 2,
        [cmd_0x99] = -((int8_t)sizeof(MFR_ID) - 1),
        [cmd_0x9A] = -((int8_t)sizeof(MFR_MDL) - 1),
        [cmd_0x9B] = -((int8_t)sizeof(MFR_REV) - 1),
        [cmd_0x9C] = -((int8_t)sizeof(MFR_LOC) - 1),
        [cmd_0x9D] = -((int8_t)sizeof(MFR_DAT) - 1),
        [cmd_0x9E] = -((int8_t)sizeof(MFR_SER) - 1),
        [cmd_0xAE] = -((int8_t)sizeof(IC_DEVICE_REV) - 1),
        /* extended commands */
        [cmd_0xFF05] = 1,
        [cmd_0xFF06] = 1,
        [cmd_0xFF10] = 4,
        [cmd_0xFFA0] = 4,
        [cmd_0xFFB0] = 1,
        [cmd_0xFFC0] = 13,
        [cmd_0xFFC1] = 7,
        [cmd_0xFFC4] = 1
// only block write-block read process calls modify the length
static int8_t cmd_data_length_query = -1;

static const cmd_t cmds_cmds[] = (cmd_t[]){
        {0x0000, (int8_t *)&cmd_data_lengths[cmd_0x00],   (uint8_t *)&page_tmp,               (fp_t)NULL,       &page_chk,         (fp_t)NULL,       QUERY_WR | QUERY_RD | QUERY_FMT_8B, 0},
        {0x001A, (int8_t *)&cmd_data_length_query,        (uint8_t *)&query_r,                (fp_t)NULL,       &query_prp,        (fp_t)NULL,       QUERY_SUP,                          1},
        {0x0020, (int8_t *)&cmd_data_lengths[cmd_0x20],   (uint8_t *)&vout_mode,              (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD,                           1},
        {0x003A, (int8_t *)&cmd_data_lengths[cmd_0x3A],   (uint8_t *)&fan_config_1_2,         &get_fan_configs, &fan_config,       (fp_t)NULL,       QUERY_WR | QUERY_FMT_NAN,           0},
        {0x003B, (int8_t *)&cmd_data_lengths[cmd_0x3B],   (uint8_t *)&setfrpms_lin[0],        (fp_t)NULL,       &set_frpms,        (fp_t)NULL,       QUERY_WR | QUERY_FMT_LIN,           0},
        {0x003C, (int8_t *)&cmd_data_lengths[cmd_0x3C],   (uint8_t *)&setfrpms_lin[1],        (fp_t)NULL,       &set_frpms,        (fp_t)NULL,       QUERY_WR | QUERY_FMT_LIN,           0},
        {0x003D, (int8_t *)&cmd_data_lengths[cmd_0x3D],   (uint8_t *)&fan_config_3_4,         &get_fan_configs, &fan_config,       (fp_t)NULL,       QUERY_WR | QUERY_FMT_NAN,           0},
        {0x003E, (int8_t *)&cmd_data_lengths[cmd_0x3E],   (uint8_t *)&setfrpms_lin[2],        (fp_t)NULL,       &set_frpms,        (fp_t)NULL,       QUERY_WR | QUERY_FMT_LIN,           0},
        {0x0078, (int8_t *)&cmd_data_lengths[cmd_0x78],   (uint8_t *)&status_b,               &read_status_b,   (fp_t)NULL,        (fp_t)NULL,       QUERY_RD,                           0},
        {0x007E, (int8_t *)&cmd_data_lengths[cmd_0x7E],   (uint8_t *)&status_cml_tmp,         &get_status_cml,  &write_status_cml, (fp_t)NULL,       QUERY_WR | QUERY_RD,                0},
        {0x008B, (int8_t *)&cmd_data_lengths[cmd_0x8B],   (uint8_t *)&curpage_volt,           &accvolt,         (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_LIN,           0},
        {0x008C, (int8_t *)&cmd_data_lengths[cmd_0x8C],   (uint8_t *)&curpage_curr,           &acccurr,         (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_LIN,           0},
        {0x008D, (int8_t *)&cmd_data_lengths[cmd_0x8D],   (uint8_t *)&temps_lin[0],           (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_LIN,           0},
        {0x008E, (int8_t *)&cmd_data_lengths[cmd_0x8E],   (uint8_t *)&temps_lin[1],           (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_LIN,           0},
        {0x008F, (int8_t *)&cmd_data_lengths[cmd_0x8F],   (uint8_t *)&temps_lin[2],           (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_LIN,           0},
        {0x0090, (int8_t *)&cmd_data_lengths[cmd_0x90],   (uint8_t *)&frpms_lin[0],           (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_LIN,           0},
        {0x0091, (int8_t *)&cmd_data_lengths[cmd_0x91],   (uint8_t *)&frpms_lin[1],           (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_LIN,           0},
        {0x0092, (int8_t *)&cmd_data_lengths[cmd_0x92],   (uint8_t *)&frpms_lin[2],           (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_LIN,           0},
        {0x0096, (int8_t *)&cmd_data_lengths[cmd_0x96],   (uint8_t *)&curpage_powr,           &accpowr,         (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_LIN,           0},
        {0x0099, (int8_t *)&cmd_data_lengths[cmd_0x99],   (uint8_t *)&MFR_ID,                 (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_NAN,           0},
        {0x009A, (int8_t *)&cmd_data_lengths[cmd_0x9A],   (uint8_t *)&MFR_MDL,                (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_NAN,           0},
        {0x009B, (int8_t *)&cmd_data_lengths[cmd_0x9B],   (uint8_t *)&MFR_REV,                (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_NAN,           0},
        {0x009C, (int8_t *)&cmd_data_lengths[cmd_0x9C],   (uint8_t *)&MFR_LOC,                (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_NAN,           0},
        {0x009D, (int8_t *)&cmd_data_lengths[cmd_0x9D],   (uint8_t *)&MFR_DAT,                (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_NAN,           0},
        {0x009E, (int8_t *)&cmd_data_lengths[cmd_0x9E],   (uint8_t *)&MFR_SER,                (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_NAN,           0},
        {0x00AE, (int8_t *)&cmd_data_lengths[cmd_0xAE],   (uint8_t *)&IC_DEVICE_REV,          (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       QUERY_RD | QUERY_FMT_NAN,           0},
        {0xFF05, (int8_t *)&cmd_data_lengths[cmd_0xFF05], (uint8_t *)&dummy_byte,             (fp_t)NULL,       &boot_new_fw,      (fp_t)NULL,       0,                                  0},
        {0xFF06, (int8_t *)&cmd_data_lengths[cmd_0xFF06], (uint8_t *)&dummy_byte,             (fp_t)NULL,       &uc_reset,         (fp_t)NULL,       0,                                  0},
        {0xFF10, (int8_t *)&cmd_data_lengths[cmd_0xFF10], (uint8_t *)&seconds_up,             (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       0,                                  0},
        {0xFFA0, (int8_t *)&cmd_data_lengths[cmd_0xFFA0], (uint8_t *)&TMR_ERROR_CNT,          (fp_t)NULL,       (fp_t)NULL,        (fp_t)NULL,       0,                                  0},
        {0xFFB0, (int8_t *)&cmd_data_lengths[cmd_0xFFB0], (uint8_t *)&use_pec_tmp,            (fp_t)NULL,       &set_pec,          (fp_t)NULL,       0,                                  1},
        {0xFFC0, (int8_t *)&cmd_data_lengths[cmd_0xFFC0], (uint8_t *)&temp_curve_points_data, (fp_t)NULL,       &set_tc_curve,     (fp_t)NULL,       0,                                  0},
        {0xFFC1, (int8_t *)&cmd_data_lengths[cmd_0xFFC1], (uint8_t *)&temp_matrix_row,        (fp_t)NULL,       &set_tc_matrix,    (fp_t)NULL,       0,                                  0},
        {0xFFC4, (int8_t *)&cmd_data_lengths[cmd_0xFFC4], (uint8_t *)&tc_on,                  (fp_t)NULL,       &set_tc_onoff,     (fp_t)NULL,       0,                                  0}
};

cmd_space_t cmds = {
        sizeof(cmds_cmds)/sizeof(cmd_t),
        cmds_cmds
static uint32_t fw_write_buf[FLASH_ROW_SIZE/4];
        usbdc_detach();
        usbdc_stop();
        usbdc_deinit();
        uint32_t *char_user_flash = (uint32_t *)&user_flash;
        user_flash_t *tmp_user_flash = (user_flash_t *)&fw_write_buf;
        for (uint8_t i = 0; i < FLASH_ROW_SIZE/4; ++i)
                fw_write_buf[i] = char_user_flash[i];

        /* set 0xBEC0ABCD copy FW code */
        tmp_user_flash->copy_fw = 0xbec0abcd;

        /* copy modified block back to the flash */
        flash_write_row((uint32_t *)&user_flash, (uint32_t *)fw_write_buf);

        /* reset the uC */
        uc_reset();
}


        if (page_tmp > MAX_PAGE)
                page = MAX_PAGE;
        int16_t cmd_idx = in_addr_space(&cmds, query_r);
        if (cmd_idx != -1)
                query_r = QUERY_SUP | cmds.cmds[cmd_idx].query_byte;
                query_r = 0;
void read_status_b(void)
{
        status_b = status_cml ? 1 << STATUS_BYTE_CML_SHIFT : 0;
}


void get_status_cml(void)
        status_cml_tmp = status_cml;
void write_status_cml(void)
        /* clear only bits set to 1 */
        status_cml &= ~status_cml_tmp;
#if defined(MMFANT) || defined(MMPROT)

{
        fan_installed[0] = (fan_config_1_2 >> 7) & 0x1;
        fan_cmdrpm[0] = (fan_config_1_2 >> 6) & 0x1;
        fan_ppr[0] = (fan_config_1_2 >> 4) & 0x3;

        fan_installed[1] = (fan_config_1_2 >> 3) & 0x1;
        fan_cmdrpm[1] = (fan_config_1_2 >> 2) & 0x1;
        fan_ppr[1] = fan_config_1_2 & 0x3;

        fan_installed[2] = (fan_config_3_4 >> 7) & 0x1;
        fan_cmdrpm[2] = (fan_config_3_4 >> 6) & 0x1;
        fan_ppr[2] = (fan_config_3_4 >> 4) & 0x3;

        uint32_t *char_user_flash = (uint32_t *)&user_flash;
        user_flash_t *tmp_user_flash = (user_flash_t *)&fw_write_buf;

        /* backup existing user data */
        for (uint8_t i = 0; i < FLASH_ROW_SIZE/4; ++i)
                fw_write_buf[i] = char_user_flash[i];

        /* set 0xBEC0ABCD copy FW code */
        for (uint8_t i = 0; i < 3; ++i) {
                tmp_user_flash->fan_installed[i] = fan_installed[i];
                tmp_user_flash->fan_cmdrpm[i] = fan_cmdrpm[i];
                tmp_user_flash->fan_ppr[i] = fan_ppr[i];
        }

        /* copy modified block back to the flash */
        flash_write_row((uint32_t *)&user_flash, (uint32_t *)fw_write_buf);
void __xMR get_fan_configs()
{
        fan_config_1_2 = (fan_installed[0] << 7) | (fan_cmdrpm[0] << 6) | (fan_ppr[0] << 4) |
                (fan_installed[1] << 3) | (fan_cmdrpm[1] << 2) | (fan_ppr[1]);
        fan_config_3_4 = (fan_installed[2] << 7) | (fan_cmdrpm[2] << 6) | (fan_ppr[2] << 4);
}

{
        setfrpms[0] = linear_to_float(setfrpms_lin[0]);
        setfrpms[1] = linear_to_float(setfrpms_lin[1]);
        setfrpms[2] = linear_to_float(setfrpms_lin[2]);

        uint32_t *char_user_flash = (uint32_t *)&user_flash;
        user_flash_t *tmp_user_flash = (user_flash_t *)&fw_write_buf;

        /* backup existing user data */
        for (uint8_t i = 0; i < FLASH_ROW_SIZE/4; ++i)
                fw_write_buf[i] = char_user_flash[i];

        /* set 0xBEC0ABCD copy FW code */
        for (uint8_t i = 0; i < 3; ++i)
                tmp_user_flash->setfrpms[i] = setfrpms[i];

        /* copy modified block back to the flash */
        flash_write_row((uint32_t *)&user_flash, (uint32_t *)fw_write_buf);
        uint8_t fan_n = temp_curve_points_data[0];
        for (uint8_t i = 0; i < 3; ++i) {
                temp_curve_points_x[fan_n][i] = linear_to_float(temp_curve_points_data[1 + 2*i]);
                temp_curve_points_y[fan_n][i] = linear_to_float(temp_curve_points_data[1 + 2*i + 1]);
        uint8_t fan_n = temp_matrix_row[0];
        for (uint8_t i = 0; i < 3; ++i) {
                temp_matrix[fan_n][i] = linear_to_float(temp_matrix_row[1 + i]);