I'm trying to use QSerialPort class to reading and writing to serial port.
Right now i'm using virtual comports implemented by eltima driver.
I can successfully send bytes like this:
QSerialPortInfo info = QSerialPortInfo("COM30");
QSerialPort serial;
serial.setPort(info);
serial.setBaudRate(57600);
serial.open(QIODevice::ReadWrite);
char arr[] = {0xAA, 0xBB, 0xCC, 0xDD};
serial.write(arr, 4);
I'm trying reading like this (I want to read just a single byte; this code is called by timer, if data is ready to be read):
virtual uint8_t getByte(void)
{
char arr[2] = {0};
int8_t err = qPort.read(arr, 1);
DEBUG_ASSERT(err != -1);
if(! isNewByte() )
{
onReceiveFinished();
}
return arr[0];
}
If I send to a virtual port (i.e. to my program) any value less then 128, I get it right (as debugger is showing). However, if I try to send 128 or more, I get value-128 o_o (if I send 153 - I get 25. Not -25 or 103).
That seems like something really odd to me.
Can anyone see where is the mistake?
My mistake was really stupid. QSerialPort is set to 7 databits by default (which seems not very practical, actually), so every received byte had its MSB cut off (like substracting 128).
Still, oddly enough, sending worked fine.
Not. You wrong do setBaudRate(). It need to do after the port is opening.
Related
I'm developing an app with Qt and I have to read frames and check each byte to see if its values are correct.
QSerialPort serial;
QByteArray data = serial.readAll();
I well receive bytes but I don't know how to check if they are well equal to my hex values. I'd like to do something like this:
if (data[0] == 0x02) {
// my code
}
My question will probably be stupid for most of you but I don't find any answer :(
I am developing a window's application that sends and receives data to an Arduino via the serial port.
The problem I have is when I try to send an int value to the serial port and pick it up in the Arduino program. I am using WriteFile() in the window's program to send the int and pick it up in the Arduino using Serial.parseInt(). When I send char values I can pick them up with no problems.
If I want to send int values the only time I receive an integer in the arduino is if I send integers 48 to 57 which give me an int value of 0 to 9 which are the ASCII characters for decimal 48 to 57, weird. e.g. 57, The Arduino seems to pick this up as 9 which is the char value for ASCII 57.
below is the code in the windows program and the Arduino
C++ code:
DWORD ComPort::WriteAnalogData(int *buffer)
{
if (!connected)
return 0;
DWORD bytesSent;
DWORD errors;
if (!WriteFile(hCom, (void *)buffer, sizeof(buffer), &bytesSent, 0))
ClearCommError(hCom, &errors, NULL); // If it fails, clear com errors
else return bytesSent; // Return the number of bytes sent
return 0; // Or return 0 on failure
}
the return value(bytesSent) after the int is written is 4 so I think this function is working. I have a similar function for sending single bytes of data which works and the Arduino picks the data up ok
Arduino Code:
int scadaAnalogVal;
scadaAnalogVal = Serial.parseInt();
digitalWrite(scadaAnalogVal,HIGH);
can anyone tell me what's going on. Probably something simple but i can't see what the issue is, thanks.
The Arduino parseInt() method has a long return type (32-bits) in the Arduino architecture. I think you should change your Arduino code to:
long scadaAnalogVal;
ParseInt documentation
I have an arduino board that is connected to a sensor. From Arduino IDE serial monitor, I see the readings are mostly 160, 150, etc. Arduino has a 10 bit ADC, so I assume the readings range from 0 to 1024.
I want to fetch that readings to my computer so that I can do further processing. It must be done this way up to this point. Now, I wrote a c++ program to read serial port buffer with Windows APIs (DCB). The transfer speed of the serial ports are set to 115200 on both the Arduino IDE and the c++ program.
I will describe my problem first: Since I want to send the readings to my computer, I expect the data looks like the following:
124
154
342
232
...
But now it looks like
321
43
5
2
123
...
As shown, the data are concatenated. I knew it because I tried to display them with [], and the data are truly messed up.
The section of the code that is doing the serial port reading on the computer is as here:
// Read
int n = 10;
char szBuff[10 + 1] = {0};
DWORD dwBytesRead = 0;
int i;
for (i = 0; i < 200; i++){
{
if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
//error occurred. Report to user.
printf("Cannot read.\n");
}
else{
printf("%s\n" , szBuff);
}
}
}
The Arduino code that's doing the serial port sending is:
char buffer [10] = { 0 };
int analogIn = 0;
int A0_val = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
A0_val = analogRead(analogIn);
sprintf(buffer, "%d", A0_val);
Serial.println(buffer);
}
I suspect that the messing up of the data is caused by different size of the buffer used to transmit and receive data in the serial port. What is the good suggestion for the size of the buffer and even better method to guarantee the successful transmission of valid data?
Thanks very much!
Your reciever code cannot assume a single read from the serial port will yield a complete line (i.e. the 2 or 3 digits followed by a '\n' that the arduino continuously sends).
It is up to the receiver to synthetize complete lines of text on reception, and only then try to use them as meaningful numbers.
Since the serial interface is extremely slow compared with your average PC computing power, there is little point in reading more than one character at a time: literally millions of CPU cycles will be spent waiting for the next character, so you really don't need to react fast to the arduino input.
Since in that particular case it will not hinder performances in the slightest, I find it more convenient to read one character at a time. That will save you the hassle of moving bits of strings around. At least it makes writing an educational example easier.
// return the next value received from the arduino as an integer
int read_arduino (HANDLE hserial)
{
char buffer[4]; // any value longer than 3 digits must come
// from a faulty transmission
// the 4th caracter is used for a terminating '\0'
size_t buf_index = 0; // storage position of received characters
for (;;)
{
char c; // read one byte at a time
if (!ReadFile(
hSerial,
&c, // 1 byte buffer
1, // of length 1
NULL, // we will read exactly one byte or die trying,
// so length checking is pointless
NULL)){
/*
* This error means something is wrong with serial port config,
* and I assume your port configuration is hard-coded,
* so the code won't work unless you modify and recompile it.
* No point in keeping the progam running, then.
*/
fprintf (stderr, "Dang! Messed up the serial port config AGAIN!");
exit(-1);
}
else // our read succeded. That's a start.
{
if (c == '\n') // we're done receiving a complete value
{
int result; // the decoded value we might return
// check for buffer overflow
if (buf_index == sizeof (buffer))
{
// warn the user and discard the input
fprintf (stderr,
"Too many characters received, input flushed\n");
}
else // valid number of characters received
{
// add a string terminator to the buffer
buffer[buf_index] = '\0';
// convert to integer
result = atoi (buffer);
if (result == 0)
{
/*
* assuming 0 is not a legit value returned by the arduino, this means the
* string contained something else than digits. It could happen in case
* of electricval problems on the line, typically if you plug/unplug the cable
* while the arduino is sending (or Mr Fluffy is busy gnawing at it).
*/
fprintf (stderr, "Wrong value received: '%s'\n", buffer);
}
else // valid value decoded
{
// at last, return the coveted value
return res; // <-- this is the only exit point
}
}
// reset buffer index to prepare receiving the next line
buf_index = 0;
}
else // character other than '\n' received
{
// store it as long as our buffer does not overflow
if (buf_index < sizeof (buffer))
{
buffer[buf_index++] = c;
/*
* if, for some reason, we receive more than the expected max number of
* characters, the input will be discarded until the next '\n' allow us
* to re-synchronize.
*/
}
}
}
}
}
CAVEAT: this is just code off the top of my head. I might have left a few typos here and there, so don't expect it to run or even compile out of the box.
A couple of basic problems here. First, it is unlikely that the PC can reliably keep up with 115,200 baud data if you only read 10 bytes at a time with ReadFile. Try a slower baud rate and/or change the buffer size and number of bytes per read to something that will get around 20 milliseconds of data, or more.
Second, after you read some data put a nul at the end of it
szBuf[dwBytesRead] = 0;
before you pass it to printf or any other C string code.
I have this simple code that use QtSerialPort:
char foo[] = {130,50,'\0'};
serial->write(foo);
The result on my serial is {2, 50}. I think that che biggest number that I can send is 128 (char go from -128 to 128). Where is the manner for send number from 0 to 255? I try to use unsigned char but the method "write" don't work with it. The same problem also appear with QByteArray.
Thankyou all.
The QIODevice interface has the default char for sending which may be compiler dependent. See the documentation for details.
qint64 QIODevice::write(const char * data, qint64 maxSize)
Writes at most maxSize bytes of data from data to the device. Returns the number of bytes that were actually written, or -1 if an error occurred.
However, you should not be concerned much if you take the data properly on the other hand. you can still send the greater than 128 values through as signed, but they will come across as negative values, for instance 0xFF will be -1.
If you take the same logic in the reverse order on the receiving end, there should be no problems about it.
However, this does not seem to relate to your issue because you do not get the corresponding negative value for 130, but you get it chopped at 7 bits. Make sure you connection is 8 data bit.
You can set that explicitly after opening the port with this code:
QSerialPort serialPort;
QString serialPortName = "foo";
serialPort.setPortName(serialPortName);
if (!serialPort.open(QIODevice::WriteOnly)) {
standardOutput << QObject::tr("Failed to open port %1, error: %2").arg(serialPortName).arg(serialPort.errorString()) << endl;
return 1;
}
if (!serialPort.setDataBits(QSerialPort::Data8)) {
standardOutput << QObject::tr("Failed to set 8 data bits for port %1, error: %2").arg(serialPortName).arg(serialPort.errorString()) << endl;
return 1;
}
// Other setup code here
char foo[] = {130,50,'\0'};
serialPort.write(foo);
Make sure you've set the serial port to send 8 bits, using QSerialPort::DataBits
The fact that '130' is coming as '2' implies that the most significant bit is being truncated.
I am doing some socket stuff on Symbian, which works fine so far. However,
I am facing a weird problem when trying to read out the data that has been sent.
Assume the code looks as follows:
TSockXfrLength len;
iSocket.RecvOneOrMore( buff, 0, iStatus, len );
User::WaitForRequest(iStatus);
if (iStatus == KErrNone)
{
printf(_L("Bytes received 1st try %4d..."), len);
printf(_L("Bytes Length received 2nd try %4d..."), &len);
}
Output in both cases is something with 7450 although I received exactly 145 bytes.
I can check that with a network analyser. Anyone knows what I am doing wrong here that
I do not get the proper bytes that have been received?
EDIT:
I am connecting to the socket in the following way:
TInetAddr serverAddr;
TUint iPort=445;
TRequestStatus iStatus;
TSockXfrLength len;
TInt res = iSocketSrv.Connect();
res = iSocket.Open(iSocketSrv,KAfInet,KSockStream, KProtocolInetTcp);
serverAddr.SetPort(iPort);
serverAddr.SetAddress(INET_ADDR(192,100,81,54));
iSocket.Connect(serverAddr,iStatus);
User::WaitForRequest(iStatus);
Hope that helps ;)
Thanks
Try
printf(_L("Bytes received 1st try %4d..."), len());
The TSockXfrLength type is actually a typedef of TPckgBuf<TInt>. This is the Symbian Descriptor way of storing arbitrary simple data in a 8-bit descriptor. To retrieve the value from the len object you need to use the () operator.
More information about TPckg* classes are available in the symbian developer library.