#include "GCS_config.h" #if HAL_GCS_ENABLED #include "GCS.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MissionItemProtocol_Waypoints.h" #include "MissionItemProtocol_Rally.h" #include "MissionItemProtocol_Fence.h" extern const AP_HAL::HAL& hal; void GCS::get_sensor_status_flags(uint32_t &present, uint32_t &enabled, uint32_t &health) { // if this assert fails then fix it and the comment in GCS.h where // _statustext_queue is declared #if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS ASSERT_STORAGE_SIZE(GCS::statustext_t, 58); #endif update_sensor_status_flags(); present = control_sensors_present; enabled = control_sensors_enabled; health = control_sensors_health; } MissionItemProtocol *GCS::missionitemprotocols[3]; void GCS::init() { mavlink_system.sysid = sysid_this_mav(); } /* * returns a mask of channels that statustexts should be sent to */ uint8_t GCS::statustext_send_channel_mask() const { uint8_t ret = 0; ret |= GCS_MAVLINK::active_channel_mask(); ret |= GCS_MAVLINK::streaming_channel_mask(); ret &= ~GCS_MAVLINK::private_channel_mask(); return ret; } /* send a text message to all GCS */ void GCS::send_textv(MAV_SEVERITY severity, const char *fmt, va_list arg_list) { uint8_t mask = statustext_send_channel_mask(); if (!update_send_has_been_called) { // we have not yet initialised the streaming-channel-mask, // which is done as part of the update() call. So just send // it to all channels: mask = (1<<_num_gcs)-1; } send_textv(severity, fmt, arg_list, mask); } void GCS::send_text(MAV_SEVERITY severity, const char *fmt, ...) { va_list arg_list; va_start(arg_list, fmt); send_textv(severity, fmt, arg_list); va_end(arg_list); } void GCS::send_to_active_channels(uint32_t msgid, const char *pkt) { const mavlink_msg_entry_t *entry = mavlink_get_msg_entry(msgid); if (entry == nullptr) { return; } for (uint8_t i=0; ialternative.handler && handler) { // already have one installed - we may need to add support for // multiple alternative handlers return false; } link->alternative.handler = handler; return true; } void GCS::update_sensor_status_flags() { control_sensors_present = 0; control_sensors_enabled = 0; control_sensors_health = 0; #if AP_INERTIALSENSOR_ENABLED const AP_InertialSensor &ins = AP::ins(); #endif #if AP_AHRS_ENABLED && AP_INERTIALSENSOR_ENABLED AP_AHRS &ahrs = AP::ahrs(); control_sensors_present |= MAV_SYS_STATUS_AHRS; if (ahrs.initialised()) { control_sensors_enabled |= MAV_SYS_STATUS_AHRS; if (ahrs.healthy()) { if (!ahrs.have_inertial_nav() || ins.accel_calibrated_ok_all()) { control_sensors_health |= MAV_SYS_STATUS_AHRS; } } } #endif #if AP_COMPASS_ENABLED const Compass &compass = AP::compass(); if (AP::compass().available()) { control_sensors_present |= MAV_SYS_STATUS_SENSOR_3D_MAG; control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_3D_MAG; } if (compass.available() && compass.healthy()) { control_sensors_health |= MAV_SYS_STATUS_SENSOR_3D_MAG; } #endif #if AP_BARO_ENABLED const AP_Baro &barometer = AP::baro(); if (barometer.num_instances() > 0) { control_sensors_present |= MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE; control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE; if (barometer.all_healthy()) { control_sensors_health |= MAV_SYS_STATUS_SENSOR_ABSOLUTE_PRESSURE; } } #endif #if AP_GPS_ENABLED const AP_GPS &gps = AP::gps(); if (gps.status() > AP_GPS::NO_GPS) { control_sensors_present |= MAV_SYS_STATUS_SENSOR_GPS; control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_GPS; } if (gps.is_healthy() && gps.status() >= min_status_for_gps_healthy()) { control_sensors_health |= MAV_SYS_STATUS_SENSOR_GPS; } #endif #if AP_BATTERY_ENABLED const AP_BattMonitor &battery = AP::battery(); control_sensors_present |= MAV_SYS_STATUS_SENSOR_BATTERY; if (battery.num_instances() > 0) { control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_BATTERY; } if (battery.healthy() && !battery.has_failsafed()) { control_sensors_health |= MAV_SYS_STATUS_SENSOR_BATTERY; } #endif #if AP_INERTIALSENSOR_ENABLED control_sensors_present |= MAV_SYS_STATUS_SENSOR_3D_GYRO; control_sensors_present |= MAV_SYS_STATUS_SENSOR_3D_ACCEL; if (!ins.calibrating()) { control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_3D_ACCEL; control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_3D_GYRO; if (ins.get_accel_health_all()) { control_sensors_health |= MAV_SYS_STATUS_SENSOR_3D_ACCEL; } if (ins.get_gyro_health_all() && ins.gyro_calibrated_ok_all()) { control_sensors_health |= MAV_SYS_STATUS_SENSOR_3D_GYRO; } } #endif #if HAL_LOGGING_ENABLED const AP_Logger &logger = AP::logger(); bool logging_present = logger.logging_present(); bool logging_enabled = logger.logging_enabled(); bool logging_healthy = !logger.logging_failed(); #if AP_GPS_ENABLED // some GPS units do logging, so they have to be healthy too: logging_present |= gps.logging_present(); logging_enabled |= gps.logging_enabled(); logging_healthy &= !gps.logging_failed(); #endif if (logging_present) { control_sensors_present |= MAV_SYS_STATUS_LOGGING; } if (logging_enabled) { control_sensors_enabled |= MAV_SYS_STATUS_LOGGING; } if (logging_healthy) { control_sensors_health |= MAV_SYS_STATUS_LOGGING; } #endif // HAL_LOGGING_ENABLED // set motors outputs as enabled if safety switch is not disarmed (i.e. either NONE or ARMED) #if !defined(HAL_BUILD_AP_PERIPH) control_sensors_present |= MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS; if (hal.util->safety_switch_state() != AP_HAL::Util::SAFETY_DISARMED) { control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS; } control_sensors_health |= MAV_SYS_STATUS_SENSOR_MOTOR_OUTPUTS; #endif #if CONFIG_HAL_BOARD == HAL_BOARD_SITL && AP_AHRS_ENABLED if (ahrs.get_ekf_type() == 10) { // always show EKF type 10 as healthy. This prevents spurious error // messages in xplane and other simulators that use EKF type 10 control_sensors_health |= MAV_SYS_STATUS_AHRS | MAV_SYS_STATUS_SENSOR_GPS | MAV_SYS_STATUS_SENSOR_3D_ACCEL | MAV_SYS_STATUS_SENSOR_3D_GYRO; } #endif #if AP_FENCE_ENABLED const AC_Fence *fence = AP::fence(); if (fence != nullptr) { if (fence->sys_status_enabled()) { control_sensors_enabled |= MAV_SYS_STATUS_GEOFENCE; } if (fence->sys_status_present()) { control_sensors_present |= MAV_SYS_STATUS_GEOFENCE; } if (!fence->sys_status_failed()) { control_sensors_health |= MAV_SYS_STATUS_GEOFENCE; } } #endif // airspeed #if AP_AIRSPEED_ENABLED const AP_Airspeed *airspeed = AP_Airspeed::get_singleton(); if (airspeed && airspeed->enabled()) { control_sensors_present |= MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE; const bool use = airspeed->use(); #if AP_AHRS_ENABLED const bool enabled = AP::ahrs().airspeed_sensor_enabled(); #else const AP_Airspeed *_airspeed = AP::airspeed(); const bool enabled = (_airspeed != nullptr && _airspeed->use()); #endif if (use) { control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE; } if (airspeed->all_healthy() && (!use || enabled)) { control_sensors_health |= MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE; } } #endif #if AP_OPTICALFLOW_ENABLED const AP_OpticalFlow *optflow = AP::opticalflow(); if (optflow && optflow->enabled()) { control_sensors_present |= MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW; control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW; } if (optflow && optflow->healthy()) { control_sensors_health |= MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW; } #endif #if HAL_VISUALODOM_ENABLED const AP_VisualOdom *visual_odom = AP::visualodom(); if (visual_odom && visual_odom->enabled()) { control_sensors_present |= MAV_SYS_STATUS_SENSOR_VISION_POSITION; control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_VISION_POSITION; if (visual_odom->healthy()) { control_sensors_health |= MAV_SYS_STATUS_SENSOR_VISION_POSITION; } } #endif // give GCS status of prearm checks. This is enabled if any arming checks are enabled. // it is healthy if armed or checks are passing #if AP_ARMING_ENABLED control_sensors_present |= MAV_SYS_STATUS_PREARM_CHECK; if (AP::arming().get_enabled_checks()) { control_sensors_enabled |= MAV_SYS_STATUS_PREARM_CHECK; if (hal.util->get_soft_armed() || AP_Notify::flags.pre_arm_check) { control_sensors_health |= MAV_SYS_STATUS_PREARM_CHECK; } } #endif #if AP_RC_CHANNEL_ENABLED if (rc().has_ever_seen_rc_input()) { control_sensors_present |= MAV_SYS_STATUS_SENSOR_RC_RECEIVER; control_sensors_enabled |= MAV_SYS_STATUS_SENSOR_RC_RECEIVER; if (!rc().in_rc_failsafe()) { // should this be has_valid_input? control_sensors_health |= MAV_SYS_STATUS_SENSOR_RC_RECEIVER; } } #endif update_vehicle_sensor_status_flags(); } bool GCS::out_of_time() const { #if defined(HAL_BUILD_AP_PERIPH) // we are never out of time for AP_Periph // as we don't have concept of AP_Scheduler in AP_Periph return false; #endif // while we are in the delay callback we are never out of time: if (hal.scheduler->in_delay_callback()) { return false; } // we always want to be able to send messages out while in the error loop: if (AP_BoardConfig::in_config_error()) { return false; } #if AP_SCHEDULER_ENABLED if (min_loop_time_remaining_for_message_send_us() <= AP::scheduler().time_available_usec()) { return false; } #endif return true; } void gcs_out_of_space_to_send(mavlink_channel_t chan) { GCS_MAVLINK *link = gcs().chan(chan); if (link == nullptr) { return; } link->out_of_space_to_send(); } /* check there is enough space for a message */ bool GCS_MAVLINK::check_payload_size(uint16_t max_payload_len) { if (txspace() < unsigned(packet_overhead()+max_payload_len)) { gcs_out_of_space_to_send(chan); return false; } return true; } #if AP_SCRIPTING_ENABLED /* lua access to command_int Note that this is called with the AP_Scheduler lock, ensuring the main thread does not race with a lua command_int */ MAV_RESULT GCS::lua_command_int_packet(const mavlink_command_int_t &packet) { // for now we assume channel 0. In the future we may create a dedicated channel auto *ch = chan(0); if (ch == nullptr) { return MAV_RESULT_UNSUPPORTED; } // we need a dummy message for some calls mavlink_message_t msg {}; return ch->handle_command_int_packet(packet, msg); } #endif // AP_SCRIPTING_ENABLED #endif // HAL_GCS_ENABLED