Setting parity for remote serial

Yurij Grechishhev
2013-07-10T15:18:02Z

GDB doesn't support command to set parity for serial ports. So there
is a problem to connect target that use "odd" or "even" parity.
The one way is to set parity before launching gdb (stty for Linux or
MODE for Windows), but for Windows gdb sets parity to "none" during
connection.
I suggest using "set remoteparity <odd | even | none>" command for this.

Example:
(gdb) set remoteparity
even none odd
(gdb) set remoteparity even
(gdb) show remoteparity
Parity for remote serial I/O is "even".

I hope this will be useful for somebody.

Do you plan to use "class serial" (set serial ...) for serial settings?
"set serial parity <odd | even | none>" is more convenient way.

diff -up ../../../gdb_old/gdb-7.6/gdb/monitor.c gdb/monitor.c
--- ../../../gdb_old/gdb-7.6/gdb/monitor.c 2013-07-10
21:55:33.656750073 +0400
+++ gdb/monitor.c 2013-07-04 23:54:32.472595952 +0400
@@ -768,6 +768,7 @@ monitor_open (char *args, struct monitor
}
}

+ serial_setparity (monitor_desc, serial_parity);
serial_raw (monitor_desc);

serial_flush_input (monitor_desc);
Common subdirectories: ../../../gdb_old/gdb-7.6/gdb/po and gdb/po
Common subdirectories: ../../../gdb_old/gdb-7.6/gdb/python and gdb/python
Common subdirectories: ../../../gdb_old/gdb-7.6/gdb/regformats and
gdb/regformats
diff -up ../../../gdb_old/gdb-7.6/gdb/remote.c gdb/remote.c
--- ../../../gdb_old/gdb-7.6/gdb/remote.c 2013-07-10 21:55:34.645747970 +0400
+++ gdb/remote.c 2013-07-04 23:50:52.855721644 +0400
@@ -4256,6 +4256,7 @@ remote_open_1 (char *name, int from_tty,
}
}

+ serial_setparity(remote_desc, serial_parity);
serial_raw (remote_desc);

/* If there is something sitting in the buffer we might take it as a
diff -up ../../../gdb_old/gdb-7.6/gdb/ser-base.c gdb/ser-base.c
--- ../../../gdb_old/gdb-7.6/gdb/ser-base.c 2013-07-10
21:55:24.161873687 +0400
+++ gdb/ser-base.c 2013-07-05 00:28:55.795720278 +0400
@@ -536,6 +536,14 @@ ser_base_setbaudrate (struct serial *scb
return 0; /* Never fails! */
}

+
+int
+ser_base_setparity (struct serial *scb, int num)
+{
+ return 0; /* Never fails! */
+}
+
+
int
ser_base_setstopbits (struct serial *scb, int num)
{
diff -up ../../../gdb_old/gdb-7.6/gdb/ser-base.h gdb/ser-base.h
--- ../../../gdb_old/gdb-7.6/gdb/ser-base.h 2013-07-10
21:55:24.168750025 +0400
+++ gdb/ser-base.h 2013-07-05 00:30:36.017596667 +0400
@@ -43,6 +43,7 @@ extern int ser_base_noflush_set_tty_stat
serial_ttystate old_ttystate);
extern int ser_base_setbaudrate (struct serial *scb, int rate);
extern int ser_base_setstopbits (struct serial *scb, int rate);
+extern int ser_base_setparity (struct serial *scb, int parity);
extern int ser_base_drain_output (struct serial *scb);

extern int ser_base_write (struct serial *scb, const char *str, int len);
diff -up ../../../gdb_old/gdb-7.6/gdb/serial.c gdb/serial.c
--- ../../../gdb_old/gdb-7.6/gdb/serial.c 2013-07-10 21:55:35.224750365 +0400
+++ gdb/serial.c 2013-07-10 20:41:31.899897384 +0400
@@ -26,6 +26,9 @@

extern void _initialize_serial (void);

+/* Parity for serial port */
+extern int serial_parity;
+
/* Is serial being debugged? */

static unsigned int global_serial_debug_p;
@@ -53,10 +56,29 @@ static const char logbase_ascii[] = "asc
static const char *const logbase_enums[] =
{logbase_hex, logbase_octal, logbase_ascii, NULL};
static const char *serial_logbase = logbase_ascii;
-

static int serial_current_type = 0;

+/* Parity for serial port */
+static const char parity_none[] = "none";
+static const char parity_odd[] = "odd";
+static const char parity_even[] = "even";
+static const char *const parity_enums[] =
+{parity_none, parity_odd, parity_even, NULL};
+static const char *parity = parity_none;
+
+static void
+set_parity (char *ignore_args, int from_tty, struct cmd_list_element *c)
+{
+ if (parity == parity_odd)
+ serial_parity = GDBPARITY_ODD;
+ else if (parity == parity_even)
+ serial_parity = GDBPARITY_EVEN;
+ else
+ serial_parity = GDBPARITY_NONE;
+}
+
+
/* Log char CH of type CHTYPE, with TIMEOUT. */

/* Define bogus char to represent a BREAK. Should be careful to choose a value
@@ -521,6 +543,12 @@ serial_setstopbits (struct serial *scb,
}

int
+serial_setparity (struct serial*scb, int parity)
+{
+ return scb->ops->setparity (scb, parity);
+}
+
+int
serial_can_async_p (struct serial *scb)
{
return (scb->ops->async != NULL);
@@ -658,6 +686,15 @@ Show numerical base for remote session l
NULL, /* FIXME: i18n: */
&setlist, &showlist);

+ add_setshow_enum_cmd ("remoteparity", no_class, parity_enums,
+ &parity, _("\
+Set parity for remote serial I/O"), _("\
+Show parity for remote serial I/O"), NULL,
+ set_parity,
+ NULL, /* FIXME: i18n: */
+ &setlist, &showlist);
+
+
add_setshow_zuinteger_cmd ("serial", class_maintenance,
&global_serial_debug_p, _("\
Set serial debugging."), _("\
diff -up ../../../gdb_old/gdb-7.6/gdb/serial.h gdb/serial.h
--- ../../../gdb_old/gdb-7.6/gdb/serial.h 2013-07-10 21:55:33.445749528 +0400
+++ gdb/serial.h 2013-07-10 20:17:17.705956716 +0400
@@ -177,6 +177,14 @@ extern int serial_noflush_set_tty_state

extern int serial_setbaudrate (struct serial *scb, int rate);

+/* Set parity for serial port. Return 0 for success, -1 for failure */
+
+#define GDBPARITY_NONE 0
+#define GDBPARITY_ODD 1
+#define GDBPARITY_EVEN 2
+
+extern int serial_setparity (struct serial *scb, int parity);
+
/* Set the number of stop bits to the value specified. Returns 0 for
success, -1 for failure. */

@@ -272,6 +280,7 @@ struct serial_ops
serial_ttystate);
int (*setbaudrate) (struct serial *, int rate);
int (*setstopbits) (struct serial *, int num);
+ int (*setparity) (struct serial *, int parity);
/* Wait for output to drain. */
int (*drain_output) (struct serial *);
/* Change the serial device into/out of asynchronous mode, call
diff -up ../../../gdb_old/gdb-7.6/gdb/ser-mingw.c gdb/ser-mingw.c
--- ../../../gdb_old/gdb-7.6/gdb/ser-mingw.c 2013-07-10
21:55:24.185807109 +0400
+++ gdb/ser-mingw.c 2013-07-10 20:51:20.459749272 +0400
@@ -156,7 +156,6 @@ ser_windows_raw (struct serial *scb)
if (GetCommState (h, &state) == 0)
return;

- state.fParity = FALSE;
state.fOutxCtsFlow = FALSE;
state.fOutxDsrFlow = FALSE;
state.fDtrControl = DTR_CONTROL_ENABLE;
@@ -166,7 +165,6 @@ ser_windows_raw (struct serial *scb)
state.fNull = FALSE;
state.fAbortOnError = FALSE;
state.ByteSize = 8;
- state.Parity = NOPARITY;

scb->current_timeout = 0;

@@ -202,6 +200,37 @@ ser_windows_setstopbits (struct serial *
}

static int
+ser_windows_setparity (struct serial *scb, int parity)
+{
+ HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
+ DCB state;
+
+ if (GetCommState (h, &state) == 0)
+ return -1;
+
+ switch (parity)
+ {
+ case GDBPARITY_NONE:
+ state.Parity = NOPARITY;
+ state.fParity = FALSE;
+ break;
+ case GDBPARITY_ODD:
+ state.Parity = ODDPARITY;
+ state.fParity = TRUE;
+ break;
+ case GDBPARITY_EVEN:
+ state.Parity = EVENPARITY;
+ state.fParity = TRUE;
+ break;
+ default:
+ return 1;
+
+ }
+
+ return (SetCommState (h, &state) != 0) ? 0 : -1;
+}
+
+static int
ser_windows_setbaudrate (struct serial *scb, int rate)
{
HANDLE h = (HANDLE) _get_osfhandle (scb->fd);
@@ -1250,6 +1279,7 @@ _initialize_ser_windows (void)

ops->go_raw = ser_windows_raw;
ops->setbaudrate = ser_windows_setbaudrate;
+ ops->setparity = ser_windows_setparity;
ops->setstopbits = ser_windows_setstopbits;
ops->drain_output = ser_windows_drain_output;
ops->readchar = ser_base_readchar;
@@ -1303,6 +1333,7 @@ _initialize_ser_windows (void)
ops->print_tty_state = ser_base_print_tty_state;
ops->noflush_set_tty_state = ser_base_noflush_set_tty_state;
ops->setbaudrate = ser_base_setbaudrate;
+ ops->setparity = ser_base_setparity;
ops->setstopbits = ser_base_setstopbits;
ops->drain_output = ser_base_drain_output;
ops->async = ser_base_async;
@@ -1338,6 +1369,7 @@ _initialize_ser_windows (void)
ops->print_tty_state = ser_base_print_tty_state;
ops->noflush_set_tty_state = ser_base_noflush_set_tty_state;
ops->setbaudrate = ser_base_setbaudrate;
+ ops->setparity = ser_base_setparity;
ops->setstopbits = ser_base_setstopbits;
ops->drain_output = ser_base_drain_output;
ops->async = ser_base_async;
diff -up ../../../gdb_old/gdb-7.6/gdb/ser-pipe.c gdb/ser-pipe.c
--- ../../../gdb_old/gdb-7.6/gdb/ser-pipe.c 2013-07-10
21:55:24.185807109 +0400
+++ gdb/ser-pipe.c 2013-07-10 20:58:32.921749511 +0400
@@ -233,6 +233,7 @@ _initialize_ser_pipe (void)
ops->print_tty_state = ser_base_print_tty_state;
ops->noflush_set_tty_state = ser_base_noflush_set_tty_state;
ops->setbaudrate = ser_base_setbaudrate;
+ ops->setparity = ser_base_setparity;
ops->setstopbits = ser_base_setstopbits;
ops->drain_output = ser_base_drain_output;
ops->async = ser_base_async;
diff -up ../../../gdb_old/gdb-7.6/gdb/ser-tcp.c gdb/ser-tcp.c
--- ../../../gdb_old/gdb-7.6/gdb/ser-tcp.c 2013-07-10
21:55:24.200748354 +0400
+++ gdb/ser-tcp.c 2013-07-05 00:33:53.026598227 +0400
@@ -396,6 +396,7 @@ _initialize_ser_tcp (void)
ops->print_tty_state = ser_base_print_tty_state;
ops->noflush_set_tty_state = ser_base_noflush_set_tty_state;
ops->setbaudrate = ser_base_setbaudrate;
+ ops->setparity = ser_base_setparity;
ops->setstopbits = ser_base_setstopbits;
ops->drain_output = ser_base_drain_output;
ops->async = ser_base_async;
diff -up ../../../gdb_old/gdb-7.6/gdb/ser-unix.c gdb/ser-unix.c
--- ../../../gdb_old/gdb-7.6/gdb/ser-unix.c 2013-07-10
21:55:24.229751815 +0400
+++ gdb/ser-unix.c 2013-07-10 20:45:43.995750064 +0400
@@ -99,6 +99,7 @@ static int hardwire_flush_output (struct
static int hardwire_flush_input (struct serial *);
static int hardwire_send_break (struct serial *);
static int hardwire_setstopbits (struct serial *, int);
+static int hardwire_setparity (struct serial *, int);

void _initialize_ser_hardwire (void);

@@ -893,6 +894,47 @@ hardwire_setstopbits (struct serial *scb
return set_tty_state (scb, &state);
}

+static int
+hardwire_setparity (struct serial *scb, int parity)
+{
+ struct hardwire_ttystate state;
+ int newparity = 0;
+
+ if (get_tty_state (scb, &state))
+ return -1;
+
+ switch (parity)
+ {
+ case GDBPARITY_NONE:
+ newparity = 0;
+ break;
+ case GDBPARITY_ODD:
+ newparity = PARENB | PARODD;
+ break;
+ case GDBPARITY_EVEN:
+ newparity = PARENB;
+ break;
+ default:
+ return 1;
+ }
+
+#ifdef HAVE_TERMIOS
+ state.termios.c_cflag |= newparity;
+#endif
+
+#ifdef HAVE_TERMIO
+ state.termio.c_cflag |= newparity;
+#endif
+
+#ifdef HAVE_SGTTY
+ return 0; /* sgtty doesn't support this */
+#endif
+
+ return set_tty_state (scb, &state);
+
+}
+
+
static void
hardwire_close (struct serial *scb)
{
@@ -929,6 +971,7 @@ _initialize_ser_hardwire (void)
ops->print_tty_state = hardwire_print_tty_state;
ops->noflush_set_tty_state = hardwire_noflush_set_tty_state;
ops->setbaudrate = hardwire_setbaudrate;
+ ops->setparity = hardwire_setparity;
ops->setstopbits = hardwire_setstopbits;
ops->drain_output = hardwire_drain_output;
ops->async = ser_base_async;
Common subdirectories: ../../../gdb_old/gdb-7.6/gdb/stubs and gdb/stubs
Common subdirectories: ../../../gdb_old/gdb-7.6/gdb/syscalls and gdb/syscalls
diff -up ../../../gdb_old/gdb-7.6/gdb/target.h gdb/target.h
--- ../../../gdb_old/gdb-7.6/gdb/target.h 2013-07-10 21:55:36.818749395 +0400
+++ gdb/target.h 2013-07-05 00:36:15.025597655 +0400
@@ -1961,6 +1961,10 @@ extern int remote_debug;

/* Speed in bits per second, or -1 which means don't mess with the speed. */
extern int baud_rate;
+
+/* Parity for serial port */
+extern int serial_parity;
+
/* Timeout limit for response from target. */
extern int remote_timeout;

Common subdirectories: ../../../gdb_old/gdb-7.6/gdb/testsuite and gdb/testsuite
diff -up ../../../gdb_old/gdb-7.6/gdb/top.c gdb/top.c
--- ../../../gdb_old/gdb-7.6/gdb/top.c 2013-07-10 21:55:32.033750880 +0400
+++ gdb/top.c 2013-07-10 20:55:06.711827223 +0400
@@ -159,6 +159,9 @@ int server_command;

int baud_rate = -1;

+/* Parity for serial port */
+int serial_parity = GDBPARITY_NONE;
+
/* Timeout limit for response from target. */

/* The default value has been changed many times over the years. It
Common subdirectories: ../../../gdb_old/gdb-7.6/gdb/tui and gdb/tui

--
With best regards!
____________________________

Yurij Grechishhev
Bauman State Technical University,
Department of Computer Systems and Networks