Hayes AT modem / UART OK and ERROR handling

Here you can share completed projects or parts of projects that may be useful to others. You may post files relevant to ZBasic - source code, schematics, etc.
Post Reply
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Hayes AT modem / UART OK and ERROR handling

Post by GTBecker »

Preface: my apologies for what feels like a long message which asks you to look at code.

The AT command structure has endured. Originally a modem control language developed by Hayes, it finds itself controlling lots of serial devices still - in my experience most commonly GPSs and Bluetooth modules.

Each time I've needed to write code to send successive AT strings and receive the responses I've never been comfortable with the result - although, of course, it worked. This time I am sending Bluetooth data from an archer's bow, as it happens, and needed to change several modes and the data rate of a common module.

Sending the AT strings is easy. I just built a list as StringVectorData and looped through it. Handling the intervening responses, though, has always been awkward and this time wasn't an exception.

This must be a common task. I'm wondering how others have treated the standard <CR><LF>OK<CR><LF> and <CR><LF>ERROR<CR><LF> strings (and incomplete fragments like <CR><LF>) and reduced them to a boolean that fires the next string or terminates the process.

Currently, here's mine. The only True result is from a six-byte <CR><LF>OK<CR><LF>; anything else yields False after hearing an <LF> - except the first legitimate <LF> in byte two - as does a timeout.

Code: Select all

function GetOK&#40;&#41; as boolean		' look for <CR><LF>OK<CR><LF>
	dim bComIn as byte, tX as single, t0 as single, charcount as byte = 0
	GetOK = True
	t0 = Timer
	Do
		Do
			tX = Timer - t0
			if tX < 0.0 then tX = tX + 86400.0
			if tX > 2.0 then GetOK = False &#58; exit function	' timeout
		Loop While GetQueueCount&#40;InQueue_7&#41; = 0
		Call GetQueue&#40;InQueue_7, bComIn, 1&#41;
		Select Case bComIn
			case asc&#40;"O"&#41;
					charcount = charcount + 1
			case asc&#40;"K"&#41;
					charcount = charcount + 1
			case 10
					charcount = charcount + 1
					if charcount = 2 then	' allow first LF to pass
					else
						if charcount <> 6 then GetOK = False ' second LF must be sixth character
						exit function
					end if
			case 13
					charcount = charcount + 1
			case else
				GetOK = False
		end select
	Loop
end function
This works well but feels awkward, brute force. I'd love to find a more elegant solution.

Has anyone done one?
Tom
stevech
Posts: 715
Joined: 22 February 2006, 20:56 PM

Post by stevech »

I'd done it many times.. XBees, modems, GPS, etc.

Just read until I get CR; discard LF.
Then take that char string to lower case and go into a big if and else if tree where each decision is based on
if (strncmp(chars, "keyword", length_of_keyword) == 0)

this, rather than one char at a time.
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: Hayes AT modem / UART OK and ERROR handling

Post by dkinzer »

GTBecker wrote:This works well but feels awkward, brute force.
Perhaps I'm wrong, but a cursory examination of the logic suggests to me that <CR><LF>KO<CR><LF>, <CR><LF>KK<CR><LF>, <CR><LF>OO<CR><LF> and other variations involving order and duplication would be incorrectly accepted.

A finite state machine could be easily constructed to do the recognition.
- Don Kinzer
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Re: Hayes AT modem / UART OK and ERROR handling

Post by GTBecker »

> ... KO...

Yes, that's true; all I do is count, and the second <LF> needs to be the sixth in the string. A state machine would work, too, but perhaps assembling a string and testing it against ..OK.. and ..ERROR.. as it builds makes good sense.
Tom
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post by GTBecker »

stevech wrote:...
Just read until I get CR; discard LF. Then take that char string to lower case and go into a big if and else if tree...
How does that avoid a false error when it detects the first <CR> of <CR><LF>OK<CR><LF>?
Tom
GTBecker
Posts: 616
Joined: 17 January 2006, 19:59 PM
Location: Cape Coral

Post by GTBecker »

Here's what I'm using now, FWIW:

Code: Select all

function GetOK&#40;&#41; as boolean		' look for <CR><LF>OK<CR><LF>
	const bLF as byte = 10, bCR as byte = 13, sTimeout as single = 2.0
	dim bComIn as byte, tX as single, t0 as single, strTest as string * 6 = ""
	dim strOK as string = chr&#40;bCR&#41; & chr&#40;bLF&#41; & "OK" & chr&#40;bCR&#41; & chr&#40;bLF&#41;
	GetOK = True
	t0 = Timer
	do
		do
			tX = Timer - t0
			if tX < 0.0 then tX = tX + 86400.0
			if tX > sTimeout then GetOK = False &#58; exit function   ' timeout
		loop while GetQueueCount&#40;InQueue_7&#41; = 0   ' wait for byte
		call GetQueue&#40;InQueue_7, bComIn, 1&#41;   ' get byte
		strTest = Mid&#40;strTest, 2, Len&#40;strTest&#41; - 1&#41; & chr&#40;bComIn&#41;   ' build string
		if &#40;bComin = bLF&#41; and &#40;Mid&#40;strTest, 2, 1&#41; = chr&#40;bLF&#41;&#41; then   ' two LFs required,
			if strTest <> strOK then GetOK = False   ' then test string
			exit function
		end if
	loop
end function
Tom
Post Reply