¿ªÔÆÌåÓý

Locked Need some insight re:Scripting, Serial Ports, and non-obvious Timing


 

Hi to all,

Some may remember that I posted a reference to a new bulk sensor channel for JMRI connecting to an Arduino sensor mux: https://model-railroad-hobbyist.com/node/34392

This uses a jython script for a direct connection into JMRI, independent of the DCC base station connection. Originally I built this with PanelPro 4.12 / Java 1.8.0_151 running on a Win10 Pro 64bit laptop. It ran great. I was asked to make it work on an RPi. My RPi 3 B+ is also running JMRI 4.12 / Java 1.8.0_65. However I had to add a delay on the RPi, that breaks the script on Windows, and a new report is that other modelers had to fiddle with the amoint of delay on their RPi version (unknown).

The sequence of events is normally:
1. Arduino starts and opens Arduino USB serial port
2. JMRI starts and then starts script, which opens usb serial port
3. Arduino detects serial port opening and restarts Arduino comms ignoring serial comms during startup
4. Script sends Arduino starup chars (!!!) indicating script is ready
5. Arduino scans its sensor pins and transmits update messages to script to update sensor table.

My RPi required the added delay to be inserted after step 2.
Adding this delay breaks comms on Windows. The actual complete script is below.

Can anyone give me some insight why no delay is needed on Windows10? Why isn't the 2 second delay universally working on RPi's. I have been at this for well over a week,searched the net repeatedly (and got more than enough bad info). Good, approriate insight would be much appreciated.

Thanks ahead. Have fun!? :-)
Best regards,
Geoff Bunza
scalemodelanimation.com

import jarray
import jmri
import purejavacomm
class SerialSensorMux(jmri.jmrit.automat.AbstractAutomaton) :
??? # ctor starts up the serial port
??? def __init__(self, portname) :
??????? global extport
??????? self.portID = purejavacomm.CommPortIdentifier.getPortIdentifier(portname)
??????? try:
??????????? self.port = self.portID.open("JMRI", 50)
??????? except purejavacomm.PortInUseException:
??????????? self.port = extport
??????? extport = self.port
??????? # set options on port
??????? baudrate = 19200
??????? self.port.setSerialPortParams(baudrate,
??????????? purejavacomm.SerialPort.DATABITS_8,
??????????? purejavacomm.SerialPort.STOPBITS_1,
??????????? purejavacomm.SerialPort.PARITY_NONE)
??????? # Anticipate the Port Opening will restart the Arduino
??????? # Uncomment the following line for use on RPi You may need to fiddle with the 2000
??????? # msec delay this works on my RPi 3 B+
??????? #self.delayMsec(2000)
??? ??? # get I/O connections for later
??????? self.inputStream = self.port.getInputStream()
??????? self.outputStream = self.port.getOutputStream()
??????? return
??? # init() is the place for your initialization
??? def init(self) :
??????? return
??? # handle() is called repeatedly until it returns false.
??? def handle(self) :
??????? global ttest
??????? if ttest == 1 :
??????????????? self.outputStream.write('!')
??????????????? self.outputStream.write('!')
??????????????? self.outputStream.write('!')
??????????????? self.outputStream.write(0x0D)
??????????????? ttest = 0
??????? # get next character???
??????? if self.inputStream.read() != 65 :
??????????????? return 1
??????? sensor_num = self.inputStream.read()
??????? sensor_state = ( sensor_num>>7 ) & 1
??????? sensor_num = sensor_num & 0x7f
??????? mesg = "AR:%d" % (sensor_num)
??????? if sensor_num == 1 and sensor_state == 1 :
??????????? print "Sensor Read Ends"
??????????? self.inputStream.close()
??????????? self.outputStream.close()
??????????? self.port.close()
??????????? return 0
??????? s = sensors.getByUserName( mesg )
??????? if s is None :
??????????????? print mesg, " Not Available"
??????????????? return 1
??????? if sensor_state == 1 :
??????????????? s.setKnownState(ACTIVE)
??????? if sensor_state == 0 :
??????????????? s.setKnownState(INACTIVE)
??????? return 1??? # to continue 0 to Kill Script
??? def write(self, data) :
??????? # now send
??????? self.outputStream.write(data)
??????? return
??? def flush(self) :
??????? self.outputStream.flush()
??????? return
ttest=1
# create one of these; provide the name of the serial port
a = SerialSensorMux("COM5")
# set the thread name, so easy to cancel if needed
a.setName("SerialSensorMux script")
# start running
a.start();
# setup? complete
a.flush()


 

One problem is the call to a.fliush() when you¡¯re starting the starting the thread. The start() call just above it returns when the thread is formally set to be able to run; whether handle() has started running or not isn¡¯t specified, and will probably be different on different kinds of machines. So the very first thing to do is move that flush call into the __init__ or init() routines.

Bob

On Dec 8, 2018, at 12:50 PM, Geoffb <gbglacier@...> wrote:

Hi to all,

Some may remember that I posted a reference to a new bulk sensor channel for JMRI connecting to an Arduino sensor mux:

This uses a jython script for a direct connection into JMRI, independent of the DCC base station connection. Originally I built this with PanelPro 4.12 / Java 1.8.0_151 running on a Win10 Pro 64bit laptop. It ran great. I was asked to make it work on an RPi. My RPi 3 B+ is also running JMRI 4.12 / Java 1.8.0_65. However I had to add a delay on the RPi, that breaks the script on Windows, and a new report is that other modelers had to fiddle with the amoint of delay on their RPi version (unknown).

The sequence of events is normally:
1. Arduino starts and opens Arduino USB serial port
2. JMRI starts and then starts script, which opens usb serial port
3. Arduino detects serial port opening and restarts Arduino comms ignoring serial comms during startup
4. Script sends Arduino starup chars (!!!) indicating script is ready
5. Arduino scans its sensor pins and transmits update messages to script to update sensor table.

My RPi required the added delay to be inserted after step 2.
Adding this delay breaks comms on Windows. The actual complete script is below.

Can anyone give me some insight why no delay is needed on Windows10? Why isn't the 2 second delay universally working on RPi's. I have been at this for well over a week,searched the net repeatedly (and got more than enough bad info). Good, approriate insight would be much appreciated.

Thanks ahead. Have fun! :-)
Best regards,
Geoff Bunza
scalemodelanimation.com

import jarray
import jmri
import purejavacomm
class SerialSensorMux(jmri.jmrit.automat.AbstractAutomaton) :
# ctor starts up the serial port
def __init__(self, portname) :
global extport
self.portID = purejavacomm.CommPortIdentifier.getPortIdentifier(portname)
try:
self.port = self.portID.open("JMRI", 50)
except purejavacomm.PortInUseException:
self.port = extport
extport = self.port
# set options on port
baudrate = 19200
self.port.setSerialPortParams(baudrate,
purejavacomm.SerialPort.DATABITS_8,
purejavacomm.SerialPort.STOPBITS_1,
purejavacomm.SerialPort.PARITY_NONE)
# Anticipate the Port Opening will restart the Arduino
# Uncomment the following line for use on RPi You may need to fiddle with the 2000
# msec delay this works on my RPi 3 B+
#self.delayMsec(2000)
# get I/O connections for later
self.inputStream = self.port.getInputStream()
self.outputStream = self.port.getOutputStream()
return
# init() is the place for your initialization
def init(self) :
return
# handle() is called repeatedly until it returns false.
def handle(self) :
global ttest
if ttest == 1 :
self.outputStream.write('!')
self.outputStream.write('!')
self.outputStream.write('!')
self.outputStream.write(0x0D)
ttest = 0
# get next character
if self.inputStream.read() != 65 :
return 1
sensor_num = self.inputStream.read()
sensor_state = ( sensor_num>>7 ) & 1
sensor_num = sensor_num & 0x7f
mesg = "AR:%d" % (sensor_num)
if sensor_num == 1 and sensor_state == 1 :
print "Sensor Read Ends"
self.inputStream.close()
self.outputStream.close()
self.port.close()
return 0
s = sensors.getByUserName( mesg )
if s is None :
print mesg, " Not Available"
return 1
if sensor_state == 1 :
s.setKnownState(ACTIVE)
if sensor_state == 0 :
s.setKnownState(INACTIVE)
return 1 # to continue 0 to Kill Script
def write(self, data) :
# now send
self.outputStream.write(data)
return
def flush(self) :
self.outputStream.flush()
return
ttest=1
# create one of these; provide the name of the serial port
a = SerialSensorMux("COM5")
# set the thread name, so easy to cancel if needed
a.setName("SerialSensorMux script")
# start running
a.start();
# setup complete
a.flush()
--
Bob Jacobsen
rgj1927@...