How to retrieve data size larger than Qt Modbus InputRegisters? - qt

From what I understand, the range of QModbusDataUnit::InputRegisters is range 0-65535 which is unsigned short.
The method to read 1 unit of inputregisters is as follows:
QModbusDataUnit readUnit(QModbusDataUnit::InputRegisters, 40006, 1);
The value of that will be in the reply, i.e : int value = result.value(0);
My question is that what if I have to read a value of unsigned int which is much larger of the range of 0 to 4,294,967,295.
How can I retrieve that value?

As you stated, Modbus input registers are 16 bit unsigned integers. So without some type of conversion they are limited to the range: 0 - 65535. For 32-bit unsigned values it is typical (in Modbus) to combine two registers.
For example, the high 16-bits could be stored at 40006 and the low 16-bits at 40007.
So, if you were reading the value ‭2271560481‬ (0x87654321 hex), you would read ‭34661‬ (0x8765) from address 40006 and 17185 (0x4321 hex) from location 40007. You would then combine them to give you the actual value.
I don't know the Qt Modbus code, but expanding on your example code you can probably read both values at the same time by doing something like this:
readUnit(QModbusDataUnit::InputRegisters, 40006, 2);
and combine them
quint32 value = result.value(0);
value = (value << 16) | result.value(1);

Related

How can a 1 byte int conversion of a QByteArray fail?

So here is the thing, I'm receiving 1 byte from Bluetooth transmission. When using QDebug I get this message:
The array with error has "\x06"
The line that fails is this:
bool ok = true;
int v = value.toInt(&ok,0);
Because ok has false. But I'm trying to wrap my head around the fact that, How can the conversion fail in the first place if the data represented in that byte (as a sequence of zeros and ones) will always have a valid integer representation. (one byte can always be represented as a int between -127 and 128). So I'm left with the question, how can the conversion fail?
Reading the documentation does not provide many clues as it does not say how the byte array will be interpreted.
QByteArray::toInt converts a string representation in the default C locale to an integer. That means to successfully convert the value in your example, your byte array must contain the string "0x06", which consists of 4 bytes.
To convert a single byte to an int, just extract it:
int i = value[0];
Type promotion will widen the char to an int

Arduino loop update of a variable is incorrect

I've got the following code snippet in the setup() function:
...
unsigned int a0val;
unsigned int a0total = 0;
...
for (i = 0; i < 1000; i++) {
a0val = analogRead(A0);
Serial.println(a0val);
a0total += a0val;
}
Serial.println(a0total);
...
This is done to baseline the analog value at startup to account for different types of sensors being used. One type may read 0 and another may read some non-zero value. The point is to have a starting point reference by averaging 1000 readings at startup time. 1000 is obviously overkill, I'll cut back later.
Now, with 1000 readings somewhere between 128 and 130, I expect a0total to be around 129,000. However, the total consistently comes out less than half that number, like 63,722 in one example. It's not even half, it's less than that.
Another example: I add up the first 500 readings when they are all around 350-352, and the total came out to 43614. It looks like wrap-around, but I'm using unsigned int for both values so that can't be happening.
So to me it almost looks like "a0total += a0val" is not updating every loop, but that doesn't make sense either.
What am I missing?
Thanks,
Ron
You are missing size of unsigned int on this platform. It is 16bits and therefore the maximum value is 65535.

zigbee module callback function incompatible to ZCL spec

I have followed the ZCL report to implement the function which is able to receive the data sent from the sensor.
In the SDk, it is defined as the following:
void ZbZclReportFunc{
struct ZbZclClusterT * clusterPtr,
zbApsdeDataInt * dataIndPtr,
uint16_t attributeId,
const uint8_t * data
}
By implementing the callback function as shown above, I am able to receive all information except data.
In ZCL spec, the Temperature Measurement Cluster defines its "MeasuredValue" Signed 16-bit Integer.
I print out the data using the following format:
printf("Degree: 0x%04x", *data);
As I expect, the data shown is "0x002b" as an example.
By casting it to Signed 16-bit integer, it does not help.
printf("Degree: 0x%04x", (int16_t)*data);
Any idea?
Thanks
Zigbee packet data is little Endian. Also, the units for MeasuredValue are "hundredths of degrees Celsius". So if your measured temperature value was 26 degrees celsius, your data buffer would look like: 28 0A. To convert to celsius you would use:
double temperature = (double)((int16_t)(data[1] << 8) | (int16_t)data[0]) / 100.0;

How to determine checksum from decoded IR remotes

I have a small 3.5ch USeries helicopter controlled by an IR remote control, using an Arduino I have decoded its 32 bit protocol. Except for last 3 bits which appear to be some form of checksum. As I have successfully decoding the channels from the remote, in that they track their corresponding controls, I can see that slight changes in the controls yield specific changes in the 3 bits, that are very reproducible and deterministic. Whereas I have not yet found a common theme or formal to reproduce the supposed checksum. I have tried simple things like Parity or Added Checksum. I can see the effects of changing specific bits on the cksum but when I combine the changes they don't simply add to the 3 bit value.
struct Useries // bit structure recieved from 32 bit IR command
{
unsigned cksum : 3; // 0..2
unsigned Rbutton : 1; // 3
unsigned Lbutton : 1; // 4
unsigned Turbo : 1; // 5
unsigned Channel : 2; // 6,7
unsigned Trim : 6; // 8..13
unsigned Yaw : 5; // 14..18
unsigned Pitch : 6; // 19..24
unsigned Throttle : 7; // 25..31
};
So the question is "How can I determine the formula for the chksum?" or what ever it is, as to program a recreation of it.
As it appears deterministic one should be able to take the recorded output of cksum and the other 27 bits and derive a formula for it. Much like PLD logic. Whereas the stimuls being 2^27 bit or 128M possibilities, versus the output being only 2^3 or 8 I would suspect even a small sample of <1% or less would provide the formula.
Another way, Is to look at it as a crypto problem and the 3 bit cksum is a hash.
Either way. Any methods or guidance as to determine the solution is greatly appreciated.
Here is sample data
FYI - The USeries is not the Syma. The Syma's decode does not have a cksum. Once I get the USeries chksum determined I will open source them from a fork of Ken Shirriff.
Just FYI
Struct SymaR5// bit structure recieved from 32 bit IR command
{
unsigned Trim : 8; // 0..7 0x7F
unsigned Throttle : 7; // 8..15 0x7F
unsigned Channel : 1; // 16 0x01
unsigned Pitch : 8; // 17..24 0x7F
unsigned Yaw : 8; // 25..31 0x7F
};
A quick check on parity masks results in seven masks that always give parity zero on your data. (Two of your bits are always the same, so I made an assumption about regularity in the mask to eliminate some contenders.) The masks are:
0x2e5cb972
0x5cb972e5
0x72e5cb97
0x972e5cb9
0xb972e5cb
0xcb972e5c
0xe5cb972e
Any of these masks anded with any of your data values (all 32 bits) results in parity zero. Three can be considered special, since each of your identified parity bits occurs just once respectively in those three (the ones ending in 2, 9, and c). So those three masks without the last three bits can be used to get each of the parity bits.
The mask repeats these seven bits: 0010111. This C code uses shifts and exclusive-ors to apply the mask and parity calculation:
p = x;
while ((x >>= 7) != 0)
p ^= x;
p = (p ^ (p >> 1) ^ (p >> 2) ^ (p >> 4)) & 7;
where x and p are 32-bit unsigned types. x is the 32 bits received. If p is zero when done, then the received value is good.

Qt - Get audio amplitude from QBytearray

I'm trying to create a program, using Qt (c++), which can record audio from my microphone using QAudioinput and QIODevice. I made a research and I came up with an example located on the this page. This example does what I need.
Now, I am trying to create an audio waveform of the recorded sound. I want to extract audio amplitudes and save them on a QList. To do that I use the following code:
//Check the number of samples in input buffer
qint64 len = m_audioInput->bytesReady();
//Limit sample size
if(len > 4096)
len = 4096;
//Read sound samples from input device to buffer
qint64 l = m_input->read(m_buffer.data(), len);
if(l > 0)
{
//Assign sound samples to short array
short* resultingData = (short*)m_buffer.data();
for ( i=0; i < len; i++ )
{
btlist.append( resultingData[ i ]);
}
}
m_audioInput is QAudioinput | m_buffer is QBytearray | m_input is QIODevice | btlist is QList
I use the following QAudioFormat:
m_format.setFrequency(44100); //set frequency to 44100
m_format.setSampleRate(44100); //set sample rate to 44100
m_format.setChannels(1); //set channels to mono
m_format.setSampleSize(16); //set sample sze to 16 bit
m_format.setSampleType(QAudioFormat::SignedInt ); //signed integer sample
m_format.setByteOrder(QAudioFormat::LittleEndian); //Byte order
m_format.setCodec("audio/pcm"); //set codec as simple audio/pcm
When I print my QList, using qWarning() << btlist.at(int), I get some positive and negative numbers which represents my audio amplitudes. I used Microsoft Excel to plot the data and compare it with the actual sound waveform.
(EDIT BASED ON THE OP COMMENT)
I am drawing the waveform using QPainter in Qt like this
for(int i = 1; i < btlist.size(); i++){
double x1 = (i-(i/1.25))-0.2;
double y1 = btlist.at(i-1);
double x2 = i-(i/1.25);
double y2 = btlist.at(i);
painter.drawLine(x1,y1,x2, y2);
}
The problem is that I also get lots of zeros (0) in my QList between the amplitude data like this, which if I draw as a waveform they are a straight line, which is not normal because it causes corruption to my waveform.
My question is why is that happening? What these zeros (0) represent? Am I doing something wrong? Also, is there a better way to extract audio amplitudes from QBytearray?
Thank you.
The drawline method you are using take integer values. Which means most of the time both of your x indexes will be the same. By simplifiyng your formula the x value at a given i is (i/5.0). By itself it is not an issue because the lines will be superposed, and it is a perfect way of drawing (just to make sure that's what you want to do).
The zero you see can be perfectly valid. They represent silence.
The real issue is that the range of your 16 bits PCM values is [-32767 , 32768]. I doubt that the paint device you are using cover this range. You need to normalize your y-axis. Moreover, it seems taht the qt coordinated system doesn't have negative values (edit: Nevermind the negatives, its says logical coordinates are converted).
For instance, convert your pcm values using :
((btlist.at(i) / MAX_AMPLITUDE + 1.0) / 2) * paintDevice.height();
Edit:
Btw, you are not using l, which is the real amount of data you read. If it is inferior to len, you will read invalid values at the end of your buffer, possibly read garbage\ read zeros\crash.
And your buffer is a byte buffer. And you iterate using a short pointer. So whether you use l or len the maximum size need to be divided by two. This is probably the cause of the ling line of zero in your picture.
for ( i=0; i < l/2; i++ )
{
btlist.append( resultingData[ i ]);
}

Resources