Tyler Sisk / battery-gauge-bq27441

Dependents:   rcCar

Fork of battery-gauge-bq27441 by u-blox

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers bq27441.cpp Source File

bq27441.cpp

Go to the documentation of this file.
00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 u-blox
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 /**
00018  * @file bq27441.cpp
00019  * This file defines the API to the TI BQ27441 battery gauge chip.
00020  */
00021 
00022 /** Define these to print debug information. */
00023 //#define DEBUG_BQ27441
00024 //#define DEBUG_BQ27441_BLOCK_DATA
00025 
00026 #include <mbed.h>
00027 #include <battery_gauge_bq27441.h>
00028 
00029 #ifdef DEBUG_BQ27441
00030 # include <stdio.h>
00031 #endif
00032 
00033 // ----------------------------------------------------------------
00034 // COMPILE-TIME MACROS
00035 // ----------------------------------------------------------------
00036 
00037 /** How many loops to wait for a configuration update to be permitted.
00038 * Experience suggests that the limit really does need to be this large. */
00039 #define CONFIG_UPDATE_LOOPS 200
00040 
00041 /** How long to delay when running around the config update loop. */
00042 #define CONFIG_UPDATE_LOOP_DELAY_MS 100
00043 
00044 /** How long to wait for all the ADC readings to be performed. */
00045 #define ADC_READ_WAIT_MS 1000
00046 
00047 /** Delay after the last config update before we can unseal the
00048 * chip again (see section 6.4.5.1.1 of the BQ27441 technical
00049 * reference manual). */
00050 #define UNSEAL_DELAY_MS 4000
00051 
00052 // ----------------------------------------------------------------
00053 // PRIVATE VARIABLES
00054 // ----------------------------------------------------------------
00055 
00056 // ----------------------------------------------------------------
00057 // GENERIC PRIVATE FUNCTIONS
00058 // ----------------------------------------------------------------
00059 
00060 // Read two bytes from an address.
00061 // Note: gpI2c should be locked before this is called.
00062 bool BatteryGaugeBq27441::getTwoBytes (uint8_t registerAddress, uint16_t *pBytes)
00063 {
00064     bool success = false;
00065     char data[3];
00066 
00067     if (gpI2c != NULL) {
00068         // Send a command to read from registerAddress
00069         data[0] = registerAddress;
00070         data[1] = 0;
00071         data[2] = 0;
00072 
00073         if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) &&
00074             (gpI2c->read(gAddress, &(data[1]), 2) == 0)) {
00075             success = true;
00076             if (pBytes) {
00077                 *pBytes = (((uint16_t) data[2]) << 8) + data[1];
00078             }
00079         }
00080     }
00081 
00082     return success;
00083 }
00084 
00085 bool BatteryGaugeBq27441::getTwoBytesSigned (uint8_t registerAddress, int16_t *pBytes)
00086 {
00087     bool success = false;
00088     char data[3];
00089 
00090     if (gpI2c != NULL) {
00091         // Send a command to read from registerAddress
00092         data[0] = registerAddress;
00093         data[1] = 0;
00094         data[2] = 0;
00095 
00096         if ((gpI2c->write(gAddress, &(data[0]), 1) == 0) &&
00097             (gpI2c->read(gAddress, &(data[1]), 2) == 0)) {
00098             success = true;
00099             if (pBytes) {
00100                 *pBytes = (((int16_t) data[2]) << 8) + data[1];
00101             }
00102         }
00103     }
00104 
00105     return success;
00106 }
00107 
00108 // Compute the checksum over a block of data.
00109 uint8_t BatteryGaugeBq27441::computeChecksum(const char * pData)
00110 {
00111     uint8_t checkSum = 0;
00112     uint8_t x;
00113 
00114     if (pData != NULL) {
00115 #ifdef DEBUG_BQ27441_BLOCK_DATA
00116         printf ("BatteryGaugeBq27441 (I2C 0x%02x): computing check sum on data block.\n", gAddress >> 1);
00117         printf (" 0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F\n");
00118 #endif
00119         for (x = 1; x <= 32; x++) {
00120             checkSum += *pData;
00121             
00122 #ifdef DEBUG_BQ27441_BLOCK_DATA
00123             if (x % 16 == 8) {
00124                 printf ("%02x  ", *pData);
00125             } else if (x % 16 == 0) {
00126                 printf ("%02x\n", *pData);
00127             } else {
00128                 printf ("%02x-", *pData);
00129             }
00130 #endif
00131             pData++;
00132         }
00133 
00134         checkSum = 0xff - checkSum;
00135     }
00136 
00137 #ifdef DEBUG_BQ27441_BLOCK_DATA
00138     if (x % 16 !=  1) {
00139         printf("\n");
00140     }
00141     
00142     printf ("BatteryGaugeBq27441 (I2C 0x%02x): check sum is 0x%02x.\n", gAddress >> 1, checkSum);
00143 #endif    
00144     
00145     return checkSum;
00146 }
00147 
00148 // Read data of a given length and class ID.
00149 // Note: gpI2c should be locked before this is called.
00150 bool BatteryGaugeBq27441::readExtendedData(uint8_t subClassId, int32_t offset, int32_t length, char * pData)
00151 {
00152     bool success = false;
00153     bool wasSealed = false;
00154     char block[32];
00155     char data[3];
00156 
00157     if ((gpI2c != NULL) && (length <= 32) && (pData != NULL)) {            
00158         
00159         // The offset + length combination must not cross a 32-byte boundary
00160         if (offset / 32 == (offset + length - 1) / 32) {
00161         
00162 #ifdef DEBUG_BQ27441
00163             printf("BatteryGaugeBq27441 (I2C 0x%02x): preparing to read %d byte(s) from offset %d of sub-class %d.\n", gAddress >> 1, (int) length, (int) offset, subClassId);
00164 #endif
00165             // Handle unsealing
00166             wasSealed = isSealed();
00167             if (!wasSealed || unseal(gSealCode)) {
00168 
00169                 // Enable Block Data Control (0x61)
00170                 data[0] = 0x61;
00171                 data[1] = 0;
00172 
00173                 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
00174                     // Write sub-class ID using Data Block Class (0x3e)
00175                     data[0] = 0x3e;
00176                     data[1] = subClassId;
00177 
00178                     if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
00179                         // Write offset using Block Offset (0x3f) and then
00180                         // read the data block
00181                         data[0] = 0x3f;
00182                         data[1] = offset / 32;
00183 
00184                         if ((gpI2c->write(gAddress, &(data[0]), 2, true) == 0) &&
00185                             (gpI2c->read(gAddress, &(block[0]), 32) == 0)) {
00186                             // Compute the block checksum and then read it
00187                             data[2] = computeChecksum(&(block[0]));
00188                             data[0] = 0x60;
00189                             data[1] = 0;
00190 
00191                             if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) &&
00192                                 (gpI2c->read(gAddress, &(data[1]), 1) == 0)) {
00193 
00194                                 // Does the checksum match?
00195                                 if (data[1] == data[2]) {              
00196                                     // If so read the new data from the block data area at 0x40 plus
00197                                     // the offset (plus the Block Offset already written)
00198                                     data[0] = 0x40 + (offset % 32);
00199                                 
00200                                     if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) &&
00201                                         (gpI2c->read(gAddress, pData, length) == 0)) {
00202                                         success = true;
00203 #ifdef DEBUG_BQ27441
00204                                         printf("BatteryGaugeBq27441 (I2C 0x%02x): read successful.\n", gAddress >> 1);
00205 #endif
00206                                     } else {
00207 #ifdef DEBUG_BQ27441
00208                                         printf("BatteryGaugeBq27441 (I2C 0x%02x): couldn't read all %d bytes of config.\r", gAddress >> 1, (int) length);
00209 #endif
00210                                     }
00211                                 } else {
00212 #ifdef DEBUG_BQ27441
00213                                     printf("BatteryGaugeBq27441 (I2C 0x%02x): checksum on data block incorrect (expected 0x%02x, received 0x%02x).\n", gAddress >> 1, data[2], data[1]);
00214 #endif
00215                                 }
00216                             } else {
00217 #ifdef DEBUG_BQ27441
00218                                 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to read Block Data Checksum for config.\n", gAddress >> 1);
00219 #endif
00220                             }
00221                         } else {
00222 #ifdef DEBUG_BQ27441
00223                             printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write Block Offset (%d), or maybe read the data block, for config.\n", gAddress >> 1, data[1]);
00224 #endif
00225                         }
00226                     } else {
00227 #ifdef DEBUG_BQ27441
00228                         printf("BatteryGaugeBq27441 (I2C 0x%02x): unable set sub-class ID (0x%02x) for config.\n", gAddress >> 1, subClassId);
00229 #endif
00230                     }
00231                 } else {
00232 #ifdef DEBUG_BQ27441
00233                     printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to set Block Data Control for config.\n", gAddress >> 1);
00234 #endif
00235                 }
00236             } else {
00237 #ifdef DEBUG_BQ27441
00238                 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to unseal chip.\n", gAddress >> 1);
00239 #endif
00240             }
00241         } else {
00242 #ifdef DEBUG_BQ27441
00243             printf("BatteryGaugeBq27441 (I2C 0x%02x): offset (%d) is in different 32 byte block to offset + length (%d) [length is %d].\n", gAddress >> 1, (int) offset, (int) (offset + length), (int) length);
00244 #endif
00245         }
00246     }
00247 
00248     // Reseal if required, and fail if it fails
00249     if (wasSealed) {
00250         if (!seal()) {
00251             success = false;
00252         }
00253     }
00254 
00255     return success;
00256 }
00257 
00258 // Write data of a given length and class ID to a given offset.  This code taken from
00259 // section 3.1 of the SLUUAC9A application technical reference manual with hints from:
00260 // https://github.com/sparkfun/SparkFun_BQ27441_Arduino_Library/blob/master/src/SparkFunBQ27441.cpp.
00261 // Note: gpI2c should be locked before this is called.
00262 bool BatteryGaugeBq27441::writeExtendedData(uint8_t subClassId, int32_t offset, int32_t length, const char * pData)
00263 {
00264     bool success = false;
00265     bool wasSealed = false;
00266     char data[3 + 32];
00267     char block[32];
00268     uint16_t answer;
00269     uint32_t count = 0;
00270 
00271     if ((gpI2c != NULL) && (length <= 32) && (pData != NULL)) {
00272 
00273         // The offset + length combination must not cross a 32-byte boundary
00274         if (offset / 32 == (offset + length - 1) / 32) {        
00275 #ifdef DEBUG_BQ27441
00276             printf("BatteryGaugeBq27441 (I2C 0x%02x): preparing to write %d byte(s) to offset %d of sub-class %d.\n", gAddress >> 1, (int) length, (int) offset, subClassId);
00277 #endif
00278             // Handle unsealing
00279             wasSealed = isSealed();
00280             if (!wasSealed || unseal(gSealCode)) {
00281 
00282                 // Send Config Update (command 0x13)
00283                 data[0] = 0;
00284                 data[1] = 0x13;
00285                 data[2] = 0;
00286 
00287                 if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
00288                     // Wait for CONFIGUPDATE to be set in Flags register (bit 4)
00289                     count = 0;
00290                     do {
00291                         answer = 0;
00292                         getTwoBytes(0x06, &answer);
00293                         count++;
00294                         wait_ms(CONFIG_UPDATE_LOOP_DELAY_MS);
00295                     } while (((answer & (1 << 4)) == 0) && (count < CONFIG_UPDATE_LOOPS));
00296 
00297                     if ((answer & (1 << 4)) != 0) {
00298                         // Enable Block Data Control (0x61)
00299                         data[0] = 0x61;
00300                         data[1] = 0;
00301 
00302                         if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
00303                             // Write sub-class ID using Data Block Class (0x3e)
00304                             data[0] = 0x3e;
00305                             data[1] = subClassId;
00306 
00307                             if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
00308                                 // Write offset using Block Offset (0x3f) and then
00309                                 // read the data block
00310                                 data[0] = 0x3f;
00311                                 data[1] = offset / 32;
00312 
00313                                 if ((gpI2c->write(gAddress, &(data[0]), 2, true) == 0) &&
00314                                     (gpI2c->read(gAddress, &(block[0]), 32) == 0)) {
00315                                     // Compute the existing block checksum and then read it
00316                                     data[2] = computeChecksum(&(block[0]));
00317                                     data[0] = 0x60;
00318                                     data[1] = 0;
00319 
00320                                     if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) &&
00321                                         (gpI2c->read(gAddress, &(data[1]), 1) == 0)) {
00322 
00323                                         // Does the checksum match?
00324                                         if (data[1] == data[2]) {
00325                                             // If so write the new data to the block data area at 0x40 plus the offset (plus the Block Offset already written)
00326                                             // NOTE: I tried doing this as two separate writes, one of the offset and then another of the
00327                                             // data block (so that I could use pData directly rather than having to extend the local
00328                                             // data array by 32) but the chip didn't like that, hence we have to copy pData into the
00329                                             // local array and do a single contiguous write.
00330                                             data[0] = 0x40 + (offset % 32);
00331                                             memcpy (&(data[1]), pData, length);
00332 
00333                                             if (gpI2c->write(gAddress, &(data[0]), length + 1) == 0) {
00334                                                 // Also write the data into our local block variable 
00335                                                 // on top of the previously read data and use
00336                                                 // that to compute the new block checksum, then write it
00337                                                 memcpy (&(block[offset % 32]), pData, length); 
00338                                                 data[0] = 0x60;
00339                                                 data[1] = computeChecksum(&(block[0]));
00340                                                 
00341                                                 if (gpI2c->write(gAddress, &(data[0]), 2) == 0) {
00342                                                     // Exit config mode with SOFT_RESET command 0x42
00343                                                     data[0] = 0;
00344                                                     data[1] = 0x42;
00345                                                     data[2] = 0;
00346 
00347                                                     if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
00348                                                         // Finally, wait for CONFIGUPDATE to be unset in Flags register (bit 4)
00349                                                         count = 0;
00350                                                         do {
00351                                                             answer = 0xFFFF;
00352                                                             getTwoBytes(0x06, &answer);
00353                                                             count++;
00354                                                             wait_ms(CONFIG_UPDATE_LOOP_DELAY_MS);
00355                                                         } while (((answer & (1 << 4)) != 0) && (count < CONFIG_UPDATE_LOOPS));
00356 
00357                                                         if ((answer & (1 << 4)) == 0) {
00358                                                             success = true;
00359                                                             // Wait around for 4 seconds if there has been a config update
00360                                                             // and there is a danger that we might have to unseal the device
00361                                                             // Note: would be nice if we could note the time and do other
00362                                                             // things but the timer is restarted when certain commands are sent,
00363                                                             // so it is better to be dumb
00364                                                             if (wasSealed) {
00365                                                                 wait_ms(UNSEAL_DELAY_MS);
00366                                                             }    
00367 #ifdef DEBUG_BQ27441
00368                                                             printf("BatteryGaugeBq27441 (I2C 0x%02x): write successful.\n", gAddress >> 1);
00369 #endif
00370                                                         } else {
00371 #ifdef DEBUG_BQ27441
00372                                                             printf("BatteryGaugeBq27441 (I2C 0x%02x): Flags register didn't show config update flag unset in time (0x%04x).\n", gAddress >> 1, answer);
00373 #endif
00374                                                         }
00375                                                     } else {
00376 #ifdef DEBUG_BQ27441
00377                                                         printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write config update exit after update.\n", gAddress >> 1);
00378 #endif
00379                                                     }
00380                                                 } else {
00381 #ifdef DEBUG_BQ27441
00382                                                     printf("BatteryGaugeBq27441 (I2C 0x%02x): checksum on modified data block incorrect (0x%02x) during config update.\n", gAddress >> 1, data[1]);
00383 #endif
00384                                                 }
00385                                             } else {
00386 #ifdef DEBUG_BQ27441
00387                                                 printf("BatteryGaugeBq27441 (I2C 0x%02x): couldn't write all %d bytes during config update.\n", gAddress >> 1, (int) length);
00388 #endif
00389                                             }
00390                                         } else {
00391 #ifdef DEBUG_BQ27441
00392                                             printf("BatteryGaugeBq27441 (I2C 0x%02x): checksum on read data block incorrect (expected 0x%02x, received 0x%02x).\n", gAddress >> 1, data[2], data[1]);
00393 #endif
00394                                         }
00395                                     } else {
00396 #ifdef DEBUG_BQ27441
00397                                         printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to read Block Data Checksum for config update.\n", gAddress >> 1);
00398 #endif
00399                                     }
00400                                 } else {
00401 #ifdef DEBUG_BQ27441
00402                                     printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write Block Offset (%d), or possibly read the data block, for config update.\n", gAddress >> 1, data[1]);
00403 #endif
00404                                 }
00405                             } else {
00406 #ifdef DEBUG_BQ27441
00407                                 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to set sub-class ID (0x%02x) for config update.\r", gAddress >> 1, subClassId);
00408 #endif
00409                             }
00410                         } else {
00411 #ifdef DEBUG_BQ27441
00412                             printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to set Block Data Control for config update.\n", gAddress >> 1);
00413 #endif
00414                         }
00415                     } else {
00416 #ifdef DEBUG_BQ27441
00417                         printf("BatteryGaugeBq27441 (I2C 0x%02x): Flags register didn't show config update flag set in time (0x%04x).\n", gAddress >> 1, answer);
00418 #endif
00419                     }
00420                 } else {
00421 #ifdef DEBUG_BQ27441
00422                     printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to write to control register for config update.\n", gAddress >> 1);
00423 #endif
00424                 }
00425             } else {
00426 #ifdef DEBUG_BQ27441
00427                 printf("BatteryGaugeBq27441 (I2C 0x%02x): unable to unseal chip.\n", gAddress >> 1);
00428 #endif
00429             }
00430         } else {
00431 #ifdef DEBUG_BQ27441
00432             printf("BatteryGaugeBq27441 (I2C 0x%02x): offset (%d) is in different 32 byte block to offset + length (%d) [length is %d].\n", gAddress >> 1, (int) offset, (int) (offset + length), (int) length);
00433 #endif
00434         }
00435     }
00436     
00437     // If the write succeeded the exit from config update state will
00438     // re-seal things.  If it failed, we need to re-seal the device
00439     // manually if it was previously sealed.
00440     if (!success && wasSealed) {
00441         if (!seal()) {
00442             success = false;
00443         }
00444     }
00445 
00446     return success;
00447 }
00448 
00449 
00450 // Check if the chip is SEALED or UNSEALED.
00451 // Note: gpI2c should be locked before this is called.
00452 bool BatteryGaugeBq27441::isSealed(void)
00453 {
00454     bool sealed = false;
00455     char data[3];
00456     uint16_t controlStatus;
00457 
00458     // Send a control command to read the control status register
00459     data[0] = 0x00;  // Set address to first register for control
00460     data[1] = 0x00;  // First byte of CONTROL_STATUS sub-command (0x00)
00461     data[2] = 0x00;  // Second byte of CONTROL_STATUS sub-command (0x00) (register address will auto-increment)
00462 
00463     if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
00464         if (getTwoBytes (0, &controlStatus)) {
00465             // Bit 5 of the high byte is set to 1 if the device is sealed
00466             if (controlStatus & (1 << 13)) {
00467                 sealed = true;
00468 #ifdef DEBUG_BQ27441
00469                 printf("BatteryGaugeBq27441 (I2C 0x%02x): is sealed (control status 0x%04x).\r\n", gAddress >> 1, controlStatus);
00470             } else {
00471                 printf("BatteryGaugeBq27441 (I2C 0x%02x): is unsealed (control status 0x%04x).\r\n", gAddress >> 1, controlStatus);
00472 #endif
00473             }
00474         }
00475     }
00476     
00477     return sealed;
00478 }
00479 
00480 // Put the chip into SEALED mode.
00481 // Note: gpI2c should be locked before this is called.
00482 bool BatteryGaugeBq27441::seal(void)
00483 {
00484     bool success = false;
00485     char data[3];
00486     uint16_t controlStatus;
00487 
00488     // Send a SEALED sub-command
00489     data[0] = 0x00;  // Set address to first register for control
00490     data[1] = 0x20;  // First byte of SEALED sub-command (0x20)
00491     data[2] = 0x00;  // Second byte of SEALED sub-command (0x00) (register address will auto-increment)
00492 
00493     if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
00494         // Check for success by reading the control status register
00495         data[0] = 0x00;  // Set address to first register for control
00496         data[1] = 0x00;  // First byte of CONTROL_STATUS sub-command (0x00)
00497         data[2] = 0x00;  // Second byte of CONTROL_STATUS sub-command (0x00) (register address will auto-increment)
00498 
00499         if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
00500             if (getTwoBytes (0, &controlStatus)) {
00501                 // Bit 5 of the high byte is set to 1 if the device is sealed
00502                 if (controlStatus & (1 << 13)) {
00503                     success = true;
00504 #ifdef DEBUG_BQ27441
00505                     printf("BatteryGaugeBq27441 (I2C 0x%02x): now sealed.\n", gAddress >> 1);
00506                 } else {
00507                     printf("BatteryGaugeBq27441 (I2C 0x%02x): seal failed (control status 0x%04x).\n", gAddress >> 1, controlStatus);
00508 #endif
00509                 }
00510             }
00511         }
00512     }
00513     
00514     return success;
00515 }
00516 
00517 // Send the seal code to the device to unseal it.
00518 // Note: gpI2c should be locked before this is called.
00519 bool BatteryGaugeBq27441::unseal(uint16_t sealCode)
00520 {
00521     bool success = false;
00522     char data[3];
00523     uint16_t controlStatus;
00524 
00525     // Send the unseal code to the control register
00526     data[0] = 0x00;  // Set address to first register for control
00527     data[1] = (char) sealCode;         // First byte of code
00528     data[2] = (char) (sealCode >> 8);  // Second byte of code (register address will auto-increment)
00529 
00530 
00531     if ((gpI2c->write(gAddress, &(data[0]), 3) == 0) &&
00532         (gpI2c->write(gAddress, &(data[0]), 3) == 0)) {
00533         // Check for success by reading the control status register
00534         data[0] = 0x00;  // Set address to first register for control
00535         data[1] = 0x00;  // First byte of CONTROL_STATUS sub-command (0x00)
00536         data[2] = 0x00;  // Second byte of CONTROL_STATUS sub-command (0x00) (register address will auto-increment)
00537 
00538         if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
00539             if (getTwoBytes (0, &controlStatus)) {
00540                 // Bit 5 of the high byte is 0 if the device is unsealed
00541                 if ((controlStatus & (1 << 13)) == 0) {
00542                     success = true;
00543 #ifdef DEBUG_BQ27441
00544                     printf("BatteryGaugeBq27441 (I2C 0x%02x): now unsealed with seal code 0x%04x (control status 0x%04x).\n", gAddress >> 1, sealCode, controlStatus);
00545                 } else {
00546                     printf("BatteryGaugeBq27441 (I2C 0x%02x): unseal failed (with seal code 0x%04x, control status 0x%04x).\n", gAddress >> 1, sealCode, controlStatus);
00547 #endif
00548                 }
00549             }
00550         }
00551     }
00552     
00553     return success;
00554 }
00555 
00556 // Make sure that the device is awake and has taken a reading.
00557 // Note: the function does its own locking of gpI2C so that it isn't
00558 // locked for the entire time we wait for ADC readings to complete.
00559 bool BatteryGaugeBq27441::makeAdcReading(void)
00560 {
00561     bool success = false;
00562     char data[3];
00563     
00564     // Send CLEAR_HIBERNATE
00565     data[0] = 0x00;  // Set address to first register for control
00566     data[1] = 0x12;  // First byte of CLEAR_HIBERNATE sub-command (0x12)
00567     data[2] = 0x00;  // Second byte of CLEAR_HIBERNATE sub-command (0x00) (register address will auto-increment)
00568 
00569     gpI2c->lock();
00570     success = (gpI2c->write(gAddress, &(data[0]), 3) == 0);
00571     gpI2c->unlock();
00572     wait_ms (ADC_READ_WAIT_MS);
00573     
00574     return success;
00575 }
00576 
00577 // Set Hibernate mode.
00578 // Note: gpI2c should be locked before this is called.
00579 bool BatteryGaugeBq27441::setHibernate(void)
00580 {
00581     char data[3];
00582     
00583     // Send SET_HIBERNATE
00584     data[0] = 0x00;  // Set address to first register for control
00585     data[1] = 0x11;  // First byte of SET_HIBERNATE sub-command (0x11)
00586     data[2] = 0x00;  // Second byte of SET_HIBERNATE sub-command (0x00) (register address will auto-increment)
00587     
00588     return (gpI2c->write(gAddress, &(data[0]), 3) == 0);
00589 }
00590 
00591 //----------------------------------------------------------------
00592 // PUBLIC FUNCTIONS
00593 // ----------------------------------------------------------------
00594 
00595 // Constructor.
00596 BatteryGaugeBq27441::BatteryGaugeBq27441(void)
00597 {
00598     gpI2c = NULL;
00599     gReady = false;
00600     gGaugeOn = false;
00601     gSealCode = 0;
00602 }
00603 
00604 // Destructor.
00605 BatteryGaugeBq27441::~BatteryGaugeBq27441(void)
00606 {
00607 }
00608 
00609 // Initialise ourselves.
00610 bool BatteryGaugeBq27441::init (I2C * pI2c, uint8_t address, uint16_t sealCode)
00611 {
00612     uint16_t answer;
00613     char data[4];
00614 
00615     gpI2c = pI2c;
00616     gAddress = address << 1;
00617     gSealCode = sealCode;
00618 
00619     if (gpI2c != NULL) {
00620         gpI2c->lock();
00621         
00622         // Send a control command to read the firmware version
00623         data[0] = 0x00;  // Set address to first register for control
00624         data[1] = 0x02;  // First byte of FW_VERSION sub-command (0x02)
00625         data[2] = 0x00;  // Second byte of FW_VERSION sub-command (0x00) (register address will auto-increment)
00626 
00627         if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
00628             if (getTwoBytes (0, &answer)) {
00629                 // The expected response is 0x0109
00630                 if (((answer >> 8) == 0x01) && ((answer & 0xff) == 0x09)) {
00631 #ifdef DEBUG_BQ27441
00632                     if (readExtendedData(112, 0, 4, &(data[0]))) {
00633                         printf("BatteryGaugeBq27441 (I2C 0x%02x): seal code stored in chip is 0x%02x%02x%02x%02x.\n", gAddress >> 1, data[0], data[1], data[2], data[3]);
00634                     }
00635 #endif
00636                     // Set the Sleep Current to the maximum value so that, if
00637                     // we tell the chip to go to sleep mode, it will do so
00638                     // straight away.  Sleep Current is offset 31 in the State
00639                     // sub-class (82) and max value is 1000.  Since offset 31
00640                     // and a length of 2 crosses a 32 bytes boundary this needs
00641                     // two separate writes.
00642                     data[0] = (char) (1000 >> 8);
00643                     data[1] = (char) 1000;
00644                     
00645                     if (writeExtendedData(82, 31, 1, &(data[0])) &&
00646                         writeExtendedData(82, 32, 1, &(data[1]))) {
00647                         // Now enter Hibernate mode to minimise power consumption
00648                         // Need to set either the Hibernate Current or Hibernate Voltage value
00649                         // to max, otherwise we won't hibernate, then set the SET_HIBERNATE
00650                         // bit.  Here we set Hibernate V element (offset 9) in the Power
00651                         // sub-class (68) to its max value (see section 6.4.1.6.2 of the
00652                         // BQ27441 technical reference manual).
00653                         // Note: the cell must also be "relaxed" for this to occur and so
00654                         // the chip may still not enter Hibernate mode for a little while.                    
00655                         data[0] = (char) (5000 >> 8);
00656                         data[1] = (char) 5000;
00657                         
00658                         if (writeExtendedData(68, 9, 2, &(data[0]))) {
00659                             // Now send SET_HIBERNATE
00660                             gReady = setHibernate();
00661                         }
00662                     }
00663                 }
00664 #ifdef DEBUG_BQ27441
00665                 printf("BatteryGaugeBq27441 (I2C 0x%02x): read 0x%04x as FW_VERSION, expected 0x0109.\n", gAddress >> 1, answer);
00666 #endif
00667             }
00668         }
00669         gpI2c->unlock();
00670     }
00671 
00672 #ifdef DEBUG_BQ27441
00673     if (gReady) {
00674         printf("BatteryGaugeBq27441 (I2C 0x%02x): handler initialised.\r\n", gAddress >> 1);
00675     } else {
00676         printf("BatteryGaugeBq27441 (I2C 0x%02x): init NOT successful.\r\n", gAddress >> 1);
00677     }
00678 #endif
00679 
00680     return gReady;
00681 }
00682 
00683 // Switch on the battery capacity monitor.
00684 bool BatteryGaugeBq27441::enableGauge (bool isSlow)
00685 {
00686     bool success = false;
00687     char data[3];
00688     
00689     if (gReady && (gpI2c != NULL)) {
00690         gpI2c->lock();
00691         // Make sure that we are not in hibernate
00692         data[0] = 0x00;  // Set address to first register for control
00693         data[1] = 0x12;  // First byte of CLEAR_HIBERNATE sub-command (0x12)
00694         data[2] = 0x00;  // Second byte of CLEAR_HIBERNATE sub-command (0x00)
00695         if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
00696             gGaugeOn = true;
00697             // Read the OpConfig register which is in the Registers sub-class
00698             // (64) at offset 0.
00699             if (readExtendedData(64, 0, 2, &(data[0]))) {
00700 #ifdef DEBUG_BQ27441
00701                 printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig is 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
00702 #endif                        
00703                 // SLEEP mode is bit 5 of the low byte of OpConfig.  In SLEEP
00704                 // mode a reading is taken every 20 seconds.
00705                 if (isSlow && ((data[1] & (1 << 5)) == 0)) {
00706                     // Set the SLEEP bit 'cos it's not set and needs to be
00707                     data[1] |= 1 << 5;
00708                     // Write the new value back
00709                     success = writeExtendedData(64, 0, 2, &(data[0]));
00710 #ifdef DEBUG_BQ27441
00711                     if (success) {
00712                         printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
00713                     }
00714 #endif                        
00715                 } else if (!isSlow && ((data[1] & (1 << 5)) != 0)) {
00716                     // Clear the SLEEP bit 'cos it's set and shouldn't be
00717                     data[1] &= ~(1 << 5);
00718                     // Write the new value back
00719                     success = writeExtendedData(64, 0, 2, &(data[0]));
00720 #ifdef DEBUG_BQ27441
00721                     if (success) {
00722                         printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
00723                     }
00724 #endif                        
00725                 } else {
00726                     success = true;
00727                 }
00728             }
00729         }
00730         
00731         gpI2c->unlock();
00732     }
00733     
00734     return success;
00735 }
00736 
00737 // Switch off the battery capacity monitor.
00738 bool BatteryGaugeBq27441::disableGauge (void)
00739 {
00740     bool success = false;
00741     
00742     if (gReady && (gpI2c != NULL)) {
00743         gpI2c->lock();
00744         // Send SET_HIBERNATE
00745         if (setHibernate()) {
00746             success = true;
00747             gGaugeOn = false;
00748         }
00749         
00750         gpI2c->unlock();
00751     }
00752     
00753     return success;
00754 }
00755 
00756 // Determine whether battery gauging is enabled.
00757 bool BatteryGaugeBq27441::isGaugeEnabled(void)
00758 {
00759     return gGaugeOn;
00760 }
00761 
00762 // Disable the battery detect pin.
00763 bool BatteryGaugeBq27441::disableBatteryDetect (void)
00764 {
00765     bool success = false;
00766     char data[3];
00767     
00768     if (gReady && (gpI2c != NULL)) {
00769         gpI2c->lock();
00770         // Read the OpConfig register which is in the Registers sub-class
00771         // (64) at offset 0.
00772         if (readExtendedData(64, 0, 2, &(data[0]))) {
00773 #ifdef DEBUG_BQ27441
00774             printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig is 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
00775 #endif                        
00776             // Battery Insertion Enabled is bit 5 of the high byte of OpConfig.
00777             // 1 means that the battery input pin is enabled
00778             if (((data[0] & (1 << 5)) != 0)) {
00779                 // Clear the BIE bit 'cos it's set and is shouldn't be
00780                 data[0] &= ~(1 << 5);
00781                 // Write the new value back
00782                 if (writeExtendedData(64, 0, 2, &(data[0]))) {
00783                     // Send the Battery Inserted message as we can't do gauging otherwise
00784                     data[0] = 0x00;  // Set address to first register for control
00785                     data[1] = 0x0C;  // First byte of BAT_INSERT sub-command (0x0C)
00786                     data[2] = 0x00;  // Second byte of BAT_INSERT sub-command (0x00)
00787                     success = gpI2c->write(gAddress, &(data[0]), 3) == 0;
00788 #ifdef DEBUG_BQ27441
00789                     if (success) {
00790                         printf("BatteryGaugeBq27441 (I2C 0x%02x): BIE disabled, BAT_INSERT sent, OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
00791                     }
00792 #endif
00793                 }
00794             } else {
00795                 success = true;
00796             }
00797         }
00798         
00799         // Set hibernate again if we are not monitoring
00800         if (!gGaugeOn) {
00801             setHibernate();
00802         }
00803 
00804         gpI2c->unlock();
00805     }
00806     
00807     return success;
00808 }
00809 
00810 // Enable the battery detect pin.
00811 bool BatteryGaugeBq27441::enableBatteryDetect (void)
00812 {
00813     bool success = false;
00814     char data[3];
00815     
00816     if (gReady && (gpI2c != NULL)) {
00817         gpI2c->lock();
00818         // Read the OpConfig register which is in the Registers sub-class
00819         // (64) at offset 0.
00820         if (readExtendedData(64, 0, 2, &(data[0]))) {
00821 #ifdef DEBUG_BQ27441
00822             printf("BatteryGaugeBq27441 (I2C 0x%02x): OpConfig is 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
00823 #endif                        
00824             // Battery Insertion Enabled is bit 5 of the high byte of OpConfig.
00825             // 1 means that the battery input pin is enabled
00826             if (((data[0] & (1 << 5)) == 0)) {
00827                 // Set the BIE bit 'cos it's not set and needs to be
00828                 data[0] |= 1 << 5;
00829                 // Write the new value back
00830                 success = writeExtendedData(64, 0, 2, &(data[0]));
00831 #ifdef DEBUG_BQ27441
00832                 if (success) {
00833                     printf("BatteryGaugeBq27441 (I2C 0x%02x): BIE enabled, OpConfig becomes 0x%02x%02x.\r\n", gAddress >> 1, data[0], data[1]);
00834                 }
00835 #endif                        
00836             } else {
00837                 success = true;
00838             }
00839         }
00840         
00841         // Set hibernate again if we are not monitoring
00842         if (!gGaugeOn) {
00843             setHibernate();
00844         }
00845 
00846         gpI2c->unlock();
00847     }
00848     
00849     return success;
00850 }
00851 
00852 // Check whether a battery has been detected or not.
00853 bool BatteryGaugeBq27441::isBatteryDetected (void)
00854 {
00855     bool isDetected = false;
00856     uint16_t data;
00857 
00858     if (gReady && (gpI2c != NULL)) {
00859         
00860         // Make sure there's a recent reading
00861         if (gGaugeOn || makeAdcReading()) {            
00862             gpI2c->lock();            
00863             // Read from the flags register address
00864             if (getTwoBytes (0x06, &data)) {
00865 
00866                 // If bit 3 is set then a battery has been detected
00867                 if (data & (1 << 3)) {
00868                     isDetected = true;
00869                 }
00870 
00871 #ifdef DEBUG_BQ27441
00872                 if (isDetected) {
00873                     printf("BatteryGaugeBq27441 (I2C 0x%02x): battery detected (flags 0x%04x).\n", gAddress >> 1, data);
00874                 } else {
00875                     printf("BatteryGaugeBq27441 (I2C 0x%02x): battery NOT detected (flags 0x%04x).\n", gAddress >> 1, data);
00876                 }
00877 #endif
00878             }
00879             
00880             // Set hibernate again if we are not monitoring
00881             if (!gGaugeOn) {
00882                 setHibernate();
00883             }
00884 
00885             gpI2c->unlock();
00886         }        
00887     }
00888     
00889     return isDetected;
00890 }
00891 
00892 // Get the temperature of the chip.
00893 bool BatteryGaugeBq27441::getTemperature (int32_t *pTemperatureC)
00894 {
00895     bool success = false;
00896     int32_t temperatureC = 0;
00897     uint16_t data;
00898 
00899     if (gReady && (gpI2c != NULL)) {
00900         // Make sure there's a recent reading
00901         if (gGaugeOn || makeAdcReading()) {            
00902             gpI2c->lock();
00903             // Read from the temperature register address
00904             if (getTwoBytes (0x02, &data)) {
00905                 success = true;
00906 
00907                 // The answer is in units of 0.1 K, so convert to C
00908                 temperatureC = ((int32_t) data / 10) - 273;
00909 
00910                 if (pTemperatureC) {
00911                     *pTemperatureC = temperatureC;
00912                 }
00913 
00914 #ifdef DEBUG_BQ27441
00915                 printf("BatteryGaugeBq27441 (I2C 0x%02x): chip temperature %.1f K, so %d C.\n", gAddress >> 1, ((float) data) / 10, (int) temperatureC);
00916 #endif
00917             }
00918         
00919             // Return to sleep if we are allowed to
00920             if (!gGaugeOn && !setHibernate()) {
00921                 success = false;
00922             }
00923             
00924             gpI2c->unlock();
00925         }
00926     }
00927 
00928     return success;
00929 }
00930 
00931 // Get the voltage of the battery.
00932 bool BatteryGaugeBq27441::getVoltage (int32_t *pVoltageMV)
00933 {
00934     bool success = false;
00935     uint16_t data = 0;
00936 
00937     if (gReady && (gpI2c != NULL)) {
00938         // Make sure there's a recent reading
00939         if (gGaugeOn || makeAdcReading()) {            
00940             gpI2c->lock();
00941             // Read from the voltage register address
00942             if (getTwoBytes (0x04, &data)) {
00943                 success = true;
00944 
00945                 // The answer is in mV
00946                 if (pVoltageMV) {
00947                     *pVoltageMV = (int32_t) data;
00948                 }
00949 
00950 #ifdef DEBUG_BQ27441
00951                 printf("BatteryGaugeBq27441 (I2C 0x%02x): battery voltage %.3f V.\n", gAddress >> 1, ((float) data) / 1000);
00952 #endif
00953             }
00954 
00955             // Return to sleep if we are allowed to
00956             if (!gGaugeOn && !setHibernate()) {
00957                 success = false;
00958             }
00959 
00960             gpI2c->unlock();
00961         }
00962     }
00963     
00964     return success;
00965 }
00966 
00967 // Get the power output of the battery
00968 bool BatteryGaugeBq27441::getPower (int32_t *pPowerMW)
00969 {
00970     bool success = false;
00971     int16_t data = 0;
00972 
00973     if (gReady && (gpI2c != NULL)) {
00974         // Make sure there's a recent reading
00975         if (gGaugeOn || makeAdcReading()) {            
00976             gpI2c->lock();
00977             // Read from the power register address
00978             if (getTwoBytesSigned (0x18, &data)) {
00979                 success = true;
00980 
00981                 // The answer is in mW
00982                 if (pPowerMW) {
00983                     *pPowerMW = (int32_t) data;
00984                 }
00985 
00986             }
00987 
00988             // Return to sleep if we are allowed to
00989             if (!gGaugeOn && !setHibernate()) {
00990                 success = false;
00991             }
00992 
00993             gpI2c->unlock();
00994         }
00995     }
00996     
00997     return success;
00998 }
00999 
01000 // Get the current flowing from the battery.
01001 bool BatteryGaugeBq27441::getCurrent (int32_t *pCurrentMA)
01002 {
01003     bool success = false;
01004     int16_t data;
01005 
01006     if (gReady && (gpI2c != NULL)) {
01007         // Make sure there's a recent reading
01008         if (gGaugeOn || makeAdcReading()) {            
01009             gpI2c->lock();            
01010             // Read from the average current register address
01011             if (getTwoBytesSigned  (0x10, &data)) {
01012                 success = true;
01013 
01014                 if (pCurrentMA) {
01015                     *pCurrentMA = (int32_t) data;
01016                 }
01017             }
01018 
01019             // Return to sleep if we are allowed to
01020             if (!gGaugeOn && !setHibernate()) {
01021                 success = false;
01022             }
01023 
01024             gpI2c->unlock();
01025         }
01026     }
01027     
01028     return success;
01029 }
01030 
01031 // Get the remaining battery capacity.
01032 bool BatteryGaugeBq27441::getRemainingCapacity (int32_t *pCapacityMAh)
01033 {
01034     bool success = false;
01035     uint16_t data = 0;
01036 
01037     if (gReady && (gpI2c != NULL)) {
01038         // Make sure there's a recent reading
01039         if (gGaugeOn || makeAdcReading()) {            
01040             gpI2c->lock();            
01041             // Read from the RemainingCapacity register address
01042             
01043             if (getTwoBytes (0x0c, &data)) {
01044                 success = true;
01045 
01046                 // The answer is in mAh
01047                 if (pCapacityMAh) {
01048                     *pCapacityMAh = (int32_t) data;
01049                 }
01050 
01051 #ifdef DEBUG_BQ27441
01052                 printf("BatteryGaugeBq27441 (I2C 0x%02x): remaining battery capacity %u mAh.\n", gAddress >> 1, data);
01053 #endif
01054             }
01055 
01056             // Return to sleep if we are allowed to
01057             if (!gGaugeOn && !setHibernate()) {
01058                 success = false;
01059             }
01060 
01061             gpI2c->unlock();
01062         }
01063     }
01064     
01065     return success;
01066 }
01067 
01068 // Get the battery percentage remaining
01069 bool BatteryGaugeBq27441::getRemainingPercentage (int32_t *pBatteryPercent)
01070 {
01071     bool success = false;
01072     uint16_t data = 0;
01073 
01074     if (gReady && (gpI2c != NULL)) {
01075         // Make sure there's a recent reading
01076         if (gGaugeOn || makeAdcReading()) {            
01077             gpI2c->lock();            
01078             
01079             // Wake up and take a reading if we have to
01080             if (!gGaugeOn && !setHibernate()) {
01081                 success = false;
01082             }
01083 
01084             // Read from the StateOfCharge register address
01085             if (getTwoBytes (0x1c, &data)) {
01086                 success = true;
01087 
01088                 if (pBatteryPercent) {
01089                     *pBatteryPercent = (int32_t) data;
01090                 }
01091 
01092 #ifdef DEBUG_BQ27441
01093                 printf("BatteryGaugeBq27441 (I2C 0x%02x): remaining battery percentage %u%%.\n", gAddress >> 1, data);
01094 #endif
01095             }
01096 
01097             // Return to sleep if we are allowed to
01098             if (!gGaugeOn && !setHibernate()) {
01099                 success = false;
01100             }
01101 
01102             gpI2c->unlock();
01103         }
01104     }
01105     
01106     return success;
01107 }
01108 
01109 // Advanced function to read a configuration data block.
01110 bool BatteryGaugeBq27441::advancedGetConfig(uint8_t subClassId, int32_t offset, int32_t length, char * pData)
01111 {
01112     bool success = false;
01113 
01114     if (gReady && (gpI2c != NULL) && (pData != NULL)) {
01115         gpI2c->lock();
01116         // Read the extended configuration data
01117         success = readExtendedData(subClassId, offset, length, pData);
01118 #ifdef DEBUG_BQ27441
01119         if (success) {
01120             printf("BatteryGaugeBq27441 (I2C 0x%02x): read extended data with subClassId %d from offset %d.\n", gAddress >> 1, subClassId, (int) offset);
01121         }
01122 #endif
01123 
01124         // Return to sleep if we are allowed to
01125         if (!gGaugeOn && !setHibernate()) {
01126             success = false;
01127         }
01128 
01129         gpI2c->unlock();
01130     }
01131 
01132     return success;
01133 }
01134 
01135 // Advanced function to write a configuration data block.
01136 bool BatteryGaugeBq27441::advancedSetConfig(uint8_t subClassId, int32_t offset, int32_t length, const char * pData)
01137 {
01138     bool success = false;
01139 
01140     if (gReady && (gpI2c != NULL) && (pData != NULL)) {
01141         gpI2c->lock();
01142         // Write the extended configuration data
01143         success = writeExtendedData(subClassId, offset, length, pData);
01144 #ifdef DEBUG_BQ27441
01145         if (success) {
01146             printf("BatteryGaugeBq27441 (I2C 0x%02x): written %d byte(s) of extended data with subClassId %d from offset %d.\n", gAddress >> 1, (int) length, subClassId, (int) offset);
01147         }
01148 #endif
01149 
01150         // Return to sleep if we are allowed to
01151         if (!gGaugeOn && !setHibernate()) {
01152             success = false;
01153         }
01154 
01155         gpI2c->unlock();
01156     }
01157 
01158     return success;
01159 }
01160 
01161 // Send a control word.
01162 bool BatteryGaugeBq27441::advancedSendControlWord (uint16_t controlWord, uint16_t *pDataReturned)
01163 {
01164     bool success = false;
01165     char data[3];
01166 
01167     if (gReady && (gpI2c != NULL)) {
01168         gpI2c->lock();
01169         // Send the control command
01170         data[0] = 0x00;  // Set address to first register for control
01171         data[1] = (char) controlWord;        // First byte of controlWord
01172         data[2] = (char) (controlWord >> 8); // Second byte of controlWord
01173         if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
01174             // Read the two bytes returned if requested
01175             if (pDataReturned != NULL) {
01176                 if (getTwoBytes(0, pDataReturned)) {
01177                     success = true;
01178 #ifdef DEBUG_BQ27441
01179                     printf("BatteryGaugeBq27441 (I2C 0x%02x): sent control word 0x%04x, read back 0x%04x.\n", gAddress >> 1, controlWord, *pDataReturned);
01180 #endif
01181                 }
01182             } else {
01183                 success = true;
01184 #ifdef DEBUG_BQ27441
01185                 printf("BatteryGaugeBq27441 (I2C 0x%02x): sent control word 0x%04x.\n", gAddress >> 1, controlWord);
01186 #endif
01187             }
01188         }
01189         gpI2c->unlock();
01190     }
01191 
01192     return success;
01193 }
01194 
01195 // Read two bytes starting at a given address on the chip.
01196 bool BatteryGaugeBq27441::advancedGet (uint8_t address, uint16_t *pDataReturned)
01197 {
01198     bool success = false;
01199     uint16_t value;
01200 
01201     if (gReady && (gpI2c != NULL)) {
01202         // Make sure there's a recent reading, as most
01203         // of these commands involve the chip having done one
01204         if (gGaugeOn || makeAdcReading()) {            
01205             gpI2c->lock();
01206             // Read the data
01207             if (getTwoBytes(address, &value)) {
01208                 success = true;
01209 #ifdef DEBUG_BQ27441
01210                 printf("BatteryGaugeBq27441 (I2C 0x%02x): read 0x%04x from addresses 0x%02x and 0x%02x.\n", gAddress >> 1, value, address, address + 1);
01211 #endif
01212                 if (pDataReturned != NULL) {
01213                     *pDataReturned = value;
01214                 }
01215             }
01216             gpI2c->unlock();
01217         }
01218     }
01219 
01220     return success;
01221 }
01222 
01223 // Check if the chip is SEALED or UNSEALED.
01224 bool BatteryGaugeBq27441::advancedIsSealed()
01225 {
01226     bool sealed = false;
01227 
01228     if (gReady && (gpI2c != NULL)) {
01229         gpI2c->lock();
01230         // Check for sealedness
01231         sealed = isSealed();
01232         
01233         // Return to sleep if we are allowed to
01234         if (!gGaugeOn) {
01235             setHibernate();
01236         }
01237 
01238         gpI2c->unlock();
01239     }
01240 
01241     return sealed;
01242 }
01243 
01244 // Put the chip into SEALED mode.
01245 bool BatteryGaugeBq27441::advancedSeal()
01246 {
01247     bool success = false;
01248 
01249     if (gReady && (gpI2c != NULL)) {
01250         gpI2c->lock();
01251         // Seal
01252         success = seal();
01253 
01254         // Return to sleep if we are allowed to
01255         if (!gGaugeOn && !setHibernate()) {
01256             success = false;
01257         }
01258 
01259         gpI2c->unlock();
01260     }
01261 
01262     return success;
01263 }
01264 
01265 // Unseal the device.
01266 bool BatteryGaugeBq27441::advancedUnseal(uint16_t sealCode)
01267 {
01268     bool success = false;
01269     char updateStatus;
01270 
01271     if (gReady && (gpI2c != NULL)) {
01272         gpI2c->lock();
01273         // Unseal and read the Update Status value
01274         if (unseal(sealCode) && readExtendedData(82, 2, 1, &updateStatus)) {
01275             // If the update status value has the top bit set then the chip will
01276             // reseal itself on the next reset, so this bit needs to be cleared to
01277             // unseal it properly
01278             if ((updateStatus & (1 << 7)) != 0) {
01279                 updateStatus &= ~(1 << 7);
01280                 success = writeExtendedData(82, 2, 1, &updateStatus);
01281             } else {
01282                 success = true;
01283             }
01284         }
01285 
01286         // Return to sleep if we are allowed to
01287         if (!gGaugeOn && !setHibernate()) {
01288             success = false;
01289         }
01290 
01291         gpI2c->unlock();
01292     }
01293 
01294     return success;
01295 }
01296 
01297 // Do a hard reset of the chip.
01298 bool BatteryGaugeBq27441::advancedReset(void)
01299 {
01300     bool success = false;
01301     bool wasSealed;
01302     char data[3];
01303 
01304     if (gReady && (gpI2c != NULL)) {
01305         gpI2c->lock();
01306 
01307         // Handle unsealing, as this command only works when unsealed
01308         wasSealed = isSealed();
01309         if (!wasSealed || unseal(gSealCode)) {
01310             // Send a RESET sub-command
01311             data[0] = 0x00;  // Set address to first register for control
01312             data[1] = 0x41;  // First byte of RESET sub-command (0x41)
01313             data[2] = 0x00;  // Second byte of RESET sub-command (0x00) (register address will auto-increment)
01314 
01315             if (gpI2c->write(gAddress, &(data[0]), 3) == 0) {
01316                 success = true;
01317 #ifdef DEBUG_BQ27441
01318                 printf("BatteryGaugeBq27441 (I2C 0x%02x): chip hard reset.\n", gAddress >> 1);
01319 #endif
01320             }
01321             
01322             // Handle re-sealing and fail if we need to re-seal but can't
01323             if (wasSealed && !seal()) {
01324                 success = false;
01325             }
01326         }
01327         
01328         // Return to sleep if we are allowed to
01329         if (!gGaugeOn && !setHibernate()) {
01330             success = false;
01331         }
01332         
01333         gpI2c->unlock();
01334     }
01335 
01336     return success;
01337 }
01338 
01339 /* End Of File */