#include "ldevusbu.h"

// Cmd - vendor code in this case
void COMMAND_E140(ldevusb *dev, u16 Cmd) {
  int status = -1;
   status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                              Cmd, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                                0, 0, NULL, 0, HZ*10);
}

// count in words, 2 - adrr
void GET_DATA_MEMORY_E140(ldevusb *dev, u16 *Data, u32 Count, u16 Addr) {
   int status = -1;
   int i,ss,s = Count/2048; // bytes
   u8 *Dat = kmalloc(4096,GFP_KERNEL);

   for(i = 0; i < s; ++i) {
      status = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                     V_GET_ARRAY_E140, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                 //(u16)(Addr+i*2048), 0, (u8 *)(&Data[2048*i]), 2048*sizeof(u16), HZ*10);
                 (u16)(Addr+i*2048), 0, (u8 *)Dat, 2048*sizeof(u16), HZ*10);
      memcpy(&Data[2048*i],Dat,2048*sizeof(u16));
   }

   ss = Count%2048;
   if(ss) {
      status = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                     V_GET_ARRAY_E140, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                // (u16)(Addr+s*2048), 0, (u8 *)(&Data[2048*s]), ss*sizeof(u16), HZ*10);
                (u16)(Addr+s*2048), 0, (u8 *)Dat, ss*sizeof(u16), HZ*10);
      memcpy(&Data[2048*s],Dat,ss*sizeof(u16));
   }
   kfree(Dat);
}

void PUT_DATA_MEMORY_E140(ldevusb *dev, u16 *Data, u32 Count, u16 Addr) {// how words
   int status = -1;
   int i,ss,s = Count/2048; // bytes
   u8 *Dat = kmalloc(4096,GFP_KERNEL);
   for(i = 0; i < s; ++i) {
      memcpy(Dat,&Data[2048*i],2048*sizeof(u16));
      status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                     V_PUT_ARRAY_E140, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                 //(u16)(Addr+i*2048), 0, (u8 *)(&Data[2048*i]), 2048*sizeof(u16), HZ*10);
                 (u16)(Addr+i*2048), 0, (u8 *)Dat, 2048*sizeof(u16), HZ*10);
   }

   ss = Count%2048;
   if(ss){
      memcpy(Dat,&Data[2048*s],ss*sizeof(u16));
      status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                     V_PUT_ARRAY_E140, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                 //(u16)(Addr+s*2048), 0, (u8 *)(&Data[2048*s]), ss*sizeof(u16), HZ*10);
                 (u16)(Addr+s*2048), 0, (u8 *)Dat, ss*sizeof(u16), HZ*10);
   }
   kfree(Dat);
}

u16 GET_DM_WORD_E140(ldevusb *dev, u16 Addr) {
   int status = -1;
   u16 Data;
   u16 *Dat = (u16 *)kmalloc(2,GFP_KERNEL);
   status = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                     V_GET_ARRAY_E140, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                     (u16)(Addr), 0, Dat, sizeof(u16), HZ*10);
   Data = Dat[0];
   kfree(Dat);
   return Data;   
}

void PUT_DM_WORD_E140(ldevusb *dev, u16 Addr, u16 Data) {
   int status = -1;
   u16 *Dat = (u16 *)kmalloc(2,GFP_KERNEL);   
   Dat[0]=Data;
   status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                     V_PUT_ARRAY_E140, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                 (u16)(Addr), 0, Dat, sizeof(u16), HZ*10);
    kfree(Dat);
}


u8 GET_PM_WORD_E140(ldevusb *dev, u16 Addr) {
   int status = -1;
   u8 Data;
   u8 *Dat = (u8 *)kmalloc(1,GFP_KERNEL);
   status = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                     V_GET_ARRAY_E140, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                     (u16)(Addr), 0, Dat, sizeof(u8), HZ*10);
    Data = Dat[0];
    kfree(Dat);
   return Data;   
}

void PUT_PM_WORD_E140(ldevusb *dev, u16 Addr, u8 Data) {
   int status = -1;
   u8 *Dat = (u8 *)kmalloc(1,GFP_KERNEL);   
   Dat[0]=Data;
   
   status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                     V_PUT_ARRAY_E140, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                 (u16)(Addr), 0, Dat, sizeof(u8), HZ*10);
    kfree(Dat);
}

//------------------------------------------------------------------------
// разрешение/запрещение режима записи в ППЗУ модуля
//------------------------------------------------------------------------
u32 EnableFlashWrite_E140(ldevusb *dev, u16 Flag) {
   PUT_PM_WORD_E140(dev, L_FLASH_ENABLED_E140, (u8)Flag);
   return 1;
}

//------------------------------------------------------------------------
// чтенние слова из ППЗУ
//------------------------------------------------------------------------
void ReadFlashWord_E140(ldevusb *dev, u16 FlashAddress, u16 *Data) {
   *Data = GET_DM_WORD_E140(dev,FlashAddress);
}

//------------------------------------------------------------------------
// запись слова в ППЗУ
//------------------------------------------------------------------------
void WriteFlashWord_E140(ldevusb *dev, u16 FlashAddress, u16 Data) {
   PUT_DM_WORD_E140(dev,FlashAddress, Data);
}


// SetFIFO - defined in E440.cpp

void EnableE140(ldevusb *dev, int b) {
    int i,status;
    ADC_PAR_E140_PACK_U ap;
    u16 st,extf,sens,mode;
    if(b) { // start ADC
        DbgPrint("Rate  %d \n", dev->adcPar.t3.Rate);
        DbgPrint("NCh  %d\n", dev->adcPar.t3.NCh);
        DbgPrint("Kadr  %d\n", dev->adcPar.t3.Kadr);
        DbgPrint("Stype  %d\n", dev->adcPar.t3.SynchroType);

        // pack adc parameters
        for(i = 0; i < 128; ++i) {
            ap.t1.Chn[i] = (u8)MAKE_E140CHAN(dev->adcPar.t3.Chn[i]);
        }
        ap.t1.Rate = dev->adcPar.t3.Rate;
        ap.t1.NCh = (u8)dev->adcPar.t3.NCh;
        ap.t1.Kadr = (u8)dev->adcPar.t3.Kadr;

        st = dev->adcPar.t3.SynchroType & 0x3;
        extf = dev->adcPar.t3.SynchroType & 0xC0;
        if(st == 1) {
            st = 2;
        } else if(st == 2) {
            st = 1;
        }
        sens = dev->adcPar.t3.SynchroSensitivity ? 2:0;
        mode = dev->adcPar.t3.SynchroMode ? 1:0;

        if(st==3) {
            st += (sens + mode);
        }
        st += extf;

        ap.t1.SynchroType = (u8)st;
        ap.t1.AdChannel = (u8)MAKE_E140CHAN(dev->adcPar.t3.AdChannel);
        ap.t1.AdPorog = dev->adcPar.t3.AdPorog;
      
        COMMAND_E140(dev, V_STOP_ADC_E140);

        PUT_DATA_MEMORY_E140(dev, (u16 *)&ap.bi, 68, L_ADC_PARS_BASE_E140);

        status=usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr));
        COMMAND_E140(dev, V_START_ADC_E140);
        DbgPrint("start start \n");
    } else { // stop ADC
        DbgPrint("stop stop \n");
        COMMAND_E140(dev, V_STOP_ADC_E140);
        DbgPrint("pipe aborted \n");
    }
}
