2017-01-06 21:02:32 -04: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/>.
|
|
|
|
*/
|
|
|
|
/*
|
2022-01-21 05:12:19 -04:00
|
|
|
SRV_Channel_aux.cpp - handling of servo auxiliary functions
|
2017-01-06 21:02:32 -04:00
|
|
|
*/
|
|
|
|
#include "SRV_Channel.h"
|
|
|
|
|
|
|
|
#include <AP_Math/AP_Math.h>
|
|
|
|
#include <AP_HAL/AP_HAL.h>
|
|
|
|
#include <RC_Channel/RC_Channel.h>
|
2023-06-22 20:10:42 -03:00
|
|
|
#include <GCS_MAVLink/GCS.h>
|
2017-01-06 21:02:32 -04:00
|
|
|
|
2021-04-29 02:12:58 -03:00
|
|
|
#if NUM_SERVO_CHANNELS == 0
|
|
|
|
#pragma GCC diagnostic ignored "-Wtype-limits"
|
|
|
|
#endif
|
|
|
|
|
2017-01-06 21:02:32 -04:00
|
|
|
extern const AP_HAL::HAL& hal;
|
|
|
|
|
|
|
|
/// map a function to a servo channel and output it
|
|
|
|
void SRV_Channel::output_ch(void)
|
|
|
|
{
|
2020-12-01 07:30:12 -04:00
|
|
|
#ifndef HAL_BUILD_AP_PERIPH
|
2017-01-06 21:02:32 -04:00
|
|
|
int8_t passthrough_from = -1;
|
2022-08-05 17:07:04 -03:00
|
|
|
bool passthrough_mapped = false;
|
2017-01-06 21:02:32 -04:00
|
|
|
|
|
|
|
// take care of special function cases
|
2021-11-29 02:56:33 -04:00
|
|
|
switch(function.get())
|
2017-01-06 21:02:32 -04:00
|
|
|
{
|
|
|
|
case k_manual: // manual
|
|
|
|
passthrough_from = ch_num;
|
|
|
|
break;
|
|
|
|
case k_rcin1 ... k_rcin16: // rc pass-thru
|
2021-11-29 02:56:33 -04:00
|
|
|
passthrough_from = int8_t((int16_t)function - k_rcin1);
|
2017-01-06 21:02:32 -04:00
|
|
|
break;
|
2022-08-05 17:07:04 -03:00
|
|
|
case k_rcin1_mapped ... k_rcin16_mapped:
|
|
|
|
passthrough_from = int8_t((int16_t)function - k_rcin1_mapped);
|
|
|
|
passthrough_mapped = true;
|
|
|
|
break;
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
if (passthrough_from != -1) {
|
|
|
|
// we are doing passthrough from input to output for this channel
|
2018-04-26 09:01:13 -03:00
|
|
|
RC_Channel *c = rc().channel(passthrough_from);
|
|
|
|
if (c) {
|
2017-01-06 21:02:32 -04:00
|
|
|
if (SRV_Channels::passthrough_disabled()) {
|
2018-04-26 09:01:13 -03:00
|
|
|
output_pwm = c->get_radio_trim();
|
2017-01-06 21:02:32 -04:00
|
|
|
} else {
|
2022-08-05 17:07:04 -03:00
|
|
|
// non-mapped rc passthrough
|
|
|
|
int16_t radio_in = c->get_radio_in();
|
|
|
|
if (passthrough_mapped) {
|
2023-08-09 20:00:41 -03:00
|
|
|
if (rc().has_valid_input()) {
|
2023-11-13 07:13:05 -04:00
|
|
|
switch (c->get_type()) {
|
|
|
|
case RC_Channel::ControlType::ANGLE:
|
|
|
|
radio_in = pwm_from_angle(c->norm_input_dz() * 4500);
|
|
|
|
break;
|
|
|
|
case RC_Channel::ControlType::RANGE:
|
|
|
|
// convert RC normalised input from -1 to +1 range to 0 to +1 and output as range
|
|
|
|
radio_in = pwm_from_range((c->norm_input_ignore_trim() + 1.0) * 0.5 * 4500);
|
|
|
|
break;
|
|
|
|
}
|
2023-08-09 20:00:41 -03:00
|
|
|
} else {
|
|
|
|
// no valid input. If we are in radio
|
|
|
|
// failsafe then go to trim values (if
|
|
|
|
// configured for this channel). Otherwise
|
|
|
|
// use the last-good value
|
|
|
|
if ( ((1U<<passthrough_from) & SRV_Channels::get_rc_fs_mask()) && rc().in_rc_failsafe()) {
|
|
|
|
radio_in = pwm_from_angle(0);
|
|
|
|
} else {
|
|
|
|
radio_in = previous_radio_in;
|
|
|
|
}
|
2023-06-22 20:10:42 -03:00
|
|
|
}
|
2022-08-05 17:07:04 -03:00
|
|
|
}
|
2019-06-02 22:57:01 -03:00
|
|
|
if (!ign_small_rcin_changes) {
|
|
|
|
output_pwm = radio_in;
|
|
|
|
previous_radio_in = radio_in;
|
|
|
|
} else {
|
|
|
|
// check if rc input value has changed by more than the deadzone
|
|
|
|
if (abs(radio_in - previous_radio_in) > c->get_dead_zone()) {
|
|
|
|
output_pwm = radio_in;
|
|
|
|
ign_small_rcin_changes = false;
|
|
|
|
}
|
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-01 07:30:12 -04:00
|
|
|
#endif // HAL_BUILD_AP_PERIPH
|
|
|
|
|
2018-04-01 03:01:37 -03:00
|
|
|
if (!(SRV_Channels::disabled_mask & (1U<<ch_num))) {
|
|
|
|
hal.rcout->write(ch_num, output_pwm);
|
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
call output_ch() on all channels
|
|
|
|
*/
|
|
|
|
void SRV_Channels::output_ch_all(void)
|
|
|
|
{
|
2022-05-15 18:51:34 -03:00
|
|
|
uint8_t max_chan = NUM_SERVO_CHANNELS;
|
|
|
|
#if NUM_SERVO_CHANNELS >= 17
|
|
|
|
if (_singleton != nullptr && _singleton->enable_32_channels.get() <= 0) {
|
|
|
|
max_chan = 16;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
for (uint8_t i = 0; i < max_chan; i++) {
|
2017-01-06 21:02:32 -04:00
|
|
|
channels[i].output_ch();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
return the current function for a channel
|
|
|
|
*/
|
|
|
|
SRV_Channel::Aux_servo_function_t SRV_Channels::channel_function(uint8_t channel)
|
|
|
|
{
|
|
|
|
if (channel < NUM_SERVO_CHANNELS) {
|
2021-11-29 02:56:33 -04:00
|
|
|
return channels[channel].function;
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
return SRV_Channel::k_none;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
setup a channels aux servo function
|
|
|
|
*/
|
|
|
|
void SRV_Channel::aux_servo_function_setup(void)
|
|
|
|
{
|
|
|
|
if (type_setup) {
|
|
|
|
return;
|
|
|
|
}
|
2021-11-29 02:56:33 -04:00
|
|
|
switch (function.get()) {
|
2017-01-06 21:02:32 -04:00
|
|
|
case k_flap:
|
|
|
|
case k_flap_auto:
|
|
|
|
case k_egg_drop:
|
2024-08-30 01:01:32 -03:00
|
|
|
case k_lift_release:
|
2017-01-06 21:02:32 -04:00
|
|
|
set_range(100);
|
|
|
|
break;
|
|
|
|
case k_heli_rsc:
|
|
|
|
case k_heli_tail_rsc:
|
|
|
|
case k_motor_tilt:
|
2017-04-17 07:04:11 -03:00
|
|
|
case k_boost_throttle:
|
2019-10-14 20:25:33 -03:00
|
|
|
case k_thrust_out:
|
2017-01-06 21:02:32 -04:00
|
|
|
set_range(1000);
|
|
|
|
break;
|
|
|
|
case k_aileron_with_input:
|
|
|
|
case k_elevator_with_input:
|
|
|
|
case k_aileron:
|
|
|
|
case k_elevator:
|
2017-07-01 03:01:32 -03:00
|
|
|
case k_dspoilerLeft1:
|
|
|
|
case k_dspoilerLeft2:
|
|
|
|
case k_dspoilerRight1:
|
|
|
|
case k_dspoilerRight2:
|
2017-01-06 21:02:32 -04:00
|
|
|
case k_rudder:
|
|
|
|
case k_steering:
|
2017-06-10 19:44:04 -03:00
|
|
|
case k_flaperon_left:
|
|
|
|
case k_flaperon_right:
|
2017-04-09 20:49:35 -03:00
|
|
|
case k_tiltMotorLeft:
|
|
|
|
case k_tiltMotorRight:
|
2020-12-18 06:53:43 -04:00
|
|
|
case k_tiltMotorRear:
|
|
|
|
case k_tiltMotorRearLeft:
|
|
|
|
case k_tiltMotorRearRight:
|
2017-04-19 08:32:47 -03:00
|
|
|
case k_elevon_left:
|
|
|
|
case k_elevon_right:
|
|
|
|
case k_vtail_left:
|
|
|
|
case k_vtail_right:
|
2020-08-19 08:48:15 -03:00
|
|
|
case k_scripting1:
|
|
|
|
case k_scripting2:
|
|
|
|
case k_scripting3:
|
|
|
|
case k_scripting4:
|
|
|
|
case k_scripting5:
|
|
|
|
case k_scripting6:
|
|
|
|
case k_scripting7:
|
|
|
|
case k_scripting8:
|
|
|
|
case k_scripting9:
|
|
|
|
case k_scripting10:
|
|
|
|
case k_scripting11:
|
|
|
|
case k_scripting12:
|
|
|
|
case k_scripting13:
|
|
|
|
case k_scripting14:
|
|
|
|
case k_scripting15:
|
|
|
|
case k_scripting16:
|
2019-10-14 20:25:33 -03:00
|
|
|
case k_roll_out:
|
|
|
|
case k_pitch_out:
|
|
|
|
case k_yaw_out:
|
2022-08-05 17:07:04 -03:00
|
|
|
case k_rcin1_mapped ... k_rcin16_mapped:
|
2017-01-06 21:02:32 -04:00
|
|
|
set_angle(4500);
|
|
|
|
break;
|
|
|
|
case k_throttle:
|
2017-02-12 21:03:03 -04:00
|
|
|
case k_throttleLeft:
|
|
|
|
case k_throttleRight:
|
2018-11-12 11:41:22 -04:00
|
|
|
case k_airbrake:
|
2017-01-06 21:02:32 -04:00
|
|
|
// fixed wing throttle
|
|
|
|
set_range(100);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// setup the output range types of all functions
|
|
|
|
void SRV_Channels::update_aux_servo_function(void)
|
|
|
|
{
|
2017-11-21 02:17:37 -04:00
|
|
|
if (!channels) {
|
|
|
|
return;
|
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
function_mask.clearall();
|
|
|
|
|
2021-11-29 03:33:29 -04:00
|
|
|
for (uint16_t i = 0; i < SRV_Channel::k_nr_aux_servo_functions; i++) {
|
2017-01-06 21:02:32 -04:00
|
|
|
functions[i].channel_mask = 0;
|
|
|
|
}
|
2022-01-02 13:40:16 -04:00
|
|
|
invalid_mask = 0;
|
2017-07-25 00:23:09 -03:00
|
|
|
|
2017-01-06 21:02:32 -04:00
|
|
|
// set auxiliary ranges
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2021-12-14 23:58:47 -04:00
|
|
|
if (!channels[i].valid_function()) {
|
2022-01-02 13:40:16 -04:00
|
|
|
invalid_mask |= 1U<<i;
|
2021-11-29 02:56:33 -04:00
|
|
|
continue;
|
2017-07-26 02:27:06 -03:00
|
|
|
}
|
2021-12-14 23:58:47 -04:00
|
|
|
const uint16_t function = channels[i].function.get();
|
2021-11-29 02:56:33 -04:00
|
|
|
channels[i].aux_servo_function_setup();
|
2021-12-14 23:58:47 -04:00
|
|
|
function_mask.set(function);
|
|
|
|
functions[function].channel_mask |= 1U<<i;
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
initialised = true;
|
|
|
|
}
|
|
|
|
|
2022-05-23 01:46:25 -03:00
|
|
|
/// Should be called after the servo functions have been initialized
|
2021-06-16 06:28:15 -03:00
|
|
|
/// called at 1Hz
|
2017-01-06 21:02:32 -04:00
|
|
|
void SRV_Channels::enable_aux_servos()
|
|
|
|
{
|
2019-02-10 00:59:44 -04:00
|
|
|
hal.rcout->set_default_rate(uint16_t(_singleton->default_rate.get()));
|
2017-07-25 00:23:09 -03:00
|
|
|
|
2017-01-06 21:02:32 -04:00
|
|
|
update_aux_servo_function();
|
|
|
|
|
|
|
|
// enable all channels that are set to a valid function. This
|
|
|
|
// includes k_none servos, which allows those to get their initial
|
|
|
|
// trim value on startup
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2018-11-09 06:26:38 -04:00
|
|
|
SRV_Channel &c = channels[i];
|
2017-01-06 21:02:32 -04:00
|
|
|
// see if it is a valid function
|
2022-04-19 14:17:10 -03:00
|
|
|
if (c.valid_function() && !(disabled_mask & (1U<<c.ch_num))) {
|
2018-11-09 06:26:38 -04:00
|
|
|
hal.rcout->enable_ch(c.ch_num);
|
2022-03-25 07:45:43 -03:00
|
|
|
} else {
|
|
|
|
hal.rcout->disable_ch(c.ch_num);
|
2018-11-09 06:26:38 -04:00
|
|
|
}
|
|
|
|
|
2020-08-30 23:35:24 -03:00
|
|
|
// output some servo functions before we fiddle with the
|
|
|
|
// parameter values:
|
2021-11-29 02:56:33 -04:00
|
|
|
if (c.function == SRV_Channel::k_min) {
|
2020-08-30 23:35:24 -03:00
|
|
|
c.set_output_pwm(c.servo_min);
|
|
|
|
c.output_ch();
|
2021-11-29 02:56:33 -04:00
|
|
|
} else if (c.function == SRV_Channel::k_trim) {
|
2020-08-30 23:35:24 -03:00
|
|
|
c.set_output_pwm(c.servo_trim);
|
|
|
|
c.output_ch();
|
2021-11-29 02:56:33 -04:00
|
|
|
} else if (c.function == SRV_Channel::k_max) {
|
2020-08-30 23:35:24 -03:00
|
|
|
c.set_output_pwm(c.servo_max);
|
|
|
|
c.output_ch();
|
|
|
|
}
|
2021-05-01 12:39:32 -03:00
|
|
|
}
|
|
|
|
|
2021-06-16 06:28:15 -03:00
|
|
|
// propagate channel masks to the ESCS
|
|
|
|
hal.rcout->update_channel_masks();
|
|
|
|
|
2021-05-01 12:39:32 -03:00
|
|
|
#if HAL_SUPPORT_RCOUT_SERIAL
|
2024-11-09 03:17:28 -04:00
|
|
|
blheli.update();
|
2021-05-01 12:39:32 -03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
for channels which have been marked as digital output then the
|
|
|
|
MIN/MAX/TRIM values have no meaning for controlling output, as
|
|
|
|
the HAL handles the scaling. We still need to cope with places
|
|
|
|
in the code that may try to set a PWM value however, so to
|
|
|
|
ensure consistency we force the MIN/MAX/TRIM to be consistent
|
|
|
|
across all digital channels. We use a MIN/MAX of 1000/2000, and
|
|
|
|
set TRIM to either 1000 or 1500 depending on whether the channel
|
|
|
|
is reversible
|
|
|
|
*/
|
2021-01-11 22:02:50 -04:00
|
|
|
void SRV_Channels::set_digital_outputs(uint32_t dig_mask, uint32_t rev_mask) {
|
2021-05-06 10:13:36 -03:00
|
|
|
digital_mask |= dig_mask;
|
|
|
|
reversible_mask |= rev_mask;
|
|
|
|
|
2022-04-19 14:17:10 -03:00
|
|
|
// add in NeoPixel and ProfiLED functions to digital array to determine anything else
|
|
|
|
// that should be disabled
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
|
|
|
SRV_Channel &c = channels[i];
|
|
|
|
switch (c.function.get()) {
|
|
|
|
case SRV_Channel::k_LED_neopixel1:
|
|
|
|
case SRV_Channel::k_LED_neopixel2:
|
|
|
|
case SRV_Channel::k_LED_neopixel3:
|
|
|
|
case SRV_Channel::k_LED_neopixel4:
|
|
|
|
case SRV_Channel::k_ProfiLED_1:
|
|
|
|
case SRV_Channel::k_ProfiLED_2:
|
|
|
|
case SRV_Channel::k_ProfiLED_3:
|
|
|
|
case SRV_Channel::k_ProfiLED_Clock:
|
|
|
|
dig_mask |= 1U<<c.ch_num;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
disabled_mask = hal.rcout->get_disabled_channels(dig_mask);
|
|
|
|
|
2021-05-01 12:39:32 -03:00
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
|
|
|
SRV_Channel &c = channels[i];
|
2018-11-09 06:26:38 -04:00
|
|
|
if (digital_mask & (1U<<i)) {
|
2022-07-04 22:47:21 -03:00
|
|
|
c.servo_min.set_and_default(1000);
|
|
|
|
c.servo_max.set_and_default(2000);
|
2018-11-09 06:26:38 -04:00
|
|
|
if (reversible_mask & (1U<<i)) {
|
2022-07-04 22:47:21 -03:00
|
|
|
c.servo_trim.set_and_default(1500);
|
2018-11-09 06:26:38 -04:00
|
|
|
} else {
|
2022-07-04 22:47:21 -03:00
|
|
|
c.servo_trim.set_and_default(1000);
|
2018-11-09 06:26:38 -04:00
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-29 05:33:49 -03:00
|
|
|
/// enable output channels using a channel mask
|
2021-01-11 22:02:50 -04:00
|
|
|
void SRV_Channels::enable_by_mask(uint32_t mask)
|
2017-04-29 05:33:49 -03:00
|
|
|
{
|
2020-01-30 19:08:22 -04:00
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2017-04-29 05:33:49 -03:00
|
|
|
if (mask & (1U<<i)) {
|
|
|
|
hal.rcout->enable_ch(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:02:32 -04:00
|
|
|
/*
|
|
|
|
set radio_out for all channels matching the given function type
|
|
|
|
*/
|
|
|
|
void SRV_Channels::set_output_pwm(SRV_Channel::Aux_servo_function_t function, uint16_t value)
|
|
|
|
{
|
|
|
|
if (!function_assigned(function)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2021-11-29 02:56:33 -04:00
|
|
|
if (channels[i].function == function) {
|
2017-01-06 21:02:32 -04:00
|
|
|
channels[i].set_output_pwm(value);
|
|
|
|
channels[i].output_ch();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
set radio_out for all channels matching the given function type
|
|
|
|
trim the output assuming a 1500 center on the given value
|
2018-07-11 14:19:39 -03:00
|
|
|
reverses pwm output based on channel reversed property
|
2017-01-06 21:02:32 -04:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
SRV_Channels::set_output_pwm_trimmed(SRV_Channel::Aux_servo_function_t function, int16_t value)
|
|
|
|
{
|
|
|
|
if (!function_assigned(function)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2021-11-29 02:56:33 -04:00
|
|
|
if (channels[i].function == function) {
|
2018-07-11 14:19:39 -03:00
|
|
|
int16_t value2;
|
|
|
|
if (channels[i].get_reversed()) {
|
|
|
|
value2 = 1500 - value + channels[i].get_trim();
|
|
|
|
} else {
|
|
|
|
value2 = value - 1500 + channels[i].get_trim();
|
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
channels[i].set_output_pwm(constrain_int16(value2,channels[i].get_output_min(),channels[i].get_output_max()));
|
|
|
|
channels[i].output_ch();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-07-01 07:04:30 -03:00
|
|
|
set and save the trim value to current output for all channels matching
|
2017-01-06 21:02:32 -04:00
|
|
|
the given function type
|
|
|
|
*/
|
|
|
|
void
|
2017-07-01 07:04:30 -03:00
|
|
|
SRV_Channels::set_trim_to_servo_out_for(SRV_Channel::Aux_servo_function_t function)
|
2017-01-06 21:02:32 -04:00
|
|
|
{
|
|
|
|
if (!function_assigned(function)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2021-11-29 02:56:33 -04:00
|
|
|
if (channels[i].function == function) {
|
2020-06-07 17:04:56 -03:00
|
|
|
channels[i].servo_trim.set_and_save_ifchanged(channels[i].get_output_pwm());
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-19 07:02:24 -03:00
|
|
|
#if AP_RC_CHANNEL_ENABLED
|
2017-01-06 21:02:32 -04:00
|
|
|
/*
|
|
|
|
copy radio_in to radio_out for a given function
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SRV_Channels::copy_radio_in_out(SRV_Channel::Aux_servo_function_t function, bool do_input_output)
|
|
|
|
{
|
|
|
|
if (!function_assigned(function)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2021-11-29 02:56:33 -04:00
|
|
|
if (channels[i].function == function) {
|
2018-04-26 09:01:13 -03:00
|
|
|
RC_Channel *c = rc().channel(channels[i].ch_num);
|
|
|
|
if (c == nullptr) {
|
2017-01-06 21:02:32 -04:00
|
|
|
continue;
|
|
|
|
}
|
2018-04-26 09:01:13 -03:00
|
|
|
channels[i].set_output_pwm(c->get_radio_in());
|
2017-01-06 21:02:32 -04:00
|
|
|
if (do_input_output) {
|
|
|
|
channels[i].output_ch();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-10 03:59:53 -03:00
|
|
|
/*
|
|
|
|
copy radio_in to radio_out for a channel mask
|
|
|
|
*/
|
|
|
|
void
|
2021-01-11 22:02:50 -04:00
|
|
|
SRV_Channels::copy_radio_in_out_mask(uint32_t mask)
|
2017-07-10 03:59:53 -03:00
|
|
|
{
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
|
|
|
if ((1U<<i) & mask) {
|
2018-04-26 09:01:13 -03:00
|
|
|
RC_Channel *c = rc().channel(channels[i].ch_num);
|
|
|
|
if (c == nullptr) {
|
2017-07-10 03:59:53 -03:00
|
|
|
continue;
|
|
|
|
}
|
2018-04-26 09:01:13 -03:00
|
|
|
channels[i].set_output_pwm(c->get_radio_in());
|
2017-07-10 03:59:53 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-03-19 07:02:24 -03:00
|
|
|
#endif // AP_RC_CHANNEL_ENABLED
|
2017-07-10 03:59:53 -03:00
|
|
|
|
2017-01-06 21:02:32 -04:00
|
|
|
/*
|
2019-11-24 21:49:24 -04:00
|
|
|
setup failsafe value for an auxiliary function type to a Limit
|
2017-01-06 21:02:32 -04:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
SRV_Channels::set_failsafe_pwm(SRV_Channel::Aux_servo_function_t function, uint16_t pwm)
|
|
|
|
{
|
|
|
|
if (!function_assigned(function)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2018-10-11 20:44:00 -03:00
|
|
|
const SRV_Channel &c = channels[i];
|
2021-11-29 02:56:33 -04:00
|
|
|
if (c.function == function) {
|
2018-10-11 20:44:00 -03:00
|
|
|
hal.rcout->set_failsafe_pwm(1U<<c.ch_num, pwm);
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2019-11-24 21:49:24 -04:00
|
|
|
setup failsafe value for an auxiliary function type to a Limit
|
2017-01-06 21:02:32 -04:00
|
|
|
*/
|
|
|
|
void
|
2019-11-24 21:49:24 -04:00
|
|
|
SRV_Channels::set_failsafe_limit(SRV_Channel::Aux_servo_function_t function, SRV_Channel::Limit limit)
|
2017-01-06 21:02:32 -04:00
|
|
|
{
|
|
|
|
if (!function_assigned(function)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2018-10-11 20:44:00 -03:00
|
|
|
const SRV_Channel &c = channels[i];
|
2021-11-29 02:56:33 -04:00
|
|
|
if (c.function == function) {
|
2018-10-11 20:44:00 -03:00
|
|
|
uint16_t pwm = c.get_limit_pwm(limit);
|
|
|
|
hal.rcout->set_failsafe_pwm(1U<<c.ch_num, pwm);
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2019-11-24 21:49:24 -04:00
|
|
|
set radio output value for an auxiliary function type to a Limit
|
2017-01-06 21:02:32 -04:00
|
|
|
*/
|
|
|
|
void
|
2019-11-24 21:49:24 -04:00
|
|
|
SRV_Channels::set_output_limit(SRV_Channel::Aux_servo_function_t function, SRV_Channel::Limit limit)
|
2017-01-06 21:02:32 -04:00
|
|
|
{
|
|
|
|
if (!function_assigned(function)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2018-10-11 20:44:00 -03:00
|
|
|
SRV_Channel &c = channels[i];
|
2021-11-29 02:56:33 -04:00
|
|
|
if (c.function == function) {
|
2018-10-11 20:44:00 -03:00
|
|
|
uint16_t pwm = c.get_limit_pwm(limit);
|
|
|
|
c.set_output_pwm(pwm);
|
2023-03-19 07:02:24 -03:00
|
|
|
#if AP_RC_CHANNEL_ENABLED
|
2021-11-29 02:56:33 -04:00
|
|
|
if (c.function == SRV_Channel::k_manual) {
|
2018-10-11 20:44:00 -03:00
|
|
|
RC_Channel *cin = rc().channel(c.ch_num);
|
|
|
|
if (cin != nullptr) {
|
2017-01-06 21:02:32 -04:00
|
|
|
// in order for output_ch() to work for k_manual we
|
|
|
|
// also have to override radio_in
|
2018-10-11 20:44:00 -03:00
|
|
|
cin->set_radio_in(pwm);
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
2023-03-19 07:02:24 -03:00
|
|
|
#endif
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
return true if a particular function is assigned to at least one RC channel
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
SRV_Channels::function_assigned(SRV_Channel::Aux_servo_function_t function)
|
|
|
|
{
|
2021-08-31 09:22:54 -03:00
|
|
|
if (!initialised) {
|
|
|
|
update_aux_servo_function();
|
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
return function_mask.get(uint16_t(function));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
set servo_out and angle_min/max, then calc_pwm and output a
|
|
|
|
value. This is used to move a AP_Mount servo
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SRV_Channels::move_servo(SRV_Channel::Aux_servo_function_t function,
|
|
|
|
int16_t value, int16_t angle_min, int16_t angle_max)
|
|
|
|
{
|
|
|
|
if (!function_assigned(function)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (angle_max <= angle_min) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
float v = float(value - angle_min) / float(angle_max - angle_min);
|
2017-02-28 03:32:28 -04:00
|
|
|
v = constrain_float(v, 0.0f, 1.0f);
|
2017-01-06 21:02:32 -04:00
|
|
|
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
|
2018-10-11 20:44:00 -03:00
|
|
|
SRV_Channel &c = channels[i];
|
2021-11-29 02:56:33 -04:00
|
|
|
if (c.function == function) {
|
2018-10-11 20:44:00 -03:00
|
|
|
float v2 = c.get_reversed()? (1-v) : v;
|
|
|
|
uint16_t pwm = c.servo_min + v2 * (c.servo_max - c.servo_min);
|
|
|
|
c.set_output_pwm(pwm);
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
set the default channel an auxiliary output function should be on
|
|
|
|
*/
|
|
|
|
bool SRV_Channels::set_aux_channel_default(SRV_Channel::Aux_servo_function_t function, uint8_t channel)
|
|
|
|
{
|
|
|
|
if (function_assigned(function)) {
|
|
|
|
// already assigned
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (channels[channel].function != SRV_Channel::k_none) {
|
|
|
|
if (channels[channel].function == function) {
|
|
|
|
return true;
|
|
|
|
}
|
2018-07-11 14:25:30 -03:00
|
|
|
hal.console->printf("Channel %u already assigned function %u\n",
|
|
|
|
(unsigned)(channel + 1),
|
2021-11-29 02:56:33 -04:00
|
|
|
(unsigned)channels[channel].function.get());
|
2017-01-06 21:02:32 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
channels[channel].type_setup = false;
|
2022-07-04 22:47:21 -03:00
|
|
|
channels[channel].function.set_and_default(function);
|
2017-01-06 21:02:32 -04:00
|
|
|
channels[channel].aux_servo_function_setup();
|
2021-11-29 03:33:29 -04:00
|
|
|
function_mask.set((uint16_t)function);
|
2021-12-14 23:58:47 -04:00
|
|
|
if (SRV_Channel::valid_function(function)) {
|
|
|
|
functions[function].channel_mask |= 1U<<channel;
|
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find first channel that a function is assigned to
|
|
|
|
bool SRV_Channels::find_channel(SRV_Channel::Aux_servo_function_t function, uint8_t &chan)
|
|
|
|
{
|
2024-08-15 11:02:12 -03:00
|
|
|
// Must have populated channel masks
|
|
|
|
if (!initialised) {
|
|
|
|
update_aux_servo_function();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure function is valid
|
|
|
|
if (!SRV_Channel::valid_function(function)) {
|
2017-01-06 21:02:32 -04:00
|
|
|
return false;
|
|
|
|
}
|
2024-08-15 11:02:12 -03:00
|
|
|
|
|
|
|
// Get the index of the first set bit, returns 0 if no bits are set
|
|
|
|
const int first_chan = __builtin_ffs(functions[function].channel_mask);
|
|
|
|
if (first_chan == 0) {
|
|
|
|
return false;
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
2024-08-15 11:02:12 -03:00
|
|
|
|
|
|
|
// Convert to 0 indexed
|
|
|
|
chan = first_chan - 1;
|
|
|
|
return true;
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2022-01-21 05:12:19 -04:00
|
|
|
get a pointer to first auxiliary channel for a channel function
|
2017-01-06 21:02:32 -04:00
|
|
|
*/
|
2023-03-28 01:13:42 -03:00
|
|
|
SRV_Channel *SRV_Channels::get_channel_for(SRV_Channel::Aux_servo_function_t function)
|
2017-01-06 21:02:32 -04:00
|
|
|
{
|
|
|
|
uint8_t chan;
|
|
|
|
if (!find_channel(function, chan)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return &channels[chan];
|
|
|
|
}
|
|
|
|
|
2021-09-18 14:54:52 -03:00
|
|
|
void SRV_Channels::set_output_scaled(SRV_Channel::Aux_servo_function_t function, float value)
|
2017-01-06 21:02:32 -04:00
|
|
|
{
|
2021-12-14 23:58:47 -04:00
|
|
|
if (SRV_Channel::valid_function(function)) {
|
2017-01-06 21:02:32 -04:00
|
|
|
functions[function].output_scaled = value;
|
|
|
|
SRV_Channel::have_pwm_mask &= ~functions[function].channel_mask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-18 14:54:52 -03:00
|
|
|
float SRV_Channels::get_output_scaled(SRV_Channel::Aux_servo_function_t function)
|
2017-01-06 21:02:32 -04:00
|
|
|
{
|
2021-12-14 23:58:47 -04:00
|
|
|
if (SRV_Channel::valid_function(function)) {
|
2017-01-06 21:02:32 -04:00
|
|
|
return functions[function].output_scaled;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-16 09:06:13 -04:00
|
|
|
// get slew limited scaled output for the given function type
|
|
|
|
float SRV_Channels::get_slew_limited_output_scaled(SRV_Channel::Aux_servo_function_t function)
|
|
|
|
{
|
|
|
|
if (!SRV_Channel::valid_function(function)) {
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
for (slew_list *slew = _slew; slew; slew = slew->next) {
|
|
|
|
if (slew->func == function) {
|
|
|
|
if (!is_positive(slew->max_change)) {
|
|
|
|
// treat negative or zero slew rate as disabled
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return constrain_float(functions[function].output_scaled, slew->last_scaled_output - slew->max_change, slew->last_scaled_output + slew->max_change);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// no slew limiting
|
|
|
|
return functions[function].output_scaled;
|
|
|
|
}
|
|
|
|
|
2017-04-17 05:15:24 -03:00
|
|
|
/*
|
|
|
|
get mask of output channels for a function
|
|
|
|
*/
|
2021-01-11 22:02:50 -04:00
|
|
|
uint32_t SRV_Channels::get_output_channel_mask(SRV_Channel::Aux_servo_function_t function)
|
2017-04-17 05:15:24 -03:00
|
|
|
{
|
2017-04-17 05:59:51 -03:00
|
|
|
if (!initialised) {
|
|
|
|
update_aux_servo_function();
|
|
|
|
}
|
2021-12-14 23:58:47 -04:00
|
|
|
if (SRV_Channel::valid_function(function)) {
|
2017-04-17 05:15:24 -03:00
|
|
|
return functions[function].channel_mask;
|
|
|
|
}
|
2022-01-02 13:40:16 -04:00
|
|
|
return invalid_mask;
|
2017-04-17 05:15:24 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-06 21:02:32 -04:00
|
|
|
// set the trim for a function channel to given pwm
|
|
|
|
void SRV_Channels::set_trim_to_pwm_for(SRV_Channel::Aux_servo_function_t function, int16_t pwm)
|
|
|
|
{
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
if (channels[i].function == function) {
|
2022-07-04 22:47:21 -03:00
|
|
|
channels[i].servo_trim.set_and_default(pwm);
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-29 08:53:20 -03:00
|
|
|
// set the trim for a function channel to min output of the channel honnoring reverse unless ignore_reversed is true
|
|
|
|
void SRV_Channels::set_trim_to_min_for(SRV_Channel::Aux_servo_function_t function, bool ignore_reversed)
|
2017-01-06 21:02:32 -04:00
|
|
|
{
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
if (channels[i].function == function) {
|
2022-07-04 22:47:21 -03:00
|
|
|
channels[i].servo_trim.set_and_default((channels[i].get_reversed() && !ignore_reversed)?channels[i].servo_max:channels[i].servo_min);
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
set the default function for a channel
|
|
|
|
*/
|
|
|
|
void SRV_Channels::set_default_function(uint8_t chan, SRV_Channel::Aux_servo_function_t function)
|
|
|
|
{
|
|
|
|
if (chan < NUM_SERVO_CHANNELS) {
|
2021-11-29 02:56:33 -04:00
|
|
|
const SRV_Channel::Aux_servo_function_t old = channels[chan].function;
|
|
|
|
channels[chan].function.set_default(function);
|
2017-01-22 19:34:52 -04:00
|
|
|
if (old != channels[chan].function && channels[chan].function == function) {
|
2021-11-29 03:33:29 -04:00
|
|
|
function_mask.set((uint16_t)function);
|
2017-01-22 19:34:52 -04:00
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SRV_Channels::set_esc_scaling_for(SRV_Channel::Aux_servo_function_t function)
|
|
|
|
{
|
|
|
|
uint8_t chan;
|
|
|
|
if (find_channel(function, chan)) {
|
|
|
|
hal.rcout->set_esc_scaling(channels[chan].get_output_min(), channels[chan].get_output_max());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
auto-adjust channel trim from an integrator value. Positive v means
|
|
|
|
adjust trim up. Negative means decrease
|
|
|
|
*/
|
|
|
|
void SRV_Channels::adjust_trim(SRV_Channel::Aux_servo_function_t function, float v)
|
|
|
|
{
|
|
|
|
if (is_zero(v)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
SRV_Channel &c = channels[i];
|
2021-11-29 02:56:33 -04:00
|
|
|
if (function != c.function) {
|
2017-01-06 21:02:32 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
float change = c.reversed?-v:v;
|
|
|
|
uint16_t new_trim = c.servo_trim;
|
2021-01-03 01:48:55 -04:00
|
|
|
if (c.servo_max <= c.servo_min) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
float trim_scaled = float(c.servo_trim - c.servo_min) / (c.servo_max - c.servo_min);
|
|
|
|
if (change > 0 && trim_scaled < 0.6f) {
|
|
|
|
new_trim++;
|
|
|
|
} else if (change < 0 && trim_scaled > 0.4f) {
|
|
|
|
new_trim--;
|
|
|
|
} else {
|
2022-09-16 17:56:43 -03:00
|
|
|
continue;
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
c.servo_trim.set(new_trim);
|
|
|
|
|
|
|
|
trimmed_mask |= 1U<<i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get pwm output for the first channel of the given function type.
|
|
|
|
bool SRV_Channels::get_output_pwm(SRV_Channel::Aux_servo_function_t function, uint16_t &value)
|
|
|
|
{
|
|
|
|
uint8_t chan;
|
|
|
|
if (!find_channel(function, chan)) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-12-14 23:58:47 -04:00
|
|
|
if (!SRV_Channel::valid_function(function)) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
channels[chan].calc_pwm(functions[function].output_scaled);
|
2020-06-07 17:04:56 -03:00
|
|
|
value = channels[chan].get_output_pwm();
|
2017-01-06 21:02:32 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set output pwm to trim for the given function
|
|
|
|
void SRV_Channels::set_output_to_trim(SRV_Channel::Aux_servo_function_t function)
|
|
|
|
{
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
if (channels[i].function == function) {
|
|
|
|
channels[i].set_output_pwm(channels[i].servo_trim);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
get the normalised output for a channel function from the pwm value
|
|
|
|
of the first matching channel
|
|
|
|
*/
|
|
|
|
float SRV_Channels::get_output_norm(SRV_Channel::Aux_servo_function_t function)
|
|
|
|
{
|
|
|
|
uint8_t chan;
|
|
|
|
if (!find_channel(function, chan)) {
|
|
|
|
return 0;
|
|
|
|
}
|
2021-12-14 23:58:47 -04:00
|
|
|
if (SRV_Channel::valid_function(function)) {
|
|
|
|
channels[chan].calc_pwm(functions[function].output_scaled);
|
|
|
|
}
|
2017-01-06 21:02:32 -04:00
|
|
|
return channels[chan].get_output_norm();
|
|
|
|
}
|
|
|
|
|
2020-08-07 22:23:56 -03:00
|
|
|
// set normalised output (-1 to 1 with 0 at mid point of servo_min/servo_max) for the given function
|
|
|
|
void SRV_Channels::set_output_norm(SRV_Channel::Aux_servo_function_t function, float value)
|
|
|
|
{
|
|
|
|
if (!function_assigned(function)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
SRV_Channel &c = channels[i];
|
|
|
|
if (c.function == function) {
|
|
|
|
c.set_output_norm(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:02:32 -04:00
|
|
|
/*
|
2017-01-07 02:13:54 -04:00
|
|
|
limit slew rate for an output function to given rate in percent per
|
|
|
|
second. This assumes output has not yet done to the hal
|
2017-01-06 21:02:32 -04:00
|
|
|
*/
|
2022-01-16 09:06:13 -04:00
|
|
|
void SRV_Channels::set_slew_rate(SRV_Channel::Aux_servo_function_t function, float slew_rate, uint16_t range, float dt)
|
2017-01-06 21:02:32 -04:00
|
|
|
{
|
2021-12-14 23:58:47 -04:00
|
|
|
if (!SRV_Channel::valid_function(function)) {
|
|
|
|
return;
|
|
|
|
}
|
2022-01-16 09:06:13 -04:00
|
|
|
const float max_change = range * slew_rate * 0.01 * dt;
|
|
|
|
|
|
|
|
for (slew_list *slew = _slew; slew; slew = slew->next) {
|
|
|
|
if (slew->func == function) {
|
|
|
|
// found existing item, update max change
|
|
|
|
slew->max_change = max_change;
|
|
|
|
return;
|
2017-01-07 02:13:54 -04:00
|
|
|
}
|
|
|
|
}
|
2022-01-16 09:06:13 -04:00
|
|
|
|
|
|
|
if (!is_positive(max_change)) {
|
|
|
|
// no point in adding a disabled slew limit
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add new item
|
2024-05-26 22:24:16 -03:00
|
|
|
slew_list *new_slew = NEW_NOTHROW slew_list(function);
|
2022-01-16 09:06:13 -04:00
|
|
|
if (new_slew == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
new_slew->last_scaled_output = functions[function].output_scaled;
|
|
|
|
new_slew->max_change = max_change;
|
|
|
|
new_slew->next = _slew;
|
|
|
|
_slew = new_slew;
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// call set_angle() on matching channels
|
|
|
|
void SRV_Channels::set_angle(SRV_Channel::Aux_servo_function_t function, uint16_t angle)
|
|
|
|
{
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
if (channels[i].function == function) {
|
|
|
|
channels[i].set_angle(angle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// call set_range() on matching channels
|
|
|
|
void SRV_Channels::set_range(SRV_Channel::Aux_servo_function_t function, uint16_t range)
|
|
|
|
{
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
if (channels[i].function == function) {
|
|
|
|
channels[i].set_range(range);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-20 23:58:12 -03:00
|
|
|
// set MIN parameter for a function
|
|
|
|
void SRV_Channels::set_output_min_max(SRV_Channel::Aux_servo_function_t function, uint16_t min_pwm, uint16_t max_pwm)
|
|
|
|
{
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
if (channels[i].function == function) {
|
|
|
|
channels[i].set_output_min(min_pwm);
|
|
|
|
channels[i].set_output_max(max_pwm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-03 09:27:54 -03:00
|
|
|
// set MIN/MAX parameter defaults for a function
|
|
|
|
void SRV_Channels::set_output_min_max_defaults(SRV_Channel::Aux_servo_function_t function, uint16_t min_pwm, uint16_t max_pwm)
|
|
|
|
{
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
if (channels[i].function == function) {
|
|
|
|
channels[i].servo_min.set_default(min_pwm);
|
|
|
|
channels[i].servo_max.set_default(max_pwm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save MIN/MAX/REVERSED parameters for a function
|
|
|
|
void SRV_Channels::save_output_min_max(SRV_Channel::Aux_servo_function_t function, uint16_t min_pwm, uint16_t max_pwm)
|
|
|
|
{
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
if (channels[i].function == function) {
|
|
|
|
// If min is larger than max swap and set reversed
|
|
|
|
const bool reversed = min_pwm > max_pwm;
|
|
|
|
channels[i].servo_min.set_and_save(reversed ? max_pwm : min_pwm);
|
|
|
|
channels[i].servo_max.set_and_save(reversed ? min_pwm : max_pwm);
|
|
|
|
channels[i].reversed.set_and_save(reversed ? 1 : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:02:32 -04:00
|
|
|
// constrain to output min/max for function
|
|
|
|
void SRV_Channels::constrain_pwm(SRV_Channel::Aux_servo_function_t function)
|
|
|
|
{
|
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
2018-10-11 20:44:00 -03:00
|
|
|
SRV_Channel &c = channels[i];
|
|
|
|
if (c.function == function) {
|
2020-06-07 17:04:56 -03:00
|
|
|
c.set_output_pwm(constrain_int16(c.output_pwm, c.servo_min, c.servo_max));
|
2017-01-06 21:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-08 20:47:43 -04:00
|
|
|
|
|
|
|
/*
|
2020-01-13 00:45:32 -04:00
|
|
|
upgrade SERVO* parameters. This does the following:
|
2017-01-08 20:47:43 -04:00
|
|
|
|
2020-01-13 00:45:32 -04:00
|
|
|
- update to 16 bit FUNCTION from AP_Int8
|
2017-01-08 20:47:43 -04:00
|
|
|
*/
|
2020-01-13 00:45:32 -04:00
|
|
|
void SRV_Channels::upgrade_parameters(void)
|
2017-01-08 20:47:43 -04:00
|
|
|
{
|
2022-04-25 21:24:59 -03:00
|
|
|
// PARAMETER_CONVERSION - Added: Jan-2020
|
2020-01-13 00:45:32 -04:00
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
|
|
|
SRV_Channel &c = channels[i];
|
|
|
|
// convert from AP_Int8 to AP_Int16
|
|
|
|
c.function.convert_parameter_width(AP_PARAM_INT8);
|
2017-01-10 01:09:42 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-10 01:50:40 -03:00
|
|
|
// set RC output frequency on a function output
|
|
|
|
void SRV_Channels::set_rc_frequency(SRV_Channel::Aux_servo_function_t function, uint16_t frequency_hz)
|
|
|
|
{
|
2021-01-11 22:02:50 -04:00
|
|
|
uint32_t mask = 0;
|
2017-04-10 01:50:40 -03:00
|
|
|
for (uint8_t i=0; i<NUM_SERVO_CHANNELS; i++) {
|
2018-10-11 20:44:00 -03:00
|
|
|
SRV_Channel &c = channels[i];
|
|
|
|
if (c.function == function) {
|
|
|
|
mask |= (1U<<c.ch_num);
|
2017-04-10 01:50:40 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mask != 0) {
|
|
|
|
hal.rcout->set_freq(mask, frequency_hz);
|
|
|
|
}
|
|
|
|
}
|