Line data Source code
1 : /* 2 : This program is free software: you can redistribute it and/or modify 3 : it under the terms of the GNU General Public License as published by 4 : the Free Software Foundation, either version 3 of the License, or 5 : (at your option) any later version. 6 : 7 : This program is distributed in the hope that it will be useful, 8 : but WITHOUT ANY WARRANTY; without even the implied warranty of 9 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 : GNU General Public License for more details. 11 : 12 : You should have received a copy of the GNU General Public License 13 : along with this program. If not, see <http://www.gnu.org/licenses/>. 14 : */ 15 : 16 : #include "AP_Torqeedo.h" 17 : 18 : #if HAL_TORQEEDO_ENABLED 19 : 20 : #include <AP_Common/AP_Common.h> 21 : #include <AP_Math/AP_Math.h> 22 : #include <GCS_MAVLink/GCS.h> 23 : #include "AP_Torqeedo_Backend.h" 24 : #include "AP_Torqeedo_TQBus.h" 25 : 26 : extern const AP_HAL::HAL& hal; 27 : 28 : const AP_Param::GroupInfo AP_Torqeedo::var_info[] = { 29 : 30 : // 1 to 7 were used for parameters before frontend/backend split 31 : 32 : // @Group: 1_ 33 : // @Path: AP_Torqeedo_Params.cpp 34 : AP_SUBGROUPINFO(_params[0], "1_", 8, AP_Torqeedo, AP_Torqeedo_Params), 35 : 36 : #if AP_TORQEEDO_MAX_INSTANCES > 1 37 : // @Group: 2_ 38 : // @Path: AP_Torqeedo_Params.cpp 39 : AP_SUBGROUPINFO(_params[1], "2_", 9, AP_Torqeedo, AP_Torqeedo_Params), 40 : #endif 41 : 42 : AP_GROUPEND 43 : }; 44 : 45 855 : AP_Torqeedo::AP_Torqeedo() 46 : { 47 285 : _singleton = this; 48 285 : AP_Param::setup_object_defaults(this, var_info); 49 285 : } 50 : 51 : // initialise driver 52 283 : void AP_Torqeedo::init() 53 : { 54 : // check init has not been called before 55 566 : for (uint8_t i = 1; i < AP_TORQEEDO_MAX_INSTANCES; i++) { 56 283 : if (get_instance(i) != nullptr) { 57 0 : return; 58 : } 59 : } 60 : 61 : // create each instance 62 : uint8_t instance; 63 849 : for (instance = 0; instance < AP_TORQEEDO_MAX_INSTANCES; instance++) { 64 566 : switch ((ConnectionType)_params[instance].type.get()) { 65 566 : case ConnectionType::TYPE_DISABLED: 66 : // do nothing 67 566 : break; 68 0 : case ConnectionType::TYPE_TILLER: 69 : case ConnectionType::TYPE_MOTOR: 70 0 : _backends[instance] = NEW_NOTHROW AP_Torqeedo_TQBus(_params[instance], instance); 71 0 : break; 72 : } 73 : } 74 : 75 : // init each instance, do it after all instances were created, so that they all know things 76 849 : for (instance = 0; instance < AP_TORQEEDO_MAX_INSTANCES; instance++) { 77 566 : if (_backends[instance] != nullptr) { 78 0 : _backends[instance]->init(); 79 : } 80 : } 81 : } 82 : 83 : // returns true if at least one backend has been configured (e.g. TYPE param has been set) 84 15226 : bool AP_Torqeedo::enabled() const 85 : { 86 45678 : for (uint8_t instance = 0; instance < AP_TORQEEDO_MAX_INSTANCES; instance++) { 87 30452 : if (enabled(instance)) { 88 0 : return true; 89 : } 90 : } 91 15226 : return false; 92 : } 93 : 94 : // returns true if the instance has been configured (e.g. TYPE param has been set) 95 30452 : bool AP_Torqeedo::enabled(uint8_t instance) const 96 : { 97 30452 : if (instance < AP_TORQEEDO_MAX_INSTANCES) { 98 30452 : switch ((ConnectionType)_params[instance].type.get()) { 99 30452 : case ConnectionType::TYPE_DISABLED: 100 30452 : return false; 101 0 : case ConnectionType::TYPE_TILLER: 102 : case ConnectionType::TYPE_MOTOR: 103 0 : return true; 104 : } 105 : } 106 0 : return false; 107 : } 108 : 109 : // returns true if all backends are communicating with the motor 110 0 : bool AP_Torqeedo::healthy() 111 : { 112 0 : uint8_t num_backends = 0; 113 0 : uint8_t num_healthy = 0; 114 0 : for (uint8_t instance = 0; instance < AP_TORQEEDO_MAX_INSTANCES; instance++) { 115 0 : auto *backend = get_instance(instance); 116 0 : if (backend != nullptr) { 117 0 : num_backends++; 118 0 : if (backend->healthy()) { 119 0 : num_healthy++; 120 : } 121 : } 122 : } 123 : 124 0 : return ((num_backends > 0) && (num_healthy == num_backends)); 125 : } 126 : 127 : // returns true if instance is healthy 128 0 : bool AP_Torqeedo::healthy(uint8_t instance) 129 : { 130 0 : auto *backend = get_instance(instance); 131 0 : if (backend == nullptr) { 132 0 : return false; 133 : } 134 0 : return backend->healthy(); 135 : } 136 : 137 : // run pre-arm check. returns false on failure and fills in failure_msg 138 : // any failure_msg returned will not include a prefix 139 15226 : bool AP_Torqeedo::pre_arm_checks(char *failure_msg, uint8_t failure_msg_len) 140 : { 141 : // exit immediately if not enabled 142 15226 : if (!enabled()) { 143 15226 : return true; 144 : } 145 : 146 0 : if (!healthy()) { 147 0 : strncpy(failure_msg, "not healthy", failure_msg_len); 148 0 : return false; 149 : } 150 0 : return true; 151 : } 152 : 153 : // clear motor errors 154 0 : void AP_Torqeedo::clear_motor_error() 155 : { 156 0 : for (uint8_t instance = 0; instance < AP_TORQEEDO_MAX_INSTANCES; instance++) { 157 0 : auto *backend = get_instance(instance); 158 0 : if (backend != nullptr) { 159 0 : backend->clear_motor_error(); 160 : } 161 : } 162 0 : } 163 : 164 : // get latest battery status info. returns true on success and populates arguments 165 : // instance is normally 0 or 1, if invalid instances are provided the first instance is used 166 0 : bool AP_Torqeedo::get_batt_info(uint8_t instance, float &voltage, float ¤t_amps, float &temp_C, uint8_t &pct_remaining) const 167 : { 168 : // for invalid instances use the first instance 169 0 : if (instance > AP_TORQEEDO_MAX_INSTANCES-1) { 170 0 : instance = 0; 171 : } 172 : 173 : // return battery info for specified instance 174 0 : auto *backend = get_instance(instance); 175 0 : if (backend != nullptr) { 176 0 : return backend->get_batt_info(voltage, current_amps, temp_C, pct_remaining); 177 : } 178 0 : return false; 179 : } 180 : 181 : // get battery capacity. returns true on success and populates argument 182 : // instance is normally 0 or 1, if invalid instances are provided the first instance is used 183 0 : bool AP_Torqeedo::get_batt_capacity_Ah(uint8_t instance, uint16_t &_hours) const 184 : { 185 : // for invalid instances use the first instance 186 0 : if (instance > AP_TORQEEDO_MAX_INSTANCES-1) { 187 0 : instance = 0; 188 : } 189 : 190 : // return battery capacity from specified instance 191 0 : auto *backend = get_instance(instance); 192 0 : if (backend != nullptr) { 193 0 : return backend->get_batt_capacity_Ah(amp_hours); 194 : } 195 0 : return false; 196 : } 197 : 198 : // return pointer to backend given an instance number 199 283 : AP_Torqeedo_Backend *AP_Torqeedo::get_instance(uint8_t instance) const 200 : { 201 283 : if (instance < AP_TORQEEDO_MAX_INSTANCES) { 202 283 : return _backends[instance]; 203 : } 204 0 : return nullptr; 205 : } 206 : 207 : // get the AP_Torqeedo singleton 208 15226 : AP_Torqeedo *AP_Torqeedo::get_singleton() 209 : { 210 15226 : return _singleton; 211 : } 212 : 213 : AP_Torqeedo *AP_Torqeedo::_singleton = nullptr; 214 : 215 : namespace AP { 216 : 217 0 : AP_Torqeedo *torqeedo() 218 : { 219 0 : return AP_Torqeedo::get_singleton(); 220 : } 221 : } 222 : 223 : #endif // HAL_TORQEEDO_ENABLED