This source file includes following definitions.
- ta_flush
- ta_push
- ta_peek
- ta_get
- opc_reset
- check_attn_key
- console_init
- console_exit
- opc_autoinput_set
- clear_opc_autoinput
- add_opc_autoinput
- opc_autoinput_show
- console_attn
- console_attn_idx
- newlineOff
- newlineOn
- handleRCP
- sendConsole
- consoleProcessIdx
- consoleProcess
- opc_iom_cmd
- opc_svc
- opc_show_nunits
- opc_set_nunits
- opc_set_config
- opc_show_config
- opc_show_device_name
- opc_set_device_name
- opc_set_console_port
- opc_show_console_port
- opc_set_console_address
- opc_show_console_address
- opc_set_console_pw
- opc_show_console_pw
- console_putstr
- consolePutchar0
- console_putchar
- consoleConnectPrompt
- startRemoteConsole
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 #include <stdio.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #ifndef __MINGW64__
37 # ifndef __MINGW32__
38 # include <termios.h>
39 # endif
40 #endif
41 #include <ctype.h>
42
43 #include "dps8.h"
44 #include "dps8_iom.h"
45 #include "dps8_sys.h"
46 #include "dps8_console.h"
47 #include "dps8_faults.h"
48 #include "dps8_scu.h"
49 #include "dps8_cable.h"
50 #include "dps8_cpu.h"
51 #include "dps8_mt.h"
52 #include "dps8_disk.h"
53 #include "dps8_utils.h"
54 #ifdef LOCKLESS
55 # include "threadz.h"
56 #endif
57
58 #include "libtelnet.h"
59 #ifdef CONSOLE_FIX
60 # include "threadz.h"
61 #endif
62
63 #ifdef SIM_NAME
64 # undef SIM_NAME
65 #endif
66 #define SIM_NAME "DPS8M"
67
68 #define DBG_CTR 1
69 #define ASSUME0 0
70
71 #ifdef TESTING
72 # undef realloc
73 # undef FREE
74 # define FREE(p) free(p)
75 # define realloc trealloc
76 #endif
77
78
79
80
81
82
83 static t_stat opc_reset (DEVICE * dptr);
84 static t_stat opc_show_nunits (FILE *st, UNIT *uptr, int val,
85 const void *desc);
86 static t_stat opc_set_nunits (UNIT * uptr, int32 value, const char * cptr,
87 void * desc);
88 static t_stat opc_autoinput_set (UNIT *uptr, int32 val, const char *cptr,
89 void *desc);
90 static t_stat opc_autoinput_show (FILE *st, UNIT *uptr, int val,
91 const void *desc);
92 static t_stat opc_set_config (UNUSED UNIT * uptr, UNUSED int32 value,
93 const char * cptr, UNUSED void * desc);
94 static t_stat opc_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
95 UNUSED int val, UNUSED const void * desc);
96 static t_stat opc_set_console_port (UNIT * uptr, UNUSED int32 value,
97 const char * cptr, UNUSED void * desc);
98 static t_stat opc_show_console_port (UNUSED FILE * st, UNIT * uptr,
99 UNUSED int val, UNUSED const void * desc);
100 static t_stat opc_set_console_address (UNIT * uptr, UNUSED int32 value,
101 const char * cptr, UNUSED void * desc);
102 static t_stat opc_show_console_address (UNUSED FILE * st, UNIT * uptr,
103 UNUSED int val, UNUSED const void * desc);
104 static t_stat opc_set_console_pw (UNIT * uptr, UNUSED int32 value,
105 const char * cptr, UNUSED void * desc);
106 static t_stat opc_show_console_pw (UNUSED FILE * st, UNIT * uptr,
107 UNUSED int val, UNUSED const void * desc);
108 static t_stat opc_set_device_name (UNIT * uptr, UNUSED int32 value,
109 const char * cptr, UNUSED void * desc);
110 static t_stat opc_show_device_name (UNUSED FILE * st, UNIT * uptr,
111 UNUSED int val, UNUSED const void * desc);
112
113 static MTAB opc_mtab[] =
114 {
115 {
116 MTAB_unit_nouc,
117 0,
118 "AUTOINPUT",
119 "AUTOINPUT",
120 opc_autoinput_set,
121 opc_autoinput_show,
122 NULL,
123 NULL
124 },
125
126 {
127 MTAB_dev_valr,
128 0,
129 "NUNITS",
130 "NUNITS",
131 opc_set_nunits,
132 opc_show_nunits,
133 "Number of OPC units in the system",
134 NULL
135 },
136
137 {
138 MTAB_unit_uc,
139 0,
140 (char *) "CONFIG",
141 (char *) "CONFIG",
142 opc_set_config,
143 opc_show_config,
144 NULL,
145 NULL,
146 },
147 {
148 MTAB_XTD | MTAB_VUN | \
149 MTAB_VALR | MTAB_NC,
150 0,
151 "NAME",
152 "NAME",
153 opc_set_device_name,
154 opc_show_device_name,
155 "Set the device name",
156 NULL
157 },
158
159 {
160 MTAB_unit_valr_nouc,
161 0,
162 "PORT",
163 "PORT",
164 opc_set_console_port,
165 opc_show_console_port,
166 "Set the console port number",
167 NULL
168 },
169
170 {
171 MTAB_unit_valr_nouc,
172 0,
173 "ADDRESS",
174 "ADDRESS",
175 opc_set_console_address,
176 opc_show_console_address,
177 "Set the console IP Address",
178 NULL
179 },
180
181 {
182 MTAB_unit_valr_nouc,
183 0,
184 "PW",
185 "PW",
186 opc_set_console_pw,
187 opc_show_console_pw,
188 "Set the console password",
189 NULL
190 },
191
192 MTAB_eol
193 };
194
195 static DEBTAB opc_dt[] =
196 {
197 { "NOTIFY", DBG_NOTIFY, NULL },
198 { "INFO", DBG_INFO, NULL },
199 { "ERR", DBG_ERR, NULL },
200 { "WARN", DBG_WARN, NULL },
201 { "DEBUG", DBG_DEBUG, NULL },
202 { "ALL", DBG_ALL, NULL },
203 { NULL, 0, NULL }
204 };
205
206
207
208
209
210
211 #define N_OPC_UNITS 1
212 #define OPC_UNIT_IDX(uptr) ((uptr) - opc_unit)
213
214
215
216 #ifdef LOCKLESS
217
218
219
220 # define ACTIVATE_1SEC 1000
221 #else
222
223
224
225 # define ACTIVATE_1SEC 4000000
226 #endif
227
228 static t_stat opc_svc (UNIT * unitp);
229
230 UNIT opc_unit[N_OPC_UNITS_MAX] = {
231 #ifdef NO_C_ELLIPSIS
232 { UDATA (& opc_svc, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
233 { UDATA (& opc_svc, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
234 { UDATA (& opc_svc, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
235 { UDATA (& opc_svc, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
236 { UDATA (& opc_svc, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
237 { UDATA (& opc_svc, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
238 { UDATA (& opc_svc, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
239 { UDATA (& opc_svc, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
240 #else
241 [0 ... N_OPC_UNITS_MAX - 1] = {
242 UDATA (& opc_svc, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL
243 }
244 #endif
245 };
246
247 DEVICE opc_dev = {
248 "OPC",
249 opc_unit,
250 NULL,
251 opc_mtab,
252 N_OPC_UNITS,
253 10,
254 8,
255 1,
256 8,
257 8,
258 NULL,
259 NULL,
260 opc_reset,
261 NULL,
262 NULL,
263 NULL,
264 NULL,
265 DEV_DEBUG,
266 0,
267 opc_dt,
268 NULL,
269 NULL,
270 NULL,
271 NULL,
272 NULL,
273 NULL,
274 NULL
275 };
276
277 enum console_model { m6001 = 0, m6004 = 1, m6601 = 2 };
278
279
280 typedef struct opc_state_t
281 {
282
283 unsigned char *tailp;
284 unsigned char *readp;
285
286
287 unsigned char *auto_input;
288 unsigned char *autop;
289
290
291 time_t startTime;
292 UNIT * unitp;
293
294
295 uv_access console_access;
296
297 enum console_model model;
298 enum console_mode { opc_no_mode, opc_read_mode, opc_write_mode } io_mode;
299
300
301 uint tally;
302 uint daddr;
303 int chan;
304
305
306
307 int autoaccept;
308
309 int noempty;
310
311 int attn_flush;
312
313 int simh_buffer_cnt;
314
315
316
317 int carrierPosition;
318
319 bool echo;
320
321 bool attn_pressed;
322 bool simh_attn_pressed;
323
324 bool bcd;
325
326
327 bool escapeSequence;
328
329 char device_name [MAX_DEV_NAME_LEN];
330
331
332
333
334 #define bufsize 257
335 unsigned char keyboardLineBuffer[bufsize];
336 bool tabStops [bufsize];
337
338 #define simh_buffer_sz 4096
339 char simh_buffer[simh_buffer_sz];
340 } opc_state_t;
341
342 static opc_state_t console_state[N_OPC_UNITS_MAX];
343
344 static char * bcd_code_page =
345 "01234567"
346 "89[#@;>?"
347 " ABCDEFG"
348 "HI&.](<\\"
349 "^JKLMNOP"
350 "QR-$*);'"
351 "+/STUVWX"
352 "YZ_,%=\"!";
353
354
355
356
357
358 #ifndef TA_BUFFER_SIZE
359 # define TA_BUFFER_SIZE 65536
360 #endif
361
362 static int ta_buffer[TA_BUFFER_SIZE];
363 static uint ta_cnt = 0;
364 static uint ta_next = 0;
365 static bool ta_ovf = false;
366
367 static void ta_flush (void)
368 {
369 ta_cnt = ta_next = 0;
370 ta_ovf = false;
371 }
372
373 static void ta_push (int c)
374 {
375
376 if (ta_cnt >= TA_BUFFER_SIZE)
377 {
378 if (! ta_ovf)
379 sim_print ("typeahead buffer overflow");
380 ta_ovf = true;
381 return;
382 }
383 ta_buffer [ta_cnt ++] = c;
384 }
385
386 static int ta_peek (void)
387 {
388 if (ta_next >= ta_cnt)
389 return SCPE_OK;
390 int c = ta_buffer[ta_next];
391 return c;
392 }
393
394 static int ta_get (void)
395 {
396 if (ta_next >= ta_cnt)
397 return SCPE_OK;
398 int c = ta_buffer[ta_next ++];
399 if (ta_next >= ta_cnt)
400 ta_flush ();
401 return c;
402 }
403
404 static t_stat opc_reset (UNUSED DEVICE * dptr)
405 {
406 for (uint i = 0; i < N_OPC_UNITS_MAX; i ++)
407 {
408 console_state[i].io_mode = opc_no_mode;
409 console_state[i].tailp = console_state[i].keyboardLineBuffer;
410 console_state[i].readp = console_state[i].keyboardLineBuffer;
411 console_state[i].carrierPosition = 1;
412 memset (console_state[i].tabStops, 0, sizeof (console_state[i].tabStops));
413 console_state[i].escapeSequence = false;
414 }
415 return SCPE_OK;
416 }
417
418 int check_attn_key (void)
419 {
420 for (uint i = 0; i < opc_dev.numunits; i ++)
421 {
422 opc_state_t * csp = console_state + i;
423 if (csp->attn_pressed)
424 {
425 csp->attn_pressed = false;
426 return (int) i;
427 }
428 }
429 return -1;
430 }
431
432
433
434 void console_init (void)
435 {
436 opc_reset (& opc_dev);
437 for (uint i = 0; i < N_OPC_UNITS_MAX; i ++)
438 {
439 opc_state_t * csp = console_state + i;
440 csp->model = m6001;
441 csp->auto_input = NULL;
442 csp->autop = NULL;
443 csp->attn_pressed = false;
444 csp->simh_attn_pressed = false;
445 csp->simh_buffer_cnt = 0;
446 strcpy (csp->console_access.pw, "MulticsRulez");
447
448 csp->autoaccept = 0;
449 csp->noempty = 0;
450 csp->attn_flush = 1;
451 csp->carrierPosition = 1;
452 csp->escapeSequence = 1;
453 memset (csp->tabStops, 0, sizeof (csp->tabStops));
454 }
455 }
456
457
458
459 void console_exit (void) {
460 for (uint i = 0; i < N_OPC_UNITS_MAX; i ++) {
461 opc_state_t * csp = console_state + i;
462 if (csp->auto_input) {
463 FREE (csp->auto_input);
464 csp->auto_input = NULL;
465 }
466 if (csp->console_access.telnetp) {
467 sim_warn ("console_exit freeing console %u telnetp %p\r\n", i, csp->console_access.telnetp);
468 telnet_free (csp->console_access.telnetp);
469 csp->console_access.telnetp = NULL;
470 }
471 }
472 }
473
474 static int opc_autoinput_set (UNIT * uptr, UNUSED int32 val,
475 const char * cptr, UNUSED void * desc)
476 {
477 int devUnitIdx = (int) OPC_UNIT_IDX (uptr);
478 opc_state_t * csp = console_state + devUnitIdx;
479
480 if (cptr)
481 {
482 unsigned char * new = (unsigned char *) strdupesc (cptr);
483 if (csp-> auto_input)
484 {
485 size_t nl = strlen ((char *) new);
486 size_t ol = strlen ((char *) csp->auto_input);
487
488 unsigned char * old = realloc (csp->auto_input, nl + ol + 1);
489 if (!old)
490 {
491 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
492 __func__, __FILE__, __LINE__);
493 #if defined(USE_BACKTRACE)
494 # ifdef SIGUSR2
495 (void)raise(SIGUSR2);
496
497 # endif
498 #endif
499 abort();
500 }
501 strcpy ((char *) old + ol, (char *) new);
502 csp->auto_input = old;
503 FREE (new);
504 }
505 else
506 csp->auto_input = new;
507 }
508 else
509 {
510 if (csp->auto_input)
511 FREE (csp->auto_input);
512 csp->auto_input = NULL;
513 }
514 csp->autop = csp->auto_input;
515 return SCPE_OK;
516 }
517
518 int clear_opc_autoinput (int32 flag, UNUSED const char * cptr)
519 {
520 opc_state_t * csp = console_state + flag;
521 if (csp->auto_input)
522 FREE (csp->auto_input);
523 csp->auto_input = NULL;
524 csp->autop = csp->auto_input;
525 return SCPE_OK;
526 }
527
528 int add_opc_autoinput (int32 flag, const char * cptr)
529 {
530 opc_state_t * csp = console_state + flag;
531 unsigned char * new = (unsigned char *) strdupesc (cptr);
532 if (csp->auto_input)
533 {
534 size_t nl = strlen ((char *) new);
535 size_t ol = strlen ((char *) csp->auto_input);
536
537 unsigned char * old = realloc (csp->auto_input, nl + ol + 1);
538 if (!old)
539 {
540 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
541 __func__, __FILE__, __LINE__);
542 #if defined(USE_BACKTRACE)
543 # ifdef SIGUSR2
544 (void)raise(SIGUSR2);
545
546 # endif
547 #endif
548 abort();
549 }
550 strcpy ((char *) old + ol, (char *) new);
551 csp->auto_input = old;
552 FREE (new);
553 }
554 else
555 csp->auto_input = new;
556 csp->autop = csp->auto_input;
557 return SCPE_OK;
558 }
559
560 static int opc_autoinput_show (UNUSED FILE * st, UNIT * uptr,
561 UNUSED int val, UNUSED const void * desc)
562 {
563 int conUnitIdx = (int) OPC_UNIT_IDX (uptr);
564 opc_state_t * csp = console_state + conUnitIdx;
565 if (csp->auto_input)
566 sim_print ("autoinput: '%s'", csp->auto_input);
567 else
568 sim_print ("autoinput: empty");
569 return SCPE_OK;
570 }
571
572 static t_stat console_attn (UNUSED UNIT * uptr);
573
574 static UNIT attn_unit[N_OPC_UNITS_MAX] = {
575 #ifdef NO_C_ELLIPSIS
576 { UDATA (& console_attn, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
577 { UDATA (& console_attn, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
578 { UDATA (& console_attn, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
579 { UDATA (& console_attn, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
580 { UDATA (& console_attn, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
581 { UDATA (& console_attn, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
582 { UDATA (& console_attn, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
583 { UDATA (& console_attn, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
584 #else
585 [0 ... N_OPC_UNITS_MAX - 1] = {
586 UDATA (& console_attn, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL
587 }
588 #endif
589 };
590
591 static t_stat console_attn (UNUSED UNIT * uptr)
592 {
593 uint con_unit_idx = (uint) (uptr - attn_unit);
594 uint ctlr_port_num = 0;
595 uint iom_unit_idx = cables->opc_to_iom[con_unit_idx][ctlr_port_num].iom_unit_idx;
596 uint chan_num = cables->opc_to_iom[con_unit_idx][ctlr_port_num].chan_num;
597 uint dev_code = 0;
598
599 send_special_interrupt (iom_unit_idx, chan_num, dev_code, 0, 0);
600 return SCPE_OK;
601 }
602
603 void console_attn_idx (int conUnitIdx)
604 {
605 console_attn (attn_unit + conUnitIdx);
606 }
607
608 #ifndef __MINGW64__
609 # ifndef __MINGW32__
610 static struct termios ttyTermios;
611 static bool ttyTermiosOk = false;
612
613 static void newlineOff (void)
614 {
615 if (! isatty (0))
616 return;
617 if (! ttyTermiosOk)
618 {
619 int rc = tcgetattr (0, & ttyTermios);
620 if (rc)
621 return;
622 ttyTermiosOk = true;
623 }
624 struct termios runtty;
625 runtty = ttyTermios;
626 runtty.c_oflag &= (unsigned int) ~OPOST;
627 tcsetattr (0, TCSAFLUSH, & runtty);
628 }
629
630 static void newlineOn (void)
631 {
632 if (! isatty (0))
633 return;
634 if (! ttyTermiosOk)
635 return;
636 tcsetattr (0, TCSAFLUSH, & ttyTermios);
637 }
638 # endif
639 #endif
640
641 static void handleRCP (uint con_unit_idx, char * text)
642 {
643
644
645
646
647
648
649
650
651
652 size_t len = strlen (text);
653 char label [len + 1];
654 char with [len + 1];
655 char drive [len + 1];
656 int rc = sscanf (text, "%*d.%*d RCP: Mount Reel %s %s ring on %s",
657 label, with, drive);
658 if (rc == 3)
659 {
660 bool withring = (strcmp (with, "with") == 0);
661 char labelDotTap[strlen (label) + strlen (".tap") + 1];
662 strcpy (labelDotTap, label);
663 strcat (labelDotTap, ".tap");
664 attachTape (labelDotTap, withring, drive);
665 return;
666 }
667
668 rc = sscanf (text, "%*d.%*d RCP: Remount Reel %s %s ring on %s",
669 label, with, drive);
670 if (rc == 3)
671 {
672 bool withring = (strcmp (with, "with") == 0);
673 char labelDotTap [strlen (label) + strlen (".tap") + 1];
674 strcpy (labelDotTap, label);
675 strcat (labelDotTap, ".tap");
676 attachTape (labelDotTap, withring, drive);
677 return;
678 }
679
680
681
682 if (console_state[con_unit_idx].autoaccept)
683 {
684 rc = sscanf (text, "%*d as dial_ctl_: Channel %s dialed to Initializer",
685 label);
686 if (rc == 1)
687 {
688
689 opc_autoinput_set (opc_unit + con_unit_idx, 0, "accept ", NULL);
690 opc_autoinput_set (opc_unit + con_unit_idx, 0, label, NULL);
691 opc_autoinput_set (opc_unit + con_unit_idx, 0, "\r", NULL);
692
693 if (console_state[con_unit_idx].io_mode != opc_read_mode)
694 console_state[con_unit_idx].attn_pressed = true;
695 return;
696 }
697 }
698 }
699
700
701 static void sendConsole (int conUnitIdx, word12 stati)
702 {
703 opc_state_t * csp = console_state + conUnitIdx;
704 uint tally = csp->tally;
705 uint ctlr_port_num = 0;
706 uint iomUnitIdx = cables->opc_to_iom[conUnitIdx][ctlr_port_num].iom_unit_idx;
707 uint chan_num = cables->opc_to_iom[conUnitIdx][ctlr_port_num].chan_num;
708 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan_num];
709
710
711 if (csp->io_mode != opc_read_mode)
712 {
713 sim_warn ("%s called with io_mode != opc_read_mode (%d)\n",
714 __func__, csp->io_mode);
715 return;
716 }
717
718 uint n_chars = (uint) (csp->tailp - csp->readp);
719 uint n_words;
720 if (csp->bcd)
721
722 n_words = ((n_chars+2) + 5) / 6;
723 else
724 n_words = (n_chars + 3) / 4;
725
726 word36 buf[n_words + 1];
727
728 memset (buf, 0, sizeof (word36) * (n_words + 1));
729 word36 * bufp = buf;
730
731
732
733 if ((!csp->bcd) && csp->noempty && n_chars == 0 && tally)
734 {
735 n_chars = 1;
736 n_words = 1;
737 putbits36_9 (bufp, 0, '@');
738 tally --;
739 }
740 else
741 {
742 int bcd_nl_state = 0;
743 while (tally && csp->readp < csp->tailp)
744 {
745 if (csp->bcd)
746 {
747
748
749 * bufp = 0;
750 for (uint charno = 0; charno < 4; ++ charno)
751 {
752 unsigned char c;
753 if (csp->readp >= csp->tailp)
754 {
755 if (bcd_nl_state == 0)
756 {
757 c = '!';
758 bcd_nl_state = 1;
759 }
760 else if (bcd_nl_state == 1)
761 {
762 c = '1';
763 bcd_nl_state = 2;
764 }
765 else
766 break;
767 }
768 else
769 c = (unsigned char) (* csp->readp ++);
770 c = (unsigned char) toupper (c);
771 int i;
772 for (i = 0; i < 64; i ++)
773 if (bcd_code_page[i] == c)
774 break;
775 if (i >= 64)
776 {
777 sim_warn ("Character %o does not map to BCD; replacing with '?'\n", c);
778 i = 017;
779 }
780 putbits36_6 (bufp, charno * 6, (word6) i);
781 }
782 }
783 else
784 {
785 * bufp = 0ul;
786 for (uint charno = 0; charno < 4; ++ charno)
787 {
788 if (csp->readp >= csp->tailp)
789 break;
790 unsigned char c = (unsigned char) (* csp->readp ++);
791 c &= 0177;
792 putbits36_9 (bufp, charno * 9, c);
793 }
794 }
795 bufp ++;
796 tally --;
797 }
798 if (csp->readp < csp->tailp)
799 {
800 sim_warn ("opc_iom_io: discarding %d characters from end of line\n",
801 (int) (csp->tailp - csp->readp));
802 }
803 }
804
805 iom_indirect_data_service (iomUnitIdx, chan_num, buf, & n_words, true);
806
807 p->charPos = n_chars % 4;
808 p->stati = (word12) stati;
809
810 csp->readp = csp->keyboardLineBuffer;
811 csp->tailp = csp->keyboardLineBuffer;
812 csp->io_mode = opc_no_mode;
813
814 send_terminate_interrupt (iomUnitIdx, chan_num);
815 }
816
817 static void console_putchar (int conUnitIdx, char ch);
818 static void console_putstr (int conUnitIdx, char * str);
819
820
821 static void consoleProcessIdx (int conUnitIdx)
822 {
823 opc_state_t * csp = console_state + conUnitIdx;
824 int c;
825
826
827
828 for (;;)
829 {
830 c = sim_poll_kbd ();
831 if (c == SCPE_OK)
832 c = accessGetChar (& csp->console_access);
833
834
835
836 if (breakEnable && stop_cpu)
837 {
838 console_putstr (conUnitIdx, " Got <sim stop> \r\n");
839 return;
840 }
841
842
843
844
845
846 if (breakEnable && c == SCPE_STOP)
847 {
848 console_putstr (conUnitIdx, " Got <sim stop> \r\n");
849 stop_cpu = 1;
850 return;
851 }
852
853
854
855 if (breakEnable && c == SCPE_BREAK)
856 {
857 console_putstr (conUnitIdx, " Got <sim stop> \r\n");
858 stop_cpu = 1;
859 return;
860 }
861
862
863
864 if (c == SCPE_OK)
865 break;
866
867
868
869 if (c < SCPE_KFLAG)
870 {
871 sim_printf ("impossible %d %o\n", c, c);
872 continue;
873 }
874
875
876
877 int ch = c - SCPE_KFLAG;
878
879
880
881
882 if (csp->io_mode != opc_read_mode)
883 {
884 if (ch == '\033' || ch == '\001')
885 {
886 if (csp->attn_flush)
887 ta_flush ();
888 csp->attn_pressed = true;
889 continue;
890 }
891 }
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916 if (ch == 023)
917 {
918 if (! csp->simh_attn_pressed)
919 {
920 ta_flush ();
921 csp->simh_attn_pressed = true;
922 csp->simh_buffer_cnt = 0;
923 console_putstr (conUnitIdx, "^S\r\n" SIM_NAME "> ");
924 }
925 continue;
926 }
927
928
929
930
931
932
933
934
935
936
937
938 if (ch == 020) {
939 if (csp->io_mode != opc_read_mode) {
940 if (csp->attn_flush)
941 ta_flush ();
942 csp->attn_pressed = true;
943 }
944 continue;
945 }
946
947
948
949 if (ch == 024)
950 {
951 char buf[256];
952 char cms[3] = "?RW";
953
954 sprintf (buf, "^T attn %c %c cnt %d next %d\r\n",
955 console_state[0].attn_pressed+'0',
956 cms[console_state[0].io_mode],
957 ta_cnt, ta_next);
958 console_putstr (conUnitIdx, buf);
959 continue;
960 }
961
962
963
964 if (csp->simh_attn_pressed)
965 {
966 ta_get ();
967 if (ch == '\177' || ch == '\010')
968 {
969 if (csp->simh_buffer_cnt > 0)
970 {
971 -- csp->simh_buffer_cnt;
972 csp->simh_buffer[csp->simh_buffer_cnt] = 0;
973 console_putstr (conUnitIdx, "\b \b");
974 }
975 return;
976 }
977
978
979
980 if (ch == '\022')
981 {
982 console_putstr (conUnitIdx, "^R\r\n" SIM_NAME "> ");
983 for (int i = 0; i < csp->simh_buffer_cnt; i ++)
984 console_putchar (conUnitIdx, (char) (csp->simh_buffer[i]));
985 return;
986 }
987
988
989
990 if (ch == '\025')
991 {
992 console_putstr (conUnitIdx, "^U\r\n" SIM_NAME "> ");
993 csp->simh_buffer_cnt = 0;
994 return;
995 }
996
997
998
999 if (ch == '\012' || ch == '\015')
1000 {
1001 console_putstr (conUnitIdx, "\r\n");
1002 csp->simh_buffer[csp->simh_buffer_cnt] = 0;
1003
1004 char * cptr = csp->simh_buffer;
1005 char gbuf[simh_buffer_sz];
1006 cptr = (char *) get_glyph (cptr, gbuf, 0);
1007 if (strlen (gbuf))
1008 {
1009 CTAB *cmdp;
1010 if ((cmdp = find_cmd (gbuf)))
1011 {
1012 t_stat stat = cmdp->action (cmdp->arg, cptr);
1013
1014 if (stat != SCPE_OK)
1015 {
1016 char buf[4096];
1017 sprintf (buf, "\r%s returned %d '%s'\r\n",
1018 SIM_NAME, stat, sim_error_text (stat));
1019 console_putstr (conUnitIdx, buf);
1020 }
1021 }
1022 else
1023 console_putstr (conUnitIdx,
1024 "\rUnrecognized " SIM_NAME " command.\r\n");
1025 }
1026 csp->simh_buffer_cnt = 0;
1027 csp->simh_buffer[0] = 0;
1028 csp->simh_attn_pressed = false;
1029 return;
1030 }
1031
1032
1033
1034 if (ch == '\033' || ch == '\004' || ch == '\032')
1035 {
1036 console_putstr (conUnitIdx, "\r\n" SIM_NAME " cancel\r\n");
1037
1038 csp->simh_buffer_cnt = 0;
1039 csp->simh_buffer[0] = 0;
1040 csp->simh_attn_pressed = false;
1041 return;
1042 }
1043
1044
1045
1046 if (isprint (ch))
1047 {
1048
1049 if (csp->simh_buffer_cnt + 1 >= simh_buffer_sz)
1050 return;
1051 csp->simh_buffer[csp->simh_buffer_cnt ++] = (char) ch;
1052 console_putchar (conUnitIdx, (char) ch);
1053 return;
1054 }
1055 return;
1056 }
1057
1058
1059
1060 ta_push (c);
1061 }
1062
1063
1064
1065 if (breakEnable && stop_cpu)
1066 {
1067 console_putstr (conUnitIdx, " Got <sim stop> \r\n");
1068 return;
1069 }
1070
1071
1072
1073
1074 if (csp->io_mode == opc_read_mode &&
1075 csp->autop != NULL)
1076 {
1077 int announce = 1;
1078 for (;;)
1079 {
1080 if (csp->tailp >= csp->keyboardLineBuffer + sizeof (csp->keyboardLineBuffer))
1081 {
1082 sim_warn ("getConsoleInput: Buffer full; flushing autoinput.\n");
1083 sendConsole (conUnitIdx, 04000);
1084 return;
1085 }
1086 unsigned char c = * (csp->autop);
1087 if (c == 4)
1088 {
1089 FREE (csp->auto_input);
1090 csp->auto_input = NULL;
1091 csp->autop = NULL;
1092
1093 csp->readp = csp->keyboardLineBuffer;
1094 csp->tailp = csp->keyboardLineBuffer;
1095 sendConsole (conUnitIdx, 04310);
1096
1097 console_putstr (conUnitIdx, "CONSOLE: RELEASED\r\n");
1098 return;
1099 }
1100 if (c == 030 || c == 031)
1101 {
1102
1103
1104 return;
1105 }
1106 if (c == 0)
1107 {
1108 FREE (csp->auto_input);
1109 csp->auto_input = NULL;
1110 csp->autop = NULL;
1111 goto eol;
1112 }
1113 if (announce)
1114 {
1115 console_putstr (conUnitIdx, "[auto-input] ");
1116 announce = 0;
1117 }
1118 csp->autop ++;
1119
1120 if (c == '\012' || c == '\015')
1121 {
1122 eol:
1123 if (csp->echo)
1124 console_putstr (conUnitIdx, "\r\n");
1125 sendConsole (conUnitIdx, 04000);
1126 return;
1127 }
1128 else
1129 {
1130 * csp->tailp ++ = c;
1131 if (csp->echo)
1132 console_putchar (conUnitIdx, (char) c);
1133 }
1134 }
1135 }
1136
1137
1138
1139
1140 if (csp->io_mode == opc_read_mode &&
1141 csp->tailp == csp->keyboardLineBuffer)
1142 {
1143 if (csp->startTime + 30 < time (NULL))
1144 {
1145 console_putstr (conUnitIdx, "CONSOLE: TIMEOUT\r\n");
1146 csp->readp = csp->keyboardLineBuffer;
1147 csp->tailp = csp->keyboardLineBuffer;
1148 sendConsole (conUnitIdx, 04310);
1149
1150 }
1151 }
1152
1153
1154
1155 c = ta_peek ();
1156
1157
1158 if (c == SCPE_OK)
1159 return;
1160
1161
1162 if (c < SCPE_KFLAG)
1163 {
1164 sim_printf ("impossible %d %o\n", c, c);
1165 return;
1166 }
1167
1168
1169
1170 int ch = c - SCPE_KFLAG;
1171
1172
1173 if (csp->io_mode != opc_read_mode)
1174 {
1175 if (ch == '\033' || ch == '\001')
1176 {
1177 ta_get ();
1178 csp->attn_pressed = true;
1179 }
1180 return;
1181 }
1182
1183 if (ch == '\177' || ch == '\010')
1184 {
1185 ta_get ();
1186 if (csp->tailp > csp->keyboardLineBuffer)
1187 {
1188 * csp->tailp = 0;
1189 -- csp->tailp;
1190 if (csp->echo)
1191 console_putstr (conUnitIdx, "\b \b");
1192 }
1193 return;
1194 }
1195
1196 if (ch == '\022')
1197 {
1198 ta_get ();
1199 if (csp->echo)
1200 {
1201 console_putstr (conUnitIdx, "^R\r\n");
1202 for (unsigned char * p = csp->keyboardLineBuffer; p < csp->tailp; p ++)
1203 console_putchar (conUnitIdx, (char) (*p));
1204 return;
1205 }
1206 }
1207
1208 if (ch == '\025')
1209 {
1210 ta_get ();
1211 console_putstr (conUnitIdx, "^U\r\n");
1212 csp->tailp = csp->keyboardLineBuffer;
1213 return;
1214 }
1215
1216 if (ch == '\030')
1217 {
1218 ta_get ();
1219 console_putstr (conUnitIdx, "^X\r\n");
1220 csp->tailp = csp->keyboardLineBuffer;
1221 return;
1222 }
1223
1224 if (ch == '\012' || ch == '\015')
1225 {
1226 ta_get ();
1227 if (csp->echo)
1228 console_putstr (conUnitIdx, "\r\n");
1229 sendConsole (conUnitIdx, 04000);
1230 return;
1231 }
1232
1233 if (ch == '\033' || ch == '\004' || ch == '\032')
1234 {
1235 ta_get ();
1236 console_putstr (conUnitIdx, "\r\n");
1237
1238 csp->readp = csp->keyboardLineBuffer;
1239 csp->tailp = csp->keyboardLineBuffer;
1240 sendConsole (conUnitIdx, 04310);
1241
1242 console_putstr (conUnitIdx, "CONSOLE: RELEASED\n");
1243 return;
1244 }
1245
1246 if (isprint (ch))
1247 {
1248
1249 ta_get ();
1250 if (csp->tailp >= csp->keyboardLineBuffer + sizeof (csp->keyboardLineBuffer))
1251 return;
1252
1253 * csp->tailp ++ = (unsigned char) ch;
1254 if (csp->echo)
1255 console_putchar (conUnitIdx, (char) ch);
1256 return;
1257 }
1258
1259 ta_get ();
1260 return;
1261 }
1262
1263 void consoleProcess (void)
1264 {
1265 for (int conUnitIdx = 0; conUnitIdx < (int) opc_dev.numunits; conUnitIdx ++)
1266 consoleProcessIdx (conUnitIdx);
1267 }
1268
1269
1270
1271
1272
1273
1274
1275
1276 iom_cmd_rc_t opc_iom_cmd (uint iomUnitIdx, uint chan) {
1277 iom_cmd_rc_t rc = IOM_CMD_PROCEED;
1278
1279 #ifdef LOCKLESS
1280 lock_libuv ();
1281 #endif
1282
1283 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1284 uint con_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1285 UNIT * unitp = & opc_unit[con_unit_idx];
1286 opc_state_t * csp = console_state + con_unit_idx;
1287
1288 p->dev_code = p->IDCW_DEV_CODE;
1289 p->stati = 0;
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299 if (IS_IDCW (p)) {
1300
1301
1302 switch (p->IDCW_DEV_CMD) {
1303 case 000:
1304 sim_debug (DBG_DEBUG, & opc_dev, "%s: Status request\n", __func__);
1305 csp->io_mode = opc_no_mode;
1306 p->stati = 04000;
1307 break;
1308
1309 case 003:
1310 sim_debug (DBG_DEBUG, & tape_dev, "%s: Read BCD echoed\n", __func__);
1311 csp->io_mode = opc_read_mode;
1312 p->recordResidue --;
1313 csp->echo = true;
1314 csp->bcd = true;
1315 p->stati = 04000;
1316 break;
1317
1318 case 013:
1319 sim_debug (DBG_DEBUG, & opc_dev, "%s: Write BCD\n", __func__);
1320 p->isRead = false;
1321 csp->bcd = true;
1322 csp->io_mode = opc_write_mode;
1323 p->recordResidue --;
1324 p->stati = 04000;
1325 break;
1326
1327 case 023:
1328 sim_debug (DBG_DEBUG, & tape_dev, "%s: Read ASCII echoed\n", __func__);
1329 csp->io_mode = opc_read_mode;
1330 p->recordResidue --;
1331 csp->echo = true;
1332 csp->bcd = false;
1333 p->stati = 04000;
1334 break;
1335
1336 case 033:
1337 sim_debug (DBG_DEBUG, & opc_dev, "%s: Write ASCII\n", __func__);
1338 p->isRead = false;
1339 csp->bcd = false;
1340 csp->io_mode = opc_write_mode;
1341 p->recordResidue --;
1342 p->stati = 04000;
1343 break;
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354 case 040:
1355 sim_debug (DBG_DEBUG, & opc_dev, "%s: Reset\n", __func__);
1356 p->stati = 04000;
1357
1358
1359
1360
1361
1362
1363
1364 break;
1365
1366 case 043:
1367 sim_debug (DBG_DEBUG, & tape_dev, "%s: Read ASCII unechoed\n", __func__);
1368 csp->io_mode = opc_read_mode;
1369 p->recordResidue --;
1370 csp->echo = false;
1371 csp->bcd = false;
1372 p->stati = 04000;
1373 break;
1374
1375 case 051:
1376 sim_debug (DBG_DEBUG, & opc_dev, "%s: Alert\n", __func__);
1377 p->isRead = false;
1378 console_putstr ((int) con_unit_idx, "CONSOLE: ALERT\r\n");
1379 console_putchar ((int) con_unit_idx, '\a');
1380 p->stati = 04000;
1381 if (csp->model == m6001 && p->isPCW) {
1382 rc = IOM_CMD_DISCONNECT;
1383 goto done;
1384 }
1385 break;
1386
1387 case 057:
1388
1389
1390
1391
1392 sim_debug (DBG_DEBUG, & opc_dev, "%s: Read ID\n", __func__);
1393 p->stati = 04500;
1394 if (csp->model == m6001 && p->isPCW) {
1395 rc = IOM_CMD_DISCONNECT;
1396 goto done;
1397 }
1398 break;
1399
1400 case 060:
1401 sim_debug (DBG_DEBUG, & opc_dev, "%s: Lock\n", __func__);
1402 console_putstr ((int) con_unit_idx, "CONSOLE: LOCK\r\n");
1403 p->stati = 04000;
1404 break;
1405
1406 case 063:
1407 sim_debug (DBG_DEBUG, & opc_dev, "%s: Unlock\n", __func__);
1408 console_putstr ((int) con_unit_idx, "CONSOLE: UNLOCK\r\n");
1409 p->stati = 04000;
1410 break;
1411
1412 default:
1413 sim_debug (DBG_DEBUG, & opc_dev, "%s: Unknown command 0%o\n", __func__, p->IDCW_DEV_CMD);
1414 p->stati = 04501;
1415 rc = IOM_CMD_ERROR;
1416 goto done;
1417 }
1418 goto done;
1419 }
1420
1421
1422 switch (csp->io_mode) {
1423 case opc_no_mode:
1424 sim_warn ("%s: Unexpected IOTx\n", __func__);
1425 rc = IOM_CMD_ERROR;
1426 goto done;
1427
1428 case opc_read_mode: {
1429 if (csp->tailp != csp->keyboardLineBuffer) {
1430 sim_warn ("%s: Discarding previously buffered input.\n", __func__);
1431 }
1432 uint tally = p->DDCW_TALLY;
1433 uint daddr = p->DDCW_ADDR;
1434
1435 if (tally == 0) {
1436 tally = 4096;
1437 }
1438
1439 csp->tailp = csp->keyboardLineBuffer;
1440 csp->readp = csp->keyboardLineBuffer;
1441 csp->startTime = time (NULL);
1442 csp->tally = tally;
1443 csp->daddr = daddr;
1444 csp->unitp = unitp;
1445 csp->chan = (int) chan;
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456 if (csp->autop && (*csp->autop == 030 || *csp->autop == 031)) {
1457
1458
1459
1460
1461
1462 clear_opc_autoinput (ASSUME0, NULL);
1463 ta_flush ();
1464 sim_printf \
1465 ("\r\nScript wedged and abandoned; autoinput and typeahead buffers flushed\r\n");
1466 }
1467 rc = IOM_CMD_PENDING;
1468 goto done;
1469 }
1470
1471 case opc_write_mode: {
1472 uint tally = p->DDCW_TALLY;
1473
1474
1475
1476
1477 if (tally == 0) {
1478 tally = 4096;
1479 }
1480
1481 word36 buf[tally];
1482 iom_indirect_data_service (iomUnitIdx, chan, buf, & tally, false);
1483 p->initiate = false;
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516 char text[tally * 4 + 1];
1517 char * textp = text;
1518 word36 * bufp = buf;
1519 * textp = 0;
1520 #ifndef __MINGW64__
1521 newlineOff ();
1522 #endif
1523
1524
1525
1526 int escape_cnt = 0;
1527
1528 while (tally) {
1529 word36 datum = * bufp ++;
1530 tally --;
1531 if (csp->bcd) {
1532
1533 for (int i = 0; i < 6; i ++) {
1534 word36 narrow_char = datum >> 30;
1535
1536 datum = datum << 6;
1537 narrow_char &= 077;
1538 char ch = bcd_code_page [narrow_char];
1539 if (escape_cnt == 2) {
1540 console_putchar ((int) con_unit_idx, ch);
1541 * textp ++ = ch;
1542 escape_cnt = 0;
1543 } else if (ch == '!') {
1544 escape_cnt ++;
1545 } else if (escape_cnt == 1) {
1546 uint lp = (uint)narrow_char;
1547
1548
1549 if (lp == 060 || lp == 075 ) {
1550 p->stati = 04320;
1551 goto done;
1552 }
1553 if (lp == 0)
1554 lp = 1;
1555 if (lp >= 16) {
1556 console_putstr ((int) con_unit_idx, "\f");
1557
1558 } else {
1559 for (uint i = 0; i < lp; i ++) {
1560 console_putstr ((int) con_unit_idx, "\r\n");
1561
1562
1563 }
1564 }
1565 escape_cnt = 0;
1566 } else if (ch == '?') {
1567 escape_cnt = 0;
1568 } else {
1569 console_putchar ((int) con_unit_idx, ch);
1570 * textp ++ = ch;
1571 escape_cnt = 0;
1572 }
1573 }
1574 } else {
1575 for (int i = 0; i < 4; i ++) {
1576 word36 wide_char = datum >> 27;
1577
1578 datum = datum << 9;
1579 char ch = wide_char & 0x7f;
1580 if (ch != 0177 && ch != 0) {
1581 console_putchar ((int) con_unit_idx, ch);
1582 * textp ++ = ch;
1583 }
1584 }
1585 }
1586 }
1587 * textp ++ = 0;
1588
1589
1590 if (csp->autop && * csp->autop == 030) {
1591
1592
1593
1594 size_t expl = strcspn ((char *) (csp->autop + 1), "\030");
1595
1596 if (strncmp (text, (char *) (csp->autop + 1), expl) == 0) {
1597 csp->autop += expl + 2;
1598 #ifdef LOCKLESS
1599
1600 sim_activate (& attn_unit[con_unit_idx], 1000);
1601 #else
1602
1603 sim_activate (& attn_unit[con_unit_idx], 4000000);
1604 #endif
1605 }
1606 }
1607
1608 if (csp->autop && * csp->autop == 031) {
1609
1610
1611
1612 size_t expl = strcspn ((char *) (csp->autop + 1), "\031");
1613
1614 char needle [expl + 1];
1615 strncpy (needle, (char *) csp->autop + 1, expl);
1616 needle [expl] = 0;
1617 if (strstr (text, needle)) {
1618 csp->autop += expl + 2;
1619 #ifdef LOCKLESS
1620
1621 sim_activate (& attn_unit[con_unit_idx], 1000);
1622 #else
1623
1624 sim_activate (& attn_unit[con_unit_idx], 4000000);
1625 #endif
1626 }
1627 }
1628 handleRCP (con_unit_idx, text);
1629 #ifndef __MINGW64__
1630 newlineOn ();
1631 #endif
1632 p->stati = 04000;
1633 goto done;
1634 }
1635 }
1636
1637 done:
1638 #ifdef LOCKLESS
1639 unlock_libuv ();
1640 #endif
1641 return rc;
1642 }
1643
1644 static t_stat opc_svc (UNIT * unitp)
1645 {
1646 int con_unit_idx = (int) OPC_UNIT_IDX (unitp);
1647 uint ctlr_port_num = 0;
1648 uint iom_unit_idx = cables->opc_to_iom[con_unit_idx][ctlr_port_num].iom_unit_idx;
1649 uint chan_num = cables->opc_to_iom[con_unit_idx][ctlr_port_num].chan_num;
1650
1651 opc_iom_cmd (iom_unit_idx, chan_num);
1652 return SCPE_OK;
1653 }
1654
1655 static t_stat opc_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
1656 UNUSED int val, UNUSED const void * desc)
1657 {
1658 sim_print ("%d units\n", opc_dev.numunits);
1659 return SCPE_OK;
1660 }
1661
1662 static t_stat opc_set_nunits (UNUSED UNIT * uptr, int32 UNUSED value,
1663 const char * cptr, UNUSED void * desc)
1664 {
1665 if (! cptr)
1666 return SCPE_ARG;
1667 int n = atoi (cptr);
1668 if (n < 1 || n > N_OPC_UNITS_MAX)
1669 return SCPE_ARG;
1670 opc_dev.numunits = (uint32) n;
1671 return SCPE_OK;
1672 }
1673
1674 static config_value_list_t cfg_on_off[] =
1675 {
1676 { "off", 0 },
1677 { "on", 1 },
1678 { "disable", 0 },
1679 { "enable", 1 },
1680 { NULL, 0 }
1681 };
1682
1683 static config_value_list_t cfg_model[] =
1684 {
1685 { "m6001", m6001 },
1686 { "m6004", m6004 },
1687 { "m6601", m6601 },
1688 { NULL, 0 }
1689 };
1690
1691 static config_list_t opc_config_list[] =
1692 {
1693 { "autoaccept", 0, 1, cfg_on_off },
1694 { "noempty", 0, 1, cfg_on_off },
1695 { "attn_flush", 0, 1, cfg_on_off },
1696 { "model", 1, 0, cfg_model },
1697 { NULL, 0, 0, NULL }
1698 };
1699
1700 static t_stat opc_set_config (UNUSED UNIT * uptr, UNUSED int32 value,
1701 const char * cptr, UNUSED void * desc)
1702 {
1703 int devUnitIdx = (int) OPC_UNIT_IDX (uptr);
1704 opc_state_t * csp = console_state + devUnitIdx;
1705
1706 config_state_t cfg_state = { NULL, NULL };
1707
1708 for (;;)
1709 {
1710 int64_t v;
1711 int rc = cfg_parse (__func__, cptr, opc_config_list,
1712 & cfg_state, & v);
1713 if (rc == -1)
1714 break;
1715
1716 if (rc == -2)
1717 {
1718 cfg_parse_done (& cfg_state);
1719 return SCPE_ARG;
1720 }
1721 const char * p = opc_config_list[rc].name;
1722
1723 if (strcmp (p, "autoaccept") == 0)
1724 {
1725 csp->autoaccept = (int) v;
1726 continue;
1727 }
1728
1729 if (strcmp (p, "noempty") == 0)
1730 {
1731 csp->noempty = (int) v;
1732 continue;
1733 }
1734
1735 if (strcmp (p, "attn_flush") == 0)
1736 {
1737 csp->attn_flush = (int) v;
1738 continue;
1739 }
1740
1741 if (strcmp (p, "model") == 0)
1742 {
1743 csp->model = (enum console_model) v;
1744 continue;
1745 }
1746
1747 sim_warn ("error: opc_set_config: Invalid cfg_parse rc <%d>\n",
1748 rc);
1749 cfg_parse_done (& cfg_state);
1750 return SCPE_ARG;
1751 }
1752 cfg_parse_done (& cfg_state);
1753 return SCPE_OK;
1754 }
1755
1756 static t_stat opc_show_config (UNUSED FILE * st, UNUSED UNIT * uptr,
1757 UNUSED int val, UNUSED const void * desc)
1758 {
1759 int devUnitIdx = (int) OPC_UNIT_IDX (uptr);
1760 opc_state_t * csp = console_state + devUnitIdx;
1761 sim_msg ("flags : ");
1762 sim_msg ("autoaccept=%d, ", csp->autoaccept);
1763 sim_msg ("noempty=%d, ", csp->noempty);
1764 sim_msg ("attn_flush=%d", csp->attn_flush);
1765 return SCPE_OK;
1766 }
1767
1768 static t_stat opc_show_device_name (UNUSED FILE * st, UNIT * uptr,
1769 UNUSED int val, UNUSED const void * desc)
1770 {
1771 int n = (int) OPC_UNIT_IDX (uptr);
1772 if (n < 0 || n >= N_OPC_UNITS_MAX)
1773 return SCPE_ARG;
1774 sim_printf("name : OPC%d", n);
1775 return SCPE_OK;
1776 }
1777
1778 static t_stat opc_set_device_name (UNIT * uptr, UNUSED int32 value,
1779 const char * cptr, UNUSED void * desc)
1780 {
1781 int n = (int) OPC_UNIT_IDX (uptr);
1782 if (n < 0 || n >= N_OPC_UNITS_MAX)
1783 return SCPE_ARG;
1784 if (cptr)
1785 {
1786 strncpy (console_state[n].device_name, cptr, MAX_DEV_NAME_LEN-1);
1787 console_state[n].device_name[MAX_DEV_NAME_LEN-1] = 0;
1788 }
1789 else
1790 console_state[n].device_name[0] = 0;
1791 return SCPE_OK;
1792 }
1793
1794 static t_stat opc_set_console_port (UNIT * uptr, UNUSED int32 value,
1795 const char * cptr, UNUSED void * desc)
1796 {
1797 int dev_idx = (int) OPC_UNIT_IDX (uptr);
1798 if (dev_idx < 0 || dev_idx >= N_OPC_UNITS_MAX)
1799 return SCPE_ARG;
1800
1801 if (cptr)
1802 {
1803 int port = atoi (cptr);
1804 if (port < 0 || port > 65535)
1805 return SCPE_ARG;
1806 console_state[dev_idx].console_access.port = port;
1807 if (port != 0)
1808 sim_msg ("[OPC emulation: TELNET server port set to %d]\r\n", (int)port);
1809 }
1810 else
1811 console_state[dev_idx].console_access.port = 0;
1812 return SCPE_OK;
1813 }
1814
1815 static t_stat opc_show_console_port (UNUSED FILE * st, UNIT * uptr,
1816 UNUSED int val, UNUSED const void * desc)
1817 {
1818 int dev_idx = (int) OPC_UNIT_IDX (uptr);
1819 if (dev_idx < 0 || dev_idx >= N_OPC_UNITS_MAX)
1820 return SCPE_ARG;
1821 if (console_state[dev_idx].console_access.port)
1822 sim_printf("port : %d", console_state[dev_idx].console_access.port);
1823 else
1824 sim_printf("port : disabled");
1825 return SCPE_OK;
1826 }
1827
1828 static t_stat opc_set_console_address (UNIT * uptr, UNUSED int32 value,
1829 const char * cptr, UNUSED void * desc)
1830 {
1831 int dev_idx = (int) OPC_UNIT_IDX (uptr);
1832 if (dev_idx < 0 || dev_idx >= N_OPC_UNITS_MAX)
1833 return SCPE_ARG;
1834
1835 if (console_state[dev_idx].console_access.address)
1836 {
1837 FREE (console_state[dev_idx].console_access.address);
1838 console_state[dev_idx].console_access.address = NULL;
1839 }
1840
1841 if (cptr)
1842 {
1843 console_state[dev_idx].console_access.address = strdup (cptr);
1844 if (!console_state[dev_idx].console_access.address)
1845 {
1846 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1847 __func__, __FILE__, __LINE__);
1848 #if defined(USE_BACKTRACE)
1849 # ifdef SIGUSR2
1850 (void)raise(SIGUSR2);
1851
1852 # endif
1853 #endif
1854 abort();
1855 }
1856 sim_msg ("\r[OPC emulation: OPC%d server address set to %s]\r\n",
1857 dev_idx, console_state[dev_idx].console_access.address);
1858 }
1859
1860 return SCPE_OK;
1861 }
1862
1863 static t_stat opc_show_console_address (UNUSED FILE * st, UNIT * uptr,
1864 UNUSED int val, UNUSED const void * desc)
1865 {
1866 int dev_idx = (int) OPC_UNIT_IDX (uptr);
1867 if (dev_idx < 0 || dev_idx >= N_OPC_UNITS_MAX)
1868 return SCPE_ARG;
1869 if (console_state[dev_idx].console_access.address)
1870 sim_printf("address : %s", console_state[dev_idx].console_access.address);
1871 else
1872 sim_printf("address : any");
1873 return SCPE_OK;
1874 }
1875
1876 static t_stat opc_set_console_pw (UNIT * uptr, UNUSED int32 value,
1877 const char * cptr, UNUSED void * desc)
1878 {
1879 long dev_idx = (int) OPC_UNIT_IDX (uptr);
1880 if (dev_idx < 0 || dev_idx >= N_OPC_UNITS_MAX)
1881 return SCPE_ARG;
1882
1883 if (cptr && (strlen(cptr) > 0))
1884 {
1885 char token[strlen (cptr)+1];
1886 int rc = sscanf (cptr, "%s", token);
1887 if (rc != 1)
1888 return SCPE_ARG;
1889 if (strlen (token) > PW_SIZE)
1890 return SCPE_ARG;
1891 strcpy (console_state[dev_idx].console_access.pw, token);
1892 }
1893 else
1894 {
1895 sim_msg ("no password\n");
1896 console_state[dev_idx].console_access.pw[0] = 0;
1897 }
1898
1899 return SCPE_OK;
1900 }
1901
1902 static t_stat opc_show_console_pw (UNUSED FILE * st, UNIT * uptr,
1903 UNUSED int val, UNUSED const void * desc)
1904 {
1905 int dev_idx = (int) OPC_UNIT_IDX (uptr);
1906 if (dev_idx < 0 || dev_idx >= N_OPC_UNITS_MAX)
1907 return SCPE_ARG;
1908 sim_printf("password : %s", console_state[dev_idx].console_access.pw);
1909 return SCPE_OK;
1910 }
1911
1912 static void console_putstr (int conUnitIdx, char * str)
1913 {
1914 size_t l = strlen (str);
1915 for (size_t i = 0; i < l; i ++)
1916 sim_putchar (str[i]);
1917 opc_state_t * csp = console_state + conUnitIdx;
1918 if (csp->console_access.loggedOn)
1919 accessStartWrite (csp->console_access.client, str,
1920 (ssize_t) l);
1921 }
1922
1923 static void consolePutchar0 (int conUnitIdx, char ch) {
1924 opc_state_t * csp = console_state + conUnitIdx;
1925 sim_putchar (ch);
1926 if (csp->console_access.loggedOn)
1927 accessStartWrite (csp->console_access.client, & ch, 1);
1928 }
1929
1930 static void console_putchar (int conUnitIdx, char ch) {
1931 opc_state_t * csp = console_state + conUnitIdx;
1932 if (csp->escapeSequence) {
1933 csp->escapeSequence = false;
1934 if (ch == '1') {
1935 if (csp->carrierPosition >= 1 && csp->carrierPosition <= 256) {
1936 csp->tabStops[csp->carrierPosition] = true;
1937 }
1938 } else if (ch == '2') {
1939 memset (csp->tabStops, 0, sizeof (csp->tabStops));
1940 } else {
1941 sim_warn ("Unrecognized escape sequence \\033\\%03o\r\n", ch);
1942 }
1943 } else if (isprint (ch)) {
1944 consolePutchar0 (conUnitIdx, ch);
1945 csp->carrierPosition ++;
1946 } else if (ch == '\t') {
1947 while (csp->carrierPosition < bufsize - 1) {
1948 consolePutchar0 (conUnitIdx, ' ');
1949 csp->carrierPosition ++;
1950 if (csp->tabStops[csp->carrierPosition])
1951 break;
1952 }
1953 } else if (ch == '\b') {
1954 consolePutchar0 (conUnitIdx, ch);
1955 csp->carrierPosition --;
1956 } else if (ch == '\f' || ch == '\r') {
1957 consolePutchar0 (conUnitIdx, ch);
1958 csp->carrierPosition = 1;
1959 } else if (ch == '\033') {
1960 csp->escapeSequence = true;
1961 } else {
1962 consolePutchar0 (conUnitIdx, ch);
1963 }
1964 }
1965
1966 static void consoleConnectPrompt (uv_tcp_t * client)
1967 {
1968 accessStartWriteStr (client, "password: \r\n");
1969 uv_access * console_access = (uv_access *) client->data;
1970 console_access->pwPos = 0;
1971 }
1972
1973 void startRemoteConsole (void)
1974 {
1975 for (int conUnitIdx = 0; conUnitIdx < N_OPC_UNITS_MAX; conUnitIdx ++)
1976 {
1977 console_state[conUnitIdx].console_access.connectPrompt = consoleConnectPrompt;
1978 console_state[conUnitIdx].console_access.connected = NULL;
1979 console_state[conUnitIdx].console_access.useTelnet = true;
1980 #ifdef CONSOLE_FIX
1981 # ifdef LOCKLESS
1982 lock_libuv ();
1983 # endif
1984 #endif
1985 uv_open_access (& console_state[conUnitIdx].console_access);
1986 #ifdef CONSOLE_FIX
1987 # ifdef LOCKLESS
1988 unlock_libuv ();
1989 # endif
1990 #endif
1991 }
1992 }