Home AMX User Forum AMXForums Archive Threads Tips and Tricks

Handling Strings with no delimiter

I'm working with a Pioneer PDP-614MX. This display doesn't have a set delimiter, instead it has a check sum which is calculated by adding up the bytes in the command and taking the lower 8 bits of the sum. I've included the code that I'm using to do this. Unfortunatley, I don't have a master or the display available to test the code out on, so I'm hoping and praying this works. If anyone sees anything that might stop this from working, let me know. Thanks.

Data_Event
data_event[dvDisplay]
{
    online:
    {
	send_command dvDisplay,"'SET BAUD 9600,N,8,1 485 DISABLE'"
	send_command dvDisplay,"'HSOFF'"
	send_command dvDisplay,"'RXON'"
    }
    
    string:
    {
	stack_var char cCMD[255]
	stack_var char cMSG[255]
	stack_var integer i
	stack_var integer iDataLength
	stack_var integer iCheckSum
	stack_var integer iCalcCheckSum
	
	while(length_string(cDisplaybuffer)>0)
	{
	    
	    iDataLength = type_cast(mid_string(cDisplaybuffer,5,1))
	    
	    iChecksum = type_cast(mid_string(cDisplayBuffer,6 + iDataLength,1))
	    
	    cCMD = left_string(cDisplaybuffer,5+iDataLength)
	    
	    iCalcCheckSum = CheckSum(cCMd)

	    if(iCalcCheckSum = iCheckSum)
	    {
		cMsg = remove_string(cDisplaybuffer,"iCheckSum",1)
		ParseSocket(cMsg)
	    }	    
	}
    }
}

CheckSum Function
DEFINE_FUNCTION char CheckSum(char cMsg[])
{
    stack_var integer i
    stack_var integer iChkSum
    
    for(i=1;i<=length_array(cMsg);i++)
    {
	iChkSum = iChkSum + type_cast(cMsg[i])
    } 
    
    iChkSum = iChkSum % 256
    
    return type_cast(iChkSum)
}

Comments

  • viningvining Posts: 4,368
    From the looks of the code snippet you don't really need to deal with the checksum unless you want to validate it. Since it appears byte 5 will always tell you the amount of data that follows you could just do a GET_BUFFER_STRING and call it a day. Other than that the code looks good and the check sum routine is similar to one I made the other day that seemed to work fine. I just used % $100, which is the same as 256.
  • HedbergHedberg Posts: 671
    I think it looks ok although I would code it differently.

    One thing that bothers me is that if the checksum verification fails that the buffer cDisplaybuffer never gets emptied and your while loop runs a real long time -- almost forever. It appears to me that the only reason to do the checksum verification is to catch those occasions when there is a problem with the return string and then you need some sort of logic to sort out what's wrong and to get your parsing back in sync with the ack messages. A brief look at the protocol indicates to me that all ack messages start with $3F. Before you go extracting the checksum from the ack and comparing it to your calculated checksum, you might want to verify that the first character in the buffer is $3F. But, $3F may appear in other places besides the first character of the ack, so, depending on how bullet proof you want to make your code, you might want to make sure that the $3F at the start of the buffer is actually the start of the return message. That's probably overkill.

    But, if there is a possibility that the checksum verification might fail, you need to have some code to empty out the buffer and prevent an infinite while loop and get synced back up.
  • HedbergHedberg Posts: 671
    vining wrote: »
    From the looks of the code snippet you don't really need to deal with the checksum unless you want to validate it. Since it appears byte 5 will always tell you the amount of data that follows you could just do a GET_BUFFER_STRING and call it a day. Other than that the code looks good and the check sum routine is similar to one I made the other day that seemed to work fine. I just used % $100, which is the same as 256.


    Agree that there's not much reason to do the checksum verification. The only time I have ever bothered to verify the checksum of a device return string was when I was doing our recent "experience evaluation."

    "% 256" (or $100) works, but for some reason I would prefer "BAND $FF". Don't know if there's a good reason to prefer one method over the other or not.

    How do you feel about stuff like:
    iDataLength = type_cast(mid_string(cDisplaybuffer,5,1))
    

    I would have thought it would throw an error because "mid_string()" returns a character array and I don't understand how a character array can get cast to an integer scalar. It appears to work, though. Rather than using "mid_string()" to extract an array of length 1, something like this looks better to me:
    iDataLength = type_cast(cDisplaybuffer[5])
    
    and the type_cast may be unnecessary.
  • viningvining Posts: 4,368
    Hedberg wrote:
    One thing that bothers me is that if the checksum verification fails that the buffer cDisplaybuffer never gets emptied and your while loop runs a real long time -- almost forever
    Good catch! I for one hardly ever use the copy commands (left,right,mid_string) unless the order of returned string is random like in HTTP headers. In a "while statement I always prefer to remove the string as soon as possible and put it into a stack var for further processing just to avoid those nasty inifinite loops.

    Hedberg wrote:
    "% 256" (or $100) works, but for some reason I would prefer "BAND $FF".
    I might agree if I really had an understanding of how it works. :) The practical was the first I really ever dealt with this and I was happy to come up with the above solution. If nothing else the practical did force me to do figure that much out and the <<< >>> stuff.

    I would prefer this method also:
    iDataLength = type_cast(cDisplaybuffer[5]) ;
    
Sign In or Register to comment.