Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

StantonC

macrumors newbie
Original poster
Jun 24, 2013
5
0
I'm writing a program in Xcode that will both read and write to a serial port device (Arduino Microcontroller). I know how to do this on a windows computer, but I'm not getting the same results from Xcode. Here is my Code:

Code:
#include <iostream>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>

using namespace std;

int main(int argc, const char * argv[]) {
    cout << "program started" << endl;
    int fd;
    fd = open("/dev/tty.usbmodem1421", O_RDWR | O_NOCTTY | O_NDELAY);
    
    if (fd == -1) cout << "Error Opening Port" << endl;
    else cout << "fd: " << fd << endl;
    
    struct termios options;
    tcgetattr(fd,&options);
    cfsetispeed(&options,B115200);
    cfsetospeed(&options,B115200);
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    tcsetattr(fd,TCSANOW,&options);
    
    char *outToArduino = new char[255];
    char *inFromArduino = new char[255];
    
    do {
        cout << "\nNew output Val: "; cin >> outToArduino;
        cout << "Out: " << outToArduino << "\t";
        write(fd, outToArduino, 1);
        // Arduino Echos back the same character
        //          that was sent to it.
        read(fd, inFromArduino, 1);
        cout << "In: " << inFromArduino << endl;
        
    } while (outToArduino[0] != 'x');
    
    cout << "program terminated" << endl;
    close(fd);
    
    return 0;
}

I am successfully able to send a character at a time to my Arduino. The problem is in reading the echo that is sent back to the computer. I think the problem is that in the time it takes for the character to get to the Arduino, get processed and sent back, the computer has already attempted to read what is on the serial port. Here is an example of my output:

****************************
program started
fd: 3

New output Val: d
Out: d In:

New output Val: d
Out: d In: d

New output Val: f
Out: f In: d

New output Val: f
Out: f In: f

New output Val: x
Out: x In: f
program terminated
********************************

Any help I can get would be appreciated,
Stanton
 

chown33

Moderator
Staff member
Aug 9, 2009
10,706
8,346
A sea of green
From fcntl.h:
Code:
/*
 * The O_* flags used to have only F* names, which were used in the kernel
 * and by fcntl.  We retain the F* names for the kernel f_flags field
 * and for backward compatibility for fcntl.
 */
#ifndef _POSIX_C_SOURCE
#define	FAPPEND		O_APPEND	/* kernel/compat */
#define	FASYNC		O_ASYNC		/* kernel/compat */
#define	FFSYNC		O_FSYNC		/* kernel */
#define	FNONBLOCK	O_NONBLOCK	/* kernel */
#define	FNDELAY		O_NONBLOCK	/* compat */
[COLOR="Red"]#define	O_NDELAY	O_NONBLOCK	/* compat */
[/COLOR]#endif
See the online man page for open(2) to learn what O_NONBLOCK does:
O_NONBLOCK do not block on open or for data to become available
Man pages are also available in Xcode's docs, and via the 'man' command in Terminal.


Did you intend to have non-blocking reads? Because that's what you're telling open() you want by giving it the O_NDELAY flag.

Do you know what a non-blocking read is? If so, is that what you'd ask for on Windows?

Did you write this code yourself after some research, or did you just copy an example with O_NDELAY from somewhere without understanding what it does? If copied, where did you copy it from?

What version of Xcode? Of OS X?

Those aren't just rhetorical questions, nor are they intended to make you feel stupid. No one here knows your programming experience, what languages you know, what programs you've written, etc.

http://www.mikeash.com/getting_answers.html
 

StantonC

macrumors newbie
Original poster
Jun 24, 2013
5
0
This is my first time posting to a forum like this, so my apologies for forgetting to post my experience level and such.

I'm using Xcode 4.6.3 and OS X 10.8.4.

No I don't know exactly what a "non-blocking" read is. I found some example programs on the web (and thats were I copied the open function from as well as the options.c_cflag stuff from) and it worked fine for outputting characters to the serial port, but didn't quite work for receiving characters from the serial port as I had intended.

As for my experience level, I know just the basics for C++ programming.

So basically what I'm looking for is when I call the read function, my program will wait until there are values available on the serial port.

Hope this clears things up a little.
Stanton
 

chown33

Moderator
Staff member
Aug 9, 2009
10,706
8,346
A sea of green
I found some example programs on the web ...

And the URL is ...?

Please read and follow the suggestions given in the "Getting Answers" link I posted.

Also please read the complete man page linked to, especially the part that explains the O_NONBLOCK flag. The fragment I quoted was not the full description.
 

StantonC

macrumors newbie
Original poster
Jun 24, 2013
5
0
And the URL is ...?
https://discussions.apple.com/thread/3056251?start=0&tstart=0

In the response that solved the persons question, the guy (xnav) supplied a download to his project in the windowController.m file. If you look in the function "(IBAction)ttyPicked: (id)sender", this is where I found the method for opening the serial port.

Also please read the complete man page linked to, especially the part that explains the O_NONBLOCK flag. The fragment I quoted was not the full description.

It would appear that O_NONBLOCK is not the thing I want. Some of the things mentioned in the manual are a little hard for me to understand... Is something like a "lock" what I'm trying to do? like flock(2), O_SHLOCK, or O_EXLOCK.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,706
8,346
A sea of green
It would appear that O_NONBLOCK is not the thing I want.
Correct.

Some of the things mentioned in the manual are a little hard for me to understand... Is something like a "lock" what I'm trying to do? like flock(2), O_SHLOCK, or O_EXLOCK.
Instead of looking for something to add, look for something to remove.

Here's what you said you wanted:
So basically what I'm looking for is when I call the read function, my program will wait until there are values available on the serial port.
Note the underlined part.

Here's the description for O_NONBLOCK from the man page:
If the O_NONBLOCK flag is specified, do not wait for the device or file to be ready or available. If
the open() call would result in the process being blocked for some reason (e.g., waiting for carrier on
a dialup line), open() returns immediately. This flag also has the effect of making all subsequent I/O
on the open file non-blocking.
Note the underlined parts.

Summary of the docs description:
O_NONBLOCK set -> does not wait, i.e. non-blocking.​
So if O_NONBLOCK is NOT set, what do you think will happen?

Using simple logic, and based on the name itself (NONBLOCK), I would guess that when O_NONBLOCK is not set, then open(), read(), write(), etc. would give blocking I/O, i.e. it waits. In other words, the opposite of NON-blocking NON-waiting I/O is blocking, waiting I/O. So remove O_NONBLOCK from the set of OR'ed flags (I assume you understand ORing). Then compile a test, try running it, and see what happens.


Also note that read() returns a value. How would you use that value to tell you how many bytes were actually read?

Note that read() has a man page, which Xcode should be able to show you, and you should be able to read online.

Being able to read docs, extract their meaning, and follow chains of related docs is a fundamental skill. Practice it regularly using real-world problems like this one.
 

StantonC

macrumors newbie
Original poster
Jun 24, 2013
5
0
Summary of the docs description:
O_NONBLOCK set -> does not wait, i.e. non-blocking.
O_NONBLOCK clear -> ________
What do you think should go in the blank?

I would put in the blank that it Does Wait.

I did what you suggested and took out the O_NONBLOCK so it looks like this now:
Code:
int fd = open("/dev/tty.usbmodem1421", O_RDWR | O_NOCTTY);

But unfortunately when I run this, it seems to get stuck in the open() function and doesn't continue on to print the value of "fd". Sorry but I also am not experienced with ORing, I get the basic concept, but maybe I'm not ORing correctly here either...

As for read() returning the the number of bytes, this is useful. It returns -1 if there is nothing, and returns a value when something is available, then returns to -1 after I've read the data.

If I still use O_NONBLOCK, but use the return value from read() like this:
Code:
ssize_t numInBytes = -1;
do {
  numInBytes = read(fd, inFromArduino, 1);
} while (numInBytes < 0);

I get the effect I'm looking for, but its still a little annoying to us a loop to accomplish this.

Any suggestions as to why my program would freeze in my open() function the way I have it?
 

chown33

Moderator
Staff member
Aug 9, 2009
10,706
8,346
A sea of green
I did what you suggested and took out the O_NONBLOCK so it looks like this now:
Code:
int fd = open("/dev/tty.usbmodem1421", O_RDWR | O_NOCTTY);

But unfortunately when I run this, it seems to get stuck in the open() function and doesn't continue on to print the value of "fd".

Oops, I didn't notice you were using the "tty" device-name. That's yet another bit of obscure knowledge.

The short answer is "Use the /dev/cu.WHATEVER" device-name. The tty name is intentionally designed to block until a DCD handshake signal is asserted. It's a holdover from the days of Unix being primarily a timesharing system with either direct-wired physical terminals or dialup modems that received calls from remote terminals.

Here's some brief summaries on tty vs. cu device-names:
http://osdir.com/ml/hardware.gps.gpsd.devel/2005-04/msg00110.html
http://www.openbsd.org/faq/faq8.html#TTY
http://www.unix.com/unix-dummies-questions-answers/14733-serial-port-device-path.html
.. find Perderabo's response


Here's some Arduino-specific code:
http://www.arduino.cc/playground/Interfacing/Cocoa

Note the details. The tty device is opened non-blocking. Then fcntl() is used to disable non-blocking (i.e. enable blocking).


Sorry but I also am not experienced with ORing, I get the basic concept, but maybe I'm not ORing correctly here either...
If this is essentially the first C++ program you've written yourself, you should probably start with something simpler. One of the major mistakes beginners make is underestimating the difficulty of a program.

If you're still learning from a book or tutorial, complete it before attempting an Arduino app. Also, use the Arduino website to find examples.
 

StantonC

macrumors newbie
Original poster
Jun 24, 2013
5
0
This solved my problem perfectly. Now when I call the read() function it waits for data to become available.

Code:
int fd = open("/dev/cu.usbmodem1421", O_RDWR | O_NOCTTY);

Thank you very much for being patient with me on my first post to a forum. If I need to post again in the future, then I will try my best to remember to explain everything thoroughly enough in the first post.

Again thanks,
Stanton
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.