locked
Accessing BLE GATT driver

    Question

  • How to access my custom BLE GATT profile driver from C++ Metro application?
    • Moved by Jesse Jiang Monday, January 21, 2013 2:27 AM
    Friday, January 18, 2013 11:42 AM

All replies

  • Igor,

    You can use the Portable Device API to access a Bluetooth LE GATT driver. 

    You can start with scenario 6 in this sample which demonstrates how to acquire a IPortableDeviceService instance. This instance can be used to access any device service, including a GATT profile service.

    http://code.msdn.microsoft.com/windowsapps/Portable-Device-API-57c4e696

    lisa

    Monday, January 21, 2013 7:27 AM
  • Lisa,
    Thank you.

    I have tried this sample. Unfortunately I received "access denied" on every attempt to connect to my service.
    I wrote device metadata which contains the sample as privileged application. I can confirm that it is loaded by using custom icon.
    I have tested metadata with this JS sample http://code.msdn.microsoft.com/windowsapps/Bluetooth-LE-Metro-sample-a2ba1b5b and it worked just fine.
    I can open device from JS. Anyhow it doesn't work for C++ application.

    I tried:
      1. Creating new device interface in driver and setting restricted mode for it;
      2. Searching by different device interfaces:
         - One that I created in restricted mode,
         - BLE UUID of my custom service,
         - WPD device interface;
      3. Enumerating all of these interfaces in appxmanifest;
      4. Creating StoreManifest.xml with corresponded ExperienceID.

    My metadata contains following hardware ID: "BTHLEDevice\{service UUID here}_LOCALMFG&000f".
    Every sample that I tried is listed there with "access custom driver" privilegy.
    Javascript sample is specified application for the device. I don't think it can interfere with privileged applications.

    Could you please advise if I missed something?

    Currently I'm thinking of writing UMDF driver (non-WPD) that will connect to my service and just dispatch messages to it.

    Also I realized that there are WPD upper level class filter drivers in stack (WpdUpFltr.sys).
    Is it possible that it can block me from accessing my service somehow?

    I tried to access my driver via deviceaccess.lib interface also.
    I got "access denied" anyway.
    Is it possible to access a service this way?

    Igor



    Monday, January 21, 2013 10:34 AM
  • Igor,

    "Every sample that I tried is listed there with "access custom driver" privilegy.
    Javascript sample is specified application for the device. I don't think it can interfere with privileged applications."

    There can only be one privileged application specified in a device metadata.  You don't need to check the "access custom driver" box for WPD drivers.

    lisa

    Monday, January 21, 2013 4:59 PM
  • Lisa,
    Thank you.

    I removed all samples from metadata except one I tested. I specified it also as metro style device app. I unchecked "Access Custom Driver" mark.
    This metadata is loaded. I can see fresh icon and description in "devices and printers". Is it enough to be sure?
    Unfortunately I still cannot access device for every UUID (restricted interface, WPD services, service UUID).

    Your statement about only one privileged application really disappointed me.
    When I open Device Metadata Authoring Wizard -> Applications I can see:
      - "Metro style Device App", which just will be downloaded automatically when device is plugged;
      - "Privileged Applications", which is actually list.

    So you asserted that "Privileged Applications" can contain only single item?
    It looks very strange. It should be considered as a bug in Authoring Wizard if it is true.

    What to do if I need access from several applications? I doubt that I should write several metadata packages. I doubt also that they can be loaded simultaneously.

    Igor


    Wednesday, January 23, 2013 8:51 AM
  • Correct, there can only be 1 application set as a Privileged Application.  This is a restriction that is enforced at runtime in the Device Broker, even if the Authoring Wizard allows entering multiple applications. 

    Just to rule this issue out, have you tried removing the JavaScript app and adding the C++ app to your metadata?

     
    Wednesday, January 23, 2013 8:56 AM
  • Lisa,

    That is what I did exactly on last attempt.

    Probably seeing new icon in "devices and printers" is not enough to be sure that metadata is loaded? It appears strange for me that I can see it without rebooting, removing and pairing the device, updating drivers. Anyway I did all of these just in case.

    Thanks,

    Igor

    Wednesday, January 23, 2013 9:04 AM
  • I see.  Can you show the code that you're using to open the device and the PnP ID used?

    Wednesday, January 23, 2013 9:10 AM
  • Lisa,

    This is code to find devices (uncomment one of aqsFilter lines):

    // Find by restricted interface
    // String^ aqsFilter = "System.Devices.InterfaceClassGuid:=\"{7E2BE04F-AB46-4441-98AF-502816F735D6}\"";

    // Find all portable devices
    // String^ aqsFilter = "System.Devices.InterfaceClassGuid:=\"{6AC27878-A6FA-4155-BA85-F98F491D4F33}\"";

    // Find all concrete devices by BLE UUID
    // String^ aqsFilter = Windows::Devices::Portable::ServiceDevice::GetDeviceSelectorFromServiceId(Platform::Guid(0xADABFB00, 0x6E7D, 0x4601, 0xBD, 0xA2, 0xBF, 0xFA, 0xA6, 0x89, 0x56, 0xBA));

    create_task(DeviceInformation::FindAllAsync(aqsFilter)).then([this] (DeviceInformationCollection^ deviceInfoCollection)
    {
        save collection here ...
    });

    And this is one to open:

    ComPtr<IPortableDeviceService> device;
    ThrowIfFailed(CoCreateInstance(CLSID_PortableDeviceServiceFTM, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&device)));
    
    auto clientInfo = GetClientInfo();
    HRESULT hr = device->Open(deviceInfoElement->Id->Begin(), clientInfo.Get());
    if (hr == E_ACCESSDENIED)
    {
        rootPage->NotifyUser("Access to " + deviceInfoElement->Name + " is denied.", NotifyType::ErrorMessage);
        return;
    }

    Hardware ID: "BTHLEDevice\{adabfb00-6e7d-4601-bda2-bffaa68956ba}_LOCALMFG&000f"

    Thanks,

    Igor

    Wednesday, January 23, 2013 9:38 AM
  • Lisa,

    One of my attempts was to connect to IPortableDevice instead of IPortableDeviceService. Should I give it a try now with new correct metadata?

    Thanks,
    Igor

    Wednesday, January 23, 2013 9:48 AM
  • Scenario 6 in the sample illustrates how to open a service. Note that you QI for IPortableDeviceServiceActivation and use OpenAsync.

    http://code.msdn.microsoft.com/windowsapps/Portable-Device-API-57c4e696/sourcecode?fileId=44795&pathId=337223116)

    Modified snippets are below:

        String^ aqsFilter = Windows::Devices::Portable::ServiceDevice::GetDeviceSelectorFromServiceId(Platform::Guid(0xADABFB00, 0x6E7D, 0x4601, 0xBD, 0xA2, 0xBF, 0xFA, 0xA6, 0x89, 0x56, 0xBA));
         create_task(DeviceInformation::FindAllAsync(aqsFilter)).then([this] (DeviceInformationCollection^ deviceInfoCollection) 
         { 
    
            // Get the first element
    
            if (deviceInfoCollection->Size > 0) 
             { 
    
                OpenDeviceServiceAsync(deviceInfoCollection->GetAt(0));
    
            } 
         }); 
    
     
    
    void OpenDeviceServiceAsync (DeviceInformation^ deviceInfoElement) 
     { 
         ComPtr<IPortableDeviceService> service; 
         ThrowIfFailed(CoCreateInstance(CLSID_PortableDeviceServiceFTM, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&service))); 
      
         ComPtr<IPortableDeviceServiceActivation> activator; 
         ThrowIfFailed(service.As(&activator)); 
      
         OnServiceOpenComplete^ openCallback = ref new OnServiceOpenComplete([this, deviceInfoElement, service] (HRESULT hr) 
         { 
             if (SUCCEEDED(hr)) 
             { 
                 rootPage->DispatcherNotifyUser("Successfully opened device service for " + deviceInfoElement->Name, NotifyType::StatusMessage); 
             } 
             else if (hr == E_ACCESSDENIED) 
             { 
             } 
         }); 
      
         auto clientInfo = GetClientInfo(); 
         ThrowIfFailed(activator->OpenAsync(deviceInfoElement->Id->Begin(), clientInfo.Get(), reinterpret_cast<IPortableDeviceServiceOpenCallback*>(openCallback))); 
     } 
    

     
    Thursday, January 24, 2013 5:34 AM
  • Lisa,
    I tried this scenario. It returned "access denied" as well. Even with new fresh metadata with single privileged application.

    Thank you,
    Igor

    Thursday, January 24, 2013 11:12 AM
  • Sorry to hear that you are still having trouble.

    To troubleshoot, can you get traces for deviceaccess.dll? The instructions are in this post:

    http://social.msdn.microsoft.com/Forums/en-US/tailoringappsfordevices/thread/5253a82d-cfc0-4eac-a8aa-fd8450765d9f

    Thursday, January 24, 2013 4:01 PM