Qt Bluetooth Low Energy - Problems using non standard GATT - c++

I have a device without knowing the used gatt profile, I only know that is something "homemade" and not anything known on the bluetooth-database.
In Linux the command
gatttool -i hci0 -b xx:xx:xx:xx:xx:xx --char-read --handle=42
returns the value as expected (with the target device mac at xx:xx:xx:xx:xx:xx).
In Qt I am using the Heartbeat-Example from http://doc-snapshot.qt-project.org/qt5-5.4/qtbluetooth-heartlistener-example.html
there they connect using a gattprofile, QBluetoothUuid::HeartRate and QBluetoothUuid::HeartRateMeasurement
I wasn't able to modify the example code in a way to read handle 42.
Can you explain where I have to put which values, that it connects to the "standard profile" as the gattool command does? If I use gatttool in interactive mode and ask primary it returns two uuids, but using them instead of the QBluetoothUuid::HeartRate did not work.

It doesn't appear that the Qt Bluetooth Low Energy API provides means for obtaining access to characteristics based on their handle value. (Neither does the Windows 8 BLE API.) You should use the UUID. Even if it's a homemade device, all services and characteristics are required by the GATT protocol to have UUIDs. The lowenergyscanner demo app can discover and display both the UUIDs and handles of all of the device's services and characteristics. I've used lowenergyscanner to deal with BLE devices I'm developing.

device discovering is by uuid, even if you create a new profile with a new service and a new characteristic, you have to give the new characteristic uuid in setup.
But i dont know, how to add multiple characteristics to one service, it does not work with me.
have fun

Related

Qt Bluetooth stuck when connecting to Classic Bluetooth Device

I am currently trying to read out Bluetooth Signals from peripherals using classic BT to control my Qt application. Later on I might use a small BT joystick but for now I am trying to connect to the buttons on my paired headphones.
I have previously
..scanned for remote devices via the QBluetoothDeviceDiscoveryAgent, which returned the QBluetoothDeviceInfo of my headphones.
...scanned for the services on that device using the QBluetoothServiceDiscoveryAgent, which returned QBluetoothServiceInfo with QBluetoothUuid::AV_RemoteControl
...added a socket which should connect to the device, like so:
socket0 = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol);
connect(socket0, &QBluetoothSocket::stateChanged, this , &BluetoothController::socketStateChanged);
connect(socket0, &QBluetoothSocket::readyRead, this, &BluetoothController::readSocket);
connect(socket0, &QBluetoothSocket::connected, this, &BluetoothController::serverConnected);
connect(socket0, &QBluetoothSocket::disconnected, this, &BluetoothController::serverDisconnected);
connect(socket0, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
this, &BluetoothController::serverError);
QBluetoothAddress address = info.device().address();
QIODevice::ReadOnly);
socket0->connectToService(address, QBluetoothUuid::AV_RemoteControl, QIODevice::ReadOnly);
At this point the socket state changes to ConnectingState, does not through an error, but also does not not trigger my readyRead() function.
I am new to Bluetooth and may be misunderstanding the concept of how connecting exactly works, so any help will be greatly appreciated.
PS.: I am working on Linux Ubuntu 18.04 and the application log also puts out:
qt.bluetooth.bluez: Missing CAP_NET_ADMIN permission. Cannot determine
whether a found address is of random or public type.
You are trying to run your software as a non-root user. The Bluetooth protocol stack for Linux checks two capabilities, which are required for operations like ones mentioned in your error log — CAP_NET_RAW and CAP_NET_ADMIN. Capabilities are an alternative to "all or nothing" approach with privileged user (root). This gives more fine-grained control over permissions to unprivileged user so it can gain only a part of root's privileges. For more details, read man 7 capabilities.
There're several techniques for leveraging capabilities, one of them are file capabilities. You can achieve the desired effect with setcap(8) like this:
sudo setcap 'cap_net_raw,cap_net_admin+eip' yourapplication

How can I know if a USB device is already in use?

I am writing a C++ Linux userspace driver for a USB device using the C library libusb. I have two copies of the same device (same vendor ID and product ID) and would like to know how to handle this case.
Here are the possibilities I can think of:
libusb_get_device_list() returns only devices that are not currently in use
I can differentiate the used vs. unused devices using information of the device descriptor, using libusb_get_device_descriptor()
libusb_open() on the currently in-use device will fail, by returning either LIBUSB_ERROR_ACCESS or LIBUSB_ERROR
How should I deal with this? Which of the preceding options, if any, is the behaviour of libusb when dealing with many of the same devices? How can I differentiate between the in-use device and the idle one?
As #fiscblog said in his answer, "Identification is done via the device descriptor (use the serialnumber which should always be unique)". My problem here is that, in order to do so, the two drivers should communicate to know which instance is handling which device (using, for instance, a file), and I would like to avoid this. I also would like to avoid having to introduce multithreading and manage two devices with one driver, as I don't have the skills to do so in an efficient and well-controlled way (nasty race conditions ... !)
The correct handling is:
enumerate all devices (get device list)
identify the requested device and open it
Identification is done via the device descriptor (use the serialnumber which should always be unique), as you discovered yourself.
How to know if a device is in use?
If a device is open, the endpoints will be bound and configured for I/O. Therefore you cannot open it again but will get the error codes you mentioned.
According to the documentation on libusb_claim_interface():
Interface claiming is used to instruct the underlying operating system that your application wishes to take ownership of the interface.
so you should be able to call libusb_claim_interface() on each device and it should only succeed on the unclaimed one:
It is legal to attempt to claim an already-claimed interface, in which case libusb just returns 0 without doing anything.
libusb is written in C and follows the same basic general guidelines for accessing devices, file descriptors, streams, etc.
1 - Connect to de device
2 - Check the connection, if there's an error, inform and return
3 - There's no error!! Interact
Following this basic flow, the solution in your case IMHO is as simple as:
Identify the devices
Iterate througth them trying to connect until one throws no failure
do something
close

Bluetooth C++ Winapi Discoverable

I'm using source codes based from the following links w/my broadcom bluetooth device:
I want to make a bluetooth server that automatically starts and other devices can pair with it.
http://www.codeproject.com/Articles/252882/Bluetooth-Server-Programming-on-Windows
http://msdn.microsoft.com/en-us/library/windows/desktop/aa362932(v=vs.85).aspx
I can get the code to compile fine, allegedly the server starts, it tells me my local bluetooth device, the server port, but I cannot see the advertisement when I scan for bluetooth devices w/my iphone or ipad.
Device manager reports my bluetooth driver as functional. I'm doing this in a vm machine on win 7.
Both links say nothing about BluetoothEnableDiscovery() function. Would I need this? I tried but not sure how it works.
Everything looks ok, in the entire process I don't receive a single error. I just think I need to set it to discoverable some how or make it advertise so my other devices can see it and pair with it.
If you have any ideas, I would appreciate them. Thanks.
EDIT: Would anyone know how I can change between Secure Simple Pairing modes, or set a a 4/8 digit key for pairing in winapi c++?
With Microsoft BT stack (even with a Widcomm dongle), under Win7, your server has to expose a 'service' first.
it can be "Discoverable' but without any service exposed, no-one will "see" your server from the outside.
Check out WSASetService: https://msdn.microsoft.com/en-us/library/aa362921(v=vs.85).aspx
PS: the service will live during your app execution only...

Accessing COM device names in C++/Win7

I'm trying to write a program that sends COM port information to devices that may get unplugged and end up with a different COM port number. Using SetupDi, I know it's possible to list all the COM ports on a computer by number, but given that the number might change I'm trying to find a better way to access the COM ports.
The COM devices I'm using are FTDI serial-to-com adapters that let me program the device model. I'd love to be able to choose a COM port based on the device model. I've tried (almost) all of the properties that I can get to using SetupDi, but no dice. It looks like there's a difference between the device list SetupDi lets me access, and the devices that show up under Devices and Printers (where the model name does show up). Is there any way to get devices in the Devices and Printers window programmatically and map them to COM port using Windows APIs?
The link below is a great (if not the only) comprehensive overview on how to enumerate COM ports on Windows and extract extra information in various ways:
http://www.naughter.com/enumser.html
What we use in our own software (Docklight) is according to what the "UsingSetupAPI1" way from the enumser.cpp file shows (SetupAPI - GUID_DEVINTERFACE_COMPORT). The UsingSetupAPI1 example demonstrates how to extract the device name as shown in the Windows Device Manager, along with the COM number. This is called "friendlyNames" in the enumser.cpp code.
Another way to identify and communicating to your device could be not asking Windows in the first place, but the FTDI D2XX API:
http://www.ftdichip.com/Support/SoftwareExamples/CodeExamples.htm
We use the D2XX API for communication when we know it is always a FTDI device. Identification is simpler and we have much better performance / less latency than using Windows Communications API via "virtual COM port".
If we need to correlate between COM port numbers and a FTDI device ID, we use the FTDI D2XX API's ListDevices and GetComPortNumber functions.

Uniquely identify PC based on software/hardware

For a requirement to generate per-PC license keys, I need some code which will return a stable and (near) unique key on any PC. It doesn't have to be guaranteed unique, but close. It does need to be reasonably stable though, so that a given PC always generates the same result unless the hardware is substantially changed.
This is for a Windows application, using wxWidgets but a Win32 or other option is fine.
I was thinking about MAC address but what about laptops which can routinely disable the network card in power-saving mode? I came across GetCurrentHwProfile but it doesn't quite look like what I want?
One idea I had a while back for this is to use CryptProtectData as a way to identify a machine. Behind-the-scenes in that API, Microsoft has done what you're looking for. I never tested it though and I'm curious if it's actually viable.
Basically you would encode a constant magic value with CryptProtectData with CRYPTPROTECT_LOCAL_MACHINE, and the result is your machine ID.
I would just go with the MAC address method; when the wireless / LAN cards are turned off they still show up in Network Connections. You should therefore still be able to get the MAC.
Consider this: Any time you'd be able to contact your webserver or whatever you're cataloging these IDs with, the user is going to have to have some form of network card available.
Oh, and you might be able to use CPU serial number of the customer's computer supports it.
I think there no really easy and unique method so far discovered here.
GetVolumeInformation retrieves not even close to unique ID.....
To use any hardware serial is problematic because manufactures are not committed to supported it always and especially to keep it globally unique
GetCurrentHwProfile retrieves GUID but it's value affected by minor! hardware changes...
Using Product Key ... will bring U to deal with the stolen software - there lot of pirate installations over the globe.
Creation of own GUID and preserving it under registry (in any place) will not prevent duplication by cloning of image ....
etc...
From my perspective of view the best way is combine:
Volume ID + MAC's list + Machine SID + Machine Name. And obviously manage license policy on the server side ;0)
Regards
Mickel.
If you want something a bit harder to spoof than whatever the machine itself can tell you, you'll probably need to provide a USB dongle dedicated for this purpose (not just a flash drive).
For a pretty brain dead test I am using the ProductID code of the OS and the computer name - both extracted from the registry. Not really secure, but its all pretend security anyway.
edit
To answer John's question about what keys I am reading:
SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductID
SYSTEM\CurrentControlset\Control\ComputerName\ComputerName\ComputerName
How about using the serial number of the harddisk where windows is installed?
The function GetVolumeInformation() will give you such serial number.
To access the ID assigned by the harddisk vendor instead of the ID assigned by Windows, you can use the Win32_PhysicalMedia Class.
To determine the drive where windows is installed, you could expand the variable %windir" by using the function ExpandEnvironmentStrings()
Another option, if your architecture allows, is to use UuidCreate() to generate a random GUID at installation time and save it permanently in the registry. This GUID can then be used as the ID as long as the registry remains. A new registry database is generally considered as a new installation.
A third option is to have a well-known server assigning the IDs. Upon starting up, the software could look up for the ID in the registry and if not found, would contact the server and supply it with its MAC address, hostname, harddisk serial number, Machine SID and any number of indentifyable information (keys).
The server then determines if the client is already registered or not based on the information given. The server could have a relaxed policy and for example only require most of the keys for a match, so that the mechanism would work even in the event of a complete wipe out of the registry and if part (but not all) of the hardware was replaced.
How about using the serial number of a CPU. I remember Microsoft used to provide an api for this that would run the necessary assembler code and give you back all sorts of info about the CPU including serial number. Not sure if it'd work with AMD chips or not, I think it was intel specific.
Surely CPU Id is secure and static enough!!