[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Simulavr-devel] Example python script for serial simulation and tracing
From: |
Kevin O'Connor |
Subject: |
[Simulavr-devel] Example python script for serial simulation and tracing |
Date: |
Sun, 24 May 2015 10:52:00 -0400 |
User-agent: |
Mutt/1.5.23 (2014-03-12) |
Hi,
I put together a python script that works with simulavr to simulate a
serial port that one can use to interact with the simulated machine's
UART. The script also supports creating of VCD trace files for
analyzing pin changes and other events.
This is useful for AVR programs that communication over a serial port
with a host system. For example, if one normally uses a host program
to communicate with a real AVR device - such as:
$ cu -l /dev/ttyS0 -s 9600
then a simulation could be done with something like:
$ avrserial.py program.elf -b 9600 -p /tmp/pseudoserial &
$ cu -l /tmp/pseudoserial -s 9600
The avrserial.py script creates a pseudo-tty device that most serial
terminal programs can use instead of a real serial device. The
created pseudo-serial is forwarded to the AVR simulation.
It took some time to get the python parameters for this correct, so I
figured I would post the script in case others find it useful. I
posted an earlier version of the script last year:
http://lists.gnu.org/archive/html/simulavr-devel/2014-08/msg00000.html
The script supports a number of options - run "avrserial.py -h" to see
them. The script uses the simulavr python library, so simulavr must
be compiled with python support and the python module must be in the
python path. I ususally run the script with something like:
$ PYTHONPATH=/path/to/simulavr/src ./avrserial.py -h
Please CC me on any replies.
-Kevin
=========================== avrserial.py ===========================
#!/usr/bin/env python
# Script to interact with simulavr by simulating a serial port.
#
# Copyright (C) 2015 Kevin O'Connor <address@hidden>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import sys, optparse, os, pty, select, fcntl, termios, traceback
import pysimulavr
SERIALBITS = 10 # 8N1 = 1 start, 8 data, 1 stop
# Class to read serial data from AVR serial transmit pin.
class SerialRxPin(pysimulavr.PySimulationMember, pysimulavr.Pin):
def __init__(self, baud):
pysimulavr.Pin.__init__(self)
pysimulavr.PySimulationMember.__init__(self)
self.sc = pysimulavr.SystemClock.Instance()
self.delay = 10**9 / baud
self.current = 0
self.pos = -1
self.queue = ""
def SetInState(self, pin):
pysimulavr.Pin.SetInState(self, pin)
self.state = pin.outState
if self.pos < 0 and pin.outState == pin.LOW:
self.pos = 0
self.sc.Add(self)
def DoStep(self, trueHwStep):
ishigh = self.state == self.HIGH
self.current |= ishigh << self.pos
self.pos += 1
if self.pos == 1:
return int(self.delay * 1.5)
if self.pos >= SERIALBITS:
self.queue += chr((self.current >> 1) & 0xff)
self.pos = -1
self.current = 0
return -1
return self.delay
def popChars(self):
d = self.queue
self.queue = ""
return d
# Class to send serial data to AVR serial receive pin.
class SerialTxPin(pysimulavr.PySimulationMember, pysimulavr.Pin):
def __init__(self, baud):
pysimulavr.Pin.__init__(self)
pysimulavr.PySimulationMember.__init__(self)
self.SetPin('H')
self.sc = pysimulavr.SystemClock.Instance()
self.delay = 10**9 / baud
self.current = 0
self.pos = 0
self.queue = ""
def DoStep(self, trueHwStep):
if not self.pos:
if not self.queue:
return -1
self.current = (ord(self.queue[0]) << 1) | 0x200
self.queue = self.queue[1:]
newstate = 'L'
if self.current & (1 << self.pos):
newstate = 'H'
self.SetPin(newstate)
self.pos += 1
if self.pos >= SERIALBITS:
self.pos = 0
return self.delay
def pushChars(self, c):
queueEmpty = not self.queue
self.queue += c
if queueEmpty:
self.sc.Add(self)
# Support for creating VCD trace files
class Tracing:
def __init__(self, filename, signals):
self.filename = filename
self.signals = signals
if not signals:
self.dman = None
return
self.dman = pysimulavr.DumpManager.Instance()
self.dman.SetSingleDeviceApp()
def show_help(self):
ostr = pysimulavr.ostringstream()
self.dman.save(ostr)
sys.stdout.write(ostr.str())
sys.exit(1)
def load_options(self):
if self.dman is None:
return
if self.signals.strip() == '?':
self.show_help()
sigs = "\n".join(["+ " + s for s in self.signals.split(',')])
self.dman.addDumpVCD(self.filename, sigs, "ns", False, False)
def start(self):
if self.dman is not None:
self.dman.start()
def finish(self):
if self.dman is not None:
self.dman.stopApplication()
# Support for creating a pseudo-tty for emulting a serial port
def create_pty(ptyname):
mfd, sfd = pty.openpty()
try:
os.unlink(ptyname)
except os.error:
pass
os.symlink(os.ttyname(sfd), ptyname)
fcntl.fcntl(mfd, fcntl.F_SETFL
, fcntl.fcntl(mfd, fcntl.F_GETFL) | os.O_NONBLOCK)
old = termios.tcgetattr(mfd)
old[3] = old[3] & ~termios.ECHO
termios.tcsetattr(mfd, termios.TCSADRAIN, old)
return mfd
def main():
usage = "%prog [options] <program.elf>"
opts = optparse.OptionParser(usage)
opts.add_option("-m", "--machine", type="string", dest="machine",
default="atmega644", help="type of AVR machine to simulate")
opts.add_option("-s", "--speed", type="int", dest="speed", default=8000000,
help="machine speed")
opts.add_option("-b", "--baud", type="int", dest="baud", default=38400,
help="baud rate of the emulated serial port")
opts.add_option("-t", "--trace", type="string", dest="trace",
help="signals to trace (? for help)")
opts.add_option("-p", "--port", type="string", dest="port",
default="/tmp/pseudoserial",
help="pseudo-tty device to create for serial port")
deffile = os.path.splitext(os.path.basename(sys.argv[0]))[0] + ".vcd"
opts.add_option("-f", "--tracefile", type="string", dest="tracefile",
default=deffile, help="filename to write signal trace to")
options, args = opts.parse_args()
if len(args) != 1:
opts.error("Incorrect number of arguments")
elffile = args[0]
proc = options.machine
ptyname = options.port
speed = options.speed
baud = options.baud
# launch simulator
sc = pysimulavr.SystemClock.Instance()
trace = Tracing(options.tracefile, options.trace)
dev = pysimulavr.AvrFactory.instance().makeDevice(proc)
dev.Load(elffile)
dev.SetClockFreq(10**9 / speed)
sc.Add(dev)
trace.load_options()
# Setup rx pin
rxpin = SerialRxPin(baud)
net = pysimulavr.Net()
net.Add(rxpin)
net.Add(dev.GetPin("D1"))
# Setup tx pin
txpin = SerialTxPin(baud)
net2 = pysimulavr.Net()
net2.Add(dev.GetPin("D0"))
net2.Add(txpin)
msg = "Starting AVR simulation: machine=%s speed=%d\n" % (proc, speed)
msg += "Serial: port=%s baud=%d\n" % (ptyname, baud)
if options.trace:
msg += "Trace file: %s\n" % (options.tracefile,)
sys.stdout.write(msg)
sys.stdout.flush()
# Create terminal device
fd = create_pty(ptyname)
# Run loop
try:
trace.start()
while 1:
starttime = sc.GetCurrentTime()
r = sc.RunTimeRange(speed/1000)
endtime = sc.GetCurrentTime()
if starttime == endtime:
break
d = rxpin.popChars()
if d:
os.write(fd, d)
res = select.select([fd], [], [], 0)
if res[0]:
d = os.read(fd, 1024)
txpin.pushChars(d)
trace.finish()
finally:
os.unlink(ptyname)
if __name__ == '__main__':
main()
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Simulavr-devel] Example python script for serial simulation and tracing,
Kevin O'Connor <=