I am trying to retrieve Service Data information from Bluetooth devices using QBluetoothDeviceInfo class (Qt 6.3), but when it contains bytes with 0 values it gets truncated.
For example I have the Service Data in my bluetooth device written as 0xFF2233000065: the problem is that serviceData() method of QBluetoothDeviceInfo returns a QByteArray that has only the first three bytes FF, 22, 33 and stops when it founds 00.
Any of you has encountered such a similar issue?
Thank you in advance
edit: Here I paste excerpts from my code, trying to clarify my issue:
//...
discoveryAgent = new QBluetoothDeviceDiscoveryAgent();
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
this, &BluetoothController::addDevice);
//...
void BluetoothController::addDevice(const QBluetoothDeviceInfo &device)
{
//...
QBluetoothUuid sId = device.serviceIds().front();
//Here is the problem: instead of having sData composed by 6 bytes
//as expected in my test (i.e 0xFF 0x22 0x33 0x00 0x00 0x65),
//sData has size = 3 and has only 0xFF 0x22 0x33
QByteArray sData = device.serviceData(sId);
//...
}
Related
I'm constantly sending structs of int64 via Pyserial with:
with serial.Serial(port='COM4', baudrate=115200, timeout=.1) as arduino:
value = write_read(struct.pack(">q", int_array[1][i])) #this sends signed int.64 in bytes
print(value)
the struct.pack has this shape, for example:
b'\xff\xff\xff\xff\xff\xff\xff\xef'
and the function write_read consists of:
def write_read(x):
arduino.write((x))
data = arduino.readline()
#the idea is to receive an ACK from the Arduino after 8 bytes (the full
#number)
return data
The code I'm trying to develop in arduino is the following:
void loop() {
// send data only when you receive data:
if (Serial.available() \> 0) {
// read the incoming byte:
incomingByte = Serial.read();
//read 8 bytes and create the result
r= function_to_read_8_last_bytes // or similar
// say what you got:
Serial.print("I received: ");
Serial.printlesultn(r, DEC);
Serial.write("ACK");
}
}
I'm very curious how I could do a robust "read 8 bytes" function.
Should I add some especial character in the Python part to indentify when it ends one value?
Thanks! I'll appreciate any help :)
Given the discussion in the comments, it's hard to receive a stream of bytes and be sure that the receiver is completely synchronized. However let's make some assumptions to ease the problem:
The serial buffer is empty when you connect your laptop to Arduino. This ensures you won't receive spurious data with no meaning. I had this problem happens a lot when the serial connection was ended abruptly by any cause.
You are not constantly sending bytes, Arduino has time to process them until the start of the new sequence.
You only send this data, so there is no need to create a higher level protocol on top of it. Bare in mind that the serial communication is almost just an hardware stack, you receive bytes with no headers.
For assumption 1 you can write a simple piece of code to consume all the spurious bytes in the serial buffer as soon as your main starts from Arudino, so this will be done everytime you connect the serial (as this is also where the power supply comes from). Something like this:
void serialFlush(){
while(Serial.available() > 0) {
char t = Serial.read();
}
}
You can send a "READY" signal back to the Python interface, so that the program knows you are ready to receive data.
Going on with the solution you can implement an easy CRC in python, an additional byte which contains a XOR of all the previous bytes, and you check that in Arduino upon reception complete.
def xor_reduce_long_int(li):
res = 0;
for i in range(8):
mask = (0xFF)<<(i*8)
print(hex(mask))
masked = (li&mask)>>(i*8)
res ^= masked
return res
with serial.Serial(port='COM4', baudrate=115200, timeout=.1) as arduino:
crc=xor_reduce_long_int(int_array[1][i])
value = write_read(struct.pack(">qc", int_array[1][i],crc)) #this sends signed int.64 in bytes
print(value)
And with Arduino I would read 8 bytes when they are available and put them into an unsigned char buffer. I would then define a union that alias such buffer to interpret it as long long int.
typedef struct long_int_CRC
{
union
{
unsigned char bytes[8];
long int data;
};
unsigned char CRC;
}data_T;
// .. Later in main
data_T = received_data;
int received_bytes=0
unsigned char my_CRC = 0;
unsigned char rec_byte= 0;
while( received_bytes < 8 )
{
if(Serial.available() )
{
// Get the byte
rec_byte = Serial.read()
// Store the byte and calc CRC
received_data.bytes[received_bytes] = rec_byte;
my_CRC ^= rec_byte;
// Increment counter for next byte
received_bytes++;
}
}
// Reception complete, check CRC
unsigned char rec_CRC;
if(Serial.available() )
{
rec_CRC = Serial.read()
}
if( my_CRC != rec_CRC )
{
// Something was wrong!
}
// Now access your data as a long int
Serial.print("I received: ");
Serial.printlesultn(received_data.data, DEC);
Serial.write("ACK");
I'm trying to get a GY-US-42 ultrasonic sensor working on the ESP32. However, I keep getting an error while compiling. For and Arduino Board it is not a problem, but for the ESP32.
My code:
#include "Wire.h"
//The Arduino Wire library uses the 7-bit version of the address, so the code example uses 0x70 instead of the 8-bit 0xE0
#define SensorAddress byte(0x70)
//The sensors ranging command has a value of 0x51
#define RangeCommand byte(0x51)
//These are the two commands that need to be sent in sequence to change the sensor address
#define ChangeAddressCommand1 byte(0xAA)
#define ChangeAddressCommand2 byte(0xA5)
void setup() {
Serial.begin(115200); //Open serial connection at 9600 baud
Wire.begin();
// changeAddress(SensorAddress,0x40,0);
}
void loop(){
takeRangeReading(); //Tell the sensor to perform a ranging cycle
delay(50); //Wait for sensor to finish
word range = requestRange(); //Get the range from the sensor
Serial.print("Range: "); Serial.println(range); //Print to the user
}
//Commands the sensor to take a range reading
void takeRangeReading(){
Wire.beginTransmission(SensorAddress); //Start addressing
Wire.write(RangeCommand); //send range command
Wire.endTransmission(); //Stop and do something else now
}
//Returns the last range that the sensor determined in its last ranging cycle in centimeters. Returns 0 if there is no communication.
word requestRange(){
Wire.requestFrom(SensorAddress, byte(2));
if(Wire.available() >= 2){ //Sensor responded with the two bytes
byte HighByte = Wire.read(); //Read the high byte back
byte LowByte = Wire.read(); //Read the low byte back
word range = word(HighByte, LowByte); //Make a 16-bit word out of the two bytes for the range
return range;
}
else {
return word(0); //Else nothing was received, return 0
}
}
Error:
sketch/GY-US42_I2C.ino.cpp.o:(.literal._Z12requestRangev+0x0): undefined reference to `makeWord(unsigned short)'
sketch/GY-US42_I2C.ino.cpp.o: In function `requestRange()':
/Users/Arduino/GY-US42_I2C/GY-US42_I2C.ino:42: undefined reference to `makeWord(unsigned short)'
collect2: error: ld returned 1 exit status
The word() is for casting a variable or literal into a 16-bit word, it does not add two bytes into a 16-bit word as you do word(HighByte, LowByte), I'm actually surprise this even compiled in Arduino.
To get the range value, you could do:
int range = HighByte * 256 + LowByte;
or:
int range = ((int)HighByte) << 8 | LowByte; //cast HighByte to int, then shift left by 8 bits.
But since Wire.read() is returning an int instead of a byte(you can see its function prototype definition here), therefore you code can actually be written like this:
int reading = Wire.read(); //read the first data
reading = reading << 8; // shift reading left by 8 bits, equivalent to reading * 256
reading |= Wire.read(); // reading = reading | Wire.read()
By the way, when you use #define, you don't need to specifically cast the const value into specific data type, the compiler will take care of the optimization and the right data type, so:
#define SensorAddress byte(0x70)
would be just fine by defining like this:
#define SensorAddress 0x70
You also do not need to cast const value with byte(2) or return word(0). In the latter case, your function prototype already expect the return would be a data type of word.
I'm trying to store an array of LED patterns to EEPROM, to later write to an external flash module. Below is my header file containing the patterns.
#ifndef DefaultPatterns_h
#define DefaultPatterns_h
#define DEFAULT_SIZE 147
const byte defaultData[DEFAULT_SIZE] PROGMEM ={225,112,111,};
#define RAINBOWPIXEL_SIZE 972
const byte rainbowpixelData[RAINBOWPIXEL_SIZE] PROGMEM ={255,0,0,0,0,0,0};
#endif
I've cut some bytes out from the above patterns as they are too long for this post.
Below is my sketch that is taken from ESP8266 EEPROM example library and I'm trying to use it as a starting point. I've commented out some things I've tried. Remember the patterns are in a header file.
#include "EEPROM.h"
#include "defaultPatterns.h"
int addr = 0;// address of EEPROM to write to
void setup() {
EEPROM.begin(512);
}
void loop() {
Serial.begin(9600);
//const byte defaultData[] = PROGMEM(defaultData,DEFAULT_SIZE );
// write the value to the appropriate byte of the EEPROM.
// these values will remain there when the board is
// turned off.
// EEPROM.write(addr, val);
//EEPROM.write(addr,byte (defaultData)) sizeof(defaultData));
//EEPROM.write ( 0, (byte *)defaultData), sizeof(defaultData)));
const char pattern = defaultData ;
EEPROM.write(addr, pattern);
// advance to the next address. There are 512 bytes in
// the EEPROM, so go back to 0 when we hit 512.
// save all changes to the flash.
addr = addr + 1;
if (addr == 512) {
addr = 0;
EEPROM.commit();
}
delay(100);
}
I've tried all sorts of different ways, but I'm getting errors and syntax errors.
I've tried to do this myself but I'll be at it forever. Any help that would be great.
I'm trying to build a LED controller that can store lots of patterns in the form of the patterns in the header file and play them back via a WS2812B strip of LEDs on button press. I've a long way to go.
Why use flash you ask? Space, I need lots of space. I know flash wears out faster, but I can replace it for a few bucks.
Look at the definition of EEPROM.write() - it only writes one byte. You need to use a for loop or EEPROM.put().
I'm experiencing unexpected results using wiringPi's wiringPiI2CWriteReg16() function, and I'm not sure if it's due to incorrect usage, or something else. This is the declaration for the function:
extern int wiringPiI2CWriteReg16 (int fd, int reg, int data);
There are notes within the wiringPiI2C.c file that state it resembles Linux's SMBus code, if that helps.
On my Arduino (both an Uno R3 and a Trinket Pro), I am running this pared-down sketch:
#include <Wire.h>
#define SLAVE_ADDR 0x04
void receive_data (int num_bytes){
Serial.print("bytes in: ");
Serial.println(num_bytes);
while(Wire.available()){
int data = Wire.read(); // tried char, uint8_t etc
Serial.println(data);
}
Serial.print("\n");
}
void setup() {
Serial.begin(9600);
Wire.begin(SLAVE_ADDR);
Wire.onReceive(receive_data);
}
void loop() {
delay(500);
}
I would think that Wire.read() would break things apart at the byte boundary, but that's not occurring in my case. Perhaps this is my issue... a misunderstanding.
Nonetheless, I have this C code (requires wiringPi v2.36+ to be installed):
// word.c
#include <wiringPiI2C.h>
void main (){
int fd = wiringPiI2CSetup(0x04);
wiringPiI2CWriteReg16(fd, 0x00, 255);
wiringPiI2CWriteReg16(fd, 0x01, 256);
}
Compiled like this:
gcc -o word word.c -lwiringPi
When run, ./word, I receive the following on my Arduino's serial output:
bytes in: 3
0
255
0
bytes in: 3
1
0
1
In the first call to wiringPiI2CWriteReg16(), I expect the first byte in the output to be zero (0x00) as that's the register address I'm requesting. The second byte (255) is also correct. The third byte (0) is meaningless from what I can tell (as I'm only sending in one byte as data).
However, in the second call to that function, I do get the correct output for the register (first byte as 0x01 == 1), but the second byte is zero, and the third byte has what appears to be the correct remainder (255 == one byte, + 1). The problem is, is that the second byte is 0.
The exact same effect happens if I pass in 511 or for that matter, any number as the data in the call.
My question is whether I'm missing something glaringly obvious (I'm relatively new to C and Arduino), and/or if I can get some pointers on how to troubleshoot this more thoroughly.
I found that the problem was in my Arduino code. In the official Raspi forums, Gordon tipped me off that the bytes are read in separately, LSB first. Throughout all of my searching, I hadn't come across that, and really didn't quite understand what was happening. After changing my I2C read loop code in my Arduino sketch to this:
while(Wire.available()){
Wire.read(); // throw away register byte
int16_t data = Wire.read(); // LSB
data += Wire.read() << 8; // MSB
Serial.print("data: ");
Serial.println(data);
}
...everything works. In effect, that's at least one way to read two-byte values over I2C on the Arduino and put the bytes back together.
I am working with an Arduino Uno and an adaFruit PN532 board. The goal is to be able to create a list of MiFare Cards currently in range of the NFC Shield.
I am having trouble figuring out the best way to write this logic, as the board only seems to detect one card per loop.
I can place two cards on the board and it sees them both but only one per loop. so how would i go about creating a current list of what is currently in range
my loop:
void loop()
{
Serial.println("--------------------Loop begin-------------------");
uint8_t success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
uint8_t index =0;
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
// 'uid' will be populated with the UID, and uidLength will indicate
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
if (success) {
// Display some basic information about the card
Serial.println("Found an ISO14443A card");
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
Serial.print(" UID Value: ");
nfc.PrintHex(uid, uidLength);
Serial.println("");
}
Serial.println("************************Loop END*********************");
}
and here is the serial monitor out when both cards in range:
--------------------Loop begin-------------------
Found an ISO14443A card
UID Length: 4 bytes
UID Value: 0x13 0x99 0x1C 0xD4
**********************Loop END*******************
--------------------Loop begin-------------------
Found an ISO14443A card
UID Length: 4 bytes
UID Value: 0x13 0x34 0x27 0xD4
**********************Loop END*******************
You need some state (something like an array of a struct with ID and length fields) outside of the loop to store your (potentially multiple) UIDs. Looking at the code for readPassiveTargetID I would think it's likely to be be a bit random which card ID is returned if there is more than one of them.
I imagine you'll need to keep reading IDs, checking the array to see if you've seen it before and storing it if not. Then after some time (or the array overflows, or some other trigger) you can print out the IDs you have seen "recently" and reset the array to being empty (eg by clearing the length field)