/*
* This file 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 file 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 .
*
* Author: Eugene Shamaev, Siddharth Bharat Purohit
*/
#include
#include
#if HAL_WITH_UAVCAN
#include "AP_UAVCAN.h"
#include
#include //电机类
#include "../../ArduSub/Sub.h"
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
//hight volt HighVoltThrusterSetRegs.hpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
//#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LED_DELAY_US 50000
extern const AP_HAL::HAL& hal;
#define debug_uavcan(level_debug, fmt, args...) do { if ((level_debug) <= AP::can().get_debug_level_driver(_driver_index)) { printf(fmt, ##args); }} while (0)
// Translation of all messages from UAVCAN structures into AP structures is done
// in AP_UAVCAN and not in corresponding drivers.
// The overhead of including definitions of DSDL is very high and it is best to
// concentrate in one place.
// table of user settable CAN bus parameters
const AP_Param::GroupInfo AP_UAVCAN::var_info[] = {
// @Param: NODE
// @DisplayName: UAVCAN node that is used for this network
// @Description: UAVCAN node should be set implicitly
// @Range: 1 250
// @User: Advanced
AP_GROUPINFO("NODE", 1, AP_UAVCAN, _uavcan_node, 10),
// @Param: SRV_BM
// @DisplayName: RC Out channels to be transmitted as servo over UAVCAN
// @Description: Bitmask with one set for channel to be transmitted as a servo command over UAVCAN
// @Bitmask: 0: Servo 1, 1: Servo 2, 2: Servo 3, 3: Servo 4, 4: Servo 5, 5: Servo 6, 6: Servo 7, 7: Servo 8, 8: Servo 9, 9: Servo 10, 10: Servo 11, 11: Servo 12, 12: Servo 13, 13: Servo 14, 14: Servo 15
// @User: Advanced
AP_GROUPINFO("SRV_BM", 2, AP_UAVCAN, _servo_bm, 0),
// @Param: ESC_BM
// @DisplayName: RC Out channels to be transmitted as ESC over UAVCAN
// @Description: Bitmask with one set for channel to be transmitted as a ESC command over UAVCAN
// @Bitmask: 0: ESC 1, 1: ESC 2, 2: ESC 3, 3: ESC 4, 4: ESC 5, 5: ESC 6, 6: ESC 7, 7: ESC 8, 8: ESC 9, 9: ESC 10, 10: ESC 11, 11: ESC 12, 12: ESC 13, 13: ESC 14, 14: ESC 15, 15: ESC 16
// @User: Advanced
AP_GROUPINFO("ESC_BM", 3, AP_UAVCAN, _esc_bm, 0),
// @Param: SRV_RT
// @DisplayName: Servo output rate
// @Description: Maximum transmit rate for servo outputs
// @Range: 1 200
// @Units: Hz
// @User: Advanced
AP_GROUPINFO("SRV_RT", 4, AP_UAVCAN, _servo_rate_hz, 50),
AP_GROUPEND
};
// this is the timeout in milliseconds for periodic message types. We
// set this to 1 to minimise resend of stale msgs
#define CAN_PERIODIC_TX_TIMEOUT_MS 2
//自定义stm32 参数设置协议--------
static uavcan::Publisher* HVoltThtSetReg[MAX_NUMBER_OF_CAN_DRIVERS];
static uavcan::Publisher* esc_Bfd1[MAX_NUMBER_OF_CAN_DRIVERS];
static uavcan::Publisher* esc_Bfd2[MAX_NUMBER_OF_CAN_DRIVERS];
static uavcan::Publisher* esc_Bfd3[MAX_NUMBER_OF_CAN_DRIVERS];
//static uavcan::Publisher* esc_MotorCommands[MAX_NUMBER_OF_CAN_DRIVERS];
static uavcan::Publisher* SetFloatParam[MAX_NUMBER_OF_CAN_DRIVERS];
static uavcan::Publisher* esc_SpeedCommands[MAX_NUMBER_OF_CAN_DRIVERS];
//自定义stm32 参数设置协议--------
// publisher interfaces
static uavcan::Publisher* act_out_array[MAX_NUMBER_OF_CAN_DRIVERS];
static uavcan::Publisher* esc_raw[MAX_NUMBER_OF_CAN_DRIVERS];
static uavcan::Publisher* rgb_led[MAX_NUMBER_OF_CAN_DRIVERS];
static uavcan::Publisher* buzzer[MAX_NUMBER_OF_CAN_DRIVERS];
static uavcan::Publisher* safety_state[MAX_NUMBER_OF_CAN_DRIVERS];
// subscribers
// handler SafteyButton
UC_REGISTRY_BINDER(ButtonCb, ardupilot::indication::Button);
static uavcan::Subscriber *safety_button_listener[MAX_NUMBER_OF_CAN_DRIVERS];
//接收局部全局变量-----------
int16_t motors_receive[12]={0,0,0,0,0,0,0,0,0,0,0,0}; //STM32发来的速度
uint8_t crc_motors[42];
union DRIVEBOX_ABNORMAL_UNI motor_stall_state;//获取所有的堵转
union PROPELLER_ABNORMAL_UNI propeller_block;//推进器缠绕等级
int16_t temperature_power = 0;//温度
int16_t voltage48V= 0;//48V电源
int16_t driveleak = 0;//泄露
extern mavlink_set_slave_parameter_t set_stm32_param;
extern mavlink_rov_state_monitoring_t rov_message;
extern mavlink_hv_reg_get_t hv_reg_get;
extern mavlink_hv_reg_set_t hv_reg_set;
extern mavlink_motor_speed_t mav_motor_speed;
//uint8_t mode_flag = 0;
uint8_t get_stm32_param_buf[7] = {0,0,0,0,0,0,0};// 板1收到的参数
//hv_motor_runmode.all = 0xFFFF;
uint8_t hv_motor_cmd_temp = 0;
uint8_t hv_motor_cmd = 0;
int16_t hv_motor_speed_32 = 0;
int16_t lightstate=0;
int16_t usbl_power=0;
int16_t current_trust=0;
#define reboot_time 3000
//----------------------------------------------
float getfloat(mavlink_set_slave_parameter_t par);
void STM32_set_packet(uavcan::equipment::esc::SetFloatParam &_msgparam);
void crc_setmotor(uavcan::equipment::esc::HighVoltThrusterSetRegs &hvmesg);
void crc_ackfault(uavcan::equipment::esc::HighVoltThrusterSetRegs &hvmesg,uint8_t number);
AP_UAVCAN::AP_UAVCAN() :
_node_allocator()
{
AP_Param::setup_object_defaults(this, var_info);
_singleton = this;
for (uint8_t i = 0; i < UAVCAN_SRV_NUMBER; i++) {
_SRV_conf[i].esc_pending = false;
_SRV_conf[i].servo_pending = false;
}
motor_stall_state.all = 0;
propeller_block.all = 0;
for (uint8_t cnt = 0; cnt < 12; cnt++)
{
motors_receive[cnt]=0;
}
for(uint8_t j=0;j<12;j++){
motor_from_stm32[j] = 0;//读到转速
}
debug_uavcan(2, "AP_UAVCAN constructed\n\r");
}
AP_UAVCAN::~AP_UAVCAN()
{
}
AP_UAVCAN *AP_UAVCAN::get_uavcan(uint8_t driver_index)
{
if (driver_index >= AP::can().get_num_drivers() ||
AP::can().get_protocol_type(driver_index) != AP_BoardConfig_CAN::Protocol_Type_UAVCAN) {
return nullptr;
}
return static_cast(AP::can().get_driver(driver_index));
}
//self define rec fun-------------------------------start---------------
static void motor_res_st_cb(const uavcan::ReceivedDataStructure& msg,uint8_t mgr )
{//接收到的数据在这里处理,打印出来
if (msg.motor_index == 0){
//推进器0,1,2
motors_receive[0] = msg.rpm0 & 0x0FFF;
propeller_block.bit.motor0 = (msg.rpm0 & 0xF000)>>12;
motors_receive[1] = msg.rpm1 & 0x0FFF;
propeller_block.bit.motor1 = (msg.rpm1 & 0xF000)>>12;
motors_receive[2] = msg.rpm2 & 0x0FFF;
propeller_block.bit.motor2 = (msg.rpm2 & 0xF000)>>12;
// gcs().send_text(MAV_SEVERITY_WARNING, "motor_index = 0 %d %d %d.",(int)motors_receive[0],(int)motors_receive[1],motors_receive[2]);
}
/*else if(msg.motor_index == 3){
//推进器3,4,5
motors_receive[3] = msg.rpm0 & 0x0FFF;
propeller_block.bit.motor3 = (msg.rpm0 & 0xF000)>>12;
motors_receive[4] = msg.rpm1 & 0x0FFF;
propeller_block.bit.motor4 = (msg.rpm1 & 0xF000)>>12;
motors_receive[5] = msg.rpm2 & 0x0FFF;
propeller_block.bit.motor5 = (msg.rpm2 & 0xF000)>>12;
static int16_t c2 = 0;
c2++;
if(c2>100){
c2 =0 ;
//gcs().send_text(MAV_SEVERITY_WARNING, "motor_index == 3 %d %d %d.",(int)motors_receive[3],(int)motors_receive[4],motors_receive[5]);
}
}*/
else if(msg.motor_index == 6){
////推进器6,7,履带1
motors_receive[6] = msg.rpm0 & 0x0FFF;
propeller_block.bit.motor6 = (msg.rpm0 & 0xF000)>>12;
motors_receive[7] = msg.rpm1 & 0x0FFF;
propeller_block.bit.motor7 = (msg.rpm1 & 0xF000)>>12;
motors_receive[8] = msg.rpm2 & 0x0FFF;
static int16_t c3 = 0;
c3++;
if(c3>100){
c3 =0 ;
//gcs().send_text(MAV_SEVERITY_WARNING, "motor_index == 6 %d %d %d",(int)motors_receive[6],(int)motors_receive[7],motors_receive[8]);
}
}
else if(msg.motor_index == 9){
////履带2,毛刷1,毛刷2
motors_receive[9] = msg.rpm0 & 0x0FFF;
motors_receive[10] = msg.rpm1 & 0x0FFF;
motors_receive[11] = msg.rpm2 & 0x0FFF;
static int16_t c4 = 0;
c4++;
if(c4>100){
c4 =0 ;
//gcs().send_text(MAV_SEVERITY_WARNING, "motor_index == 9 %d %d %d.",(int)motors_receive[9],(int)motors_receive[10],motors_receive[11]);
}
}
else if(msg.motor_index == 12){
////
voltage48V = msg.rpm0;
temperature_power = msg.rpm1;
motor_stall_state.all = msg.rpm2;//所有电机的堵转
static int16_t c5 = 0;
c5++;
if(c5>100){
c5 =0 ;
//gcs().send_text(MAV_SEVERITY_WARNING, "motor_index == 12 %d %d %x.",(int)voltage48V,(int)temperature_power,motor_stall_state.all);
}
}
else if(msg.motor_index == 15){
////履带2,毛刷1,毛刷2
lightstate = msg.rpm0;
usbl_power = msg.rpm1;
current_trust = msg.rpm2;
}
}
static void motor_res_st_cb0(const uavcan::ReceivedDataStructure& msg ){
motor_res_st_cb(msg,0);
}
static void motor_res_st_cb1(const uavcan::ReceivedDataStructure& msg ){
motor_res_st_cb(msg,1);
}
static void (*motor_res_st_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
={motor_res_st_cb0,motor_res_st_cb1};
//==========================================================================================================================
//获取stm32板1参数------XXXXXXXX.YY-------------------------
float getfloat(mavlink_set_slave_parameter_t par){
float data =(par.XX1/16)*10000000+(par.XX1%16)*1000000 +
(par.XX2/16)*100000+(par.XX2%16)*10000+
(par.XX3/16)*1000+(par.XX3%16)*100 +
(par.XX4/16)*10 + (par.XX4%16) +
(par.YY/16)*0.1 +(par.YY%16)*0.01;
return data;
}
static void motor_par1_cb(const uavcan::ReceivedDataStructure& msg,uint8_t mgr ){
get_stm32_param_buf[0] = msg.number;
get_stm32_param_buf[1] = msg.flag;
get_stm32_param_buf[2] = msg.XX1;
get_stm32_param_buf[3] = msg.XX2;
get_stm32_param_buf[4] = msg.XX3;
get_stm32_param_buf[5] = msg.XX4;
get_stm32_param_buf[6] = msg.YY;
}
static void motor_par1_cb0(const uavcan::ReceivedDataStructure& msg ){
motor_par1_cb(msg,0);
}
static void motor_par1_cb1(const uavcan::ReceivedDataStructure& msg ){
motor_par1_cb(msg,1);
}
static void (*motor_par1_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
={motor_par1_cb0,motor_par1_cb1};
//高压电调1参数返回
static void thruster1GetRegs_cb(const uavcan::ReceivedDataStructure& msg,uint8_t mgr ){
uint8_t buffer[7]={0,0,0,0,0,0,0};
for (uint8_t i = 0; i < 7; i++)
{
buffer[i] = msg.BUFFER[i];
}
hv_reg_get.aim = 3;
hv_reg_get.data[0] = (uint32_t)buffer[1] + (uint32_t)(buffer[2]<<8) + (uint32_t)(buffer[3]<<16) + (uint32_t)(buffer[4]<<24);
hv_reg_get.data[1] = 0;
hv_reg_get.data[2] = 0;
gcs().send_text(MAV_SEVERITY_WARNING, "thruster3 %x .",(uint32_t)hv_reg_get.data[0]);
}
static void Thruster1GetRegs_cb0(const uavcan::ReceivedDataStructure& msg ){
thruster1GetRegs_cb(msg,0);
}
static void Thruster1GetRegs_cb1(const uavcan::ReceivedDataStructure& msg ){
thruster1GetRegs_cb(msg,1);
}
static void (*Thruster1GetRegs_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
={Thruster1GetRegs_cb0,Thruster1GetRegs_cb1};
//高压电调2参数返回
static void thruster2GetRegs_cb(const uavcan::ReceivedDataStructure& msg ,uint8_t mgr){
uint8_t buffer[7]={0,0,0,0,0,0,0};
for (uint8_t i = 0; i < 7; i++)
{
buffer[i] = msg.BUFFER[i];
}
hv_reg_get.aim = 4;
hv_reg_get.data[0] = (uint32_t)buffer[1] + (uint32_t)(buffer[2]<<8) + (uint32_t)(buffer[3]<<16) + (uint32_t)(buffer[4]<<24);
hv_reg_get.data[1] = 0;
hv_reg_get.data[2] = 0;
gcs().send_text(MAV_SEVERITY_WARNING, "thruster4 %x .",(uint32_t)hv_reg_get.data[0]);
}
static void Thruster2GetRegs_cb0(const uavcan::ReceivedDataStructure& msg ){
thruster2GetRegs_cb(msg,0);
}
static void Thruster2GetRegs_cb1(const uavcan::ReceivedDataStructure& msg ){
thruster2GetRegs_cb(msg,1);
}
static void (*Thruster2GetRegs_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
={Thruster2GetRegs_cb0,Thruster2GetRegs_cb1};
//高压电调3参数返回
static void thruster3GetRegs_cb(const uavcan::ReceivedDataStructure& msg ,uint8_t mgr){
uint8_t buffer[7]={0,0,0,0,0,0,0};
for (uint8_t i = 0; i < 7; i++)
{
buffer[i] = msg.BUFFER[i];
}
hv_reg_get.aim = 5;
hv_reg_get.data[0] = (uint32_t)buffer[1] + (uint32_t)(buffer[2]<<8) + (uint32_t)(buffer[3]<<16) + (uint32_t)(buffer[4]<<24);
hv_reg_get.data[1] = 0;
hv_reg_get.data[2] = 0;
gcs().send_text(MAV_SEVERITY_WARNING, "thruster5 %x .",(uint32_t)hv_reg_get.data[0]);
//gcs().send_text(MAV_SEVERITY_WARNING, "thruster3data %d %d %d %d.",(int)buffer[0],(int)buffer[1],(int)buffer[2],(int)buffer[3]);
//gcs().send_text(MAV_SEVERITY_WARNING, "thruster3 %d %d %d.",hv_reg_get.aim,(int)data[0],(int)data[1]);
}
static void Thruster3GetRegs_cb0(const uavcan::ReceivedDataStructure& msg ){
thruster3GetRegs_cb(msg,0);
}
static void Thruster3GetRegs_cb1(const uavcan::ReceivedDataStructure& msg ){
thruster3GetRegs_cb(msg,1);
}
static void (*Thruster3GetRegs_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
={Thruster3GetRegs_cb0,Thruster3GetRegs_cb1};
//高压电调1定时返回
struct HVmes Thruster1={0,0,0,0,0,0};
struct HVmes Thruster2={0,0,0,0,0,0};
struct HVmes Thruster3={0,0,0,0,0,0};
struct HVmotor haoye1={0,0,0,0,0,0};
struct HVmotor haoye2={0,0,0,0,0,0};
//static void Thruster1timeback_cb(const uavcan::ReceivedDataStructure& msg ,uint8_t mgr){
static void Thruster1timeback_cb(const uavcan::ReceivedDataStructure& msg ,uint8_t mgr){
uint8_t buffer[6]={0,0,0,0,0,0};
for (uint8_t i = 0; i < 6; i++)
{
buffer[i] = msg.BUFFER[i];
}
HVcycle(msg.CODE,buffer,Thruster1);
//if(msg.CODE == 0x0A){
//int16_t speedmes = buffer[4]+(buffer[5]<<8);
static int8_t per = 0;
per++;
if (per>100)
{
per = 0;
gcs().send_text(MAV_SEVERITY_INFO, "HV3 %d %d %d %d",(int)Thruster1.voltage,(int)Thruster1.speedref,(int)Thruster1.temperature,(int)Thruster1.motortemperature);
}
//}
}
//static void Thruster1timeback_cb0(const uavcan::ReceivedDataStructure& msg ){
static void Thruster1timeback_cb0(const uavcan::ReceivedDataStructure& msg ){
Thruster1timeback_cb(msg,0);
}
//static void Thruster1timeback_cb1(const uavcan::ReceivedDataStructure& msg ){
static void Thruster1timeback_cb1(const uavcan::ReceivedDataStructure& msg ){
Thruster1timeback_cb(msg,1);
}
//static void (*Thruster1timeback_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
static void (*Thruster1timeback_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
={Thruster1timeback_cb0,Thruster1timeback_cb1};
//高压电调2定时返回
//static void Thruster2timeback_cb(const uavcan::ReceivedDataStructure& msg ,uint8_t mgr){
static void Thruster2timeback_cb(const uavcan::ReceivedDataStructure& msg ,uint8_t mgr){
uint8_t buffer[6]={0,0,0,0,0,0};
for (uint8_t i = 0; i < 6; i++)
{
buffer[i] = msg.BUFFER[i];
}
HVcycle(msg.CODE,buffer,Thruster2);
//if(msg.CODE == 0x0A){
//int16_t speedmes = buffer[4]+(buffer[5]<<8);
static int8_t per = 0;
per++;
if (per>100)
{
per = 0;
gcs().send_text(MAV_SEVERITY_INFO, "HV4 %d %d %d %d",(int)Thruster2.voltage,(int)Thruster2.speedref,(int)Thruster2.temperature,(int)Thruster2.motortemperature);
}
//}
}
//static void Thruster2timeback_cb0(const uavcan::ReceivedDataStructure& msg ){
static void Thruster2timeback_cb0(const uavcan::ReceivedDataStructure& msg ){
Thruster2timeback_cb(msg,0);
}
//static void Thruster2timeback_cb1(const uavcan::ReceivedDataStructure& msg ){
static void Thruster2timeback_cb1(const uavcan::ReceivedDataStructure& msg ){
Thruster2timeback_cb(msg,1);
}
//static void (*Thruster2timeback_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
static void (*Thruster2timeback_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
={Thruster2timeback_cb0,Thruster2timeback_cb1};
//高压电调2定时返回
//static void Thruster3timeback_cb(const uavcan::ReceivedDataStructure& msg ,uint8_t mgr){
static void Thruster3timeback_cb(const uavcan::ReceivedDataStructure& msg ,uint8_t mgr){
uint8_t buffer[6]={0,0,0,0,0,0};
for (uint8_t i = 0; i < 6; i++)
{
buffer[i] = msg.BUFFER[i];
}
HVcycle(msg.CODE,buffer,Thruster3);
//if(msg.CODE == 0x0A){
//int16_t speedmes = buffer[4]+(buffer[5]<<8);
static int8_t per = 0;
per++;
if (per>100)
{
per = 0;
gcs().send_text(MAV_SEVERITY_INFO, "HV5 %d %d %d %d",(int)Thruster3.voltage,(int)Thruster3.speedref,(int)Thruster3.temperature,(int)Thruster3.motortemperature);
}
//}
}
//static void Thruster3timeback_cb0(const uavcan::ReceivedDataStructure& msg ){
static void Thruster3timeback_cb0(const uavcan::ReceivedDataStructure& msg ){
Thruster3timeback_cb(msg,0);
}
//static void Thruster3timeback_cb1(const uavcan::ReceivedDataStructure& msg ){
static void Thruster3timeback_cb1(const uavcan::ReceivedDataStructure& msg ){
Thruster3timeback_cb(msg,1);
}
//static void (*Thruster3timeback_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
static void (*Thruster3timeback_cb_arr[2])(const uavcan::ReceivedDataStructure& msg )
={Thruster3timeback_cb0,Thruster3timeback_cb1};
//self define rec fun-------------------------------end---------------
void AP_UAVCAN::init(uint8_t driver_index, bool enable_filters)
{
//hal.scheduler->delay_microseconds(1000);
if (_initialized) {
debug_uavcan(2, "UAVCAN: init called more than once\n\r");
return;
}
_driver_index = driver_index;
AP_HAL::CANManager* can_mgr = hal.can_mgr[driver_index];
if (can_mgr == nullptr) {
debug_uavcan(2, "UAVCAN: init called for inexisting CAN driver\n\r");
return;
}
if (!can_mgr->is_initialized()) {
debug_uavcan(1, "UAVCAN: CAN driver not initialized\n\r");
return;
}
uavcan::ICanDriver* driver = can_mgr->get_driver();
if (driver == nullptr) {
debug_uavcan(2, "UAVCAN: can't get UAVCAN interface driver\n\r");
return;
}
_node = new uavcan::Node<0>(*driver, SystemClock::instance(), _node_allocator);
if (_node == nullptr) {
debug_uavcan(1, "UAVCAN: couldn't allocate node\n\r");
return;
}
if (_node->isStarted()) {
debug_uavcan(2, "UAVCAN: node was already started?\n\r");
return;
}
uavcan::NodeID self_node_id(_uavcan_node);
_node->setNodeID(self_node_id);
char ndname[20];
snprintf(ndname, sizeof(ndname), "org.ardupilot:%u", driver_index);
uavcan::NodeStatusProvider::NodeName name(ndname);
_node->setName(name);
uavcan::protocol::SoftwareVersion sw_version; // Standard type uavcan.protocol.SoftwareVersion
sw_version.major = AP_UAVCAN_SW_VERS_MAJOR;
sw_version.minor = AP_UAVCAN_SW_VERS_MINOR;
_node->setSoftwareVersion(sw_version);
uavcan::protocol::HardwareVersion hw_version; // Standard type uavcan.protocol.HardwareVersion
hw_version.major = AP_UAVCAN_HW_VERS_MAJOR;
hw_version.minor = AP_UAVCAN_HW_VERS_MINOR;
const uint8_t uid_buf_len = hw_version.unique_id.capacity();
uint8_t uid_len = uid_buf_len;
uint8_t unique_id[uid_buf_len];
if (hal.util->get_system_id_unformatted(unique_id, uid_len)) {
uavcan::copy(unique_id, unique_id + uid_len, hw_version.unique_id.begin());
}
_node->setHardwareVersion(hw_version);
int start_res = _node->start();
if (start_res < 0) {
debug_uavcan(1, "UAVCAN: node start problem, error %d\n\r", start_res);
return;
}
//Start Servers
#ifdef HAS_UAVCAN_SERVERS
_servers.init(*_node);
#endif
// Roundup all subscribers from supported drivers
AP_GPS_UAVCAN::subscribe_msgs(this);
AP_Compass_UAVCAN::subscribe_msgs(this);
AP_Baro_UAVCAN::subscribe_msgs(this);
AP_BattMonitor_UAVCAN::subscribe_msgs(this);
AP_Airspeed_UAVCAN::subscribe_msgs(this);
AP_OpticalFlow_HereFlow::subscribe_msgs(this);
AP_RangeFinder_UAVCAN::subscribe_msgs(this);
//创建设备类型------------------
auto *node= get_node();
uavcan::Subscriber* motor_res_st;
motor_res_st = new uavcan::Subscriber(*node);
const int motor_res_start_res = motor_res_st->start(motor_res_st_cb_arr[_driver_index]);//定义回调函数用于接收
if (motor_res_start_res<0)
{
return;
}
//创建设备类型获取stm32参数1
uavcan::Subscriber* motor_par1_st;
motor_par1_st = new uavcan::Subscriber(*node);
const int motor_par1_res = motor_par1_st->start(motor_par1_cb_arr[_driver_index]);//定义回调函数用于接收
if (motor_par1_res<0)
{
return;
}
//高压电调1 参数返回
uavcan::Subscriber* Thruster1GetRegs;
Thruster1GetRegs = new uavcan::Subscriber(*node);
const int Tht1GetReg = Thruster1GetRegs->start(Thruster1GetRegs_cb_arr[_driver_index]);//定义回调函数用于接收
if (Tht1GetReg<0)
{
return;
}
//高压电调2 参数返回
uavcan::Subscriber* Thruster2GetRegs;
Thruster2GetRegs = new uavcan::Subscriber(*node);
const int Tht2GetReg = Thruster2GetRegs->start(Thruster2GetRegs_cb_arr[_driver_index]);//定义回调函数用于接收
if (Tht2GetReg<0)
{
return;
}
//高压电调3 参数返回
uavcan::Subscriber* Thruster3GetRegs;
Thruster3GetRegs = new uavcan::Subscriber(*node);
const int Tht3GetReg = Thruster3GetRegs->start(Thruster3GetRegs_cb_arr[_driver_index]);//定义回调函数用于接收
if (Tht3GetReg<0)
{
return;
}
//高压电调1 定时参数返回
uavcan::Subscriber* Thruster1timeback;
Thruster1timeback = new uavcan::Subscriber(*node);
const int Tht1timecb = Thruster1timeback->start(Thruster1timeback_cb_arr[_driver_index]);//定义回调函数用于接收
if (Tht1timecb<0)
{
return;
}
//高压电调2 定时参数返回
uavcan::Subscriber* Thruster2timeback;
Thruster2timeback = new uavcan::Subscriber(*node);
const int Tht2timecb = Thruster2timeback->start(Thruster2timeback_cb_arr[_driver_index]);//定义回调函数用于接收
if (Tht2timecb<0)
{
return;
}
//高压电调3 定时参数返回
uavcan::Subscriber* Thruster3timeback;
Thruster3timeback = new uavcan::Subscriber(*node);
const int Tht3timecb = Thruster3timeback->start(Thruster3timeback_cb_arr[_driver_index]);//定义回调函数用于接收
if (Tht3timecb<0)
{
return;
}
//创建发送设备类型
esc_SpeedCommands[driver_index] = new uavcan::Publisher(*_node);
esc_SpeedCommands[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2));
esc_SpeedCommands[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest);
//HVoltThtSetReg
//高压电调参数设置
HVoltThtSetReg[driver_index] = new uavcan::Publisher(*_node);
HVoltThtSetReg[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(20));
HVoltThtSetReg[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest);
//创建发送设备类型
esc_Bfd1[driver_index] = new uavcan::Publisher(*_node);
esc_Bfd1[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2));
esc_Bfd1[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest);
esc_Bfd2[driver_index] = new uavcan::Publisher(*_node);
esc_Bfd2[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2));
esc_Bfd2[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest);
esc_Bfd3[driver_index] = new uavcan::Publisher(*_node);
esc_Bfd3[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2));
esc_Bfd3[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest);
//esc_MotorCommands[driver_index] = new uavcan::Publisher(*_node);
// esc_MotorCommands[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2));
// esc_MotorCommands[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest);
//创建参数设置类型
SetFloatParam[driver_index] = new uavcan::Publisher(*_node);
SetFloatParam[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2));
SetFloatParam[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest);
//-----------------------------------
act_out_array[driver_index] = new uavcan::Publisher(*_node);
act_out_array[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2));
act_out_array[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest);
esc_raw[driver_index] = new uavcan::Publisher(*_node);
esc_raw[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(2));
esc_raw[driver_index]->setPriority(uavcan::TransferPriority::OneLowerThanHighest);
rgb_led[driver_index] = new uavcan::Publisher(*_node);
rgb_led[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(20));
rgb_led[driver_index]->setPriority(uavcan::TransferPriority::OneHigherThanLowest);
buzzer[driver_index] = new uavcan::Publisher(*_node);
buzzer[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(20));
buzzer[driver_index]->setPriority(uavcan::TransferPriority::OneHigherThanLowest);
safety_state[driver_index] = new uavcan::Publisher(*_node);
safety_state[driver_index]->setTxTimeout(uavcan::MonotonicDuration::fromMSec(20));
safety_state[driver_index]->setPriority(uavcan::TransferPriority::OneHigherThanLowest);
safety_button_listener[driver_index] = new uavcan::Subscriber(*_node);
if (safety_button_listener[driver_index]) {
safety_button_listener[driver_index]->start(ButtonCb(this, &handle_button));
}
_led_conf.devices_count = 0;
if (enable_filters) {
configureCanAcceptanceFilters(*_node);
}
/*
* Informing other nodes that we're ready to work.
* Default mode is INITIALIZING.
*/
_node->setModeOperational();
// Spin node for device discovery
_node->spin(uavcan::MonotonicDuration::fromMSec(5000));
snprintf(_thread_name, sizeof(_thread_name), "uavcan_%u", driver_index);
if (!hal.scheduler->thread_create(FUNCTOR_BIND_MEMBER(&AP_UAVCAN::loop, void), _thread_name, 4096, AP_HAL::Scheduler::PRIORITY_CAN, 0)) {
_node->setModeOfflineAndPublish();
debug_uavcan(1, "UAVCAN: couldn't create thread\n\r");
return;
}
_initialized = true;
debug_uavcan(2, "UAVCAN: init done\n\r");
}
void STM32_set_packet(uavcan::equipment::esc::SetFloatParam &_msgparam){
_msgparam.number =set_stm32_param.number;
_msgparam.flag = set_stm32_param.flag;
_msgparam.XX1 = set_stm32_param.XX1;
_msgparam.XX2 = set_stm32_param.XX2;
_msgparam.XX3 = set_stm32_param.XX3;
_msgparam.XX4 = set_stm32_param.XX4;
_msgparam.YY = set_stm32_param.YY;
}
void crc_setmotor(uavcan::equipment::esc::HighVoltThrusterSetRegs &hvmesg){
uint8_t crc_dataset[10]={0,0,0,0,0,0,0,0,0,0};
hvmesg.NUMBER = hv_reg_set.aim;
hvmesg.TYPE = hv_reg_set.code;
hvmesg.PARNUMBER = (uint16_t)hv_reg_set.data[0] + (uint16_t)(hv_reg_set.data[1]<<8);
crc_dataset[0] = hvmesg.NUMBER ;
crc_dataset[1] = hvmesg.TYPE;
crc_dataset[2] = hv_reg_set.data[0];
crc_dataset[3] = hv_reg_set.data[1];
for (uint8_t j = 0; j < 6; j++)
{
hvmesg.DATA[j] = hv_reg_set.data[j+2];
crc_dataset[j+4] = hvmesg.DATA[j];
}
uint16_t crcdata = calc_crc_modbus(crc_dataset,10);
hvmesg.DATA[6] = (uint8_t)crcdata;
hvmesg.DATA[7] = (uint8_t)(crcdata>>8);
}
void crc_ackfault(uavcan::equipment::esc::HighVoltThrusterSetRegs &hvmesg,uint8_t number){
uint8_t crc_dataset[10]={0,0,0,0,0,0,0,0,0,0};
hvmesg.NUMBER = number;
hvmesg.TYPE = 0x03;
hvmesg.PARNUMBER = 0x5A5A;
crc_dataset[0] = hvmesg.NUMBER ;
crc_dataset[1] = hvmesg.TYPE;
crc_dataset[2] = 0x5A;
crc_dataset[3] = 0x5A;
for (uint8_t j = 0; j < 6; j++)
{
hvmesg.DATA[j] = 0;
crc_dataset[j+4] = hvmesg.DATA[j];
}
uint16_t crcdata = calc_crc_modbus(crc_dataset,10);
hvmesg.DATA[6] = (uint8_t)crcdata;
hvmesg.DATA[7] = (uint8_t)(crcdata>>8);
}
uint8_t HVreset = 0;
void AP_UAVCAN::loop(void)
{
while (true) {
if (!_initialized) {
hal.scheduler->delay_microseconds(1000);
continue;
}
const int error = _node->spin(uavcan::MonotonicDuration::fromMSec(1));
if (error < 0) {
hal.scheduler->delay_microseconds(100);
continue;
}
//接收的周期性数据--------------------
for(uint8_t j=0;j<12;j++){
motor_from_stm32[j] = motors_receive[j];//读到转速
}
motor_stall_flag = motor_stall_state.all;//堵转
propellerblock_flag = propeller_block.all;//推进器缠绕等级
temperature_48Vpower = temperature_power;//can获取18B20温度
board_voltage = voltage48V;//can获取48V电源
driverleakstate = driveleak;
HVmotor1 = Thruster1;
HVmotor2 = Thruster2;
HVmotor3 = Thruster3;
rov_message.hvMotorMod = 0xffff;
uavcan::equipment::esc::HighVoltThrusterSetRegs hvmesg;//高压电调参数设置
//2-------------------aim取值0,1,2,3 高压电调设置
if(hv_reg_set.aim == 0 || (hv_reg_set.aim &0x0F) !=0){
crc_setmotor(hvmesg);
hv_reg_set.aim = 0xF0;
HVoltThtSetReg[_driver_index]->broadcast(hvmesg);//高压电调读取或者设置参数
}
//----------------------------------------------------------
//2---------------高压电调设置end*******************************************
//---------重启设置---------------------------
static uint8_t stm32_rboot = 0;
if((set_stm32_param.flag == 0xF0)&&(set_stm32_param.number ==12)){
set_stm32_param.flag = 0;
//消除缠绕
stm32_rboot = 1;
//高压电调消除故障
HVreset = 7;
}
//-------发送数据-------------------------------------------------
const AP_Motors6DOF &motors6dof = AP::motors6dof();//6自由度电机计算出来的PWM
uavcan::equipment::esc::SingleMotorCommand msg;
uavcan::equipment::esc::SpeedCommands msgarryspeed;
uavcan::equipment::esc::SetFloatParam msgparam;
uavcan::equipment::esc::Bfd1 msgbfd1;
uavcan::equipment::esc::Bfd2 msgbfd2;
uavcan::equipment::esc::Bfd3 msgbfd3;
uint32_t nowtime = AP_HAL::micros();
static uint32_t last_send_time = nowtime;
if (nowtime - last_send_time >1000000UL/200 )//发送周期
{ last_send_time = nowtime;
msgbfd1.index = 0;
msgbfd1.speed1 = 0;
msgbfd1.speed2 = 0;
if ((HVreset&0x01)==1 )
{
if (HVmotor1.fault!=0)
{
msgbfd1.speed3 = 0;
}else{
msgbfd1.speed3 = motors6dof.motor_to_can[2];
HVreset = HVreset&0x06;
}
}else{
msgbfd1.speed3 = motors6dof.motor_to_can[2];
}
esc_Bfd1[_driver_index]->broadcast(msgbfd1);//大约100HZ 在没有设置参数的情况下 发送驱动*/
//-----------------------------------------------------------------------------------------------------
msgbfd2.index = 0;
if ((HVreset&0x02)==2 )
{
if (HVmotor2.fault!=0)
{
msgbfd2.speed1 = 0;
}else{
msgbfd2.speed1 = motors6dof.motor_to_can[3];
HVreset =HVreset&0x05;
}
}else{
msgbfd2.speed1 = motors6dof.motor_to_can[3];
}
if ((HVreset&0x04)==4 )
{
if (HVmotor3.fault!=0)
{
msgbfd2.speed2 = 0;
}else{
msgbfd2.speed2 = motors6dof.motor_to_can[4];
HVreset = HVreset&0x03;
}
}else{
msgbfd2.speed2 = motors6dof.motor_to_can[4];
}
msgbfd2.speed3 = 0;
esc_Bfd2[_driver_index]->broadcast(msgbfd2);//大约100HZ 在没有设置参数的情况下 发送驱动*/
//-------------------------------------------------------------------------------------------------
msgbfd3.index = 0;
msgbfd3.speed1 = 0;
msgbfd3.speed2 = 0;
msgbfd3.speed3 = 0;
esc_Bfd3[_driver_index]->broadcast(msgbfd3);//大约100HZ 在没有设置参数的情况下 发送驱动*/
}
uint32_t nowtime2 = AP_HAL::micros();
static uint32_t last_send_time2 = nowtime2;
static uint32_t lasttime_reboot = 0;
if(nowtime2 - last_send_time2 >1000000UL/200 )
{ last_send_time2 = nowtime2;
if(stm32_rboot==1)
{
static uint8_t reboot_cnt = 0;
if((motor_from_stm32[0]!=0 || motor_from_stm32[1]!=0 ||motor_from_stm32[8]!=0 ||motor_from_stm32[9]!=0)&&(reboot_cnt<170)){
msgarryspeed.rpm.push_back(0);
msgarryspeed.rpm.push_back(0);
msgarryspeed.rpm.push_back(0);
msgarryspeed.rpm.push_back(0);
msgarryspeed.rpm.push_back(0);
msgarryspeed.rpm.push_back(0);
reboot_cnt++;
esc_SpeedCommands[_driver_index]->broadcast(msgarryspeed);//大约100HZ 在没有设置参数的情况下 发送驱动
}else{
stm32_rboot = 0;
reboot_cnt=0;
lasttime_reboot = AP_HAL::millis();
}
}
uint32_t errortime_reboot = 0;
uint32_t nowtime_restart = AP_HAL::millis();//ms
errortime_reboot = nowtime_restart - lasttime_reboot;//重启时间
if ((errortime_reboot > reboot_time)&&(stm32_rboot==0))
{
int16_t pwm ;
pwm = motors6dof.motor_to_can[0];
msgarryspeed.rpm.push_back(pwm);
pwm = motors6dof.motor_to_can[1];
msgarryspeed.rpm.push_back(pwm);
pwm = motors6dof.motor_to_can[8];
msgarryspeed.rpm.push_back(pwm);
pwm = motors6dof.motor_to_can[9];
msgarryspeed.rpm.push_back(pwm);
pwm = sub.lights;
msgarryspeed.rpm.push_back(pwm);
pwm = sub.usblpoweroff;
msgarryspeed.rpm.push_back(pwm);
esc_SpeedCommands[_driver_index]->broadcast(msgarryspeed);//大约100HZ 在没有设置参数的情况下 发送驱动
}
//+++++++++设置stm32 参数----------------------------------------
// 上位机没有发送的时候不会发送 退出初始化之后才能写参数
if( !sub.motors.armed()&&(((set_stm32_param.flag == 0xF0)&&(set_stm32_param.number!=16))||(set_stm32_param.flag == 0xFF)))
{
STM32_set_packet(msgparam);
SetFloatParam[_driver_index]->broadcast(msgparam);//广播发送
set_stm32_param.flag = 0x00;
gcs().send_text(MAV_SEVERITY_WARNING, "set %x%x%x%x.%x .",msgparam.XX1,msgparam.XX2,msgparam.XX3,msgparam.XX4,msgparam.YY);
}
}
}
}
///// SRV output /////
void AP_UAVCAN::SRV_send_actuator(void)
{
uint8_t starting_servo = 0;
bool repeat_send;
WITH_SEMAPHORE(SRV_sem);
do {
repeat_send = false;
uavcan::equipment::actuator::ArrayCommand msg;
uint8_t i;
// UAVCAN can hold maximum of 15 commands in one frame
for (i = 0; starting_servo < UAVCAN_SRV_NUMBER && i < 15; starting_servo++) {
uavcan::equipment::actuator::Command cmd;
/*
* Servo output uses a range of 1000-2000 PWM for scaling.
* This converts output PWM from [1000:2000] range to [-1:1] range that
* is passed to servo as unitless type via UAVCAN.
* This approach allows for MIN/TRIM/MAX values to be used fully on
* autopilot side and for servo it should have the setup to provide maximum
* physically possible throws at [-1:1] limits.
*/
if (_SRV_conf[starting_servo].servo_pending && ((((uint32_t) 1) << starting_servo) & _servo_bm)) {
cmd.actuator_id = starting_servo + 1;
// TODO: other types
cmd.command_type = uavcan::equipment::actuator::Command::COMMAND_TYPE_UNITLESS;
// TODO: failsafe, safety
cmd.command_value = constrain_float(((float) _SRV_conf[starting_servo].pulse - 1000.0) / 500.0 - 1.0, -1.0, 1.0);
msg.commands.push_back(cmd);
i++;
}
}
if (i > 0) {
act_out_array[_driver_index]->broadcast(msg);
if (i == 15) {
repeat_send = true;
}
}
} while (repeat_send);
}
void AP_UAVCAN::SRV_send_esc(void)
{
static const int cmd_max = uavcan::equipment::esc::RawCommand::FieldTypes::cmd::RawValueType::max();
uavcan::equipment::esc::RawCommand esc_msg;
uint8_t active_esc_num = 0, max_esc_num = 0;
uint8_t k = 0;
WITH_SEMAPHORE(SRV_sem);
// find out how many esc we have enabled and if they are active at all
for (uint8_t i = 0; i < UAVCAN_SRV_NUMBER; i++) {
if ((((uint32_t) 1) << i) & _esc_bm) {
max_esc_num = i + 1;
if (_SRV_conf[i].esc_pending) {
active_esc_num++;
}
}
}
// if at least one is active (update) we need to send to all
if (active_esc_num > 0) {
k = 0;
for (uint8_t i = 0; i < max_esc_num && k < 20; i++) {
if ((((uint32_t) 1) << i) & _esc_bm) {
// TODO: ESC negative scaling for reverse thrust and reverse rotation
float scaled = cmd_max * (hal.rcout->scale_esc_to_unity(_SRV_conf[i].pulse) + 1.0) / 2.0;
scaled = constrain_float(scaled, 0, cmd_max);
esc_msg.cmd.push_back(static_cast(scaled));
} else {
esc_msg.cmd.push_back(static_cast(0));
}
k++;
}
esc_raw[_driver_index]->broadcast(esc_msg);
}
}
void AP_UAVCAN::SRV_push_servos()
{
WITH_SEMAPHORE(SRV_sem);
for (uint8_t i = 0; i < NUM_SERVO_CHANNELS; i++) {
// Check if this channels has any function assigned
if (SRV_Channels::channel_function(i)) {
_SRV_conf[i].pulse = SRV_Channels::srv_channel(i)->get_output_pwm();
_SRV_conf[i].esc_pending = true;
_SRV_conf[i].servo_pending = true;
}
}
_SRV_armed = hal.util->safety_switch_state() != AP_HAL::Util::SAFETY_DISARMED;
}
///// LED /////
void AP_UAVCAN::led_out_send()
{
uint64_t now = AP_HAL::micros64();
if ((now - _led_conf.last_update) < LED_DELAY_US) {
return;
}
uavcan::equipment::indication::LightsCommand msg;
{
WITH_SEMAPHORE(_led_out_sem);
if (_led_conf.devices_count == 0) {
return;
}
uavcan::equipment::indication::SingleLightCommand cmd;
for (uint8_t i = 0; i < _led_conf.devices_count; i++) {
cmd.light_id =_led_conf.devices[i].led_index;
cmd.color.red = _led_conf.devices[i].red >> 3;
cmd.color.green = _led_conf.devices[i].green >> 2;
cmd.color.blue = _led_conf.devices[i].blue >> 3;
msg.commands.push_back(cmd);
}
}
rgb_led[_driver_index]->broadcast(msg);
_led_conf.last_update = now;
}
bool AP_UAVCAN::led_write(uint8_t led_index, uint8_t red, uint8_t green, uint8_t blue)
{
if (_led_conf.devices_count >= AP_UAVCAN_MAX_LED_DEVICES) {
return false;
}
WITH_SEMAPHORE(_led_out_sem);
// check if a device instance exists. if so, break so the instance index is remembered
uint8_t instance = 0;
for (; instance < _led_conf.devices_count; instance++) {
if (_led_conf.devices[instance].led_index == led_index) {
break;
}
}
// load into the correct instance.
// if an existing instance was found in above for loop search,
// then instance value is < _led_conf.devices_count.
// otherwise a new one was just found so we increment the count.
// Either way, the correct instance is the current value of instance
_led_conf.devices[instance].led_index = led_index;
_led_conf.devices[instance].red = red;
_led_conf.devices[instance].green = green;
_led_conf.devices[instance].blue = blue;
if (instance == _led_conf.devices_count) {
_led_conf.devices_count++;
}
return true;
}
// buzzer send
void AP_UAVCAN::buzzer_send()
{
uavcan::equipment::indication::BeepCommand msg;
WITH_SEMAPHORE(_buzzer.sem);
uint8_t mask = (1U << _driver_index);
if ((_buzzer.pending_mask & mask) == 0) {
return;
}
_buzzer.pending_mask &= ~mask;
msg.frequency = _buzzer.frequency;
msg.duration = _buzzer.duration;
buzzer[_driver_index]->broadcast(msg);
}
// buzzer support
void AP_UAVCAN::set_buzzer_tone(float frequency, float duration_s)
{
WITH_SEMAPHORE(_buzzer.sem);
_buzzer.frequency = frequency;
_buzzer.duration = duration_s;
_buzzer.pending_mask = 0xFF;
}
// SafetyState send
void AP_UAVCAN::safety_state_send()
{
ardupilot::indication::SafetyState msg;
uint32_t now = AP_HAL::millis();
if (now - _last_safety_state_ms < 500) {
// update at 2Hz
return;
}
_last_safety_state_ms = now;
switch (hal.util->safety_switch_state()) {
case AP_HAL::Util::SAFETY_ARMED:
msg.status = ardupilot::indication::SafetyState::STATUS_SAFETY_OFF;
break;
case AP_HAL::Util::SAFETY_DISARMED:
msg.status = ardupilot::indication::SafetyState::STATUS_SAFETY_ON;
break;
default:
// nothing to send
return;
}
safety_state[_driver_index]->broadcast(msg);
}
/*
handle Button message
*/
void AP_UAVCAN::handle_button(AP_UAVCAN* ap_uavcan, uint8_t node_id, const ButtonCb &cb)
{
switch (cb.msg->button) {
case ardupilot::indication::Button::BUTTON_SAFETY: {
AP_BoardConfig *brdconfig = AP_BoardConfig::get_singleton();
if (brdconfig && brdconfig->safety_button_handle_pressed(cb.msg->press_time)) {
AP_HAL::Util::safety_state state = hal.util->safety_switch_state();
if (state == AP_HAL::Util::SAFETY_ARMED) {
hal.rcout->force_safety_on();
} else {
hal.rcout->force_safety_off();
}
}
break;
}
}
}
AP_UAVCAN *AP_UAVCAN::_singleton;
namespace AP {
AP_UAVCAN &uavcan()
{
return *AP_UAVCAN::get_singleton();
}
};
#endif // HAL_WITH_UAVCAN