Linux, termios: how to handle negative result of select() - linux

I'm developing on an am335x system with ubuntu and the last kernel released from TI (vendor).
I'm using a virtual tty device (ttyUSB0) for comunicate with a remote device. After about one hour of continuous comunication (cyclic open-transmit-receive-close) I get a strange behaviour of read(). If the UART is opened in blocking mode the read hangs forever (no matter what value I set on VMIN&VTIME). If I open it in non-blocking mode it return -1 for ever (after 1 hour).
Now I'm using select() to check if there is data to be read.
In case I receive a negative result from select, how can I handle the error? What is a good practice? I have to restart the service?
This code is a part of a service that start at boot time(with upstart). When it hangs, if I restart it, it works again. The restart do not have any effect on the device with which I'm communicating. It works properly.
This is a piece of code, just for completeness:
FD_ZERO(&set); /* clear the set */
FD_SET(tty_fileDescriptor, &set); /* add our file descriptor to the set */
timeout.tv_sec = 10;
timeout.tv_usec = 0;
rv = select(tty_fileDescriptor + 1, &set, NULL, NULL, &timeout);
if(rv>0){
letti=read(tty_fileDescriptor,payLoadTMP,300);
}if(rv<0){
perror("select")
//what to do here to re-stablish communication?
}
The perror's output is:
select: Resource temporarily unavailable
this is a grep on dmesg
usb 1-1: cp210x converter now attached to ttyUSB0
any ideas? How to re-stablish connection?

Related

UART Interrupts disabling I/O on Sam3X8E/ Arduino Due

I am starting to use an Arduino Due for some project work which requires a UART and am confused by what looks like an interaction between UART interrupts and I/O.
My first piece of code was a small routine to set up the UART, send out data continuously by loading the transmit buffer upon receipt of a TXBE interrupt. I had the UART output hooked up to an oscilloscope and had set another I/O pin as a general purpose output which would flip state and therefore be used to trigger the scope when the transmit buffer was reloaded. Problem was that I was seeing UART data and it looked good, but the I/O wasn't flipping. At this point my loop() routine was empty so I set up another output port and in loop() just toggled its state as a sanity check. Still no output except for the UART.
Here's the code that I ended up with:
uint32_t tempo; // 32-bit temporary variable
boolean flag = true;
void UART_Handler(void) {
REG_UART_THR = 0x6DL; // load data into the transmit buffer
if (flag) {
REG_PIOD_SODR = 0x02L; // drive PD1 high
flag = false;
} else {
REG_PIOD_CODR = 0x02L; // drive PD1 low
flag = true;
}
}
void setup() {
// set up the UART I/O
REG_PIOA_IDR = 0x0300L; // disable interrupts on PA8 and PA9
tempo = REG_PIOA_ABSR; // get the current settings of the AB select register
REG_PIOA_ABSR = tempo & 0xFFFFFCFF; // set PA8 and PA9 to peripheral A control
REG_PIOA_PDR = 0x0300L; // disable parallel I/O for PA8 and PA9
NVIC_EnableIRQ(UART_IRQn); // enable UART interrupts in NVIC
// now set up the UART
tempo = REG_PMC_PCSR0; // get the current settings of the peripheral clock register 0
REG_PMC_PCER0 = tempo | 0x0100L; // enable the UART clocks
REG_UART_CR = 0x0CL; // reset UART receiver and transmitter
REG_UART_MR = 0x0800L; // set to normal outputs with no parity
REG_UART_BRGR = 0x89L; // baud rate set to 38400
REG_UART_IDR = 0x1FBL; // disable all UART interrupts
REG_UART_IER = 0x0800L; // enable TXBUFE interrupt
REG_UART_CR = 0x50L; // enable UART receiver and transmitter
// set up the debug outputs
REG_PIOD_IDR = 0x03L; // disable interrupts on PD0 and PD1
REG_PIOD_PER = 0x03L; // enable parallel I/O for PD0 & PD1
REG_PIOD_OER = 0x03L; // set PD0 & PD1 output enabled
REG_PIOD_CODR = 0x03L; // drive PD0 & PD1 low
}
void loop() // run over and over
{
REG_PIOD_SODR = 0x01L; // drive PD0 high
delay(1);
REG_PIOD_CODR = 0x01L; // drive PD0 low
delay(1);
}
the scope output can be viewed at http://www.iwanczuk.com/temp/scope1.png (don't have enough reputation here to post images!).
After staring at things for while and getting no insight I disabled the TXBUFE interrupts by commenting out the line REG_UART_IER = 0x0800L; // enable TXBUFE interrupt and the toggling of PortD1 was then visible but obviously no UART output (see http://www.iwanczuk.com/temp/scope2.png). It seems that the two are mutually exclusive which would be just silly if it were true. I am sure I'm missing something but I can't see or find what it is.
I have read the SAM3X8E data sheet to see if there's anything obvious I'm missing and if there is I can't see it. I've also done what I think are relevant web searches with no luck in finding a solution. I have also tried using general purpose outputs for the two outputs on port A and port D and have tried this on two Arduino Due boards with similar results on both.
Anyone have any ideas what I might be doing wrong? Thanks in advance.
Well, I have got to the bottom of this problem. Not sure it's the best answer but it's a solution. The long and short of it is to avoid TXBE interrupts. If I use TXEMPTY interrupts instead it works fine.
A line on page 168 of the Atmel data sheet says (sic) "A interrupt can enter pending state even it is disabled" so I wondered if the problem with TXBE was because I was not clearing the pending interrupt before or even inside the ISR so I added NVIC_ClearPendingIRQ(UART_IRQn); at the start of the ISR and also just before I enabled the TXBE interrupt but the (mis)behaviour didn't change.
The operation of TXEMPTY is still a little odd (to me) because it appears that the interrupt is generated by the transmit shift register just being empty, not when it goes empty. If you enable interrupts without having loaded the transmit buffer you will immediately get an interrupt. Some may like this "self=priming' behaviour, but it doesn't do it for me. I am writing my sending routine such that the TXEMPTY interrupt is not enabled until the transmitter has been loaded with the first byte to be sent.
Based on this post on the Arduino Forum: http://forum.arduino.cc/index.php?topic=186388.0 I presume that the USARTs have a similar issue.
Hopefully this will help others.
I just realised what could be the real error at the source of my problem. The UART interrupt register descriptions talk about the TXBUFE bit in the context of transmit buffer empty and so my assumption was that this is the bit that tells me when I can put another byte into the transmit holding register. However the UART Status Register description say that the TXBUFE bit is "the buffer full signal from the transmitter PDC channel". The latter puts a whole different slant on what this bit does. According to the UART Status Register description the bit I need to be looking at is the TXRDY bit!

Last Reboot detection on PhyCORE-AM335x-PD13.1.2 Linux 3.2

In an embedded system using BSP linux 3.2 on the sitara AM3359, at application startup, I want to detect what caused the last reboot and save this status in one of two counters: a Watchdog reset and a Power-on reset.
Usually in a MCU, I test the watchdog by reserving spot in the ram and write special key on the first boot and reset using the watchdog. If not there when reboot it's power on if it's there it's a watchdog reset.
My first question is, how to save the key variables on RAM that would survive a reboot or a watchdog reset ?
It's seem something clean the ram at boot...can I disable that?
There usually a register with that information. On AM335x there is the PRM_RSTST register with the bit (WDT1_RST), I am using ioctl() with WDIOC_GETBOOTSTATUS to Check if the last boot is caused by watchdog or it's power-on-reset. This call doesn't return me something I can understand. Can somebody explain it ? How can I get this register...
Power ON:
test1: 1076092848
test2: 1076113328
test3: 1075589040
test4: 1076203440
watchdog:
test5: 1076481968
test6: 1075732400
test7: 1075965872
code use:
/* Check if last boot is caused by watchdog */
if (ioctl(fd, WDIOC_GETBOOTSTATUS, &bootstatus) == 0) {
fprintf(stdout, "Last boot is caused by : %s, bootstatus= %d\n",
(bootstatus != 0) ? "Watchdog" : "Power-On-Reset", bootstatus);
} else {
fprintf(stderr, "Error: Cannot read watchdog status\n");
exit(EXIT_FAILURE);
}
Is there another way to get this information (mmap, write driver, sys, etc)?
I would propose you to use your bootloader to see processor register values (for u-boot I beleive the command is reginfo). The same way (but another command) for the memory where you stock watchdog keys. Once debugged with your bootloader you can think about passing them to the kernel.
I start by using terminal command devmem 0x44E00F08 (busybox) to see if reading the physical memory will work then I use mmap() to read the PRM_RSTST register and know if the last reset was watchdog reset.

How to change the watchdog timer in linux embedded

I have to use the linux watchdog driver (/dev/watchdog). It works great, I write an character like this:
echo 1 > /dev/watchdog
And the watchdog start and after an about 1 minute, the system reboot.
The question is, how can I change the timeout? I have to change the time interval in the driver?
Please read the Linux documentation. The standard method of changing the timeout from user space is to use an ioctl().
int timeout = 45; /* a time in seconds */
int fd;
fd = open("/dev/watchdog");
ioctl(fd, WDIOC_SETTIMEOUT, &timeout); /* Send time request to the driver. */
Each watchdog device may have an upper (and possibly lower) limit on that the hardware supports, so you can not set the timeout arbitrarily high. So after setting a timeout, it is good to read back the timeout.
ioctl(fd, WDIOC_GETTIMEOUT, &timeout); /* Update timeout with driver value. */
Now, the re-read timeout can be used as a kick frequency.
assert(timeout > 2);
while (1) {
ioctl(fd, WDIOC_KEEPALIVE, 0);
sleep(timeout-2);
}
You can write your own kicking routine in a script/shell command,
while [ 1 ] ; do sleep 1; echo V > /dev/watchdog; done
However, the userspace watchdog program is usually used. This should take care of all the esoteric features. You can nice the user space program to a minimum priority and then the system will reset if user space becomes hung up. BusyBox includes a watchdog applet.
Each watchdog driver has separate module parameters and most include a mechanism to set the timeout; use either the kernel command line or module parameter setting mechanism. However, the infra-structure ioctl timeout is more portable if you do not have specific knowledge of your watchdog hardware. The ioctl is probably more future proof, in that your hardware may change.
Sample user space code is included in the Linux samples directory.

'close' function on serial port descriptor blocks in linux

Recently I've found a problem which is quite new for me and I'd appreciate advice. I'm doing serial communication on Linux using termios functions. I actually don't use real serial port, but virtual gadget serial driver /dev/ttyGS0. File descriptor is opened as non-blocking.
My program periodically generates data and sends it to /dev/ttyGS0. There is no information if the other end reads it or not. If it does not, some internal fifo fills up and write returns "would block" error. So far so good, I have no problems with that.
Problem is, when I want to close such file descriptor with filled fifo, close functions blocks! Not indefinitely, but for about 10 seconds.
I tried to do tcflush(uart->fd, TCOFLUSH) before closing without any effect.
This is so strange behavior to me and I found no description, that close could block. Is there any way how to avoid this? Or at least decrease this timeout? Where should I look for this timeout? VTIME attribute has also no effect to this.
As Amardeep mentioned, the close() call is handled by the driver. Close itself is always a blocking call, but generally it's a fast one.
So, the answer is that the delay is specific to the virtual gadget driver. I don't have experience with that one to help.
How important is it to close the file? If the delay is a major problem and the file needs to be closed (such as avoiding file descriptor leaks in a long-running process), then the close will probably need to be called in a separate thread. Obviously, the best answer would be one specific to that driver; perhaps research there might yield an answer, such as an ioctl() call that clears the state of the virtual device.
You may need to configure your port's closing_wait parameter. From the setserial manual:
closing_wait delay
Specify the amount of time, in hundredths of a second, that the kernel should wait for data to be transmitted from
the serial port while
closing the port. If "none" is specified, no delay will occur. If "infinite" is specified the kernel will wait
indefinitely for the
buffered data to be transmitted. The default setting is 3000 or 30 seconds of delay. This default is generally
appropriate for most
devices. If too long a delay is selected, then the serial port may hang for a long time if when a serial port which is
not connected, and
has data pending, is closed. If too short a delay is selected, then there is a risk that some of the transmitted data is
output at all.
If the device is extremely slow, like a plotter, the closing_wait may need to be larger.
Check with setserial the parameters for your port:
$ setserial -g -a /dev/ttyS0
/dev/ttyS0, Line 0, UART: 16550A, Port: 0x03f8, IRQ: 4
Baud_base: 115200, close_delay: 50, divisor: 0
closing_wait: 3000
Flags: spd_normal skip_test
In my case, a faulting device was not receiving the last bytes I sent it, and closing the port always took 30 seconds because of this. You can change this timeout with setserial, for example, to 1 second:
$ sudo setserial /dev/ttyS0 closing_wait 100
Of course, you may want to issue this command on startup in your /etc/rc.local or whatever script your distro uses to configure your ports.
I faced the same issue, in my case disabling flowcontrol before closing the device helped. You can do this using following function:
int set_flowcontrol(int fd, int control)
{
struct termios tty;
memset(&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0)
{
perror("error from tggetattr");
return -1;
}
if(control) tty.c_cflag |= CRTSCTS;
else tty.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &tty) != 0)
{
perror("error setting term attributes");
return -1;
}
return 0;
}
Just call this before closing:
...
rc = set_flowcontrol(fd, 0);
if (rc != 0)
{
perror("error setting flowcontrol: ");
exit(-1);
}
rc = close(fd);
if (rc != 0)
{
perror("error closing fd: ");
exit(-1);
}
...

How to open serial port in linux without changing any pin?

Posix requires changing RTS pin on port opening. I want a way to avoid it.
I have no idea why you'd want to do this, but this can be done pretty easily by modifying the linux kernel driver for your serial console so it doesn't toggle RTS. For example, for the 8250-series driver in drivers/tty/serial/8250/ you could change every write to the MCR register (UART_MCR) to ensure that bit 1 (mask is UART_MCR_RTS) is never set.
Since it's abstracted away in userspace, you're out of luck if you want to do this without modifying the kernel driver.
Having the same problem, I'd give it a try by patching the ftdi_sio kernel driver. You just need to uncomment a small piece of code in ftdi_dtr_rts() like this:
static void ftdi_dtr_rts(struct usb_serial_port *port, int on) {
...
/* drop RTS and DTR */
if (on)
set_mctrl(port, TIOCM_DTR /*| TIOCM_RTS*/); // <<-- HERE
else
clear_mctrl(port, TIOCM_DTR /*| TIOCM_RTS*/); // <<-- and HERE
}
and the RTS handshake line is not longer changed upon open() call.
Note, that the uart than might not longer working with RTS/CTS hardware handshake, as long as your modified kernel driver is loaded. But you can still control the state of the RTS handshake line manually by calling e.g.:
int opins = TIOCM_RTS;
ioctl(tty_fd, TIOCMBIC, &opins);
I'd tested this with the Ctrl+A+G command of picocom 2.3a, running Kubuntu 16.04 64 bit and Ftdi FT2232H based usb uart adapter.
You might find more details on this topic here.
A change in the DTR pin can be (eventually) avoided using the command line
stty -F /dev/ttyUSB0 -hupcl
This has the effect of making DTR turn on; and subsequently when the port is opened and closed, DTR is not affected.
Source: https://raspberrypi.stackexchange.com/questions/9695/disable-dtr-on-ttyusb0/27706#27706
And there is code there to do the same thing from python via termios, this can be done before opening the port via pyserial:
import termios
path = '/dev/ttyACM0'
# Disable reset after hangup
with open(path) as f:
attrs = termios.tcgetattr(f)
attrs[2] = attrs[2] & ~termios.HUPCL
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
The OP was running this on a Raspberry Pi, but I just tried it on Linux Mint on x86_64, it worked. I don't know how RTS is affected.
The reason I find this useful, is for communication with an Arduino Nano - which has a USB-> serial chip on board - and normally the Arduino gets reset every time you open the serial port from linux (rising edge of DTR causes reset). For some applications, this is not a problem, but it's clearly useful to avoid this for other applications, and it's not so easy to remove that tiny capacitor from the Arduino which connects DTR to reset.
You will still get a single reset when the stty command is executed (after plugging in the USB cable). But at least you can then keep opening and closing the serial port after that without further resets.
calling fopen("/dev/ACM0", "r") doesn't require you do do anything:) You may not receive the data you expect though.

Resources