2020年的春节因为疫情的原因一直出不了门,听说melexis测温头价格从40块涨到400块,并且还买不到货;正好有同事要求调到驱动:mlx测温模块驱动,基于android平台:

3. app:

这个客户已经做好了,并且提供的应用接口,我只要在jni里实现接口就行了;

2. JNI 接口的封装:

open()

read()

write()

close()

1. 驱动调试:

由于规格书上说mlx使用smbus接口,本人用硬件i2c驱动来调试时遇到了麻烦,搞了两天都通讯不成功,不得已放弃了;于是只能改用io,用io来模拟i2c,这种方式很好用。

#if 8 // 888
static void SMBus_Delay(u16 time);
static void SMBus_StartBit(void);
static void SMBus_StopBit(void);
static void SMBus_SendBit(u8);
static u8 SMBus_SendByte(u8);
static u8 SMBus_ReceiveBit(void);
static u8 SMBus_ReceiveByte(u8);
static void SMBus_Delay(u16);
static int SMBus_Init(void);
static u16 SMBus_ReadMemory(u8, u8);
static u8 PEC_Calculation(u8*);
static unsigned long SMBus_ReadTemp(void);    //?????
static void SMBus_DisplayTemperature(void);    //?LCD?5,6?????
static int SMBus_Write(u8 slaveAddress, u8 command, u8 dataL,u8 dataH);

static unsigned long int mlx90616_value;
static char smbus_io_first = 1;
static void mlx90616_main(void)
{
    unsigned long int DATA;     
    if(smbus_io_first == 1){
        smbus_io_first = 0;
        SMBus_Init();//rk_gpio_init();
    }
    mlx90616_value = SMBus_ReadTemp();
}

//#include "myiic.h"
//#include "delay.h"
#define ACK     0
#define    NACK 1
#define SA                0x00 //????,??MLX90614????0x00,????????0x5a
#define RAM_ACCESS        0x00 //RAM access command
#define EEPROM_ACCESS    0x20 //EEPROM access command
#define RAM_TOBJ1        0x07 //To1 address in the eeprom

//#define SMBUS_PORT        GPIOB
#define SMBUS_SCK        113 //251 //GPIO_Pin_6
#define SMBUS_SDA        8 //237 //GPIO_Pin_7

#define RCC_APB2Periph_SMBUS_PORT        RCC_APB2Periph_GPIOB

#define SMBUS_SCK_H()        gpio_direction_output(SMBUS_SCK, 1) //SMBUS_PORT->BSRR = SMBUS_SCK
#define SMBUS_SCK_L()        gpio_direction_output(SMBUS_SCK, 0) //SMBUS_PORT->BRR = SMBUS_SCK
#define SMBUS_SDA_H()        gpio_direction_output(SMBUS_SDA, 1) //SMBUS_PORT->BSRR = SMBUS_SDA
#define SMBUS_SDA_L()        gpio_direction_output(SMBUS_SDA, 0) //SMBUS_PORT->BRR = SMBUS_SDA

//#define SMBUS_SDA_PIN()        SMBUS_PORT->IDR & SMBUS_SDA //??????
static int SMBUS_SDA_PIN(void)
{
    int ret = 0;    
    gpio_direction_input(SMBUS_SDA);
    ret = gpio_get_value(SMBUS_SDA);
    return ret;
}

/*******************************************************************************
* ???: SMBus_StartBit
* ??  : ?????
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static void SMBus_StartBit(void)
{
    if(smbus_io_first == 1){
        smbus_io_first = 0;
        if(0 != SMBus_Init()) {
            smbus_io_first =0xff; // io init failed
        }
    }
    SMBUS_SDA_H();        // Set SDA line
    SMBus_Delay(5);        // Wait a few microseconds
    SMBUS_SCK_H();        // Set SCL line
    SMBus_Delay(5);        // Generate bus free time between Stop
    SMBUS_SDA_L();        // Clear SDA line
    SMBus_Delay(5);        // Hold time after (Repeated) Start
    // Condition. After this period, the first clock is generated.
    //(Thd:sta=4.0us min)
    SMBUS_SCK_L();        // Clear SCL line
    SMBus_Delay(5);        // Wait a few microseconds
}

/*******************************************************************************
* ???: SMBus_StopBit
* ??: Generate STOP condition on SMBus
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static void SMBus_StopBit(void)
{
    if(smbus_io_first == 1){
        smbus_io_first = 0;
        if(0 != SMBus_Init()) {
            smbus_io_first =0xff; // io init failed
        }
    }
    SMBUS_SCK_L();        // Clear SCL line
    SMBus_Delay(5);        // Wait a few microseconds
    SMBUS_SDA_L();        // Clear SDA line
    SMBus_Delay(5);        // Wait a few microseconds
    SMBUS_SCK_H();        // Set SCL line
    SMBus_Delay(5);        // Stop condition setup time(Tsu:sto=4.0us min)
    SMBUS_SDA_H();        // Set SDA line
}

/*******************************************************************************
* ???: SMBus_SendByte
* ??: Send a byte on SMBus
* Input          : Tx_buffer
* Output         : None
* Return         : None
*******************************************************************************/
static u8 SMBus_SendByte(u8 Tx_buffer)
{
    u8    Bit_counter;
    u8    Ack_bit;
    u8    bit_out;

for(Bit_counter=8; Bit_counter; Bit_counter--)
    {
        if (Tx_buffer&0x80)
        {
            bit_out=1;   // If the current bit of Tx_buffer is 1 set bit_out
        }
        else
        {
            bit_out=0;  // else clear bit_out
        }
        SMBus_SendBit(bit_out);        // Send the current bit on SDA
        Tx_buffer<<=1;                // Get next bit for checking
    }

Ack_bit=SMBus_ReceiveBit();        // Get acknowledgment bit
    return    Ack_bit;
}

/*******************************************************************************
* ???: SMBus_SendBit
* ??: Send a bit on SMBus 82.5kHz
* Input          : bit_out
* Output         : None
* Return         : None
*******************************************************************************/
static void SMBus_SendBit(u8 bit_out)
{
    if(bit_out==0)
    {
        SMBUS_SDA_L();
    }
    else
    {
        SMBUS_SDA_H();
    }
    SMBus_Delay(2);                    // Tsu:dat = 250ns minimum
    SMBUS_SCK_H();                    // Set SCL line
    SMBus_Delay(6);                    // High Level of Clock Pulse
    SMBUS_SCK_L();                    // Clear SCL line
    SMBus_Delay(3);                    // Low Level of Clock Pulse
//    SMBUS_SDA_H();                    // Master release SDA line ,
    return;
}

/*******************************************************************************
* Function Name  : SMBus_ReceiveBit
* Description    : Receive a bit on SMBus
* Input          : None
* Output         : None
* Return         : Ack_bit
*******************************************************************************/
static u8 SMBus_ReceiveBit(void)
{
    u8 Ack_bit;

SMBUS_SDA_H();          //?????????,????
    SMBus_Delay(2);            // High Level of Clock Pulse
    SMBUS_SCK_H();            // Set SCL line
    SMBus_Delay(5);            // High Level of Clock Pulse
    if (SMBUS_SDA_PIN())
    {
        Ack_bit=1;
    }
    else
    {
        Ack_bit=0;
    }
    SMBUS_SCK_L();            // Clear SCL line
    SMBus_Delay(3);            // Low Level of Clock Pulse

return    Ack_bit;
}

/*******************************************************************************
* ???: SMBus_ReceiveByte
* ??: Receive a byte on SMBus
* Input          : ack_nack
* Output         : None
* Return         : RX_buffer
*******************************************************************************/
static u8 SMBus_ReceiveByte(u8 ack_nack)
{
    u8     RX_buffer;
    u8    Bit_Counter;

for(Bit_Counter=8; Bit_Counter; Bit_Counter--)
    {
        if(SMBus_ReceiveBit())            // Get a bit from the SDA line
        {
            RX_buffer <<= 1;            // If the bit is HIGH save 1  in RX_buffer
            RX_buffer |=0x01;
        }
        else
        {
            RX_buffer <<= 1;            // If the bit is LOW save 0 in RX_buffer
            RX_buffer &=0xfe;
        }
    }
    SMBus_SendBit(ack_nack);            // Sends acknowledgment bit
    return RX_buffer;
}

/*******************************************************************************
* ???: SMBus_Delay
* ??: ??  ?????1us
* Input          : time
* Output         : None
* Return         : None
*******************************************************************************/
static void SMBus_Delay(u16 time)
{
    u16 i, j;
    for (i=0; i<5; i++)
    {
        udelay(time);//for (j=0; j<time; j++);
    }
}

/*******************************************************************************
* ???: SMBus_Init
* ??: SMBus???
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static int SMBus_Init()
{
    #if 0
    GPIO_InitTypeDef    GPIO_InitStructure;

/* Enable SMBUS_PORT clocks */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SMBUS_PORT, ENABLE);

/*??SMBUS_SCK?SMBUS_SDA????????*/
    GPIO_InitStructure.GPIO_Pin = SMBUS_SDA;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(SMBUS_PORT, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = SMBUS_SCK ;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(SMBUS_PORT, &GPIO_InitStructure);
    SMBUS_SCK_H();
    SMBUS_SDA_H();
    #else
    
    int err;
    err = gpio_request(SMBUS_SDA,"RK_GPIO_SDA");
    if(err){
            printk("Cannot Request the gpio of    %d\n", SMBUS_SDA);
            return -1;
    }

err = gpio_direction_output(SMBUS_SDA, 1);
    if (err < 0) {
            printk("Cannot set SMBUS_SDA output mode. \n");
            gpio_free(SMBUS_SDA);
            return -1;
    }
    //gpio_set_value(RK_GPIO_SDA, 1);
    radio_dbg("liuxd SMBUS_SDA init ok\n");
    
    err = gpio_request(SMBUS_SCK,"RK_GPIO_SCL");
    if(err){
            printk("Cannot Request SMBUS_SCK    %d\n", SMBUS_SCK);
            return -1;
    }

err = gpio_direction_output(SMBUS_SCK, 1);
    if (err < 0) {
            printk("Cannot set SMBUS_SCK output mode. \n");
            gpio_free(SMBUS_SCK);
            return -1;
    }
    //gpio_set_value(SMBUS_SCK, 1);
    radio_dbg("liuxd RK_GPIO_SCL init ok\n");    
    SMBUS_SCK_H();
    SMBUS_SDA_H();
    return 0;
    #endif
}

/*******************************************************************************
 * ???: SMBus_ReadMemory
 * ??: READ DATA FROM RAM/EEPROM
 * Input          : slaveAddress, command
 * Return         : Data
*******************************************************************************/
static u16 SMBus_ReadMemory(u8 slaveAddress, u8 command)
{
    u16 data;            // Data storage (DataH:DataL)
    u8 Pec;                // PEC byte storage
    u8 DataL=0;            // Low data byte storage
    u8 DataH=0;            // High data byte storage
    u8 arr[6];            // Buffer for the sent bytes
    u8 PecReg;            // Calculated PEC byte storage
    u8 ErrorCounter;    // Defines the number of the attempts for communication with MLX90614

ErrorCounter=0x00;                // Initialising of ErrorCounter
    slaveAddress <<= 1;    //2-7???????
    
    do
    {
repeat:
        SMBus_StopBit();                //If slave send NACK stop comunication
        --ErrorCounter;                    //Pre-decrement ErrorCounter
        if(!ErrorCounter)                 //ErrorCounter=0?
        {
            break;                        //Yes,go out from do-while{}
        }

SMBus_StartBit();                //Start condition
        if(SMBus_SendByte(slaveAddress))//Send SlaveAddress ???Wr=0????????
        {
            goto    repeat;                //Repeat comunication again
        }
        if(SMBus_SendByte(command))        //Send command
        {
            goto    repeat;                //Repeat comunication again
        }

SMBus_StartBit();                    //Repeated Start condition
        if(SMBus_SendByte(slaveAddress+1))    //Send SlaveAddress ???Rd=1????????
        {
            goto    repeat;                 //Repeat comunication again
        }

DataL = SMBus_ReceiveByte(ACK);    //Read low data,master must send ACK
        DataH = SMBus_ReceiveByte(ACK); //Read high data,master must send ACK
        Pec = SMBus_ReceiveByte(NACK);    //Read PEC byte, master must send NACK
        SMBus_StopBit();                //Stop condition

arr[5] = slaveAddress;        //
        arr[4] = command;            //
        arr[3] = slaveAddress+1;    //Load array arr
        arr[2] = DataL;                //
        arr[1] = DataH;                //
        arr[0] = 0;                    //
        PecReg=PEC_Calculation(arr);//Calculate CRC
    }
    while(PecReg != Pec);        //If received and calculated CRC are equal go out from do-while{}

data = (DataH<<8) | DataL;    //data=DataH:DataL
    return data;
}

/*******************************************************************************
* ???: PEC_calculation
* ?? : ????
* Input          : pec[]
* Output         : None
* Return         : pec[0]-this byte contains calculated crc value
*******************************************************************************/
static u8 PEC_Calculation(u8 pec[])
{
    u8     crc[6];
    u8    BitPosition=47;
    u8    shift;
    u8    i;
    u8    j;
    u8    temp;

do
    {
        /*Load pattern value 0x000000000107*/
        crc[5]=0;
        crc[4]=0;
        crc[3]=0;
        crc[2]=0;
        crc[1]=0x01;
        crc[0]=0x07;

/*Set maximum bit position at 47 ( six bytes byte5...byte0,MSbit=47)*/
        BitPosition=47;

/*Set shift position at 0*/
        shift=0;

/*Find first "1" in the transmited message beginning from the MSByte byte5*/
        i=5;
        j=0;
        while((pec[i]&(0x80>>j))==0 && i>0)
        {
            BitPosition--;
            if(j<7)
            {
                j++;
            }
            else
            {
                j=0x00;
                i--;
            }
        }/*End of while */

/*Get shift value for pattern value*/
        shift=BitPosition-8;

/*Shift pattern value */
        while(shift)
        {
            for(i=5; i<0xFF; i--)
            {
                if((crc[i-1]&0x80) && (i>0))
                {
                    temp=1;
                }
                else
                {
                    temp=0;
                }
                crc[i]<<=1;
                crc[i]+=temp;
            }/*End of for*/
            shift--;
        }/*End of while*/

/*Exclusive OR between pec and crc*/
        for(i=0; i<=5; i++)
        {
            pec[i] ^=crc[i];
        }/*End of for*/
    }
    while(BitPosition>8); /*End of do-while*/

return pec[0];
}

/*******************************************************************************
 * ???: SMBus_ReadTemp
 * ??: ????????
 * Return         : SMBus_ReadMemory(0x00, 0x07)*0.02-273.15
*******************************************************************************/
static unsigned long SMBus_ReadTemp(void)
{   
    //return SMBus_ReadMemory(SA, RAM_ACCESS|RAM_TOBJ1)*0.02-273.15;
    unsigned long tmp = SMBus_ReadMemory(SA, RAM_ACCESS|RAM_TOBJ1);
    tmp = abs(tmp*2-27315);
    //radio_dbg("liuxd tmp=%d\n",tmp);
    return tmp;
    
}

/****
*
*/
static int SMBus_Write(u8 slaveAddress, u8 command, u8 dataL,u8 dataH)
{
    
    int err = -1;        // result: 0 is ok; 
    u8 ErrorCounter;    // Defines the number of the attempts for communication with MLX90614
    u8 arr[6],Pecreg;    
    ErrorCounter=0x00;                // Initialising of ErrorCounter
    slaveAddress <<= 1;    //2-7???????
    arr[5] = 0;
    arr[4] = slaveAddress;
    arr[3] = command;
    arr[2] = dataL;
    arr[1] = dataH;
    arr[0] = 0;

Pecreg = PEC_Calculation(arr);  
    do
    {
repeat:
        SMBus_StopBit();                //If slave send NACK stop comunication
        --ErrorCounter;                    //Pre-decrement ErrorCounter
        if(!ErrorCounter)                 //ErrorCounter=0?
        {
            break;                        //Yes,go out from do-while{}
        }

SMBus_StartBit();                //Start condition
        if(SMBus_SendByte(slaveAddress))//Send SlaveAddress ???Wr=0????????
        {
            goto    repeat;                //Repeat comunication again
        }
        //radio_dbg("liuxd step111\n");
        if(SMBus_SendByte(command))        //Send command
        {
            goto    repeat;                //Repeat comunication again
        }
        //radio_dbg("liuxd step222\n");
        if(SMBus_SendByte(dataL))        //Send data
        {
            goto    repeat;                //Repeat comunication again
        }
        //radio_dbg("liuxd step333\n");
        if(SMBus_SendByte(dataH))        //Send data
        {
            goto    repeat;                //Repeat comunication again
        }
        //radio_dbg("liuxd step444\n");
        if(SMBus_SendByte(Pecreg))        //Send data
        {
            goto    repeat;                //Repeat comunication again
        }        
        
        SMBus_StopBit();                //Stop condition
        //radio_dbg("liuxd step555\n");
        err = 0;
        break;
        
    }
    while(err);        //If received and calculated CRC are equal go out from do-while{}    
    return err;
}

#endif

#if 1
//#define SLA_8BIT     1
#define MAX_TIMES     3
static int MLX90641_I2CRead(uint8_t slaveAddr, uint16_t startAddress,uint16_t nMemAddressRead, uint16_t *data)
{
    uint8_t sa;
    int ack = 0;
    int cnt = 0;
    int i = 0;
    char cmd[2] = {0,0};
    char i2cData[1664] = {0};
    uint16_t *p;
    u8 ErrorCounter;
    u8 flag = 1;
    int no;
    char * ptr;
    
    p = data;
    ptr = i2cData;
    sa = (slaveAddr << 1);
    cmd[0] = startAddress >> 8;
    cmd[1] = startAddress & 0x00FF;
    ErrorCounter=MAX_TIMES;
    no = nMemAddressRead<<1;
    
    
    do
    {
repeat:
        SMBus_StopBit();                //If slave send NACK stop comunication
        if(smbus_io_first == 0xff){
            printk("io alloc failed,MLX90641_I2CRead abort!\n");
            return -1;
        }
        --ErrorCounter;                 //Pre-decrement ErrorCounter
        if(!ErrorCounter)                //ErrorCounter=0?
        {
            return -1;                        //Yes,go out from do-while{}
        }

SMBus_StartBit();                //Start condition
        if(SMBus_SendByte(sa))//Send SlaveAddress ???Wr=0????????
        {
            goto    repeat;             //Repeat comunication again
        }
        if(SMBus_SendByte(cmd[0]))     //Send command
        {
            goto    repeat;             //Repeat comunication again
        }
        if(SMBus_SendByte(cmd[1]))    
        {
            goto    repeat;             
        }

SMBus_StartBit();                    //Repeated Start condition
        if(SMBus_SendByte(sa+1))    //Send SlaveAddress ???Rd=1????????
        {
            goto    repeat;                 //Repeat comunication again
        }

for(i=0;i<no-1;i++){
            *ptr = SMBus_ReceiveByte(ACK);
            ptr++;
        }
        
        *ptr = SMBus_ReceiveByte(NACK);    //Read PEC byte, master must send NACK
        SMBus_StopBit();                //Stop condition
        flag = 0;
        //dump_raw(s,no);
    }
    while(flag);        //If received and calculated CRC are equal go out from do-while{}
    for(cnt=0; cnt < nMemAddressRead; cnt++)
    {
        i = cnt << 1;
        *p++ = (int)i2cData[i]*256 + (int)i2cData[i+1];
    } 
    return 0;
    
  
}

static void MLX90641_I2CFreqSet(int freq)
{
    //freqCnt = freq>>1;
}

static int MLX90641_I2CWrite(uint8_t slaveAddr, uint16_t writeAddress, uint16_t data)
{
    uint8_t sa;
    int ack = 0,i;
    char cmd[4] = {0,0,0,0};
    static uint16_t dataCheck;
    u8 ErrorCounter,err =1;
    ErrorCounter=MAX_TIMES;

sa = (slaveAddr << 1);
    cmd[0] = writeAddress >> 8;
    cmd[1] = writeAddress & 0x00FF;
    cmd[2] = data >> 8;
    cmd[3] = data & 0x00FF;

do
    {
repeat:
        SMBus_StopBit();                //If slave send NACK stop comunication
        if(smbus_io_first == 0xff){
            printk("io alloc failed,MLX90641_I2CRead abort!\n");
            return -1;
        }
        --ErrorCounter;                    //Pre-decrement ErrorCounter
        if(!ErrorCounter)                 //ErrorCounter=0?
        {
            return -1;                        //Yes,go out from do-while{}
        }

SMBus_StartBit();                //Start condition
        if(SMBus_SendByte(sa))//Send SlaveAddress ???Wr=0????????
        {
            goto    repeat;                //Repeat comunication again
        }
        
        //if(SMBus_SendByte(cmd))        //Send command
        //{
        //    goto    repeat;                //Repeat comunication again
        //}

for(i=0;i<4;i++){
            if(SMBus_SendByte(cmd[i]))        //Send data
            {
                goto    repeat;                //Repeat comunication again
            }
        }                
        
        SMBus_StopBit();                //Stop condition
        
        err = 0;
        break;
        
    }
    while(err);    
    MLX90641_I2CRead(slaveAddr,writeAddress,1, &dataCheck);
    
    if ( dataCheck != data)
    {
        return -2;
    } 
    return 0;
    
}

static float fabs(float a)
{
    if(a > 0.000001)
        return a;
    else
        return -a;
}

static float pow(float x,double y)
{
    if(y>0)
        return(x*pow(x,y-1));
    else
        return 1;
}

#define DBL_EPSILON 0.0000001
static double sqrt(double A)
{
    double x0 = A + 0.25, x1, xx = x0;
    int second = 0;
    if(A<=DBL_EPSILON){
        x1 = DBL_EPSILON;
        //printk("sqrt < DBL_EPSILON\n");
        return x1;
    }
    for(;;) {
        x1 = (x0*x0 + A) / (2*x0);
        if(fabs(x1 - x0) <= DBL_EPSILON) break;
        if(xx == x1) break; // to break two value cycle.
        if(second++ > 32) {printk("sqrt > 32\n");break;}
        xx = x0;
        x0 = x1;
    }
 
    return x1;
}

#define SCALEALPHA 0.000001
    
typedef struct
{
    int16_t kVdd;
    int16_t vdd25;
    float KvPTAT;
    float KtPTAT;
    uint16_t vPTAT25;
    float alphaPTAT;
    int16_t gainEE;
    float tgc;
    float cpKv;
    float cpKta;
    uint8_t resolutionEE;
    uint8_t calibrationModeEE;
    float KsTa;
    float ksTo[8];
    int16_t ct[8];
    uint16_t alpha[192]; 
    uint8_t alphaScale;   
    int16_t offset[2][192];    
    int8_t kta[192];
    uint8_t ktaScale;    
    int8_t kv[192];
    uint8_t kvScale;
    float cpAlpha;
    int16_t cpOffset;
    float emissivityEE; 
    uint16_t brokenPixels[2];
} paramsMLX90641;

static int MLX90641_DumpEE(uint8_t slaveAddr, uint16_t *eeData);
static int MLX90641_GetFrameData(uint8_t slaveAddr, uint16_t *frameData);
static int MLX90641_ExtractParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static float MLX90641_GetVdd(uint16_t *frameData, const paramsMLX90641 *params);
static float MLX90641_GetTa(uint16_t *frameData, const paramsMLX90641 *params);
static void MLX90641_GetImage(uint16_t *frameData, const paramsMLX90641 *params, float *result);
static void MLX90641_CalculateTo(uint16_t *frameData, const paramsMLX90641 *params, float emissivity, float tr, float *result);
static int MLX90641_SetResolution(uint8_t slaveAddr, uint8_t resolution);
static int MLX90641_GetCurResolution(uint8_t slaveAddr);
static int MLX90641_SetRefreshRate(uint8_t slaveAddr, uint8_t refreshRate);   
static int MLX90641_GetRefreshRate(uint8_t slaveAddr);  
static int MLX90641_GetSubPageNumber(uint16_t *frameData);
static float MLX90641_GetEmissivity(const paramsMLX90641 *mlx90641);
static void MLX90641_BadPixelsCorrection(uint16_t *pixels, float *to, paramsMLX90641 *params);

static void ExtractVDDParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractPTATParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractGainParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractTgcParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractEmissivityParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractResolutionParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractKsTaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractKsToParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractAlphaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractOffsetParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractKtaPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractKvPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static void ExtractCPParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
static int ExtractDeviatingPixels(uint16_t *eeData, paramsMLX90641 *mlx90641);
static int CheckEEPROMValid(uint16_t *eeData); 
static int HammingDecode(uint16_t *eeData);

//------------------------------------------------------------------------------
  
static int MLX90641_DumpEE(uint8_t slaveAddr, uint16_t *eeData)
{
     int error = 1;
     #if 1 // org
     error = MLX90641_I2CRead(slaveAddr, 0x2400, 832, eeData);
     #else
     error = 0 ;//MLX90641_I2CRead(slaveAddr, 0x2400, 32, eeData);
     #endif
     if (error == 0)
     {
        error = HammingDecode(eeData); 
        //printk("liuxd MLX90641_DumpEE ok\n");
     }else {
         printk("liuxd MLX90641_DumpEE ng\n");
     }
         
     return error;
}

//------------------------------------------------------------------------------

static int HammingDecode(uint16_t *eeData)
{
    int error = 0;
    int16_t parity[5];
    int8_t D[16];
    int16_t check;
    uint16_t data;
    uint16_t mask;
    int addr,i;
    
    for ( addr=16; addr<832; addr++)
    {
        parity[0] = -1;
        parity[1] = -1;
        parity[2] = -1;
        parity[3] = -1;
        parity[4] = -1;
        
        data = eeData[addr];
        mask = 1;
        for(  i = 0; i < 16; i++)
        {          
          D[i] = (data & mask) >> i;
          mask = mask << 1;
        }
        
        parity[0] = D[0]^D[1]^D[3]^D[4]^D[6]^D[8]^D[10]^D[11];
        parity[1] = D[0]^D[2]^D[3]^D[5]^D[6]^D[9]^D[10]^D[12];
        parity[2] = D[1]^D[2]^D[3]^D[7]^D[8]^D[9]^D[10]^D[13];
        parity[3] = D[4]^D[5]^D[6]^D[7]^D[8]^D[9]^D[10]^D[14];
        parity[4] = D[0]^D[1]^D[2]^D[3]^D[4]^D[5]^D[6]^D[7]^D[8]^D[9]^D[10]^D[11]^D[12]^D[13]^D[14]^D[15];
       
        if ((parity[0]!=0) || (parity[1]!=0) || (parity[2]!=0) || (parity[3]!=0) || (parity[4]!=0))
        {        
            check = (parity[0]<<0) + (parity[1]<<1) + (parity[2]<<2) + (parity[3]<<3) + (parity[4]<<4);
    
            if ((check > 15)&&(check < 32))
            {
                switch (check)
                {    
                    case 16:
                        D[15] = 1 - D[15];
                        break;
                    
                    case 24:
                        D[14] = 1 - D[14];
                        break;
                        
                    case 20:
                        D[13] = 1 - D[13];
                        break;
                        
                    case 18:
                        D[12] = 1 - D[12];
                        break;                                
                        
                    case 17:
                        D[11] = 1 - D[11];
                        break;
                        
                    case 31:
                        D[10] = 1 - D[10];
                        break;
                        
                    case 30:
                        D[9] = 1 - D[9];
                        break;
                    
                    case 29:
                        D[8] = 1 - D[8];
                        break;                
                    
                    case 28:
                        D[7] = 1 - D[7];
                        break;
                        
                    case 27:
                        D[6] = 1 - D[6];
                        break;
                            
                    case 26:
                        D[5] = 1 - D[5];
                        break;    
                        
                    case 25:
                        D[4] = 1 - D[4];
                        break;     
                        
                    case 23:
                        D[3] = 1 - D[3];
                        break; 
                        
                    case 22:
                        D[2] = 1 - D[2];
                        break; 
                            
                    case 21:
                        D[1] = 1 - D[1];
                        break; 
                        
                    case 19:
                        D[0] = 1 - D[0];
                        break;     
                                     
                }
               
                if(error == 0)
                {
                    error = -9;
                   
                }
                
                data = 0;
                mask = 1;
                for(  i = 0; i < 16; i++)
                {                    
                    data = data + D[i]*mask;
                    mask = mask << 1;
                }
       
            }
            else
            {
                error = -10;                
            }   
         }
        
        eeData[addr] = data & 0x07FF;
    }
    
    return error;
}

//------------------------------------------------------------------------------

static int MLX90641_GetFrameData(uint8_t slaveAddr, uint16_t *frameData)
{
    uint16_t dataReady = 1;
    uint16_t controlRegister1;
    uint16_t statusRegister;
    int error = 1;
    uint8_t cnt = 0;
    uint8_t subPage = 0;
    
    dataReady = 0;
    while(dataReady == 0)
    {
        error = MLX90641_I2CRead(slaveAddr, 0x8000, 1, &statusRegister);
        if(error != 0)
        {
            return error;
        }    
        dataReady = statusRegister & 0x0008;
    }   
    subPage = statusRegister & 0x0001;
        
    while(dataReady != 0 && cnt < 5)
    { 
        error = MLX90641_I2CWrite(slaveAddr, 0x8000, 0x0030);
        if(error == -1)
        {
            return error;
        }
            
        if(subPage == 0)
        { 
            error = MLX90641_I2CRead(slaveAddr, 0x0400, 32, frameData); 
            if(error != 0)
            {
                return error;
            }
            error = MLX90641_I2CRead(slaveAddr, 0x0440, 32, frameData+32); 
            if(error != 0)
            {
                return error;
            }
            error = MLX90641_I2CRead(slaveAddr, 0x0480, 32, frameData+64); 
            if(error != 0)
            {
                return error;
            }
            error = MLX90641_I2CRead(slaveAddr, 0x04C0, 32, frameData+96); 
            if(error != 0)
            {
                return error;
            }
            error = MLX90641_I2CRead(slaveAddr, 0x0500, 32, frameData+128); 
            if(error != 0)
            {
                return error;
            }
            error = MLX90641_I2CRead(slaveAddr, 0x0540, 32, frameData+160); 
            if(error != 0)
            {
                return error;
            }
        }    
        else
        {
             error = MLX90641_I2CRead(slaveAddr, 0x0420, 32, frameData); 
            if(error != 0)
            {
                return error;
            }
            error = MLX90641_I2CRead(slaveAddr, 0x0460, 32, frameData+32); 
            if(error != 0)
            {
                return error;
            }
            error = MLX90641_I2CRead(slaveAddr, 0x04A0, 32, frameData+64); 
            if(error != 0)
            {
                return error;
            }
            error = MLX90641_I2CRead(slaveAddr, 0x04E0, 32, frameData+96); 
            if(error != 0)
            {
                return error;
            }
            error = MLX90641_I2CRead(slaveAddr, 0x0520, 32, frameData+128); 
            if(error != 0)
            {
                return error;
            }
            error = MLX90641_I2CRead(slaveAddr, 0x0560, 32, frameData+160); 
            if(error != 0)
            {
                return error;
            }
        }   
        
        error = MLX90641_I2CRead(slaveAddr, 0x0580, 48, frameData+192); 
        if(error != 0)
        {
            return error;
        }            
                   
        error = MLX90641_I2CRead(slaveAddr, 0x8000, 1, &statusRegister);
        if(error != 0)
        {
            return error;
        }    
        dataReady = statusRegister & 0x0008;
        subPage = statusRegister & 0x0001;      
        cnt = cnt + 1;
    }
    
    if(cnt > 4)
    {
        return -8;
    }    
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
    
    frameData[240] = controlRegister1;
    frameData[241] = statusRegister & 0x0001;
    
    if(error != 0)
    {
        return error;
    }
    
    return frameData[241];    
}

//------------------------------------------------------------------------------

static int MLX90641_ExtractParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    int error = CheckEEPROMValid(eeData);
    
    if(error == 0)
    {
        ExtractVDDParameters(eeData, mlx90641);
        ExtractPTATParameters(eeData, mlx90641);
        ExtractGainParameters(eeData, mlx90641);
        ExtractTgcParameters(eeData, mlx90641);
        ExtractEmissivityParameters(eeData, mlx90641);
        ExtractResolutionParameters(eeData, mlx90641);
        ExtractKsTaParameters(eeData, mlx90641);
        ExtractKsToParameters(eeData, mlx90641);
        ExtractAlphaParameters(eeData, mlx90641);
        ExtractOffsetParameters(eeData, mlx90641);
        ExtractKtaPixelParameters(eeData, mlx90641);
        ExtractKvPixelParameters(eeData, mlx90641);
        ExtractCPParameters(eeData, mlx90641);
        error = ExtractDeviatingPixels(eeData, mlx90641);  
    }
    
    return error;

}

//------------------------------------------------------------------------------

static int MLX90641_SetResolution(uint8_t slaveAddr, uint8_t resolution)
{
    uint16_t controlRegister1;
    int value;
    int error;
    
    value = (resolution & 0x03) << 10;
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
    
    if(error == 0)
    {
        value = (controlRegister1 & 0xF3FF) | value;
        error = MLX90641_I2CWrite(slaveAddr, 0x800D, value);        
    }    
    
    return error;
}

//------------------------------------------------------------------------------

static int MLX90641_GetCurResolution(uint8_t slaveAddr)
{
    uint16_t controlRegister1;
    int resolutionRAM;
    int error;
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
    if(error != 0)
    {
        return error;
    }    
    resolutionRAM = (controlRegister1 & 0x0C00) >> 10;
    
    return resolutionRAM; 
}

//------------------------------------------------------------------------------

static int MLX90641_SetRefreshRate(uint8_t slaveAddr, uint8_t refreshRate)
{
    uint16_t controlRegister1;
    int value;
    int error;
    
    value = (refreshRate & 0x07)<<7;
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
    if(error == 0)
    {
        value = (controlRegister1 & 0xFC7F) | value;
        error = MLX90641_I2CWrite(slaveAddr, 0x800D, value);
    }    
    
    return error;
}

//------------------------------------------------------------------------------

static int MLX90641_GetRefreshRate(uint8_t slaveAddr)
{
    uint16_t controlRegister1;
    int refreshRate;
    int error;
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
    if(error != 0)
    {
        return error;
    }    
    refreshRate = (controlRegister1 & 0x0380) >> 7;
    
    return refreshRate;
}

//------------------------------------------------------------------------------

static void MLX90641_CalculateTo(uint16_t *frameData, const paramsMLX90641 *params, float emissivity, float tr, float *result)
{
    float vdd;
    float ta;
    float ta4;
    float tr4;
    float taTr;
    float gain;
    float irDataCP;
    float irData;
    float alphaCompensated;
    float Sx;
    float To;
    float alphaCorrR[8];
    int8_t range;
    uint16_t subPage;
    float ktaScale;
    float kvScale;
    float alphaScale;
    float kta;
    float kv;
    int pixelNumber;
    
    subPage = frameData[241];
    vdd = MLX90641_GetVdd(frameData, params);
    ta = MLX90641_GetTa(frameData, params);    
    ta4 = (ta + 273.15);
    ta4 = ta4 * ta4;
    ta4 = ta4 * ta4;
    tr4 = (tr + 273.15);
    tr4 = tr4 * tr4;
    tr4 = tr4 * tr4;
    
    taTr = tr4 - (tr4-ta4)/emissivity;
    
    ktaScale = pow(2,(double)params->ktaScale);
    kvScale = pow(2,(double)params->kvScale);
    alphaScale = pow(2,(double)params->alphaScale);
    
    alphaCorrR[1] = 1 / (1 + params->ksTo[1] * 20);
    alphaCorrR[0] = alphaCorrR[1] / (1 + params->ksTo[0] * 20);
    alphaCorrR[2] = 1 ;
    alphaCorrR[3] = (1 + params->ksTo[2] * params->ct[3]);
    alphaCorrR[4] = alphaCorrR[3] * (1 + params->ksTo[3] * (params->ct[4] - params->ct[3]));
    alphaCorrR[5] = alphaCorrR[4] * (1 + params->ksTo[4] * (params->ct[5] - params->ct[4]));
    alphaCorrR[6] = alphaCorrR[5] * (1 + params->ksTo[5] * (params->ct[6] - params->ct[5]));
    alphaCorrR[7] = alphaCorrR[6] * (1 + params->ksTo[6] * (params->ct[7] - params->ct[6]));
    
//------------------------- Gain calculation -----------------------------------    
    gain = frameData[202];
    if(gain > 32767)
    {
        gain = gain - 65536;
    }
    
    gain = params->gainEE / gain; 
  
//------------------------- To calculation -------------------------------------        
    irDataCP = frameData[200];  
    if(irDataCP > 32767)
    {
        irDataCP = irDataCP - 65536;
    }
    irDataCP = irDataCP * gain;

irDataCP = irDataCP - params->cpOffset * (1 + params->cpKta * (ta - 25)) * (1 + params->cpKv * (vdd - 3.3));
    
    for(  pixelNumber = 0; pixelNumber < 192; pixelNumber++)
    {      
        irData = frameData[pixelNumber];
        if(irData > 32767)
        {
            irData = irData - 65536;
        }
        irData = irData * gain;
        
        kta = (float)params->kta[pixelNumber]/ktaScale;
        kv = (float)params->kv[pixelNumber]/kvScale;
            
        irData = irData - params->offset[subPage][pixelNumber]*(1 + kta*(ta - 25))*(1 + kv*(vdd - 3.3));                
    
        irData = irData - params->tgc * irDataCP;
        
        irData = irData / emissivity;
        
        alphaCompensated = SCALEALPHA*alphaScale/params->alpha[pixelNumber];
        alphaCompensated = alphaCompensated*(1 + params->KsTa * (ta - 25));
        
        Sx = alphaCompensated * alphaCompensated * alphaCompensated * (irData + alphaCompensated * taTr);
        Sx = sqrt(sqrt(Sx)) * params->ksTo[2];
        
        To = sqrt(sqrt(irData/(alphaCompensated * (1 - params->ksTo[2] * 273.15) + Sx) + taTr)) - 273.15;
                
        if(To < params->ct[1])
        {
            range = 0;
        }
        else if(To < params->ct[2])   
        {
            range = 1;            
        }   
        else if(To < params->ct[3])
        {
            range = 2;            
        }
        else if(To < params->ct[4])
        {
            range = 3;            
        }
        else if(To < params->ct[5])
        {
            range = 4;            
        }
        else if(To < params->ct[6])
        {
            range = 5;            
        }
        else if(To < params->ct[7])
        {
            range = 6;            
        }
        else
        {
            range = 7;            
        }      
        
        To = sqrt(sqrt(irData / (alphaCompensated * alphaCorrR[range] * (1 + params->ksTo[range] * (To - params->ct[range]))) + taTr)) - 273.15;
        
        result[pixelNumber] = To;
    }
}

//------------------------------------------------------------------------------

static void MLX90641_GetImage(uint16_t *frameData, const paramsMLX90641 *params, float *result)
{
    float vdd;
    float ta;
    float gain;
    float irDataCP;
    float irData;
    float alphaCompensated;
    float image;
    uint16_t subPage;
    int pixelNumber;
    
    subPage = frameData[241];
    
    vdd = MLX90641_GetVdd(frameData, params);
    ta = MLX90641_GetTa(frameData, params);
    
//------------------------- Gain calculation -----------------------------------    
    gain = frameData[202];
    if(gain > 32767)
    {
        gain = gain - 65536;
    }
    
    gain = params->gainEE / gain; 
  
//------------------------- Image calculation -------------------------------------    
    irDataCP = frameData[200];  
    if(irDataCP > 32767)
    {
        irDataCP = irDataCP - 65536;
    }
    irDataCP = irDataCP * gain;

irDataCP = irDataCP - params->cpOffset * (1 + params->cpKta * (ta - 25)) * (1 + params->cpKv * (vdd - 3.3));
    
    for(  pixelNumber = 0; pixelNumber < 192; pixelNumber++)
    {
        irData = frameData[pixelNumber];
        if(irData > 32767)
        {
            irData = irData - 65536;
        }
        irData = irData * gain;
        
        irData = irData - params->offset[subPage][pixelNumber]*(1 + params->kta[pixelNumber]*(ta - 25))*(1 + params->kv[pixelNumber]*(vdd - 3.3));
        
        irData = irData - params->tgc * irDataCP;
            
        alphaCompensated = (params->alpha[pixelNumber] - params->tgc * params->cpAlpha);
            
        image = irData*alphaCompensated;
            
        result[pixelNumber] = image;
    }
}

//------------------------------------------------------------------------------

static float MLX90641_GetVdd(uint16_t *frameData, const paramsMLX90641 *params)
{
    float vdd;
    float resolutionCorrection;
    
    int resolutionRAM;    
    
    vdd = frameData[234];
    if(vdd > 32767)
    {
        vdd = vdd - 65536;
    }
    resolutionRAM = (frameData[240] & 0x0C00) >> 10;
    resolutionCorrection = pow(2, (double)params->resolutionEE) / pow(2, (double)resolutionRAM);
    vdd = (resolutionCorrection * vdd - params->vdd25) / params->kVdd + 3.3;
    
    return vdd;
}

//------------------------------------------------------------------------------

static float MLX90641_GetTa(uint16_t *frameData, const paramsMLX90641 *params)
{
    float ptat;
    float ptatArt;
    float vdd;
    float ta;
    
    vdd = MLX90641_GetVdd(frameData, params);
    
    ptat = frameData[224];
    if(ptat > 32767)
    {
        ptat = ptat - 65536;
    }
    
    ptatArt = frameData[192];
    if(ptatArt > 32767)
    {
        ptatArt = ptatArt - 65536;
    }
    ptatArt = (ptat / (ptat * params->alphaPTAT + ptatArt)) * pow(2, (double)18);
    
    ta = (ptatArt / (1 + params->KvPTAT * (vdd - 3.3)) - params->vPTAT25);
    ta = ta / params->KtPTAT + 25;
    
    return ta;
}

//------------------------------------------------------------------------------

static int MLX90641_GetSubPageNumber(uint16_t *frameData)
{
    return frameData[241];

}

//------------------------------------------------------------------------------
static void MLX90641_BadPixelsCorrection(uint16_t *pixels, float *to, paramsMLX90641 *params)
{   
    float ap[2];
    uint8_t pix;
    uint8_t line;
    uint8_t column;
    
    pix = 0;
    while(pixels[pix]< 65535)
    {
        line = pixels[pix]>>5;
        column = pixels[pix] - (line<<5);
               
        if(column == 0)
        {
            to[pixels[pix]] = to[pixels[pix]+1];            
        }
        else if(column == 1 || column == 14)
        {
            to[pixels[pix]] = (to[pixels[pix]-1]+to[pixels[pix]+1])/2.0;                
        } 
        else if(column == 15)
        {
            to[pixels[pix]] = to[pixels[pix]-1];
        } 
        else
        {            
            ap[0] = to[pixels[pix]+1] - to[pixels[pix]+2];
            ap[1] = to[pixels[pix]-1] - to[pixels[pix]-2];
            if(fabs(ap[0]) > fabs(ap[1]))
            {
                to[pixels[pix]] = to[pixels[pix]-1] + ap[1];                        
            }
            else
            {
                to[pixels[pix]] = to[pixels[pix]+1] + ap[0];                        
            }
                    
        }                      
     
        pix = pix + 1;    
    }    
}

//------------------------------------------------------------------------------

static void ExtractVDDParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    int16_t kVdd;
    int16_t vdd25;
    
    kVdd = eeData[39];
    if(kVdd > 1023)
    {
        kVdd = kVdd - 2048;
    }
    kVdd = 32 * kVdd;
    
    vdd25 = eeData[38];
    if(vdd25 > 1023)
    {
        vdd25 = vdd25 - 2048;
    }
    vdd25 = 32 * vdd25;
    
    mlx90641->kVdd = kVdd;
    mlx90641->vdd25 = vdd25; 
}

//------------------------------------------------------------------------------

static void ExtractPTATParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float KvPTAT;
    float KtPTAT;
    int16_t vPTAT25;
    float alphaPTAT;
    
    KvPTAT = eeData[43];
    if(KvPTAT > 1023)
    {
        KvPTAT = KvPTAT - 2048;
    }
    KvPTAT = KvPTAT/4096;
    
    KtPTAT = eeData[42];
    if(KtPTAT > 1023)
    {
        KtPTAT = KtPTAT - 2048;
    }
    KtPTAT = KtPTAT/8;
    
    vPTAT25 = 32 * eeData[40] + eeData[41];
    
    alphaPTAT = eeData[44] / 128.0f;
    
    mlx90641->KvPTAT = KvPTAT;
    mlx90641->KtPTAT = KtPTAT;    
    mlx90641->vPTAT25 = vPTAT25;
    mlx90641->alphaPTAT = alphaPTAT;   
}

//------------------------------------------------------------------------------

static void ExtractGainParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    int16_t gainEE;
    
    gainEE = 32 * eeData[36] + eeData[37];

mlx90641->gainEE = gainEE;    
}

//------------------------------------------------------------------------------

static void ExtractTgcParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float tgc;
    tgc = eeData[51] & 0x01FF;
    if(tgc > 255)
    {
        tgc = tgc - 512;
    }
    tgc = tgc / 64.0f;
    
    mlx90641->tgc = tgc;        
}

//------------------------------------------------------------------------------

static void ExtractEmissivityParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float emissivity;
    emissivity = eeData[35];
       
    if(emissivity > 1023)
    {
        emissivity = emissivity - 2048;
    }
    emissivity = emissivity/512;
    
    mlx90641->emissivityEE = emissivity;
}
    
//------------------------------------------------------------------------------

static void ExtractResolutionParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    uint8_t resolutionEE;
    resolutionEE = (eeData[51] & 0x0600) >> 9;    
    
    mlx90641->resolutionEE = resolutionEE;
}

//------------------------------------------------------------------------------

static void ExtractKsTaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float KsTa;
    KsTa = eeData[34];
    if(KsTa > 1023)
    {
        KsTa = KsTa - 2048;
    }
    KsTa = KsTa / 32768.0f;
    
    mlx90641->KsTa = KsTa;
}

//------------------------------------------------------------------------------

static void ExtractKsToParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    int KsToScale;
    int i;
    
    mlx90641->ct[0] = -40;
    mlx90641->ct[1] = -20;
    mlx90641->ct[2] = 0;
    mlx90641->ct[3] = 80;
    mlx90641->ct[4] = 120;
    mlx90641->ct[5] = eeData[58];
    mlx90641->ct[6] = eeData[60];
    mlx90641->ct[7] = eeData[62];
     
    KsToScale = eeData[52];
    KsToScale = 1 << KsToScale;
    
    mlx90641->ksTo[0] = eeData[53];
    mlx90641->ksTo[1] = eeData[54];
    mlx90641->ksTo[2] = eeData[55];
    mlx90641->ksTo[3] = eeData[56];
    mlx90641->ksTo[4] = eeData[57];
    mlx90641->ksTo[5] = eeData[59];
    mlx90641->ksTo[6] = eeData[61];
    mlx90641->ksTo[7] = eeData[63];
    
    
    for( i = 0; i < 8; i++)
    {
        if(mlx90641->ksTo[i] > 1023)
        {
            mlx90641->ksTo[i] = mlx90641->ksTo[i] - 2048;
        }
        mlx90641->ksTo[i] = mlx90641->ksTo[i] / KsToScale;
    } 
}

//------------------------------------------------------------------------------

static void ExtractAlphaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float rowMaxAlphaNorm[6];
    uint16_t scaleRowAlpha[6];
    uint8_t alphaScale;
    float alphaTemp[192];
    float temp;
    int p = 0;
    int i,j;

scaleRowAlpha[0] = (eeData[25] >> 5) + 20;
    scaleRowAlpha[1] = (eeData[25] & 0x001F) + 20;
    scaleRowAlpha[2] = (eeData[26] >> 5) + 20;
    scaleRowAlpha[3] = (eeData[26] & 0x001F) + 20;
    scaleRowAlpha[4] = (eeData[27] >> 5) + 20;
    scaleRowAlpha[5] = (eeData[27] & 0x001F) + 20;

for( i = 0; i < 6; i++)
    {
        rowMaxAlphaNorm[i] = eeData[28 + i] / pow(2,(double)scaleRowAlpha[i]);
        rowMaxAlphaNorm[i] = rowMaxAlphaNorm[i] / 2047.0f;
    }

for( i = 0; i < 6; i++)
    {
        for( j = 0; j < 32; j ++)
        {
            p = 32 * i +j;
            alphaTemp[p] = eeData[256 + p] * rowMaxAlphaNorm[i]; 
            alphaTemp[p] = alphaTemp[p] - mlx90641->tgc * mlx90641->cpAlpha;
            alphaTemp[p] = SCALEALPHA/alphaTemp[p];
        }
    }
    
    temp = alphaTemp[0];
    for( i = 1; i < 192; i++)
    {
        if (alphaTemp[i] > temp)
        {
            temp = alphaTemp[i];
        }
    }
    
    alphaScale = 0;
    while(temp < 32768)
    {
        temp = temp*2;
        alphaScale = alphaScale + 1;
    } 
    
    for( i = 0; i < 192; i++)
    {
        temp = alphaTemp[i] * pow(2,(double)alphaScale);        
        mlx90641->alpha[i] = (temp + 0.5);        
        
    } 
    
    mlx90641->alphaScale = alphaScale;      
}

//------------------------------------------------------------------------------

static void ExtractOffsetParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    int scaleOffset;
    int16_t offsetRef;
    int16_t tempOffset; 
    int i;
    
    scaleOffset = eeData[16] >> 5;
    scaleOffset = 1 << scaleOffset;

offsetRef = 32 * eeData[17] + eeData[18];
    if (offsetRef > 32767)
    {
        offsetRef = offsetRef - 65536;
    }

for( i = 0; i < 192; i++)
    {
        tempOffset = eeData[64 + i];
        if(tempOffset > 1023)
        {
           tempOffset = eeData[64 + i] - 2048; 
        }
        mlx90641->offset[0][i] = tempOffset * scaleOffset + offsetRef;
        
        tempOffset = eeData[640 + i];
        if(tempOffset > 1023)
        {
           tempOffset = eeData[640 + i] - 2048; 
        }
        mlx90641->offset[1][i] = tempOffset * scaleOffset + offsetRef;
    }
}

//------------------------------------------------------------------------------

static void ExtractKtaPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    uint8_t ktaScale1;
    uint8_t ktaScale2;
    int16_t ktaAvg;
    int16_t tempKta;
    float ktaTemp[192];
    float temp;
    int i;

ktaAvg = eeData[21];
    if (ktaAvg > 1023)
    {
        ktaAvg = ktaAvg - 2048;
    }
  
    ktaScale1 = eeData[22] >> 5;
    ktaScale2 = eeData[22] & 0x001F;

for( i = 0; i < 192; i++)
    {
        tempKta = (eeData[448 + i] >> 5);
        if (tempKta > 31)
        {
            tempKta = tempKta - 64;
        }

ktaTemp[i] = tempKta * pow(2,(double)ktaScale2);
        ktaTemp[i] = ktaTemp[i] + ktaAvg;
        ktaTemp[i] = ktaTemp[i] / pow(2,(double)ktaScale1);
    }
    
    temp = fabs(ktaTemp[0]);
    for( i = 1; i < 192; i++)
    {
        if (fabs(ktaTemp[i]) > temp)
        {
            temp = fabs(ktaTemp[i]);
        }
    }
    
    ktaScale1 = 0;
    while(temp < 64)
    {
        temp = temp*2;
        ktaScale1 = ktaScale1 + 1;
    }    
     
    for( i = 0; i < 192; i++)
    {
        temp = ktaTemp[i] * pow(2,(double)ktaScale1);
        if (temp < 0)
        {
            mlx90641->kta[i] = (temp - 0.5);
        }
        else
        {
            mlx90641->kta[i] = (temp + 0.5);
        }        
        
    } 
    
    mlx90641->ktaScale = ktaScale1;
}

//------------------------------------------------------------------------------

static void ExtractKvPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    uint8_t kvScale1;
    uint8_t kvScale2;
    int16_t kvAvg;
    int16_t tempKv;
    float kvTemp[192];
    float temp;
    int i;

kvAvg = eeData[23];
    if (kvAvg > 1023)
    {
        kvAvg = kvAvg - 2048;
    }
  
    kvScale1 = eeData[24] >> 5;
    kvScale2 = eeData[24] & 0x001F;

for( i = 0; i < 192; i++)
    {
        tempKv = (eeData[448 + i] & 0x001F);
        if (tempKv > 15)
        {
            tempKv = tempKv - 32;
        }

kvTemp[i] = tempKv * pow(2,(double)kvScale2);
        kvTemp[i] = kvTemp[i] + kvAvg;
        kvTemp[i] = kvTemp[i] / pow(2,(double)kvScale1);
    }
    
    temp = fabs(kvTemp[0]);
    for( i = 1; i < 192; i++)
    {
        if (fabs(kvTemp[i]) > temp)
        {
            temp = fabs(kvTemp[i]);
        }
    }
    
    kvScale1 = 0;
    while(temp < 64)
    {
        temp = temp*2;
        kvScale1 = kvScale1 + 1;
    }    
     
    for( i = 0; i < 192; i++)
    {
        temp = kvTemp[i] * pow(2,(double)kvScale1);
        if (temp < 0)
        {
            mlx90641->kv[i] = (temp - 0.5);
        }
        else
        {
            mlx90641->kv[i] = (temp + 0.5);
        }        
        
    } 
    
    mlx90641->kvScale = kvScale1;        
}

//------------------------------------------------------------------------------

static void ExtractCPParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float alphaCP;
    int16_t offsetCP;
    float cpKv;
    float cpKta;
    uint8_t alphaScale;
    uint8_t ktaScale1;
    uint8_t kvScale;

alphaScale = eeData[46];
    
    offsetCP = 32 * eeData[47] + eeData[48];
    if (offsetCP > 32767)
    {
        offsetCP = offsetCP - 65536;
    }
       
    alphaCP = eeData[45];
    if (alphaCP > 1023)
    {
        alphaCP = alphaCP - 2048;
    }
    
    alphaCP = alphaCP /  pow(2,(double)alphaScale);
    
    
    cpKta = eeData[49] & 0x001F;
    if (cpKta > 31)
    {
        cpKta = cpKta - 64;
    }
    ktaScale1 = eeData[49] >> 6;    
    mlx90641->cpKta = cpKta / pow(2,(double)ktaScale1);
    
    cpKv = eeData[50] & 0x001F;
    if (cpKv > 31)
    {
        cpKv = cpKv - 64;
    }
    kvScale = eeData[50] >> 6;
    mlx90641->cpKv = cpKv / pow(2,(double)kvScale);
       
    mlx90641->cpAlpha = alphaCP;
    mlx90641->cpOffset = offsetCP;
}

//------------------------------------------------------------------------------

static float MLX90641_GetEmissivity(const paramsMLX90641 *mlx90641)
{
    return  mlx90641->emissivityEE;
}

//------------------------------------------------------------------------------

static int ExtractDeviatingPixels(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    uint16_t pixCnt = 0;
    uint16_t brokenPixCnt = 0;

int warn = 0;
    
    for(pixCnt = 0; pixCnt<3; pixCnt++)
    {
        mlx90641->brokenPixels[pixCnt] = 0xFFFF;
    }
        
    pixCnt = 0;    
    while (pixCnt < 192 && brokenPixCnt < 3)
    {
        if((eeData[pixCnt+64] == 0) && (eeData[pixCnt+256] == 0) && (eeData[pixCnt+448] == 0) && (eeData[pixCnt+640] == 0))
        {
            mlx90641->brokenPixels[brokenPixCnt] = pixCnt;
            brokenPixCnt = brokenPixCnt + 1;
        }    
        
        pixCnt = pixCnt + 1;
        
    } 
    
    if(brokenPixCnt > 1)  
    {
        warn = -3;
    }         
    
    return warn;
       
}
 
 //------------------------------------------------------------------------------
 
 static int CheckEEPROMValid(uint16_t *eeData)  
 {
     int deviceSelect;
     deviceSelect = eeData[10] & 0x0040;
     if(deviceSelect != 0)
     {
         return 0;
     }
     
     return -7;    
 }

static int mlx90641_ta = 0;
static unsigned char slaveAddress;
static int eeMLX90641[832];
static int mlx90641Frame[242];
static paramsMLX90641 mlx90641;
static float emissivity = 0.95;
static float tr = 23.15;
static float mlx90641To[192];

//int MLX90641_ExtractParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
//void MLX90641_CalculateTo(uint16_t *frameData, const paramsMLX90641 *params, float emissivity, float tr, float *result)
//int MLX90641_DumpEE(uint8_t slaveAddr, uint16_t *eeData);
//int MLX90641_GetFrameData(uint8_t slaveAddr, uint16_t *frameData);
//float MLX90641_GetTa(uint16_t *frameData, const paramsMLX90641 *params)
static void mlx90641_main_ta(void)
{    
    slaveAddress = 0x33;
    #if 1
    MLX90641_DumpEE(slaveAddress, eeMLX90641);    
    MLX90641_ExtractParameters(eeMLX90641, &mlx90641);
    MLX90641_GetFrameData(0x33, mlx90641Frame);    
    mlx90641_ta = (int)MLX90641_GetTa(mlx90641Frame,&mlx90641);
    #else
    
    #endif
    
    printk("mlx90641_ta=%d\n",mlx90641_ta);
}

static void mlx90641_main_to(void)
{
    slaveAddress = 0x33;
    MLX90641_DumpEE(slaveAddress, eeMLX90641);    
    MLX90641_ExtractParameters(eeMLX90641, &mlx90641);
    MLX90641_GetFrameData(0x33, mlx90641Frame);
    MLX90641_CalculateTo(mlx90641Frame,&mlx90641,emissivity,tr,mlx90641To);    
    printk("mlx90641_to0=%d\n",(int)mlx90641To[0]);
    printk("mlx90641_to1=%d\n",(int)mlx90641To[1]);
    printk("mlx90641_to2=%d\n",(int)mlx90641To[2]);
    printk("mlx90641_to3=%d\n",(int)mlx90641To[3]);
    mlx90641_ta = mlx90641To[0];
}

#endif

人体测温 melexis迈来芯 linux 平台mlx90614/mlx90621/mlx90641驱动调试相关推荐

  1. 基于红外热成像人体测温系统解决方案的组成

    概述 当前,各行各业已基本实现复工复产,但新冠肺炎疫情防控仍处在关键阶段.疫情期间,车站.机场.写字楼等公共场所人流聚集,该如何监控异常体温,成为一大难题.如何更高效地监测人员体温信息,且避免人员发生 ...

  2. 基于红外传感器人体测温系统设计(STC89C51单片机)

    目 录 摘 要 I ABSTRACT II 目 录 III 1绪论 1 1.1选题背景及依据 1 1.2国内外研究现状 1 1.3研究内容 3 2 红外传感器人体测温系统原理及方案设计 4 2.1温度 ...

  3. [C#] 折腾海康威视的人体测温 模组

    单位的项目需要测温,同事买了个海康威视的人体测温机芯,型号位:TB-4117-3/S,给了一份pdf的说明书. 按说明书把设备连接设置好,从官网下载vb.net教程了sdk,我的个乖乖,压缩包就有70 ...

  4. 红外测温仪人体测温解决方案

    红外人体测温仪是一种利用红外线照射的测温仪器,在此之前,红外测温都是作为工厂生产的用的,用来检测产品的温度,和监测设备的运行发热状态.逐渐的人们突发奇想,转变用于人体测温,来规避人员之间身体直接接触( ...

  5. 智能无感人体测温系统解决方案

    中国已全面进入"全民战疫"的非常状态.随着春运返程高峰的到来,全国各大城市的防疫形势更加严峻,防控进入关键时期.6108方案凭借自身在AIoT领域的技术优势,推出了一套智能无感人体 ...

  6. [linux kernel] 内核下ksz8081驱动调试

    系统版本:Ubuntu18.04-64 编译器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1) uboot版本:2018.07 - ...

  7. STM32 + CT1711超级准的人体测温方案

    一.前言 做一个手腕式检测设备玩玩,其中设计到人体温度检测,就测试手腕温度皮肤表面温度,采用ct1711温度传感器,该传感器是可以直接与人体接触的,其参数如下: CT1711 的典型静态电流仅为10n ...

  8. Linux平台Segmentation fault(段错误)调试方法

    1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访问了只读的内存地址等等情况. 2. 段错误的原因 段错 ...

  9. bcm4360 蓝牙 linux,Android BCM4330 蓝牙BT驱动调试记录

    网上关于BT的驱动很少,所以我在开发过程中把其中的步骤记录下来.供大家相互学习讨论. 一.关于BT driver的移植: 1. Enablebluetootch in BoadConfig.mk BO ...

最新文章

  1. Flask学习之路(一)--初识flask
  2. sed替换ip地址为网关
  3. 通过ngrok在内网捕获meterpreter反弹
  4. 对弈程序基本技术---最小-最大搜索
  5. 如果给你一个亿,你想去干嘛?各专业的科研狗是这样回答的……
  6. python编写自制编译器_编译器构造-编译Python
  7. Spring精华问答 | 什么是YAML?
  8. 铃木uy125最高时速_五菱宏光mini EV月销三万辆,铃木是否后悔退出中国?
  9. 老兵的十年职场之路(一)
  10. 4999元起!华为Mate 30 5G系列今日预售:支持SA及NSA 5G双模
  11. 05_DecisionTree_统计学习方法
  12. mapper mysl实现批量插入 更新
  13. 高德地图基于阿里云MaxCompute的最佳实践
  14. couldn't create PTY
  15. 伺服电机编码器为什么要调零或校正
  16. 【?】【9908】守望者的逃离
  17. MRR@K P@K R@K意义阐述与对比
  18. 2021亚太杯A|B|C题全网最全解题思路+数据分享
  19. java compiler类_利用 JavaCompiler 编译 Java 类文件
  20. 面经分享 | 2年经验,1个月拿下阿里P6 Offer

热门文章

  1. line怎么添加好友?
  2. QT应用程序-获取Application-获取主窗口指针-QT内嵌浏览器-QT菜单动作
  3. 实验室服务器使用指南:pytorch、tensorflow安装问题、visdom安装问题本地远程调用服务器jupyter问题、本地pycharm远程连接服务器
  4. 海康网络摄像头android,海康网络摄像头的Android端Demo
  5. 边缘检测算子性能评价Matlab实现之——MSE,PSNR,FOM(品质因数)
  6. 2018.11.3 Nescafe18 T2 太鼓达人
  7. Java 浏览器下载文件及文件预览
  8. SAP 物料主数据BP主数据同步第三方系统
  9. 北京八维计算机学校分数线,廊坊 中专 排名
  10. Enlight官方第三届“金融帝国杯”玩家游戏视频邀请赛《竞赛规则》(2022.12.23修订)