#include <stdio.h>
#include <string.h>

#include "lcomp/stubs.h"
#include "lcomp/ioctl.h"
#include "lcomp/e2010cmd.h"

#include "lcomp/ifc_ldev.h"
#include "ldevbase.h"
#include "e2010.h"


#define E2010_CHECK_MCU_VER(vh, vl, req_h, req_l) ((vh > req_h) || ((vh == req_h) && (vl >= req_l)))

typedef struct {
    CHAR McuName[25];   // название микроконтроллера
    CHAR Version[10];   // версия драйвера микроконтроллера
    CHAR Created[14];   // дата сборки драйвера микроконтроллера
    CHAR Manufacturer[25];  // производитель драйвера микроконтроллера
    CHAR Author[25];    // автор драйвера микроконтроллера
    CHAR Comment[128];  // строка комментария
} t_e2010_mcu_descriptor;


FDF(ULONG) DaqE2010::LoadBios(const char *FileName) {
    LONG PLDSize = 0;
    int status = L_SUCCESS;
    /* Загрузку PLD требуют только ревизии A и B, в ревизии
     * C PLD записан во Flash и загрузка не требуется (запросы игнорируются).
     * Тем не менее для нее вызываем DIOC_LOAD_BIOS с нулевым размером,
     * т.к. по этой команде идет зачистка возможной необорванной активности
     * по передаче данных */
    if ((pdu.t6.Rev == 'A') || (pdu.t6.Rev == 'B')) {
        LONG    NBytes;
        ULONG cbRet;
        CHAR  FName[512];

        int internal_name = (FileName == NULL) ||
                (FileName[0]=='\0') ||
                (FileName[0]=='\n') ||
                (FileName[0]=='\r');

        if (internal_name) {
            strcpy(FName, LCOMP_INSTALL_FIRMWARE_DIR);
            strcat(FName, "/");
            if (sl.BoardType == E2010) {
                strcat(FName, "e2010");
            } else {
                /* E20-10B  может быть индустриальной версией, которая требует
                   заливки другой прошивки */
                t_e2010_mcu_descriptor mcu_descr;
                bool industrial = false;
                status = inmbyte(FIRMWARE_DESCRIPTOR_ADDRESS, reinterpret_cast<UCHAR*>(&mcu_descr),
                                 sizeof(mcu_descr));
                if (status == L_SUCCESS) {
                    unsigned mcu_ver_h, mcu_ver_l;
                    sscanf(mcu_descr.Version, "%d.%d", &mcu_ver_h, &mcu_ver_l);
                    if (E2010_CHECK_MCU_VER(mcu_ver_h, mcu_ver_l, 2, 4)) {
                        UCHAR tg_info;
                        status = inmbyte(SEL_MODULE_TG_DATA, &tg_info, 1);
                        if (status == L_SUCCESS) {
                            industrial = tg_info & 1;
                        }
                    }
                }

                if (industrial) {
                    strcat(FName, "e2010mi");
                } else {
                    strcat(FName, "e2010m");
                }
            }
        } else {
            strncpy(FName, FileName, sizeof(FName) - 5);
        }

        if (status == L_SUCCESS) {
            FILE  *BiosFile = 0;
            strcat(FName,".pld");

            BiosFile=fopen(FName, "rb");
            if(!BiosFile) {
                status = L_ERROR;
            } else {
                PUCHAR  BiosCode=0;
                PUCHAR BC=0;

                fseek(BiosFile,0,SEEK_END);
                PLDSize=NBytes = ftell(BiosFile);
                rewind(BiosFile);

                BC=BiosCode=new UCHAR[NBytes+2];
                if(BiosCode==NULL)  {
                    status = L_ERROR;
                }

                if (status == L_SUCCESS) {
                    if (fread(BiosCode,1,NBytes,BiosFile) != (size_t)NBytes) {
                        status = L_ERROR;
                    }
                }


                fclose(BiosFile);


                // transfer bios to driver
                int len = 4096;
                // first call alloc memory, other simple add data
                while ((status == L_SUCCESS) && (NBytes > 0)) {
                    if (NBytes<len)
                        len=NBytes;
                    if(!LDeviceIoControl( hVxd, DIOC_SEND_BIOS,
                                          &NBytes,sizeof(LONG),
                                          BiosCode, len*sizeof(CHAR),
                                          &cbRet, NULL)) {
                        status = L_ERROR;
                    } else {
                        BiosCode+=len;
                        NBytes-=len;
                    }
                }
                delete[] BC;
            }
        }
    }

    if (status == L_SUCCESS) {
        ULONG cbRet;
        if(!LDeviceIoControl( hVxd, DIOC_LOAD_BIOS,
                              &PLDSize,sizeof(LONG),
                              NULL, 0,
                              &cbRet, NULL)) {
            status = L_ERROR;
        }
    }

    return status;
}
