FRONTPANEL: Added support to debug traffic to/from the simulator

This commit is contained in:
Mark Pizzolato 2015-02-15 11:04:18 -08:00
parent 2c2ffe39bf
commit 335def0d32
2 changed files with 175 additions and 26 deletions

View file

@ -47,19 +47,33 @@ extern "C" {
#include <signal.h> #include <signal.h>
#include <pthread.h> #include <pthread.h>
#include "sim_sock.h"
#if defined(_WIN32) #if defined(_WIN32)
#include <process.h> #include <process.h>
#include <windows.h>
#define sleep(n) Sleep(n*1000) #define sleep(n) Sleep(n*1000)
#define msleep(n) Sleep(n) #define msleep(n) Sleep(n)
#define strtoull _strtoui64 #define strtoull _strtoui64
#define CLOCK_REALTIME 0
int clock_gettime(int clk_id, struct timespec *tp)
{
unsigned long long now, unixbase;
unixbase = 116444736;
unixbase *= 1000000000;
GetSystemTimeAsFileTime((FILETIME*)&now);
now -= unixbase;
tp->tv_sec = (long)(now/10000000);
tp->tv_nsec = (now%10000000)*100;
return 0;
}
#else #else
#include <unistd.h> #include <unistd.h>
#define msleep(n) usleep(1000*n) #define msleep(n) usleep(1000*n)
#include <sys/wait.h> #include <sys/wait.h>
#endif #endif
#include "sim_sock.h"
typedef struct { typedef struct {
char *name; char *name;
void *addr; void *addr;
@ -93,6 +107,8 @@ struct PANEL {
int callback_thread_running; int callback_thread_running;
void *callback_context; void *callback_context;
int callbacks_per_second; int callbacks_per_second;
int debug;
FILE *Debug;
#if defined(_WIN32) #if defined(_WIN32)
HANDLE hProcess; HANDLE hProcess;
#else #else
@ -108,6 +124,7 @@ static void *_panel_reader(void *arg);
static void *_panel_callback(void *arg); static void *_panel_callback(void *arg);
static void sim_panel_set_error (const char *fmt, ...); static void sim_panel_set_error (const char *fmt, ...);
#define TN_IAC 0xFFu /* -1 */ /* protocol delim */ #define TN_IAC 0xFFu /* -1 */ /* protocol delim */
#define TN_DONT 0xFEu /* -2 */ /* dont */ #define TN_DONT 0xFEu /* -2 */ /* dont */
#define TN_DO 0xFDu /* -3 */ /* do */ #define TN_DO 0xFDu /* -3 */ /* do */
@ -117,6 +134,8 @@ static void sim_panel_set_error (const char *fmt, ...);
#define TN_BIN 0 /* bin */ #define TN_BIN 0 /* bin */
#define TN_ECHO 1 /* echo */ #define TN_ECHO 1 /* echo */
#define TN_SGA 3 /* sga */ #define TN_SGA 3 /* sga */
#define TN_CR 015 /* carriage return */
#define TN_LF 012 /* line feed */
#define TN_LINE 34 /* line mode */ #define TN_LINE 34 /* line mode */
static unsigned char mantra[] = { static unsigned char mantra[] = {
@ -127,6 +146,111 @@ static unsigned char mantra[] = {
TN_IAC, TN_DO, TN_BIN TN_IAC, TN_DO, TN_BIN
}; };
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;
struct timespec time_now;
va_list arglist;
clock_gettime(CLOCK_REALTIME, &time_now);
fprintf(p->Debug, "%lld.%03d ", (long long)(time_now.tv_sec), (int)(time_now.tv_nsec/1000000));
va_start (arglist, bufsize);
vfprintf (p->Debug, fmt, arglist);
va_end (arglist);
for (i=0; i<bufsize; ++i) {
switch ((unsigned char)buf[i]) {
case TN_CR:
fprintf(p->Debug, "_TN_CR_");
break;
case TN_LF:
fprintf(p->Debug, "_TN_LF_");
break;
case TN_IAC:
fprintf(p->Debug, "_TN_IAC_");
switch ((unsigned char)buf[i+1]) {
case TN_IAC:
fprintf(p->Debug, "_TN_IAC_"); ++i;
break;
case TN_DONT:
fprintf(p->Debug, "_TN_DONT_"); ++i;
break;
case TN_DO:
fprintf(p->Debug, "_TN_DO_"); ++i;
break;
case TN_WONT:
fprintf(p->Debug, "_TN_WONT_"); ++i;
break;
case TN_WILL:
fprintf(p->Debug, "_TN_WILL_"); ++i;
break;
default:
fprintf(p->Debug, "_0x%02X_", (unsigned char)buf[i+1]); ++i;
break;
}
switch ((unsigned char)buf[i+1]) {
case TN_BIN:
fprintf(p->Debug, "_TN_BIN_"); ++i;
break;
case TN_ECHO:
fprintf(p->Debug, "_TN_ECHO_"); ++i;
break;
case TN_SGA:
fprintf(p->Debug, "_TN_SGA_"); ++i;
break;
case TN_LINE:
fprintf(p->Debug, "_TN_LINE_"); ++i;
break;
default:
fprintf(p->Debug, "_0x%02X_", (unsigned char)buf[i+1]); ++i;
break;
}
break;
default:
if (isprint((u_char)buf[i]))
fprintf(p->Debug, "%c", buf[i]);
else {
fprintf(p->Debug, "_");
if ((buf[i] >= 1) && (buf[i] <= 26))
fprintf(p->Debug, "^%c", 'A' + buf[i] - 1);
else
fprintf(p->Debug, "\\%03o", (u_char)buf[i]);
fprintf(p->Debug, "_");
}
break;
}
}
fprintf(p->Debug, "\n");
}
}
void
sim_panel_set_debug_file (PANEL *panel, const char *debug_file)
{
if (!panel)
return;
panel->Debug = fopen(debug_file, "w");
}
void
sim_panel_set_debug_mode (PANEL *panel, int debug_bits)
{
if (panel)
panel->debug = debug_bits;
}
void
sim_panel_flush_debug (PANEL *panel)
{
if (!panel)
return;
if (panel->Debug)
fflush (panel->Debug);
}
static void * static void *
_panel_malloc (size_t size) _panel_malloc (size_t size)
@ -155,6 +279,7 @@ while (len) {
pthread_mutex_unlock (&p->io_send_lock); pthread_mutex_unlock (&p->io_send_lock);
return bsent; return bsent;
} }
_panel_debug (p, DBG_XMT, "Sent:", msg, bsent);
len -= bsent; len -= bsent;
msg += bsent; msg += bsent;
sent += bsent; sent += bsent;
@ -257,7 +382,8 @@ sim_panel_start_simulator (const char *sim_path,
size_t device_panel_count) size_t device_panel_count)
{ {
PANEL *p = NULL; PANEL *p = NULL;
FILE *f = NULL; FILE *fIn = NULL;
FILE *fOut = NULL;
struct stat statb; struct stat statb;
char *buf = NULL; char *buf = NULL;
int port, i; int port, i;
@ -307,38 +433,36 @@ p->config = (char *)_panel_malloc (strlen (sim_config) + 1);
if (p->config == NULL) if (p->config == NULL)
goto Error_Return; goto Error_Return;
strcpy (p->config, sim_config); strcpy (p->config, sim_config);
f = fopen (sim_config, "rb"); fIn = fopen (sim_config, "r");
if (f == NULL) { if (fIn == NULL) {
sim_panel_set_error ("Can't open configuration file '%s': %s", sim_config, strerror(errno)); sim_panel_set_error ("Can't open configuration file '%s': %s", sim_config, strerror(errno));
goto Error_Return; goto Error_Return;
} }
if (statb.st_size != fread (buf, 1, statb.st_size, f)) {
sim_panel_set_error ("Can't read complete configuration file '%s': %s", sim_config, strerror(errno));
goto Error_Return;
}
fclose (f);
f = NULL;
p->temp_config = (char *)_panel_malloc (strlen (sim_config) + 40); p->temp_config = (char *)_panel_malloc (strlen (sim_config) + 40);
if (p->temp_config == NULL) if (p->temp_config == NULL)
goto Error_Return; goto Error_Return;
sprintf (p->temp_config, "%s-Panel-%d", sim_config, getpid()); sprintf (p->temp_config, "%s-Panel-%d", sim_config, getpid());
f = fopen (p->temp_config, "w"); fOut = fopen (p->temp_config, "w");
if (f == NULL) { if (fOut == NULL) {
sim_panel_set_error ("Can't create temporary configuration file '%s': %s", p->temp_config, strerror(errno)); sim_panel_set_error ("Can't create temporary configuration file '%s': %s", p->temp_config, strerror(errno));
goto Error_Return; goto Error_Return;
} }
fprintf (f, "# Temporary FrontPanel generated simh configuration file\n"); fprintf (fOut, "# Temporary FrontPanel generated simh configuration file\n");
fprintf (f, "# Original Configuration File: %s\n", p->config); fprintf (fOut, "# Original Configuration File: %s\n", p->config);
fprintf (f, "# Simulator Path: %s\n", sim_path); fprintf (fOut, "# Simulator Path: %s\n", sim_path);
fprintf (f, "%s\n", buf); while (fgets (buf, statb.st_size, fIn))
fputs (buf, fOut);
free (buf); free (buf);
buf = NULL; buf = NULL;
fprintf (f, "set remote -u telnet=%s\n", hostport); fclose (fIn);
fIn = NULL;
fprintf (fOut, "set remote notelnet\n");
if (device_panel_count) if (device_panel_count)
fprintf (f, "set remote connections=%d\n", (int)device_panel_count+1); fprintf (fOut, "set remote connections=%d\n", (int)device_panel_count+1);
fprintf (f, "set remote master\n"); fprintf (fOut, "set remote -u telnet=%s\n", hostport);
fclose (f); fprintf (fOut, "set remote master\n");
f = NULL; fclose (fOut);
fOut = NULL;
if (1) { if (1) {
#if defined(_WIN32) #if defined(_WIN32)
char cmd[2048]; char cmd[2048];
@ -421,8 +545,12 @@ _panel_register_panel (p);
return p; return p;
Error_Return: Error_Return:
if (f) if (fIn)
fclose (f); fclose (fIn);
if (fOut) {
fclose (fOut);
remove (p->temp_config);
}
if (buf) if (buf)
free (buf); free (buf);
sim_panel_destroy (p); sim_panel_destroy (p);
@ -501,6 +629,7 @@ sim_panel_destroy (PANEL *panel)
REG *reg; REG *reg;
if (panel) { if (panel) {
_panel_debug (panel, DBG_XMT|DBG_RCV, "Closing Panel %s\n", NULL, 0, panel->name);
if (panel->devices) { if (panel->devices) {
size_t i; size_t i;
@ -786,8 +915,12 @@ while (p->sock != INVALID_SOCKET) {
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));
if (new_data <= 0) if (new_data <= 0) {
sim_panel_set_error ("%s", sim_get_err_sock("Unexpected socket read"));
_panel_debug (p, DBG_RCV, "%s", NULL, 0, sim_panel_get_error());
break; break;
}
_panel_debug (p, DBG_RCV, "Received:", &buf[buf_data], new_data);
buf_data += new_data; buf_data += new_data;
buf[buf_data] = '\0'; buf[buf_data] = '\0';
s = buf; s = buf;
@ -849,12 +982,17 @@ while (p->sock != INVALID_SOCKET) {
} }
memmove (buf, s, strlen (s)+1); memmove (buf, s, strlen (s)+1);
buf_data = strlen (buf); buf_data = strlen (buf);
if (!strcmp("Simulator Running", buf)) { if (!strcmp("Simulator Running...", buf)) {
p->State = Run; p->State = Run;
buf_data = 0; buf_data = 0;
buf[0] = '\0'; buf[0] = '\0';
} }
} }
if (p->io_waiting) {
_panel_debug (p, DBG_RCV, "Receive: restarting waiting thread while exiting", NULL, 0);
p->io_waiting = 0;
pthread_cond_signal (&p->io_done);
}
p->io_thread_running = 0; p->io_thread_running = 0;
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
return NULL; return NULL;

View file

@ -100,6 +100,17 @@ sim_panel_get_state (PANEL *panel);
const char *sim_panel_get_error (void); const char *sim_panel_get_error (void);
void sim_panel_clear_error (void); void sim_panel_clear_error (void);
void
sim_panel_set_debug_file (PANEL *panel, const char *debug_file);
#define DBG_XMT 1 /* Transmit Data */
#define DBG_RCV 2 /* Receive Data */
void
sim_panel_set_debug_mode (PANEL *panel, int debug_bits);
void
sim_panel_flush_debug (PANEL *panel);
#ifdef __cplusplus #ifdef __cplusplus
} }