#include "ltrsrv_mspec_ltr01.h"
#include "lbitfield.h"
#include "ltrsrv_log.h"
#include <stdio.h>

#define RESP_ID_FLD_SUBID_L         (0x0FFFUL <<  0U)
#define RESP_ID_FLD_SUBID_H         (0x0001UL << 15U)
#define RESP_ID_FLD_MODIFICATION    (0x0007UL << 12U)

#define LTR01_SUBID_FLD_NUM         (0x03FFUL <<  0U)
#define LTR01_SUBID_FLD_GROUP       (0x0007UL << 10U)


/** Группы дополнительных модулей */
typedef enum {
    LTR01_SUBID_GROUP_GENERAL = 0, /**< Общая группа, в которой идут модули без принадлежности
                                        к какой-либо группе или модули, разработанные до
                                        введения класификации на группы */
    LTR01_SUBID_GROUP_LTRK    = 1, /**< Модули семейства LTRK */
} e_LTR01_SUBID_GROUP;


#define LTR01_MAKE_SUBID(group, num)    ((((group) & 0x7) << 10) | ((num) & 0x3FF))
#define LTR01_MAKE_SUBID_GENERAL(num)   LTR01_MAKE_SUBID(LTR01_SUBID_GROUP_GENERAL, num)
#define LTR01_MAKE_SUBID_LTRK(num)      LTR01_MAKE_SUBID(LTR01_SUBID_GROUP_LTRK, num)


/** Коды расширенных идентификаторов, позволяющие определить, какой именно дополнительный
    модуль реально установлен */
typedef enum {
    LTR01_SUBID_INVALID = 0,
    LTR01_SUBID_LTRS511 = LTR01_MAKE_SUBID_GENERAL(1), /**< Идентификатор модуля LTRS511 */
    LTR01_SUBID_LTRS411 = LTR01_MAKE_SUBID_GENERAL(2), /**< Идентификатор модуля LTRS411 */
    LTR01_SUBID_LTRS412 = LTR01_MAKE_SUBID_GENERAL(3), /**< Идентификатор модуля LTRS412 */
    LTR01_SUBID_LTRT10  = LTR01_MAKE_SUBID_GENERAL(4), /**< Идентификатор модуля LTRT10 */
    LTR01_SUBID_LTRT13  = LTR01_MAKE_SUBID_GENERAL(5), /**< Идентификатор модуля LTRT13 */
    LTR01_SUBID_LTRK511 = LTR01_MAKE_SUBID_GENERAL(6), /**< Идентификатор модуля LTRK511 */
    LTR01_SUBID_LTRK416 = LTR01_MAKE_SUBID_GENERAL(7), /**< Идентификатор модуля LTRK416 */
    LTR01_SUBID_LTRK415 = LTR01_MAKE_SUBID_GENERAL(8), /**< Идентификатор модуля LTRK415 */
    LTR01_SUBID_LTRK71  = LTR01_MAKE_SUBID_GENERAL(9), /**< Идентификатор модуля LTRK71 */
} e_LTR01_SUBID;

static struct {
    uint16_t id;
    const char *name;
    unsigned flags;
} f_modules_names[] = {
    {LTR01_SUBID_LTRS511, "LTRS511", 0},
    {LTR01_SUBID_LTRS411, "LTRS411", 0},
    {LTR01_SUBID_LTRS412, "LTRS412", 0},
    {LTR01_SUBID_LTRT10,  "LTRT10",  0},
    {LTR01_SUBID_LTRT13,  "LTRT13",  LTR_MODULE_FLAGS_USE_SYNC_MARK},
    {LTR01_SUBID_LTRK511, "LTRK511", 0},
    {LTR01_SUBID_LTRK416, "LTRK416", 0},
    {LTR01_SUBID_LTRK415, "LTRK415", 0},
    {LTR01_SUBID_LTRK71,  "LTRK71",  0},
};


static void f_fill_module_name(uint16_t subid_code, char *name, int *flags) {
    uint16_t subid = LBITFIELD_GET(subid_code, RESP_ID_FLD_SUBID_L) | (LBITFIELD_GET(subid_code, RESP_ID_FLD_SUBID_H) << 12U);
    uint8_t modification =  LBITFIELD_GET(subid_code, RESP_ID_FLD_MODIFICATION);
    const uint8_t group = LBITFIELD_GET(subid, LTR01_SUBID_FLD_GROUP);
    const uint8_t num = LBITFIELD_GET(subid, LTR01_SUBID_FLD_NUM);
    int fnd = 0;
    if (group == LTR01_SUBID_GROUP_GENERAL) {
        unsigned i;
        for (i = 0, fnd = 0; !fnd && (i < sizeof(f_modules_names)/sizeof(f_modules_names[0])); ++i) {
            if (f_modules_names[i].id == subid) {
                fnd = 1;
                if (modification == 0) {
                    strcpy(name, f_modules_names[i].name);
                } else {
                    sprintf(name, "%s-%d", f_modules_names[i].name, modification);
                }
                *flags |= f_modules_names[i].flags;
            }
        }
    } else if (group == LTR01_SUBID_GROUP_LTRK) {
        if (modification == 0) {
            sprintf(name, "LTRK%d", modification);
        } else {
            sprintf(name, "LTRK%d-%d", num, modification);
        }
        fnd = 1;
    }

    if (!fnd) {
        sprintf(name, "LTR01 (0x%04X)", subid_code);
    }
}



static int f_proc_rcv_cmd(t_ltr_crate *crate, t_ltr_module *module, uint32_t wrd) {
    int proc = 0;
    if ((wrd & LTR_CRATE_STREAM_CMD_CODE_Msk) == LTR01_CMD_SUBID) {
        uint16_t subid_code = LTR_CRATE_STREAM_GET_CMD_DATA(wrd);
        if ((module->state == LTR_MODULE_STATE_WAIT_SUBID) ||
            ((module->state == LTR_MODULE_STATE_WORK) && (module->subid_code != subid_code))) {
            int slot = LTR_CRATE_STREAM_GET_SLOT(wrd);
            module->subid_code = subid_code;

            f_fill_module_name(subid_code, module->name, &module->flags);
            ltrsrv_log_make_module_srcstr(crate, slot);
            if (module->state == LTR_MODULE_STATE_WAIT_SUBID) {
                module->state = LTR_MODULE_STATE_WORK;
                ltrsrv_log_rec(LTRSRV_LOGLVL_INFO, module->log_str, 0,
                               "Initialized successfully");
            } else {
                ltrsrv_log_rec(LTRSRV_LOGLVL_INFO, module->log_str, 0,
                               "Module subid changed");
            }
        }
    }
    return proc;
}


int ltrsrv_ltr01_init(t_ltr_module *module, uint32_t init_flags) {
    int err = 0;
    module->state = LTR_MODULE_STATE_NEED_GET_SUBID;
    module->func.proc_rcv_cmd = f_proc_rcv_cmd;
    module->flags |= LTR_MODULE_FLAGS_HIGH_BAUD;
    return err;
}


