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:
beeanyew
2021-05-18 05:15:42 +02:00
parent df3221c950
commit e7e393b324
8 changed files with 884 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
{
"devices": {
"PI0": {
"volume": "PiDisk",
"path": "/home/pi/a314shared"
}
}
}

8
a314/files_pi/picmd.conf Normal file
View 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
View 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.

View File

@@ -0,0 +1 @@
vc pi.c -lamiga -o ../pi

View 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.