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.