OpenBSD serial I/O: -lpthead makes read() block forever, even with termios VTIME set? - serial-port

I have an FTDI USB serial device which I use via the termios serial API. I set up the port so that it will time-out on read() calls in half a second (by using the VTIME parameter), and this works on Linux as well as on FreeBSD. On OpenBSD 5.1, however, the read() call simply blocks forever when no data is available (see below.) I would expect read() to return 0 after 500ms.
Can anyone think of a reason that the termios API would behave differently under OpenBSD, at least with respect to the timeout feature?
EDIT: The no-timeout problem is caused by linking against pthread. Regardless of whether I'm actually using any pthreads, mutexes, etc., simply linking against that library causes read() to block forever instead of timing out based on the VTIME setting. Again, this problem only manifests on OpenBSD -- Linux and FreeBSD work as expected.
if ((sd = open(devPath, O_RDWR | O_NOCTTY)) >= 0)
{
struct termios newtio;
char input;
memset(&newtio, 0, sizeof(newtio));
// set options, including non-canonical mode
newtio.c_cflag = (CREAD | CS8 | CLOCAL);
newtio.c_lflag = 0;
// when waiting for responses, wait until we haven't received
// any characters for 0.5 seconds before timing out
newtio.c_cc[VTIME] = 5;
newtio.c_cc[VMIN] = 0;
// set the input and output baud rates to 7812
cfsetispeed(&newtio, 7812);
cfsetospeed(&newtio, 7812);
if ((tcflush(sd, TCIFLUSH) == 0) &&
(tcsetattr(sd, TCSANOW, &newtio) == 0))
{
read(sd, &input, 1); // even though VTIME is set on the device,
// this read() will block forever when no
// character is available in the Rx buffer
}
}

from the termios manpage:
Another dependency is whether the O_NONBLOCK flag is set by open() or
fcntl(). If the O_NONBLOCK flag is clear, then the read request is
blocked until data is available or a signal has been received. If the
O_NONBLOCK flag is set, then the read request is completed, without
blocking, in one of three ways:
1. If there is enough data available to satisfy the entire
request, and the read completes successfully the number of
bytes read is returned.
2. If there is not enough data available to satisfy the entire
request, and the read completes successfully, having read as
much data as possible, the number of bytes read is returned.
3. If there is no data available, the read returns -1, with errno
set to EAGAIN.
can you check if this is the case?
cheers.
Edit: OP traced back the problem to a linking with pthreads that caused the read function to block. By upgrading to OpenBSD >5.2 this issue was resolved by the change to the new rthreads implementation as the default threading library on openbsd. more info on guenther# EuroBSD2012 slides

Related

HC-SR04P reading errors

In my project I need to measure distances up to 3-4m, so I am using a HC-SR04P sensor hooked up to an ESP32 dev board.
The code is written without any third-party library (was inspired by a very simple HC-SR04 arduino library, though), in plain C, within a project created from the ESP32 eclipse IDF plugin; no extra libraries or arduino code; just the RTOS.
Everything works fine when the device boots and measurements are pretty accurate, but after a while (can't say exactly what triggers this), the sensor/devboard circuit (can't say which) starts behaving strangely : after the TRIG pulse, the ECHO pin does not go HIGH within a reasonable 1s timeout, and no measurement is performed.
Once this happens, no new measurement is performed again unless reboot/power on; it looks like something happens and somehow there is a faulty state either for the sensor or within the communication code.
A couple of observations :
sensor is the right version to be powered at 3.3V.
HC-SR04P uses GPIO2 and GPIO4 for TRIG and ECHO.
measurements are not required to be frequent, hence the 30s timer for the measurement task.
at power on, everything works fine.
after reset by dev board micro-switch, everything works correctly again.
when timeout occurs, re-init the sensor (settings up GPIOs, etc.), but nothing happens; still timeouts.
For reference, the timing function is below (the HCSR04_Info struct holds only pin and measurement data); it is called from a timed task every 30s.
uint32_t hcsr04_timing(HCSR04_Info* pDevice)
{
// TRIG pulse for 10ms
gpio_set_level(pDevice->trig, 1);
ets_delay_us(10);
gpio_set_level(pDevice->trig, 0);
pDevice->startMicros = esp_timer_get_time();
// wait for the echo pin HIGH or timeout
while ((!gpio_get_level(pDevice->echo)) && (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout);
if (!gpio_get_level(pDevice->echo)) {
pDevice->status = STATUS_OFFLINE;
ESP_LOGE(TAG, "hcsr04_timing timeout (1)");
return 0;
}
pDevice->startMicros = esp_timer_get_time();
// wait for the echo pin LOW or timeout
while ((gpio_get_level(pDevice->echo)) && (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout);
if (gpio_get_level(pDevice->echo)) {
pDevice->status = STATUS_OFFLINE;
ESP_LOGE(TAG, "hcsr04_timing timeout (2)");
return 0;
}
pDevice->status = STATUS_ONLINE;
pDevice->endMicros = esp_timer_get_time();
return pDevice->endMicros - pDevice->startMicros;
}
Any help is appreciated. Thank you.
This does not generate a pulse of 10 ms; it's 10 us. Probably takes your device into an undetermined state eventually.
// TRIG pulse for 10ms
gpio_set_level(pDevice->trig, 1);
ets_delay_us(10);
gpio_set_level(pDevice->trig, 0);
The comment in the header file where ets_delay_us() is defined says: In FreeRTOS task, please call FreeRTOS apis.
Anyway, use delay(10) if in Arduino-land; or vTaskDelay(pdMS_TO_TICKS(10)) if in FreeRTOS-land.
Following up on campescassiano suggestions on overflow, the solution finally presented itself. Not really an overflow in the exact sense of the problem, but closely related.
It's finally a stupid bug in the code, so please close or delete the question if appropriate.
The problem was that pDevice->startMicros was defined as an uint32_t (probably because of a copy/paste or bad habit error), while esp_timer_get_time() returns microseconds as an uint64_t.
So it 'overflows' at about 1h 11m 34s (which is about 232 microseconds) after boot, and timeout calculations become off since (esp_timer_get_time() - pDevice->startMicros) will obviously be an uint64_t.
Because of that (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout will always be false after 1h 11m 34s, so the loop breaks before getting an ECHO input.

Sim800L lag/delay before incoming calls are visible to arduino

I use SIM800L GSM module to detect incoming calls and generally it works fine. The only problem is that sometimes it takes up to 8 RINGS before the GSM module tells arduino that someone is calling (before RING appears on the serial connection). It looks like a GSM Network congestion but I do not have such issues with normal calls (I mean calls between people). It happens to often - so it cannot be network/Provider overload. Does anybody else had such a problem?
ISP/Provider: Plus GSM in Poland
I don't put any code, because the problem is in different layer I think
sorry that I didn't answer earlier. I've tested it and it turned out that in bare minimum code it worked OK! I mean, I can see 'RING' on the serial monitor immediately after dialing the number. So it's not a hardware issue!
//bare minimum code:
void loop() {
if(serialSIM800.available()){
Serial.write(serialSIM800.read());
}
if(Serial.available()){
serialSIM800.write(Serial.read());
}
}
In my real code I need to compare calling number with the trusted list. To do that I saved all trusted numbers in the contact list on the sim card (with the common prefix name 'mytrusted'). So, in the main loop there's if statement:
while(mySerial.available()){
incomingByte = mySerial.read();
inputString += incomingByte;
}
if (inputString.indexOf("mytrusted") > 0){
isTrusted = 1;
Serial.println("A TRUSTED NUMBER IS CALLING");
}
After adding this "if condition" Arduino sometimes recognize trusted number after 1'st call, and sometimes after 4'th or 5'th. I'm not suspecting the if statement itself , but the preceding while loop, where incoming bytes are combined into one string.
Any ideas, what can be improved in this simply code?
It seems, I found workaround for my problem. I just send a simple 'AT' command every 20 seconds to SIM800L (it replies with 'OK' ). I use timer to count this 20 seconds interval (instead of simply delay function)
TimerObject *timer2 = new TimerObject(20000); //AT command interval
....
timer2->setOnTimer(&SendATCMD);
....
void SendATCMD () {
mySerial.println("AT");
timer2->Stop();
timer2->Start();
}
With this simple modification Arduino always sees incoming call immediately (after 1 ring)

Understanding UNIX termios VMIN and VTIME

I am currently working on a simple serial interface on a UNIX based device and cant find a definitive answer to the following:
I am currently trying to determine if a 'pure time read' (VMIN = 0, VTIME >0) will return half way through reading to n_bytes, as the timer is started when read is called, not when the first character is received.
For example, if I send a message to the device on the other end of the serial interface and I want a response I'd attempt the following (pseudo code):
m_tty.c_cc[VMIN] = 0;
m_tty.c_cc[VTIME] = 5; //i.e. > 0
write(myFileHandle, myData, sizeof(myData));
usleep(sizeof(myData) * 100); //assuming 100 us per char to Tx.
read(myFileHandle, myRxData, expectedMinNumBytes);
I am unclear as to whether read() would return if the first byte arrived just as the timer was about to expire, or if it would continue until 'expectedMinNumBytes' once the first is received?
Thanks for the help in advance!
This is a pure timed read. If there is available data, the read is immediately satisfied. If there is no data, the timer is started at the time read is called, and the read returns: either because the timer expires (returns 0) or a single byte is available.

Reading a long text from GPRS Shield with Arduino

I am having hell with this and I know it is probably really simple. I am trying to read a text message from my Seeed GPRS shield. I have the shield setup as a software serial and I am displaying the information received from the GPRS to the serial monitor. I am currently sending all AT commands over serial while I work on my code. To display the data from the software serial to the serial monitor, I am using the following code.
while(GPRS.available()!=0) {
Serial.write(GPRS.read());
}
GPRS is my software serial obviously. The problem is, the text is long and I only get a few characters from it. Something like this.
+CMGR: "REC READ","1511","","13/12/09,14:34:54-24" Welcome to TM eos8
This text is a "Welcome to T-Mobile" text that is much longer. The last few characters shown are scrambled. I have done some research and have seen that I can mod the serial buffer size to 256 instead of the default 64. I want to avoid this because I am sure there is an easier way. Any ideas?
Have you tried reading into a character array, one byte at a time? See if this helps:
if (GPRS.available()) { // GPRS talking ..
while(GPRS.available()) { // As long as it is talking ..
buffer[count++]=GPRS.read();     
// read char into array
if(count == 64) break; // Enough said!
}
Serial.write(buffer,count); // Display in Terminal
clearBufferArray();
count = 0;
}
You need to declare the variables 'buffer' and 'count' appropriately and define the function 'clearBufferArray()'
Let me know if this helps.
Looks like this is simply the result of the lack of flow control in all Arduino serial connections. If you cannot pace your GPRS() input byte sequence to a rate that guarantees the input FIFO can't overflow, then your Serial.write() will block when the output FIFO fills. At that point you will be dropping new GPRS input bytes on the floor until Serial output frees up more space.
Since the captured output is apparently clean up to about 64 bytes, this suggests
a) a 64 byte buffer,
b) a GPRS data rate much higher than the Serial one, and
c) that the garbage data is actually the occasional valid byte from later in the sequence.
You might confirm this by testing the return code from Serial.write. If you get back zero, that byte is getting lost.
If you were using 9600 for Serial and 57600 for GPRS, I would expect somewhat more than 64 bytes to come through before the output gets mangled, but if the GPRS rate is more than 64x the Serial rate, the entire output FIFO could fill up within a single output byte transmission time.
Capturing to an intermediate buffer should resolve your issue, as long as it is large enough for the whole message. Similarly, extending the size of either the source (in conjunction with testing the Serial.write) or destination (without any additional code) FIFOs to the maximum datagram size should work.
I've had the same problem trying to read messages and get 64 characters. I overcame it by adding a "delay(10)" in the loop calling the function that does the read from the GPRS. Seems to be enough to overcome the race scenario. - Using Arduino Mega.
void loop() {
ReadmyGPRS();
delay(10); //A race condition exists to get the data.
}
void ReadmyGPRS(){
if (Serial1.available()){ // if data is comming from GPRS serial port
count = 0; // reset counter
while(Serial1.available()) // reading data into char array
{
buffer[count++]=Serial1.read(); // writing data into array
if(count == 160)break;
}
Serial.write(buffer,count);
}
}

Simple algorithm for reliable communications

So, I have worked on large systems in the past, like an iso stack session layer, and something like that is too big for what I need, but I do have some understanding of the big picture. What I have now is a serial point to point communications link, where some component is dropping data (often).
So I am going to have to write my own, reliable delivery system using it for transport. Can someone point me in the directions for basic algorithms, or even give a clue as to what they are called? I tried a Google, but end up with post graduate theories on genetic algorithms and such. I need the basics. e.g. 10-20 lines of pure C.
XMODEM. It's old, it's bad, but it is widely supported both in hardware and in software, with libraries available for literally every language and market niche.
HDLC - High-Level Data Link Control. It's the protocol which has fathered lots of reliable protocols over the last 3 decades, including the TCP/IP. You can't use it directly, but it is a template how to develop your own protocol. Basic premise is:
every data byte (or packet) is numbered
both sides of communication maintain locally two numbers: last received and last sent
every packet contains the copy of two number
every successful transmission is confirmed by sending back an empty (or not) packet with the updated numbers
if transmission is not confirmed within some timeout, send again.
For special handling (synchronization) add flags to the packet (often only one bit is sufficient, to tell that the packet is special and use). And do not forget the CRC.
Neither of the protocols has any kind of session support. But you can introduce one by simply adding another layer - a simple state machine and a timer:
session starts with a special packet
there should be at least one (potentially empty) packet within specified timeout
if this side hasn't sent a packet within the timeout/2, send an empty packet
if there was no packet seen from the other side of communication within the timeout, the session has been termianted
one can use another special packet for graceful session termination
That is as simple as session control can get.
There are (IMO) two aspects to this question.
Firstly, if data is being dropped then I'd look at resolving the hardware issues first, as otherwise you'll have GIGO
As for the comms protocols, your post suggests a fairly trivial system? Are you wanting to validate data (parity, sumcheck?) or are you trying to include error correction?
If validation is all that is required, I've got reliable systems running using RS232 and CRC8 sumchecks - in which case this StackOverflow page probably helps
If some components are droping data in a serial point to point link, there must exist some bugs in your code.
Firstly, you should comfirm that there is no problem in the physical layer's communication
Secondly, you need some konwledge about data communication theroy such like ARQ(automatic request retransmission)
Further thoughts, after considering your response to the first two answers... this does indicate hardware problems, and no amount of clever code is going to fix that.
I suggest you get an oscilloscope onto the link, which should help to determine where the fault lies. In particular look at the baud rate of the two sides (Tx, Rx) to ensure that they are within spec... auto-baud is often a problem?!
But look to see if drop out is regular, or can be sync-ed with any other activity.
on the sending side;
///////////////////////////////////////// XBee logging
void dataLog(int idx, int t, float f)
{
ubyte stx[2] = { 0x10, 0x02 };
ubyte etx[2] = { 0x10, 0x03 };
nxtWriteRawHS(stx, 2, 1);
wait1Msec(1);
nxtWriteRawHS(idx, 2, 1);
wait1Msec(1);
nxtWriteRawHS(t, 2, 1);
wait1Msec(1);
nxtWriteRawHS(f, 4, 1);
wait1Msec(1);
nxtWriteRawHS(etx, 2, 1);
wait1Msec(1);
}
on the receiving side
void XBeeMonitorTask()
{
int[] lastTick = Enumerable.Repeat<int>(int.MaxValue, 10).ToArray();
int[] wrapCounter = new int[10];
while (!XBeeMonitorEnd)
{
if (XBee != null && XBee.BytesToRead >= expectedMessageSize)
{
// read a data element, parse, add it to collection, see above for message format
if (XBee.BaseStream.Read(XBeeIncoming, 0, expectedMessageSize) != expectedMessageSize)
throw new InvalidProgramException();
//System.Diagnostics.Trace.WriteLine(BitConverter.ToString(XBeeIncoming, 0, expectedMessageSize));
if ((XBeeIncoming[0] != 0x10 && XBeeIncoming[1] != 0x02) || // dle stx
(XBeeIncoming[10] != 0x10 && XBeeIncoming[11] != 0x03)) // dle etx
{
System.Diagnostics.Trace.WriteLine("recover sync");
while (true)
{
int b = XBee.BaseStream.ReadByte();
if (b == 0x10)
{
int c = XBee.BaseStream.ReadByte();
if (c == 0x03)
break; // realigned (maybe)
}
}
continue; // resume at loop start
}
UInt16 idx = BitConverter.ToUInt16(XBeeIncoming, 2);
UInt16 tick = BitConverter.ToUInt16(XBeeIncoming, 4);
Single val = BitConverter.ToSingle(XBeeIncoming, 6);
if (tick < lastTick[idx])
wrapCounter[idx]++;
lastTick[idx] = tick;
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => DataAdd(idx, tick * wrapCounter[idx], val)));
}
Thread.Sleep(2); // surely we can up with the NXT
}
}

Resources