Linux termios VTIME not working? - linux

We've been bashing our heads off of this one all morning. We've got some serial lines setup between an embedded linux device and an Ubuntu box. Our reads are getting screwed up because our code usually returns two (sometimes more, sometimes exactly one) message reads instead of one message read per actual message sent.
Here is the code that opens the serial port. InterCharTime is set to 4.
void COMClass::openPort()
{
struct termios tio;
this->fd = -1;
int tmpFD;
tempFD = open( port, O_RDWR | O_NOCTTY);
if (tempFD < 0)
{
cerr<< "the port is not opened"<< port <<"\n";
portOpen = 0;
return;
}
tio.c_cflag = BaudRate | CS8 | CLOCAL | CREAD ;
tio.c_oflag = 0;
tio.c_iflag = IGNPAR;
newtio.c_cc[VTIME] = InterCharTime;
newtio.c_cc[VMIN] = readBufferSize;
newtio.c_lflag = 0;
tcflush(tempFD, TCIFLUSH);
tcsetattr(tempFD,TCSANOW,&tio);
this->fd = tempFD;
portOpen = true;
}
The other end is configured similarly for communication, and has one small section of particular iterest:
while (1)
{
sprintf(out, "\r\nHello world %lu", ++ulCount);
puts(out);
WritePort((BYTE *)out, strlen(out)+1);
sleep(2);
} //while
Now, when I run a read thread on the receiving machine, "hello world" is usually broken up over a couple messages. Here is some sample output:
1: Hello
2: world 1
3: Hello
4: world 2
5: Hello
6: world 3
where number followed by a colon is one message recieved. Can you see any error we are making?
Thank you.
Edit:
For clarity, please view section 3.2 of the Linux Serial Programming HOWTO. To my understanding, with a VTIME of a couple seconds (meaning vtime is set anywhere between 10 and 50, trial-and-error), and a VMIN of 1, there should be no reason that the message is broken up over two separate messages.

I don't see why you are surprised.
You are asking for at least one byte. If your read() is asking for more, which seems probable since you are surprised you aren't getting the whole string in a single read, it can get whatever data is available up to the read() size. But all the data isn't available in a single read so your string is chopped up between reads.
In this scenario the timer doesn't really matter. The timer won't be set until at least one byte is available. But you have set the minimum at 1. So it just returns whatever number of bytes ( >= 1) are available up to read() size bytes.

If you are still experiencing this problem (realizing the question is old), and your code is accurate, you are setting your VTIME and VMIN in the newtio struct, and the rest of the other parameters in the tio struct.

Related

Controlling TI OMAP l138 frequency leads to "Division by zero in kernel"

My team is trying to control the frequency of an Texas Instruments OMAP l138. The default frequency is 300 MHz and we want to put it to 372 MHz in a "complete" form: we would like not only to change the default value to the desired one (or at least configure it at startup), but also be capable of changing the value at run time.
Searching on the web about how to do this, we found an article which tells that one of the ways to do this is by an "echo" command:
echo 372000 /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
We did some tests with this command and it runs fine with one problem: sometimes the first call to this echo command leads to a error message of "Division by zero in kernel":
In my personal tests, this error appeared always in the first call to the echo command. All the later calls worked without error. If, then, I reset my processor and calls the command again, the same problem occurs: the first call leads to this error and later calls work without problem.
So my questions are: what is causing this problem? And how could I solve it? (Obviously the answer "always type it twice" doesn't count!)
(Feel free to mention other ways of controlling the OMAP l138's frequency at real time as well!)
Looks to me like you have division by zero in davinci_spi_cpufreq_transition() function. Somewhere in this function (or in some function that's being called in davinci_spi_cpufreq_transition) there is a buggy division operation which tries to divide by some variable which is (in your case) has value of 0. And this is obviously error case which should be handled properly in code, but in fact it isn't.
It's hard to tell which code exactly leads to this, because I don't know which kernel you are using. It would be much more easier if you can provide link to your kernel repository. Although I couldn't find davinci_spi_cpufreq_transition in upstream kernel, I found it here.
davinci_spi_cpufreq_transition() function appears to be in drivers/spi/davinci_spi.c. It calls davinci_spi_calc_clk_div() function. There are 2 division operations there. First is:
prescale = ((clk_rate / hz) - 1);
And second is:
if (hz < (clk_rate / (prescale + 1)))
One of them is probably causing "division by zero" error. I propose you to trace which one is that by modifying davinci_spi_calc_clk_div() function in next way (just add lines marked as "+"):
static void davinci_spi_calc_clk_div(struct davinci_spi *davinci_spi)
{
struct davinci_spi_platform_data *pdata;
unsigned long clk_rate;
u32 hz, cs_num, prescale;
pdata = davinci_spi->pdata;
cs_num = davinci_spi->cs_num;
hz = davinci_spi->speed;
clk_rate = clk_get_rate(davinci_spi->clk);
+ printk(KERN_ERR "### hz = %u\n", hz);
prescale = ((clk_rate / hz) - 1);
if (prescale > 0xff)
prescale = 0xff;
+ printk("### prescale + 1 = %u\n", prescale + 1UL);
if (hz < (clk_rate / (prescale + 1)))
prescale++;
if (prescale < 2) {
pr_info("davinci SPI controller min. prescale value is 2\n");
prescale = 2;
}
clear_fmt_bits(davinci_spi->base, 0x0000ff00, cs_num);
set_fmt_bits(davinci_spi->base, prescale << 8, cs_num);
}
My guess -- it's "hz" variable which is 0 in your case. If it's so, you also may want to add next debug line to davinci_spi_setup_transfer() function:
if (!hz)
hz = spi->max_speed_hz;
+ printk(KERN_ERR "### setup_transfer: setting speed to %u\n", hz);
davinci_spi->speed = hz;
davinci_spi->cs_num = spi->chip_select;
With all those modifications made, rebuild your kernel and you will probably get the clue why you have that "div by zero" error. Just look for lines started with "###" in your kernel boot log. In case you don't know what to do next -- attach those debug lines and I will try to help you.

Bluetooth data shown as 0X80 instead of 0X00

I have been using Bluetooth module (HC-05) with Atmega8(both A and L) microcontroller to transmit data to my Android device. In following code an 8-bit signed(or unsigned doesn't made any change) value is sent over bluetooth to be displayed on device, this value starts at 0X00 and is incremented in every iteration:
#define F_CPU 1000000
#define BAUD 9600
#define MYUBRR (F_CPU/16/BAUD-1)
#include <avr/io.h>
#include <util/delay.h>
int main (void)
{
uint8_t data = 0;
UBRRH = (MYUBRR >> 8); // setting higher bits of UBRR
UBRRL = MYUBRR; // setting lower bit of UBRR
UCSRB = (1 << TXEN); // transmit enable
UCSRC = ((1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0)); //URSEL=USART reg selection (R/W), UCSZ1 & UCSZ0 set equal to 011 that is 8 bit data size
while (1)
{
UDR=data; // loading data in USART Data register (8-bit) and it will be transmitted immidiately
while(!(UCSRA&(1<<UDRE))); // waiting till complete data sent and UDRE flag set
_delay_ms(200); // after some time
data++; // incrementing data
}
return 0;
}
On the android device end there is "Bluetooth spp Pro" app to display the recieved data on screen.
Following is the configuration of recieve mode (Data is displayed as Hex values):
The data recieved here should start at 0X00 and go up to 0XFF instead it starts at 0X80 and increments upto 0XFF in a very unfamiliar manner.
Referring above image. The pattern I observed here is that the tens place digit starts at 8 and units place change from 0 to F then in next loop again it becomes 9 and unit place change from 0 to F after that instead of incrementing (expected) tens place again goes to 8 and then in next cycle it again becomes 9, after these four cycles of two repetetive words tens place increments to A and units place change from 0 to F and later the strange tens place pattern reappears for A and B then for C and D and later for E and F at tens place.
So my concern is:
Why is the device showing 80 for 00, as it is correctly working for ones place why is it not working for tens place as expected???
Thanks!!!
Edit:
This problem is neither Android version nor device manufacturer specific.
Problem was with voltage levels. Operating the microcontroller circuit on 3.2V and Bluetooth module on 3.8V solved the problem and data is transmitted as expected. However I am unable to predict an explanation for this.
Please help.
It is observed clearly on varying the potentiometer of voltage regulator, when I keep it below 3.20V data is transmitted smooth, and as the voltage level crosses 3.20V the tens place of data starts getting corrupted up to the point of complete data corruption and output becomes constant data 0XFE at 3.8V.

Linux Serial Port Blocked using termios.h configuration

I'm writing an embedded Linux application that (1) opens a serial connection to another device, (2) sends a known command, (3) checks port for incoming characters (response) until expected response phrase or character is detected, (4) repeats step 2 and 3 until a series of commands are sent and responses received, (5) then closes the port.
My app would go through some cycles of the above sequence and every now and then it would be waiting for a response (reading) when all of a sudden the communication stops and my software faults out because of my built-in timeout logic.
Is there anything in my port configuration that would cause the port to be blocked due to specific byte sent (possibly due to electrical noise)?
Here is how I'm opening my ports (showing configurations via termios.h):
struct termios options;
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1) {
debug() << "Port open failed!"
return FAIL;
}
debug() << "Port Opened Successful"
fcntl(fd, F_SETFL, 0); // This setting interacts with VMIN and VTIME below
// Get options
tcgetattr(fd, &options);
// Adjust Com port options
options.c_cflag |= (CLOCAL | CREAD); // Program will not "own" port, enable reading on port
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Sets RAW input mode (does not treat input as a line of text with CR/LF ending)
options.c_oflag &= ~ OPOST; // Sets RAW ouput mode (avoids newline mapping to CR+LF characters)
options.c_iflag &= ~(IXON | IXOFF | IXANY); // Turns off SW flow c
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
// Set options
tcsetattr(fd, TCSANOW, &options);
//return fd;
return SUCCEED;
I can't figure out why the communication all of a sudden just freezes up and then goes away when I cycle power to my device. Thanks all!
More info - here are my read and write functions:
int Comm::Receive(unsigned char* rBuf)
{
int bytes;
ioctl(fd, FIONREAD, &bytes);
if (bytes >= 1)
{
bytes = read(fd, rBuf, 1);
if (bytes < 0)
return READ_ERR;
return SUCCEED;
}
else
return NO_DATA_AVAILABLE;
}
int Comm::Send(int xCt, unsigned char* xBuf)
{
int bytes;
if (fd == -1)
return FAIL;
bytes = write(fd, xBuf, xCt);
if (bytes != xCt)
return FAIL;
else
return SUCCEED;
}
Welcome to the joys of serial ports...
Thought 1: wrap your read calls with a select ()
Thought 2: Unset the ICANON flag in tcsetattr, and set a VTIME attribute for a deliberate timeout (and then, obviously, handle it)
Thought 3: Nothing about serial comms ever works perfectly.
I also had a similar problem with sending command to devices and reading responses from the device. Please refer to below SOF post and the answer this was working for my problem.
In these cases, We have to care about the protocol which we are going to use for device communication (send and receive). If we can send commands successfully and we didn't receive a response with a noise from device implies there is something wrong in the data packet which was sent to the device. First of all check the protocol specification first and create a byte array for a simple command (like make a beep sound) and send it.
Send data to a barcode scanner over RS232 serial port
I can do something for you If you can post your complete source code with the output.
Enjoy the code. Thanks.

recv with flags MSG_DONTWAIT | MSG_PEEK on TCP socket

I have a TCP stream connection used to exchange messages. This is inside Linux kernel. The consumer thread keeps processing incoming messages. After consuming one message, I want to check if there are more pending messages; in which case I would process them too. My code to achieve this looks like below. krecv is wrapper for sock_recvmsg(), passing value of flags without modification (krecv from ksocket kernel module)
With MSG_DONTWAIT, I am expecting it should not block, but apparently it blocks. With MSG_PEEK, if there is no data to be read, it should just return zero. Is this understanding correct ? Is there a better way to achieve what I need here ? I am guessing this should be a common requirement as message passing across nodes is used frequently.
int recvd = 0;
do {
recvd += krecv(*sockp, (uchar*)msg + recvd, sizeof(my_msg) - recvd, 0);
printk("recvd = %d / %lu\n", recvd, sizeof(my_msg));
} while(recvd < sizeof(my_msg));
BUG_ON(recvd != sizeof(my_msg));
/* For some reason, below line _blocks_ even with no blocking flags */
recvd = krecv(*sockp, (uchar*)tempbuf, sizeof(tempbuf), MSG_PEEK | MSG_DONTWAIT);
if (recvd) {
printk("more data waiting to be read");
more_to_process = true;
} else {
printk("NO more data waiting to be read");
}
You might check buffer's length first :
int bytesAv = 0;
ioctl(m_Socket,FIONREAD,&bytesAv); //m_Socket is the socket client's fd
If there are data in it , then recv with MSG_PEEK should not be blocked ,
If there are no data at all , then no need to MSG_PEEK ,
that might be what you like to do .
This is a very-very old question, but
1. problem persits
2. I faced with it.
At least for me (Ubuntu 19.04 with python 2.7) this MSG_DONTWAIT has no effect, however if I set the timeout to zero (with settimeout function), it works nicely.
This can be done in c with setsockopt function.

How to read from a Linux serial port

I am working on robot which has to control using wireless serial communication. The robot is running on a microcontroller (by burning a .hex file). I want to control it using my Linux (Ubuntu) PC. I am new to serial port programming. I am able to send the data, but I am not able to read data.
A few piece of code which is running over at the microcontroller:
Function to send data:
void TxData(unsigned char tx_data)
{
SBUF = tx_data; // Transmit data that is passed to this function
while(TI == 0) // Wait while data is being transmitted
;
}
I am sending data through an array of characters data_array[i]:
for (i=4; i<=6; i++)
{
TxData(data_array[i]);
RI = 0; // Clear receive interrupt. Must be cleared by the user.
TI = 0; // Clear transmit interrupt. Must be cleared by the user.
}
Now the piece of code from the C program running on Linux...
while (flag == 0) {
int res = read(fd, buf, 255);
buf[res] = 0; /* Set end of string, so we can printf */
printf(":%s:%d\n", buf, res);
if (buf[0] == '\0')
flag = 1;
}
It prints out value of res = 0.
Actually I want to read data character-by-character to perform calculations and take further decision. Is there another way of doing this?
Note: Is there good study material (code) for serial port programming on Linux?
How can I read from the Linux serial port...
This is a good guide: Serial Programming Guide for POSIX Operating Systems
The read call may return with no data and errno set to EAGAIN. You need to check the return value and loop around to read again if you're expecting data to arrive.
First, take a look at /proc/tty/driver/serial to see that everything is set up correctly (i.e., you see the signals you should see). Then, have a look at the manual page for termios(3), you may be interested in the VMIN and VTIME explanation.

Resources