Die, buffer data... DIE!
fogled@mizzou
Posts: 549
I can't kill my buffer data! Every time I submit something to a virtual device with a buffer tied to it (create_buffer vdv_cobis,cobisbuffout), all the data that was ever in the buffer seems to come back to haunt me. I can get the length right before the send_data, and the length will report back as 0. I then send ~200 characters of text to the virtual, and suddenly my buffer has over 3,000 characters in it. The sending process will chew on all the data in the buffer, sending it all out until buffer length goes back down to 0. Then when I send another chunk of data (~200 characters) the buffer is right back to 3,000+ characters in it.
I'm not defining the buffer container as persistent. I'm explicitly clearing it / setting it to "". Yet my zombie data keeps re-appearing once I add something to the buffer by sending it to the virtual.
If I manually add to the buffer (cobisbuffout = "cobisbuffout,this_string") it works as expected.
I've got dozens of buffers running in my controllers, and have never seen this before. What's up?
I'm not defining the buffer container as persistent. I'm explicitly clearing it / setting it to "". Yet my zombie data keeps re-appearing once I add something to the buffer by sending it to the virtual.
If I manually add to the buffer (cobisbuffout = "cobisbuffout,this_string") it works as expected.
I've got dozens of buffers running in my controllers, and have never seen this before. What's up?
0
Comments
Post your code.
In general, if you send a string to a virtual device, you will immediately get back that string from the device. So if you do a CREATE_BUFFER to the virtual device and do a SEND_STRING, the device will "echo back" the string received - and if a buffer was created, the buffer will be filled with the echo. This again will give a echo etc.
If you have a look tio the device notification of the virtual device, you will see that you always get a STRING TO and a STRING FROM with the same content.
This is why the Netlinx code based modules in general use SEND_COMMANDs to getinstructions into the module thru the virtual device, but data from the module comes back as STRING thru the virtual device.
So then, something in your code is resetting your buffer length to the max value. It's seeing all the old, previously processed data, because somewhere along the line it has been notified it is once again part of the string. That's what you need to be looking for, whatever is changing how the string functions determine the end point.
DEFINE_DEVICE //Physical Devices
dvip_cobis = 0:54:0 //COBIS Ticket API
DEFINE_DEVICE //Virtual Devices
vdvip_cobis = 33052:1:0 //cobis server api
integer help_btns[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30} //Help Screen Buttons
long logtimeout[1] = {10000} //timeout for cobis connection
structure helpfile {
char btn[100]
char url[100]
}
DEFINE_VARIABLE
char cobisbuffout[10000] //help ticket buffers & data
char cobisbuffin[1024]
persistent helpfile help[30]
persistent integer helpcount
(* SUBROUTINE/FUNCTION DEFINITIONS GO BELOW *)
define_call 'submittroubleticket' (this_room,char this_pawprint[64]) {
stack_var char room[10]
stack_var char user[30]
stack_var char problem[1024]
stack_var char httpheader[2048]
stack_var char httpcontent[4096]
room = rm[this_room].name
user = right_string(this_pawprint,length_string(this_pawprint)-5)
call 'debug' ("'Ticket Process - Room:',room,' User:',user")
for(tmp_idx3=1;tmp_idx3<=helpcount;tmp_idx3++) {
if(rm[this_room].helpbtns[tmp_idx3]==1) {
problem = "problem,help[tmp_idx3].url,','" //add to help string
call 'debug' ("'Added Prob:',problem")
}
}
//format content stream
httpcontent = "'room=',room,'&user=',user,'&problem=',problem"
call 'debug' ("'HTTP Content: ',httpcontent")
//format data to send to buffer
httpheader = "'POST /cobisapi.php HTTP/1.1',13,10";
httpheader = "httpheader,'Connection: close',13,10";
httpheader = "httpheader,'User-Agent: HTTPTool/1.0',13,10";
httpheader = "httpheader,'Host: localhost',13,10"
httpheader = "httpheader,'Content-Type: text/plain',13,10";
httpheader = "httpheader,'Content-Length: ',ITOA(LENGTH_STRING(httpcontent)),13,10";
httpheader = "httpheader,13,10" // Extra Line Between Content
//submit data to buffer
call 'debug' ("'Buffer Len: ',itoa(length_string(cobisbuffout))")
// ABOVE CALL SHOWS BUFFER LENGTH AT 0
call 'debug' ("'Data Len: ',itoa(length_string(httpheader)+length_string(httpcontent)+3)")
// ABOVE CALL SHOWS DATA LENGTH ~220
// HERES THE PART THAT DOESN'T WORK
// AS SOON AS THE STRING IS SENT, BUFFER SIZE JUMPS TO 3000 CHARS +
// WITH DOZENS OF INSTANCES IN BUFFER
// send_string vdvip_cobis,"httpheader,httpcontent,'|||'" //using triple pipe for delimiter
// HERES WHAT DOES WORK INSTEAD TO GET ONLY THE ~220 NEW CHARACTERS TO SHOW UP IN BUFFER
cobisbuffout = "cobisbuffout,httpheader,httpcontent,'|||'"
call 'debug' ("'Buffer Len: ',itoa(length_string(cobisbuffout))")
// ABOVE CALL SHOWS 3200+ CHARACTERS IN BUFFER WHEN USING THE SEND_STRING,
// BUT ONLY THE ONE ~200 CHAR MESSAGE WHEN USING MANUAL BUFFER ADDITION
for(tmp_idx3=1;tmp_idx3<helpcount;tmp_idx3++) { //clear button selections
rm[this_room].helpbtns[tmp_idx3] = 0
}
}
define_call 'cobisresponseparser' (char this_data[1024]) {
call 'debug' ("'COBIS Response received: ',this_data")
}
(***********************************************************)
(* STARTUP CODE GOES BELOW *)
(***********************************************************)
DEFINE_START
create_buffer vdvip_cobis,cobisbuffout
create_buffer dvip_cobis,cobisbuffin
cobisbuffout = ""
cobisbuffin = ""
(***********************************************************)
(* THE EVENTS GO BELOW *)
(***********************************************************)
DEFINE_EVENT
data_event[dvip_cobis] { //COBIS
onerror: {
call 'debug' ("'COBIS Port ERROR=',ITOA(Data.Number)")
}
online: {
cobisipconnect = 1
call 'debug' ("'COBIS Port Open... '")
}
offline: {
cobisipconnect = 0
call 'debug' ("'COBIS Port CLOSED... '")
}
string: {
call 'debug' ("'Data From COBIS:',itoa(data.device.number),':',itoa(data.device.port),' - ',data.text")
// Commands from unit should automatically go into cobisbuffin
}
}
data_event[vdvip_cobis] { //COBIS virtual
online: { }
offline: { }
onerror: { }
string: {
//data should automatically be appended to cobisbuffout, picked up by program processing
}
}
data_event[dvtp_all] { //Room panel initialization
online: {
stack_var integer this_pid
this_pid = getpid(data.device.number)
send_command data.device,"'@PPX'"
if(rm[this_pid].deck==1) {
send_command data.device,"'PAGE-HomeDeck'"
}
else {
send_command data.device,"'PAGE-Home'"
}
SEND_COMMAND data.device,"'!F',250,'1'"
SEND_COMMAND data.device,"'TEXT250-Cornell Hall RM ',rm[this_pid].name,' Panel'"
SEND_COMMAND data.device,"'!F',251,'1'"
SEND_COMMAND data.device,"'TEXT251-Compiled = ',__FILE__,', ',DATE,', ',TIME"
SEND_COMMAND data.device,"'!F',252,'1'"
SEND_COMMAND data.device,"'TEXT252-Code Version = ',__VERSION__"
SEND_COMMAND data.device,"'!F',253,'1'"
(* Must fill this (Master Ver) *)
SEND_COMMAND data.device,'TEXT253-'
SEND_COMMAND data.device,"'!F',254,'1'"
(* Must fill this (Panel File) *)
SEND_COMMAND data.device,'TEXT254-Panel Type = NXT-CV7'
SEND_COMMAND data.device,"'!F',255,'1'"
(* Must fill this (Dealer Info) *)
SEND_COMMAND data.device,'TEXT255-University of Missouri'
send_command data.device,"'^TXT-1,0,ROOM ',rm[this_pid].name"
call 'extronvolfeedback' (this_pid)
}
offline: {
//what here?
}
onerror: {
//what here?
}
string: { //Trouble ticket coming in!
stack_var integer this_pid
this_pid = getpid(data.device.number)
call 'debug' ("'Input from Panel: ',data.text")
if(find_string(data.text,"'KEYB-'",1)) {
call 'debug' ("'KBD INPUT, PROCESS TICKET...'")
call 'submittroubleticket' (this_pid,data.text)
}
}
}
(***********************************************************)
(* THE ACTUAL PROGRAM GOES BELOW *)
(***********************************************************)
DEFINE_PROGRAM
//COBIS API
while(!timeline_active(98)&&find_string(cobisbuffout,"'|||'",1)) {
//start timeline to timeout connection - NOT IN RUNNING PROGRAM YET
timeline_create(98,logtimeout,1,timeline_once,timeline_absolute)
call 'debug' ("'COBIS Trap Len:',itoa(length_string(cobisbuffout)),' Data:',cobisbuffout")
cobisticket = remove_string(cobisbuffout,"'|||'",1)
cobisticket = left_string(cobisticket,length_string(cobisticket)-3)
call 'debug' ("'COBIS HTTP Len:',itoa(length_string(cobisbuffout)),' Data:',cobisticket")
ip_client_open(dvip_cobis.port,cobisipaddress,80,1)//80=port,1=TCP
wait_until(cobisipconnect==1) { //set to 1 in online data event, 0 in offline event
send_string dvip_cobis,"cobisticket"
call 'debug' ("'COBIS SUBMIT: ',cobisticket")
}
}
while(find_string(cobisbuffin,"$0D",1)) {
call 'cobisresponseparser' (remove_string(cobisbuffin,"$0D",1))
}
1) I have this exact same buffer methodology running for about 60 other communications buffers in this very program. This is the only one that's having zombie data. However, all the other buffer variables are part of data structures; this is the only one that's just a plain declared CHAR variable.
2) The variable size is currently set to 10,000, and as I've been testing it, I can see that the zombie data really is all the previous sends, plus the latest one. It doesn't completely fill the buffer, but the size of the data in the buffer grows by the size of the submitted data on every SEND.
This is an old 2100 controller BTW; I've updated to the latest firmware, etc., but could the old controller have issues?
If it were me, I would have given up already and just stuck with the string concatenation method you have commented as working and abandoned trying to use SEND_STRING.
This is the only codebase like this I have running on a 2100; all the other ones are 3100's or 3101's. I've updated to the latest firmware in the 2100, but... who knows. I'm calling some kind of goofy bug in the length indexing of the variable.
I don't know what the problem is but I have to ask about this code:
//format data to send to buffer
httpheader = "'POST /cobisapi.php HTTP/1.1',13,10";
httpheader = "httpheader,'Connection: close',13,10";
httpheader = "httpheader,'User-Agent: HTTPTool/1.0',13,10";
httpheader = "httpheader,'Host: localhost',13,10"
httpheader = "httpheader,'Content-Type: text/plain',13,10";
httpheader = "httpheader,'Content-Length: ',ITOA(LENGTH_STRING(httpcontent)),13,10";
httpheader = "httpheader,13,10" // Extra Line Between Content
I would have written it like this (with white space so the text lines up):
//format data to send to buffer
httpheader = "'POST /cobisapi.php HTTP/1.1',13,10",
'Connection: close',13,10",
'User-Agent: HTTPTool/1.0',13,10",
'Host: localhost',13,10",
'Content-Type: text/plain',13,10",
'Content-Length: ',ITOA(LENGTH_STRING(httpcontent)),13,10,13,10"
Its easier to read and gets rid of all the assignments and processing required to concatenate all the small strings. Just a thought.
Paul
I respectfully beg to differ. DATA.TEXT may never go wrong for virtual devices, but it frequently does for real ones, especially RS-232. A string event is triggered by a data burst punctuated with a pause ... and if the device pauses for any reason at all except that it is actually done, you don't have all the data, just the bit before it paused. Likewise, if the pause isn't long enough, you might get two events in the same DATA.TEXT. And If you are going to use a construct ilike sMyBuffer = "sMyBuffer, DATA.TEXT", then it is identical to CREATE_BUFFER anyway.
I concur. Back when we we all switched over to Netlinx, Data.Text was baffling in how it dealt with older pokey RS-232 devices. I kinda got gun shy using it. So, while (early on) everyone was bashing CREATE_BUFFER as being old skool, I was secretly still using it. I'd still keep trying data.text and figuring out how it worked. Nowadays, how it works or does not work is fairly well documented and its quirks are well known.
To me, as Dave so eligantly pooints out, both methods are 'what they are' and how one uses one or the other depends upon the situation. I do notice a lot of newer coders don't use C_Buff but basically recreate it with buffer=" buffer,data.text" anyway.
Personally, I use both.