Home AMX User Forum NetLinx Studio

sending commands problem

udiudi Posts: 107
I have problem with sending commands to a device. Sometimes when I am doing a send command to the device the command doesn’t sent properly. Because it gets some commands together and not one command each time.
I am trying to do a function that gets called every time I am sending a command to the device and gets put into a queue before sending it so that proper wait time is place in between commands. But I don’t know how to do that.
Anyone knows how to do that? Or maybe have an easier way?

Comments

  • viningvining Posts: 4,368
    Here a queuing method I use:
    Button Event:
    SELECT
    			 {
    			 ACTIVE(nBTN == TV_BTN_PLAY):		{fnTV_Q_Cmd(TV_CMD_ARRY[TV_CMD_IR],sTVmod.nCurSet,'b0')}
    			 ACTIVE(nBTN == TV_BTN_STOP):		{fnTV_Q_Cmd(TV_CMD_ARRY[TV_CMD_IR],sTVmod.nCurSet,'b1')}
    			 ACTIVE(nBTN == TV_BTN_PAUSE):		{fnTV_Q_Cmd(TV_CMD_ARRY[TV_CMD_IR],sTVmod.nCurSet,'ba')}
    
    Q Function:
    DEFINE_FUNCTION fnTV_Q_Cmd(CHAR iCmd[],INTEGER iSet,CHAR iData[2])
         
         {
         STACK_VAR INTEGER nFBS ;
         
         sTVmod.sQ[sTVmod.nQHead].cCmd	= iCmd ;
         sTVmod.sQ[sTVmod.nQHead].nSet	= iSet ;
         sTVmod.sQ[sTVmod.nQHead].cData     = iData ;  
                  
         SELECT
    	  {
    	  ACTIVE(sTVmod.nQHead == TV_QSIZE): 
    	       {// If head is at end
    	       if(sTVmod.nQTail <> 1) 
    		    {// Don't overwrite if full
    		    sTVmod.nQHead = 1 ;
    		    }
    	       }
    	  ACTIVE(sTVmod.nQTail <> sTVmod.nQHead + 1): 
    	       {// Don't overwrite if full
    	       sTVmod.nQHead++ ;
    	       }
    	  }
         
         sTVmod.nQHasItem = 1 ;
         if(sTVmod.nConState == IP_CLIENT_DISCO && sTVmod.nIP_Port)
    	  {
    	  fnTV_Client_Open() ;
    	  }
         
         if(!TIMELINE_ACTIVE(TL_PROCESS))
    	  {
    	  TIMELINE_CREATE(TL_PROCESS,nTL_QRT,1,TIMELINE_ABSOLUTE,TIMELINE_REPEAT) ;
    	  CANCEL_WAIT 'TL_KILLED_QUERY' ;
    	  sTVmod.nTLActive = 1 ;
    	  }
              
         RETURN ;
         }
    
    Process Q to send strings:
    DEFINE_FUNCTION fnTV_Process_Q()
    
         {
         if(sTVmod.nQTail <> sTVmod.nQHead)
    	  {
    	  fnTV_DeBug("sTVmod.sQ[sTVmod.nQTail].cCmd,' 0',itoa(sTVmod.sQ[sTVmod.nQTail].nSet),' ',sTVmod.sQ[sTVmod.nQTail].cData,',CR :DEBUG<',ITOA(__LINE__),'>'") ;
    	  SEND_STRING dvTV, "sTVmod.sQ[sTVmod.nQTail].cCmd,' 0',itoa(sTVmod.sQ[sTVmod.nQTail].nSet),' ',sTVmod.sQ[sTVmod.nQTail].cData,13" ;
    	  sTVmod.nCTS = TV_TX_BUSY ;
    	  WAIT TV_CTS_TIMEOUT 'TV_CTS_TIMEOUT'
    	       {
    	       sTVmod.nCTS = TV_TX_CTS ;
    	       }
    	  sTVmod.nCmdSent = sTVmod.nQTail ;
    	  if(sTVmod.nQTail < TV_QSIZE)
    	       {
    	       sTVmod.nQTail++ ;
    	       }
    	  else
    	       {
    	       sTVmod.nQTail = 1 ;
    	       }
    	  }
         
         if(sTVmod.nQTail == sTVmod.nQHead)
    	  {
    	  sTVmod.nQHasItem = 0 ;//timeline is killed in timeline
    	  }	  
         }
    
    TIME_LINE (could be DEFINE_PROGRAM):
    DEFINE_EVENT    //TIMELINE_EVENT [TL_PROCESS]
         
    TIMELINE_EVENT [TL_PROCESS]//200ms repeating
    
         {
         LOCAL_VAR INTEGER nTicToc ;
         
         nTicToc++ ;
         if(sTVmod.nConState >= IP_CLIENT_CONNECTED)
    	  {
    	  if(sTVmod.nQHasItem && sTVmod.nCTS == TV_TX_CTS)
    	       {
    	       fnTV_Process_Q() ;
    	       }
    	  }
           continued....
    
    Note sTVmod.nCTS is reset upon RX from devices and the wait gets canceled. You'll have to adpt this to your code and change the necassary vars but once you get this you'll be golden. Also note that "IP_CLIENT_CONNECTED" doesn't necassarily mean it's an IP device. In this case it just means the dev is ONLINE. In this module the dev could be IP, 232 or IR.
  • udiudi Posts: 107
    Explanation?

    Hi vininig,
    I didn’t I understood your variables.
    What data types sTVmod including and what each variable means. Can you explain more about the variables you have in the code?
    I have an iLight device and the commands I sent is: SEND_STRING dvILIGHT, "'@SC001:A001:L100:F004',13" ( for example). So I need to put the string : @SC001:A001:L100:F004' into the queuing.
    How I do it? How can I change your code? which vars I need to change???
    Regrds,

    udi
  • viningvining Posts: 4,368
    The vars in my code are a structure:
    DEFINE_TYPE     //TV FB VALUES 
    
    STRUCTURE _sFB
    
         {
         CHAR cValue[20] ;
         INTEGER nValue ;
         INTEGER nMainValue ;
         }
         
    DEFINE_TYPE     //TV CMD QUEUE
    
    STRUCTURE _sQ  
         {
         CHAR cCmd[2] ;
         INTEGER nSet ;
         CHAR cData[5] ;
         }
         
    DEFINE_TYPE     //TV RX Data
    
    STRUCTURE _sRX  
         {
         CHAR cCmd[2] ;
         INTEGER nSet ;
         CHAR cResult[2] ;
         CHAR cData[5] ;
         }
         
    DEFINE_TYPE     //TV STATUS
    
    STRUCTURE _sTVmod 
         
         {
         INTEGER nConState ;
         INTEGER nReCon ;
         CHAR    cIP[15] ; //IP or serial
         LONG    nIP_Port ;
         INTEGER nInstance ;
         INTEGER nSerial ;
         INTEGER nCTS ;
         INTEGER nCurSet ;
         INTEGER nQHead ;
         INTEGER nQTail ;
         INTEGER nLstTail ;
         INTEGER nQHasItem  ;
         INTEGER nTLActive ;//just for testing & tracting
         _sQ sQ[TV_QSIZE] ;
         _sFB sFB[TV_NUM_FB_LVLs] ;
         }
    
    DEFINE_VARIABLE //STRUCTURE VARIABLE
    
    VOLATILE _sTVmod sTVmod ;
    
    You could make them plain vars based on the type declared in the above DEINE_TYPES or just leave as is and remove the vars in the structure that you don't need.

    I have to run so I can't elaborate any more right now. Maybe later when I get back online.
  • udiudi Posts: 107
    some questions

    Hi vining
    I begin to understand your code.
    But I still need a little help.
    1. there are some parameters I did not understand and what their value are :
    nTL_QRT, TV_TX_CTS, TV_TX_BUSY , TV_CTS_TIMEOUT , nTicToc
    sTVmod.nCTS,
    sTVmod.nConState

    2. the parameter sTVmod.nCmdSent isn't declared in the code .
    3. where do you use: CANCEL_WAIT 'TL_KILLED_QUERY' ;
    4. Do I need to initialize sTVmod.nQTail and sTVmod.nQHead to 1

    5. In my code I need to send 2 types of coomands.
    SEND_STRING dvILIGHT, "'@SC004:A001:L100:F004',13"
    SEND_STRING dvILIGHT, "'@RC04:A01',13"
    So I only need the cCmd but what length should be variable right
    How do I set the variable to be sometimes the first command length and sometimes the second command length?


    I hope you could help me Thanks
  • viningvining Posts: 4,368
    Here's the constants your missing:
    DEFINE_CONSTANT //SEND STRING / CONTROL COMMANDS
    
    CHAR TL_PROCESS 		= 1 ;
    CHAR STR_CRLF[2]            	= {$0D,$0A} ;
    CHAR STR_CR[1]  		= {$0D} ;
    CHAR TCP 			= 1 ;
    CHAR TV_NUM_FB_LVLs		= 8 ;
    CHAR TV_TX_CTS          	= 0 ;
    CHAR TV_TX_BUSY         	= $FF ;
    CHAR TV_IS_SERIAL         	= $FF ;
    CHAR TV_POWER_ON_DELAY		= 150 ; //delay 
    CHAR TV_CTS_TIMEOUT		= 40 ;  //delay 
    CHAR TV_LENGTH_CMDs		= 2 ;
    CHAR TV_LENGTH_PARAMs		= 4 ;
    
    CHAR TV_QSIZE			= 12 ;
    
    CHAR IP_CLIENT_DISABLED		= 0 ;
    CHAR IP_CLIENT_DISCO		= 1 ;
    CHAR IP_CLIENT_PENDING		= 2 ;
    CHAR IP_CLIENT_CONNECTED	= 3 ;
    CHAR IP_CLIENT_DEVICE_READY	= 4 ;
    CHAR IP_CLIENT_RX_DATA		= 5 ;
    CHAR IP_CLIENT_TX_DATA		= 6 ;
    

    sTVmod.nCTS & sTVmod.nConstate are members of STRUCTURE _sTVmod. .nCTS is sent to TV_TX_BUSY when I send a string to the device. It has a time out in case a response is not recieved where it is set to TV_TX_CTS and the timeout wait is canceled and .nCTS is set to TV_TX_CTS when a response is received form the device. sTVmod.nConState is set to IP_CLIENT_CONNECTED in the devs online event handler. To disco in the offline and either disco or disabled in the onerror. If it's IR or serial RS232 device it's not that important to track and manage the connection state.

    Here's the start up code that initializes my head and tail:
    DEFINE_START    //SET IP if PROVIDED && initial values
         
         {
         if(length_string(cIP))
    	  {
    	  STACK_VAR INTEGER nFBS ;
    	  
    	  nFBS = find_string(cIP,"':'",1) ;
    	  if(nFBS)
    	       {
    	       sTVmod.cIP   = LEFT_STRING(cIP,nFBS -1) ;
    	       sTVmod.nIP_Port = atoi(RIGHT_STRING(cIP,LENGTH_STRING(cIP) - nFBS)) ;
    	       sTVmod.nComType = TV_IS_SERIAL ;
    	       sTVmod.nConState = IP_CLIENT_DISCO ;
    	       fnTV_Client_Open() ;
    	       }
    	  else
    	       {
    	       fnTV_DeBug("'ERR! Bad IP string format no ":" found, should be "IP:PORT" :DEBUG<',ITOA(__LINE__),'>'") ;
    	       sTVmod.cIP = '' ;
    	       sTVmod.nIP_Port = 0 ;
    	       }
    	  }
         else
    	  {
    	  sTVmod.cIP = '' ;
    	  sTVmod.nIP_Port = 0 ;
    	  }
         sTVmod.nReCon = 0 ;
         sTVmod.nQHead = 1 ;
         sTVmod.nQTail = 1 ;
         sTVmod.nCurSet = 1 ;
         sTVmod.nCmdSent = 1 ;
         if(!sTVmod.nIP_Port)
    	  {//if not set by being IP device, then set to what is passed in. either serial or IR link
    	  sTVmod.nComType = nComType ;
    	  }
         sTVmod.nInstance = nInstance ;
         
         if(!TIMELINE_ACTIVE(TL_PROCESS))//this will initially start TL and if Q empty & pwr is off it will stop
    	  {                          //tests the connection at start up
    	  TIMELINE_CREATE(TL_PROCESS,nTL_QRT,1,TIMELINE_ABSOLUTE,TIMELINE_REPEAT) ;
    	  CANCEL_WAIT 'TL_KILLED_QUERY' ;
    	  sTVmod.nTLActive = 1 ;
    	  }
         }
    

    My online event:
    DEFINE_EVENT    //DATA_EVENT[dvTV]
    
    DATA_EVENT[dvTV]//IP or SERIAL COMMS 
         
         {
         ONLINE://online set up for serial in comm module.  This allows for IP.
    	  {
    	  fnTV_DeBug("fnDEV_TO_STRING(DATA.DEVICE),' ONLINE :DEBUG<',ITOA(__LINE__),'>'") ;
    	  CANCEL_WAIT'TV_RECONNECT' ;
    	  CANCEL_WAIT 'IP_ERR_DELAY_RECON' ;
    	  sTVmod.nConState = IP_CLIENT_CONNECTED ;
    	  if(sTVmod.nIP_Port)//this is an IP Device
    	       {
    	       fnTV_DeBug("'Dev:',fnDEV_TO_STRING(DATA.DEVICE),', is an IP Device. :DEBUG<',ITOA(__LINE__),'>'") ;
    	       }
    	  else
    	       {
    	       if(sTVmod.nComType == TV_IS_SERIAL)//$FF indicates this should be a serial device (232 not IR)
    		    {
    		    SEND_COMMAND dvTV,'SET BAUD 9600,N,8,1 485 DISABLE'
    		    SEND_COMMAND dvTV,'HSOFF' ;
    		    SEND_COMMAND dvTV,'RXON' ;
    		    fnTV_DeBug("'Dev:',fnDEV_TO_STRING(DATA.DEVICE),', is a Serial Device. :DEBUG<',ITOA(__LINE__),'>'") ;
    		    }
    	       else
    		    {
    		    SEND_COMMAND dvTV,"'PTOF',1000" ;	//time = 0 - 255. Given in 1/10ths of a second. Default is 15 (1.5 seconds).
    		    SEND_COMMAND dvTV,"'SET MODE IR'" ; //sets IR port to IR mode
    	       	    SEND_COMMAND dvTV,"'CARON'" ;   	//Enable the IR carrier signals (default).
    		    SEND_COMMAND dvTV,"'CTON',2" ;	//time = 0 - 255. Given in 1/10ths of a second. Default is 5 (0.5 seconds).
    		    SEND_COMMAND dvTV,"'CTOF',2" ;	//time = 0 - 255. Given in 1/10ths of a second. Default is 5 (0.5 seconds).
    		    SEND_COMMAND dvTV,"'XCHM-0'" ;      //Mode 0 Example (default): [x][x]<x><enter>
    		    fnTV_DeBug("'Dev:',fnDEV_TO_STRING(DATA.DEVICE),', is an IR Device. :DEBUG<',ITOA(__LINE__),'>'") ;
    		    if(sTVmod.nComType) //1-8 indicates which IO to link to
    			 {
    			 fnTV_DeBug("'Dev:',fnDEV_TO_STRING(DATA.DEVICE),', SET IO LINK-(',itoa(sTVmod.nComType),') :DEBUG<',ITOA(__LINE__),'>'") ;
    			 SEND_COMMAND dvTV,"'SET IO LINK ',itoa(sTVmod.nComType)" ;//1 sets IR port to link with I/O channel 1 (port 17)
    			 }
    		    }
    	       }
    	  if(sTVmod.nIP_Port || sTVmod.nComType == TV_IS_SERIAL)
    	       {
    	       nTV_OnlineQuery = 1 ;
    	       WAIT 900 'LGTV_ONLINE_QUERY'
    		    {
    		    if(nTV_OnlineQuery)
    			 {
    			 fnTV_Q_Cmd(TV_CMD_ARRY[TV_CMD_POWER],sTVmod.nCurSet,'FF') ;
    			 }
    		    }
    	       }
    	  sTVmod.nReCon = 0 ;
    	  }
    

    I used a multi part queue so I could logically seperate my commands from my parameters to simplify later comparing to responses but you could easily just create an array to hold the entire string and make it long enough to hold your longest possible string.

    Instead of using an array and the head & tail pointers you could just as easily create a char array 512 bytes long (shorter or longer) and just concanenate your commands to it to create one long string type queue. When it's time to send a string just grab up to and including "13". (Uses 13 as the delimeter) The just do something like "send_string dev, remove_string(LongStringQueue,"13",1) ; which will pull the first command in the string.
Sign In or Register to comment.