FRONTPANEL: sim_frontpanel API version 3 release

Adds:
1) Simulator side execution of register update activities at an interval
    specified in usecs.  Rates in excess of 1000Hz should be achievable
    for locally connected frontpanel applications.
2) New API for simulators to describe the register state available in
    the simulator.  If all of a the state which is potentially interesting
    to front panel applications is always present in the variables
    described by simh REG structures, then frontpanel API access to
    that data can be more efficiently provided.
This commit is contained in:
Mark Pizzolato 2017-01-27 23:06:30 -08:00
parent 7ac92a0e84
commit 110ded6904
6 changed files with 726 additions and 221 deletions

View file

@ -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/;&quot;../../windows-build/winpcap/Wpdpack/Include&quot;;&quot;../../windows-build/PCRE/include/&quot;;&quot;../../windows-build/pthreads&quot;"
PreprocessorDefinitions="_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;PTW32_STATIC_LIB"
StringPooling="true"

View file

@ -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 ();

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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);