diff --git a/Visual Studio Projects/FrontPanelTest.vcproj b/Visual Studio Projects/FrontPanelTest.vcproj index e684a37d..95c97aaa 100644 --- a/Visual Studio Projects/FrontPanelTest.vcproj +++ b/Visual Studio Projects/FrontPanelTest.vcproj @@ -35,6 +35,9 @@ <Tool Name="VCXMLDataGeneratorTool" /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> <Tool Name="VCMIDLTool" /> @@ -116,6 +119,9 @@ <Tool Name="VCXMLDataGeneratorTool" /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> <Tool Name="VCMIDLTool" /> @@ -126,7 +132,7 @@ EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" OmitFramePointers="true" - WholeProgramOptimization="true" + WholeProgramOptimization="false" AdditionalIncludeDirectories="./;../;../VAX/;../pdp11/;"../../windows-build/winpcap/Wpdpack/Include";"../../windows-build/PCRE/include/";"../../windows-build/pthreads"" PreprocessorDefinitions="_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;PTW32_STATIC_LIB" StringPooling="true" diff --git a/frontpanel/FrontPanelTest.c b/frontpanel/FrontPanelTest.c index 9537ada4..612b4313 100644 --- a/frontpanel/FrontPanelTest.c +++ b/frontpanel/FrontPanelTest.c @@ -148,11 +148,10 @@ if ((argc > 1) && ((!strcmp("-d", argv[1])) || (!strcmp("-D", argv[1])) || (!str if ((f = fopen (sim_config, "w"))) { if (debug) { fprintf (f, "set verbose\n"); - fprintf (f, "set log simulator.dbg\n"); - fprintf (f, "set debug -n -a log\n"); + fprintf (f, "set debug -n -a simulator.dbg\n"); fprintf (f, "set cpu conhalt\n"); fprintf (f, "set remote telnet=2226\n"); - fprintf (f, "set rem-con debug=XMT;RCV\n"); + fprintf (f, "set rem-con debug=XMT;RCV;MODE;REPEAT;CMD\n"); fprintf (f, "set remote notelnet\n"); } fprintf (f, "set cpu autoboot\n"); @@ -184,9 +183,8 @@ if (!panel) { } if (debug) { - sim_panel_set_debug_mode (panel, DBG_XMT|DBG_RCV); + sim_panel_set_debug_mode (panel, DBG_XMT|DBG_RCV|DBG_REQ|DBG_RSP); } - tape = sim_panel_add_device_panel (panel, "TAPE DRIVE"); if (!tape) { @@ -313,7 +311,7 @@ if (sim_panel_get_registers (panel, NULL)) { printf ("Error getting register data: %s\n", sim_panel_get_error()); goto Done; } -if (sim_panel_set_display_callback (panel, &DisplayCallback, NULL, 5)) { +if (sim_panel_set_display_callback_interval (panel, &DisplayCallback, NULL, 200000)) { printf ("Error setting automatic display callback: %s\n", sim_panel_get_error()); goto Done; } @@ -336,19 +334,27 @@ if (sim_panel_dismount (panel, "RL0")) { } remove ("TEST-RL.DSK"); if (sim_panel_break_set (panel, "400")) { - printf ("Unexpected establishing a breakpoint: %s\n", sim_panel_get_error()); + printf ("Unexpected error establishing a breakpoint: %s\n", sim_panel_get_error()); goto Done; } if (sim_panel_break_clear (panel, "400")) { - printf ("Unexpected clearing a breakpoint: %s\n", sim_panel_get_error()); + printf ("Unexpected error clearing a breakpoint: %s\n", sim_panel_get_error()); goto Done; } if (sim_panel_break_output_set (panel, "\"32..31..30\"")) { - printf ("Unexpected establishing an output breakpoint: %s\n", sim_panel_get_error()); + printf ("Unexpected error establishing an output breakpoint: %s\n", sim_panel_get_error()); goto Done; } if (sim_panel_break_output_clear (panel, "\"32..31..30\"")) { - printf ("Unexpected clearing an output breakpoint: %s\n", sim_panel_get_error()); + printf ("Unexpected error clearing an output breakpoint: %s\n", sim_panel_get_error()); + goto Done; + } +if (sim_panel_break_output_set (panel, "-P \"Normal operation not possible.\"")) { + printf ("Unexpected error establishing an output breakpoint: %s\n", sim_panel_get_error()); + goto Done; + } +if (sim_panel_break_output_set (panel, "-P \"Device? [XQA0]: \"")) { + printf ("Unexpected error establishing an output breakpoint: %s\n", sim_panel_get_error()); goto Done; } sim_panel_clear_error (); diff --git a/sim_console.c b/sim_console.c index 11f55c23..5553fa73 100644 --- a/sim_console.c +++ b/sim_console.c @@ -114,6 +114,9 @@ sim_ttisatty called to determine if running interactively sim_os_poll_kbd poll for keyboard input sim_os_putchar output character to console + sim_set_noconsole_port Enable automatic WRU console polling + sim_set_stable_registers_state Declare that all registers are always stable + The first group is OS-independent; the second group is OS-dependent. @@ -172,6 +175,7 @@ int32 sim_del_char = '\b'; /* delete character */ #else int32 sim_del_char = 0177; #endif +extern TMLN *sim_oline; /* global output socket */ static t_stat sim_con_poll_svc (UNIT *uptr); /* console connection poll routine */ static t_stat sim_con_reset (DEVICE *dptr); /* console reset routine */ @@ -243,6 +247,16 @@ sim_con_console_port = FALSE; return SCPE_OK; } +static t_bool sim_con_stable_registers = FALSE; + +/* Enable automatic WRU console polling */ + +t_stat sim_set_stable_registers_state (void) +{ +sim_con_stable_registers = TRUE; +return SCPE_OK; +} + /* Unit service for console connection polling */ static t_stat sim_con_poll_svc (UNIT *uptr) @@ -409,18 +423,28 @@ while (*cptr != 0) { return SCPE_OK; } +#define MAX_REMOTE_SESSIONS 40 /* Arbitrary Session Limit */ + t_stat sim_rem_con_poll_svc (UNIT *uptr); /* remote console connection poll routine */ t_stat sim_rem_con_data_svc (UNIT *uptr); /* remote console connection data routine */ +t_stat sim_rem_con_repeat_svc (UNIT *uptr); /* remote auto repeat command console timing routine */ t_stat sim_rem_con_reset (DEVICE *dptr); /* remote console reset routine */ -UNIT sim_rem_con_unit[2] = { +UNIT sim_rem_con_unit[2+MAX_REMOTE_SESSIONS] = { { UDATA (&sim_rem_con_poll_svc, UNIT_IDLE, 0) }, /* remote console connection polling unit */ { UDATA (&sim_rem_con_data_svc, UNIT_IDLE|UNIT_DIS, 0) }}; /* console data handling unit */ +#define DBG_MOD 0x00000004 /* Remote Console Mode activities */ +#define DBG_REP 0x00000008 /* Remote Console Repeat activities */ +#define DBG_CMD 0x00000010 /* Remote Console Command activities */ + DEBTAB sim_rem_con_debug[] = { {"TRC", DBG_TRC, "routine calls"}, {"XMT", DBG_XMT, "Transmitted Data"}, {"RCV", DBG_RCV, "Received Data"}, {"CON", DBG_CON, "connection activity"}, + {"CMD", DBG_CMD, "Remote Console Command activity"}, + {"MODE", DBG_MOD, "Remote Console Mode activity"}, + {"REPEAT", DBG_REP, "Remote Console Repeat activity"}, {0} }; @@ -439,10 +463,15 @@ DEVICE sim_remote_console = { NULL, NULL, sim_rem_con_reset, NULL, NULL, NULL, NULL, DEV_DEBUG | DEV_NOSAVE, 0, sim_rem_con_debug, NULL, NULL, NULL, NULL, NULL, sim_rem_con_description}; -#define MAX_REMOTE_SESSIONS 40 /* Arbitrary Session Limit */ static int32 *sim_rem_buf_size = NULL; static int32 *sim_rem_buf_ptr = NULL; static char **sim_rem_buf = NULL; +static char **sim_rem_act_buf = NULL; +static size_t *sim_rem_act_buf_size = NULL; +static char **sim_rem_act = NULL; +static uint32 *sim_rem_repeat_interval = NULL; +static t_bool *sim_rem_repeat_pending = NULL; +static char **sim_rem_repeat_action = NULL; static t_bool *sim_rem_single_mode = NULL; /* per line command mode (single command or must continue) */ static TMXR sim_rem_con_tmxr = { 0, 0, 0, NULL, NULL, &sim_remote_console };/* remote console line mux */ static uint32 sim_rem_read_timeout = 30; /* seconds before automatic continue */ @@ -523,6 +552,10 @@ for (i=connections=0; i<sim_rem_con_tmxr.lines; i++) { else fprintf (st, "Remote Console Input on connection %d does not continue automatically\n", i); } + if (sim_rem_repeat_action[i]) { + fprintf (st, "The Command: %s\n", sim_rem_repeat_action[i]); + fprintf (st, " is repeated every %s\n", sim_fmt_secs (sim_rem_repeat_interval[i] / 1000000.0)); + } } return SCPE_OK; } @@ -567,17 +600,22 @@ return SCPE_OK; static t_stat x_continue_cmd (int32 flag, CONST char *cptr) { -return SCPE_IERR; /* This routine should never be called */ +return 1+SCPE_IERR; /* This routine should never be called */ +} + +static t_stat x_repeat_cmd (int32 flag, CONST char *cptr) +{ +return 2+SCPE_IERR; /* This routine should never be called */ } static t_stat x_step_cmd (int32 flag, CONST char *cptr) { -return SCPE_IERR; /* This routine should never be called */ +return 3+SCPE_IERR; /* This routine should never be called */ } static t_stat x_run_cmd (int32 flag, CONST char *cptr) { -return SCPE_IERR; /* This routine should never be called */ +return 4+SCPE_IERR; /* This routine should never be called */ } static t_stat x_help_cmd (int32 flag, CONST char *cptr); @@ -591,6 +629,7 @@ static CTAB allowed_remote_cmds[] = { { "ASSIGN", &assign_cmd, 0 }, { "DEASSIGN", &deassign_cmd, 0 }, { "CONTINUE", &x_continue_cmd, 0 }, + { "REPEAT", &x_repeat_cmd, 0 }, { "STEP", &x_step_cmd, 0 }, { "PWD", &pwd_cmd, 0 }, { "SAVE", &save_cmd, 0 }, @@ -612,6 +651,7 @@ static CTAB allowed_master_remote_cmds[] = { { "ASSIGN", &assign_cmd, 0 }, { "DEASSIGN", &deassign_cmd, 0 }, { "CONTINUE", &x_continue_cmd, 0 }, + { "REPEAT", &x_repeat_cmd, 0 }, { "STEP", &x_step_cmd, 0 }, { "PWD", &pwd_cmd, 0 }, { "SAVE", &save_cmd, 0 }, @@ -629,6 +669,9 @@ static CTAB allowed_master_remote_cmds[] = { { "BOOT", &x_run_cmd, RU_BOOT }, { "BREAK", &brk_cmd, SSH_ST }, { "NOBREAK", &brk_cmd, SSH_CL }, + { "EXPECT", &expect_cmd, 1 }, + { "NOEXPECT", &expect_cmd, 0 }, + { "SEND", &send_cmd, 0 }, { NULL, NULL } }; @@ -637,6 +680,7 @@ static CTAB allowed_single_remote_cmds[] = { { "DETACH", &detach_cmd, 0 }, { "EXAMINE", &exdep_cmd, EX_E }, { "EVALUATE", &eval_cmd, 0 }, + { "REPEAT", &x_repeat_cmd, 0 }, { "PWD", &pwd_cmd, 0 }, { "DIR", &dir_cmd, 0 }, { "LS", &dir_cmd, 0 }, @@ -646,6 +690,11 @@ static CTAB allowed_single_remote_cmds[] = { { NULL, NULL } }; +static CTAB remote_only_cmds[] = { + { "REPEAT", &x_repeat_cmd, 0 }, + { NULL, NULL } + }; + static t_stat x_help_cmd (int32 flag, CONST char *cptr) { CTAB *cmdp, *cmdph; @@ -690,23 +739,27 @@ return stat; static void _sim_rem_log_out (TMLN *lp) { char cbuf[4*CBUFSIZE]; +int line = (int)(lp - sim_rem_con_tmxr.ldsc); -if (sim_log) { - int32 unwritten; - +if ((!sim_oline) && (sim_log)) { fflush (sim_log); sim_fseeko (sim_log, sim_rem_cmd_log_start, SEEK_SET); cbuf[sizeof(cbuf)-1] = '\0'; while (fgets (cbuf, sizeof(cbuf)-1, sim_log)) tmxr_linemsgf (lp, "%s", cbuf); - if (!tmxr_input_pending_ln (lp)) { - do { - unwritten = tmxr_send_buffered_data (lp); - if (unwritten == lp->txbsz) - sim_os_ms_sleep (100); - } while (unwritten == lp->txbsz); - } } +sim_oline = NULL; +if ((sim_rem_act[line] == NULL) && + (!tmxr_input_pending_ln (lp))) { + int32 unwritten; + + do { + unwritten = tmxr_send_buffered_data (lp); + if (unwritten == lp->txbsz) + sim_os_ms_sleep (100); + } while (unwritten == lp->txbsz); + } + } void sim_remote_process_command (void) @@ -724,17 +777,152 @@ cptr = cbuf; cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ sim_rem_active_command = find_cmd (gbuf); /* find command */ -sim_ttcmd (); /* restore console */ +if (!sim_processing_event) + sim_ttcmd (); /* restore console */ stat = sim_rem_active_command->action (sim_rem_active_command->arg, cptr);/* execute command */ if (stat != SCPE_OK) stat = _sim_rem_message (gbuf, stat); /* display results */ sim_last_cmd_stat = SCPE_BARE_STATUS(stat); -sim_ttrun (); /* set console mode */ -sim_cancel (&sim_rem_con_unit[1]); /* force immediate activation of sim_rem_con_data_svc */ -sim_activate (&sim_rem_con_unit[1], -1); +if (!sim_processing_event) { + sim_ttrun (); /* set console mode */ + sim_cancel (&sim_rem_con_unit[1]); /* force immediate activation of sim_rem_con_data_svc */ + sim_activate (&sim_rem_con_unit[1], -1); + } sim_switches = saved_switches; /* restore original switches */ } +/* Clear pending actions */ + +static char *sim_rem_clract (int32 line) +{ +TMLN *lp = &sim_rem_con_tmxr.ldsc[line]; + +tmxr_send_buffered_data (lp); /* flush any buffered data */ +return sim_rem_act[line] = NULL; +} + +/* Set up pending actions */ + +static void sim_rem_setact (int32 line, const char *action) +{ +if (action) { + size_t act_size = strlen (action) + 1; + + if (act_size > sim_rem_act_buf_size[line]) {/* expand buffer if necessary */ + sim_rem_act_buf[line] = (char *)realloc (sim_rem_act_buf[line], act_size); + sim_rem_act_buf_size[line] = act_size; + } + strcpy (sim_rem_act_buf[line], action); /* populate buffer */ + sim_rem_act[line] = sim_rem_act_buf[line]; /* start at beginning of buffer */ + } +else + sim_rem_clract (line); +} + +/* Get next pending action, if any */ + +static char *sim_rem_getact (int32 line, char *buf, int32 size) +{ +char *ep; +size_t lnt; + +if (sim_rem_act[line] == NULL) /* any action? */ + return NULL; +while (sim_isspace (*sim_rem_act[line])) /* skip spaces */ + sim_rem_act[line]++; +if (*sim_rem_act[line] == 0) /* now empty? */ + return sim_rem_clract (line); +if ((ep = strchr (sim_rem_act[line], ';'))) { /* cmd delimiter? */ + lnt = ep - sim_rem_act[line]; /* cmd length */ + memcpy (buf, sim_rem_act[line], lnt + 1); /* copy with ; */ + buf[lnt] = 0; /* erase ; */ + sim_rem_act[line] += lnt + 1; /* adv ptr */ + } +else { + strncpy (buf, sim_rem_act[line], size); /* copy action */ + sim_rem_act[line] += strlen (sim_rem_act[line]);/* adv ptr to end */ + } +return buf; +} + +/* + Parse and setup Remote Console REPEAT command: + REPEAT EVERY nnn USECS Command {; command...} + */ +static t_stat _rem_repeat_cmd_setup (int32 line, CONST char **iptr) +{ +char gbuf[CBUFSIZE]; +int32 val; +t_bool all_stop = FALSE; +t_stat stat = SCPE_OK; +CONST char *cptr = *iptr; + +sim_debug (DBG_REP, &sim_remote_console, "Repeat Setup: %s\n", cptr); +if (*cptr == 0) /* required argument? */ + stat = SCPE_2FARG; +else { + cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ + if (MATCH_CMD (gbuf, "EVERY") == 0) { + cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ + val = (int32) get_uint (gbuf, 10, INT_MAX, &stat); + if ((stat != SCPE_OK) || (val <= 0)) /* error? */ + stat = SCPE_ARG; + else { + cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ + if ((MATCH_CMD (gbuf, "USECS") != 0) || (*cptr == 0)) + stat = SCPE_ARG; + else + sim_rem_repeat_interval[line] = val; + } + } + else { + if (MATCH_CMD (gbuf, "STOP") == 0) { + if (*cptr) { /* more command arguments? */ + cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ + if ((MATCH_CMD (gbuf, "ALL") != 0) || /* */ + (*cptr != 0) || /* */ + (line != 0)) /* master line? */ + stat = SCPE_ARG; + else + all_stop = TRUE; + } + else + sim_rem_repeat_interval[line] = 0; + } + else + stat = SCPE_ARG; + } + } +if (stat == SCPE_OK) { + if (all_stop) { + for (line = 0; line < sim_rem_con_tmxr.lines; line++) { + free (sim_rem_repeat_action[line]); + sim_rem_repeat_action[line] = NULL; + sim_cancel (&sim_rem_con_unit[line + 2]); + sim_rem_repeat_pending[line] = FALSE; + sim_rem_clract (line); + } + } + else { + if (sim_rem_repeat_interval[line] != 0) { + sim_rem_repeat_action[line] = (char *)realloc (sim_rem_repeat_action[line], 1 + strlen (cptr)); + strcpy (sim_rem_repeat_action[line], cptr); + cptr += strlen (cptr); + stat = sim_activate_after (&sim_rem_con_unit[line + 2], sim_rem_repeat_interval[line]); + } + else { + free (sim_rem_repeat_action[line]); + sim_rem_repeat_action[line] = NULL; + sim_cancel (&sim_rem_con_unit[line + 2]); + } + sim_rem_repeat_pending[line] = FALSE; + sim_rem_clract (line); + } + } +*iptr = cptr; +return stat; +} + /* Unit service for remote console data polling */ t_stat sim_rem_con_data_svc (UNIT *uptr) @@ -760,8 +948,13 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0); t_bool master_session = (sim_rem_master_mode && (i == 0)); lp = &sim_rem_con_tmxr.ldsc[i]; - if (!lp->conn) + if (!lp->conn) { + if (sim_rem_repeat_interval[i]) { /* was repeated enabled? */ + cptr = strcpy (gbuf, "STOP"); + _rem_repeat_cmd_setup (i, &cptr); /* make sure it is now disabled */ + } continue; + } if (master_session && !sim_rem_master_was_connected) { tmxr_linemsgf (lp, "\nMaster Mode Session\r\n"); tmxr_send_buffered_data (lp); /* flush any buffered data */ @@ -770,6 +963,7 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0); stat = SCPE_OK; if ((was_active_command) || (master_session && !sim_rem_single_mode[i])) { + sim_debug (DBG_MOD, &sim_remote_console, "Session: %d %s %s\n", i, was_active_command ? "Was Active" : "", (master_session && !sim_rem_single_mode[i]) ? "master_session && !sim_rem_single_mode[i]" : ""); if (was_active_command) { sim_rem_cmd_active_line = -1; /* Done with active command */ if (!sim_rem_active_command) { /* STEP command? */ @@ -792,58 +986,59 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0); tmxr_linemsgf (lpj, "\nRemote Master Console(%s) Entering Commands\n", lp->ipad); tmxr_send_buffered_data (lpj); /* flush any buffered data */ } - lp = &sim_rem_con_tmxr.ldsc[i]; } } else { - c = tmxr_getc_ln (lp); - if (!(TMXR_VALID & c)) - continue; - c = c & ~TMXR_VALID; - if (sim_rem_single_mode[i]) { - if (c == sim_int_char) { /* ^E (the interrupt character) must start continue mode console interaction */ - sim_rem_single_mode[i] = FALSE; /* enter multi command mode */ - sim_is_running = 0; - sim_stop_timer_services (); - stat = SCPE_STOP; - _sim_rem_message ("RUN", stat); - _sim_rem_log_out (lp); - for (j=0; j < sim_rem_con_tmxr.lines; j++) { - TMLN *lpj = &sim_rem_con_tmxr.ldsc[j]; - if ((i == j) || (!lpj->conn)) - continue; - tmxr_linemsgf (lpj, "\nRemote Console %d(%s) Entering Commands\n", i, lp->ipad); - tmxr_send_buffered_data (lpj); /* flush any buffered data */ - } - lp = &sim_rem_con_tmxr.ldsc[i]; - if (!master_session) - tmxr_linemsg (lp, "\r\nSimulator paused.\r\n"); - if (!master_session && sim_rem_read_timeouts[i]) { - tmxr_linemsgf (lp, "Simulation will resume automatically if input is not received in %d seconds\n", sim_rem_read_timeouts[i]); - tmxr_linemsgf (lp, "\r\n"); - tmxr_send_buffered_data (lp); /* flush any buffered data */ - } - } - else { - if ((sim_rem_buf_ptr[i] == 0) && /* At beginning of input line */ - ((c == '\n') || /* Ignore bare LF between commands (Microsoft Telnet bug) */ - (c == '\r'))) /* Ignore empty commands */ - continue; - if ((c == '\004') || (c == '\032')) { /* EOF character (^D or ^Z) ? */ - tmxr_linemsgf (lp, "\r\nGoodbye\r\n"); - tmxr_send_buffered_data (lp); /* flush any buffered data */ - tmxr_reset_ln (lp); - continue; - } - if (sim_rem_buf_ptr[i] == 0) { - /* we just picked up the first character on a command line */ + if ((!sim_rem_repeat_pending[i]) || (sim_rem_buf_ptr[i] != 0)) { + c = tmxr_getc_ln (lp); + if (!(TMXR_VALID & c)) + continue; + c = c & ~TMXR_VALID; + if (sim_rem_single_mode[i]) { + if (c == sim_int_char) { /* ^E (the interrupt character) must start continue mode console interaction */ + sim_rem_single_mode[i] = FALSE; /* enter multi command mode */ + sim_is_running = 0; + sim_stop_timer_services (); + stat = SCPE_STOP; + _sim_rem_message ("RUN", stat); + _sim_rem_log_out (lp); + for (j=0; j < sim_rem_con_tmxr.lines; j++) { + TMLN *lpj = &sim_rem_con_tmxr.ldsc[j]; + if ((i == j) || (!lpj->conn)) + continue; + tmxr_linemsgf (lpj, "\nRemote Console %d(%s) Entering Commands\n", i, lp->ipad); + tmxr_send_buffered_data (lpj); /* flush any buffered data */ + } + lp = &sim_rem_con_tmxr.ldsc[i]; if (!master_session) - tmxr_linemsgf (lp, "\r\n%s", sim_prompt); - else - tmxr_linemsgf (lp, "\r\n%s", sim_is_running ? "SIM> " : "sim> "); - sim_debug (DBG_XMT, &sim_remote_console, "Prompt Written: %s\n", sim_is_running ? "SIM> " : "sim> "); - if (!tmxr_input_pending_ln (lp)) - tmxr_send_buffered_data (lp); /* flush any buffered data */ + tmxr_linemsg (lp, "\r\nSimulator paused.\r\n"); + if (!master_session && sim_rem_read_timeouts[i]) { + tmxr_linemsgf (lp, "Simulation will resume automatically if input is not received in %d seconds\n", sim_rem_read_timeouts[i]); + tmxr_linemsgf (lp, "\r\n"); + tmxr_send_buffered_data (lp); /* flush any buffered data */ + } + } + else { + if ((sim_rem_buf_ptr[i] == 0) && /* At beginning of input line */ + ((c == '\n') || /* Ignore bare LF between commands (Microsoft Telnet bug) */ + (c == '\r'))) /* Ignore empty commands */ + continue; + if ((c == '\004') || (c == '\032')) { /* EOF character (^D or ^Z) ? */ + tmxr_linemsgf (lp, "\r\nGoodbye\r\n"); + tmxr_send_buffered_data (lp); /* flush any buffered data */ + tmxr_reset_ln (lp); + continue; + } + if (sim_rem_buf_ptr[i] == 0) { + /* we just picked up the first character on a command line */ + if (!master_session) + tmxr_linemsgf (lp, "\r\n%s", sim_prompt); + else + tmxr_linemsgf (lp, "\r\n%s", sim_is_running ? "SIM> " : "sim> "); + sim_debug (DBG_XMT, &sim_remote_console, "Prompt Written: %s\n", sim_is_running ? "SIM> " : "sim> "); + if ((sim_rem_act[i] == NULL) && (!tmxr_input_pending_ln (lp))) + tmxr_send_buffered_data (lp); /* flush any buffered data */ + } } } } @@ -861,6 +1056,31 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0); tmxr_send_buffered_data (lp); /* flush any buffered data */ } do { + if (sim_rem_buf_ptr[i] == 0) { + if (sim_rem_getact (i, sim_rem_buf[i], sim_rem_buf_size[i])) { + if (!master_session) + tmxr_linemsgf (lp, "%s%s\n", sim_prompt, sim_rem_buf[i]); + else + tmxr_linemsgf (lp, "%s%s\n", sim_is_running ? "SIM> " : "sim> ", sim_rem_buf[i]); + sim_rem_buf_ptr[i] = strlen (sim_rem_repeat_action[i]); + got_command = TRUE; + break; + } + else { + if (sim_rem_repeat_pending[i]) { + sim_rem_repeat_pending[i] = FALSE; + sim_rem_setact (i, sim_rem_repeat_action[i]); + sim_rem_getact (i, sim_rem_buf[i], sim_rem_buf_size[i]); + if (!master_session) + tmxr_linemsgf (lp, "%s%s\n", sim_prompt, sim_rem_buf[i]); + else + tmxr_linemsgf (lp, "%s%s\n", sim_is_running ? "SIM> " : "sim> ", sim_rem_buf[i]); + sim_rem_buf_ptr[i] = strlen (sim_rem_repeat_action[i]); + got_command = TRUE; + break; + } + } + } if (!sim_rem_single_mode[i]) { c = tmxr_getc_ln (lp); if (!(TMXR_VALID & c)) { @@ -957,12 +1177,13 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0); c = c & ~TMXR_VALID; } } while ((!got_command) && ((!sim_rem_single_mode[i]) || c)); - if (!tmxr_input_pending_ln (lp)) + if ((sim_rem_act[i] == NULL) && (!tmxr_input_pending_ln (lp))) tmxr_send_buffered_data (lp); /* flush any buffered data */ if ((sim_rem_single_mode[i]) && !got_command) { break; } - sim_printf ("Remote Console Command from %s> %s\r\n", lp->ipad, sim_rem_buf[i]); + if (!sim_rem_master_mode) + sim_printf ("Remote Console Command from %s> %s\r\n", lp->ipad, sim_rem_buf[i]); got_command = FALSE; if (strlen(sim_rem_buf[i]) >= sizeof(cbuf)) { sim_printf ("\r\nLine too long. Ignored. Continuing Simulator execution\r\n"); @@ -1000,6 +1221,8 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0); } sim_rem_cmd_log_start = sim_ftell (sim_log); basecmdp = find_cmd (gbuf); /* validate basic command */ + if (basecmdp == NULL) + basecmdp = find_ctab (remote_only_cmds, gbuf);/* validate basic command */ if (basecmdp == NULL) { if ((gbuf[0] == ';') || (gbuf[0] == '#')) { /* ignore comment */ sim_rem_cmd_active_line = i; @@ -1013,39 +1236,64 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0); } else { if ((cmdp = find_ctab (sim_rem_single_mode[i] ? allowed_single_remote_cmds : (master_session ? allowed_master_remote_cmds : allowed_remote_cmds), gbuf))) {/* lookup command */ - if (cmdp->action == &x_continue_cmd) + sim_debug (DBG_CMD, &sim_remote_console, "gbuf='%s', basecmd='%s', cmd='%s', action=%p, continue_cmd=%p, repeat_cmd=%p\n", gbuf, basecmdp->name, cmdp->name, cmdp->action, &x_continue_cmd, &x_repeat_cmd); + if (cmdp->action == &x_continue_cmd) { + sim_debug (DBG_CMD, &sim_remote_console, "continue_cmd executing\n"); stat = SCPE_OK; + } else { if (cmdp->action == &exit_cmd) return SCPE_EXIT; if (cmdp->action == &x_step_cmd) { + sim_debug (DBG_CMD, &sim_remote_console, "step_cmd executing\n"); steps = 1; /* default of 1 instruction */ stat = SCPE_OK; if (*cptr != 0) { /* argument? */ - cptr = get_glyph (cptr, gbuf, 0);/* get next glyph */ - if (*cptr != 0) /* should be end */ - stat = SCPE_2MARG; - else { - steps = (int32) get_uint (gbuf, 10, INT_MAX, &stat); - if ((stat != SCPE_OK) || (steps <= 0)) /* error? */ - stat = SCPE_ARG; - } - } + cptr = get_glyph (cptr, gbuf, 0);/* get next glyph */ + if (*cptr != 0) /* should be end */ + stat = SCPE_2MARG; + else { + steps = (int32) get_uint (gbuf, 10, INT_MAX, &stat); + if ((stat != SCPE_OK) || (steps <= 0)) /* error? */ + stat = SCPE_ARG; + } + } if (stat != SCPE_OK) cmdp = NULL; } else { if (cmdp->action == &x_run_cmd) { - sim_switches |= SIM_SW_HIDE;/* Request Setup only */ + sim_debug (DBG_CMD, &sim_remote_console, "run_cmd executing\n"); + if (sim_con_stable_registers && /* can we process command now? */ + sim_rem_master_mode) + sim_oline = lp; /* specify output socket */ + sim_switches |= SIM_SW_HIDE; /* Request Setup only */ stat = basecmdp->action (cmdp->arg, cptr); - sim_switches &= ~SIM_SW_HIDE;/* Done with Setup only mode */ + sim_switches &= ~SIM_SW_HIDE; /* Done with Setup only mode */ if (stat == SCPE_OK) { /* switch to CONTINUE after x_run_cmd() did RUN setup */ cmdp = find_ctab (allowed_master_remote_cmds, "CONTINUE"); } } - else - stat = SCPE_REMOTE; /* force processing outside of sim_instr() */ + else { + if (cmdp->action == &x_repeat_cmd) { + sim_debug (DBG_CMD, &sim_remote_console, "repeat_cmd executing\n"); + stat = _rem_repeat_cmd_setup (i, &cptr); + } + else { + if (sim_con_stable_registers && + sim_rem_master_mode) { /* can we process command now? */ + sim_debug (DBG_CMD, &sim_remote_console, "Processing Command directly\n"); + sim_oline = lp; /* specify output socket */ + sim_remote_process_command (); + stat = SCPE_OK; /* any message has already been emitted */ + } + else { + sim_debug (DBG_CMD, &sim_remote_console, "Processing Command via SCPE_REMOTE\n"); + stat = SCPE_REMOTE; /* force processing outside of sim_instr() */ + } + } + } } } } @@ -1136,14 +1384,36 @@ else return SCPE_OK; /* keep going */ } +t_stat sim_rem_con_repeat_svc (UNIT *uptr) +{ +int line = uptr - (sim_rem_con_unit + 2); + +sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_repeat_svc(line=%d) - interval=%d\n", line, sim_rem_repeat_interval[line]); +if (sim_rem_repeat_interval[line]) { + sim_rem_repeat_pending[line] = TRUE; + sim_activate_after (uptr, sim_rem_repeat_interval[line]); /* reschedule */ + sim_activate_abs (&sim_rem_con_unit[1], -1); /* wake up to process */ + } +return SCPE_OK; +} + t_stat sim_rem_con_reset (DEVICE *dptr) { if (sim_rem_con_tmxr.lines) { int32 i; - for (i=0; i<sim_rem_con_tmxr.lines; i++) - if (sim_rem_con_tmxr.ldsc[i].conn) - break; + sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_reset(lines=%d)\n", sim_rem_con_tmxr.lines); + for (i=0; i<MAX_REMOTE_SESSIONS; i++) { + sim_rem_con_unit[i + 2].flags = UNIT_DIS; + sim_rem_con_unit[i + 2].action = &sim_rem_con_repeat_svc; + } + for (i=0; i<sim_rem_con_tmxr.lines; i++) { + if (!sim_rem_con_tmxr.ldsc[i].conn) + continue; + sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_reset(line=%d, usecs=%d)\n", i, sim_rem_repeat_interval[i]); + if (sim_rem_repeat_interval[i]) + sim_activate_after (sim_rem_con_unit + 2 + i, sim_rem_repeat_interval[i]);/* schedule */ + } if (i != sim_rem_con_tmxr.lines) sim_activate_after (&dptr->units[1], 100000); /* continue polling for open sessions */ return sim_rem_con_poll_svc (&dptr->units[0]); /* establish polling as needed */ @@ -1208,10 +1478,22 @@ sim_rem_con_tmxr.ldsc = (TMLN *)realloc (sim_rem_con_tmxr.ldsc, sizeof(*sim_rem_ memset (sim_rem_con_tmxr.ldsc, 0, sizeof(*sim_rem_con_tmxr.ldsc)*lines); sim_rem_buf = (char **)realloc (sim_rem_buf, sizeof(*sim_rem_buf)*lines); memset (sim_rem_buf, 0, sizeof(*sim_rem_buf)*lines); +sim_rem_act_buf = (char **)realloc (sim_rem_act_buf, sizeof(*sim_rem_act_buf)*lines); +memset (sim_rem_act_buf, 0, sizeof(*sim_rem_act_buf)*lines); +sim_rem_act_buf_size = (size_t *)realloc (sim_rem_act_buf_size, sizeof(*sim_rem_act_buf_size)*lines); +memset (sim_rem_act_buf_size, 0, sizeof(*sim_rem_act_buf_size)*lines); +sim_rem_act = (char **)realloc (sim_rem_act, sizeof(*sim_rem_act)*lines); +memset (sim_rem_act, 0, sizeof(*sim_rem_act)*lines); sim_rem_buf_size = (int32 *)realloc (sim_rem_buf_size, sizeof(*sim_rem_buf_size)*lines); memset (sim_rem_buf_size, 0, sizeof(*sim_rem_buf_size)*lines); sim_rem_buf_ptr = (int32 *)realloc (sim_rem_buf_ptr, sizeof(*sim_rem_buf_ptr)*lines); memset (sim_rem_buf_ptr, 0, sizeof(*sim_rem_buf_ptr)*lines); +sim_rem_repeat_interval = (uint32 *)realloc (sim_rem_repeat_interval, sizeof(*sim_rem_repeat_interval)*lines); +memset (sim_rem_repeat_interval, 0, sizeof(*sim_rem_repeat_interval)*lines); +sim_rem_repeat_pending = (t_bool *)realloc (sim_rem_repeat_pending, sizeof(*sim_rem_repeat_pending)*lines); +memset (sim_rem_repeat_pending, 0, sizeof(*sim_rem_repeat_pending)*lines); +sim_rem_repeat_action = (char **)realloc (sim_rem_repeat_action, sizeof(*sim_rem_repeat_action)*lines); +memset (sim_rem_repeat_action, 0, sizeof(*sim_rem_repeat_action)*lines); sim_rem_single_mode = (t_bool *)realloc (sim_rem_single_mode, sizeof(*sim_rem_single_mode)*lines); memset (sim_rem_single_mode, 0, sizeof(*sim_rem_single_mode)*lines); sim_rem_read_timeouts = (uint32 *)realloc (sim_rem_read_timeouts, sizeof(*sim_rem_read_timeouts)*lines); @@ -1346,7 +1628,8 @@ t_stat sim_show_kmap (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char { if (sim_devices[0]->dradix == 16) fprintf (st, "%s = %X\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK])); -else fprintf (st, "%s = %o\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK])); +else + fprintf (st, "%s = %o\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK])); return SCPE_OK; } @@ -1376,7 +1659,8 @@ t_stat sim_show_pchar (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST cha { if (sim_devices[0]->dradix == 16) fprintf (st, "pchar mask = %X", sim_tt_pchar); -else fprintf (st, "pchar mask = %o", sim_tt_pchar); +else + fprintf (st, "pchar mask = %o", sim_tt_pchar); if (sim_tt_pchar) { static const char *pchars[] = {"NUL(^@)", "SOH(^A)", "STX(^B)", "ETX(^C)", "EOT(^D)", "ENQ(^E)", "ACK(^F)", "BEL(^G)", "BS(^H)" , "HT(^I)", "LF(^J)", "VT(^K)", "FF(^L)", "CR(^M)", "SO(^N)", "SI(^O)", @@ -1433,7 +1717,7 @@ r = sim_open_logfile (gbuf, FALSE, &sim_log, &sim_log_ref); /* open log */ if (r != SCPE_OK) /* error? */ return r; if (!sim_quiet) - printf ("Logging to file \"%s\"\n", + fprintf (stdout, "Logging to file \"%s\"\n", sim_logfile_name (sim_log, sim_log_ref)); fprintf (sim_log, "Logging to file \"%s\"\n", sim_logfile_name (sim_log, sim_log_ref)); /* start of log */ @@ -1451,7 +1735,7 @@ if (cptr && (*cptr != 0)) /* now eol? */ if (sim_log == NULL) /* no log? */ return SCPE_OK; if (!sim_quiet) - printf ("Log file closed\n"); + fprintf (stdout, "Log file closed\n"); fprintf (sim_log, "Log file closed\n"); sim_close_logfile (&sim_log_ref); /* close log */ sim_log = NULL; @@ -1467,7 +1751,8 @@ if (cptr && (*cptr != 0)) if (sim_log) fprintf (st, "Logging enabled to \"%s\"\n", sim_logfile_name (sim_log, sim_log_ref)); -else fprintf (st, "Logging disabled\n"); +else + fprintf (st, "Logging disabled\n"); return SCPE_OK; } @@ -1591,7 +1876,8 @@ if (sim_deb) { } } } -else fprintf (st, "Debug output disabled\n"); +else + fprintf (st, "Debug output disabled\n"); return SCPE_OK; } diff --git a/sim_console.h b/sim_console.h index a36d452e..7f2d4901 100644 --- a/sim_console.h +++ b/sim_console.h @@ -113,6 +113,7 @@ SEND *sim_cons_get_send (void); EXPECT *sim_cons_get_expect (void); t_stat sim_show_cons_send_input (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr); t_stat sim_set_noconsole_port (void); +t_stat sim_set_stable_registers_state (void); t_stat sim_poll_kbd (void); t_stat sim_putchar (int32 c); t_stat sim_putchar_s (int32 c); diff --git a/sim_frontpanel.c b/sim_frontpanel.c index f8ff5aab..fde13a2f 100644 --- a/sim_frontpanel.c +++ b/sim_frontpanel.c @@ -134,6 +134,7 @@ struct PANEL { size_t reg_count; REG *regs; char *reg_query; + int new_register; size_t reg_query_size; unsigned long long array_element_data; OperationalState State; @@ -143,6 +144,8 @@ struct PANEL { int io_thread_running; pthread_mutex_t io_lock; pthread_mutex_t io_send_lock; + pthread_mutex_t io_command_lock; + int command_count; int io_reg_query_pending; int io_waiting; char *io_response; @@ -154,7 +157,7 @@ struct PANEL { pthread_t callback_thread; int callback_thread_running; void *callback_context; - int callbacks_per_second; + int usecs_between_callbacks; int debug; char *simulator_version; int radix; @@ -167,10 +170,16 @@ struct PANEL { }; static const char *sim_prompt = "sim> "; +static const char *register_repeat_prefix = "repeat every "; +static const char *register_repeat_stop = "repeat stop"; +static const char *register_repeat_stop_all = "repeat stop all"; +static const char *register_repeat_units = " usecs "; static const char *register_get_prefix = "show time"; static const char *register_get_echo = "# REGISTERS-DONE"; +static const char *register_repeat_echo = "# REGISTERS-REPEAT-DONE"; static const char *register_dev_echo = "# REGISTERS-FOR-DEVICE:"; static const char *register_ind_echo = "# REGISTER-INDIRECT:"; +static const char *command_status = "ECHO Status:%STATUS%-%TSTATUS%"; static const char *command_done_echo = "# COMMAND-DONE"; static int little_endian; static void *_panel_reader(void *arg); @@ -209,7 +218,18 @@ if (p == NULL) return p; } -static void _panel_debug (PANEL *p, int dbits, const char *fmt, const char *buf, int bufsize, ...) +/* Allow compiler to help validate printf style format arguments */ +#if !defined __GNUC__ +#define GCC_FMT_ATTR(n, m) +#endif +#if !defined(GCC_FMT_ATTR) +#define GCC_FMT_ATTR(n, m) __attribute__ ((format (__printf__, n, m))) +#endif + +static void __panel_debug (PANEL *p, int dbits, const char *fmt, const char *buf, int bufsize, ...) GCC_FMT_ATTR(3, 6); +#define _panel_debug(p, dbits, fmt, buf, bufsize, ...) do { if (p && p->Debug && (dbits & p->debug)) __panel_debug (p, dbits, fmt, buf, bufsize, ##__VA_ARGS__);} while (0) + +static void __panel_debug (PANEL *p, int dbits, const char *fmt, const char *buf, int bufsize, ...) { if (p && p->Debug && (dbits & p->debug)) { int i; @@ -300,6 +320,7 @@ sim_panel_set_debug_file (PANEL *panel, const char *debug_file) if (!panel) return; panel->Debug = fopen(debug_file, "w"); +setvbuf (panel->Debug, NULL, _IOFBF, 65536); } void @@ -348,13 +369,13 @@ return sent; } static int -_panel_sendf (PANEL *p, int wait_for_completion, char **response, const char *fmt, ...); +_panel_sendf (PANEL *p, int *completion_status, char **response, const char *fmt, ...); static int _panel_register_query_string (PANEL *panel, char **buf, size_t *buf_size) { size_t i, j, buf_data, buf_needed = 0; -char *dev; +const char *dev; pthread_mutex_lock (&panel->io_lock); buf_needed = 2 + strlen (register_get_prefix); /* SHOW TIME */ @@ -381,7 +402,7 @@ sprintf (*buf + buf_data, "%s\r", register_get_prefix); buf_data += strlen (*buf + buf_data); dev = ""; for (i=j=0; i<panel->reg_count; i++) { - char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : ""; + const char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : ""; if (panel->regs[i].indirect) continue; @@ -412,9 +433,9 @@ for (i=j=0; i<panel->reg_count; i++) { } else { if (j == 0) - sprintf (*buf + buf_data, "E -H %s %s[0:%d]", dev, panel->regs[i].name, panel->regs[i].element_count-1); + sprintf (*buf + buf_data, "E -H %s %s[0:%d]", dev, panel->regs[i].name, (int)(panel->regs[i].element_count-1)); else - sprintf (*buf + buf_data, ",%s[0:%d]", panel->regs[i].name, panel->regs[i].element_count-1); + sprintf (*buf + buf_data, ",%s[0:%d]", panel->regs[i].name, (int)(panel->regs[i].element_count-1)); } ++j; buf_data += strlen (*buf + buf_data); @@ -424,7 +445,7 @@ if (buf_data && ((*buf)[buf_data-1] != '\r')) { buf_data += strlen (*buf + buf_data); } for (i=j=0; i<panel->reg_count; i++) { - char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : ""; + const char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : ""; if (!panel->regs[i].indirect) continue; @@ -495,6 +516,7 @@ FILE *fOut = NULL; struct stat statb; char *buf = NULL; int port; +int cmd_stat; size_t i, device_num; char hostport[64]; union {int i; char c[sizeof (int)]; } end_test; @@ -540,7 +562,6 @@ else { } else break; - } if (stat (sim_config, &statb) < 0) { sim_panel_set_error ("Can't stat simulator configuration '%s': %s", sim_config, strerror(errno)); @@ -599,6 +620,30 @@ if (debug_file) { sim_panel_set_debug_file (p, debug_file); sim_panel_set_debug_mode (p, DBG_XMT|DBG_RCV); _panel_debug (p, DBG_XMT|DBG_RCV, "Creating Simulator Process %s\n", NULL, 0, sim_path); + + if (stat (p->temp_config, &statb) < 0) { + sim_panel_set_error ("Can't stat temporary simulator configuration '%s': %s", p->temp_config, strerror(errno)); + goto Error_Return; + } + buf = (char *)_panel_malloc (statb.st_size+1); + if (buf == NULL) + goto Error_Return; + buf[statb.st_size] = '\0'; + fIn = fopen (p->temp_config, "r"); + if (fIn == NULL) { + sim_panel_set_error ("Can't open temporary configuration file '%s': %s", p->temp_config, strerror(errno)); + goto Error_Return; + } + _panel_debug (p, DBG_XMT|DBG_RCV, "Using Temporary Configuration File '%s' containing:", NULL, 0, p->temp_config); + i = 0; + while (fgets (buf, statb.st_size, fIn)) { + ++i; + buf[strlen(buf) - 1] = '\0'; + _panel_debug (p, DBG_XMT|DBG_RCV, "Line %2d: %s", NULL, 0, (int)i, buf); + } + free (buf); + buf = NULL; + fclose (fIn); } if (!simulator_panel) { #if defined(_WIN32) @@ -659,9 +704,10 @@ if (p->sock == INVALID_SOCKET) { } goto Error_Return; } -_panel_debug (p, DBG_XMT|DBG_RCV, "Connected to simulator at %s after %dms\n", NULL, 0, p->hostport, i*100); +_panel_debug (p, DBG_XMT|DBG_RCV, "Connected to simulator on %s after %dms\n", NULL, 0, p->hostport, (int)i*100); pthread_mutex_init (&p->io_lock, NULL); pthread_mutex_init (&p->io_send_lock, NULL); +pthread_mutex_init (&p->io_command_lock, NULL); pthread_cond_init (&p->io_done, NULL); pthread_cond_init (&p->startup_cond, NULL); if (sizeof(mantra) != _panel_send (p, (char *)mantra, sizeof(mantra))) { @@ -696,7 +742,7 @@ else { if (p->State == Error) goto Error_Return; /* Validate sim_frontpanel API version */ - if (_panel_sendf (p, 1, &p->simulator_version, "SHOW VERSION\r")) + if (_panel_sendf (p, &cmd_stat, &p->simulator_version, "SHOW VERSION\r")) goto Error_Return; if (1) { int api_version = 0; @@ -712,7 +758,7 @@ else { if (1) { char *radix = NULL; - if (_panel_sendf (p, 1, &radix, "SHOW %s RADIX\r", p->device_name ? p->device_name : "")) { + if (_panel_sendf (p, &cmd_stat, &radix, "SHOW %s RADIX\r", p->device_name ? p->device_name : "")) { free (radix); goto Error_Return; } @@ -807,18 +853,23 @@ if (panel) { int wait_count; /* First, wind down the automatic register queries */ - sim_panel_set_display_callback (panel, NULL, NULL, 0); - /* Next, attempt a simulator shutdown */ - _panel_send (panel, "\005\rEXIT\r", 7); + sim_panel_set_display_callback_interval (panel, NULL, NULL, 0); + /* Next, attempt a simulator shutdown only with the master panel */ + if (panel->parent == NULL) { + if (panel->State == Run) + _panel_send (panel, "\005\r", 2); + _panel_send (panel, "EXIT\r", 5); + } /* Wait for up to 2 seconds for a graceful shutdown */ for (wait_count=0; panel->io_thread_running && (wait_count<20); ++wait_count) msleep (100); - /* Now close the socket which should stop a pending read which hasn't completed */ + /* Now close the socket which should stop a pending read that hasn't completed */ panel->sock = INVALID_SOCKET; sim_close_sock (sock); pthread_join (panel->io_thread, NULL); pthread_mutex_destroy (&panel->io_lock); pthread_mutex_destroy (&panel->io_send_lock); + pthread_mutex_destroy (&panel->io_command_lock); pthread_cond_destroy (&panel->io_done); } #if defined(_WIN32) @@ -881,11 +932,16 @@ _panel_add_register (PANEL *panel, REG *regs, *reg; char *response = NULL; size_t i; +int cmd_stat; if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } +if (panel->State == Run) { + sim_panel_set_error ("Not Halted"); + return -1; + } regs = (REG *)_panel_malloc ((1 + panel->reg_count)*sizeof(*regs)); if (regs == NULL) { panel->State = Error; @@ -953,7 +1009,7 @@ reg->size = size; reg->element_count = element_count; pthread_mutex_unlock (&panel->io_lock); /* Validate existence of requested register/array */ -if (_panel_sendf (panel, 1, &response, "EXAMINE %s %s%s\r", device_name? device_name : "", name, (element_count > 0) ? "[0]" : "")) { +if (_panel_sendf (panel, &cmd_stat, &response, "EXAMINE %s %s%s\r", device_name? device_name : "", name, (element_count > 0) ? "[0]" : "")) { free (reg->name); free (reg->device_name); free (regs); @@ -969,7 +1025,7 @@ if (!strcmp ("Invalid argument\r\n", response)) { } free (response); if (element_count > 0) { - if (_panel_sendf (panel, 1, &response, "EXAMINE %s %s[%d]\r", device_name? device_name : "", name, element_count-1)) { + if (_panel_sendf (panel, &cmd_stat, &response, "EXAMINE %s %s[%d]\r", device_name? device_name : "", name, element_count-1)) { free (reg->name); free (reg->device_name); free (regs); @@ -989,6 +1045,7 @@ pthread_mutex_lock (&panel->io_lock); ++panel->reg_count; free (panel->regs); panel->regs = regs; +panel->new_register = 1; pthread_mutex_unlock (&panel->io_lock); /* Now build the register query string for the whole register list */ if (_panel_register_query_string (panel, &panel->reg_query, &panel->reg_query_size)) @@ -1028,14 +1085,14 @@ sim_panel_add_register_indirect (PANEL *panel, return _panel_add_register (panel, name, device_name, size, addr, 1, 0); } -int -sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time) +static int +_panel_get_registers (PANEL *panel, int calledback, unsigned long long *simulation_time) { if ((!panel) || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } -if (panel->callback) { +if ((!calledback) && (panel->callback)) { sim_panel_set_error ("Callback provides register data"); return -1; } @@ -1043,11 +1100,18 @@ if (!panel->reg_count) { sim_panel_set_error ("No registers specified"); return -1; } +pthread_mutex_lock (&panel->io_command_lock); pthread_mutex_lock (&panel->io_lock); if (panel->reg_query_size != _panel_send (panel, panel->reg_query, panel->reg_query_size)) { pthread_mutex_unlock (&panel->io_lock); + pthread_mutex_unlock (&panel->io_command_lock); return -1; } +while (panel->io_reg_query_pending != 0) { + pthread_mutex_unlock (&panel->io_lock); + msleep (100); + pthread_mutex_lock (&panel->io_lock); + } ++panel->io_reg_query_pending; panel->io_waiting = 1; while (panel->io_waiting) @@ -1055,14 +1119,21 @@ while (panel->io_waiting) if (simulation_time) *simulation_time = panel->simulation_time; pthread_mutex_unlock (&panel->io_lock); +pthread_mutex_unlock (&panel->io_command_lock); return 0; } int -sim_panel_set_display_callback (PANEL *panel, - PANEL_DISPLAY_PCALLBACK callback, - void *context, - int callbacks_per_second) +sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time) +{ +return _panel_get_registers (panel, 0, simulation_time); +} + +int +sim_panel_set_display_callback_interval (PANEL *panel, + PANEL_DISPLAY_PCALLBACK callback, + void *context, + int usecs_between_callbacks) { if (!panel) { sim_panel_set_error ("Invalid Panel"); @@ -1071,10 +1142,10 @@ if (!panel) { pthread_mutex_lock (&panel->io_lock); panel->callback = callback; panel->callback_context = context; -if (callbacks_per_second && (0 == panel->callbacks_per_second)) { /* Need to start callbacks */ +if (usecs_between_callbacks && (0 == panel->usecs_between_callbacks)) { /* Need to start/enable callbacks */ pthread_attr_t attr; - panel->callbacks_per_second = callbacks_per_second; + panel->usecs_between_callbacks = usecs_between_callbacks; pthread_cond_init (&panel->startup_cond, NULL); pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); @@ -1084,8 +1155,8 @@ if (callbacks_per_second && (0 == panel->callbacks_per_second)) { /* Need to sta pthread_cond_wait (&panel->startup_cond, &panel->io_lock); /* Wait for thread to stabilize */ pthread_cond_destroy (&panel->startup_cond); } -if ((callbacks_per_second == 0) && panel->callbacks_per_second) { /* Need to stop callbacks */ - panel->callbacks_per_second = 0; +if ((usecs_between_callbacks == 0) && panel->usecs_between_callbacks) { /* Need to stop callbacks */ + panel->usecs_between_callbacks = 0; pthread_mutex_unlock (&panel->io_lock); pthread_join (panel->callback_thread, NULL); pthread_mutex_lock (&panel->io_lock); @@ -1127,7 +1198,7 @@ if (panel->State == Run) { sim_panel_set_error ("Not Halted"); return -1; } -if (_panel_sendf (panel, 0, NULL, "BOOT %s\r", device)) +if (_panel_sendf (panel, NULL, NULL, "BOOT %s\r", device)) return -1; panel->State = Run; return 0; @@ -1148,7 +1219,7 @@ if (panel->State == Run) { sim_panel_set_error ("Not Halted"); return -1; } -if (_panel_sendf (panel, 0, NULL, "CONT\r", 5)) +if (_panel_sendf (panel, NULL, NULL, "CONT\r", 5)) return -1; panel->State = Run; return 0; @@ -1179,6 +1250,9 @@ return 0; int sim_panel_break_set (PANEL *panel, const char *condition) { +char *response = NULL; +int cmd_stat; + if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; @@ -1192,14 +1266,22 @@ if (panel->State == Run) { return -1; } -if (_panel_sendf (panel, 1, NULL, "BREAK %s\r", condition)) +if ((_panel_sendf (panel, &cmd_stat, &response, "BREAK %s\r", condition)) || + (*response)) { + sim_panel_set_error ("Error establishing breakpoint at '%s': %s", condition, response ? response : ""); + free (response); return -1; + } +free (response); return 0; } int sim_panel_break_clear (PANEL *panel, const char *condition) { +char *response = NULL; +int cmd_stat; + if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; @@ -1213,14 +1295,22 @@ if (panel->State == Run) { return -1; } -if (_panel_sendf (panel, 1, NULL, "NOBREAK %s\r", condition)) +if ((_panel_sendf (panel, &cmd_stat, &response, "NOBREAK %s\r", condition)) || + (*response)) { + sim_panel_set_error ("Error clearing breakpoint at '%s': %s", condition, response ? response : ""); + free (response); return -1; + } +free (response); return 0; } int sim_panel_break_output_set (PANEL *panel, const char *condition) { +char *response = NULL; +int cmd_stat; + if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; @@ -1234,14 +1324,22 @@ if (panel->State == Run) { return -1; } -if (_panel_sendf (panel, 1, NULL, "EXPECT %s\r", condition)) +if ((_panel_sendf (panel, &cmd_stat, &response, "EXPECT %s\r", condition)) || + (*response)) { + sim_panel_set_error ("Error establishing output breakpoint for '%s': %s", condition, response ? response : ""); + free (response); return -1; + } +free (response); return 0; } int sim_panel_break_output_clear (PANEL *panel, const char *condition) { +char *response = NULL; +int cmd_stat; + if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; @@ -1255,8 +1353,13 @@ if (panel->State == Run) { return -1; } -if (_panel_sendf (panel, 1, NULL, "NOEXPECT %s\r", condition)) +if ((_panel_sendf (panel, &cmd_stat, &response, "NOEXPECT %s\r", condition)) || + (*response)) { + sim_panel_set_error ("Error clearing output breakpoint for '%s': %s", condition, response ? response : ""); + free (response); return -1; + } +free (response); return 0; } @@ -1279,6 +1382,7 @@ sim_panel_gen_examine (PANEL *panel, { char *response = NULL, *c; unsigned long long data = 0; +int cmd_stat; if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); @@ -1288,7 +1392,7 @@ if (panel->State == Run) { sim_panel_set_error ("Not Halted"); return -1; } -if (_panel_sendf (panel, 1, &response, "EXAMINE -H %s", name_or_addr)) { +if (_panel_sendf (panel, &cmd_stat, &response, "EXAMINE -H %s", name_or_addr)) { free (response); return -1; } @@ -1325,6 +1429,7 @@ sim_panel_gen_deposit (PANEL *panel, const void *value) { unsigned long long data = 0; +int cmd_stat; if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); @@ -1338,7 +1443,7 @@ if (little_endian) memcpy (&data, value, size); else memcpy (((char *)&data) + sizeof(data)-size, value, size); -if (_panel_sendf (panel, 1, NULL, "DEPOSIT -H %s %llx", name_or_addr, data)) +if (_panel_sendf (panel, &cmd_stat, NULL, "DEPOSIT -H %s %llx", name_or_addr, data)) return -1; return 0; } @@ -1367,6 +1472,7 @@ sim_panel_mem_examine (PANEL *panel, { char *response = NULL, *c; unsigned long long data = 0, address = 0; +int cmd_stat; if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); @@ -1380,7 +1486,7 @@ if (little_endian) memcpy (&address, addr, addr_size); else memcpy (((char *)&address) + sizeof(address)-addr_size, addr, addr_size); -if (_panel_sendf (panel, 1, &response, (panel->radix == 16) ? "EXAMINE -H %llx" : "EXAMINE -H %llo", address)) { +if (_panel_sendf (panel, &cmd_stat, &response, (panel->radix == 16) ? "EXAMINE -H %llx" : "EXAMINE -H %llo", address)) { free (response); return -1; } @@ -1422,6 +1528,7 @@ sim_panel_mem_deposit (PANEL *panel, const void *value) { unsigned long long data = 0, address = 0; +int cmd_stat; if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); @@ -1439,7 +1546,7 @@ else { memcpy (((char *)&data) + sizeof(data)-value_size, value, value_size); memcpy (((char *)&address) + sizeof(address)-addr_size, addr, addr_size); } -if (_panel_sendf (panel, 1, NULL, (panel->radix == 16) ? "DEPOSIT -H %llx %llx" : "DEPOSIT -H %llo %llx", address, data)) +if (_panel_sendf (panel, &cmd_stat, NULL, (panel->radix == 16) ? "DEPOSIT -H %llx %llx" : "DEPOSIT -H %llo %llx", address, data)) return -1; return 0; } @@ -1460,6 +1567,8 @@ sim_panel_set_register_value (PANEL *panel, const char *name, const char *value) { +int cmd_stat; + if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; @@ -1468,7 +1577,7 @@ if (panel->State == Run) { sim_panel_set_error ("Not Halted"); return -1; } -if (_panel_sendf (panel, 1, NULL, "DEPOSIT %s %s", name, value)) +if (_panel_sendf (panel, &cmd_stat, NULL, "DEPOSIT %s %s", name, value)) return -1; return 0; } @@ -1487,30 +1596,42 @@ sim_panel_mount (PANEL *panel, const char *switches, const char *path) { -char *response = NULL, *status = NULL; +char *response = NULL; +OperationalState OrigState; +int stat = 0; +int cmd_stat; if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } -if (_panel_sendf (panel, 1, &response, "ATTACH %s %s %s", switches, device, path)) { - free (response); - return -1; - } -if (_panel_sendf (panel, 1, &status, "ECHO %%STATUS%%")) { - free (response); - free (status); - return -1; - } -if (!status || (strcmp (status, "00000000\r\n"))) { - sim_panel_set_error (response); - free (response); - free (status); - return -1; +pthread_mutex_lock (&panel->io_lock); +OrigState = panel->State; +if (OrigState == Run) { + sim_panel_exec_halt (panel); + while (panel->State == Run) { + pthread_mutex_unlock (&panel->io_lock); + msleep (100); + pthread_mutex_lock (&panel->io_lock); + } } +pthread_mutex_unlock (&panel->io_lock); +do { + if (_panel_sendf (panel, &cmd_stat, &response, "ATTACH %s %s %s", switches, device, path)) { + stat = -1; + break; + } + if (cmd_stat) { + sim_panel_set_error (response); + stat = -1; + } + } while (0); +pthread_mutex_lock (&panel->io_lock); +if (OrigState == Run) + sim_panel_exec_run (panel); +pthread_mutex_unlock (&panel->io_lock); free (response); -free (status); -return 0; +return stat; } /** @@ -1523,30 +1644,42 @@ int sim_panel_dismount (PANEL *panel, const char *device) { -char *response = NULL, *status = NULL; +char *response = NULL; +OperationalState OrigState; +int stat = 0; +int cmd_stat; if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } -if (_panel_sendf (panel, 1, &response, "DETACH %s", device)) { - free (response); - return -1; - } -if (_panel_sendf (panel, 1, &status, "ECHO %%STATUS%%")) { - free (response); - free (status); - return -1; - } -if (!status || (strcmp (status, "00000000\r\n"))) { - sim_panel_set_error (response); - free (response); - free (status); - return -1; +pthread_mutex_lock (&panel->io_lock); +OrigState = panel->State; +if (OrigState == Run) { + sim_panel_exec_halt (panel); + while (panel->State == Run) { + pthread_mutex_unlock (&panel->io_lock); + msleep (100); + pthread_mutex_lock (&panel->io_lock); + } } +pthread_mutex_unlock (&panel->io_lock); +do { + if (_panel_sendf (panel, &cmd_stat, &response, "DETACH %s", device)) { + stat = -1; + break; + } + if (cmd_stat) { + sim_panel_set_error (response); + stat = -1; + } + } while (0); +pthread_mutex_lock (&panel->io_lock); +if (OrigState == Run) + sim_panel_exec_run (panel); +pthread_mutex_unlock (&panel->io_lock); free (response); -free (status); -return 0; +return stat; } @@ -1683,8 +1816,7 @@ while ((p->sock != INVALID_SOCKET) && else { size_t name_len = strlen (p->regs[i].name); - if ((0 == memcmp (p->regs[i].name, s, name_len), s) && - (s[name_len] == '[')) { + if ((0 == memcmp (p->regs[i].name, s, name_len)) && (s[name_len] == '[')) { size_t array_index = (size_t)atoi (s + name_len + 1); size_t end_index = array_index; char *end = strchr (s + name_len + 1, '['); @@ -1714,22 +1846,23 @@ while ((p->sock != INVALID_SOCKET) && *e = ':'; /* Unexpected Register Data Found (or other output containing a : character) */ } - if (!strcmp (s + strlen (sim_prompt), register_get_echo)) { - pthread_mutex_lock (&p->io_lock); - --p->io_reg_query_pending; + if (!strcmp (s + strlen (sim_prompt), register_repeat_echo)) { if (p->callback) { pthread_mutex_unlock (&p->io_lock); p->callback (p, p->simulation_time, p->callback_context); } - else { - p->io_waiting = 0; - pthread_cond_signal (&p->io_done); - pthread_mutex_unlock (&p->io_lock); - } + } + if (!strcmp (s + strlen (sim_prompt), register_get_echo)) { + pthread_mutex_lock (&p->io_lock); + --p->io_reg_query_pending; + p->io_waiting = 0; + pthread_cond_signal (&p->io_done); + pthread_mutex_unlock (&p->io_lock); } else { pthread_mutex_lock (&p->io_lock); if (!strcmp (s + strlen (sim_prompt), command_done_echo)) { + _panel_debug (p, DBG_RCV, "Received Command Complete", NULL, 0); p->io_waiting = 0; pthread_cond_signal (&p->io_done); } @@ -1751,11 +1884,14 @@ while ((p->sock != INVALID_SOCKET) && p->io_response = t; p->io_response_size = p->io_response_data + strlen (s) + 3; } + _panel_debug (p, DBG_RCV, "Receive Data Accumulated: '%s'", NULL, 0, s); strcpy (p->io_response + p->io_response_data, s); p->io_response_data += strlen(s); strcpy (p->io_response + p->io_response_data, "\r\n"); p->io_response_data += 2; } + else + _panel_debug (p, DBG_RCV, "Receive Data Discarded: '%s'", NULL, 0, s); } pthread_mutex_unlock (&p->io_lock); } @@ -1794,6 +1930,7 @@ struct sched_param sched_priority; char *buf = NULL; size_t buf_data = 0; unsigned int callback_count = 0; +int cmd_stat; /* Boost Priority for timer thread so it doesn't compete @@ -1810,31 +1947,78 @@ pthread_cond_signal (&p->startup_cond); /* Signal we're ready to go */ msleep (100); pthread_mutex_lock (&p->io_lock); while ((p->sock != INVALID_SOCKET) && - (p->callbacks_per_second) && + (p->usecs_between_callbacks) && (p->State != Error)) { - int rate = p->callbacks_per_second; + int interval = p->usecs_between_callbacks; + int new_register = p->new_register; + p->new_register = 0; pthread_mutex_unlock (&p->io_lock); - ++callback_count; - if (1 == callback_count%rate) { /* once a second update the query string */ + if (new_register) /* need to get and send updated register info */ _panel_register_query_string (p, &buf, &buf_data); - } - msleep (1000/rate); + + /* twice a second activities: */ + /* 1) update the query string if it has changed */ + /* (only really happens at startup) */ + /* 2) update register state by polling if the simulator is halted */ + msleep (500); pthread_mutex_lock (&p->io_lock); - if (((p->State == Run) || ((p->State == Halt) && (0 == callback_count%(5*rate)))) && - (p->io_reg_query_pending == 0)) { - ++p->io_reg_query_pending; + if (new_register) { + if (p->io_reg_query_pending == 0) { + size_t repeat_data = strlen (register_repeat_prefix) + /* prefix */ + 20 + /* max int width */ + strlen (register_repeat_units) + /* units and spacing */ + buf_data + /* command contents */ + 1 + /* carriage return */ + strlen (register_repeat_echo) + /* auto repeat completion */ + 1 + /* carriage return */ + 1; /* NUL */ + char *repeat = (char *)malloc (repeat_data); + char *c; + + sprintf (repeat, "%s%d%s%*.*s", register_repeat_prefix, + p->usecs_between_callbacks, + register_repeat_units, + (int)buf_data, (int)buf_data, buf); + pthread_mutex_unlock (&p->io_lock); + for (c = strchr (repeat, '\r'); c != NULL; c = strchr (c, '\r')) + *c = ';'; /* replace carriage returns with semicolons */ + c = strstr (repeat, register_get_echo); /* remove register_done_echo string and */ + strcpy (c, register_repeat_echo); /* replace it with the register_repeat_echo string */ + if (_panel_sendf (p, &cmd_stat, NULL, "%s", repeat)) { + pthread_mutex_lock (&p->io_lock); + free (repeat); + break; + } + pthread_mutex_lock (&p->io_lock); + free (repeat); + } + else { /* already busy */ + p->new_register = 1; /* retry later */ + _panel_debug (p, DBG_XMT, "Waiting on prior command completion before specifying repeat interval", NULL, 0); + } + } + /* when halted, we directly poll the halted system to get updated */ + /* register state which may have changed due to panel activities */ + if (p->State == Halt) { pthread_mutex_unlock (&p->io_lock); - if (buf_data != _panel_send (p, buf, buf_data)) { + if (_panel_get_registers (p, 1, NULL)) { pthread_mutex_lock (&p->io_lock); break; } pthread_mutex_lock (&p->io_lock); } - else - _panel_debug (p, DBG_XMT, "Waiting for prior register query completion", NULL, 0); } +pthread_mutex_unlock (&p->io_lock); +/* stop any established repeating activity in the simulator */ +if (p->parent == NULL) /* Top level panel? */ + _panel_sendf (p, &cmd_stat, NULL, "%s", register_repeat_stop_all); +else { + if (p->State == Run) + _panel_sendf (p, &cmd_stat, NULL, "%s", register_repeat_stop); + } +pthread_mutex_lock (&p->io_lock); p->callback_thread_running = 0; pthread_mutex_unlock (&p->io_lock); free (buf); @@ -1905,13 +2089,13 @@ return; } static int -_panel_sendf (PANEL *p, int wait_for_completion, char **response, const char *fmt, ...) +_panel_sendf (PANEL *p, int *completion_status, char **response, const char *fmt, ...) { char stackbuf[1024]; int bufsize = sizeof(stackbuf); char *buf = stackbuf; -int len; -int post_fix_len = wait_for_completion ? 5 + strlen (command_done_echo): 1; +int len, status_echo_len = 0; +int post_fix_len = completion_status ? 7 + sizeof (command_done_echo) + sizeof (command_status) : 1; va_list arglist; int ret; @@ -1938,20 +2122,23 @@ while (1) { /* format passed string, arg } if (len && (buf[len-1] != '\r')) { - strcat (buf, "\r"); /* Make sure command line is terminated */ + strcpy (&buf[len], "\r"); /* Make sure command line is terminated */ ++len; } -if (wait_for_completion) { - strcat (buf, command_done_echo); - strcat (buf, "\r"); +pthread_mutex_lock (&p->io_command_lock); +++p->command_count; +if (completion_status) { + sprintf (&buf[len], "%s\r%s\r", command_status, command_done_echo); + status_echo_len = strlen (&buf[len]); pthread_mutex_lock (&p->io_lock); p->io_response_data = 0; } -ret = (strlen (buf) == _panel_send (p, buf, strlen (buf))) ? 0 : -1; +_panel_debug (p, DBG_REQ, "Command %d Request%s: %*.*s", NULL, 0, p->command_count, completion_status ? " (with response)" : "", len, len, buf); +ret = ((len + status_echo_len) == _panel_send (p, buf, len + status_echo_len)) ? 0 : -1; -if (wait_for_completion) { +if (completion_status) { if (!ret) { /* Sent OK? */ p->io_waiting = 1; while (p->io_waiting) @@ -1959,16 +2146,33 @@ if (wait_for_completion) { if (response) { *response = (char *)_panel_malloc (p->io_response_data + 1); if (0 == memcmp (buf, p->io_response + strlen (sim_prompt), len)) { + char *eol, *status; memcpy (*response, p->io_response + strlen (sim_prompt) + len + 1, p->io_response_data + 1 - (strlen (sim_prompt) + len + 1)); + *completion_status = -1; + status = strstr (*response, command_status); + if (status) { + *(status - strlen (sim_prompt)) = '\0'; + status += strlen (command_status) + 2; + eol = strchr (status, '\r'); + if (eol) + *eol = '\0'; + sscanf (status, "Status:%08X-", completion_status); + } } else memcpy (*response, p->io_response, p->io_response_data + 1); + _panel_debug (p, DBG_RSP, "Command %d Response(Status=%d): '%s'", NULL, 0, p->command_count, *completion_status, *response); + } + else { + if (p->io_response_data) + _panel_debug (p, DBG_RSP, "Discarded Unwanted Command %d Response Data:", p->io_response, p->io_response_data, p->command_count); } - p->io_response_data = 0; - p->io_response[0] = '\0'; } + p->io_response_data = 0; + p->io_response[0] = '\0'; pthread_mutex_unlock (&p->io_lock); } +pthread_mutex_unlock (&p->io_command_lock); if (buf != stackbuf) free (buf); diff --git a/sim_frontpanel.h b/sim_frontpanel.h index c01cc5b4..86aa4d6d 100644 --- a/sim_frontpanel.h +++ b/sim_frontpanel.h @@ -57,7 +57,7 @@ extern "C" { #if !defined(__VAX) /* Unsupported platform */ -#define SIM_FRONTPANEL_VERSION 2 +#define SIM_FRONTPANEL_VERSION 3 /** @@ -128,7 +128,7 @@ sim_panel_destroy (PANEL *panel); simulator. The registers that a particular frontpanel application mught need - access to are described by the application by calling: + access to are described by the application when it calls: sim_panel_add_register sim_panel_add_register_array @@ -175,10 +175,10 @@ sim_panel_add_register_indirect (PANEL *panel, 1) The values can be polled (when ever it is desired) by calling sim_panel_get_registers(). - 2) The panel can call sim_panel_set_display_callback() to specify a - callback routine and a periodic rate that the callback routine - should be called. The panel API will make a best effort to deliver - the current register state at the desired rate. + 2) The panel can call sim_panel_set_display_callback_interval() to + specify a callback routine and a periodic rate that the callback + routine should be called. The panel API will make a best effort + to deliver the current register state at the desired rate. Note 1: The buffers described in a panel's register set will be @@ -203,10 +203,10 @@ typedef void (*PANEL_DISPLAY_PCALLBACK)(PANEL *panel, void *context); int -sim_panel_set_display_callback (PANEL *panel, - PANEL_DISPLAY_PCALLBACK callback, - void *context, - int callbacks_per_second); +sim_panel_set_display_callback_interval (PANEL *panel, + PANEL_DISPLAY_PCALLBACK callback, + void *context, + int usecs_between_callbacks); /** @@ -450,6 +450,8 @@ sim_panel_set_debug_file (PANEL *panel, const char *debug_file); #define DBG_XMT 1 /* Transmit Data */ #define DBG_RCV 2 /* Receive Data */ +#define DBG_REQ 4 /* Request Data */ +#define DBG_RSP 8 /* Response Data */ void sim_panel_set_debug_mode (PANEL *panel, int debug_bits);