SERIAL PROTOCOL FOR FNORDLICHT-NG FIRMWARE ========================================== Physical bus description ------------------------ The serial bus consists of up to 254 devices, each device having the uart rx pin connected to the uart tx pin of the predecessor, the uart tx pin connected to the tx successor. The uart is used with a baud rate of 19200. A device will retransmit each received byte immediately and unaltered, the only exception is the address byte in the sync sequence (which is incremented by one before retransmission). An interrupt line is connected to each device. Diagram: +----------------+ +----------------+ | device N | | device N+1 | UART: ... --> >-|RX TX|-> --> >-|RX TX|-> ... | INT | | INT | +-------+--------+ +-------+--------+ | | INT: -------------------+--------------------------+----------> ... Bootloader startup procedure ---------------------------- For updating the firmware installed on the devices of a bus, each device should be equipped with a bootloader program. At power-on, the bootloader should be started, sleep for 100ms and check afterwards, if the INT line is pulled down (by a bus-master). If INT is not pulled down, the bootloader is allowed to start the main firmware. Otherwise it should not attempt to start the main firmware, but wait for commands received over the bus. This procedure allows a recovery from a broken firmware which does not process commands received over the bus (such as the BOOTLOADER command). To enter the bootloader via the BOOTLOADER command, first pull down the INT line, then issue the command. Initial sync sequence --------------------- For the purpose of (automatic) address discovery and resetting the bus, a sync sequence consisting of 15x ESC (0x1b) followed by an address byte is used. The controller sends 15x ESC, followed by a null byte. Please note that the length of the sync sequence (16 byte) is different from the length of a command packet, which is 15 byte! A device MUST be able to detect this sequence asynchronously, i.e. even if it is in the middle of receiving a command packet. The device does not need to withhold the execution of the received command packet until it is clear if a sequence of ESC bytes constitutes a sync sequence. Example: A device received 4 bytes, say A B C D, of a packet, then a sync sequence. It may (or may not) execute the packet A B C D ESC ESC ... ESC but the sync sequence must be detected, too. Asynchronous detection of the sync sequence can be done by just counting the number of consecutive ESC bytes, as 15 consecutive ESC bytes can only occur in a sync sequence, never in a command packet (ESC cannot occur as a command in the second byte of a command packet). Flow: * controller sends 15x ESC, followed by the address of the first device (usually a null) * first device on the bus receives and retransmits 15x ESC, receives address byte, stores own address in ram, increments address byte and transmits new address to next device on the bus Result: Each device on the bus knows it's own address (=position). Commands -------- Commands are sent in packets, 15 bytes in length, and are passed from device to device unmodified. The first byte is the destination address (0-254, 255 is broadcast), the second byte contains the command. The meaning of the following 13 bytes depends on the value of the second byte (command). A device ignores non-broadcast packets for which the address byte does not match it's own address. Bytes which are declared as "don't care" bytes SHOULD be set to zero, this makes future extensions easier. List of commands: ----------------- command | function | description -------------------------------------------------------- 0x01 | FADE_RGB | set color/fade to color (RGB) 0x02 | FADE_HSV | set color/fade to color (HSV) 0x03 | SAVE_RGB | save color to EEPROM (RGB) 0x04 | SAVE_HSV | save color to EEPROM (HSV) 0x05 | SAVE_CURRENT | save current color to EEPROM 0x06 | CONFIG_OFFSETS | set global offset values 0x07 | START_PROGRAM | start program 0x08 | STOP | stop color changing 0x09 | MODIFY_CURRENT | modify current color 0x0A | PULL_INT | pull down INT line 0x0B | CONFIG_STARTUP | configure startup 0x0C | POWERDOWN | power down the device 0x1B | | RESERVED (sync-sequence) 0x80 | BOOTLOADER | start bootloader 0x81 | BOOT_CONFIG | configure bootloader 0x82 | BOOT_INIT | initialize bootloader data buffer 0x83 | BOOT_DATA | store data in bootloader data buffer 0x84 | BOOT_CRC_CHECK | compare check-sum 0x85 | BOOT_CRC_FLASH | compare check-sum with flash 0x86 | BOOT_FLASH | write provided data to flash 0x87 | BOOT_ENTER_APP | start application Command: FADE_RGB - set color/fade to color (RGB) (0x01) -------------------------------------------------------- Instruct the device to fade to the specified absolute color, given as a RGB value, with a specific speed. Step and delay might be modified by application of the global offsets (see CONFIG_OFFSETS), color values (red, green, blue) are used unmodified. All values are unsigned 8 bit integers. If step is set to 255, the target color is set without fading. If delay is 0, the target color is set directly after receiving the command packet. byte offset | name | description --------------------------------- 2 | step | increment step for fading 3 | delay | delay between steps when fading (in 10ms) 4 | red | red value 5 | green | green value 6 | blue | blue value 7-14 | - | don't care Command: FADE_HSV - set color/fade to color (HSV) (0x02) -------------------------------------------------------- Instruct the device to fade to the specified absolute color, given as a HSV value, with a specific speed. Step, delay and hue might be modified by application of the global offsets, saturation and value might be scaled by global scales (see CONFIG_OFFSETS). All values are unsigned 8 bit integers, except hue, which is a 16 bit little endian integer. If step is set to 255, the target color is set without fading. If delay is 0, the target color is set directly after receiving the command packet. byte offset | name | description ------------------------------------ 2 | step | increment step for fading 3 | delay | delay between steps when fading (in 10ms) 4-5 | hue | hue, 0-360, little endian 6 | saturation | saturation 7 | value | value (brightness) 8-14 | - | don't care Command: SAVE_RGB - save color to EEPROM (RGB) (0x03) ----------------------------------------------------- Save a color in RGB format, a fade speed (step and delay) and a pause length to the EEPROM. The EEPROM can store 60 color and speed/delay values (see section "EEPROM color storage" below). While writing the data to the EEPROM, the INT line is pulled down. All values are unsigned 8 bit integers, except pause, which is a little endian 16 bit integer. byte offset | name | description ------------------------------ 2 | slot | slot in the EEPROM (0-59) 3 | step | increment step for fading 4 | delay | delay between steps when fading (in 10ms) 5-6 | pause | time to wait before fading to next color (in 100ms) 7 | red | red value 8 | green | green value 9 | blue | blue value 10-14 | - | don't care Command: SAVE_HSV - save color to EEPROM (HSV) (0x04) ----------------------------------------------------- Save a color in HSV format, a fade speed (step and delay) and a pause length to the EEPROM. The EEPROM can store 60 color and speed/delay values (see section "EEPROM color storage" below). While writing the data to the EEPROM, the INT line is pulled down. All values are unsigned 8 bit integers, except pause and hue, which are little endian 16 bit integers. byte offset | name | description ----------------------------------- 2 | slot | slot in the EEPROM (0-59) 3 | step | increment step for fading 4 | delay | delay between steps when fading (in 10ms) 5-6 | pause | time to wait before fading to next color | | (in 100ms) 7-8 | hue | hue, 0-360, little endian 9 | saturation | saturation 10 | value | value (brightness) 11-14 | - | don't care Command: SAVE_CURRENT - save current color to EEPROM (0x05) ----------------------------------------------------------- Save the current color to EEPROM (RGB), together with a fade speed and a pause length. While writing the data to the EEPROM, the INT line is pulled down. All values are unsigned 8 bit integers, except pause, which is a little endian 16 bit integers. byte offset | name | description ---------------------------------------- 2 | slot | slot in the EEPROM (0-59) 3 | step | increment step for fading 4 | delay | delay between steps when fading (in 10ms) 5-6 | pause | time to wait before fading to next color | | (in 100ms) 7-14 | - | don't care Command: CONFIG_OFFSETS - set global offset values (0x06) --------------------------------------------------------- Set global values which influence how fast and what colors are when using FADE_RGB or FADE_HSV or the static programs documented below. All bytes are signed 8 bit integers, except hue, which is a little endian signed 16 bit integer. Saturation and value are scales. This means, the final saturation and value will be scaled with saturation/255 and value/255, respectively. byte offset | name | description ------------------------------------------- 2 | step | increment step for fading (offset) 3 | delay | delay between steps when fading | | (in 10ms, offset) 4-5 | hue | hue offset, signed, little endian 6 | saturation | saturation scale, unsigned, 0-255 7 | value | value scale, unsigned, 0-255 8-14 | - | don't care Command: START_PROGRAM - start program (0x07) --------------------------------------------- Start a program (a function compiled into the firmware) with given parameters. This command stops all other programs (and EEPROM fade sequences). For a list of programs and parameters see section "Static Programs". byte offset | name | description --------------------------------- 2 | program | program id, 0-255 3-11 | params | 10 byte parameters passed to program 12-13 | - | don't care Command: STOP - stop color changing (0x08) ------------------------------------------ Stop all processes modifying the current color. Optionally, also stop the current fading process. byte offset | name | description --------------------------------- 2 | fade | stop fading if set (1) 3-14 | - | don't care Command: MODIFY_CURRENT - modify current color (0x09) ----------------------------------------------------- Instruct the device to fade to a new target color, which is determined relatively to the one currently visible. This works only if no program (or EEPROM fade sequence) is running. The current color is faded to the target color with the given step and delay values. The RGB offsets are applied before the HSV offsets. Setting either one to zero will not modify the color in that color space. Step and delay are unsigned 8 bit integers, all other values are signed 8 (or 16) bit integers. byte offset | name | description ------------------------------------- 2 | step | increment step for fading 3 | delay | delay between steps when fading (in 10ms) 4 | red | red offset 5 | green | green offset 6 | blue | blue offset 4-5 | hue | hue offset 6 | saturation | saturation offset 7 | value | value offset 8-14 | - | don't care Command: PULL_INT - pull down INT line (0x0A) --------------------------------------------- Instruct the adressed device to immediately pull down the INT line (connected to all devices in parallel) for a given amount of time. This can be efficiently used to determine the number of devices listening to the bus (eg. by binary search). byte offset | name | description --------------------------------- 2 | delay | time to wait before releasing the INT line | (in 50ms, maximum 2550ms, jitter +-10ms) 3-14 | - | don't care Command: CONFIG_STARTUP - configure startup (0x0B) -------------------------------------------------- Configure what a device should perform after power-up. Mode is an unsigned 8 bit integer, selecting the desired startup mode. Two different modes can be configured: * NOTHING (mode == 0): Do nothing after startup (ie do not show any color, stay black) * PROGRAM (mode == 1): Start a static program compiled into the firmware, using the following 10 bytes as parameters for the program (for details see section "Static Programs"). If startup mode is PROGRAM, the CONFIGURE_STARTUP packet is constructed in this way (for the program indexes and meaning of the parameters see section "Static Programs"): byte offset | name | description ------------------------------------ 2 | mode | desired startup mode (1 in this case) 3 | program | static program index 4-14 | parameters | parameters to configured program Command: POWERDOWN - power down device (0x0C) --------------------------------------------- Power down the device. After receiving this command, the device should power down all light outputs and suspend itself to reduce the power consumption to a minimum. A device must resume operation after a falling edge on the INT pin. It is allowed to activate a pull-up resistor on that pin, to pull the pin to a defined level. byte offset | name | description ------------------------------------ 2-14 | don't care | Command: BOOTLOADER - start bootloader (0x80) --------------------------------------------- If a bootloader is installed, jump to the bootloader, otherwise just restart the device. A magic byte sequence of 0xfc27566b (little endian) must follow the command byte. Pull down the INT line BEFORE sending this command, otherwise the bootloader might not be able to detect wether to start the main firmware or remain within the bootloader code. byte offset | name | description --------------------------------- 2 | byte1 | magic byte 1 (0x6b) 3 | byte2 | magic byte 2 (0x56) 4 | byte3 | magic byte 3 (0x27) 5 | byte4 | magic byte 4 (0xfc) 6-14 | - | don't care Command: BOOT_CONFIG - configure bootloader (0x81) -------------------------------------------------- Set configuration options of the bootloader. Currently the only options is the start address. Start address is an unsigned 16-bit integer automatically incremented by the configured packet size upon each flash command. byte offset | name | description --------------------------------- 2-3 | start | address to flash to 4-14 | - | don't care Command: BOOT_INIT - initialize bootloader data buffer (0x82) ------------------------------------------------------------- This resets and clears the internal bootloader data buffer. byte offset | name | description --------------------------------- 2-14 | data | payload Command: BOOT_DATA - store data in the bootloader data buffer (0x83) -------------------------------------------------------------------- Store data (up to 13 data bytes) at the end of the bootloader data buffer. If the buffer is full, additional bytes will be ignored. byte offset | name | description --------------------------------- 2-14 | data | payload Command: BOOT_CRC_CHECK - compare check-sum (0x84) -------------------------------------------------- Compare provided CRC-16 checksum against calculated checksum over the first len bytes of previously received data in the data buffer. If both checksums do not match, the boot loader MUST immediately pull down the INT line. The INT line must be held down for the time specified in delay and be released afterwards. chksum is a little endian unsigned 16 bit integer. The CRC calculation uses the polynomial x^16 + x^15 + x^2 + 1 (0xa001) and 0xffff as initial value. byte offset | name | description --------------------------------- 2-3 | len | checksum over the first len buffer bytes in the buffer 4-5 | chksum | CRC-16 checksum over the data chunk 6 | delay | time to wait before releasing the INT line | (in 50ms, maximum 2550ms, jitter +-10ms) 7-14 | - | don't care Command: BOOT_CRC_FLASH - compare check-sum with flash (0x85) ------------------------------------------------------------- Compare provided CRC-16 checksum against calculated checksum over len bytes from flash starting at addr. If both checksums do not match, the boot loader MUST immediately pull down the INT line. The INT line must be held down for the time specified in delay and be released afterwards. Chksum, start and len are unsigned 16 bit little endian integers. The CRC calculation uses the polynomial x^16 + x^15 + x^2 + 1 (0xa001) and 0xffff as initial value. byte offset | name | description --------------------------------- 2-3 | addr | checksum len bytes starting at this address 4-6 | len | checksum over the first len buffer bytes in the buffer 6-8 | chksum | CRC-16 checksum over the data chunk 9 | delay | time to wait before releasing the INT line | (in 50ms, maximum 2550ms, jitter +-10ms) 10-14 | - | don't care Command: BOOT_FLASH - write provided data to flash (0x86) --------------------------------------------------------- Write the data provided earlier to the flash memory of the device. The device pulls the interrupt line down upon reception of the command and releases it on successful completion of the command. This way the master node is capable of detecting when the successing initial data packet may be provided by continuously sensing the interrupt line. After completion of this command the address where to flash to is incremented by the configured chunk data size. byte offset | name | description --------------------------------- 2-14 | - | don't care Command: BOOT_ENTER_APP - start application (0x87) -------------------------------------------------- Leave bootloader and launch application code. byte offset | name | description ------------------------------------ 2-14 | - | don't care Static Programs --------------- This section describes the programs which are (in the default version) compiled into the firmware. program "colorwheel", program index 0 ------------------------------------- This program fades throught the HSV color space, with fixed saturation and value, starting at hue_start. In each step, hue_step is added to the current hue value, afterwards the device fades to the resulting color (using fade_step and fade_delay) and waits for the time specified by fade_sleep. If add_addr is nonzero (attention: signed integer!), the fade ist not started at hue_start but (hue_start + addr_add * device_address * hue_step). This program honors the globally defined offsets set with the CONFIG_OFFSETS command in each step. If a global offset is reconfigured, the new value will be applied in the next color calculation of this program. byte offset | name | description --------------------------------------------------------- 0 | fade_step | used for fading to new color | | (unsigned 8 bit integer) 1 | fade_delay | used for fading to now color | | (unsigned 8 bit integer) 2 | fade_sleep | sleep between steps (in seconds) | | (unsigned 8 bit integer) 3-4 | hue_start | start at this hue value | | (unsigned 16 bit integer 5-6 | hue_step | add this to the hue in each step | | (signed 16 bit integer) 7 | add_addr | add hue_step address-times before start | | (signed 8 bit integer) 8 | saturation | saturation | | (unsigned 8 bit integer) 9 | value | value | | (unsigned 8 bit integer) program "random", program index 1 --------------------------------- When this program is started, the pseudo-random generator is initialized with the seed value. If the use_address-bit within the flags byte is set, the address of a device is XORed with the seed before initializing the pseudo-random generator, so the random values also depend on the address of the device. In each step, this program generates a new random hue value which is at least min_distance away from the current hue value. Afterwards the device fades to the new color (using the generated hue and the configured saturation and value from the parameters). The parameters fade_step and fade_delay are used in each fade. If the wait_for_fade-bit within the flags byte is set, the device waits until the target color is reached. Afterwards the device sleeps for a configurable amount of time (fade_sleep). This program honors the globally defined offsets set with the CONFIG_OFFSETS command in each step. If a global offset is reconfigured, the new value will be applied in the next color calculation of this program. flags (1 byte) -------------- Bits: MSB LSB 7 6 5 4 3 2 1 0 | | | | | | | \- use_address -- XOR device address and seed before | | | initializing the pseudo random generator | | \--- wait_for_fade -- wait until the (newly generated) | | target color is reached before sleeping \---------+----- reserved byte offset | name | description ---------------------------------------------------------------------- 0-1 | seed | used for initializing the random generator | | (unsigned 16 bit integer) 2 | flags | flags | | (unsigned 8 bit integer) 3 | fade_step | used for fading to new color | | (unsigned 8 bit integer) 4 | fade_delay | used for fading to now color | | (unsigned 8 bit integer) 5-6 | fade_sleep | sleep between steps (in 100ms) | | (unsigned 16 bit integer) 7 | saturation | saturation | | (unsigned 8 bit integer) 8 | value | value | | (unsigned 8 bit integer) 9 | min_distance | minimal distance for new hue value | | (unsigned 8 bit integer) program "replay", program index 2 --------------------------------- The commands SAVE_RGB, SAVE_HSV and SAVE_CURRENT stores a color, fade_step, fade_delay and fade_sleep to the EEPROM. This program replays the stored colors, from start to end. If repeat is 0, the sequence stops when end is reached, if repeat is 1, the sequence is restarted from the beginning and if repeat is 2, the color sequence is played in reverse order, from end to beginning. This program honors the globally defined offsets set with the CONFIG_OFFSETS command for hsv colors in each step. If a global offset is reconfigured, the new value will be applied in the next color calculation of this program. byte offset | name | description ---------------------------------------------------------------------- 0 | start | index of the first color | | (unsigned 8 bit integer) 1 | end | index of the last color (included) | | (unsigned 8 bit integer) 3 | repeat | configure repetition | | (unsigned 8 bit integer) 4-9 | don't care |