2 * Copyright (c) 2018-2021 Niklas Ekström
5 #include <exec/types.h>
6 #include <exec/ports.h>
7 #include <exec/tasks.h>
8 #include <exec/memory.h>
10 #include <libraries/dos.h>
11 #include <libraries/dosextens.h>
13 #include <proto/dos.h>
14 #include <proto/exec.h>
21 #include <clib/alib_protos.h>
22 #include <proto/expansion.h>
23 #include <clib/expansion_protos.h>
25 #include "../../a314device/a314.h"
26 #include "../../a314device/proto_a314.h"
28 #define PICMD_SERVICE_NAME "picmd"
30 #define ID_314_DISK (('3' << 24) | ('1' << 16) | ('4' << 8))
32 struct MsgPort *sync_mp;
33 struct MsgPort *async_mp;
35 struct A314_IORequest *read_ior;
36 struct A314_IORequest *sync_ior;
38 struct Library *A314Base;
40 struct FileHandle *con;
46 struct StandardPacket sync_sp;
47 struct StandardPacket wait_sp;
49 BOOL pending_a314_read = FALSE;
50 BOOL pending_con_wait = FALSE;
51 BOOL stream_closed = FALSE;
53 ULONG a314_addr = 0xFFFFFFFF;
55 //#define DEBUG printf
58 void put_con_sp(struct MsgPort *reply_port, struct StandardPacket *sp, LONG action, LONG arg1, LONG arg2, LONG arg3)
60 sp->sp_Msg.mn_Node.ln_Type = NT_MESSAGE;
61 sp->sp_Msg.mn_Node.ln_Pri = 0;
62 sp->sp_Msg.mn_Node.ln_Name = (char *)&(sp->sp_Pkt);
63 sp->sp_Msg.mn_Length = sizeof(struct StandardPacket);
64 sp->sp_Msg.mn_ReplyPort = reply_port;
65 sp->sp_Pkt.dp_Link = &(sp->sp_Msg);
66 sp->sp_Pkt.dp_Port = reply_port;
67 sp->sp_Pkt.dp_Type = action;
68 sp->sp_Pkt.dp_Arg1 = arg1;
69 sp->sp_Pkt.dp_Arg2 = arg2;
70 sp->sp_Pkt.dp_Arg3 = arg3;
71 PutMsg(con->fh_Type, &(sp->sp_Msg));
74 LONG set_screen_mode(LONG mode)
76 put_con_sp(sync_mp, &sync_sp, ACTION_SCREEN_MODE, mode, 0, 0);
77 Wait(1L << sync_mp->mp_SigBit);
79 return sync_sp.sp_Pkt.dp_Res1;
82 LONG con_write(char *s, int length)
84 put_con_sp(sync_mp, &sync_sp, ACTION_WRITE, con->fh_Arg1, (LONG)s, length);
85 Wait(1L << sync_mp->mp_SigBit);
87 return sync_sp.sp_Pkt.dp_Res1;
90 LONG con_read(char *s, int length)
92 put_con_sp(sync_mp, &sync_sp, ACTION_READ, con->fh_Arg1, (LONG)s, length);
93 Wait(1L << sync_mp->mp_SigBit);
95 return sync_sp.sp_Pkt.dp_Res1;
100 put_con_sp(async_mp, &wait_sp, ACTION_WAIT_CHAR, 100000, 0, 0);
101 pending_con_wait = TRUE;
104 void start_a314_cmd(struct MsgPort *reply_port, struct A314_IORequest *ior, UWORD cmd, char *buffer, int length)
106 ior->a314_Request.io_Message.mn_ReplyPort = reply_port;
107 ior->a314_Request.io_Command = cmd;
108 ior->a314_Request.io_Error = 0;
109 ior->a314_Socket = socket;
110 ior->a314_Buffer = buffer;
111 ior->a314_Length = length;
112 SendIO((struct IORequest *)ior);
115 BYTE a314_connect(char *name)
118 start_a314_cmd(sync_mp, sync_ior, A314_CONNECT, name, strlen(name));
119 Wait(1L << sync_mp->mp_SigBit);
121 return sync_ior->a314_Request.io_Error;
124 BYTE a314_write(char *buffer, int length)
126 ULONG *bef = (ULONG *)buffer;
127 DEBUG("Buf[0]: %.8X Buf[1]: %.8X\n", bef[0], bef[1]);
128 DEBUG("Len: %d\n", length);
129 start_a314_cmd(sync_mp, sync_ior, A314_WRITE, buffer, length);
130 Wait(1L << sync_mp->mp_SigBit);
132 return sync_ior->a314_Request.io_Error;
137 start_a314_cmd(sync_mp, sync_ior, A314_EOS, NULL, 0);
138 Wait(1L << sync_mp->mp_SigBit);
140 return sync_ior->a314_Request.io_Error;
145 start_a314_cmd(sync_mp, sync_ior, A314_RESET, NULL, 0);
146 Wait(1L << sync_mp->mp_SigBit);
148 return sync_ior->a314_Request.io_Error;
151 void start_a314_read()
153 start_a314_cmd(async_mp, read_ior, A314_READ, arbuf, 255);
154 pending_a314_read = TRUE;
157 void handle_con_wait_completed()
159 DEBUG("handling con wait completed.\n");
160 pending_con_wait = FALSE;
165 if (wait_sp.sp_Pkt.dp_Res1 == DOSFALSE)
171 unsigned char buf[64];
172 int len = con_read(buf, sizeof(buf));
174 if (len == 0 || len == -1)
177 stream_closed = TRUE;
181 a314_write(buf, len);
187 void handle_a314_read_completed()
189 DEBUG("handling read completed.\n");
190 pending_a314_read = FALSE;
195 int res = read_ior->a314_Request.io_Error;
196 if (res == A314_READ_OK)
198 UBYTE *p = read_ior->a314_Buffer;
199 int len = read_ior->a314_Length;
204 else if (res == A314_READ_EOS)
207 stream_closed = TRUE;
209 else if (res == A314_READ_RESET)
211 stream_closed = TRUE;
215 UBYTE *create_and_send_start_msg(int *buffer_len, BPTR current_dir, int argc, char **argv, short rows, short cols)
219 int component_count = 0;
220 UBYTE *components[20];
222 DEBUG("casmm: SetupDir\n");
223 if (current_dir != 0)
225 struct FileLock *fl = (struct FileLock *)BADDR(current_dir);
226 struct DeviceList *dl = (struct DeviceList *)BADDR(fl->fl_Volume);
228 if (dl->dl_DiskType == ID_314_DISK)
230 struct FileInfoBlock *fib = AllocMem(sizeof(struct FileInfoBlock), 0);
232 BPTR lock = DupLock(current_dir);
236 if (Examine(lock, fib) == 0)
242 int n = strlen(fib->fib_FileName);
243 UBYTE *p = AllocMem(n + 1, 0);
245 memcpy(&p[1], fib->fib_FileName, n);
246 components[component_count++] = p;
251 lock = ParentDir(child);
255 FreeMem(fib, sizeof(struct FileInfoBlock));
259 DEBUG("casmm: Stage 2\n");
260 for (int i = 1; i < argc; i++)
261 buf_len += strlen(argv[i]) + 1;
263 UBYTE *buffer = AllocMem(buf_len, MEMF_FAST);
272 DEBUG("casmm: Stage 3\n");
273 DEBUG("p: %.8X\n", (ULONG)p);
274 DEBUG("component count: %d\n", component_count);
275 *p++ = (UBYTE)component_count;
276 for (int i = 0; i < component_count; i++)
278 UBYTE *q = components[component_count - 1 - i];
285 DEBUG("casmm: Stage 4\n");
286 *p++ = (UBYTE)(argc - 1);
287 for (int i = 1; i < argc; i++)
289 UBYTE *q = (UBYTE *)argv[i];
296 DEBUG("casmm: Stage 5\n");
297 ULONG buf_desc[2] = {(ULONG)buffer, buf_len};
298 DEBUG("casmm: Stage 6\n");
299 a314_write((char *)buf_desc, sizeof(buf_desc));
301 DEBUG("casmm: Stage 7\n");
302 *buffer_len = buf_len;
306 int main(int argc, char **argv)
308 ULONG board_addr = 0xFFFFFFFF;
309 struct ExpansionBase *ExpansionBase = (struct ExpansionBase *)OpenLibrary((STRPTR)"expansion.library", 0L);
311 if (ExpansionBase == NULL) {
312 printf("Failed to open expansion.library.\n");
316 struct ConfigDev* cd = NULL;
317 cd = (struct ConfigDev*)FindConfigDev(cd, 2011, 0xA3);
319 board_addr = (unsigned int)cd->cd_BoardAddr;
321 printf ("Failed to find A314 emulation device.\n");
322 CloseLibrary((struct Library *)ExpansionBase);
325 CloseLibrary((struct Library *)ExpansionBase);
327 printf ("A314 emulation device found at $%.8X\n", board_addr);
328 a314_addr = board_addr;
330 sync_mp = CreatePort(NULL, 0);
333 printf("Unable to create sync reply message port\n");
336 DEBUG("Created sync reply message port.\n");
338 async_mp = CreatePort(NULL, 0);
339 if (async_mp == NULL)
341 printf("Unable to create async reply message port\n");
345 DEBUG("Created async reply message port.\n");
347 sync_ior = (struct A314_IORequest *)CreateExtIO(sync_mp, sizeof(struct A314_IORequest));
348 if (sync_ior == NULL)
350 printf("Unable to create io request for synchronous commands\n");
351 DeletePort(async_mp);
355 DEBUG("Created IORequest for synchronous commands.\n");
357 read_ior = (struct A314_IORequest *)CreateExtIO(sync_mp, sizeof(struct A314_IORequest));
358 if (read_ior == NULL)
360 printf("Unable to create io request for reads\n");
361 DeleteExtIO((struct IORequest *)sync_ior);
362 DeletePort(async_mp);
366 DEBUG("Created IORequest for reads.\n");
368 if (OpenDevice(A314_NAME, 0, (struct IORequest *)sync_ior, 0) != 0)
370 printf("Unable to open a314.device\n");
371 DeleteExtIO((struct IORequest *)read_ior);
372 DeleteExtIO((struct IORequest *)sync_ior);
373 DeletePort(async_mp);
377 DEBUG("Opened a314.device.\n");
379 memcpy(read_ior, sync_ior, sizeof(struct A314_IORequest));
381 A314Base = &(sync_ior->a314_Request.io_Device->dd_Library);
383 if (a314_connect(PICMD_SERVICE_NAME) != A314_CONNECT_OK)
385 printf("Unable to connect to picmd service\n");
386 CloseDevice((struct IORequest *)sync_ior);
387 DeleteExtIO((struct IORequest *)read_ior);
388 DeleteExtIO((struct IORequest *)sync_ior);
389 DeletePort(async_mp);
393 DEBUG("Connected to picmd service.\n");
395 struct Process *proc = (struct Process *)FindTask(NULL);
396 con = (struct FileHandle *)BADDR(proc->pr_CIS);
398 set_screen_mode(DOSTRUE);
399 DEBUG("Set screen mode.\n");
401 con_write("\x9b" "0 q", 4);
403 int len = con_read(arbuf, 32); // "\x9b" "1;1;33;77 r"
404 if (len < 10 || arbuf[len - 1] != 'r')
406 printf("Failure to receive window bounds report\n");
407 set_screen_mode(DOSFALSE);
409 CloseDevice((struct IORequest *)sync_ior);
410 DeleteExtIO((struct IORequest *)read_ior);
411 DeleteExtIO((struct IORequest *)sync_ior);
412 DeletePort(async_mp);
416 DEBUG("Received window bounds report.\n");
418 con_write("\x9b" "12{", 4);
422 while (arbuf[ind] != ';')
425 int rows = atoi(arbuf + start);
428 while (arbuf[ind] != ' ')
431 int cols = atoi(arbuf + start);
434 DEBUG("Sending start message.\n");
435 UBYTE *start_msg = create_and_send_start_msg(&start_msg_len, proc->pr_CurrentDir, argc, argv, (short)rows, (short)cols);
436 DEBUG("Sent start message.\n");
438 DEBUG("Started con wait.\n");
440 DEBUG("Started A314 read.\n");
443 ULONG portsig = 1L << async_mp->mp_SigBit;
445 DEBUG("Entering main loop.\n");
448 ULONG signal = Wait(portsig | SIGBREAKF_CTRL_C);
450 if (signal & portsig)
453 while (msg = GetMsg(async_mp))
455 if (msg == (struct Message *)&wait_sp)
456 handle_con_wait_completed();
457 else if (msg == (struct Message *)read_ior)
458 handle_a314_read_completed();
462 if (stream_closed && !pending_a314_read && !pending_con_wait)
466 set_screen_mode(DOSFALSE);
468 FreeMem(start_msg, start_msg_len);
470 CloseDevice((struct IORequest *)sync_ior);
471 DeleteExtIO((struct IORequest *)read_ior);
472 DeleteExtIO((struct IORequest *)sync_ior);
473 DeletePort(async_mp);