Firmware
Ocelot Firmware guide
Panda Firmware
Panda firmware should run as-is and the board will be detected as a Black Panda. Compatible firmware is available from https://github.com/RetroPilot/ocelot/tree/main/firmware/panda
Ocelot Firmware
Ocelot Firmware draws heavily from Panda and Pedal. We'll cover a few example use cases, then dive into building our own custom firmware.
Environment setup
Ocelot firmware uses Docker to build firmware binaries for the device, but expects a local dfu-util in order to flash. Firmware building and flashing are supported under both Linux and Mac OS. To begin, git clone
the ocelot repo to your computer from https://github.com/RetroPilot/ocelot/.
Next, build the Docker container by running ./build_container.sh
Once the container has been built, firmware can be compiled by running ./flash_docker.sh
followed by the project name. Running with no project specified will list all available projects to build.
iBooster Gateway
The first use case for Ocelot firmware was to retrofit iBoosters into older vehicles, allowing them to achieve brake-by-wire for use with RetroPilot/openpilot.
Hardware should be connected so that the iBooster's Vehicle CAN is on Bus 2 of the Ocelot and Yaw CAN is on Bus 3 of the Ocelot. Bus 1 of the Ocelot is used to accept the RetroPilot Brake Command message, and the Ocelot will output information from the iBooster on this bus as well. Information on wiring can be found here: https://www.evcreate.nl/wiring-the-tesla-ibooster/ https://www.evcreate.nl/ibooster-can-bus/
Once everything is connected, the firmware can be flashed. Enter DFU (ocelot pro - ocelot gateway), then from the panda
folder:
cd board/ibst
./recover.sh
The Ocelot should now be flashed with iBooster Gateway Firmware. Using joystick controls with openpilot [todo: links to joystick controls/op setup] you should be able to command the iBooster on a bench.
SmartDSU
Setup and Flashing
Since Ocelot is a CAN gateway, it is also capable of filtering and modifying messages on-the-fly. This means it's capable of being used as a SmartDSU, filtering out the 0x343
ACC control message in 2017-2019 Corollas, Priuses, RAV4s and other DSU-equipped Toyotas. Wiring is simple enough:
Vehicle CAN from the car -> BUS1 on Ocelot DSU Vehicle CAN -> BUS3 on Ocelot
This configuration separates the DSU from the vehicle PTCAN, and the firmware takes care of modifying the control message when the car boots up. To flash the firmware, enter the `panda` folder. With the Ocelot in DFU mode:
cd board/smart_dsu
./recover.sh
Firmware Explanation
Now, let's step though the firmware to see how it works: https://github.com/RetroPilot/ocelot/blob/main/firmware/smart_dsu/main.c
Most of the magic happens inside CAN3_RX0_IRQ_Handler, where the DSU is sending its CAN frames and being intercepted by Ocelot.
First, the forwarding buffers are setup and filled with the incoming CAN packet data. This ensures that we only modify necessary messages and leave everything else untouched.
while ((CAN3->RF0R & CAN_RF0R_FMP0) != 0) {
CAN_FIFOMailBox_TypeDef to_fwd;
to_fwd.RIR = CAN3->sFIFOMailBox[0].RIR | 1; // TXQ
to_fwd.RDTR = CAN3->sFIFOMailBox[0].RDTR;
to_fwd.RDLR = CAN3->sFIFOMailBox[0].RDLR;
to_fwd.RDHR = CAN3->sFIFOMailBox[0].RDHR;
uint16_t address = CAN3->sFIFOMailBox[0].RIR >> 21;
#ifdef DEBUG_CAN
puts("CAN2 RX: ");
puth(address);
puts("\n");
#endif
// CAN data buffer
uint8_t dat[8];
Next, we look at the incoming message address and decide whether it should be modified with a switch case. Let's take a look at the 0x343
ACC Control message as an example. If we want to disable the low-speed lockout, a single bit in that message must be set to 1 so the PCM can disable the lockout and the car can brake to stop. First, the data must be stored into the buffer:
for (int i=0; i<8; i++) {
dat[i] = GET_BYTE(&CAN3->sFIFOMailBox[0], i);
}
Next, the buffer can be modified by bitwise operations and the checksum recomputed:
// add permit_braking and recompute the checksum
dat[2] &= 0x3F; // mask off the top 2 bits
dat[2] |= (1 << 6U); // SET_ME_X01
dat[3] |= (1 << 6U); // permit_braking
dat[7] = toyota_checksum(address, dat, 8);
And finally, the resulting buffer can be sent into the forwarding queue:
to_fwd.RDLR = dat[0] | (dat[1] << 8) | (dat[2] << 16) | (dat[3] << 24);
to_fwd.RDHR = dat[4] | (dat[5] << 8) | (dat[6] << 16) | (dat[7] << 24);
Last updated
Was this helpful?