GVRET Protocol Documentation
Is there any proper documentation for the GVRET protocol aside from the gvret_comm source files?
I am designing a few ESP32 based modules with Quad CAN functionality (1x ESP TWAI, 3x MCP25625). I have already modified all of my internal libraries to utilize the can_common CAN_FRAME struct. For debugging, I would like to write and implement a custom GVRET task so that I can connect to my module and monitor the CAN bus activity or quickly script new tests without a firmware flash.
If not, I would be happy to write some documentation after I implement my own - I just wanted to check if there was any already.
I was struggling with the same problem. I wanted to implement the GVRET protocol in my own device to use SavvyCAN. Here is what I found out and got working using WiFi connectivity, though the actual data protocol is identical for UART/serial communication as well:
You need to listen for incoming TCP connection on port 23 (traditionally known as telnet).
GVRET seems to use a two-byte command structure: 0xf1 starts a new command, followed by a 1-byte command ID.
Using SavvyCAN, it attempts a new connection using a few default commands, including validation messages and something like a regular heartbeat / ping-pong.
To establish a full connection that SavvyCAN is happy with, I needed to implement these commands with fixed responses:
C code snippet:
if (rx_buffer[0] == 0xf1 && rx_buffer[1] == 0x09) {
// heartbeat - ping - validation OK
uint8_t tx_buffer[] = {0xf1, 0x09};
written = send(sock, tx_buffer, sizeof(tx_buffer), 0);
} else if (rx_buffer[0] == 0xf1 && rx_buffer[1] == 0x06) {
// GET_CANBUS_PARAMS
// 0x11 = bus enabled and listen-only
// baud rate 500,000 encoded as little-endian
uint8_t tx_buffer[] = {0xf1, 0x06, /*CAN0*/ 0x11, 0x20, 0xa1, 0x07, 0x00, /* CAN1 */ 0x00, 0x00, 0x00, 0x00, 0x00};
written = send(sock, tx_buffer, sizeof(tx_buffer), 0);
} else if (rx_buffer[0] == 0xf1 && rx_buffer[1] == 0x0c) {
// GET_NUM_BUSES with a single one
uint8_t tx_buffer[] = {0xf1, 0x0c, 0x01};
written = send(sock, tx_buffer, sizeof(tx_buffer), 0);
} else if (rx_buffer[0] == 0xf1 && rx_buffer[1] == 0x0d) {
// GET_EXT_BUSES with none
uint8_t tx_buffer[] = {0xf1, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
written = send(socket, tx_buffer, sizeof(tx_buffer), 0);
}
Now that SavvyCAN is happy, I can send new CAN frames from my device by sending this payload from the device to SavvyCAN:
- 0xf1 to start the command
- 0x00 to indicate we are sending a CAN frame
- 4 bytes for a micro-second timestamp
- 4 bytes for the CAN message ID
- 1 byte for the CAN message length (usually 8) + the bus ID encoded in the upper nibble (my device only has one CAN bus, so this is 0 anyway)
- now follow all bytes of the CAN message itself
- with a final 0x00 to terminate the message (note: the code below is a bit condensed and simply assumes that there are at most 8 bytes in the payload to simplify the buffer size handling)
C code snippet:
uint64_t timestamp = (uint32_t)esp_timer_get_time();
uint8_t bus_id = 0; // only one bus present and used
uint8_t tx_buffer[] = {
0xf1,
0x00, // sending CAN bus frame
(uint8_t)(timestamp & 0xFF),
(uint8_t)(timestamp >> 8),
(uint8_t)(timestamp >> 16),
(uint8_t)(timestamp >> 24),
(uint8_t)(msg->identifier & 0xFF),
(uint8_t)(msg->identifier >> 8),
(uint8_t)(msg->identifier >> 16),
(uint8_t)(msg->identifier >> 24),
msg->data_length_code + (uint8_t)(bus_id << 4),
msg->data[0],
msg->data[1],
msg->data[2],
msg->data[3],
msg->data[4],
msg->data[5],
msg->data[6],
msg->data[7],
0x00,
};
tx_buffer[11 + msg->data_length_code] = 0x00;
int written = send(socket, tx_buffer, 12 + msg->data_length_code, 0);