mirror of
https://github.com/bobbimanners/ProDOS-Utils.git
synced 2024-06-06 06:29:31 +00:00
Compare commits
4 Commits
ee70f87d16
...
9e6f64151e
Author | SHA1 | Date | |
---|---|---|---|
|
9e6f64151e | ||
|
1a5cacda9d | ||
|
599d653692 | ||
|
ec1dc1874c |
|
@ -14,6 +14,11 @@ place of the ADTPro server for this purpose. VEServer is a much smaller and
|
||||||
simpler program, so it is easier to modify and better suited to being run as
|
simpler program, so it is easier to modify and better suited to being run as
|
||||||
a system service.
|
a system service.
|
||||||
|
|
||||||
|
VEServer can also support RS232 serial connections, in which case ADTPro's
|
||||||
|
`VSDRIVE.SYSTEM` should be used on the Apple II rather than `VEDRIVE.SYSTEM`.
|
||||||
|
The default mode of operation is to use ethernet. See the Command Line
|
||||||
|
Options section below for information on how to switch to serial mode.
|
||||||
|
|
||||||
## Principle of Operation
|
## Principle of Operation
|
||||||
|
|
||||||
VEServer uses IPv6 and listens on UDP port 6502 for incoming datagrams from
|
VEServer uses IPv6 and listens on UDP port 6502 for incoming datagrams from
|
||||||
|
@ -24,7 +29,8 @@ VEServer uses IPv6 and listens on UDP port 6502 for incoming datagrams from
|
||||||
|
|
||||||
Two simulated drives are supported, backed up by disk files in `.po` "ProDOS
|
Two simulated drives are supported, backed up by disk files in `.po` "ProDOS
|
||||||
Order". These may be 143K or 800K floppy disk images or any volume up to the
|
Order". These may be 143K or 800K floppy disk images or any volume up to the
|
||||||
ProDOS limit of 32MB.
|
ProDOS limit of 32MB. `.2mg` container files are also supported, provided
|
||||||
|
the volume within the `.2mg` file is in ProDOS order.
|
||||||
|
|
||||||
VEServer can provide system date and time in a similar manner to an Apple II
|
VEServer can provide system date and time in a similar manner to an Apple II
|
||||||
clock such as Thunderclock or No Slot Clock. Because the legacy ProDOS date
|
clock such as Thunderclock or No Slot Clock. Because the legacy ProDOS date
|
||||||
|
@ -34,12 +40,19 @@ ProDOS 2.5 please specify the `--prodos25` flag to use the new format.
|
||||||
|
|
||||||
## Command Line Options
|
## Command Line Options
|
||||||
|
|
||||||
There are only a few options:
|
VEServer accepts the following command line options; each option has a short
|
||||||
|
form and a verbose form:
|
||||||
|
|
||||||
- `-h`, `--help` - Display brief usage information.
|
- `-h`, `--help` - Display brief usage information.
|
||||||
- `-p`, `--prodos25` - Use new ProDOS 2.5 date/time format (see above.)
|
- `-p`, `--prodos25` - Use new ProDOS 2.5 date/time format (see above.)
|
||||||
- `-1 FNAME`, `--disk1=FNAME` - Specify filename for disk 1 image.
|
- `-1 FNAME`, `--disk1=FNAME` - Specify filename for disk 1 image.
|
||||||
- `-2 FNAME`, `--disk2=FNAME` - Specify filename for disk 1 image.
|
- `-2 FNAME`, `--disk2=FNAME` - Specify filename for disk 1 image.
|
||||||
|
- `-s`, `--serial` - Use RS232 serial rather than Ethernet.
|
||||||
|
- `-b nnnnn`, `--baud=nnnnn` - Specify baud rate when using serial connection.
|
||||||
|
|
||||||
|
If the `--disk1=FNAME` or `--disk2=FNAME` options are not specified, VEServer
|
||||||
|
will fall back to using the default values hard coded at the top of the
|
||||||
|
Python script.
|
||||||
|
|
||||||
## Running in a Shell
|
## Running in a Shell
|
||||||
|
|
||||||
|
@ -75,3 +88,28 @@ following command:
|
||||||
Rather than using colour to indicate reads and writes the letter 'R' or 'W' is
|
Rather than using colour to indicate reads and writes the letter 'R' or 'W' is
|
||||||
shown before the block number in the log.
|
shown before the block number in the log.
|
||||||
|
|
||||||
|
## Working with Multiple Apple II Clients (Advanced)
|
||||||
|
|
||||||
|
If you use `VEDRIVE.SYSTEM` on more than one Apple II machine, it is sometimes
|
||||||
|
convenient to be able to use different disk images on each machine. VEServer
|
||||||
|
offers a way to do this.
|
||||||
|
|
||||||
|
Suppose the disk1 filename is set to `virtual-1.po` and the disk2 filename is
|
||||||
|
set to `virtual-2.po` (either using the `--disk1=FNAME` / `--disk2=FNAME`
|
||||||
|
command line parameters, or using the hard-coded default.) Further, suppose
|
||||||
|
the IP address of the Apple II client is 192.168.0.100. In this case, when
|
||||||
|
accessing drive 1, VEServer will first look for the file:
|
||||||
|
|
||||||
|
- `virtual-1-192.168.0.100.po`
|
||||||
|
|
||||||
|
If this is found that file will be served. If not found, VEServer will fall
|
||||||
|
back to:
|
||||||
|
|
||||||
|
- `virtual-1.po`
|
||||||
|
|
||||||
|
Similarly for drive 2, `virtual-2-192.168.0.100.po` will be used if it exists,
|
||||||
|
or `virtual-2.po` otherwise.
|
||||||
|
|
||||||
|
This mechanism allows you to serve different disk images for each client,
|
||||||
|
allowing read/write access with no risk of data corruption due to simultaneous
|
||||||
|
access.
|
||||||
|
|
BIN
sortdir.po
BIN
sortdir.po
Binary file not shown.
54
veserver.py
54
veserver.py
|
@ -11,8 +11,8 @@
|
||||||
###########################################################################
|
###########################################################################
|
||||||
|
|
||||||
pd25 = False # Default to old-style date/time --prodos25 to use new format
|
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
|
file1 = "/home/bobbi/virtual-1.po" # Disk image drive 1 --disk1 to override
|
||||||
file2 = "/home/pi/virtual-2.po" # Disk image drive 2 --disk2 to override
|
file2 = "/home/bobbi/virtual-2.po" # Disk image drive 2 --disk2 to override
|
||||||
serial_port = None # Serial port to use instead of ethernet
|
serial_port = None # Serial port to use instead of ethernet
|
||||||
baud_rate = 115200 # Baud rate for serial mode
|
baud_rate = 115200 # Baud rate for serial mode
|
||||||
|
|
||||||
|
@ -107,10 +107,36 @@ def printinfo(drv, blknum, isWrite, isError, cs):
|
||||||
prevop = isWrite
|
prevop = isWrite
|
||||||
prevcs = cs
|
prevcs = cs
|
||||||
|
|
||||||
|
#
|
||||||
|
# Augment filename by adding IP
|
||||||
|
# If filename is basename.ext and IP is 192.168.2.3
|
||||||
|
# will return basename-192.168.2.3.ext
|
||||||
|
#
|
||||||
|
def augment_filename(filename, ip):
|
||||||
|
idx = filename.rfind(".")
|
||||||
|
basename = filename[0 : idx]
|
||||||
|
ext = filename[idx:]
|
||||||
|
return basename + "-" + ip + ext
|
||||||
|
|
||||||
|
#
|
||||||
|
# See if augmented filename exists, if so return that name
|
||||||
|
# otherwise return the unaugmented name
|
||||||
|
#
|
||||||
|
def select_filename(filename, ip):
|
||||||
|
if serial_port:
|
||||||
|
return filename
|
||||||
|
filename_with_ip = augment_filename(filename, ip)
|
||||||
|
try:
|
||||||
|
with open(filename_with_ip, "rb"):
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
return filename
|
||||||
|
return filename_with_ip
|
||||||
|
|
||||||
#
|
#
|
||||||
# Read block with date/time update
|
# Read block with date/time update
|
||||||
#
|
#
|
||||||
def read3(dataport, addr, d):
|
def read3(dataport, addr, ip, d):
|
||||||
global packet
|
global packet
|
||||||
|
|
||||||
d = dataport.recvmore(d, 3)
|
d = dataport.recvmore(d, 3)
|
||||||
|
@ -124,6 +150,8 @@ def read3(dataport, addr, d):
|
||||||
drv = 2
|
drv = 2
|
||||||
skip = skip2
|
skip = skip2
|
||||||
|
|
||||||
|
file = select_filename(file, ip)
|
||||||
|
|
||||||
blknum = d[2] + 256 * d[3]
|
blknum = d[2] + 256 * d[3]
|
||||||
|
|
||||||
err = False
|
err = False
|
||||||
|
@ -164,12 +192,12 @@ def read3(dataport, addr, d):
|
||||||
printinfo(drv, blknum, False, err, cs)
|
printinfo(drv, blknum, False, err, cs)
|
||||||
|
|
||||||
b = dataport.sendto(bytearray(l), addr)
|
b = dataport.sendto(bytearray(l), addr)
|
||||||
#print('Sent {} bytes to {}'.format(b, addr))
|
#print('Sent {} bytes to {}'.format(b, ip))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Write block
|
# Write block
|
||||||
#
|
#
|
||||||
def write(dataport, addr, d):
|
def write(dataport, addr, ip, d):
|
||||||
global packet
|
global packet
|
||||||
|
|
||||||
d = dataport.recvmore(d, BLKSZ + 4)
|
d = dataport.recvmore(d, BLKSZ + 4)
|
||||||
|
@ -183,6 +211,8 @@ def write(dataport, addr, d):
|
||||||
drv = 2
|
drv = 2
|
||||||
skip = skip2
|
skip = skip2
|
||||||
|
|
||||||
|
file = select_filename(file, ip)
|
||||||
|
|
||||||
cs = 0
|
cs = 0
|
||||||
for i in range (0, BLKSZ):
|
for i in range (0, BLKSZ):
|
||||||
cs ^= d[i+5]
|
cs ^= d[i+5]
|
||||||
|
@ -192,7 +222,7 @@ def write(dataport, addr, d):
|
||||||
err = False
|
err = False
|
||||||
if cs == d[517]:
|
if cs == d[517]:
|
||||||
try:
|
try:
|
||||||
with open(file, 'r+b') as f:
|
with open(file, 'rb') as f:
|
||||||
b = blknum * BLKSZ + skip
|
b = blknum * BLKSZ + skip
|
||||||
f.seek(b)
|
f.seek(b)
|
||||||
for i in range (0, BLKSZ):
|
for i in range (0, BLKSZ):
|
||||||
|
@ -220,7 +250,7 @@ def write(dataport, addr, d):
|
||||||
printinfo(drv, blknum, True, err, cs)
|
printinfo(drv, blknum, True, err, cs)
|
||||||
|
|
||||||
b = dataport.sendto(bytearray(l), addr)
|
b = dataport.sendto(bytearray(l), addr)
|
||||||
#print('Sent {} bytes to {}'.format(b, addr))
|
#print('Sent {} bytes to {}'.format(b, ip))
|
||||||
|
|
||||||
#
|
#
|
||||||
# See if file is a 2MG and, if so, that it contains .PO image
|
# See if file is a 2MG and, if so, that it contains .PO image
|
||||||
|
@ -332,7 +362,7 @@ for a, v in args:
|
||||||
elif a in ('-b', '--baud'):
|
elif a in ('-b', '--baud'):
|
||||||
baud_rate = int(v)
|
baud_rate = int(v)
|
||||||
|
|
||||||
print("VEServer v1.1")
|
print("VEServer v1.2")
|
||||||
if pd25:
|
if pd25:
|
||||||
print("ProDOS 2.5+ Clock Driver")
|
print("ProDOS 2.5+ Clock Driver")
|
||||||
else:
|
else:
|
||||||
|
@ -347,11 +377,13 @@ with DataPort(serial_port, baud_rate) as dataport:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
data, address = dataport.recvfrom(2)
|
data, address = dataport.recvfrom(2)
|
||||||
# print('Received {} bytes from {}'.format(len(data), address))
|
ip = address[0]
|
||||||
|
ip = ip[ip.rfind(":")+1:]
|
||||||
|
#print('Received {} bytes from {}'.format(len(data), ip))
|
||||||
if (data[0] == 0xc5):
|
if (data[0] == 0xc5):
|
||||||
if (data[1] == 0x03) or (data[1] == 0x05):
|
if (data[1] == 0x03) or (data[1] == 0x05):
|
||||||
read3(dataport, address, data)
|
read3(dataport, address, ip, data)
|
||||||
elif (data[1] == 0x02) or (data[1] == 0x04):
|
elif (data[1] == 0x02) or (data[1] == 0x04):
|
||||||
write(dataport, address, data)
|
write(dataport, address, ip, data)
|
||||||
except DataPort.Timeout:
|
except DataPort.Timeout:
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Reference in New Issue
Block a user