For a project i need to establish 2 way xbee communication. But I have a problem sending data from my pc. I use cpp with termios to transmitt a char array but on the xbee tx pin I do only get a signal (I observe this on an oscilloscope) when one of the chars is 0x0A.
The XBee module is on a 30011662-02 board, which is connected to my pc via usb.
I thought maybe this is some kind of starting parameter needed by the xbee board to transmit but couldnt find any information on this.
ctx->debug = debug;
//open USB port for read/write and check success
ctx->fd = open(devFileName, O_RDWR | O_NOCTTY); //opens the usb port for reading
if (ctx->fd < 0) {
cerr << "Could not open the USB Port. Try adding User to group dialout!" << endl;
return 0;
}
//is the opened port a terminal?
if(!isatty(ctx->fd)) {
close(ctx->fd);
errno = ENOTTY;
return 0;
}
//setup termios
tcgetattr(ctx->fd, &(ctx->oldtio));
cfmakeraw(&newtio);
cfsetispeed(&newtio, baudrate);
cfsetospeed(&newtio, baudrate);
tcsetattr(ctx->fd, TCSANOW, &newtio); //connects fd to newtio
tcflush(ctx->fd, TCIOFLUSH); //discards data not transmitted or received
lseek(ctx->fd, 0, SEEK_END);
ctx->bufIO = fdopen(ctx->fd, "r+");
bool connection_status=0;
unsigned char frame_id=0x00;
unsigned char checksum=0xff;
int j=0;
while(!connection_status){
checksum=0xFF;
unsigned char buffer[] = {
0x7E, //start delimiter
0x00,0x07,//length of the data packet
0x01,//API identifier (refer to XBee module manual for further details)
frame_id++, //frame id
0x00,0x0B,//destination address
0x00,//options
0x02,0x03,//data: 0,receiver address,mode
0x00}; //checksumm
for(unsigned int i=0;i<sizeof(buffer);i++){
checksum-=buffer[i];
}
cout << buffer << endl;
j++;
buffer[10]=checksum;
fwrite(buffer,sizeof(char),sizeof(buffer),ctx->bufIO);
usleep(2000000);
}
I do expect to see data on the xbee tx pin in every itteration of the while loop but so far it only works when frame_id is 0x0A or i manually enter 0x0A in the array buffer. But still it does not seem to be sending the correct data. Maybe you have some hints for me.
You're probably missing a setting (maybe O_NDELAY?) for the serial port (tty) and it's in line mode. You might want to look at this serial driver used in an Open Source XBee Host Library written in ANSI C (instead of C++). You might even be able to build your application on top of that library. At the very least, you could compile the samples and see if they work with your module as a way to verify your wiring and XBee configuration.
Related
In a sketch of Arduino there is an example WiFi Telnet To Serial with ESP8266. There is a piece of code that is used to receive data from a client:
//check clients for data
for(i = 0; i < MAX_SRV_CLIENTS; i++){
if (serverClients[i] && serverClients[i].connected()){
if(serverClients[i].available()){
//get data from the telnet client and push it to the UART
while(serverClients[i].available())
Serial.write(serverClients[i].read());
}
}
}
This data is sent to the console or the serial port, but I need to capture that data and store it in a byte array:
byte bufferMSGfromCliente[1024]
How to do it?
Its not c++ but you might be able to use a processing sketch. The syntax is very close to arduino so it should be familiar.
import processing.serial.*;
Serial myPort; // The serial port
void setup() {
// List all the available serial ports
printArray(Serial.list());
// Open the port you are using at the rate you want:
myPort = new Serial(this, Serial.list()[0], 9600);
}
void draw() {
int i = 0;
byte[] bufferMSGfromCliente = new byte[1024];
while (myPort.available() > 0) {
int inByte = myPort.read();
if(i > 1024)
{
i = 0;
}
bufferMSGfromCliente[i] = inByte;
i++;
}
}
Did you try to write it to another Serial port? Here you write it on the same Serial port as your Serial Monitor.
Best would be to store serverClients[i].read() into a Byte and then Serial.println(Byte) to see what the information is.
After that, ask yourself:
1. What Serial port will this information be sent to, what is the destination?
2. How can I confirm that information is sent succesfully and has the ability to be debugged.
Also, use Serial.flush() to make sure the Serial.write function completes. Eventhough it says ''flush'', the function in Arduino IDE waits for the Serial write function to be completed.
I am using a BeagleBone Black to read data coming from a microcontroller(s) via a UART port(s). I need the reading of the UART port to be a blocking call. Additionally, for the usage of this software there will be some non-standard baud rates in use (aka not provided by termios). Additionally, the UART should follow 8-N-1 (8 data bits, no parity, 1 stop bit).
The code I have for the opening the UART port is as follows:
int UART::UART_open(unsigned int baudRate)
{
mFd = open(mPath.c_str(), O_RDWR | O_NOCTTY);
if(mFd < 0)
{
return -1;
}
struct termios2 tty;
if(ioctl(mFd, TCGETS2, &tty) == -1)
{
return -1;
}
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 5;
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_cflag &= ~CBAUD;
tty.c_cflag |= (BOTHER | CREAD | CLOCAL);
tty.c_ispeed = baudRate;
tty.c_ospeed = baudRate;
if(ioctl(mFd, TCSETS2, &tty) == -1)
{
return -1;
}
return 0;
}
The code I have for reading the UART port is as follows:
int UART::UART_read(unsigned char* buf, int length)
{
if(mFd < 0)
{
return -1;
}
if(read(mFd, buf, length) != length)
{
return -1;
}
return length;
}
There is some odd behavior going on. What happens is, the reading is inconsistent. Sometimes when I test it with an Mbed microcontroller sending data continuously (with small delays in between) via UART to the right port, and a test program to continuously read the UART port on the BeagleBone Black, and print out the data it gets, it works fine, and I am able to print out the data sent and everything works as expected. However, what happens often is the very first read simply blocks forever. No errors occur from the functions, the UART_read function simply hangs. So, to debug the error the first thing I do is I use 'screen' to monitor the /dev/ttyO* port I am trying to read from. What I find is that data is being sent to that port just fine. Then, the odd thing is, after I use screen, if I run my test program to continuously read the UART port, it works fine. This happens consistently too, if I do a quick 'screen' of the port when it is not working, I see data being sent, then my test program works. I have tried changing some of the opening termios2 struct options, to no avail. Any help would be appreciated!
Your termios initialization is obviously incomplete. There's a partial configuration for raw mode, e.g.
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 5;
yet you never actually enable noncanonical mode.
The "blocks forever" behavior of read() is symptomatic of a serial terminal (mis)configured for canonical mode when only binary data is received (i.e. there is no line terminator to "complete" the request).
Another possible cause of "blocks forever" behavior is failure to disable hardware flow-control when it is not used.
The insertion of the following statements would enable noncanonical mode and disable the HW handshake:
cfmakeraw(&tty);
tty.c_cflag &= ~CRTSCTS;
Refer to this answer for a complete example.
if(read(mFd, buf, length) != length)
{
return -1;
}
There is no requirement that a read() of a serial terminal will fill the buffer. Depending on the configuration, a "successful" read can return zero or more bytes up to the number requested.
Therefore a short read is not actually an error condition.
How can I write and read hex data when I open serial port?
if (serial->isOpen()) {
qDebug() << "seccus: " ;
static const char buff[] = {0xA1, 0xFF, 0xFF, 0x00,97};
serial->write(buff,sizeof(buff));
}
if (serial->bytesAvailable()) { // If there are bytes available
QByteArray f_data; // data container
f_data.clear();
if (serial->open(QIODevice::ReadWrite)) { // Try to open the port
while(serial->bytesAvailable()) { // Reading loop
f_data.append(serial->readAll());
}
serial->flush();
}
qDebug()<< "the result" << f_data; // Check the result
}
if(!serial->isOpen())
qDebug() << "carte disconnect"<<serial->errorString();
To debug your issue, I would start with simplifying what you're trying to do. Try writing some test code to start, to make sure things work as you expect:
Test serial is open - should not be
Open serial
Test serial is open - should be
Test if bytes are available - should not be
write data to serial. Flush.
Test if bytes are available - should be
Read and print to screen (i.e test your reading it correctly)
Close the serial port - test its not open
Perhaps if one of these steps doesn't work as you expect, you can at least focus on why that particular part is not working.
Good luck.
We are using FTDI serial port CHIP in our hardware. Now we have working code in Linux and we moved to windows 7. We get some weird problems.
The Problem:
We can't write data to Serial Port without running other console application which do this:
serial.setPortName("COM3");
if (serial.open(QIODevice::ReadWrite)) {
bool success = serial.setBaudRate(QSerialPort::Baud9600) &
serial.setStopBits(QSerialPort::OneStop) &
serial.setDataBits(QSerialPort::Data8) &
serial.setParity(QSerialPort::NoParity) &
serial.setFlowControl(QSerialPort::NoFlowControl);
qDebug() << "Connected to usb device: " << (success ? "OK" : "FAIL");
while(true) {
if(serial.waitForReadyRead(-1)) {
QByteArray out = serial.readAll();
for(int i=0; i< out.length(); i++) {
qDebug() << (int) out[i];
}
}
}
serial.close();
So its just loop with read all. Hardware dosen't send anything, so read is just infinity loop. After closing and running our write program it runs correctly.
char* input;
input = new char[size+3];
QByteArray bytearr;
for(int i=0;i<size+2;i++) {
input[i] = (char) package[i];
bytearr.append((unsigned char) package[i]);
}
QString serialPortName = "COM3";
QSerialPort serialPort;
serialPort.setPortName(serialPortName);
serialPort.open(QIODevice::ReadWrite);
serialPort.write(bytearr);
serialPort.flush();
serialPort.close();
After running read everything works, but without read all, it wont work. What are we doing wrong?
Thanks.
We had similar problem in our application with a board with FTDI chip. We tried to write bytes with 19200 baud/sec, had though in real about 1200 baud/sec (seen using oscilloscope). The problem was closing the serial port right after writing a byte. Just waiting using QThread::msleep(5) before closing the port helped. It seems, that the device gets a reset or something during close operation and latest bytes are sent with false baudrate and other parameters.
I found out that the QT serial port SW requires you to process QT events in order to work.
Putting a qApp->processEvents() in the loop before the read made it work for me.
(QT 4.8.5 on Windows-7)
Problem:
I have a hand held device that scans those graphic color barcodes on all packaging. There is a track device that I can use that will slide the device automatically. This track device functions by taking ascii code through a serial port. I need to get this thing to work in FileMaker on a Mac. So no terminal programs, etc...
What I've got so far:
I bought a Keyspan USB/Serial adapter. Using a program called ZTerm I was successful in sending commands to the device.
Example:
"C,7^M^J"
I was also able to do the same thing in Terminal using this command: screen /dev/tty.KeySerial1 57600
and then type in the same command above(but when I typed in I just hit Control-M and Control-J for the carriage return and line feed)
Now I'm writing a plug-in for FileMaker(in C++ of course). I want to get what I did above happen in C++ so when I install that plug-in in FileMaker I can just call one of those functions and have the whole process take place right there.
I'm able to connect to the device, but I can't talk to it. It is not responding to anything.
I've tried connecting to the device(successfully) using these:
FILE *comport;
if ((comport = fopen("/dev/tty.KeySerial1", "w")) == NULL){...}
and
int fd;
fd = open("/dev/tty.KeySerial1", O_RDWR | O_NOCTTY | O_NDELAY);
This is what I've tried so far in way of talking to the device:
fputs ("C,7^M^J",comport);
or
fprintf(comport,"C,7^M^J");
or
char buffer[] = { 'C' , ',' , '7' , '^' , 'M' , '^' , 'J' };
fwrite (buffer , 1 , sizeof(buffer) , comport );
or
fwrite('C,7^M^J', 1, 1, comport);
Questions:
When I connected to the device from Terminal and using ZTerm, I was able to set my baud rate of 57600. I think that may be why it isn't responding here. But I don't know how to do it here.... Does any one know how to do that? I tried this, but it didn't work:
comport->BaudRate = 57600;
There are a lot of class solutions out there but they all call these include files like termios.h and stdio.h. I don't have these and, for whatever reason, I can't find them to download. I've downloaded a few examples but there are like 20 files in them and they're all calling other files I can't find(like the ones listed above). Do I need to find these and if so where? I just don't know enough about C++ Is there a website where I can download libraries??
Another solution might be to put those terminal commands in C++. Is there a way to do that?
So this has been driving me crazy. I'm not a C++ guy, I only know basic programming concepts. Is anyone out there a C++ expert? I ideally I'd like this to just work using functions I already have, like those fwrite, fputs stuff.
Thanks!
Sending a ^ and then a M doesn't send control-M, thats just the way you write it,
to send a control character the easiest way is to just use the ascii control code.
ps. ^M is carriage return ie "\r" and ^J is linefeed "\n"
edit: Probably more than you will (hopefully) ever need to know - but read The Serial Port Howto before going any further.
This isn't a C++ question. You're asking how to interact with the TTY driver to set teh baud rate. The fact that you're opening the file under /dev tells me that you're on a unix derivative, so the relevant man page to read on a linux system is "man 3 termios".
Basically, you use the open() variant above, and pass the file descriptor to tcsetattr/tcgetattr.
Are you sure you've installed all the compiler tools properly? On my OS X 10.5.8 Mac,
termios.h and stdio.h are right there under /usr/include, just as I'd expect. The
code you've already found for serial port programming on other Unix variants should
only require minor changes (if any) to work on a Mac. Can you tell us a bit more about
what you've tried, and what went wrong?
mgb also has a good point about how the control characters need to be represented.
You can set the baud rate with ioctl. Here's a link to an example.
You don't specify which Unix you are using, so below I'm posting some Linux production code I use.
Pleae note below code is a class method so ignore any external (ie undeclared) references.
Steps are as follows -
Configure your termio structure, this is where you set any needed flags etc (ie the step you accomplished using zterm. The termio settings below configure the port to 8 databits, 1 stopbit and no parity (8-n-1). Also the port will be in "raw" (as opposed to cooked) mode so its a character stream, text isn't framed into lines etc The baud constants match the actual value, ie for 56700 baud you use "57600".
The timing parameters mean that characters are returned from the device as soon as they are available.
Once you have your termainal parameters set, you open the device (using POSIX open()), and then can use tcgetattr/tcsetattr to configure the device via the fd.
At this point you can read/write to the device using the read()/write() system calls.
Note that in the below example read() will block if no data is available so you may want to use select()/poll() if blocking is undesirable.
Hope that helps.
termios termio
tcflag_t baud_specifier;
//reset device state...
memset (&termio, 0, sizeof (termios));
read_buffer.clear();
//get our boad rate...
if (!(baud_specifier = baud_constant (baud))) {
ostringstream txt;
txt << "invalid baud - " << baud;
device_status_msg = txt.str();
status = false;
return (true);
}
//configure device state...
termio.c_cflag = baud_specifier | CS8 | CLOCAL | CREAD;
//do we want handshaking?
if (rtscts) {
termio.c_cflag |= CRTSCTS;
}
termio.c_iflag = IGNPAR;
termio.c_oflag = 0;
termio.c_lflag = 0;
//com port timing, no wait between characters and read unblocks as soon as there is a character
termio.c_cc[VTIME] = 0;
termio.c_cc[VMIN] = 0;
//open device...
if ((fd = open (device.c_str(), O_RDWR | O_NOCTTY)) == -1) {
ostringstream txt;
txt << "open(\"" << device << "\") failed with " << errno << " - "
<< std_error_msg (errno);
device_status_msg = txt.str();
status = false;
return (true);
}
//keep a copy of curret device state...
if (tcgetattr (fd, &old_termio) == -1) {
ostringstream txt;
txt << "tcgetattr() failed with " << errno << " - " << std_error_msg (errno);
device_status_msg = txt.str();
status = false;
return (true);
}
//flush any unwanted bytes
if (tcflush (fd, TCIOFLUSH) == -1) {
ostringstream txt;
txt << "tcflush() failed with " << errno << " - " << std_error_msg (errno);
device_status_msg = txt.str();
status = false;
return (true);
}
//apply our device config...
if (tcsetattr (fd, TCSANOW, &termio) == -1) {
ostringstream txt;
txt << "tcsetattr() failed with " << errno << " - " << std_error_msg (errno);
device_status_msg = txt.str();
status = false;
return (true);
}
node_log_f ("successfully initialised device %s at %i baud", "open_device()",
device.c_str(), baud);
status = true;
return (true);
}