<!-- Source: https://medius.k4tech.net/native/commands/patch -->
# Patch

_Overwrite bytes in the clone's descriptors_

[`PATCH`](/native/commands/patch.md#patch) stores byte overwrites for the descriptors the clone serves at enumeration. The set persists in NVS under the device's VID:PID, and the clone serves the copy taken at its last [presentation](/native/commands/patch.md#presentation).

```
  real device --USB3--> HOST chip
                            |
                            |  snapshot of every descriptor
                            v
  NVS, per VID:PID ---> DEVICE chip    copy the stored set, overwrite in place
  [ stored set ]            |
                            |  clone checks, consistency checks
                            v
  game PC <---USB1----- the clone      patched, or unpatched when a check fails
```

| Action | Value | Effect |
| --- | --- | --- |
| [store](/native/commands/patch.md#patch) | `0` to `4` | add, overwrite or remove one patch in the stored set |
| [APPLY](/native/commands/patch.md#apply) | `0xFE` | present the clone again with the stored set |
| [CLEAR](/native/commands/patch.md#clear) | `0xFF` | erase the set; a clone serving patches is presented again without them |

The value is the first payload byte. Read the set back with [`QUERY(PATCHES)`](/native/commands/requests.md#patches) and one patch in full with [`QUERY(PATCH_ENTRY)`](/native/commands/requests.md#patch-entry).

> **Warning**
>
> A stored set reaches the game PC only under [`OPTION(IMPERFECT)`](/native/commands/option.md#imperfect); see [the gate](/native/commands/patch.md#gate).

## PATCH

_Store, overwrite, or remove one patch_

A patch names a descriptor, an offset into it, and the bytes to write there. [Opcode](/native/frame.md#opcodes) `0x1D`.

```text
PATCH 0x1D · payload 5 + n bytes
```

_Fire-and-forget_

#### PAYLOAD

| Offset | Field | Type | Notes |
| --- | --- | --- | --- |
| 0 | `section` | `u8` | descriptor (table below) |
| 1 | `cfg` | `u8` | configuration's position in capture order, `0` first |
| 2 | `index` | `u8` | interface number for REPORT, string index for STRING |
| 3 | `offset` | `u16` | first byte overwritten, counted from the descriptor's first byte; little-endian |
| 5 | `bytes` | `u8[]` | overwrite, 0 to 505 bytes, delimited by the frame [`LEN`](/native/frame.md#layout) |

#### SECTION

| Value | Name | Effect |
| --- | --- | --- |
| `0` | DEVICE | the 18-byte device descriptor; `cfg` and `index` ignored |
| `1` | CONFIG | configuration `cfg`, every byte of its `wTotalLength`; `index` ignored |
| `2` | REPORT | the HID report descriptor of interface `index` in configuration `cfg` |
| `3` | STRING | string `index`, replaced whole; `cfg` and `offset` ignored |
| `4` | BOS | the BOS descriptor; `cfg` and `index` ignored |

#### KEY

A patch is stored under `(section, cfg, index, offset)` exactly as sent, ignored fields included, so send `0` in those.

| Sent | Effect |
| --- | --- |
| bytes at a new key | appended to the set |
| other bytes at a stored key | replaced and moved to the end of the set |
| the bytes already stored at that key | no change: the patch keeps its place and NVS is untouched |
| zero bytes at a stored key | removed |

#### REFUSALS

| Refused when | Why |
| --- | --- |
| no device attached | the set is keyed on the attached device; a device the box refuses to clone still counts as attached |
| store payload under 5 bytes | the first five are the address |
| `section` is `5` to `0xFD` | five descriptor kinds, then APPLY and CLEAR |
| `bytes` longer than 505 | the patch must fit its [`RESP(PATCH_ENTRY)`](/native/commands/requests.md#patch-entry) read-back in one frame |
| a 17th key | 16 patches per device; [`RESP(PATCHES)`](/native/commands/requests.md#patches) sets `FULL` |
| the set's bytes would pass 1024 | one pool holds every patch's bytes; `FULL` is set, and an overwrite that does not fit leaves the old patch in place |
| zero `bytes` at an unstored key | nothing to remove |

#### EFFECT

A change is written to NVS at once and reaches the game PC at the clone's next [presentation](/native/commands/patch.md#presentation). A refused frame has no reply: read [`RESP(PATCHES)`](/native/commands/requests.md#patches) for the patch, or for `FULL`.

#### EXAMPLE

Set `bcdDevice` to `0x0200`: section DEVICE, `offset = 12`, bytes `00 02`:

```
+--------+--------+--------+--------+--------+--------+
| A5     | 1D     | 00     | 07 00  | 00     | 00     |
+--------+--------+--------+--------+--------+--------+
| SOF    | TYPE   | SEQ    | LEN    | section| cfg    |
+--------+--------+--------+--------+--------+--------+

+--------+--------+--------+--------+
| 00     | 0C 00  | 00 02  | lo hi  |
+--------+--------+--------+--------+
| index  | offset | bytes  | CRC16  |
+--------+--------+--------+--------+
```

Library binding: [`set_patch`](/library/advanced/patch.md#set-patch).

## APPLY

_Present the clone again with the stored set_

APPLY is a `PATCH` frame with `section` `0xFE`; the rest of the payload is ignored.

```text
PATCH 0x1D · payload 1 byte
```

_Fire-and-forget_

#### PAYLOAD

| Offset | Field | Type | Notes |
| --- | --- | --- | --- |
| 0 | `section` | `u8` | `0xFE` |

#### EFFECT

When the stored set differs from the one the clone serves, the box [presents](/native/commands/patch.md#presentation) the clone again with a copy of the stored set and runs the [checks](/native/commands/patch.md#ladder). An emptied set presents it unpatched.

#### REFUSALS

| Refused when | Why |
| --- | --- |
| the stored set is the one the clone serves | it would change nothing and cost the game PC a re-enumeration |
| the stored set failed a check at its last presentation and is unchanged since | it would fail the same way; [`PATCHES`](/native/commands/requests.md#patches) b2 is set |
| [`OPTION(IMPERFECT)`](/native/commands/option.md#imperfect) off | the clone serves no patches without the opt-in |
| no device attached | the box rebuilds the clone from the snapshot taken at attach |

#### EXAMPLE

Present the stored set:

```
+--------+--------+--------+--------+--------+--------+
| A5     | 1D     | 01     | 01 00  | FE     | lo hi  |
+--------+--------+--------+--------+--------+--------+
| SOF    | TYPE   | SEQ    | LEN    | section| CRC16  |
+--------+--------+--------+--------+--------+--------+
```

Library binding: [`apply_patch`](/library/advanced/patch.md#apply-patch).

## CLEAR

_Erase the set and present the clone without it_

CLEAR is a `PATCH` frame with `section` `0xFF`. It runs with the opt-in off and with the device unplugged.

```text
PATCH 0x1D · payload 1 byte
```

_Fire-and-forget_

#### PAYLOAD

| Offset | Field | Type | Notes |
| --- | --- | --- | --- |
| 0 | `section` | `u8` | `0xFF` |

#### EFFECT

| State | Effect |
| --- | --- |
| the clone serves patches | the set and its NVS key are erased, and the clone is [presented](/native/commands/patch.md#presentation) again unpatched, as APPLY presents it |
| the clone serves none | the set and its NVS key are erased; the clone is unchanged |

Either way [`RESP(PATCHES)`](/native/commands/requests.md#patches) then reads with `REFUSED` and `FULL` clear. With the device unplugged, CLEAR erases the key of the last device attached since boot, or nothing after a boot with none attached.

#### EXAMPLE

Erase the set:

```
+--------+--------+--------+--------+--------+--------+
| A5     | 1D     | 02     | 01 00  | FF     | lo hi  |
+--------+--------+--------+--------+--------+--------+
| SOF    | TYPE   | SEQ    | LEN    | section| CRC16  |
+--------+--------+--------+--------+--------+--------+
```

Library binding: [`clear_patch`](/library/advanced/patch.md#clear-patch).

## Presentation

_When the stored set reaches the game PC_

The clone serves the set it was last presented with, every section included. A presentation copies the stored set, runs the [checks](/native/commands/patch.md#ladder) and re-enumerates the clone on the game PC.

```
  PATCH   --> stored set        NVS, read back by QUERY(PATCHES)
                  |
                  |  presentation: attach, APPLY, CLEAR, opt-in toggle
                  v
              served set        what the game PC reads at enumeration
```

| Event | Presents when | Serves |
| --- | --- | --- |
| the device attaches | always | the stored set, under the opt-in |
| [APPLY](/native/commands/patch.md#apply) | the stored set differs from the served one | the stored set, or none when it is empty |
| [CLEAR](/native/commands/patch.md#clear) | the clone serves patches | none |
| the [opt-in](/native/commands/patch.md#gate) turned on | the stored set differs from the served one and is not [refused](/native/commands/patch.md#ladder) | the stored set |
| the opt-in turned off | the clone serves patches | none |

[`RESP(PATCHES)`](/native/commands/requests.md#patches) lists the stored set; its flags say whether the clone serves it.

> **Note**
>
> A presentation re-clones the device, as a replug does. It releases [injection](/native/injection.md#state), [locks](/native/commands/lock.md), [transforms](/native/commands/transform.md), [rewrite rules](/native/commands/rewrite.md#lifecycle), the loaded [clip](/native/commands/clip.md) and its triggers, and the [`CATCH`](/native/commands/catch.md) table. The release moves the [`session`](/native/commands/requests.md#stats) count.

## Sections

_Per-section behaviour_

A patch writes over bytes the descriptor already has, except STRING, which replaces the string. One that would run past the descriptor's end is skipped whole, never truncated.

```
  device descriptor   00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11
  offset 12, 2 bytes                                      xx xx                  lands
  offset 17, 2 bytes                                                     xx xx   past the end: skipped
```

| Name | Behaviour |
| --- | --- |
| DEVICE | Writes the served identity, which [`QUERY(DEVICE_INFO)`](/native/commands/requests.md#device-info) then reports. The set and every learned setting stay keyed on the real VID:PID. Byte 17, `bNumConfigurations`, is set to the captured configuration count after the patch lands. |
| CONFIG | Writes the served configuration, which the box then parses for its interfaces and endpoints, so a patched endpoint faces the same clone checks a native one does. |
| REPORT | Writes the report descriptor before the box parses it, so [`INJECT`](/native/commands/inject.md), [`LOCK`](/native/commands/lock.md) and the emitted report follow the patched layout. |
| STRING | Serves the bytes as the whole string, any length up to 127, one UTF-16 code unit per byte; a `0x00` byte ends it. Index `0`, the language list, is not patched. |
| BOS | Writes the BOS descriptor, on a device that has one. |

With two STRING patches on one index, the one listed first in [`RESP(PATCHES)`](/native/commands/requests.md#patches) is served. An overwrite moves a patch to the end of that list.

> **Note**
>
> A CONFIG patch to `bInterval` is served as written, while the box keeps polling the device at the rate [`OPTION(EMIT)`](/native/commands/option.md#emit) forces.

## Checks

_What a patched clone must pass_

A set that fails a check the device passes without it is refused: the clone is presented unpatched and one [`LOG`](/native/commands/admin.md#log) line names the check. A device that fails without the set is refused as any device is.

```
  patched descriptors
        |
        +-- the clone checks every device faces
        +-- framing: length and type fields
        +-- bcdUSB against BOS
        +-- wDescriptorLength against the report descriptor, every configuration
        +-- wMaxPacketSize against the report, the configuration in force
        |
        +-- all hold   -->  clone served patched, PATCHES b0, HEALTH PATCH_ON
        +-- one fails  -->  clone served unpatched, PATCHES b1 + b2, one LOG line
```

#### CHECKS

| Refused when | Why |
| --- | --- |
| a clone check fails, such as an endpoint `wMaxPacketSize` above 64 | the patched descriptors face the checks every device does |
| a patch changes the device descriptor's `bLength` or `bDescriptorType`, or a configuration's or the BOS's `bLength`, `bDescriptorType` or `wTotalLength` | the box serves these as written: a larger length reads the host past the descriptor, a smaller one hides its tail |
| `bcdUSB` `0x0201` or above with no BOS | a host requests the BOS of any 2.01 device |
| a HID descriptor's `wDescriptorLength` differs from its served report descriptor, in any configuration | the game PC would ask for one length and get another |
| an interrupt-IN endpoint of a HID interface, in the configuration in force, has a `wMaxPacketSize` below that interface's report | the report would not fit the packet the endpoint advertises |

#### REFUSED SET

The set stays stored with [`PATCHES`](/native/commands/requests.md#patches) b2 set until it changes, and [APPLY](/native/commands/patch.md#apply) skips it until then. Change or remove the failing patch and APPLY, or [CLEAR](/native/commands/patch.md#clear) the set.

## Opt-in gate

_Stored always, presented under the opt-in_

[`OPTION(IMPERFECT)`](/native/commands/option.md#imperfect) gates whether the stored set reaches the clone.

| Item | Opt-in off |
| --- | --- |
| [`PATCH`](/native/commands/patch.md#patch) | stored and written to NVS |
| [APPLY](/native/commands/patch.md#apply) | ignored |
| [CLEAR](/native/commands/patch.md#clear) | runs |
| a clone of the device | presented unpatched, with [`PATCHES`](/native/commands/requests.md#patches) b1 set while a set is stored |

#### TOGGLE

A toggle [presents](/native/commands/patch.md#presentation) the clone again when that changes the set it serves. When the clone needs the opt-in for anything else, the device chip reboots and re-clones, as the [option](/native/commands/option.md#imperfect) describes.

#### WHILE APPLIED

While the clone serves a patched set, [`HEALTH`](/native/commands/requests.md#health) sets `PATCH_ON` (`0x0200`) and [`QUERY(OPTIONS, 0)`](/native/commands/requests.md#options) reports `clone_imperfect = 1`. A refused set sets neither.

## Lifecycle

_Stored configuration_

A set is stored per device, loaded when that device attaches, and kept until a removal, a CLEAR, or a [`RESET`](/native/commands/admin.md#reset) with the NVS flag erases it.

#### ERASED BY

```
remove      a PATCH with zero bytes at the patch's key
CLEAR       a PATCH with section 0xFF: the whole set
RESET       a RESET carrying the NVS flag: the whole store
```

| Event | Effect |
| --- | --- |
| the device detaches | the clone, `PATCH_ON` and `REFUSED` go; the set stays stored and readable until another device attaches |
| another device attaches | that device's set loads in its place, cloned or refused |
