View Full Version : How to use 'Event masking' in Serial Communication

December 16th, 2007, 10:42 AM
I like to mask out certain events (like CTS). So when these events occur the callback-function should not be called.
I read the function
[res], [err] = Event([mask], [timeout])would do that.
But how do I implement this into my serial driver?

What is the syntax (and where to put) when I only want to get the callback called when data has been received.

Rob H
December 16th, 2007, 10:47 AM
It's probably easier to just check for those in the callback function and just mask them there.

December 16th, 2007, 12:46 PM
I already was afraid someone would suggest this. The disadvantage is I can't use the noresponsetimer to wait for a valid repsons because I first get an invalid repons.
I send a command an then wait for a repsons. If I get a repons I process the data and continue my program.
Now I get a respons but there is no data; the program continues without the data.

Rob H
December 16th, 2007, 04:11 PM
Um why would you use the NoResponse timer for this?

I can understand using IncompleteResponse for this.

Can you post your ReceiveResponse method?

December 17th, 2007, 07:27 AM
Sure Rob, here it is:

First the Serial Plugin


local device = serial.Classes.Simple:New({
Name = "ICPCON",
Description = "Controlling ICPDAS Modules over RS485.",
GlobalName = 'ICPCON',
LogLevel = 3,
BaudRate = 9600,
Parity = 0,
StopBits = 0,
DataBits = 8,
FlowControl = 'N',
IntraCharacterDelay = 0, --test
BurstSize = 256, -- default=256.
CallbackType = serial.CB_TERMINATED,
ReceiveTerminator = '\r\n',
SendTerminator = '\r\n',
IncompleteResponseTimeout = 100,
Initialize = function (self)
gir.LogMessage(self.Name, 'ICPCON Communications OK',3)
self.Status = 'Waiting for commands'
return serial.Classes.Simple.Initialize (self)

ReceiveResponse = function ( self, data, code )
if math.band (code,serial.RXCHAR) and data and Initialized then
--if string.sub((data or ""),1,1)==">" and Initialized then
serial.Classes.Simple.ReceiveResponse (self,data,code)
QueryAD = function(self, command)
while self.Response=="" do
if win.GetElapsedMilliseconds(Ticks.ICPCON)>=100 then self.Response="-timeout-" break end
return self.Response

serial.AddDevice (device)

And the processing and calling function:

function CheckAD() --called every 10 seconds for reading two AD converters
if not Enable.ICPCON then return end
local data=ICPCON:QueryAD("#01")..ICPCON:QueryAD("#00")
if string.len(data)==112 then
local LogString,Channel=""
for Channel=1,16 do
AD.Value[Channel]=(math.round((tonumber(string.sub(data,(Channel-1)*7+1,(Channel-1)*7+7))*100)+AD.Offset[Channel],3)) --AD range 1V
NetRemote.SetVariable("Temp"..Channel,string.format("%2.2f",math.round(AD.Value[Channel],2)).." C.",false,true)
if AD.Value[Channel]>AD.Highest[Channel] then
NetRemote.SetVariable("AD.Highest"..Channel,string.format("%2.2f",math.round(AD.Highest[Channel],2)).." C.",false,true)
rh1:Write("AD.Highest"..Channel, tostring(AD.Highest[Channel]))
if AD.Value[Channel]<AD.Lowest[Channel] then
NetRemote.SetVariable("AD.Lowest"..Channel,string.format("%2.2f",math.round(AD.Lowest[Channel],2)).." C.",false,true)
rh1:Write("AD.Lowest"..Channel, tostring(AD.Lowest[Channel]))
ADLog(string.sub(LogString,2)) --trim first semicolon
NetRemote.SetVariable("Counter3", "ICPCON:"..Count.ICPCON,false,true)
ErrorLog("AD ERROR: corrupt datastring ("..data..")")
When the ReceiveRespons would have been triggered only bij received data I did not have to use the 'QueryAD()' function.
The QueryAD() function now keeps me in the Serial driver until I get the real data or the timeout has elapsed.
Do you get my point or am I seeing something wrong?

Rob H
December 17th, 2007, 10:04 AM
Hmm... so what events do you see otherwise? RTS and CTS? any others?

If not then it sounds like the device is using hardware flow control, in which case I'd suggest that you set FlowControl to 'H' rather than 'N'.

Not keen on the win.Sleep() in the serial thread either.

Serial devices are pretty much asynchronous but you are treating this one as synchronous in your CheckAD and QueryAD functions.

I'd think about restructuring the code. e.g. using gir.TriggerEvent() when you get a response. When you get the response to the first ADC you would trigger an event which would request the data for the second one. When you get that one you'd trigger another event to indicate that you have all the data and can process it.

December 17th, 2007, 10:21 AM
I only get the CTS callbacks (code:8). I already tried hardware to 'H' but I still got the CTS replies.

Because the Sleep is a separate thread I thought it could not harm my main threads. Or do you still think this code will delay my mainscripts?

I agree to you asynchronous remarks. When I had one ADC I did it the way you described. After connecting the second there was no way to be 100% sure from which ADC the reply comes.

Or is there a way to ad something to the calling command which returns in the answer from the device? So a kind of prefix to the data.

Rob H
December 17th, 2007, 11:47 AM
Well, you could just store the command that was last sent - if it was #00 then it's ADC 0 etc.

I wonder what's going on with the signalling lines then. Do you have a link to the protocol of this device?

December 17th, 2007, 02:31 PM
I have the protocol specs. Nothing about handshaking. Did you notice it's a RS485 device and connected over one twisted pair. No handshaking connections. The other ports on my quad RS485 device do not generate these CTS signals. Only the data is received (loglevel=0 shows everything what is happening).

But to start with my first question again. How to use the 'Event' function described in the manual to disable certain triggers?

Rob H
December 17th, 2007, 03:26 PM
Hmm.. I wonder where the CTS is coming from then?

I did notice the original question - I was sort of hoping that Ron would pipe up, since I have no idea, I've never had to use Event()