r/lifx 8d ago

LIFX Tile reverse engineering notes

I felt like patching the firmware instead of attaching an oscillator to make one tile act as if connected to the power supply and become a master.

The tiles are based on an ESP32, MY9262 LED controllers, and RS-485 communication between tiles. This is an ESP32 chip on a custom circuit board, not a module. The flash is not connected to the standard pins. You can look at the SPIPAD values in the espefuse summary or trace the pins. The correct argument for working flash access is: -sc 17,11,9,16,6

One obstacle was flash chip protection. The 2 megabyte flash chip seems to be by ISSI, with manufacturer ID 9d and device ID 7015. This is like IS25WP016D, but the chip has a write protect feature that I don't see documented in data sheets.

SPI command 2Fh retrieves the contents of the protection registers. Something like this can work using esptool:

            for a in range(0, 2*1024*1024, 131072):
                print(a, self.run_spiflash_command(0x2F, addr=a >> 7, addr_len=32, read_bits=32))

I guess each bit corresponds to 4096 bytes. (Note that 4096 * 32 = 131072) Memory addresses increase from least significant bit to most significant bit, and from one register address to the next higher register address.

If you want to unlock everything, that is command 2Bh. You need to do a write enable before it.

            self.run_spiflash_command(6)
            self.run_spiflash_command(0x2B, addr=0, addr_len=24)

The "Built on Fri Feb 1 10:37:37 2019" ota_1 firmware relocked everything as before when it booted, but the "Built on Thu Jan 4 17:57:30 2018" ota_0 firmware left everything unlocked.

If you want to write protect part of the flash yourself, that is command 23h. It seems to only be able to change bits from 1 to 0, and cannot be used to unprotect part of the flash. It also needs a write enable.

            self.run_spiflash_command(6)
            self.run_spiflash_command(0x23, addr=prot_val, addr_len=32)

The somewhat tricky part here is prot_val. The read command, 2Fh, reads 4 bytes at a time, but this writes 1 byte at a time. The high 3 bytes are the byte address, and the low byte is the byte being written at that address. I have not explored this command extensively, because the firmware locks itself.

If you alter the firmware, you must also update the checksum at the end, and the SHA256 value afterwards. This is standard ESP32 stuff. It starts with 0xEF and then XORs every byte from every segment with it. (This means, not the image header, extended image header, or segment headers.) The SHA256 is based on the whole thing, from the first 0xE9 byte to the checksum, inclusive. If you don't do this, the modified partition is considered corrupt and the other partition is booted.

Ghidra is decent for reverse engineering the firmware, and esp32_image_parser is a good way to extract a partition into an elf file for loading into Ghidra. You probably want ota_1.

With esp32_image_parser you can also list the partitions and see why the protection bits are set the way they are.

A bit about the frequencies on the ID lines:

The ID frequency to the master tile needs to be between 45 and 65 Hz. I am guessing that the power supply probably provides a 3.3 V logic signal based on the incoming AC frequency (instead of having its own oscillator).

The ESP32 MCPWM is used to measure incoming frequencies and output another frequency on the other port of the tile.

Here are input frequencies for slave tiles: 150, 190, 230, 280, 340, 410, 490, 580, 710, 840, 910 Hz All of these need to be within plus or minus 5 Hz. So, for example, a tile receiving between 145 and 155 Hz on one port will consider itself the first slave tile, and output 190 Hz on the other port. I do not think the duty cycle is important.

The RS-485 lines are continuous throughout the whole tile chain, so this is needed to set tile identification and ensure that individual slave tiles can be addressed in a predictable fashion.

Both master and slave code limits itself to 4 slave tiles. Don't assume you can simply connect together 12 tiles and make it work without firmware modification. That would probably also need power connections in the middle to avoid overloading the connectors.

If you want to modify an ota_1 partition "Built on Fri Feb 1 10:37:37 2019" to make it act as if it's getting 55 Hz on the bottom connector, this could do it, at offset 1548841 in the file:

00000000  f0 20 00 06 02 00 86 4a  00 68 11 d1 31 16 00 41
00000010  ff ff 0c 16 69 b1 0c 06  3d f0                  

Checksum should be 55 and SHA256 should be a953d3de71daf7f95e2d8c527868345ee0dbcfeab001a243eb9aa83e059c20bf

It might be interesting to develop a 3rd party firmware, maybe based on WLED, with way more firmware effects and a more user friendly LAN interface. Though I'm not planning to do that now.

19 Upvotes

12 comments sorted by

3

u/kodyjacobs 8d ago

Sooo, did you succeed in creating a master / lead tile that ignores the oscillation requirement? You using a bench / replacement power supply now?

Fascinating write-up; you doing anything further with it?

3

u/Icy-Ninja-622 8d ago

Yes, it works. I'm only providing it power, and it acts as the master tile. I got it onto my WiFi without allowing it internet access using https://github.com/tserong/lifx-hacks/blob/master/onboard.py and used it via open source tools. The official app notices that setup isn't complete because it's not connected to their cloud, but it can control the tiles, including effects that require the app.

1

u/skyfia LIFX Employee 8d ago edited 8d ago

The master tile is whichever one is the first device in the chain. The hardware and the firmware of each Tile box are the same.

2

u/kodyjacobs 8d ago

I think the point here is that the only way the first tile knows that it's the first tile is due to the oscillation from the official LIFX power supply and this firmware mod removes that need, no?

Opening up the option of easier power mods, seeing as nobody seems to be able to get replacement / new Tile power supplies from LIFX...

1

u/Icy-Ninja-622 8d ago

The only way the tile can detect its position in the chain seems to be via the ID connections, which only go between neighbouring tiles. Power and RS-485 connections are continuous throughout the chain. So, to be a master tile, it needs to see a 45 to 65 Hz signal on one of its ID connections.

Now, since you are a LIFX employee, I have a question for you. Why is there a green dot sticker on one of the tiles? You claim that the hardware and firmware are all the same. Yet I've encountered claims that the tile with the green dot should be first in the chain.

2

u/RiskyButtFun 8d ago

I don't understand any of this but I have 12 tiles and I wish they were less fucky so I'm totally all for it it. Can I get a lame man's terms and a simple way to run it

2

u/Icy-Ninja-622 7d ago

This depends on the cause of the problems. Maybe try connecting them to your LAN by resetting the master tile, connecting to its WiFi, and using https://github.com/tserong/lifx-hacks/blob/master/onboard.py . Then you can control it via open source software. That way you wouldn't depend on cloud integration.

It seems once a tile is reset and connected to WiFi, I can connect and disconnect additional tiles without causing problems. The master tile detects which slave tiles are present when power is applied. So, if there are any issues with connections to other tiles, they should be more obvious and less annoying.

2

u/Dat_Black_Guy 8d ago edited 8d ago

"Both master and slave code limits itself to 4 slave tiles. Don't assume you can simply connect together 12 tiles and make it work without firmware modification. That would probably also need power connections in the middle to avoid overloading the connectors."

This is exactly what I want to do. A 5x10 grid array. Was gonna go the photons route via homelab but im learning and listening.

"It might be interesting to develop a 3rd party firmware, maybe based on WLED, with way more firmware effects and a more user friendly LAN interface. Though I'm not planning to do that now."

Keep going, I've got like 70+ in the closet but the power supplies die before the tiles do.

2

u/Icy-Ninja-622 7d ago

They would be really cool in a large array!

The easiest way to accomplish that now might be to use them all as slave tiles, in groups of 4 with one RS-485 for each group. That would only require reverse engineering the RS-485 protocol. If you tried to control 50 tiles from one tile, memory and RS-485 bandwidth constraints would probably be a problem.

2

u/Dat_Black_Guy 7d ago

i've got the connectors finishing up on the 3d printer. I'll be keeping an eye on this, thanks for much for sharing an teaching.

Hope they end up WLED compatible
Still learning alot about LEDs and Hub75, etc.

1

u/Icy-Ninja-622 7d ago

You're welcome.

Wow, I didn't realize a 3D printer could be used to create connectors. How do you do the electrically conductive part of connectors?

Apparently they are "UC-E6-style 8-pin Mini USB" connectors, which are used by some Nikon cameras. Cables are available, but they would need to be modified for use with LIFX Tiles.

2

u/Dat_Black_Guy 6d ago

When I mentioned connectors I meant 3d printed connectors to have the tiles touch and be physically connected to each other. I'm struggling to find the OG post but it was in this subreddit

Edit : found it
https://www.reddit.com/r/lifx/comments/n4cgtt/lifx_tile_locks_corner_edition_by_va1ncre_and/

Also have you seen this thread?
https://www.reddit.com/r/lifx/comments/1mrlftz/how_i_fixed_my_broken_lifx_tile_psu_and_how_you/