/* 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 . */ /* * AP_ServoRelayEvents - handle servo and relay MAVLink events */ #include #include #include "AP_ServoRelayEvents.h" #include #include #include extern const AP_HAL::HAL& hal; bool AP_ServoRelayEvents::do_set_servo(uint8_t _channel, uint16_t pwm) { SRV_Channel *c = SRV_Channels::srv_channel(_channel-1); if (c == nullptr) { return false; } switch(c->get_function()) { case SRV_Channel::k_none: case SRV_Channel::k_manual: case SRV_Channel::k_sprayer_pump: case SRV_Channel::k_sprayer_spinner: case SRV_Channel::k_gripper: case SRV_Channel::k_rcin1 ... SRV_Channel::k_rcin16: // rc pass-thru break; default: gcs().send_text(MAV_SEVERITY_INFO, "ServoRelayEvent: Channel %d is already in use", _channel); return false; } if (type == EVENT_TYPE_SERVO && channel == _channel) { // cancel previous repeat repeat = 0; } c->set_output_pwm(pwm); c->ignore_small_rcin_changes(); return true; } bool AP_ServoRelayEvents::do_set_relay(uint8_t relay_num, uint8_t state) { AP_Relay *relay = AP::relay(); if (relay == nullptr) { return false; } if (!relay->enabled(relay_num)) { return false; } if (type == EVENT_TYPE_RELAY && channel == relay_num) { // cancel previous repeat repeat = 0; } if (state == 1) { relay->on(relay_num); } else if (state == 0) { relay->off(relay_num); } else { relay->toggle(relay_num); } return true; } bool AP_ServoRelayEvents::do_repeat_servo(uint8_t _channel, uint16_t _servo_value, int16_t _repeat, uint16_t _delay_ms) { SRV_Channel *c = SRV_Channels::srv_channel(_channel-1); if (c == nullptr) { return false; } switch(c->get_function()) { case SRV_Channel::k_none: case SRV_Channel::k_manual: case SRV_Channel::k_sprayer_pump: case SRV_Channel::k_sprayer_spinner: case SRV_Channel::k_gripper: case SRV_Channel::k_rcin1 ... SRV_Channel::k_rcin16: // rc pass-thru break; default: gcs().send_text(MAV_SEVERITY_INFO, "ServoRelayEvent: Channel %d is already in use", _channel); return false; } channel = _channel; type = EVENT_TYPE_SERVO; start_time_ms = 0; delay_ms = _delay_ms / 2; repeat = _repeat * 2; servo_value = _servo_value; update_events(); return true; } bool AP_ServoRelayEvents::do_repeat_relay(uint8_t relay_num, int16_t _repeat, uint32_t _delay_ms) { AP_Relay *relay = AP::relay(); if (relay == nullptr) { return false; } if (!relay->enabled(relay_num)) { return false; } type = EVENT_TYPE_RELAY; channel = relay_num; start_time_ms = 0; delay_ms = _delay_ms/2; // half cycle time repeat = _repeat*2; // number of full cycles update_events(); return true; } /* update state for MAV_CMD_DO_REPEAT_SERVO and MAV_CMD_DO_REPEAT_RELAY */ void AP_ServoRelayEvents::update_events(void) { if (repeat == 0 || (AP_HAL::millis() - start_time_ms) < delay_ms) { return; } start_time_ms = AP_HAL::millis(); switch (type) { case EVENT_TYPE_SERVO: { SRV_Channel *c = SRV_Channels::srv_channel(channel-1); if (c != nullptr) { if (repeat & 1) { c->set_output_pwm(c->get_trim()); } else { c->set_output_pwm(servo_value); c->ignore_small_rcin_changes(); } } break; } case EVENT_TYPE_RELAY: { AP_Relay *relay = AP::relay(); if (relay != nullptr) { relay->toggle(channel); } break; } } if (repeat > 0) { repeat--; } else { // toggle bottom bit so servos flip in value repeat ^= 1; } } // singleton instance AP_ServoRelayEvents *AP_ServoRelayEvents::_singleton; namespace AP { AP_ServoRelayEvents *servorelayevents() { return AP_ServoRelayEvents::get_singleton(); } }