2017-02-05 22:15:33 -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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* RC_Channels.cpp - class containing an array of RC_Channel objects
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
#include <AP_HAL/AP_HAL.h>
|
|
|
|
extern const AP_HAL::HAL& hal;
|
|
|
|
|
|
|
|
#include <AP_Math/AP_Math.h>
|
2019-05-20 21:41:52 -03:00
|
|
|
#include <AP_Logger/AP_Logger.h>
|
2017-02-05 22:15:33 -04:00
|
|
|
|
|
|
|
#include "RC_Channel.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
channels group object constructor
|
|
|
|
*/
|
|
|
|
RC_Channels::RC_Channels(void)
|
|
|
|
{
|
|
|
|
// set defaults from the parameter table
|
|
|
|
AP_Param::setup_object_defaults(this, var_info);
|
|
|
|
|
2018-04-13 23:22:14 -03:00
|
|
|
if (_singleton != nullptr) {
|
|
|
|
AP_HAL::panic("RC_Channels must be singleton");
|
2017-02-05 22:15:33 -04:00
|
|
|
}
|
2018-04-13 23:22:14 -03:00
|
|
|
_singleton = this;
|
2017-02-05 22:15:33 -04:00
|
|
|
}
|
|
|
|
|
2018-04-13 23:22:14 -03:00
|
|
|
void RC_Channels::init(void)
|
2018-04-03 23:16:36 -03:00
|
|
|
{
|
2018-04-13 23:22:14 -03:00
|
|
|
// setup ch_in on channels
|
|
|
|
for (uint8_t i=0; i<NUM_RC_CHANNELS; i++) {
|
|
|
|
channel(i)->ch_in = i;
|
2018-04-03 23:16:36 -03:00
|
|
|
}
|
2018-04-13 23:22:14 -03:00
|
|
|
|
|
|
|
init_aux_all();
|
2018-04-03 23:16:36 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t RC_Channels::get_radio_in(uint16_t *chans, const uint8_t num_channels)
|
|
|
|
{
|
2018-08-06 18:52:19 -03:00
|
|
|
memset(chans, 0, num_channels*sizeof(*chans));
|
|
|
|
|
2018-04-13 23:22:14 -03:00
|
|
|
const uint8_t read_channels = MIN(num_channels, NUM_RC_CHANNELS);
|
2018-04-03 23:16:36 -03:00
|
|
|
for (uint8_t i = 0; i < read_channels; i++) {
|
2018-04-13 23:22:14 -03:00
|
|
|
chans[i] = channel(i)->get_radio_in();
|
2018-04-03 23:16:36 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
return read_channels;
|
|
|
|
}
|
|
|
|
|
2018-07-24 22:50:01 -03:00
|
|
|
// update all the input channels
|
2018-04-13 23:22:14 -03:00
|
|
|
bool RC_Channels::read_input(void)
|
2017-02-05 22:15:33 -04:00
|
|
|
{
|
2020-05-18 19:37:55 -03:00
|
|
|
if (hal.rcin->new_input()) {
|
|
|
|
_has_had_rc_receiver = true;
|
|
|
|
} else if (!has_new_overrides) {
|
2018-04-24 01:20:02 -03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-04-25 23:06:19 -03:00
|
|
|
has_new_overrides = false;
|
|
|
|
|
2020-03-30 23:08:24 -03:00
|
|
|
last_update_ms = AP_HAL::millis();
|
|
|
|
|
2018-07-24 22:50:01 -03:00
|
|
|
bool success = false;
|
2017-02-05 22:15:33 -04:00
|
|
|
for (uint8_t i=0; i<NUM_RC_CHANNELS; i++) {
|
2018-04-13 23:22:14 -03:00
|
|
|
success |= channel(i)->update();
|
2017-02-05 22:15:33 -04:00
|
|
|
}
|
2018-04-24 01:20:02 -03:00
|
|
|
|
2018-07-24 22:50:01 -03:00
|
|
|
return success;
|
2017-02-05 22:15:33 -04:00
|
|
|
}
|
2018-04-03 23:16:36 -03:00
|
|
|
|
|
|
|
uint8_t RC_Channels::get_valid_channel_count(void)
|
|
|
|
{
|
|
|
|
return MIN(NUM_RC_CHANNELS, hal.rcin->num_channels());
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t RC_Channels::get_receiver_rssi(void)
|
|
|
|
{
|
|
|
|
return hal.rcin->get_rssi();
|
|
|
|
}
|
2021-07-13 13:45:08 -03:00
|
|
|
int16_t RC_Channels::get_receiver_link_quality(void)
|
|
|
|
{
|
|
|
|
return hal.rcin->get_rx_link_quality();
|
|
|
|
}
|
2018-04-03 23:16:36 -03:00
|
|
|
void RC_Channels::clear_overrides(void)
|
|
|
|
{
|
2018-08-02 08:41:07 -03:00
|
|
|
RC_Channels &_rc = rc();
|
2018-04-25 23:06:19 -03:00
|
|
|
for (uint8_t i = 0; i < NUM_RC_CHANNELS; i++) {
|
2018-08-02 08:41:07 -03:00
|
|
|
_rc.channel(i)->clear_override();
|
2018-04-25 23:06:19 -03:00
|
|
|
}
|
|
|
|
// we really should set has_new_overrides to true, and rerun read_input from
|
|
|
|
// the vehicle code however doing so currently breaks the failsafe system on
|
|
|
|
// copter and plane, RC_Channels needs to control failsafes to resolve this
|
2018-04-03 23:16:36 -03:00
|
|
|
}
|
|
|
|
|
2021-05-15 00:45:43 -03:00
|
|
|
uint16_t RC_Channels::get_override_mask(void)
|
|
|
|
{
|
|
|
|
uint16_t ret = 0;
|
|
|
|
RC_Channels &_rc = rc();
|
|
|
|
for (uint8_t i = 0; i < NUM_RC_CHANNELS; i++) {
|
|
|
|
if (_rc.channel(i)->has_override()) {
|
|
|
|
ret |= (1U << i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-04-25 23:06:19 -03:00
|
|
|
void RC_Channels::set_override(const uint8_t chan, const int16_t value, const uint32_t timestamp_ms)
|
2018-04-03 23:16:36 -03:00
|
|
|
{
|
2018-08-02 08:41:07 -03:00
|
|
|
RC_Channels &_rc = rc();
|
2018-04-03 23:16:36 -03:00
|
|
|
if (chan < NUM_RC_CHANNELS) {
|
2018-08-02 08:41:07 -03:00
|
|
|
_rc.channel(chan)->set_override(value, timestamp_ms);
|
2018-04-03 23:16:36 -03:00
|
|
|
}
|
2018-04-25 23:06:19 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RC_Channels::has_active_overrides()
|
|
|
|
{
|
2018-08-02 08:41:07 -03:00
|
|
|
RC_Channels &_rc = rc();
|
2018-04-25 23:06:19 -03:00
|
|
|
for (uint8_t i = 0; i < NUM_RC_CHANNELS; i++) {
|
2018-08-02 08:41:07 -03:00
|
|
|
if (_rc.channel(i)->has_override()) {
|
2018-04-25 23:06:19 -03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-03 23:16:36 -03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RC_Channels::receiver_bind(const int dsmMode)
|
|
|
|
{
|
|
|
|
return hal.rcin->rc_bind(dsmMode);
|
|
|
|
}
|
2018-04-13 23:22:14 -03:00
|
|
|
|
|
|
|
|
|
|
|
// support for auxillary switches:
|
|
|
|
// read_aux_switches - checks aux switch positions and invokes configured actions
|
|
|
|
void RC_Channels::read_aux_all()
|
|
|
|
{
|
2018-07-31 21:10:33 -03:00
|
|
|
if (!has_valid_input()) {
|
|
|
|
// exit immediately when no RC input
|
2018-04-13 23:22:14 -03:00
|
|
|
return;
|
|
|
|
}
|
2019-05-20 21:41:52 -03:00
|
|
|
bool need_log = false;
|
2018-04-13 23:22:14 -03:00
|
|
|
|
|
|
|
for (uint8_t i=0; i<NUM_RC_CHANNELS; i++) {
|
|
|
|
RC_Channel *c = channel(i);
|
|
|
|
if (c == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
2019-05-20 21:41:52 -03:00
|
|
|
need_log |= c->read_aux();
|
|
|
|
}
|
|
|
|
if (need_log) {
|
|
|
|
// guarantee that we log when a switch changes
|
|
|
|
AP::logger().Write_RCIN();
|
2018-04-13 23:22:14 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RC_Channels::init_aux_all()
|
|
|
|
{
|
|
|
|
for (uint8_t i=0; i<NUM_RC_CHANNELS; i++) {
|
|
|
|
RC_Channel *c = channel(i);
|
|
|
|
if (c == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
c->init_aux();
|
|
|
|
}
|
|
|
|
reset_mode_switch();
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Support for mode switches
|
|
|
|
//
|
2021-06-22 01:13:51 -03:00
|
|
|
RC_Channel *RC_Channels::flight_mode_channel() const
|
2018-04-13 23:22:14 -03:00
|
|
|
{
|
|
|
|
const int8_t num = flight_mode_channel_number();
|
|
|
|
if (num <= 0) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (num >= NUM_RC_CHANNELS) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-06-22 01:13:51 -03:00
|
|
|
return rc_channel(num-1);
|
2018-04-13 23:22:14 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
void RC_Channels::reset_mode_switch()
|
|
|
|
{
|
|
|
|
RC_Channel *c = flight_mode_channel();
|
|
|
|
if (c == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
c->reset_mode_switch();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RC_Channels::read_mode_switch()
|
|
|
|
{
|
2018-07-31 21:10:33 -03:00
|
|
|
if (!has_valid_input()) {
|
|
|
|
// exit immediately when no RC input
|
2018-04-13 23:22:14 -03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
RC_Channel *c = flight_mode_channel();
|
|
|
|
if (c == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
c->read_mode_switch();
|
|
|
|
}
|
|
|
|
|
2021-06-16 22:13:54 -03:00
|
|
|
// check if flight mode channel is assigned RC option
|
|
|
|
// return true if assigned
|
2021-06-22 01:13:51 -03:00
|
|
|
bool RC_Channels::flight_mode_channel_conflicts_with_rc_option() const
|
2021-06-16 22:13:54 -03:00
|
|
|
{
|
|
|
|
RC_Channel *chan = flight_mode_channel();
|
|
|
|
if (chan == nullptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return (RC_Channel::aux_func_t)chan->option.get() != RC_Channel::AUX_FUNC::DO_NOTHING;
|
|
|
|
}
|
|
|
|
|
2019-12-03 22:08:33 -04:00
|
|
|
/*
|
|
|
|
get the RC input PWM value given a channel number. Note that
|
|
|
|
channel numbers start at 1, as this API is designed for use in
|
|
|
|
LUA
|
|
|
|
*/
|
|
|
|
bool RC_Channels::get_pwm(uint8_t c, uint16_t &pwm) const
|
|
|
|
{
|
2019-12-19 02:36:44 -04:00
|
|
|
RC_Channel *chan = rc_channel(c-1);
|
|
|
|
if (chan == nullptr) {
|
2019-12-03 22:08:33 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int16_t pwm_signed = chan->get_radio_in();
|
|
|
|
if (pwm_signed < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pwm = (uint16_t)pwm_signed;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-08-12 23:28:28 -03:00
|
|
|
// return mask of enabled protocols.
|
|
|
|
uint32_t RC_Channels::enabled_protocols() const
|
|
|
|
{
|
|
|
|
if (_singleton == nullptr) {
|
|
|
|
// for example firmware
|
|
|
|
return 1U;
|
|
|
|
}
|
|
|
|
return uint32_t(_protocols.get());
|
|
|
|
}
|
2018-04-13 23:22:14 -03:00
|
|
|
|
|
|
|
// singleton instance
|
|
|
|
RC_Channels *RC_Channels::_singleton;
|
|
|
|
|
|
|
|
|
|
|
|
RC_Channels &rc()
|
|
|
|
{
|
|
|
|
return *RC_Channels::get_singleton();
|
|
|
|
}
|