FRONTPANEL: sim_frontpanel API release 12

- Cleanup session reading logic to properly handle all cases of TCP send
   coalesced data.
- Use Remote Console EXECUTE Command to consolidate register query activity
   when halted.
- Use -16 switch for EXAMINE and DEPOSIT commands to be sure to present data
   in a reliable simulator independent way.
- Add sim_panel_halt_text and sim_panel_device_debug_mode APIs
- Better cleanup of simulator process during panel shutdown on Win32
This commit is contained in:
Mark Pizzolato 2018-01-12 10:07:15 -08:00
parent 3eda8f909c
commit 2efc3a17ec
2 changed files with 212 additions and 117 deletions

View file

@ -153,9 +153,9 @@ struct PANEL {
pthread_mutex_t io_send_lock; pthread_mutex_t io_send_lock;
pthread_mutex_t io_command_lock; pthread_mutex_t io_command_lock;
int command_count; int command_count;
int io_reg_query_pending;
int io_waiting; int io_waiting;
char *io_response; char *io_response;
char *halt_reason;
size_t io_response_data; size_t io_response_data;
size_t io_response_size; size_t io_response_size;
const char *completion_string; const char *completion_string;
@ -177,6 +177,7 @@ struct PANEL {
FILE *Debug; FILE *Debug;
#if defined(_WIN32) #if defined(_WIN32)
HANDLE hProcess; HANDLE hProcess;
DWORD dwProcessId;
#else #else
pid_t pidProcess; pid_t pidProcess;
#endif #endif
@ -221,7 +222,7 @@ static const char *register_collect_mid3 = " percent ";
static const char *register_get_postfix = "sampleout"; static const char *register_get_postfix = "sampleout";
static const char *register_get_start = "# REGISTERS-START"; static const char *register_get_start = "# REGISTERS-START";
static const char *register_get_end = "# REGISTERS-DONE"; static const char *register_get_end = "# REGISTERS-DONE";
static const char *register_repeat_start = "# REGISTERS-REPEAT-START\r"; static const char *register_repeat_start = "# REGISTERS-REPEAT-START";
static const char *register_repeat_end = "# REGISTERS-REPEAT-DONE"; static const char *register_repeat_end = "# REGISTERS-REPEAT-DONE";
static const char *register_dev_echo = "# REGISTERS-FOR-DEVICE:"; static const char *register_dev_echo = "# REGISTERS-FOR-DEVICE:";
static const char *register_ind_echo = "# REGISTER-INDIRECT:"; static const char *register_ind_echo = "# REGISTER-INDIRECT:";
@ -408,9 +409,9 @@ pthread_mutex_lock (&p->io_lock);
while (p->sock != INVALID_SOCKET) { while (p->sock != INVALID_SOCKET) {
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
msleep (1000); msleep (1000);
pthread_mutex_lock (&p->io_lock);
if (0 == (sleeps++)%flush_interval) if (0 == (sleeps++)%flush_interval)
sim_panel_flush_debug (p); sim_panel_flush_debug (p);
pthread_mutex_lock (&p->io_lock);
} }
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
@ -484,7 +485,7 @@ size_t i, j, buf_data, buf_needed = 0, reg_count = 0, bit_reg_count = 0;
const char *dev; const char *dev;
pthread_mutex_lock (&panel->io_lock); pthread_mutex_lock (&panel->io_lock);
buf_needed = 3 + buf_needed = 3 + 7 + /* EXECUTE */
strlen (register_get_start) + /* # REGISTERS-START */ strlen (register_get_start) + /* # REGISTERS-START */
strlen (register_get_prefix); /* SHOW TIME */ strlen (register_get_prefix); /* SHOW TIME */
for (i=0; i<panel->reg_count; i++) { for (i=0; i<panel->reg_count; i++) {
@ -492,7 +493,7 @@ for (i=0; i<panel->reg_count; i++) {
++bit_reg_count; ++bit_reg_count;
else { else {
++reg_count; ++reg_count;
buf_needed += 9 + strlen (panel->regs[i].name) + (panel->regs[i].device_name ? strlen (panel->regs[i].device_name) : 0); buf_needed += 10 + strlen (panel->regs[i].name) + (panel->regs[i].device_name ? strlen (panel->regs[i].device_name) : 0);
if (panel->regs[i].element_count > 0) if (panel->regs[i].element_count > 0)
buf_needed += 4 + 6 /* 6 digit register array index */; buf_needed += 4 + 6 /* 6 digit register array index */;
if (panel->regs[i].indirect) if (panel->regs[i].indirect)
@ -514,7 +515,7 @@ if (buf_needed > *buf_size) {
} }
buf_data = 0; buf_data = 0;
if (reg_count) { if (reg_count) {
sprintf (*buf + buf_data, "%s\r%s\r", register_get_start, register_get_prefix); sprintf (*buf + buf_data, "EXECUTE %s;%s;", register_get_start, register_get_prefix);
buf_data += strlen (*buf + buf_data); buf_data += strlen (*buf + buf_data);
} }
dev = ""; dev = "";
@ -536,7 +537,7 @@ for (i=j=0; i<panel->reg_count; i++) {
strcpy (tbuf, *buf); strcpy (tbuf, *buf);
free (*buf); free (*buf);
*buf = tbuf; *buf = tbuf;
sprintf (*buf + buf_data, "%s%s%s\r", (i == 0)? "" : "\r", register_dev_echo, reg_dev); sprintf (*buf + buf_data, "%s%s%s;", (i == 0)? "" : ";", register_dev_echo, reg_dev);
buf_data += strlen (*buf + buf_data); buf_data += strlen (*buf + buf_data);
dev = reg_dev; dev = reg_dev;
j = 0; j = 0;
@ -544,21 +545,21 @@ for (i=j=0; i<panel->reg_count; i++) {
} }
if (panel->regs[i].element_count == 0) { if (panel->regs[i].element_count == 0) {
if (j == 0) if (j == 0)
sprintf (*buf + buf_data, "E -H %s %s", dev, panel->regs[i].name); sprintf (*buf + buf_data, "E -16 %s %s", dev, panel->regs[i].name);
else else
sprintf (*buf + buf_data, ",%s", panel->regs[i].name); sprintf (*buf + buf_data, ",%s", panel->regs[i].name);
} }
else { else {
if (j == 0) if (j == 0)
sprintf (*buf + buf_data, "E -H %s %s[0:%d]", dev, panel->regs[i].name, (int)(panel->regs[i].element_count-1)); sprintf (*buf + buf_data, "E -16 %s %s[0:%d]", dev, panel->regs[i].name, (int)(panel->regs[i].element_count-1));
else else
sprintf (*buf + buf_data, ",%s[0:%d]", panel->regs[i].name, (int)(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; ++j;
buf_data += strlen (*buf + buf_data); buf_data += strlen (*buf + buf_data);
} }
if (buf_data && ((*buf)[buf_data-1] != '\r')) { if (buf_data && ((*buf)[buf_data-1] != ';')) {
strcpy (*buf + buf_data, "\r"); strcpy (*buf + buf_data, ";");
buf_data += strlen (*buf + buf_data); buf_data += strlen (*buf + buf_data);
} }
for (i=j=0; i<panel->reg_count; i++) { for (i=j=0; i<panel->reg_count; i++) {
@ -566,13 +567,13 @@ for (i=j=0; i<panel->reg_count; i++) {
if ((!panel->regs[i].indirect) || (panel->regs[i].bits)) if ((!panel->regs[i].indirect) || (panel->regs[i].bits))
continue; continue;
sprintf (*buf + buf_data, "%s%s\rE -H %s %s,$\r", register_ind_echo, panel->regs[i].name, reg_dev, panel->regs[i].name); sprintf (*buf + buf_data, "%s%s;E -16 %s %s,$;", register_ind_echo, panel->regs[i].name, reg_dev, panel->regs[i].name);
buf_data += strlen (*buf + buf_data); buf_data += strlen (*buf + buf_data);
} }
if (bit_reg_count) { if (bit_reg_count) {
strcpy (*buf + buf_data, register_get_postfix); strcpy (*buf + buf_data, register_get_postfix);
buf_data += strlen (*buf + buf_data); buf_data += strlen (*buf + buf_data);
strcpy (*buf + buf_data, "\r"); strcpy (*buf + buf_data, ";");
buf_data += strlen (*buf + buf_data); buf_data += strlen (*buf + buf_data);
} }
strcpy (*buf + buf_data, register_get_end); strcpy (*buf + buf_data, register_get_end);
@ -855,6 +856,7 @@ if (!simulator_panel) {
if (CreateProcessA(NULL, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &StartupInfo, &ProcessInfo)) { if (CreateProcessA(NULL, cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &StartupInfo, &ProcessInfo)) {
CloseHandle (ProcessInfo.hThread); CloseHandle (ProcessInfo.hThread);
p->hProcess = ProcessInfo.hProcess; p->hProcess = ProcessInfo.hProcess;
p->dwProcessId = ProcessInfo.dwProcessId;
} }
else { /* Creation Problem */ else { /* Creation Problem */
sim_panel_set_error (NULL, "CreateProcess Error: %d", GetLastError()); sim_panel_set_error (NULL, "CreateProcess Error: %d", GetLastError());
@ -1074,6 +1076,8 @@ if (panel) {
pthread_cond_destroy (&panel->io_done); pthread_cond_destroy (&panel->io_done);
#if defined(_WIN32) #if defined(_WIN32)
if (panel->hProcess) { if (panel->hProcess) {
GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, panel->dwProcessId);
msleep (200);
TerminateProcess (panel->hProcess, 0); TerminateProcess (panel->hProcess, 0);
WaitForSingleObject (panel->hProcess, INFINITE); WaitForSingleObject (panel->hProcess, INFINITE);
CloseHandle (panel->hProcess); CloseHandle (panel->hProcess);
@ -1106,6 +1110,7 @@ if (panel) {
free (panel->regs); free (panel->regs);
free (panel->reg_query); free (panel->reg_query);
free (panel->io_response); free (panel->io_response);
free (panel->halt_reason);
free (panel->simulator_version); free (panel->simulator_version);
if ((panel->Debug) && (!panel->parent)) if ((panel->Debug) && (!panel->parent))
fclose (panel->Debug); fclose (panel->Debug);
@ -1353,12 +1358,9 @@ if (panel->reg_query_size != _panel_send (panel, panel->reg_query, panel->reg_qu
pthread_mutex_unlock (&panel->io_command_lock); pthread_mutex_unlock (&panel->io_command_lock);
return -1; return -1;
} }
while (panel->io_reg_query_pending != 0) { if (panel->io_response_data)
pthread_mutex_unlock (&panel->io_lock); _panel_debug (panel, DBG_RCV, "Receive Data Discarded: ", panel->io_response, panel->io_response_data);
msleep (100); panel->io_response_data = 0;
pthread_mutex_lock (&panel->io_lock);
}
++panel->io_reg_query_pending;
panel->io_waiting = 1; panel->io_waiting = 1;
while (panel->io_waiting) while (panel->io_waiting)
pthread_cond_wait (&panel->io_done, &panel->io_lock); pthread_cond_wait (&panel->io_done, &panel->io_lock);
@ -1372,7 +1374,7 @@ return 0;
int int
sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time) sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time)
{ {
return _panel_get_registers (panel, 0, simulation_time); return _panel_get_registers (panel, (panel->State == Halt), simulation_time);
} }
int int
@ -1472,6 +1474,15 @@ if (panel->State == Run) {
return 0; return 0;
} }
const char *
sim_panel_halt_text (PANEL *panel)
{
if (!panel || !panel->halt_reason)
return "";
return panel->halt_reason;
}
int int
sim_panel_exec_boot (PANEL *panel, const char *device) sim_panel_exec_boot (PANEL *panel, const char *device)
{ {
@ -1538,7 +1549,7 @@ if ((simtime = strstr (response, "Time:"))) {
} }
free (response); free (response);
panel->simulation_time_base += panel->simulation_time; panel->simulation_time_base += panel->simulation_time;
if (_panel_sendf_completion (panel, NULL, "Simulator Running...", "RUN -Q\r", 5)) { if (_panel_sendf_completion (panel, NULL, "Simulator Running...", "RUN\r", 5)) {
_panel_debug (panel, DBG_THR, "Unable to start simulator: %s", NULL, 0, sim_panel_get_error()); _panel_debug (panel, DBG_THR, "Unable to start simulator: %s", NULL, 0, sim_panel_get_error());
return -1; return -1;
} }
@ -1768,6 +1779,40 @@ free (response);
return 0; return 0;
} }
int
sim_panel_device_debug_mode (PANEL *panel,
const char *device,
int set_unset,
const char *mode_bits)
{
char *response = NULL;
int cmd_stat;
if (!panel || (panel->State == Error)) {
sim_panel_set_error (NULL, "Invalid Panel");
return -1;
}
if (_panel_sendf (panel, &cmd_stat, &response, "SHOW %s", device) ||
(cmd_stat)) {
sim_panel_set_error (NULL, "Can't %s Debug Mode: '%s' on Device '%s': %s",
set_unset ? "Enable" : "Disable", mode_bits ? mode_bits : "", device, response);
free (response);
return -1;
}
free (response);
response = NULL;
if (_panel_sendf (panel, &cmd_stat, &response, "%sDEBUG %s %s",
set_unset ? "" : "NO", device, mode_bits ? mode_bits : "") ||
(cmd_stat)) {
sim_panel_set_error (NULL, "Can't %s Debug Mode: '%s' on Device '%s': %s",
set_unset ? "Enable" : "Disable", mode_bits ? mode_bits : "", device, response);
free (response);
return -1;
}
free (response);
return 0;
}
/** /**
sim_panel_gen_deposit sim_panel_gen_deposit
@ -2069,7 +2114,7 @@ struct sched_param sched_priority;
char buf[4096]; char buf[4096];
int buf_data = 0; int buf_data = 0;
int processing_register_output = 0; int processing_register_output = 0;
int io_wait_done; int io_wait_done = 0;
/* /*
Boost Priority for this response processing thread to quickly digest Boost Priority for this response processing thread to quickly digest
@ -2119,6 +2164,7 @@ while ((p->sock != INVALID_SOCKET) &&
int new_data; int new_data;
char *s, *e, *eol; char *s, *e, *eol;
if (NULL == strchr (buf, '\n')) {
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
new_data = sim_read_sock (p->sock, &buf[buf_data], sizeof(buf)-(buf_data+1)); new_data = sim_read_sock (p->sock, &buf[buf_data], sizeof(buf)-(buf_data+1));
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
@ -2131,6 +2177,7 @@ while ((p->sock != INVALID_SOCKET) &&
_panel_debug (p, DBG_RCV, "Received %d bytes: ", &buf[buf_data], new_data, new_data); _panel_debug (p, DBG_RCV, "Received %d bytes: ", &buf[buf_data], new_data, new_data);
buf_data += new_data; buf_data += new_data;
buf[buf_data] = '\0'; buf[buf_data] = '\0';
}
s = buf; s = buf;
while ((eol = strchr (s, '\n'))) { while ((eol = strchr (s, '\n'))) {
/* Line to process */ /* Line to process */
@ -2258,42 +2305,43 @@ while ((p->sock != INVALID_SOCKET) &&
/* Unexpected Register Data Found (or other output containing a : character) */ /* Unexpected Register Data Found (or other output containing a : character) */
} }
} }
if (!strcmp (s + strlen (sim_prompt), register_repeat_end)) { if ((strlen (s) > strlen (sim_prompt)) && (!strcmp (s + strlen (sim_prompt), register_repeat_end))) {
_panel_debug (p, DBG_RCV, "*Repeat Block Complete", NULL, 0); _panel_debug (p, DBG_RCV, "*Repeat Block Complete (Accumulated Data = %d)", NULL, 0, (int)p->io_response_data);
if (p->callback) { if (p->callback) {
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
p->callback (p, p->simulation_time_base + p->simulation_time, p->callback_context); p->callback (p, p->simulation_time_base + p->simulation_time, p->callback_context);
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
} }
processing_register_output = 0; processing_register_output = 0;
p->io_response_data = 0;
p->io_response[p->io_response_data] = '\0';
goto Start_Next_Line; goto Start_Next_Line;
} }
if ((!strcmp (s + strlen (sim_prompt), register_repeat_start)) || if ((strlen (s) > strlen (sim_prompt)) &&
(!strcmp (s + strlen (sim_prompt), register_get_start))) { ((!strcmp (s + strlen (sim_prompt), register_repeat_start)) ||
(!strcmp (s + strlen (sim_prompt), register_get_start)))) {
_panel_debug (p, DBG_RCV, "*Repeat/Register Block Starting", NULL, 0); _panel_debug (p, DBG_RCV, "*Repeat/Register Block Starting", NULL, 0);
processing_register_output = 1; processing_register_output = 1;
goto Start_Next_Line; goto Start_Next_Line;
} }
if (!strcmp (s + strlen (sim_prompt), register_get_end)) { if ((strlen (s) > strlen (sim_prompt)) &&
(!strcmp (s + strlen (sim_prompt), register_get_end))) {
_panel_debug (p, DBG_RCV, "*Register Block Complete", NULL, 0); _panel_debug (p, DBG_RCV, "*Register Block Complete", NULL, 0);
--p->io_reg_query_pending;
p->io_waiting = 0; p->io_waiting = 0;
processing_register_output = 0; processing_register_output = 0;
pthread_cond_signal (&p->io_done); pthread_cond_signal (&p->io_done);
goto Start_Next_Line; goto Start_Next_Line;
} }
if (!strcmp (s + strlen (sim_prompt), command_done_echo)) { if ((strlen (s) > strlen (sim_prompt)) && (!strcmp (s + strlen (sim_prompt), command_done_echo))) {
_panel_debug (p, DBG_RCV, "*Received Command Complete", NULL, 0); _panel_debug (p, DBG_RCV, "*Received Command Complete", NULL, 0);
p->io_waiting = 0; p->io_waiting = 0;
pthread_cond_signal (&p->io_done); pthread_cond_signal (&p->io_done);
goto Start_Next_Line; goto Start_Next_Line;
} }
/* Non Register Data Found (echo of EXAMINE or other commands and/or command output) */ /* Non Register Data Found (echo of EXAMINE or other commands and/or command output) */
if (p->io_waiting) {
char *t;
if (p->io_response_data + strlen (s) + 3 > p->io_response_size) { if (p->io_response_data + strlen (s) + 3 > p->io_response_size) {
t = (char *)_panel_malloc (p->io_response_data + strlen (s) + 3); char *t = (char *)_panel_malloc (p->io_response_data + strlen (s) + 3);
if (t == NULL) { if (t == NULL) {
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error()); _panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
p->State = Error; p->State = Error;
@ -2313,17 +2361,16 @@ while ((p->sock != INVALID_SOCKET) &&
(p->completion_string) && (p->completion_string) &&
(!memcmp (s, p->completion_string, strlen (p->completion_string)))) { (!memcmp (s, p->completion_string, strlen (p->completion_string)))) {
_panel_debug (p, DBG_RCV, "Match with potentially coalesced additional data: '%s'", NULL, 0, p->completion_string); _panel_debug (p, DBG_RCV, "Match with potentially coalesced additional data: '%s'", NULL, 0, p->completion_string);
if (eol < &buf[buf_data])
memset (s + strlen (s), ' ', eol - (s + strlen (s)));
break; break;
} }
}
else
_panel_debug (p, DBG_RCV, "Receive Data Discarded: '%s'", NULL, 0, s);
Start_Next_Line: Start_Next_Line:
s = eol; s = eol;
while (isspace(0xFF & (*s))) while (isspace(0xFF & (*s)))
++s; ++s;
} }
memmove (buf, s, strlen (s) + 1); memmove (buf, s, buf_data - (s - buf) + 1);
buf_data = strlen (buf); buf_data = strlen (buf);
if (buf_data) if (buf_data)
_panel_debug (p, DBG_RSP, "Remnant Buffer Contents: '%s'", NULL, 0, buf); _panel_debug (p, DBG_RSP, "Remnant Buffer Contents: '%s'", NULL, 0, buf);
@ -2337,11 +2384,12 @@ Start_Next_Line:
_panel_debug (p, DBG_RSP, "State transitioning to Run", NULL, 0); _panel_debug (p, DBG_RSP, "State transitioning to Run", NULL, 0);
p->State = Run; p->State = Run;
buf_data -= 20; buf_data -= 20;
buf[buf_data] = '\0';
if (buf_data) { if (buf_data) {
memmove (buf, buf + 20, strlen (buf + 20) + 1); memmove (buf, buf + 20, buf_data + 1);
buf_data = strlen (buf);
_panel_debug (p, DBG_RSP, "Remnant Buffer Contents: '%s'", NULL, 0, buf); _panel_debug (p, DBG_RSP, "Remnant Buffer Contents: '%s'", NULL, 0, buf);
}
else
buf[buf_data] = '\0';
if (io_wait_done) { /* someone waiting for this? */ if (io_wait_done) { /* someone waiting for this? */
_panel_debug (p, DBG_RCV, "*Match Command Complete - Match signaling waiting thread", NULL, 0); _panel_debug (p, DBG_RCV, "*Match Command Complete - Match signaling waiting thread", NULL, 0);
io_wait_done = 0; io_wait_done = 0;
@ -2355,10 +2403,17 @@ Start_Next_Line:
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
} }
} }
}
if ((p->State == Run) && (!strcmp (buf, sim_prompt))) { if ((p->State == Run) && (!strcmp (buf, sim_prompt))) {
_panel_debug (p, DBG_RSP, "State transitioning to Halt", NULL, 0); _panel_debug (p, DBG_RSP, "State transitioning to Halt: io_wait_done: %d", NULL, 0, io_wait_done);
p->State = Halt; p->State = Halt;
free (p->halt_reason);
p->halt_reason = (char *)_panel_malloc (1 + strlen (p->io_response));
if (p->halt_reason == NULL) {
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
p->State = Error;
break;
}
strcpy (p->halt_reason, p->io_response);
} }
if (io_wait_done) { if (io_wait_done) {
_panel_debug (p, DBG_RCV, "*Match Command Complete - Match signaling waiting thread", NULL, 0); _panel_debug (p, DBG_RCV, "*Match Command Complete - Match signaling waiting thread", NULL, 0);
@ -2426,28 +2481,30 @@ while ((p->sock != INVALID_SOCKET) &&
msleep (500); msleep (500);
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
if (new_register) { if (new_register) {
if (p->io_reg_query_pending == 0) {
size_t repeat_data = strlen (register_repeat_prefix) + /* prefix */ size_t repeat_data = strlen (register_repeat_prefix) + /* prefix */
20 + /* max int width */ 20 + /* max int width */
strlen (register_repeat_units) + /* units and spacing */ strlen (register_repeat_units) + /* units and spacing */
buf_data + /* command contents */ buf_data + /* command contents */
1 + /* carriage return */ 1 + /* ; */
strlen (register_repeat_start) + /* auto repeat begin */ strlen (register_repeat_start) + /* auto repeat begin */
1 + /* carriage return */ 1 + /* ; */
strlen (register_repeat_end) + /* auto repeat completion */ strlen (register_repeat_end) + /* auto repeat completion */
1 + /* carriage return */ 1 + /* carriage return */
1; /* NUL */ 1; /* NUL */
char *repeat = (char *)malloc (repeat_data); char *repeat = (char *)malloc (repeat_data);
char *c; char *c;
c = strstr (buf, register_get_start); /* remove register_get_start string and anything before it */
if (c) { /* always true */
buf_data -= (c - buf) + strlen (register_get_start);
c += strlen (register_get_start);
}
sprintf (repeat, "%s%d%s%s%*.*s", register_repeat_prefix, sprintf (repeat, "%s%d%s%s%*.*s", register_repeat_prefix,
p->usecs_between_callbacks, p->usecs_between_callbacks,
register_repeat_units, register_repeat_units,
register_repeat_start, register_repeat_start,
(int)buf_data, (int)buf_data, buf); (int)buf_data, (int)buf_data, c);
pthread_mutex_unlock (&p->io_lock); 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_end); /* remove register_done_echo string and */ c = strstr (repeat, register_get_end); /* remove register_done_echo string and */
if (c) /* always true */ if (c) /* always true */
strcpy (c, register_repeat_end); /* replace it with the register_repeat_end string */ strcpy (c, register_repeat_end); /* replace it with the register_repeat_end string */
@ -2459,11 +2516,6 @@ while ((p->sock != INVALID_SOCKET) &&
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
free (repeat); 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 */ /* when halted, we directly poll the halted system to get updated */
/* register state which may have changed due to panel activities */ /* register state which may have changed due to panel activities */
if (p->State == Halt) { if (p->State == Halt) {
@ -2545,7 +2597,7 @@ while (1) { /* format passed string, arg
if (len >= (int)(sim_panel_error_bufsize-1)) { if (len >= (int)(sim_panel_error_bufsize-1)) {
free (sim_panel_error_buf); free (sim_panel_error_buf);
sim_panel_error_bufsize = sim_panel_error_bufsize * 2; sim_panel_error_bufsize = sim_panel_error_bufsize * 2;
while ((int)sim_panel_error_bufsize < len + 1) while ((int)sim_panel_error_bufsize < len + 2)
sim_panel_error_bufsize = sim_panel_error_bufsize * 2; sim_panel_error_bufsize = sim_panel_error_bufsize * 2;
sim_panel_error_buf = (char *) malloc (sim_panel_error_bufsize); sim_panel_error_buf = (char *) malloc (sim_panel_error_bufsize);
if (sim_panel_error_buf == NULL) { if (sim_panel_error_buf == NULL) {
@ -2610,6 +2662,8 @@ if (completion_status || completion_string) {
} }
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);
p->completion_string = completion_string; p->completion_string = completion_string;
if (p->io_response_data)
_panel_debug (p, DBG_RCV, "Receive Data Discarded: ", p->io_response, p->io_response_data);
p->io_response_data = 0; p->io_response_data = 0;
p->io_waiting = 1; p->io_waiting = 1;
} }

View file

@ -56,7 +56,7 @@ extern "C" {
#if !defined(__VAX) /* Unsupported platform */ #if !defined(__VAX) /* Unsupported platform */
#define SIM_FRONTPANEL_VERSION 11 #define SIM_FRONTPANEL_VERSION 12
/** /**
@ -284,6 +284,19 @@ sim_panel_exec_run (PANEL *panel);
int int
sim_panel_exec_step (PANEL *panel); sim_panel_exec_step (PANEL *panel);
/**
A simulator often displays some useful information as it stops
executing instructions.
sim_panel_halt_text - Returns the simulator output immediately prior
to the most recent transition to the Halt state.
*/
const char *
sim_panel_halt_text (PANEL *panel);
/** /**
When a front panel application wants to describe conditions that When a front panel application wants to describe conditions that
@ -472,6 +485,34 @@ sim_panel_get_history (PANEL *panel,
char *buffer); char *buffer);
/**
A front panel application might want some details of simulator
and/or device behavior that is provided by a particular simulator
via debug information. Debugging for particular device(s)
and/or simulator debug settings can be controlled via the
sim_panel_device_debug_mode API.
*/
/**
sim_panel_device_debug_mode
device the device whose debug mode is to change
set_untset 1 to set debug flags, 0 to clear debug flags
mode_bits character string with different debug mode bits
to enable or disable. An empty string will
enable or disable all mode bits for the specified
device
*/
int
sim_panel_device_debug_mode (PANEL *panel,
const char *device,
int set_unset,
const char *mode_bits);
/** /**
When a front panel application needs to change the media When a front panel application needs to change the media