Is there a way to send a byte to serial with QT.
I only found a function for sending chars.
serialport->write(const QByteArray &data)
I want to send a array with these three bytes in Hex: 0xF0 0x02 0x0D
Do you have something like
serialport->write(QByteArray::fromHex("F0020D"));
in mind ?
You send 8-bit values. "Hexadecimal" is just a form of notation of integer values.
QByteArray ba;
ba.resize(3);
ba[0] = 0xF0;
ba[1] = 0x02;
ba[2] = 0x0D;
serialport->write(ba);
or:
char arr[3] = {0xF0, 0x02, 0x0D};
QByteArray ba(arr, 3);
serialport->write(ba);
Related
I'm going to receive length delimited frame from server with QTcpSocket in this format:-
+----------+--------------------------------+
| len: u32 | frame payload |
+----------+--------------------------------+
where u32 is in 32 bit unsigned integer encoded in Big-Endian format. depending on config, It can also be Little Endian But I will know about endianness beforehand on client side.
How can I convert first 4 bytes of this char* array or QByteArray to 32 bit unsigned int ?
After reading the frame I will need to send message in same format. So If I have message of length 20 bytes, How can I write 20 as 32 bit unsigned int to QByteArray or char* in Big/Little endian format ?
You can use Qt's QtEndian utility functions to accomplish that.
For example, if you have a quint32 (or uint32_t) and want to write that value in little-endian format to the first four bytes of a char array:
const quint32 myValue = 12345;
char frameBuffer[256];
qToLittleEndian(myValue, frameBuffer);
... or, alternatively, to read the first four bytes of a char array in as a little-endian quint32 (or uint32_t):
const char frameBuffer[256] = {0x01, 0x00, 0x00, 0x00};
quint32 myValue = qFromLittleEndian<quint32>(frameBuffer);
Big-endian reads/writes work the same, just replace the substring Little with Big in the function-names.
the way to do is:
bytearray -> stream ->setorder -> serialize to variable
QByteArray newData = ....;
QDataStream stream(newData);
stream.setByteOrder(QDataStream::LittleEndian); // or BigEndian
stream >> variable;
I am receiving serial communication through the USB port to my Arduino (ATmega2560) by using the RX0 pin. In the receive function I want to compare the register that receives information UDR0 with unsigned char pckaffe[4]. The data that is being sent through the USB port onto the Arduino comes from a pc and if everything works correctly, it should be sending unsigned char arrays, which is why I am comparing UDR0 to unsigned char pckaffe.
However at the if statement, the compiler is saying Error ISO C++ forbids comparison between pointer and integer [-fpermissive]
Why is that?
unsigned char pckaffe[4] = { 0x0C, 0x0A, 0x0F, 0x0E };
void USART_Receive(){
while(!(UCSR0A & (1<<RXC0)) );
if(UDR0 == pckaffe){
PORTB ^= (1 << PB1);
}
}
Why is that?
unsigned char pckaffe[4] = { 0x0C, 0x0A, 0x0F, 0x0E };
pckaffe is a unsigned char pointer, which you are trying to compare to an integer here
if(UDR0 == pckaffe)
pckaffe is a pointer to an array of chars, so the if statement is comparing the value of UDR0 (an int) to the address of pckaffe, which are incompatible types.
I want to compare the register that receives information UDR0 with unsigned char pckaffe[4]
URD0 contains one byte of data. pckaffe[4] - four of them. how you want to compare them?
Of course if(UDR0 == pckaffe) has no sense, pckaffe without index is implicitly converted to a pointer to the array. That gives you compilation error.
Probably you want something like that:
unsigned char pckaffe[4] = { 0x0C, 0x0A, 0x0F, 0x0E };
unsigned int pckaffe_pos = 0;
void USART_Receive(){
while(!(UCSR0A & (1<<RXC0)) ); // Wait for next received byte
uint8_t data = UDR0; // Get received byte
if (data == pckaffe[pckaffe_pos]) { // Compare the byte with next position in the array
pckaffe_pos++; // if matches, increase position
if (pckaffe_pos >= 4) { // If all bytes matched
pckaffe_pos = 0; // reset the pointer
PORTB ^= (1 << PB1); // do something
}
} else if (data == pckaffe[0]) { // next byte does not match, but matches the first
pckaffe_pos = 1; // next byte assumed to be the second in the sequence
} else { // does not match anything
pckaffe_pos = 0; // wait for the first byte in the sequence
}
}
In my project I'm working with QByteArrays appending data to them as the program goes. Most of the time, a simple quint8 gets appended just fine using QByteArray::append(). But when a quint16 gets appended, only 1 byte gets appended instead of 2.
QByteArray ba = QByteArray::fromHex("010203");
quint number(300);//300 in hex is 012c
ba.append(number);//What should be appended instead of just number?
//the current incorrect result is
ba.toHex() == "0102032c"
//the desired result is
ba.toHex() == "010203012c"
I've already tried this, but it just inserts the value as a string (4 bytes):
ba.append(QByteArray::number(number, 16));
What should I append to the QByteArray so both bytes of "number" get appended instead of just one byte? Also, the fastest method possible is preferred since this program needs to have great performance times. So absolutely no converting to QStrings.
Thanks for your time.
On its own, QByteArray only supports appending bytes; to append a big-endian representation of fixed-size integer types you can build your own operator<< (or what you prefer) overloads using the appropriate bit shifts:
QByteArray &operator<<(QByteArray &l, quint8 r)
{
l.append(r);
return l;
}
QByteArray &operator<<(QByteArray &l, quint16 r)
{
return l<<quint8(r>>8)<<quint8(r);
}
QByteArray &operator<<(QByteArray &l, quint32 r)
{
return l<<quint16(r>>16)<<quint16(r);
}
This allows you to write code like:
QByteArray b;
b<<quint16(300); // appends 0x01 0x2c
b<<quint8(4); // appends 0x04
b<<quint16(4); // appends 0x00 0x04
b<<quint32(123456); // appends 0x00 0x01 0xe2 0x40
b<<quint8(1)<<quin16(2)<<quint32(3); // appends 0x01 0x00 0x02 0x00 0x00 0x00 0x03
You should probably avoid writing
QByteArray b;
b<<1;
because in theory the output depends on the size of the current platform integer (although AFAIK on all platforms supported by Qt int is 32 bit).
I am using the Wire class to have two Arduino Unos communicate using I2C. It seems that the Wire class ends transmission on a value of 0. So if I send bytes 0x01, 0x02, 0x00, and 0x04, the master receives: 0x01, 0x02, 0xFF, 0xFF.
It seems odd that a communication network designed for processor communication cannot send a 0x00. All the examples for I2C that I have seen use ASCII only. Inter-processor communication restricted to ASCII does not seem to make any sense. Am I missing something with I2C or is this just an implementation limitation of the Arduino Wire class?
Master
void loop() {
Wire.requestFrom(2, 4);
while(Wire.available()) {
byte b = (byte) Wire.read();
Serial.println(b);
}
delay(1000);
}
Slave
void requestEvent() {
char bytes[4] = {0x01,0x02,0x00,0x04};
Wire.write(bytes);
}
The results are: 1 2 255 255.
When that 0x00 was 0x03 I got the expected: 1 2 3 4.
You are passing an array of chars to Wire.write()... This makes Wire treat the argument as a null-terminated string, and therefore the NULL byte terminates the transmission. If you want to send bytes, call the write() function once for each byte, passing it byte types.
Alternatively, you can call the write(const uint8_t *, size_t); version: you pass it a pointer to / array of bytes, but you also have to give it a size of your data array.
Do you have Wire.begin() and Wire.beginTransmission() (with correct address) happening before calling Wire.write()?
I have defined the following struct to represent an IPv4 header (up until the options field):
struct IPv4Header
{
// First row in diagram
u_int32 Version:4;
u_int32 InternetHeaderLength:4; // Header length is expressed in units of 32 bits.
u_int32 TypeOfService:8;
u_int32 TotalLength:16;
// Second row in diagram
u_int32 Identification:16;
u_int32 Flags:3;
u_int32 FragmentOffset:13;
// Third row in diagram
u_int32 TTL:8;
u_int32 Protocol:8;
u_int32 HeaderChecksum:16;
// Fourth row in diagram
u_int32 SourceAddress:32;
// Fifth row in diagram
u_int32 DestinationAddress:32;
};
I now also captured an IP frame with Wireshark. As an array literal it looks like this:
// Captured with Wireshark
const u_int8 cIPHeaderSample[] = {
0x45, 0x00, 0x05, 0x17,
0xA7, 0xE0, 0x40, 0x00,
0x2E, 0x06, 0x1B, 0xEA,
0x51, 0x58, 0x25, 0x02,
0x0A, 0x04, 0x03, 0xB9
};
My question is: How can I create a IPv4Header object using the array data?
This doesn't work because of incompatible endianness:
IPv4Header header = *((IPv4Header*)cIPHeaderSample);
I'm aware of the functions like ntohs and ntohl, but it can't figure out how to use them correctly:
u_int8 version = ntohs(cIPHeaderSample[0]);
printf("version: %x \n", version);
// Output is:
// version: 0
Can anyone help?
The most portable way to do it is one field at a time, using memcpy() for types longer than a byte. You don't need to worry about endianness for byte-length fields:
uint16_t temp_u16;
uint32_t temp_u32;
struct IPv4Header header;
header.Version = cIPHeaderSample[0] >> 4;
header.InternetHeaderLength = cIPHeaderSample[0] & 0x0f;
header.TypeOfServer = cIPHeaderSample[1];
memcpy(&temp_u16, &cIPHeaderSample[2], 2);
header.TotalLength = ntohs(temp_u16);
memcpy(&temp_u16, &cIPHeaderSample[4], 2);
header.Identification = ntohs(temp_u16);
header.Flags = cIPHeaderSample[6] >> 5;
memcpy(&temp_u16, &cIPHeaderSample[6], 2);
header.FragmentOffset = ntohs(temp_u16) & 0x1fff;
header.TTL = cIPHeaderSample[8];
header.Protocol = cIPHeaderSample[9];
memcpy(&temp_u16, &cIPHeaderSample[10], 2);
header.HeaderChecksum = ntohs(temp_u16);
memcpy(&temp_u32, &cIPHeaderSample[12], 4);
header.SourceAddress = ntohl(temp_u32);
memcpy(&temp_u32, &cIPHeaderSample[16], 4);
header.DestinationAddress = ntohl(temp_u32);
ntohl and ntohs don't operate on 1-byte fields. They are for 32 and 16 bit fields, respectively. You probably want to start with a cast or memcpy then byte swap the 16 and 32-bit fields if you need to. If you find that version isn't coming through with that approach without any byte swapping, then you have bit field troubles.
Bit fields are a big mess in C. Most people (including me) will advise you to avoid them.
You want to take a look at an the source for ip.h, that one is from FreeBSD. There should be a pre-dedined iphdr struct on your system, use that. Don't reinvent the wheel if you don't have to.
The easiest way to make this work is to take a pointer to the byte array from wireshark and cast it into a pointer to an iphdr. That'll let you use the correct header struct.
struct iphdr* hrd;
hdr = (iphdr*) cIPHeaderSample;
unsigned int version = hdr->version;
Also, htons takes in a 16-bit and changes the byte order, calling it on a 32-bit variable is just going to make a mess of things. You want htonl for 32-bit variables. Also note that for a byte there is no such thing as an endianess, it takes multiple bytes to have different endianess.
Updated:
I suggest you use memcpy to avoid the issues of bitfields and struct alignment, as this can get messy. The solution below works on a simple example, and can be easily extended:
struct IPv4Header
{
uint32_t Source;
};
int main(int argc, char **argv) {
const uint8_t cIPHeaderSample[] = {
0x45, 0x00, 0x05, 0x17
};
IPv4Header header;
memcpy(&header.Source, cIPHeaderSample, sizeof(uint8_t) * 4);
header.Source= ntohl(header.Source);
cout << hex << header.Source<< endl;
}
Output:
45000517