2021-09-24 02:28:48 +00:00
|
|
|
(local core (require :core))
|
|
|
|
(local socket (require :socket))
|
|
|
|
(local {: int16-to-bytes : int32-to-bytes : lo} (require :lib.util))
|
|
|
|
|
|
|
|
(local config {
|
2021-09-26 04:34:48 +00:00
|
|
|
:host "rat.local"
|
2021-09-24 02:28:48 +00:00
|
|
|
:port 6502
|
|
|
|
})
|
|
|
|
|
|
|
|
{:cmd {
|
|
|
|
:write 0
|
|
|
|
:read 1
|
|
|
|
:jmp 2
|
|
|
|
:pause 3
|
|
|
|
:ping 4
|
|
|
|
}
|
|
|
|
:response {
|
|
|
|
:ack 0
|
|
|
|
:data 1
|
|
|
|
}
|
|
|
|
:pending {}
|
|
|
|
:msgid 0
|
|
|
|
:connect
|
|
|
|
(fn [self ?port ?host]
|
|
|
|
(when (not self.connection)
|
|
|
|
(local [port host] [(or ?port config.port) (or ?host config.host)])
|
|
|
|
(set self.connection (assert (socket.udp)))
|
|
|
|
(assert (self.connection:setpeername host port))
|
|
|
|
(self.connection:settimeout 0)
|
|
|
|
(core.add_thread #(while (self:connected?) (self:receive) (coroutine.yield)) self.connection)))
|
|
|
|
:connected? (fn [self] (not= self.connection nil))
|
|
|
|
:disconnect
|
|
|
|
(fn [self]
|
|
|
|
(when self.connection
|
|
|
|
(self.connection:close)
|
|
|
|
(set self.connection nil)
|
|
|
|
(set self.pending {})))
|
|
|
|
:next-msgid
|
|
|
|
(fn [self]
|
|
|
|
(set self.msgid (lo (+ self.msgid 1)))
|
|
|
|
self.msgid)
|
|
|
|
:send
|
|
|
|
(fn [self cmd ?data ?callback]
|
|
|
|
(let [msgid (self:next-msgid)
|
|
|
|
msg (.. (string.char msgid cmd) (or ?data ""))]
|
|
|
|
(when ?callback (tset self.pending msgid ?callback))
|
|
|
|
(self.connection:send msg)))
|
|
|
|
:receive
|
|
|
|
(fn [self]
|
|
|
|
(when self.connection
|
|
|
|
(let [data (self.connection:receive)]
|
|
|
|
(when data
|
|
|
|
(let [msgid (string.byte (data:sub 1 1))
|
|
|
|
cmd (string.byte (data:sub 2 2))
|
|
|
|
pendingfn (. self.pending msgid)]
|
2021-09-26 04:34:48 +00:00
|
|
|
(print msgid cmd)
|
2021-09-24 02:28:48 +00:00
|
|
|
(when pendingfn
|
|
|
|
(tset self.pending msgid nil)
|
|
|
|
(pendingfn self cmd (data:sub 3))))))))
|
|
|
|
:jump (fn [self addr] (self:send self.cmd.jmp (int32-to-bytes addr)))
|
|
|
|
; todo: break up into multiple calls
|
|
|
|
:read
|
|
|
|
(fn [self addr len]
|
|
|
|
(let [coro (coroutine.running)]
|
|
|
|
(self:send self.cmd.read (.. (int32-to-bytes addr)
|
|
|
|
(int16-to-bytes len))
|
|
|
|
#(coroutine.resume coro $3))
|
|
|
|
(coroutine.yield)))
|
|
|
|
:write
|
|
|
|
(fn [self addr data]
|
|
|
|
(let [coro (coroutine.running)]
|
|
|
|
(self:send self.cmd.write (.. (int32-to-bytes addr)
|
|
|
|
(int16-to-bytes (length data))
|
|
|
|
data)
|
|
|
|
#(coroutine.resume coro $3))
|
|
|
|
(coroutine.yield)))
|
|
|
|
:launch (fn [self prg] (self:jump (prg:lookup-addr prg.start-symbol)))
|
|
|
|
}
|