Home AMX User Forum NetLinx Studio

CREATE_MULTI_BUFFER

Has anybody used this with much success? It seems like it'd be neat to use. Just haven't actually tested it out.

Bueller? Bueller?

Comments

  • Joe HebertJoe Hebert Posts: 2,159
    I never noticed the CREATE_MULTI_BUFFER command before.

    I did a quick test with a couple of virtual devices and it works as advertised.

    The code:
    DEFINE_DEVICE
    
    dvTP	= 10001:1:0
    
    vdv1	= 33001:1:0
    vdv2	= 33002:1:0
    
    DEFINE_VARIABLE
    
    DEV	vdvArray[] = {vdv1,vdv2}
    CHAR 	cMultiBuffer[1024]
    
    DEFINE_START
    
    [b]CREATE_MULTI_BUFFER[/b]  vdvArray,cMultiBuffer
    
    DEFINE_EVENT
    
    BUTTON_EVENT[dvTP,1] {
    
       PUSH: {
          SEND_STRING vdv1,'Happy'
          SEND_STRING vdv2,'New'
          SEND_STRING vdv1,'Year'
          SEND_STRING vdv2,'!'
       }
    
    }
    
    BUTTON_EVENT[dvTP,2] {
    
       PUSH: {
          SEND_STRING 0,"'cMultiBuffer=',cMultiBuffer"
       }
    
    }
    

    And the output after button 1 and button 2 is pushed:
    Line      1 (09:01:37)::  cMultiBuffer=$FF$01$05Happy$FF$02$03New$FF$01$04Year$FF$02$01!
    

    I can’t think of a reason why I would use this command yet but I’ll have to keep it in mind as it may come in handy some day.
  • jjamesjjames Posts: 2,908
    Joe Hebert wrote: »
    I can’t think of a reason why I would use this command yet but I’ll have to keep it in mind as it may come in handy some day.

    First - thanks for playing around.

    The thing that made me stumble across this is that we often install several of the same type of equipment on a job. I.e. multiple Oppo bluray players, multiple Integra DTRs, etc. so of course I use one DATA_EVENT for each kind of equipment. I then use get_last and pull from the data.text and put it into its respective container to parse. I noticed on the last job that in rare occasions when the devices were firing info off at the same time, I either wasn't pulling out the data properly or get_last wasn't synced right when pulling it out. Or maybe . . . I'm not getting the full concept of data.text; is it a single buffer per DATA_EVENT, even when using an array? Or is it a single buffer per device in the DATA_EVENT?

    Either way, this seems like a handy way to handle multiple devices in a single DATA_EVENT. This way there is a concrete indication of each device's received data.
  • viningvining Posts: 4,368
    Data.text is a global value that holds the current value of the most recent data event. So there's not one per device or event. There's just one for everything. You can use it anywhere you'd like but you can only gaurentee what it will hold in a specific data event for a specific device.

    I've wondered about the multi buffer function for a long time and recently thought about using it and then said screw it since I'm not using buffers much lately anyway unless I need to hold over 15999 bytes. I'd rather just use data.text and append to local vars in an array to achieve the same thing for multiple devices.

    If you want to use created buffers you can just create an array of buffers that match an array of devices and in define start run a for loop to associate each buffer buffer to its device.
    {
         STACK_VAR INTEGER i ;
         
         cServer_IP	= '192.168.1.60' ;  
         
         for(i = 1 ; i <= SERVER_NUM_SERVERS ; i ++)
    	  {
    	  SWITCH(i)
    	       {
    	       CASE 1://SERVER 1
    		    {
    		    CREATE_BUFFER vSERVER_Arry[i],cSServerAXI_Buf[i] ;
    		    cSServerLogin[i][1]	= '' ;
    		    cSServerLogin[i][2] = '' ;	    
    

    An in the strinfg event do something like this:
    STRING:
    	  {
    	  LOCAL_VAR INTEGER nIndx ;//change back to stack after testing
    	  LOCAL_VAR CHAR cServers_RX[SERVER_NUM_SERVERS][8192] ;//remove after testing completed
    	  
    	  nIndx = GET_LAST(vSERVER_Arry) ;
    	  
    	  SWITCH(nIndx)
    	       {
    	       CASE 1://AXIS MOTION WINDOW SERVER
    		    {
    		    if(find_string(cSServerAXI_Buf[nIndx],"'"',STR_LF",1))//should only ever rx 1 at a time
    			 {
    			 STACK_VAR INTEGER nFBS ;
    			 STACK_VAR CHAR cServers_Tmp[256] ;
    			 
    			 cServers_Tmp = REMOVE_STRING(cSServerAXI_Buf[nIndx],"'"',STR_LF",1) ;
    			 nFBS = find_string(cServers_Tmp,"'"',STR_LF",1) ;
    			 fnParseCameraServerRX(GET_BUFFER_STRING(cServers_Tmp,nFBS-1)) ;
    			 }
    		    //CLEAR_BUFFER cSServerAXI_Buf[nIndx] ;
    		    }
    	       CASE 2://SITREP SERVERS
    	       CASE 3:
    	       CASE 4:
    	       CASE 5:
    	       CASE 6:
    		    {//max string from virt to main should be 31212 so all data should arrive in 1 event???
    		    if(cSServerAXI_Buf[nIndx][1] == 1)
    			 {
    			 STACK_VAR SINTEGER nResult ;
    			 
    			 GET_BUFFER_CHAR(cSServerAXI_Buf[nIndx]) ;
    			 fnSServer_DeBug("'RX From Mod-',itoa(nIndx),': rcv''d (',itoa(length_string(cSServerAXI_Buf[nIndx])),') encoded bytes :DEBUG<',ITOA(__LINE__),'>'") ;
    			 nResult = fnSServer_StrToVar(cSServerAXI_Buf[nIndx],nIndx) ;
    			 if(nResult == 0)//success
    			      {
    			      fnSServer_DeBug("'RX From Mod-',itoa(nIndx),': String to Va
    
    I guess if a complete parse ready string is always received in one chuck the multi buffer might make sense but it's easy enought to do just using arrays that you control and fully understand.
  • jjamesjjames Posts: 2,908
    Are you using CREATE_BUFFER successfully the way shown? Per the help file: "This command creates a buffer. It can only appear in the DEFINE_START section of the program."
  • viningvining Posts: 4,368
    jjames wrote: »
    Are you using CREATE_BUFFER successfully the way shown? Per the help file: "This command creates a buffer. It can only appear in the DEFINE_START section of the program."

    I didn't show the def start in the code but I did elude to it in the text line above the code block. Normally I would just use a regular array and append data.text to it. In this example I'm receiving data well over 20kbytes so I went the CREATED BUFFER route.
  • jjamesjjames Posts: 2,908
    vining wrote: »
    I didn't show the def start in the code but I did elude to it in the text line above the code block. Normally I would just use a regular array and append data.text to it. In this example I'm receiving data well over 20kbytes so I went the CREATED BUFFER route.

    My bad - sorry. I missed that part.
  • a_riot42a_riot42 Posts: 1,624
    jjames wrote: »
    I noticed on the last job that in rare occasions when the devices were firing info off at the same time, I either wasn't pulling out the data properly or get_last wasn't synced right when pulling it out.

    I don't really see how that would be possible. A data_event is run when the string comes in from the port. You may not get the complete string depending on timings, but data.text shouldn't have text from two different ports in one string event. The only scenario I can see where this might not work is if you have waits or some other delay in the data_event and data.text is getting overwritten before you have emptied it.
    Paul
  • viningvining Posts: 4,368
    a_riot42 wrote: »
    I don't really see how that would be possible. A data_event is run when the string comes in from the port. You may not get the complete string depending on timings, but data.text shouldn't have text from two different ports in one string event. The only scenario I can see where this might not work is if you have waits or some other delay in the data_event and data.text is getting overwritten before you have emptied it.
    Paul
    yeah, definitely shouldn't have a wait with anything code using the event objects of any flavor be they data.text, button.input.... . These are all gobal and hold the most recent value of the most recent event through out the entire system. If there's a wait in your code that's like playing russian roulette cuz you can't be sure what you'll get when that wait fires. The value by then could be anything from anywhere.
  • jjamesjjames Posts: 2,908
    Well, here is the "offending" code. And after looking at it while posting - I believe I see my error, but I'll post it anyway. This is a deviation from my normal code I should mention - not an excuse, but an error in my evolution.
    data_event[dv_dtr]
    {
    	string:
    	{
    		local_var char s_buffer[256];
    		stack_var char s_reply[256];
    		stack_var integer i_index;
    		
    		i_index = get_last(dv_dtr);
    		s_buffer = "s_buffer,data.text";
    		
    		while(find_string(s_buffer,"$1a",1))
    		{
    			stack_var char s_result[3];
    			
    			s_reply = remove_string(s_buffer,"$1a",1)
    			// s_reply = !1PWR00<$1a>
    			remove_string(s_reply,'!1',1);
    			
    			// s_reply = PWR00<$1a>
    			set_length_string(s_reply,length_string(s_reply)-1);
    			
    			s_result = remove_string(s_reply,left_string(s_reply,3),1)
    			// s_reply = PWR00
    			
    			switch(s_result)
    			{
    				///////////////////////////////////////////////////////////////////
    				// Zone 1
    				///////////////////////////////////////////////////////////////////
    				// Power status
    				case 'PWR':
    				{
    					Receiver[i_index].i_power = atoi(s_reply);
    				}
    				
    				//etc.
    			}
    		}
    	}
    }
    
  • a_riot42a_riot42 Posts: 1,624
    jjames wrote: »
    Well, here is the "offending" code. And after looking at it while posting - I believe I see my error, but I'll post it anyway. This is a deviation from my normal code I should mention - not an excuse, but an error in my evolution.
    data_event[dv_dtr]
    {
    	string:
    	{
    		local_var char s_buffer[256];
    		stack_var char s_reply[256];
    		stack_var integer i_index;
    		
    		i_index = get_last(dv_dtr);
    		s_buffer = "s_buffer,data.text";
    	
    

    You will need an array per device to store your data.text if you want to keep it separate. Otherwise you are mingling them together by using local_var and appending the new data to the old.
    Paul
  • jjamesjjames Posts: 2,908
    a_riot42 wrote: »
    You will need an array per device to store your data.text if you want to keep it separate. Otherwise you are mingling them together by using local_var and appending the new data to the old.
    Paul
    Exactly! While copying it over, I saw that. I did it in my old parsing routine, but for whatever reason didn't here.

    I should also add s_buffer[i_index] = "s_buffer[i_index],data.text" after the WHILE loop as well; this parsing routine was shown to me by someone when I first start programming and eventually saw that it was actually taken from TN 616.

    I should also note, that it seems that CREATE_MULTI_BUFFER skips over the need of creating multi-dimensional character arrays, which looks tempting to be honest.
  • viningvining Posts: 4,368
    jjames wrote: »
    I should also note, that it seems that CREATE_MULTI_BUFFER skips over the need of creating multi-dimensional character arrays, which looks tempting to be honest.
    I don't see it that way. I see it as a bunch of devices dumping into one common buffer which as I said earlier is ok if everything you want per device will arrive in one event. Basically it's data.text with the string attributes of a buffer, ie can handle strings over 2048 (data.text) and concantenated strings over 15999. I read somewhere virtuals can pass strings up to 31212 bytes so if you were transferring large strings beyond the limit of data.text you good use the multi buffer if it arrived in one event. These would likely be internal strings using command/string events from virtuals I recon.

    If the data did arrive in segments spanning more than one event you would still need to handle it in a var array of your own creation and concantenate your data for each device in it's own container until ready for processing.
  • a_riot42a_riot42 Posts: 1,624
    vining wrote: »
    I don't see it that way. I see it as a bunch of devices dumping into one common buffer which as I said earlier is ok if everything you want per device will arrive in one event.

    This seems to be the case and it makes sense. The multi buffer has delimiters separating the strings between devices.

    "Each command string placed in the multi-buffer has a three-byte header associated with it. The first header byte, $FF, marks the start of a new command string, the second header byte is the number of the device (not the Port number) that received the string, and the third byte is the length of the string, as shown below:

    $FF, device number or DEV[ ] index, length, <string>"

    Personally I prefer to roll my own, as I have found hard to trace bugs when using these types of built in stuctures. YMMV.
    Paul
  • viningvining Posts: 4,368
    Your right, guess I should have looked at Joe's example a little closer. I did wonder where that other crap came from but I didn't examine the code and assumed (which makes me an a$$) Joe added it for some reason.

    I'm not sure what to make of it now. I wonder what the capacity of the entire string is and does it concantenate into each delimited section or does it just add to the end of the string with its ID delimeters.

    If it adds to the existing section of the string that's sort of neat but makes finding strings a little more laborious since you have the potential of essentially having to look through several buffers while looking for a particular string before getting to the string section begining with the correct ID to then start your search. Of course if you trigger off of data.text on the incoming and then pull from the buffered string that's not so laborious. I usually prefer to do that anyway when web scraping or dealing with other large strings that come in chunks less than the D.T limit. Of course I could always just keep updating my find_string pointer.

    If the incoming strings just get added to the end that complicate the code cuz you either have to pull out strings as they come in and concantenate into your own array which makes using the multi buffer pointless or you wait for a specific ending tag to trigger your parsing and then collect the various sections with matching IDs.

    Maybe there's a reason it's stayed in the shadows all these year.
  • jjamesjjames Posts: 2,908
    vining wrote: »
    If the incoming strings just get added to the end that complicate the code cuz you either have to pull out strings as they come in and concantenate into your own array which makes using the multi buffer pointless or you wait for a specific ending tag to trigger your parsing and then collect the various sections with matching IDs.
    I think you're right about that. I'll continue to roll my own . . . if I had to pick through and put them into an another array, that'd be a slight pain, but even more inefficient.
Sign In or Register to comment.