From 27a645353bf5be2ddb4b21a4f9121ab1681afb21 Mon Sep 17 00:00:00 2001 From: ksschwabe Date: Fri, 1 Jan 2016 18:17:00 +0100 Subject: [PATCH] batt_smbus: Adds functions for reading out the SBS Info Functions added for reading out the following info: - Manufacturer Name - Device Name - Serial Number - Device Chemistry --- src/drivers/batt_smbus/batt_smbus.cpp | 294 ++++++++++++++++++++++++-- 1 file changed, 272 insertions(+), 22 deletions(-) diff --git a/src/drivers/batt_smbus/batt_smbus.cpp b/src/drivers/batt_smbus/batt_smbus.cpp index 31b9c72913..f9214834c8 100644 --- a/src/drivers/batt_smbus/batt_smbus.cpp +++ b/src/drivers/batt_smbus/batt_smbus.cpp @@ -88,8 +88,11 @@ #define BATT_SMBUS_FULL_CHARGE_CAPACITY 0x10 ///< capacity when fully charged #define BATT_SMBUS_DESIGN_CAPACITY 0x18 ///< design capacity register #define BATT_SMBUS_DESIGN_VOLTAGE 0x19 ///< design voltage register -#define BATT_SMBUS_SERIALNUM 0x1c ///< serial number register -#define BATT_SMBUS_MANUFACTURE_NAME 0x20 ///< manufacturer name +#define BATT_SMBUS_MANUFACTURE_DATE 0x1B ///< manufacture date register +#define BATT_SMBUS_SERIAL_NUMBER 0x1C ///< serial number register +#define BATT_SMBUS_MANUFACTURER_NAME 0x20 ///< manufacturer name +#define BATT_SMBUS_DEVICE_NAME 0x21 ///< device name register +#define BATT_SMBUS_DEVICE_CHEMISTRY 0x22 ///< device chemistry register #define BATT_SMBUS_MANUFACTURER_DATA 0x23 ///< manufacturer data #define BATT_SMBUS_MANUFACTURE_INFO 0x25 ///< cell voltage register #define BATT_SMBUS_CURRENT 0x2a ///< current register @@ -139,6 +142,57 @@ public: */ int search(); + /** + * Get the SBS manufacturer name of the battery device + * + * @param manufacturer_name pointer a buffer into which the manufacturer name is to be written + * @param max_length the maximum number of bytes to attempt to read from the manufacturer name register, including the null character that is appended to the end + * + * @return the number of bytes read + */ + uint8_t manufacturer_name(uint8_t *man_name, uint8_t max_length); + + /** + * Return the SBS manufacture date of the battery device + * + * @return the date in the following format: + * see Smart Battery Data Specification, Revision 1.1 + * http://sbs-forum.org/specs/sbdat110.pdf for more details + * Date as uint16_t = (year-1980) * 512 + month * 32 + day + * | Field | Bits | Format | Allowable Values | + * | ----- | ---- | ------------------ | ------------------------------------------ | + * | Day 0-4 5-bit binary value 1-31 (corresponds to day) | + * | Month 5-8 4-bit binary value 1-12 (corresponds to month number) | + * | Year 9-15 7-bit binary value 0-127 (corresponds to year biased by 1980) | + * otherwise, return 0 on failure + */ + uint16_t manufacture_date(); + + /** + * Get the SBS device name of the battery device + * + * @param dev_name pointer a buffer into which the device name is to be written + * @param max_length the maximum number of bytes to attempt to read from the device name register, including the null character that is appended to the end + * + * @return the number of bytes read + */ + uint8_t device_name(uint8_t *dev_name, uint8_t max_length); + + /** + * Return the SBS serial number of the battery device + */ + uint16_t serial_number(); + + /** + * Get the SBS device chemistry of the battery device + * + * @param dev_chem pointer a buffer into which the device chemistry is to be written + * @param max_length the maximum number of bytes to attempt to read from the device chemistry register, including the null character that is appended to the end + * + * @return the number of bytes read + */ + uint8_t device_chemistry(uint8_t *dev_chem, uint8_t max_length); + protected: /** * Check if the device can be contacted @@ -222,6 +276,12 @@ void batt_smbus_usage(); extern "C" __EXPORT int batt_smbus_main(int argc, char *argv[]); +int manufacturer_name(); +int manufacture_date(); +int device_name(); +int serial_number(); +int device_chemistry(); + BATT_SMBUS::BATT_SMBUS(int bus, uint16_t batt_smbus_addr) : I2C("batt_smbus", BATT_SMBUS0_DEVICE_PATH, bus, batt_smbus_addr, 100000), _enabled(false), @@ -368,6 +428,82 @@ BATT_SMBUS::search() return OK; } +uint8_t +BATT_SMBUS::manufacturer_name(uint8_t *man_name, uint8_t max_length) +{ + uint8_t len = read_block(BATT_SMBUS_MANUFACTURER_NAME, man_name, max_length, false); + + if (len > 0) { + if (len >= max_length - 1) { + man_name[max_length - 1] = 0; + + } else { + man_name[len] = 0; + } + } + + return len; +} + +uint16_t +BATT_SMBUS::manufacture_date() +{ + uint16_t man_date; + + if (read_reg(BATT_SMBUS_MANUFACTURE_DATE, man_date) == OK) { + return man_date; + } + + // Return 0 if could not read the date correctly + return 0; +} + +uint8_t +BATT_SMBUS::device_name(uint8_t *dev_name, uint8_t max_length) +{ + uint8_t len = read_block(BATT_SMBUS_DEVICE_NAME, dev_name, max_length, false); + + if (len > 0) { + if (len >= max_length - 1) { + dev_name[max_length - 1] = 0; + + } else { + dev_name[len] = 0; + } + } + + return len; +} + +uint16_t +BATT_SMBUS::serial_number() +{ + uint16_t serial_num; + + if (read_reg(BATT_SMBUS_SERIAL_NUMBER, serial_num) == OK) { + return serial_num; + } + + return -1; +} + +uint8_t +BATT_SMBUS::device_chemistry(uint8_t *dev_chem, uint8_t max_length) +{ + uint8_t len = read_block(BATT_SMBUS_DEVICE_CHEMISTRY, dev_chem, max_length, false); + + if (len > 0) { + if (len >= max_length - 1) { + dev_chem[max_length - 1] = 0; + + } else { + dev_chem[len] = 0; + } + } + + return len; +} + int BATT_SMBUS::probe() { @@ -451,28 +587,28 @@ BATT_SMBUS::cycle() } } - /* - // read the button press indicator - if (read_block(BATT_SMBUS_MANUFACTURER_DATA, buff, 6, false) == 6) { - bool pressed = (buff[1] >> 3) & 0x01; + /* + // read the button press indicator + if (read_block(BATT_SMBUS_MANUFACTURER_DATA, buff, 6, false) == 6) { + bool pressed = (buff[1] >> 3) & 0x01; - if(_button_press_counts >= ((BATT_SMBUS_BUTTON_DEBOUNCE_MS * 1000) / BATT_SMBUS_MEASUREMENT_INTERVAL_US)) { - // battery will power off - new_report.is_powering_off = true; - // warn only once - if(_button_press_counts++ == ((BATT_SMBUS_BUTTON_DEBOUNCE_MS * 1000) / BATT_SMBUS_MEASUREMENT_INTERVAL_US)) { - warnx("system is shutting down NOW..."); + if(_button_press_counts >= ((BATT_SMBUS_BUTTON_DEBOUNCE_MS * 1000) / BATT_SMBUS_MEASUREMENT_INTERVAL_US)) { + // battery will power off + new_report.is_powering_off = true; + // warn only once + if(_button_press_counts++ == ((BATT_SMBUS_BUTTON_DEBOUNCE_MS * 1000) / BATT_SMBUS_MEASUREMENT_INTERVAL_US)) { + warnx("system is shutting down NOW..."); + } + } else if(pressed) { + // battery will power off if the button is held + _button_press_counts++; + } else { + // button released early, reset counters + _button_press_counts = 0; + new_report.is_powering_off = false; } - } else if(pressed) { - // battery will power off if the button is held - _button_press_counts++; - } else { - // button released early, reset counters - _button_press_counts = 0; - new_report.is_powering_off = false; } - } - */ + */ // publish to orb if (_batt_topic != -1) { @@ -693,12 +829,92 @@ BATT_SMBUS::ManufacturerAccess(uint16_t cmd) void batt_smbus_usage() { - warnx("missing command: try 'start', 'test', 'stop', 'search'"); + warnx("missing command: try 'start', 'test', 'stop', 'search', 'man_name', 'man_date', 'dev_name', 'serial_num', 'dev_chem', 'sbs_info'"); warnx("options:"); warnx(" -b i2cbus (%d)", BATT_SMBUS_I2C_BUS); warnx(" -a addr (0x%x)", BATT_SMBUS_ADDR); } +int +manufacturer_name() +{ + uint8_t man_name[21]; + uint8_t len = g_batt_smbus->manufacturer_name(man_name, sizeof(man_name)); + + if (len > 0) { + warnx("The manufacturer name: %s", man_name); + return OK; + + } else { + warnx("Unable to read manufacturer name."); + } + + return -1; +} + +int +manufacture_date() +{ + uint16_t man_date = g_batt_smbus->manufacture_date(); + + if (man_date > 0) { + // Convert the uint16_t into human-readable date format + uint16_t year = ((man_date >> 9) & 0xFF) + 1980; + uint8_t month = (man_date >> 5) & 0xF; + uint8_t day = man_date & 0x1F; + warnx("The manufacturer date is: %d which is %4d-%02d-%02d", man_date, year, month, day); + return OK; + + } else { + warnx("Unable to read the manufacturer date."); + } + + return -1; +} + +int +device_name() +{ + uint8_t device_name[21]; + uint8_t len = g_batt_smbus->device_name(device_name, sizeof(device_name)); + + if (len > 0) { + warnx("The device name: %s", device_name); + return OK; + + } else { + warnx("Unable to read device name."); + } + + return -1; +} + +int +serial_number() +{ + uint16_t serial_num = g_batt_smbus->serial_number(); + warnx("The serial number: 0x%04x (%d in decimal)", serial_num, serial_num); + + return OK; +} + +int +device_chemistry() +{ + uint8_t device_chemistry[5]; + uint8_t len = g_batt_smbus->device_chemistry(device_chemistry, sizeof(device_chemistry)); + + if (len > 0) { + warnx("The device chemistry: %s", device_chemistry); + return OK; + + } else { + warnx("Unable to read device chemistry."); + } + + return -1; +} + int batt_smbus_main(int argc, char *argv[]) { @@ -776,6 +992,40 @@ batt_smbus_main(int argc, char *argv[]) exit(0); } + if (!strcmp(verb, "man_name")) { + manufacturer_name(); + exit(0); + } + + if (!strcmp(verb, "man_date")) { + manufacture_date(); + exit(0); + } + + if (!strcmp(verb, "dev_name")) { + device_name(); + exit(0); + } + + if (!strcmp(verb, "serial_num")) { + serial_number(); + exit(0); + } + + if (!strcmp(verb, "dev_chem")) { + device_chemistry(); + exit(0); + } + + if (!strcmp(verb, "sbs_info")) { + manufacturer_name(); + manufacture_date(); + device_name(); + serial_number(); + device_chemistry(); + exit(0); + } + batt_smbus_usage(); exit(0); }