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
TESTS/unit_tests/default/main.cpp
- Committer:
- RobMeades
- Date:
- 2017-11-10
- Revision:
- 2:4c699a813451
- Parent:
- 1:ee7cc8d75283
File content as of revision 2:4c699a813451:
#include "mbed.h" #include "greentea-client/test_env.h" #include "unity.h" #include "utest.h" #include "battery_gauge_bq35100.h" using namespace utest::v1; // ---------------------------------------------------------------- // COMPILE-TIME MACROS // ---------------------------------------------------------------- // The gauge enable pin #define GAUGE_ENABLE_PIN D4 // Pick some sensible minimum and maximum numbers #define MAX_TEMPERATURE_READING_C 80 #define MIN_TEMPERATURE_READING_C -20 #define MIN_VOLTAGE_READING_MV 0 #define MAX_VOLTAGE_READING_MV 12000 #define MAX_CURRENT_READING_MA 2000 #define MIN_CURRENT_READING_MA -2000 #define MIN_CAPACITY_READING_UAH 0 #define MAX_CAPACITY_READING_UAH 32177000 // Some randomly chosen #define SET_DESIGN_CAPACITY_MAH 32177 // values that match // ---------------------------------------------------------------- // PRIVATE VARIABLES // ---------------------------------------------------------------- // I2C interface I2C * gpI2C = new I2C(I2C_SDA, I2C_SCL); // ---------------------------------------------------------------- // PRIVATE FUNCTIONS // ---------------------------------------------------------------- // ---------------------------------------------------------------- // TESTS // ---------------------------------------------------------------- // Test that the BQ35100 battery gauge can be initialised void test_init() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); TEST_ASSERT_FALSE(pBatteryGauge->init(NULL, GAUGE_ENABLE_PIN)); TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); } // Test that a temperature reading can be performed void test_temperature() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); int32_t temperatureC = MIN_TEMPERATURE_READING_C - 1; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->getTemperature(&temperatureC)); // Normal case TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); TEST_ASSERT(pBatteryGauge->getTemperature(&temperatureC)); printf ("Temperature %d C.\n", (int) temperatureC); // Range check TEST_ASSERT((temperatureC >= MIN_TEMPERATURE_READING_C) && (temperatureC <= MAX_TEMPERATURE_READING_C)); // The parameter is allowed to be NULL TEST_ASSERT(pBatteryGauge->getTemperature(NULL)); } // Test that a voltage reading can be performed void test_voltage() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); int32_t voltageMV = MIN_VOLTAGE_READING_MV - 1; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->getVoltage(&voltageMV)); // Normal case TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); TEST_ASSERT(pBatteryGauge->getVoltage(&voltageMV)); printf ("Voltage %.3f V.\n", ((float) voltageMV) / 1000); // Range check TEST_ASSERT((voltageMV >= MIN_VOLTAGE_READING_MV) && (voltageMV <= MAX_VOLTAGE_READING_MV)); // The parameter is allowed to be NULL TEST_ASSERT(pBatteryGauge->getVoltage(NULL)); } // Test that a current reading can be performed void test_current() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); int32_t currentMA = MIN_CURRENT_READING_MA - 1; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->getCurrent(¤tMA)); // Normal case TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); TEST_ASSERT(pBatteryGauge->getCurrent(¤tMA)); printf ("Current %.3f A.\n", ((float) currentMA) / 1000); // Range check TEST_ASSERT((currentMA >= MIN_CURRENT_READING_MA) && (currentMA <= MAX_CURRENT_READING_MA)); // The parameter is allowed to be NULL TEST_ASSERT(pBatteryGauge->getCurrent(NULL)); } // Test that a capacity used reading can be performed void test_used_capacity() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); uint32_t capacityUAh = MIN_CAPACITY_READING_UAH - 1; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->getUsedCapacity(&capacityUAh)); // Normal case TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); TEST_ASSERT(pBatteryGauge->getUsedCapacity(&capacityUAh)); printf ("Used capacity %.3f mAh.\n", ((float) capacityUAh) / 1000); // Range check TEST_ASSERT((capacityUAh >= MIN_CAPACITY_READING_UAH) && (capacityUAh <= MAX_CAPACITY_READING_UAH)); // The parameter is allowed to be NULL TEST_ASSERT(pBatteryGauge->getUsedCapacity(NULL)); } // Test that the design capacity can be set and read void test_design_capacity() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); uint32_t originalDesignCapacity; uint32_t newDesignCapacity = SET_DESIGN_CAPACITY_MAH; uint32_t readDesignCapacity = 0; // Calls should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->getDesignCapacity(&readDesignCapacity)); TEST_ASSERT_FALSE(pBatteryGauge->setDesignCapacity(newDesignCapacity)); // First get the original design capacity TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); TEST_ASSERT(pBatteryGauge->getDesignCapacity(&originalDesignCapacity)); printf ("Design capacity was originally %d mAh.\n", (unsigned int) originalDesignCapacity); // Avoid the old and new values being the same if (originalDesignCapacity == newDesignCapacity) { newDesignCapacity--; } // Now set a new value TEST_ASSERT(pBatteryGauge->setDesignCapacity(newDesignCapacity)); printf ("Design capacity set to %d mAh.\n", (unsigned int) newDesignCapacity); // Read the value back and check that it's been set TEST_ASSERT(pBatteryGauge->getDesignCapacity(&readDesignCapacity)); printf ("Design capacity was read as %d mAh.\n", (unsigned int) readDesignCapacity); TEST_ASSERT(readDesignCapacity = newDesignCapacity) // The parameter in the get call is allowed to be NULL TEST_ASSERT(pBatteryGauge->getDesignCapacity(NULL)); // Put the original value back TEST_ASSERT(pBatteryGauge->setDesignCapacity(originalDesignCapacity)); printf ("Design capacity returned to %d mAh.\n", (unsigned int) originalDesignCapacity); } // Test that a remaining capacity reading can be performed void test_remaining_capacity() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); uint32_t capacityUAh = MIN_CAPACITY_READING_UAH - 1; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->getRemainingCapacity(&capacityUAh)); // Normal case TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); TEST_ASSERT(pBatteryGauge->getRemainingCapacity(&capacityUAh)); printf ("Remaining capacity %.3f mAh.\n", ((float) capacityUAh) / 1000); // Range check TEST_ASSERT((capacityUAh >= MIN_CAPACITY_READING_UAH) && (capacityUAh <= MAX_CAPACITY_READING_UAH)); // The parameter is allowed to be NULL TEST_ASSERT(pBatteryGauge->getRemainingCapacity(NULL)); } // Test that a remaining precentage reading can be performed void test_remaining_percentage() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); int32_t percentage = -1; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->getRemainingPercentage(&percentage)); // Normal case TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); TEST_ASSERT(pBatteryGauge->getRemainingPercentage(&percentage)); printf ("Remaining capacity %d%%.\n", (signed int) percentage); // Range check TEST_ASSERT((percentage >= 0) && (percentage <= 100)); // The parameter is allowed to be NULL TEST_ASSERT(pBatteryGauge->getRemainingPercentage(NULL)); } // Test behaviours with gauging on void test_gauging() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); uint32_t capacityUAh = MIN_CAPACITY_READING_UAH - 1; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->enableGauge()); TEST_ASSERT_FALSE(pBatteryGauge->disableGauge()); TEST_ASSERT_FALSE(pBatteryGauge->isGaugeEnabled()); // Normal case, gauging should be off to begin with TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); TEST_ASSERT_FALSE(pBatteryGauge->isGaugeEnabled()); // Enable gauge, without non-volatile storage TEST_ASSERT(pBatteryGauge->enableGauge()); TEST_ASSERT(pBatteryGauge->getUsedCapacity(&capacityUAh)); printf ("Used capacity %.3f mAh.\n", ((float) capacityUAh) / 1000); // Range check TEST_ASSERT((capacityUAh >= MIN_CAPACITY_READING_UAH) && (capacityUAh <= MAX_CAPACITY_READING_UAH)); TEST_ASSERT(pBatteryGauge->isGaugeEnabled()); TEST_ASSERT(pBatteryGauge->disableGauge()); TEST_ASSERT_FALSE(pBatteryGauge->isGaugeEnabled()); // Enable gauge, with non-volatile storage TEST_ASSERT(pBatteryGauge->enableGauge(true)); TEST_ASSERT(pBatteryGauge->getUsedCapacity(&capacityUAh)); printf ("Used capacity %.3f mAh.\n", ((float) capacityUAh) / 1000); // Range check // TODO: any way to check that the non-volatileness has worked? TEST_ASSERT((capacityUAh >= MIN_CAPACITY_READING_UAH) && (capacityUAh <= MAX_CAPACITY_READING_UAH)); TEST_ASSERT(pBatteryGauge->isGaugeEnabled()); TEST_ASSERT(pBatteryGauge->disableGauge()); TEST_ASSERT_FALSE(pBatteryGauge->isGaugeEnabled()); } // Test the new battery call void test_new_battery() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); uint32_t originalDesignCapacity; uint32_t newDesignCapacity = SET_DESIGN_CAPACITY_MAH; uint32_t readDesignCapacity = 0; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->newBattery(1000)); // Normal case TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); // Get the original design capacity so that we can set it back // at the end TEST_ASSERT(pBatteryGauge->getDesignCapacity(&originalDesignCapacity)); printf ("Design capacity was originally %d mAh.\n", (unsigned int) originalDesignCapacity); // Avoid the old and new values being the same if (originalDesignCapacity == newDesignCapacity) { newDesignCapacity--; } // Now add the new battery TEST_ASSERT(pBatteryGauge->newBattery(newDesignCapacity)); printf ("New battery added with design capacity %d mAh.\n", (unsigned int) newDesignCapacity); // Read the value back and check that it's been set TEST_ASSERT(pBatteryGauge->getDesignCapacity(&readDesignCapacity)); printf ("Design capacity was read as %d mAh.\n", (unsigned int) readDesignCapacity); TEST_ASSERT(readDesignCapacity = newDesignCapacity) // Put the original value back TEST_ASSERT(pBatteryGauge->setDesignCapacity(originalDesignCapacity)); printf ("Design capacity returned to %d mAh.\n", (unsigned int) originalDesignCapacity); } // Test get/set config void test_advanced_get_set_config() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); int32_t address = 0x4036; // Manufacturer Info Block A01, a 1 byte field char originalValue; char oldValue; char newValue; // Calls should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->advancedGetConfig(address, &originalValue, sizeof(originalValue))); TEST_ASSERT_FALSE(pBatteryGauge->advancedSetConfig(address, &newValue, sizeof(newValue))); // Initialise the battery gauge TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); // Normal case TEST_ASSERT(pBatteryGauge->advancedGetConfig(address, &originalValue, sizeof(originalValue))); // Invert the result and write it back oldValue = originalValue; printf ("Original value was 0x%02x.\n", oldValue); newValue = ~oldValue; printf ("Setting it to 0x%02x.\n", newValue); TEST_ASSERT(pBatteryGauge->advancedSetConfig(address, &newValue, sizeof(newValue))); // Read it and check that it has changed TEST_ASSERT(pBatteryGauge->advancedGetConfig(address, &oldValue, sizeof(oldValue))); printf ("Read back 0x%02x.\n", oldValue); TEST_ASSERT_EQUAL_UINT8(newValue, oldValue); // Put the original value back again TEST_ASSERT(pBatteryGauge->advancedSetConfig(address, &originalValue, sizeof(originalValue))); } // Send a control word void test_advanced_control() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); uint16_t controlWord = 0x0003; // get HW version uint16_t response = 0; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->advancedSendControlWord(controlWord, &response)); // Initialise the battery gauge TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); // Normal case TEST_ASSERT(pBatteryGauge->advancedSendControlWord(controlWord, &response)); // FW version must be 0x00a8 TEST_ASSERT_EQUAL_UINT16(0x00a8, response); // The parameter is allowed to be null TEST_ASSERT(pBatteryGauge->advancedSendControlWord(controlWord, NULL)); } // Read using a standard command void test_advanced_get() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); uint8_t address = 0x06; // Temperature uint16_t value = 0; int32_t temperatureC = -1; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->advancedGet(address, &value)); // Initialise the battery gauge TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); // Normal case TEST_ASSERT(pBatteryGauge->advancedGet(address, &value)); // Get the temperature via the standard API command TEST_ASSERT(pBatteryGauge->getTemperature(&temperatureC)); // Convert the value returned into a temperature reading and compare // it with the real answer, allowing a 1 degree tolerance in case // it has changed between readings. TEST_ASSERT_INT32_WITHIN (1, temperatureC, ((int32_t) value / 10) - 273); // The parameter is allowed to be null TEST_ASSERT(pBatteryGauge->advancedGet(address, NULL)); } // Test that the security mode of the chip can be changed void test_advanced_security_mode() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); BatteryGaugeBq35100::SecurityMode securityMode; // Get the existing device mode and then set it to sealed TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); printf ("Calling advancedGetSecurityMode()...\n"); securityMode = pBatteryGauge->advancedGetSecurityMode(); printf ("Calling advancedSetSecurityMode(SECURITY_MODE_SEALED)...\n"); TEST_ASSERT(pBatteryGauge->advancedSetSecurityMode(BatteryGaugeBq35100::SECURITY_MODE_SEALED)); delete pBatteryGauge; pBatteryGauge = new BatteryGaugeBq35100(); // Calls should fail if the battery gauge has not been initialised printf ("Calling advancedGetSecurityMode()...\n"); TEST_ASSERT(pBatteryGauge->advancedGetSecurityMode() == BatteryGaugeBq35100::SECURITY_MODE_UNKNOWN); printf ("Calling advancedSetSecurityMode(SECURITY_MODE_UNSEALED)...\n"); TEST_ASSERT_FALSE(pBatteryGauge->advancedSetSecurityMode(BatteryGaugeBq35100::SECURITY_MODE_UNSEALED)); // Normal case printf ("Calling init()...\n"); TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); printf ("Calling advancedGetSecurityMode()...\n"); TEST_ASSERT(pBatteryGauge->advancedGetSecurityMode() == BatteryGaugeBq35100::SECURITY_MODE_SEALED); // These calls should fail // TODO do a thing that only works when unsealed // TODO do a thing that only works when full access // Now unseal it printf ("Calling advancedSetSecurityMode(SECURITY_MODE_UNSEALED)...\n"); TEST_ASSERT(pBatteryGauge->advancedSetSecurityMode(BatteryGaugeBq35100::SECURITY_MODE_UNSEALED)); // This call should now pass // TODO do a thing that only works when unsealed // But this should still fail // TODO do a thing that only works when full access // Seal it again printf ("Calling advancedSetSecurityMode(SECURITY_MODE_SEALED)...\n"); TEST_ASSERT(pBatteryGauge->advancedSetSecurityMode(BatteryGaugeBq35100::SECURITY_MODE_SEALED)); // Now allow full access, which should fail as you can't get there from SEALED printf ("Calling advancedSetSecurityMode(SECURITY_MODE_FULL_ACCESS)...\n"); TEST_ASSERT_FALSE(pBatteryGauge->advancedSetSecurityMode(BatteryGaugeBq35100::SECURITY_MODE_FULL_ACCESS)); // Now unseal it printf ("Calling advancedSetSecurityMode(SECURITY_MODE_UNSEALED)...\n"); TEST_ASSERT(pBatteryGauge->advancedSetSecurityMode(BatteryGaugeBq35100::SECURITY_MODE_UNSEALED)); // *Now* allow full access, which should succeed printf ("Calling advancedSetSecurityMode(SECURITY_MODE_FULL_ACCESS)...\n"); TEST_ASSERT(pBatteryGauge->advancedSetSecurityMode(BatteryGaugeBq35100::SECURITY_MODE_FULL_ACCESS)); // These calls should now both pass // TODO do a thing that only works when unsealed // TODO do a thing that only works when full access // Put the device back the way it was TEST_ASSERT(pBatteryGauge->advancedSetSecurityMode(securityMode)); } // Reset the BQ35100 battery gauge chip void test_advanced_reset() { BatteryGaugeBq35100 * pBatteryGauge = new BatteryGaugeBq35100(); BatteryGaugeBq35100::SecurityMode securityMode; // Call should fail if the battery gauge has not been initialised TEST_ASSERT_FALSE(pBatteryGauge->advancedReset()); // Get the existing security mode and then set it to unsealed TEST_ASSERT(pBatteryGauge->init(gpI2C, GAUGE_ENABLE_PIN)); printf ("Calling advancedGetSecurityMode()...\n"); securityMode = pBatteryGauge->advancedGetSecurityMode(); printf ("Calling advancedSetSecurityMode(SECURITY_MODE_UNSEALED)...\n"); TEST_ASSERT(pBatteryGauge->advancedSetSecurityMode(BatteryGaugeBq35100::SECURITY_MODE_UNSEALED)); // TODO: modify a thing that will later be reset // Now reset the chip printf ("Calling advancedReset()...\n"); TEST_ASSERT(pBatteryGauge->advancedReset()); // TODO check that the thing has been reset // Put the security mode back to what it was TEST_ASSERT(pBatteryGauge->advancedSetSecurityMode(securityMode)); } // ---------------------------------------------------------------- // TEST ENVIRONMENT // ---------------------------------------------------------------- // Setup the test environment utest::v1::status_t test_setup(const size_t number_of_cases) { // Setup Greentea, timeout is long enough to run these tests with // DEBUG_BQ35100 defined GREENTEA_SETUP(250, "default_auto"); return verbose_test_setup_handler(number_of_cases); } // Test cases Case cases[] = { Case("Initialisation", test_init), Case("Temperature read", test_temperature), Case("Voltage read", test_voltage), Case("Current read", test_current), Case("Used capacity read", test_used_capacity), Case("Design capacity read/set", test_design_capacity), Case("Remaining capacity read", test_remaining_capacity), Case("Remaining precentage read", test_remaining_percentage), Case("Gauging", test_gauging), Case("New battery", test_new_battery), Case("Advanced get/set config", test_advanced_get_set_config), Case("Advanced control", test_advanced_control), Case("Advanced get", test_advanced_get), Case("Advanced security mode", test_advanced_security_mode), Case("Advanced reset", test_advanced_reset) }; Specification specification(test_setup, cases); // ---------------------------------------------------------------- // MAIN // ---------------------------------------------------------------- // Entry point into the tests int main() { bool success = false; if (gpI2C != NULL) { success = !Harness::run(specification); } else { printf ("Unable to instantiate I2C interface.\n"); } return success; } // End Of File