GUI no respondse when invokeAsynchronous the COM IO fucntion

Hi, I did a function to monitor COM port , and run this in system.unitl.invokeAsynchronous. but GUI has no response when I click a button to execute this function (OpenCOMDevice in my attached code), meanwhile I see it can receive the bytes from COM port and write to tags in background. can anyone help on this? I searched a lot topic about this, but no luck

import sys, jarray, traceback
from java.lang import String, Thread
from java.util import Date
from org.apache.commons.lang3 import StringEscapeUtils

logger = system.util.getLogger('clientCOMIO')

def OpenCOMDevice(devicepath):
	system.tag.writeBlocking(['[default]%s/Active' % devicepath], [1])
	system.util.invokeAsynchronous(COMReadAndWrite(devicepath),devicepath)
	logger.debug("device opened:" +devicepath)
def CloseCOMDevice(devicepath):
	system.tag.writeBlocking(['[default]%s/Active' % devicepath], [0])
	logger.debug("device closed:" +devicepath)

def COMReadAndWrite(devicepath):
	values=system.tag.readBlocking(['[default]%s/Port' % devicepath,'[default]%s/BitRate' % devicepath,'[default]%s/HandShake' % devicepath,'[default]%s/FlowControl' % devicepath\
	,'[default]%s/Parity' % devicepath,'[default]%s/DataBit' % devicepath,'[default]%s/StopBit' % devicepath])
	port = values[0].value
	bitrate = values[1].value
	handshake = values[2].value
	flowcontrol = values[3].value
	parity = values[4].value
	databit = values[5].value
	stopbit = values[6].value
#	port = system.tag.read('[default]%s/Port' % devicepath).value
#	bitrate=system.tag.read('[default]%s/BitRate' % devicepath).value
#	handshake=system.tag.read('[default]%s/HandShake' % devicepath).value
#	flowcontrol=system.tag.read('[default]%s/FlowControl' % devicepath).value
#	parity=system.tag.read('[default]%s/Parity' % devicepath).value
#	databit=system.tag.read('[default]%s/DataBit' % devicepath).value
#	stopbit=system.tag.read('[default]%s/StopBit' % devicepath).value
	started = False
	try:
		system.serial.configureSerialPort(port, bitrate, databit,handshake, flowcontrol, parity, stopbit)
		system.serial.openSerialPort(port)
		active = system.tag.readBlocking(['[default]%s/Active' % devicepath])[0].value
		while active:
			receivedbytes = system.serial.readBytes(port,32,1000)
			started=-1
			for i in range(len(receivedbytes)):
				if receivedbytes[i] <> 0:
					started=i
					break
			if started > -1:
				ended = -1
				for i in range(started,len(receivedbytes)):
					if receivedbytes[i]==0:
						ended=i
						break
				
				# verify received data
				
				system.tag.writeAsync(['[default]%s/LastTrafficTime' % devicepath,'[default]%s/Received' % devicepath,'[default]%s/LastError' % devicepath], [Date(),receivedbytes[started:ended],''],None)
			send=system.tag.readBlocking(['[default]%s/Send' % devicepath])[0].value
			if (len(send)>0):
				system.serial.writeBytes(port,send)
				system.tag.writeAsync(['[default]%s/Send' % devicepath], [''])
			active = system.tag.readBlocking(['[default]%s/Active' % devicepath])[0].value
			Thread.sleep(100)

	finally:
		system.serial.closeSerialPort(port)	
		CloseCOMDevice(devicepath)

This function accepts no parameters for the function your pating into it. Also, currently you are actually running the function openCOMDevice in the gui thread. You need to pass in the function definition (ie without parenthesis, otherwise you will be executing the function and passing in its return value.

To pass in your parameters, you need to rely on Python's... Inherited scope variables.. I can't remember the name, @pturmel?

1 Like

Hi Nick, thank you very much, I know the reason now.
I modified the code to use a global variable, replace for the parameter of function openCOMDevice. Code works now. Code as below:

import sys, jarray, traceback
from java.lang import String, Thread
from java.util import Date
from org.apache.commons.lang3 import StringEscapeUtils

logger = system.util.getLogger('clientCOMIO')
devicepath=''
def OpenCOMDevice(device):
	global devicepath
	system.tag.writeBlocking(['[default]%s/Active' % device], [1])
	devicepath=device
	system.util.invokeAsynchronous(COMReadAndWrite)
	logger.debug("device opened:" +devicepath)
def CloseCOMDevice(device):
	system.tag.writeBlocking(['[default]%s/Active' % device], [0])
	logger.debug("device closed:" +device)
1 Like

"Closures"

You can also use default parameters for an inline-defined function. I recommend just using my later.py script module.

For anyone reading this in the future you can pass parameters to the system.util.invokeAsynchronous() with the help of partial library

def func1(param1):
     # do stuff		

from functools import partial		
param1 = 'test'				
system.util.invokeAsynchronous(partial(func1, param1)) # note; call func1 without parenthesis ()
4 Likes

Great!, this really help lots.

Also, for posterity, as of 8.0.15 you can pass args and kwargs objects to system.util.invokeAsychronous directly.

2 Likes

sweet!