Home AMX User Forum AMX General Discussion

Best Practice Question

Hi, I am communicating with a lumagen scaler that I need to confirm is on and ready to receive commands before sending rs232 commands.

What is the recommended way to code...

Send a command...

Check if unit is on
If not on, switch on
Wait for confirmation unit is ready to receive commands
Send Command

tia

Phil

Comments

  • yuriyuri Posts: 861
    does the unit auto switch off?
    Otherwise i would build a timeline that checks communication with the scaler. Scaler doesn't respond? Then it's off (or broken ;) ) Send power on command.
    Keep checking the status and adjust if necesarry. This way, when you want to execute a command it's done instantly :)
  • hodeyphodeyp Posts: 104
    call me old fashioned but i'd prefer to keep the unit in standby when it is not in use. I get enough grief from the missus when I don't recycle!!

    any other suggestions would be appreciated
  • DHawthorneDHawthorne Posts: 4,584
    I have had many customers complain to me if a device is left on when the rest of the system has shut down. I often try to explain that most modern equipment is on all the time anyway, and all you are doing is turning off the display, but they feel better if the stuff "looks" like it's off.

    With a single room system, I just use discrete power commands. When the device is selected, turn it on. When the entire system is shut down, turn it off. If it's a multi-room system, I'll still turn it on when selected, but only turn it off after checking that none of the rooms are using it.

    Having discrete power commands takes all the guesswork out of it, and eliminates the need to test. Most devices with serial control have that in the protocol. But if you really have to test and send a power toggle command, you still only need to do it when the device is selected and on shutdown; it's unnecessary to test on every command.
  • hodeyphodeyp Posts: 104
    Thanks for you comments. The issue I have is if I send a command prior to startup the command is discarded. Because of this I have created a channel that is on if I have received a power-up message from the unit.

    If this channel is off, I need to send a power-up command, wait until the unit confirms it is available and then send the command.

    What is the most appropriate way of implementing this?

    thx

    Phil
  • mpullinmpullin Posts: 949
    How does the device behave when you send it a command before it is ready to receive it?
  • NMarkRobertsNMarkRoberts Posts: 455
    hodeyp wrote:
    If this channel is off, I need to send a power-up command, wait until the unit confirms it is available and then send the command.

    The following code is how to do this. Note it doesn't implement a queue or flow control or powerup delays or any of the other good things you need for serial comms.
    define_constant
    
    (* Enumerated states *)
    nStateUnknown = 0
    nStateOff = 1
    nStateOn = 2
    nStateWhatever = 3
    
    define_variable
    
    volatile integer nStateDesired = nStateOff
    volatile integer nStateReported = nStateUnknown
    
    define_function CheckState()
    {
    if (nStateDesired <> nStateReported)
      {
      SendCommandForDesiredState()
      }
    }
    
    define_event
    
    data_event[dWhatever]
      {
      string:
        {
        InterpretReplyToUpdateReportedState()
        }
      }
    
    define_program
    
    wait 10
      {
      CheckState()
      }
    
    
  • hodeyphodeyp Posts: 104
    mpullin wrote:
    How does the device behave when you send it a command before it is ready to receive it?

    if the device receives a command before it is ready to receive it it ignores the command. THis is the crux of the problem - any advice on best practise for queuing code?

    tia

    PH
  • mpullinmpullin Posts: 949
    hodeyp wrote:
    if the device receives a command before it is ready to receive it it ignores the command. THis is the crux of the problem - any advice on best practise for queuing code?

    tia

    PH
    To set up a queue in NetLinx, I prefer sliding window, which invokes three variables:
    DEFINE_VARIABLE
    CHAR arrQUEUE[10][8] // 10 is max commands that can be queued, 8 is max size of a command
    INTEGER nQUEUE_LOAD = 1 // index of the last command added
    INTEGER nQUEUE_EXE = 1 // index of the last command that you know worked
    
    I will illustrate how this works, it'll be easier than typing it out.
    arrQUEUE = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}
    nQUEUE_LOAD = 1   nQUEUE_EXE = 1
    empty
    
    arrQUEUE = {' ','POWR1',' ',' ',' ',' ',' ',' ',' ',' '}
    nQUEUE_LOAD = 2*   nQUEUE_EXE = 1
    added power on command
    
    arrQUEUE = {' ','POWR1','INPT3',' ',' ',' ',' ',' ',' ',' '}
    nQUEUE_LOAD = 3*   nQUEUE_EXE = 1
    added input command
    
    arrQUEUE = {' ',' ','INPT3',' ',' ',' ',' ',' ',' ',' '}
    nQUEUE_LOAD = 3   nQUEUE_EXE = 2*
    get positive ack from device
    
    arrQUEUE = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}
    nQUEUE_LOAD = 3   nQUEUE_EXE = 3*
    get positive ack from device
    empty
    
    Queue is empty if nQUEUE_LOAD == nQUEUE_EXE, otherwise you need to send a command. Both indexes will wrap around to 1 once they are > 10. This is by no means the only way to do this but this way makes sense to me. Good luck
  • NMarkRobertsNMarkRoberts Posts: 455
    hodeyp wrote:
    if the device receives a command before it is ready to receive it it ignores the command. THis is the crux of the problem - any advice on best practise for queuing code?

    A queue doesn't solve that problem. Take a look at my earlier posting for a solution.

    Nevertheless you do need a queue and here is my string queue code. Its layout is odd because I use two character tabs. I have modified it slightly for this posting so there is a possibility it's broken:
    define_constant
    
    integer   nQueueStringMaximum                    = 255
    integer   nQueueMaximumCount                     = 100
    
    define_type
    
    structure tQueue
      {
      char    sName       [100]
      char    sQueue      [nQueueMaximumCount][nQueueStringMaximum]    
      integer nMaximumCount
      integer nInPointer  
      integer nOutPointer
      integer nCount      
      } (* tQueue *)   
    
    (******************************************************************************)
    define_function integer QueueEmpty     ( (* Result - true or false            *)
      tQueue    qArgQueue                  ) (* Input  - Queue structure          *)
    (******************************************************************************)
    {
    return (qArgQueue.nCount = 0);
    } (* QueueEmpty *)
    
    (******************************************************************************)
    define_function QueueInitialise        (
      tQueue  qArgQueue                    , (* Output - Queue structure          *)
      char    sArgName[]                   , (* Input  - Queue name for debug     *)
      integer nArgMaximumCount             ) (* Input  - Queue maximum size       *)
    (******************************************************************************)
    {
    qArgQueue.sName                                  = sArgName
    
    if (nArgMaximumCount > nQueueMaximumCount)   
      {
      qArgQueue.nMaximumCount                        = nQueueMaximumCount
      }
    else                 
      {
      qArgQueue.nMaximumCount                        = nArgMaximumCount
    	}
    
    QueueClear(qArgQueue)
    } (* QueueInitialise *)
    
    (******************************************************************************)
    define_function QueueClear             (
      tQueue    qArgQueue                  ) (* Output - Queue structure          *)
    (******************************************************************************)
    {
    stack_var integer nMyPointer
    
    qArgQueue.nCount                                 = 0 (* Nothing in queue                           *)
    qArgQueue.nInPointer                             = 0 (* Will be incremented before first add       *)
    qArgQueue.nOutPointer                            = 1 (* Will be incremented after the first remove *)
    
    (* Gratuitous emptying of strings *)
    for (nMyPointer = 1; nMyPointer <= qArgQueue.nMaximumCount; nMyPointer++)
    	{
    	qArgQueue.sQueue[nMyPointer]                   = ''  
    	}
    } (* QueueClear *)
    
    (******************************************************************************)   
    define_function QueueAdd               (
      tQueue  qArgQueue                    , (* I/O   - Queue structure           *)
      char    sArgText[]                   ) (* Input - String to add             *) 
    (******************************************************************************)
    {                                  
    (* If already full, do nothing more *)
    if (qArgQueue.nCount >= qArgQueue.nMaximumCount)
      {                     
      // Debug("'Queue full ',qArgQueue.sName") (* else recursive blowout *)
    	return;
      }
    	
    (* Advance pointer in array *)
    qArgQueue.nInPointer++
    
    (* End of array? *)
    if (qArgQueue.nInPointer > qArgQueue.nMaximumCount)
    	{
    	(* Wrap at end of array to 1 not 0 *)
    	qArgQueue.nInPointer                         = 1
    	}
    
    (* Increment queue counter, known not to be already full *)
    qArgQueue.nCount++
    		
    (* Add to queue *)
    qArgQueue.sQueue[qArgQueue.nInPointer]         = sArgText                         
    }  (* QueueAdd *)                         
    
    (******************************************************************************)
    define_function integer QueueRemove    ( (* Output         - Success / Fail   *)
      tQueue  qArgQueue                    , (* Input / Output - Queue structure  *)
      char    sArgResult[]                 ) (* Output         - Unqeueued string *)  
    (******************************************************************************)
    {  
    if (qArgQueue.nCount > 0)
    	{                                                                 
    			
    	(* There is something in the queue *)
    	sArgResult                                     = qArgQueue.sQueue[qArgQueue.nOutPointer]
    
    	(* Blank what was there *)
    	qArgQueue.sQueue[qArgQueue.nOutPointer]        = ''                        
    
    	(* Move along array, wrap to beginning if necessary *)
    	qArgQueue.nOutPointer++
    	if (qArgQueue.nOutPointer > qArgQueue.nMaximumCount)
    		{
    		qArgQueue.nOutPointer                        = 1
    		}
    
    	(* Queue is now shorter *)  
    	qArgQueue.nCount--
    	return True;
    	} (* Something in this queue *)
    
    (* Nothing in the queue *)
    sArgResult                                       = ''
    return False;  
    } (* QueueRemove *)                  
    
    
  • Spire_JeffSpire_Jeff Posts: 1,917
    hodeyp wrote:
    if the device receives a command before it is ready to receive it it ignores the command. THis is the crux of the problem - any advice on best practise for queuing code?

    tia

    PH

    There are a couple of things that will vary the solution. If the device acknowledges commands with a response, then you are able to control delivery of the queued commands based on responses from the device. You could create a queue based on one of the previous examples. You queue the command then send it without advancing the current command pointer. At this point, you also start a wait (or handle it in a timeline) to resend the command after a designated time period if no response is received. You should also consider tracking the number of times a command has been sent so you can alert someone to a device not responding after x retries. When a response is received indicating the command was successful, you increment the current command pointer and depending on how you are initiating the next command delivery, you may initiate the next command be sent.

    If the device does not acknowledge commands, but does allow you to query it for data, you could create a timeline for command delivery that meters command delivery and base the timing on the baud rate plus any processing time required by the device. You then have to insert the query command every x time commands are sent and if you go y amount of time without receiving a response, you increase the time interval of the timeline and/or halt the delivery of queued commands while you wait for a response.

    If the device offers now 2 way communication, all you can do is handle transmission based on a timeline and hope for the best :)

    Jeff
  • hodeyphodeyp Posts: 104
    thanks all, will give your suggestions a go!
Sign In or Register to comment.