Summer of Pinephone: Week 14

This week was spent implementing a command for submitting SMS messages. Given that I already had encoding working, it shouldn't have taken more than a day. Unfortunately, things don't always go as planned. Sometimes in more stupid, embarrassing ways than others.

There are four characters in this story: atd, a program that accepts high level commands, converts them to a form that the modem can understand, and can interpret responses from the modem; atc, a CLI frontend for atd; atsim, a program which lets me act like the modem, and send responses to atd; and modemtalk, a small program that lets me talk to the modem directly, through stdin and stdout.

When I started testing the submit command, I found that it would work when I used atsim to send atd what I expected the modem to send, but it wouldn't work when I tested against the actual modem. At one level, this was expected; I concluded that my mental model of the modem's behavior was doing was incorrect. However, when I tried to use modemtalk to see what the modem was actually doing, it was in-line with my mental modem. Immediately after, I ran atd again, tested it, and it worked properly. I killed it, started it, and again, it worked properly.

When the modem starts up, it spits out a bunch of information, even before commands are sent to it. My initial suspicion was that this output was somehow corrupting the internal state of atd, causing issues. I ended up rewriting the code that sends configuration commands to the modem, hoping that would solve the issue. It did not. I'm happy I did this however, because the code is just nicer now.

Looking deeper, the core problem seemed to be the following: atd expects to get a prompt from the modem, after which it could input the SMS message and send it on it's merry way. Even atd was sending the AT+CMGS command to the modem, the prompt was not arriving.

To help debug, I started adding a bunch of print statements to get the content of the modem input and output buffers, and found another issue: I expected responses from the modem to be terminated by \r\n, but instead they were only terminated by \n. This was a massive, vigorously waved red flag that something was wrong with the TTY configuration (modem communication happens through a TTY interface). modemtalk and atd use the exact same function to configure the TTY, so to confirm that they were doing the same thing, I went line by line the functions, making sure that all the flags being set were the same. They indeed were, which left me even more confused. I reverted to my hypothesis that somehow the initial output that the modem spit out was somehow messing up atd as to make the carriage returns disappear from the buffers, and somehow losing the SMS prompt. To fix the state without restarting the modem, I would start modemtalk, and input a character so that the modem would stop listening for an SMS message, and go back to listening for commands. Then I would start atd, and it would work flawlessly. Of course if I restarted the modem, atd would be broken again.

This morning, getting desperate, I did a more thorough check of the TTY configuration functions again, and found my problem. While the configuration function was the same in both modemtalk and atd, I wasn't actually calling the function in atd. This meant that if I ran atd on modem startup, the TTY would be misconfigured until running modemtalk, which actually configured it properly. In hindsight, this should have been the first thing I checked, but didn't even consider because all was well until I added SMS. More specifically, it broke because the kernel would wait until encountering a newline to send it to atd. The prompt doesn't end with a newline, so it would just never send.

It seems to work well now, so I can say that atd finally has the ability to send texts!

The next steps will be saving received texts, and the user interface.