parsing long string with no delimiter
i am self taught programmer so my methods will not have that formal look or feel. Also my programming skill is limited so please, if you comment, be easy on me.
OK, so i want to get the run hours for a NEC projector's lamp, filter panel ect..
The proj responds with a 104 bit HEX string with an known beginning but no delimiter.
The string comes in broken up into 2 data events.
The code i came up with only works in a perfect world where the only data coming in is that 104 bit string.
$23,$8A,$1,$10,$62 is the known beginning and the last 17 bit is the data i want.
I know the code above is wrong and i could use some guidance on handling this kind of problem.
OK, so i want to get the run hours for a NEC projector's lamp, filter panel ect..
The proj responds with a 104 bit HEX string with an known beginning but no delimiter.
The string comes in broken up into 2 data events.
The code i came up with only works in a perfect world where the only data coming in is that 104 bit string.
$23,$8A,$1,$10,$62 is the known beginning and the last 17 bit is the data i want.
string:
{
local_var char cProjectorString[256]
cProjectorString="cProjectorString,data.text"
if((find_string(cProjectorString,"$23,$8A,$1,$10,$62",1))&&(length_string(cProjectorString)=104))
{
cProjectorInfo=right_string(cProjectorString,17)
cProjectorString="''"
}
}
I know the code above is wrong and i could use some guidance on handling this kind of problem.
Comments
I tend to make a buffer, building it myself from he data event or even use the old Create Buffer for really large messages like web page scrapes. The idea is that you create a function to check and see if the buffer contains all the stuff you need and then process the string only then. You use the data event to fire the checking routine.
I then fire the parsing routine from a timeline that is only on when there's stuff waiting in the buffer. An empty buffer kills the timeline. But there's many other ways to do this.
Once I'm sure I have a complete message, I then send it to the parsing routine.
G'day Postich,
I too, am completely self taught.
Your code may have bugs or perhaps could have been written better but it's never "wrong".
What will help you here is the knowledge that the 5th byte of the return string from NEC projectors is the length of the string - 6 bytes. eg The length of the string in your example is 104 bytes long. 104 - 6 = 98 ($62) which is what the 5th byte is!
So, some code..
STRING: { local_var char cProjectorString[256] cProjectorString="cProjectorString,data.text" If (Length_String(cProjectorString) = (6 + cProjectorString[5])) // If we have a complete string { cProjectorInfo=right_string(cProjectorString,17) cProjectorString="''" } }I hope this helps.
Good luck!
Mush
oh yeah it is, that helps. when ever i read api guides i tend to just skim over the pages until i see what i need. must have missed that piece of valuable info.
If the known beginning is all that gets sent or all you'll ever care about receiving.
Then I would add additional code to verify my string begins with this with no junk prior.
STRING: { local_var char cProjectorString[256] stack_var integer nFBS; cProjectorString="cProjectorString,data.text" nFBS = find_string(cProjectorString,"$23,$8A,$1,$10",1);//less the length byte in case this is common to all types of returns if(nFBS > 1) get_buffer_string(nFBS-1);//remove all beginning crap if(nFBS) { SELECT { ACTIVE{Length_String(cProjectorString) = (6 + HEXTOI(cProjectorString[5]))): // If we have a complete string { SEND_STRING 0, "'NEC PROJ RX, MATCH FOUND, STR-[ ',cProjectorString,' ]'"; cProjectorInfo=right_string(cProjectorString,17) cProjectorString="''" } ACTIVE(1): SEND_STRING 0, "'NEC PROJ RX, NO MATCH FOUND!, STR-[ ',cProjectorString,' ]'"; } } }I could be wrong but I think a created buffer will keep shifting to the left as more data comes in from the right and these non created buffers don't, once they fill they won't accept any more data. Could someone else confirm this is actually correct.
STRING: { local_var char cProjectorString[256] stack_var integer nFBS; cProjectorString="cProjectorString,data.text" nFBS = find_string(cProjectorString,"$23,$8A,$1,$10",1);//less the length byte in case this is common to all types of returns if(nFBS) { if(nFBS > 1)//moved so it doesn't run twice unless string is found get_buffer_string(nFBS-1); SELECT { ACTIVE{Length_String(cProjectorString) = (6 + HEXTOI(cProjectorString[5]))): // If we have a complete string { SEND_STRING 0, "'NEC PROJ RX, MATCH FOUND, STR-[ ',cProjectorString,' ]'"; cProjectorInfo=right_string(cProjectorString,17) cProjectorString="''" } ACTIVE(1): SEND_STRING 0, "'NEC PROJ RX, NO MATCH FOUND!, STR-[ ',cProjectorString,' ]'"; } } else cProjectorString="''"; }I used different parts of the code that you guys showed and came up with this final (for now)string handler.
STRING: { local_var char cProjectorString[2048] cProjectorString="cProjectorString,data.text" if(Length_String(cProjectorString)=(6+cProjectorString[5])) //complete string found { fnParseProj(cProjectorString) cancel_wait 'hold' cProjectorString="''" } else { wait 1 'hold' { cProjectorString="''" } } }the nec will have different beginnings for string depending on the command sent so i didn't use find_string in the event, instead i look only for a complete string and if i find one i send it to parse.
i used a wait to allow time for incomplete string to arrive, not sure if that is best but it works.(10th of a second sould be enough you think?)
as far as error checking and garbage handling, well... i think that if the 5th byte = the total length then it is a good bet i have valid info and if not the parser should be able to ignore it with find_string.
what i like about this is that this code can be use with any similar protocol.
its funny how simple the solution was but i could not see it until i studied the code you guys posted, super cool, thanks.
P.S. HEXTOI was not applicable in my instance, still have yet to find a use for it.
Are you goiing to process the other possible returns? If not don't worry about them but if you are list the various beginnings that you'll want to process so we can suggest a more reliable option.
I assume since there are different beginnings the differences indicate the type of return and the format of the data that follows which would be the key to proper string parsing.
iv tested it for a few hours, bombarding it with all kings of commands, everything seems OK so far. have not seen any strange behavior yet.
here is the parser fn
DEFINE_VARIABLE persistent long nProjectorHrs[5] DEFINE_FUNCTION fnParseProj(char stringdata[]) { local_var char debug[2048] local_var char cTemp[16] debug=stringdata if(find_string(stringdata,"$23,$8A,$1,$10,$62",1)) { cTemp=mid_string(stringdata,88,16) nProjectorHrs[4]=((cTemp[8]*16777216)+(cTemp[7]*65536)+(cTemp[6]*256)+(cTemp[5]))/3600 send_command dvTP,"'^TXT-8,0,',itoa(nProjectorHrs[4]),' hrs.'" // projector total hrs nProjectorHrs[1]=((cTemp[16]*16777216)+(cTemp[15]*65536)+(cTemp[14]*256)+(cTemp[13]))/3600 send_command dvTP,"'^TXT-5,0,',itoa(nProjectorHrs[1]),' hrs.'" // filter hrs send_string dvDISPLAY,"cProjLamp1" } if(find_string(stringdata,"$23,$9B,$01,$10,$07,$00,$00,$00",1)) { cTemp=mid_string(stringdata,9,4) nProjectorHrs[2]=((cTemp[4]*16777216)+(cTemp[3]*65536)+(cTemp[2]*256)+(cTemp[1]))/3600 send_command dvTP,"'^TXT-6,0,',itoa(nProjectorHrs[2]),' hrs.'" // lamp1 hrs send_string dvDISPLAY,"cProjLamp2" } if(find_string(stringdata,"$23,$9B,$01,$10,$07,$01,$00,$00",1)) { cTemp=mid_string(stringdata,9,4) nProjectorHrs[3]=((cTemp[4]*16777216)+(cTemp[3]*65536)+(cTemp[2]*256)+(cTemp[1]))/3600 send_command dvTP,"'^TXT-7,0,',itoa(nProjectorHrs[3]),' hrs.'" //lamp2 hrs } }here is the datd event
STRING: { local_var char cProjectorString[2048] cProjectorString="cProjectorString,data.text" if(Length_String(cProjectorString)=(6+cProjectorString[5])) //complete string found { fnParseProj(cProjectorString) cancel_wait 'hold' cProjectorString="''" } else { wait 1 'hold' { cProjectorString="''" } } }iv tested it for a few hours, bombarding it with all kings of commands, everything seems OK so far. have not seen any strange behavior yet.
here is the parser fn
DEFINE_VARIABLE persistent long nProjectorHrs[5] DEFINE_FUNCTION fnParseProj(char stringdata[]) { local_var char debug[2048] local_var char cTemp[16] debug=stringdata if(find_string(stringdata,"$23,$8A,$1,$10,$62",1)) { cTemp=mid_string(stringdata,88,16) nProjectorHrs[4]=((cTemp[8]*16777216)+(cTemp[7]*65536)+(cTemp[6]*256)+(cTemp[5]))/3600 send_command dvTP,"'^TXT-8,0,',itoa(nProjectorHrs[4]),' hrs.'" // projector total hrs nProjectorHrs[1]=((cTemp[16]*16777216)+(cTemp[15]*65536)+(cTemp[14]*256)+(cTemp[13]))/3600 send_command dvTP,"'^TXT-5,0,',itoa(nProjectorHrs[1]),' hrs.'" // filter hrs send_string dvDISPLAY,"cProjLamp1" } if(find_string(stringdata,"$23,$9B,$01,$10,$07,$00,$00,$00",1)) { cTemp=mid_string(stringdata,9,4) nProjectorHrs[2]=((cTemp[4]*16777216)+(cTemp[3]*65536)+(cTemp[2]*256)+(cTemp[1]))/3600 send_command dvTP,"'^TXT-6,0,',itoa(nProjectorHrs[2]),' hrs.'" // lamp1 hrs send_string dvDISPLAY,"cProjLamp2" } if(find_string(stringdata,"$23,$9B,$01,$10,$07,$01,$00,$00",1)) { cTemp=mid_string(stringdata,9,4) nProjectorHrs[3]=((cTemp[4]*16777216)+(cTemp[3]*65536)+(cTemp[2]*256)+(cTemp[1]))/3600 send_command dvTP,"'^TXT-7,0,',itoa(nProjectorHrs[3]),' hrs.'" //lamp2 hrs } }here is the data_event
STRING: { local_var char cProjectorString[2048] cProjectorString="cProjectorString,data.text" if(Length_String(cProjectorString)=(6+cProjectorString[5])) //complete string found { fnParseProj(cProjectorString) cancel_wait 'hold' cProjectorString="''" } else { wait 1 'hold' { cProjectorString="''" } } }