This source file includes following definitions.
- sim_con_poll_svc
- sim_con_reset
- sim_set_console
- sim_show_console
- sim_set_remote_console
- sim_show_remote_console
- sim_rem_con_poll_svc
- x_continue_cmd
- x_step_cmd
- x_run_cmd
- x_help_cmd
- _sim_rem_message
- _sim_rem_log_out
- sim_remote_process_command
- sim_rem_con_data_svc
- sim_rem_con_reset
- sim_set_rem_telnet
- sim_set_rem_connections
- sim_set_rem_timeout
- sim_set_kmap
- sim_show_kmap
- sim_set_pchar
- sim_set_cons_speed
- sim_show_cons_speed
- sim_set_logon
- sim_set_logoff
- sim_show_log
- sim_set_debon
- sim_debug_flush
- sim_set_deboff
- sim_show_debug
- sim_set_telnet
- sim_set_notelnet
- sim_show_telnet
- sim_set_cons_buff
- sim_set_cons_unbuff
- sim_set_cons_log
- sim_set_cons_nolog
- sim_show_cons_log
- sim_show_cons_buff
- sim_show_cons_expect
- sim_open_logfile
- sim_close_logfile
- sim_logfile_name
- sim_check_console
- sim_cons_get_send
- sim_cons_get_expect
- sim_show_cons_send_input
- sim_poll_kbd
- sim_putchar
- sim_ttinit
- sim_ttrun
- sim_ttcmd
- sim_ttclose
- sim_ttisatty
- ControlHandler
- sim_os_ttinit
- sim_os_ttrun
- sim_os_ttcmd
- sim_os_ttclose
- sim_os_ttisatty
- sim_os_poll_kbd
- sim_os_putchar
- sim_os_ttinit
- sim_os_ttrun
- sim_os_ttcmd
- sim_os_ttclose
- sim_os_ttisatty
- sim_os_poll_kbd
- sim_os_putchar
- sim_os_ttinit
- sim_os_ttrun
- sim_os_ttcmd
- sim_os_ttclose
- sim_os_ttisatty
- sim_os_poll_kbd
- sim_os_putchar
- decode
- sim_set_halt
- sim_set_response
- sim_set_delay
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 #include "sim_defs.h"
79 #include "sim_tmxr.h"
80 #include "sim_timer.h"
81 #include <ctype.h>
82 #include <signal.h>
83 #include <math.h>
84
85 #define DBG_CTR 0
86
87 #include "../dps8/dps8.h"
88
89 #if defined(__HAIKU__)
90 # define nice(n) ({})
91 #endif
92
93 #if defined(TESTING)
94 # include "../dps8/dps8_cpu.h"
95 #endif
96
97 #define FREE(p) do \
98 { \
99 free((p)); \
100 (p) = NULL; \
101 } while(0)
102
103
104
105 static t_stat sim_os_poll_kbd (void);
106 static t_stat sim_os_putchar (int32 out);
107 static t_stat sim_os_ttinit (void);
108 static t_stat sim_os_ttrun (void);
109 static t_stat sim_os_ttcmd (void);
110 static t_stat sim_os_ttclose (void);
111 static t_bool sim_os_ttisatty (void);
112
113 static t_stat sim_set_rem_telnet (int32 flag, CONST char *cptr);
114 static t_stat sim_set_rem_connections (int32 flag, CONST char *cptr);
115 static t_stat sim_set_rem_timeout (int32 flag, CONST char *cptr);
116
117
118 static t_stat sim_set_halt (int32 flag, CONST char *cptr);
119 static t_stat sim_set_response (int32 flag, CONST char *cptr);
120 static t_stat sim_set_delay (int32 flag, CONST char *cptr);
121
122 #define KMAP_WRU 0
123 #define KMAP_BRK 1
124 #define KMAP_DEL 2
125 #define KMAP_MASK 0377
126 #define KMAP_NZ 0400
127
128 int32 sim_int_char = 005;
129 int32 sim_brk_char = 000;
130 int32 sim_tt_pchar = 0x00002780;
131 #if defined (_WIN32)
132 int32 sim_del_char = '\b';
133 #else
134 int32 sim_del_char = 0177;
135 #endif
136
137 static t_stat sim_con_poll_svc (UNIT *uptr);
138 static t_stat sim_con_reset (DEVICE *dptr);
139 UNIT sim_con_unit = { UDATA (&sim_con_poll_svc, 0, 0) };
140
141
142 #define DBG_TRC TMXR_DBG_TRC
143 #define DBG_XMT TMXR_DBG_XMT
144 #define DBG_RCV TMXR_DBG_RCV
145 #define DBG_RET TMXR_DBG_RET
146 #define DBG_ASY TMXR_DBG_ASY
147 #define DBG_EXP 0x00000001
148 #define DBG_SND 0x00000002
149
150 static DEBTAB sim_con_debug[] = {
151 {"TRC", DBG_TRC},
152 {"XMT", DBG_XMT},
153 {"RCV", DBG_RCV},
154 {"RET", DBG_RET},
155 {"ASY", DBG_ASY},
156 {"EXP", DBG_EXP},
157 {"SND", DBG_SND},
158 {0}
159 };
160
161 static REG sim_con_reg[] = {
162 { ORDATAD (WRU, sim_int_char, 8, "interrupt character") },
163 { ORDATAD (BRK, sim_brk_char, 8, "break character") },
164 { ORDATAD (DEL, sim_del_char, 8, "delete character ") },
165 { ORDATAD (PCHAR, sim_tt_pchar, 32, "printable character mask") },
166 { 0 },
167 };
168
169 static MTAB sim_con_mod[] = {
170 { 0 },
171 };
172
173 DEVICE sim_con_telnet = {
174 "CON-TEL", &sim_con_unit, sim_con_reg, sim_con_mod,
175 1, 0, 0, 0, 0, 0,
176 NULL, NULL, sim_con_reset, NULL, NULL, NULL,
177 NULL, DEV_DEBUG, 0, sim_con_debug};
178 TMLN sim_con_ldsc = { 0 };
179 TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc, NULL, &sim_con_telnet };
180
181 SEND sim_con_send = {SEND_DEFAULT_DELAY, &sim_con_telnet, DBG_SND};
182 EXPECT sim_con_expect = {&sim_con_telnet, DBG_EXP};
183
184 static t_bool sim_con_console_port = TRUE;
185
186
187
188 static t_stat sim_con_poll_svc (UNIT *uptr)
189 {
190 if ((sim_con_tmxr.master == 0) &&
191 (sim_con_ldsc.serport == 0) &&
192
193 (sim_con_console_port))
194 return SCPE_OK;
195 if (tmxr_poll_conn (&sim_con_tmxr) >= 0)
196 sim_con_ldsc.rcve = 1;
197 sim_activate_after(uptr, 1000000);
198
199 if (!sim_con_console_port)
200 sim_poll_kbd();
201 if (sim_con_ldsc.conn)
202 tmxr_send_buffered_data (&sim_con_ldsc);
203 return SCPE_OK;
204 }
205
206 static t_stat sim_con_reset (DEVICE *dptr)
207 {
208 return sim_con_poll_svc (&dptr->units[0]);
209 }
210
211
212
213 static CTAB set_con_tab[] = {
214 { "WRU", &sim_set_kmap, KMAP_WRU | KMAP_NZ },
215 { "BRK", &sim_set_kmap, KMAP_BRK },
216 { "DEL", &sim_set_kmap, KMAP_DEL |KMAP_NZ },
217 { "PCHAR", &sim_set_pchar, 0 },
218 { "SPEED", &sim_set_cons_speed, 0 },
219 { "TELNET", &sim_set_telnet, 0 },
220 { "NOTELNET", &sim_set_notelnet, 0 },
221 { "LOG", &sim_set_logon, 0 },
222 { "NOLOG", &sim_set_logoff, 0 },
223 { "DEBUG", &sim_set_debon, 0 },
224 { "NODEBUG", &sim_set_deboff, 0 },
225 #define CMD_WANTSTR 0100000
226 { "HALT", &sim_set_halt, 1 | CMD_WANTSTR },
227 { "NOHALT", &sim_set_halt, 0 },
228 { "DELAY", &sim_set_delay, 0 },
229 { "RESPONSE", &sim_set_response, 1 | CMD_WANTSTR },
230 { "NORESPONSE", &sim_set_response, 0 },
231 { NULL, NULL, 0 }
232 };
233
234 static CTAB set_rem_con_tab[] = {
235 { "CONNECTIONS", &sim_set_rem_connections, 0 },
236 { "TELNET", &sim_set_rem_telnet, 1 },
237 { "NOTELNET", &sim_set_rem_telnet, 0 },
238 { "TIMEOUT", &sim_set_rem_timeout, 0 },
239 { NULL, NULL, 0 }
240 };
241
242 static SHTAB show_con_tab[] = {
243 { "WRU", &sim_show_kmap, KMAP_WRU },
244 { "BRK", &sim_show_kmap, KMAP_BRK },
245 { "DEL", &sim_show_kmap, KMAP_DEL },
246 { "SPEED", &sim_show_cons_speed, 0 },
247 { "LOG", &sim_show_cons_log, 0 },
248 { "TELNET", &sim_show_telnet, 0 },
249 { "BUFFERED", &sim_show_cons_buff, 0 },
250 { "EXPECT", &sim_show_cons_expect, 0 },
251 { "HALT", &sim_show_cons_expect, 0 },
252 { "INPUT", &sim_show_cons_send_input, 0 },
253 { "RESPONSE", &sim_show_cons_send_input, 0 },
254 { "DELAY", &sim_show_cons_expect, 0 },
255 { NULL, NULL, 0 }
256 };
257
258 static CTAB set_con_telnet_tab[] = {
259 { "LOG", &sim_set_cons_log, 0 },
260 { "NOLOG", &sim_set_cons_nolog, 0 },
261 { "BUFFERED", &sim_set_cons_buff, 0 },
262 { "NOBUFFERED", &sim_set_cons_unbuff, 0 },
263 { "UNBUFFERED", &sim_set_cons_unbuff, 0 },
264 { NULL, NULL, 0 }
265 };
266
267 static int32 *cons_kmap[] = {
268 &sim_int_char,
269 &sim_brk_char,
270 &sim_del_char
271 };
272
273
274
275
276
277
278
279
280
281
282
283 t_stat sim_set_console (int32 flag, CONST char *cptr)
284 {
285 char *cvptr, gbuf[CBUFSIZE];
286 CTAB *ctptr;
287 t_stat r;
288
289 if ((cptr == NULL) || (*cptr == 0))
290 return SCPE_2FARG;
291 while (*cptr != 0) {
292 cptr = get_glyph_nc (cptr, gbuf, ',');
293 if ((cvptr = strchr (gbuf, '=')))
294 *cvptr++ = 0;
295 (void)get_glyph (gbuf, gbuf, 0);
296 if ((ctptr = find_ctab (set_con_tab, gbuf))) {
297 r = ctptr->action (ctptr->arg, cvptr);
298 if (r != SCPE_OK)
299 return r;
300 }
301 else return SCPE_NOPARAM;
302 }
303 return SCPE_OK;
304 }
305
306
307
308 t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
309 {
310 char gbuf[CBUFSIZE];
311 SHTAB *shptr;
312 int32 i;
313
314 if (*cptr == 0) {
315 for (i = 0; show_con_tab[i].name; i++)
316 show_con_tab[i].action (st, dptr, uptr, show_con_tab[i].arg, cptr);
317 return SCPE_OK;
318 }
319 while (*cptr != 0) {
320 cptr = get_glyph (cptr, gbuf, ',');
321 if ((shptr = find_shtab (show_con_tab, gbuf)))
322 shptr->action (st, dptr, uptr, shptr->arg, NULL);
323 else return SCPE_NOPARAM;
324 }
325 return SCPE_OK;
326 }
327
328 t_stat sim_rem_con_poll_svc (UNIT *uptr);
329 t_stat sim_rem_con_data_svc (UNIT *uptr);
330 t_stat sim_rem_con_reset (DEVICE *dptr);
331 UNIT sim_rem_con_unit[2] = {
332 { UDATA (&sim_rem_con_poll_svc, UNIT_IDLE, 0) },
333 { UDATA (&sim_rem_con_data_svc, UNIT_IDLE, 0) }};
334
335 DEBTAB sim_rem_con_debug[] = {
336 {"TRC", DBG_TRC},
337 {"XMT", DBG_XMT},
338 {"RCV", DBG_RCV},
339 {0}
340 };
341
342 MTAB sim_rem_con_mod[] = {
343 { 0 },
344 };
345
346 DEVICE sim_remote_console = {
347 "REM-CON", sim_rem_con_unit, NULL, sim_rem_con_mod,
348 2, 0, 0, 0, 0, 0,
349 NULL, NULL, sim_rem_con_reset, NULL, NULL, NULL,
350 NULL, DEV_DEBUG | DEV_NOSAVE, 0, sim_rem_con_debug};
351 #define MAX_REMOTE_SESSIONS 40
352 static int32 *sim_rem_buf_size = NULL;
353 static int32 *sim_rem_buf_ptr = NULL;
354 static char **sim_rem_buf = NULL;
355 static t_bool *sim_rem_single_mode = NULL;
356 static TMXR sim_rem_con_tmxr = { 0, 0, 0, NULL, NULL, &sim_remote_console };
357 static uint32 sim_rem_read_timeout = 30;
358 static uint32 *sim_rem_read_timeouts = NULL;
359 static int32 sim_rem_active_number = -1;
360 int32 sim_rem_cmd_active_line = -1;
361 static CTAB *sim_rem_active_command = NULL;
362 static char *sim_rem_command_buf;
363 static t_bool sim_log_temp = FALSE;
364 static char sim_rem_con_temp_name[PATH_MAX+1];
365 static t_bool sim_rem_master_mode = FALSE;
366 static t_bool sim_rem_master_was_enabled = FALSE;
367 static t_bool sim_rem_master_was_connected = FALSE;
368 static t_offset sim_rem_cmd_log_start = 0;
369
370
371
372 t_stat sim_set_remote_console (int32 flag, CONST char *cptr)
373 {
374 char *cvptr, gbuf[CBUFSIZE];
375 CTAB *ctptr;
376 t_stat r;
377
378 if ((cptr == NULL) || (*cptr == 0))
379 return SCPE_2FARG;
380 while (*cptr != 0) {
381 cptr = get_glyph_nc (cptr, gbuf, ',');
382 if ((cvptr = strchr (gbuf, '=')))
383 *cvptr++ = 0;
384 (void)get_glyph (gbuf, gbuf, 0);
385 if ((ctptr = find_ctab (set_rem_con_tab, gbuf))) {
386 r = ctptr->action (ctptr->arg, cvptr);
387 if (r != SCPE_OK)
388 return r;
389 }
390 else return SCPE_NOPARAM;
391 }
392 return SCPE_OK;
393 }
394
395
396
397 t_stat sim_show_remote_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
398 {
399 int32 i, connections;
400 TMLN *lp;
401
402 if (*cptr != 0)
403 return SCPE_NOPARAM;
404 if (sim_rem_active_number >= 0) {
405 if (sim_rem_master_mode && (sim_rem_active_number == 0))
406 fprintf (st, "Running from Master Mode Remote Console Connection\n");
407 else
408 fprintf (st, "Running from Remote Console Connection %lu\n",
409 (unsigned long)sim_rem_active_number);
410 }
411 if (sim_rem_con_tmxr.lines > 1)
412 fprintf (st, "Remote Console Input Connections from %lu sources are supported concurrently\n",
413 (unsigned long)sim_rem_con_tmxr.lines);
414 if (sim_rem_read_timeout)
415 fprintf (st, "Remote Console Input automatically continues after %lu seconds\n",
416 (unsigned long)sim_rem_read_timeout);
417 if (!sim_rem_con_tmxr.master)
418 fprintf (st, "Remote Console Command input is disabled\n");
419 else
420 fprintf (st, "Remote Console Command Input listening on TCP port: %s\n",
421 sim_rem_con_unit[0].filename);
422 for (i=connections=0; i<sim_rem_con_tmxr.lines; i++) {
423 lp = &sim_rem_con_tmxr.ldsc[i];
424 if (!lp->conn)
425 continue;
426 ++connections;
427 if (connections == 1)
428 fprintf (st, "Remote Console Connections:\n");
429 tmxr_fconns (st, lp, i);
430 if (sim_rem_read_timeouts[i] != sim_rem_read_timeout) {
431 if (sim_rem_read_timeouts[i])
432 fprintf (st, "Remote Console Input on connection %lu automatically continues after %lu seconds\n",
433 (unsigned long)i, (unsigned long)sim_rem_read_timeouts[i]);
434 else
435 fprintf (st, "Remote Console Input on connection %lu does not continue automatically\n",
436 (unsigned long)i);
437 }
438 }
439 return SCPE_OK;
440 }
441
442
443
444 t_stat sim_rem_con_poll_svc (UNIT *uptr)
445 {
446 int32 c;
447
448 c = tmxr_poll_conn (&sim_rem_con_tmxr);
449 if (c >= 0) {
450 TMLN *lp = &sim_rem_con_tmxr.ldsc[c];
451 char wru_name[8];
452
453 sim_activate_after(uptr + 1, 1000000);
454 lp->rcve = 1;
455 sim_rem_buf_ptr[c] = 0;
456 sim_rem_single_mode[c] = TRUE;
457 sim_rem_read_timeouts[c] = sim_rem_read_timeout;
458 if (isprint(sim_int_char & 0xFF))
459 (void)sprintf(wru_name, "'%c'", sim_int_char & 0xFF);
460 else
461 if (sim_int_char <= 26)
462 (void)sprintf(wru_name, "^%c", '@' + (sim_int_char & 0xFF));
463 else
464 (void)sprintf(wru_name, "'\\%03o'", sim_int_char & 0xFF);
465 tmxr_linemsgf (lp, "%s Remote Console\r\n"
466 "Enter single commands or to enter multiple command mode enter the %s character\r"
467 "%s",
468 sim_name, wru_name,
469 ((sim_rem_master_mode && (c == 0)) ? "" : "\nSimulator Running..."));
470 if (sim_rem_master_mode && (c == 0))
471 sim_rem_single_mode[c] = FALSE;
472 tmxr_send_buffered_data (lp);
473 }
474 sim_activate_after(uptr, 1000000);
475 if (sim_con_ldsc.conn)
476 tmxr_send_buffered_data (&sim_con_ldsc);
477 return SCPE_OK;
478 }
479
480 static t_stat x_continue_cmd (int32 flag, CONST char *cptr)
481 {
482 return SCPE_IERR;
483 }
484
485 static t_stat x_step_cmd (int32 flag, CONST char *cptr)
486 {
487 return SCPE_IERR;
488 }
489
490 static t_stat x_run_cmd (int32 flag, CONST char *cptr)
491 {
492 return SCPE_IERR;
493 }
494
495 static t_stat x_help_cmd (int32 flag, CONST char *cptr);
496
497 static CTAB allowed_remote_cmds[] = {
498 { "EXAMINE", &exdep_cmd, EX_E },
499 { "DEPOSIT", &exdep_cmd, EX_D },
500 { "EVALUATE", &eval_cmd, 0 },
501 { "ATTACH", &attach_cmd, 0 },
502 { "DETACH", &detach_cmd, 0 },
503
504
505
506
507 { "CONTINUE", &x_continue_cmd, 0 },
508 { "STEP", &x_step_cmd, 0 },
509 { "ECHO", &echo_cmd, 0 },
510 { "SET", &set_cmd, 0 },
511 { "SHOW", &show_cmd, 0 },
512 { "HELP", &x_help_cmd, 0 },
513 { NULL, NULL }
514 };
515
516 static CTAB allowed_master_remote_cmds[] = {
517 { "EXAMINE", &exdep_cmd, EX_E },
518 { "DEPOSIT", &exdep_cmd, EX_D },
519 { "EVALUATE", &eval_cmd, 0 },
520 { "ATTACH", &attach_cmd, 0 },
521 { "DETACH", &detach_cmd, 0 },
522
523
524
525
526 { "CONTINUE", &x_continue_cmd, 0 },
527 { "STEP", &x_step_cmd, 0 },
528 { "ECHO", &echo_cmd, 0 },
529 { "SET", &set_cmd, 0 },
530 { "SHOW", &show_cmd, 0 },
531 { "HELP", &x_help_cmd, 0 },
532 { "EXIT", &exit_cmd, 0 },
533 { "QUIT", &exit_cmd, 0 },
534 { "RUN", &x_run_cmd, RU_RUN },
535 { "GO", &x_run_cmd, RU_GO },
536 { "BOOT", &x_run_cmd, RU_BOOT },
537 { "BREAK", &brk_cmd, SSH_ST },
538 { "NOBREAK", &brk_cmd, SSH_CL },
539 { NULL, NULL }
540 };
541
542 static CTAB allowed_single_remote_cmds[] = {
543 { "ATTACH", &attach_cmd, 0 },
544 { "DETACH", &detach_cmd, 0 },
545 { "EXAMINE", &exdep_cmd, EX_E },
546 { "EVALUATE", &eval_cmd, 0 },
547 { "ECHO", &echo_cmd, 0 },
548 { "SHOW", &show_cmd, 0 },
549 { "HELP", &x_help_cmd, 0 },
550 { NULL, NULL }
551 };
552
553 static t_stat x_help_cmd (int32 flag, CONST char *cptr)
554 {
555 CTAB *cmdp, *cmdph;
556
557 if (*cptr) {
558 int32 saved_switches = sim_switches;
559 t_stat r;
560
561 sim_switches |= SWMASK ('F');
562 r = help_cmd (flag, cptr);
563 sim_switches = saved_switches;
564 return r;
565 }
566 sim_printf ("Help is available for the following Remote Console commands:\r\n");
567 for (cmdp=allowed_remote_cmds; cmdp->name != NULL; ++cmdp) {
568 cmdph = find_cmd (cmdp->name);
569 if (cmdph && cmdph->help)
570 sim_printf (" %s\r\n", cmdp->name);
571 }
572 sim_printf ("Enter \"HELP cmd\" for detailed help on a command\r\n");
573 return SCPE_OK;
574 }
575
576 static t_stat _sim_rem_message (const char *cmd, t_stat stat)
577 {
578 CTAB *cmdp = NULL;
579 t_stat stat_nomessage = stat & SCPE_NOMESSAGE;
580
581 cmdp = find_cmd (cmd);
582 stat = SCPE_BARE_STATUS(stat);
583 if (!stat_nomessage) {
584 if (cmdp && (cmdp->message))
585 cmdp->message (NULL, stat);
586 else {
587 if (stat >= SCPE_BASE)
588 sim_printf ("%s\r\n", sim_error_text (stat));
589 }
590 }
591 return stat;
592 }
593
594 static void _sim_rem_log_out (TMLN *lp)
595 {
596 char cbuf[4*CBUFSIZE];
597
598 if (sim_log) {
599 size_t unwritten;
600
601 (void)fflush (sim_log);
602 (void)sim_fseeko (sim_log, sim_rem_cmd_log_start, SEEK_SET);
603 cbuf[sizeof(cbuf)-1] = '\0';
604 while (fgets (cbuf, sizeof(cbuf)-1, sim_log))
605 tmxr_linemsgf (lp, "%s", cbuf);
606 if (!tmxr_input_pending_ln (lp)) {
607 do {
608 unwritten = tmxr_send_buffered_data (lp);
609 if (unwritten == lp->txbsz)
610 sim_os_ms_sleep (100);
611 } while (unwritten == lp->txbsz);
612 }
613 }
614 }
615
616 void sim_remote_process_command (void)
617 {
618 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], *argv[1] = {NULL};
619 CONST char *cptr;
620 int32 saved_switches = sim_switches;
621 t_stat stat;
622
623 strcpy (cbuf, sim_rem_command_buf);
624 while (isspace((unsigned char)cbuf[0]))
625 memmove (cbuf, cbuf+1, strlen(cbuf+1)+1);
626 sim_sub_args (cbuf, sizeof(cbuf), argv);
627 cptr = cbuf;
628 cptr = get_glyph (cptr, gbuf, 0);
629 sim_rem_active_command = find_cmd (gbuf);
630
631 sim_ttcmd ();
632 stat = sim_rem_active_command->action (sim_rem_active_command->arg, cptr);
633 if (stat != SCPE_OK)
634 stat = _sim_rem_message (gbuf, stat);
635 sim_last_cmd_stat = SCPE_BARE_STATUS(stat);
636 sim_ttrun ();
637 sim_cancel (&sim_rem_con_unit[1]);
638 sim_activate (&sim_rem_con_unit[1], -1);
639 sim_switches = saved_switches;
640 }
641
642
643
644 t_stat sim_rem_con_data_svc (UNIT *uptr)
645 {
646 int32 i, j, c = 0;
647 t_stat stat = SCPE_OK;
648 int32 steps = 0;
649 t_bool was_active_command = (sim_rem_cmd_active_line != -1);
650 t_bool got_command;
651 t_bool close_session = FALSE;
652 TMLN *lp;
653 char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], *argv[1] = {NULL};
654 CONST char *cptr;
655 CTAB *cmdp = NULL;
656 CTAB *basecmdp = NULL;
657 uint32 read_start_time = 0;
658 #if defined(TESTING)
659 cpu_state_t * cpup = _cpup;
660 #endif
661
662 tmxr_poll_rx (&sim_rem_con_tmxr);
663 for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
664 (i < sim_rem_con_tmxr.lines);
665 i++) {
666 t_bool master_session = (sim_rem_master_mode && (i == 0));
667
668 lp = &sim_rem_con_tmxr.ldsc[i];
669 if (!lp->conn)
670 continue;
671 if (master_session && !sim_rem_master_was_connected) {
672 tmxr_linemsgf (lp, "\nMaster Mode Session\r\n");
673 tmxr_send_buffered_data (lp);
674 }
675 sim_rem_master_was_connected |= master_session;
676 stat = SCPE_OK;
677 if ((was_active_command) ||
678 (master_session && !sim_rem_single_mode[i])) {
679 if (was_active_command) {
680 sim_rem_cmd_active_line = -1;
681 if (!sim_rem_active_command) {
682 stat = SCPE_STEP;
683 _sim_rem_message ("STEP", stat);
684 }
685 _sim_rem_log_out (lp);
686 sim_rem_active_command = NULL;
687 was_active_command = FALSE;
688 i = -1;
689 continue;
690 }
691 else {
692 sim_is_running = 0;
693 sim_stop_timer_services ();
694 for (j=0; j < sim_rem_con_tmxr.lines; j++) {
695 TMLN *lpj = &sim_rem_con_tmxr.ldsc[j];
696 if ((i == j) || (!lpj->conn))
697 continue;
698 tmxr_linemsgf (lpj, "\nRemote Master Console(%s) Entering Commands\n", lp->ipad);
699 tmxr_send_buffered_data (lpj);
700 }
701 lp = &sim_rem_con_tmxr.ldsc[i];
702 }
703 }
704 else {
705 c = tmxr_getc_ln (lp);
706 if (!(TMXR_VALID & c))
707 continue;
708 c = c & ~TMXR_VALID;
709 if (sim_rem_single_mode[i]) {
710 if (c == sim_int_char) {
711 sim_rem_single_mode[i] = FALSE;
712 sim_is_running = 0;
713 sim_stop_timer_services ();
714 stat = SCPE_STOP;
715 _sim_rem_message ("RUN", stat);
716 _sim_rem_log_out (lp);
717 for (j=0; j < sim_rem_con_tmxr.lines; j++) {
718 TMLN *lpj = &sim_rem_con_tmxr.ldsc[j];
719 if ((i == j) || (!lpj->conn))
720 continue;
721 tmxr_linemsgf (lpj, "\nRemote Console %lu(%s) Entering Commands\n",
722 (unsigned long)i, lp->ipad);
723 tmxr_send_buffered_data (lpj);
724 }
725 lp = &sim_rem_con_tmxr.ldsc[i];
726 if (!master_session)
727 tmxr_linemsg (lp, "\r\nSimulator paused.\r\n");
728 if (!master_session && sim_rem_read_timeouts[i]) {
729 tmxr_linemsgf (lp, "Simulation will resume automatically if input is not received in %lu seconds\n",
730 (unsigned long)sim_rem_read_timeouts[i]);
731 tmxr_linemsgf (lp, "\r\n");
732 tmxr_send_buffered_data (lp);
733 }
734 }
735 else {
736 if ((sim_rem_buf_ptr[i] == 0) &&
737 ((c == '\n') ||
738 (c == '\r')))
739 continue;
740 if ((c == '\004') || (c == '\032')) {
741 tmxr_linemsgf (lp, "\r\nGoodbye\r\n");
742 tmxr_send_buffered_data (lp);
743 tmxr_reset_ln (lp);
744 continue;
745 }
746 if (sim_rem_buf_ptr[i] == 0) {
747
748 if (!master_session)
749 tmxr_linemsgf (lp, "\r\n%s", sim_prompt);
750 else
751 tmxr_linemsgf (lp, "\r\n%s", sim_is_running ? "SIM> " : "sim> ");
752 sim_debug (DBG_XMT, &sim_remote_console, "Prompt Written: %s\n", sim_is_running ? "SIM> " : "sim> ");
753 if (!tmxr_input_pending_ln (lp))
754 tmxr_send_buffered_data (lp);
755 }
756 }
757 }
758 }
759 got_command = FALSE;
760 while (1) {
761 if (stat == SCPE_EXIT)
762 return stat|SCPE_NOMESSAGE;
763 if (!sim_rem_single_mode[i]) {
764 read_start_time = sim_os_msec();
765 if (master_session)
766 tmxr_linemsg (lp, "sim> ");
767 else
768 tmxr_linemsg (lp, sim_prompt);
769 tmxr_send_buffered_data (lp);
770 }
771 do {
772 if (!sim_rem_single_mode[i]) {
773 c = tmxr_getc_ln (lp);
774 if (!(TMXR_VALID & c)) {
775 tmxr_send_buffered_data (lp);
776 if (!master_session &&
777 sim_rem_read_timeouts[i] &&
778 ((sim_os_msec() - read_start_time)/1000 >= sim_rem_read_timeouts[i])) {
779 while (sim_rem_buf_ptr[i] > 0) {
780 tmxr_linemsg (lp, "\b \b");
781 --sim_rem_buf_ptr[i];
782 }
783 if (sim_rem_buf_ptr[i]+80 >= sim_rem_buf_size[i]) {
784 sim_rem_buf_size[i] += 1024;
785 sim_rem_buf[i] = (char *)realloc (sim_rem_buf[i], sim_rem_buf_size[i]);
786 }
787 strcpy (sim_rem_buf[i], "CONTINUE ! Automatic continue due to timeout");
788 tmxr_linemsgf (lp, "%s\n", sim_rem_buf[i]);
789 got_command = TRUE;
790 break;
791 }
792 sim_os_ms_sleep (50);
793 tmxr_poll_rx (&sim_rem_con_tmxr);
794 if (!lp->conn) {
795 sim_rem_single_mode[i] = TRUE;
796 break;
797 }
798 continue;
799 }
800 read_start_time = sim_os_msec();
801 c = c & ~TMXR_VALID;
802 }
803 switch (c) {
804 case 0:
805 break;
806 case '\b':
807 case 127:
808 if (sim_rem_buf_ptr[i] > 0) {
809 tmxr_linemsg (lp, "\b \b");
810 --sim_rem_buf_ptr[i];
811 }
812 break;
813 case 27:
814 case 21:
815 while (sim_rem_buf_ptr[i] > 0) {
816 tmxr_linemsg (lp, "\b \b");
817 --sim_rem_buf_ptr[i];
818 }
819 break;
820 case '\n':
821 if (sim_rem_buf_ptr[i] == 0)
822 break;
823
824 case '\r':
825 tmxr_linemsg (lp, "\r\n");
826 if (sim_rem_buf_ptr[i]+1 >= sim_rem_buf_size[i]) {
827 sim_rem_buf_size[i] += 1024;
828 sim_rem_buf[i] = (char *)realloc (sim_rem_buf[i], sim_rem_buf_size[i]);
829 }
830 sim_rem_buf[i][sim_rem_buf_ptr[i]++] = '\0';
831 sim_debug (DBG_RCV, &sim_remote_console,
832 "Got Command (%lu bytes still in buffer): %s\n",
833 (unsigned long)tmxr_input_pending_ln (lp), sim_rem_buf[i]);
834 got_command = TRUE;
835 break;
836 case '\004':
837 case '\032':
838 while (sim_rem_buf_ptr[i] > 0) {
839 tmxr_linemsg (lp, "\b \b");
840 --sim_rem_buf_ptr[i];
841 }
842 if (!sim_rem_single_mode[i]) {
843 if (sim_rem_buf_ptr[i]+80 >= sim_rem_buf_size[i]) {
844 sim_rem_buf_size[i] += 1024;
845 sim_rem_buf[i] = (char *)realloc (sim_rem_buf[i], sim_rem_buf_size[i]);
846 }
847 strcpy (sim_rem_buf[i], "CONTINUE ! Automatic continue before close");
848 tmxr_linemsgf (lp, "%s\n", sim_rem_buf[i]);
849 got_command = TRUE;
850 }
851 close_session = TRUE;
852 break;
853 default:
854 tmxr_putc_ln (lp, c);
855 if (sim_rem_buf_ptr[i]+2 >= sim_rem_buf_size[i]) {
856 sim_rem_buf_size[i] += 1024;
857 sim_rem_buf[i] = (char *)realloc (sim_rem_buf[i], sim_rem_buf_size[i]);
858 }
859 sim_rem_buf[i][sim_rem_buf_ptr[i]++] = (char)c;
860 sim_rem_buf[i][sim_rem_buf_ptr[i]] = '\0';
861 if (((size_t)sim_rem_buf_ptr[i]) >= sizeof(cbuf))
862 got_command = TRUE;
863 break;
864 }
865 c = 0;
866 if ((!got_command) && (sim_rem_single_mode[i]) && (tmxr_input_pending_ln (lp))) {
867 c = tmxr_getc_ln (lp);
868 c = c & ~TMXR_VALID;
869 }
870 } while ((!got_command) && ((!sim_rem_single_mode[i]) || c));
871 if (!tmxr_input_pending_ln (lp))
872 tmxr_send_buffered_data (lp);
873 if ((sim_rem_single_mode[i]) && !got_command) {
874 break;
875 }
876 sim_printf ("Remote Console Command from %s> %s\r\n", lp->ipad, sim_rem_buf[i]);
877 got_command = FALSE;
878 if (strlen(sim_rem_buf[i]) >= sizeof(cbuf)) {
879 sim_printf ("\r\nLine too long. Ignored. Continuing Simulator execution\r\n");
880 tmxr_linemsgf (lp, "\nLine too long. Ignored. Continuing Simulator execution\n");
881 tmxr_send_buffered_data (lp);
882 break;
883 }
884 strcpy (cbuf, sim_rem_buf[i]);
885 sim_rem_buf_ptr[i] = 0;
886 sim_rem_buf[i][sim_rem_buf_ptr[i]] = '\0';
887 while (isspace((unsigned char)cbuf[0]))
888 memmove (cbuf, cbuf+1, strlen(cbuf+1)+1);
889 if (cbuf[0] == '\0') {
890 if (sim_rem_single_mode[i]) {
891 sim_rem_single_mode[i] = FALSE;
892 break;
893 }
894 else
895 continue;
896 }
897 strcpy (sim_rem_command_buf, cbuf);
898 sim_sub_args (cbuf, sizeof(cbuf), argv);
899 cptr = cbuf;
900 cptr = get_glyph (cptr, gbuf, 0);
901 sim_switches = 0;
902 sim_rem_active_number = i;
903 if (!sim_log) {
904 int32 save_quiet = sim_quiet;
905
906 sim_quiet = 1;
907 (void)sprintf (sim_rem_con_temp_name, "sim_remote_console_%d.temporary_log", (int)getpid());
908 sim_set_logon (0, sim_rem_con_temp_name);
909 sim_quiet = save_quiet;
910 sim_log_temp = TRUE;
911 }
912 sim_rem_cmd_log_start = sim_ftell (sim_log);
913 basecmdp = find_cmd (gbuf);
914 if (basecmdp == NULL) {
915 if ((gbuf[0] == ';') || (gbuf[0] == '#')) {
916 sim_rem_cmd_active_line = i;
917 was_active_command = TRUE;
918 sim_rem_active_command = &allowed_single_remote_cmds[0];
919 i = i - 1;
920 break;
921 }
922 else
923 stat = SCPE_UNK;
924 }
925 else {
926 if ((cmdp = find_ctab (
927 sim_rem_single_mode[i] ? allowed_single_remote_cmds : \
928 (master_session ? allowed_master_remote_cmds : \
929 allowed_remote_cmds), gbuf))) {
930 if (cmdp->action == &x_continue_cmd)
931 stat = SCPE_OK;
932 else {
933 if (cmdp->action == &exit_cmd)
934 return SCPE_EXIT;
935 if (cmdp->action == &x_step_cmd) {
936 steps = 1;
937 stat = SCPE_OK;
938 if (*cptr != 0) {
939 cptr = get_glyph (cptr, gbuf, 0);
940 if (*cptr != 0)
941 stat = SCPE_2MARG;
942 else {
943 steps = (int32) get_uint (gbuf, 10, INT_MAX, &stat);
944 if ((stat != SCPE_OK) || (steps <= 0))
945 stat = SCPE_ARG;
946 }
947 }
948 if (stat != SCPE_OK)
949 cmdp = NULL;
950 }
951 else {
952 if (cmdp->action == &x_run_cmd) {
953 sim_switches |= SIM_SW_HIDE;
954 stat = basecmdp->action (cmdp->arg, cptr);
955 sim_switches &= ~SIM_SW_HIDE;
956 if (stat == SCPE_OK) {
957
958 cmdp = find_ctab (allowed_master_remote_cmds, "CONTINUE");
959 }
960 }
961 else
962 stat = SCPE_REMOTE;
963 }
964 }
965 }
966 else
967 stat = SCPE_INVREM;
968 }
969 sim_rem_active_number = -1;
970 if ((stat != SCPE_OK) && (stat != SCPE_REMOTE))
971 stat = _sim_rem_message (gbuf, stat);
972 _sim_rem_log_out (lp);
973 if (master_session && !sim_rem_master_mode) {
974 sim_rem_single_mode[i] = TRUE;
975 return SCPE_STOP;
976 }
977 if (cmdp && (cmdp->action == &x_continue_cmd)) {
978 sim_rem_cmd_active_line = -1;
979 if (sim_log_temp &&
980 (!sim_rem_master_mode)) {
981 int32 save_quiet = sim_quiet;
982
983 sim_quiet = 1;
984 sim_set_logoff (0, NULL);
985 sim_quiet = save_quiet;
986 remove (sim_rem_con_temp_name);
987 sim_log_temp = FALSE;
988 }
989 else {
990 (void)fflush (sim_log);
991 sim_rem_cmd_log_start = sim_ftell (sim_log);
992 }
993 if (!sim_rem_single_mode[i]) {
994 tmxr_linemsg (lp, "Simulator Running...");
995 tmxr_send_buffered_data (lp);
996 for (j=0; j < sim_rem_con_tmxr.lines; j++) {
997 TMLN *lpj = &sim_rem_con_tmxr.ldsc[j];
998 if ((i == j) || (!lpj->conn))
999 continue;
1000 tmxr_linemsg (lpj, "Simulator Running...");
1001 tmxr_send_buffered_data (lpj);
1002 }
1003 sim_is_running = 1;
1004 sim_start_timer_services ();
1005 }
1006
1007 if (cmdp && (cmdp->action == &x_continue_cmd))
1008 sim_rem_single_mode[i] = TRUE;
1009 else {
1010 if (!sim_rem_single_mode[i]) {
1011 if (master_session)
1012 tmxr_linemsgf (lp, "%s", "sim> ");
1013 else
1014 tmxr_linemsgf (lp, "%s", sim_prompt);
1015 tmxr_send_buffered_data (lp);
1016 }
1017 }
1018 break;
1019 }
1020 if ((cmdp && (cmdp->action == &x_step_cmd)) ||
1021 (stat == SCPE_REMOTE)) {
1022 sim_rem_cmd_active_line = i;
1023 break;
1024 }
1025 }
1026 if (close_session) {
1027 tmxr_linemsgf (lp, "\r\nGoodbye\r\n");
1028 tmxr_send_buffered_data (lp);
1029 tmxr_reset_ln (lp);
1030 sim_rem_single_mode[i] = FALSE;
1031 }
1032 }
1033 if (sim_rem_master_was_connected &&
1034 !sim_rem_con_tmxr.ldsc[0].sock)
1035 return SCPE_EXIT;
1036 if (sim_rem_cmd_active_line != -1) {
1037 if (steps)
1038 sim_activate(uptr, steps);
1039 else
1040 return SCPE_REMOTE;
1041 }
1042 else
1043 sim_activate_after(uptr, 100000);
1044 if (sim_rem_master_was_enabled && !sim_rem_master_mode) {
1045 lp = &sim_rem_con_tmxr.ldsc[0];
1046 tmxr_linemsgf (lp, "Non Master Mode Session...");
1047 tmxr_send_buffered_data (lp);
1048 return SCPE_STOP|SCPE_NOMESSAGE;
1049 }
1050 else
1051 return SCPE_OK;
1052 }
1053
1054 t_stat sim_rem_con_reset (DEVICE *dptr)
1055 {
1056 if (sim_rem_con_tmxr.lines) {
1057 int32 i;
1058
1059 for (i=0; i<sim_rem_con_tmxr.lines; i++)
1060 if (sim_rem_con_tmxr.ldsc[i].conn)
1061 break;
1062 if (i != sim_rem_con_tmxr.lines)
1063 sim_activate_after (&dptr->units[1], 100000);
1064 return sim_rem_con_poll_svc (&dptr->units[0]);
1065 }
1066 return SCPE_OK;
1067 }
1068
1069 static t_stat sim_set_rem_telnet (int32 flag, CONST char *cptr)
1070 {
1071 t_stat r;
1072
1073 if (flag) {
1074 r = sim_parse_addr (cptr, NULL, 0, NULL, NULL, 0, NULL, NULL);
1075 if (r == SCPE_OK) {
1076 if (sim_rem_con_tmxr.master)
1077 sim_set_rem_telnet (0, NULL);
1078 if (sim_rem_con_tmxr.lines == 0)
1079 sim_set_rem_connections (0, "1");
1080 sim_rem_con_tmxr.buffered = 1400;
1081 sim_register_internal_device (&sim_remote_console);
1082 r = tmxr_attach (&sim_rem_con_tmxr, &sim_rem_con_unit[0], cptr);
1083 if (r == SCPE_OK)
1084 sim_activate_after(&sim_rem_con_unit[0], 1000000);
1085 return r;
1086 }
1087 return SCPE_NOPARAM;
1088 }
1089 else {
1090 if (sim_rem_con_tmxr.master) {
1091 int32 i;
1092
1093 tmxr_detach (&sim_rem_con_tmxr, &sim_rem_con_unit[0]);
1094 for (i=0; i<sim_rem_con_tmxr.lines; i++) {
1095 FREE (sim_rem_buf[i]);
1096 sim_rem_buf[i] = NULL;
1097 sim_rem_buf_size[i] = 0;
1098 sim_rem_buf_ptr[i] = 0;
1099 sim_rem_single_mode[i] = TRUE;
1100 }
1101 }
1102 }
1103 return SCPE_OK;
1104 }
1105
1106 static t_stat sim_set_rem_connections (int32 flag, CONST char *cptr)
1107 {
1108 int32 lines;
1109 t_stat r;
1110 int32 i;
1111
1112 if (cptr == NULL)
1113 return SCPE_ARG;
1114 lines = (int32) get_uint (cptr, 10, MAX_REMOTE_SESSIONS, &r);
1115 if (r != SCPE_OK)
1116 return r;
1117 if (sim_rem_con_tmxr.master)
1118 return SCPE_ARG;
1119 for (i=0; i<sim_rem_con_tmxr.lines; i++)
1120 FREE (sim_rem_buf[i]);
1121 sim_rem_con_tmxr.lines = lines;
1122 sim_rem_con_tmxr.ldsc = (TMLN *)realloc (sim_rem_con_tmxr.ldsc, sizeof(*sim_rem_con_tmxr.ldsc)*lines);
1123 if (!sim_rem_con_tmxr.ldsc)
1124 {
1125 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1126 __func__, __FILE__, __LINE__);
1127 #if defined(USE_BACKTRACE)
1128 # if defined(SIGUSR2)
1129 (void)raise(SIGUSR2);
1130
1131 # endif
1132 #endif
1133 abort();
1134 }
1135 (void)memset (sim_rem_con_tmxr.ldsc, 0, sizeof(*sim_rem_con_tmxr.ldsc)*lines);
1136 sim_rem_buf = (char **)realloc (sim_rem_buf, sizeof(*sim_rem_buf)*lines);
1137 if (!sim_rem_buf)
1138 {
1139 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1140 __func__, __FILE__, __LINE__);
1141 #if defined(USE_BACKTRACE)
1142 # if defined(SIGUSR2)
1143 (void)raise(SIGUSR2);
1144
1145 # endif
1146 #endif
1147 abort();
1148 }
1149 (void)memset (sim_rem_buf, 0, sizeof(*sim_rem_buf)*lines);
1150 sim_rem_buf_size = (int32 *)realloc (sim_rem_buf_size, sizeof(*sim_rem_buf_size)*lines);
1151 if (!sim_rem_buf_size)
1152 {
1153 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1154 __func__, __FILE__, __LINE__);
1155 #if defined(USE_BACKTRACE)
1156 # if defined(SIGUSR2)
1157 (void)raise(SIGUSR2);
1158
1159 # endif
1160 #endif
1161 abort();
1162 }
1163 (void)memset (sim_rem_buf_size, 0, sizeof(*sim_rem_buf_size)*lines);
1164 sim_rem_buf_ptr = (int32 *)realloc (sim_rem_buf_ptr, sizeof(*sim_rem_buf_ptr)*lines);
1165 if (!sim_rem_buf_ptr)
1166 {
1167 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1168 __func__, __FILE__, __LINE__);
1169 #if defined(USE_BACKTRACE)
1170 # if defined(SIGUSR2)
1171 (void)raise(SIGUSR2);
1172
1173 # endif
1174 #endif
1175 abort();
1176 }
1177 (void)memset (sim_rem_buf_ptr, 0, sizeof(*sim_rem_buf_ptr)*lines);
1178 sim_rem_single_mode = (t_bool *)realloc (sim_rem_single_mode, sizeof(*sim_rem_single_mode)*lines);
1179 if (!sim_rem_single_mode)
1180 {
1181 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1182 __func__, __FILE__, __LINE__);
1183 #if defined(USE_BACKTRACE)
1184 # if defined(SIGUSR2)
1185 (void)raise(SIGUSR2);
1186
1187 # endif
1188 #endif
1189 abort();
1190 }
1191 (void)memset (sim_rem_single_mode, 0, sizeof(*sim_rem_single_mode)*lines);
1192 sim_rem_read_timeouts = (uint32 *)realloc (sim_rem_read_timeouts, sizeof(*sim_rem_read_timeouts)*lines);
1193 if (!sim_rem_read_timeouts)
1194 {
1195 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1196 __func__, __FILE__, __LINE__);
1197 #if defined(USE_BACKTRACE)
1198 # if defined(SIGUSR2)
1199 (void)raise(SIGUSR2);
1200
1201 # endif
1202 #endif
1203 abort();
1204 }
1205 (void)memset (sim_rem_read_timeouts, 0, sizeof(*sim_rem_read_timeouts)*lines);
1206 sim_rem_command_buf = (char *)realloc (sim_rem_command_buf, 4*CBUFSIZE+1);
1207 if (!sim_rem_command_buf)
1208 {
1209 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1210 __func__, __FILE__, __LINE__);
1211 #if defined(USE_BACKTRACE)
1212 # if defined(SIGUSR2)
1213 (void)raise(SIGUSR2);
1214
1215 # endif
1216 #endif
1217 abort();
1218 }
1219 (void)memset (sim_rem_command_buf, 0, 4*CBUFSIZE+1);
1220 return SCPE_OK;
1221 }
1222
1223 static t_stat sim_set_rem_timeout (int32 flag, CONST char *cptr)
1224 {
1225 int32 timeout;
1226 t_stat r;
1227
1228 if (cptr == NULL)
1229 return SCPE_ARG;
1230 timeout = (int32) get_uint (cptr, 10, 3600, &r);
1231 if (r != SCPE_OK)
1232 return r;
1233 if (sim_rem_active_number >= 0)
1234 sim_rem_read_timeouts[sim_rem_active_number] = timeout;
1235 else
1236 sim_rem_read_timeout = timeout;
1237 return SCPE_OK;
1238 }
1239
1240
1241
1242 t_stat sim_set_kmap (int32 flag, CONST char *cptr)
1243 {
1244 DEVICE *dptr = sim_devices[0];
1245 int32 val, rdx;
1246 t_stat r;
1247
1248 if ((cptr == NULL) || (*cptr == 0))
1249 return SCPE_2FARG;
1250 if (dptr->dradix == 16) rdx = 16;
1251 else rdx = 8;
1252 val = (int32) get_uint (cptr, rdx, 0177, &r);
1253 if ((r != SCPE_OK) ||
1254 ((val == 0) && (flag & KMAP_NZ)))
1255 return SCPE_ARG;
1256 *(cons_kmap[flag & KMAP_MASK]) = val;
1257 return SCPE_OK;
1258 }
1259
1260
1261
1262 t_stat sim_show_kmap (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
1263 {
1264 if (sim_devices[0]->dradix == 16)
1265 fprintf (st, "%s = %X\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK]));
1266 else fprintf (st, "%s = %o\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK]));
1267 return SCPE_OK;
1268 }
1269
1270
1271
1272 t_stat sim_set_pchar (int32 flag, CONST char *cptr)
1273 {
1274 DEVICE *dptr = sim_devices[0];
1275 uint32 val, rdx;
1276 t_stat r;
1277
1278 if ((cptr == NULL) || (*cptr == 0))
1279 return SCPE_2FARG;
1280 if (dptr->dradix == 16) rdx = 16;
1281 else rdx = 8;
1282 val = (uint32) get_uint (cptr, rdx, 0xFFFFFFFF, &r);
1283 if ((r != SCPE_OK) ||
1284 ((val & 0x00002400) == 0))
1285 return SCPE_ARG;
1286 sim_tt_pchar = val;
1287 return SCPE_OK;
1288 }
1289
1290
1291
1292 t_stat sim_set_cons_speed (int32 flag, CONST char *cptr)
1293 {
1294 return tmxr_set_line_speed (&sim_con_ldsc, cptr);
1295 }
1296
1297 t_stat sim_show_cons_speed (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
1298 {
1299 if (sim_con_ldsc.rxbps) {
1300 fprintf (st, "Speed = %ld", (long)sim_con_ldsc.rxbps);
1301 if (sim_con_ldsc.rxbpsfactor != TMXR_RX_BPS_UNIT_SCALE)
1302 fprintf (st, "*%.0f", sim_con_ldsc.rxbpsfactor/TMXR_RX_BPS_UNIT_SCALE);
1303 fprintf (st, " bps\n");
1304 }
1305 return SCPE_OK;
1306 }
1307
1308
1309
1310 t_stat sim_set_logon (int32 flag, CONST char *cptr)
1311 {
1312 char gbuf[CBUFSIZE];
1313 t_stat r;
1314 time_t now;
1315
1316 if ((cptr == NULL) || (*cptr == 0))
1317 return SCPE_2FARG;
1318 cptr = get_glyph_nc (cptr, gbuf, 0);
1319 if (*cptr != 0)
1320 return SCPE_2MARG;
1321 sim_set_logoff (0, NULL);
1322 r = sim_open_logfile (gbuf, (sim_switches & SWMASK ('B')) == SWMASK ('B'),
1323 &sim_log, &sim_log_ref);
1324 if (r != SCPE_OK)
1325 return r;
1326 if (!sim_quiet)
1327 printf ("Logging to file \"%s\"\n",
1328 sim_logfile_name (sim_log, sim_log_ref));
1329 fprintf (sim_log, "Logging to file \"%s\"\n",
1330 sim_logfile_name (sim_log, sim_log_ref));
1331 time(&now);
1332 fprintf (sim_log, "Logging to file \"%s\" at %s", sim_logfile_name (sim_log, sim_log_ref), ctime(&now));
1333 return SCPE_OK;
1334 }
1335
1336
1337
1338 t_stat sim_set_logoff (int32 flag, CONST char *cptr)
1339 {
1340 if (cptr && (*cptr != 0))
1341 return SCPE_2MARG;
1342 if (sim_log == NULL)
1343 return SCPE_OK;
1344 if (!sim_quiet)
1345 printf ("Log file closed\n");
1346 fprintf (sim_log, "Log file closed\n");
1347 sim_close_logfile (&sim_log_ref);
1348 sim_log = NULL;
1349 return SCPE_OK;
1350 }
1351
1352
1353
1354 t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
1355 {
1356 if (cptr && (*cptr != 0))
1357 return SCPE_2MARG;
1358 if (sim_log)
1359 fprintf (st, "Logging enabled to \"%s\"\n",
1360 sim_logfile_name (sim_log, sim_log_ref));
1361 else fprintf (st, "Logging disabled\n");
1362 return SCPE_OK;
1363 }
1364
1365
1366
1367 t_stat sim_set_debon (int32 flag, CONST char *cptr)
1368 {
1369 char gbuf[CBUFSIZE];
1370 t_stat r;
1371 time_t now;
1372
1373 sim_deb_switches = sim_switches;
1374 if ((cptr == NULL) || (*cptr == 0))
1375 return SCPE_2FARG;
1376 cptr = get_glyph_nc (cptr, gbuf, 0);
1377 if (*cptr != 0)
1378 return SCPE_2MARG;
1379 r = sim_open_logfile (gbuf, FALSE, &sim_deb, &sim_deb_ref);
1380
1381 if (r != SCPE_OK)
1382 return r;
1383
1384 if (sim_deb_switches & SWMASK ('R')) {
1385 clock_gettime(CLOCK_REALTIME, &sim_deb_basetime);
1386 if (!(sim_deb_switches & (SWMASK ('A') | SWMASK ('T'))))
1387 sim_deb_switches |= SWMASK ('T');
1388 }
1389 if (!sim_quiet) {
1390 sim_printf ("Debug output to \"%s\"\n",
1391 sim_logfile_name (sim_deb, sim_deb_ref));
1392 if (sim_deb_switches & SWMASK ('P'))
1393 sim_printf (" Debug messages contain current PC value\n");
1394 if (sim_deb_switches & SWMASK ('T'))
1395 sim_printf (" Debug messages display time of day as hh:mm:ss.msec%s\n",
1396 sim_deb_switches & SWMASK ('R') ? " relative to the start of debugging" : "");
1397 if (sim_deb_switches & SWMASK ('A'))
1398 sim_printf (" Debug messages display time of day as seconds.msec%s\n",
1399 sim_deb_switches & SWMASK ('R') ? " relative to the start of debugging" : "");
1400 time(&now);
1401 fprintf (sim_deb, "Debug output to \"%s\" at %s",
1402 sim_logfile_name (sim_deb, sim_deb_ref), ctime(&now));
1403 show_version (sim_deb, NULL, NULL, 0, NULL);
1404 }
1405 if (sim_deb_switches & SWMASK ('N'))
1406 sim_deb_switches &= ~SWMASK ('N');
1407
1408 return SCPE_OK;
1409 }
1410
1411 t_stat sim_debug_flush (void)
1412 {
1413 int32 saved_quiet = sim_quiet;
1414 int32 saved_sim_switches = sim_switches;
1415 int32 saved_deb_switches = sim_deb_switches;
1416 struct timespec saved_deb_basetime = sim_deb_basetime;
1417 char saved_debug_filename[CBUFSIZE];
1418
1419 if (sim_deb == NULL)
1420 return SCPE_OK;
1421
1422 if (sim_deb == sim_log) {
1423 (void)fflush (sim_deb);
1424 return SCPE_OK;
1425 }
1426
1427 strcpy (saved_debug_filename, sim_logfile_name (sim_deb, sim_deb_ref));
1428
1429 sim_quiet = 1;
1430 sim_set_deboff (0, NULL);
1431 sim_switches = saved_deb_switches;
1432 sim_set_debon (0, saved_debug_filename);
1433 sim_deb_basetime = saved_deb_basetime;
1434 sim_switches = saved_sim_switches;
1435 sim_quiet = saved_quiet;
1436 return SCPE_OK;
1437 }
1438
1439
1440
1441 t_stat sim_set_deboff (int32 flag, CONST char *cptr)
1442 {
1443 if (cptr && (*cptr != 0))
1444 return SCPE_2MARG;
1445 if (sim_deb == NULL)
1446 return SCPE_OK;
1447 sim_close_logfile (&sim_deb_ref);
1448 sim_deb = NULL;
1449 sim_deb_switches = 0;
1450 if (!sim_quiet)
1451 sim_printf ("Debug output disabled\n");
1452 return SCPE_OK;
1453 }
1454
1455
1456
1457 t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
1458 {
1459 int32 i;
1460
1461 if (cptr && (*cptr != 0))
1462 return SCPE_2MARG;
1463 if (sim_deb) {
1464 fprintf (st, "Debug output enabled to \"%s\"\n",
1465 sim_logfile_name (sim_deb, sim_deb_ref));
1466 if (sim_deb_switches & SWMASK ('P'))
1467 fprintf (st, " Debug messages contain current PC value\n");
1468 if (sim_deb_switches & SWMASK ('T'))
1469 fprintf (st, " Debug messages display time of day as hh:mm:ss.msec%s\n",
1470 sim_deb_switches & SWMASK ('R') ? " relative to the start of debugging" : "");
1471 if (sim_deb_switches & SWMASK ('A'))
1472 fprintf (st, " Debug messages display time of day as seconds.msec%s\n",
1473 sim_deb_switches & SWMASK ('R') ? " relative to the start of debugging" : "");
1474 for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
1475 if (!(dptr->flags & DEV_DIS) &&
1476 (dptr->flags & DEV_DEBUG) &&
1477 (dptr->dctrl)) {
1478 fprintf (st, "Device: %-6s ", dptr->name);
1479 show_dev_debug (st, dptr, NULL, 0, NULL);
1480 }
1481 }
1482 for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
1483 if (!(dptr->flags & DEV_DIS) &&
1484 (dptr->flags & DEV_DEBUG) &&
1485 (dptr->dctrl)) {
1486 fprintf (st, "Device: %-6s ", dptr->name);
1487 show_dev_debug (st, dptr, NULL, 0, NULL);
1488 }
1489 }
1490 }
1491 else fprintf (st, "Debug output disabled\n");
1492 return SCPE_OK;
1493 }
1494
1495
1496
1497
1498
1499 t_stat sim_set_telnet (int32 flag, CONST char *cptr)
1500 {
1501 char *cvptr, gbuf[CBUFSIZE];
1502 CTAB *ctptr;
1503 t_stat r;
1504
1505 if ((cptr == NULL) || (*cptr == 0))
1506 return SCPE_2FARG;
1507 while (*cptr != 0) {
1508 cptr = get_glyph_nc (cptr, gbuf, ',');
1509 if ((cvptr = strchr (gbuf, '=')))
1510 *cvptr++ = 0;
1511 (void)get_glyph (gbuf, gbuf, 0);
1512 if ((ctptr = find_ctab (set_con_telnet_tab, gbuf))) {
1513 r = ctptr->action (ctptr->arg, cvptr);
1514 if (r != SCPE_OK)
1515 return r;
1516 }
1517 else {
1518 if (sim_con_tmxr.master)
1519 sim_set_notelnet (0, NULL);
1520 r = tmxr_attach (&sim_con_tmxr, &sim_con_unit, gbuf);
1521 if (r == SCPE_OK)
1522 sim_activate_after(&sim_con_unit, 1000000);
1523 else
1524 return r;
1525 }
1526 }
1527 return SCPE_OK;
1528 }
1529
1530
1531
1532 t_stat sim_set_notelnet (int32 flag, CONST char *cptr)
1533 {
1534 if (cptr && (*cptr != 0))
1535 return SCPE_2MARG;
1536 if (sim_con_tmxr.master == 0)
1537 return SCPE_OK;
1538 return tmxr_close_master (&sim_con_tmxr);
1539 }
1540
1541
1542
1543 t_stat sim_show_telnet (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, CONST char *cptr)
1544 {
1545 if (cptr && (*cptr != 0))
1546 return SCPE_2MARG;
1547 if ((sim_con_tmxr.master == 0) &&
1548 (sim_con_ldsc.serport == 0))
1549 fprintf (st, "Connected to console window\n");
1550 else {
1551 if (sim_con_ldsc.serport) {
1552 fprintf (st, "Connected to ");
1553 tmxr_fconns (st, &sim_con_ldsc, -1);
1554 }
1555 else
1556 if (sim_con_ldsc.sock == 0)
1557 fprintf (st, "Listening on port %s\n", sim_con_tmxr.port);
1558 else {
1559 fprintf (st, "Listening on port %s, connection from %s\n",
1560 sim_con_tmxr.port, sim_con_ldsc.ipad);
1561 tmxr_fconns (st, &sim_con_ldsc, -1);
1562 }
1563 tmxr_fstats (st, &sim_con_ldsc, -1);
1564 }
1565 return SCPE_OK;
1566 }
1567
1568
1569
1570 t_stat sim_set_cons_buff (int32 flg, CONST char *cptr)
1571 {
1572 char cmdbuf[CBUFSIZE];
1573
1574 (void)sprintf(cmdbuf, "BUFFERED%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
1575 return tmxr_open_master (&sim_con_tmxr, cmdbuf);
1576 }
1577
1578
1579
1580 t_stat sim_set_cons_unbuff (int32 flg, CONST char *cptr)
1581 {
1582 char cmdbuf[CBUFSIZE];
1583
1584 (void)sprintf(cmdbuf, "UNBUFFERED%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
1585 return tmxr_open_master (&sim_con_tmxr, cmdbuf);
1586 }
1587
1588
1589
1590 t_stat sim_set_cons_log (int32 flg, CONST char *cptr)
1591 {
1592 char cmdbuf[CBUFSIZE];
1593
1594 (void)sprintf(cmdbuf, "LOG%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
1595 return tmxr_open_master (&sim_con_tmxr, cmdbuf);
1596 }
1597
1598
1599
1600 t_stat sim_set_cons_nolog (int32 flg, CONST char *cptr)
1601 {
1602 char cmdbuf[CBUFSIZE];
1603
1604 (void)sprintf(cmdbuf, "NOLOG%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
1605 return tmxr_open_master (&sim_con_tmxr, cmdbuf);
1606 }
1607
1608 t_stat sim_show_cons_log (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, CONST char *cptr)
1609 {
1610 if (cptr && (*cptr != 0))
1611 return SCPE_2MARG;
1612 if (sim_con_tmxr.ldsc->txlog)
1613 fprintf (st, "Log File being written to %s\n", sim_con_tmxr.ldsc->txlogname);
1614 else
1615 fprintf (st, "No Logging\n");
1616 return SCPE_OK;
1617 }
1618
1619 t_stat sim_show_cons_buff (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, CONST char *cptr)
1620 {
1621 if (cptr && (*cptr != 0))
1622 return SCPE_2MARG;
1623 if (!sim_con_tmxr.ldsc->txbfd)
1624 fprintf (st, "Unbuffered\n");
1625 else
1626 fprintf (st, "Buffer Size = %lld\n",
1627 (long long)sim_con_tmxr.ldsc->txbsz);
1628 return SCPE_OK;
1629 }
1630
1631
1632
1633
1634
1635 t_stat sim_show_cons_expect (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, CONST char *cptr)
1636 {
1637 return sim_exp_show (st, &sim_con_expect, cptr);
1638 }
1639
1640
1641
1642
1643
1644 t_stat sim_open_logfile (const char *filename, t_bool binary, FILE **pf, FILEREF **pref)
1645 {
1646 char gbuf[CBUFSIZE - 1];
1647 const char *tptr;
1648
1649 if ((filename == NULL) || (*filename == 0))
1650 return SCPE_2FARG;
1651 tptr = get_glyph (filename, gbuf, 0);
1652 if (*tptr != 0)
1653 return SCPE_2MARG;
1654 sim_close_logfile (pref);
1655 *pf = NULL;
1656 if (strcmp (gbuf, "LOG") == 0) {
1657 if (sim_log == NULL)
1658 return SCPE_ARG;
1659 *pf = sim_log;
1660 *pref = sim_log_ref;
1661 if (*pref)
1662 ++(*pref)->refcount;
1663 }
1664 else if (strcmp (gbuf, "DEBUG") == 0) {
1665 if (sim_deb == NULL)
1666 return SCPE_ARG;
1667 *pf = sim_deb;
1668 *pref = sim_deb_ref;
1669 if (*pref)
1670 ++(*pref)->refcount;
1671 }
1672 else if (strcmp (gbuf, "STDOUT") == 0) {
1673 *pf = stdout;
1674 *pref = NULL;
1675 }
1676 else if (strcmp (gbuf, "STDERR") == 0) {
1677 *pf = stderr;
1678 *pref = NULL;
1679 }
1680 else {
1681 *pref = (FILEREF *)calloc (1, sizeof(**pref));
1682 if (!*pref)
1683 return SCPE_MEM;
1684 (void)get_glyph_nc (filename, gbuf, 0);
1685 (void)strncpy ((*pref)->name, gbuf, sizeof((*pref)->name) - 1);
1686 (*pref)->name[sizeof((*pref)->name) - 1] = '\0';
1687 if (sim_switches & SWMASK ('N'))
1688 *pf = sim_fopen (gbuf, (binary ? "w+b" : "w+"));
1689 else
1690 *pf = sim_fopen (gbuf, (binary ? "a+b" : "a+"));
1691 if (*pf == NULL) {
1692 FREE (*pref);
1693 *pref = NULL;
1694 return SCPE_OPENERR;
1695 }
1696 (*pref)->file = *pf;
1697 (*pref)->refcount = 1;
1698 }
1699 return SCPE_OK;
1700 }
1701
1702
1703
1704 t_stat sim_close_logfile (FILEREF **pref)
1705 {
1706 if (NULL == *pref)
1707 return SCPE_OK;
1708 (*pref)->refcount = (*pref)->refcount - 1;
1709 if ((*pref)->refcount > 0) {
1710 *pref = NULL;
1711 return SCPE_OK;
1712 }
1713 fclose ((*pref)->file);
1714 FREE (*pref);
1715 *pref = NULL;
1716 return SCPE_OK;
1717 }
1718
1719
1720
1721 const char *sim_logfile_name (const FILE *st, FILEREF *ref)
1722 {
1723 if (!st)
1724 return "";
1725 if (st == stdout)
1726 return "STDOUT";
1727 if (st == stderr)
1728 return "STDERR";
1729 if (!ref)
1730 return "";
1731 return ref->name;
1732 }
1733
1734
1735
1736
1737 t_stat sim_check_console (int32 sec)
1738 {
1739 int32 c, trys = 0;
1740
1741 if (sim_rem_master_mode) {
1742 for (;trys < sec; ++trys) {
1743 sim_rem_con_poll_svc (&sim_rem_con_unit[0]);
1744 if (sim_rem_con_tmxr.ldsc[0].conn)
1745 break;
1746 if ((trys % 10) == 0) {
1747 sim_printf ("Waiting for Remote Console connection\r\n");
1748 (void)fflush (stdout);
1749 if (sim_log)
1750 (void)fflush (sim_log);
1751 }
1752 sim_os_sleep (1);
1753 }
1754 if ((sim_rem_con_tmxr.ldsc[0].conn) &&
1755 (!sim_con_ldsc.serport) &&
1756 (sim_con_tmxr.master == 0) &&
1757 (sim_con_console_port)) {
1758 tmxr_linemsgf (&sim_rem_con_tmxr.ldsc[0], "\r\nConsole port must be Telnet or Serial with Master Remote Console\r\n");
1759 tmxr_linemsgf (&sim_rem_con_tmxr.ldsc[0], "Goodbye\r\n");
1760 while (tmxr_send_buffered_data (&sim_rem_con_tmxr.ldsc[0]))
1761 sim_os_ms_sleep (100);
1762 sim_os_ms_sleep (100);
1763 tmxr_reset_ln (&sim_rem_con_tmxr.ldsc[0]);
1764 sim_printf ("Console port must be Telnet or Serial with Master Remote Console\r\n");
1765 return SCPE_EXIT;
1766 }
1767 }
1768 if (trys == sec) {
1769 return SCPE_TTMO;
1770 }
1771 if (sim_con_ldsc.serport)
1772 if (tmxr_poll_conn (&sim_con_tmxr) >= 0)
1773 sim_con_ldsc.rcve = 1;
1774 if ((sim_con_tmxr.master == 0) ||
1775 (sim_con_ldsc.serport))
1776 return SCPE_OK;
1777 if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) {
1778 tmxr_poll_rx (&sim_con_tmxr);
1779 if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) {
1780 if (!sim_con_ldsc.conn) {
1781 sim_printf ("Running with Buffered Console\r\n");
1782 (void)fflush (stdout);
1783 if (sim_log)
1784 (void)fflush (sim_log);
1785 }
1786 return SCPE_OK;
1787 }
1788 }
1789 for (; trys < sec; trys++) {
1790 if (tmxr_poll_conn (&sim_con_tmxr) >= 0) {
1791 sim_con_ldsc.rcve = 1;
1792 if (trys) {
1793 sim_printf ("Running\r\n");
1794 (void)fflush (stdout);
1795 if (sim_log)
1796 (void)fflush (sim_log);
1797 }
1798 return SCPE_OK;
1799 }
1800 c = sim_os_poll_kbd ();
1801 if ((c == SCPE_STOP) || stop_cpu)
1802 return SCPE_STOP;
1803 if ((trys % 10) == 0) {
1804 sim_printf ("Waiting for console Telnet connection\r\n");
1805 (void)fflush (stdout);
1806 if (sim_log)
1807 (void)fflush (sim_log);
1808 }
1809 sim_os_sleep (1);
1810 }
1811 return SCPE_TTMO;
1812 }
1813
1814
1815
1816 SEND *sim_cons_get_send (void)
1817 {
1818 return &sim_con_send;
1819 }
1820
1821
1822
1823 EXPECT *sim_cons_get_expect (void)
1824 {
1825 return &sim_con_expect;
1826 }
1827
1828
1829
1830 t_stat sim_show_cons_send_input (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
1831 {
1832 return sim_show_send_input (st, &sim_con_send);
1833 }
1834
1835
1836
1837 t_stat sim_poll_kbd (void)
1838 {
1839 t_stat c;
1840
1841 if (!sim_localopc)
1842 return SCPE_OK;
1843
1844 if (sim_send_poll_data (&sim_con_send, &c))
1845 return c;
1846 if (!sim_rem_master_mode) {
1847 if ((sim_con_ldsc.rxbps) &&
1848 (sim_gtime () < sim_con_ldsc.rxnexttime))
1849 return SCPE_OK;
1850 c = sim_os_poll_kbd ();
1851 if (c == SCPE_STOP) {
1852 stop_cpu = 1;
1853 return SCPE_OK;
1854 }
1855 if ((sim_con_tmxr.master == 0) &&
1856 (sim_con_ldsc.serport == 0)) {
1857 if (c && sim_con_ldsc.rxbps)
1858 sim_con_ldsc.rxnexttime =
1859 floor (sim_gtime () + ((sim_con_ldsc.rxdelta * sim_timer_inst_per_sec ())/sim_con_ldsc.rxbpsfactor));
1860 return c;
1861 }
1862 if (!sim_con_ldsc.conn) {
1863 if (!sim_con_ldsc.txbfd)
1864 return SCPE_LOST;
1865 if (tmxr_poll_conn (&sim_con_tmxr) >= 0)
1866 sim_con_ldsc.rcve = 1;
1867 else
1868 return SCPE_OK;
1869 }
1870 }
1871 tmxr_poll_rx (&sim_con_tmxr);
1872 if ((c = (t_stat)tmxr_getc_ln (&sim_con_ldsc)))
1873 return (c & (SCPE_BREAK | 0377)) | SCPE_KFLAG;
1874 return SCPE_OK;
1875 }
1876
1877
1878
1879 t_stat sim_putchar (int32 c)
1880 {
1881 sim_exp_check (&sim_con_expect, c);
1882 if ((sim_con_tmxr.master == 0) &&
1883 (sim_con_ldsc.serport == 0)) {
1884 if (sim_log)
1885 fputc (c, sim_log);
1886 return sim_os_putchar (c);
1887 }
1888 if (!sim_con_ldsc.conn) {
1889 if (!sim_con_ldsc.txbfd)
1890 return SCPE_LOST;
1891 if (tmxr_poll_conn (&sim_con_tmxr) >= 0)
1892 sim_con_ldsc.rcve = 1;
1893 }
1894 tmxr_putc_ln (&sim_con_ldsc, c);
1895 tmxr_poll_tx (&sim_con_tmxr);
1896 return SCPE_OK;
1897 }
1898
1899
1900
1901
1902
1903
1904
1905 t_stat sim_ttinit (void)
1906 {
1907 sim_con_tmxr.ldsc->mp = &sim_con_tmxr;
1908 sim_register_internal_device (&sim_con_telnet);
1909 tmxr_startup ();
1910 return sim_os_ttinit ();
1911 }
1912
1913 t_stat sim_ttrun (void)
1914 {
1915 if (!sim_con_tmxr.ldsc->uptr) {
1916 sim_con_unit.dynflags &= ~UNIT_TM_POLL;
1917 sim_con_unit.dynflags |= TMUF_NOASYNCH;
1918 }
1919
1920
1921
1922
1923 tmxr_start_poll ();
1924 return sim_os_ttrun ();
1925 }
1926
1927 t_stat sim_ttcmd (void)
1928 {
1929 tmxr_stop_poll ();
1930 return sim_os_ttcmd ();
1931 }
1932
1933 t_stat sim_ttclose (void)
1934 {
1935 t_stat r1 = tmxr_shutdown ();
1936 t_stat r2 = sim_os_ttclose ();
1937
1938 if (r1 != SCPE_OK)
1939 return r1;
1940
1941 return r2;
1942 }
1943
1944 t_bool sim_ttisatty (void)
1945 {
1946 return sim_os_ttisatty ();
1947 }
1948
1949
1950
1951 #if defined (_WIN32)
1952
1953 # include <fcntl.h>
1954 # include <io.h>
1955 # include <windows.h>
1956 # define RAW_MODE 0
1957 static HANDLE std_input;
1958 static HANDLE std_output;
1959 static DWORD saved_mode;
1960
1961
1962
1963
1964
1965
1966
1967
1968 static BOOL WINAPI
1969 ControlHandler(DWORD dwCtrlType)
1970 {
1971 DWORD Mode;
1972 extern void int_handler (int sig);
1973
1974 switch (dwCtrlType)
1975 {
1976 case CTRL_BREAK_EVENT:
1977 case CTRL_C_EVENT:
1978 int_handler(0);
1979 return TRUE;
1980 case CTRL_CLOSE_EVENT:
1981 case CTRL_LOGOFF_EVENT:
1982 if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &Mode))
1983 return TRUE;
1984
1985 case CTRL_SHUTDOWN_EVENT:
1986 int_handler(0);
1987 return TRUE;
1988 }
1989 return FALSE;
1990 }
1991
1992 static t_stat sim_os_ttinit (void)
1993 {
1994 SetConsoleCtrlHandler( ControlHandler, TRUE );
1995 std_input = GetStdHandle (STD_INPUT_HANDLE);
1996 std_output = GetStdHandle (STD_OUTPUT_HANDLE);
1997 if ((std_input) &&
1998 (std_input != INVALID_HANDLE_VALUE))
1999 GetConsoleMode (std_input, &saved_mode);
2000 return SCPE_OK;
2001 }
2002
2003 static t_stat sim_os_ttrun (void)
2004 {
2005 if ((std_input) &&
2006 (std_input != INVALID_HANDLE_VALUE) &&
2007 (!GetConsoleMode(std_input, &saved_mode) ||
2008 !SetConsoleMode(std_input, RAW_MODE)))
2009 return SCPE_TTYERR;
2010 if (sim_log) {
2011 (void)fflush (sim_log);
2012 _setmode (_fileno (sim_log), _O_BINARY);
2013 }
2014 sim_os_set_thread_priority (PRIORITY_BELOW_NORMAL);
2015 return SCPE_OK;
2016 }
2017
2018 static t_stat sim_os_ttcmd (void)
2019 {
2020 if (sim_log) {
2021 (void)fflush (sim_log);
2022 _setmode (_fileno (sim_log), _O_TEXT);
2023 }
2024 sim_os_set_thread_priority (PRIORITY_NORMAL);
2025 if ((std_input) &&
2026 (std_input != INVALID_HANDLE_VALUE) &&
2027 (!SetConsoleMode(std_input, saved_mode)))
2028 return SCPE_TTYERR;
2029 return SCPE_OK;
2030 }
2031
2032 static t_stat sim_os_ttclose (void)
2033 {
2034 return SCPE_OK;
2035 }
2036
2037 static t_bool sim_os_ttisatty (void)
2038 {
2039 DWORD Mode;
2040
2041 return (std_input) && (std_input != INVALID_HANDLE_VALUE) && GetConsoleMode (std_input, &Mode);
2042 }
2043
2044 static t_stat sim_os_poll_kbd (void)
2045 {
2046 int c = -1;
2047 DWORD nkbevents, nkbevent;
2048 INPUT_RECORD rec;
2049
2050 sim_debug (DBG_TRC, &sim_con_telnet, "sim_os_poll_kbd()\n");
2051
2052 if ((std_input == NULL) ||
2053 (std_input == INVALID_HANDLE_VALUE))
2054 return SCPE_OK;
2055 if (!GetNumberOfConsoleInputEvents(std_input, &nkbevents))
2056 return SCPE_TTYERR;
2057 while (c == -1) {
2058 if (0 == nkbevents)
2059 return SCPE_OK;
2060 if (!ReadConsoleInput(std_input, &rec, 1, &nkbevent))
2061 return SCPE_TTYERR;
2062 if (0 == nkbevent)
2063 return SCPE_OK;
2064 --nkbevents;
2065 if (rec.EventType == KEY_EVENT) {
2066 if (rec.Event.KeyEvent.bKeyDown) {
2067 if (0 == rec.Event.KeyEvent.uChar.UnicodeChar) {
2068 if (rec.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE)
2069 c = sim_brk_char | SCPE_BREAK;
2070 else
2071 if (rec.Event.KeyEvent.wVirtualKeyCode == '2')
2072 c = 0;
2073 } else
2074 c = rec.Event.KeyEvent.uChar.AsciiChar;
2075 }
2076 }
2077 }
2078 if ((c & 0177) == sim_del_char)
2079 c = 0177;
2080 if ((c & 0177) == sim_int_char)
2081 return SCPE_STOP;
2082 if ((sim_brk_char && ((c & 0177) == sim_brk_char)) || (c & SCPE_BREAK))
2083 return SCPE_BREAK;
2084 return c | SCPE_KFLAG;
2085 }
2086
2087 # define BELL_CHAR 7
2088 # define BELL_INTERVAL_MS 500
2089 static t_stat sim_os_putchar (int32 c)
2090 {
2091 DWORD unused;
2092 static uint32 last_bell_time;
2093
2094 if (!sim_localopc)
2095 return SCPE_OK;
2096
2097 if (c != 0177) {
2098 if (c == BELL_CHAR) {
2099 uint32 now = sim_os_msec ();
2100
2101 if ((now - last_bell_time) > BELL_INTERVAL_MS) {
2102 WriteConsoleA(std_output, &c, 1, &unused, NULL);
2103 last_bell_time = now;
2104 }
2105 }
2106 else
2107 WriteConsoleA(std_output, &c, 1, &unused, NULL);
2108 }
2109 return SCPE_OK;
2110 }
2111
2112 #elif defined (BSDTTY)
2113
2114
2115
2116 # include <sgtty.h>
2117 # include <fcntl.h>
2118 # include <unistd.h>
2119
2120 struct sgttyb cmdtty, runtty;
2121 struct tchars cmdtchars, runtchars;
2122 struct ltchars cmdltchars, runltchars;
2123 int cmdfl,runfl;
2124
2125 static t_stat sim_os_ttinit (void)
2126 {
2127 cmdfl = fcntl (0, F_GETFL, 0);
2128 runfl = cmdfl | FNDELAY;
2129 if (ioctl (0, TIOCGETP, &cmdtty) < 0)
2130 return SCPE_TTIERR;
2131 if (ioctl (0, TIOCGETC, &cmdtchars) < 0)
2132 return SCPE_TTIERR;
2133 if (ioctl (0, TIOCGLTC, &cmdltchars) < 0)
2134 return SCPE_TTIERR;
2135 runtty = cmdtty;
2136 runtty.sg_flags = cmdtty.sg_flags & ~(ECHO|CRMOD) | CBREAK;
2137 runtchars.t_intrc = sim_int_char;
2138 runtchars.t_quitc = 0xFF;
2139 runtchars.t_startc = 0xFF;
2140 runtchars.t_stopc = 0xFF;
2141 runtchars.t_eofc = 0xFF;
2142 runtchars.t_brkc = 0xFF;
2143 runltchars.t_suspc = 0xFF;
2144 runltchars.t_dsuspc = 0xFF;
2145 runltchars.t_rprntc = 0xFF;
2146 runltchars.t_flushc = 0xFF;
2147 runltchars.t_werasc = 0xFF;
2148 runltchars.t_lnextc = 0xFF;
2149 return SCPE_OK;
2150 }
2151
2152 static t_stat sim_os_ttrun (void)
2153 {
2154 runtchars.t_intrc = sim_int_char;
2155 (void)fcntl (0, F_SETFL, runfl);
2156 if (ioctl (0, TIOCSETP, &runtty) < 0)
2157 return SCPE_TTIERR;
2158 if (ioctl (0, TIOCSETC, &runtchars) < 0)
2159 return SCPE_TTIERR;
2160 if (ioctl (0, TIOCSLTC, &runltchars) < 0)
2161 return SCPE_TTIERR;
2162 sim_os_set_thread_priority (PRIORITY_BELOW_NORMAL);
2163 return SCPE_OK;
2164 }
2165
2166 static t_stat sim_os_ttcmd (void)
2167 {
2168 sim_os_set_thread_priority (PRIORITY_NORMAL);
2169 (void)fcntl (0, F_SETFL, cmdfl);
2170 if (ioctl (0, TIOCSETP, &cmdtty) < 0)
2171 return SCPE_TTIERR;
2172 if (ioctl (0, TIOCSETC, &cmdtchars) < 0)
2173 return SCPE_TTIERR;
2174 if (ioctl (0, TIOCSLTC, &cmdltchars) < 0)
2175 return SCPE_TTIERR;
2176 return SCPE_OK;
2177 }
2178
2179 static t_stat sim_os_ttclose (void)
2180 {
2181 return sim_ttcmd ();
2182 }
2183
2184 static t_bool sim_os_ttisatty (void)
2185 {
2186 return isatty (fileno (stdin));
2187 }
2188
2189 static t_stat sim_os_poll_kbd (void)
2190 {
2191 int status;
2192 unsigned char buf[1];
2193
2194 status = read (0, buf, 1);
2195 if (status != 1) return SCPE_OK;
2196 if (sim_brk_char && (buf[0] == sim_brk_char))
2197 return SCPE_BREAK;
2198 if (sim_int_char && (buf[0] == sim_int_char))
2199 return SCPE_STOP;
2200 return (buf[0] | SCPE_KFLAG);
2201 }
2202
2203 static t_stat sim_os_putchar (int32 out)
2204 {
2205 char c;
2206
2207 if (!sim_localopc)
2208 return SCPE_OK;
2209
2210 c = out;
2211 if (write (1, &c, 1)) {};
2212 return SCPE_OK;
2213 }
2214
2215
2216
2217 #else
2218
2219 # include <termios.h>
2220 # include <unistd.h>
2221
2222 struct termios cmdtty, runtty;
2223
2224 static t_stat sim_os_ttinit (void)
2225 {
2226 if (!isatty (fileno (stdin)))
2227 return SCPE_OK;
2228 if (tcgetattr (0, &cmdtty) < 0)
2229 return SCPE_TTIERR;
2230 runtty = cmdtty;
2231 runtty.c_lflag = runtty.c_lflag & ~(ECHO | ICANON);
2232 runtty.c_oflag = runtty.c_oflag & ~OPOST;
2233 runtty.c_iflag = runtty.c_iflag & ~ICRNL;
2234 runtty.c_cc[VINTR] = sim_int_char;
2235 runtty.c_cc[VQUIT] = 0;
2236 runtty.c_cc[VERASE] = 0;
2237 runtty.c_cc[VKILL] = 0;
2238 runtty.c_cc[VEOF] = 0;
2239 runtty.c_cc[VEOL] = 0;
2240 runtty.c_cc[VSTART] = 0;
2241 runtty.c_cc[VSUSP] = 0;
2242 runtty.c_cc[VSTOP] = 0;
2243 # if defined (VREPRINT)
2244 runtty.c_cc[VREPRINT] = 0;
2245 # endif
2246 # if defined (VDISCARD)
2247 runtty.c_cc[VDISCARD] = 0;
2248 # endif
2249 # if defined (VWERASE)
2250 runtty.c_cc[VWERASE] = 0;
2251 # endif
2252 # if defined (VLNEXT)
2253 runtty.c_cc[VLNEXT] = 0;
2254 # endif
2255 runtty.c_cc[VMIN] = 0;
2256 runtty.c_cc[VTIME] = 0;
2257 # if defined (VDSUSP)
2258 runtty.c_cc[VDSUSP] = 0;
2259 # endif
2260 # if defined (VSTATUS)
2261 runtty.c_cc[VSTATUS] = 0;
2262 # endif
2263 return SCPE_OK;
2264 }
2265
2266 static t_stat sim_os_ttrun (void)
2267 {
2268 if (!isatty (fileno (stdin)))
2269 return SCPE_OK;
2270 runtty.c_cc[VINTR] = sim_int_char;
2271 # if defined(__ANDROID__)
2272 # define TCSA_TYPE TCSANOW
2273 (void)fflush(stdout);
2274 (void)fflush(stderr);
2275 # else
2276 # define TCSA_TYPE TCSAFLUSH
2277 # endif
2278 if (tcsetattr (0, TCSA_TYPE, &runtty) < 0)
2279 return SCPE_TTIERR;
2280 sim_os_set_thread_priority (PRIORITY_BELOW_NORMAL);
2281 return SCPE_OK;
2282 }
2283
2284 static t_stat sim_os_ttcmd (void)
2285 {
2286 if (!isatty (fileno (stdin)))
2287 return SCPE_OK;
2288 sim_os_set_thread_priority (PRIORITY_NORMAL);
2289 # if defined(__ANDROID__)
2290 (void)fflush(stdout);
2291 (void)fflush(stderr);
2292 # endif
2293 if (tcsetattr (0, TCSA_TYPE, &cmdtty) < 0)
2294 return SCPE_TTIERR;
2295 return SCPE_OK;
2296 }
2297
2298 static t_stat sim_os_ttclose (void)
2299 {
2300 return sim_ttcmd ();
2301 }
2302
2303 static t_bool sim_os_ttisatty (void)
2304 {
2305 return isatty (fileno (stdin));
2306 }
2307
2308 static t_stat sim_os_poll_kbd (void)
2309 {
2310 int status;
2311 unsigned char buf[1];
2312
2313 status = read (0, buf, 1);
2314 if (status != 1) return SCPE_OK;
2315 if (sim_brk_char && (buf[0] == sim_brk_char))
2316 return SCPE_BREAK;
2317 if (sim_int_char && (buf[0] == sim_int_char))
2318 return SCPE_STOP;
2319 return (buf[0] | SCPE_KFLAG);
2320 }
2321
2322 static t_stat sim_os_putchar (int32 out)
2323 {
2324 char c;
2325
2326 if (!sim_localopc)
2327 return SCPE_OK;
2328
2329 c = out;
2330 (void)!write (1, &c, 1);
2331 return SCPE_OK;
2332 }
2333
2334 #endif
2335
2336
2337
2338
2339
2340
2341
2342 #define ESC_CHAR '~'
2343
2344 static void decode (char *decoded, const char *encoded)
2345 {
2346 char c;
2347
2348
2349 while ((c = *decoded++ = *encoded++))
2350 if (c == ESC_CHAR) {
2351 if ((isalpha ((unsigned char)*encoded)) ||
2352 (*encoded == '@') ||
2353 ((*encoded >= '[') && (*encoded <= '_')))
2354
2355 *(decoded - 1) = *encoded++ & 037;
2356 else {
2357 if ((*encoded == '\0') ||
2358 (*encoded++ != ESC_CHAR))
2359 decoded--;
2360 }
2361 }
2362 return;
2363 }
2364
2365
2366
2367 static t_stat sim_set_halt (int32 flag, CONST char *cptr)
2368 {
2369 if (flag == 0)
2370 sim_exp_clrall (&sim_con_expect);
2371 else {
2372 char *mbuf;
2373 char *mbuf2;
2374
2375 if (cptr == NULL || *cptr == 0)
2376 return SCPE_2FARG;
2377
2378 sim_exp_clrall (&sim_con_expect);
2379
2380 mbuf = (char *)malloc (1 + strlen (cptr));
2381 if (!mbuf)
2382 {
2383 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2384 __func__, __FILE__, __LINE__);
2385 #if defined(USE_BACKTRACE)
2386 # if defined(SIGUSR2)
2387 (void)raise(SIGUSR2);
2388
2389 # endif
2390 #endif
2391 abort();
2392 }
2393 decode (mbuf, cptr);
2394
2395 mbuf2 = (char *)malloc (3 + strlen(cptr));
2396 if (!mbuf2)
2397 {
2398 fprintf (stderr, "\rFATAL: Out out memory! Aborting at %s[%s:%d]\r\n",
2399 __func__, __FILE__, __LINE__);
2400 #if defined(USE_BACKTRACE)
2401 # if defined(SIGUSR2)
2402 (void)raise(SIGUSR2);
2403
2404 # endif
2405 #endif
2406 abort();
2407 }
2408 (void)sprintf (mbuf2, "%s%s%s",
2409 (sim_switches & SWMASK ('A')) ? "\n" : "", mbuf,
2410 (sim_switches & SWMASK ('I')) ? "" : "\n");
2411 FREE (mbuf);
2412 mbuf = sim_encode_quoted_string ((uint8 *)mbuf2, strlen (mbuf2));
2413 sim_exp_set (&sim_con_expect, mbuf, 0, sim_con_expect.after, EXP_TYP_PERSIST, NULL);
2414 FREE (mbuf);
2415 FREE (mbuf2);
2416 }
2417
2418 return SCPE_OK;
2419 }
2420
2421
2422
2423 static t_stat sim_set_response (int32 flag, CONST char *cptr)
2424 {
2425 if (flag == 0)
2426 sim_send_clear (&sim_con_send);
2427 else {
2428 uint8 *rbuf;
2429
2430 if (cptr == NULL || *cptr == 0)
2431 return SCPE_2FARG;
2432
2433 rbuf = (uint8 *)malloc (1 + strlen(cptr));
2434 if (!rbuf)
2435 {
2436 fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2437 __func__, __FILE__, __LINE__);
2438 #if defined(USE_BACKTRACE)
2439 # if defined(SIGUSR2)
2440 (void)raise(SIGUSR2);
2441
2442 # endif
2443 #endif
2444 abort();
2445 }
2446
2447 decode ((char *)rbuf, cptr);
2448 sim_send_input (&sim_con_send, rbuf, strlen((char *)rbuf), 0, 0);
2449 FREE (rbuf);
2450 }
2451
2452 return SCPE_OK;
2453 }
2454
2455
2456
2457 static t_stat sim_set_delay (int32 flag, CONST char *cptr)
2458 {
2459 int32 val;
2460 t_stat r;
2461
2462 if (cptr == NULL || *cptr == 0)
2463 return SCPE_2FARG;
2464
2465 val = (int32) get_uint (cptr, 10, INT_MAX, &r);
2466
2467 if (r == SCPE_OK)
2468 sim_con_expect.after = val;
2469
2470 return r;
2471 }