2021-07-01 01:56:00 -03:00
|
|
|
/*
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "AP_Torqeedo.h"
|
|
|
|
|
|
|
|
#if HAL_TORQEEDO_ENABLED
|
|
|
|
|
|
|
|
#include <AP_Common/AP_Common.h>
|
|
|
|
#include <AP_Math/AP_Math.h>
|
2021-07-19 07:55:33 -03:00
|
|
|
#include <GCS_MAVLink/GCS.h>
|
2024-03-11 09:10:52 -03:00
|
|
|
#include "AP_Torqeedo_Backend.h"
|
|
|
|
#include "AP_Torqeedo_TQBus.h"
|
2021-07-01 01:56:00 -03:00
|
|
|
|
|
|
|
extern const AP_HAL::HAL& hal;
|
|
|
|
|
|
|
|
const AP_Param::GroupInfo AP_Torqeedo::var_info[] = {
|
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// 1 to 7 were used for parameters before frontend/backend split
|
2021-07-19 07:55:33 -03:00
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// @Group: 1_
|
|
|
|
// @Path: AP_Torqeedo_Params.cpp
|
|
|
|
AP_SUBGROUPINFO(_params[0], "1_", 8, AP_Torqeedo, AP_Torqeedo_Params),
|
2021-09-04 01:41:30 -03:00
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
#if AP_TORQEEDO_MAX_INSTANCES > 1
|
|
|
|
// @Group: 2_
|
|
|
|
// @Path: AP_Torqeedo_Params.cpp
|
|
|
|
AP_SUBGROUPINFO(_params[1], "2_", 9, AP_Torqeedo, AP_Torqeedo_Params),
|
|
|
|
#endif
|
2021-09-04 01:41:30 -03:00
|
|
|
|
2021-07-01 01:56:00 -03:00
|
|
|
AP_GROUPEND
|
|
|
|
};
|
|
|
|
|
|
|
|
AP_Torqeedo::AP_Torqeedo()
|
|
|
|
{
|
|
|
|
_singleton = this;
|
|
|
|
AP_Param::setup_object_defaults(this, var_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialise driver
|
|
|
|
void AP_Torqeedo::init()
|
|
|
|
{
|
2024-03-11 09:10:52 -03:00
|
|
|
// check init has not been called before
|
|
|
|
for (uint8_t i = 1; i < AP_TORQEEDO_MAX_INSTANCES; i++) {
|
|
|
|
if (get_instance(i) != nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
2021-07-20 05:06:28 -03:00
|
|
|
}
|
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// create each instance
|
|
|
|
uint8_t instance;
|
|
|
|
for (instance = 0; instance < AP_TORQEEDO_MAX_INSTANCES; instance++) {
|
|
|
|
switch ((ConnectionType)_params[instance].type.get()) {
|
|
|
|
case ConnectionType::TYPE_DISABLED:
|
|
|
|
// do nothing
|
|
|
|
break;
|
|
|
|
case ConnectionType::TYPE_TILLER:
|
|
|
|
case ConnectionType::TYPE_MOTOR:
|
|
|
|
_backends[instance] = new AP_Torqeedo_TQBus(_params[instance], instance);
|
|
|
|
break;
|
|
|
|
}
|
2021-07-01 01:56:00 -03:00
|
|
|
}
|
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// init each instance, do it after all instances were created, so that they all know things
|
|
|
|
for (instance = 0; instance < AP_TORQEEDO_MAX_INSTANCES; instance++) {
|
|
|
|
if (_backends[instance] != nullptr) {
|
|
|
|
_backends[instance]->init();
|
|
|
|
}
|
2021-07-01 01:56:00 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// returns true if at least one backend has been configured (e.g. TYPE param has been set)
|
|
|
|
bool AP_Torqeedo::enabled() const
|
2021-07-01 01:56:00 -03:00
|
|
|
{
|
2024-03-11 09:10:52 -03:00
|
|
|
for (uint8_t instance = 0; instance < AP_TORQEEDO_MAX_INSTANCES; instance++) {
|
|
|
|
if (enabled(instance)) {
|
|
|
|
return true;
|
2021-07-20 05:06:28 -03:00
|
|
|
}
|
2021-07-01 01:56:00 -03:00
|
|
|
}
|
2024-03-11 09:10:52 -03:00
|
|
|
return false;
|
2021-07-01 01:56:00 -03:00
|
|
|
}
|
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// returns true if the instance has been configured (e.g. TYPE param has been set)
|
|
|
|
bool AP_Torqeedo::enabled(uint8_t instance) const
|
2021-07-20 05:06:28 -03:00
|
|
|
{
|
2024-03-11 09:10:52 -03:00
|
|
|
if (instance < AP_TORQEEDO_MAX_INSTANCES) {
|
|
|
|
switch ((ConnectionType)_params[instance].type.get()) {
|
|
|
|
case ConnectionType::TYPE_DISABLED:
|
|
|
|
return false;
|
|
|
|
case ConnectionType::TYPE_TILLER:
|
|
|
|
case ConnectionType::TYPE_MOTOR:
|
|
|
|
return true;
|
|
|
|
}
|
2021-07-20 05:06:28 -03:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// returns true if all backends are communicating with the motor
|
|
|
|
bool AP_Torqeedo::healthy()
|
2021-07-01 01:56:00 -03:00
|
|
|
{
|
2024-03-11 09:10:52 -03:00
|
|
|
uint8_t num_backends = 0;
|
|
|
|
uint8_t num_healthy = 0;
|
|
|
|
for (uint8_t instance = 0; instance < AP_TORQEEDO_MAX_INSTANCES; instance++) {
|
|
|
|
auto *backend = get_instance(instance);
|
|
|
|
if (backend != nullptr) {
|
|
|
|
num_backends++;
|
|
|
|
if (backend->healthy()) {
|
|
|
|
num_healthy++;
|
2021-07-20 05:06:28 -03:00
|
|
|
}
|
2021-07-01 01:56:00 -03:00
|
|
|
}
|
|
|
|
}
|
2024-03-11 09:10:52 -03:00
|
|
|
|
|
|
|
return ((num_backends > 0) && (num_healthy == num_backends));
|
2021-07-01 01:56:00 -03:00
|
|
|
}
|
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// returns true if instance is healthy
|
|
|
|
bool AP_Torqeedo::healthy(uint8_t instance)
|
2021-07-13 09:14:07 -03:00
|
|
|
{
|
2024-03-11 09:10:52 -03:00
|
|
|
auto *backend = get_instance(instance);
|
|
|
|
if (backend == nullptr) {
|
2021-07-13 09:14:07 -03:00
|
|
|
return false;
|
|
|
|
}
|
2024-03-11 09:10:52 -03:00
|
|
|
return backend->healthy();
|
2021-07-13 09:14:07 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
// run pre-arm check. returns false on failure and fills in failure_msg
|
2021-08-09 01:46:17 -03:00
|
|
|
// any failure_msg returned will not include a prefix
|
2021-07-13 09:14:07 -03:00
|
|
|
bool AP_Torqeedo::pre_arm_checks(char *failure_msg, uint8_t failure_msg_len)
|
|
|
|
{
|
2021-07-20 05:06:28 -03:00
|
|
|
// exit immediately if not enabled
|
|
|
|
if (!enabled()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-07-13 09:14:07 -03:00
|
|
|
if (!healthy()) {
|
2021-08-09 01:46:17 -03:00
|
|
|
strncpy(failure_msg, "not healthy", failure_msg_len);
|
2021-07-13 09:14:07 -03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// clear motor errors
|
|
|
|
void AP_Torqeedo::clear_motor_error()
|
2021-12-04 01:57:30 -04:00
|
|
|
{
|
2024-03-11 09:10:52 -03:00
|
|
|
for (uint8_t instance = 0; instance < AP_TORQEEDO_MAX_INSTANCES; instance++) {
|
|
|
|
auto *backend = get_instance(instance);
|
|
|
|
if (backend != nullptr) {
|
|
|
|
backend->clear_motor_error();
|
2021-12-03 03:04:53 -04:00
|
|
|
}
|
2021-09-04 01:41:30 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get latest battery status info. returns true on success and populates arguments
|
2024-03-11 09:10:52 -03:00
|
|
|
// instance is normally 0 or 1, if invalid instances are provided the first instance is used
|
|
|
|
bool AP_Torqeedo::get_batt_info(uint8_t instance, float &voltage, float ¤t_amps, float &temp_C, uint8_t &pct_remaining) const
|
2021-09-04 01:41:30 -03:00
|
|
|
{
|
2024-03-11 09:10:52 -03:00
|
|
|
// for invalid instances use the first instance
|
|
|
|
if (instance > AP_TORQEEDO_MAX_INSTANCES-1) {
|
|
|
|
instance = 0;
|
2021-09-04 01:41:30 -03:00
|
|
|
}
|
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// return battery info for specified instance
|
|
|
|
auto *backend = get_instance(instance);
|
|
|
|
if (backend != nullptr) {
|
|
|
|
return backend->get_batt_info(voltage, current_amps, temp_C, pct_remaining);
|
2021-09-04 01:41:30 -03:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get battery capacity. returns true on success and populates argument
|
2024-03-11 09:10:52 -03:00
|
|
|
// instance is normally 0 or 1, if invalid instances are provided the first instance is used
|
|
|
|
bool AP_Torqeedo::get_batt_capacity_Ah(uint8_t instance, uint16_t &_hours) const
|
2021-09-04 01:41:30 -03:00
|
|
|
{
|
2024-03-11 09:10:52 -03:00
|
|
|
// for invalid instances use the first instance
|
|
|
|
if (instance > AP_TORQEEDO_MAX_INSTANCES-1) {
|
|
|
|
instance = 0;
|
2021-09-04 01:41:30 -03:00
|
|
|
}
|
2021-10-20 21:47:49 -03:00
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// return battery capacity from specified instance
|
|
|
|
auto *backend = get_instance(instance);
|
|
|
|
if (backend != nullptr) {
|
|
|
|
return backend->get_batt_capacity_Ah(amp_hours);
|
2021-10-20 21:47:49 -03:00
|
|
|
}
|
2024-03-11 09:10:52 -03:00
|
|
|
return false;
|
2021-07-01 01:56:00 -03:00
|
|
|
}
|
|
|
|
|
2024-03-11 09:10:52 -03:00
|
|
|
// return pointer to backend given an instance number
|
|
|
|
AP_Torqeedo_Backend *AP_Torqeedo::get_instance(uint8_t instance) const
|
2021-07-19 07:55:33 -03:00
|
|
|
{
|
2024-03-11 09:10:52 -03:00
|
|
|
if (instance < AP_TORQEEDO_MAX_INSTANCES) {
|
|
|
|
return _backends[instance];
|
2021-07-19 07:55:33 -03:00
|
|
|
}
|
2024-03-11 09:10:52 -03:00
|
|
|
return nullptr;
|
2021-09-04 01:41:30 -03:00
|
|
|
}
|
|
|
|
|
2021-07-01 01:56:00 -03:00
|
|
|
// get the AP_Torqeedo singleton
|
|
|
|
AP_Torqeedo *AP_Torqeedo::get_singleton()
|
|
|
|
{
|
|
|
|
return _singleton;
|
|
|
|
}
|
|
|
|
|
|
|
|
AP_Torqeedo *AP_Torqeedo::_singleton = nullptr;
|
|
|
|
|
|
|
|
namespace AP {
|
2024-03-11 09:10:52 -03:00
|
|
|
|
2021-07-01 01:56:00 -03:00
|
|
|
AP_Torqeedo *torqeedo()
|
|
|
|
{
|
|
|
|
return AP_Torqeedo::get_singleton();
|
|
|
|
}
|
2024-03-11 09:10:52 -03:00
|
|
|
}
|
2021-07-01 01:56:00 -03:00
|
|
|
|
|
|
|
#endif // HAL_TORQEEDO_ENABLED
|