Connect Port Serial Port Access
From Digi Developer
Accessing the Digi Connect/Connect Port serial ports
Enabling Serial Port Access
By default many Digi products assign the direct serial ports for use by terminal login (meaning they send out the "Login:" prompt). Since only 1 task can control a serial port at one time, this means attempts to open the serial port in Python will always fail.
Therefore, to enable Python access to the serial port you must open the Digi product's Web interface and select the "Configuration | Serial Port" option on the left, then set the "Serial Port Profile" to RealPort, which frees the port up for Python access - as long as no host activates RealPort. You do not want the profile to be <unassigned>, plus you will need to reboot after setting this new profile.
Opening the Serial Port
Access the serial port of the Digi Connect/Connect Port family products using the Python "os" module (import os). While this provides an interface quite unlike most serial port libraries on Windows or other embedded system, it has the benefit of allowing the serial port to be treated as a normal TCP socket within a select() statement. Thus a Python program implementing a TCP server function to offer access to serial data can handle socket I/O and serial I/O within a single thread context.
The serial ports are named '/com/0', '/com/1', '/com/2' and so on. Digi products with the GPS virtual service have a device named '/gps/0', which acts like a serial port returning NMEA formated data; see also: Virtual_GPS_NMEA_Access
This code opens a serial port for read-write access, plus enables non-blocking behavior:
try: serfd = os.open( '/com/0', os.O_RDWR | os.O_NONBLOCK) except: ( ... handle port in use or invalid name ... )
Reading from the Serial Port
As mentioned, if your application already receives TCP socket data via the select() statement, then add the serial port handle to the list of sockets for select to wait upon. This handle is the 'serfd' variable in the open() example above.
However, you can also read the port directly. In this example we handle non-blocking behavior to enable response timeouts. This example requires importing both 'os' and 'errno':
try: data = os.read( serfd, max_bytes) except OSError, e: if( e.errno == errno.EAGAIN): # EAGAIN just means NO data ready, try again ( ... handle NO data received or response timeout here ... ) else: # other errors ( ... handle port faults - likely fatal ... ) traceback.print_exc() # make sure you show the user what error was
Be forewarned: some of the 'OSError' text messages may be misleading since they are used for many purposes. Don't Panic.
Write to the Serial Port
Writing data is straight-forward. A 'try-except' is shown below, however unlike the non-blocking read() we do not expect to see errors here:
try: count = os.write( serfd, data) except: ( ... handle port faults - likely fatal ... )
Closing the Serial Port
Closing is also straight-forward, and we ignore errors since any port faults might have invalidated the 'serfd' handle already:
try: os.close( serfd) except: pass # ignore errors here
Setting Serial Port Characteristics like Baud Rate
See Python Programmer's Guide, termios module for complete details, but specific details are explained here.
Use 'import termios' to access the tcgetattr/tcsetattr functions. These are available on Digi Python products and Unix/Linux. They are not standard in Python for Windows computers.
print 'termios =', termios.tcgetattr( self.fd)
tcgetattr returns a list, with the above code printing this example from a Digi Connect WAN IA:
termios = [5120, 0, 48, 0, 9600, 9600, ['\x11', '\x13', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00']]
The tcgetattr list is defined as: [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
The Python Programmer's Guide, termios module explains the constants required to decode these fields. The most interesting are:
- cflag defines the parity, start bits, stop bits and so on (shown as 48 or 8,N,1 here)
- ispeed is baud rate in (shown as 9600 above)
- ospeed is baud rate out (shown as 9600 above)
The easiest way to write the serial port setting is to first read them with termios.tcgetattr(), modify the returned list, and then resubmit the list to termios.tcsetattr(). You should not change settings you don't understand.
old = termios.tcgetattr(fd) old = 19200 # ispeed old = 19200 # ospeed try: termios.tcsetattr(fd, termios.TCSADRAIN, old) except: ( ... handle a port not accepting your settings ... )
Reading and Setting Control Signals
The Python Programmer's Guide, termios module gives nice examples of the special Digi-specific routines to use.
termios.tcgetstats() returns the status of flow, any incoming signals such as DSR, CTS, DCD and RI, and also the current status of the outgoing signals DTR and RTS.
termios.tcsetsignals() can be used to set the outgoing signals DTR and RTS - as long as they are not already controlled by flow control.