ESP32RET icon indicating copy to clipboard operation
ESP32RET copied to clipboard

GVRET Protocol Documentation

Open nickdaria opened this issue 1 year ago • 1 comments

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.

nickdaria avatar Mar 08 '24 19:03 nickdaria

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);

Kriechi avatar Jan 04 '25 19:01 Kriechi