Hayes AT

A long long time ago, in galaxy far far away (no, scratch that bit), a standard evolved for talking to modems, well, specifically Hayes modems, but it was widely adopted.

It works over a serial link by sending commands starting AT for (attention). Now, I am pretty sure they were reasonably consistent, back in the day, but like many things this standard has evolved and been bastardised.

We now have things like this SIM800 module, which is basically a mobile phone in a can, with no display or keypad. It talks on a serial bus and talks Hayes AT commands, but as modified by various GSM bodies.

Now, some AT commands are consistent. You send AT and some options, and get some data followed by OK. Good.

There is a reasonably consistent format for commands and settings and queries, mostly. There are then AT+ functions which are used for a lot of the mobile stuff.

But it is far from consistent. The AT+CIPSEND, after the > sends "SEND OK" not "SENT OK" or "OK", and AT+CIPSHUT sends "SHUT OK". Why are these not just "OK" like the rest? I am also pretty sure I had one case of a response with no OK (but cannot find it now).

Then we have the asynchronous messages from the device. Most start with a +, like "+CREG: 0,1", so can be recognised if you are expecting another response. But some are just text like "SMS Ready". These smack of debug messages left in the code.

Half the interface was clearly designed for a person sat at a terminal typing stuff, and the other half was designed for talking to a machine!

But when you get to some of the higher level functions, like establishing a UDP "connection", it gets even more special. For a start, you look for "CONNECT OK" not simply "OK", and mostly at that point it seems to avoid sending asynchronous messages (though I cannot be sure). Some still can be sent, like "+PDP: DEACT" when it loses the connection. What you do get though, with no prompt, header, or indication of length is the raw binary content of any UDP packets you receive on the connection. So send a packet containing "+PDP: DEACT" and I'll think the connection has dropped!

What would have been sensible would have been a line something like "+DATA=N" and then N bytes of data, or some such, but no, it is simply the raw UDP packet.

Then we have some interesting little bugs and discrepancies. One that took a while to work but was that the length of UDP data I can send is limited. Not to 65535 which is what IP limits to, but to 1472 which is the available UDP in a 1500 byte IPv4 packet. Except it is not. It is actually 1460, any more says "ERROR". Oh, and it won't allow me to send a zero length UDP packet - no idea why, and as NAT is often used this is something I may want to send as a keep alive. I ended up having to send one byte.

But there is an even more special feature. When you receive a UDP packet, as I say, it arrives as the raw binary data via serial. I am relieved to see no mangling of any bytes, which is good. Except it truncates the last byte of the message. Yep, I have to send an extra dummy byte on my packets to the device. WTF?

I could save myself from a lot of this by coding PPP, pretending to dial on an old style modem and talking PPP which the device fakes and converts to packet data. This is a serious consideration, to be honest.

However, after a lot of messing about, my GPS trackers are sending (and receiving, when needed) tracking data over UDP over mobile - yay!

P.S. I may have maligned the SIM800 as incoming UDP looks like it may be my bug losing a byte, and there is an option for a header with length for incoming UDP. But the Quectel M95 does look a bit nicer.


  1. "So send a packet containing "+PDP: DEACT" and I'll think the connection has dropped!"

    To be fair, that's no worse than the old "+++ath0" feature of the original Hayes set :)

    1. I loved sending ECHO REPLY with ++ATH0 embedded back in the day. Systems would try to reply and instead drop their connections.

    2. Proper implementations of the Hayes protocol were supposed to expect a pause after the "+++" - if the "ATH0" came straight away with no pause, they would treat the whole sequence as data and not hang up. But lots of modems didn't implement that (patent issue?), so it would indeed cause the other end to hang up.

  2. The standards for all of this is in the Technical Reference: 27.007 Title: AT command set for User Equipment (UE),

  3. Off topic, but I'd love to read a blog post on your thoughts of the 'british broadband' announcement...

  4. Bite the bullet and go for the PPP thing, if you have space in your host controller for it.

    It'll make swapping out the SIM800 module easier later.

    When I've done stuff with the (extended) AT command set in the past, I've stuck to the standardised stuff that's commonly implemented and got to a higher level standard (that's also commonly implemented) as soon as possible.

    Of course, it's engineering trade-offs as usual. If you're doing a super lean, cost-down product then you might need to take advantage of as many of the "smarts" and "value-add" of the SIM800 as possible, but you'll have a more reusable platform if you get to PPP as soon as possible.

    Sometimes a module will implement a command almost similar to another module, but not well specified enough to really rely on, but then provide another command of its own that has better semantics and is easier to distinguish.

    Also, keep an eye out for the AT* commands. ;-)

    Good luck! I can't wait to read more about what you find.


Comments are moderated purely to filter out obvious spam, but it means they may not show immediately.

Angles Mort

I saw this on a truck (non UK plates), and they do puzzle me a bit. For a start, it is not clear - are the black bits the death angles - in ...