| diff --git a/capture_nrf_52840/capture_nrf_52840.c b/capture_nrf_52840/capture_nrf_52840.c
|
| index 80978c7f6..253f0f592 100644
|
| --- a/capture_nrf_52840/capture_nrf_52840.c
|
| +++ b/capture_nrf_52840/capture_nrf_52840.c
|
| @@ -8,6 +8,7 @@
|
| #include <string.h>
|
| #include <termios.h>
|
| #include <fcntl.h>
|
| +#include <sys/ioctl.h>
|
|
|
| #include "../config.h"
|
|
|
| @@ -314,25 +315,72 @@ int open_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
| }
|
|
|
| tcgetattr(localnrf->fd,&localnrf->oldtio); /* save current serial port settings */
|
| - bzero(&localnrf->newtio, sizeof(localnrf->newtio)); /* clear struct for new port settings */
|
|
|
| - /* set the baud rate and flags */
|
| - localnrf->newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
|
| + /* Build the new termios state from the device's current state and then
|
| + * normalise it. Avoid the bzero()+field-assignment pattern: with
|
| + * _FORTIFY_SOURCE=3 (enabled by -fhardened in GCC 14+) the checked
|
| + * memset can short-zero the struct if __builtin_object_size resolves
|
| + * to less than sizeof(struct termios), leaving stray bits (PARODD,
|
| + * IBAUD, etc.) in c_cflag that propagate straight through tcsetattr.
|
| + */
|
| + localnrf->newtio = localnrf->oldtio;
|
|
|
| - /* ignore parity errors */
|
| - localnrf->newtio.c_iflag = IGNPAR;
|
| + /* raw mode: clears canonical, echo, signals, IXON/IXOFF, OPOST, etc. */
|
| + cfmakeraw(&localnrf->newtio);
|
|
|
| - /* raw output */
|
| - localnrf->newtio.c_oflag = 0;
|
| + cfsetispeed(&localnrf->newtio, B115200);
|
| + cfsetospeed(&localnrf->newtio, B115200);
|
|
|
| - /* newtio.c_lflag = ICANON; */
|
| + /* enable receiver, ignore modem control lines */
|
| + localnrf->newtio.c_cflag |= (CLOCAL | CREAD | CS8);
|
| + localnrf->newtio.c_cflag &= ~(PARENB | PARODD | CSTOPB | CRTSCTS);
|
| +
|
| + /* ignore parity errors */
|
| + localnrf->newtio.c_iflag |= IGNPAR;
|
|
|
| - localnrf->newtio.c_lflag &= ~ICANON; /* Set non-canonical mode */
|
| - localnrf->newtio.c_cc[VTIME] = 1; /* Set timeout in deciseconds */
|
| + /* short read timeout, no minimum */
|
| + localnrf->newtio.c_cc[VMIN] = 0;
|
| + localnrf->newtio.c_cc[VTIME] = 1;
|
| +
|
| + /* one-shot diagnostic: log what we are about to push to the kernel.
|
| + * If c_cflag carries bits we never set (e.g. PARODD, B50<<IBSHIFT,
|
| + * 0xc000) or sizeof differs from the expected glibc layout, the
|
| + * struct is being mangled before tcsetattr sees it.
|
| + */
|
| + fprintf(stderr,
|
| + "DEBUG nrf52840 termios: cflag=%08lx iflag=%08lx oflag=%08lx "
|
| + "lflag=%08lx ispeed=%u ospeed=%u VMIN=%u VTIME=%u sizeof=%zu\n",
|
| + (unsigned long) localnrf->newtio.c_cflag,
|
| + (unsigned long) localnrf->newtio.c_iflag,
|
| + (unsigned long) localnrf->newtio.c_oflag,
|
| + (unsigned long) localnrf->newtio.c_lflag,
|
| + (unsigned) cfgetispeed(&localnrf->newtio),
|
| + (unsigned) cfgetospeed(&localnrf->newtio),
|
| + (unsigned) localnrf->newtio.c_cc[VMIN],
|
| + (unsigned) localnrf->newtio.c_cc[VTIME],
|
| + sizeof(localnrf->newtio));
|
|
|
| /* flush and set up */
|
| tcflush(localnrf->fd, TCIFLUSH);
|
| - tcsetattr(localnrf->fd, TCSANOW, &localnrf->newtio);
|
| + if (tcsetattr(localnrf->fd, TCSANOW, &localnrf->newtio) < 0) {
|
| + snprintf(msg, STATUS_MAX, "%s tcsetattr failed - %s",
|
| + localnrf->name, strerror(errno));
|
| + pthread_mutex_unlock(&(localnrf->serial_mutex));
|
| + return -1;
|
| + }
|
| +
|
| + /* explicitly assert RTS/DTR after tcsetattr. cdc-acm forwards these
|
| + * to the device's SET_CONTROL_LINE_STATE; some firmwares hold output
|
| + * until RTS is asserted. With CRTSCTS off, the kernel will not
|
| + * touch them automatically.
|
| + */
|
| + {
|
| + int mctrl = 0;
|
| + if (ioctl(localnrf->fd, TIOCMGET, &mctrl) == 0) {
|
| + mctrl |= TIOCM_RTS | TIOCM_DTR;
|
| + ioctl(localnrf->fd, TIOCMSET, &mctrl);
|
| + }
|
| + }
|
|
|
| pthread_mutex_unlock(&(localnrf->serial_mutex));
|
|
|