Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

i2c.c

Go to the documentation of this file.
00001 /*! \file i2c.c \brief I2C interface using AVR Two-Wire Interface (TWI) hardware. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'i2c.c'
00005 // Title        : I2C interface using AVR Two-Wire Interface (TWI) hardware
00006 // Author       : Pascal Stang - Copyright (C) 2002-2003
00007 // Created      : 2002.06.25
00008 // Revised      : 2003.03.02
00009 // Version      : 0.9
00010 // Target MCU   : Atmel AVR series
00011 // Editor Tabs  : 4
00012 //
00013 // This code is distributed under the GNU Public License
00014 //      which can be found at http://www.gnu.org/licenses/gpl.txt
00015 //
00016 //*****************************************************************************
00017 
00018 #include <avr/io.h>
00019 #include <avr/interrupt.h>
00020 
00021 #include "i2c.h"
00022 
00023 #include "rprintf.h"    // include printf function library
00024 #include "uart2.h"
00025 
00026 // Standard I2C bit rates are:
00027 // 100KHz for slow speed
00028 // 400KHz for high speed
00029 
00030 //#define I2C_DEBUG
00031 
00032 // I2C state and address variables
00033 static volatile eI2cStateType I2cState;
00034 static u08 I2cDeviceAddrRW;
00035 // send/transmit buffer (outgoing data)
00036 static u08 I2cSendData[I2C_SEND_DATA_BUFFER_SIZE];
00037 static u08 I2cSendDataIndex;
00038 static u08 I2cSendDataLength;
00039 // receive buffer (incoming data)
00040 static u08 I2cReceiveData[I2C_RECEIVE_DATA_BUFFER_SIZE];
00041 static u08 I2cReceiveDataIndex;
00042 static u08 I2cReceiveDataLength;
00043 
00044 // function pointer to i2c receive routine
00045 //! I2cSlaveReceive is called when this processor
00046 // is addressed as a slave for writing
00047 static void (*i2cSlaveReceive)(u08 receiveDataLength, u08* recieveData);
00048 //! I2cSlaveTransmit is called when this processor
00049 // is addressed as a slave for reading
00050 static u08 (*i2cSlaveTransmit)(u08 transmitDataLengthMax, u08* transmitData);
00051 
00052 // functions
00053 void i2cInit(void)
00054 {
00055     // set pull-up resistors on I2C bus pins
00056     // TODO: should #ifdef these
00057     sbi(PORTC, 0);  // i2c SCL on ATmega163,323,16,32,etc
00058     sbi(PORTC, 1);  // i2c SDA on ATmega163,323,16,32,etc
00059     sbi(PORTD, 0);  // i2c SCL on ATmega128,64
00060     sbi(PORTD, 1);  // i2c SDA on ATmega128,64
00061 
00062     // clear SlaveReceive and SlaveTransmit handler to null
00063     i2cSlaveReceive = 0;
00064     i2cSlaveTransmit = 0;
00065     // set i2c bit rate to 100KHz
00066     i2cSetBitrate(100);
00067     // enable TWI (two-wire interface)
00068     sbi(TWCR, TWEN);
00069     // set state
00070     I2cState = I2C_IDLE;
00071     // enable TWI interrupt and slave address ACK
00072     sbi(TWCR, TWIE);
00073     sbi(TWCR, TWEA);
00074     //outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
00075     // enable interrupts
00076     sei();
00077 }
00078 
00079 void i2cSetBitrate(u16 bitrateKHz)
00080 {
00081     u08 bitrate_div;
00082     // set i2c bitrate
00083     // SCL freq = F_CPU/(16+2*TWBR))
00084     #ifdef TWPS0
00085         // for processors with additional bitrate division (mega128)
00086         // SCL freq = F_CPU/(16+2*TWBR*4^TWPS)
00087         // set TWPS to zero
00088         cbi(TWSR, TWPS0);
00089         cbi(TWSR, TWPS1);
00090     #endif
00091     // calculate bitrate division   
00092     bitrate_div = ((F_CPU/1000l)/bitrateKHz);
00093     if(bitrate_div >= 16)
00094         bitrate_div = (bitrate_div-16)/2;
00095     outb(TWBR, bitrate_div);
00096 }
00097 
00098 void i2cSetLocalDeviceAddr(u08 deviceAddr, u08 genCallEn)
00099 {
00100     // set local device address (used in slave mode only)
00101     outb(TWAR, ((deviceAddr&0xFE) | (genCallEn?1:0)) );
00102 }
00103 
00104 void i2cSetSlaveReceiveHandler(void (*i2cSlaveRx_func)(u08 receiveDataLength, u08* recieveData))
00105 {
00106     i2cSlaveReceive = i2cSlaveRx_func;
00107 }
00108 
00109 void i2cSetSlaveTransmitHandler(u08 (*i2cSlaveTx_func)(u08 transmitDataLengthMax, u08* transmitData))
00110 {
00111     i2cSlaveTransmit = i2cSlaveTx_func;
00112 }
00113 
00114 inline void i2cSendStart(void)
00115 {
00116     // send start condition
00117     outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTA));
00118 }
00119 
00120 inline void i2cSendStop(void)
00121 {
00122     // transmit stop condition
00123     // leave with TWEA on for slave receiving
00124     outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA)|BV(TWSTO));
00125 }
00126 
00127 inline void i2cWaitForComplete(void)
00128 {
00129     // wait for i2c interface to complete operation
00130     while( !(inb(TWCR) & BV(TWINT)) );
00131 }
00132 
00133 inline void i2cSendByte(u08 data)
00134 {
00135     // save data to the TWDR
00136     outb(TWDR, data);
00137     // begin send
00138     outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
00139 }
00140 
00141 inline void i2cReceiveByte(u08 ackFlag)
00142 {
00143     // begin receive over i2c
00144     if( ackFlag )
00145     {
00146         // ackFlag = TRUE: ACK the recevied data
00147         outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
00148     }
00149     else
00150     {
00151         // ackFlag = FALSE: NACK the recevied data
00152         outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
00153     }
00154 }
00155 
00156 inline u08 i2cGetReceivedByte(void)
00157 {
00158     // retieve received data byte from i2c TWDR
00159     return( inb(TWDR) );
00160 }
00161 
00162 inline u08 i2cGetStatus(void)
00163 {
00164     // retieve current i2c status from i2c TWSR
00165     return( inb(TWSR) );
00166 }
00167 
00168 void i2cMasterSend(u08 deviceAddr, u08 length, u08* data)
00169 {
00170     u08 i;
00171     // wait for interface to be ready
00172     while(I2cState);
00173     // set state
00174     I2cState = I2C_MASTER_TX;
00175     // save data
00176     I2cDeviceAddrRW = (deviceAddr & 0xFE);  // RW cleared: write operation
00177     for(i=0; i<length; i++)
00178         I2cSendData[i] = *data++;
00179     I2cSendDataIndex = 0;
00180     I2cSendDataLength = length;
00181     // send start condition
00182     i2cSendStart();
00183 }
00184 
00185 void i2cMasterReceive(u08 deviceAddr, u08 length, u08* data)
00186 {
00187     u08 i;
00188     // wait for interface to be ready
00189     while(I2cState);
00190     // set state
00191     I2cState = I2C_MASTER_RX;
00192     // save data
00193     I2cDeviceAddrRW = (deviceAddr|0x01);    // RW set: read operation
00194     I2cReceiveDataIndex = 0;
00195     I2cReceiveDataLength = length;
00196     // send start condition
00197     i2cSendStart();
00198     // wait for data
00199     while(I2cState);
00200     // return data
00201     for(i=0; i<length; i++)
00202         *data++ = I2cReceiveData[i];
00203 }
00204 
00205 u08 i2cMasterSendNI(u08 deviceAddr, u08 length, u08* data)
00206 {
00207     u08 retval = I2C_OK;
00208 
00209     // disable TWI interrupt
00210     cbi(TWCR, TWIE);
00211 
00212     // send start condition
00213     i2cSendStart();
00214     i2cWaitForComplete();
00215 
00216     // send device address with write
00217     i2cSendByte( deviceAddr & 0xFE );
00218     i2cWaitForComplete();
00219 
00220     // check if device is present and live
00221     if( inb(TWSR) == TW_MT_SLA_ACK)
00222     {
00223         // send data
00224         while(length)
00225         {
00226             i2cSendByte( *data++ );
00227             i2cWaitForComplete();
00228             length--;
00229         }
00230     }
00231     else
00232     {
00233         // device did not ACK it's address,
00234         // data will not be transferred
00235         // return error
00236         retval = I2C_ERROR_NODEV;
00237     }
00238 
00239     // transmit stop condition
00240     // leave with TWEA on for slave receiving
00241     i2cSendStop();
00242     while( !(inb(TWCR) & BV(TWSTO)) );
00243 
00244     // enable TWI interrupt
00245     sbi(TWCR, TWIE);
00246 
00247     return retval;
00248 }
00249 
00250 u08 i2cMasterReceiveNI(u08 deviceAddr, u08 length, u08 *data)
00251 {
00252     u08 retval = I2C_OK;
00253 
00254     // disable TWI interrupt
00255     cbi(TWCR, TWIE);
00256 
00257     // send start condition
00258     i2cSendStart();
00259     i2cWaitForComplete();
00260 
00261     // send device address with read
00262     i2cSendByte( deviceAddr | 0x01 );
00263     i2cWaitForComplete();
00264 
00265     // check if device is present and live
00266     if( inb(TWSR) == TW_MR_SLA_ACK)
00267     {
00268         // accept receive data and ack it
00269         while(length > 1)
00270         {
00271             i2cReceiveByte(TRUE);
00272             i2cWaitForComplete();
00273             *data++ = i2cGetReceivedByte();
00274             // decrement length
00275             length--;
00276         }
00277 
00278         // accept receive data and nack it (last-byte signal)
00279         i2cReceiveByte(FALSE);
00280         i2cWaitForComplete();
00281         *data++ = i2cGetReceivedByte();
00282     }
00283     else
00284     {
00285         // device did not ACK it's address,
00286         // data will not be transferred
00287         // return error
00288         retval = I2C_ERROR_NODEV;
00289     }
00290 
00291     // transmit stop condition
00292     // leave with TWEA on for slave receiving
00293     i2cSendStop();
00294 
00295     // enable TWI interrupt
00296     sbi(TWCR, TWIE);
00297 
00298     return retval;
00299 }
00300 /*
00301 void i2cMasterTransferNI(u08 deviceAddr, u08 sendlength, u08* senddata, u08 receivelength, u08* receivedata)
00302 {
00303     // disable TWI interrupt
00304     cbi(TWCR, TWIE);
00305 
00306     // send start condition
00307     i2cSendStart();
00308     i2cWaitForComplete();
00309 
00310     // if there's data to be sent, do it
00311     if(sendlength)
00312     {
00313         // send device address with write
00314         i2cSendByte( deviceAddr & 0xFE );
00315         i2cWaitForComplete();
00316         
00317         // send data
00318         while(sendlength)
00319         {
00320             i2cSendByte( *senddata++ );
00321             i2cWaitForComplete();
00322             sendlength--;
00323         }
00324     }
00325 
00326     // if there's data to be received, do it
00327     if(receivelength)
00328     {
00329         // send repeated start condition
00330         i2cSendStart();
00331         i2cWaitForComplete();
00332 
00333         // send device address with read
00334         i2cSendByte( deviceAddr | 0x01 );
00335         i2cWaitForComplete();
00336 
00337         // accept receive data and ack it
00338         while(receivelength > 1)
00339         {
00340             i2cReceiveByte(TRUE);
00341             i2cWaitForComplete();
00342             *receivedata++ = i2cGetReceivedByte();
00343             // decrement length
00344             receivelength--;
00345         }
00346 
00347         // accept receive data and nack it (last-byte signal)
00348         i2cReceiveByte(TRUE);
00349         i2cWaitForComplete();
00350         *receivedata++ = i2cGetReceivedByte();
00351     }
00352     
00353     // transmit stop condition
00354     // leave with TWEA on for slave receiving
00355     i2cSendStop();
00356     while( !(inb(TWCR) & BV(TWSTO)) );
00357 
00358     // enable TWI interrupt
00359     sbi(TWCR, TWIE);
00360 }
00361 */
00362 
00363 //! I2C (TWI) interrupt service routine
00364 SIGNAL(SIG_2WIRE_SERIAL)
00365 {
00366     // read status bits
00367     u08 status = inb(TWSR) & TWSR_STATUS_MASK;
00368 
00369     switch(status)
00370     {
00371     // Master General
00372     case TW_START:                      // 0x08: Sent start condition
00373     case TW_REP_START:                  // 0x10: Sent repeated start condition
00374         #ifdef I2C_DEBUG
00375         rprintfInit(uart1AddToTxBuffer);
00376         rprintf("I2C: M->START\r\n");
00377         rprintfInit(uart1SendByte);
00378         #endif
00379         // send device address
00380         i2cSendByte(I2cDeviceAddrRW);
00381         break;
00382     
00383     // Master Transmitter & Receiver status codes
00384     case TW_MT_SLA_ACK:                 // 0x18: Slave address acknowledged
00385     case TW_MT_DATA_ACK:                // 0x28: Data acknowledged
00386         #ifdef I2C_DEBUG
00387         rprintfInit(uart1AddToTxBuffer);
00388         rprintf("I2C: MT->SLA_ACK or DATA_ACK\r\n");
00389         rprintfInit(uart1SendByte);
00390         #endif
00391         if(I2cSendDataIndex < I2cSendDataLength)
00392         {
00393             // send data
00394             i2cSendByte( I2cSendData[I2cSendDataIndex++] );
00395         }
00396         else
00397         {
00398             // transmit stop condition, enable SLA ACK
00399             i2cSendStop();
00400             // set state
00401             I2cState = I2C_IDLE;
00402         }
00403         break;
00404     case TW_MR_DATA_NACK:               // 0x58: Data received, NACK reply issued
00405         #ifdef I2C_DEBUG
00406         rprintfInit(uart1AddToTxBuffer);
00407         rprintf("I2C: MR->DATA_NACK\r\n");
00408         rprintfInit(uart1SendByte);
00409         #endif
00410         // store final received data byte
00411         I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
00412         // continue to transmit STOP condition
00413     case TW_MR_SLA_NACK:                // 0x48: Slave address not acknowledged
00414     case TW_MT_SLA_NACK:                // 0x20: Slave address not acknowledged
00415     case TW_MT_DATA_NACK:               // 0x30: Data not acknowledged
00416         #ifdef I2C_DEBUG
00417         rprintfInit(uart1AddToTxBuffer);
00418         rprintf("I2C: MTR->SLA_NACK or MT->DATA_NACK\r\n");
00419         rprintfInit(uart1SendByte);
00420         #endif
00421         // transmit stop condition, enable SLA ACK
00422         i2cSendStop();
00423         // set state
00424         I2cState = I2C_IDLE;
00425         break;
00426     case TW_MT_ARB_LOST:                // 0x38: Bus arbitration lost
00427     //case TW_MR_ARB_LOST:              // 0x38: Bus arbitration lost
00428         #ifdef I2C_DEBUG
00429         rprintfInit(uart1AddToTxBuffer);
00430         rprintf("I2C: MT->ARB_LOST\r\n");
00431         rprintfInit(uart1SendByte);
00432         #endif
00433         // release bus
00434         outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
00435         // set state
00436         I2cState = I2C_IDLE;
00437         // release bus and transmit start when bus is free
00438         //outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTA));
00439         break;
00440     case TW_MR_DATA_ACK:                // 0x50: Data acknowledged
00441         #ifdef I2C_DEBUG
00442         rprintfInit(uart1AddToTxBuffer);
00443         rprintf("I2C: MR->DATA_ACK\r\n");
00444         rprintfInit(uart1SendByte);
00445         #endif
00446         // store received data byte
00447         I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
00448         // fall-through to see if more bytes will be received
00449     case TW_MR_SLA_ACK:                 // 0x40: Slave address acknowledged
00450         #ifdef I2C_DEBUG
00451         rprintfInit(uart1AddToTxBuffer);
00452         rprintf("I2C: MR->SLA_ACK\r\n");
00453         rprintfInit(uart1SendByte);
00454         #endif
00455         if(I2cReceiveDataIndex < (I2cReceiveDataLength-1))
00456             // data byte will be received, reply with ACK (more bytes in transfer)
00457             i2cReceiveByte(TRUE);
00458         else
00459             // data byte will be received, reply with NACK (final byte in transfer)
00460             i2cReceiveByte(FALSE);
00461         break;
00462 
00463     // Slave Receiver status codes
00464     case TW_SR_SLA_ACK:                 // 0x60: own SLA+W has been received, ACK has been returned
00465     case TW_SR_ARB_LOST_SLA_ACK:        // 0x68: own SLA+W has been received, ACK has been returned
00466     case TW_SR_GCALL_ACK:               // 0x70:     GCA+W has been received, ACK has been returned
00467     case TW_SR_ARB_LOST_GCALL_ACK:      // 0x78:     GCA+W has been received, ACK has been returned
00468         #ifdef I2C_DEBUG
00469         rprintfInit(uart1AddToTxBuffer);
00470         rprintf("I2C: SR->SLA_ACK\r\n");
00471         rprintfInit(uart1SendByte);
00472         #endif
00473         // we are being addressed as slave for writing (data will be received from master)
00474         // set state
00475         I2cState = I2C_SLAVE_RX;
00476         // prepare buffer
00477         I2cReceiveDataIndex = 0;
00478         // receive data byte and return ACK
00479         outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
00480         break;
00481     case TW_SR_DATA_ACK:                // 0x80: data byte has been received, ACK has been returned
00482     case TW_SR_GCALL_DATA_ACK:          // 0x90: data byte has been received, ACK has been returned
00483         #ifdef I2C_DEBUG
00484         rprintfInit(uart1AddToTxBuffer);
00485         rprintf("I2C: SR->DATA_ACK\r\n");
00486         rprintfInit(uart1SendByte);
00487         #endif
00488         // get previously received data byte
00489         I2cReceiveData[I2cReceiveDataIndex++] = inb(TWDR);
00490         // check receive buffer status
00491         if(I2cReceiveDataIndex < I2C_RECEIVE_DATA_BUFFER_SIZE)
00492         {
00493             // receive data byte and return ACK
00494             i2cReceiveByte(TRUE);
00495             //outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
00496         }
00497         else
00498         {
00499             // receive data byte and return NACK
00500             i2cReceiveByte(FALSE);
00501             //outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
00502         }
00503         break;
00504     case TW_SR_DATA_NACK:               // 0x88: data byte has been received, NACK has been returned
00505     case TW_SR_GCALL_DATA_NACK:         // 0x98: data byte has been received, NACK has been returned
00506         #ifdef I2C_DEBUG
00507         rprintfInit(uart1AddToTxBuffer);
00508         rprintf("I2C: SR->DATA_NACK\r\n");
00509         rprintfInit(uart1SendByte);
00510         #endif
00511         // receive data byte and return NACK
00512         i2cReceiveByte(FALSE);
00513         //outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
00514         break;
00515     case TW_SR_STOP:                    // 0xA0: STOP or REPEATED START has been received while addressed as slave
00516         #ifdef I2C_DEBUG
00517         rprintfInit(uart1AddToTxBuffer);
00518         rprintf("I2C: SR->SR_STOP\r\n");
00519         rprintfInit(uart1SendByte);
00520         #endif
00521         // switch to SR mode with SLA ACK
00522         outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
00523         // i2c receive is complete, call i2cSlaveReceive
00524         if(i2cSlaveReceive) i2cSlaveReceive(I2cReceiveDataIndex, I2cReceiveData);
00525         // set state
00526         I2cState = I2C_IDLE;
00527         break;
00528 
00529     // Slave Transmitter
00530     case TW_ST_SLA_ACK:                 // 0xA8: own SLA+R has been received, ACK has been returned
00531     case TW_ST_ARB_LOST_SLA_ACK:        // 0xB0:     GCA+R has been received, ACK has been returned
00532         #ifdef I2C_DEBUG
00533         rprintfInit(uart1AddToTxBuffer);
00534         rprintf("I2C: ST->SLA_ACK\r\n");
00535         rprintfInit(uart1SendByte);
00536         #endif
00537         // we are being addressed as slave for reading (data must be transmitted back to master)
00538         // set state
00539         I2cState = I2C_SLAVE_TX;
00540         // request data from application
00541         if(i2cSlaveTransmit) I2cSendDataLength = i2cSlaveTransmit(I2C_SEND_DATA_BUFFER_SIZE, I2cSendData);
00542         // reset data index
00543         I2cSendDataIndex = 0;
00544         // fall-through to transmit first data byte
00545     case TW_ST_DATA_ACK:                // 0xB8: data byte has been transmitted, ACK has been received
00546         #ifdef I2C_DEBUG
00547         rprintfInit(uart1AddToTxBuffer);
00548         rprintf("I2C: ST->DATA_ACK\r\n");
00549         rprintfInit(uart1SendByte);
00550         #endif
00551         // transmit data byte
00552         outb(TWDR, I2cSendData[I2cSendDataIndex++]);
00553         if(I2cSendDataIndex < I2cSendDataLength)
00554             // expect ACK to data byte
00555             outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
00556         else
00557             // expect NACK to data byte
00558             outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT));
00559         break;
00560     case TW_ST_DATA_NACK:               // 0xC0: data byte has been transmitted, NACK has been received
00561     case TW_ST_LAST_DATA:               // 0xC8:
00562         #ifdef I2C_DEBUG
00563         rprintfInit(uart1AddToTxBuffer);
00564         rprintf("I2C: ST->DATA_NACK or LAST_DATA\r\n");
00565         rprintfInit(uart1SendByte);
00566         #endif
00567         // all done
00568         // switch to open slave
00569         outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA));
00570         // set state
00571         I2cState = I2C_IDLE;
00572         break;
00573 
00574     // Misc
00575     case TW_NO_INFO:                    // 0xF8: No relevant state information
00576         // do nothing
00577         #ifdef I2C_DEBUG
00578         rprintfInit(uart1AddToTxBuffer);
00579         rprintf("I2C: NO_INFO\r\n");
00580         rprintfInit(uart1SendByte);
00581         #endif
00582         break;
00583     case TW_BUS_ERROR:                  // 0x00: Bus error due to illegal start or stop condition
00584         #ifdef I2C_DEBUG
00585         rprintfInit(uart1AddToTxBuffer);
00586         rprintf("I2C: BUS_ERROR\r\n");
00587         rprintfInit(uart1SendByte);
00588         #endif
00589         // reset internal hardware and release bus
00590         outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTO)|BV(TWEA));
00591         // set state
00592         I2cState = I2C_IDLE;
00593         break;
00594     }
00595 }
00596 
00597 eI2cStateType i2cGetState(void)
00598 {
00599     return I2cState;
00600 }

Generated on Sun Oct 29 03:41:06 2006 for Procyon AVRlib by  doxygen 1.4.2