PySerial Simulator
--D. Thiebaut (talk) 13:45, 21 April 2014 (EDT)
The purpose of this tutorial is to illustrate the basic steps required to build a Python module that can be used as a PySerial replacement while developing a Python application that interfaces with an Arduino. The module presented here supports the basic PySerial functions one needs to call from a Python app to talk to an Arduino, but these functions either do not do anything, or returned canned, predefined data.
PySerial
First we look at how the real PySerial module behaves when supporting a Python program that interacts with an Arduino. We pick several examples from the PySerial documentation.
These examples of a real PySerial program are taken from http://pyserial.sourceforge.net/shortintro.html, and are reproduced below:
Example 1
>>> import serial
>>> ser = serial.Serial(0) # open first serial port
>>> print ser.name # check which port was really used
>>> ser.write("hello") # write a string
>>> ser.close() # close port
Example 2
>>> ser = serial.Serial('/dev/ttyS1', 19200, timeout=1)
>>> x = ser.read() # read one byte
>>> s = ser.read(10) # read up to ten bytes (timeout)
>>> line = ser.readline() # read a '\n' terminated line
>>> ser.close()
Example 3
>>> ser = serial.Serial(1, 38400, timeout=0,
... parity=serial.PARITY_EVEN, rtscts=1)
>>> s = ser.read(100) # read up to one hundred bytes
... # or as much is in the buffer
Example 4
>>> ser = serial.Serial()
>>> ser.baudrate = 19200
>>> ser.port = 0
>>> ser
Serial<id=0xa81c10, open=False>(port='COM1', baudrate=19200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=0, rtscts=0)
>>> ser.open()
>>> ser.isOpen()
True
>>> ser.close()
>>> ser.isOpen()
False
Implementing the Simulator Module
So, all we have to do is create a module called fakeSerial.py that will contain
- a class called Serial() that can be initialized with various amount of arguments
- a member variable of this class should be called name and return the name of a port.
- a method called write( ) which receives a string and passes it to the fake Arduino
- a method called read() which will read some number of bytes from the Arduino
- a method called close() that closes the port and make all further operations with the Arduino impossible.
- a method called isOpen() which will return True or False depending on whether the port to the fake Arduino is opened or closed.
- a method called readline() that will return characters until a \n is found.
Below is our first attempt at building this module.
# fakeSerial.py
# D. Thiebaut
# A very crude simulator for PySerial assuming it
# is emulating an Arduino.
# a Serial class emulator
class Serial:
## init(): the constructor. Many of the arguments have default values
# and can be skipped when calling the constructor.
def __init__( self, port='COM1', baudrate = 19200, timeout=1,
bytesize = 8, parity = 'N', stopbits = 1, xonxoff=0,
rtscts = 0):
self.name = port
self.port = port
self.timeout = timeout
self.parity = parity
self.baudrate = baudrate
self.bytesize = bytesize
self.stopbits = stopbits
self.xonxoff = xonxoff
self.rtscts = rtscts
self._isOpen = True
self._receivedData = ""
self._data = "It was the best of times.\nIt was the worst of times.\n"
## isOpen()
# returns True if the port to the Arduino is open. False otherwise
def isOpen( self ):
return self._isOpen
## open()
# opens the port
def open( self ):
self._isOpen = True
## close()
# closes the port
def close( self ):
self._isOpen = False
## write()
# writes a string of characters to the Arduino
def write( self, string ):
print( 'Arduino got: "' + string + '"' )
self._receivedData += string
## read()
# reads n characters from the fake Arduino. Actually n characters
# are read from the string _data and returned to the caller.
def read( self, n=1 ):
s = self._data[0:n]
self._data = self._data[n:]
#print( "read: now self._data = ", self._data )
return s
## readline()
# reads characters from the fake Arduino until a \n is found.
def readline( self ):
returnIndex = self._data.index( "\n" )
if returnIndex != -1:
s = self._data[0:returnIndex+1]
self._data = self._data[returnIndex+1:]
return s
else:
return ""
## __str__()
# returns a string representation of the serial class
def __str__( self ):
return "Serial<id=0xa81c10, open=%s>( port='%s', baudrate=%d," \
% ( str(self.isOpen), self.port, self.baudrate ) \
+ " bytesize=%d, parity='%s', stopbits=%d, xonxoff=%d, rtscts=%d)"\
% ( self.bytesize, self.parity, self.stopbits, self.xonxoff,
self.rtscts )
Test Program
Below is our test program that uses the simulator and runs the same tests we listed at the top of the page. Note that the output is the same as with a real Arduino!
import fakeSerial as serial
def Example1():
ser = serial.Serial(0) # open first serial port
print( ser.name ) # check which port was really used
ser.write("hello") # write a string
ser.close() # close port
def Example2():
ser = serial.Serial('/dev/ttyS1', 19200, timeout=1)
x = ser.read() # read one byte
print( "x = ", x )
s = ser.read(10) # read up to ten bytes (timeout)
print( "s = ", s )
line = ser.readline() # read a '\n' terminated line
ser.close()
print( "line = ", line )
def Example3():
ser = serial.Serial()
ser.baudrate = 19200
ser.port = 0
print( ser )
ser.open()
print( str( ser.isOpen() ) )
ser.close()
print( ser.isOpen() )
Example1()
Example2()
Example3()
The output of the program is shown below:
0 Arduino got: "hello" x = I s = t was the line = best of times. Serial<id=0xa81c10, open=<bound method Serial.isOpen of <fakeSerial.Serial object at 0x102b37ad0>>>( port='0', baudrate=19200, bytesize=8, parity='N', stopbits=1, xonxoff=0, rtscts=0) True False