From 7dadd9c75b7e11feddcc49a81372a2188fcf2bc0 Mon Sep 17 00:00:00 2001 From: Renee Harke Date: Sat, 11 Dec 2021 12:19:01 -0500 Subject: [PATCH 1/4] Add serial port support ("vsserver") --- veserver.py | 91 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 19 deletions(-) diff --git a/veserver.py b/veserver.py index a7f4251..98a588e 100755 --- a/veserver.py +++ b/veserver.py @@ -13,6 +13,8 @@ pd25 = False # Default to old-style date/time --prodos25 to use new format file1 = "/home/pi/virtual-1.po" # Disk image drive 1 --disk1 to override file2 = "/home/pi/virtual-2.po" # Disk image drive 2 --disk2 to override +serial_port = None # Serial port to use instead of ethernet +baud_rate = 115200 # Baud rate for serial mode ########################################################################### @@ -108,8 +110,10 @@ def printinfo(drv, blknum, isWrite, isError, cs): # # Read block with date/time update # -def read3(sock, addr, d): - global packet, skip +def read3(dataport, addr, d): + global packet + + d = dataport.recvmore(d, 3) if d[1] == 0x03: file = file1 @@ -133,8 +137,9 @@ def read3(sock, addr, d): dt = getDateTimeBytes() l = [] - appendbyte(l, packet & 0xff, 0) # Packet number - packet += 1 + if not serial_port: + appendbyte(l, packet & 0xff, 0) # Packet number + packet += 1 cs = appendbyte(l, 0xc5, 0) # "E" cs = appendbyte(l, d[1], cs) # 0x03 or 0x05 cs = appendbyte(l, d[2], cs) # Block num LSB @@ -158,15 +163,17 @@ def read3(sock, addr, d): printinfo(drv, blknum, False, err, cs) - b = sock.sendto(bytearray(l), addr) + b = dataport.sendto(bytearray(l), addr) #print('Sent {} bytes to {}'.format(b, addr)) # # Write block # -def write(sock, addr, d): +def write(dataport, addr, d): global packet + d = dataport.recvmore(BLKSZ + 4) + if d[1] == 0x02: file = file1 drv = 1 @@ -201,8 +208,9 @@ def write(sock, addr, d): cs = d[517] + 1 l = [] - appendbyte(l, packet & 0xff, 0) # Packet number - packet += 1 + if not serial_port: + appendbyte(l, packet & 0xff, 0) # Packet number + packet += 1 appendbyte(l, 0xc5, 0) # "E" appendbyte(l, d[1], 0) # 0x02 or 0x04 appendbyte(l, d[2], 0) # Block num LSB @@ -211,7 +219,7 @@ def write(sock, addr, d): printinfo(drv, blknum, True, err, cs) - b = sock.sendto(bytearray(l), addr) + b = dataport.sendto(bytearray(l), addr) #print('Sent {} bytes to {}'.format(b, addr)) # @@ -231,12 +239,56 @@ def check2MG(filename): return 64 return 0 +class DataPort: + def __init__(self, serial_port, baud_rate): + if serial_port: + import serial # Import locally to avoid hard dependency + self.impl = serial.Serial( + port=serial_port, baudrate=baud_rate, bytesize=serial.EIGHTBITS, + parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, + xonxoff=False, rtscts=True, dsrdtr=True, exclusive=None + ) + self.stream = True + print("veserver - listening on serial port {}".format(serial_port)) + else: + self.impl = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + self.impl.bind((IP, PORT)) + self.stream = False + print("veserver - listening on UDP port {}".format(PORT)) + + def __enter__(self): + self.impl.__enter__() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.impl.__exit__(exc_type, exc_val, exc_tb) + + def recvfrom(self, required_bytes): + if self.stream: + return self.impl.read(required_bytes), None + else: + return self.recvfrom(1024) + + def recvmore(self, data, remaining_bytes): + if self.stream: + return data + self.impl.read(remaining_bytes) + else: + return data + + def sendto(self, data, addr): + if self.stream: + return self.impl.write(data) + else: + return self.impl.sendto(data, addr) + def usage(): print('usage: veserver [OPTION]...') print(' -h, --help Show this help'); print(' -p, --prodos25 Use ProDOS 2.5 date/time format'); print(' -1 FNAME, --disk1=FNAME Specify filename for disk 1 image'); print(' -2 FNAME, --disk2=FNAME Specify filename for disk 2 image'); + print(' -s PORT, --serial=PORT Use a serial link instead of ethernet'); + print(' -b BAUD, --baud=BAUD Baud rate for serial link'); # # Entry point @@ -246,8 +298,8 @@ def usage(): if 'INVOCATION_ID' in os.environ: systemd = True -short_opts = "hp1:2:" -long_opts = ["help", "prodos25", "disk1=", "disk2="] +short_opts = "hp1:2:s:b:" +long_opts = ["help", "prodos25", "disk1=", "disk2=", "serial=", "baud="] try: args, vals = getopt.getopt(sys.argv[1:], short_opts, long_opts) except getopt.error as e: @@ -265,6 +317,10 @@ for a, v in args: file1 = v elif a in ('-2', '--disk2'): file2 = v + elif a in ('-s', '--serial'): + serial_port = v + elif a in ('-b', '--baud'): + baud_rate = int(v) print("VEServer v1.0") if pd25: @@ -277,16 +333,13 @@ skip1 = check2MG(file1) print("Disk 2: {}".format(file2)) skip2 = check2MG(file2) -with socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) as s: - s.bind((IP, PORT)) - print("veserver - listening on UDP port {}".format(PORT)) - +with DataPort(serial_port, baud_rate) as dataport: while True: - data, address = s.recvfrom(1024) - #print('Received {} bytes from {}'.format(len(data), address)) + data, address = dataport.recvfrom(2) + # print('Received {} bytes from {}'.format(len(data), address)) if (data[0] == 0xc5): if (data[1] == 0x03) or (data[1] == 0x05): - read3(s, address, data) + read3(dataport, address, data) elif (data[1] == 0x02) or (data[1] == 0x04): - write(s, address, data) + write(dataport, address, data) From 6acd9208c32e349e3d7c39b16ab52ae5e849b34e Mon Sep 17 00:00:00 2001 From: Renee Harke Date: Sun, 12 Dec 2021 16:23:34 -0500 Subject: [PATCH 2/4] Fix missing parameter --- veserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/veserver.py b/veserver.py index 98a588e..612b9b6 100755 --- a/veserver.py +++ b/veserver.py @@ -172,7 +172,7 @@ def read3(dataport, addr, d): def write(dataport, addr, d): global packet - d = dataport.recvmore(BLKSZ + 4) + d = dataport.recvmore(d, BLKSZ + 4) if d[1] == 0x02: file = file1 From 68e550a92d376d5b95bce9d8acc3e41cf84dfe88 Mon Sep 17 00:00:00 2001 From: Renee Harke Date: Mon, 13 Dec 2021 00:42:03 -0500 Subject: [PATCH 3/4] Add timeout on serial links --- veserver.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/veserver.py b/veserver.py index 612b9b6..3f318a2 100755 --- a/veserver.py +++ b/veserver.py @@ -240,13 +240,19 @@ def check2MG(filename): return 0 class DataPort: + class Timeout(Exception): + pass + def __init__(self, serial_port, baud_rate): if serial_port: import serial # Import locally to avoid hard dependency + + # Use a short timeout so that the protocol resets on desync. This + # tends to happen if you reboot the client. self.impl = serial.Serial( port=serial_port, baudrate=baud_rate, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, - xonxoff=False, rtscts=True, dsrdtr=True, exclusive=None + timeout=1, xonxoff=False, rtscts=True, dsrdtr=True ) self.stream = True print("veserver - listening on serial port {}".format(serial_port)) @@ -265,7 +271,11 @@ class DataPort: def recvfrom(self, required_bytes): if self.stream: - return self.impl.read(required_bytes), None + data = self.impl.read(required_bytes) + if len(data) < required_bytes: + raise DataPort.Timeout + else: + return data, None else: return self.recvfrom(1024) @@ -335,11 +345,13 @@ skip2 = check2MG(file2) with DataPort(serial_port, baud_rate) as dataport: while True: - data, address = dataport.recvfrom(2) - # print('Received {} bytes from {}'.format(len(data), address)) - if (data[0] == 0xc5): - if (data[1] == 0x03) or (data[1] == 0x05): - read3(dataport, address, data) - elif (data[1] == 0x02) or (data[1] == 0x04): - write(dataport, address, data) - + try: + data, address = dataport.recvfrom(2) + # print('Received {} bytes from {}'.format(len(data), address)) + if (data[0] == 0xc5): + if (data[1] == 0x03) or (data[1] == 0x05): + read3(dataport, address, data) + elif (data[1] == 0x02) or (data[1] == 0x04): + write(dataport, address, data) + except DataPort.Timeout: + pass From f2adc973725ed5e9a5a15c8c7a0142646c521a5c Mon Sep 17 00:00:00 2001 From: Renee Harke Date: Mon, 5 Sep 2022 15:04:25 -0400 Subject: [PATCH 4/4] Fix network mode --- veserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/veserver.py b/veserver.py index 3f318a2..71b8b30 100755 --- a/veserver.py +++ b/veserver.py @@ -277,7 +277,7 @@ class DataPort: else: return data, None else: - return self.recvfrom(1024) + return self.impl.recvfrom(1024) def recvmore(self, data, remaining_bytes): if self.stream: