Path: blob/master/libraries/AP_DroneCAN/AP_DroneCAN.h
9914 views
/*1* This file is free software: you can redistribute it and/or modify it2* under the terms of the GNU General Public License as published by the3* Free Software Foundation, either version 3 of the License, or4* (at your option) any later version.5*6* This file is distributed in the hope that it will be useful, but7* WITHOUT ANY WARRANTY; without even the implied warranty of8* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.9* See the GNU General Public License for more details.10*11* You should have received a copy of the GNU General Public License along12* with this program. If not, see <http://www.gnu.org/licenses/>.13*14* Author: Eugene Shamaev, Siddharth Bharat Purohit15*/16#pragma once1718#include <AP_HAL/AP_HAL.h>1920#if HAL_ENABLE_DRONECAN_DRIVERS2122#include "AP_Canard_iface.h"23#include <AP_CANManager/AP_CANManager.h>24#include <AP_HAL/Semaphores.h>25#include <AP_Param/AP_Param.h>26#include <AP_ESC_Telem/AP_ESC_Telem_Backend.h>27#include <SRV_Channel/SRV_Channel_config.h>28#include <canard/publisher.h>29#include <canard/subscriber.h>30#include <canard/service_client.h>31#include <canard/service_server.h>32#include <stdio.h>33#include "AP_DroneCAN_DNA_Server.h"34#include <canard.h>35#include <dronecan_msgs.h>36#include <AP_SerialManager/AP_SerialManager_config.h>37#include <AP_Relay/AP_Relay_config.h>38#include <AP_Servo_Telem/AP_Servo_Telem_config.h>39#include <AP_Mount/AP_Mount_config.h>4041#ifndef DRONECAN_SRV_NUMBER42#define DRONECAN_SRV_NUMBER NUM_SERVO_CHANNELS43#endif4445#ifndef AP_DRONECAN_SEND_GPS46#define AP_DRONECAN_SEND_GPS (HAL_PROGRAM_SIZE_LIMIT_KB > 1024)47#endif4849#define AP_DRONECAN_SW_VERS_MAJOR 150#define AP_DRONECAN_SW_VERS_MINOR 05152#define AP_DRONECAN_HW_VERS_MAJOR 153#define AP_DRONECAN_HW_VERS_MINOR 0545556#ifndef AP_DRONECAN_HOBBYWING_ESC_SUPPORT57#define AP_DRONECAN_HOBBYWING_ESC_SUPPORT (HAL_PROGRAM_SIZE_LIMIT_KB>1024)58#endif5960#ifndef AP_DRONECAN_HIMARK_SERVO_SUPPORT61#define AP_DRONECAN_HIMARK_SERVO_SUPPORT (HAL_PROGRAM_SIZE_LIMIT_KB>1024)62#endif6364#ifndef AP_DRONECAN_SERIAL_ENABLED65#define AP_DRONECAN_SERIAL_ENABLED AP_SERIALMANAGER_REGISTER_ENABLED && (HAL_PROGRAM_SIZE_LIMIT_KB>1024)66#endif6768#ifndef AP_DRONECAN_VOLZ_FEEDBACK_ENABLED69#define AP_DRONECAN_VOLZ_FEEDBACK_ENABLED 070#endif7172#if AP_DRONECAN_SERIAL_ENABLED73#include "AP_DroneCAN_serial.h"74#endif7576// fwd-declare callback classes77class AP_DroneCAN_DNA_Server;78class CANSensor;7980class AP_DroneCAN : public AP_CANDriver, public AP_ESC_Telem_Backend {81friend class AP_DroneCAN_DNA_Server;82public:83AP_DroneCAN(const int driver_index);84~AP_DroneCAN();8586static const struct AP_Param::GroupInfo var_info[];8788// Return uavcan from @driver_index or nullptr if it's not ready or doesn't exist89static AP_DroneCAN *get_dronecan(uint8_t driver_index);90bool prearm_check(char* fail_msg, uint8_t fail_msg_len) const;9192__INITFUNC__ void init(uint8_t driver_index) override;93bool add_interface(AP_HAL::CANIface* can_iface) override;9495// add an 11 bit auxillary driver96bool add_11bit_driver(CANSensor *sensor) override;9798// handler for outgoing frames for auxillary drivers99bool write_aux_frame(AP_HAL::CANFrame &out_frame, const uint32_t timeout_us) override;100101uint8_t get_driver_index() const { return _driver_index; }102103// define string with length structure104struct string { uint8_t len; uint8_t data[128]; };105106FUNCTOR_TYPEDEF(ParamGetSetIntCb, bool, AP_DroneCAN*, const uint8_t, const char*, int32_t &);107FUNCTOR_TYPEDEF(ParamGetSetFloatCb, bool, AP_DroneCAN*, const uint8_t, const char*, float &);108FUNCTOR_TYPEDEF(ParamGetSetStringCb, bool, AP_DroneCAN*, const uint8_t, const char*, string &);109FUNCTOR_TYPEDEF(ParamSaveCb, void, AP_DroneCAN*, const uint8_t, bool);110111void send_node_status();112113///// SRV output /////114void SRV_push_servos(void);115116///// LED /////117bool led_write(uint8_t led_index, uint8_t red, uint8_t green, uint8_t blue);118119// buzzer120void set_buzzer_tone(float frequency, float duration_s);121122// Send Reboot command123// Note: Do not call this from outside UAVCAN thread context,124// you can call this from dronecan callbacks and handlers.125// THIS IS NOT A THREAD SAFE API!126void send_reboot_request(uint8_t node_id);127128// get or set param value129// returns true on success, false on failure130// failures occur when waiting on node to respond to previous get or set request131bool set_parameter_on_node(uint8_t node_id, const char *name, float value, ParamGetSetFloatCb *cb);132bool set_parameter_on_node(uint8_t node_id, const char *name, int32_t value, ParamGetSetIntCb *cb);133bool set_parameter_on_node(uint8_t node_id, const char *name, const string &value, ParamGetSetStringCb *cb);134bool get_parameter_on_node(uint8_t node_id, const char *name, ParamGetSetFloatCb *cb);135bool get_parameter_on_node(uint8_t node_id, const char *name, ParamGetSetIntCb *cb);136bool get_parameter_on_node(uint8_t node_id, const char *name, ParamGetSetStringCb *cb);137138// Save parameters139bool save_parameters_on_node(uint8_t node_id, ParamSaveCb *cb);140141// options bitmask142enum class Options : uint16_t {143DNA_CLEAR_DATABASE = (1U<<0),144DNA_IGNORE_DUPLICATE_NODE = (1U<<1),145CANFD_ENABLED = (1U<<2),146DNA_IGNORE_UNHEALTHY_NODE = (1U<<3),147USE_ACTUATOR_PWM = (1U<<4),148SEND_GNSS = (1U<<5),149USE_HIMARK_SERVO = (1U<<6),150USE_HOBBYWING_ESC = (1U<<7),151ENABLE_STATS = (1U<<8),152ENABLE_FLEX_DEBUG = (1U<<9),153ALLOW_EXTENDED_AUX = (1U<<10),154};155156// check if a option is set157bool option_is_set(Options option) const {158return (uint16_t(_options.get()) & uint16_t(option)) != 0;159}160161// check if a option is set and if it is then reset it to162// 0. return true if it was set163bool check_and_reset_option(Options option);164165CanardInterface& get_canard_iface() { return canard_iface; }166167Canard::Publisher<uavcan_equipment_indication_LightsCommand> rgb_led{canard_iface};168Canard::Publisher<uavcan_equipment_indication_BeepCommand> buzzer{canard_iface};169Canard::Publisher<uavcan_equipment_gnss_RTCMStream> rtcm_stream{canard_iface};170171#if HAL_MOUNT_XACTI_ENABLED172// xacti specific publishers173Canard::Publisher<com_xacti_CopterAttStatus> xacti_copter_att_status{canard_iface};174Canard::Publisher<com_xacti_GimbalControlData> xacti_gimbal_control_data{canard_iface};175Canard::Publisher<com_xacti_GnssStatus> xacti_gnss_status{canard_iface};176#endif // HAL_MOUNT_XACTI_ENABLED177178#if AP_RELAY_DRONECAN_ENABLED179// Hardpoint for relay180// Needs to be public so relay can edge trigger as well as streaming181Canard::Publisher<uavcan_equipment_hardpoint_Command> relay_hardpoint{canard_iface};182#endif183184#if AP_SCRIPTING_ENABLED185bool get_FlexDebug(uint8_t node_id, uint16_t msg_id, uint32_t ×tamp_us, dronecan_protocol_FlexDebug &msg) const;186#endif187188private:189void loop(void);190191///// SRV output /////192void SRV_send_actuator();193void SRV_send_esc();194#if AP_DRONECAN_HIMARK_SERVO_SUPPORT195void SRV_send_himark();196#endif197198//scale servo output appropriately before sending199int16_t scale_esc_output(uint8_t idx);200201// SafetyState202void safety_state_send();203204// send notify vehicle state205void notify_state_send();206207// check for parameter get/set response timeout208void check_parameter_callback_timeout();209210// send queued parameter get/set request. called from loop211void send_parameter_request();212213// send queued parameter save request. called from loop214void send_parameter_save_request();215216// periodic logging217void logging();218219// get parameter on a node220ParamGetSetIntCb *param_int_cb; // latest get param request callback function (for integers)221ParamGetSetFloatCb *param_float_cb; // latest get param request callback function (for floats)222ParamGetSetStringCb *param_string_cb; // latest get param request callback function (for strings)223bool param_request_sent = true; // true after a param request has been sent, false when queued to be sent224uint32_t param_request_sent_ms; // system time that get param request was sent225HAL_Semaphore _param_sem; // semaphore protecting this block of variables226uint8_t param_request_node_id; // node id of most recent get param request227228// save parameters on a node229ParamSaveCb *save_param_cb; // latest save param request callback function230bool param_save_request_sent = true; // true after a save param request has been sent, false when queued to be sent231HAL_Semaphore _param_save_sem; // semaphore protecting this block of variables232uint8_t param_save_request_node_id; // node id of most recent save param request233234// UAVCAN parameters235AP_Int8 _dronecan_node;236AP_Int32 _servo_bm;237AP_Int32 _esc_bm;238AP_Int8 _esc_offset;239AP_Int16 _servo_rate_hz;240AP_Int16 _options;241AP_Int16 _notify_state_hz;242AP_Int16 _pool_size;243AP_Int32 _esc_rv;244245uint32_t *mem_pool;246247uint8_t _driver_index;248249CanardInterface canard_iface;250251AP_DroneCAN_DNA_Server _dna_server;252253char _thread_name[13];254bool _initialized;255///// SRV output /////256struct {257uint16_t pulse;258bool esc_pending;259bool servo_pending;260} _SRV_conf[DRONECAN_SRV_NUMBER];261262uint32_t _esc_send_count;263uint32_t _srv_send_count;264uint32_t _fail_send_count;265266uint32_t _SRV_armed_mask; // mask of servo outputs that are active267uint32_t _ESC_armed_mask; // mask of ESC outputs that are active268uint32_t _SRV_last_send_us;269HAL_Semaphore SRV_sem;270271// last log time272uint32_t last_log_ms;273274#if AP_DRONECAN_SEND_GPS275// send GNSS Fix and yaw, same thing AP_GPS_DroneCAN would receive276void gnss_send_fix();277void gnss_send_yaw();278279// GNSS Fix and Status280struct {281uint32_t last_gps_lib_fix_ms;282uint32_t last_send_status_ms;283uint32_t last_lib_yaw_time_ms;284} _gnss;285#endif286287// node status send288uint32_t _node_status_last_send_ms;289290// safety status send state291uint32_t _last_safety_state_ms;292293// notify vehicle state294uint32_t _last_notify_state_ms;295uavcan_protocol_NodeStatus node_status_msg;296297#if AP_RELAY_DRONECAN_ENABLED298void relay_hardpoint_send();299struct {300AP_Int16 rate_hz;301uint32_t last_send_ms;302uint8_t last_index;303} _relay;304#endif305306#if AP_DRONECAN_SERIAL_ENABLED307AP_DroneCAN_Serial serial;308#endif309310Canard::Publisher<uavcan_protocol_NodeStatus> node_status{canard_iface};311Canard::Publisher<dronecan_protocol_CanStats> can_stats{canard_iface};312Canard::Publisher<dronecan_protocol_Stats> protocol_stats{canard_iface};313Canard::Publisher<uavcan_equipment_actuator_ArrayCommand> act_out_array{canard_iface};314Canard::Publisher<uavcan_equipment_esc_RawCommand> esc_raw{canard_iface};315Canard::Publisher<ardupilot_indication_SafetyState> safety_state{canard_iface};316Canard::Publisher<uavcan_equipment_safety_ArmingStatus> arming_status{canard_iface};317Canard::Publisher<ardupilot_indication_NotifyState> notify_state{canard_iface};318319#if AP_DRONECAN_HIMARK_SERVO_SUPPORT320Canard::Publisher<com_himark_servo_ServoCmd> himark_out{canard_iface};321#endif322323#if AP_DRONECAN_SEND_GPS324Canard::Publisher<uavcan_equipment_gnss_Fix2> gnss_fix2{canard_iface};325Canard::Publisher<uavcan_equipment_gnss_Auxiliary> gnss_auxiliary{canard_iface};326Canard::Publisher<ardupilot_gnss_Heading> gnss_heading{canard_iface};327Canard::Publisher<ardupilot_gnss_Status> gnss_status{canard_iface};328#endif329// incoming messages330Canard::ObjCallback<AP_DroneCAN, ardupilot_indication_Button> safety_button_cb{this, &AP_DroneCAN::handle_button};331Canard::Subscriber<ardupilot_indication_Button> safety_button_listener{safety_button_cb, _driver_index};332333Canard::ObjCallback<AP_DroneCAN, ardupilot_equipment_trafficmonitor_TrafficReport> traffic_report_cb{this, &AP_DroneCAN::handle_traffic_report};334Canard::Subscriber<ardupilot_equipment_trafficmonitor_TrafficReport> traffic_report_listener{traffic_report_cb, _driver_index};335336#if AP_SERVO_TELEM_ENABLED337Canard::ObjCallback<AP_DroneCAN, uavcan_equipment_actuator_Status> actuator_status_cb{this, &AP_DroneCAN::handle_actuator_status};338Canard::Subscriber<uavcan_equipment_actuator_Status> actuator_status_listener{actuator_status_cb, _driver_index};339#endif340341Canard::ObjCallback<AP_DroneCAN, uavcan_equipment_esc_Status> esc_status_cb{this, &AP_DroneCAN::handle_ESC_status};342Canard::Subscriber<uavcan_equipment_esc_Status> esc_status_listener{esc_status_cb, _driver_index};343344#if AP_EXTENDED_ESC_TELEM_ENABLED345Canard::ObjCallback<AP_DroneCAN, uavcan_equipment_esc_StatusExtended> esc_status_extended_cb{this, &AP_DroneCAN::handle_esc_ext_status};346Canard::Subscriber<uavcan_equipment_esc_StatusExtended> esc_status_extended_listener{esc_status_extended_cb, _driver_index};347#endif348349Canard::ObjCallback<AP_DroneCAN, uavcan_protocol_debug_LogMessage> debug_cb{this, &AP_DroneCAN::handle_debug};350Canard::Subscriber<uavcan_protocol_debug_LogMessage> debug_listener{debug_cb, _driver_index};351352#if AP_DRONECAN_HIMARK_SERVO_SUPPORT && AP_SERVO_TELEM_ENABLED353Canard::ObjCallback<AP_DroneCAN, com_himark_servo_ServoInfo> himark_servo_ServoInfo_cb{this, &AP_DroneCAN::handle_himark_servoinfo};354Canard::Subscriber<com_himark_servo_ServoInfo> himark_servo_ServoInfo_cb_listener{himark_servo_ServoInfo_cb, _driver_index};355#endif356#if AP_DRONECAN_VOLZ_FEEDBACK_ENABLED357Canard::ObjCallback<AP_DroneCAN, com_volz_servo_ActuatorStatus> volz_servo_ActuatorStatus_cb{this, &AP_DroneCAN::handle_actuator_status_Volz};358Canard::Subscriber<com_volz_servo_ActuatorStatus> volz_servo_ActuatorStatus_listener{volz_servo_ActuatorStatus_cb, _driver_index};359#endif360361// param client362Canard::ObjCallback<AP_DroneCAN, uavcan_protocol_param_GetSetResponse> param_get_set_res_cb{this, &AP_DroneCAN::handle_param_get_set_response};363Canard::Client<uavcan_protocol_param_GetSetResponse> param_get_set_client{canard_iface, param_get_set_res_cb};364365Canard::ObjCallback<AP_DroneCAN, uavcan_protocol_param_ExecuteOpcodeResponse> param_save_res_cb{this, &AP_DroneCAN::handle_param_save_response};366Canard::Client<uavcan_protocol_param_ExecuteOpcodeResponse> param_save_client{canard_iface, param_save_res_cb};367368// reboot client369void handle_restart_node_response(const CanardRxTransfer& transfer, const uavcan_protocol_RestartNodeResponse& msg) {}370Canard::ObjCallback<AP_DroneCAN, uavcan_protocol_RestartNodeResponse> restart_node_res_cb{this, &AP_DroneCAN::handle_restart_node_response};371Canard::Client<uavcan_protocol_RestartNodeResponse> restart_node_client{canard_iface, restart_node_res_cb};372373uavcan_protocol_param_ExecuteOpcodeRequest param_save_req;374uavcan_protocol_param_GetSetRequest param_getset_req;375376// Node Info Server377Canard::ObjCallback<AP_DroneCAN, uavcan_protocol_GetNodeInfoRequest> node_info_req_cb{this, &AP_DroneCAN::handle_node_info_request};378Canard::Server<uavcan_protocol_GetNodeInfoRequest> node_info_server{canard_iface, node_info_req_cb};379uavcan_protocol_GetNodeInfoResponse node_info_rsp;380381#if AP_SCRIPTING_ENABLED382Canard::ObjCallback<AP_DroneCAN, dronecan_protocol_FlexDebug> FlexDebug_cb{this, &AP_DroneCAN::handle_FlexDebug};383Canard::Subscriber<dronecan_protocol_FlexDebug> FlexDebug_listener{FlexDebug_cb, _driver_index};384#endif385386#if AP_DRONECAN_HOBBYWING_ESC_SUPPORT387/*388Hobbywing ESC support. Note that we need additional meta-data as389the status messages do not have an ESC ID in them, so we need a390mapping from node ID391*/392#define HOBBYWING_MAX_ESC 8393struct {394uint32_t last_GetId_send_ms;395uint8_t thr_chan[HOBBYWING_MAX_ESC];396} hobbywing;397void hobbywing_ESC_update();398399void SRV_send_esc_hobbywing();400Canard::Publisher<com_hobbywing_esc_RawCommand> esc_hobbywing_raw{canard_iface};401Canard::Publisher<com_hobbywing_esc_GetEscID> esc_hobbywing_GetEscID{canard_iface};402Canard::ObjCallback<AP_DroneCAN, com_hobbywing_esc_GetEscID> esc_hobbywing_GetEscID_cb{this, &AP_DroneCAN::handle_hobbywing_GetEscID};403Canard::Subscriber<com_hobbywing_esc_GetEscID> esc_hobbywing_GetEscID_listener{esc_hobbywing_GetEscID_cb, _driver_index};404Canard::ObjCallback<AP_DroneCAN, com_hobbywing_esc_StatusMsg1> esc_hobbywing_StatusMSG1_cb{this, &AP_DroneCAN::handle_hobbywing_StatusMsg1};405Canard::Subscriber<com_hobbywing_esc_StatusMsg1> esc_hobbywing_StatusMSG1_listener{esc_hobbywing_StatusMSG1_cb, _driver_index};406Canard::ObjCallback<AP_DroneCAN, com_hobbywing_esc_StatusMsg2> esc_hobbywing_StatusMSG2_cb{this, &AP_DroneCAN::handle_hobbywing_StatusMsg2};407Canard::Subscriber<com_hobbywing_esc_StatusMsg2> esc_hobbywing_StatusMSG2_listener{esc_hobbywing_StatusMSG2_cb, _driver_index};408bool hobbywing_find_esc_index(uint8_t node_id, uint8_t &esc_index) const;409void handle_hobbywing_GetEscID(const CanardRxTransfer& transfer, const com_hobbywing_esc_GetEscID& msg);410void handle_hobbywing_StatusMsg1(const CanardRxTransfer& transfer, const com_hobbywing_esc_StatusMsg1& msg);411void handle_hobbywing_StatusMsg2(const CanardRxTransfer& transfer, const com_hobbywing_esc_StatusMsg2& msg);412#endif // AP_DRONECAN_HOBBYWING_ESC_SUPPORT413414#if AP_DRONECAN_HIMARK_SERVO_SUPPORT && AP_SERVO_TELEM_ENABLED415void handle_himark_servoinfo(const CanardRxTransfer& transfer, const com_himark_servo_ServoInfo &msg);416#endif417418// incoming button handling419void handle_button(const CanardRxTransfer& transfer, const ardupilot_indication_Button& msg);420void handle_traffic_report(const CanardRxTransfer& transfer, const ardupilot_equipment_trafficmonitor_TrafficReport& msg);421#if AP_SERVO_TELEM_ENABLED422void handle_actuator_status(const CanardRxTransfer& transfer, const uavcan_equipment_actuator_Status& msg);423#endif424#if AP_DRONECAN_VOLZ_FEEDBACK_ENABLED425void handle_actuator_status_Volz(const CanardRxTransfer& transfer, const com_volz_servo_ActuatorStatus& msg);426#endif427void handle_ESC_status(const CanardRxTransfer& transfer, const uavcan_equipment_esc_Status& msg);428#if AP_EXTENDED_ESC_TELEM_ENABLED429void handle_esc_ext_status(const CanardRxTransfer& transfer, const uavcan_equipment_esc_StatusExtended& msg);430#endif431static bool is_esc_data_index_valid(const uint8_t index);432void handle_debug(const CanardRxTransfer& transfer, const uavcan_protocol_debug_LogMessage& msg);433void handle_param_get_set_response(const CanardRxTransfer& transfer, const uavcan_protocol_param_GetSetResponse& rsp);434void handle_param_save_response(const CanardRxTransfer& transfer, const uavcan_protocol_param_ExecuteOpcodeResponse& rsp);435void handle_node_info_request(const CanardRxTransfer& transfer, const uavcan_protocol_GetNodeInfoRequest& req);436437#if AP_SCRIPTING_ENABLED438void handle_FlexDebug(const CanardRxTransfer& transfer, const dronecan_protocol_FlexDebug& msg);439struct FlexDebug {440struct FlexDebug *next;441uint32_t timestamp_us;442uint8_t node_id;443dronecan_protocol_FlexDebug msg;444} *flexDebug_list;445#endif446};447448#endif // #if HAL_ENABLE_DRONECAN_DRIVERS449450451