PythonでCANアダプタを使っていてPCANの受信のレスポンスがちょっと遅い気がしたのでESP32でSLCANデバイスを作って試してみた。
前にESP-WROOM-32でCANを使ってみたときと同じハードで、最新のArduino CoreでCANライブラリを使わずに使えるようにしてみた。
#include "driver/twai.h"
#define SERIAL_BAUD 921600
const gpio_num_t CAN_TX_PIN = GPIO_NUM_32;
const gpio_num_t CAN_RX_PIN = GPIO_NUM_35;
boolean enableSLCAN = false;
boolean timestamp = false;
boolean cr = false;
int can_speed = 250;
static const char hexval[17] = "0123456789ABCDEF";
void slcan_ack() { Serial.write('\r'); }
void slcan_nack() { Serial.write('\a'); }
twai_timing_config_t get_timing(int speed_kbps) {
switch(speed_kbps) {
case 100: return TWAI_TIMING_CONFIG_100KBITS();
case 125: return TWAI_TIMING_CONFIG_125KBITS();
case 250: return TWAI_TIMING_CONFIG_250KBITS();
case 500: return TWAI_TIMING_CONFIG_500KBITS();
case 800: return TWAI_TIMING_CONFIG_800KBITS();
case 1000: return TWAI_TIMING_CONFIG_1MBITS();
default: return TWAI_TIMING_CONFIG_250KBITS();
}
}
void send_canmsg(char *buf, bool rtr, bool ext) {
if (!enableSLCAN) return;
twai_message_t tx_frame = {};
int msg_id = 0, msg_ide = 0, msg_len = 0;
if (rtr) {
if (ext) sscanf(&buf[1], "%04x%04x", &msg_ide, &msg_id), tx_frame.flags = TWAI_MSG_FLAG_EXTD | TWAI_MSG_FLAG_RTR;
else sscanf(&buf[1], "%03x", &msg_id), tx_frame.flags = TWAI_MSG_FLAG_RTR;
} else {
if (ext) sscanf(&buf[1], "%04x%04x", &msg_ide, &msg_id), tx_frame.flags = TWAI_MSG_FLAG_EXTD;
else sscanf(&buf[1], "%03x", &msg_id), tx_frame.flags = 0;
}
tx_frame.identifier = ext ? (msg_ide * 65536 + msg_id) : msg_id;
if (ext) sscanf(&buf[9], "%01x", &msg_len);
else sscanf(&buf[4], "%01x", &msg_len);
tx_frame.data_length_code = msg_len;
for (int i = 0; i < msg_len; i++) {
int candata;
if (ext) sscanf(&buf[10 + i*2], "%02x", &candata);
else sscanf(&buf[5 + i*2], "%02x", &candata);
tx_frame.data[i] = candata;
}
twai_transmit(&tx_frame, pdMS_TO_TICKS(10));
}
void pars_slcancmd(char *buf) {
switch(buf[0]) {
case 'O': { // OPEN CAN
if (!enableSLCAN) {
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(CAN_TX_PIN, CAN_RX_PIN, TWAI_MODE_NORMAL);
twai_timing_config_t t_config = get_timing(can_speed);
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK &&
twai_start() == ESP_OK) enableSLCAN = true;
}
slcan_ack();
} break;
case 'C': { // CLOSE CAN
if (enableSLCAN) {
twai_stop();
twai_driver_uninstall();
enableSLCAN = false;
}
slcan_ack();
} break;
case 't': send_canmsg(buf, false, false); slcan_ack(); break;
case 'T': send_canmsg(buf, false, true); slcan_ack(); break;
case 'r': send_canmsg(buf, true, false); slcan_ack(); break;
case 'R': send_canmsg(buf, true, true); slcan_ack(); break;
case 'Z': timestamp = (buf[1] == '1'); slcan_ack(); break;
case 'S': {
int new_speed = 0;
switch(buf[1]) {
case '3': new_speed = 100; break;
case '4': new_speed = 125; break;
case '5': new_speed = 250; break;
case '6': new_speed = 500; break;
case '7': new_speed = 800; break;
case '8': new_speed = 1000; break;
default: slcan_nack(); return;
}
if (enableSLCAN) {
twai_stop();
twai_driver_uninstall();
enableSLCAN = false;
}
can_speed = new_speed;
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(CAN_TX_PIN, CAN_RX_PIN, TWAI_MODE_NORMAL);
twai_timing_config_t t_config = get_timing(can_speed);
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK &&
twai_start() == ESP_OK) {
enableSLCAN = true;
slcan_ack();
} else slcan_nack();
} break;
case 'V': Serial.print("V1234"); slcan_ack(); break;
case 'N': Serial.print("N2208"); slcan_ack(); break;
case 'F': Serial.print("F00"); slcan_ack(); break;
default: slcan_nack(); break;
}
}
void transfer_tty2can() {
static char cmdbuf[32];
static int cmdidx = 0;
while(Serial.available()) {
char val = Serial.read();
cmdbuf[cmdidx++] = val;
if (cmdidx == 32) { slcan_nack(); cmdidx=0; }
else if (val == '\r') {
cmdbuf[cmdidx]='\0';
pars_slcancmd(cmdbuf);
cmdidx = 0;
}
}
}
void transfer_can2tty() {
if (!enableSLCAN) return;
twai_message_t rx_frame;
if (twai_receive(&rx_frame, pdMS_TO_TICKS(3)) == ESP_OK) {
String command = "";
if (rx_frame.flags & TWAI_MSG_FLAG_EXTD) {
command += (rx_frame.flags & TWAI_MSG_FLAG_RTR) ? "R" : "T";
command += hexval[(rx_frame.identifier >> 28) & 0xF];
command += hexval[(rx_frame.identifier >> 24) & 0xF];
command += hexval[(rx_frame.identifier >> 20) & 0xF];
command += hexval[(rx_frame.identifier >> 16) & 0xF];
command += hexval[(rx_frame.identifier >> 12) & 0xF];
command += hexval[(rx_frame.identifier >> 8) & 0xF];
command += hexval[(rx_frame.identifier >> 4) & 0xF];
command += hexval[rx_frame.identifier & 0xF];
} else {
command += (rx_frame.flags & TWAI_MSG_FLAG_RTR) ? "r" : "t";
command += hexval[(rx_frame.identifier >> 8) & 0xF];
command += hexval[(rx_frame.identifier >> 4) & 0xF];
command += hexval[rx_frame.identifier & 0xF];
}
command += hexval[rx_frame.data_length_code & 0xF];
for (int i = 0; i < rx_frame.data_length_code; i++) {
command += hexval[(rx_frame.data[i] >> 4) & 0xF];
command += hexval[rx_frame.data[i] & 0xF];
}
if (timestamp) {
uint16_t t = millis() % 60000;
command += hexval[(t >> 12) & 0xF];
command += hexval[(t >> 8) & 0xF];
command += hexval[(t >> 4) & 0xF];
command += hexval[t & 0xF];
}
command += '\r';
Serial.print(command);
if (cr) Serial.println();
}
}
void setup() {
Serial.begin(SERIAL_BAUD);
}
void loop() {
transfer_can2tty();
transfer_tty2can();
}ESP32でSLCANを実装していた人がいたのでそのCAN部分をTWAIドライバに変更してみただけ。たしかにシリアル通信なのでBluetooth経由でもCANが使えるようにできるわけか…
Python-Canはソケット通信にも対応してるのでそのままWiFi化とかもできそう。
0 件のコメント:
コメントを投稿