2014-12-06 19:30:25 -08:00
|
|
|
/*
|
2020-01-28 10:46:19 -08:00
|
|
|
Copyright 2016 - 2020 Benjamin Vedder benjamin@vedder.se
|
2014-12-06 19:30:25 -08:00
|
|
|
|
2016-11-04 07:18:34 -07:00
|
|
|
This file is part of the VESC firmware.
|
|
|
|
|
|
|
|
The VESC firmware is free software: you can redistribute it and/or modify
|
2014-12-06 19:30:25 -08:00
|
|
|
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.
|
|
|
|
|
2016-11-04 07:18:34 -07:00
|
|
|
The VESC firmware is distributed in the hope that it will be useful,
|
2014-12-06 19:30:25 -08:00
|
|
|
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/>.
|
2016-11-04 07:18:34 -07:00
|
|
|
*/
|
2014-12-06 19:30:25 -08:00
|
|
|
|
2015-04-26 15:02:32 -07:00
|
|
|
#include <string.h>
|
2017-09-04 12:12:43 -07:00
|
|
|
#include <math.h>
|
2014-12-06 19:30:25 -08:00
|
|
|
#include "comm_can.h"
|
|
|
|
#include "ch.h"
|
|
|
|
#include "hal.h"
|
2015-10-08 14:09:39 -07:00
|
|
|
#include "stm32f4xx_conf.h"
|
2014-12-06 19:30:25 -08:00
|
|
|
#include "datatypes.h"
|
|
|
|
#include "buffer.h"
|
2015-12-08 12:01:23 -08:00
|
|
|
#include "mc_interface.h"
|
2014-12-06 19:30:25 -08:00
|
|
|
#include "timeout.h"
|
|
|
|
#include "commands.h"
|
2015-02-19 12:20:07 -08:00
|
|
|
#include "app.h"
|
2015-04-26 15:02:32 -07:00
|
|
|
#include "crc.h"
|
2015-05-20 07:13:48 -07:00
|
|
|
#include "packet.h"
|
2019-02-18 10:30:19 -08:00
|
|
|
#include "hw.h"
|
|
|
|
#include "canard_driver.h"
|
2020-01-28 10:46:19 -08:00
|
|
|
#include "encoder.h"
|
2020-03-16 10:32:39 -07:00
|
|
|
#include "utils.h"
|
|
|
|
#include "mempools.h"
|
2020-03-20 09:35:25 -07:00
|
|
|
#include "shutdown.h"
|
2020-10-21 23:32:51 -07:00
|
|
|
#include "bms.h"
|
2014-12-06 19:30:25 -08:00
|
|
|
|
|
|
|
// Settings
|
2015-05-20 07:13:48 -07:00
|
|
|
#define RX_FRAMES_SIZE 100
|
|
|
|
#define RX_BUFFER_SIZE PACKET_MAX_PL_LEN
|
2014-12-06 19:30:25 -08:00
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
#if CAN_ENABLE
|
2014-12-06 19:30:25 -08:00
|
|
|
// Threads
|
2015-10-08 14:09:39 -07:00
|
|
|
static THD_WORKING_AREA(cancom_read_thread_wa, 512);
|
|
|
|
static THD_WORKING_AREA(cancom_process_thread_wa, 4096);
|
2020-03-16 10:32:39 -07:00
|
|
|
static THD_WORKING_AREA(cancom_status_thread_wa, 512);
|
2015-10-08 14:09:39 -07:00
|
|
|
static THD_FUNCTION(cancom_read_thread, arg);
|
|
|
|
static THD_FUNCTION(cancom_status_thread, arg);
|
|
|
|
static THD_FUNCTION(cancom_process_thread, arg);
|
2015-02-19 12:20:07 -08:00
|
|
|
|
2020-03-16 10:32:39 -07:00
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
static THD_FUNCTION(cancom_status_internal_thread, arg);
|
|
|
|
static THD_WORKING_AREA(cancom_status_internal_thread_wa, 512);
|
|
|
|
#endif
|
|
|
|
|
2015-10-08 14:09:39 -07:00
|
|
|
static mutex_t can_mtx;
|
2019-02-18 10:30:19 -08:00
|
|
|
static mutex_t can_rx_mtx;
|
2015-05-20 07:13:48 -07:00
|
|
|
static uint8_t rx_buffer[RX_BUFFER_SIZE];
|
|
|
|
static unsigned int rx_buffer_last_id;
|
2015-05-08 13:53:59 -07:00
|
|
|
static CANRxFrame rx_frames[RX_FRAMES_SIZE];
|
|
|
|
static int rx_frame_read;
|
|
|
|
static int rx_frame_write;
|
2019-02-18 10:30:19 -08:00
|
|
|
static thread_t *process_tp = 0;
|
|
|
|
static thread_t *ping_tp = 0;
|
2020-10-09 12:08:48 -07:00
|
|
|
static volatile HW_TYPE ping_hw_last = HW_TYPE_VESC;
|
2020-11-12 14:09:03 -08:00
|
|
|
static volatile int ping_hw_last_id = -1;
|
2019-02-18 10:30:19 -08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Variables
|
|
|
|
static can_status_msg stat_msgs[CAN_STATUS_MSGS_TO_STORE];
|
|
|
|
static can_status_msg_2 stat_msgs_2[CAN_STATUS_MSGS_TO_STORE];
|
|
|
|
static can_status_msg_3 stat_msgs_3[CAN_STATUS_MSGS_TO_STORE];
|
|
|
|
static can_status_msg_4 stat_msgs_4[CAN_STATUS_MSGS_TO_STORE];
|
2019-05-16 14:30:40 -07:00
|
|
|
static can_status_msg_5 stat_msgs_5[CAN_STATUS_MSGS_TO_STORE];
|
2020-10-09 12:08:48 -07:00
|
|
|
static io_board_adc_values io_board_adc_1_4[CAN_STATUS_MSGS_TO_STORE];
|
|
|
|
static io_board_adc_values io_board_adc_5_8[CAN_STATUS_MSGS_TO_STORE];
|
|
|
|
static io_board_digial_inputs io_board_digital_in[CAN_STATUS_MSGS_TO_STORE];
|
2019-02-18 10:30:19 -08:00
|
|
|
static unsigned int detect_all_foc_res_index = 0;
|
|
|
|
static int8_t detect_all_foc_res[50];
|
2014-12-06 19:30:25 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 500KBaud, automatic wakeup, automatic recover
|
|
|
|
* from abort mode.
|
|
|
|
* See section 22.7.7 on the STM32 reference manual.
|
|
|
|
*/
|
2017-11-08 13:04:56 -08:00
|
|
|
static CANConfig cancfg = {
|
2015-02-19 12:20:07 -08:00
|
|
|
CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP,
|
2017-11-08 05:07:35 -08:00
|
|
|
CAN_BTR_SJW(3) | CAN_BTR_TS2(2) |
|
|
|
|
CAN_BTR_TS1(9) | CAN_BTR_BRP(5)
|
2014-12-06 19:30:25 -08:00
|
|
|
};
|
|
|
|
|
2015-04-26 15:02:32 -07:00
|
|
|
// Private functions
|
2020-03-16 10:32:39 -07:00
|
|
|
static void set_timing(int brp, int ts1, int ts2);
|
2019-02-18 10:30:19 -08:00
|
|
|
#if CAN_ENABLE
|
2015-05-20 07:13:48 -07:00
|
|
|
static void send_packet_wrapper(unsigned char *data, unsigned int len);
|
2020-03-16 10:32:39 -07:00
|
|
|
static void decode_msg(uint32_t eid, uint8_t *data8, int len, bool is_replaced);
|
|
|
|
static void send_status1(uint8_t id, bool replace);
|
|
|
|
static void send_status2(uint8_t id, bool replace);
|
|
|
|
static void send_status3(uint8_t id, bool replace);
|
|
|
|
static void send_status4(uint8_t id, bool replace);
|
|
|
|
static void send_status5(uint8_t id, bool replace);
|
2019-02-18 10:30:19 -08:00
|
|
|
#endif
|
2015-04-26 15:02:32 -07:00
|
|
|
|
2017-10-28 02:06:21 -07:00
|
|
|
// Function pointers
|
|
|
|
static void(*sid_callback)(uint32_t id, uint8_t *data, uint8_t len) = 0;
|
2020-01-28 10:46:19 -08:00
|
|
|
static void(*eid_callback)(uint32_t id, uint8_t *data, uint8_t len) = 0;
|
2017-10-28 02:06:21 -07:00
|
|
|
|
2014-12-06 19:30:25 -08:00
|
|
|
void comm_can_init(void) {
|
2015-02-19 12:20:07 -08:00
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
stat_msgs[i].id = -1;
|
2019-02-18 10:30:19 -08:00
|
|
|
stat_msgs_2[i].id = -1;
|
|
|
|
stat_msgs_3[i].id = -1;
|
|
|
|
stat_msgs_4[i].id = -1;
|
2020-08-13 04:53:29 -07:00
|
|
|
stat_msgs_5[i].id = -1;
|
2020-10-09 12:08:48 -07:00
|
|
|
|
|
|
|
io_board_adc_1_4[i].id = -1;
|
|
|
|
io_board_adc_5_8[i].id = -1;
|
|
|
|
io_board_digital_in[i].id = -1;
|
2015-02-19 12:20:07 -08:00
|
|
|
}
|
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
#if CAN_ENABLE
|
2015-05-08 13:53:59 -07:00
|
|
|
rx_frame_read = 0;
|
|
|
|
rx_frame_write = 0;
|
|
|
|
|
2015-10-08 14:09:39 -07:00
|
|
|
chMtxObjectInit(&can_mtx);
|
2019-02-18 10:30:19 -08:00
|
|
|
chMtxObjectInit(&can_rx_mtx);
|
2015-02-19 12:20:07 -08:00
|
|
|
|
2020-03-16 10:32:39 -07:00
|
|
|
palSetPadMode(HW_CANRX_PORT, HW_CANRX_PIN,
|
2019-02-18 10:30:19 -08:00
|
|
|
PAL_MODE_ALTERNATE(HW_CAN_GPIO_AF) |
|
2014-12-06 19:30:25 -08:00
|
|
|
PAL_STM32_OTYPE_PUSHPULL |
|
|
|
|
PAL_STM32_OSPEED_MID1);
|
2020-03-16 10:32:39 -07:00
|
|
|
palSetPadMode(HW_CANTX_PORT, HW_CANTX_PIN,
|
2019-02-18 10:30:19 -08:00
|
|
|
PAL_MODE_ALTERNATE(HW_CAN_GPIO_AF) |
|
2014-12-06 19:30:25 -08:00
|
|
|
PAL_STM32_OTYPE_PUSHPULL |
|
|
|
|
PAL_STM32_OSPEED_MID1);
|
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
canStart(&HW_CAN_DEV, &cancfg);
|
|
|
|
|
|
|
|
canard_driver_init();
|
2014-12-06 19:30:25 -08:00
|
|
|
|
2015-05-08 13:53:59 -07:00
|
|
|
chThdCreateStatic(cancom_read_thread_wa, sizeof(cancom_read_thread_wa), NORMALPRIO + 1,
|
|
|
|
cancom_read_thread, NULL);
|
2015-02-19 12:20:07 -08:00
|
|
|
chThdCreateStatic(cancom_status_thread_wa, sizeof(cancom_status_thread_wa), NORMALPRIO,
|
|
|
|
cancom_status_thread, NULL);
|
2015-05-08 13:53:59 -07:00
|
|
|
chThdCreateStatic(cancom_process_thread_wa, sizeof(cancom_process_thread_wa), NORMALPRIO,
|
|
|
|
cancom_process_thread, NULL);
|
2020-03-16 10:32:39 -07:00
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
chThdCreateStatic(cancom_status_internal_thread_wa, sizeof(cancom_status_internal_thread_wa),
|
|
|
|
NORMALPRIO, cancom_status_internal_thread, NULL);
|
|
|
|
#endif
|
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
#endif
|
2014-12-06 19:30:25 -08:00
|
|
|
}
|
|
|
|
|
2017-11-08 05:07:35 -08:00
|
|
|
void comm_can_set_baud(CAN_BAUD baud) {
|
|
|
|
switch (baud) {
|
|
|
|
case CAN_BAUD_125K: set_timing(15, 14, 4); break;
|
|
|
|
case CAN_BAUD_250K: set_timing(7, 14, 4); break;
|
|
|
|
case CAN_BAUD_500K: set_timing(5, 9, 2); break;
|
|
|
|
case CAN_BAUD_1M: set_timing(2, 9, 2); break;
|
2020-01-31 15:37:25 -08:00
|
|
|
case CAN_BAUD_10K: set_timing(299, 10, 1); break;
|
|
|
|
case CAN_BAUD_20K: set_timing(149, 10, 1); break;
|
|
|
|
case CAN_BAUD_50K: set_timing(59, 10, 1); break;
|
|
|
|
case CAN_BAUD_75K: set_timing(39, 10, 1); break;
|
2017-11-08 05:07:35 -08:00
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-16 10:32:39 -07:00
|
|
|
/**
|
|
|
|
* Transmit CAN packet with extended ID.
|
|
|
|
*
|
|
|
|
* @param id
|
|
|
|
* EID
|
|
|
|
*
|
|
|
|
* @param data
|
|
|
|
* Data
|
|
|
|
*
|
|
|
|
* @param len
|
|
|
|
* Length of data, max 8 bytes.
|
|
|
|
*
|
|
|
|
* @param replace
|
|
|
|
* Process packets for motor2 directly instead of sending them. Unused
|
|
|
|
* on single motor hardware.
|
|
|
|
*/
|
|
|
|
void comm_can_transmit_eid_replace(uint32_t id, const uint8_t *data, uint8_t len, bool replace) {
|
2017-10-28 02:06:21 -07:00
|
|
|
if (len > 8) {
|
|
|
|
len = 8;
|
|
|
|
}
|
|
|
|
|
2015-04-27 11:43:02 -07:00
|
|
|
#if CAN_ENABLE
|
2020-03-16 10:32:39 -07:00
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
if (app_get_configuration()->can_mode == CAN_MODE_VESC) {
|
|
|
|
if (replace && ((id & 0xFF) == utils_second_motor_id() ||
|
|
|
|
(id & 0xFF) == app_get_configuration()->controller_id)) {
|
|
|
|
uint8_t data_tmp[10];
|
|
|
|
memcpy(data_tmp, data, len);
|
|
|
|
decode_msg(id, data_tmp, len, true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
(void)replace;
|
|
|
|
#endif
|
|
|
|
|
2015-05-08 13:53:59 -07:00
|
|
|
CANTxFrame txmsg;
|
|
|
|
txmsg.IDE = CAN_IDE_EXT;
|
|
|
|
txmsg.EID = id;
|
|
|
|
txmsg.RTR = CAN_RTR_DATA;
|
|
|
|
txmsg.DLC = len;
|
|
|
|
memcpy(txmsg.data8, data, len);
|
2014-12-06 19:30:25 -08:00
|
|
|
|
2015-05-08 13:53:59 -07:00
|
|
|
chMtxLock(&can_mtx);
|
2019-02-18 10:30:19 -08:00
|
|
|
canTransmit(&HW_CAN_DEV, CAN_ANY_MAILBOX, &txmsg, MS2ST(5));
|
2015-10-08 14:09:39 -07:00
|
|
|
chMtxUnlock(&can_mtx);
|
2015-04-27 11:43:02 -07:00
|
|
|
#else
|
|
|
|
(void)id;
|
|
|
|
(void)data;
|
|
|
|
(void)len;
|
2020-03-16 10:32:39 -07:00
|
|
|
(void)replace;
|
2015-04-27 11:43:02 -07:00
|
|
|
#endif
|
2014-12-06 19:30:25 -08:00
|
|
|
}
|
|
|
|
|
2020-03-16 10:32:39 -07:00
|
|
|
void comm_can_transmit_eid(uint32_t id, const uint8_t *data, uint8_t len) {
|
|
|
|
comm_can_transmit_eid_replace(id, data, len, true);
|
|
|
|
}
|
|
|
|
|
2017-10-28 02:06:21 -07:00
|
|
|
void comm_can_transmit_sid(uint32_t id, uint8_t *data, uint8_t len) {
|
|
|
|
if (len > 8) {
|
|
|
|
len = 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if CAN_ENABLE
|
|
|
|
CANTxFrame txmsg;
|
|
|
|
txmsg.IDE = CAN_IDE_STD;
|
|
|
|
txmsg.SID = id;
|
|
|
|
txmsg.RTR = CAN_RTR_DATA;
|
|
|
|
txmsg.DLC = len;
|
|
|
|
memcpy(txmsg.data8, data, len);
|
|
|
|
|
|
|
|
chMtxLock(&can_mtx);
|
2019-02-18 10:30:19 -08:00
|
|
|
canTransmit(&HW_CAN_DEV, CAN_ANY_MAILBOX, &txmsg, MS2ST(5));
|
2017-10-28 02:06:21 -07:00
|
|
|
chMtxUnlock(&can_mtx);
|
|
|
|
#else
|
|
|
|
(void)id;
|
|
|
|
(void)data;
|
|
|
|
(void)len;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set function to be called when standard CAN frames are received.
|
|
|
|
*
|
|
|
|
* @param p_func
|
|
|
|
* Pointer to the function.
|
|
|
|
*/
|
|
|
|
void comm_can_set_sid_rx_callback(void (*p_func)(uint32_t id, uint8_t *data, uint8_t len)) {
|
|
|
|
sid_callback = p_func;
|
|
|
|
}
|
|
|
|
|
2020-01-28 10:46:19 -08:00
|
|
|
/**
|
|
|
|
* Set function to be called when extended CAN frames are received. Will only be called when
|
|
|
|
* the CAN mode is CAN_MODE_COMM_BRIDGE.
|
|
|
|
*
|
|
|
|
* @param p_func
|
|
|
|
* Pointer to the function.
|
|
|
|
*/
|
|
|
|
void comm_can_set_eid_rx_callback(void (*p_func)(uint32_t id, uint8_t *data, uint8_t len)) {
|
|
|
|
eid_callback = p_func;
|
|
|
|
}
|
|
|
|
|
2015-04-26 15:02:32 -07:00
|
|
|
/**
|
2015-05-20 07:13:48 -07:00
|
|
|
* Send a buffer up to RX_BUFFER_SIZE bytes as fragments. If the buffer is 6 bytes or less
|
2015-04-27 11:43:02 -07:00
|
|
|
* it will be sent in a single CAN frame, otherwise it will be split into
|
|
|
|
* several frames.
|
2015-04-26 15:02:32 -07:00
|
|
|
*
|
|
|
|
* @param controller_id
|
|
|
|
* The controller id to send to.
|
|
|
|
*
|
|
|
|
* @param data
|
|
|
|
* The payload.
|
|
|
|
*
|
|
|
|
* @param len
|
|
|
|
* The payload length.
|
|
|
|
*
|
|
|
|
* @param send
|
2019-02-18 10:30:19 -08:00
|
|
|
* 0: Packet goes to commands_process_packet of receiver
|
|
|
|
* 1: Packet goes to commands_send_packet of receiver
|
|
|
|
* 2: Packet goes to commands_process and send function is set to null
|
|
|
|
* so that no reply is sent back.
|
2015-04-26 15:02:32 -07:00
|
|
|
*/
|
2019-02-18 10:30:19 -08:00
|
|
|
void comm_can_send_buffer(uint8_t controller_id, uint8_t *data, unsigned int len, uint8_t send) {
|
2015-04-26 15:02:32 -07:00
|
|
|
uint8_t send_buffer[8];
|
|
|
|
|
2015-04-27 11:43:02 -07:00
|
|
|
if (len <= 6) {
|
|
|
|
uint32_t ind = 0;
|
|
|
|
send_buffer[ind++] = app_get_configuration()->controller_id;
|
|
|
|
send_buffer[ind++] = send;
|
|
|
|
memcpy(send_buffer + ind, data, len);
|
|
|
|
ind += len;
|
2017-09-04 12:12:43 -07:00
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_PROCESS_SHORT_BUFFER << 8), send_buffer, ind);
|
2015-04-27 11:43:02 -07:00
|
|
|
} else {
|
2015-05-20 07:13:48 -07:00
|
|
|
unsigned int end_a = 0;
|
|
|
|
for (unsigned int i = 0;i < len;i += 7) {
|
2015-12-27 16:50:23 -08:00
|
|
|
if (i > 255) {
|
2015-05-20 07:13:48 -07:00
|
|
|
break;
|
|
|
|
}
|
2015-04-27 11:43:02 -07:00
|
|
|
|
2016-01-24 04:44:51 -08:00
|
|
|
end_a = i + 7;
|
|
|
|
|
2015-05-20 07:13:48 -07:00
|
|
|
uint8_t send_len = 7;
|
2015-04-27 11:43:02 -07:00
|
|
|
send_buffer[0] = i;
|
|
|
|
|
|
|
|
if ((i + 7) <= len) {
|
|
|
|
memcpy(send_buffer + 1, data + i, send_len);
|
|
|
|
} else {
|
|
|
|
send_len = len - i;
|
|
|
|
memcpy(send_buffer + 1, data + i, send_len);
|
|
|
|
}
|
2015-04-26 15:02:32 -07:00
|
|
|
|
2017-09-04 12:12:43 -07:00
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_FILL_RX_BUFFER << 8), send_buffer, send_len + 1);
|
2015-04-26 15:02:32 -07:00
|
|
|
}
|
|
|
|
|
2015-05-20 07:13:48 -07:00
|
|
|
for (unsigned int i = end_a;i < len;i += 6) {
|
|
|
|
uint8_t send_len = 6;
|
|
|
|
send_buffer[0] = i >> 8;
|
|
|
|
send_buffer[1] = i & 0xFF;
|
|
|
|
|
|
|
|
if ((i + 6) <= len) {
|
|
|
|
memcpy(send_buffer + 2, data + i, send_len);
|
|
|
|
} else {
|
|
|
|
send_len = len - i;
|
|
|
|
memcpy(send_buffer + 2, data + i, send_len);
|
|
|
|
}
|
|
|
|
|
2017-09-04 12:12:43 -07:00
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_FILL_RX_BUFFER_LONG << 8), send_buffer, send_len + 2);
|
2015-05-20 07:13:48 -07:00
|
|
|
}
|
|
|
|
|
2015-04-27 11:43:02 -07:00
|
|
|
uint32_t ind = 0;
|
|
|
|
send_buffer[ind++] = app_get_configuration()->controller_id;
|
|
|
|
send_buffer[ind++] = send;
|
2015-05-20 07:13:48 -07:00
|
|
|
send_buffer[ind++] = len >> 8;
|
|
|
|
send_buffer[ind++] = len & 0xFF;
|
2015-04-27 11:43:02 -07:00
|
|
|
unsigned short crc = crc16(data, len);
|
|
|
|
send_buffer[ind++] = (uint8_t)(crc >> 8);
|
|
|
|
send_buffer[ind++] = (uint8_t)(crc & 0xFF);
|
2015-04-26 15:02:32 -07:00
|
|
|
|
2017-09-04 12:12:43 -07:00
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_PROCESS_RX_BUFFER << 8), send_buffer, ind++);
|
2015-04-27 11:43:02 -07:00
|
|
|
}
|
2015-04-26 15:02:32 -07:00
|
|
|
}
|
|
|
|
|
2014-12-06 19:30:25 -08:00
|
|
|
void comm_can_set_duty(uint8_t controller_id, float duty) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[4];
|
|
|
|
buffer_append_int32(buffer, (int32_t)(duty * 100000.0), &send_index);
|
2017-09-04 12:12:43 -07:00
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_SET_DUTY << 8), buffer, send_index);
|
2014-12-06 19:30:25 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void comm_can_set_current(uint8_t controller_id, float current) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[4];
|
|
|
|
buffer_append_int32(buffer, (int32_t)(current * 1000.0), &send_index);
|
2017-09-04 12:12:43 -07:00
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_SET_CURRENT << 8), buffer, send_index);
|
2014-12-06 19:30:25 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void comm_can_set_current_brake(uint8_t controller_id, float current) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[4];
|
|
|
|
buffer_append_int32(buffer, (int32_t)(current * 1000.0), &send_index);
|
2017-09-04 12:12:43 -07:00
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_SET_CURRENT_BRAKE << 8), buffer, send_index);
|
2014-12-06 19:30:25 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void comm_can_set_rpm(uint8_t controller_id, float rpm) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[4];
|
|
|
|
buffer_append_int32(buffer, (int32_t)rpm, &send_index);
|
2017-09-04 12:12:43 -07:00
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_SET_RPM << 8), buffer, send_index);
|
2014-12-06 19:30:25 -08:00
|
|
|
}
|
2015-02-19 12:20:07 -08:00
|
|
|
|
2015-04-26 15:02:32 -07:00
|
|
|
void comm_can_set_pos(uint8_t controller_id, float pos) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[4];
|
|
|
|
buffer_append_int32(buffer, (int32_t)(pos * 1000000.0), &send_index);
|
2017-09-04 12:12:43 -07:00
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_SET_POS << 8), buffer, send_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set current relative to the minimum and maximum current limits.
|
|
|
|
*
|
|
|
|
* @param controller_id
|
|
|
|
* The ID of the VESC to set the current on.
|
|
|
|
*
|
|
|
|
* @param current_rel
|
|
|
|
* The relative current value, range [-1.0 1.0]
|
|
|
|
*/
|
|
|
|
void comm_can_set_current_rel(uint8_t controller_id, float current_rel) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[4];
|
|
|
|
buffer_append_float32(buffer, current_rel, 1e5, &send_index);
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_SET_CURRENT_REL << 8), buffer, send_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set brake current relative to the minimum current limit.
|
|
|
|
*
|
|
|
|
* @param controller_id
|
|
|
|
* The ID of the VESC to set the current on.
|
|
|
|
*
|
|
|
|
* @param current_rel
|
|
|
|
* The relative current value, range [0.0 1.0]
|
|
|
|
*/
|
|
|
|
void comm_can_set_current_brake_rel(uint8_t controller_id, float current_rel) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[4];
|
|
|
|
buffer_append_float32(buffer, current_rel, 1e5, &send_index);
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_SET_CURRENT_BRAKE_REL << 8), buffer, send_index);
|
2018-03-02 02:48:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set handbrake current.
|
|
|
|
*
|
|
|
|
* @param controller_id
|
|
|
|
* The ID of the VESC to set the handbrake current on.
|
|
|
|
*
|
|
|
|
* @param current_rel
|
|
|
|
* The handbrake current value
|
|
|
|
*/
|
|
|
|
void comm_can_set_handbrake(uint8_t controller_id, float current) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[4];
|
|
|
|
buffer_append_float32(buffer, current, 1e3, &send_index);
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_SET_CURRENT_HANDBRAKE << 8), buffer, send_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set handbrake current relative to the minimum current limit.
|
|
|
|
*
|
|
|
|
* @param controller_id
|
|
|
|
* The ID of the VESC to set the handbrake current on.
|
|
|
|
*
|
|
|
|
* @param current_rel
|
|
|
|
* The relative handbrake current value, range [0.0 1.0]
|
|
|
|
*/
|
|
|
|
void comm_can_set_handbrake_rel(uint8_t controller_id, float current_rel) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[4];
|
|
|
|
buffer_append_float32(buffer, current_rel, 1e5, &send_index);
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_SET_CURRENT_HANDBRAKE_REL << 8), buffer, send_index);
|
2015-04-26 15:02:32 -07:00
|
|
|
}
|
|
|
|
|
2015-02-19 12:20:07 -08:00
|
|
|
/**
|
2019-02-18 10:30:19 -08:00
|
|
|
* Check if a VESC on the CAN-bus responds.
|
2015-02-19 12:20:07 -08:00
|
|
|
*
|
2019-02-18 10:30:19 -08:00
|
|
|
* @param controller_id
|
|
|
|
* The ID of the VESC.
|
2015-02-19 12:20:07 -08:00
|
|
|
*
|
2020-10-09 12:08:48 -07:00
|
|
|
* @param hw_type
|
|
|
|
* The hardware type of the CAN device.
|
|
|
|
*
|
2015-02-19 12:20:07 -08:00
|
|
|
* @return
|
2019-02-18 10:30:19 -08:00
|
|
|
* True for success, false otherwise.
|
2015-02-19 12:20:07 -08:00
|
|
|
*/
|
2020-10-09 12:08:48 -07:00
|
|
|
bool comm_can_ping(uint8_t controller_id, HW_TYPE *hw_type) {
|
2019-03-31 01:49:18 -07:00
|
|
|
#if CAN_ENABLE
|
2020-01-28 10:46:19 -08:00
|
|
|
if (app_get_configuration()->can_mode != CAN_MODE_VESC) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-03-16 10:32:39 -07:00
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
if (controller_id == app_get_configuration()->controller_id) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
ping_tp = chThdGetSelfX();
|
|
|
|
chEvtGetAndClearEvents(ALL_EVENTS);
|
|
|
|
|
2020-11-12 14:09:03 -08:00
|
|
|
ping_hw_last_id = controller_id;
|
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
uint8_t buffer[1];
|
|
|
|
buffer[0] = app_get_configuration()->controller_id;
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_PING << 8), buffer, 1);
|
|
|
|
|
|
|
|
int ret = chEvtWaitAnyTimeout(1 << 29, MS2ST(10));
|
|
|
|
ping_tp = 0;
|
2020-10-09 12:08:48 -07:00
|
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
if (hw_type) {
|
|
|
|
*hw_type = ping_hw_last;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
return ret != 0;
|
2019-03-31 01:49:18 -07:00
|
|
|
#else
|
|
|
|
(void)controller_id;
|
|
|
|
return 0;
|
|
|
|
#endif
|
2015-02-19 12:20:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-02-18 10:30:19 -08:00
|
|
|
* Detect and apply FOC settings.
|
2015-02-19 12:20:07 -08:00
|
|
|
*
|
2019-02-18 10:30:19 -08:00
|
|
|
* @param controller_id
|
|
|
|
* The ID of the VESC.
|
2015-02-19 12:20:07 -08:00
|
|
|
*
|
2019-02-18 10:30:19 -08:00
|
|
|
* @param activate_status_msgs
|
|
|
|
* Activate CAN status messages on the target VESC on success.
|
|
|
|
*
|
|
|
|
* @param max_power_loss
|
|
|
|
* Maximum accepted power losses.
|
2015-02-19 12:20:07 -08:00
|
|
|
*/
|
2019-02-18 10:30:19 -08:00
|
|
|
void comm_can_detect_apply_all_foc(uint8_t controller_id, bool activate_status_msgs, float max_power_loss) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[6];
|
|
|
|
buffer[send_index++] = app_get_configuration()->controller_id;
|
|
|
|
buffer[send_index++] = activate_status_msgs;
|
|
|
|
buffer_append_float32(buffer, max_power_loss, 1e3, &send_index);
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_DETECT_APPLY_ALL_FOC << 8), buffer, send_index);
|
2015-02-19 12:20:07 -08:00
|
|
|
}
|
2015-04-26 15:02:32 -07:00
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
/**
|
|
|
|
* Update current limits on VESC on CAN-bus.
|
|
|
|
*
|
|
|
|
* @param controller_id
|
|
|
|
* ID of the VESC.
|
|
|
|
*
|
|
|
|
* @param store
|
|
|
|
* Store parameters in emulated EEPROM (FLASH).
|
|
|
|
*
|
|
|
|
* @param min
|
|
|
|
* Minimum current (negative value).
|
|
|
|
*
|
|
|
|
* @param max
|
|
|
|
* Maximum current.
|
|
|
|
*/
|
|
|
|
void comm_can_conf_current_limits(uint8_t controller_id,
|
|
|
|
bool store, float min, float max) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
buffer_append_float32(buffer, min, 1e3, &send_index);
|
|
|
|
buffer_append_float32(buffer, max, 1e3, &send_index);
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)(store ? CAN_PACKET_CONF_STORE_CURRENT_LIMITS :
|
|
|
|
CAN_PACKET_CONF_CURRENT_LIMITS) << 8), buffer, send_index);
|
2015-04-26 15:02:32 -07:00
|
|
|
}
|
2017-11-08 05:07:35 -08:00
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
/**
|
|
|
|
* Update input current limits on VESC on CAN-bus.
|
|
|
|
*
|
|
|
|
* @param controller_id
|
|
|
|
* ID of the VESC.
|
|
|
|
*
|
|
|
|
* @param store
|
|
|
|
* Store parameters in emulated EEPROM (FLASH).
|
|
|
|
*
|
|
|
|
* @param min
|
|
|
|
* Minimum current (negative value).
|
|
|
|
*
|
|
|
|
* @param max
|
|
|
|
* Maximum current.
|
|
|
|
*/
|
|
|
|
void comm_can_conf_current_limits_in(uint8_t controller_id,
|
|
|
|
bool store, float min, float max) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
buffer_append_float32(buffer, min, 1e3, &send_index);
|
|
|
|
buffer_append_float32(buffer, max, 1e3, &send_index);
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)(store ? CAN_PACKET_CONF_STORE_CURRENT_LIMITS_IN :
|
|
|
|
CAN_PACKET_CONF_CURRENT_LIMITS_IN) << 8), buffer, send_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update FOC ERPM settings on VESC on CAN-bus.
|
|
|
|
*
|
|
|
|
* @param controller_id
|
|
|
|
* ID of the VESC.
|
|
|
|
*
|
|
|
|
* @param store
|
|
|
|
* Store parameters in emulated EEPROM (FLASH).
|
|
|
|
*
|
|
|
|
* @param foc_openloop_rpm
|
|
|
|
* Run in openloop below this ERPM in sensorless mode.
|
|
|
|
*
|
|
|
|
* @param foc_sl_erpm
|
|
|
|
* Use sensors below this ERPM in sensored mode.
|
|
|
|
*/
|
|
|
|
void comm_can_conf_foc_erpms(uint8_t controller_id,
|
|
|
|
bool store, float foc_openloop_rpm, float foc_sl_erpm) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
buffer_append_float32(buffer, foc_openloop_rpm, 1e3, &send_index);
|
|
|
|
buffer_append_float32(buffer, foc_sl_erpm, 1e3, &send_index);
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)(store ? CAN_PACKET_CONF_STORE_FOC_ERPMS :
|
|
|
|
CAN_PACKET_CONF_FOC_ERPMS) << 8), buffer, send_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
int comm_can_detect_all_foc_res(unsigned int index) {
|
|
|
|
if (index < detect_all_foc_res_index) {
|
|
|
|
return detect_all_foc_res[detect_all_foc_res_index];
|
|
|
|
} else {
|
|
|
|
return -999;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int comm_can_detect_all_foc_res_size(void) {
|
|
|
|
return detect_all_foc_res_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
void comm_can_detect_all_foc_res_clear(void) {
|
|
|
|
detect_all_foc_res_index = 0;
|
|
|
|
}
|
|
|
|
|
2020-03-20 09:35:25 -07:00
|
|
|
void comm_can_conf_battery_cut(uint8_t controller_id,
|
|
|
|
bool store, float start, float end) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
buffer_append_float32(buffer, start, 1e3, &send_index);
|
|
|
|
buffer_append_float32(buffer, end, 1e3, &send_index);
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)(store ? CAN_PACKET_CONF_STORE_BATTERY_CUT :
|
|
|
|
CAN_PACKET_CONF_BATTERY_CUT) << 8), buffer, send_index);
|
|
|
|
}
|
|
|
|
|
2020-03-20 17:05:42 -07:00
|
|
|
void comm_can_shutdown(uint8_t controller_id) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
comm_can_transmit_eid(controller_id |
|
|
|
|
((uint32_t)(CAN_PACKET_SHUTDOWN) << 8), buffer, send_index);
|
|
|
|
}
|
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
/**
|
|
|
|
* Get status message by index.
|
|
|
|
*
|
|
|
|
* @param index
|
|
|
|
* Index in the array
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The message or 0 for an invalid index.
|
|
|
|
*/
|
|
|
|
can_status_msg *comm_can_get_status_msg_index(int index) {
|
|
|
|
if (index < CAN_STATUS_MSGS_TO_STORE) {
|
|
|
|
return &stat_msgs[index];
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get status message by id.
|
|
|
|
*
|
|
|
|
* @param id
|
|
|
|
* Id of the controller that sent the status message.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The message or 0 for an invalid id.
|
|
|
|
*/
|
|
|
|
can_status_msg *comm_can_get_status_msg_id(int id) {
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
if (stat_msgs[i].id == id) {
|
|
|
|
return &stat_msgs[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get status message 2 by index.
|
|
|
|
*
|
|
|
|
* @param index
|
|
|
|
* Index in the array
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The message or 0 for an invalid index.
|
|
|
|
*/
|
|
|
|
can_status_msg_2 *comm_can_get_status_msg_2_index(int index) {
|
|
|
|
if (index < CAN_STATUS_MSGS_TO_STORE) {
|
|
|
|
return &stat_msgs_2[index];
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get status message 2 by id.
|
|
|
|
*
|
|
|
|
* @param id
|
|
|
|
* Id of the controller that sent the status message.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The message or 0 for an invalid id.
|
|
|
|
*/
|
|
|
|
can_status_msg_2 *comm_can_get_status_msg_2_id(int id) {
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
if (stat_msgs_2[i].id == id) {
|
|
|
|
return &stat_msgs_2[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get status message 3 by index.
|
|
|
|
*
|
|
|
|
* @param index
|
|
|
|
* Index in the array
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The message or 0 for an invalid index.
|
|
|
|
*/
|
|
|
|
can_status_msg_3 *comm_can_get_status_msg_3_index(int index) {
|
|
|
|
if (index < CAN_STATUS_MSGS_TO_STORE) {
|
|
|
|
return &stat_msgs_3[index];
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get status message 3 by id.
|
|
|
|
*
|
|
|
|
* @param id
|
|
|
|
* Id of the controller that sent the status message.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The message or 0 for an invalid id.
|
|
|
|
*/
|
|
|
|
can_status_msg_3 *comm_can_get_status_msg_3_id(int id) {
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
if (stat_msgs_3[i].id == id) {
|
|
|
|
return &stat_msgs_3[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get status message 4 by index.
|
|
|
|
*
|
|
|
|
* @param index
|
|
|
|
* Index in the array
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The message or 0 for an invalid index.
|
|
|
|
*/
|
|
|
|
can_status_msg_4 *comm_can_get_status_msg_4_index(int index) {
|
|
|
|
if (index < CAN_STATUS_MSGS_TO_STORE) {
|
|
|
|
return &stat_msgs_4[index];
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get status message 4 by id.
|
|
|
|
*
|
|
|
|
* @param id
|
|
|
|
* Id of the controller that sent the status message.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The message or 0 for an invalid id.
|
|
|
|
*/
|
|
|
|
can_status_msg_4 *comm_can_get_status_msg_4_id(int id) {
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
if (stat_msgs_4[i].id == id) {
|
|
|
|
return &stat_msgs_4[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-16 14:30:40 -07:00
|
|
|
/**
|
|
|
|
* Get status message 5 by index.
|
|
|
|
*
|
|
|
|
* @param index
|
|
|
|
* Index in the array
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The message or 0 for an invalid index.
|
|
|
|
*/
|
|
|
|
can_status_msg_5 *comm_can_get_status_msg_5_index(int index) {
|
|
|
|
if (index < CAN_STATUS_MSGS_TO_STORE) {
|
|
|
|
return &stat_msgs_5[index];
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get status message 5 by id.
|
|
|
|
*
|
|
|
|
* @param id
|
|
|
|
* Id of the controller that sent the status message.
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* The message or 0 for an invalid id.
|
|
|
|
*/
|
|
|
|
can_status_msg_5 *comm_can_get_status_msg_5_id(int id) {
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
if (stat_msgs_5[i].id == id) {
|
|
|
|
return &stat_msgs_5[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-09 12:08:48 -07:00
|
|
|
io_board_adc_values *comm_can_get_io_board_adc_1_4_index(int index) {
|
|
|
|
if (index < CAN_STATUS_MSGS_TO_STORE) {
|
|
|
|
return &io_board_adc_1_4[index];
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
io_board_adc_values *comm_can_get_io_board_adc_1_4_id(int id) {
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
if (io_board_adc_1_4[i].id == id) {
|
|
|
|
return &io_board_adc_1_4[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
io_board_adc_values *comm_can_get_io_board_adc_5_8_index(int index) {
|
|
|
|
if (index < CAN_STATUS_MSGS_TO_STORE) {
|
|
|
|
return &io_board_adc_5_8[index];
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
io_board_adc_values *comm_can_get_io_board_adc_5_8_id(int id) {
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
if (io_board_adc_5_8[i].id == id) {
|
|
|
|
return &io_board_adc_1_4[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
io_board_digial_inputs *comm_can_get_io_board_digital_in_index(int index) {
|
|
|
|
if (index < CAN_STATUS_MSGS_TO_STORE) {
|
|
|
|
return &io_board_digital_in[index];
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
io_board_digial_inputs *comm_can_get_io_board_digital_in_id(int id) {
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
if (io_board_digital_in[i].id == id) {
|
|
|
|
return &io_board_digital_in[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void comm_can_io_board_set_output_digital(int id, int channel, bool on) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
|
|
|
|
buffer[send_index++] = channel;
|
|
|
|
buffer[send_index++] = 1;
|
|
|
|
buffer[send_index++] = on ? 1 : 0;
|
|
|
|
|
|
|
|
comm_can_transmit_eid(id | ((uint32_t)CAN_PACKET_IO_BOARD_SET_OUTPUT_DIGITAL << 8),
|
|
|
|
buffer, send_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void comm_can_io_board_set_output_pwm(int id, int channel, float duty) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
|
|
|
|
buffer[send_index++] = channel;
|
|
|
|
buffer_append_float16(buffer, duty, 1e3, &send_index);
|
|
|
|
|
|
|
|
comm_can_transmit_eid(id | ((uint32_t)CAN_PACKET_IO_BOARD_SET_OUTPUT_PWM << 8),
|
|
|
|
buffer, send_index);
|
|
|
|
}
|
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
CANRxFrame *comm_can_get_rx_frame(void) {
|
2019-03-31 01:49:18 -07:00
|
|
|
#if CAN_ENABLE
|
2019-02-18 10:30:19 -08:00
|
|
|
chMtxLock(&can_rx_mtx);
|
|
|
|
if (rx_frame_read != rx_frame_write) {
|
|
|
|
CANRxFrame *res = &rx_frames[rx_frame_read++];
|
|
|
|
|
|
|
|
if (rx_frame_read == RX_FRAMES_SIZE) {
|
|
|
|
rx_frame_read = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
chMtxUnlock(&can_rx_mtx);
|
|
|
|
return res;
|
|
|
|
} else {
|
|
|
|
chMtxUnlock(&can_rx_mtx);
|
|
|
|
return 0;
|
|
|
|
}
|
2019-03-31 01:49:18 -07:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
2019-02-18 10:30:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#if CAN_ENABLE
|
|
|
|
static THD_FUNCTION(cancom_read_thread, arg) {
|
|
|
|
(void)arg;
|
|
|
|
chRegSetThreadName("CAN read");
|
|
|
|
|
|
|
|
event_listener_t el;
|
|
|
|
CANRxFrame rxmsg;
|
|
|
|
|
|
|
|
chEvtRegister(&HW_CAN_DEV.rxfull_event, &el, 0);
|
|
|
|
|
|
|
|
while(!chThdShouldTerminateX()) {
|
2019-02-18 15:25:52 -08:00
|
|
|
// Feed watchdog
|
|
|
|
timeout_feed_WDT(THREAD_CANBUS);
|
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
if (chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(10)) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg_t result = canReceive(&HW_CAN_DEV, CAN_ANY_MAILBOX, &rxmsg, TIME_IMMEDIATE);
|
|
|
|
|
|
|
|
while (result == MSG_OK) {
|
|
|
|
chMtxLock(&can_rx_mtx);
|
|
|
|
rx_frames[rx_frame_write++] = rxmsg;
|
|
|
|
if (rx_frame_write == RX_FRAMES_SIZE) {
|
|
|
|
rx_frame_write = 0;
|
|
|
|
}
|
|
|
|
chMtxUnlock(&can_rx_mtx);
|
|
|
|
|
|
|
|
chEvtSignal(process_tp, (eventmask_t) 1);
|
|
|
|
|
|
|
|
result = canReceive(&HW_CAN_DEV, CAN_ANY_MAILBOX, &rxmsg, TIME_IMMEDIATE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
chEvtUnregister(&HW_CAN_DEV.rxfull_event, &el);
|
|
|
|
}
|
|
|
|
|
|
|
|
static THD_FUNCTION(cancom_process_thread, arg) {
|
|
|
|
(void)arg;
|
|
|
|
|
|
|
|
chRegSetThreadName("CAN process");
|
|
|
|
process_tp = chThdGetSelfX();
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
chEvtWaitAny((eventmask_t)1);
|
|
|
|
|
2020-01-28 10:46:19 -08:00
|
|
|
if (app_get_configuration()->can_mode == CAN_MODE_UAVCAN) {
|
|
|
|
continue;
|
|
|
|
} else if (app_get_configuration()->can_mode == CAN_MODE_COMM_BRIDGE) {
|
|
|
|
CANRxFrame *rxmsg_tmp;
|
|
|
|
while ((rxmsg_tmp = comm_can_get_rx_frame()) != 0) {
|
|
|
|
CANRxFrame rxmsg = *rxmsg_tmp;
|
|
|
|
commands_fwd_can_frame(rxmsg.DLC, rxmsg.data8,
|
|
|
|
rxmsg.IDE == CAN_IDE_EXT ? rxmsg.EID : rxmsg.SID,
|
|
|
|
rxmsg.IDE == CAN_IDE_EXT);
|
|
|
|
|
|
|
|
if (rxmsg.IDE == CAN_IDE_STD) {
|
|
|
|
if (sid_callback) {
|
|
|
|
sid_callback(rxmsg.SID, rxmsg.data8, rxmsg.DLC);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (eid_callback) {
|
|
|
|
eid_callback(rxmsg.EID, rxmsg.data8, rxmsg.DLC);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-18 10:30:19 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
CANRxFrame *rxmsg_tmp;
|
|
|
|
while ((rxmsg_tmp = comm_can_get_rx_frame()) != 0) {
|
|
|
|
CANRxFrame rxmsg = *rxmsg_tmp;
|
|
|
|
|
|
|
|
if (rxmsg.IDE == CAN_IDE_EXT) {
|
2020-10-21 23:32:51 -07:00
|
|
|
if (!bms_process_can_frame(rxmsg.EID, rxmsg.data8, rxmsg.DLC, true)) {
|
|
|
|
decode_msg(rxmsg.EID, rxmsg.data8, rxmsg.DLC, false);
|
|
|
|
}
|
2019-02-18 10:30:19 -08:00
|
|
|
} else {
|
2020-10-21 23:32:51 -07:00
|
|
|
if (!bms_process_can_frame(rxmsg.SID, rxmsg.data8, rxmsg.DLC, false)) {
|
|
|
|
if (sid_callback) {
|
|
|
|
sid_callback(rxmsg.SID, rxmsg.data8, rxmsg.DLC);
|
|
|
|
}
|
2019-02-18 10:30:19 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-16 10:32:39 -07:00
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
/*
|
2020-08-13 04:53:29 -07:00
|
|
|
* This thread sends all status messages and uses the internal decoder. That
|
|
|
|
* way the second motor always shows up on the CAN-bus.
|
2020-03-16 10:32:39 -07:00
|
|
|
*/
|
|
|
|
static THD_FUNCTION(cancom_status_internal_thread, arg) {
|
|
|
|
(void)arg;
|
|
|
|
chRegSetThreadName("CAN stat loc");
|
|
|
|
|
|
|
|
mc_interface_select_motor_thread(2);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
send_status1(utils_second_motor_id(), true);
|
|
|
|
send_status2(utils_second_motor_id(), true);
|
|
|
|
send_status3(utils_second_motor_id(), true);
|
|
|
|
send_status4(utils_second_motor_id(), true);
|
|
|
|
send_status5(utils_second_motor_id(), true);
|
|
|
|
chThdSleepMilliseconds(2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
static THD_FUNCTION(cancom_status_thread, arg) {
|
|
|
|
(void)arg;
|
|
|
|
chRegSetThreadName("CAN status");
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
const app_configuration *conf = app_get_configuration();
|
|
|
|
|
2020-01-28 10:46:19 -08:00
|
|
|
if (conf->can_mode == CAN_MODE_VESC) {
|
2019-02-18 10:30:19 -08:00
|
|
|
if (conf->send_can_status == CAN_STATUS_1 ||
|
|
|
|
conf->send_can_status == CAN_STATUS_1_2 ||
|
|
|
|
conf->send_can_status == CAN_STATUS_1_2_3 ||
|
2019-05-16 14:30:40 -07:00
|
|
|
conf->send_can_status == CAN_STATUS_1_2_3_4 ||
|
|
|
|
conf->send_can_status == CAN_STATUS_1_2_3_4_5) {
|
2020-03-16 10:32:39 -07:00
|
|
|
mc_interface_select_motor_thread(1);
|
|
|
|
send_status1(conf->controller_id, false);
|
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
mc_interface_select_motor_thread(2);
|
|
|
|
send_status1(utils_second_motor_id(), false);
|
|
|
|
#endif
|
2019-02-18 10:30:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (conf->send_can_status == CAN_STATUS_1_2 ||
|
|
|
|
conf->send_can_status == CAN_STATUS_1_2_3||
|
2019-05-16 14:30:40 -07:00
|
|
|
conf->send_can_status == CAN_STATUS_1_2_3_4 ||
|
|
|
|
conf->send_can_status == CAN_STATUS_1_2_3_4_5) {
|
2020-03-16 10:32:39 -07:00
|
|
|
mc_interface_select_motor_thread(1);
|
|
|
|
send_status2(conf->controller_id, false);
|
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
mc_interface_select_motor_thread(2);
|
|
|
|
send_status2(utils_second_motor_id(), false);
|
|
|
|
#endif
|
2019-02-18 10:30:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (conf->send_can_status == CAN_STATUS_1_2_3 ||
|
2019-05-16 14:30:40 -07:00
|
|
|
conf->send_can_status == CAN_STATUS_1_2_3_4 ||
|
|
|
|
conf->send_can_status == CAN_STATUS_1_2_3_4_5) {
|
2020-03-16 10:32:39 -07:00
|
|
|
mc_interface_select_motor_thread(1);
|
|
|
|
send_status3(conf->controller_id, false);
|
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
mc_interface_select_motor_thread(2);
|
|
|
|
send_status3(utils_second_motor_id(), false);
|
|
|
|
#endif
|
2019-02-18 10:30:19 -08:00
|
|
|
}
|
|
|
|
|
2019-05-16 14:30:40 -07:00
|
|
|
if (conf->send_can_status == CAN_STATUS_1_2_3_4 ||
|
|
|
|
conf->send_can_status == CAN_STATUS_1_2_3_4_5) {
|
2020-03-16 10:32:39 -07:00
|
|
|
mc_interface_select_motor_thread(1);
|
|
|
|
send_status4(conf->controller_id, false);
|
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
mc_interface_select_motor_thread(2);
|
|
|
|
send_status4(utils_second_motor_id(), false);
|
|
|
|
#endif
|
2019-02-18 10:30:19 -08:00
|
|
|
}
|
2019-05-16 14:30:40 -07:00
|
|
|
|
|
|
|
if (conf->send_can_status == CAN_STATUS_1_2_3_4_5) {
|
2020-03-16 10:32:39 -07:00
|
|
|
mc_interface_select_motor_thread(1);
|
|
|
|
send_status5(conf->controller_id, false);
|
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
mc_interface_select_motor_thread(2);
|
|
|
|
send_status5(utils_second_motor_id(), false);
|
|
|
|
#endif
|
2019-05-16 14:30:40 -07:00
|
|
|
}
|
2019-02-18 10:30:19 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
systime_t sleep_time = CH_CFG_ST_FREQUENCY / conf->send_can_status_rate_hz;
|
|
|
|
if (sleep_time == 0) {
|
|
|
|
sleep_time = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
chThdSleep(sleep_time);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void send_packet_wrapper(unsigned char *data, unsigned int len) {
|
|
|
|
comm_can_send_buffer(rx_buffer_last_id, data, len, 1);
|
|
|
|
}
|
2020-03-16 10:32:39 -07:00
|
|
|
|
|
|
|
static void decode_msg(uint32_t eid, uint8_t *data8, int len, bool is_replaced) {
|
|
|
|
int32_t ind = 0;
|
|
|
|
unsigned int rxbuf_len;
|
|
|
|
unsigned int rxbuf_ind;
|
|
|
|
uint8_t crc_low;
|
|
|
|
uint8_t crc_high;
|
|
|
|
uint8_t commands_send;
|
|
|
|
|
|
|
|
uint8_t id = eid & 0xFF;
|
|
|
|
CAN_PACKET_ID cmd = eid >> 8;
|
|
|
|
|
|
|
|
int id1 = app_get_configuration()->controller_id;
|
|
|
|
|
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
int motor_last = mc_interface_get_motor_thread();
|
|
|
|
int id2 = utils_second_motor_id();
|
|
|
|
if (id == id2) {
|
|
|
|
mc_interface_select_motor_thread(2);
|
|
|
|
} else {
|
|
|
|
mc_interface_select_motor_thread(1);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int id2 = id1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (id == 255 || id == id1 || id == id2) {
|
|
|
|
switch (cmd) {
|
|
|
|
case CAN_PACKET_SET_DUTY:
|
|
|
|
ind = 0;
|
|
|
|
mc_interface_set_duty(buffer_get_float32(data8, 1e5, &ind));
|
|
|
|
timeout_reset();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_SET_CURRENT:
|
|
|
|
ind = 0;
|
|
|
|
mc_interface_set_current(buffer_get_float32(data8, 1e3, &ind));
|
|
|
|
timeout_reset();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_SET_CURRENT_BRAKE:
|
|
|
|
ind = 0;
|
|
|
|
mc_interface_set_brake_current(buffer_get_float32(data8, 1e3, &ind));
|
|
|
|
timeout_reset();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_SET_RPM:
|
|
|
|
ind = 0;
|
|
|
|
mc_interface_set_pid_speed(buffer_get_float32(data8, 1e0, &ind));
|
|
|
|
timeout_reset();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_SET_POS:
|
|
|
|
ind = 0;
|
|
|
|
mc_interface_set_pid_pos(buffer_get_float32(data8, 1e6, &ind));
|
|
|
|
timeout_reset();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_FILL_RX_BUFFER:
|
|
|
|
memcpy(rx_buffer + data8[0], data8 + 1, len - 1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_FILL_RX_BUFFER_LONG:
|
|
|
|
rxbuf_ind = (unsigned int)data8[0] << 8;
|
|
|
|
rxbuf_ind |= data8[1];
|
|
|
|
if (rxbuf_ind < RX_BUFFER_SIZE) {
|
|
|
|
memcpy(rx_buffer + rxbuf_ind, data8 + 2, len - 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_PROCESS_RX_BUFFER:
|
|
|
|
ind = 0;
|
|
|
|
rx_buffer_last_id = data8[ind++];
|
|
|
|
commands_send = data8[ind++];
|
|
|
|
rxbuf_len = (unsigned int)data8[ind++] << 8;
|
|
|
|
rxbuf_len |= (unsigned int)data8[ind++];
|
|
|
|
|
|
|
|
if (rxbuf_len > RX_BUFFER_SIZE) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
crc_high = data8[ind++];
|
|
|
|
crc_low = data8[ind++];
|
|
|
|
|
|
|
|
if (crc16(rx_buffer, rxbuf_len)
|
|
|
|
== ((unsigned short) crc_high << 8
|
|
|
|
| (unsigned short) crc_low)) {
|
2020-04-25 08:54:12 -07:00
|
|
|
|
|
|
|
if (is_replaced) {
|
|
|
|
if (rx_buffer[0] == COMM_JUMP_TO_BOOTLOADER ||
|
|
|
|
rx_buffer[0] == COMM_ERASE_NEW_APP ||
|
|
|
|
rx_buffer[0] == COMM_WRITE_NEW_APP_DATA ||
|
|
|
|
rx_buffer[0] == COMM_WRITE_NEW_APP_DATA_LZO ||
|
|
|
|
rx_buffer[0] == COMM_ERASE_BOOTLOADER) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-16 10:32:39 -07:00
|
|
|
switch (commands_send) {
|
|
|
|
case 0:
|
|
|
|
commands_process_packet(rx_buffer, rxbuf_len, send_packet_wrapper);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
commands_send_packet(rx_buffer, rxbuf_len);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
commands_process_packet(rx_buffer, rxbuf_len, 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_PROCESS_SHORT_BUFFER:
|
|
|
|
ind = 0;
|
|
|
|
rx_buffer_last_id = data8[ind++];
|
|
|
|
commands_send = data8[ind++];
|
|
|
|
|
2020-04-25 08:54:12 -07:00
|
|
|
if (is_replaced) {
|
|
|
|
if (data8[ind] == COMM_JUMP_TO_BOOTLOADER ||
|
|
|
|
data8[ind] == COMM_ERASE_NEW_APP ||
|
|
|
|
data8[ind] == COMM_WRITE_NEW_APP_DATA ||
|
|
|
|
data8[ind] == COMM_WRITE_NEW_APP_DATA_LZO ||
|
|
|
|
data8[ind] == COMM_ERASE_BOOTLOADER) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-16 10:32:39 -07:00
|
|
|
switch (commands_send) {
|
|
|
|
case 0:
|
|
|
|
commands_process_packet(data8 + ind, len - ind, send_packet_wrapper);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
commands_send_packet(data8 + ind, len - ind);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
commands_process_packet(data8 + ind, len - ind, 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_SET_CURRENT_REL:
|
|
|
|
ind = 0;
|
|
|
|
mc_interface_set_current_rel(buffer_get_float32(data8, 1e5, &ind));
|
|
|
|
timeout_reset();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_SET_CURRENT_BRAKE_REL:
|
|
|
|
ind = 0;
|
|
|
|
mc_interface_set_brake_current_rel(buffer_get_float32(data8, 1e5, &ind));
|
|
|
|
timeout_reset();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_SET_CURRENT_HANDBRAKE:
|
|
|
|
ind = 0;
|
|
|
|
mc_interface_set_handbrake(buffer_get_float32(data8, 1e3, &ind));
|
|
|
|
timeout_reset();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_SET_CURRENT_HANDBRAKE_REL:
|
|
|
|
ind = 0;
|
|
|
|
mc_interface_set_handbrake_rel(buffer_get_float32(data8, 1e5, &ind));
|
|
|
|
timeout_reset();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_PING: {
|
2020-10-09 12:08:48 -07:00
|
|
|
uint8_t buffer[2];
|
2020-03-16 10:32:39 -07:00
|
|
|
buffer[0] = app_get_configuration()->controller_id;
|
2020-10-09 12:08:48 -07:00
|
|
|
buffer[1] = HW_TYPE_VESC;
|
2020-03-16 10:32:39 -07:00
|
|
|
comm_can_transmit_eid(data8[0] |
|
2020-10-09 12:08:48 -07:00
|
|
|
((uint32_t)CAN_PACKET_PONG << 8), buffer, 2);
|
2020-03-16 10:32:39 -07:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case CAN_PACKET_PONG:
|
2020-11-12 14:09:03 -08:00
|
|
|
if (ping_tp && ping_hw_last_id == data8[0]) {
|
2020-10-09 12:08:48 -07:00
|
|
|
if (len >= 2) {
|
|
|
|
ping_hw_last = data8[1];
|
|
|
|
} else {
|
|
|
|
ping_hw_last = HW_TYPE_VESC;
|
|
|
|
}
|
2020-03-16 10:32:39 -07:00
|
|
|
chEvtSignal(ping_tp, 1 << 29);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_DETECT_APPLY_ALL_FOC: {
|
|
|
|
if (is_replaced) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ind = 1;
|
|
|
|
bool activate_status = data8[ind++];
|
|
|
|
float max_power_loss = buffer_get_float32(data8, 1e3, &ind);
|
|
|
|
int res = conf_general_detect_apply_all_foc(max_power_loss, true, false);
|
|
|
|
if (res >= 0 && activate_status) {
|
|
|
|
app_configuration *appconf = mempools_alloc_appconf();
|
|
|
|
*appconf = *app_get_configuration();
|
|
|
|
|
|
|
|
if (appconf->send_can_status != CAN_STATUS_1_2_3_4) {
|
|
|
|
appconf->send_can_status = CAN_STATUS_1_2_3_4;
|
|
|
|
conf_general_store_app_configuration(appconf);
|
|
|
|
app_set_configuration(appconf);
|
|
|
|
}
|
|
|
|
|
|
|
|
mempools_free_appconf(appconf);
|
|
|
|
}
|
|
|
|
|
|
|
|
int8_t buffer[1];
|
|
|
|
buffer[0] = res;
|
|
|
|
comm_can_transmit_eid(data8[0] |
|
|
|
|
((uint32_t)CAN_PACKET_DETECT_APPLY_ALL_FOC_RES << 8), (uint8_t*)buffer, 1);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CAN_PACKET_DETECT_APPLY_ALL_FOC_RES: {
|
|
|
|
if (is_replaced) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
detect_all_foc_res[detect_all_foc_res_index++] = (int8_t)data8[0];
|
|
|
|
detect_all_foc_res_index %= sizeof(detect_all_foc_res);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CAN_PACKET_CONF_CURRENT_LIMITS:
|
|
|
|
case CAN_PACKET_CONF_STORE_CURRENT_LIMITS: {
|
|
|
|
ind = 0;
|
|
|
|
float min = buffer_get_float32(data8, 1e3, &ind);
|
|
|
|
float max = buffer_get_float32(data8, 1e3, &ind);
|
|
|
|
|
|
|
|
mc_configuration *mcconf = mempools_alloc_mcconf();
|
|
|
|
*mcconf = *mc_interface_get_configuration();
|
|
|
|
|
|
|
|
if (mcconf->l_current_min != min || mcconf->l_current_max != max) {
|
|
|
|
mcconf->l_current_min = min;
|
|
|
|
mcconf->l_current_max = max;
|
|
|
|
|
|
|
|
if (cmd == CAN_PACKET_CONF_STORE_CURRENT_LIMITS) {
|
|
|
|
conf_general_store_mc_configuration(mcconf,
|
|
|
|
mc_interface_get_motor_thread() == 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
mc_interface_set_configuration(mcconf);
|
|
|
|
}
|
|
|
|
|
|
|
|
mempools_free_mcconf(mcconf);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CAN_PACKET_CONF_CURRENT_LIMITS_IN:
|
|
|
|
case CAN_PACKET_CONF_STORE_CURRENT_LIMITS_IN: {
|
|
|
|
ind = 0;
|
|
|
|
float min = buffer_get_float32(data8, 1e3, &ind);
|
|
|
|
float max = buffer_get_float32(data8, 1e3, &ind);
|
|
|
|
|
|
|
|
mc_configuration *mcconf = mempools_alloc_mcconf();
|
|
|
|
*mcconf = *mc_interface_get_configuration();
|
|
|
|
|
|
|
|
if (mcconf->l_in_current_min != min || mcconf->l_in_current_max != max) {
|
|
|
|
mcconf->l_in_current_min = min;
|
|
|
|
mcconf->l_in_current_max = max;
|
|
|
|
|
|
|
|
if (cmd == CAN_PACKET_CONF_STORE_CURRENT_LIMITS_IN) {
|
|
|
|
conf_general_store_mc_configuration(mcconf,
|
|
|
|
mc_interface_get_motor_thread() == 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
mc_interface_set_configuration(mcconf);
|
|
|
|
}
|
|
|
|
|
|
|
|
mempools_free_mcconf(mcconf);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CAN_PACKET_CONF_FOC_ERPMS:
|
|
|
|
case CAN_PACKET_CONF_STORE_FOC_ERPMS: {
|
|
|
|
ind = 0;
|
|
|
|
float foc_openloop_rpm = buffer_get_float32(data8, 1e3, &ind);
|
|
|
|
float foc_sl_erpm = buffer_get_float32(data8, 1e3, &ind);
|
|
|
|
|
|
|
|
mc_configuration *mcconf = mempools_alloc_mcconf();
|
|
|
|
*mcconf = *mc_interface_get_configuration();
|
|
|
|
|
|
|
|
if (mcconf->foc_openloop_rpm != foc_openloop_rpm ||
|
|
|
|
mcconf->foc_sl_erpm != foc_sl_erpm) {
|
|
|
|
mcconf->foc_openloop_rpm = foc_openloop_rpm;
|
|
|
|
mcconf->foc_sl_erpm = foc_sl_erpm;
|
|
|
|
|
|
|
|
if (cmd == CAN_PACKET_CONF_STORE_FOC_ERPMS) {
|
|
|
|
conf_general_store_mc_configuration(mcconf,
|
|
|
|
mc_interface_get_motor_thread() == 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
mc_interface_set_configuration(mcconf);
|
|
|
|
}
|
|
|
|
|
|
|
|
mempools_free_mcconf(mcconf);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CAN_PACKET_POLL_TS5700N8501_STATUS: {
|
|
|
|
comm_can_transmit_eid(app_get_configuration()->controller_id |
|
|
|
|
((uint32_t)CAN_PACKET_POLL_TS5700N8501_STATUS << 8),
|
|
|
|
encoder_ts5700n8501_get_raw_status(), 8);
|
|
|
|
} break;
|
|
|
|
|
2020-03-20 09:35:25 -07:00
|
|
|
case CAN_PACKET_CONF_BATTERY_CUT:
|
|
|
|
case CAN_PACKET_CONF_STORE_BATTERY_CUT: {
|
|
|
|
ind = 0;
|
|
|
|
float start = buffer_get_float32(data8, 1e3, &ind);
|
|
|
|
float end = buffer_get_float32(data8, 1e3, &ind);
|
|
|
|
|
|
|
|
mc_configuration *mcconf = mempools_alloc_mcconf();
|
|
|
|
*mcconf = *mc_interface_get_configuration();
|
|
|
|
|
|
|
|
if (mcconf->l_battery_cut_start != start || mcconf->l_battery_cut_end != end) {
|
|
|
|
mcconf->l_battery_cut_start = start;
|
|
|
|
mcconf->l_battery_cut_end = end;
|
|
|
|
|
|
|
|
if (cmd == CAN_PACKET_CONF_STORE_BATTERY_CUT) {
|
|
|
|
conf_general_store_mc_configuration(mcconf,
|
|
|
|
mc_interface_get_motor_thread() == 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
mc_interface_set_configuration(mcconf);
|
|
|
|
}
|
|
|
|
|
|
|
|
mempools_free_mcconf(mcconf);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CAN_PACKET_SHUTDOWN: {
|
|
|
|
#ifdef HW_SHUTDOWN_HOLD_ON
|
|
|
|
SHUTDOWN_SET_SAMPLING_DISABLED(true);
|
|
|
|
mc_interface_lock();
|
|
|
|
DISABLE_GATE();
|
|
|
|
HW_SHUTDOWN_HOLD_OFF();
|
|
|
|
chThdSleepMilliseconds(5000);
|
|
|
|
HW_SHUTDOWN_HOLD_ON();
|
|
|
|
ENABLE_GATE();
|
|
|
|
mc_interface_unlock();
|
|
|
|
SHUTDOWN_SET_SAMPLING_DISABLED(false);
|
|
|
|
#endif
|
|
|
|
} break;
|
|
|
|
|
2020-03-16 10:32:39 -07:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case CAN_PACKET_STATUS:
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
can_status_msg *stat_tmp = &stat_msgs[i];
|
|
|
|
if (stat_tmp->id == id || stat_tmp->id == -1) {
|
|
|
|
ind = 0;
|
|
|
|
stat_tmp->id = id;
|
|
|
|
stat_tmp->rx_time = chVTGetSystemTime();
|
|
|
|
stat_tmp->rpm = (float)buffer_get_int32(data8, &ind);
|
|
|
|
stat_tmp->current = (float)buffer_get_int16(data8, &ind) / 10.0;
|
|
|
|
stat_tmp->duty = (float)buffer_get_int16(data8, &ind) / 1000.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_STATUS_2:
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
can_status_msg_2 *stat_tmp_2 = &stat_msgs_2[i];
|
|
|
|
if (stat_tmp_2->id == id || stat_tmp_2->id == -1) {
|
|
|
|
ind = 0;
|
|
|
|
stat_tmp_2->id = id;
|
|
|
|
stat_tmp_2->rx_time = chVTGetSystemTime();
|
|
|
|
stat_tmp_2->amp_hours = (float)buffer_get_int32(data8, &ind) / 1e4;
|
|
|
|
stat_tmp_2->amp_hours_charged = (float)buffer_get_int32(data8, &ind) / 1e4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_STATUS_3:
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
can_status_msg_3 *stat_tmp_3 = &stat_msgs_3[i];
|
|
|
|
if (stat_tmp_3->id == id || stat_tmp_3->id == -1) {
|
|
|
|
ind = 0;
|
|
|
|
stat_tmp_3->id = id;
|
|
|
|
stat_tmp_3->rx_time = chVTGetSystemTime();
|
|
|
|
stat_tmp_3->watt_hours = (float)buffer_get_int32(data8, &ind) / 1e4;
|
|
|
|
stat_tmp_3->watt_hours_charged = (float)buffer_get_int32(data8, &ind) / 1e4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_STATUS_4:
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
can_status_msg_4 *stat_tmp_4 = &stat_msgs_4[i];
|
|
|
|
if (stat_tmp_4->id == id || stat_tmp_4->id == -1) {
|
|
|
|
ind = 0;
|
|
|
|
stat_tmp_4->id = id;
|
|
|
|
stat_tmp_4->rx_time = chVTGetSystemTime();
|
|
|
|
stat_tmp_4->temp_fet = (float)buffer_get_int16(data8, &ind) / 10.0;
|
|
|
|
stat_tmp_4->temp_motor = (float)buffer_get_int16(data8, &ind) / 10.0;
|
|
|
|
stat_tmp_4->current_in = (float)buffer_get_int16(data8, &ind) / 10.0;
|
|
|
|
stat_tmp_4->pid_pos_now = (float)buffer_get_int16(data8, &ind) / 50.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_STATUS_5:
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
can_status_msg_5 *stat_tmp_5 = &stat_msgs_5[i];
|
|
|
|
if (stat_tmp_5->id == id || stat_tmp_5->id == -1) {
|
|
|
|
ind = 0;
|
|
|
|
stat_tmp_5->id = id;
|
|
|
|
stat_tmp_5->rx_time = chVTGetSystemTime();
|
|
|
|
stat_tmp_5->tacho_value = buffer_get_int32(data8, &ind);
|
|
|
|
stat_tmp_5->v_in = (float)buffer_get_int16(data8, &ind) / 1e1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2020-10-09 12:08:48 -07:00
|
|
|
case CAN_PACKET_IO_BOARD_ADC_1_TO_4:
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
io_board_adc_values *msg = &io_board_adc_1_4[i];
|
|
|
|
if (msg->id == id || msg->id == -1) {
|
|
|
|
ind = 0;
|
|
|
|
msg->id = id;
|
|
|
|
msg->rx_time = chVTGetSystemTime();
|
|
|
|
ind = 0;
|
|
|
|
int j = 0;
|
|
|
|
while (ind < len) {
|
|
|
|
msg->adc_voltages[j++] = buffer_get_float16(data8, 1e2, &ind);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_IO_BOARD_ADC_5_TO_8:
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
io_board_adc_values *msg = &io_board_adc_5_8[i];
|
|
|
|
if (msg->id == id || msg->id == -1) {
|
|
|
|
ind = 0;
|
|
|
|
msg->id = id;
|
|
|
|
msg->rx_time = chVTGetSystemTime();
|
|
|
|
ind = 0;
|
|
|
|
int j = 0;
|
|
|
|
while (ind < len) {
|
|
|
|
msg->adc_voltages[j++] = buffer_get_float16(data8, 1e2, &ind);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CAN_PACKET_IO_BOARD_DIGITAL_IN:
|
|
|
|
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
|
|
|
|
io_board_digial_inputs *msg = &io_board_digital_in[i];
|
|
|
|
if (msg->id == id || msg->id == -1) {
|
|
|
|
ind = 0;
|
|
|
|
msg->id = id;
|
|
|
|
msg->rx_time = chVTGetSystemTime();
|
|
|
|
msg->inputs = 0;
|
|
|
|
ind = 0;
|
|
|
|
while (ind < len) {
|
|
|
|
msg->inputs |= (uint64_t)data8[ind] << (ind * 8);
|
|
|
|
ind++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
2020-03-16 10:32:39 -07:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HW_HAS_DUAL_MOTORS
|
|
|
|
mc_interface_select_motor_thread(motor_last);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void send_status1(uint8_t id, bool replace) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
buffer_append_int32(buffer, (int32_t)mc_interface_get_rpm(), &send_index);
|
|
|
|
buffer_append_int16(buffer, (int16_t)(mc_interface_get_tot_current_filtered() * 1e1), &send_index);
|
|
|
|
buffer_append_int16(buffer, (int16_t)(mc_interface_get_duty_cycle_now() * 1e3), &send_index);
|
|
|
|
comm_can_transmit_eid_replace(id | ((uint32_t)CAN_PACKET_STATUS << 8),
|
|
|
|
buffer, send_index, replace);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void send_status2(uint8_t id, bool replace) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
buffer_append_int32(buffer, (int32_t)(mc_interface_get_amp_hours(false) * 1e4), &send_index);
|
|
|
|
buffer_append_int32(buffer, (int32_t)(mc_interface_get_amp_hours_charged(false) * 1e4), &send_index);
|
|
|
|
comm_can_transmit_eid_replace(id | ((uint32_t)CAN_PACKET_STATUS_2 << 8),
|
|
|
|
buffer, send_index, replace);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void send_status3(uint8_t id, bool replace) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
buffer_append_int32(buffer, (int32_t)(mc_interface_get_watt_hours(false) * 1e4), &send_index);
|
|
|
|
buffer_append_int32(buffer, (int32_t)(mc_interface_get_watt_hours_charged(false) * 1e4), &send_index);
|
|
|
|
comm_can_transmit_eid_replace(id | ((uint32_t)CAN_PACKET_STATUS_3 << 8),
|
|
|
|
buffer, send_index, replace);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void send_status4(uint8_t id, bool replace) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
buffer_append_int16(buffer, (int16_t)(mc_interface_temp_fet_filtered() * 1e1), &send_index);
|
|
|
|
buffer_append_int16(buffer, (int16_t)(mc_interface_temp_motor_filtered() * 1e1), &send_index);
|
|
|
|
buffer_append_int16(buffer, (int16_t)(mc_interface_get_tot_current_in_filtered() * 1e1), &send_index);
|
|
|
|
buffer_append_int16(buffer, (int16_t)(mc_interface_get_pid_pos_now() * 50.0), &send_index);
|
|
|
|
comm_can_transmit_eid_replace(id | ((uint32_t)CAN_PACKET_STATUS_4 << 8),
|
|
|
|
buffer, send_index, replace);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void send_status5(uint8_t id, bool replace) {
|
|
|
|
int32_t send_index = 0;
|
|
|
|
uint8_t buffer[8];
|
|
|
|
buffer_append_int32(buffer, mc_interface_get_tachometer_value(false), &send_index);
|
|
|
|
buffer_append_int16(buffer, (int16_t)(GET_INPUT_VOLTAGE() * 1e1), &send_index);
|
|
|
|
buffer_append_int16(buffer, 0, &send_index); // Reserved for now
|
|
|
|
comm_can_transmit_eid_replace(id | ((uint32_t)CAN_PACKET_STATUS_5 << 8),
|
|
|
|
buffer, send_index, replace);
|
|
|
|
}
|
2020-10-09 12:08:48 -07:00
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
#endif
|
|
|
|
|
2020-01-31 15:37:25 -08:00
|
|
|
/**
|
|
|
|
* Set the CAN timing. The CAN is clocked at 42 MHz, and the baud rate can be
|
|
|
|
* calculated with
|
|
|
|
*
|
|
|
|
* 42000000 / ((brp + 1) * (ts1 + ts2 + 3))
|
|
|
|
*
|
|
|
|
* ts1 should be larger than ts2 in general to take the sample after the
|
|
|
|
* signal had time to stabilize.
|
|
|
|
*
|
|
|
|
* @param brp
|
|
|
|
* Prescaler.
|
|
|
|
*
|
|
|
|
* @param ts1
|
|
|
|
* TS1.
|
|
|
|
*
|
|
|
|
* @param ts2
|
|
|
|
* TS2.
|
|
|
|
*/
|
2017-11-08 05:07:35 -08:00
|
|
|
static void set_timing(int brp, int ts1, int ts2) {
|
|
|
|
brp &= 0b1111111111;
|
|
|
|
ts1 &= 0b1111;
|
|
|
|
ts2 &= 0b111;
|
|
|
|
|
2017-11-08 13:04:56 -08:00
|
|
|
cancfg.btr = CAN_BTR_SJW(3) | CAN_BTR_TS2(ts2) |
|
2017-11-08 05:07:35 -08:00
|
|
|
CAN_BTR_TS1(ts1) | CAN_BTR_BRP(brp);
|
2017-11-08 13:04:56 -08:00
|
|
|
|
2019-02-18 10:30:19 -08:00
|
|
|
canStop(&HW_CAN_DEV);
|
|
|
|
canStart(&HW_CAN_DEV, &cancfg);
|
2017-11-08 05:07:35 -08:00
|
|
|
}
|