|
|
|
@ -47,8 +47,8 @@
@@ -47,8 +47,8 @@
|
|
|
|
|
|
|
|
|
|
extern "C" __EXPORT int batt_smbus_main(int argc, char *argv[]); |
|
|
|
|
|
|
|
|
|
BATT_SMBUS::BATT_SMBUS(SMBus *interface, const char *path) : |
|
|
|
|
ScheduledWorkItem(MODULE_NAME, px4::device_bus_to_wq(interface->get_device_id())), |
|
|
|
|
BATT_SMBUS::BATT_SMBUS(I2CSPIBusOption bus_option, const int bus, SMBus *interface) : |
|
|
|
|
I2CSPIDriver(MODULE_NAME, px4::device_bus_to_wq(interface->get_device_id()), bus_option, bus), |
|
|
|
|
_interface(interface) |
|
|
|
|
{ |
|
|
|
|
battery_status_s new_report = {}; |
|
|
|
@ -81,79 +81,8 @@ BATT_SMBUS::~BATT_SMBUS()
@@ -81,79 +81,8 @@ BATT_SMBUS::~BATT_SMBUS()
|
|
|
|
|
param_set(param_find("BAT_SOURCE"), &battsource); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int BATT_SMBUS::task_spawn(int argc, char *argv[]) |
|
|
|
|
void BATT_SMBUS::RunImpl() |
|
|
|
|
{ |
|
|
|
|
enum BATT_SMBUS_BUS busid = BATT_SMBUS_BUS_ALL; |
|
|
|
|
|
|
|
|
|
int myoptind = 1; |
|
|
|
|
int ch; |
|
|
|
|
const char *myoptarg = nullptr; |
|
|
|
|
|
|
|
|
|
while ((ch = px4_getopt(argc, argv, "XTRIA", &myoptind, &myoptarg)) != EOF) { |
|
|
|
|
switch (ch) { |
|
|
|
|
case 'X': |
|
|
|
|
busid = BATT_SMBUS_BUS_I2C_EXTERNAL; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 'T': |
|
|
|
|
busid = BATT_SMBUS_BUS_I2C_EXTERNAL1; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 'R': |
|
|
|
|
busid = BATT_SMBUS_BUS_I2C_EXTERNAL2; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 'I': |
|
|
|
|
busid = BATT_SMBUS_BUS_I2C_INTERNAL; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case 'A': |
|
|
|
|
busid = BATT_SMBUS_BUS_ALL; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
print_usage(); |
|
|
|
|
return PX4_ERROR; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < NUM_BUS_OPTIONS; i++) { |
|
|
|
|
|
|
|
|
|
if (!is_running() && (busid == BATT_SMBUS_BUS_ALL || smbus_bus_options[i].busid == busid)) { |
|
|
|
|
|
|
|
|
|
SMBus *interface = new SMBus(smbus_bus_options[i].busnum, BATT_SMBUS_ADDR); |
|
|
|
|
BATT_SMBUS *dev = new BATT_SMBUS(interface, smbus_bus_options[i].devpath); |
|
|
|
|
|
|
|
|
|
int result = dev->get_startup_info(); |
|
|
|
|
|
|
|
|
|
if (result != PX4_OK) { |
|
|
|
|
delete dev; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Successful read of device type, we've found our battery
|
|
|
|
|
_object.store(dev); |
|
|
|
|
_task_id = task_id_is_work_queue; |
|
|
|
|
|
|
|
|
|
dev->ScheduleOnInterval(BATT_SMBUS_MEASUREMENT_INTERVAL_US); |
|
|
|
|
|
|
|
|
|
return PX4_OK; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PX4_WARN("Not found."); |
|
|
|
|
return PX4_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void BATT_SMBUS::Run() |
|
|
|
|
{ |
|
|
|
|
if (should_exit()) { |
|
|
|
|
ScheduleClear(); |
|
|
|
|
exit_and_cleanup(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Get the current time.
|
|
|
|
|
uint64_t now = hrt_absolute_time(); |
|
|
|
|
|
|
|
|
@ -354,7 +283,7 @@ int BATT_SMBUS::dataflash_read(uint16_t &address, void *data, const unsigned len
@@ -354,7 +283,7 @@ int BATT_SMBUS::dataflash_read(uint16_t &address, void *data, const unsigned len
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int BATT_SMBUS::dataflash_write(uint16_t &address, void *data, const unsigned length) |
|
|
|
|
int BATT_SMBUS::dataflash_write(uint16_t address, void *data, const unsigned length) |
|
|
|
|
{ |
|
|
|
|
uint8_t code = BATT_SMBUS_MANUFACTURER_BLOCK_ACCESS; |
|
|
|
|
|
|
|
|
@ -387,7 +316,7 @@ int BATT_SMBUS::get_startup_info()
@@ -387,7 +316,7 @@ int BATT_SMBUS::get_startup_info()
|
|
|
|
|
result = manufacturer_name((uint8_t *)man_name, sizeof(man_name)); |
|
|
|
|
|
|
|
|
|
if (result != PX4_OK) { |
|
|
|
|
PX4_WARN("Failed to get manufacturer name"); |
|
|
|
|
PX4_DEBUG("Failed to get manufacturer name"); |
|
|
|
|
return PX4_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -559,133 +488,181 @@ int BATT_SMBUS::lifetime_read_block_one()
@@ -559,133 +488,181 @@ int BATT_SMBUS::lifetime_read_block_one()
|
|
|
|
|
return PX4_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int BATT_SMBUS::custom_command(int argc, char *argv[]) |
|
|
|
|
void BATT_SMBUS::print_usage() |
|
|
|
|
{ |
|
|
|
|
const char *input = argv[0]; |
|
|
|
|
uint8_t man_name[22]; |
|
|
|
|
int result = 0; |
|
|
|
|
PRINT_MODULE_DESCRIPTION( |
|
|
|
|
R"DESCR_STR( |
|
|
|
|
### Description |
|
|
|
|
Smart battery driver for the BQ40Z50 fuel gauge IC. |
|
|
|
|
|
|
|
|
|
if (!is_running()) { |
|
|
|
|
PX4_ERR("not running"); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
### Examples |
|
|
|
|
To write to flash to set parameters. address, number_of_bytes, byte0, ... , byteN |
|
|
|
|
$ batt_smbus -X write_flash 19069 2 27 0 |
|
|
|
|
|
|
|
|
|
BATT_SMBUS *obj = get_instance(); |
|
|
|
|
)DESCR_STR"); |
|
|
|
|
|
|
|
|
|
if (!strcmp(input, "man_info")) { |
|
|
|
|
PRINT_MODULE_USAGE_NAME("batt_smbus", "driver"); |
|
|
|
|
|
|
|
|
|
result = obj->manufacturer_name(man_name, sizeof(man_name)); |
|
|
|
|
PX4_INFO("The manufacturer name: %s", man_name); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND("start"); |
|
|
|
|
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, false); |
|
|
|
|
PRINT_MODULE_USAGE_PARAMS_I2C_ADDRESS(0x0B); |
|
|
|
|
|
|
|
|
|
result = obj->manufacture_date(); |
|
|
|
|
PX4_INFO("The manufacturer date: %d", result); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("man_info", "Prints manufacturer info."); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("unseal", "Unseals the devices flash memory to enable write_flash commands."); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("seal", "Seals the devices flash memory to disbale write_flash commands."); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("suspend", "Suspends the driver from rescheduling the cycle."); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("resume", "Resumes the driver from suspension."); |
|
|
|
|
|
|
|
|
|
uint16_t serial_num = 0; |
|
|
|
|
serial_num = obj->get_serial_number(); |
|
|
|
|
PX4_INFO("The serial number: %d", serial_num); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("write_flash", "Writes to flash. The device must first be unsealed with the unseal command."); |
|
|
|
|
PRINT_MODULE_USAGE_ARG("address", "The address to start writing.", true); |
|
|
|
|
PRINT_MODULE_USAGE_ARG("number of bytes", "Number of bytes to send.", true); |
|
|
|
|
PRINT_MODULE_USAGE_ARG("data[0]...data[n]", "One byte of data at a time separated by spaces.", true); |
|
|
|
|
PRINT_MODULE_USAGE_DEFAULT_COMMANDS(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
I2CSPIDriverBase *BATT_SMBUS::instantiate(const BusCLIArguments &cli, const BusInstanceIterator &iterator, |
|
|
|
|
int runtime_instance) |
|
|
|
|
{ |
|
|
|
|
SMBus *interface = new SMBus(iterator.bus(), cli.i2c_address); |
|
|
|
|
if (interface == nullptr) { |
|
|
|
|
PX4_ERR("alloc failed"); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
BATT_SMBUS *instance = new BATT_SMBUS(iterator.configuredBusOption(), iterator.bus(), interface); |
|
|
|
|
|
|
|
|
|
if (!strcmp(input, "unseal")) { |
|
|
|
|
obj->unseal(); |
|
|
|
|
return 0; |
|
|
|
|
if (instance == nullptr) { |
|
|
|
|
PX4_ERR("alloc failed"); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!strcmp(input, "seal")) { |
|
|
|
|
obj->seal(); |
|
|
|
|
return 0; |
|
|
|
|
int result = instance->get_startup_info(); |
|
|
|
|
|
|
|
|
|
if (result != PX4_OK) { |
|
|
|
|
delete instance; |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!strcmp(input, "suspend")) { |
|
|
|
|
obj->suspend(); |
|
|
|
|
return 0; |
|
|
|
|
instance->ScheduleOnInterval(BATT_SMBUS_MEASUREMENT_INTERVAL_US); |
|
|
|
|
|
|
|
|
|
return instance; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
BATT_SMBUS::custom_method(const BusCLIArguments &cli) |
|
|
|
|
{ |
|
|
|
|
switch(cli.custom1) { |
|
|
|
|
case 1: { |
|
|
|
|
uint8_t man_name[22]; |
|
|
|
|
int result = manufacturer_name(man_name, sizeof(man_name)); |
|
|
|
|
PX4_INFO("The manufacturer name: %s", man_name); |
|
|
|
|
|
|
|
|
|
result = manufacture_date(); |
|
|
|
|
PX4_INFO("The manufacturer date: %d", result); |
|
|
|
|
|
|
|
|
|
uint16_t serial_num = 0; |
|
|
|
|
serial_num = get_serial_number(); |
|
|
|
|
PX4_INFO("The serial number: %d", serial_num); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case 2: |
|
|
|
|
unseal(); |
|
|
|
|
break; |
|
|
|
|
case 3: |
|
|
|
|
seal(); |
|
|
|
|
break; |
|
|
|
|
case 4: |
|
|
|
|
suspend(); |
|
|
|
|
break; |
|
|
|
|
case 5: |
|
|
|
|
resume(); |
|
|
|
|
break; |
|
|
|
|
case 6: |
|
|
|
|
if (cli.custom_data) { |
|
|
|
|
unsigned address = cli.custom2; |
|
|
|
|
uint8_t *tx_buf = (uint8_t*)cli.custom_data; |
|
|
|
|
unsigned length = tx_buf[0]; |
|
|
|
|
|
|
|
|
|
if (PX4_OK != dataflash_write(address, tx_buf+1, length)) { |
|
|
|
|
PX4_ERR("Dataflash write failed: %d", address); |
|
|
|
|
} |
|
|
|
|
px4_usleep(100000); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
extern "C" __EXPORT int batt_smbus_main(int argc, char *argv[]) |
|
|
|
|
{ |
|
|
|
|
using ThisDriver = BATT_SMBUS; |
|
|
|
|
BusCLIArguments cli{true, false}; |
|
|
|
|
cli.default_i2c_frequency = 100000; |
|
|
|
|
cli.i2c_address = BATT_SMBUS_ADDR; |
|
|
|
|
|
|
|
|
|
const char *verb = cli.parseDefaultArguments(argc, argv); |
|
|
|
|
if (!verb) { |
|
|
|
|
ThisDriver::print_usage(); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BusInstanceIterator iterator(MODULE_NAME, cli, DRV_BAT_DEVTYPE_SMBUS); |
|
|
|
|
|
|
|
|
|
if (!strcmp(verb, "start")) { |
|
|
|
|
return ThisDriver::module_start(cli, iterator); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!strcmp(input, "resume")) { |
|
|
|
|
obj->resume(); |
|
|
|
|
return 0; |
|
|
|
|
if (!strcmp(verb, "stop")) { |
|
|
|
|
return ThisDriver::module_stop(iterator); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!strcmp(input, "serial_num")) { |
|
|
|
|
uint16_t serial_num = obj->get_serial_number(); |
|
|
|
|
PX4_INFO("Serial number: %d", serial_num); |
|
|
|
|
return 0; |
|
|
|
|
if (!strcmp(verb, "status")) { |
|
|
|
|
return ThisDriver::module_status(iterator); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!strcmp(input, "write_flash")) { |
|
|
|
|
if (!strcmp(verb, "man_info")) { |
|
|
|
|
cli.custom1 = 1; |
|
|
|
|
return ThisDriver::module_custom_method(cli, iterator, false); |
|
|
|
|
} |
|
|
|
|
if (!strcmp(verb, "unseal")) { |
|
|
|
|
cli.custom1 = 2; |
|
|
|
|
return ThisDriver::module_custom_method(cli, iterator); |
|
|
|
|
} |
|
|
|
|
if (!strcmp(verb, "seal")) { |
|
|
|
|
cli.custom1 = 3; |
|
|
|
|
return ThisDriver::module_custom_method(cli, iterator); |
|
|
|
|
} |
|
|
|
|
if (!strcmp(verb, "suspend")) { |
|
|
|
|
cli.custom1 = 4; |
|
|
|
|
return ThisDriver::module_custom_method(cli, iterator); |
|
|
|
|
} |
|
|
|
|
if (!strcmp(verb, "resume")) { |
|
|
|
|
cli.custom1 = 5; |
|
|
|
|
return ThisDriver::module_custom_method(cli, iterator); |
|
|
|
|
} |
|
|
|
|
if (!strcmp(verb, "write_flash")) { |
|
|
|
|
cli.custom1 = 6; |
|
|
|
|
if (argc >= 3) { |
|
|
|
|
uint16_t address = atoi(argv[1]); |
|
|
|
|
unsigned length = atoi(argv[2]); |
|
|
|
|
uint8_t tx_buf[32] = {}; |
|
|
|
|
uint8_t tx_buf[33]; |
|
|
|
|
cli.custom_data = &tx_buf; |
|
|
|
|
|
|
|
|
|
if (length > 32) { |
|
|
|
|
PX4_WARN("Data length out of range: Max 32 bytes"); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tx_buf[0] = length; |
|
|
|
|
// Data needs to be fed in 1 byte (0x01) at a time.
|
|
|
|
|
for (unsigned i = 0; i < length; i++) { |
|
|
|
|
if ((unsigned)argc <= 3 + i) { |
|
|
|
|
tx_buf[i] = atoi(argv[3 + i]); |
|
|
|
|
tx_buf[i+1] = atoi(argv[3 + i]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (PX4_OK != obj->dataflash_write(address, tx_buf, length)) { |
|
|
|
|
PX4_INFO("Dataflash write failed: %d", address); |
|
|
|
|
px4_usleep(100000); |
|
|
|
|
return 1; |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
px4_usleep(100000); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
cli.custom2 = address; |
|
|
|
|
return ThisDriver::module_custom_method(cli, iterator); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
print_usage(); |
|
|
|
|
|
|
|
|
|
return PX4_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int BATT_SMBUS::print_usage() |
|
|
|
|
{ |
|
|
|
|
PRINT_MODULE_DESCRIPTION( |
|
|
|
|
R"DESCR_STR( |
|
|
|
|
### Description |
|
|
|
|
Smart battery driver for the BQ40Z50 fuel gauge IC. |
|
|
|
|
|
|
|
|
|
### Examples |
|
|
|
|
To write to flash to set parameters. address, number_of_bytes, byte0, ... , byteN |
|
|
|
|
$ batt_smbus -X write_flash 19069 2 27 0 |
|
|
|
|
|
|
|
|
|
)DESCR_STR"); |
|
|
|
|
|
|
|
|
|
PRINT_MODULE_USAGE_NAME("batt_smbus", "driver"); |
|
|
|
|
|
|
|
|
|
PRINT_MODULE_USAGE_COMMAND("start"); |
|
|
|
|
PRINT_MODULE_USAGE_PARAM_FLAG('X', "BATT_SMBUS_BUS_I2C_EXTERNAL", true); |
|
|
|
|
PRINT_MODULE_USAGE_PARAM_FLAG('T', "BATT_SMBUS_BUS_I2C_EXTERNAL1", true); |
|
|
|
|
PRINT_MODULE_USAGE_PARAM_FLAG('R', "BATT_SMBUS_BUS_I2C_EXTERNAL2", true); |
|
|
|
|
PRINT_MODULE_USAGE_PARAM_FLAG('I', "BATT_SMBUS_BUS_I2C_INTERNAL", true); |
|
|
|
|
PRINT_MODULE_USAGE_PARAM_FLAG('A', "BATT_SMBUS_BUS_ALL", true); |
|
|
|
|
|
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("man_info", "Prints manufacturer info."); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("unseal", "Unseals the devices flash memory to enable write_flash commands."); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("seal", "Seals the devices flash memory to disbale write_flash commands."); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("suspend", "Suspends the driver from rescheduling the cycle."); |
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("resume", "Resumes the driver from suspension."); |
|
|
|
|
|
|
|
|
|
PRINT_MODULE_USAGE_COMMAND_DESCR("write_flash", "Writes to flash. The device must first be unsealed with the unseal command."); |
|
|
|
|
PRINT_MODULE_USAGE_ARG("address", "The address to start writing.", true); |
|
|
|
|
PRINT_MODULE_USAGE_ARG("number of bytes", "Number of bytes to send.", true); |
|
|
|
|
PRINT_MODULE_USAGE_ARG("data[0]...data[n]", "One byte of data at a time separated by spaces.", true); |
|
|
|
|
PRINT_MODULE_USAGE_DEFAULT_COMMANDS(); |
|
|
|
|
|
|
|
|
|
return PX4_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int batt_smbus_main(int argc, char *argv[]) |
|
|
|
|
{ |
|
|
|
|
return BATT_SMBUS::main(argc, argv); |
|
|
|
|
ThisDriver::print_usage(); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|