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
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
0
Comments
Otherwise i would build a timeline that checks communication with the scaler. Scaler doesn't respond? Then it's off (or broken
Keep checking the status and adjust if necesarry. This way, when you want to execute a command it's done instantly
any other suggestions would be appreciated
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.
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
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() }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
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 luckA 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 *)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