Snelstartgids voor NFC CX

Deze handleiding laat zien hoe u een NFC-functioneel stuurprogramma schrijft met behulp van het NFC Class Extension (NFC CX)-stuurprogramma.

Note

Een stuurprogramma dat gebruikmaakt van een stuurprogramma voor de klasse-extensie in de implementatie, wordt een 'clientstuurprogramma' genoemd. Dat wil zeggen, een client van het klasse-extensiestuurprogramma.

Prerequisites

Verantwoordelijkheden van het clientstuurprogramma

Het NFC CX-stuurprogramma is verantwoordelijk voor het verwerken van I/O-aanvragen die naar het stuurprogramma worden verzonden en het maken van de relevante NCI-opdrachtpakketten. Het clientstuurprogramma is verantwoordelijk voor het verzenden van die NCI-pakketten naar de NFC-controller en het terugsturen van de NCI-antwoordpakketten naar het NFC CX-stuurprogramma.

Het is aan het clientstuurprogramma om te bepalen hoe de NCI-pakketten naar de NFC-controller moeten worden verzonden. Dit proces varieert afhankelijk van het type hardwarebus dat wordt gebruikt. Veelgebruikte bussen die worden gebruikt door NFC Controllers zijn I2C, SPI en USB.

Volledige projectcode

Een volledige versie van deze voorbeeldcode is beschikbaar op GitHub: Voorbeeld van het NFC CX-clientstuurprogramma.

Projectopstelling

  1. Maak in Visual Studio een nieuw project 'User Mode Driver, Empty (UMDF V2)'.

    Wijs in het menu Bestand de optie Nieuw aan en selecteer Project. Selecteer in het knooppunt Visual C++, onder Windows Stuurprogramma's, WDF en selecteer vervolgens Stuurprogramma voor gebruikersmodus, Leeg (UMDF V2)

    Schermopname van het dialoogvenster 'Nieuw project' in Visual Studio met 'Gebruikersmodusstuurprogramma, Leeg (UMDF V2)' geselecteerd.

  2. Open het INF-bestand.

    Dubbelklik op <project-name>.inf in Solution Explorer, onder het knooppunt <project-name>, in de map Stuurprogrammabestanden.

  3. Verwijder in het INF-bestand de aangepaste apparaatklasse met behulp van de volgende stappen:

    1. Verwijder de volgende twee secties:

      [ClassInstall32]
      AddReg=SampleClass_RegistryAdd
      
      [SampleClass_RegistryAdd]
      HKR,,,,%ClassName%
      HKR,,Icon,,"-10"
      
    2. Verwijder onder de [Strings] sectie de volgende regel.

      ClassName="Samples" ; TODO: edit ClassName
      
  4. Stel in het INF-bestand de apparaatklasse van het stuurprogramma in op Proximity:

    1. Wijzig de waarde van Class in Proximity
    2. Wijzig de waarde van ClassGuid in {5630831C-06C9-4856-B327-F5D32586E060}
      • Dit is de GUID van de proximity-apparaatklasse.
    [Version]
    ...
    Class=Proximity
    ClassGuid={5630831C-06C9-4856-B327-F5D32586E060} ; Proximity class GUID
    ...
    
  5. Voeg in het INF-bestand een verwijzing toe naar de NFC-klasseextensie. Dit zorgt ervoor dat Windows Driver Framework (WDF) het NFC CX-stuurprogramma laadt wanneer het clientstuurprogramma wordt geladen.

    1. Zoek de <project-name>_Install sectie.
    2. Voeg UmdfExtensions=NfcCx0102toe.
    [<project-name>_Install]
    ...
    UmdfExtensions=NfcCx0102
    
  6. Maak in de build-instellingen van het stuurprogramma een koppeling naar de NFC-klasse-extensie. Dit zorgt ervoor dat de NFC CX-API beschikbaar is tijdens het compileren van code.

    1. Klik in Solution Explorer met de rechtermuisknop op het project en selecteer Eigenschappen. Selecteer in Configuratie-eigenschappen onder Stuurprogramma-instellingenNFC.
    2. Zorg ervoor dat de configuratie is ingesteld op All Configurations.
    3. Zorg ervoor dat Platform moet worden ingesteld op All Platforms.
    4. Stel koppeling naar NFC-klasse-extensie in op Yes.

    Visual Studio dialoogvenster: MyNfcDriver-eigenschappenpagina's, met 'Koppeling naar NFC-klasse-extensie' ingesteld op 'Ja'.

  7. Voeg het bestand met de naam Driver.cpp toe aan het project.

  8. Maak een DriverEntry routine in Driver.cpp. Dit is het toegangspunt voor de bestuurder. Het primaire doel is om WDF te initialiseren en de EvtDriverDeviceAdd callback-functie te registreren.

    #include <windows.h>
    #include <wdf.h>
    
    #include "Device.h" // created in Step 9
    
    // The entry point for the driver.
    extern "C" NTSTATUS DriverEntry(
        _In_ PDRIVER_OBJECT DriverObject,
        _In_ PUNICODE_STRING RegistryPath
        )
    {
        NTSTATUS status = STATUS_SUCCESS;
    
        // Specify `DeviceContext::AddDevice` as the
        // `EvtDriverDeviceAdd` function for the driver.
        WDF_DRIVER_CONFIG driverConfig;
        WDF_DRIVER_CONFIG_INIT(&driverConfig, DeviceContext::AddDevice);
    
        // Initialize WDF.
        status = WdfDriverCreate(
            DriverObject,
            RegistryPath,
            WDF_NO_OBJECT_ATTRIBUTES,
            &driverConfig,
            WDF_NO_HANDLE);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
        return STATUS_SUCCESS;
    }
    
  9. Voeg twee bestanden met de naam Device.cpp en Device.h aan het project toe.

  10. Definieer in Device.h de klasse DeviceContext.

    #pragma once
    
    #include <windows.h>
    #include <wdf.h>
    #include <NfcCx.h>
    
    // The class that will store the driver's custom state for
    // a device instance.
    class DeviceContext
    {
    public:
        // Implementation of `EvtDriverDeviceAdd`.
        static NTSTATUS AddDevice(
            _In_ WDFDRIVER Driver,
            _Inout_ PWDFDEVICE_INIT DeviceInit);
    
    private:
        // Implementation of `EvtDevicePrepareHardware`.
        static NTSTATUS PrepareHardware(
            _In_ WDFDEVICE Device,
            _In_ WDFCMRESLIST ResourcesRaw,
            _In_ WDFCMRESLIST ResourcesTranslated);
    
        // Implementation of `EvtDeviceReleaseHardware`.
        static NTSTATUS ReleaseHardware(
            _In_ WDFDEVICE Device,
            _In_ WDFCMRESLIST ResourcesTranslated);
    
        // Implementation of `EvtDeviceD0Entry`.
        static NTSTATUS D0Entry(
            _In_ WDFDEVICE Device,
            _In_ WDF_POWER_DEVICE_STATE PreviousState);
    
        // Implementation of `EvtDeviceD0Exit`.
        static NTSTATUS D0Exit(
            _In_ WDFDEVICE Device,
            _In_ WDF_POWER_DEVICE_STATE TargetState);
    
        // Implementation of `EvtNfcCxWriteNciPacket`.
        static void WriteNciPacket(
            _In_ WDFDEVICE Device,
            _In_ WDFREQUEST Request);
    };
    
    // Define the `DeviceGetContext` function.
    WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DeviceContext, DeviceGetContext);
    
  11. Begin Device.cppin de definitie van de DeviceContext::AddDevice functie.

    #include "Device.h"
    
    NTSTATUS DeviceContext::AddDevice(
        _In_ WDFDRIVER Driver,
        _Inout_ PWDFDEVICE_INIT DeviceInit)
    {
        NTSTATUS status;
    
    
  12. Stel de configuratie van het NFC CX-apparaat in. De configuratie van het apparaat omvat het leveren van de EvtNfcCxWriteNciPacket callback-functie. Deze callback ontvangt de NCI-pakketten van het NFC CX-stuurprogramma die het clientstuurprogramma moet doorsturen naar de NFC-controller.

        // Create the NfcCx config.
        NFC_CX_CLIENT_CONFIG nfcCxConfig;
        NFC_CX_CLIENT_CONFIG_INIT(&nfcCxConfig, NFC_CX_TRANSPORT_CUSTOM);
        nfcCxConfig.EvtNfcCxWriteNciPacket = WriteNciPacket;
        nfcCxConfig.DriverFlags = NFC_CX_DRIVER_ENABLE_EEPROM_WRITE_PROTECTION;
    
        // Set the NfcCx config.
        status = NfcCxDeviceInitConfig(DeviceInit, &nfcCxConfig);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
  13. Registreer de PnP-power callbacks die zijn vereist voor het clientstuurprogramma.

    Een typisch clientstuurprogramma vereist waarschijnlijk de EvtDevicePrepareHardware, de EvtDeviceReleaseHardware, de EvtDeviceD0Entry en de EvtDeviceD0Exit functies. De vereisten kunnen variëren, afhankelijk van hoe uw clientstuurprogramma energiebeheer afhandelt.

        // Create the PnP power callbacks configuration.
        WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks;
        WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks);
        pnpCallbacks.EvtDevicePrepareHardware = PrepareHardware;
        pnpCallbacks.EvtDeviceReleaseHardware = ReleaseHardware;
        pnpCallbacks.EvtDeviceD0Entry = D0Entry;
        pnpCallbacks.EvtDeviceD0Exit = D0Exit;
    
        // Set the PnP power callbacks.
        WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks);
    
  14. Roep de WdfDeviceCreate functie aan om het WDFDEVICE object te maken.

        // Create WDF object attributes for the WDFDEVICE object.
        WDF_OBJECT_ATTRIBUTES deviceAttributes;
        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DeviceContext);
    
        // Create the device.
        WDFDEVICE device;
        status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
  15. Roep de functie NfcCxDeviceInitialize aan.

    Deze functie moet worden aangeroepen nadat het WDFDEVICE object is gemaakt, zodat het NFC CX-stuurprogramma de initialisatie van het apparaatexemplaar kan voltooien.

        // Let NFC CX finish initializing the device instance.
        status = NfcCxDeviceInitialize(device);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
  16. Roep NfcCxSetRfDiscoveryConfig aan om de NFC-technologieën en -protocollen op te geven die worden ondersteund door de NFC-controller.

        // Create the RF config. (Enable everything.)
        NFC_CX_RF_DISCOVERY_CONFIG discoveryConfig;
        NFC_CX_RF_DISCOVERY_CONFIG_INIT(&discoveryConfig);
        discoveryConfig.PollConfig =
            NFC_CX_POLL_NFC_A | NFC_CX_POLL_NFC_B |
            NFC_CX_POLL_NFC_F_212 | NFC_CX_POLL_NFC_F_424 |
            NFC_CX_POLL_NFC_15693 | NFC_CX_POLL_NFC_ACTIVE |
            NFC_CX_POLL_NFC_A_KOVIO;
        discoveryConfig.NfcIPMode =
            NFC_CX_NFCIP_NFC_A | NFC_CX_NFCIP_NFC_F_212 |
            NFC_CX_NFCIP_NFC_F_424 | NFC_CX_NFCIP_NFC_ACTIVE |
            NFC_CX_NFCIP_NFC_ACTIVE_A | NFC_CX_NFCIP_NFC_ACTIVE_F_212 |
            NFC_CX_NFCIP_NFC_ACTIVE_F_424;
        discoveryConfig.NfcIPTgtMode =
            NFC_CX_NFCIP_TGT_NFC_A | NFC_CX_NFCIP_TGT_NFC_F |
            NFC_CX_NFCIP_TGT_NFC_ACTIVE_A | NFC_CX_NFCIP_TGT_NFC_ACTIVE_F;
        discoveryConfig.NfcCEMode =
            NFC_CX_CE_NFC_A | NFC_CX_CE_NFC_B |
            NFC_CX_CE_NFC_F;
    
        // Set the RF config.
        status = NfcCxSetRfDiscoveryConfig(device, &discoveryConfig);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
  17. Beëindig de DeviceContext::AddDevice functie.

        return STATUS_SUCCESS;
    }
    
  18. Implementeer de callbackfuncties PrepareHardware en ReleaseHardware.

    Deze twee functies worden gebruikt om de hardwarebronnen die zijn toegewezen aan de apparaatinstantie van de NFC-controller te initialiseren en te de-initialiseren. De implementatie is afhankelijk van het type bus waarmee het apparaat is verbonden (bijvoorbeeld I2C, SPI en USB).

    NTSTATUS DeviceContext::PrepareHardware(
        _In_ WDFDEVICE Device,
        _In_ WDFCMRESLIST ResourcesRaw,
        _In_ WDFCMRESLIST ResourcesTranslated)
    {
        // FIX ME: Initialize hardware resources.
        return STATUS_SUCCESS;
    }
    
    NTSTATUS DeviceContext::ReleaseHardware(
        _In_ WDFDEVICE Device,
        _In_ WDFCMRESLIST ResourcesTranslated)
    {
        // FIX ME: Uninitialize hardware resources.
        return STATUS_SUCCESS;
    }
    
  19. Roep de NfcCxHardwareEvent functie aan met HostActionStart en HostActionStop om de NCI-statusmachine op de juiste tijdstippen te starten en te stoppen.

    Sommige stuurprogramma's doen dit tijdens de D0Entry en D0Exit PnP-energiecallbacks. Dit kan echter variëren, afhankelijk van hoe uw clientstuurprogramma energiebeheer afhandelt.

    // Device exiting low power state (or is booting up).
    NTSTATUS DeviceContext::D0Entry(
        _In_ WDFDEVICE Device,
        _In_ WDF_POWER_DEVICE_STATE PreviousState)
    {
        (void)PreviousState;
    
        NTSTATUS status;
    
        // Invoke the HostActionStart event, so that the NFC CX initializes
        // the NFC Controller.
        NFC_CX_HARDWARE_EVENT eventArgs = {};
        eventArgs.HostAction = HostActionStart;
    
        status = NfcCxHardwareEvent(Device, &eventArgs);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
        return STATUS_SUCCESS;
    }
    
    // Device entering low power state.
    NTSTATUS DeviceContext::D0Exit(
        _In_ WDFDEVICE Device,
        _In_ WDF_POWER_DEVICE_STATE TargetState)
    {
        (void)TargetState;
    
        NTSTATUS status;
    
        // Trigger the HostActionStop event, so that the NFC CX
        // uninitializes the NFC Controller.
        NFC_CX_HARDWARE_EVENT eventArgs = {};
        eventArgs.HostAction = HostActionStop;
    
        status = NfcCxHardwareEvent(Device, &eventArgs);
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
        return STATUS_SUCCESS;
    }
    
  20. Implementeer de WriteNciPacket functie.

    Deze callback wordt aangeroepen door de NFC CX wanneer er een NCI-pakket is dat naar de NFC-controller moet worden verzonden.

    void DeviceContext::WriteNciPacket(
        _In_ WDFDEVICE Device,
        _In_ WDFREQUEST Request)
    {
        NTSTATUS status;
    
        // Get the NCI packet as a raw byte buffer.
        void* nciPacket;
        size_t nciPacketLength;
        status = WdfRequestRetrieveInputBuffer(Request, 0, &nciPacket, &nciPacketLength);
        if (!NT_SUCCESS(status))
        {
            WdfRequestComplete(Request, status);
            return;
        }
    
        // FIX ME: Use the NCI packet in some way.
    
        // FIX ME: Call `WdfRequestComplete` on `Request` with failure
        // or success `NTSTATUS` code.
    };
    
  21. Roep de NfcCxNciReadNotification functie aan wanneer de NFC-controller een NCI-pakket heeft dat naar de NFC CX moet worden verzonden. Doe dit meestal in een callback van hardware-gebeurtenissen.

    Voorbeeld:

Logging

Overweeg logboekregistratie toe te voegen aan het clientstuurprogramma, zodat u eenvoudiger fouten kunt opsporen. Zowel ETW-tracering als WPP-tracering zijn goede opties.