I am sending data between an XBee transceiver and my PC.
The issue is that, initially (in my program) the data is random characters. Only after opening a serial connection in XCTU does it work.
So the serial data is being sent correctly, but XCTU does something to synchronise my pc to the XBee. Baud rates are set at 9600 both sides.
Does anybody know what XCTU is doing? Or how I can replicate it within my C++ program?
Hopefully the image below explain what is happening more clearly:
The serial port settings under Windows can be seen with GetCommState and set with SetCommState. Use the first one to see what the XCTU set. Your code can then use the same settings by calling SetCommState.
I found the issue. I was assuming default options with the boost serial_port object. After setting more of the options the serial communication works reliably.
Here are the options that I ended up setting:
port.set_option(asio::serial_port_base::baud_rate(9600));
port.set_option(asio::serial_port_base::character_size(8));
port.set_option(asio::serial_port_base::flow_control(asio::serial_port_base::flow_control::none));
port.set_option(asio::serial_port_base::parity(asio::serial_port_base::parity::none));
port.set_option(asio::serial_port_base::stop_bits(asio::serial_port_base::stop_bits::one));
where port is an asio::serial_port object.
Related
I'm writing a small program using QModbusDevice over the serial port (using the QModbusRtuSerialMaster class) and have some problems.
One of the problems seems to be that the flow control of the serial port is incorrect. Checking in a serial port sniffer I see that a working client sets RTS on when it sends requests, and then RTS off to receive replies. When I use QModbusRtuSerialMaster to send messages that doesn't happen.
The message is sent correctly (sometimes, subject for another question) compared to the working client. It's just the control flow that doesn't work and which causes the servers to be unable to reply.
I have set the Windows port settings for the COM-port in question to hardware flow control but it doesn't matter, the sniffer still reports no flow control.
Is there a way to get QModbusRtuSerialMaster to set the flow control as I would like? Or is there a way to manually handle the flow control (which is what the working client does)? Or is the only solution to skip the Qt modbus classes and make up my own using the serial port directly?
A short summary of what I'm doing...
First the initialization of the QModbusRtuSerialMaster object:
QModbusDevice* modbusDevice = new QModbusRtuSerialMaster(myMainWindow);
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, "COM3");
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);
modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, QSerialPort::Baud115200);
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);
modbusDevice->setTimeout(100);
modbusDevice->setNumberOfRetries(3);
modbusDevice->connectDevice();
Then how I send a request:
auto response = modbusDevice->sendReadRequest(QModbusDataUnit(QModbusDataUnit::Coils, 0, 1), 1);
QtModbus does not implement an automatic toggling for the RTS line because it expects your hardware to do it on its own (with a dedicated line instead).
This should be the case for most RS485 converters (even cheap ones). You would only need the RTS line if you have a separate transceiver like this one with a DE/~RE input.
If you were on Linux and had some specific hardware you could try to use the RS485 mode to toggle the RTS line for you automatically. But you don't seem to be on Linux and the supported hardware is certainly very limited.
You can also toggle the line manually with port.setRequestToSend(true), see here. But note that depending on the timing needs of the device you are talking too, this software solution might not be very reliable. This particular problem has been discussed at length here. Take a look at the links on my answer too, I made some benchmarks with libmodbus that show good results.
Enabling or disabling flow control on the driver won't have any effect on this issue because this is not actually a flow control problem but a direction control one. Modbus runs on two-wire half-duplex links very often, and that means you need a way to indicate which device is allowed to talk on the bus at all times. The RTS (flow control) from an RS232 port can be used for this purpose as a software workaround.
In the end, it would be much less of a headache if you just replace your transceiver with one that supports hardware direction control. If you have a serial port with an FTDI engine you should be able to use the TXEN line for this purpose. Sometimes this hardware line is not directly routed and available on a pin but you can reroute it with MProg.
I would like to highlight that you did not mention if you are running your Modbus on RS485. I guess it's fair to assume you are, but if you have only a couple of devices next to each other you might use RS232 (even on TTL levels) and forget about direction control (you would be running full-duplex with three wires: TX, RX and GND).
I am trying to use QSerialPort to implement one side of a simple serial communication protocol. The board on the receiving end of the protocol is not under my control, so I am trying to debug my side by using a null DE-9 cable to loop-back from one serial port to another on the same board, and running a simple "listener" app that relies on the same underlying transport-protocol code.
The transport protocol requires instantly sending an "acknowledgment" packet when a valid message packet is received, so ports are always opened in read/write mode, and after each message packet is sent the code waits and listens for an acknowledgment; the port is not closed again until after a timeout period has passed. EDIT 4: The port is, however, closed when the program is not trying to send a message or specifically listening for data.
I've discovered that the code behaves differently depending on whether or not the baud rate of the ports before the Qt programs are run matches the baud rate selected by the Qt program. That is, I'm using setBaudRate() (in both the sender and the listener) to determine the baud rate, and if I set it to whatever it was before running my programs, then the listener sees the correct byte sequences, but if I set it to something else, then the listener just sees garbage on the serial port.
(Even when the listener sees the correct byte sequences and sends acks, these acks are not seen by the other program, and I'm not sure why; I suspect this problem may be related, but for this question it's not my focus.)
It does not appear to matter what baud rate is actually used; I just need to set it using stty before running the Qt programs, even though the Qt programs set the baud rate explicitly. If I use stty to set the baud rate to something other than what the Qt programs use, the listener sees garbage.
I have printed the values of baudRate(Input), baudRate(Output), dataBits(), flowControl(), parity(), and stopBits() for each port after setting the baud rates in order to assess whether the baud rate isn't being set correctly or whether some other property of the serial port is incorrect, but the values printed are identical in every case.
I have experimented (though not extensively) with other properties of stty (for instance setting both ports to raw or to cooked before running my programs), and have observed that no settings except for the baud rate appear to have any affect.
Does anyone have any idea what might be going on here, how to debug it, and whether QSerialPort or QSerialPortInfo provide the proper tools to fix whatever inconsistency is manifesting?
EDIT: To clarify, I know that the Qt baud-rate-setting code is having some effect, because the remote end of the protocol (the one that's not under my control) uses 57600 baud, and I can send and receive some messages with that hardware after using Qt (not stty) to change my port's baud rate from the default 9600 to 57600. (If I do not change the baud rate, communication is not possible; I get characters that don't match what the hardware is actually sending.)
It should also be clear that the Qt code is having some effect from the fact that the loopback test would always work if there were no effect from setting the baud rate in my program.
EDIT 2: Before setting the baud rate, Qt apparently perceives the rate, as determined by baudRate(), to be 9600 (the default rate), regardless of how it has been set by stty.
Also, if I use stty to set the "sending" side to the "right" baud rate and the "listening" side to the "wrong" baud rate, I get the partially-correct behavior that I get when both ports are set to the "wrong" rate in advance (i.e. the listener sees messages, but the sender never sees acknowledgments).
EDIT 3: I previously had an edit noting that some of these tests were done with the loopback cable unplugged, but I have just realized that I was mistaken.
Qt version: 5.4.0
OS: Debian 7
It turns out I was losing data due to the fact that I was opening and closing the ports. When a QSerialPort is closed, data is either not buffered (by the driver) in the first place, or it is discarded as soon as the port is re-opened.
Presumably, the reason that setting the baud rate using stty to match the baud rate used by Qt affected the program behavior is that, when the baud rate is already what Qt needs to set it to, the setBaudRate() call is a no-op, and no clean-up action is required upon close to restore the old baud rate; whereas when Qt does need to change the baud rate, it must also restore the old baud rate when closing the port, which takes up a significant amount of processing time.
All,
I am working on an embedded linux application that is to use a cellular connection to communicate with a database.
I know that I can use AT commands to create socket to the server, but how do I get access to the socket from a C++ program? That is, after I issue the AT commands, how do I use it from an application?
Sorry if this is a stupid question, but I can't find an answer...
Thanks for all your help!
:bp:
Check the documentation for your modem. Multitech has one online here for their modems which may or may not be helpful (if yours is compatible).
Generally, after doing the WIPCREATE, you need to wait for a WIPREADY or WIPACCEPT from the modem; you can then do WIPDATA to put your connection to the modem into data mode, at which point everything you write will be sent to the socket, and anything received on the socket will be sent back to you (so you can treat the fd connected to the modem as if it was a socket, you just need to be careful not to send escape sequences accidentally -- or at least escape the escape sequences properly).
That depends on your OS. On most normal Unix OS's you can simply use /dev/tty*, open it, set the baudrate etc and issue AT commands.
I'm seeing some pretty odd behaviour from windows regarding my COM-Buffers.
I use 3 USB-Serial Converter with FTDI chips. I open the com ports with CreateFile and it all works fine. All 3 ports have the same configuration except for the baud rates. 2 work at 38400 and one at 9600.
Here is the odd part:
I am able to successfully write out of the 9600 port and one of the 38400 port. The second 38400 ports seems to be buffering the data. I have connected to this port with Hyperterminal and see that on the working ports i immediately get a response and on the "weird" port i only get the data when i close my application...
Has anyone else experienced this? How did you resolve this?
This is kind of a shot in the dark... but.
Check the flow control settings for both ends of the "weird" connection. I've seen strange things like this when the flow control is mismatched. The act of closing the port clears the bits and allows the buffered data to flow.
Having worked a bit with FTDI chips, I would suggest you check out the advanced driver settings for each port. The driver supports both buffering and latency control in order to allow you to compromise between high throughput and low latency. So check the settings that work and use the same for the one that doesn't (if they're not the same).
On a side note, by using FTDI:s own API you don't have to keep track of COM-port reassignment and the like. The API is quite similar to the normal Win32 one but exposes more configuration options.
I'm having a peculiar problem with boost::asio and a boost::asio::serial_port device. The code is finally working pretty well with asynchronous reads and stuff, but I can't figure out how to change the speed of the serial port on the fly.
What I'm trying to do right now is just telling the device connected in my serial port to change the serial port speed to say 38400 baud, then I'm setting my computers serial port to the same speed via:
port_.set_option(boost::asio::serial_port_base::baud_rate(rate));
But what's really happening is that if I do the set_option part, the device never receives the command to change the speed. If I don't do the set_option part the device changes speed correctly. From what I gather what's happening is that the (blocking, synchronous) write puts stuff in the hardware buffer on my computer and returns, then does the set_option which discards the buffer (before it has had time to send data to the device). So I need to think of some way to check if the hardware buffer is empty and the device really has received the command to change the speed, before reconfiguring my computers serial port. I also cannot find any info on if I have to do close() and open() on the port for the speed change to take affect. I'm also wondering if close() discards the stuff in the buffer or not... I'm using a USB->serial port adapter and my platform is Ubuntu 10.10 if it makes any difference.
Have you looked at man 3 termios? It seems tcdrain does what you need
tcdrain() waits until all output
written to the object referred to by
fd has been transmitted.
You can get the native descriptor from the boost::asio::serial_port::native method.
Did you try flushing the buffer or looking for an appropriate flush alternative?
Are the client and server in the same process?
Boost.Asio iostream flush not working?