mirror of
https://github.com/captain-amygdala/pistorm.git
synced 2026-04-15 16:09:58 +00:00
Adapt picmd to work on PiStorm + A314 emulation
Requires both .cfg files from `files_pi` to be in /etc/opt/a314, and picmd.py needs to be started after the emulator. I have no idea how to better streamline this, but I'm sure someone will come up with a brilliant solution.
This commit is contained in:
8
a314/files_pi/a314fs.conf
Normal file
8
a314/files_pi/a314fs.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"devices": {
|
||||
"PI0": {
|
||||
"volume": "PiDisk",
|
||||
"path": "/home/pi/a314shared"
|
||||
}
|
||||
}
|
||||
}
|
||||
8
a314/files_pi/picmd.conf
Normal file
8
a314/files_pi/picmd.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"paths": ["/home/pi/amiga_sdk/vbcc/bin"],
|
||||
"env_vars": {
|
||||
"VBCC": "/home/pi/amiga_sdk/vbcc"
|
||||
},
|
||||
"sgr_map": {
|
||||
}
|
||||
}
|
||||
391
a314/files_pi/picmd.py
Normal file
391
a314/files_pi/picmd.py
Normal file
@@ -0,0 +1,391 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2018-2021 Niklas Ekström
|
||||
|
||||
import select
|
||||
import sys
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
import os
|
||||
import struct
|
||||
import pty
|
||||
import signal
|
||||
import termios
|
||||
import fcntl
|
||||
import logging
|
||||
import json
|
||||
|
||||
logging.basicConfig(format = '%(levelname)s, %(asctime)s, %(name)s, line %(lineno)d: %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
FS_CFG_FILE = '/etc/opt/a314/a314fs.conf'
|
||||
PICMD_CFG_FILE = '/etc/opt/a314/picmd.conf'
|
||||
|
||||
volume_paths = {}
|
||||
search_path = ''
|
||||
env_vars = {}
|
||||
sgr_map = {}
|
||||
|
||||
def load_cfg():
|
||||
with open(FS_CFG_FILE, 'rt') as f:
|
||||
cfg = json.load(f)
|
||||
devs = cfg['devices']
|
||||
for _, dev in devs.items():
|
||||
volume_paths[dev['volume']] = dev['path']
|
||||
|
||||
global search_path
|
||||
search_path = os.getenv('PATH')
|
||||
|
||||
with open(PICMD_CFG_FILE, 'rt') as f:
|
||||
cfg = json.load(f)
|
||||
|
||||
if 'paths' in cfg:
|
||||
search_path = ':'.join(cfg['paths']) + ':' + search_path
|
||||
os.environ['PATH'] = search_path
|
||||
|
||||
if 'env_vars' in cfg:
|
||||
for key, val in cfg['env_vars'].items():
|
||||
env_vars[key] = val
|
||||
|
||||
if 'sgr_map' in cfg:
|
||||
for key, val in cfg['sgr_map'].items():
|
||||
sgr_map[key] = str(val)
|
||||
|
||||
load_cfg()
|
||||
|
||||
MSG_REGISTER_REQ = 1
|
||||
MSG_REGISTER_RES = 2
|
||||
MSG_DEREGISTER_REQ = 3
|
||||
MSG_DEREGISTER_RES = 4
|
||||
MSG_READ_MEM_REQ = 5
|
||||
MSG_READ_MEM_RES = 6
|
||||
MSG_WRITE_MEM_REQ = 7
|
||||
MSG_WRITE_MEM_RES = 8
|
||||
MSG_CONNECT = 9
|
||||
MSG_CONNECT_RESPONSE = 10
|
||||
MSG_DATA = 11
|
||||
MSG_EOS = 12
|
||||
MSG_RESET = 13
|
||||
|
||||
def wait_for_msg():
|
||||
header = b''
|
||||
while len(header) < 9:
|
||||
data = drv.recv(9 - len(header))
|
||||
if not data:
|
||||
logger.error('Connection to a314d was closed, terminating.')
|
||||
exit(-1)
|
||||
header += data
|
||||
(plen, stream_id, ptype) = struct.unpack('=IIB', header)
|
||||
payload = b''
|
||||
while len(payload) < plen:
|
||||
data = drv.recv(plen - len(payload))
|
||||
if not data:
|
||||
logger.error('Connection to a314d was closed, terminating.')
|
||||
exit(-1)
|
||||
payload += data
|
||||
return (stream_id, ptype, payload)
|
||||
|
||||
def send_register_req(name):
|
||||
m = struct.pack('=IIB', len(name), 0, MSG_REGISTER_REQ) + name
|
||||
drv.sendall(m)
|
||||
|
||||
def send_read_mem_req(address, length):
|
||||
m = struct.pack('=IIBII', 8, 0, MSG_READ_MEM_REQ, address, length)
|
||||
drv.sendall(m)
|
||||
|
||||
def read_mem(address, length):
|
||||
send_read_mem_req(address, length)
|
||||
stream_id, ptype, payload = wait_for_msg()
|
||||
if ptype != MSG_READ_MEM_RES:
|
||||
logger.error('Expected MSG_READ_MEM_RES but got %s. Shutting down.', ptype)
|
||||
exit(-1)
|
||||
return payload
|
||||
|
||||
def send_write_mem_req(address, data):
|
||||
m = struct.pack('=IIBI', 4 + len(data), 0, MSG_WRITE_MEM_REQ, address) + data
|
||||
drv.sendall(m)
|
||||
|
||||
def write_mem(address, data):
|
||||
send_write_mem_req(address, data)
|
||||
stream_id, ptype, payload = wait_for_msg()
|
||||
if ptype != MSG_WRITE_MEM_RES:
|
||||
logger.error('Expected MSG_WRITE_MEM_RES but got %s. Shutting down.', ptype)
|
||||
exit(-1)
|
||||
|
||||
def send_connect_response(stream_id, result):
|
||||
m = struct.pack('=IIBB', 1, stream_id, MSG_CONNECT_RESPONSE, result)
|
||||
drv.sendall(m)
|
||||
|
||||
def send_data(stream_id, data):
|
||||
m = struct.pack('=IIB', len(data), stream_id, MSG_DATA) + data
|
||||
drv.sendall(m)
|
||||
|
||||
def send_eos(stream_id):
|
||||
m = struct.pack('=IIB', 0, stream_id, MSG_EOS)
|
||||
drv.sendall(m)
|
||||
|
||||
def send_reset(stream_id):
|
||||
m = struct.pack('=IIB', 0, stream_id, MSG_RESET)
|
||||
drv.sendall(m)
|
||||
|
||||
sessions = {}
|
||||
|
||||
class PiCmdSession(object):
|
||||
def __init__(self, stream_id):
|
||||
self.stream_id = stream_id
|
||||
self.pid = 0
|
||||
|
||||
self.first_packet = True
|
||||
self.reset_after = None
|
||||
|
||||
self.rasp_was_esc = False
|
||||
self.rasp_in_cs = False
|
||||
self.rasp_holding = ''
|
||||
|
||||
self.amiga_in_cs = False
|
||||
self.amiga_holding = ''
|
||||
|
||||
def process_amiga_ansi(self, data):
|
||||
data = data.decode('latin-1')
|
||||
out = ''
|
||||
for c in data:
|
||||
if not self.amiga_in_cs:
|
||||
if c == '\x9b':
|
||||
self.amiga_in_cs = True
|
||||
self.amiga_holding = '\x1b['
|
||||
else:
|
||||
out += c
|
||||
else: # self.amiga_in_cs
|
||||
self.amiga_holding += c
|
||||
if c >= chr(0x40) and c <= chr(0x7e):
|
||||
if c == 'r':
|
||||
# Window Bounds Report
|
||||
# ESC[1;1;rows;cols r
|
||||
rows, cols = map(int, self.amiga_holding[6:-2].split(';'))
|
||||
winsize = struct.pack('HHHH', rows, cols, 0, 0)
|
||||
fcntl.ioctl(self.fd, termios.TIOCSWINSZ, winsize)
|
||||
elif c == '|':
|
||||
# Input Event Report
|
||||
# ESC[12;0;0;x;x;x;x;x|
|
||||
# Window resized
|
||||
send_data(self.stream_id, b'\x9b' + b'0 q')
|
||||
else:
|
||||
out += self.amiga_holding
|
||||
self.amiga_holding = ''
|
||||
self.amiga_in_cs = False
|
||||
if len(out) != 0:
|
||||
os.write(self.fd, out.encode('utf-8'))
|
||||
|
||||
def process_msg_data(self, data):
|
||||
if self.first_packet:
|
||||
if len(data) != 8:
|
||||
send_reset(self.stream_id)
|
||||
del sessions[self.stream_id]
|
||||
else:
|
||||
address, length = struct.unpack('>II', data)
|
||||
buf = read_mem(address, length)
|
||||
|
||||
ind = 0
|
||||
rows, cols = struct.unpack('>HH', buf[ind:ind+4])
|
||||
ind += 4
|
||||
|
||||
component_count = buf[ind]
|
||||
ind += 1
|
||||
|
||||
components = []
|
||||
for _ in range(component_count):
|
||||
n = buf[ind]
|
||||
ind += 1
|
||||
components.append(buf[ind:ind+n].decode('latin-1'))
|
||||
ind += n
|
||||
|
||||
arg_count = buf[ind]
|
||||
ind += 1
|
||||
|
||||
args = []
|
||||
for _ in range(arg_count):
|
||||
n = buf[ind]
|
||||
ind += 1
|
||||
args.append(buf[ind:ind+n].decode('latin-1'))
|
||||
ind += n
|
||||
|
||||
if arg_count == 0:
|
||||
args.append('bash')
|
||||
|
||||
self.pid, self.fd = pty.fork()
|
||||
if self.pid == 0:
|
||||
for key, val in env_vars.items():
|
||||
os.putenv(key, val)
|
||||
os.putenv('PATH', search_path)
|
||||
os.putenv('TERM', 'ansi')
|
||||
winsize = struct.pack('HHHH', rows, cols, 0, 0)
|
||||
fcntl.ioctl(sys.stdin, termios.TIOCSWINSZ, winsize)
|
||||
if component_count != 0 and components[0] in volume_paths:
|
||||
path = volume_paths[components[0]]
|
||||
os.chdir(os.path.join(path, *components[1:]))
|
||||
else:
|
||||
os.chdir(os.getenv('HOME', '/'))
|
||||
os.execvp(args[0], args)
|
||||
|
||||
self.first_packet = False
|
||||
|
||||
elif self.pid:
|
||||
self.process_amiga_ansi(data)
|
||||
|
||||
def close(self):
|
||||
if self.pid:
|
||||
os.kill(self.pid, signal.SIGTERM)
|
||||
self.pid = 0
|
||||
os.close(self.fd)
|
||||
del sessions[self.stream_id]
|
||||
|
||||
def process_rasp_ansi(self, text):
|
||||
text = text.decode('utf-8')
|
||||
out = ''
|
||||
for c in text:
|
||||
if not self.rasp_in_cs:
|
||||
if not self.rasp_was_esc:
|
||||
if c == '\x1b':
|
||||
self.rasp_was_esc = True
|
||||
else:
|
||||
out += c
|
||||
else: # self.rasp_was_esc
|
||||
if c == '[':
|
||||
self.rasp_was_esc = False
|
||||
self.rasp_in_cs = True
|
||||
self.rasp_holding = '\x1b['
|
||||
elif c == '\x1b':
|
||||
out += '\x1b'
|
||||
else:
|
||||
out += '\x1b'
|
||||
out += c
|
||||
self.rasp_was_esc = False
|
||||
else: # self.rasp_in_cs
|
||||
self.rasp_holding += c
|
||||
if c >= chr(0x40) and c <= chr(0x7e):
|
||||
if c == 'm':
|
||||
# Select Graphic Rendition
|
||||
# ESC[30;37m
|
||||
attrs = self.rasp_holding[2:-1].split(';')
|
||||
attrs = [sgr_map[a] if a in sgr_map else a for a in attrs]
|
||||
out += '\x1b[' + (';'.join(attrs)) + 'm'
|
||||
else:
|
||||
out += self.rasp_holding
|
||||
self.rasp_holding = ''
|
||||
self.rasp_in_cs = False
|
||||
return out.encode('latin-1', 'replace')
|
||||
|
||||
def handle_text(self):
|
||||
try:
|
||||
text = os.read(self.fd, 1024)
|
||||
text = self.process_rasp_ansi(text)
|
||||
while len(text) > 0:
|
||||
take = min(len(text), 252)
|
||||
send_data(self.stream_id, text[:take])
|
||||
text = text[take:]
|
||||
except:
|
||||
#os.close(self.fd)
|
||||
os.kill(self.pid, signal.SIGTERM)
|
||||
self.pid = 0
|
||||
send_eos(self.stream_id)
|
||||
self.reset_after = time.time() + 10
|
||||
|
||||
def handle_timeout(self):
|
||||
if self.reset_after and self.reset_after < time.time():
|
||||
send_reset(self.stream_id)
|
||||
del sessions[self.stream_id]
|
||||
|
||||
def fileno(self):
|
||||
return self.fd
|
||||
|
||||
def process_drv_msg(stream_id, ptype, payload):
|
||||
if ptype == MSG_CONNECT:
|
||||
if payload == b'picmd':
|
||||
s = PiCmdSession(stream_id)
|
||||
sessions[stream_id] = s
|
||||
send_connect_response(stream_id, 0)
|
||||
else:
|
||||
send_connect_response(stream_id, 3)
|
||||
elif stream_id in sessions:
|
||||
s = sessions[stream_id]
|
||||
|
||||
if ptype == MSG_DATA:
|
||||
s.process_msg_data(payload)
|
||||
elif ptype == MSG_EOS:
|
||||
if s.pid:
|
||||
send_eos(s.stream_id)
|
||||
s.close()
|
||||
elif ptype == MSG_RESET:
|
||||
s.close()
|
||||
|
||||
done = False
|
||||
|
||||
try:
|
||||
idx = sys.argv.index('-ondemand')
|
||||
except ValueError:
|
||||
idx = -1
|
||||
|
||||
if idx != -1:
|
||||
fd = int(sys.argv[idx + 1])
|
||||
drv = socket.socket(fileno=fd)
|
||||
else:
|
||||
drv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
drv.connect(('localhost', 7110))
|
||||
drv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
|
||||
send_register_req(b'picmd')
|
||||
_, _, payload = wait_for_msg()
|
||||
if payload[0] != 1:
|
||||
logger.error('Unable to register picmd with driver, shutting down')
|
||||
drv.close()
|
||||
done = True
|
||||
|
||||
rbuf = b''
|
||||
|
||||
if not done:
|
||||
logger.info('picmd server is running')
|
||||
|
||||
while not done:
|
||||
sel_fds = [drv] + [s for s in sessions.values() if s.pid]
|
||||
if idx == -1:
|
||||
sel_fds.append(sys.stdin)
|
||||
rfd, wfd, xfd = select.select(sel_fds, [], [], 5.0)
|
||||
|
||||
for fd in rfd:
|
||||
if fd == sys.stdin:
|
||||
line = sys.stdin.readline()
|
||||
if not line or line.startswith('quit'):
|
||||
for s in sessions.values():
|
||||
s.close()
|
||||
drv.close()
|
||||
done = True
|
||||
elif fd == drv:
|
||||
buf = drv.recv(1024)
|
||||
if not buf:
|
||||
for s in sessions.values():
|
||||
s.close()
|
||||
drv.close()
|
||||
done = True
|
||||
else:
|
||||
rbuf += buf
|
||||
while True:
|
||||
if len(rbuf) < 9:
|
||||
break
|
||||
|
||||
(plen, stream_id, ptype) = struct.unpack('=IIB', rbuf[:9])
|
||||
if len(rbuf) < 9 + plen:
|
||||
break
|
||||
|
||||
rbuf = rbuf[9:]
|
||||
payload = rbuf[:plen]
|
||||
rbuf = rbuf[plen:]
|
||||
|
||||
process_drv_msg(stream_id, ptype, payload)
|
||||
else:
|
||||
fd.handle_text()
|
||||
|
||||
for s in sessions.values():
|
||||
s.handle_timeout()
|
||||
Binary file not shown.
Binary file not shown.
1
a314/software-amiga/pi_pistorm/build.bat
Normal file
1
a314/software-amiga/pi_pistorm/build.bat
Normal file
@@ -0,0 +1 @@
|
||||
vc pi.c -lamiga -o ../pi
|
||||
476
a314/software-amiga/pi_pistorm/pi.c
Normal file
476
a314/software-amiga/pi_pistorm/pi.c
Normal file
@@ -0,0 +1,476 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2021 Niklas Ekström
|
||||
*/
|
||||
|
||||
#include <exec/types.h>
|
||||
#include <exec/ports.h>
|
||||
#include <exec/tasks.h>
|
||||
#include <exec/memory.h>
|
||||
|
||||
#include <libraries/dos.h>
|
||||
#include <libraries/dosextens.h>
|
||||
|
||||
#include <proto/dos.h>
|
||||
#include <proto/exec.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <clib/alib_protos.h>
|
||||
#include <proto/expansion.h>
|
||||
#include <clib/expansion_protos.h>
|
||||
|
||||
#include "../../a314device/a314.h"
|
||||
#include "../../a314device/proto_a314.h"
|
||||
|
||||
#define PICMD_SERVICE_NAME "picmd"
|
||||
|
||||
#define ID_314_DISK (('3' << 24) | ('1' << 16) | ('4' << 8))
|
||||
|
||||
struct MsgPort *sync_mp;
|
||||
struct MsgPort *async_mp;
|
||||
|
||||
struct A314_IORequest *read_ior;
|
||||
struct A314_IORequest *sync_ior;
|
||||
|
||||
struct Library *A314Base;
|
||||
|
||||
struct FileHandle *con;
|
||||
|
||||
ULONG socket;
|
||||
|
||||
UBYTE arbuf[256];
|
||||
|
||||
struct StandardPacket sync_sp;
|
||||
struct StandardPacket wait_sp;
|
||||
|
||||
BOOL pending_a314_read = FALSE;
|
||||
BOOL pending_con_wait = FALSE;
|
||||
BOOL stream_closed = FALSE;
|
||||
|
||||
ULONG a314_addr = 0xFFFFFFFF;
|
||||
|
||||
//#define DEBUG printf
|
||||
#define DEBUG(...)
|
||||
|
||||
void put_con_sp(struct MsgPort *reply_port, struct StandardPacket *sp, LONG action, LONG arg1, LONG arg2, LONG arg3)
|
||||
{
|
||||
sp->sp_Msg.mn_Node.ln_Type = NT_MESSAGE;
|
||||
sp->sp_Msg.mn_Node.ln_Pri = 0;
|
||||
sp->sp_Msg.mn_Node.ln_Name = (char *)&(sp->sp_Pkt);
|
||||
sp->sp_Msg.mn_Length = sizeof(struct StandardPacket);
|
||||
sp->sp_Msg.mn_ReplyPort = reply_port;
|
||||
sp->sp_Pkt.dp_Link = &(sp->sp_Msg);
|
||||
sp->sp_Pkt.dp_Port = reply_port;
|
||||
sp->sp_Pkt.dp_Type = action;
|
||||
sp->sp_Pkt.dp_Arg1 = arg1;
|
||||
sp->sp_Pkt.dp_Arg2 = arg2;
|
||||
sp->sp_Pkt.dp_Arg3 = arg3;
|
||||
PutMsg(con->fh_Type, &(sp->sp_Msg));
|
||||
}
|
||||
|
||||
LONG set_screen_mode(LONG mode)
|
||||
{
|
||||
put_con_sp(sync_mp, &sync_sp, ACTION_SCREEN_MODE, mode, 0, 0);
|
||||
Wait(1L << sync_mp->mp_SigBit);
|
||||
GetMsg(sync_mp);
|
||||
return sync_sp.sp_Pkt.dp_Res1;
|
||||
}
|
||||
|
||||
LONG con_write(char *s, int length)
|
||||
{
|
||||
put_con_sp(sync_mp, &sync_sp, ACTION_WRITE, con->fh_Arg1, (LONG)s, length);
|
||||
Wait(1L << sync_mp->mp_SigBit);
|
||||
GetMsg(sync_mp);
|
||||
return sync_sp.sp_Pkt.dp_Res1;
|
||||
}
|
||||
|
||||
LONG con_read(char *s, int length)
|
||||
{
|
||||
put_con_sp(sync_mp, &sync_sp, ACTION_READ, con->fh_Arg1, (LONG)s, length);
|
||||
Wait(1L << sync_mp->mp_SigBit);
|
||||
GetMsg(sync_mp);
|
||||
return sync_sp.sp_Pkt.dp_Res1;
|
||||
}
|
||||
|
||||
void start_con_wait()
|
||||
{
|
||||
put_con_sp(async_mp, &wait_sp, ACTION_WAIT_CHAR, 100000, 0, 0);
|
||||
pending_con_wait = TRUE;
|
||||
}
|
||||
|
||||
void start_a314_cmd(struct MsgPort *reply_port, struct A314_IORequest *ior, UWORD cmd, char *buffer, int length)
|
||||
{
|
||||
ior->a314_Request.io_Message.mn_ReplyPort = reply_port;
|
||||
ior->a314_Request.io_Command = cmd;
|
||||
ior->a314_Request.io_Error = 0;
|
||||
ior->a314_Socket = socket;
|
||||
ior->a314_Buffer = buffer;
|
||||
ior->a314_Length = length;
|
||||
SendIO((struct IORequest *)ior);
|
||||
}
|
||||
|
||||
BYTE a314_connect(char *name)
|
||||
{
|
||||
socket = time(NULL);
|
||||
start_a314_cmd(sync_mp, sync_ior, A314_CONNECT, name, strlen(name));
|
||||
Wait(1L << sync_mp->mp_SigBit);
|
||||
GetMsg(sync_mp);
|
||||
return sync_ior->a314_Request.io_Error;
|
||||
}
|
||||
|
||||
BYTE a314_write(char *buffer, int length)
|
||||
{
|
||||
ULONG *bef = (ULONG *)buffer;
|
||||
DEBUG("Buf[0]: %.8X Buf[1]: %.8X\n", bef[0], bef[1]);
|
||||
DEBUG("Len: %d\n", length);
|
||||
start_a314_cmd(sync_mp, sync_ior, A314_WRITE, buffer, length);
|
||||
Wait(1L << sync_mp->mp_SigBit);
|
||||
GetMsg(sync_mp);
|
||||
return sync_ior->a314_Request.io_Error;
|
||||
}
|
||||
|
||||
BYTE a314_eos()
|
||||
{
|
||||
start_a314_cmd(sync_mp, sync_ior, A314_EOS, NULL, 0);
|
||||
Wait(1L << sync_mp->mp_SigBit);
|
||||
GetMsg(sync_mp);
|
||||
return sync_ior->a314_Request.io_Error;
|
||||
}
|
||||
|
||||
BYTE a314_reset()
|
||||
{
|
||||
start_a314_cmd(sync_mp, sync_ior, A314_RESET, NULL, 0);
|
||||
Wait(1L << sync_mp->mp_SigBit);
|
||||
GetMsg(sync_mp);
|
||||
return sync_ior->a314_Request.io_Error;
|
||||
}
|
||||
|
||||
void start_a314_read()
|
||||
{
|
||||
start_a314_cmd(async_mp, read_ior, A314_READ, arbuf, 255);
|
||||
pending_a314_read = TRUE;
|
||||
}
|
||||
|
||||
void handle_con_wait_completed()
|
||||
{
|
||||
DEBUG("handling con wait completed.\n");
|
||||
pending_con_wait = FALSE;
|
||||
|
||||
if (stream_closed)
|
||||
return;
|
||||
|
||||
if (wait_sp.sp_Pkt.dp_Res1 == DOSFALSE)
|
||||
{
|
||||
start_con_wait();
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char buf[64];
|
||||
int len = con_read(buf, sizeof(buf));
|
||||
|
||||
if (len == 0 || len == -1)
|
||||
{
|
||||
a314_reset();
|
||||
stream_closed = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
a314_write(buf, len);
|
||||
start_con_wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_a314_read_completed()
|
||||
{
|
||||
DEBUG("handling read completed.\n");
|
||||
pending_a314_read = FALSE;
|
||||
|
||||
if (stream_closed)
|
||||
return;
|
||||
|
||||
int res = read_ior->a314_Request.io_Error;
|
||||
if (res == A314_READ_OK)
|
||||
{
|
||||
UBYTE *p = read_ior->a314_Buffer;
|
||||
int len = read_ior->a314_Length;
|
||||
|
||||
con_write(p, len);
|
||||
start_a314_read();
|
||||
}
|
||||
else if (res == A314_READ_EOS)
|
||||
{
|
||||
a314_eos();
|
||||
stream_closed = TRUE;
|
||||
}
|
||||
else if (res == A314_READ_RESET)
|
||||
{
|
||||
stream_closed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
UBYTE *create_and_send_start_msg(int *buffer_len, BPTR current_dir, int argc, char **argv, short rows, short cols)
|
||||
{
|
||||
int buf_len = 6;
|
||||
|
||||
int component_count = 0;
|
||||
UBYTE *components[20];
|
||||
|
||||
DEBUG("casmm: SetupDir\n");
|
||||
if (current_dir != 0)
|
||||
{
|
||||
struct FileLock *fl = (struct FileLock *)BADDR(current_dir);
|
||||
struct DeviceList *dl = (struct DeviceList *)BADDR(fl->fl_Volume);
|
||||
|
||||
if (dl->dl_DiskType == ID_314_DISK)
|
||||
{
|
||||
struct FileInfoBlock *fib = AllocMem(sizeof(struct FileInfoBlock), 0);
|
||||
|
||||
BPTR lock = DupLock(current_dir);
|
||||
|
||||
while (lock != 0)
|
||||
{
|
||||
if (Examine(lock, fib) == 0)
|
||||
{
|
||||
UnLock(lock);
|
||||
break;
|
||||
}
|
||||
|
||||
int n = strlen(fib->fib_FileName);
|
||||
UBYTE *p = AllocMem(n + 1, 0);
|
||||
p[0] = (UBYTE)n;
|
||||
memcpy(&p[1], fib->fib_FileName, n);
|
||||
components[component_count++] = p;
|
||||
|
||||
buf_len += n + 1;
|
||||
|
||||
BPTR child = lock;
|
||||
lock = ParentDir(child);
|
||||
UnLock(child);
|
||||
}
|
||||
|
||||
FreeMem(fib, sizeof(struct FileInfoBlock));
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG("casmm: Stage 2\n");
|
||||
for (int i = 1; i < argc; i++)
|
||||
buf_len += strlen(argv[i]) + 1;
|
||||
|
||||
UBYTE *buffer = AllocMem(buf_len, MEMF_FAST);
|
||||
|
||||
UBYTE *p = buffer;
|
||||
|
||||
*(short *)p = rows;
|
||||
p += 2;
|
||||
*(short *)p = cols;
|
||||
p += 2;
|
||||
|
||||
DEBUG("casmm: Stage 3\n");
|
||||
DEBUG("p: %.8X\n", (ULONG)p);
|
||||
DEBUG("component count: %d\n", component_count);
|
||||
*p++ = (UBYTE)component_count;
|
||||
for (int i = 0; i < component_count; i++)
|
||||
{
|
||||
UBYTE *q = components[component_count - 1 - i];
|
||||
int n = *q;
|
||||
memcpy(p, q, n + 1);
|
||||
p += n + 1;
|
||||
FreeMem(q, n + 1);
|
||||
}
|
||||
|
||||
DEBUG("casmm: Stage 4\n");
|
||||
*p++ = (UBYTE)(argc - 1);
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
UBYTE *q = (UBYTE *)argv[i];
|
||||
int n = strlen(q);
|
||||
*p++ = (UBYTE)n;
|
||||
memcpy(p, q, n);
|
||||
p += n;
|
||||
}
|
||||
|
||||
DEBUG("casmm: Stage 5\n");
|
||||
ULONG buf_desc[2] = {(ULONG)buffer, buf_len};
|
||||
DEBUG("casmm: Stage 6\n");
|
||||
a314_write((char *)buf_desc, sizeof(buf_desc));
|
||||
|
||||
DEBUG("casmm: Stage 7\n");
|
||||
*buffer_len = buf_len;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ULONG board_addr = 0xFFFFFFFF;
|
||||
struct ExpansionBase *ExpansionBase = (struct ExpansionBase *)OpenLibrary((STRPTR)"expansion.library", 0L);
|
||||
|
||||
if (ExpansionBase == NULL) {
|
||||
printf("Failed to open expansion.library.\n");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
struct ConfigDev* cd = NULL;
|
||||
cd = (struct ConfigDev*)FindConfigDev(cd, 2011, 0xA3);
|
||||
if (cd != NULL)
|
||||
board_addr = (unsigned int)cd->cd_BoardAddr;
|
||||
else {
|
||||
printf ("Failed to find A314 emulation device.\n");
|
||||
CloseLibrary((struct Library *)ExpansionBase);
|
||||
return 0;
|
||||
}
|
||||
CloseLibrary((struct Library *)ExpansionBase);
|
||||
}
|
||||
printf ("A314 emulation device found at $%.8X\n", board_addr);
|
||||
a314_addr = board_addr;
|
||||
|
||||
sync_mp = CreatePort(NULL, 0);
|
||||
if (sync_mp == NULL)
|
||||
{
|
||||
printf("Unable to create sync reply message port\n");
|
||||
return 0;
|
||||
}
|
||||
DEBUG("Created sync reply message port.\n");
|
||||
|
||||
async_mp = CreatePort(NULL, 0);
|
||||
if (async_mp == NULL)
|
||||
{
|
||||
printf("Unable to create async reply message port\n");
|
||||
DeletePort(sync_mp);
|
||||
return 0;
|
||||
}
|
||||
DEBUG("Created async reply message port.\n");
|
||||
|
||||
sync_ior = (struct A314_IORequest *)CreateExtIO(sync_mp, sizeof(struct A314_IORequest));
|
||||
if (sync_ior == NULL)
|
||||
{
|
||||
printf("Unable to create io request for synchronous commands\n");
|
||||
DeletePort(async_mp);
|
||||
DeletePort(sync_mp);
|
||||
return 0;
|
||||
}
|
||||
DEBUG("Created IORequest for synchronous commands.\n");
|
||||
|
||||
read_ior = (struct A314_IORequest *)CreateExtIO(sync_mp, sizeof(struct A314_IORequest));
|
||||
if (read_ior == NULL)
|
||||
{
|
||||
printf("Unable to create io request for reads\n");
|
||||
DeleteExtIO((struct IORequest *)sync_ior);
|
||||
DeletePort(async_mp);
|
||||
DeletePort(sync_mp);
|
||||
return 0;
|
||||
}
|
||||
DEBUG("Created IORequest for reads.\n");
|
||||
|
||||
if (OpenDevice(A314_NAME, 0, (struct IORequest *)sync_ior, 0) != 0)
|
||||
{
|
||||
printf("Unable to open a314.device\n");
|
||||
DeleteExtIO((struct IORequest *)read_ior);
|
||||
DeleteExtIO((struct IORequest *)sync_ior);
|
||||
DeletePort(async_mp);
|
||||
DeletePort(sync_mp);
|
||||
return 0;
|
||||
}
|
||||
DEBUG("Opened a314.device.\n");
|
||||
|
||||
memcpy(read_ior, sync_ior, sizeof(struct A314_IORequest));
|
||||
|
||||
A314Base = &(sync_ior->a314_Request.io_Device->dd_Library);
|
||||
|
||||
if (a314_connect(PICMD_SERVICE_NAME) != A314_CONNECT_OK)
|
||||
{
|
||||
printf("Unable to connect to picmd service\n");
|
||||
CloseDevice((struct IORequest *)sync_ior);
|
||||
DeleteExtIO((struct IORequest *)read_ior);
|
||||
DeleteExtIO((struct IORequest *)sync_ior);
|
||||
DeletePort(async_mp);
|
||||
DeletePort(sync_mp);
|
||||
return 0;
|
||||
}
|
||||
DEBUG("Connected to picmd service.\n");
|
||||
|
||||
struct Process *proc = (struct Process *)FindTask(NULL);
|
||||
con = (struct FileHandle *)BADDR(proc->pr_CIS);
|
||||
|
||||
set_screen_mode(DOSTRUE);
|
||||
DEBUG("Set screen mode.\n");
|
||||
|
||||
con_write("\x9b" "0 q", 4);
|
||||
|
||||
int len = con_read(arbuf, 32); // "\x9b" "1;1;33;77 r"
|
||||
if (len < 10 || arbuf[len - 1] != 'r')
|
||||
{
|
||||
printf("Failure to receive window bounds report\n");
|
||||
set_screen_mode(DOSFALSE);
|
||||
a314_reset();
|
||||
CloseDevice((struct IORequest *)sync_ior);
|
||||
DeleteExtIO((struct IORequest *)read_ior);
|
||||
DeleteExtIO((struct IORequest *)sync_ior);
|
||||
DeletePort(async_mp);
|
||||
DeletePort(sync_mp);
|
||||
return 0;
|
||||
}
|
||||
DEBUG("Received window bounds report.\n");
|
||||
|
||||
con_write("\x9b" "12{", 4);
|
||||
|
||||
int start = 5;
|
||||
int ind = start;
|
||||
while (arbuf[ind] != ';')
|
||||
ind++;
|
||||
arbuf[ind] = 0;
|
||||
int rows = atoi(arbuf + start);
|
||||
ind++;
|
||||
start = ind;
|
||||
while (arbuf[ind] != ' ')
|
||||
ind++;
|
||||
arbuf[ind] = 0;
|
||||
int cols = atoi(arbuf + start);
|
||||
|
||||
int start_msg_len;
|
||||
DEBUG("Sending start message.\n");
|
||||
UBYTE *start_msg = create_and_send_start_msg(&start_msg_len, proc->pr_CurrentDir, argc, argv, (short)rows, (short)cols);
|
||||
DEBUG("Sent start message.\n");
|
||||
|
||||
DEBUG("Started con wait.\n");
|
||||
start_con_wait();
|
||||
DEBUG("Started A314 read.\n");
|
||||
start_a314_read();
|
||||
|
||||
ULONG portsig = 1L << async_mp->mp_SigBit;
|
||||
|
||||
DEBUG("Entering main loop.\n");
|
||||
while (TRUE)
|
||||
{
|
||||
ULONG signal = Wait(portsig | SIGBREAKF_CTRL_C);
|
||||
|
||||
if (signal & portsig)
|
||||
{
|
||||
struct Message *msg;
|
||||
while (msg = GetMsg(async_mp))
|
||||
{
|
||||
if (msg == (struct Message *)&wait_sp)
|
||||
handle_con_wait_completed();
|
||||
else if (msg == (struct Message *)read_ior)
|
||||
handle_a314_read_completed();
|
||||
}
|
||||
}
|
||||
|
||||
if (stream_closed && !pending_a314_read && !pending_con_wait)
|
||||
break;
|
||||
}
|
||||
|
||||
set_screen_mode(DOSFALSE);
|
||||
|
||||
FreeMem(start_msg, start_msg_len);
|
||||
|
||||
CloseDevice((struct IORequest *)sync_ior);
|
||||
DeleteExtIO((struct IORequest *)read_ior);
|
||||
DeleteExtIO((struct IORequest *)sync_ior);
|
||||
DeletePort(async_mp);
|
||||
DeletePort(sync_mp);
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user