How can I use Bluez5 DBUS API in C++ to pair and connect new devices? - c++

I am writing a bluetooth driver for Intel Edison. Board software is latest available, and I am developing using the Eclipse based IDE.
Bluez version number in this edison release is 5.37.
I am designing a system which has to meet the following requirements:
Scan for bluetooth devices nearby. [X]
Detect sensor devices based on name and MAC address. [X]
Pair and connect sensor devices automatically. []
Last item is the problem since I can detect sensor devices but I am not able to pair them using the bluez5 interface. So far I have tried to use the D-BUS interface but it is not working since I keep getting the following error message:
Method "FindAdapter" with signature "s" on interface "org.bluez.Manager" doesn't exist
Code is presented here. Please note:
DBusConnection *conn -> DBUS_BUS_SYSTEM
const char *adapter -> "hci0".
Code:
DBusMessage *msg, *reply;
DBusError err;
const char *reply_path;
char *path;
msg = dbus_message_new_method_call("org.bluez", "/","org.bluez.Manager", "FindAdapter");
dbus_message_append_args(msg, DBUS_TYPE_STRING, &adapter,DBUS_TYPE_INVALID);
dbus_error_init(&err);
reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
dbus_message_unref(msg);
Any ideas?

To give you an anwser, Pair and Connect are associated with the device-api.txt. To call these methods you can send dbus messages (like you did in the code presented above) or build a Proxy object with the following parameters (found in the documentation) :
name : "org.bluez"
interface "org.bluez.Device1"
path : "/org/bluez/dev_AA_BB_CC_DD_EE" where AA_BB_CC_DD_EE is your device mac address.
If you choose to build a proxy object, you can call methods like Pair or Connect through the proxy.
Could you explain what you are trying to achieve in the code above ? I understand that you want to find which adapter to use (I see the "FindAdapter" method) however it seems you already knows that your adapter name is "hci0".
I have been working with the DBus API exposed by Bluez recently and I was unfamiliar with the interface "org.bluez.Manager".
After a quick search in the official documentation (https://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc) I was able to find the following commit which specifies that the interface was dropped in 2012 :
https://git.kernel.org/cgit/bluetooth/bluez.git/commit/doc?id=86a7b07c22f3a595ba3c48092359287905bf0878
I also noticed you were using the DBus low-level API, as advised by freedesktop themselves (read at the bottom of the page here : https://dbus.freedesktop.org/doc/api/html/group__DBus.html ), this is very complex API useful to create bindings in other languages. If you can, switch to GLib GDBus for a much simpler API.

Related

Apache Thrift for just processing, not server

I hope I don't have misunderstood the Thrift concept, but what I see from (example) questions like this, this framework is composed by different modular layers that can be enabled or disabled.
I'm mostly interesed in the "IDL part" of Thrift, so that I can create a common interface between my C++ code and an external Javascript application. I would like to call C++ functions using JS, with Binary data transmission, and I've already used the compiler for this.
But both my C++ (the server) and JS (client) application already exchange data using a C++ Webserver with Websockets support, it is not provided by Thrift.
So I was thinking to setup the following items:
In JS (already done):
TWebSocketTransport to send data to my "Websocket server" (with host ws://xxx.xxx.xxx.xxx)
TBinaryProtocol to encapsulate the data (using this JS implementation)
The compiled Thrift JS library with the correspondent C++ functions to call (done with the JS compiler)
In C++ (partial):
TBinaryProtocol to encode/decode the data
A TProcessor with handler to get the data from the client and process it
For now, the client is already able to sent requests to my websocket server, I see receiving them in binary form and I just need Thrift to:
Decode the input
Call the appropriate C++ function
Encode the output
My webserver will send the response to the client. So no "Thrift server" is needed here. I see there is the TProcessor->process() function, I'm trying to use it when I receive the binary data but it needs an in/out TProtocol. No problem here... but in order to create the TBinaryProtocol I also need a TTransport! If no Thrift server is expected... what Transport should I use?
I tried to set TTransport to NULL in TBinaryProtocol constructor, but once I use it it gives nullptr exception.
Code is something like:
Init:
boost::shared_ptr<MySDKServiceHandler> handler(new MySDKServiceHandler());
thriftCommandProcessor = boost::shared_ptr<TProcessor>(new MySDKServiceProcessor(handler));
thriftInputProtocol = boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(TTransport???));
thriftOutputProtocol = boost::shared_ptr<TBinaryProtocol>(new TBinaryProtocol(TTransport???));
When data arrives:
this->thriftInputProtocol->writeBinary(input); // exception here
this->thriftCommandProcessor->process(this->thriftInputProtocol, this->thriftOutputProtocol, NULL);
this->thriftOutputProtocol->readBinary(output);
I've managed to do it using the following components:
// create the Processor using my compiled Thrift class (from IDL)
boost::shared_ptr<MySDKServiceHandler> handler(new MySDKServiceHandler());
thriftCommandProcessor = boost::shared_ptr<TProcessor>(new ThriftSDKServiceProcessor(handler));
// Transport is needed, I use the TMemoryBuffer so everything is kept in local memory
boost::shared_ptr<TTransport> transport(new apache::thrift::transport::TMemoryBuffer());
// my client/server data is based on binary protocol. I pass the transport to it
thriftProtocol = boost::shared_ptr<TProtocol>(new TBinaryProtocol(transport, 0, 0, false, false));
/* .... when the message arrives through my webserver */
void parseMessage(const byte* input, const int input_size, byte*& output, int& output_size)
{
// get the transports to write and read Thrift data
boost::shared_ptr<TTransport> iTr = this->thriftProtocol->getInputTransport();
boost::shared_ptr<TTransport> oTr = this->thriftProtocol->getOutputTransport();
// "transmit" my data to Thrift
iTr->write(input, input_size);
iTr->flush();
// make the Thrift work using the Processor
this->thriftCommandProcessor->process(this->thriftProtocol, NULL);
// the output transport (oTr) contains the called procedure result
output = new byte[MAX_SDK_WS_REPLYSIZE];
output_size = oTr->read(output, MAX_SDK_WS_REPLYSIZE);
}
My webserver will send the response to the client. So no "Thrift server" is needed here. I see there is the TProcessor->process() function, I'm trying to use it when I receive the binary data but it needs an in/out TProtocol. No problem here... but in order to create the TBinaryProtocol I also need a TTransport! If no Thrift server is expected... what Transport should I use?
The usual pattern is to store the bits somewhere and use that buffer or data stream as the input, same for the output. For certain languages there is a TStreamTransport available, for C++ the TBufferBase class looks promising to me.

DCMTK Understand the "DIMSE No valid Presentation Context ID" error

I'm currently developing a simple application for querying/retrieving data on a PACS. I use DCMTK for this purpose, and a DCM4CHEE PACS as test server.
My goal is to implement simple C-FIND queries, and a C-MOVE retrieving system (coupled with a custom SCP to actually download the data).
To do so, I've created a CustomSCU class, that inherits the DCMTK DcmSCU class.
I first implemented a C-ECHO message, that worked great.
Then, I tried to implement C-FIND requesting, but I got the error "DIMSE No valid Presentation Context ID" (more on that in the next paragraph) from my application, but no other log from DCM4CHEE. I've then used the command tool findscu (from dcmtk) to see if there was some configuration issue but the tool just worked fine. So in order to implement my C-FIND request, I've read the source of findscu (here) and adapted it in my code (meaning that i'm not using DcmSCU::sendCFindRequest but the class DcmFindSU).
But now, i'm facing the same problem with C-MOVE request. My code is pretty straight-forward :
//transfer syntaxes
OFList<OFString> ts;
ts.push_back(UID_LittleEndianExplicitTransferSyntax);
ts.push_back(UID_BigEndianExplicitTransferSyntax);
ts.push_back(UID_LittleEndianImplicitTransferSyntax);
//sop class
OFString pc = UID_MOVEPatientRootQueryRetrieveInformationModel;
addPresentationContext(pc, ts);
DcmDataset query;
query.putAndInsertOFStringArray(DCM_QueryRetrieveLevel, "PATIENT");
query.putAndInsertOFStringArray(DCM_PatientID, <ThePatientId>);
OFCondition condition = sendMOVERequest(findPresentationContextID(pc, ""), getAETitle(), &query, nullptr);
return condition.good();
I've also tried using UID_MOVEStudyRootQueryRetrieveInformationModel instead of UID_MOVEPatientRootQueryRetrieveInformationModel, with the same result : my application shows the error
DIMSE No valid Presentation Context ID
As I understand, a presentation context is concatenation of one or more transfer syntax and one SOP class. I read that the problem could come from the PACS that won't accept my presentation contexts. To be sure, I used the movescu tool (from DCMTK). It worked, and I saw this in the logs from de server DCM4CHEE :
received AAssociatedRQ
pc-1 : as=<numbers>/Patient Root Q/R InfoModel = FIND
ts=<numbers>/Explicit VR Little Endian
ts=<numbers>/Explicit VR Big Endian
ts=<numbers>/Implicit VR Little Endian
That means that the movescu tool does a find before attempting an actual move ?
Therefore, I changed my application context creation with :
OFList<OFString> ts;
ts.push_back(UID_LittleEndianExplicitTransferSyntax);
ts.push_back(UID_BigEndianExplicitTransferSyntax);
ts.push_back(UID_LittleEndianImplicitTransferSyntax);
OFString pc1 = UID_FINDPatientRootQueryRetrieveInformationModel;
OFString pc = UID_MOVEPatientRootQueryRetrieveInformationModel;
addPresentationContext(pc1, ts);
addPresentationContext(pc, ts);
(also tried study root)
But this didn't do the trick.
The problem seems to lie on the client side, as findPresentationContextID(pc, ""); alwasy return 0, no matter what.
I don't feel like it's possible to adapt the code of the movescu tool, as it appears to be very complex and not adequat for simple retrieve operations.
I don't know what to try. I hope someone can help me understand what's going on. That's the last part of my application, as the storage SCP already works.
Regards
It looks like you are not negotiating the association with the PACS.
After adding the presentation contexts and before sending any command, the SCU must connect to the PACS and negotiate the PresentationContexts with DcmSCU::initNetwork and then DcmSCU::negotiateAssociation.

Connecting to Mobile Network via Mobile Broadband API

I am trying to connect to a mobile network via a modem and a sim card. Every time I try to set the APN String and User Credentials in a Context via SetProvisionedContext() I get the E_INVALIDARG HRESULT.
As Parameters I used an Instance of MBN_CONTEXT, a wchar_t* in form of &std::vector<wchar_t>[0], and a ULONG*.
MBN_CONTEXT context;
std::vector<WCHAR> apnVector;
inParamAPN.GetCString(apnVector);
std::vector<WCHAR> userNameVec;
inParamUsername.GetCString(userNameVec);
std::vector<WCHAR> passwordVector;
inParamPassword.GetCString(passwordVector);
context.contextID = MBN_CONTEXT_ID_APPEND;
context.contextType = MBN_CONTEXT_TYPE_INTERNET;
context.accessString = &apnVector[0];
context.userName = &userNameVec[0];
context.password = &passwordVector[0];
context.compression = MBN_COMPRESSION_NONE;
context.authType = MBN_AUTH_PROTOCOL_PAP;
and later when I have the IMbnConnectionContext:
std::vector<WCHAR> providerVector;
InParamProvider.GetCString(providerVector);
ULONG requestID;
contextInterface->SetProvisionedContext(context, &providerVector[0], &requestID);
So my Question is: Which Parameter does the WinAPI have a Problem with, and how can I fix it?
Also any Tips of additional Sources for Information are appriciated.
All I have so far are the official MSDN and the Code Example contained in the Windows 7 SDK. Are there any further sources of Information I am not aware of? A google search didn't yield the hoped for results.
In the end I did not get it working as it should. I used the second way of connecting to a custom APN, by making a new connection profile. For this I used a XML filled with the Values I needed.
Along the way I encountered another problem with an unforseen Error Code which I described here.
Best regards,
Stefan

WlanHostedNetworkStartUsing or how windows 10 builtin mobile hotspot works

I'm trying to write a program which creates hotspot. I'm using WlanHostedNetworkStartUsing but it returns ERROR_INVALID_STATE. And yet when I call WlanHostedNetworkInitSettings it returns succsess. According to documemtation (last paragraph in Remarks section) it should to create a virtual wireless connection under Control Panel\Network and Internet\Network and Sharing Center but it doesn't.
I've searching a bit and found this:
When I run netsh wlan show drivers it puts:
Driver : Intel(R) Dual Band Wireless-AC 3165
Vendor : Intel Corporation
Provider : Intel
Date : 07-Sep-16
Version : 19.20.0.6
INF file : ????
Type : Native Wi-Fi Driver
Radio types supported : 802.11b 802.11g 802.11n 802.11a 802.11ac
/ ...
Hosted network supported : No <--- Here
/ ...
So it says my wifi adapter doesn't wifi sharing at all (I have last drivers from HP site).
BUT when I try to create hotspot with Windows 10 builtin' tool it works.
The question: How could windows tool do it and how can I use this mechanism in my app?
Original 06/06/2018 comments here (see updates below):
Microsoft deprecated the WLAN HostedNetwork capability and it is NOT
available for Win10 drivers. To use the old model in Win10 you must
find and install drivers from 2015 (8.1 or possibly earlier depending
on vendor).
The Win10 driver model changed the mechanism of HostedNetwork to be
based on WiFi Direct, and took control away from app-developers and
moved this feature to the kernel. There are some samples available if
you dig around, that show how to use the modern-com (RT) UWP app
libraries to configure a WiFi Direct HostedNetwork. It is a PITA,
which was not explained by Microsoft, is not understood by most people
commenting on this in the web, and which mostly looks like a two-step
microsoft failure where product features were cut to make ship
schedule and re-orgs among teams changed the ownership and plan for
WiFi and hotspots. WiFi direct enables - theoretically - a simpler
pairing and authentication model between devices. But the currently
implementation involves bluetooth and therefore it is questionable
other than support a limited mobile device WiFi 2.0 scenario. If you
are working with headless devices or IoT device scenarios this is
broken.
I've had to do a lot of work in this area. If you have a choice in
WiFi hardware, I strongly recommend a hardware chipset that uses the
Intel drivers (they are solid).
You may find this App store app helpful if your scenario allows for UX
interaction.
http://www.topuwp.com/windowsapps/wifi-direct-access-point/598084.html
====================
02/27/2020 Update to that story...
When Hosted network supported : No then legacy hosted network support is not available on your adapter because you have WiFi Direct in Windows 10 etc. In which case you'll want to know and use this very sparsely commented on supported portion of WiFi Direct:
https://learn.microsoft.com/en-us/uwp/api/windows.networking.networkoperators.networkoperatortetheringmanager.createfromconnectionprofile
Command Line to HotSpot settings: start ms-settings:network-mobilehotspot
Article that talks about PowerShell programmatic access to the WinRT HotSpot APIs
enable Win10 inbuild hotspot by cmd/batch/powershell
KEYWORDS: "Virtual Wi-Fi", SoftAP, AdHoc IBSS, MobileHotSpot, netsh wlan HostedNetwork
====================
Which would not be complete without a working C++/WinRT code sample as follows:
#include <winrt/Windows.Networking.Connectivity.h>
#include <winrt/Windows.Networking.NetworkOperators.h>
#include <winrt/Windows.Devices.WiFiDirect.h>
#include <winrt/Windows.Security.Credentials.h>
namespace winrt { // /ZW embed in :<winrt> when `Windows` is ambiguously defined
static void af_winrt_wifi_hotspot_test() {
// start ms-settings:network-mobilehotspot
init_apartment(); // apartment_type::multi_threaded
if (false /* play as you wish to test this all in simple c++ console app, I used clang */) {
auto publisher = Windows::Devices::WiFiDirect::WiFiDirectAdvertisementPublisher();
auto advertisement = publisher.Advertisement();
advertisement.ListenStateDiscoverability(Windows::Devices::WiFiDirect::WiFiDirectAdvertisementListenStateDiscoverability::Intensive);
advertisement.IsAutonomousGroupOwnerEnabled(true);
auto legacySettings = advertisement.LegacySettings();
legacySettings.IsEnabled(true);
legacySettings.Ssid(L"your-hotspot-name");
auto credential = Windows::Security::Credentials::PasswordCredential(); credential.Password(L"the-password!");
legacySettings.Passphrase(credential);
publisher.Start();
}
else {
auto connectionProfile{ Windows::Networking::Connectivity::NetworkInformation::GetInternetConnectionProfile() };
auto tetheringManager = Windows::Networking::NetworkOperators::NetworkOperatorTetheringManager::CreateFromConnectionProfile(connectionProfile);
auto credential = Windows::Security::Credentials::PasswordCredential(); credential.Password(L"the-password!");
auto conf = Windows::Networking::NetworkOperators::NetworkOperatorTetheringAccessPointConfiguration();
conf.Ssid(L"I-Own-You"); conf.Passphrase(credential.Password());
auto oldConf = tetheringManager.GetCurrentAccessPointConfiguration();
auto oldSsid = oldConf.Ssid(); auto oldPwd = oldConf.Passphrase();
tetheringManager.ConfigureAccessPointAsync(conf); // Sets new ssid/pwd here
switch (tetheringManager.TetheringOperationalState()) {
case Windows::Networking::NetworkOperators::TetheringOperationalState::Off: {
auto ioAsync = tetheringManager.StartTetheringAsync();
auto fResult = ioAsync.get();
}
break;
case Windows::Networking::NetworkOperators::TetheringOperationalState::On: {
// auto ioAsync = tetheringManager.StopTetheringAsync();
// auto fResult = ioAsync.get();
}
break;
case Windows::Networking::NetworkOperators::TetheringOperationalState::InTransition:
default:
break;
}
}
clear_factory_cache();
uninit_apartment();
}
}
Look here for older Microsoft Samples relating to WiFiDirectAdvertisementPublisher:
C++ WiFiDirectLegacyAPDemo_v1.0.zip on Microsoft Page
C# Microsoft IoT Sample OnboardingAccessPoint.cs on GitHub Page
mobile broadband networks, use IMbnConnectionProfileManager::CreateConnectionProfile
Wi-Fi networks, use WlanSetProfile function
Mobile Hotspot XML WFD_GROUP_OWNER_PROFILE profile is in this dir-path: C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces\
So many articles on the web, so much confusion created by WiFi-Direct.
I've spent two whole days figuring it all out. Which, for my time, is a lot.
No excuse for Microsoft (where I use to work as an Architect) not having created a Blog about this very popular topic. Let alone simply having made netsh and Ad Hoc Wifi compat support, instead of leaving it so cryptic and confusing for devops, end-users, and developers.
-- enjoy David
The above is pretty concise, and exposes working c++/WinRT code for all scenarios.
[I now have this bundled in EdgeS: EdgeShell/EdgeScript/afm-scm toolset]
[]5
Your computer does not support hosted network.
Because of that, this won't work.
Open command prompt as admin and try these commands:
netsh wlan set hostednetwork mode=allow ssid=“OSToto Hotspot” key=“12345678”
The ssid is the name of your network and the key is the password. You can name them like the above command.
Then run:
netsh wlan start hostednetwork
Rest before saying anything else, I would like to got through your source code.

Creating simple WebService in C++ / Qt (acting as server) providing JSON data

I need to create a simple web service (being the "server"). The goal is to provide some data I do read in an Qt / C++ application as JSON data. Basically a JavaScript application in the browser shall read its data from the Qt app. It is usually a single user scenario, so the user runs a Google Maps application in her browser, while additional data come from the Qt application.
So far I have found these libs:
Qxt: http://libqxt.bitbucket.org/doc/0.6/index.html but being a newbie on C++/Qt I miss some examples. Added: I have found one example here
gSoap: http://www.cs.fsu.edu/~engelen/soap.html has more examples and documentation and also seems to support JSON
KD SOAP: http://www.kdab.com/kdab-products/kd-soap/ with no example as far as I can tell, docu is here
Qt features itself, but it is more about acting as a client: http://qt-project.org/videos/watch/qt-networking-web-services
Checking SO gives me basically links to the above libs
webservice with Qt with an example I do not really get.
How to Create a webservice by Qt
So basically I do have the following questions:
Which lib would you use? I want to keep it as simple as possible and would need an example.
Is there another (easy!) way to provide the JSON data to the JavaScript Web page besides the WebService?
-- Edit, remarks: ---
Needs to be application intrinsic. No web server can be installed, no extra run time can be used. The user just runs the app. Maybe the Qt WebKit could be an approach....
-- Edit 2 --
Currently checking the tiny web servers as of SO " Qt HTTP Server? "
As of my tests, currently I am using QtWebApp: http://stefanfrings.de/qtwebapp/index-en.html This is one of the answers of Edit 2 ( Qt HTTP Server? )
Stefan's small WebServer has some well documented code, is written in "Qt C++" and easy to use, especially if you have worked with servlets already. Since it can be easily integrated in my Qt project, I'll end up with an internal WebServer.
Some demo code from my JSON tests, showing that generating the JSON content is basically creating a QString.
void WebServiceController::service(HttpRequest& request, HttpResponse& response) {
// set some headers
response.setHeader("Content-Type", "application/json; charset=ISO-8859-1");
response.setCookie(HttpCookie("wsTest","CreateDummyPerson",600));
QString dp = WebServiceController::getDummyPerson();
QByteArray ba = dp.toLocal8Bit();
const char *baChar = ba.data();
response.write(ba);
}
If someone has easy examples with other libs to share, please let me know.
QByteArray ba = dp.toLocal8Bit();
const char *baChar = ba.data();
You don't need to convert the QByteArray to char array. Response.write() can also be called with a QByteArray.
By the way: qPrintable(dp) is a shortcut to convert from QString to char array.