# Firmware

## 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/](https://github.com/RetroPilot/ocelot/tree/main/firmware).&#x20;

Next, build the Docker container by running `./build_container.sh`&#x20;

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](https://wiki.retropilot.org/index/hardware/hardware-ocelot-pro#dfu) - [ocelot gateway](https://wiki.retropilot.org/index/hardware/hardware-ocelot-gateway#dfu-mode)), 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](https://github.com/RetroPilot/ocelot/blob/b80fa0d32d1fc535c48614c35e9cb4f5862f1657/firmware/smart_dsu/main.c#L373), 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.

```cpp
  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:

```c
          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:

```c
            // 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:

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.retropilot.org/index/hardware/ocelot/firmware.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
