#include "ltr010api.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include "ltrd_protocol_defs.h"

#define LTR010_COMMAND_TIMEOUT 1000
#define LTR010_FIRM_SIZE (8 + 2 + EP1K50_SIZE)

#ifdef _WIN32
    int ___CPPdebugHook = 0;
#endif

static const TLTR_ERROR_STRING_DEF ErrorStrings[] = {
    { LTR010_ERROR_GET_ARRAY,       "Ошибка выполнения команды GET_ARRAY." },
    { LTR010_ERROR_PUT_ARRAY,       "Ошибка выполнения команды PUT_ARRAY." },
    { LTR010_ERROR_GET_MODULE_NAME, "Ошибка выполнения команды GET_MODULE_NAME." },
    { LTR010_ERROR_GET_MODULE_DESCR,"Ошибка выполнения команды GET_MODULE_DESCRIPTOR." },
    { LTR010_ERROR_INIT_FPGA,       "Ошибка выполнения команды INIT_FPGA." },
    { LTR010_ERROR_RESET_FPGA,      "Ошибка выполнения команды RESET_FPGA." },
    { LTR010_ERROR_INIT_DMAC,       "Ошибка выполнения команды INIT_DMAC." },
    { LTR010_ERROR_LOAD_FPGA,       "Ошибка выполнения команды LOAD_FPGA." },
    { LTR010_ERROR_OPEN_FILE,       "Ошибка открытия файла." },
    { LTR010_ERROR_GET_INFO_FPGA,   "Ошибка выполнения команды GET_INFO_FPGA." }
};


//-----------------------------------------------------------------------------
LTR010API_DllExport(INT) LTR010_Init(TLTR010 *module) {
    return module == NULL ? LTR_ERROR_INVALID_MODULE_DESCR : LTR_Init(&module->ltr);
}

//-----------------------------------------------------------------------------
LTR010API_DllExport(INT) LTR010_Open(TLTR010 *module, DWORD saddr, WORD sport, const CHAR *csn) {
    INT res = module == NULL ? LTR_ERROR_INVALID_MODULE_DESCR : LTR_OK;
    if (res==LTR_OK)
        res = LTR010_Close(module);
    if (res == LTR_OK) {
        res = LTR_OpenCrate(&module->ltr, saddr, sport, LTR_CRATE_IFACE_UNKNOWN, csn);
    }
    return res;
}
//-----------------------------------------------------------------------------
LTR010API_DllExport(INT)  LTR010_Close(TLTR010 *module) {
    return module == NULL ? LTR_ERROR_INVALID_MODULE_DESCR : LTR_Close(&module->ltr);
}

//-----------------------------------------------------------------------------
LTR010API_DllExport(INT) LTR010_GetArray(TLTR010 *module, BYTE *buf, DWORD size, DWORD address) {
    INT res = module == NULL ? LTR_ERROR_INVALID_MODULE_DESCR : buf==NULL ? LTR_ERROR_PARAMETERS : LTR_OK;
    if (res==LTR_OK) {
        DWORD sbuf[] = {
            CONTROL_COMMAND_START, CONTROL_COMMAND_GET_ARRAY, 0, 0
        };
        sbuf[2] = address;
        sbuf[3] = size;
        res = LTR__GenericCtlFunc(&module->ltr,
                                  sbuf, sizeof(sbuf), buf, size,
                                  LTR010_ERROR_GET_ARRAY, LTR010_COMMAND_TIMEOUT);
    }
    return res;
}
//-----------------------------------------------------------------------------
LTR010API_DllExport(INT) LTR010_PutArray(TLTR010 *module, const BYTE *buf, DWORD size, DWORD address) {
    INT res = module == NULL ? LTR_ERROR_INVALID_MODULE_DESCR : buf==NULL ? LTR_ERROR_PARAMETERS : LTR_OK;
    size_t send_size = 4 * sizeof(DWORD) + size;
    DWORD* pbuf = NULL;

    if (res==LTR_OK) {
        pbuf = malloc(send_size);
        if (pbuf==NULL)
            res = LTR_ERROR_MEMORY_ALLOC;
    }

    if (res==LTR_OK) {
        pbuf[0] = CONTROL_COMMAND_START;
        pbuf[1] = CONTROL_COMMAND_PUT_ARRAY;
        pbuf[2] = address;
        pbuf[3] = size;
        memcpy(&pbuf[4], buf, size);
        res = LTR__GenericCtlFunc(&module->ltr,
                                  pbuf, (DWORD)send_size, NULL, 0,
                                  LTR010_ERROR_PUT_ARRAY, LTR010_COMMAND_TIMEOUT);
    }
    free (pbuf);

    return res;
}
//-----------------------------------------------------------------------------
LTR010API_DllExport(INT) LTR010_GetDescription(TLTR010 *module, TDESCRIPTION_LTR010 *description) {
    DWORD sbuf[] = {
        CONTROL_COMMAND_START, CONTROL_COMMAND_GET_DESCRIPTION
    };
    INT res = module == NULL ? LTR_ERROR_INVALID_MODULE_DESCR : LTR_OK;

    if (res==LTR_OK) {
        res =  LTR__GenericCtlFunc(&module->ltr,
                               sbuf, sizeof(sbuf), description, sizeof(TDESCRIPTION_LTR010),
                               LTR010_ERROR_GET_MODULE_DESCR, LTR010_COMMAND_TIMEOUT);
    }
    return res;
}
//-----------------------------------------------------------------------------
LTR010API_DllExport(INT) LTR010_LoadFPGA(TLTR010 *module, const CHAR *fname, BYTE rdma, BYTE wdma) {
    INT res = module == NULL ? LTR_ERROR_INVALID_MODULE_DESCR : fname==NULL ?
                                   LTR_ERROR_PARAMETERS : LTR_IsOpened(&module->ltr);
    BYTE *data = NULL;

    if (res==LTR_OK) {
        data = malloc(LTR010_FIRM_SIZE);
        if (data==NULL)
            res = LTR_ERROR_MEMORY_ALLOC;
    }

    if (res==LTR_OK) {
        FILE *f = fopen(fname, "rt");
        if (f == NULL) {
            res = LTR010_ERROR_OPEN_FILE;
        } else {
            DWORD datasize = 10;


            *((LPDWORD)&data[0]) = CONTROL_COMMAND_START;
            *((LPDWORD)&data[4]) = CONTROL_COMMAND_LOAD_FPGA;
            data[8] = rdma;
            data[9] = wdma;

            memset(&data[datasize], 0, LTR010_FIRM_SIZE - datasize);
            while (!feof(f) && (datasize < LTR010_FIRM_SIZE)) {
                int d;
                if (fscanf(f, "%3d,", &d) > 0)
                    data[datasize++] = d & 0xFF;
            }
            fclose(f);
            res = LTR__GenericCtlFunc(&module->ltr,
                                   data, LTR010_FIRM_SIZE, NULL, 0,
                                   LTR010_ERROR_LOAD_FPGA, 8000);
        }
    }
    free(data);

    return res;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
LTR010API_DllExport(LPCSTR)  LTR010_GetErrorString(INT error) {
    size_t i;
    for (i = 0; i < sizeof(ErrorStrings) / sizeof(ErrorStrings[0]); i++) {
        if (ErrorStrings[i].code == error)
            return ErrorStrings[i].message;
    }
    return LTR_GetErrorString(error);
}
//-----------------------------------------------------------------------------
#ifdef _WIN32
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) {
    return 1;
}
#endif

