This page is a work in progress and incomplete

Savefile Format

Vortex Engine uses a custom format to save and transfer modes, this save format can be represented in a variety of ways but always follows the same structure.

It is not important to know how the savefile is structured in odrer to use Vortex Engine, however if you are looking to do special modifications to a mode then understanding the structure can help.

A savefile is split into two components, the header and the modes.

The Savefile Header

The start of a savefile will always be the section called the save header. The save header contains the global information about the device.

The data that is found in the save header includes:

  • Vortex Engine Version Number (ex. 1.2.3)
  • Global Flags (one-click mode enabled, whether the device is locked, etc)
  • Device Brightness (ex: 150, max is 255)
  • Number of modes (May be less than device max)
  • Other global information that may be added in the future

The Savefile Modes

Immediately after the savefile header is a list of savefile modes, the number of modes in the list is represented in the ‘Number of Modes’ field of the savefile header.

A typical Mode entry looks like this:

  • The number of leds the mode contains
  • Extra flags/info about the mode
  • A list of ‘patterns’, one for each led
  • A list of ‘colorsets’, one for each led

Each Pattern in the list contains:

  • a pattern id (number saying which pattern it is)
  • 7 fields for blink timing customization

Each colorset in the list contains:

  • The number of colors in the colorset
  • A list of up to 8 RGB colors

Each RGB Color in the list of colors contains:

  • 0-255 Red value
  • 0-255 Green value
  • 0-255 Blue value

Example Duo Savedata

To explain the savefile format below is an explanation of the most confusing savefile, the Duo:

This is savedata from a Duo, the first 256 bytes come from the EEPROM and the second 256 bytes come from the last pages of flash (0x7e00 to 0x8000). Both of these together make up 512 bytes of storage space the Duo has available.

header:
0x0000:  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xE5, 0x92, 0x0A, 0x01, 0x05, 0x00, 0xFF, 
0x0010:  0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 

data:
0x001b:  0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x1F, 0x45, 0x6E, 0x02, 0x06, 0x06, 0x03, 0xFF, 0x00, 0x00, 0x00, 0xFF, 
0x0030:  0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x0040:  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x0050:  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x0060:  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 
0x0070:  0xD6, 0xBD, 0x18, 0x02, 0x02, 0x1C, 0x03, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 
0x0080:  0x00, 0x19, 0x03, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 
0x0090:  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00a0:  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00b0:  0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFC, 0x21, 0xCD, 0x02, 
0x00c0:  0x02, 0x00, 0x01, 0x97, 0x70, 0x9F, 0x00, 0x07, 0x01, 0x4D, 0x00, 0xB2, 0x00, 0x00, 0x00, 0x00, 
0x00d0:  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00e0:  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00f0:  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 
0x0100:  0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x2F, 0xC4, 0xDF, 0x02, 0x02, 0x00, 0x06, 
0x0110:  0xC4, 0x70, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x3B, 0x00, 0x00, 0xE9, 
0x0120:  0x4E, 0x00, 0x00, 0x03, 0x03, 0xC4, 0x4D, 0x00, 0x00, 0x00, 0x17, 0x3B, 0xB2, 0xE9, 0x00, 0xFF, 
0x0130:  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0x0140:  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1D, 0x00, 0x00, 0x00, 
0x0150:  0x00, 0x00, 0x00, 0x00, 0x76, 0x9D, 0x97, 0x16, 0x02, 0x06, 0x0E, 0x08, 0xFF, 0x23, 0x00, 0x00, 
0x0160:  0x06, 0x48, 0xFF, 0x55, 0xC6, 0x55, 0xFF, 0x43, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x66, 0x55, 
0x0170:  0xFF, 0x55, 0x57, 0x00, 0x00, 0x55, 0x57, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0x0180:  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0x0190:  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x01a0:  0xC4, 0x00, 0x47, 0x57, 0x02, 0x02, 0x0D, 0x01, 0x0D, 0x1E, 0xD8, 0x00, 0x0D, 0x05, 0x9F, 0x00, 
0x01b0:  0x00, 0x5A, 0xFF, 0xFF, 0xFF, 0x9F, 0x00, 0x00, 0x00, 0x66, 0xFF, 0xFF, 0x9F, 0x00, 0xFF, 0xFF, 
0x01c0:  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0x01d0:  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0x01e0:  0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x1B, 0x66, 0xE2, 
0x01f0:  0x02, 0x02, 0x05, 0x01, 0x97, 0x10, 0x6E, 0x00, 0x05, 0x05, 0x00, 0x00, 0x30, 0xFF, 0x54, 0xAA, 

Duo Save Breakdown

Every chunk of data stored by Vortex Engine is wrapped in a ‘ByteStream’ which always starts with a ‘Stream Header’.

The purpose of the stream header is to verify the size and CRC of the data that follows, while also carrying along information such as whether the stream is compressed or not.

The ‘save header’ of the duo is only 6 bytes, but those 6 bytes are wrapped in a ‘ByteStream’ which starts with a 12 byte ‘Stream Header’.

So, in the first 18 bytes, the first 12 bytes are the ‘Stream Header’, followed by 6 bytes for the ‘Duo Header’ itself.

In the future the Duo header could grow up to be 15 bytes without breaking the storage format, because the next 9 bytes after are reserved leaving 27 bytes for the Duo header maximum (12 Stream Header + 15 Duo Header)

The reason for 27 bytes is actually because the Duo save is split across two places, the EEPROM and it’s own flash memory.

The first 256 bytes of save are stored in the EEPROM, and 76 bytes must be reserved for each mode. That means 3 modes can be stored in the EEPROM with exactly 27 bytes left over. Those 27 bytes are reserved as the save header.

The remaining 6 modes of the Duo are stored across the 512 bytes of the last two flash pages of memory.

# First 18 bytes of save data above
0x0000:  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xE5, 0x92, 0x0A, 0x01, 0x05, 0x00, 0xFF, 
0x0010:  0x05, 0x02,

The way Duo storage is layed out, there is 27 bytes reserved for the save header and so far this is only 18, the next 9 bytes are 0x00’s because they act as reserved space for future header size increases.

So the full Duo Save Header storage space is these first 27 bytes of the EEPROM:

0x0000:  0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xE5, 0x92, 0x0A, 0x01, 0x05, 0x00, 0xFF, 
0x0010:  0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|--------|--------------|------------------|-------------------------------|
| Offset | Hex Values   | Value            | Description                   |
|--------|--------------|------------------|-------------------------------|
| 0000   | 06 00 00 00  | 00000006 modes   | Stream Size (4 bytes)         |
| 0004   | 00 00 00 00  | 00000000 flags   | Stream Flags (4 bytes)        |
| 0008   | 51 E5 92 0A  | 0A92E551 CRC     | Stream CRC (4 bytes)          |
|        |              |                  |                               |
| 000C   | 01           | Major = 1        | Version Major (1 byte)        |
| 000D   | 05           | Minor = 5        | Version Minor (1 byte)        |
| 000E   | 00           | Flags = 0        | Global Flags (1 byte)         |
| 000F   | FF           | Brightness = 255 | Brightness (1 byte)           |
| 0010   | 05           | Num Modes = 5    | Number of Modes (1 byte)      |
| 0011   | 02           | Build Number = 2 | Version Build Number (1 byte) |
|--------|--------------|------------------|-------------------------------|

+--------+----------------------------+------------------+-------------------------------+
| Offset | Hex Values                 | Value            | Description                   |
|--------|----------------------------|------------------|-------------------------------|
| 0x0000 | 06 00 00 00                | Size = 6 bytes   | Stream Size (4 bytes)         |
| 0x0004 | 00 00 00 00                | flags = 0        | Stream Flags (4 bytes)        |
| 0x0008 | 51 E5 92 0A                | CRC = 0A92E551   | Stream CRC (4 bytes)          |
+--------+----------------------------+------------------+-------------------------------+
| 0x000C | 01                         | Major = 1        | Version Major (1 byte)        |
| 0x000D | 05                         | Minor = 5        | Version Minor (1 byte)        |
| 0x000E | 00                         | Flags = 0        | Global Flags (1 byte)         |
| 0x000F | FF                         | Brightness = 255 | Brightness (1 byte)           |
| 0x0010 | 05                         | Num Modes = 5    | Number of Modes (1 byte)      |
| 0x0011 | 02                         | Build Number = 2 | Version Build Number (1 byte) |
+--------+----------------------------+------------------+-------------------------------+
| 0x0012 | 00 00 00 00 00 00 00 00 00 | (Padding)        | Reserved / Padding (9 bytes)  |
+--------+----------------------------+------------------+-------------------------------+

+--------+----------------------------+------------------+-------------------------------+
| 0x001B | 0E 00 00 00                | Size = 14 bytes  | Stream Size (4 bytes)         |
| 0x001F | 00 00 00 00                | flags = 0        | Stream Flags (4 bytes)        |
| 0x0023 | 33 1F 45 6E                | CRC = 6E451F33   | Stream CRC (4 bytes)          |
+--------+----------------------------+------------------+-------------------------------+
| 0x0027 | 02                         | Num LEDs = 2     | Number of LEDs (1 byte)       |
| 0x0028 | 06                         | Mode Flags = 6   | Mode Flags (1 byte)           |
| 0x0029 | 06                         | Pattern ID = 6   | Pattern ID (1 byte)           |
| 0x002A | 03                         | Num Colors = 3   | Number of Colors (1 byte)     |
| 0x002B | FF 00 00                   | Red Values       | Red Components (3 bytes)      |
| 0x002C | 00 FF 00                   | Green Values     | Green Components (3 bytes)    |
| 0x002D | 00 00 FF                   | Blue Values      | Blue Components (3 bytes)     |
| 0x002E | 00                         | Arg Map = 0      | Pattern Arg Differences Map   |
| 0x002F | 00 00 00 00 00 00 00 ...   | (Padding)        | Reserved / Padding (50 bytes) |
+--------+----------------------------+------------------+-------------------------------+

+--------+----------------------------+------------------+-------------------------------+
| 000000 | 02                         | Num LEDs = 2     | Number of LEDs (1 byte)       |
| 000001 | 06                         | Mode Flags = 6   | Mode Flags (1 byte)           |
+--------+----------------------------+------------------+-------------------------------+
| 000002 | 06                         | Pattern ID = 6   | Pattern ID (1 byte)           |
| 000003 | 03                         | Num Colors = 8   | Number of Colors (1 byte)     |
| 000004 | FF 00 00 44 55 66 77 88    | Red Values       | Red Components (3 bytes)      |
| 000012 | 00 FF 00 44 55 66 77 88    | Green Values     | Green Components (3 bytes)    |
| 000020 | 00 00 FF 44 55 66 77 88    | Blue Values      | Blue Components (3 bytes)     |
| 000028 | 7F                         | Map = 01111111   | Pattern Arg Map (1 byte)      |
| 000029 | 00 00 00 00 00 00 00       | Args             | Argument Overrides (7 bytes)  |
+--------+----------------------------+------------------+-------------------------------+
| 000036 | 06                         | Pattern ID = 6   | Pattern ID (1 byte)           |
| 000037 | 03                         | Num Colors = 8   | Number of Colors (1 byte)     |
| 000038 | FF 00 00 44 55 66 77 88    | Red Values       | Red Components (3 bytes)      |
| 000046 | 00 FF 00 44 55 66 77 88    | Green Values     | Green Components (3 bytes)    |
| 000054 | 00 00 FF 44 55 66 77 88    | Blue Values      | Blue Components (3 bytes)     |
| 000062 | 7F                         | Map = 01111111   | Pattern Arg Map (1 byte)      |
| 000063 | 00 00 00 00 00 00 00       | Args             | Argument Overrides (7 bytes)  |
+--------+----------------------------+------------------+-------------------------------+

+--------+----------------------------+------------------+-------------------------------+
| 000070 | ...
+--------+----------------------------+------------------+-------------------------------+

+ 12 bytes for header?

0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x1F, 0x45, 0x6E,

0x02, 0x06, 0x06, 0x03, 0xFF, 0x00, 0x00, 0x00, 0xFF,

0x0030: 0x00, 0x00, 0x00, 0xFF, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00,

0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x0070: 0xD6, 0xBD, 0x18, 0x02, 0x02, 0x1C, 0x03, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x0080: 0x00, 0x19, 0x03, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0090: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00a0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00b0: 0x00, 0x00, 0x00,