- example for lakeshore tutorial - lakeshore simulator (merge with frappy_psils370sim) - rename stringio-server to sim-server Change-Id: I33a9c75ea268349573f8a8387910921e19f242eb Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30516 Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
188 lines
5.5 KiB
Python
Executable File
188 lines
5.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# pylint: disable=invalid-name
|
|
# -*- coding: utf-8 -*-
|
|
# *****************************************************************************
|
|
# This program is free software; you can redistribute it and/or modify it under
|
|
# the terms of the GNU General Public License as published by the Free Software
|
|
# Foundation; either version 2 of the License, or (at your option) any later
|
|
# version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along with
|
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
# Module authors:
|
|
# Markus Zolliker <markus.zolliker@psi.ch>
|
|
# *****************************************************************************
|
|
"""server for a string communicator
|
|
|
|
Usage:
|
|
|
|
bin/stringio-server <communciator> <server port>
|
|
|
|
open a server on <server port> to communicate with the string based <communicator> over TCP/IP.
|
|
|
|
Use cases, mainly for test purposes:
|
|
- as a T, if the hardware allows only one connection, and more than one is needed
|
|
- relay to a communicator not using TCP/IP, if Frappy should run on an other host
|
|
- relay to a hardware simulation written as a communicator
|
|
"""
|
|
|
|
import sys
|
|
import argparse
|
|
from os import path
|
|
import asyncore
|
|
import socket
|
|
import time
|
|
|
|
# Add import path for inplace usage
|
|
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
|
|
|
|
from frappy.lib import get_class, formatException, mkthread
|
|
|
|
|
|
class LineHandler(asyncore.dispatcher_with_send):
|
|
|
|
def __init__(self, sock):
|
|
self.buffer = b""
|
|
asyncore.dispatcher_with_send.__init__(self, sock)
|
|
self.crlf = 0
|
|
|
|
def handle_line(self, line):
|
|
raise NotImplementedError
|
|
|
|
def handle_read(self):
|
|
data = self.recv(8192)
|
|
if data:
|
|
parts = data.split(b"\n")
|
|
if len(parts) == 1:
|
|
self.buffer += data
|
|
else:
|
|
self.handle_line((self.buffer + parts[0]).decode('latin_1'))
|
|
for part in parts[1:-1]:
|
|
if part[-1] == b"\r":
|
|
self.crlf = True
|
|
part = part[:-1]
|
|
else:
|
|
self.crlf = False
|
|
self.handle_line(part.decode('latin_1'))
|
|
self.buffer = parts[-1]
|
|
|
|
def send_line(self, line):
|
|
self.send((line + ("\r\n" if self.crlf else "\n")).encode('latin_1'))
|
|
|
|
|
|
class LineServer(asyncore.dispatcher):
|
|
|
|
def __init__(self, port, line_handler_cls, handler_args):
|
|
asyncore.dispatcher.__init__(self)
|
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
self.set_reuse_addr()
|
|
self.bind(('0.0.0.0', port))
|
|
self.listen(5)
|
|
print('accept connections at port', port)
|
|
self.line_handler_cls = line_handler_cls
|
|
self.handler_args = handler_args
|
|
|
|
def handle_accept(self):
|
|
pair = self.accept()
|
|
if pair is not None:
|
|
sock, addr = pair
|
|
print("Incoming connection from %s" % repr(addr))
|
|
self.line_handler_cls(sock, self.handler_args)
|
|
|
|
def loop(self):
|
|
asyncore.loop()
|
|
|
|
|
|
class Server(LineServer):
|
|
|
|
class Dispatcher:
|
|
def announce_update(self, *_):
|
|
pass
|
|
|
|
def announce_update_error(self, *_):
|
|
pass
|
|
|
|
def __init__(self, *args, **kwds):
|
|
super().__init__(*args, **kwds)
|
|
self.dispatcher = self.Dispatcher()
|
|
|
|
|
|
class Handler(LineHandler):
|
|
def __init__(self, sock, handler_args):
|
|
super().__init__(sock)
|
|
self.module = handler_args['module']
|
|
self.verbose = handler_args['verbose']
|
|
|
|
def handle_line(self, line):
|
|
try:
|
|
reply = self.module.communicate(line.strip())
|
|
if self.verbose:
|
|
print('%-40s | %s' % (line, reply))
|
|
except Exception:
|
|
print(formatException(verbose=True))
|
|
return
|
|
self.send_line(reply)
|
|
|
|
|
|
class Logger:
|
|
def debug(self, *args):
|
|
pass
|
|
|
|
def log(self, level, *args):
|
|
pass
|
|
|
|
def info(self, *args):
|
|
print(*args)
|
|
|
|
exception = error = warn = info
|
|
|
|
|
|
def parse_argv(argv):
|
|
parser = argparse.ArgumentParser(description="Simulate HW with a serial interface")
|
|
parser.add_argument("-v", "--verbose",
|
|
help="output full communication",
|
|
action='store_true', default=False)
|
|
parser.add_argument("cls",
|
|
type=str,
|
|
help="simulator class.\n",)
|
|
parser.add_argument('-p',
|
|
'--port',
|
|
action='store',
|
|
help='server port or uri',
|
|
default=2089)
|
|
return parser.parse_args(argv)
|
|
|
|
|
|
def poller(pollfunc):
|
|
while True:
|
|
time.sleep(1.0)
|
|
pollfunc()
|
|
|
|
|
|
def main(argv=None):
|
|
if argv is None:
|
|
argv = sys.argv
|
|
|
|
args = parse_argv(argv[1:])
|
|
|
|
opts = {'description': 'simulator'}
|
|
|
|
handler_args = {'verbose': args.verbose}
|
|
srv = Server(int(args.port), Handler, handler_args)
|
|
module = get_class(args.cls)(args.cls, Logger(), opts, srv)
|
|
handler_args['module'] = module
|
|
module.earlyInit()
|
|
mkthread(poller, module.doPoll)
|
|
srv.loop()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main(sys.argv))
|