AP_BattMonitor_SMBus.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include "AP_BattMonitor_SMBus.h"
  2. #define AP_BATTMONITOR_SMBUS_PEC_POLYNOME 0x07 // Polynome for CRC generation
  3. AP_BattMonitor_SMBus::AP_BattMonitor_SMBus(AP_BattMonitor &mon,
  4. AP_BattMonitor::BattMonitor_State &mon_state,
  5. AP_BattMonitor_Params &params,
  6. AP_HAL::OwnPtr<AP_HAL::I2CDevice> dev)
  7. : AP_BattMonitor_Backend(mon, mon_state, params),
  8. _dev(std::move(dev))
  9. {
  10. _params._serial_number = AP_BATT_SERIAL_NUMBER_DEFAULT;
  11. _params._pack_capacity = 0;
  12. }
  13. void AP_BattMonitor_SMBus::init(void) {
  14. if (_dev) {
  15. _dev->register_periodic_callback(100000, FUNCTOR_BIND_MEMBER(&AP_BattMonitor_SMBus::timer, void));
  16. }
  17. }
  18. /// read the battery_voltage and current, should be called at 10hz
  19. void AP_BattMonitor_SMBus::read(void)
  20. {
  21. // nothing to be done here for actually interacting with the battery
  22. // however we can use this to set any parameters that need to be set
  23. if (_serial_number != _params._serial_number) {
  24. _params._serial_number.set_and_notify(_serial_number);
  25. }
  26. if (_full_charge_capacity != _params._pack_capacity) {
  27. _params._pack_capacity.set_and_notify(_full_charge_capacity);
  28. }
  29. }
  30. // reads the pack full charge capacity
  31. // returns true if the read was successful, or if we already knew the pack capacity
  32. bool AP_BattMonitor_SMBus::read_full_charge_capacity(void)
  33. {
  34. uint16_t data;
  35. if (_full_charge_capacity != 0) {
  36. return true;
  37. } else if (read_word(BATTMONITOR_SMBUS_FULL_CHARGE_CAPACITY, data)) {
  38. _full_charge_capacity = data;
  39. return true;
  40. }
  41. return false;
  42. }
  43. // reads the remaining capacity
  44. // returns true if the read was succesful, which is only considered to be the
  45. // we know the full charge capacity
  46. bool AP_BattMonitor_SMBus::read_remaining_capacity(void)
  47. {
  48. int32_t capacity = _params._pack_capacity;
  49. if (capacity > 0) {
  50. uint16_t data;
  51. if (read_word(BATTMONITOR_SMBUS_REMAINING_CAPACITY, data)) {
  52. _state.consumed_mah = MAX(0, capacity - data);
  53. return true;
  54. }
  55. }
  56. return false;
  57. }
  58. // reads the temperature word from the battery
  59. // returns true if the read was successful
  60. bool AP_BattMonitor_SMBus::read_temp(void)
  61. {
  62. uint16_t data;
  63. if (read_word(BATTMONITOR_SMBUS_TEMP, data)) {
  64. _state.temperature_time = AP_HAL::millis();
  65. _state.temperature = ((float)(data - 2731)) * 0.1f;
  66. return true;
  67. }
  68. return false;
  69. }
  70. // reads the serial number if it's not already known
  71. // returns true if the read was successful or the number was already known
  72. bool AP_BattMonitor_SMBus::read_serial_number(void) {
  73. uint16_t data;
  74. // don't recheck the serial number if we already have it
  75. if (_serial_number != -1) {
  76. return true;
  77. } else if (read_word(BATTMONITOR_SMBUS_SERIAL, data)) {
  78. _serial_number = data;
  79. return true;
  80. }
  81. return false;
  82. }
  83. // read word from register
  84. // returns true if read was successful, false if failed
  85. bool AP_BattMonitor_SMBus::read_word(uint8_t reg, uint16_t& data) const
  86. {
  87. // buffer to hold results (1 extra byte returned holding PEC)
  88. const uint8_t read_size = 2 + (_pec_supported ? 1 : 0);
  89. uint8_t buff[read_size]; // buffer to hold results
  90. // read the appropriate register from the device
  91. if (!_dev->read_registers(reg, buff, sizeof(buff))) {
  92. return false;
  93. }
  94. // check PEC
  95. if (_pec_supported) {
  96. const uint8_t pec = get_PEC(AP_BATTMONITOR_SMBUS_I2C_ADDR, reg, true, buff, 2);
  97. if (pec != buff[2]) {
  98. return false;
  99. }
  100. }
  101. // convert buffer to word
  102. data = (uint16_t)buff[1]<<8 | (uint16_t)buff[0];
  103. // return success
  104. return true;
  105. }
  106. /// get_PEC - calculate packet error correction code of buffer
  107. uint8_t AP_BattMonitor_SMBus::get_PEC(const uint8_t i2c_addr, uint8_t cmd, bool reading, const uint8_t buff[], uint8_t len) const
  108. {
  109. // exit immediately if no data
  110. if (len == 0) {
  111. return 0;
  112. }
  113. // prepare temp buffer for calculating crc
  114. uint8_t tmp_buff[len+3];
  115. tmp_buff[0] = i2c_addr << 1;
  116. tmp_buff[1] = cmd;
  117. tmp_buff[2] = tmp_buff[0] | (uint8_t)reading;
  118. memcpy(&tmp_buff[3],buff,len);
  119. // initialise crc to zero
  120. uint8_t crc = 0;
  121. uint8_t shift_reg = 0;
  122. bool do_invert;
  123. // for each byte in the stream
  124. for (uint8_t i=0; i<sizeof(tmp_buff); i++) {
  125. // load next data byte into the shift register
  126. shift_reg = tmp_buff[i];
  127. // for each bit in the current byte
  128. for (uint8_t j=0; j<8; j++) {
  129. do_invert = (crc ^ shift_reg) & 0x80;
  130. crc <<= 1;
  131. shift_reg <<= 1;
  132. if(do_invert) {
  133. crc ^= AP_BATTMONITOR_SMBUS_PEC_POLYNOME;
  134. }
  135. }
  136. }
  137. // return result
  138. return crc;
  139. }