Best Practice Question
hodeyp
Junior Member
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
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
-
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
-
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 -
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. -
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 -
How does the device behave when you send it a command before it is ready to receive it?
-
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() } -
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 -
To set up a queue in NetLinx, I prefer sliding window, which invokes three variables: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
PHDEFINE_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 emptyarrQUEUE = {' ','POWR1',' ',' ',' ',' ',' ',' ',' ',' '} nQUEUE_LOAD = 2* nQUEUE_EXE = 1 added power on commandarrQUEUE = {' ','POWR1','INPT3',' ',' ',' ',' ',' ',' ',' '} nQUEUE_LOAD = 3* nQUEUE_EXE = 1 added input commandarrQUEUE = {' ',' ','INPT3',' ',' ',' ',' ',' ',' ',' '} nQUEUE_LOAD = 3 nQUEUE_EXE = 2* get positive ack from devicearrQUEUE = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' '} nQUEUE_LOAD = 3 nQUEUE_EXE = 3* get positive ack from device emptyQueue 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 -
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 *) -
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 -
thanks all, will give your suggestions a go!
Categories
- All Categories
- 2.5K AMX General Discussion
- 922 AMX Technical Discussion
- 514 AMX Hardware
- 502 AMX Control Products
- 3 AMX Video Distribution Products
- 9 AMX Networked AV (SVSI) Products
- AMX Workspace & Collaboration Products
- 3.4K AMX Software
- 151 AMX Resource Management Suite Software
- 386 AMX Design Tools
- 2.4K NetLinx Studio
- 135 Duet/Cafe Duet
- 248 NetLinx Modules & Duet Modules
- 57 AMX RPM Forum
- 228 MODPEDIA - The Public Repository of Modules for Everyone
- 943 AMX Specialty Forums
- 2.6K AMXForums Archive
- 2.6K AMXForums Archive Threads
- 1.5K AMX Hardware
- 432 AMX Applications and Solutions
- 249 Residential Forum
- 182 Tips and Tricks
- 146 AMX Website/Forums