# Beyond Config Data Format
## Basic Info
Programmable values in the microcontroller are assigned to a special region of Flash memory in the ATSAMG55G19 microcontroller. It has a 512 byte region saved just for “user signature” which I’ve used for this config region. There are USB HID commands to read and write raw bytes to this region. But to make those bytes actually do something, you’ll need to format them properly.
## Config Region Format
All of the variables in the config region are saved in a “Tag, Length, Value, CRC” format. That means there isn’t a specific byte location in memory that you will find a variable. You have to read the whole 512 byte region and decode it from start to finish.
* Tag: Defines the data type, see table below. One byte.
* Length: number of data bytes in the tag. One byte.
* Value: The actual data saved for this variable, number of bytes depend on data type.
* CRC: 8-bit cyclic redundancy check, one byte. Calculated with polynomial “0x07” and initialization of “0xFF”. See appendix for example code to generate the CRC.
An example saved variable would look like:

| Byte#:    | 0     | 1     | 2     | 3     |
| ---           | ---   | ---   | ---   | ---   |
| __Content:__  | tag   | Data Length | Data | CRC8 |
| __Value:__ | 0x03 (fan speed) | 0x01 | 0x55 (decimal 85, meaning 85%) | 0x2F |


## Config Region Tags:

| Name | Tag | Length (bytes) | Description |
| ---  | --- | ---            | ---         |
|Serial|	0x01|	Variable|	Board (PCBA) serial number. |Generally saved by CM at the factory.
|RGB Color|	0x02|	3|	Red, green, blue color settings, same as HID command.|
|Fan Speed|	0x03|	1|	Fan speed as a percent. Value allowed 0 to 100.|
|Proximity Disable|	0x04|	1|	If it is any value other than zero the proximity sensor will be disabled (displays will always turn on regardless of proximity sensor)|
|Linkbox V1 (Deprecated|	0x05|	1|	If it is any value other than zero then the DisplayPort Hot Plug Detect line level is inverted. This was needed for Linkbox V1. All newer Linkboxes do not need this setting.|
|Proximity Calibration|	0x06|	2|	Unsigned 16-bit integer (LSB first). Proximity raw value when nothing is present. This value is subtracted from proximity readings as a null offset.|
|FATP Mode|	0x07|	1|	Surprise! It’s actually not used right now in firmware. Doesn’t really change to FATP mode at boot. Must use USB HID command to do it.|
|HMD Serial|	0x08|	Variable|	HMD unit serial number. Would be saved by us or CM after headset is assembled, but isn’t usually done yet.|
|Tracking Serial|	0x09|	Variable|	Tracking flex serial number. (Can also be retrieved by using SteamVR “lighthouse_console.exe”). Would be saved by us or CM after headset is assembled, but isn’t usually done yet.|
|Display Brightness	|0x0A|	2|	Unsigned 16-bit integer (LSB first), default startup OLED brightness. Can be 0 to 1023 (0x0000 to 0x03FF), where 1023 is maximum brightness.|
Proximity Threshold|	0x0B|	2|	Unsigned 16-bit integer (LSB first). Sets the threshold proximity sensor value that triggers display on / off.|
|Proximity Hysteresis	|0x0C	|2	|Unsigned 16-bit integer (LSB first). Sets the hysteresis in proximity sensor value. For example: <br> * Displays turn on when prox value is >= (thresh + hyst) <br> * Displays turn off when prox value <= (thresh – hyst)|
|EDID Override Switch|	0x0D|	1|	Sets the monitor resolutions in the Extended Display Identification Data (EDID) to include the following resolutions / timings:<br> * 0: Both 75Hz and 90Hz available<br> * 1: Only 90Hz available<br> * 2: Only 75Hz available<br> * All other values: not allowed|
|Invalid / Blank|	0xFF|	n/a|	All unused bytes are set to 0xFF. When you are traversing the 512 byte chunk and reading off data, when you hit a tag “0xFF” you can safely assume you’ve reached the end of saved variables.|

## Appendix A: Example C code for CRC-8 generation
```C
// Calculates a CRC8 checksum value over any length of data
#define CRC8POLY    (0x07) // Polynomial generator for CRC
#define CRC8INITVAL (0xFF) // Initial value for CRC

uint8_t crc8(const uint8_t* input_data, uint32_t len) {
    uint32_t i;
    uint8_t j;
    uint8_t initcrc = CRC8INITVAL;
    const uint8_t* l_input;
    l_input = input_data;
    for(i = 0; i < len; i++) {
	    initcrc ^= *l_input;
	    l_input++;
        for(j = 0; j < 8; j++) {
            if(initcrc & 0x80u) {
                initcrc = (initcrc << 1) ^ CRC8POLY;
                } else {
                initcrc = (initcrc << 1);
            }
        }
    }
    return initcrc;
}
```

## Appendix B: Example Python code for CRC-8 generation
```Python
CRC_INIT_VAL = 0xFF
CRC_POLY = 0x07

def crc8(input_data: bytes) -> int:
    initval = CRC_INIT_VAL
    for bb in input_data:
        # for each byte, xor with the current value of CRC
        # then iterate over all 8 bits using the polynomial 
        # to generate crc bits
        initval = initval ^ bb
        for _ in range(8):
            if(initval & 0x80):
                initval = ((initval << 1) & 0xFF) ^ CRC_POLY
            else:
                initval = (initval << 1) & 0xFF
    return initval
```