-- comms (gpio bridge) function rpin(i) return peek(0x5f80+i) end function wpin(i,v) poke(0x5f80+i,v) end -- pin (byte) map p_turn=0 p_state=1 p_fid=2 p_flen=3 p_dlen=4 p_op=5 p_arg=6 p_data=7 data_bytes=119 my_turn=0 their_turn=1 -- opcodes: cart -> js op_req_timeline=0x10 op_req_thread=0x11 op_req_more=0x12 op_req_demo=0x13 op_req_demo_stop=0x14 op_post_create=0x20 op_post_reply=0x21 op_like=0x22 -- arg=refid, data "1"=like / "0"=unlike op_repost=0x23 -- arg=refid, data "1"=repost / "0"=unrepost op_post_quote=0x24 -- arg=refid (quoted post), data=comment text -- opcodes: js -> cart op_resp_post=0x30 op_resp_end=0x31 op_resp_error=0x32 op_resp_ok=0x33 op_resp_auth_lost=0x34 op_demo_stop=0x41 op_resp_fire=0x42 op_resp_image=0x35 -- pixelated 32x32 thumbnail (2px/byte, hi nibble first) op_resp_image_fail=0x36 -- image fetch failed; arg=refid op_resp_avatar=0x37 -- pixelated 16x16 avatar (2px/byte, 128 bytes, ~2 frames) op_resp_avatar_fail=0x38 -- avatar fetch failed; arg=refid op_resp_feeds=0x39 -- subscribed feed names (\1-joined); idx 1=following fsep=255 -- field separator rsep=254 -- record separator outq={} -- outbound frame queue inbuf="" -- inbound assembly buffer imgbuf={} -- raw byte accumulator for multi-frame image data avbuf={} -- raw byte accumulator for avatar data (always 1 frame) -- split a string into <=119 byte frames and queue them function enqueue(op,arg,s) s=s or "" local n=max(1,ceil(#s/data_bytes)) for i=1,n do local chunk=sub(s,1,data_bytes) s=sub(s,#chunk+1) add(outq,{op=op,arg=arg or 0,fid=i,flen=n,data=chunk}) end end function write_frame(f) wpin(p_op,f.op) wpin(p_arg,f.arg) wpin(p_fid,f.fid) wpin(p_flen,f.flen) wpin(p_dlen,#f.data) for i=1,#f.data do local c=sub(f.data,i,i) local b=ord(c) or 32 if c=="\n" then b=0 end wpin(p_data+i-1,b) end end function clear_out() wpin(p_op,0) wpin(p_arg,0) wpin(p_fid,0) wpin(p_flen,0) wpin(p_dlen,0) end -- decode inbound bytes; field/record seps -> \1 / \2 markers function read_frame() local op=rpin(p_op) if op==0 then return end -- firehose deltas arrive as raw bytes (no text decode / separators) if op==op_resp_fire then on_fire( rpin(p_data),rpin(p_data+1), rpin(p_data+2),rpin(p_data+3), rpin(p_data+4),rpin(p_arg)) return end -- frame id / count / payload length, shared by every remaining branch local fid,flen,dlen=rpin(p_fid),rpin(p_flen),rpin(p_dlen) if ONLINE then if op==op_resp_image then for i=1,dlen do add(imgbuf,rpin(p_data+i-1)) end if fid>=flen then on_image(rpin(p_arg),imgbuf) imgbuf={} end return end if op==op_resp_image_fail then on_image_fail(rpin(p_arg)) return end if op==op_resp_avatar then for i=1,dlen do add(avbuf,rpin(p_data+i-1)) end if fid>=flen then on_avatar(rpin(p_arg),avbuf) avbuf={} end return end if op==op_resp_avatar_fail then return end end local s="" for i=1,dlen do local b=rpin(p_data+i-1) if b==0 then s=s.."\n" elseif b==fsep then s=s.."\1" elseif b==rsep then s=s.."\2" else s=s..chr(b) end end inbuf=inbuf..s if fid>=flen then local full=inbuf inbuf="" on_message(op,rpin(p_arg),full) end end function comms_update() if rpin(p_turn)!=my_turn then return end read_frame() if #outq>0 then write_frame(deli(outq,1)) else clear_out() end wpin(p_state,scr) wpin(p_turn,their_turn) end