Skip to content

PandaProtocol

Chris Whiteford edited this page Dec 30, 2022 · 6 revisions

Panda UDP Protocol

Manual Root

Original comma.ai protocol (what the CANServer calls v1)

The Panda protocol was originally created by comma.ai for use with their panda can interface module.

The protocol is a simple UDP based protocol. It operates on port 1338.

To initiate a panda session with the CANServer all an application has to do it send a udp packet containing 'hello'. This packet will cause the CANServer to start sending can frames back to the address of the system that sent the initial 'hello' data (on the same 1338 port)

The 'hello' data needs to be sent every 5 seconds as a heartbeat. If the CANServer doesn't see a heartbeat for 10 seconds (timeout is doubled incase a UDP packet is dropped) it will stop sending data and close the session with the client.

The v1 protocol is unfiltered and ALL can frames received by the CANServer will be sent to the client.

The sent data is structured as follows:

Panda packets are a UDP packet containing between 1-512 frames of the following format:
                    Panda UDP Packet format
                │               │
┌───┬───┬───┬───┼───┬───┬─┬─┬─┬─┼───┬───┬───┬───┬───┬───┬───┬───┐
│   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │   │
└───┴───┴───┴───┴───┴───┴─┴─┴─┴─┴───┴───┴───┴───┴───┴───┴───┴───┘
│              ││         │   │ │
└─────┴────────┘└─────?───┴─▲─┘▲└─────────────────────▶
11-bits or 29-bits          │  │        Payload data
     Address                │  │
                            │  │
                    Bus ID ─┘  │
             Payload Length────┘

Example python code to decode the data is as follows:

bytesFromUDP = <received bytes from the CANServer>
unpackedHeader = struct.unpack('<II', bytesFromUDP[0:8])
frameID = unpackedHeader[0] >> 21
frameLength = unpackedHeader[1] & 0x0F
frameBusId = unpackedHeader[1] >> 4 
frameData = bytesFromUDP[8:16]

Each can frame is packed as 16 bytes (even when the payload length is shorter then 8). The first 8 bytes are the frame id, bus id, and payload length. The CANServer will send a UDP packet with a maximum size of 768 bytes (or 48 frames).

Enhanced protocol (what the CANServer calls v2)

Because the CANServer can process a high rate of can frames per second and most client applications don't have a need for the full raw stream an enhanced version of the Panda protocol was created.

This enhanced protocol allows better control over the can frames delivered bu applying filters.

To initiate an enhanced protocol (v2) session with the CANServer a client needs to send a udp packet containing a 'ehllo' string. Similar to a v1 session, this packet needs to be sent every 5 seconds as a heartbeat. The same timeout for disconnect applies as the v1 protocol.

When a new session is established with the CANServer using the v2 protocol an initial can frame is immediately sent to the client. This can frame comes from the CANServer's internal bus (details about all of the internal can frames can be found here). This initial ACK can frame (bus id 15, frame id 0x06) is a way to identify the CANServer as a v2 compatible server. Sending a modified 'ehllo' initial packet will work with older v1 only clients as they don't strictly match the initial packet/heartbeat string.

Once a client receives the special ACK frame it then knows that the more advanced filtering features can be used.

When a client connects to the CANServer using the v2 protocol outside of the initial ACK can frame no other frames will be sent. The client application will need to apply filters before any data will be sent.

To apply filters the client can send a udp packet with the following content:

0x0F - Shift In character (the identifier for "add filters")
<1 byte for bus id>
<2 bytes for frame id>
...
<1 byte for bus id>
<2 bytes for frame id>

Bus id can be 0, 1, or 0xff. When 0xff is used then the frame id will be matched on any bus.

A maximum of 43 bus id/frame id pairs can be sent per packet. If more filters need to be applied another filter packet can be sent.

The same format packet can be used to remove applied filters as needed. The only difference is the identifier byte at the start of the packet. To remove the udp packet should be like the following:

0x0E - Shift Out character (the identifier for "remove filters")
<1 byte for bus id>
<2 bytes for frame id>
...
<1 byte for bus id>
<2 bytes for frame id>

A packet with a single byte:

0x18 - Cancel character (the identifier for "clear filters")

Can be used to clear all filters applied

And inversely a packet with a single byte:

0x0C - Form Feed character (the identifier for "send all frames")

Can be used to send all can frames (causes the v2 protocol to behave similar to the v1 protocol)

The sent packet format is the same as the v1 protocol. Parsing should be handled the same way for any received data.