I'm looking for a way to sbitshift a QByteArray.
QByteArray statusByte = QByteArray::fromHex("40"); // 0100 0000
What i need to achieve is to get statusByte to 0x20 by bit shifting. Since I can't directly bit shift the QByteArray, what is the simplest method for achieving the shift?
You don't really need a byte array if you only want to get a single numeric (byte) value from a hexadecimal representation of one byte, not multiple bytes.
#if 1
// Qt 5, C++11 compilers
quint8 byte = QStringLiteral("40").toInt(nullptr, 16);
#endif
#if 0
// Qt 5, pre-C++11 compilers
quint8 byte = QStringLiteral("40").toInt(NULL, 16);
#endif
#if 0
// Qt 4
quint8 byte = QByteArray("40").toInt(NULL, 16);
#endif
byte >>= 1;
Q_ASSERT(byte == 0x20); // this is for demonstration only
If you need to bit-shift multiple bytes at once, of course it's also possible - please amend your question to make that clear.
Bit shifting is not a problem when you are talking about single byte, this is trivial (I don't know why you claim it is impossible).
QByteArray statusByte = QByteArray::fromHex("40");
statusByte[0] = statusByte[0]>>1;
statusByte[0]>>=1; // this should also work
if you have multiple bytes then it is more complicated!
endian! How do you define shift where the oldest bit should go, to next byte or to previos byte?
what should happen when array ends? loose data, or extend array?
Related
I'm working with .wav files and I need to get their duration in seconds.
So far I've been determining it with:
File size / byte_rate
Byte_rate being (Sample Rate * BitsPerSample * Channels) / 8.
And it works, with smaller files, when I try to parse bigger files, I get more seconds than the actual duration.
Example:
Size(bytes): 45207622 Byte_rate: 176400 Duration: 256
(45207622 / 176400)
but the actual duration is 250...
FYI: I've double checked the size and byte_rate, they are correct.
Without a sample RIFF header or your code, it would be difficult to answer the specifics in your question. (i.e. Why your math isn't coming to your expected result.)
However, since you've specified that you're working in C in the comments, might I suggest using the sox library instead of parsing the headers with newly written code? In addition to catching a fair number of edge cases, this allows you to support any format sox supports reading without having to write any of the reading code yourself. (Though anyone inclined to do so should probably take a look at Can someone explain .wav(WAVE) file headers? and RIFF WAVE format specifications. The process should be roughly the method described in the question, at least in most cases. [Edit: That is chunk data length divided by the header's byte rate.])
Example code:
#include <sox.h>
#include <stdio.h>
int main(int argc, char **argv) {
sox_format_t *fmt;
if(argc < 2) {
printf("Please provide audio file.\n");
return 1;
}
fmt = sox_open_read(argv[1], NULL, NULL, NULL);
__uint64_t ws = fmt->signal.length / fmt->signal.channels;
if(fmt->signal.length) {
printf("%0.2f seconds long\n", (double)ws / fmt->signal.rate);
} else {
printf("Cannot determine duration from header.\n");
}
}
For anyone curious, I largely derived this from the sox command line tool's source code.
Thank you EPR for giving me the fix to timing in my program. I'm not using libsox, I've set up a struct trying to match the original at http://www.lightlink.com/tjweber/StripWav/Canon.html This is NOT the correct way to do it but it works for simple files. Another useful reference is at http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
Anyway I assume the header is 44 bytes and read() it into memory at the location of the struct. Then I can access fields of the struct, malloc space for the pcm data and read() it into the pcm space from where the file pointer was left. I'm just writing an audiogram program so it needs to be close to correct for the WAV files I generate with arecord, sox, Audacity. Always 2 channels, 44100 sample rate. My struct:
struct wavhdr { // defined by Microsoft, needs to match
char riff[4]; // should be "RIFF"
uint32_t len8; // file length - 8
char wave[4]; // should be "WAVE"
char fmt[4]; // should be "fmt "
uint32_t fdatalen; // should be 16 (0x10)
uint16_t ftag; // format tag, 1 = pcm
uint16_t channels; // 2 for stereo
uint32_t sps; // samples/sec
uint32_t srate; // sample rate in bytes/sec (block align)
uint16_t chan8; // channels * bits/sample / 8
uint16_t bps; // bits/sample
char data[4]; // should be "data"
uint32_t datlen; // length of data block
// pcm data follows this
} hdr;
I was trying to use the measured file size - header length / samples/sec, that didn't work, I was off by a factor of 6.
Basically I am looking to make an serial-like system that runs communication between IR LEDs on an arduino. Below the code gets to the point having an array with a collection of 1s and 0s in it. I need to convert this 8 bit array into a single character and output it. But I don't know how to do this. Help would be appreciated.
int IR_serial_read(){
int output_val;
int current_byte[7];
int counter = 0;
IR_serial_port = digitalRead(4);
if (IR_serial_port == HIGH){
output_val =1;
}
if (IR_serial_port == LOW){
output_val =0;
}
current_byte[counter] = output_val;
counter +=1
}
This would best be done with bitwise operators, I think the or function would be of best use here as it will set a bit if the input is 1 and not change it if it is 0, could use a loop to loop through your array and set the bits.
Looking at your code, are you sure you are receiving all 8 bits? You seem to be saving 7 bits.
As you are creating a byte array solely for the purpose of using only 1s and 0s, it suggest immediately setting the bits in the same loop.
Here is the code that I suggest:
byte inputByte = 0; // Result from IR transfer. Bits are set progressively.
for (byte bit = 0; bit < 8; bit++) { // Read the IR receiver once for each bit in the byte
byte mask = digitalRead(4); // digitalRead returns 1 or 0 for HIGH and LOW
mask <<= bit; // Shift that 1 or 0 into the bit of the byte we are on
inputByte |= mask; // Set the bit of the byte depending on receive
}
This would also be put inside a loop to read all the bytes in your data stream.
It is designed for readability and can be optimised further. It reads the least significant bit first.
You can also apply the same technique to your array if you wish to keep using an array of bytes just for 1s and 0s, just replace the digitalRead with the array location (current_byte[bit]).
I am programming Arduino and I am trying to Serial.print() bytes in hexadecimal format "the my way" (keep reading for more information).
That is, by using the following code
byte byte1 = 0xA2;
byte byte2 = 0x05;
byte byte3 = 0x00;
Serial.println(byte1, HEX);
Serial.println(byte2, HEX);
Serial.println(byte3, HEX);
I get the following output in the Serial Monitor:
A2
5
0
However I would like to output the following:
A2
05
00
In words, I would like to print the "full" hexadecimal value including 0s (05 instead of 0 and 00 instead of 0).
How can I make that?
Simple brute force method, is to write a routine as:
void p(char X) {
if (X < 16) {Serial.print("0");}
Serial.println(X, HEX);
}
And in the main code:
p(byte1); // etc.
sorry - not enough reputation to comment but found previous answer is not fully correct. Actually, the nice light way to code it should be :
void p(byte X) {
if (X < 10) {Serial.print("0");}
...
giving the code:
void p(byte X) {
if (X < 10) {Serial.print("0");}
Serial.println(X, HEX);
}
And in the main code:
p(byte1); // etc.
hope this helps
Use sprintf to print into a buffer (two chars per byte + null terminator):
byte byte1 = 0xA2;
byte byte2 = 0x05;
byte byte3 = 0x00;
char s[7];
sprintf(s, "%02x\n%02x\n%02x", byte1, byte2, byte3);
Serial.println(s);
Added new lines in between to get each on new line. About '%02x', the % means here comes formatting information, 0 means to pad with 0, 2 means pad input until 2 characters wide and x means give me this as hexadecimal.
For other formatting options see http://linux.die.net/man/3/sprintf
The lowest footprint in Memory, Code and runtime would be classic bit playing
byte b;
Serial.print(b>>4, HEX);
Serial.print(b&0x0F,HEX);
Which is working fine on any 8bit type. For any other mask also the first line to
Serial.print((b>>4)&0x0F, HEX);
Try this:
//Converts the upper nibble of a binary value to a hexadecimal ASCII byte.
//For example, btohexa_high(0xAE) will return 'A'.
unsigned char btohexa_high(unsigned char b)
{
b >>= 4;
return (b>0x9u) ? b+'A'-10:b+'0';
}
//Converts the lower nibble of a binary value to a hexadecimal ASCII byte.
// For example, btohexa_low(0xAE) will return 'E'.
unsigned char btohexa_low(unsigned char b)
{
b &= 0x0F;
return (b>9u) ? b+'A'-10:b+'0';
}
And in main code:
comand_mod=0xA1; //example variable
Serial.print(btohexa_high(comand_mod));
Serial.print(btohexa_low(comand_mod));
wow! 7 years ago and I felt here, my answer might be useful for you (hopefully not anymore) or others looking for the answers like me.
Use "Serial.write()" to send a hex byte over serial.
All Serial.print() eg. println, printf, sprint, print will "print" your value in ASCII.
I need to send floating point numbers using a UDP connection to a Qt application. Now in Qt the only function available is
qint64 readDatagram ( char * data, qint64 maxSize, QHostAddress * address = 0, quint16 * port = 0 )
which accepts data in the form of signed character buffer. I can convert my float into a string and send it but it will obviously not be very efficient converting a 4 byte float into a much longer sized character buffer.
I got hold of these 2 functions to convert a 4 byte float into an unsinged 32 bit integer to transfer over network which works fine for a simple C++ UDP program but for Qt I need to receive the data as unsigned char.
Is it possible to avoid converting the floatinf point data into a string and then sending it?
uint32_t htonf(float f)
{
uint32_t p;
uint32_t sign;
if (f < 0) { sign = 1; f = -f; }
else { sign = 0; }
p = ((((uint32_t)f)&0x7fff)<<16) | (sign<<31); // Whole part and sign.
p |= (uint32_t)(((f - (int)f) * 65536.0f))&0xffff; // Fraction.
return p;
}
float ntohf(uint32_t p)
{
float f = ((p>>16)&0x7fff); // Whole part.
f += (p&0xffff) / 65536.0f; // Fraction.
if (((p>>31)&0x1) == 0x1) { f = -f; } // Sign bit set.
return f;
}
Have you tried using readDatagram? Or converting the data to a QByteArray after reading? In many cases a char* is really just a byte array. This is one of those cases. Note that the writeDatagram can take a QByteArray.
Generally every thing sent across sockets is in bytes not strings, layers on either end do the conversions. Take a look here, especially the Broadcaster examples. They show how to create a QByteArray for broadcast and receive.
Not sure why the downvote, since the question is vague in requirements.
A 4-byte float is simply a 4 character buffer, if cast as one. If the systems are homogenous, the float can be sent as a signed char *, and bit for bit it'll be the same read into the signed char * on the receiver directly, no conversion needed. If the systems are heterogenous, then this won't work and you need to convert it to a portable format, anyway. IEEE format is often used, but my question is still, what are the requirements, is the float format the same between systems?
If I read it correctly, your primary question seems to be how to receive data of type unsigned char with QT's readDatagram function which uses a pointer to a buffer of type char.
The short answer is use a cast along these lines:
const size_t MAXSIZE = 1024;
unsigned char* data = malloc(MAXSIZE);
readDatagram ( (unsigned char *)data, MAXSIZE, address, port )
I'm going to assume you have multiple machines which use the same IEEE floating point format but some of which are big endian and some of which are little endian. See this SO post for a good discussion of this issue.
In that case you could do something a bit simpler like this:
const size_t FCOUNT = 256;
float* data = malloc(FCOUNT * sizeof(*data));
readDatagram ( (char *)data, FCOUNT * sizeof(*data), address, port )
for (int i = 0; i != FCOUNT; ++i)
data[i] = ntohf(*((uint32_t*)&data[i]));
The thing to remember is that as far as networking functions like readDatagram are concerned, the data is just a bunch of bits and it doesn't care what type those bits are interpreted as.
If both ends of your UDP connection use Qt, I would suggest looking at QDataStream. You can create this from a QByteArray each time you read a datagram, and then read whatever values you require - floats, maps, lists, QVariants, and of course string.
Similarly, on the sending side, you'd create a data stream, push data into it, then send the resulting QByteArray over writeDatagram.
Obviously this only works if both ends use Qt - the data encoding is well-defined, but non-trivial to generate by hand.
(If you want stream orientated behaviour, you could use the fact that QUDPSocket is a QIODevice with a data-stream, but it sounds as if you want per-datagram behaviour)
As you may have figured out from the title, I'm having problems converting a QByteArray to an integer.
QByteArray buffer = server->read(8192);
QByteArray q_size = buffer.mid(0, 2);
int size = q_size.toInt();
However, size is 0. The buffer doesn't receive any ASCII character and I believe the toInt() function won't work if it's not an ASCII character. The int size should be 37 (0x25), but - as I have said - it's 0.
The q_size is 0x2500 (or the other endianness order - 0x0025).
What's the problem here ? I'm pretty sure q_size holds the data I need.
Something like this should work, using a data stream to read from the buffer:
QDataStream ds(buffer);
short size; // Since the size you're trying to read appears to be 2 bytes
ds >> size;
// You can continue reading more data from the stream here
The toInt method parses a int if the QByteArray contains a string with digits. You want to interpret the raw bits as an integer. I don't think there is a method for that in QByteArray, so you'll have to construct the value yourself from the single bytes. Probably something like this will work:
int size = (static_cast<unsigned int>(q_size[0]) & 0xFF) << 8
+ (static_cast<unsigned int>(q_size[1]) & 0xFF);
(Or the other way around, depending on Endianness)
I haven't tried this myself to see if it works but it looks from the Qt docs like you want a QDataStream. This supports extracting all the basic C++ types and can be created wth a QByteArray as input.
bool ok;
q_size.toHex().toInt(&ok, 16);
works for me
I had great problems in converting serial data (QByteArray) to integer which was meant to be used as the value for a Progress Bar, but solved it in a very simple way:
QByteArray data = serial->readall();
QString data2 = tr(data); //converted the byte array to a string
ui->QProgressBar->setValue(data2.toUInt()); //converted the string to an unmarked integer..
This works for me:
QByteArray array2;
array2.reserve(4);
array2[0] = data[1];
array2[1] = data[2];
array2[2] = data[3];
array2[3] = data[4];
memcpy(&blockSize, array2, sizeof(int));
data is a qbytearray, from index = 1 to 4 are array integer.
Create a QDataStream that operates on your QByteArray. Documentation is here
Try toInt(bool *ok = Q_NULLPTR, int base = 10) const method of QByteArray Class.
QByteArray Documentatio: http://doc.qt.io/qt-5/QByteArray.html