/***************************************************************************//**
  Файл содержит функции специфичные для загрузки через can-интерфейс
  Пока только для Windows и для адаптера CAN-USB
  *****************************************************************************/



#include "lboot.h"
#include "stdio.h"
#include "can.h"
#include "can_lss.h"
#include "string.h"



#define LBOOT_CAN_MAX_BLOCK_SIZE  1024


/** Максимальный размер данных в пакете CAN */
#define CAN_MAX_DATA_SIZE  8



static const char* f_port = "COM1";
static t_can_hnd f_hnd = 0;
static uint32_t f_rx_tout = 1000;



static int f_parse_option(int opt);
static const char* f_get_opt_descr(void);
static const char* f_get_err_str(int err);
static int f_open(const char* devname, const char* serial, const void* params,
                   t_lboot_devinfo* info, int *out);
int lboot_can_get_devmode(uint8_t* mode);
int lboot_can_get_bootloader_version(uint16_t* ver);
int lboot_can_get_dev_flags(uint32_t* flags);
int lboot_can_get_features(uint32_t* features);
int lboot_can_start_write(t_lboot_startwr_info wr_info);
int lboot_can_write(const uint8_t* buf, uint32_t size);
int lboot_can_write_sign(const uint8_t* sign, uint32_t size);
int lboot_can_speccmd(const t_lboot_speccmd_info* cmd_info, uint32_t size);
int lboot_can_close(void);




/** Коды ошибок для интерфейса Modbus RTU */
typedef enum {
    /** ошибка открытия адаптера CAN*/
    LBOOT_ERR_CAN_ADAPTER_OPEN = -400,
    /** ошибка передачи сообщения адаптеру */
    LBOOT_ERR_CAN_MSG_SEND     = -401,
    LBOOT_ERR_CAN_TX_MSG_LEN   = -402
} t_lboot_can_errs;


static const char* f_err_str[] =
{
    "Can't open CAN adapter",
    "Can't send CAN Message",
    "Invalid tx message length"
};




/** структура с информацией о модуле USB */
const t_interface_info g_can_intf_info =
{
    "can_lss",
    "Extended LSS protocol (from CANOpen) over CAN interface",
    LBOOT_CAN_MAX_BLOCK_SIZE,
    LBOOT_ERR_CAN_START_ERR,
    LBOOT_ERR_CAN_START_ERR -
            (int32_t)(sizeof(f_err_str)/sizeof(f_err_str[0]))+1,
    f_parse_option,
    f_get_opt_descr,
    f_get_err_str,
    f_open,
    lboot_can_get_devmode,
    lboot_can_get_bootloader_version,
    lboot_can_get_dev_flags,
    lboot_can_get_features,
    lboot_can_start_write,
    lboot_can_write,
    lboot_can_write_sign,
    lboot_can_speccmd,
    lboot_can_close
};

/** Описание опций интерфейса Modbus */
static const char* f_opt_descr =
"can options:\n";

static int f_parse_option(int opt)
{
    int err = 0;
    switch (opt)
    {
        default:
        err = LBOOT_ERR_INVALID_OPTION;
            break;
    }
    return err;
}

static const char* f_get_opt_descr(void)
{
    return f_opt_descr;
}

static const char* f_get_err_str(int err)
{
    return f_err_str[LBOOT_ERR_CAN_START_ERR-err];
}


/***************************************************************************//**
  Передача запроса по LSS
  @param[in] data  Передаваемые данные (первый байт - код команды)
  @param[in] len   Количество в пакете CAN
  @return          Код ошибки
  *****************************************************************************/
const static int f_send_lss(const char* data, uint8_t len)
{
    t_can_msg msg;
    if ((len < 1) || (len > 8))
        return LBOOT_ERR_CAN_TX_MSG_LEN;

    msg.id = CAN_COBID_LSS_REQ;
    msg.len = len;
    msg.flags = 0;
    memcpy(msg.data, data, len);

    return can_send_msg(f_hnd, &msg);
}






static int f_open(const char* devname, const char* serial, const void* params,
                   t_lboot_devinfo* info, int* out)
{
    int err = LBOOT_ERR_DEVICE_NOT_FOUND;
    uint8_t cmd_data[CAN_MAX_DATA_SIZE];

    f_hnd = can_open_rs(f_port);
    if (!f_hnd)
    {
        err = LBOOT_ERR_CAN_ADAPTER_OPEN;
        *out = 1;
    }
    else
    {
        can_set_speed(f_hnd, CAN_BR_250);
        can_set_filter(f_hnd, 0x7E4);


        if (serial)
        {

        }
        else
        {
            cmd_data[0] = CAN_LSS_CS_SWITCH_MODE_GLOBAL;
            memset(&cmd_data[1], 0, CAN_MAX_DATA_SIZE-1);
            err = f_send_lss(cmd_data, CAN_MAX_DATA_SIZE);

            if (!err)
            {
                t_can_msg msg;
                err = can_recv_msg(f_hnd, &msg, f_rx_tout);
            }
        }
    }

    return err;
}



int lboot_can_get_devmode(uint8_t* mode)
{
    int err = 0;



    return err;
}




int lboot_can_get_bootloader_version(uint16_t* ver)
{
    int err = 0;

    return err;
}

int lboot_can_get_dev_flags(uint32_t* flags)
{
    int err = 0;

    return err;
}

int lboot_can_get_features(uint32_t* features)
{
    int err = 0;

    return err;
}



int lboot_can_speccmd(const t_lboot_speccmd_info* cmd_info, uint32_t size)
{
    int err = 0;

    return err;
}

int lboot_can_start_write(t_lboot_startwr_info wr_info)
{

    int err = 0;

    return err;
}

int lboot_can_write(const uint8_t* buf, uint32_t size)
{
    int err = 0;

    return err;
}

int lboot_can_write_sign(const uint8_t* sign, uint32_t size)
{
    int err = 0;

    return err;
}

int lboot_can_close(void)
{
    int err = 0;

    return err;
}
