675 lines
17 KiB
C++
675 lines
17 KiB
C++
#include <cstdint>
|
|
#include <string.h>
|
|
|
|
#include "esp_avrc_api.h"
|
|
#include "esp_timer.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/portmacro.h"
|
|
#include "freertos/task.h"
|
|
#include "driver/spi_common.h"
|
|
#include "driver/spi_master.h"
|
|
#include "esp_err.h"
|
|
#include "esp_log.h"
|
|
#include "hal/spi_types.h"
|
|
|
|
#include "can.h"
|
|
#include "can_data.h"
|
|
|
|
#define CAN_TAG "APP_CAN"
|
|
|
|
#define PIN_NUM_MOSI 23
|
|
#define PIN_NUM_MISO 19
|
|
#define PIN_NUM_CLK 18
|
|
#define PIN_NUM_CS 5
|
|
|
|
#define MCP_SIDH 0
|
|
#define MCP_SIDL 1
|
|
#define MCP_EID8 2
|
|
#define MCP_EID0 3
|
|
|
|
#define MCP_TXB_EXIDE_M 0x08
|
|
#define MCP_DLC_MASK 0x0F
|
|
#define MCP_RTR_MASK 0x40
|
|
|
|
#define MCP_RXB_RX_STDEXT 0x00
|
|
#define MCP_RXB_RX_MASK 0x60
|
|
#define MCP_RXB_BUKT_MASK (1<<2)
|
|
|
|
#define MCP_STAT_TXIF_MASK 0xA8
|
|
#define MCP_STAT_TX0IF 0x08
|
|
#define MCP_STAT_TX1IF 0x20
|
|
#define MCP_STAT_TX2IF 0x80
|
|
#define MCP_STAT_RXIF_MASK 0x03
|
|
|
|
// Instructions
|
|
#define MCP_WRITE 0x02
|
|
#define MCP_READ 0x03
|
|
#define MCP_BITMOD 0x05
|
|
#define MCP_READ_RX0 0x90
|
|
#define MCP_READ_RX1 0x94
|
|
#define MCP_READ_STATUS 0xA0
|
|
#define MCP_RESET 0xC0
|
|
|
|
// Registers
|
|
#define MCP_RXF0SIDH 0x00
|
|
#define MCP_RXF1SIDH 0x04
|
|
#define MCP_CANSTAT 0x0E
|
|
#define MCP_CANCTRL 0x0F
|
|
#define MCP_RXM0SIDH 0x20
|
|
#define MCP_RXM1SIDH 0x24
|
|
#define MCP_CNF3 0x28
|
|
#define MCP_CNF2 0x29
|
|
#define MCP_CNF1 0x2A
|
|
#define MCP_CANINTE 0x2B
|
|
#define MCP_CANINTF 0x2C
|
|
#define MCP_TXB0CTRL 0x30
|
|
#define MCP_TXB1CTRL 0x40
|
|
#define MCP_TXB2CTRL 0x50
|
|
#define MCP_RXB0CTRL 0x60
|
|
#define MCP_RXB1CTRL 0x70
|
|
|
|
// CANCTRL Register values
|
|
#define MODE_NORMAL 0x00
|
|
#define MODE_SLEEP 0x20
|
|
#define MODE_LISTENONLY 0x60
|
|
#define MODE_CONFIG 0x80
|
|
#define MODE_MASK 0xE0
|
|
|
|
// CANINTF Register bits
|
|
#define MCP_RX0IF 0x01
|
|
#define MCP_RX1IF 0x02
|
|
#define MCP_TX0IF 0x04
|
|
#define MCP_TX1IF 0x08
|
|
#define MCP_TX2IF 0x10
|
|
#define MCP_WAKIF 0x40
|
|
|
|
static void send_cmd(spi_device_handle_t spi, const uint8_t cmd) {
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8;
|
|
t.tx_buffer = &cmd;
|
|
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
}
|
|
|
|
static uint8_t read_register(spi_device_handle_t spi, const uint8_t address) {
|
|
// Acquire the bus in order to use SPI_TRANS_CS_KEEP_ACTIVE
|
|
esp_err_t ret = spi_device_acquire_bus(spi, portMAX_DELAY);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
// Send the command
|
|
{
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8*2;
|
|
uint8_t cmd[] = { MCP_READ, address };
|
|
t.tx_buffer = cmd;
|
|
t.flags = SPI_TRANS_CS_KEEP_ACTIVE;
|
|
|
|
ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
}
|
|
|
|
// Read the data
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8;
|
|
t.flags = SPI_TRANS_USE_RXDATA;
|
|
|
|
ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
spi_device_release_bus(spi);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
return t.rx_data[0];
|
|
}
|
|
|
|
static void set_register(spi_device_handle_t spi, const uint8_t address, const uint8_t value) {
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8*3;
|
|
uint8_t cmd[] = { MCP_WRITE, address, value };
|
|
t.tx_buffer = cmd;
|
|
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
}
|
|
|
|
static void set_registers(spi_device_handle_t spi, const uint8_t address, const uint8_t* buf, int len) {
|
|
// Acquire the bus in order to use SPI_TRANS_CS_KEEP_ACTIVE
|
|
esp_err_t ret = spi_device_acquire_bus(spi, portMAX_DELAY);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
// Send the initial command
|
|
{
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8*2;
|
|
uint8_t cmd[] = { MCP_WRITE, address };
|
|
t.tx_buffer = cmd;
|
|
t.flags = SPI_TRANS_CS_KEEP_ACTIVE;
|
|
|
|
ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
}
|
|
|
|
// Send the data
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8*len;
|
|
t.tx_buffer = buf;
|
|
|
|
ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
spi_device_release_bus(spi);
|
|
ESP_ERROR_CHECK(ret);
|
|
}
|
|
|
|
static void modify_register(spi_device_handle_t spi, const uint8_t address, const uint8_t mask, const uint8_t data) {
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8*4;
|
|
uint8_t cmd[] = { MCP_BITMOD, address, mask, data };
|
|
t.tx_buffer = cmd;
|
|
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
}
|
|
|
|
static bool request_new_mode(spi_device_handle_t spi, const uint8_t new_mode) {
|
|
unsigned long start = esp_timer_get_time() / 1000;
|
|
|
|
for (;;) {
|
|
modify_register(spi, MCP_CANCTRL, MODE_MASK, new_mode);
|
|
uint8_t state = read_register(spi, MCP_CANSTAT);
|
|
if ((state & MODE_MASK) == new_mode) {
|
|
return true;
|
|
} else if ((esp_timer_get_time() / 1000 - start) > 200) {
|
|
ESP_LOGE(CAN_TAG, "Failed to set new mode");
|
|
abort();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
static uint8_t get_mode(spi_device_handle_t spi) {
|
|
return read_register(spi, MCP_CANSTAT) & MODE_MASK;
|
|
}
|
|
|
|
static void set_CANCTRL_mode(spi_device_handle_t spi, uint8_t new_mode) {
|
|
ESP_LOGI(CAN_TAG, "set_CANCTRL_mode");
|
|
if (get_mode(spi) == MODE_SLEEP && new_mode != MODE_SLEEP) {
|
|
ESP_LOGI(CAN_TAG, "if");
|
|
uint8_t wake_int_enabled = (read_register(spi, MCP_CANINTE) & MCP_WAKIF);
|
|
if (!wake_int_enabled) {
|
|
modify_register(spi, MCP_CANINTE, MCP_WAKIF, MCP_WAKIF);
|
|
}
|
|
|
|
modify_register(spi, MCP_CANINTF, MCP_WAKIF, MCP_WAKIF);
|
|
|
|
request_new_mode(spi, MODE_LISTENONLY);
|
|
|
|
if (!wake_int_enabled) {
|
|
modify_register(spi, MCP_CANINTE, MCP_WAKIF, 0);
|
|
}
|
|
}
|
|
|
|
modify_register(spi, MCP_CANINTF, MCP_WAKIF, 0);
|
|
|
|
request_new_mode(spi, new_mode);
|
|
ESP_LOGI(CAN_TAG, "done!");
|
|
}
|
|
|
|
static void config_rate(spi_device_handle_t spi) {
|
|
// This is for 16MHz, 125kBPS
|
|
set_register(spi, MCP_CNF1, 0x01);
|
|
set_register(spi, MCP_CNF2, 0xb1);
|
|
set_register(spi, MCP_CNF3, 0x05);
|
|
}
|
|
|
|
static void init_CAN_buffers(spi_device_handle_t spi) {
|
|
uint8_t a1 = MCP_TXB0CTRL;
|
|
uint8_t a2 = MCP_TXB1CTRL;
|
|
uint8_t a3 = MCP_TXB2CTRL;
|
|
|
|
for (int i = 0; i < 14; i++) {
|
|
set_register(spi, a1, 0);
|
|
set_register(spi, a2, 0);
|
|
set_register(spi, a3, 0);
|
|
|
|
a1++;
|
|
a2++;
|
|
a3++;
|
|
}
|
|
|
|
set_register(spi, MCP_RXB0CTRL, 0);
|
|
set_register(spi, MCP_RXB1CTRL, 0);
|
|
}
|
|
|
|
static uint8_t read_status(spi_device_handle_t spi) {
|
|
// Acquire the bus in order to use SPI_TRANS_CS_KEEP_ACTIVE
|
|
esp_err_t ret = spi_device_acquire_bus(spi, portMAX_DELAY);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
// Send the command
|
|
{
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8;
|
|
uint8_t cmd[] = { MCP_READ_STATUS };
|
|
t.tx_buffer = cmd;
|
|
t.flags = SPI_TRANS_CS_KEEP_ACTIVE;
|
|
|
|
ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
}
|
|
|
|
// Read the data
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8;
|
|
t.flags = SPI_TRANS_USE_RXDATA;
|
|
|
|
ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
spi_device_release_bus(spi);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
return t.rx_data[0];
|
|
}
|
|
|
|
static bool available(spi_device_handle_t spi) {
|
|
uint8_t res = read_status(spi);
|
|
|
|
return res & MCP_STAT_RXIF_MASK;
|
|
}
|
|
|
|
static uint8_t read_rx_tx_status(spi_device_handle_t spi) {
|
|
uint8_t ret = (read_status(spi) & (MCP_STAT_TXIF_MASK | MCP_STAT_RXIF_MASK));
|
|
|
|
ret = (ret & MCP_STAT_TX0IF ? MCP_TX0IF : 0) |
|
|
(ret & MCP_STAT_TX1IF ? MCP_TX1IF : 0) |
|
|
(ret & MCP_STAT_TX2IF ? MCP_TX2IF : 0) |
|
|
(ret & MCP_STAT_RXIF_MASK);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void read_can_msg(spi_device_handle_t spi, uint8_t buffer_load_addr, unsigned long* id, uint8_t* ext, uint8_t* rtr_bit, uint8_t* len, uint8_t* buf) {
|
|
// Acquire the bus in order to use SPI_TRANS_CS_KEEP_ACTIVE
|
|
esp_err_t ret = spi_device_acquire_bus(spi, portMAX_DELAY);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
// Send the command
|
|
{
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8;
|
|
uint8_t cmd[] = { buffer_load_addr };
|
|
t.tx_buffer = cmd;
|
|
t.flags = SPI_TRANS_CS_KEEP_ACTIVE;
|
|
|
|
ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
}
|
|
|
|
// Read id + length
|
|
{
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8*5;
|
|
uint8_t data[5];
|
|
t.rx_buffer = data;
|
|
t.flags = SPI_TRANS_CS_KEEP_ACTIVE;
|
|
|
|
ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
*id = (data[MCP_SIDH] << 3) + (data[MCP_SIDL] >> 5);
|
|
*ext = 0;
|
|
if ((data[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M) {
|
|
// Extended id
|
|
// @TODO Do we need this for our application
|
|
*id = (*id << 2) + (data[MCP_SIDL] & 0x03);
|
|
*id = (*id << 8) + data[MCP_EID8];
|
|
*id = (*id << 8) + data[MCP_EID0];
|
|
*ext = 1;
|
|
}
|
|
|
|
*len = data[4] & MCP_DLC_MASK;
|
|
|
|
// @TODO Do we need this in our application
|
|
*rtr_bit = (data[0] & MCP_RTR_MASK) ? 1 : 0;
|
|
}
|
|
|
|
// Read the data
|
|
{
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(t));
|
|
t.length = 8*(*len);
|
|
t.rx_buffer = buf;
|
|
|
|
ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
}
|
|
|
|
// Make sure we release the bus
|
|
spi_device_release_bus(spi);
|
|
ESP_ERROR_CHECK(ret);
|
|
}
|
|
|
|
static void print_buttons(can::Buttons buttons) {
|
|
/* ESP_LOGI(CAN_TAG, "BUTTONS"); */
|
|
if (buttons.forward) {
|
|
ESP_LOGI(CAN_TAG, "Button: F");
|
|
}
|
|
if (buttons.backward) {
|
|
ESP_LOGI(CAN_TAG, "Button: B");
|
|
}
|
|
if (buttons.volume_up) {
|
|
ESP_LOGI(CAN_TAG, "Button: U");
|
|
}
|
|
if (buttons.volume_down) {
|
|
ESP_LOGI(CAN_TAG, "Button: D");
|
|
}
|
|
if (buttons.source) {
|
|
ESP_LOGI(CAN_TAG, "Button: S");
|
|
}
|
|
|
|
// Only print when scroll changes value
|
|
static uint8_t scroll = 0;
|
|
if (buttons.scroll != scroll) {
|
|
scroll = buttons.scroll;
|
|
ESP_LOGI(CAN_TAG, "Scroll: %i", buttons.scroll);
|
|
}
|
|
}
|
|
|
|
static void print_radio(can::Radio radio) {
|
|
ESP_LOGI(CAN_TAG, "RADIO");
|
|
if (radio.enabled) {
|
|
ESP_LOGI(CAN_TAG, "Enabled: %i", radio.enabled);
|
|
}
|
|
if (radio.muted) {
|
|
ESP_LOGI(CAN_TAG, "Muted: %i", radio.muted);
|
|
}
|
|
if (radio.cd_changer_available) {
|
|
ESP_LOGI(CAN_TAG, "CD Changer: %i", radio.cd_changer_available);
|
|
}
|
|
switch (radio.disk_status) {
|
|
case can::DiskStatus::Init:
|
|
ESP_LOGI(CAN_TAG, "CD: Init");
|
|
break;
|
|
case can::DiskStatus::Unavailable:
|
|
ESP_LOGI(CAN_TAG, "CD: Unavailable");
|
|
break;
|
|
case can::DiskStatus::Available:
|
|
ESP_LOGI(CAN_TAG, "CD: Available");
|
|
break;
|
|
default:
|
|
ESP_LOGW(CAN_TAG, "CD: Invalid");
|
|
break;
|
|
}
|
|
|
|
switch (radio.source) {
|
|
case can::Source::Bluetooth:
|
|
ESP_LOGI(CAN_TAG, "Source: Bluetooth");
|
|
break;
|
|
case can::Source::USB:
|
|
ESP_LOGI(CAN_TAG, "Source: USB");
|
|
break;
|
|
case can::Source::AUX2:
|
|
ESP_LOGI(CAN_TAG, "Source: AUX2");
|
|
break;
|
|
case can::Source::AUX1:
|
|
ESP_LOGI(CAN_TAG, "Source: AUX1");
|
|
break;
|
|
case can::Source::CD_Changer:
|
|
ESP_LOGI(CAN_TAG, "Source: CD Changer");
|
|
break;
|
|
case can::Source::CD:
|
|
ESP_LOGI(CAN_TAG, "Source: CD");
|
|
break;
|
|
case can::Source::Tuner:
|
|
ESP_LOGI(CAN_TAG, "Source: Tuner");
|
|
break;
|
|
default:
|
|
ESP_LOGW(CAN_TAG, "Source: Invalid");
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void read_message(spi_device_handle_t spi) {
|
|
uint8_t status = read_rx_tx_status(spi);
|
|
|
|
unsigned long id;
|
|
uint8_t ext;
|
|
uint8_t rtr_bit;
|
|
uint8_t len;
|
|
uint8_t buf[8];
|
|
|
|
if (status & MCP_RX0IF) {
|
|
read_can_msg(spi, MCP_READ_RX0, &id, &ext, &rtr_bit, &len, buf);
|
|
} else if (status & MCP_RX1IF) {
|
|
read_can_msg(spi, MCP_READ_RX0, &id, &ext, &rtr_bit, &len, buf);
|
|
}
|
|
|
|
/* ESP_LOGI(CAN_TAG, "Received: id=%lu, ext=%i, rtr_bit=%i, len=%i", id, ext, rtr_bit, len); */
|
|
|
|
// @TODO Implement the length check in a more elegant manner
|
|
/* switch (id) { */
|
|
/* case BUTTONS_ID: */
|
|
/* print_buttons(*(can::Buttons*)buf); */
|
|
/* break; */
|
|
|
|
/* case RADIO_ID: */
|
|
/* print_radio(*(can::Radio*)buf); */
|
|
/* break; */
|
|
|
|
/* default: */
|
|
/* break; */
|
|
/* } */
|
|
|
|
// @TODO Only do this if we actually are on AUX2
|
|
if (id == BUTTONS_ID) {
|
|
static can::Buttons previous;
|
|
can::Buttons buttons = *(can::Buttons*)buf;
|
|
|
|
// Forward
|
|
{
|
|
static uint8_t counter = 0;
|
|
static bool disabled = false;
|
|
|
|
if (buttons.forward && !disabled) {
|
|
counter++;
|
|
|
|
ESP_LOGI(CAN_TAG, "Counter: %i", counter);
|
|
|
|
if (counter > 5) {
|
|
ESP_LOGI(CAN_TAG, "Forward");
|
|
// Fast forward
|
|
esp_err_t ret = esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_FORWARD, ESP_AVRC_PT_CMD_STATE_PRESSED);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
ret = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_FORWARD, ESP_AVRC_PT_CMD_STATE_RELEASED);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
// Disable actions from happening again until we release the button
|
|
disabled = true;
|
|
}
|
|
}
|
|
|
|
if (previous.forward != buttons.forward && !buttons.forward) {
|
|
if (counter <= 5) {
|
|
// @TODO Get this from the actual device instead of assuming that on startup it is falce
|
|
static bool play_status = false;
|
|
play_status = !play_status;
|
|
|
|
ESP_LOGI(CAN_TAG, "Play button has been pressed");
|
|
|
|
if (play_status) {
|
|
ESP_LOGI(CAN_TAG, "Playing");
|
|
// @TODO Abstract this away so that we are not directly interfacing with AVRC things
|
|
esp_err_t ret = esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STATE_PRESSED);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
ret = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STATE_RELEASED);
|
|
ESP_ERROR_CHECK(ret);
|
|
} else {
|
|
ESP_LOGI(CAN_TAG, "Pausing");
|
|
esp_err_t ret = esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_PAUSE, ESP_AVRC_PT_CMD_STATE_PRESSED);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
ret = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_PAUSE, ESP_AVRC_PT_CMD_STATE_RELEASED);
|
|
ESP_ERROR_CHECK(ret);
|
|
}
|
|
}
|
|
|
|
counter = 0;
|
|
disabled = false;
|
|
}
|
|
}
|
|
|
|
// Backwards
|
|
{
|
|
static uint8_t counter = 0;
|
|
static bool disabled = false;
|
|
|
|
if (buttons.backward && !disabled) {
|
|
counter++;
|
|
|
|
ESP_LOGI(CAN_TAG, "Counter: %i", counter);
|
|
|
|
if (counter > 5) {
|
|
ESP_LOGI(CAN_TAG, "Backwards");
|
|
// Fast forward
|
|
esp_err_t ret = esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_BACKWARD, ESP_AVRC_PT_CMD_STATE_PRESSED);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
ret = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_BACKWARD, ESP_AVRC_PT_CMD_STATE_RELEASED);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
// Disable actions from happening again until we release the button
|
|
disabled = true;
|
|
}
|
|
}
|
|
|
|
if (previous.backward != buttons.backward && !buttons.backward) {
|
|
if (counter <= 5) {
|
|
// @TODO What do we do when we just press this button?
|
|
// Might be nice to somehow trigger the google assistant, altough that requires Handsfree profile, which might interfere with the car itself
|
|
}
|
|
|
|
counter = 0;
|
|
disabled = false;
|
|
}
|
|
}
|
|
|
|
previous = buttons;
|
|
}
|
|
}
|
|
|
|
static void id_to_buf(const uint8_t ext, const unsigned long id, uint8_t* buf) {
|
|
uint16_t canid = id & 0xFFFF;
|
|
|
|
if (ext) {
|
|
buf[MCP_EID0] = canid & 0xFF;
|
|
buf[MCP_EID8] = canid >> 8;
|
|
canid = id >> 16;
|
|
buf[MCP_SIDL] = canid & 0x03;
|
|
buf[MCP_SIDL] += canid & 0x1C << 3;
|
|
buf[MCP_SIDL] |= MCP_TXB_EXIDE_M;
|
|
buf[MCP_SIDH] = canid >> 5;
|
|
} else {
|
|
buf[MCP_SIDH] = canid >> 3;
|
|
buf[MCP_SIDL] = (canid & 0x07) << 5;
|
|
buf[MCP_EID0] = 0;
|
|
buf[MCP_EID8] = 0;
|
|
}
|
|
}
|
|
|
|
static void write_id(spi_device_handle_t spi, const uint8_t addr, const uint8_t ext, const unsigned long id) {
|
|
uint8_t buf[4];
|
|
|
|
id_to_buf(ext, id, buf);
|
|
set_registers(spi, addr, buf, 4);
|
|
}
|
|
|
|
void can_task(void* params) {
|
|
spi_device_handle_t spi = *(spi_device_handle_t*)params;
|
|
|
|
for (;;) {
|
|
if (available(spi)) {
|
|
read_message(spi);
|
|
}
|
|
}
|
|
}
|
|
|
|
void can::init() {
|
|
ESP_LOGI(CAN_TAG, "Initializing can");
|
|
|
|
spi_bus_config_t buscfg = {
|
|
.mosi_io_num=PIN_NUM_MOSI,
|
|
.miso_io_num=PIN_NUM_MISO,
|
|
.sclk_io_num=PIN_NUM_CLK,
|
|
.quadwp_io_num=-1,
|
|
.quadhd_io_num=-1,
|
|
.max_transfer_sz=0
|
|
};
|
|
esp_err_t ret = spi_bus_initialize(VSPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
ESP_LOGI(CAN_TAG, "Adding device");
|
|
spi_device_interface_config_t devcfg = {
|
|
.mode=0,
|
|
.clock_speed_hz=10*1000*1000,
|
|
.spics_io_num=PIN_NUM_CS,
|
|
.queue_size=7,
|
|
};
|
|
spi_device_handle_t* spi = new spi_device_handle_t;
|
|
ret = spi_bus_add_device(VSPI_HOST, &devcfg, spi);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
ESP_LOGI(CAN_TAG, "Resetting MCP1525");
|
|
send_cmd(*spi, MCP_RESET);
|
|
// @TODO Check if this is really needed
|
|
// Copied from other libary, here to give the MCP2515 time to wake up
|
|
vTaskDelay(5 / portTICK_PERIOD_MS);
|
|
|
|
ESP_LOGI(CAN_TAG, "Enter config mode");
|
|
set_CANCTRL_mode(*spi, MODE_CONFIG);
|
|
|
|
ESP_LOGI(CAN_TAG, "Setting rate");
|
|
config_rate(*spi);
|
|
|
|
ESP_LOGI(CAN_TAG, "Init CAN buffers");
|
|
init_CAN_buffers(*spi);
|
|
|
|
ESP_LOGI(CAN_TAG, "Setting interrupt mode");
|
|
set_register(*spi, MCP_CANINTE, MCP_RX0IF | MCP_RX1IF);
|
|
|
|
ESP_LOGI(CAN_TAG, "Enable receive buffers");
|
|
modify_register(*spi, MCP_RXB0CTRL, MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK);
|
|
modify_register(*spi, MCP_RXB1CTRL, MCP_RXB_RX_MASK, MCP_RXB_RX_STDEXT);
|
|
|
|
// @TODO Setup filter so we only receive messages that we are interested in
|
|
ESP_LOGI(CAN_TAG, "Init mask");
|
|
write_id(*spi, MCP_RXM0SIDH, 0, 0x3ff);
|
|
write_id(*spi, MCP_RXM1SIDH, 0, 0x3ff);
|
|
|
|
ESP_LOGI(CAN_TAG, "Init filter");
|
|
/* write_id(*spi, MCP_RXF0SIDH, 0, 0x165); */
|
|
write_id(*spi, MCP_RXF1SIDH, 0, 0x21f);
|
|
|
|
ESP_LOGI(CAN_TAG, "Enter normal mode");
|
|
set_CANCTRL_mode(*spi, MODE_NORMAL);
|
|
|
|
ESP_LOGI(CAN_TAG, "Init done!");
|
|
|
|
xTaskCreate(can_task, "CAN Task", 4096, spi, 0, nullptr);
|
|
}
|