Now I had the AI running, I could happily fire up many Tamagotchis at a time without having to pay attention to them. The Tamagotchis themselves still lived in isolation, however: they had no way to talk to eachother. The hardware in this version of the Tamagotchi does actually support this: through a simple IR LED and receiver, two Tamagotchis can exchange data and visit each other or play a game. The infrared port was still unemulated, and I would need to change that first.
In order to network the Tamagotchis, I first would have to make them communicate, and I would need a sort of arbiter to do so: the infrared protocol the Tamagotchis use is meant for an one-to-one conversation and the Tamagotchis broadcasting their IR signal to every other Tamagotchi would lead to failure. I designed a simple daemon called the Tamaserver for this. The purpose of this Tamaserver is to connect a Tamagotchi to a random other Tamagotchi as soon as the AI in it decides it it time for some quality time spent together in company.
The infrared signal has already been reverse engineered by Natalie. It's basically a protocol similar to a standard IR remote control protocol. There's a start- and a stop sequence, and a bunch of ones and zeros indicated by a burst of IR output and then a pause. For both the ones and the zeroes, the burst lasts about 1.5mS. For the ones, however, the pause lasts 3mS while the zeroes only have a 1.5mS pause.
With the protocol being what it is, it isn't really possible to just take the output of the IR diode and push it over some UDP packets to the other Tamagotchi. Each Tamagotchi is in its own separate process, and there a lot of things that can happen that make the Tamagotchis run out of sync for a while: the server may decide to swap out something, there'sa big packet coming in, something needs to be written to disk... especially on a server not dedicated to running the Tamagotchis, there's just too much going on to get the millisecond precision in communication between processes we need.
My solution to this was to decode the IR signals within the Tamagotchi. The emulator basically decodes the IR signals and converts them to a binary message. That binary message is sent to the other Tamagotchi emulator, which re-modulates the message as an IR signal and feeds it to the Tamagotchi itself.
Unfortunately, this led to another problem. The Tamagotchis are used to the IR transmission to have no latency at all
(sending and receiving happens simultaneously), while the decoding introduces latency: the receiving Tamagotchi
doesn't get a message until the message that the sending Tamagotchi spits out has been entirely decoded. This leads
to all sorts of timeouts, making communication fail. To clarify, this is what the Tamagotchi is expecting to happen:
However, with the decoding and recoding latency added, this happens. Tama1 times out and will abort the communication
How to solve this? Well, we're talking about emulators here; why not just stop time? If we suspend execution on
a Tamagotchi emulator, it will not see the time passing when we replay the IR message, and it will happily continue
communicating without timing out:
So now all was needed was some additions to the AI. When one AI decides it is time to visit another Tamagotchi, it will send an UDP packet to the Tamaserver, which will hook it up with another Tamagotchi. The AI for the second Tamagotchi will also get a message indicating it should go to infrared receive mode. Both AIs will navigate the menus to make the Tamagotchis communicate over IR and relay the messages to eachother, usually leading to a successful visit. Here's me triggering one of those visits: