![]() |
| | #1 |
| Registered User Join Date: Mar 2008
Posts: 43
| Can't Read From Serial Port I would have preferred to write this in just C, but I'll be forwarding code to another project that will be using it and they've said they need the libraries in C++, so I'm using C++, even though the methods I'm using are not C++ specific. I have a sender program in C++ that sends commands to the device and I have a listener in C++ that is not receiving the data properly. Ideally I want the listener to block while waiting for a new byte from the serial port because it'll be one of two threads and it'll spend most of its time blocked (overall, not much data comes back in), which makes thread management easier. Last night I was finally able to get something from the serial port, but it was all 0x00, which is not what I know was being sent. I've also found that the C++ sender was working fine without me setting any serial port parameters, but that's probably because they were still set from the Perl program. As I said, the Perl listener is working, but the C++ one is not. Here's the code to set up the serial port from Perl: Code:
$port = "/dev/ttyS0";
$baud = "115200";
$ob = Device::SerialPort->new ($port) || die "Can't Open $port: $!";
$ob->baudrate($baud) || die "failed setting baudrate";
$ob->parity("none") || die "failed setting parity";
$ob->databits(8) || die "failed setting databits";
$ob->handshake("none") || die "failed setting handshake";
$ob->write_settings || die "no settings";
Code: #include <iostream>
#include <string>
#include <vector>
#include <fcntl.h>
#include <termios.h>
void openinfile() {
long BAUD = B115200;
long DATABITS = CS8;
long STOPBITS = 0;
long PARITYON = 0;
long PARITY = 0;
struct termios options;
cout << "Opening port for listening: " << serdev << endl;
//serdev is already set to /dev/ttyS0, serfd is an int
serfd = open(serdev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
tcgetattr(serfd, &options);
options.c_cflag |= B115200;
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag |= (CLOCAL | CREAD);
// options.c_iflag &= ~(IXON | IXOFF | IXANY);
int rc = tcsetattr(serfd,TCSANOW ,&options);
cout << "Attr return code: " << rc << endl;
//Return code is always 0
// options.c_cflag |= CRTSCTS;
if (serfd == -1 ) {
perror("open_port: Unable to open port");
exit(1);
} else {
// fcntl(serfd, F_SETFL, 0);
printf("Port 1 has been sucessfully opened and %d is the file description\n", serfd);
}
return;
}
void readinfile() {
char cIn, *buff;
int i, rd;
//This next line should make us block until a byte comes in, but
// with it in place, no data comes in. With it commented out,
// all 0x00 bytes are coming in now and not as many as should be for
// the data coming back from the device.
// fcntl(serfd, F_SETFL, 0);
while (true) {
rd = read(serfd, buff, 10);
//DEBUG: Remove when I know it's blocking and not looping.
// cout << "Waiting: " << rd << endl;
if (rd <= 0)
continue;
//DEBUG: Remove this line once I know it's actually reading in characters!
// cout << "Got a character!\n";
cIn = buff[0];
//chout just prints the character as a 2 digit hex number, the decimal format, then the
// character itself it it's in printable range.
chout(cIn);
}
return;
}
My guess is that I'm doing something or not doing something incredibly obvious that a new C++ programmer might not see but someone with experience will laugh at. If so, it's likely something on the low level end or Linux/serial port specific. Why is it I either get no characters at all or only 0x00 from the C++ program? I've been using a serial port article at http://www.easysw.com/~mike/serial/serial.html for one source and I've been doing a lot of Googling. It looks to me like it should work, but it doesn't. Thanks for any help and links! |
| HalNineThousand is offline | |
| | #2 |
| Kernel hacker Join Date: Jul 2007 Location: Farncombe, Surrey, England
Posts: 15,686
| Check that the serial port is not being held by some other process. -- Mats
__________________ Compilers can produce warnings - make the compiler programmers happy: Use them! Please don't PM me for help - and no, I don't do help over instant messengers. |
| matsp is offline | |
| | #3 |
| Registered User Join Date: Mar 2008
Posts: 43
| How do I check that? And if it were being held, wouldn't that block the Perl program as well? |
| HalNineThousand is offline | |
| | #4 | |
| Kernel hacker Join Date: Jul 2007 Location: Farncombe, Surrey, England
Posts: 15,686
| Quote:
What about this idea then: Code: options.c_cflag &= ~CRTSCTS; -- Mats
__________________ Compilers can produce warnings - make the compiler programmers happy: Use them! Please don't PM me for help - and no, I don't do help over instant messengers. | |
| matsp is offline | |
| | #5 | |
| Registered User Join Date: Mar 2008
Posts: 43
| Quote:
Here's an interesting change, though. Out of curiosity, after not seeing a change from that, I uncommented the line: Code: options.c_cflag |= CRTSCTS; Is there any chance the output is being buffered and I wouldn't see anything until there were 256 or 512 or some other number of bytes? (I doubt it, but still, just asking...) Also, if I run the Perl program first, which sets all the params, then run the listener, should the listener's connection be dealing with whatever settings the Perl program used -- that is, if I don't specify any settings? Last edited by HalNineThousand; 03-19-2008 at 10:20 AM. Reason: Tried something else | |
| HalNineThousand is offline | |
| | #6 |
| Registered User Join Date: Mar 2008
Posts: 43
| I changed: Code: rd = read(serfd, buff, 10); |
| HalNineThousand is offline | |
| | #7 |
| Kernel hacker Join Date: Jul 2007 Location: Farncombe, Surrey, England
Posts: 15,686
| What is your sender sending? A constant char, or a packet of some sort? Yes, A5 printed as a signed char will be 0xFFFFFFA5. -- Mats
__________________ Compilers can produce warnings - make the compiler programmers happy: Use them! Please don't PM me for help - and no, I don't do help over instant messengers. |
| matsp is offline | |
| | #8 |
| Registered User Join Date: Mar 2008
Posts: 43
| First, I ran again, with a slight mod, and it's all coming out 0x00 now, but it's the right number of bytes, so at least it's getting characters and I'm willing to accept that I might have messed up the conversion routine. The sender is usually sending this string: 0xA4 0x10 0x02 0x01 0x00 0x00 0x01 0x00 0x00 0x00 0x79 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x34. I'm using that as a test command because it's easy to hear the results. When I sent that, I should have gotten an echo back confirming the device received it. I got the right number of bytes, but all 0x00. I sent a second command and got the same result: the right number of bytes, all 0x00. I'm including the conversion/printout function I'm using to output the results, just in case I'm doing something wrong there, but it worked before, with other data, so it shouldn't be a problem. Code: void chout(char cIn) {
char c;
char chex [10], cdec[10];
unsigned int n, iIn;
iIn = c;
if (iIn == 0xA4) {
cout << endl << endl;
}
sprintf(chex, "0x%2x", iIn);
if (chex[2] == ' ')
chex[2] = '0';
cout << chex << ":" << iIn << " [";
if (iIn >= 32 && iIn <= 126) {
cout << c;
}
cout << "], ";
return;
}
|
| HalNineThousand is offline | |
| | #9 |
| Kernel hacker Join Date: Jul 2007 Location: Farncombe, Surrey, England
Posts: 15,686
| Code: void chout(char cIn) {
char c;
char chex [10], cdec[10];
unsigned int n, iIn;
iIn = c;
-- Mats
__________________ Compilers can produce warnings - make the compiler programmers happy: Use them! Please don't PM me for help - and no, I don't do help over instant messengers. |
| matsp is offline | |
| | #10 |
| Registered User Join Date: Mar 2008
Posts: 43
| Uh, yeah. I knew that. (He says turning quite red in the face, realizing what an idjit mistake that was.) I'm wondering if working with Java that forces me to set values could have made me lazy, since I missed that c had not been set. Okay, so it's reading in data now and I'm down to 2 questions that should resolve it, one's a serial question, one's the conversion. 1) When I'm converting, I use this: Code: sprintf(chex, "0x%2x", iIn); 2) I included the commented out line: Code: fcntl(serfd, F_SETFL, 0); And thanks, by the way, for your help on this. I think the "won't read" issue was because of a mistake I had in waiting for 10 bytes instead of 1 as well as needing to st the flags as you pointed out. |
| HalNineThousand is offline | |
| | #11 |
| Registered User Join Date: Mar 2008
Posts: 43
| Got the conversion issue fixed. I had not realized a char could be unsigned. It didn't quite make sense to me until I looked it over. All that's left is getting it to block while waiting for a character. |
| HalNineThousand is offline | |
| | #12 |
| Senior software engineer Join Date: Mar 2007 Location: Portland, OR
Posts: 5,381
| Compiling with optimizations and warnings turned on should reveal such problems. |
| brewbuck is offline | |
| | #13 |
| Kernel hacker Join Date: Jul 2007 Location: Farncombe, Surrey, England
Posts: 15,686
| Add -Wall to your gcc compile line, and you should get more info about various things that MAY be wrong. I think you should remove O_NDELAY from your open, and that will fix your "need to wait for input". If you still want to time-out on input, you can set the c_cc[VTIME] = n, where n is 0.1s periods that you are willing to way, e.g. 30 will wait for 3 seconds before "giving up". -- Mats
__________________ Compilers can produce warnings - make the compiler programmers happy: Use them! Please don't PM me for help - and no, I don't do help over instant messengers. |
| matsp is offline | |
| | #14 | |||
| Registered User Join Date: Mar 2008
Posts: 43
| Quote:
Quote:
Quote:
Thanks, again, for all the help. I'll try leaving out O_NDELAY and see what that does. | |||
| HalNineThousand is offline | |
| | #15 |
| Registered User Join Date: Mar 2008
Posts: 43
| Just an update: It's working fine now, not only on a regular RS232C interface on my computer, but also through a USB port connected to a USB->RS232C adaptor. I eliminated the O_NDELAY from the open statement and it works fine for both reading and writing (but I haven't tried for it to do both at the same time yet) and it seems like it is blocking at the read until a new byte comes in. I'll be testing that again later. Thanks for all the help on this! |
| HalNineThousand is offline | |
![]() |
| Thread Tools | |
| Display Modes | |
|
Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Serial Port Questions | valaris | Tech Board | 2 | 05-22-2009 08:26 AM |
| FTP program | jakemott | Linux Programming | 14 | 10-06-2008 01:58 PM |
| Serial Port Issues (again!) | HalNineThousand | Linux Programming | 6 | 04-09-2008 08:26 PM |
| HELP with storing serial port data into txt file | inmaterichard | C Programming | 2 | 04-02-2008 02:20 AM |
| Serial port read..can someone tell me.. | Unregistered | C Programming | 3 | 06-27-2002 08:21 AM |