mirror of
https://github.com/dschmenk/PLASMA.git
synced 2024-06-28 19:29:43 +00:00
Internet CHAT client/server
This commit is contained in:
parent
9a5d238910
commit
d6f3b5c475
233
src/chatsrc/chat.pla
Normal file
233
src/chatsrc/chat.pla
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
//
|
||||||
|
// HTTP Daemon
|
||||||
|
//
|
||||||
|
import cmdsys
|
||||||
|
predef syscall, call, getc, gets, putc, puts, putln, gotoxy
|
||||||
|
predef memset, memcpy, modaddr, modexec
|
||||||
|
predef isugt, isuge, isult, isule
|
||||||
|
predef heapmark, heapallocalign, heapalloc, heaprelease
|
||||||
|
byte MACHID
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Net object
|
||||||
|
//
|
||||||
|
import inet
|
||||||
|
word iNet
|
||||||
|
struc t_inet
|
||||||
|
word initIP
|
||||||
|
word serviceIP
|
||||||
|
word openUDP
|
||||||
|
word sendUDP
|
||||||
|
word closeUDP
|
||||||
|
word listenTCP
|
||||||
|
word connectTCP
|
||||||
|
word sendTCP
|
||||||
|
word closeTCP
|
||||||
|
word setInterfaceIP
|
||||||
|
word getInterfaceHA
|
||||||
|
word setDNS
|
||||||
|
word resolveIP
|
||||||
|
word setCallback
|
||||||
|
word setParam
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
const VERSION = 3
|
||||||
|
const txtline = $07D0
|
||||||
|
const inbuf = $0200
|
||||||
|
const instr = $01FF
|
||||||
|
|
||||||
|
byte[4] serverIP
|
||||||
|
word port, timeout
|
||||||
|
word update_list, update_len
|
||||||
|
byte response
|
||||||
|
byte hellopkt = $DA, $7E, VERSION, VERSION >> 8, $00, $00, $A2, 'H'
|
||||||
|
byte[9] handle = ""
|
||||||
|
byte chatpkt = $DA, $7E, VERSION, VERSION >> 8, $00, $01, $A2, 'C'
|
||||||
|
byte[33] msg
|
||||||
|
//
|
||||||
|
// DEBUG
|
||||||
|
//
|
||||||
|
def putln
|
||||||
|
return putc($0D)
|
||||||
|
end
|
||||||
|
def putb(hexb)
|
||||||
|
return call($FDDA, hexb, 0, 0, 0)
|
||||||
|
end
|
||||||
|
def puth(hex)
|
||||||
|
return call($F941, hex >> 8, hex, 0, 0)
|
||||||
|
end
|
||||||
|
def puti(i)
|
||||||
|
if i < 0; putc('-'); i = -i; fin
|
||||||
|
if i < 10
|
||||||
|
putc(i + '0')
|
||||||
|
else
|
||||||
|
puti(i / 10)
|
||||||
|
putc(i % 10 + '0')
|
||||||
|
fin
|
||||||
|
end
|
||||||
|
def putip(ipptr)
|
||||||
|
byte i
|
||||||
|
|
||||||
|
for i = 0 to 2
|
||||||
|
puti(ipptr->[i]); putc('.')
|
||||||
|
next
|
||||||
|
return puti(ipptr->[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
def toupper(c)
|
||||||
|
if c >= 'a'
|
||||||
|
c = c - $20
|
||||||
|
fin
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
def recvUDP(ipsrc, portsrc, data, len, param)
|
||||||
|
byte t
|
||||||
|
|
||||||
|
response = data->7
|
||||||
|
when response
|
||||||
|
is 'C'
|
||||||
|
putln
|
||||||
|
if data->16
|
||||||
|
^$32 = $3F // Inverse
|
||||||
|
for t = 0 to data->8
|
||||||
|
putc(toupper(^(data + t + 9)))
|
||||||
|
next
|
||||||
|
^$32 = $FF // Normal
|
||||||
|
for t = data->8 to 7
|
||||||
|
putc(' ')
|
||||||
|
next
|
||||||
|
puts(data + 16)
|
||||||
|
else
|
||||||
|
puts("Welcome, "); puts(data + 8)
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is 'W'
|
||||||
|
//puts("Connected to ")
|
||||||
|
//puts(instr); putc('='); putip(@serverIP)
|
||||||
|
break
|
||||||
|
is 'U'
|
||||||
|
update_list = data
|
||||||
|
update_len = len
|
||||||
|
break;
|
||||||
|
is 'E'
|
||||||
|
puts("Server error!"); putln
|
||||||
|
wend
|
||||||
|
end
|
||||||
|
|
||||||
|
def gotoxy(x, y)
|
||||||
|
^$24 = x + ^$20
|
||||||
|
return call($FB5B, y + ^$22, 0, 0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def txtwin(left, top, width, height)
|
||||||
|
if !width or !height
|
||||||
|
left = 0
|
||||||
|
top = 0
|
||||||
|
width = 40
|
||||||
|
height = 24
|
||||||
|
fin
|
||||||
|
^$20 = left
|
||||||
|
^$21 = width
|
||||||
|
^$22 = top
|
||||||
|
^$23 = height + top
|
||||||
|
return gotoxy(0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
def txtclr
|
||||||
|
^$20 = 0
|
||||||
|
^$21 = 40
|
||||||
|
^$22 = 0
|
||||||
|
^$23 = 24
|
||||||
|
return call($FC58, $00, $00, $00, $00)
|
||||||
|
end
|
||||||
|
|
||||||
|
def kbstr
|
||||||
|
byte key, inlen
|
||||||
|
|
||||||
|
^$C010
|
||||||
|
inlen = 0
|
||||||
|
repeat
|
||||||
|
^(txtline + inlen) = $DF
|
||||||
|
key = ^$C000
|
||||||
|
if key & $80
|
||||||
|
^(txtline + inlen) = $A0
|
||||||
|
^$C010
|
||||||
|
if key == $88
|
||||||
|
if inlen > 0
|
||||||
|
inlen = inlen - 1
|
||||||
|
fin
|
||||||
|
elsif key == $9B
|
||||||
|
while inlen
|
||||||
|
^(txtline + inlen) = $A0
|
||||||
|
inlen = inlen - 1
|
||||||
|
loop
|
||||||
|
elsif key >= $A0 and inlen < 39
|
||||||
|
^(txtline + inlen) = key
|
||||||
|
^(inbuf + inlen) = key & $7F
|
||||||
|
inlen = inlen + 1
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
iNet:serviceIP()
|
||||||
|
until key == $8D
|
||||||
|
^instr = inlen
|
||||||
|
repeat
|
||||||
|
^(txtline + inlen) = $A0
|
||||||
|
inlen = inlen - 1
|
||||||
|
until inlen == $FF
|
||||||
|
return instr
|
||||||
|
end
|
||||||
|
if !iNet:initIP()
|
||||||
|
return -1
|
||||||
|
fin
|
||||||
|
repeat
|
||||||
|
puts("Enter chat server address\n")
|
||||||
|
gets(':'+$80)
|
||||||
|
if ^instr
|
||||||
|
if iNet:resolveIP(instr, @serverIP)
|
||||||
|
repeat
|
||||||
|
puts("Enter chat handle (7 characters or less)\n")
|
||||||
|
gets(':'+$80)
|
||||||
|
until ^instr > 0 and ^instr < 8
|
||||||
|
memcpy(@handle, instr, ^instr + 1)
|
||||||
|
port = iNet:openUDP($6501, @recvUDP, 0)
|
||||||
|
iNet:sendUDP(port, @serverIP, $6502, @hellopkt, 16)
|
||||||
|
timeout = 1000
|
||||||
|
while !response and timeout
|
||||||
|
iNet:serviceIP()
|
||||||
|
timeout = timeout - 1
|
||||||
|
loop
|
||||||
|
if response == 'W'
|
||||||
|
txtclr()
|
||||||
|
gotoxy(0, 22)
|
||||||
|
puts("========================================")
|
||||||
|
txtwin(0, 0, 40, 22)
|
||||||
|
gotoxy(0, 0)
|
||||||
|
repeat
|
||||||
|
kbstr()
|
||||||
|
if ^instr
|
||||||
|
if ^instr > 31
|
||||||
|
^instr = 31
|
||||||
|
fin
|
||||||
|
memcpy(@msg, instr, ^instr + 1)
|
||||||
|
iNet:sendUDP(port, @serverIP, $6502, @chatpkt, 40)
|
||||||
|
fin
|
||||||
|
until ^instr == 0
|
||||||
|
txtclr()
|
||||||
|
elsif response == 'U'
|
||||||
|
heaprelease(update_list + update_len) // Set top of heap to end of update list
|
||||||
|
memcpy($0300, @serverIP, 4) // Pass serverIP to UPDATE
|
||||||
|
*$0304 = $6502 // Pass server port to UPDATE
|
||||||
|
*$0306 = update_list + 8 // Pass list pointer to UPDATE
|
||||||
|
^instr = 0
|
||||||
|
modexec("UPDATE")
|
||||||
|
else
|
||||||
|
puts("Welcome timed out."); putln
|
||||||
|
fin
|
||||||
|
else
|
||||||
|
puts("Unable to resolve."); puts(instr); putln
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
until not ^instr
|
||||||
|
done
|
16
src/chatsrc/chatserver/chat-version.xml
Normal file
16
src/chatsrc/chatserver/chat-version.xml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<chat xmlns="updates">
|
||||||
|
<file name="PLASMA.SYSTEM" type="0xFF" aux="0x2000" mask="0x0001"/>
|
||||||
|
<file name="UTHERNET" type="0xFE" aux="0x1000" mask="0x0002"/>
|
||||||
|
<file name="UTHERNET2" type="0xFE" aux="0x1000" mask="0x0004"/>
|
||||||
|
<file name="ETHERIP" type="0xFE" aux="0x1000" mask="0x0008"/>
|
||||||
|
<file name="INET" type="0xFE" aux="0x1000" mask="0x0010"/>
|
||||||
|
<file name="DHCP" type="0xFE" aux="0x1000" mask="0x0020"/>
|
||||||
|
<file name="UPDATE" type="0xFE" aux="0x1000" mask="0x0040"/>
|
||||||
|
<file name="CHAT" type="0xFE" aux="0x1000" mask="0x0080"/>
|
||||||
|
<file name="AUTORUN" type="0x06" aux="0x0000" mask="0x0100"/>
|
||||||
|
<current level="3"/>
|
||||||
|
<version level="1" updates="0x0000"/>
|
||||||
|
<version level="2" updates="0x00C0"/>
|
||||||
|
<version level="3" updates="0x01C0"/>
|
||||||
|
</chat>
|
44
src/chatsrc/chatserver/client.py
Executable file
44
src/chatsrc/chatserver/client.py
Executable file
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import sys, struct, socket, select
|
||||||
|
|
||||||
|
server = ("localhost", 0x6502)
|
||||||
|
myhandle = "Python"
|
||||||
|
VERSION = 3
|
||||||
|
|
||||||
|
# SOCK_DGRAM is the socket type to use for UDP sockets
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
s.sendto(struct.pack('<HHHBc8p', 0x7EDA, VERSION, 1, 0xFF, 'H', myhandle), server)
|
||||||
|
data, server = s.recvfrom(2048)
|
||||||
|
magic, ver, seq, hw, res = struct.unpack_from('<HHHBc', data)
|
||||||
|
if res == 'U':
|
||||||
|
ulistofst = 8
|
||||||
|
print "Update file list: (", len(data), " bytes)"
|
||||||
|
while len(data) - ulistofst >= 20:
|
||||||
|
filename, filetype, fileaux = struct.unpack_from('<17pBH', data, ulistofst)
|
||||||
|
if filename == "": break
|
||||||
|
print filename, filetype, fileaux
|
||||||
|
ulistofst += 20
|
||||||
|
elif res <> 'W':
|
||||||
|
print "Server rejected HELLO"
|
||||||
|
else:
|
||||||
|
p = select.poll()
|
||||||
|
p.register(s, select.POLLIN)
|
||||||
|
p.register(sys.stdin, select.POLLIN)
|
||||||
|
while 1:
|
||||||
|
pollin = p.poll()
|
||||||
|
if len(pollin) > 0:
|
||||||
|
if pollin[0][0] == sys.stdin.fileno():
|
||||||
|
instr = raw_input()
|
||||||
|
if len(instr) == 0: break
|
||||||
|
s.sendto(struct.pack('<HHHBc32p', 0x7EDA, VERSION, 1, 0xFF, 'C', instr), server)
|
||||||
|
elif pollin[0][0] == s.fileno():
|
||||||
|
data, server = s.recvfrom(2048)
|
||||||
|
magic, ver, seq, hw, req = struct.unpack_from('<HHHBc', data)
|
||||||
|
if req == 'C':
|
||||||
|
handle, msg = struct.unpack_from('8p32p', data, 8)
|
||||||
|
if msg:
|
||||||
|
print handle, ": ", msg
|
||||||
|
#elif handle <> myhandle:
|
||||||
|
else:
|
||||||
|
print "Welcome, ", handle
|
||||||
|
s.close()
|
1
src/chatsrc/chatserver/clientfiles/AUTORUN
Normal file
1
src/chatsrc/chatserver/clientfiles/AUTORUN
Normal file
|
@ -0,0 +1 @@
|
||||||
|
+CHAT
|
BIN
src/chatsrc/chatserver/clientfiles/CHAT
Normal file
BIN
src/chatsrc/chatserver/clientfiles/CHAT
Normal file
Binary file not shown.
BIN
src/chatsrc/chatserver/clientfiles/DHCP
Normal file
BIN
src/chatsrc/chatserver/clientfiles/DHCP
Normal file
Binary file not shown.
BIN
src/chatsrc/chatserver/clientfiles/ETHERIP
Normal file
BIN
src/chatsrc/chatserver/clientfiles/ETHERIP
Normal file
Binary file not shown.
BIN
src/chatsrc/chatserver/clientfiles/INET
Normal file
BIN
src/chatsrc/chatserver/clientfiles/INET
Normal file
Binary file not shown.
BIN
src/chatsrc/chatserver/clientfiles/PLASMA.SYSTEM
Normal file
BIN
src/chatsrc/chatserver/clientfiles/PLASMA.SYSTEM
Normal file
Binary file not shown.
BIN
src/chatsrc/chatserver/clientfiles/UPDATE
Normal file
BIN
src/chatsrc/chatserver/clientfiles/UPDATE
Normal file
Binary file not shown.
BIN
src/chatsrc/chatserver/clientfiles/UTHERNET
Normal file
BIN
src/chatsrc/chatserver/clientfiles/UTHERNET
Normal file
Binary file not shown.
BIN
src/chatsrc/chatserver/clientfiles/UTHERNET2
Normal file
BIN
src/chatsrc/chatserver/clientfiles/UTHERNET2
Normal file
Binary file not shown.
104
src/chatsrc/chatserver/server.py
Executable file
104
src/chatsrc/chatserver/server.py
Executable file
|
@ -0,0 +1,104 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# Apple II Chat server program
|
||||||
|
import struct, socket, select, time
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
HOST = '' # Symbolic name meaning all available interfaces
|
||||||
|
PORT = 0x6502 # Apple II Chat non-privileged port
|
||||||
|
VERSION = 1
|
||||||
|
client_list = {}
|
||||||
|
chat_files = {}
|
||||||
|
chat_vers = []
|
||||||
|
|
||||||
|
def client_add(address, port, handle):
|
||||||
|
global client_list
|
||||||
|
client_list[address] = (port, handle)
|
||||||
|
|
||||||
|
def broadcast(handle, msg):
|
||||||
|
global client_list
|
||||||
|
if msg:
|
||||||
|
print handle, ": ", msg
|
||||||
|
else:
|
||||||
|
print "Welcome, ", handle
|
||||||
|
bcastmsg = struct.pack('<HHHBc8p32p', 0x7EDA, VERSION, 0, 0xCA, 'C', handle, msg)
|
||||||
|
for c in client_list:
|
||||||
|
client = (c, client_list[c][0])
|
||||||
|
s.sendto(bcastmsg, client)
|
||||||
|
|
||||||
|
def send_update(client, ver):
|
||||||
|
updatemask = 0
|
||||||
|
updatelist = []
|
||||||
|
for i in xrange(ver, VERSION):
|
||||||
|
updatemask |= chat_vers[i]
|
||||||
|
for f in chat_files:
|
||||||
|
if updatemask & chat_files[f][2]:
|
||||||
|
updatelist.append(f)
|
||||||
|
print "Update client version ", ver, " with:", updatelist
|
||||||
|
pkthdr = struct.pack('<HHHBc', 0x7EDA, VERSION, 0, 0xCA, 'U')
|
||||||
|
pktmsg = ""
|
||||||
|
for f in updatelist:
|
||||||
|
pktmsg += struct.pack('<17pBH', f, chat_files[f][0], chat_files[f][1])
|
||||||
|
pktmsg += struct.pack('B', 0)
|
||||||
|
s.sendto(pkthdr + pktmsg, client)
|
||||||
|
#
|
||||||
|
# Read version XML file
|
||||||
|
#
|
||||||
|
tree = ET.parse('chat-version.xml')
|
||||||
|
root = tree.getroot()
|
||||||
|
for chatfile in root.findall('{updates}file'):
|
||||||
|
fname = chatfile.get('name')
|
||||||
|
ftype = int(chatfile.get('type'), 0)
|
||||||
|
faux = int(chatfile.get('aux'), 0)
|
||||||
|
fmask = int(chatfile.get('mask'), 0)
|
||||||
|
chat_files[fname] = (ftype, faux, fmask)
|
||||||
|
for chatver in root.findall('{updates}version'):
|
||||||
|
chat_vers.insert(int(chatver.get('level')), int(chatver.get('updates'), 0))
|
||||||
|
chatver = root.find('{updates}current')
|
||||||
|
VERSION = int(chatver.get('level'))
|
||||||
|
print "CHAT server version:", VERSION
|
||||||
|
#
|
||||||
|
# Initialize UDP socket
|
||||||
|
#
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
s.bind((HOST, PORT))
|
||||||
|
p = select.poll()
|
||||||
|
p.register(s.fileno(), select.POLLIN)
|
||||||
|
#
|
||||||
|
# Main server loop
|
||||||
|
#
|
||||||
|
while 1:
|
||||||
|
if p.poll(1000):
|
||||||
|
data, client = s.recvfrom(2048)
|
||||||
|
address, port = client
|
||||||
|
magic, ver, seq, hw, req = struct.unpack_from('<HHHBc', data)
|
||||||
|
if req == 'H':
|
||||||
|
handle, = struct.unpack_from('8p', data, 8)
|
||||||
|
if ver <> VERSION:
|
||||||
|
send_update(client, ver)
|
||||||
|
else:
|
||||||
|
client_add(address, port, handle)
|
||||||
|
s.sendto(struct.pack('<HHHBc', magic, ver, seq, 0xCA, 'W'), client)
|
||||||
|
broadcast(handle, "")
|
||||||
|
elif req == 'C':
|
||||||
|
try:
|
||||||
|
msg, = struct.unpack_from('32p', data, 8)
|
||||||
|
handle = client_list[address][1]
|
||||||
|
broadcast(handle, msg)
|
||||||
|
except:
|
||||||
|
s.sendto(struct.pack('<HHHBc', 0x7EDA, VERSION, 0, 0xCA, 'E'), client)
|
||||||
|
elif req == 'F':
|
||||||
|
try:
|
||||||
|
filename, fileblock = struct.unpack_from('<17pH', data, 8)
|
||||||
|
f = open('clientfiles/'+filename, 'r')
|
||||||
|
f.seek(fileblock * 1024)
|
||||||
|
msg = f.read(1024)
|
||||||
|
f.close()
|
||||||
|
s.sendto(struct.pack('<HHHBc', 0x7EDA, VERSION, seq, 0xCA, 'F') + msg, client)
|
||||||
|
except:
|
||||||
|
s.sendto(struct.pack('<HHHBc', 0x7EDA, VERSION, seq, 0xCA, 'E'), client)
|
||||||
|
else:
|
||||||
|
print "Unknown request: " + req
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
s.close()
|
||||||
|
|
37
src/chatsrc/makefile
Executable file
37
src/chatsrc/makefile
Executable file
|
@ -0,0 +1,37 @@
|
||||||
|
.SUFFIXES =
|
||||||
|
AFLAGS = -o $@
|
||||||
|
CHAT = CHAT\#FE1000
|
||||||
|
UPDATE = UPDATE\#FE1000
|
||||||
|
PLASM = ../plasm
|
||||||
|
#
|
||||||
|
# Image filetypes for Virtual ][
|
||||||
|
#
|
||||||
|
PLATYPE = .\$$ED
|
||||||
|
BINTYPE = .BIN
|
||||||
|
SYSTYPE = .SYS
|
||||||
|
TXTTYPE = .TXT
|
||||||
|
#
|
||||||
|
# Image filetypes for CiderPress
|
||||||
|
#
|
||||||
|
#RELTYPE = \#FE1000
|
||||||
|
#INTERPTYPE = \#050000
|
||||||
|
#BINTYPE = \#060000
|
||||||
|
#SYSTYPE = \#FF2000
|
||||||
|
#TXTTYPE = \#040000
|
||||||
|
|
||||||
|
all: $(UPDATE) $(CHAT)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm *FE1000 *FF2000
|
||||||
|
-rm *.o *~ *.a
|
||||||
|
|
||||||
|
$(UPDATE): update.pla $(PLASM)
|
||||||
|
./$(PLASM) -AM < update.pla > update.a
|
||||||
|
acme --setpc 4094 -o $(UPDATE) update.a
|
||||||
|
cp $(UPDATE) chatserver/clientfiles/UPDATE
|
||||||
|
|
||||||
|
$(CHAT): chat.pla $(PLASM)
|
||||||
|
./$(PLASM) -AM < chat.pla > chat.a
|
||||||
|
acme --setpc 4094 -o $(CHAT) chat.a
|
||||||
|
cp $(CHAT) chatserver/clientfiles/CHAT
|
||||||
|
|
231
src/chatsrc/update.pla
Normal file
231
src/chatsrc/update.pla
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
//
|
||||||
|
// HTTP Daemon
|
||||||
|
//
|
||||||
|
import cmdsys
|
||||||
|
predef syscall, call, getc, gets, putc, puts, putln
|
||||||
|
predef memset, memcpy, modaddr, modexec
|
||||||
|
predef isugt, isuge, isult, isule
|
||||||
|
predef heapmark, heapallocalign, heapalloc, heaprelease
|
||||||
|
byte MACHID
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Net object
|
||||||
|
//
|
||||||
|
import inet
|
||||||
|
word iNet
|
||||||
|
struc t_inet
|
||||||
|
word initIP
|
||||||
|
word serviceIP
|
||||||
|
word openUDP
|
||||||
|
word sendUDP
|
||||||
|
word closeUDP
|
||||||
|
word listenTCP
|
||||||
|
word connectTCP
|
||||||
|
word sendTCP
|
||||||
|
word closeTCP
|
||||||
|
word setInterfaceIP
|
||||||
|
word getInterfaceHA
|
||||||
|
word setDNS
|
||||||
|
word resolveIP
|
||||||
|
word setCallback
|
||||||
|
word setParam
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
const VERSION = 1
|
||||||
|
|
||||||
|
byte[4] serverIP
|
||||||
|
word serverPort
|
||||||
|
word updateList
|
||||||
|
word portUDP, timeout
|
||||||
|
byte response
|
||||||
|
byte perr
|
||||||
|
byte dlFile = "DOWNLOAD"
|
||||||
|
byte dlRef
|
||||||
|
byte rdreqpkt = $DA, $7E, VERSION, VERSION >> 8, $00, $00, $A2, 'F'
|
||||||
|
byte[17] filename = ""
|
||||||
|
word fileblock
|
||||||
|
word xferlen
|
||||||
|
|
||||||
|
asm reboot
|
||||||
|
BIT $C082 ; ENABLE ROM
|
||||||
|
DEC $03F4 ; INVALIDATE POWER-UP BYTE
|
||||||
|
JMP ($FFFC) ; RESET
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// ProDOS routines
|
||||||
|
//
|
||||||
|
def getpfx(path)
|
||||||
|
byte params[3]
|
||||||
|
|
||||||
|
^path = 0
|
||||||
|
params.0 = 1
|
||||||
|
params:1 = path
|
||||||
|
perr = syscall($C7, @params)
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
def setpfx(path)
|
||||||
|
byte params[3]
|
||||||
|
|
||||||
|
params.0 = 1
|
||||||
|
params:1 = path
|
||||||
|
perr = syscall($C6, @params)
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
def open(path, buff)
|
||||||
|
byte params[6]
|
||||||
|
|
||||||
|
params.0 = 3
|
||||||
|
params:1 = path
|
||||||
|
params:3 = buff
|
||||||
|
params.5 = 0
|
||||||
|
perr = syscall($C8, @params)
|
||||||
|
return params.5
|
||||||
|
end
|
||||||
|
def close(refnum)
|
||||||
|
byte params[2]
|
||||||
|
|
||||||
|
params.0 = 1
|
||||||
|
params.1 = refnum
|
||||||
|
perr = syscall($CC, @params)
|
||||||
|
return perr
|
||||||
|
end
|
||||||
|
def read(refnum, buff, len)
|
||||||
|
byte params[8]
|
||||||
|
|
||||||
|
params.0 = 4
|
||||||
|
params.1 = refnum
|
||||||
|
params:2 = buff
|
||||||
|
params:4 = len
|
||||||
|
params:6 = 0
|
||||||
|
perr = syscall($CA, @params)
|
||||||
|
return params:6
|
||||||
|
end
|
||||||
|
def write(refnum, buff, len)
|
||||||
|
byte params[8]
|
||||||
|
|
||||||
|
params.0 = 4
|
||||||
|
params.1 = refnum
|
||||||
|
params:2 = buff
|
||||||
|
params:4 = len
|
||||||
|
params:6 = 0
|
||||||
|
perr = syscall($CB, @params)
|
||||||
|
return params:6
|
||||||
|
end
|
||||||
|
def create(path, access, type, aux)
|
||||||
|
byte params[12]
|
||||||
|
|
||||||
|
params.0 = 7
|
||||||
|
params:1 = path
|
||||||
|
params.3 = access
|
||||||
|
params.4 = type
|
||||||
|
params:5 = aux
|
||||||
|
params.7 = $1
|
||||||
|
params:8 = 0
|
||||||
|
params:10 = 0
|
||||||
|
perr = syscall($C0, @params)
|
||||||
|
return perr
|
||||||
|
end
|
||||||
|
def destroy(path)
|
||||||
|
byte params[3]
|
||||||
|
|
||||||
|
params.0 = 1
|
||||||
|
params:1 = path
|
||||||
|
perr = syscall($C1, @params)
|
||||||
|
return perr
|
||||||
|
end
|
||||||
|
def rename(path, newpath)
|
||||||
|
byte params[5]
|
||||||
|
|
||||||
|
params.0 = 2
|
||||||
|
params:1 = path
|
||||||
|
params:3 = newpath
|
||||||
|
perr = syscall($C2, @params)
|
||||||
|
return perr
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Restart
|
||||||
|
//
|
||||||
|
def restart
|
||||||
|
puts("Press any key to reboot...")
|
||||||
|
getc()
|
||||||
|
reboot()
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Error
|
||||||
|
//
|
||||||
|
def dl_error(errstr)
|
||||||
|
puts("Update Error: "); puts(errstr); putln
|
||||||
|
restart()
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Receive UDP packet
|
||||||
|
//
|
||||||
|
def recvUDP(ipsrc, portsrc, data, len, param)
|
||||||
|
when data->7
|
||||||
|
is 'F'
|
||||||
|
if data=>4 == rdreqpkt:4 // Sequence numbers match
|
||||||
|
xferlen = len - 8
|
||||||
|
if xferlen > 0
|
||||||
|
if write(dlRef, data + 8, xferlen) <> xferlen or perr
|
||||||
|
dl_error("Write download file")
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
response = 'F'
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is 'E'
|
||||||
|
dl_error("Server error")
|
||||||
|
break
|
||||||
|
otherwise
|
||||||
|
dl_error("Unexpected packet")
|
||||||
|
wend
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Main update loop
|
||||||
|
//
|
||||||
|
memcpy(@serverIP, $0300, 4) // Passed in IP
|
||||||
|
serverPort = *$0304 // Passed in port
|
||||||
|
updateList = *$0306 // Passed in update list
|
||||||
|
portUDP = iNet:openUDP($6500, @recvUDP, 0)
|
||||||
|
while ^updateList
|
||||||
|
puts("Updating: "); puts(updateList)
|
||||||
|
destroy(@dlFile)
|
||||||
|
if create(@dlFile, $C3, updateList->17, updateList=>18)
|
||||||
|
dl_error("Unable to create download file")
|
||||||
|
fin
|
||||||
|
dlRef = open(@dlFile, $0800) // Use system io_buffer
|
||||||
|
if not dlRef
|
||||||
|
dl_error("Unable to open download file")
|
||||||
|
fin
|
||||||
|
rdreqpkt:4 = 2 // Init sequence number
|
||||||
|
memcpy(@filename, updateList, 17)
|
||||||
|
fileblock = 0
|
||||||
|
repeat
|
||||||
|
iNet:sendUDP(portUDP, @serverIP, serverPort, @rdreqpkt, 27)
|
||||||
|
timeout = 1000
|
||||||
|
response = 0
|
||||||
|
while not response and timeout
|
||||||
|
iNet:serviceIP()
|
||||||
|
timeout = timeout - 1
|
||||||
|
loop
|
||||||
|
if not response
|
||||||
|
dl_error("No response from server")
|
||||||
|
fin
|
||||||
|
putc('.')
|
||||||
|
fileblock = fileblock + 1
|
||||||
|
rdreqpkt:4 = rdreqpkt:4 + 1 // Increment sequence
|
||||||
|
until xferlen <> 1024
|
||||||
|
close(dlRef)
|
||||||
|
destroy(updateList)
|
||||||
|
rename(@dlFile, updateList)
|
||||||
|
if perr
|
||||||
|
dl_error("Rename download file")
|
||||||
|
fin
|
||||||
|
updateList = updateList + 20
|
||||||
|
putln
|
||||||
|
loop
|
||||||
|
iNet:closeUDP(portUDP)
|
||||||
|
puts("Update complete.\n")
|
||||||
|
restart()
|
||||||
|
done
|
|
@ -1,6 +1,14 @@
|
||||||
//
|
//
|
||||||
// Original Uthernet ethernet card based on Cirrus Logic cs8900a
|
// Original Uthernet ethernet card based on Cirrus Logic cs8900a
|
||||||
//
|
//
|
||||||
|
import cmdsys
|
||||||
|
predef syscall, call, getc, gets, putc, puts, putln
|
||||||
|
predef isugt, isuge, isult, isule
|
||||||
|
predef memset, memcpy, modaddr, modexec
|
||||||
|
predef heapmark, heapallocalign, heapalloc, heaprelease, heapavail
|
||||||
|
byte MACHID
|
||||||
|
end
|
||||||
|
//
|
||||||
// Include dependency on S/W IP stack
|
// Include dependency on S/W IP stack
|
||||||
//
|
//
|
||||||
import etherip
|
import etherip
|
||||||
|
@ -213,7 +221,7 @@ end
|
||||||
//
|
//
|
||||||
// Identify Uthernet card and initialize
|
// Identify Uthernet card and initialize
|
||||||
//
|
//
|
||||||
for slot = $F0 downto $90 step $10
|
for slot = $90 to $F0 step $10
|
||||||
if (peekiow(slot+TXCMD) & $CC3F) == $09
|
if (peekiow(slot+TXCMD) & $CC3F) == $09
|
||||||
pokeiow(slot+PREG_INDEX, 0)
|
pokeiow(slot+PREG_INDEX, 0)
|
||||||
if peekiow(slot+PREG_DATA) == $630E
|
if peekiow(slot+PREG_DATA) == $630E
|
||||||
|
@ -238,6 +246,9 @@ for slot = $F0 downto $90 step $10
|
||||||
//
|
//
|
||||||
// Install etherip driver
|
// Install etherip driver
|
||||||
//
|
//
|
||||||
|
puts("Found Uthernet I in slot #")
|
||||||
|
putc('0' + ((slot - $80) >> 4))
|
||||||
|
putln
|
||||||
setEtherDriver(@utherMAC, @peekfrmlen, @peekfrm, @pokefrmlen, @pokefrm)
|
setEtherDriver(@utherMAC, @peekfrmlen, @peekfrm, @pokefrmlen, @pokefrm)
|
||||||
return modkeep
|
return modkeep
|
||||||
fin
|
fin
|
||||||
|
|
|
@ -104,8 +104,10 @@ const WIZ_RXMEM3 = $7800
|
||||||
//
|
//
|
||||||
// Wiznet indirect registers
|
// Wiznet indirect registers
|
||||||
//
|
//
|
||||||
byte regidx, regdata
|
byte slot
|
||||||
word slot, saveidx
|
word saveidx
|
||||||
|
byte regidx
|
||||||
|
byte regdata
|
||||||
//
|
//
|
||||||
// Wiznet MAC address
|
// Wiznet MAC address
|
||||||
//
|
//
|
||||||
|
@ -720,14 +722,11 @@ def wizServiceIP
|
||||||
if ir
|
if ir
|
||||||
wiz = @wizChannel
|
wiz = @wizChannel
|
||||||
for i = 0 to 3
|
for i = 0 to 3
|
||||||
when ir & (1 << i)
|
if ir & (1 << i)
|
||||||
is 1
|
|
||||||
is 2
|
|
||||||
is 4
|
|
||||||
is 8
|
|
||||||
wizregs = wiz=>channel_regs
|
wizregs = wiz=>channel_regs
|
||||||
wizdata = wiz=>channel_rxmem
|
wizdata = wiz=>channel_rxmem
|
||||||
sir = peekreg(wizregs + WIZ_SnIR)
|
sir = peekreg(wizregs + WIZ_SnIR)
|
||||||
|
pokereg(wiz=>channel_regs + WIZ_SnIR, sir) // Clear SnIR
|
||||||
when wiz->channel_proto
|
when wiz->channel_proto
|
||||||
is WIZ_PROTO_UDP
|
is WIZ_PROTO_UDP
|
||||||
if sir & $04
|
if sir & $04
|
||||||
|
@ -813,15 +812,9 @@ def wizServiceIP
|
||||||
wend
|
wend
|
||||||
fin
|
fin
|
||||||
wend
|
wend
|
||||||
pokereg(wiz=>channel_regs + WIZ_SnIR, sir) // Clear SnIR
|
fin
|
||||||
ir = ir ^ (1 << i)
|
|
||||||
wend
|
|
||||||
wiz = wiz + t_channel
|
wiz = wiz + t_channel
|
||||||
next
|
next
|
||||||
//
|
|
||||||
// Clear IR
|
|
||||||
//
|
|
||||||
pokereg(WIZ_IR, ir)
|
|
||||||
fin
|
fin
|
||||||
end
|
end
|
||||||
//
|
//
|
||||||
|
@ -885,6 +878,12 @@ for slot = $90 to $F0 step $10
|
||||||
pokereg(WIZ_RMSR, $55) // 2K Rx memory/channel
|
pokereg(WIZ_RMSR, $55) // 2K Rx memory/channel
|
||||||
pokereg(WIZ_TMSR, $55) // 2K Tx memory/channel
|
pokereg(WIZ_TMSR, $55) // 2K Tx memory/channel
|
||||||
//
|
//
|
||||||
|
// Print settings
|
||||||
|
//
|
||||||
|
puts("Found Uthernet II in slot #")
|
||||||
|
putc('0' + ((slot - $80) >> 4))
|
||||||
|
putln
|
||||||
|
//
|
||||||
// Fill channel structure
|
// Fill channel structure
|
||||||
//
|
//
|
||||||
saveidx = @wizChannel
|
saveidx = @wizChannel
|
||||||
|
|
|
@ -977,7 +977,7 @@ def create(path, access, type, aux)
|
||||||
return perr
|
return perr
|
||||||
end
|
end
|
||||||
def destroy(path)
|
def destroy(path)
|
||||||
byte params[12]
|
byte params[3]
|
||||||
|
|
||||||
params.0 = 1
|
params.0 = 1
|
||||||
params:1 = path
|
params:1 = path
|
||||||
|
|
Loading…
Reference in New Issue
Block a user