]> git.sesse.net Git - pistorm/blob - a314/software-amiga/pi_pistorm/pi.c
Adapt picmd to work on PiStorm + A314 emulation
[pistorm] / a314 / software-amiga / pi_pistorm / pi.c
1 /*
2  * Copyright (c) 2018-2021 Niklas Ekström
3  */
4
5 #include <exec/types.h>
6 #include <exec/ports.h>
7 #include <exec/tasks.h>
8 #include <exec/memory.h>
9
10 #include <libraries/dos.h>
11 #include <libraries/dosextens.h>
12
13 #include <proto/dos.h>
14 #include <proto/exec.h>
15
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <time.h>
20
21 #include <clib/alib_protos.h>
22 #include <proto/expansion.h>
23 #include <clib/expansion_protos.h>
24
25 #include "../../a314device/a314.h"
26 #include "../../a314device/proto_a314.h"
27
28 #define PICMD_SERVICE_NAME "picmd"
29
30 #define ID_314_DISK (('3' << 24) | ('1' << 16) | ('4' << 8))
31
32 struct MsgPort *sync_mp;
33 struct MsgPort *async_mp;
34
35 struct A314_IORequest *read_ior;
36 struct A314_IORequest *sync_ior;
37
38 struct Library *A314Base;
39
40 struct FileHandle *con;
41
42 ULONG socket;
43
44 UBYTE arbuf[256];
45
46 struct StandardPacket sync_sp;
47 struct StandardPacket wait_sp;
48
49 BOOL pending_a314_read = FALSE;
50 BOOL pending_con_wait = FALSE;
51 BOOL stream_closed = FALSE;
52
53 ULONG a314_addr = 0xFFFFFFFF;
54
55 //#define DEBUG printf
56 #define DEBUG(...)
57
58 void put_con_sp(struct MsgPort *reply_port, struct StandardPacket *sp, LONG action, LONG arg1, LONG arg2, LONG arg3)
59 {
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));
72 }
73
74 LONG set_screen_mode(LONG mode)
75 {
76         put_con_sp(sync_mp, &sync_sp, ACTION_SCREEN_MODE, mode, 0, 0);
77         Wait(1L << sync_mp->mp_SigBit);
78         GetMsg(sync_mp);
79         return sync_sp.sp_Pkt.dp_Res1;
80 }
81
82 LONG con_write(char *s, int length)
83 {
84         put_con_sp(sync_mp, &sync_sp, ACTION_WRITE, con->fh_Arg1, (LONG)s, length);
85         Wait(1L << sync_mp->mp_SigBit);
86         GetMsg(sync_mp);
87         return sync_sp.sp_Pkt.dp_Res1;
88 }
89
90 LONG con_read(char *s, int length)
91 {
92         put_con_sp(sync_mp, &sync_sp, ACTION_READ, con->fh_Arg1, (LONG)s, length);
93         Wait(1L << sync_mp->mp_SigBit);
94         GetMsg(sync_mp);
95         return sync_sp.sp_Pkt.dp_Res1;
96 }
97
98 void start_con_wait()
99 {
100         put_con_sp(async_mp, &wait_sp, ACTION_WAIT_CHAR, 100000, 0, 0);
101         pending_con_wait = TRUE;
102 }
103
104 void start_a314_cmd(struct MsgPort *reply_port, struct A314_IORequest *ior, UWORD cmd, char *buffer, int length)
105 {
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);
113 }
114
115 BYTE a314_connect(char *name)
116 {
117         socket = time(NULL);
118         start_a314_cmd(sync_mp, sync_ior, A314_CONNECT, name, strlen(name));
119         Wait(1L << sync_mp->mp_SigBit);
120         GetMsg(sync_mp);
121         return sync_ior->a314_Request.io_Error;
122 }
123
124 BYTE a314_write(char *buffer, int length)
125 {
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);
131         GetMsg(sync_mp);
132         return sync_ior->a314_Request.io_Error;
133 }
134
135 BYTE a314_eos()
136 {
137         start_a314_cmd(sync_mp, sync_ior, A314_EOS, NULL, 0);
138         Wait(1L << sync_mp->mp_SigBit);
139         GetMsg(sync_mp);
140         return sync_ior->a314_Request.io_Error;
141 }
142
143 BYTE a314_reset()
144 {
145         start_a314_cmd(sync_mp, sync_ior, A314_RESET, NULL, 0);
146         Wait(1L << sync_mp->mp_SigBit);
147         GetMsg(sync_mp);
148         return sync_ior->a314_Request.io_Error;
149 }
150
151 void start_a314_read()
152 {
153         start_a314_cmd(async_mp, read_ior, A314_READ, arbuf, 255);
154         pending_a314_read = TRUE;
155 }
156
157 void handle_con_wait_completed()
158 {
159         DEBUG("handling con wait completed.\n");
160         pending_con_wait = FALSE;
161
162         if (stream_closed)
163                 return;
164
165         if (wait_sp.sp_Pkt.dp_Res1 == DOSFALSE)
166         {
167                 start_con_wait();
168         }
169         else
170         {
171                 unsigned char buf[64];
172                 int len = con_read(buf, sizeof(buf));
173
174                 if (len == 0 || len == -1)
175                 {
176                         a314_reset();
177                         stream_closed = TRUE;
178                 }
179                 else
180                 {
181                         a314_write(buf, len);
182                         start_con_wait();
183                 }
184         }
185 }
186
187 void handle_a314_read_completed()
188 {
189         DEBUG("handling read completed.\n");
190         pending_a314_read = FALSE;
191
192         if (stream_closed)
193                 return;
194
195         int res = read_ior->a314_Request.io_Error;
196         if (res == A314_READ_OK)
197         {
198                 UBYTE *p = read_ior->a314_Buffer;
199                 int len = read_ior->a314_Length;
200
201                 con_write(p, len);
202                 start_a314_read();
203         }
204         else if (res == A314_READ_EOS)
205         {
206                 a314_eos();
207                 stream_closed = TRUE;
208         }
209         else if (res == A314_READ_RESET)
210         {
211                 stream_closed = TRUE;
212         }
213 }
214
215 UBYTE *create_and_send_start_msg(int *buffer_len, BPTR current_dir, int argc, char **argv, short rows, short cols)
216 {
217         int buf_len = 6;
218
219         int component_count = 0;
220         UBYTE *components[20];
221
222         DEBUG("casmm: SetupDir\n");
223         if (current_dir != 0)
224         {
225                 struct FileLock *fl = (struct FileLock *)BADDR(current_dir);
226                 struct DeviceList *dl = (struct DeviceList *)BADDR(fl->fl_Volume);
227
228                 if (dl->dl_DiskType == ID_314_DISK)
229                 {
230                         struct FileInfoBlock *fib = AllocMem(sizeof(struct FileInfoBlock), 0);
231
232                         BPTR lock = DupLock(current_dir);
233
234                         while (lock != 0)
235                         {
236                                 if (Examine(lock, fib) == 0)
237                                 {
238                                         UnLock(lock);
239                                         break;
240                                 }
241
242                                 int n = strlen(fib->fib_FileName);
243                                 UBYTE *p = AllocMem(n + 1, 0);
244                                 p[0] = (UBYTE)n;
245                                 memcpy(&p[1], fib->fib_FileName, n);
246                                 components[component_count++] = p;
247
248                                 buf_len += n + 1;
249
250                                 BPTR child = lock;
251                                 lock = ParentDir(child);
252                                 UnLock(child);
253                         }
254
255                         FreeMem(fib, sizeof(struct FileInfoBlock));
256                 }
257         }
258
259         DEBUG("casmm: Stage 2\n");
260         for (int i = 1; i < argc; i++)
261                 buf_len += strlen(argv[i]) + 1;
262
263         UBYTE *buffer = AllocMem(buf_len, MEMF_FAST);
264
265         UBYTE *p = buffer;
266
267         *(short *)p = rows;
268         p += 2;
269         *(short *)p = cols;
270         p += 2;
271
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++)
277         {
278                 UBYTE *q = components[component_count - 1 - i];
279                 int n = *q;
280                 memcpy(p, q, n + 1);
281                 p += n + 1;
282                 FreeMem(q, n + 1);
283         }
284
285         DEBUG("casmm: Stage 4\n");
286         *p++ = (UBYTE)(argc - 1);
287         for (int i = 1; i < argc; i++)
288         {
289                 UBYTE *q = (UBYTE *)argv[i];
290                 int n = strlen(q);
291                 *p++ = (UBYTE)n;
292                 memcpy(p, q, n);
293                 p += n;
294         }
295
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));
300
301         DEBUG("casmm: Stage 7\n");
302         *buffer_len = buf_len;
303         return buffer;
304 }
305
306 int main(int argc, char **argv)
307 {
308         ULONG board_addr = 0xFFFFFFFF;
309     struct ExpansionBase *ExpansionBase = (struct ExpansionBase *)OpenLibrary((STRPTR)"expansion.library", 0L);
310
311     if (ExpansionBase == NULL) {
312             printf("Failed to open expansion.library.\n");
313                 return 0;
314         }
315         else {
316                 struct ConfigDev* cd = NULL;
317                 cd = (struct ConfigDev*)FindConfigDev(cd, 2011, 0xA3);
318                 if (cd != NULL)
319                         board_addr = (unsigned int)cd->cd_BoardAddr;
320                 else {
321                         printf ("Failed to find A314 emulation device.\n");
322                 CloseLibrary((struct Library *)ExpansionBase);
323                         return 0;
324                 }
325         CloseLibrary((struct Library *)ExpansionBase);
326         }
327         printf ("A314 emulation device found at $%.8X\n", board_addr);
328         a314_addr = board_addr;
329
330         sync_mp = CreatePort(NULL, 0);
331         if (sync_mp == NULL)
332         {
333                 printf("Unable to create sync reply message port\n");
334                 return 0;
335         }
336         DEBUG("Created sync reply message port.\n");
337
338         async_mp = CreatePort(NULL, 0);
339         if (async_mp == NULL)
340         {
341                 printf("Unable to create async reply message port\n");
342                 DeletePort(sync_mp);
343                 return 0;
344         }
345         DEBUG("Created async reply message port.\n");
346
347         sync_ior = (struct A314_IORequest *)CreateExtIO(sync_mp, sizeof(struct A314_IORequest));
348         if (sync_ior == NULL)
349         {
350                 printf("Unable to create io request for synchronous commands\n");
351                 DeletePort(async_mp);
352                 DeletePort(sync_mp);
353                 return 0;
354         }
355         DEBUG("Created IORequest for synchronous commands.\n");
356
357         read_ior = (struct A314_IORequest *)CreateExtIO(sync_mp, sizeof(struct A314_IORequest));
358         if (read_ior == NULL)
359         {
360                 printf("Unable to create io request for reads\n");
361                 DeleteExtIO((struct IORequest *)sync_ior);
362                 DeletePort(async_mp);
363                 DeletePort(sync_mp);
364                 return 0;
365         }
366         DEBUG("Created IORequest for reads.\n");
367
368         if (OpenDevice(A314_NAME, 0, (struct IORequest *)sync_ior, 0) != 0)
369         {
370                 printf("Unable to open a314.device\n");
371                 DeleteExtIO((struct IORequest *)read_ior);
372                 DeleteExtIO((struct IORequest *)sync_ior);
373                 DeletePort(async_mp);
374                 DeletePort(sync_mp);
375                 return 0;
376         }
377         DEBUG("Opened a314.device.\n");
378
379         memcpy(read_ior, sync_ior, sizeof(struct A314_IORequest));
380
381         A314Base = &(sync_ior->a314_Request.io_Device->dd_Library);
382
383         if (a314_connect(PICMD_SERVICE_NAME) != A314_CONNECT_OK)
384         {
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);
390                 DeletePort(sync_mp);
391                 return 0;
392         }
393         DEBUG("Connected to picmd service.\n");
394
395         struct Process *proc = (struct Process *)FindTask(NULL);
396         con = (struct FileHandle *)BADDR(proc->pr_CIS);
397
398         set_screen_mode(DOSTRUE);
399         DEBUG("Set screen mode.\n");
400
401         con_write("\x9b" "0 q", 4);
402
403         int len = con_read(arbuf, 32);  // "\x9b" "1;1;33;77 r"
404         if (len < 10 || arbuf[len - 1] != 'r')
405         {
406                 printf("Failure to receive window bounds report\n");
407                 set_screen_mode(DOSFALSE);
408                 a314_reset();
409                 CloseDevice((struct IORequest *)sync_ior);
410                 DeleteExtIO((struct IORequest *)read_ior);
411                 DeleteExtIO((struct IORequest *)sync_ior);
412                 DeletePort(async_mp);
413                 DeletePort(sync_mp);
414                 return 0;
415         }
416         DEBUG("Received window bounds report.\n");
417
418         con_write("\x9b" "12{", 4);
419
420         int start = 5;
421         int ind = start;
422         while (arbuf[ind] != ';')
423                 ind++;
424         arbuf[ind] = 0;
425         int rows = atoi(arbuf + start);
426         ind++;
427         start = ind;
428         while (arbuf[ind] != ' ')
429                 ind++;
430         arbuf[ind] = 0;
431         int cols = atoi(arbuf + start);
432
433         int start_msg_len;
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");
437
438         DEBUG("Started con wait.\n");
439         start_con_wait();
440         DEBUG("Started A314 read.\n");
441         start_a314_read();
442
443         ULONG portsig = 1L << async_mp->mp_SigBit;
444
445         DEBUG("Entering main loop.\n");
446         while (TRUE)
447         {
448                 ULONG signal = Wait(portsig | SIGBREAKF_CTRL_C);
449
450                 if (signal & portsig)
451                 {
452                         struct Message *msg;
453                         while (msg = GetMsg(async_mp))
454                         {
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();
459                         }
460                 }
461
462                 if (stream_closed && !pending_a314_read && !pending_con_wait)
463                         break;
464         }
465
466         set_screen_mode(DOSFALSE);
467
468         FreeMem(start_msg, start_msg_len);
469
470         CloseDevice((struct IORequest *)sync_ior);
471         DeleteExtIO((struct IORequest *)read_ior);
472         DeleteExtIO((struct IORequest *)sync_ior);
473         DeletePort(async_mp);
474         DeletePort(sync_mp);
475         return 0;
476 }