2020-06-11 04:24:27 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
#
|
|
|
|
# Bobbi 2020
|
|
|
|
#
|
|
|
|
# Alternative server for ADTPro's VEDRIVE.SYSTEM
|
|
|
|
# Virtual Ethernet Drive for Apple II / ProDOS
|
|
|
|
#
|
|
|
|
# See https://www.adtpro.com/protocolv1.html
|
|
|
|
#
|
|
|
|
|
|
|
|
import socket
|
2020-06-11 18:40:05 +00:00
|
|
|
import time
|
2020-06-11 04:24:27 +00:00
|
|
|
|
|
|
|
IP = "::"
|
|
|
|
PORT = 6502
|
|
|
|
FILE1 = "virtual-1.po"
|
|
|
|
FILE2 = "virtual-2.po"
|
|
|
|
BLKSZ = 512
|
|
|
|
|
2020-06-11 18:40:05 +00:00
|
|
|
GRN = '\033[92m'
|
|
|
|
RED = '\033[91m'
|
|
|
|
ENDC = '\033[0m'
|
|
|
|
|
|
|
|
pd25 = True # Set to True for ProDOS 2.5+ clock driver, False otherwise
|
|
|
|
|
2020-06-11 04:24:27 +00:00
|
|
|
packet = 1
|
|
|
|
|
2020-06-11 18:40:05 +00:00
|
|
|
#
|
|
|
|
# Get date/time bytes
|
|
|
|
#
|
|
|
|
def getDateTimeBytes(pd25):
|
|
|
|
t = time.localtime()
|
|
|
|
dt = []
|
|
|
|
if pd25:
|
|
|
|
# ProDOS 2.5+
|
|
|
|
word1 = 2048 * t.tm_mday + 64 * t.tm_hour + t.tm_min
|
|
|
|
word2 = 4096 * (t.tm_mon + 1) + t.tm_year
|
|
|
|
else:
|
|
|
|
# Legacy ProDOS <2.5
|
|
|
|
word1 = t.tm_mday + 32 * t.tm_mon + 512 * (t.tm_year - 2000)
|
|
|
|
word2 = t.tm_min + 256 * t.tm_hour
|
|
|
|
dt.append(word1 & 0xff)
|
|
|
|
dt.append((word1 & 0xff00) >> 8)
|
|
|
|
dt.append(word2 & 0xff)
|
|
|
|
dt.append((word2 & 0xff00) >> 8)
|
|
|
|
return dt
|
|
|
|
|
|
|
|
#
|
|
|
|
# Append byte b to list l, return updated checksum
|
|
|
|
#
|
2020-06-11 04:24:27 +00:00
|
|
|
def appendbyte(l, b, csin):
|
|
|
|
l.append(b)
|
|
|
|
return csin ^ b
|
|
|
|
|
|
|
|
#
|
|
|
|
# Read block with date/time update
|
|
|
|
#
|
|
|
|
def read3(sock, addr, drive, d):
|
|
|
|
global packet
|
2020-06-11 18:40:05 +00:00
|
|
|
global pd25
|
|
|
|
dt = getDateTimeBytes(pd25)
|
2020-06-11 04:24:27 +00:00
|
|
|
l = []
|
|
|
|
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
|
|
|
|
cs = appendbyte(l, d[3], cs) # Block num MSB
|
2020-06-11 18:40:05 +00:00
|
|
|
cs = appendbyte(l, dt[0], cs) # Time of day LSB
|
|
|
|
cs = appendbyte(l, dt[1], cs) # Time of day MSB
|
|
|
|
cs = appendbyte(l, dt[2], cs) # Date LSB
|
|
|
|
cs = appendbyte(l, dt[3], cs) # Date MSB
|
2020-06-11 04:24:27 +00:00
|
|
|
appendbyte(l, cs, cs) # Checksum
|
|
|
|
|
|
|
|
blknum = d[2] + 256 * d[3]
|
2020-06-11 18:40:05 +00:00
|
|
|
print('{0}{1:05d}{2} '.format(GRN, blknum, ENDC), end='', flush=True)
|
2020-06-11 04:24:27 +00:00
|
|
|
b = blknum * BLKSZ
|
2020-06-11 18:40:05 +00:00
|
|
|
|
2020-06-11 04:24:27 +00:00
|
|
|
if d[1] == 0x03:
|
|
|
|
file = FILE1
|
|
|
|
else:
|
|
|
|
file = FILE2
|
2020-06-11 18:40:05 +00:00
|
|
|
|
2020-06-11 04:24:27 +00:00
|
|
|
with open(file, 'rb') as f:
|
|
|
|
f.seek(b)
|
|
|
|
block = f.read(BLKSZ)
|
|
|
|
|
|
|
|
cs = 0
|
|
|
|
for i in range (0, BLKSZ):
|
|
|
|
cs = appendbyte(l, block[i], cs)
|
|
|
|
appendbyte(l, cs, cs)
|
|
|
|
|
|
|
|
b = sock.sendto(bytearray(l), addr)
|
|
|
|
#print('Sent {} bytes to {}'.format(b, addr))
|
|
|
|
|
|
|
|
#
|
|
|
|
# Write block
|
|
|
|
#
|
|
|
|
def write(sock, addr, drive, d):
|
|
|
|
global packet
|
|
|
|
l = []
|
|
|
|
appendbyte(l, packet & 0xff, 0) # Packet number
|
|
|
|
packet += 1
|
|
|
|
cs = appendbyte(l, 0xc5, 0) # "E"
|
|
|
|
cs = appendbyte(l, d[1], cs) # 0x02 or 0x04
|
|
|
|
cs = appendbyte(l, d[2], cs) # Block num LSB
|
|
|
|
cs = appendbyte(l, d[3], cs) # Block num MSB
|
|
|
|
cs = appendbyte(l, d[517], cs) # Block num MSB
|
|
|
|
|
|
|
|
blknum = d[2] + 256 * d[3]
|
2020-06-11 18:40:05 +00:00
|
|
|
print('{0}{1:05d}{2} '.format(RED, blknum, ENDC), end='', flush=True)
|
2020-06-11 04:24:27 +00:00
|
|
|
b = blknum * BLKSZ
|
|
|
|
|
|
|
|
if d[1] == 0x02:
|
|
|
|
file = FILE1
|
|
|
|
else:
|
|
|
|
file = FILE2
|
2020-06-11 18:40:05 +00:00
|
|
|
|
2020-06-11 04:24:27 +00:00
|
|
|
with open(file, 'r+b') as f:
|
|
|
|
f.seek(b)
|
|
|
|
for i in range (0, BLKSZ):
|
|
|
|
f.write(bytes([d[i+5]]))
|
|
|
|
|
|
|
|
b = sock.sendto(bytearray(l), addr)
|
|
|
|
#print('Sent {} bytes to {}'.format(b, addr))
|
|
|
|
|
|
|
|
|
2020-06-11 18:40:05 +00:00
|
|
|
print("VEServer v0.5 alpha")
|
|
|
|
if pd25:
|
|
|
|
print("ProDOS 2.5+ Clock Driver")
|
|
|
|
else:
|
|
|
|
print("Legacy ProDOS Clock Driver")
|
|
|
|
|
2020-06-11 04:24:27 +00:00
|
|
|
with socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) as s:
|
|
|
|
s.bind((IP, PORT))
|
2020-06-11 18:40:05 +00:00
|
|
|
print("veserver - listening on UDP port {}".format(PORT))
|
|
|
|
|
2020-06-11 04:24:27 +00:00
|
|
|
while True:
|
|
|
|
data, address = s.recvfrom(1024)
|
|
|
|
#print('Received {} bytes from {}'.format(len(data), address))
|
|
|
|
if (data[0] == 0xc5):
|
|
|
|
if (data[1] == 0x03):
|
|
|
|
read3(s, address, 1, data)
|
|
|
|
elif (data[1] == 0x05):
|
|
|
|
read3(s, address, 2, data)
|
|
|
|
elif (data[1] == 0x02):
|
|
|
|
write(s, address, 1, data)
|
|
|
|
elif (data[1] == 0x04):
|
|
|
|
write(s, address, 2, data)
|
|
|
|
|