Sample Code

Windows Driver Samples/ Sample UMDF Filter above UMDF Function Driver for OSR USB-FX2 (UMDF Version 1)/ C++/ umdf_driver/ Device.cpp/

/*++
 
Copyright (C) Microsoft Corporation, All Rights Reserved.

Module Name:

    Device.cpp

Abstract:

    This module contains the implementation of the UMDF OSR Fx2 driver's
    device callback object.

Environment:

   Windows User-Mode Driver Framework (WUDF)

--*/
#include "internal.h"
#include "initguid.h"
#include "usb_hw.h"
#include <devpkey.h>

#include "device.tmh"
#define CONCURRENT_READS 2

CMyDevice::~CMyDevice(
    )
{
    SAFE_RELEASE(m_pIoTargetInterruptPipeStateMgmt); 
}

HRESULT
CMyDevice::CreateInstance(
    _In_ IWDFDriver *FxDriver,
    _In_ IWDFDeviceInitialize * FxDeviceInit,
    _Out_ PCMyDevice *Device
    )
/*++
 
  Routine Description:

    This method creates and initializs an instance of the OSR Fx2 driver's 
    device callback object.

  Arguments:

    FxDeviceInit - the settings for the device.

    Device - a location to store the referenced pointer to the device object.

  Return Value:

    Status

--*/
{
    PCMyDevice device;
    HRESULT hr;

    //
    // Allocate a new instance of the device class.
    //

    device = new CMyDevice();

    if (NULL == device)
    {
        return E_OUTOFMEMORY;
    }

    //
    // Initialize the instance.
    //

    hr = device->Initialize(FxDriver, FxDeviceInit);

    if (SUCCEEDED(hr)) 
    {
        *Device = device;
    } 
    else 
    {
        device->Release();
    }

    return hr;
}

HRESULT
CMyDevice::Initialize(
    _In_ IWDFDriver           * FxDriver,
    _In_ IWDFDeviceInitialize * FxDeviceInit
    )
/*++
 
  Routine Description:

    This method initializes the device callback object and creates the
    partner device object.

    The method should perform any device-specific configuration that:
        *  could fail (these can't be done in the constructor)
        *  must be done before the partner object is created -or-
        *  can be done after the partner object is created and which aren't 
           influenced by any device-level parameters the parent (the driver
           in this case) might set.

  Arguments:

    FxDeviceInit - the settings for this device.

  Return Value:

    status.

--*/
{
    IWDFDevice2 *fxDevice = NULL;

    HRESULT hr = S_OK;

    //
    // TODO: Any per-device initialization which must be done before 
    //       creating the partner object.
    //

    //
    // Set no locking unless you need an automatic callbacks synchronization
    //

    FxDeviceInit->SetLockingConstraint(None);

    //
    // TODO: If you're writing a filter driver then indicate that here. 
    //       And then don't claim power policy ownership below
    //
    // FxDeviceInit->SetFilter();
    //
        
    //
    // Set the Fx2 driver as the power policy owner.
    //

    FxDeviceInit->SetPowerPolicyOwnership(TRUE);

    //
    // Create a new FX device object and assign the new callback object to 
    // handle any device level events that occur.
    //

    //
    // QueryIUnknown references the IUnknown interface that it returns
    // (which is the same as referencing the device).  We pass that to 
    // CreateDevice, which takes its own reference if everything works.
    //

    if (SUCCEEDED(hr)) 
    {
        IUnknown *unknown = this->QueryIUnknown();
        IWDFDevice* device1;

        hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &device1);

        //
        // Convert the interface to version 2
        //

        if (SUCCEEDED(hr)) {
            device1->QueryInterface(IID_PPV_ARGS(&fxDevice));
            _Analysis_assume_(fxDevice != NULL);
            device1->Release();
        }

        unknown->Release();
    }

    //
    // If that succeeded then set our FxDevice member variable.
    //

    if (SUCCEEDED(hr)) 
    {
        m_FxDevice = fxDevice;

        //
        // Drop the reference we got from CreateDevice.  Since this object
        // is partnered with the framework object they have the same 
        // lifespan - there is no need for an additional reference.
        //

        fxDevice->Release();
    }

    return hr;
}

HRESULT
CMyDevice::Configure(
    VOID
    )
/*++
 
  Routine Description:

    This method is called after the device callback object has been initialized 
    and returned to the driver.  It would setup the device's queues and their 
    corresponding callback objects.

  Arguments:

    FxDevice - the framework device object for which we're handling events.

  Return Value:

    status

--*/
{   
    HRESULT hr = S_OK;

    //
    // Get the bus type GUID for the device and confirm that we're attached to
    // USB.
    //
    // NOTE: Since this device only supports USB we'd normally trust our INF 
    // to ensure this.
    //
    // But if the device also supported 1394 then we could 
    // use this to determine which type of bus we were attached to.
    // 

    hr = GetBusTypeGuid();

    if (FAILED(hr))
    {
        return hr;
    }

    //
    // Create the read-write queue.
    //

    hr = CMyReadWriteQueue::CreateInstance(this, &m_ReadWriteQueue);

    if (FAILED(hr))
    {
        return hr;
    }

    //
    // We use default queue for read/write
    //
    
    hr = m_ReadWriteQueue->Configure();

    m_ReadWriteQueue->Release();

    //
    // Create the control queue and configure forwarding for IOCTL requests.
    //

    if (SUCCEEDED(hr)) 
    {
        hr = CMyControlQueue::CreateInstance(this, &m_ControlQueue);

        if (SUCCEEDED(hr)) 
        {
            hr = m_ControlQueue->Configure();
            if (SUCCEEDED(hr)) 
            {
                m_FxDevice->ConfigureRequestDispatching(
                                m_ControlQueue->GetFxQueue(),
                                WdfRequestDeviceIoControl,
                                true
                                );
            }
            m_ControlQueue->Release();         
        }
    }

    //
    // Create a manual I/O queue to hold requests for notification when
    // the switch state changes.
    //

    hr = m_FxDevice->CreateIoQueue(NULL,
                                   FALSE,
                                   WdfIoQueueDispatchManual,
                                   FALSE,
                                   FALSE,
                                   &m_SwitchChangeQueue);
    

    //
    // Release creation reference as object tree will keep a reference
    //
    
    m_SwitchChangeQueue->Release();

    if (SUCCEEDED(hr)) 
    {
        hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_OSRUSBFX2,
                                               NULL);
    }

    //
    // Mark the interface as restricted to allow access to applications bound
    // using device metadata.  Failures here are not fatal so we log them but
    // ignore them otherwise.
    //
    if (SUCCEEDED(hr))
    {
        WDF_PROPERTY_STORE_ROOT RootSpecifier;
        IWDFUnifiedPropertyStoreFactory * pUnifiedPropertyStoreFactory = NULL;
        IWDFUnifiedPropertyStore * pUnifiedPropertyStore = NULL;
        DEVPROP_BOOLEAN isRestricted = DEVPROP_TRUE;
        HRESULT hrSetProp;

        hrSetProp = m_FxDevice->QueryInterface(IID_PPV_ARGS(&pUnifiedPropertyStoreFactory));

        WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrSetProp));

        RootSpecifier.LengthCb = sizeof(RootSpecifier);
        RootSpecifier.RootClass = WdfPropertyStoreRootClassDeviceInterfaceKey;
        RootSpecifier.Qualifier.DeviceInterfaceKey.InterfaceGUID = &GUID_DEVINTERFACE_OSRUSBFX2;
        RootSpecifier.Qualifier.DeviceInterfaceKey.ReferenceString = NULL;

        hrSetProp = pUnifiedPropertyStoreFactory->RetrieveUnifiedDevicePropertyStore(&RootSpecifier,
                                                                                     &pUnifiedPropertyStore);

        if (SUCCEEDED(hrSetProp))
        {
            hrSetProp = pUnifiedPropertyStore->SetPropertyData(&DEVPKEY_DeviceInterface_Restricted,
                                                               0, // Lcid
                                                               0, // Flags
                                                               DEVPROP_TYPE_BOOLEAN,
                                                               sizeof(isRestricted),
                                                               &isRestricted);
        }

        if (FAILED(hrSetProp))
        {
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Could not set restricted property %!HRESULT!",
                        hrSetProp
                        );
        }

        SAFE_RELEASE(pUnifiedPropertyStoreFactory);
        SAFE_RELEASE(pUnifiedPropertyStore);
    }

    return hr;
}

HRESULT
CMyDevice::QueryInterface(
    _In_ REFIID InterfaceId,
    _Outptr_ PVOID *Object
    )
/*++
 
  Routine Description:

    This method is called to get a pointer to one of the object's callback
    interfaces.  

  Arguments:

    InterfaceId - the interface being requested

    Object - a location to store the interface pointer if successful

  Return Value:

    S_OK or E_NOINTERFACE

--*/
{
    HRESULT hr;

    if (IsEqualIID(InterfaceId, __uuidof(IPnpCallbackHardware)))
    {
        *Object = QueryIPnpCallbackHardware();
        hr = S_OK;    
    }
    else if (IsEqualIID(InterfaceId, __uuidof(IPnpCallback)))
    {
        *Object = QueryIPnpCallback();
        hr = S_OK;    
    }     
    else if (IsEqualIID(InterfaceId, __uuidof(IPnpCallbackSelfManagedIo)))
    {
        *Object = QueryIPnpCallbackSelfManagedIo();
        hr = S_OK;    
    }     
    else if(IsEqualIID(InterfaceId, __uuidof(IUsbTargetPipeContinuousReaderCallbackReadersFailed))) 
    {    
        *Object = QueryContinousReaderFailureCompletion();
        hr = S_OK;  
    } 
    else if(IsEqualIID(InterfaceId, __uuidof(IUsbTargetPipeContinuousReaderCallbackReadComplete))) 
    {    
        *Object = QueryContinousReaderCompletion();
        hr = S_OK;  
    }
    else
    {
        hr = CUnknown::QueryInterface(InterfaceId, Object);
    }

    return hr;
}

HRESULT
CMyDevice::OnPrepareHardware(
    _In_ IWDFDevice * /* FxDevice */
    )
/*++

Routine Description:

    This routine is invoked to ready the driver
    to talk to hardware. It opens the handle to the 
    device and talks to it using the WINUSB interface.
    It invokes WINUSB to discver the interfaces and stores
    the information related to bulk endpoints.

Arguments:

    FxDevice  : Pointer to the WDF device interface

Return Value:

    HRESULT 

--*/
{
    PWSTR deviceName = NULL;
    DWORD deviceNameCch = 0;

    HRESULT hr;

    //
    // Get the device name.
    // Get the length to allocate first
    //

    hr = m_FxDevice->RetrieveDeviceName(NULL, &deviceNameCch);

    if (FAILED(hr))
    {
        TraceEvents(TRACE_LEVEL_ERROR, 
                    TEST_TRACE_DEVICE, 
                    "%!FUNC! Cannot get device name %!HRESULT!",
                    hr
                    );
    }

    //
    // Allocate the buffer
    //

    if (SUCCEEDED(hr))
    {
        deviceName = new WCHAR[deviceNameCch];

        if (deviceName == NULL)
        {
            hr = E_OUTOFMEMORY;
        }
    }

    //
    // Get the actual name
    //

    if (SUCCEEDED(hr))
    {
        hr = m_FxDevice->RetrieveDeviceName(deviceName, &deviceNameCch);

        if (FAILED(hr))
        {
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Cannot get device name %!HRESULT!",
                        hr
                        );
        }
    }

    if (SUCCEEDED(hr))
    {
        TraceEvents(TRACE_LEVEL_INFORMATION, 
                    TEST_TRACE_DEVICE, 
                    "%!FUNC! Device name %S",
                    deviceName
                    );
    }

    //
    // Create USB I/O Targets and configure them
    //

    if (SUCCEEDED(hr))
    {
        hr = CreateUsbIoTargets();
    }

    if (SUCCEEDED(hr))
    {
        ULONG length = sizeof(m_Speed);

        hr = m_pIUsbTargetDevice->RetrieveDeviceInformation(DEVICE_SPEED, 
                                                            &length,
                                                            &m_Speed);
        if (FAILED(hr)) 
        {
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Cannot get usb device speed information %!HRESULT!",
                        hr
                        );
        }
    }

    if (SUCCEEDED(hr)) 
    {
        TraceEvents(TRACE_LEVEL_INFORMATION, 
                    TEST_TRACE_DEVICE, 
                    "%!FUNC! Speed - %x\n",
                    m_Speed
                    );
    }

    if (SUCCEEDED(hr))
    {
        hr = ConfigureUsbPipes();
    }

    // Setup power-management settings on the device.
    //

    if (SUCCEEDED(hr))
    {
        hr = SetPowerManagement();
    }

    //
    //
    // Clear the seven segement display to indicate that we're done with 
    // prepare hardware.
    //

    if (SUCCEEDED(hr))
    {
        hr = IndicateDeviceReady();
    }

    if (SUCCEEDED(hr))
    {
        hr = ConfigContReaderForInterruptEndPoint();
    }

    delete[] deviceName;

    return hr;
}

HRESULT
CMyDevice::OnReleaseHardware(
    _In_ IWDFDevice * /* FxDevice */
    )
/*++

Routine Description:

    This routine is invoked when the device is being removed or stopped
    It releases all resources allocated for this device.

Arguments:

    FxDevice - Pointer to the Device object.

Return Value:

    HRESULT - Always succeeds.

--*/
{
    //
    // Delete USB Target Device WDF Object, this will in turn
    // delete all the children - interface and the pipe objects
    //
    // This makes sure that 
    //    1. We drain the the pending read which does not come from an I/O queue
    //    2. We remove USB target objects from object tree (and thereby free them)
    //       before any potential subsequent OnPrepareHardware creates new ones
    //
    // m_pIUsbTargetDevice could be NULL if OnPrepareHardware failed so we need
    // to guard against that
    //

    if (m_pIUsbTargetDevice)
    {
        m_pIUsbTargetDevice->DeleteWdfObject();
    }

    return S_OK;
}

HRESULT
CMyDevice::CreateUsbIoTargets(
    )
/*++

Routine Description:

    This routine creates Usb device, interface and pipe objects

Arguments:

    None

Return Value:

    HRESULT
--*/
{
    HRESULT                 hr;
    UCHAR                   NumEndPoints = 0;
    IWDFUsbTargetFactory *  pIUsbTargetFactory = NULL;
    IWDFUsbTargetDevice *   pIUsbTargetDevice = NULL;
    IWDFUsbInterface *      pIUsbInterface = NULL;
    IWDFUsbTargetPipe *     pIUsbPipe = NULL;
    
    hr = m_FxDevice->QueryInterface(IID_PPV_ARGS(&pIUsbTargetFactory));

    if (FAILED(hr))
    {
        TraceEvents(TRACE_LEVEL_ERROR, 
                    TEST_TRACE_DEVICE, 
                    "%!FUNC! Cannot get usb target factory %!HRESULT!",
                    hr
                    );        
    }

    if (SUCCEEDED(hr)) 
    {
        hr = pIUsbTargetFactory->CreateUsbTargetDevice(
                                                  &pIUsbTargetDevice);
        if (FAILED(hr))
        {
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Unable to create USB Device I/O Target %!HRESULT!",
                        hr
                        );        
        }
        else
        {
            m_pIUsbTargetDevice = pIUsbTargetDevice;

            //
            // Release the creation reference as object tree will maintain a reference
            //
            
            pIUsbTargetDevice->Release();            
        }
    }

    if (SUCCEEDED(hr)) 
    {
        UCHAR NumInterfaces = pIUsbTargetDevice->GetNumInterfaces();

        WUDF_TEST_DRIVER_ASSERT(1 == NumInterfaces);
        
        hr = pIUsbTargetDevice->RetrieveUsbInterface(0, &pIUsbInterface);
        if (FAILED(hr))
        {
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Unable to retrieve USB interface from USB Device I/O Target %!HRESULT!",
                        hr
                        );        
        }
        else
        {
            m_pIUsbInterface = pIUsbInterface;

            pIUsbInterface->Release(); //release creation reference                        
        }
    }

    if (SUCCEEDED(hr)) 
    {
        NumEndPoints = pIUsbInterface->GetNumEndPoints();

        if (NumEndPoints != NUM_OSRUSB_ENDPOINTS) {
            hr = E_UNEXPECTED;
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Has %d endpoints, expected %d, returning %!HRESULT! ", 
                        NumEndPoints,
                        NUM_OSRUSB_ENDPOINTS,
                        hr
                        );
        }
    }

    if (SUCCEEDED(hr)) 
    {
        for (UCHAR PipeIndex = 0; PipeIndex < NumEndPoints; PipeIndex++)
        {
            hr = pIUsbInterface->RetrieveUsbPipeObject(PipeIndex, 
                                                  &pIUsbPipe);

            if (FAILED(hr))
            {
                TraceEvents(TRACE_LEVEL_ERROR, 
                            TEST_TRACE_DEVICE, 
                            "%!FUNC! Unable to retrieve USB Pipe for PipeIndex %d, %!HRESULT!",
                            PipeIndex,
                            hr
                            );        
            }
            else
            {
                if ( pIUsbPipe->IsInEndPoint() )
                {
                    if ( UsbdPipeTypeInterrupt == pIUsbPipe->GetType() )
                    {
                        m_pIUsbInterruptPipe = pIUsbPipe;

                        WUDF_TEST_DRIVER_ASSERT (m_pIoTargetInterruptPipeStateMgmt == NULL);

                        hr = m_pIUsbInterruptPipe->QueryInterface(__uuidof(
                                                   IWDFIoTargetStateManagement),
                                                   reinterpret_cast<void**>(&m_pIoTargetInterruptPipeStateMgmt)
                                                   );
                        if (FAILED(hr))
                        {
                            m_pIoTargetInterruptPipeStateMgmt = NULL;
                        }                        
                    }
                    else if ( UsbdPipeTypeBulk == pIUsbPipe->GetType() )
                    {
                        m_pIUsbInputPipe = pIUsbPipe;
                    }
                    else
                    {
                        pIUsbPipe->DeleteWdfObject();
                    }                      
                }
                else if ( pIUsbPipe->IsOutEndPoint() && (UsbdPipeTypeBulk == pIUsbPipe->GetType()) )
                {
                    m_pIUsbOutputPipe = pIUsbPipe;
                }
                else
                {
                    pIUsbPipe->DeleteWdfObject();
                }
    
                SAFE_RELEASE(pIUsbPipe); //release creation reference
            }
        }

        if (NULL == m_pIUsbInputPipe || NULL == m_pIUsbOutputPipe)
        {
            hr = E_UNEXPECTED;
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Input or output pipe not found, returning %!HRESULT!",
                        hr
                        );        
        }
    }

    SAFE_RELEASE(pIUsbTargetFactory);

    return hr;
}

HRESULT
CMyDevice::ConfigureUsbPipes(
    )
/*++

Routine Description:

    This routine retrieves the IDs for the bulk end points of the USB device.

Arguments:

    None

Return Value:

    HRESULT
--*/
{
    HRESULT                 hr = S_OK;
    LONG                    timeout;

    //
    // Set timeout policies for input/output pipes
    //

    if (SUCCEEDED(hr)) 
    {
        timeout = ENDPOINT_TIMEOUT;

        hr = m_pIUsbInputPipe->SetPipePolicy(PIPE_TRANSFER_TIMEOUT, 
                                             sizeof(timeout),
                                             &timeout);
        if (FAILED(hr))
        {
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Unable to set timeout policy for input pipe %!HRESULT!",
                        hr
                        );
        }
    }
        
    if (SUCCEEDED(hr)) 
    {
        timeout = ENDPOINT_TIMEOUT;

        hr = m_pIUsbOutputPipe->SetPipePolicy(PIPE_TRANSFER_TIMEOUT,
                                             sizeof(timeout),
                                             &timeout);
        if (FAILED(hr)) 
        {
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Unable to set timeout policy for output pipe %!HRESULT!",
                        hr
                        );
        }
    }

    return hr;
}

HRESULT
CMyDevice::IndicateDeviceReady(
    VOID
    )
/*++
 
  Routine Description:

    This method lights the period on the device's seven-segment display to 
    indicate that the driver's PrepareHardware method has completed.

  Arguments:

    None

  Return Value:

    Status

--*/
{
    SEVEN_SEGMENT display = {0};

    HRESULT hr;

    //
    // First read the contents of the seven segment display.
    //

    hr = GetSevenSegmentDisplay(&display);

    if (SUCCEEDED(hr)) 
    {
        display.Segments |= 0x08;

        hr = SetSevenSegmentDisplay(&display);
    }

    return hr;
}

HRESULT
CMyDevice::GetBarGraphDisplay(
    _In_ PBAR_GRAPH_STATE BarGraphState
    )
/*++
 
  Routine Description:

    This method synchronously retrieves the bar graph display information 
    from the OSR USB-FX2 device.  It uses the buffers in the FxRequest
    to hold the data it retrieves.

  Arguments:

    FxRequest - the request for the bar-graph info.

  Return Value:

    Status

--*/
{
    WINUSB_CONTROL_SETUP_PACKET setupPacket;

    ULONG bytesReturned;

    HRESULT hr = S_OK;

    //
    // Zero the contents of the buffer - the controller OR's in every
    // light that's set.
    //

    BarGraphState->BarsAsUChar = 0;

    //
    // Setup the control packet.
    //

    WINUSB_CONTROL_SETUP_PACKET_INIT( &setupPacket,
                                      BmRequestDeviceToHost,
                                      BmRequestToDevice,
                                      USBFX2LK_READ_BARGRAPH_DISPLAY,
                                      0,
                                      0 );

    //
    // Issue the request to WinUsb.
    //

    hr = SendControlTransferSynchronously(
                &(setupPacket.WinUsb),
                (PUCHAR) BarGraphState,
                sizeof(BAR_GRAPH_STATE),
                &bytesReturned
                );

    return hr;
}

HRESULT
CMyDevice::SetBarGraphDisplay(
    _In_ PBAR_GRAPH_STATE BarGraphState
    )
/*++
 
  Routine Description:

    This method synchronously sets the bar graph display on the OSR USB-FX2 
    device using the buffers in the FxRequest as input.

  Arguments:

    FxRequest - the request to set the bar-graph info.

  Return Value:

    Status

--*/
{
    WINUSB_CONTROL_SETUP_PACKET setupPacket;

    ULONG bytesTransferred;

    HRESULT hr = S_OK;

    //
    // Setup the control packet.
    //

    WINUSB_CONTROL_SETUP_PACKET_INIT( &setupPacket,
                                      BmRequestHostToDevice,
                                      BmRequestToDevice,
                                      USBFX2LK_SET_BARGRAPH_DISPLAY,
                                      0,
                                      0 );

    //
    // Issue the request to WinUsb.
    //

    hr = SendControlTransferSynchronously(
                &(setupPacket.WinUsb),
                (PUCHAR) BarGraphState,
                sizeof(BAR_GRAPH_STATE),
                &bytesTransferred
                );


    return hr;
}

HRESULT
CMyDevice::GetSevenSegmentDisplay(
    _In_ PSEVEN_SEGMENT SevenSegment
    )
/*++
 
  Routine Description:

    This method synchronously retrieves the bar graph display information 
    from the OSR USB-FX2 device.  It uses the buffers in the FxRequest
    to hold the data it retrieves.

  Arguments:

    FxRequest - the request for the bar-graph info.

  Return Value:

    Status

--*/
{
    WINUSB_CONTROL_SETUP_PACKET setupPacket;

    ULONG bytesReturned;

    HRESULT hr = S_OK;

    //
    // Zero the output buffer - the device will or in the bits for 
    // the lights that are set.
    //

    SevenSegment->Segments = 0;

    //
    // Setup the control packet.
    //

    WINUSB_CONTROL_SETUP_PACKET_INIT( &setupPacket,
                                      BmRequestDeviceToHost,
                                      BmRequestToDevice,
                                      USBFX2LK_READ_7SEGMENT_DISPLAY,
                                      0,
                                      0 );

    //
    // Issue the request to WinUsb.
    //

    hr = SendControlTransferSynchronously(
                &(setupPacket.WinUsb),
                (PUCHAR) SevenSegment,
                sizeof(SEVEN_SEGMENT),
                &bytesReturned
                );

    return hr;
}

HRESULT
CMyDevice::SetSevenSegmentDisplay(
    _In_ PSEVEN_SEGMENT SevenSegment
    )
/*++
 
  Routine Description:

    This method synchronously sets the bar graph display on the OSR USB-FX2 
    device using the buffers in the FxRequest as input.

  Arguments:

    FxRequest - the request to set the bar-graph info.

  Return Value:

    Status

--*/
{
    WINUSB_CONTROL_SETUP_PACKET setupPacket;

    ULONG bytesTransferred;

    HRESULT hr = S_OK;

    //
    // Setup the control packet.
    //

    WINUSB_CONTROL_SETUP_PACKET_INIT( &setupPacket,
                                      BmRequestHostToDevice,
                                      BmRequestToDevice,
                                      USBFX2LK_SET_7SEGMENT_DISPLAY,
                                      0,
                                      0 );

    //
    // Issue the request to WinUsb.
    //

    hr = SendControlTransferSynchronously(
                &(setupPacket.WinUsb),
                (PUCHAR) SevenSegment,
                sizeof(SEVEN_SEGMENT),
                &bytesTransferred
                );

    return hr;
}

HRESULT
CMyDevice::ReadSwitchState(
    _In_ PSWITCH_STATE SwitchState
    )
/*++
 
  Routine Description:

    This method synchronously retrieves the bar graph display information 
    from the OSR USB-FX2 device.  It uses the buffers in the FxRequest
    to hold the data it retrieves.

  Arguments:

    FxRequest - the request for the bar-graph info.

  Return Value:

    Status

--*/
{
    WINUSB_CONTROL_SETUP_PACKET setupPacket;

    ULONG bytesReturned;

    HRESULT hr = S_OK;

    //
    // Zero the output buffer - the device will or in the bits for 
    // the lights that are set.
    //

    SwitchState->SwitchesAsUChar = 0;

    //
    // Setup the control packet.
    //

    WINUSB_CONTROL_SETUP_PACKET_INIT( &setupPacket,
                                      BmRequestDeviceToHost,
                                      BmRequestToDevice,
                                      USBFX2LK_READ_SWITCHES,
                                      0,
                                      0 );

    //
    // Issue the request to WinUsb.
    //

    hr = SendControlTransferSynchronously(
                &(setupPacket.WinUsb),
                (PUCHAR) SwitchState,
                sizeof(SWITCH_STATE),
                &bytesReturned
                );

    return hr;
}

HRESULT
CMyDevice::SendControlTransferSynchronously(
    _In_ PWINUSB_SETUP_PACKET SetupPacket,
    _Inout_updates_(BufferLength) PBYTE Buffer,
    _In_ ULONG BufferLength,
    _Out_ PULONG LengthTransferred
    )
{
    HRESULT hr = S_OK;
    HRESULT hrRequest = S_OK;
    IWDFIoRequest *pWdfRequest = NULL;
    IWDFDriver * FxDriver = NULL;
    IWDFMemory * FxMemory = NULL; 
    IWDFRequestCompletionParams * FxComplParams = NULL;
    IWDFUsbRequestCompletionParams * FxUsbComplParams = NULL;

    *LengthTransferred = 0;
    
    hr = m_FxDevice->CreateRequest( NULL, //pCallbackInterface
                                    NULL, //pParentObject
                                    &pWdfRequest);
    hrRequest = hr;

    if (SUCCEEDED(hr))
    {
        m_FxDevice->GetDriver(&FxDriver);

        hr = FxDriver->CreatePreallocatedWdfMemory( Buffer,
                                                    BufferLength,
                                                    NULL, //pCallbackInterface
                                                    pWdfRequest, //pParetObject
                                                    &FxMemory );
    }

    if (SUCCEEDED(hr))
    {
        hr = m_pIUsbTargetDevice->FormatRequestForControlTransfer( pWdfRequest,
                                                                   SetupPacket,
                                                                   FxMemory,
                                                                   NULL); //TransferOffset
    }                                                          
                        
    if (SUCCEEDED(hr))
    {
        hr = pWdfRequest->Send( m_pIUsbTargetDevice,
                                WDF_REQUEST_SEND_OPTION_SYNCHRONOUS,
                                0); //Timeout
    }

    if (SUCCEEDED(hr))
    {
        pWdfRequest->GetCompletionParams(&FxComplParams);

        hr = FxComplParams->GetCompletionStatus();
    }

    if (SUCCEEDED(hr))
    {
        HRESULT hrQI = FxComplParams->QueryInterface(IID_PPV_ARGS(&FxUsbComplParams));
        WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrQI));

        WUDF_TEST_DRIVER_ASSERT( WdfUsbRequestTypeDeviceControlTransfer == 
                            FxUsbComplParams->GetCompletedUsbRequestType() );

        FxUsbComplParams->GetDeviceControlTransferParameters( NULL,
                                                             LengthTransferred,
                                                             NULL,
                                                             NULL );
    }

    SAFE_RELEASE(FxUsbComplParams);
    SAFE_RELEASE(FxComplParams);
    SAFE_RELEASE(FxMemory);

    if (SUCCEEDED(hrRequest))
    {
        pWdfRequest->DeleteWdfObject();
    }
    SAFE_RELEASE(pWdfRequest);

    SAFE_RELEASE(FxDriver);

    return hr;
}

WDF_IO_TARGET_STATE
CMyDevice::GetTargetState(
    IWDFIoTarget * pTarget
    )
{
    IWDFIoTargetStateManagement * pStateMgmt = NULL;
    WDF_IO_TARGET_STATE state;

    HRESULT hrQI = pTarget->QueryInterface(IID_PPV_ARGS(&pStateMgmt));
    WUDF_TEST_DRIVER_ASSERT((SUCCEEDED(hrQI) && pStateMgmt));
    
    state = pStateMgmt->GetState();

    SAFE_RELEASE(pStateMgmt);
    
    return state;
}
    
VOID
CMyDevice::ServiceSwitchChangeQueue(
    _In_ SWITCH_STATE NewState,
    _In_ HRESULT CompletionStatus,
    _In_opt_ IWDFFile *SpecificFile
    )
/*++
 
  Routine Description:

    This method processes switch-state change notification requests as 
    part of reading the OSR device's interrupt pipe.  As each read completes
    this pulls all pending I/O off the switch change queue and completes
    each request with the current switch state.

  Arguments:

    NewState - the state of the switches

    CompletionStatus - all pending operations are completed with this status.

    SpecificFile - if provided only requests for this file object will get
                   completed.

  Return Value:

    None

--*/
{
    IWDFIoRequest *fxRequest;

    HRESULT enumHr = S_OK;

    do 
    {
        HRESULT hr;

        //
        // Get the next request.
        //

        if (NULL != SpecificFile)
        {
            enumHr = m_SwitchChangeQueue->RetrieveNextRequestByFileObject(
                                            SpecificFile,
                                            &fxRequest
                                            );
        }
        else
        {
            enumHr = m_SwitchChangeQueue->RetrieveNextRequest(&fxRequest);
        }

        //
        // if we got one then complete it.
        //

        if (SUCCEEDED(enumHr)) 
        {
            if (SUCCEEDED(CompletionStatus)) 
            {
                IWDFMemory *fxMemory;

                //
                // First copy the result to the request buffer.
                //

                fxRequest->GetOutputMemory(&fxMemory );

                hr = fxMemory->CopyFromBuffer(0, 
                                              &NewState, 
                                              sizeof(SWITCH_STATE));
                fxMemory->Release();
            }
            else 
            {
                hr = CompletionStatus;
            }

            //
            // Complete the request with the status of the copy (or the completion
            // status if that was an error).
            //

            if (SUCCEEDED(hr)) 
            {
                fxRequest->CompleteWithInformation(hr, sizeof(SWITCH_STATE));
            }
            else
            {
                fxRequest->Complete(hr);
            }

            fxRequest->Release();            
        }
    }
    while (SUCCEEDED(enumHr));
}

HRESULT
CMyDevice::SetPowerManagement(
    VOID
    )
/*++

  Routine Description:

    This method enables the idle and wake functionality
    using UMDF. UMDF has been set as the power policy
    owner (PPO) for the device stack and we are using power
    managed queues.

  Arguments:

    None

  Return Value:
    
    Status

--*/
{ 
    HRESULT hr;

    //
    // Enable USB selective suspend on the device.    
    // 
    
    hr = m_FxDevice->AssignS0IdleSettings( IdleUsbSelectiveSuspend,
                                PowerDeviceMaximum,
                                IDLE_TIMEOUT_IN_MSEC,
                                IdleAllowUserControl,
                                WdfUseDefault);                                                                                                   

    if (FAILED(hr))
    {
        TraceEvents(TRACE_LEVEL_ERROR, 
                    TEST_TRACE_DEVICE, 
                    "%!FUNC! Unable to assign S0 idle settings for the device %!HRESULT!",
                    hr
                    );
    }

    //
    // Enable Sx wake settings
    //

    if (SUCCEEDED(hr))
    {
        hr = m_FxDevice->AssignSxWakeSettings( PowerDeviceMaximum,
                                    WakeAllowUserControl,
                                    WdfUseDefault);
                                    
        if (FAILED(hr))
        {
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Unable to set Sx Wake Settings for the device %!HRESULT!",
                        hr
                        );
        }
        
    }


    return hr;
}

HRESULT
CMyDevice::OnD0Entry(
    _In_ IWDFDevice*  pWdfDevice,
    _In_ WDF_POWER_DEVICE_STATE  previousState
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);
    UNREFERENCED_PARAMETER(previousState);

    // 
    // Start/Stop the I/O target if you support a continuous reader.
    // The rest of the I/O is fed through power managed queues. The queue 
    // itself will stop feeding I/O to targets (and will wait for any pending 
    // I/O to complete before going into low power state), hence targets 
    // don�t need to be stopped/started. The continuous reader I/O is outside
    // of power managed queues so we need to Stop the I/O target on D0Exit and
    //  start it on D0Entry. Please note that bulk pipe target doesn't need to 
    // be stopped/started because I/O submitted to this pipe comes from power 
    // managed I/O queue, which delivers I/O only in power on state.
    //

    m_pIoTargetInterruptPipeStateMgmt->Start();

    return S_OK;
}

HRESULT
CMyDevice::OnD0Exit(
    _In_ IWDFDevice*  pWdfDevice,
    _In_ WDF_POWER_DEVICE_STATE  previousState
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);
    UNREFERENCED_PARAMETER(previousState);

    //
    // Stop the I/O target always succeedes.
    //
    m_pIoTargetInterruptPipeStateMgmt->Stop(WdfIoTargetCancelSentIo);
    return S_OK;
}

void
CMyDevice::OnSurpriseRemoval(
    _In_ IWDFDevice*  pWdfDevice
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);
    return;
}

HRESULT
CMyDevice::OnQueryRemove(
    _In_ IWDFDevice*  pWdfDevice
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);
    return S_OK;
}

HRESULT
CMyDevice::OnQueryStop(
    _In_ IWDFDevice*  pWdfDevice
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);
    return S_OK;
}

//
// Self Managed Io Callbacks
//

VOID
CMyDevice::OnSelfManagedIoCleanup(
    _In_ IWDFDevice*  pWdfDevice
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);
    return;
}

VOID
CMyDevice::OnSelfManagedIoFlush(
    _In_ IWDFDevice*  pWdfDevice
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);

    //
    // Complete every switch change operation with an error.
    //
    ServiceSwitchChangeQueue(m_SwitchState, 
                             HRESULT_FROM_WIN32(ERROR_DEVICE_REMOVED),
                             NULL);

    return;
}

HRESULT
CMyDevice::OnSelfManagedIoInit(
    _In_ IWDFDevice*  pWdfDevice
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);
    return S_OK;
}

HRESULT
CMyDevice::OnSelfManagedIoRestart(
    _In_ IWDFDevice*  pWdfDevice
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);
    return S_OK;
}

HRESULT
CMyDevice::OnSelfManagedIoStop(
    _In_ IWDFDevice*  pWdfDevice
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);
    return S_OK;
}

HRESULT
CMyDevice::OnSelfManagedIoSuspend(
    _In_ IWDFDevice*  pWdfDevice
    )
{
    UNREFERENCED_PARAMETER(pWdfDevice);
    return S_OK;
}



HRESULT
CMyDevice::ConfigContReaderForInterruptEndPoint(
    VOID
    )
/*++

Routine Description:

    This routine configures a continuous reader on the
    interrupt endpoint. It's called from the PrepareHarware event.

Arguments:


Return Value:

    HRESULT value

--*/
{
    HRESULT hr, hrQI;
    IUsbTargetPipeContinuousReaderCallbackReadComplete *pOnCompletionCallback = NULL;
    IUsbTargetPipeContinuousReaderCallbackReadersFailed *pOnFailureCallback= NULL;
    IWDFUsbTargetPipe2 * pIUsbInterruptPipe2;

    hrQI = this->QueryInterface(IID_PPV_ARGS(&pOnCompletionCallback));
    WUDF_TEST_DRIVER_ASSERT((SUCCEEDED(hrQI) && pOnCompletionCallback));

    hrQI = this->QueryInterface(IID_PPV_ARGS(&pOnFailureCallback));
    WUDF_TEST_DRIVER_ASSERT((SUCCEEDED(hrQI) && pOnFailureCallback));

    hrQI = m_pIUsbInterruptPipe->QueryInterface(IID_PPV_ARGS(&pIUsbInterruptPipe2));
    WUDF_TEST_DRIVER_ASSERT((SUCCEEDED(hrQI) && pIUsbInterruptPipe2));

    //
    // Reader requests are not posted to the target automatically.
    // Driver must explictly call WdfIoTargetStart to kick start the
    // reader.  In this sample, it's done in D0Entry.
    // By defaut, framework queues two requests to the target
    // endpoint. Driver can configure up to 10 requests with the 
    // parameter CONCURRENT_READS
    //    
    hr = pIUsbInterruptPipe2->ConfigureContinuousReader( sizeof(m_SwitchStateBuffer), 
                                                          0,//header
                                                          0,//trailer
                                                          CONCURRENT_READS, 
                                                          NULL,
                                                          pOnCompletionCallback,
                                                          m_pIUsbInterruptPipe,
                                                          pOnFailureCallback
                                                          );
               
    if (FAILED(hr)) {
        TraceEvents(TRACE_LEVEL_ERROR, TEST_TRACE_DEVICE,
                    "OsrFxConfigContReaderForInterruptEndPoint failed %!HRESULT!",
                    hr);
    }

    SAFE_RELEASE(pOnCompletionCallback);
    SAFE_RELEASE(pOnFailureCallback);
    SAFE_RELEASE(pIUsbInterruptPipe2);

    return hr;
}


BOOL
CMyDevice::OnReaderFailure(
    IWDFUsbTargetPipe * pPipe,
    HRESULT hrCompletion
    )
{   
    UNREFERENCED_PARAMETER(pPipe);
    
    m_InterruptReadProblem = hrCompletion;
    TraceEvents(TRACE_LEVEL_INFORMATION, 
                TEST_TRACE_DEVICE, 
                "%!FUNC! Failure completed with %!HRESULT!",
                hrCompletion
                );
    
    ServiceSwitchChangeQueue(m_SwitchState, 
                             hrCompletion,
                             NULL);

    return TRUE;
}

VOID
CMyDevice::OnReaderCompletion(
    IWDFUsbTargetPipe * pPipe,
    IWDFMemory * pMemory,
    SIZE_T NumBytesTransferred,
    PVOID Context
    )
{        
    WUDF_TEST_DRIVER_ASSERT(pPipe ==  (IWDFUsbTargetPipe *)Context);

    //
    // Make sure that there is data in the read packet.  Depending on the device
    // specification, it is possible for it to return a 0 length read in
    // certain conditions.
    //

    if (NumBytesTransferred == 0) {
        TraceEvents(TRACE_LEVEL_INFORMATION, 
                    TEST_TRACE_DEVICE, 
                    "%!FUNC! Zero length read occured on the Interrupt Pipe's "
                    "Continuous Reader\n"
                    );
        return;
    }

    WUDF_TEST_DRIVER_ASSERT(NumBytesTransferred == sizeof(m_SwitchState));
    
    //
    // Get the switch state
    //
    
    PVOID pBuff = pMemory->GetDataBuffer(NULL);

    CopyMemory(&m_SwitchState, pBuff, sizeof(m_SwitchState));
    
        
    //
    // Satisfy application request for switch change notification
    //
    
    ServiceSwitchChangeQueue(m_SwitchState, 
                             S_OK,
                             NULL);

    //
    // Make sure that the request that got completed is the one that we reuse
    // Don't Delete the request because it gets reused
    //
}


HRESULT
CMyDevice::GetBusTypeGuid(
    VOID
    )
/*++
 
  Routine Description:

    This routine gets the device instance ID then invokes SetupDi to 
    retrieve the bus type guid for the device.  The bus type guid is 
    stored in object.

  Arguments:

    None

  Return Value:

    Status

--*/
{
    ULONG instanceIdCch = 0;
    PWSTR instanceId = NULL;

    HDEVINFO deviceInfoSet = NULL;
    SP_DEVINFO_DATA deviceInfo = {sizeof(SP_DEVINFO_DATA)};

    HRESULT hr;

    //
    // Retrieve the device instance ID.
    //

    hr = m_FxDevice->RetrieveDeviceInstanceId(NULL, &instanceIdCch);

    if (FAILED(hr))
    {
        goto Exit;
    }

    instanceId = new WCHAR[instanceIdCch];

    if (instanceId == NULL)
    {
        hr = E_OUTOFMEMORY;
        goto Exit;
    }

    hr = m_FxDevice->RetrieveDeviceInstanceId(instanceId, &instanceIdCch);

    if (FAILED(hr))
    {
        goto Exit2;
    }

    //
    // Call SetupDI to open the device info.
    //

    deviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL);

    if (deviceInfoSet == INVALID_HANDLE_VALUE)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit2;
    }

    if (SetupDiOpenDeviceInfo(deviceInfoSet,
                              instanceId,
                              NULL,
                              0,
                              &deviceInfo) == FALSE)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit3;
    }

    if (SetupDiGetDeviceRegistryProperty(deviceInfoSet,
                                         &deviceInfo,
                                         SPDRP_BUSTYPEGUID,
                                         NULL,
                                         (PBYTE) &m_BusTypeGuid,
                                         sizeof(m_BusTypeGuid),
                                         NULL) == FALSE)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        goto Exit3;
    }

Exit3:
    SetupDiDestroyDeviceInfoList(deviceInfoSet);

Exit2:

    delete[] instanceId;

Exit:

    return hr;
}

HRESULT
CMyDevice::PlaybackFile(
    _In_ PFILE_PLAYBACK PlayInfo,
    _In_ IWDFIoRequest *FxRequest
    )
/*++
 
  Routine Description:

    This method impersonates the caller, opens the file and prints each 
    character to the seven segement display.

  Arguments:

    PlayInfo - the playback info from the request.
  
    FxRequest - the request (used for impersonation)

  Return Value:

    Status

--*/

{
    PLAYBACK_IMPERSONATION_CONTEXT context = {PlayInfo, NULL, S_OK};
    IWDFIoRequest2* fxRequest2;

    HRESULT hr;

    // Convert FxRequest to FxRequest2.  No error can occur here.
    FxRequest->QueryInterface(IID_PPV_ARGS(&fxRequest2));
    _Analysis_assume_(fxRequest2 != NULL);

    //
    // Impersonate and open the playback file.
    //

    hr = FxRequest->Impersonate(
                        SecurityImpersonation,
                        this->QueryIImpersonateCallback(),
                        &context
                        );
    if (FAILED(hr))
    {
        goto exit;
    }

    //
    // Release the reference that was added in QueryIImpersonateCallback()
    //
    this->Release();

    hr = context.Hr;

    if (FAILED(hr))
    {
        goto exit;
    }
    
    //
    // The impersonation callback succeeded - tell code analysis that the 
    // file handle is non-null
    //

    _Analysis_assume_(context.FileHandle != NULL);

    //
    // Read from the file one character at a time until we hit 
    // EOF or the request is cancelled.
    //

    do
    {
        UCHAR c;
        ULONG bytesRead;

        //
        // Check for cancellation.
        //

        if (fxRequest2->IsCanceled())
        {
            hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
        }
        else
        {
            BOOL result;

            //
            // Read a character from the file and see if we can 
            // encode it on the display.
            //

            result = ReadFile(context.FileHandle,
                              &c,
                              sizeof(c),
                              &bytesRead,
                              NULL);

            if (result)
            {
                SEVEN_SEGMENT segment;
                BAR_GRAPH_STATE barGraph;

                if (bytesRead > 0)
                {
                    #pragma prefast(suppress:__WARNING_USING_UNINIT_VAR,"Above this->Release() method does not actually free 'this'")
                    if(EncodeSegmentValue(c, &segment) == true)
                    {
                        barGraph.BarsAsUChar = c;

                        SetSevenSegmentDisplay(&segment);
                        SetBarGraphDisplay(&barGraph);
                    }

                    Sleep(PlayInfo->Delay);
                }
                else
                {
                    hr = S_OK;
                    break;
                }
            }
            else
            {
                hr = HRESULT_FROM_WIN32(GetLastError());
            }
        }

    } while(SUCCEEDED(hr));
    
    CloseHandle(context.FileHandle);

exit:

    fxRequest2->Release();
    return hr;
}

VOID
CMyDevice::OnImpersonate(
    _In_ PVOID Context
    )
/*++
 
  Routine Description:

    This routine handles the impersonation for the PLAY FILE I/O control.

  Arguments:

    Context - pointer to the impersonation context

  Return Value:

    None

--*/
{
    PPLAYBACK_IMPERSONATION_CONTEXT context;

    context = (PPLAYBACK_IMPERSONATION_CONTEXT) Context;

    context->FileHandle = CreateFile(context->PlaybackInfo->Path, 
                                     GENERIC_READ,
                                     FILE_SHARE_READ,
                                     NULL,
                                     OPEN_EXISTING,
                                     FILE_ATTRIBUTE_NORMAL,
                                     NULL);

    if (context->FileHandle == INVALID_HANDLE_VALUE)
    {
        DWORD error = GetLastError();
        context->Hr = HRESULT_FROM_WIN32(error);
    }
    else
    {
        context->Hr = S_OK;
    }

    return;
}

#define SS_LEFT (SS_TOP_LEFT | SS_BOTTOM_LEFT)
#define SS_RIGHT (SS_TOP_RIGHT | SS_BOTTOM_RIGHT)

bool
CMyDevice::EncodeSegmentValue(
    _In_ UCHAR Character,
    _Out_ SEVEN_SEGMENT *SevenSegment
    )
{
    UCHAR letterMap[] = {
        (SS_TOP | SS_BOTTOM_LEFT | SS_RIGHT | SS_CENTER | SS_BOTTOM),   // a
        (SS_LEFT | SS_CENTER | SS_BOTTOM | SS_BOTTOM_RIGHT),            // b
        (SS_CENTER | SS_BOTTOM_LEFT | SS_BOTTOM),                       // c
        (SS_BOTTOM_LEFT | SS_CENTER | SS_BOTTOM | SS_RIGHT),            // d
        (SS_LEFT | SS_TOP | SS_CENTER | SS_BOTTOM),                     // e
        (SS_LEFT | SS_TOP | SS_CENTER),                                 // f
        (SS_TOP | SS_TOP_LEFT | SS_CENTER | SS_BOTTOM | SS_RIGHT),      // g
        (SS_LEFT | SS_RIGHT | SS_CENTER),                               // h
        (SS_BOTTOM_LEFT),                                               // i
        (SS_BOTTOM | SS_RIGHT),                                         // j
        (SS_LEFT | SS_CENTER | SS_BOTTOM),                              // k
        (SS_LEFT | SS_BOTTOM),                                          // l
        (SS_LEFT | SS_TOP | SS_RIGHT),                                  // m
        (SS_BOTTOM_LEFT | SS_CENTER | SS_BOTTOM_RIGHT),                 // n
        (SS_BOTTOM_LEFT | SS_BOTTOM_RIGHT | SS_CENTER | SS_BOTTOM),     // o
        (SS_LEFT | SS_TOP | SS_CENTER | SS_TOP_RIGHT),                  // p
        (SS_TOP_LEFT | SS_TOP | SS_CENTER | SS_RIGHT),                  // q
        (SS_BOTTOM_LEFT | SS_CENTER),                                   // r
        (SS_TOP_LEFT | 
         SS_TOP | SS_CENTER | SS_BOTTOM | 
         SS_BOTTOM_RIGHT),                                              // s
        (SS_TOP | SS_RIGHT),                                            // t
        (SS_LEFT | SS_RIGHT | SS_BOTTOM),                               // u
        (SS_BOTTOM_LEFT | SS_BOTTOM | SS_BOTTOM_RIGHT),                 // v
        (SS_LEFT | SS_BOTTOM | SS_BOTTOM_RIGHT),                        // w
        (SS_LEFT | SS_CENTER | SS_RIGHT),                               // x
        (SS_TOP_LEFT | SS_CENTER | SS_RIGHT),                           // y 
        (SS_TOP_RIGHT | 
         SS_TOP | SS_CENTER | SS_BOTTOM | 
         SS_BOTTOM_LEFT),                                               // z
    };

    UCHAR numberMap[] = {
        (SS_LEFT | SS_TOP | SS_BOTTOM | SS_RIGHT | SS_DOT),             // 0
        (SS_RIGHT | SS_DOT),                                            // 1
        (SS_TOP | 
         SS_TOP_RIGHT | SS_CENTER | SS_BOTTOM_LEFT | 
         SS_BOTTOM | SS_DOT),                                           // 2
        (SS_TOP | SS_CENTER | SS_BOTTOM | SS_RIGHT | SS_DOT),           // 3
        (SS_TOP_LEFT | SS_CENTER | SS_RIGHT | SS_DOT),                  // 4
        (SS_TOP_LEFT | 
         SS_TOP | SS_CENTER | SS_BOTTOM | 
         SS_BOTTOM_RIGHT | SS_DOT),                                     // 5
        (SS_TOP | SS_CENTER | SS_BOTTOM | 
         SS_LEFT | SS_BOTTOM_RIGHT | SS_DOT),                           // 6
        (SS_TOP | SS_RIGHT | SS_DOT),                                   // 7
        (SS_TOP | SS_BOTTOM | SS_CENTER | 
         SS_LEFT | SS_RIGHT | SS_DOT),                                  // 8
        (SS_TOP_LEFT | SS_TOP | SS_CENTER | SS_RIGHT | SS_DOT),         // 9
    };

    if (((Character >= 'a') && (Character <= 'z')) || 
        ((Character >= 'A') && (Character <= 'Z')))
    {
        SevenSegment->Segments = letterMap[tolower(Character) - 'a'];
        return true;
    }
    else if ((Character >= '0') && (Character <= '9'))
    {
        SevenSegment->Segments = numberMap[Character - '0'];
        return true;
    }
    else
    {
        SevenSegment->Segments = 0;
        return false;
    }
}

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS