This class provides APIs to all of the registers of the TI BQ35100 battery gauge, as used on the u-blox C030 primary battery shield.
Dependents: example-battery-gauge-bq35100
bq35100.cpp
- Committer:
- RobMeades
- Date:
- 2017-11-09
- Revision:
- 1:ee7cc8d75283
- Parent:
- 0:cec745c014b7
- Child:
- 2:4c699a813451
File content as of revision 1:ee7cc8d75283:
/* mbed Microcontroller Library * Copyright (c) 2017 u-blox * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file bq35100.cpp * This file defines the API to the TI BQ35100 battery gauge chip. */ /** Define these to print debug information. */ #define DEBUG_BQ35100 #define DEBUG_BQ35100_BLOCK_DATA #include <mbed.h> #include <battery_gauge_bq35100.h> #ifdef DEBUG_BQ35100 # include <stdio.h> #endif // ---------------------------------------------------------------- // COMPILE-TIME MACROS // ---------------------------------------------------------------- /** How many loops to wait for a configuration update to be permitted. * Experience suggests that the limit really does need to be this large. */ #define CONFIG_UPDATE_LOOPS 200 /** How long to delay when running around the config update loop. */ #define CONFIG_UPDATE_LOOP_DELAY_MS 100 /** How long to wait for each loop while device is initialising. */ #define INIT_LOOP_WAIT_MS 100 /** The maximum number of init loops to wait for. */ #define INIT_LOOP_COUNT 10 /** How long to wait for a security mode change to succeed. */ #define SET_SECURITY_MODE_RETRY_SECONDS 5 // ---------------------------------------------------------------- // PRIVATE VARIABLES // ---------------------------------------------------------------- // ---------------------------------------------------------------- // GENERIC PRIVATE FUNCTIONS // ---------------------------------------------------------------- // Read two bytes from an address. // Note: gpI2c should be locked before this is called. bool BatteryGaugeBq35100::getTwoBytes (uint8_t registerAddress, uint16_t *pBytes) { bool success = false; char data[3]; if (gpI2c != NULL) { data[0] = registerAddress; data[1] = 0; data[2] = 0; // Send a command to read from registerAddress if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) && (gpI2c->read(gAddress, &(data[1]), 2) == 0)) { success = true; if (pBytes) { *pBytes = (((uint16_t) data[2]) << 8) + data[1]; } } } return success; } // Compute the checksum over an address plus the block of data. uint8_t BatteryGaugeBq35100::computeChecksum (const char * pData, int32_t length) { uint8_t checkSum = 0; uint8_t x = 0; if (pData != NULL) { #ifdef DEBUG_BQ35100_BLOCK_DATA printf ("BatteryGaugeBq35100 (I2C 0x%02x): computing check sum on data block.\n", gAddress >> 1); printf (" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); #endif for (x = 1; x <= length; x++) { checkSum += *pData; #ifdef DEBUG_BQ35100_BLOCK_DATA if (x % 16 == 8) { printf ("%02x ", *pData); } else if (x % 16 == 0) { printf ("%02x\n", *pData); } else { printf ("%02x-", *pData); } #endif pData++; } checkSum = 0xff - checkSum; } #ifdef DEBUG_BQ35100_BLOCK_DATA if (x % 16 != 1) { printf("\n"); } printf ("BatteryGaugeBq35100 (I2C 0x%02x): check sum is 0x%02x.\n", gAddress >> 1, checkSum); #endif return checkSum; } // Read data of a given length from a given address. // Note: gpI2c should be locked before this is called. bool BatteryGaugeBq35100::readExtendedData (int32_t address, int32_t length, char * pData) { int32_t lengthRead; bool success = false; SecurityMode securityMode = getSecurityMode(); char block[32 + 2 + 2]; // 32 bytes of data, 2 bytes of address, // 1 byte of MACDataSum and 1 byte of MACDataLen char data[3]; // Handle security mode if (setSecurityMode(SECURITY_MODE_UNSEALED)) { if ((gpI2c != NULL) && (length <= 32) && (address >= 0x4000) && (address < 0x4400) && (pData != NULL)) { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): preparing to read %d byte(s) from address 0x%04x.\n", gAddress >> 1, (int) length, (unsigned int) address); #endif // Enable Block Data Control (0x61) data[0] = 0x61; data[1] = 0; if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { // Write address to ManufacturerAccessControl (0x3e) data[0] = 0x3e; data[1] = (char) address; data[2] = (char) (address >> 8); if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { // Read the address from ManufacturerAccessControl (0x3e then 0x3f), // data from MACData (0x40 to 0x5f), checksum from MACDataSum (0x60) // and length from MACDataLen (0x61) if ((gpI2c->write(gAddress, &(data[0]), 1, true) == 0) && (gpI2c->read(gAddress, &(block[0]), sizeof (block)) == 0)) { // Check that the address matches if ((block[0] == (char) address) && (block[1] == (char) (address >> 8))) { // Check that the checksum matches (-2 on MACDataLen as it includes MACDataSum and itself) if (block[34] == computeChecksum (&(block[0]), block[35] - 2)) { // All is good, copy the data to the user lengthRead = block[35] - 4; // -4 rather than -2 to remove the two bytes of address as well if (lengthRead > length) { lengthRead = length; } memcpy(pData, &(block[2]), lengthRead); success = true; #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): %d byte(s) read successfully.\n", gAddress >> 1, (int) lengthRead); #endif } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): checksum didn't match (0x%02x expected).\n", gAddress >> 1, block[34]); #endif } } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): address didn't match (expected 0x%04x, received 0x%02x%02x).\n", gAddress >> 1, (unsigned int) address, block[1], block[0]); #endif } } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to read %d bytes from ManufacturerAccessControl.\n", gAddress >> 1, sizeof (block)); #endif } } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write %d bytes to ManufacturerAccessControl.\r", gAddress >> 1, 3); #endif } } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set Block Data Control.\n", gAddress >> 1); #endif } } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set the security mode of the chip.\n", gAddress >> 1); #endif } } // Put the security mode back to what it was if (!setSecurityMode(securityMode)) { success = false; } return success; } // Write data of a given length to a given address. // Note: gpI2c should be locked before this is called. bool BatteryGaugeBq35100::writeExtendedData(int32_t address, int32_t length, const char * pData) { bool success = false; SecurityMode securityMode = getSecurityMode(); char data[3 + 32]; if ((gpI2c != NULL) && (length <= 32) && (address >= 0x4000) && (address < 0x4400) && (pData != NULL)) { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): preparing to write %d byte(s) to address 0x%04x.\n", gAddress >> 1, (int) length, (unsigned int) address); #endif // Handle security mode if (setSecurityMode(SECURITY_MODE_UNSEALED)) { // Enable Block Data Control (0x61) data[0] = 0x61; data[1] = 0; if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { // Start write at ManufacturerAccessControl (0x3e) data[0] = 0x3e; // Next two bytes are the address we will write to data[1] = (char) address; data[2] = (char) (address >> 8); // Remaining bytes are the data bytes we wish to write memcpy (&(data[3]), pData, length); if (gpI2c->write(gAddress, &(data[0]), 3 + length) == 0) { // Compute the checksum and write it to MACDataSum (0x60) data[1] = computeChecksum (&(data[1]), length + 2); data[0] = 0x60; if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { // Write 4 + length to MACDataLen (0x61) data[1] = length + 4; data[0] = 0x61; if (gpI2c->write(gAddress, &(data[0]), 2) == 0) { // TODO check for successful write success = true; #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): write successful.\n", gAddress >> 1); #endif } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to read write to MACDataLen.\n", gAddress >> 1); #endif } } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write to MACDataSum.\n", gAddress >> 1); #endif } } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to write %d bytes to ManufacturerAccessControl.\r", gAddress >> 1, (int) length + 2); #endif } } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set Block Data Control.\n", gAddress >> 1); #endif } } else { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): unable to set the security mode of the chip.\n", gAddress >> 1); #endif } } // Put the security mode back to what it was if (!setSecurityMode(securityMode)) { success = false; } return success; } // Get the security mode of the chip. // Note: gpI2c should be locked before this is called. BatteryGaugeBq35100::SecurityMode BatteryGaugeBq35100::getSecurityMode(void) { SecurityMode securityMode = SECURITY_MODE_UNKNOWN; char data[1]; uint16_t controlStatus; data[0] = 0; // Set address to first register for Control // Send a control command to read the control status register if (gpI2c->write(gAddress, &(data[0]), 1) == 0) { if (getTwoBytes(0, &controlStatus)) { // Bits 13 and 14 of the high byte represent the security status, // 01 = full access // 10 = unsealed access // 11 = sealed access securityMode = (SecurityMode) ((controlStatus >> 13) & 0x03); #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode is 0x%02x (control status 0x%04x).\r\n", gAddress >> 1, securityMode, controlStatus); #endif } } return securityMode; } // Set the security mode of the chip. // Note: gpI2c should be locked before this is called. bool BatteryGaugeBq35100::setSecurityMode(SecurityMode securityMode) { bool success = false; char data[3]; SecurityMode currentSecurityMode = getSecurityMode(); if (securityMode != SECURITY_MODE_UNKNOWN) { if (securityMode != currentSecurityMode) { // For reasons that aren't clear, the BQ35100 sometimes refuses // to change security mode if a previous security mode change // happend only a few seconds ago, hence the retry here for (int32_t x = 0; (x < SET_SECURITY_MODE_RETRY_SECONDS) && !success; x++) { data[0] = 0; // Set address to first register for Control) switch (securityMode) { case SECURITY_MODE_SEALED: // Just seal the chip data[1] = 0x20; // First byte of SEALED sub-command (0x20) data[2] = 0x00; // Second byte of SEALED sub-command (0x00) (register address will auto-increment) gpI2c->write(gAddress, &(data[0]), 3); break; case SECURITY_MODE_FULL_ACCESS: // Send the full access code with endianness conversion // in TWO writes data[2] = (char) (gFullAccessCodes >> 24); data[1] = (char) (gFullAccessCodes >> 16); gpI2c->write(gAddress, &(data[0]), 3); data[2] = (char) (gFullAccessCodes >> 8); data[1] = (char) gFullAccessCodes; gpI2c->write(gAddress, &(data[0]), 3); break; case SECURITY_MODE_UNSEALED: data[2] = (char) (gSealCodes >> 24); data[1] = (char) (gSealCodes >> 16); gpI2c->write(gAddress, &(data[0]), 3); data[2] = (char) (gSealCodes >> 8); data[1] = (char) gSealCodes; gpI2c->write(gAddress, &(data[0]), 3); break; case SECURITY_MODE_UNKNOWN: default: MBED_ASSERT(false); break; } currentSecurityMode = getSecurityMode(); if (currentSecurityMode == securityMode) { success = true; #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode is now 0x%02x.\n", gAddress >> 1, currentSecurityMode); #endif } else { wait_ms(1000); #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): security mode set failed (wanted 0x%02x, got 0x%02x), will retry.\n", gAddress >> 1, securityMode, currentSecurityMode); #endif } } } else { success = true; } } return success; } // Make sure that the device is awake and has taken a reading. // Note: the function does its own locking of gpI2C so that it isn't // locked for the entire time we wait for ADC readings to complete. bool BatteryGaugeBq35100::makeAdcReading(void) { bool success = false; uint16_t controlStatus; char data[1]; // Wait for INITCOMP to be set data[0] = 0; // Set address to first register for Control gpI2c->lock(); // Raise the pin *pGaugeEnable = 1; wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS); for (int x = 0; !success && (x < INIT_LOOP_COUNT); x++) { if (gpI2c->write(gAddress, &(data[0]), 1) == 0) { if (getTwoBytes(0, &controlStatus)) { #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): read 0x%04x as CONTROL_STATUS.\n", gAddress >> 1, controlStatus); #endif // Bit 7 is INITCOMP if (((controlStatus >> 7) & 0x01) == 0x01) { success = true; } } wait_ms (INIT_LOOP_WAIT_MS); } } gpI2c->unlock(); return success; } //---------------------------------------------------------------- // PUBLIC FUNCTIONS // ---------------------------------------------------------------- // Constructor. BatteryGaugeBq35100::BatteryGaugeBq35100(void) { gpI2c = NULL; pGaugeEnable = NULL; gReady = false; gSealCodes = 0; gFullAccessCodes = 0; gGaugeOn = false; } // Destructor. BatteryGaugeBq35100::~BatteryGaugeBq35100(void) { if (pGaugeEnable) { *pGaugeEnable = 0; delete pGaugeEnable; } } // Initialise ourselves. bool BatteryGaugeBq35100::init(I2C * pI2c, PinName gaugeEnable, uint8_t address, uint32_t sealCodes) { uint16_t answer; char data[4]; gpI2c = pI2c; gAddress = address << 1; gSealCodes = sealCodes; pGaugeEnable = new DigitalOut(gaugeEnable, 1); wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS); if (gpI2c != NULL) { gpI2c->lock(); gpI2c->frequency(I2C_CLOCK_FREQUENCY); // Send a control command to read the device type data[0] = 0x3e; // Set address to ManufacturerAccessControl data[1] = 0x03; // First byte of HW_VERSION sub-command (0x03) data[2] = 0x00; // Second byte of HW_VERSION sub-command (0x00) (register address will auto-increment) if ((gpI2c->write(gAddress, &(data[0]), 3) == 0) && getTwoBytes(0x40, &answer)) { // Read from MACData address if (answer == 0x00a8) { // Read the full access codes, in case we need them if (readExtendedData(0x41d0, sizeof (data), &(data[0]))) { // The four bytes are the full access codes gFullAccessCodes = ((uint32_t) data[0] << 24) + ((uint32_t) data[1] << 16) + ((uint32_t) data[2] << 8) + data[3]; #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): full access code is 0x%08x.\n", gAddress >> 1, (unsigned int) gFullAccessCodes); #endif gReady = true; } } #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): read 0x%04x as HW_VERSION, expected 0x00a8.\n", gAddress >> 1, answer); #endif } if (!gGaugeOn) { *pGaugeEnable = 0; } gpI2c->unlock(); } #ifdef DEBUG_BQ35100 if (gReady) { printf("BatteryGaugeBq35100 (I2C 0x%02x): handler initialised.\n", gAddress >> 1); } else { printf("BatteryGaugeBq35100 (I2C 0x%02x): init NOT successful.\n", gAddress >> 1); } #endif return gReady; } // Switch on the battery capacity monitor. bool BatteryGaugeBq35100::enableGauge(void) { bool success = false; if (gReady) { *pGaugeEnable = 1; wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS); success = true; } return success; } // Switch off the battery capacity monitor. bool BatteryGaugeBq35100::disableGauge(void) { bool success = false; if (gReady) { *pGaugeEnable = 0; success = true; } return success; } // Determine whether battery gauging is enabled. bool BatteryGaugeBq35100::isGaugeEnabled(void) { bool isEnabled = false; if (gReady) { isEnabled = true; } return isEnabled; } // Set the designed capacity of the cell. bool BatteryGaugeBq35100::setDesignCapacity(uint32_t capacityMAh) { bool success = false; char data[2]; if (gReady) { gpI2c->lock(); data[0] = capacityMAh >> 8; // Upper byte of design capacity data[1] = capacityMAh; // Lower byte of design capacity // Write to the "Cell Design Capacity mAh" address in data flash if (writeExtendedData(0x41fe, sizeof(data), &(data[0]))) { success = true; #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): designed cell capacity set to %d mAh.\n", gAddress >> 1, (unsigned int) capacityMAh); #endif } gpI2c->unlock(); } return success; } // Get the designed capacity of the cell. bool BatteryGaugeBq35100::getDesignCapacity(uint32_t *pCapacityMAh) { bool success = false; uint16_t data; if (gReady) { gpI2c->lock(); // Read from the DesignCapacity address if (getTwoBytes (0x3c, &data)) { success = true; // The answer is in mAh if (pCapacityMAh) { *pCapacityMAh = data; } #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): designed cell capacity is %d mAh.\n", gAddress >> 1, data); #endif } } return success; } // Get the temperature of the chip. bool BatteryGaugeBq35100::getTemperature(int32_t *pTemperatureC) { bool success = false; int32_t temperatureC = 0; uint16_t data; if (gReady && (gGaugeOn || makeAdcReading())) { gpI2c->lock(); // Read from the temperature register address if (getTwoBytes (0x06, &data)) { success = true; // The answer is in units of 0.1 K, so convert to C temperatureC = ((int32_t) data / 10) - 273; if (pTemperatureC) { *pTemperatureC = temperatureC; } #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): chip temperature %.1f K, so %d C.\n", gAddress >> 1, ((float) data) / 10, (int) temperatureC); #endif } if (!gGaugeOn) { *pGaugeEnable = 0; } gpI2c->unlock(); } return success; } // Get the voltage of the battery. bool BatteryGaugeBq35100::getVoltage(int32_t *pVoltageMV) { bool success = false; uint16_t data = 0; if (gReady && (gGaugeOn || makeAdcReading())) { gpI2c->lock(); // Read from the voltage register address if (getTwoBytes (0x08, &data)) { success = true; // The answer is in mV if (pVoltageMV) { *pVoltageMV = (int32_t) data; } #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery voltage %.3f V.\n", gAddress >> 1, ((float) data) / 1000); #endif } if (!gGaugeOn) { *pGaugeEnable = 0; } gpI2c->unlock(); } return success; } // Get the current flowing from the battery. bool BatteryGaugeBq35100::getCurrent(int32_t *pCurrentMA) { bool success = false; int32_t currentMA = 0; uint16_t data; if (gReady && (gGaugeOn || makeAdcReading())) { gpI2c->lock(); // Read from the average current register address if (getTwoBytes (0x0c, &data)) { success = true; if (pCurrentMA) { *pCurrentMA = currentMA; } #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): current %d mA.\n", gAddress >> 1, (int) currentMA); #endif } if (!gGaugeOn) { *pGaugeEnable = 0; } gpI2c->unlock(); } return success; } // Get the battery capacity used. bool BatteryGaugeBq35100::getUsedCapacity(uint32_t *pCapacityUAh) { bool success = false; char bytes[5]; uint32_t data; if (gReady && (gGaugeOn || makeAdcReading())) { gpI2c->lock(); // Read four bytes from the AccummulatedCapacity register address // Send a command to read from registerAddress bytes[0] = 0x02; bytes[1] = 0; bytes[2] = 0; bytes[3] = 0; bytes[4] = 0; if ((gpI2c->write(gAddress, &(bytes[0]), 1) == 0) && (gpI2c->read(gAddress, &(bytes[1]), 4) == 0)) { success = true; data = (((uint32_t) bytes[4]) << 24) + (((uint32_t) bytes[3]) << 16) + (((uint32_t) bytes[2]) << 8) + bytes[1]; // The answer is in uAh if (pCapacityUAh) { *pCapacityUAh = data; } #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity used %u uAh.\n", gAddress >> 1, (unsigned int) data); #endif } if (!gGaugeOn) { *pGaugeEnable = 0; } gpI2c->unlock(); } return success; } // Get the battery capacity remaining. bool BatteryGaugeBq35100::getRemainingCapacity(uint32_t *pCapacityUAh) { bool success = false; uint32_t designCapacityUAh; uint32_t usedCapacityUAh; // First, get the designed capacity if (getDesignCapacity(&designCapacityUAh)) { designCapacityUAh *= 1000; // Then get the used capacity if (getUsedCapacity(&usedCapacityUAh)) { success = true; // Limit the result if (usedCapacityUAh > designCapacityUAh) { usedCapacityUAh = designCapacityUAh; } // The answer is in uAh if (pCapacityUAh) { *pCapacityUAh = designCapacityUAh - usedCapacityUAh; } #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity remaining %u uAh (from a designed capacity of %d uAh).\n", gAddress >> 1, (unsigned int) (designCapacityUAh - usedCapacityUAh), (unsigned int) designCapacityUAh); #endif } } return success; } // Get the percentage capacity remaining. bool BatteryGaugeBq35100::getRemainingPercentage(int32_t *pBatteryPercentage) { bool success = false; uint32_t designCapacityUAh; uint32_t usedCapacityUAh; int32_t batteryPercentage; // First, get the designed capacity if (getDesignCapacity(&designCapacityUAh)) { designCapacityUAh *= 1000; // Then get the used capacity if (getUsedCapacity(&usedCapacityUAh)) { success = true; // Limit the result if (usedCapacityUAh > designCapacityUAh) { usedCapacityUAh = designCapacityUAh; } batteryPercentage = (uint64_t) (designCapacityUAh - usedCapacityUAh) * 100 / designCapacityUAh; if (pBatteryPercentage) { *pBatteryPercentage = batteryPercentage; } #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): battery capacity remaining %d%%.\n", gAddress >> 1, (unsigned int) batteryPercentage); #endif } } return success; } // Get the security mode of the chip. BatteryGaugeBq35100::SecurityMode BatteryGaugeBq35100::advancedGetSecurityMode(void) { SecurityMode securityMode = SECURITY_MODE_UNKNOWN; if (gReady) { gpI2c->lock(); if (!gGaugeOn) { *pGaugeEnable = 1; wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS); } securityMode = getSecurityMode(); if (!gGaugeOn) { *pGaugeEnable = 0; } gpI2c->unlock(); } return securityMode; } // Set the security mode of the chip. bool BatteryGaugeBq35100::advancedSetSecurityMode(SecurityMode securityMode) { bool success = false; if (gReady) { gpI2c->lock(); if (!gGaugeOn) { *pGaugeEnable = 1; wait_ms(GAUGE_ENABLE_SETTLING_TIME_MS); } success = setSecurityMode(securityMode); if (!gGaugeOn) { *pGaugeEnable = 0; } gpI2c->unlock(); } return success; } // Do a hard reset of the chip. bool BatteryGaugeBq35100::advancedReset(void) { bool success = false; SecurityMode securityMode; char data[3]; if (gReady && (gpI2c != NULL)) { gpI2c->lock(); securityMode = getSecurityMode(); // Must be inside lock() // Handle unsealing, as this command only works when unsealed if (setSecurityMode(SECURITY_MODE_UNSEALED)) { // Send a RESET sub-command data[0] = 0x3e; // Set address to first register for ManufacturerAccessControl data[1] = 0x41; // First byte of RESET sub-command (0x41) data[2] = 0x00; // Second byte of RESET sub-command (0x00) (register address will auto-increment) if (gpI2c->write(gAddress, &(data[0]), 3) == 0) { success = true; #ifdef DEBUG_BQ35100 printf("BatteryGaugeBq35100 (I2C 0x%02x): chip hard reset.\n", gAddress >> 1); #endif } // Set the security mode back to what it was if (!setSecurityMode(securityMode)) { success = false; } } if (!gGaugeOn) { *pGaugeEnable = 0; } gpI2c->unlock(); } return success; } /* End Of File */