UT: Add eSE initialize tests.
This change adds tests for initializing NCI with an eSE and for connecting/disconnecting an eSE client handle.
This commit is contained in:
Родитель
9e221cfa4b
Коммит
5eb4d43180
|
@ -23,7 +23,8 @@ DeviceContext::DeviceAdd(
|
|||
NFC_CX_CLIENT_CONFIG_INIT(&nfcCxConfig, NFC_CX_TRANSPORT_CUSTOM);
|
||||
nfcCxConfig.EvtNfcCxWriteNciPacket = WriteNciPacketCallback;
|
||||
nfcCxConfig.EvtNfcCxDeviceIoControl = DeviceIoCallback;
|
||||
nfcCxConfig.DriverFlags = NFC_CX_DRIVER_ENABLE_EEPROM_WRITE_PROTECTION;
|
||||
nfcCxConfig.DriverFlags = NFC_CX_DRIVER_ENABLE_EEPROM_WRITE_PROTECTION |
|
||||
NFC_CX_DRIVER_POWER_AND_LINK_CONTROL_SUPPORTED;
|
||||
|
||||
status = NfcCxDeviceInitConfig(DeviceInit, &nfcCxConfig);
|
||||
if (!NT_SUCCESS(status))
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
<WppModuleName>NfcNciSimulator</WppModuleName>
|
||||
<WppScanConfigurationData>Trace.h</WppScanConfigurationData>
|
||||
<DisableSpecificWarnings>4577;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\Api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\Api;$(ProjectDir)..\..\..\inc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>tracepdb -f $(OutDir)$(AssemblyName).pdb -p $(OutDir)</Command>
|
||||
|
|
|
@ -0,0 +1,436 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All Rights Reserved
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Async
|
||||
{
|
||||
namespace Details
|
||||
{
|
||||
// Helper class for `RunOnBackground` function.
|
||||
template <typename FuncType>
|
||||
struct RunOnBackgroundContext
|
||||
{
|
||||
FuncType Func;
|
||||
|
||||
static void CALLBACK Callback(
|
||||
_Inout_ PTP_CALLBACK_INSTANCE Instance,
|
||||
_Inout_opt_ void* Context)
|
||||
{
|
||||
(void)Instance;
|
||||
std::unique_ptr<RunOnBackgroundContext> context(reinterpret_cast<RunOnBackgroundContext*>(Context));
|
||||
context->Func();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Runs a functor on a threadpool thread.
|
||||
template <typename FuncType>
|
||||
inline void RunOnBackground(FuncType&& func)
|
||||
{
|
||||
using ContextType = Details::RunOnBackgroundContext<std::remove_reference_t<FuncType>>;
|
||||
auto context = std::unique_ptr<ContextType>(new ContextType{ std::forward<FuncType>(func) });
|
||||
|
||||
BOOL submitResult = TrySubmitThreadpoolCallback(&ContextType::Callback, context.get(), nullptr);
|
||||
if (!submitResult)
|
||||
{
|
||||
throw std::system_error(::GetLastError(), std::system_category());
|
||||
}
|
||||
|
||||
// Transfer ownership of context to callback.
|
||||
context.release();
|
||||
}
|
||||
|
||||
namespace Details
|
||||
{
|
||||
// Stores the result value for `AsyncTaskBase`.
|
||||
// This type exists to help handle the case where the result type is `void`.
|
||||
template <typename ResultType>
|
||||
struct AsyncTaskBaseStorage
|
||||
{
|
||||
template <typename... ArgTypes>
|
||||
AsyncTaskBaseStorage(ArgTypes&&... args) :
|
||||
_Value{ std::forward<ArgTypes>(args)... }
|
||||
{
|
||||
}
|
||||
|
||||
ResultType Acquire()
|
||||
{
|
||||
return std::move(_Value);
|
||||
}
|
||||
|
||||
private:
|
||||
ResultType _Value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct AsyncTaskBaseStorage<void>
|
||||
{
|
||||
void Acquire()
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// An object that returns a result sometime in the future. (e.g. std::future, IAsyncOperation).
|
||||
template <typename ResultType>
|
||||
class AsyncTaskBase :
|
||||
public std::enable_shared_from_this<AsyncTaskBase<ResultType>>
|
||||
{
|
||||
public:
|
||||
// The function signature of the completed callback.
|
||||
//
|
||||
// Note: The task's result can be retrieved at any time after the task has completed, not just during
|
||||
// the completed callback.
|
||||
using CompletedHandlerType = void(AsyncTaskBase<ResultType>& asyncTask);
|
||||
|
||||
// Sets a callback function that is called when the task completes.
|
||||
// If the task has already completed, then the callback is invoked during the SetCompletedHandler call.
|
||||
//
|
||||
// Return:
|
||||
// true - The callback function was succesfully set.
|
||||
// false - The callback function has already been set.
|
||||
bool SetCompletedHandler(std::function<CompletedHandlerType>&& completedHandler)
|
||||
{
|
||||
std::unique_lock<std::mutex> gate(_Lock);
|
||||
if (_CompletedHandlerWasSet)
|
||||
{
|
||||
// Completed handler already set.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_Result.has_value())
|
||||
{
|
||||
// Set the completed handler.
|
||||
_CompletedHandler = std::move(completedHandler);
|
||||
_CompletedHandlerWasSet = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
_CompletedHandlerWasSet = true;
|
||||
gate.unlock();
|
||||
|
||||
// Both result and completed handler are now available.
|
||||
// So call the completed handler immediately.
|
||||
completedHandler(*this);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sets a callback function that is called when the task completes.
|
||||
// The callback is guaranteed not to be called during the SetAsyncCompletedHandler call.
|
||||
//
|
||||
// Return:
|
||||
// true - The callback function was succesfully set.
|
||||
// false - The callback function has already been set.
|
||||
bool SetAsyncCompletedHandler(std::function<CompletedHandlerType>&& completedHandler)
|
||||
{
|
||||
std::unique_lock<std::mutex> gate(_Lock);
|
||||
if (_CompletedHandlerWasSet)
|
||||
{
|
||||
// Completed handler already set.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the completed handler.
|
||||
_CompletedHandler = std::move(completedHandler);
|
||||
_CompletedHandlerWasSet = true;
|
||||
|
||||
if (!_Result.has_value())
|
||||
{
|
||||
// No result available yet. The callback will be invoked when the result is provided.
|
||||
return true;
|
||||
}
|
||||
|
||||
gate.unlock();
|
||||
|
||||
// Both result and completed handler are now available.
|
||||
// Queue the completed callback to be invoked on another thread.
|
||||
RunOnBackground(
|
||||
[me = shared_from_this()]()
|
||||
{
|
||||
// Note: It is safe to read and modify _CompletedHandler here outside of the lock as
|
||||
// no other thread will ever touch the variable again.
|
||||
me->_CompletedHandler(*me);
|
||||
me->_CompletedHandler = nullptr;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns if the task has completed.
|
||||
bool Completed()
|
||||
{
|
||||
std::unique_lock<std::mutex> gate(_Lock);
|
||||
return _Result.has_value();
|
||||
}
|
||||
|
||||
// Requests that the async operation is canceled.
|
||||
// This is best effort and may be ignored.
|
||||
void Cancel()
|
||||
{
|
||||
std::unique_lock<std::mutex> gate(_Lock);
|
||||
|
||||
if (_Canceled || _Result.has_value())
|
||||
{
|
||||
// Task has already been canceled or the task has already completed.
|
||||
return;
|
||||
}
|
||||
|
||||
_Canceled = true;
|
||||
|
||||
gate.unlock();
|
||||
|
||||
// Tell child class that a cancelation request has been made.
|
||||
OnCanceled();
|
||||
}
|
||||
|
||||
// Waits for the task to complete, with a timeout.
|
||||
//
|
||||
// Return:
|
||||
// true - The task completed succesfully.
|
||||
// false - The wait timed out.
|
||||
bool Wait(DWORD timeoutMilliseconds)
|
||||
{
|
||||
std::unique_lock<std::mutex> gate(_Lock);
|
||||
while (!_Result.has_value())
|
||||
{
|
||||
if (std::cv_status::timeout == _Updated.wait_for(gate, std::chrono::milliseconds(timeoutMilliseconds)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Waits for the task to complete.
|
||||
void Wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> gate(_Lock);
|
||||
while (!_Result.has_value())
|
||||
{
|
||||
_Updated.wait(gate);
|
||||
}
|
||||
}
|
||||
|
||||
// Waits and returns the result (via std::move).
|
||||
ResultType Get()
|
||||
{
|
||||
std::unique_lock<std::mutex> gate(_Lock);
|
||||
while (!_Result.has_value())
|
||||
{
|
||||
_Updated.wait(gate);
|
||||
}
|
||||
|
||||
return _Result.value().Acquire();
|
||||
}
|
||||
|
||||
protected:
|
||||
// Returns if a cancelation has been requested.
|
||||
bool Canceled()
|
||||
{
|
||||
std::unique_lock<std::mutex> gate(_Lock);
|
||||
return _Canceled;
|
||||
}
|
||||
|
||||
// Set the result of the task.
|
||||
//
|
||||
// Return:
|
||||
// true - The result was succesfully set.
|
||||
// false - The result has already been set.
|
||||
template <typename... ArgTypes>
|
||||
bool EmplaceResult(ArgTypes&&... args)
|
||||
{
|
||||
std::unique_lock<std::mutex> gate(_Lock);
|
||||
if (_Result.has_value())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_Result.emplace(std::forward<ArgTypes>(args)...);
|
||||
_Updated.notify_all();
|
||||
|
||||
if (!_CompletedHandlerWasSet)
|
||||
{
|
||||
// Still waiting on the completed handler.
|
||||
return true;
|
||||
}
|
||||
|
||||
gate.unlock();
|
||||
|
||||
// Both result and completed handler are now available.
|
||||
// So call the completed handler.
|
||||
// Note: It is safe to read and modify _CompletedHandler here outside of the lock as
|
||||
// no other thread will ever touch the variable again.
|
||||
_CompletedHandler(*this);
|
||||
_CompletedHandler = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void OnCanceled()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex _Lock;
|
||||
std::condition_variable _Updated;
|
||||
std::function<CompletedHandlerType> _CompletedHandler;
|
||||
std::optional<Details::AsyncTaskBaseStorage<ResultType>> _Result;
|
||||
bool _CompletedHandlerWasSet = false;
|
||||
bool _Canceled = false;
|
||||
};
|
||||
|
||||
// A type that promises to provide a value sometime in the future. (e.g. std::promise)
|
||||
template <typename ResultType>
|
||||
class AsyncTaskCompletionSource final :
|
||||
public AsyncTaskBase<ResultType>
|
||||
{
|
||||
public:
|
||||
AsyncTaskCompletionSource() = default;
|
||||
using AsyncTaskBase::EmplaceResult;
|
||||
using AsyncTaskBase::Canceled;
|
||||
};
|
||||
|
||||
// Makes a `AsyncTaskCompletionSource` type.
|
||||
template <typename ResultType>
|
||||
std::shared_ptr<AsyncTaskCompletionSource<ResultType>> MakeCompletionSource()
|
||||
{
|
||||
return std::make_shared<AsyncTaskCompletionSource<ResultType>>();
|
||||
}
|
||||
|
||||
namespace Details
|
||||
{
|
||||
// Implementation of `RunBackgroundTask` function, when the result type is not `void`.
|
||||
template <bool IsResultVoid>
|
||||
struct RunBackgroundTaskImpl
|
||||
{
|
||||
template <typename FuncType>
|
||||
static auto Run(FuncType&& func) -> std::shared_ptr<AsyncTaskBase<std::invoke_result_t<FuncType>>>
|
||||
{
|
||||
using ResultType = std::invoke_result_t<FuncType>;
|
||||
std::shared_ptr<AsyncTaskCompletionSource<ResultType>> completionSource = MakeCompletionSource<ResultType>();
|
||||
|
||||
RunOnBackground(
|
||||
[func = std::forward<FuncType>(func), completionSource]()
|
||||
{
|
||||
completionSource->EmplaceResult(func());
|
||||
});
|
||||
|
||||
return completionSource;
|
||||
}
|
||||
};
|
||||
|
||||
// Implementation of `RunBackgroundTask` function, when the result type is `void`.
|
||||
template <>
|
||||
struct RunBackgroundTaskImpl<true>
|
||||
{
|
||||
template <typename FuncType>
|
||||
static auto Run(FuncType&& func) -> std::shared_ptr<AsyncTaskBase<std::invoke_result_t<FuncType>>>
|
||||
{
|
||||
using ResultType = std::invoke_result_t<FuncType>;
|
||||
std::shared_ptr<AsyncTaskCompletionSource<ResultType>> completionSource = MakeCompletionSource<ResultType>();
|
||||
|
||||
RunOnBackground(
|
||||
[func = std::forward<FuncType>(func), completionSource]()
|
||||
{
|
||||
func();
|
||||
completionSource->EmplaceResult();
|
||||
});
|
||||
|
||||
return completionSource;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Executes a function on a threadpool thread.
|
||||
//
|
||||
// Return: A task that completes when the function has finished executing, which provides the result of the function.
|
||||
template <typename FuncType>
|
||||
inline auto RunBackgroundTask(FuncType&& func) -> std::shared_ptr<AsyncTaskBase<std::invoke_result_t<FuncType>>>
|
||||
{
|
||||
using ImplType = Details::RunBackgroundTaskImpl<std::is_void_v<std::invoke_result_t<FuncType>>>;
|
||||
return ImplType::Run(std::forward<FuncType>(func));
|
||||
}
|
||||
|
||||
namespace Details
|
||||
{
|
||||
// The type that keeps track of the state of a `WaitForAny` call.
|
||||
struct WaitForAnyContext
|
||||
{
|
||||
static constexpr size_t UnsetTaskIndex = 0;
|
||||
std::atomic<size_t> CompletedTaskIndex = UnsetTaskIndex;
|
||||
};
|
||||
|
||||
// Sets the completed handler on the provided task for the WaitForAnyFor function.
|
||||
template <typename ResultType>
|
||||
inline void WaitForAny_SetCompletedHandler(size_t index, const std::shared_ptr<WaitForAnyContext>& context, AsyncTaskBase<ResultType>& task)
|
||||
{
|
||||
task.SetCompletedHandler(
|
||||
[index, context](AsyncTaskBase<ResultType>& task)
|
||||
{
|
||||
(void)task;
|
||||
size_t expectedValue = WaitForAnyContext::UnsetTaskIndex;
|
||||
if (context->CompletedTaskIndex.compare_exchange_strong(expectedValue, index))
|
||||
{
|
||||
::WakeByAddressAll(&context->CompletedTaskIndex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Sets the completed handler on the provided tasks for the WaitForAnyFor function.
|
||||
template <typename ResultType, typename... ResultTypes>
|
||||
inline void WaitForAny_SetCompletedHandler(size_t index, const std::shared_ptr<WaitForAnyContext>& context, AsyncTaskBase<ResultType>& task, AsyncTaskBase<ResultTypes>&... tasks)
|
||||
{
|
||||
WaitForAny_SetCompletedHandler(index, context, task);
|
||||
WaitForAny_SetCompletedHandler(index + 1, context, tasks...);
|
||||
}
|
||||
}
|
||||
|
||||
// Waits for any of the provided tasks to complete or for the timeout to expire.
|
||||
//
|
||||
// Return:
|
||||
// 0 - The timeout expired.
|
||||
// 1+ - The index of the task that completed.
|
||||
template <typename... ResultTypes>
|
||||
inline size_t WaitForAnyWithTimeout(DWORD timeoutMilliseconds, const std::shared_ptr<AsyncTaskBase<ResultTypes>>&... tasks)
|
||||
{
|
||||
auto context = std::make_shared<Details::WaitForAnyContext>();
|
||||
Details::WaitForAny_SetCompletedHandler(1, context, (*tasks)...);
|
||||
|
||||
size_t index = context->CompletedTaskIndex;
|
||||
while (index == Details::WaitForAnyContext::UnsetTaskIndex)
|
||||
{
|
||||
static_assert(sizeof(index) == sizeof(context->CompletedTaskIndex), "Unsupported std::atomic implementation");
|
||||
if (!::WaitOnAddress(&context->CompletedTaskIndex, &index, sizeof(index), timeoutMilliseconds))
|
||||
{
|
||||
// Timed out.
|
||||
return 0;
|
||||
}
|
||||
|
||||
index = context->CompletedTaskIndex;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Waits for any of the provided tasks to complete.
|
||||
//
|
||||
// Return: The index of the task that completed.
|
||||
template <typename... ResultTypes>
|
||||
inline size_t WaitForAny(const std::shared_ptr<AsyncTaskBase<ResultTypes>>&... tasks)
|
||||
{
|
||||
size_t index = WaitForAnyWithTimeout(INFINITE, tasks...);
|
||||
return index - 1;
|
||||
}
|
||||
}
|
|
@ -72,3 +72,24 @@ DriverHandleFactory::OpenSmartcardHandle(
|
|||
|
||||
return std::move(scInterface);
|
||||
}
|
||||
|
||||
std::shared_ptr<::Async::AsyncTaskBase<UniqueHandle>>
|
||||
DriverHandleFactory::OpenSmartcardHandleAsync(
|
||||
_In_ PCWSTR deviceName,
|
||||
_In_ ::winrt::Windows::Devices::SmartCards::SmartCardReaderKind readerKind)
|
||||
{
|
||||
return Async::RunBackgroundTask(
|
||||
[deviceName = std::wstring(deviceName), readerKind]()
|
||||
{
|
||||
return OpenSmartcardHandle(deviceName.c_str(), readerKind);
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<::Async::AsyncTaskBase<void>>
|
||||
DriverHandleFactory::CloseHandleAsync(UniqueHandle&& obj)
|
||||
{
|
||||
return Async::RunBackgroundTask(
|
||||
[obj = std::move(obj)]()
|
||||
{
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include <winrt/windows.devices.smartcards.h>
|
||||
|
||||
#include "AsyncTask.h"
|
||||
#include "UniqueHandle.h"
|
||||
|
||||
class DriverHandleFactory
|
||||
|
@ -20,4 +23,8 @@ public:
|
|||
static UniqueHandle OpenSmartcardHandle(
|
||||
_In_ PCWSTR deviceName,
|
||||
_In_ ::winrt::Windows::Devices::SmartCards::SmartCardReaderKind readerKind);
|
||||
static std::shared_ptr<::Async::AsyncTaskBase<UniqueHandle>> OpenSmartcardHandleAsync(
|
||||
_In_ PCWSTR deviceName,
|
||||
_In_ ::winrt::Windows::Devices::SmartCards::SmartCardReaderKind readerKind);
|
||||
static std::shared_ptr<::Async::AsyncTaskBase<void>> CloseHandleAsync(UniqueHandle&& obj);
|
||||
};
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
#include "IoOperation.h"
|
||||
|
||||
std::shared_ptr<IoOperation>
|
||||
IoOperation::DeviceIoControl(_In_ HANDLE driverHandle, _In_ DWORD ioctl, _In_reads_bytes_opt_(inputSize) const void* input, _In_ DWORD inputSize, DWORD _In_ outputBufferSize, _In_ std::function<Callback> callback)
|
||||
IoOperation::DeviceIoControl(_In_ HANDLE driverHandle, _In_ DWORD ioctl, _In_reads_bytes_opt_(inputSize) const void* input, _In_ DWORD inputSize, _In_ DWORD outputBufferSize)
|
||||
{
|
||||
auto ioOperation = std::make_shared<IoOperation>(PrivateToken{}, driverHandle, input, inputSize, outputBufferSize, std::move(callback));
|
||||
auto ioOperation = std::make_shared<IoOperation>(PrivateToken{}, driverHandle, input, inputSize, outputBufferSize);
|
||||
|
||||
void* inputBuffer = inputSize == 0 ?
|
||||
nullptr :
|
||||
|
@ -32,11 +32,10 @@ IoOperation::DeviceIoControl(_In_ HANDLE driverHandle, _In_ DWORD ioctl, _In_rea
|
|||
return ioOperation;
|
||||
}
|
||||
|
||||
IoOperation::IoOperation(PrivateToken, _In_ HANDLE driverHandle, _In_reads_bytes_opt_(inputSize) const void* input, _In_ DWORD inputSize, DWORD _In_ outputBufferSize, std::function<Callback>&& callback) :
|
||||
IoOperation::IoOperation(PrivateToken, _In_ HANDLE driverHandle, _In_reads_bytes_opt_(inputSize) const void* input, _In_ DWORD inputSize, _In_ DWORD outputBufferSize) :
|
||||
_DriverHandle(driverHandle),
|
||||
_InputBuffer((const BYTE*)input, (const BYTE*)input + inputSize),
|
||||
_OutputBuffer(outputBufferSize),
|
||||
_Callback(std::move(callback))
|
||||
_OutputBuffer(outputBufferSize)
|
||||
{
|
||||
ZeroMemory(&_Overlapped, sizeof(_Overlapped));
|
||||
|
||||
|
@ -84,70 +83,18 @@ IoOperation::IoCompleted()
|
|||
// Drop the self-reference once this function has completed.
|
||||
std::shared_ptr<IoOperation> selfRef = std::move(_SelfRef);
|
||||
|
||||
// Get the result of the operation.
|
||||
BOOL operationSucceeded = GetOverlappedResult(_DriverHandle, &_Overlapped, &_BytesReturned, /*wait*/ false);
|
||||
// Get the results of the operation.
|
||||
DWORD bytesTransferred;
|
||||
BOOL operationSucceeded = GetOverlappedResult(_DriverHandle, &_Overlapped, &bytesTransferred, /*wait*/ false);
|
||||
|
||||
// Handle results.
|
||||
if (operationSucceeded)
|
||||
{
|
||||
_OperationResult = ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
_OperationResult = GetLastError();
|
||||
}
|
||||
DWORD errorCode = operationSucceeded ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
// Let other threads know that the operation has completed.
|
||||
WakeByAddressAll(&_OperationResult);
|
||||
|
||||
// Call callback (if provided).
|
||||
if (_Callback)
|
||||
{
|
||||
_Callback(selfRef);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IoOperation::Wait(_In_ DWORD timeoutMilliseconds)
|
||||
{
|
||||
for (DWORD operationResult = _OperationResult; _OperationResult == ERROR_IO_PENDING; operationResult = _OperationResult)
|
||||
{
|
||||
static_assert(sizeof(_OperationResult) == sizeof(DWORD), "std::atomic has an unsupported implementation");
|
||||
if (!WaitOnAddress(&_OperationResult, &operationResult, sizeof(DWORD), timeoutMilliseconds))
|
||||
{
|
||||
// Wait timed out
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
// Set the task result.
|
||||
EmplaceResult(errorCode, bytesTransferred, std::move(_OutputBuffer));
|
||||
}
|
||||
|
||||
void
|
||||
IoOperation::Cancel()
|
||||
IoOperation::OnCanceled()
|
||||
{
|
||||
CancelIoEx(_DriverHandle, &_Overlapped);
|
||||
}
|
||||
|
||||
IoOperation::Result
|
||||
IoOperation::GetResult()
|
||||
{
|
||||
if (_OperationResult == ERROR_IO_PENDING)
|
||||
{
|
||||
throw std::runtime_error("I/O operation has not completed yet.");
|
||||
}
|
||||
|
||||
return { _OperationResult, _BytesReturned, std::move(_OutputBuffer) };
|
||||
}
|
||||
|
||||
// Waits for the I/O request to complete and returns the result.
|
||||
IoOperation::Result
|
||||
IoOperation::WaitForResult(_In_ DWORD timeoutMilliseconds)
|
||||
{
|
||||
if (!Wait(timeoutMilliseconds))
|
||||
{
|
||||
return { ERROR_TIMEOUT, 0, {} };
|
||||
}
|
||||
|
||||
return { _OperationResult, _BytesReturned, std::move(_OutputBuffer) };
|
||||
}
|
||||
|
|
|
@ -9,49 +9,36 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "AsyncTask.h"
|
||||
#include "UniqueHandle.h"
|
||||
|
||||
struct IoOperationResult
|
||||
{
|
||||
DWORD ErrorCode = ERROR_SUCCESS;
|
||||
DWORD BytesTransferred = 0;
|
||||
std::vector<BYTE> Output;
|
||||
};
|
||||
|
||||
// A helper class for making a Win32 I/O request.
|
||||
class IoOperation
|
||||
class IoOperation final :
|
||||
public Async::AsyncTaskBase<IoOperationResult>
|
||||
{
|
||||
// Make the constructor private but still allow std::make_shared to be used.
|
||||
struct PrivateToken {};
|
||||
|
||||
public:
|
||||
using Callback = void(const std::shared_ptr<IoOperation>& ioOperation);
|
||||
|
||||
struct Result
|
||||
{
|
||||
DWORD ErrorCode = ERROR_SUCCESS;
|
||||
DWORD BytesTransferred = 0;
|
||||
std::vector<BYTE> Output;
|
||||
};
|
||||
|
||||
static std::shared_ptr<IoOperation> DeviceIoControl(
|
||||
_In_ HANDLE driverHandle,
|
||||
_In_ DWORD ioctl,
|
||||
_In_reads_bytes_opt_(inputSize) const void* input,
|
||||
_In_ DWORD inputSize,
|
||||
_In_ DWORD outputBufferSize,
|
||||
_In_ std::function<Callback> callback = nullptr);
|
||||
_In_ DWORD outputBufferSize);
|
||||
|
||||
IoOperation(PrivateToken, _In_ HANDLE driverHandle, _In_reads_bytes_opt_(inputSize) const void* input, _In_ DWORD inputSize, DWORD _In_ outputBufferSize, std::function<Callback>&& callback);
|
||||
IoOperation(PrivateToken, _In_ HANDLE driverHandle, _In_reads_bytes_opt_(inputSize) const void* input, _In_ DWORD inputSize, _In_ DWORD outputBufferSize);
|
||||
~IoOperation();
|
||||
|
||||
IoOperation(const IoOperation&) = delete;
|
||||
IoOperation(IoOperation&&) = delete;
|
||||
IoOperation& operator=(const IoOperation&) = delete;
|
||||
IoOperation& operator=(IoOperation&&) = delete;
|
||||
|
||||
// Waits for the I/O request to complete.
|
||||
bool Wait(_In_ DWORD timeoutMilliseconds);
|
||||
// Requests that the I/O request is canceled. Note that the I/O request will still be completed.
|
||||
void Cancel();
|
||||
// Gets the result.
|
||||
Result GetResult();
|
||||
// Waits for the I/O request to complete and returns the result. If I/O operation fails to complete in
|
||||
// the specified time, ERROR_TIMEOUT is returned.
|
||||
Result WaitForResult(_In_ DWORD timeoutMilliseconds);
|
||||
protected:
|
||||
void OnCanceled() override;
|
||||
|
||||
private:
|
||||
static void CALLBACK IoCompletedCallback(
|
||||
|
@ -69,7 +56,4 @@ private:
|
|||
std::shared_ptr<IoOperation> _SelfRef;
|
||||
std::vector<BYTE> _InputBuffer;
|
||||
std::vector<BYTE> _OutputBuffer;
|
||||
DWORD _BytesReturned = 0;
|
||||
std::atomic<DWORD> _OperationResult = ERROR_IO_PENDING;
|
||||
std::function<Callback> _Callback;
|
||||
};
|
||||
|
|
|
@ -35,8 +35,9 @@ bool
|
|||
RadioManager::GetNfcRadioState()
|
||||
{
|
||||
std::shared_ptr<IoOperation> ioOperation = IoOperation::DeviceIoControl(_DeviceInterface.Get(), IOCTL_NFCRM_QUERY_RADIO_STATE, nullptr, 0, sizeof(NFCRM_RADIO_STATE));
|
||||
IoOperation::Result ioResult = ioOperation->WaitForResult(/*wait (ms)*/ 1'000);
|
||||
VERIFY_IS_TRUE(ioOperation->Wait(/*wait (ms)*/ 1'000));
|
||||
|
||||
IoOperationResult ioResult = ioOperation->Get();
|
||||
VERIFY_WIN32_SUCCEEDED(ioResult.ErrorCode, L"Get radio state");
|
||||
|
||||
auto radioState = reinterpret_cast<const NFCRM_RADIO_STATE*>(ioResult.Output.data());
|
||||
|
@ -66,7 +67,9 @@ RadioManager::SetRadioState(bool isSystemUpdate, bool enableRadio)
|
|||
radioState.MediaRadioOn = enableRadio;
|
||||
|
||||
std::shared_ptr<IoOperation> ioOperation = IoOperation::DeviceIoControl(_DeviceInterface.Get(), IOCTL_NFCRM_SET_RADIO_STATE, &radioState, sizeof(radioState), 0);
|
||||
IoOperation::Result ioResult = ioOperation->WaitForResult(/*wait (ms)*/ 1'000);
|
||||
VERIFY_IS_TRUE(ioOperation->Wait(/*wait (ms)*/ 1'000));
|
||||
|
||||
IoOperationResult ioResult = ioOperation->Get();
|
||||
|
||||
// ERROR_BAD_COMMAND is returned when the state is already correct.
|
||||
if (ioResult.ErrorCode != ERROR_BAD_COMMAND)
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(FrameworkSdkDir)Testing\Development\inc;$(ProjectDir)..\NfcCxTestDeviceDriver\Api;$(ProjectDir)..\..\libs\NfcCoreLib\inc;$(ProjectDir)..\..\libs\NfcCoreLib\lib\NciCore;$(ProjectDir)..\..\libs\NfcCoreLib\lib\Nci;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(FrameworkSdkDir)Testing\Development\inc;$(ProjectDir)..\NfcCxTestDeviceDriver\Api;$(ProjectDir)..\..\libs\NfcCoreLib\inc;$(ProjectDir)..\..\libs\NfcCoreLib\lib\Fri;$(ProjectDir)..\..\libs\NfcCoreLib\lib\LibNfc;$(ProjectDir)..\..\libs\NfcCoreLib\lib\NciCore;$(ProjectDir)..\..\libs\NfcCoreLib\lib\Nci;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<PreprocessorDefinitions>INITGUID;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
|
@ -79,6 +79,7 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="IOHelpers\AsyncTask.h" />
|
||||
<ClInclude Include="IOHelpers\DeviceQuery.h" />
|
||||
<ClInclude Include="IOHelpers\DriverHandleFactory.h" />
|
||||
<ClInclude Include="IOHelpers\IoOperation.h" />
|
||||
|
@ -88,9 +89,11 @@
|
|||
<ClInclude Include="SimulationSequences\InitSequences.h" />
|
||||
<ClInclude Include="SimulationSequences\Precomp.h" />
|
||||
<ClInclude Include="SimulationSequences\RfDiscoverySequences.h" />
|
||||
<ClInclude Include="SimulationSequences\SEInitializationSequences.h" />
|
||||
<ClInclude Include="SimulationSequences\TagSequences.h" />
|
||||
<ClInclude Include="Simulation\NciControlPacket.h" />
|
||||
<ClInclude Include="Simulation\NciDataPacket.h" />
|
||||
<ClInclude Include="Simulation\NciHciDataPacket.h" />
|
||||
<ClInclude Include="Simulation\NciPacket.h" />
|
||||
<ClInclude Include="Simulation\NciSimConnector.h" />
|
||||
<ClInclude Include="Simulation\Precomp.h" />
|
||||
|
@ -112,9 +115,11 @@
|
|||
<ClCompile Include="IOHelpers\UniqueHandle.cpp" />
|
||||
<ClCompile Include="SimulationSequences\InitSequences.cpp" />
|
||||
<ClCompile Include="SimulationSequences\RfDiscoverySequences.cpp" />
|
||||
<ClCompile Include="SimulationSequences\SEInitializationSequences.cpp" />
|
||||
<ClCompile Include="SimulationSequences\TagSequences.cpp" />
|
||||
<ClCompile Include="Simulation\NciControlPacket.cpp" />
|
||||
<ClCompile Include="Simulation\NciDataPacket.cpp" />
|
||||
<ClCompile Include="Simulation\NciHciDataPacket.cpp" />
|
||||
<ClCompile Include="Simulation\NciPacket.cpp" />
|
||||
<ClCompile Include="Simulation\NciSimConnector.cpp" />
|
||||
<ClCompile Include="Simulation\SimSequenceRunner.cpp" />
|
||||
|
@ -126,6 +131,7 @@
|
|||
<ClCompile Include="Tests\AirplaneModeTests.cpp" />
|
||||
<ClCompile Include="Tests\InitTests.cpp" />
|
||||
<ClCompile Include="Tests\Module.cpp" />
|
||||
<ClCompile Include="Tests\SETests.cpp" />
|
||||
<ClCompile Include="Tests\TagTests.cpp" />
|
||||
<ClCompile Include="Tests\TestLogging.cpp" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -87,6 +87,15 @@
|
|||
<ClInclude Include="Simulation\TestDeviceInstall.h">
|
||||
<Filter>Simulation</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IOHelpers\AsyncTask.h">
|
||||
<Filter>IOHelpers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Simulation\NciHciDataPacket.h">
|
||||
<Filter>Simulation</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SimulationSequences\SEInitializationSequences.h">
|
||||
<Filter>SimulationSequences</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="IOHelpers\DeviceQuery.cpp">
|
||||
|
@ -158,5 +167,14 @@
|
|||
<ClCompile Include="Simulation\TestDeviceInstall.cpp">
|
||||
<Filter>Simulation</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Simulation\NciHciDataPacket.cpp">
|
||||
<Filter>Simulation</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SimulationSequences\SEInitializationSequences.cpp">
|
||||
<Filter>SimulationSequences</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Tests\SETests.cpp">
|
||||
<Filter>Tests</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,152 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All Rights Reserved
|
||||
//
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "NciHciDataPacket.h"
|
||||
|
||||
NciHciDataPacket::NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ phHciNfc_MsgType_t messageType,
|
||||
_In_ uint8_t instruction,
|
||||
_In_ std::initializer_list<uint8_t> payload)
|
||||
:
|
||||
NciHciDataPacket(connectionId, pipeId, messageType, instruction, payload.begin(), uint8_t(payload.size()), true)
|
||||
{
|
||||
}
|
||||
|
||||
NciHciDataPacket::NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ phHciNfc_MsgType_t messageType,
|
||||
_In_ uint8_t instruction,
|
||||
_In_ std::initializer_list<uint8_t> payload,
|
||||
_In_ bool finalPacket)
|
||||
:
|
||||
NciHciDataPacket(connectionId, pipeId, messageType, instruction, payload.begin(), uint8_t(payload.size()), finalPacket)
|
||||
{
|
||||
}
|
||||
|
||||
NciHciDataPacket::NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ phHciNfc_MsgType_t messageType,
|
||||
_In_ uint8_t instruction,
|
||||
_In_reads_(payloadLength) const uint8_t* payload,
|
||||
_In_ uint8_t payloadLength,
|
||||
_In_ bool finalPacket)
|
||||
:
|
||||
NciDataPacket(connectionId, GenerateFirstPacket(pipeId, messageType, instruction, payload, payloadLength, finalPacket).data(), CalculateFirstPacketLength(payloadLength), true)
|
||||
{
|
||||
}
|
||||
|
||||
NciHciDataPacket::NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ std::initializer_list<uint8_t> payload)
|
||||
:
|
||||
NciHciDataPacket(connectionId, pipeId, payload.begin(), uint8_t(payload.size()), true)
|
||||
{
|
||||
}
|
||||
|
||||
NciHciDataPacket::NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ std::initializer_list<uint8_t> payload,
|
||||
_In_ bool finalPacket)
|
||||
:
|
||||
NciHciDataPacket(connectionId, pipeId, payload.begin(), uint8_t(payload.size()), finalPacket)
|
||||
{
|
||||
}
|
||||
|
||||
NciHciDataPacket::NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_reads_(payloadLength) const uint8_t* payload,
|
||||
_In_ uint8_t payloadLength,
|
||||
_In_ bool finalPacket)
|
||||
:
|
||||
NciDataPacket(connectionId, GenerateSubsequentPacket(pipeId, payload, payloadLength, finalPacket).data(), CalculateSubsequentPacketLength(payloadLength), true)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr uint8_t
|
||||
NciHciDataPacket::GenerateHcpHeader(bool isFinalPacket, uint8_t pipeId)
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 5.1, HCP packets
|
||||
constexpr uint8_t chainBit = 0x80; // bit 8
|
||||
constexpr uint8_t instructionMask = 0x7F; // bits [0,7]
|
||||
|
||||
return (isFinalPacket ? chainBit : 0x00) |
|
||||
(pipeId & instructionMask);
|
||||
}
|
||||
|
||||
std::array<uint8_t, NciPacketRaw::MaxPayloadLength>
|
||||
NciHciDataPacket::GenerateFirstPacket(
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ phHciNfc_MsgType_t messageType,
|
||||
_In_ uint8_t instruction,
|
||||
_In_reads_(payloadLength) const uint8_t* payload,
|
||||
_In_ uint8_t payloadLength,
|
||||
_In_ bool finalPacket)
|
||||
{
|
||||
std::array<uint8_t, NciPacketRaw::MaxPayloadLength> packet = {};
|
||||
|
||||
// Add HCP packet header
|
||||
packet[0] = GenerateHcpHeader(finalPacket, pipeId);
|
||||
|
||||
// Add HCP message header
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 5.2, HCP message structure
|
||||
constexpr uint8_t messageTypeBitShift = 6;
|
||||
constexpr uint8_t messageTypeBitMask = 0xC0; // bits [7,8]
|
||||
constexpr uint8_t instructionBitMask = 0x3F; // bits [0,6]
|
||||
packet[1] = ((messageType << messageTypeBitShift) & messageTypeBitMask) |
|
||||
(instruction & instructionBitMask);
|
||||
|
||||
// Ensure HCI payload isn't too big.
|
||||
if (payloadLength > NciHciDataPacket::MaxPayloadSize)
|
||||
{
|
||||
throw std::exception("NciHciDataPacket payload is too big.");
|
||||
}
|
||||
|
||||
// Copy payload.
|
||||
std::copy(payload, payload + payloadLength, packet.data() + 2);
|
||||
return packet;
|
||||
}
|
||||
|
||||
constexpr uint8_t
|
||||
NciHciDataPacket::CalculateFirstPacketLength(uint8_t payloadLength)
|
||||
{
|
||||
return payloadLength + 2; // Add 2 bytes for HCP header + HCP message header
|
||||
}
|
||||
|
||||
std::array<uint8_t, NciPacketRaw::MaxPayloadLength>
|
||||
NciHciDataPacket::GenerateSubsequentPacket(
|
||||
_In_ uint8_t pipeId,
|
||||
_In_reads_(payloadLength) const uint8_t* payload,
|
||||
_In_ uint8_t payloadLength,
|
||||
_In_ bool finalPacket)
|
||||
{
|
||||
std::array<uint8_t, NciPacketRaw::MaxPayloadLength> packet = {};
|
||||
|
||||
// Add HCP packet header
|
||||
packet[0] = GenerateHcpHeader(finalPacket, pipeId);
|
||||
|
||||
if (payloadLength > NciHciDataPacket::MaxPayloadSize)
|
||||
{
|
||||
throw std::exception("NciHciDataPacket payload is too big.");
|
||||
}
|
||||
|
||||
std::copy(payload, payload + payloadLength, packet.data() + 1);
|
||||
return packet;
|
||||
}
|
||||
|
||||
constexpr uint8_t
|
||||
NciHciDataPacket::CalculateSubsequentPacketLength(uint8_t payloadLength)
|
||||
{
|
||||
return payloadLength + 1; // Add 1 byte for HCP header
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All Rights Reserved
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
#include <phHciNfc_Core.h>
|
||||
#include <phHciNfc_Interface.h>
|
||||
|
||||
#include "NciDataPacket.h"
|
||||
|
||||
// A HCI packet wrapped within an NCI data packet.
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 5, HCP
|
||||
class NciHciDataPacket :
|
||||
public NciDataPacket
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t MaxHeaderSize = 2;
|
||||
static constexpr uint8_t MaxPayloadSize = NciPacketRaw::MaxPayloadLength - MaxHeaderSize;
|
||||
|
||||
// Simple packet (no message fragment chaining).
|
||||
NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ phHciNfc_MsgType_t messageType,
|
||||
_In_ uint8_t instruction,
|
||||
_In_ std::initializer_list<uint8_t> payload);
|
||||
|
||||
// First packet in message fragment chain.
|
||||
NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ phHciNfc_MsgType_t messageType,
|
||||
_In_ uint8_t instruction,
|
||||
_In_ std::initializer_list<uint8_t> payload,
|
||||
_In_ bool finalPacket);
|
||||
|
||||
// First packet in message fragment chain.
|
||||
NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ phHciNfc_MsgType_t messageType,
|
||||
_In_ uint8_t instruction,
|
||||
_In_reads_(payloadLength) const uint8_t* payload,
|
||||
_In_ uint8_t payloadLength,
|
||||
_In_ bool finalPacket);
|
||||
|
||||
// Subsequent and final packet in message fragment chain.
|
||||
NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ std::initializer_list<uint8_t> payload);
|
||||
|
||||
// Subsequent packet in message fragment chain.
|
||||
NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ std::initializer_list<uint8_t> payload,
|
||||
_In_ bool finalPacket);
|
||||
|
||||
// Subsequent packet in message fragment chain.
|
||||
NciHciDataPacket(
|
||||
_In_ uint8_t connectionId,
|
||||
_In_ uint8_t pipeId,
|
||||
_In_reads_(payloadLength) const uint8_t* payload,
|
||||
_In_ uint8_t payloadLength,
|
||||
_In_ bool finalPacket);
|
||||
|
||||
private:
|
||||
static constexpr uint8_t
|
||||
GenerateHcpHeader(bool isFinalPacket, uint8_t pipeId);
|
||||
|
||||
static std::array<uint8_t, NciPacketRaw::MaxPayloadLength>
|
||||
GenerateFirstPacket(
|
||||
_In_ uint8_t pipeId,
|
||||
_In_ phHciNfc_MsgType_t messageType,
|
||||
_In_ uint8_t instruction,
|
||||
_In_reads_(payloadLength) const uint8_t* payload,
|
||||
_In_ uint8_t payloadLength,
|
||||
_In_ bool finalPacket);
|
||||
|
||||
static constexpr uint8_t
|
||||
CalculateFirstPacketLength(uint8_t payloadLength);
|
||||
|
||||
static std::array<uint8_t, NciPacketRaw::MaxPayloadLength>
|
||||
GenerateSubsequentPacket(
|
||||
_In_ uint8_t pipeId,
|
||||
_In_reads_(payloadLength) const uint8_t* payload,
|
||||
_In_ uint8_t payloadLength,
|
||||
_In_ bool finalPacket);
|
||||
|
||||
static constexpr uint8_t
|
||||
CalculateSubsequentPacketLength(uint8_t payloadLength);
|
||||
};
|
|
@ -59,15 +59,21 @@ NciSimConnector::~NciSimConnector()
|
|||
|
||||
while (_CallbacksState != CallbacksState::Stopped)
|
||||
{
|
||||
std::shared_ptr<IoOperation> callbackIo = _CurrentCallbackIo.lock();
|
||||
|
||||
// Cancel any pending I/O.
|
||||
if (_CurrentCallbackIo)
|
||||
if (callbackIo)
|
||||
{
|
||||
_CurrentCallbackIo->Cancel();
|
||||
callbackIo->Cancel();
|
||||
}
|
||||
|
||||
// Wait for the callbacks loop to stop.
|
||||
_CallbacksUpdatedEvent.wait(gate);
|
||||
}
|
||||
|
||||
// Ensure there aren't any leftover callbacks, to ensure the test has accounted for all the events.
|
||||
VERIFY_ARE_EQUAL(0u, _LibNfcThreadCallbacks.size());
|
||||
VERIFY_ARE_EQUAL(0u, _PowerCallbacks.size());
|
||||
}
|
||||
|
||||
const std::wstring&
|
||||
|
@ -153,6 +159,42 @@ NciSimConnector::ReceivePowerCallback()
|
|||
return std::move(result);
|
||||
}
|
||||
|
||||
std::shared_ptr<Async::AsyncTaskBase<void>>
|
||||
NciSimConnector::WhenLibNfcThreadCallbackAvailableAsync()
|
||||
{
|
||||
std::shared_ptr<Async::AsyncTaskCompletionSource<void>> completionSource = Async::MakeCompletionSource<void>();
|
||||
|
||||
std::unique_lock<std::mutex> gate(_CallbacksLock);
|
||||
if (!_LibNfcThreadCallbacks.empty())
|
||||
{
|
||||
completionSource->EmplaceResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_LibNfcThreadCallbackWaiters.push_back(completionSource);
|
||||
}
|
||||
|
||||
return completionSource;
|
||||
}
|
||||
|
||||
std::shared_ptr<Async::AsyncTaskBase<void>>
|
||||
NciSimConnector::WhenPowerCallbackAvailableAsync()
|
||||
{
|
||||
std::shared_ptr<Async::AsyncTaskCompletionSource<void>> completionSource = Async::MakeCompletionSource<void>();
|
||||
|
||||
std::unique_lock<std::mutex> gate(_CallbacksLock);
|
||||
if (!_PowerCallbacks.empty())
|
||||
{
|
||||
completionSource->EmplaceResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_PowerCallbackWaiters.push_back(completionSource);
|
||||
}
|
||||
|
||||
return completionSource;
|
||||
}
|
||||
|
||||
void
|
||||
NciSimConnector::StartGetNextCallback()
|
||||
{
|
||||
|
@ -164,19 +206,22 @@ NciSimConnector::StartGetNextCallback()
|
|||
return;
|
||||
}
|
||||
|
||||
_CurrentCallbackIo = IoOperation::DeviceIoControl(_DriverHandle.Get(), IOCTL_NCISIM_GET_NEXT_CALLBACK, nullptr, 0, _CallbackAllocSize,
|
||||
[this](const std::shared_ptr<IoOperation>& ioOperation)
|
||||
std::shared_ptr<IoOperation> callbackIo = IoOperation::DeviceIoControl(_DriverHandle.Get(), IOCTL_NCISIM_GET_NEXT_CALLBACK, nullptr, 0, _CallbackAllocSize);
|
||||
_CurrentCallbackIo = callbackIo;
|
||||
|
||||
callbackIo->SetAsyncCompletedHandler(
|
||||
[this](Async::AsyncTaskBase<IoOperationResult>& ioOperation)
|
||||
{
|
||||
this->CallbackRetrieved(ioOperation);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
NciSimConnector::CallbackRetrieved(const std::shared_ptr<IoOperation>& ioOperation)
|
||||
NciSimConnector::CallbackRetrieved(Async::AsyncTaskBase<IoOperationResult>& ioOperation)
|
||||
{
|
||||
std::unique_lock<std::mutex> gate(_CallbacksLock);
|
||||
|
||||
_CurrentCallbackIo = nullptr;
|
||||
_CurrentCallbackIo.reset();
|
||||
if (_CallbacksState == CallbacksState::Stopping)
|
||||
{
|
||||
// Class is being destroyed.
|
||||
|
@ -185,7 +230,7 @@ NciSimConnector::CallbackRetrieved(const std::shared_ptr<IoOperation>& ioOperati
|
|||
return;
|
||||
}
|
||||
|
||||
IoOperation::Result ioResult = ioOperation->GetResult();
|
||||
IoOperationResult ioResult = ioOperation.Get();
|
||||
if (ioResult.ErrorCode == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
// Increase the size of the output buffer.
|
||||
|
@ -196,6 +241,7 @@ NciSimConnector::CallbackRetrieved(const std::shared_ptr<IoOperation>& ioOperati
|
|||
|
||||
// Try get the message again but with a bigger buffer this time.
|
||||
StartGetNextCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
ThrowIfWin32Failed(ioResult.ErrorCode);
|
||||
|
@ -208,14 +254,33 @@ NciSimConnector::CallbackRetrieved(const std::shared_ptr<IoOperation>& ioOperati
|
|||
{
|
||||
case NciSimCallbackType::NciWrite:
|
||||
case NciSimCallbackType::SequenceHandler:
|
||||
{
|
||||
_LibNfcThreadCallbacks.push(std::move(callbackMessage));
|
||||
break;
|
||||
|
||||
for (const std::shared_ptr<Async::AsyncTaskCompletionSource<void>>& waiter : _LibNfcThreadCallbackWaiters)
|
||||
{
|
||||
waiter->EmplaceResult();
|
||||
}
|
||||
|
||||
_LibNfcThreadCallbackWaiters.clear();
|
||||
|
||||
break;
|
||||
}
|
||||
case NciSimCallbackType::D0Entry:
|
||||
case NciSimCallbackType::D0Exit:
|
||||
{
|
||||
_PowerCallbacks.push(std::move(callbackMessage));
|
||||
|
||||
for (const std::shared_ptr<Async::AsyncTaskCompletionSource<void>>& waiter : _PowerCallbackWaiters)
|
||||
{
|
||||
waiter->EmplaceResult();
|
||||
}
|
||||
|
||||
_PowerCallbackWaiters.clear();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_CallbacksUpdatedEvent.notify_all();
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <NfcCxTestDeviceDriver.h>
|
||||
|
||||
#include <IOHelpers\AsyncTask.h>
|
||||
#include <IOHelpers\IoOperation.h>
|
||||
#include <IOHelpers\UniqueHandle.h>
|
||||
|
||||
|
@ -54,6 +55,8 @@ public:
|
|||
void SendSequenceCompleted(NTSTATUS status, ULONG flags);
|
||||
NciSimCallbackMessage ReceiveLibNfcThreadCallback();
|
||||
NciSimCallbackMessage ReceivePowerCallback();
|
||||
std::shared_ptr<Async::AsyncTaskBase<void>> WhenLibNfcThreadCallbackAvailableAsync();
|
||||
std::shared_ptr<Async::AsyncTaskBase<void>> WhenPowerCallbackAvailableAsync();
|
||||
|
||||
private:
|
||||
static void ThrowIfWin32BoolFailed(BOOL succeeded);
|
||||
|
@ -62,7 +65,7 @@ private:
|
|||
void SendCommandSync(_In_ DWORD ioctl, _In_reads_bytes_opt_(inputSize) const void* input, _In_ DWORD inputSize);
|
||||
|
||||
void StartGetNextCallback();
|
||||
void CallbackRetrieved(const std::shared_ptr<IoOperation>& ioOperation);
|
||||
void CallbackRetrieved(Async::AsyncTaskBase<IoOperationResult>& ioOperation);
|
||||
|
||||
UniqueHandle _DriverHandle;
|
||||
std::vector<BYTE> _CallbackDataBuffer;
|
||||
|
@ -82,7 +85,9 @@ private:
|
|||
std::condition_variable _CallbacksUpdatedEvent;
|
||||
CallbacksState _CallbacksState = CallbacksState::Stopped;
|
||||
DWORD _CallbackAllocSize = NciPacketRaw::MaxLength + sizeof(NciSimCallbackHeader);
|
||||
std::shared_ptr<IoOperation> _CurrentCallbackIo;
|
||||
std::weak_ptr<IoOperation> _CurrentCallbackIo;
|
||||
std::queue<NciSimCallbackMessage> _LibNfcThreadCallbacks;
|
||||
std::queue<NciSimCallbackMessage> _PowerCallbacks;
|
||||
std::vector<std::shared_ptr<Async::AsyncTaskCompletionSource<void>>> _LibNfcThreadCallbackWaiters;
|
||||
std::vector<std::shared_ptr<Async::AsyncTaskCompletionSource<void>>> _PowerCallbackWaiters;
|
||||
};
|
||||
|
|
|
@ -26,6 +26,7 @@ SimSequenceRunner::VerifyStep(
|
|||
{
|
||||
LogExpectedStep(expectedStep);
|
||||
LogByteBuffer(L"Actual NCI packet ", nciWrite->NciMessage, nciPacketSize);
|
||||
VERIFY_FAIL(L"Step and driver message don't match.");
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -39,6 +40,7 @@ SimSequenceRunner::VerifyStep(
|
|||
{
|
||||
LogExpectedStep(expectedStep);
|
||||
LOG_COMMENT(L"Actual sequence handler: %d", int(params->Sequence));
|
||||
VERIFY_FAIL(L"Step and driver message don't match.");
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -49,6 +51,7 @@ SimSequenceRunner::VerifyStep(
|
|||
{
|
||||
LogExpectedStep(expectedStep);
|
||||
LOG_COMMENT(L"Actual: D0 Entry");
|
||||
VERIFY_FAIL(L"Step and driver message don't match.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -58,6 +61,7 @@ SimSequenceRunner::VerifyStep(
|
|||
{
|
||||
LogExpectedStep(expectedStep);
|
||||
LOG_COMMENT(L"Actual: D0 Exit");
|
||||
VERIFY_FAIL(L"Step and driver message don't match.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,22 @@ SimSequenceStep::NciDataRead(
|
|||
return NciRead(std::move(stepName), packet);
|
||||
}
|
||||
|
||||
SimSequenceStep
|
||||
SimSequenceStep::HciWrite(
|
||||
std::wstring stepName,
|
||||
const NciHciDataPacket& packet)
|
||||
{
|
||||
return NciWrite(std::move(stepName), packet);
|
||||
}
|
||||
|
||||
SimSequenceStep
|
||||
SimSequenceStep::HciRead(
|
||||
std::wstring stepName,
|
||||
const NciHciDataPacket& packet)
|
||||
{
|
||||
return NciRead(std::move(stepName), packet);
|
||||
}
|
||||
|
||||
SimSequenceStep
|
||||
SimSequenceStep::SequenceHandler(
|
||||
std::wstring stepName,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "NciControlPacket.h"
|
||||
#include "NciDataPacket.h"
|
||||
#include "NciHciDataPacket.h"
|
||||
#include "NciPacket.h"
|
||||
|
||||
enum class SimSequenceStepType
|
||||
|
@ -51,6 +52,12 @@ struct SimSequenceStep
|
|||
std::wstring stepName);
|
||||
static SimSequenceStep D0Exit(
|
||||
std::wstring stepName);
|
||||
static SimSequenceStep HciWrite(
|
||||
std::wstring stepName,
|
||||
const NciHciDataPacket& packet);
|
||||
static SimSequenceStep HciRead(
|
||||
std::wstring stepName,
|
||||
const NciHciDataPacket& packet);
|
||||
|
||||
static SimSequenceStep SequenceHandler(
|
||||
std::wstring stepName,
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
#include <combaseapi.h>
|
||||
#include <system_error>
|
||||
|
||||
#include <SimulationSequences\InitSequences.h>
|
||||
|
||||
#include "NciSimConnector.h"
|
||||
#include "SimSequenceRunner.h"
|
||||
#include "TestDeviceInstall.h"
|
||||
|
||||
TestDeviceInstall::TestDeviceInstall()
|
||||
|
@ -41,6 +45,11 @@ TestDeviceInstall::TestDeviceInstall()
|
|||
}
|
||||
|
||||
VerifyHresultSucceeded(createResult);
|
||||
|
||||
// Handle the initial D0 entry/exit that occurs during device initialization.
|
||||
NciSimConnector simConnector;
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Power::D0Entry);
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Power::D0Exit);
|
||||
}
|
||||
|
||||
TestDeviceInstall::~TestDeviceInstall()
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <phNciNfc_RfConfig.h>
|
||||
|
||||
#include "InitSequences.h"
|
||||
#include "SEInitializationSequences.h"
|
||||
|
||||
const SimSequenceStep InitSequences::Reset::NciResetCommand = SimSequenceStep::NciControlWrite(
|
||||
L"CORE_RESET_CMD",
|
||||
|
@ -69,14 +70,14 @@ const SimSequenceStep InitSequences::Reset::NciResetNotification_Nci2 = SimSeque
|
|||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::PreInitialize = SimSequenceStep::SequenceHandler(
|
||||
const SimSequenceStep InitSequences::Initialize::PreInitialize = SimSequenceStep::SequenceHandler(
|
||||
L"SequencePreInit",
|
||||
SequencePreInit,
|
||||
STATUS_SUCCESS,
|
||||
NFC_CX_SEQUENCE_PRE_INIT_FLAG_SKIP_CONFIG
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::InitializeCommand_Nci1 = SimSequenceStep::NciControlWrite(
|
||||
const SimSequenceStep InitSequences::Initialize::InitializeCommand_Nci1 = SimSequenceStep::NciControlWrite(
|
||||
L"CORE_INIT_CMD",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 4.2, CORE_INIT_CMD
|
||||
|
@ -86,7 +87,7 @@ const SimSequenceStep InitSequences::InitializeNoSEs::InitializeCommand_Nci1 = S
|
|||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::InitializeCommand_Nci2 = SimSequenceStep::NciControlWrite(
|
||||
const SimSequenceStep InitSequences::Initialize::InitializeCommand_Nci2 = SimSequenceStep::NciControlWrite(
|
||||
L"CORE_INIT_CMD",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 2.0, Section 4.2, CORE_INIT_CMD
|
||||
|
@ -99,7 +100,7 @@ const SimSequenceStep InitSequences::InitializeNoSEs::InitializeCommand_Nci2 = S
|
|||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::InitializeResponse_Nci1 = SimSequenceStep::NciControlRead(
|
||||
const SimSequenceStep InitSequences::Initialize::InitializeResponse_Nci1 = SimSequenceStep::NciControlRead(
|
||||
L"CORE_INIT_RSP",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 4.2, CORE_INIT_RSP
|
||||
|
@ -128,9 +129,7 @@ const SimSequenceStep InitSequences::InitializeNoSEs::InitializeResponse_Nci1 =
|
|||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::InitializeResponse_Nci2 = SimSequenceStep::NciControlRead(
|
||||
const SimSequenceStep InitSequences::Initialize::InitializeResponse_Nci2 = SimSequenceStep::NciControlRead(
|
||||
L"CORE_INIT_RSP",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 2.0, Section 4.2, CORE_INIT_RSP
|
||||
|
@ -167,14 +166,14 @@ const SimSequenceStep InitSequences::InitializeNoSEs::InitializeResponse_Nci2 =
|
|||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::InitializeComplete = SimSequenceStep::SequenceHandler(
|
||||
const SimSequenceStep InitSequences::Initialize::InitializeComplete = SimSequenceStep::SequenceHandler(
|
||||
L"SequenceInitComplete",
|
||||
SequenceInitComplete,
|
||||
STATUS_SUCCESS,
|
||||
0
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::GetConfigCommand = SimSequenceStep::NciControlWrite(
|
||||
const SimSequenceStep InitSequences::Initialize::GetConfigCommand = SimSequenceStep::NciControlWrite(
|
||||
L"CORE_GET_CONFIG_CMD",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 4.3.2, CORE_GET_CONFIG_CMD
|
||||
|
@ -191,7 +190,7 @@ const SimSequenceStep InitSequences::InitializeNoSEs::GetConfigCommand = SimSequ
|
|||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::GetConfigResponse = SimSequenceStep::NciControlRead(
|
||||
const SimSequenceStep InitSequences::Initialize::GetConfigResponse = SimSequenceStep::NciControlRead(
|
||||
L"CORE_GET_CONFIG_RSP",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 4.3.2, CORE_GET_CONFIG_RSP
|
||||
|
@ -221,57 +220,6 @@ const SimSequenceStep InitSequences::InitializeNoSEs::GetConfigResponse = SimSeq
|
|||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::PreNfceeDiscovery = SimSequenceStep::SequenceHandler(
|
||||
L"SequencePreNfceeDisc",
|
||||
SequencePreNfceeDisc,
|
||||
STATUS_SUCCESS,
|
||||
0
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::NfceeDiscoverCommand_Nci1 = SimSequenceStep::NciControlWrite(
|
||||
L"NFCEE_DISCOVER_CMD",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.2, NFCEE_DISCOVER_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtNfceeDiscCmdOid,
|
||||
{
|
||||
0x01, // Enable NFCEE discovery
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::NfceeDiscoverCommand_Nci2 = SimSequenceStep::NciControlWrite(
|
||||
L"NFCEE_DISCOVER_CMD",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.2, NFCEE_DISCOVER_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtNfceeDiscCmdOid,
|
||||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::NfceeDiscoverResponse = SimSequenceStep::NciControlRead(
|
||||
L"NFCEE_DISCOVER_RSP",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.2, NFCEE_DISCOVER_RSP
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlRsp,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtNfceeDiscCmdOid,
|
||||
{
|
||||
PH_NCINFC_STATUS_OK, // Status
|
||||
0x0, // Number of NFCEEs.
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::InitializeNoSEs::NfceeDiscoveryComplete = SimSequenceStep::SequenceHandler(
|
||||
L"SequenceNfceeDiscComplete",
|
||||
SequenceNfceeDiscComplete,
|
||||
STATUS_SUCCESS,
|
||||
0
|
||||
);
|
||||
|
||||
const SimSequenceStep InitSequences::Uninitialize::PreShutdown = SimSequenceStep::SequenceHandler(
|
||||
L"SequencePreShutdown",
|
||||
SequencePreShutdown,
|
||||
|
@ -307,9 +255,8 @@ const SimSequenceStep InitSequences::Reset::Sequence_Nci2[3] =
|
|||
NciResetNotification_Nci2,
|
||||
};
|
||||
|
||||
// Error-free NCI 1.1 initialize.
|
||||
// Reports 0 attached SEs.
|
||||
const SimSequenceView InitSequences::InitializeNoSEs::Sequence_Nci1[11] =
|
||||
// Error-free initialize that reports 0 attached SEs using NCI 1.1.
|
||||
const SimSequenceView InitSequences::Initialize::NoSEsSequence_Nci1[8] =
|
||||
{
|
||||
PreInitialize,
|
||||
Reset::Sequence_Nci1,
|
||||
|
@ -318,15 +265,11 @@ const SimSequenceView InitSequences::InitializeNoSEs::Sequence_Nci1[11] =
|
|||
InitializeComplete,
|
||||
GetConfigCommand,
|
||||
GetConfigResponse,
|
||||
PreNfceeDiscovery,
|
||||
NfceeDiscoverCommand_Nci1,
|
||||
NfceeDiscoverResponse,
|
||||
NfceeDiscoveryComplete,
|
||||
SEInitializationSequences::NoSEs::InitializeSequence_Nci1,
|
||||
};
|
||||
|
||||
// Error-free NCI 2.0 initialize.
|
||||
// Reports 0 attached SEs.
|
||||
const SimSequenceView InitSequences::InitializeNoSEs::Sequence_Nci2[11] =
|
||||
// Error-free initialize that reports 0 attached SEs using NCI 2.0.
|
||||
const SimSequenceView InitSequences::Initialize::NoSEsSequence_Nci2[8] =
|
||||
{
|
||||
PreInitialize,
|
||||
Reset::Sequence_Nci2,
|
||||
|
@ -335,23 +278,33 @@ const SimSequenceView InitSequences::InitializeNoSEs::Sequence_Nci2[11] =
|
|||
InitializeComplete,
|
||||
GetConfigCommand,
|
||||
GetConfigResponse,
|
||||
PreNfceeDiscovery,
|
||||
NfceeDiscoverCommand_Nci2,
|
||||
NfceeDiscoverResponse,
|
||||
NfceeDiscoveryComplete,
|
||||
SEInitializationSequences::NoSEs::InitializeSequence_Nci2,
|
||||
};
|
||||
|
||||
const SimSequenceView
|
||||
InitSequences::InitializeNoSEs::Sequence(bool isNci2)
|
||||
InitSequences::Initialize::NoSEsSequence(bool isNci2)
|
||||
{
|
||||
if (isNci2)
|
||||
{
|
||||
return Sequence_Nci2;
|
||||
return NoSEsSequence_Nci2;
|
||||
}
|
||||
|
||||
return Sequence_Nci1;
|
||||
return NoSEsSequence_Nci1;
|
||||
}
|
||||
|
||||
// Error-free initialize with an eSE using NCI 1.1.
|
||||
const SimSequenceView InitSequences::Initialize::WithEseSequence_Nci1[8] =
|
||||
{
|
||||
PreInitialize,
|
||||
Reset::Sequence_Nci1,
|
||||
InitializeCommand_Nci1,
|
||||
InitializeResponse_Nci1,
|
||||
InitializeComplete,
|
||||
GetConfigCommand,
|
||||
GetConfigResponse,
|
||||
SEInitializationSequences::WithEse::InitializeSequence_Nci1,
|
||||
};
|
||||
|
||||
// Error-free NCI 1.1 uninitialize.
|
||||
const SimSequenceView InitSequences::Uninitialize::Sequence_Nci1[3] =
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@ struct InitSequences
|
|||
static const SimSequenceStep Sequence_Nci2[3];
|
||||
};
|
||||
|
||||
struct InitializeNoSEs
|
||||
struct Initialize
|
||||
{
|
||||
static const SimSequenceStep PreInitialize;
|
||||
static const SimSequenceStep InitializeCommand_Nci1;
|
||||
|
@ -31,15 +31,12 @@ struct InitSequences
|
|||
static const SimSequenceStep InitializeComplete;
|
||||
static const SimSequenceStep GetConfigCommand;
|
||||
static const SimSequenceStep GetConfigResponse;
|
||||
static const SimSequenceStep PreNfceeDiscovery;
|
||||
static const SimSequenceStep NfceeDiscoverCommand_Nci1;
|
||||
static const SimSequenceStep NfceeDiscoverCommand_Nci2;
|
||||
static const SimSequenceStep NfceeDiscoverResponse;
|
||||
static const SimSequenceStep NfceeDiscoveryComplete;
|
||||
|
||||
static const SimSequenceView Sequence_Nci1[11];
|
||||
static const SimSequenceView Sequence_Nci2[11];
|
||||
static const SimSequenceView Sequence(bool isNci2);
|
||||
static const SimSequenceView NoSEsSequence_Nci1[8];
|
||||
static const SimSequenceView NoSEsSequence_Nci2[8];
|
||||
static const SimSequenceView NoSEsSequence(bool isNci2);
|
||||
|
||||
static const SimSequenceView WithEseSequence_Nci1[8];
|
||||
};
|
||||
|
||||
struct Uninitialize
|
||||
|
|
|
@ -0,0 +1,791 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All Rights Reserved
|
||||
//
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include <phLibNfc_Internal.h>
|
||||
#include <phNciNfc.h>
|
||||
#include <phNciNfc_Core.h>
|
||||
#include <phNciNfc_CoreStatus.h>
|
||||
#include <phHciNfc_Core.h>
|
||||
#include <phHciNfc_Interface.h>
|
||||
|
||||
#include "SEInitializationSequences.h"
|
||||
|
||||
static constexpr uint8_t EseNfceeId = phHciNfc_e_ProprietaryHostID_Min;
|
||||
static constexpr uint8_t EseApduPipeId = 0x19;
|
||||
static constexpr uint8_t HciNetworkConnectionId = 0x03;
|
||||
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 4.4.4, CORE_CONN_CREDITS_NTF
|
||||
const SimSequenceStep SEInitializationSequences::HciNetworkCredit = SimSequenceStep::NciControlRead(
|
||||
L"CORE_CONN_CREDITS_NTF",
|
||||
{
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlNtf,
|
||||
phNciNfc_e_CoreNciCoreGid,
|
||||
phNciNfc_e_NciCoreConnCreditNtfOid,
|
||||
{
|
||||
1, // Number of entries that follow
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
1, // Number of credits
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep SEInitializationSequences::Common::PreNfceeDiscovery = SimSequenceStep::SequenceHandler(
|
||||
L"SequencePreNfceeDisc",
|
||||
SequencePreNfceeDisc,
|
||||
STATUS_SUCCESS,
|
||||
0
|
||||
);
|
||||
|
||||
// Driver asks NFC Controller to enumerate the NFCEEs.
|
||||
const SimSequenceStep SEInitializationSequences::Common::NfceeDiscoverCommand_Nci1 = SimSequenceStep::NciControlWrite(
|
||||
L"NFCEE_DISCOVER_CMD",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.2, NFCEE_DISCOVER_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtNfceeDiscCmdOid,
|
||||
{
|
||||
0x01, // Enable NFCEE discovery
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Driver asks NFC Controller to enumerate the NFCEEs.
|
||||
const SimSequenceStep SEInitializationSequences::Common::NfceeDiscoverCommand_Nci2 = SimSequenceStep::NciControlWrite(
|
||||
L"NFCEE_DISCOVER_CMD",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.2, NFCEE_DISCOVER_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtNfceeDiscCmdOid,
|
||||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep SEInitializationSequences::Common::NfceeDiscoveryComplete = SimSequenceStep::SequenceHandler(
|
||||
L"SequenceNfceeDiscComplete",
|
||||
SequenceNfceeDiscComplete,
|
||||
STATUS_SUCCESS,
|
||||
0
|
||||
);
|
||||
|
||||
// NFC Controller responds that there are 0 NFCEEs.
|
||||
const SimSequenceStep SEInitializationSequences::NoSEs::NfceeDiscoverResponse = SimSequenceStep::NciControlRead(
|
||||
L"NFCEE_DISCOVER_RSP",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.2, NFCEE_DISCOVER_RSP
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlRsp,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtNfceeDiscCmdOid,
|
||||
{
|
||||
PH_NCINFC_STATUS_OK, // Status
|
||||
0x0, // Number of NFCEEs.
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// NFC Controller responds that there is 1 NFCEE.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::NfceeDiscoverResponse = SimSequenceStep::NciControlRead(
|
||||
L"NFCEE_DISCOVER_RSP",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.2, NFCEE_DISCOVER_RSP
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlRsp,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtNfceeDiscCmdOid,
|
||||
{
|
||||
PH_NCINFC_STATUS_OK, // Status
|
||||
0x1, // Number of NFCEEs.
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// NFC Controller enumerates the first NFCEE, which is the HCI Network.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::HciNetworkEnumeration = SimSequenceStep::NciControlRead(
|
||||
L"NFCEE_DISCOVER_NTF (HCI Network)",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.2, NFCEE_DISCOVER_NTF
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlNtf,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtNfceeDiscNtfOid,
|
||||
{
|
||||
phHciNfc_e_TerminalHostID, // NFCEE ID
|
||||
phNciNfc_NfceeStatus_Enabled, // NFCEE status
|
||||
1, // Number of protocol entries (that follow)
|
||||
phNciNfc_e_NfceeHciAccessIf, // HCI access protocol
|
||||
0, // Number of information TLVs
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Driver opens a connection to the HCI Network.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::HciNetworkCreateConnectionCommand = SimSequenceStep::NciControlWrite(
|
||||
L"CORE_CONN_CREATE_CMD",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 4.4.2, CORE_CONN_CREATE_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreNciCoreGid,
|
||||
phNciNfc_e_NciCoreConnCreateCmdOid,
|
||||
{
|
||||
phNciNfc_e_NFCEE, // Destination type
|
||||
1, // Number of TLV parameters that follow
|
||||
0x01, // Type (NFEE Type)
|
||||
2, // Length
|
||||
// Value:
|
||||
phHciNfc_e_TerminalHostID, // NFCEE ID
|
||||
phNciNfc_e_NfceeHciAccessIf, // NFCEE protocol
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// NFC Controller responds that the connection to the HCI Network was opened successfully.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::HciNetworkCreateConnectionResponse = SimSequenceStep::NciControlRead(
|
||||
L"CORE_CONN_CREATE_RSP",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 4.4.2, CORE_CONN_CREATE_RSP
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlRsp,
|
||||
phNciNfc_e_CoreNciCoreGid,
|
||||
phNciNfc_e_NciCoreConnCreateCmdOid,
|
||||
{
|
||||
PH_NCINFC_STATUS_OK, // Status
|
||||
0xFF, // Max data packet payload size
|
||||
1, // Initial number of credits
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// NFC Controller notifies that an eSE NFCEE also exists.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EseEnumeration = SimSequenceStep::NciControlRead(
|
||||
L"NFCEE_DISCOVER_NTF (eSE)",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.2, NFCEE_DISCOVER_NTF
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlNtf,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtNfceeDiscNtfOid,
|
||||
{
|
||||
EseNfceeId,
|
||||
phNciNfc_NfceeStatus_Enabled,
|
||||
1, // Number of protocol entries (that follow)
|
||||
0x80, // Proprietary protocol
|
||||
0, // Number of information TLVs (that follow)
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// NFC Controller notifies that eSE supports NFC-A card emulation.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EseSupportsNfcA = SimSequenceStep::NciControlRead(
|
||||
L"RF_NFCEE_DISCOVERY_REQ_NTF (eSE, NFC-A)",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 7.4, RF_NFCEE_DISCOVERY_REQ_NTF
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlNtf,
|
||||
phNciNfc_e_CoreRfMgtGid,
|
||||
phNciNfc_e_RfMgtRfNfceeDiscoveryReqNtfOid,
|
||||
{
|
||||
1, // Number of TLV information entries (that follow)
|
||||
phNciNfc_e_RfNfceeDiscReqAdd, // Type (add information)
|
||||
3, // Value length
|
||||
// Value:
|
||||
EseNfceeId, // NFCEE Id
|
||||
phNciNfc_NFCA_Listen, // RF technology/mode
|
||||
phNciNfc_e_RfProtocolsIsoDepProtocol, // RF protocol
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// NFC Controller notifies that eSE supports NFC-B card emulation.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EseSupportsNfcB = SimSequenceStep::NciControlRead(
|
||||
L"RF_NFCEE_DISCOVERY_REQ_NTF (eSE, NFC-B)",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 7.4, RF_NFCEE_DISCOVERY_REQ_NTF
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlNtf,
|
||||
phNciNfc_e_CoreRfMgtGid,
|
||||
phNciNfc_e_RfMgtRfNfceeDiscoveryReqNtfOid,
|
||||
{
|
||||
1, // Number of TLV information entries (that follow)
|
||||
phNciNfc_e_RfNfceeDiscReqAdd, // Type (add information)
|
||||
3, // Value length
|
||||
// Value:
|
||||
EseNfceeId, // NFCEE Id
|
||||
phNciNfc_NFCB_Listen, // RF technology/mode
|
||||
phNciNfc_e_RfProtocolsIsoDepProtocol, // RF protocol
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// NFC Controller notifies that the eSE supports NFC-F (Type 3 Tag) card emulation.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EseSupportsNfcF = SimSequenceStep::NciControlRead(
|
||||
L"RF_NFCEE_DISCOVERY_REQ_NTF (eSE, NFC-F)",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 7.4, RF_NFCEE_DISCOVERY_REQ_NTF
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlNtf,
|
||||
phNciNfc_e_CoreRfMgtGid,
|
||||
phNciNfc_e_RfMgtRfNfceeDiscoveryReqNtfOid,
|
||||
{
|
||||
1, // Number of TLV information entries (that follow)
|
||||
phNciNfc_e_RfNfceeDiscReqAdd, // Type (add information)
|
||||
3, // Value length
|
||||
// Value:
|
||||
EseNfceeId, // NFCEE Id
|
||||
phNciNfc_NFCF_Listen, // RF technology/mode
|
||||
phNciNfc_e_RfProtocolsT3tProtocol, // RF protocol
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Driver opens the HCI admin pipe so that it can communicate with the HCI host controller (which is implemented by the NFC Controller).
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::OpenAdminPipeCommand = SimSequenceStep::HciWrite(
|
||||
L"[HCI] ANY_OPEN_PIPE",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.3, ANY_OPEN_PIPE
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeCommand, // Message type
|
||||
phHciNfc_e_AnyOpenPipe, // Command ID
|
||||
{
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// HCI host controller (aka, NFC Controller) responds with ANY_OK.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::OpenAdminPipeResponse = SimSequenceStep::HciRead(
|
||||
L"[HCI] ANY_OPEN_PIPE (response)",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.3, ANY_OPEN_PIPE
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeResponse, // Message type
|
||||
phHciNfc_e_RspAnyOk, // Response code
|
||||
{
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Driver tells the HCI host controller (aka, NFC controller) to permit communication between the driver and the eSE.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::SetWhitelistCommand = SimSequenceStep::HciWrite(
|
||||
L"[HCI] ANY_SET_PARAMETER: WHITELIST",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.1, ANY_SET_PARAMETER
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeCommand, // Message type
|
||||
phHciNfc_e_AnySetParameter, // Command code
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 7.1.1.1, Table 20, WHITELIST
|
||||
phHciNfc_e_WhitelistRegistryId, // Parameter ID
|
||||
EseNfceeId,
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// HCI host controller (aka, NFC controller) responds with ANY_OK.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::SetWhitelistResponse = SimSequenceStep::HciRead(
|
||||
L"[HCI] ANY_SET_PARAMETER: WHITELIST (response)",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.1, ANY_SET_PARAMETER
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeResponse, // Message type
|
||||
phHciNfc_e_RspAnyOk, // Response code
|
||||
{
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Driver tells the HCI host controller (aka, NFC controller) that the driver is a HCI terminal host.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::SetHostTypeCommand = SimSequenceStep::HciWrite(
|
||||
L"[HCI] ANY_SET_PARAMETER: HOST_TYPE",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.1, ANY_SET_PARAMETER
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeCommand, // Message type
|
||||
phHciNfc_e_AnySetParameter, // Command code
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 7.1.1.1, Table 20, HOST_TYPE
|
||||
phHciNfc_e_HostTypeRegistryId, // Parameter ID
|
||||
phHciNfc_e_HostType_Terminal >> 8, // Host type family
|
||||
phHciNfc_e_HostType_Terminal & 0xFF, // Host type
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// HCI host controller (aka, NFC controller) responds with ANY_OK.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::SetHostTypeResponse = SimSequenceStep::HciRead(
|
||||
L"[HCI] ANY_SET_PARAMETER: HOST_TYPE (response)",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.1, ANY_SET_PARAMETER
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeResponse, // Message type
|
||||
phHciNfc_e_RspAnyOk, // Response code
|
||||
{
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Driver requests the session ID from the HCI host controller (aka, NFC controller).
|
||||
// This is used to check if any hardware configuration has changed (e.g. an eSE firmware update occured, a SIM card was
|
||||
// swapped, etc.), as this may require the HCI pipes to be re-initialized.
|
||||
//
|
||||
// The driver is free to use the session ID for whatever it wants. But NfcCx uses it to store information relating to
|
||||
// the open pipes.
|
||||
//
|
||||
// See, ETSI Host Controller Interface (HCI), Version 12.1.0, Section 8.4, Session initialization
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::GetSessionIdCommand = SimSequenceStep::HciWrite(
|
||||
L"[HCI] ANY_SET_PARAMETER: SESSION_IDENTITY",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.2, ANY_GET_PARAMETER
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeCommand, // Message type
|
||||
phHciNfc_e_AnyGetParameter, // Command code
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 7.1.1.1, Table 20, SESSION_IDENTITY
|
||||
phHciNfc_e_SessionIdentityRegistryId, // Parameter ID
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// HCI host controller (aka, NFC controller) returns the session ID.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::GetSessionIdResponse = SimSequenceStep::HciRead(
|
||||
L"[HCI] ANY_SET_PARAMETER: SESSION_IDENTITY (response)",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.2, ANY_GET_PARAMETER
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeResponse, // Message type
|
||||
phHciNfc_e_RspAnyOk, // Response code
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 7.1.1.1, Table 20, SESSION_IDENTITY
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, EseApduPipeId, 0x7F
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Driver requests the host list from the HCI host controller (aka, NFC controller).
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::GetHostListCommand = SimSequenceStep::HciWrite(
|
||||
L"[HCI] ANY_GET_PARAMETER: HOST_LIST",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.2, ANY_GET_PARAMETER
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeCommand, // Message type
|
||||
phHciNfc_e_AnyGetParameter, // Command code
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 7.1.1.1, Table 20, HOST_LIST
|
||||
phHciNfc_e_HostListRegistryId, // Parameter ID
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// HCI host controller (aka, NFC controller) returns host list.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::GetHostListResponse = SimSequenceStep::HciRead(
|
||||
L"[HCI] ANY_GET_PARAMETER: HOST_LIST (response)",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.2, ANY_GET_PARAMETER
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeResponse, // Message type
|
||||
phHciNfc_e_RspAnyOk, // Response code
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 7.1.1.1, Table 20, HOST_LIST
|
||||
phHciNfc_e_HostControllerID,
|
||||
EseNfceeId,
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Driver requests the host type list from the HCI host controller (aka, NFC controller).
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::GetHostTypeListCommand = SimSequenceStep::HciWrite(
|
||||
L"[HCI] ANY_GET_PARAMETER: HOST_TYPE_LIST",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.2, ANY_GET_PARAMETER
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeCommand, // Message type
|
||||
phHciNfc_e_AnyGetParameter, // Command code
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 7.1.1.1, Table 20, HOST_TYPE_LIST
|
||||
phHciNfc_e_HostTypeListRegistryId, // Parameter ID
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// HCI host controller (aka, NFC controller) returns the host type list.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::GetHostTypeListResponse = SimSequenceStep::HciRead(
|
||||
L"[HCI] ANY_GET_PARAMETER: HOST_TYPE_LIST (response)",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 6.1.2.2, ANY_GET_PARAMETER
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
phHciNfc_e_HciAdminPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeResponse, // Message type
|
||||
phHciNfc_e_RspAnyOk, // Response code
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 7.1.1.1, Table 20, HOST_TYPE_LIST
|
||||
|
||||
// Host controller
|
||||
phHciNfc_e_HostType_HostController >> 8, // Host type family
|
||||
phHciNfc_e_HostType_HostController & 0xFF, // Host type
|
||||
|
||||
// Terminal (aka, Host Device. aka, Driver)
|
||||
phHciNfc_e_HostType_Terminal >> 8, // Host type family
|
||||
phHciNfc_e_HostType_Terminal & 0xFF, // Host type
|
||||
|
||||
// eSE
|
||||
phHciNfc_e_HostType_eSE >> 8, // Host type family
|
||||
phHciNfc_e_HostType_eSE & 0xFF, // Host type
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Driver tells NFC Controller to enable the eSE.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EseEnableCommand = SimSequenceStep::NciControlWrite(
|
||||
L"NFCEE_MODE_SET_CMD: ENABLE",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.3, NFCEE_MODE_SET_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtModeSetCmdOid,
|
||||
{
|
||||
EseNfceeId, // NFCEE ID
|
||||
PH_NCINFC_EXT_NFCEEMODE_ENABLE, // NFCEE mode (enable)
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// NFC Controller responds that the eSE was enabled successfully.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EseEnableResponse = SimSequenceStep::NciControlRead(
|
||||
L"NFCEE_MODE_SET_RSP: ENABLE",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.3, NFCEE_MODE_SET_RSP
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlRsp,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtModeSetCmdOid,
|
||||
{
|
||||
PH_NCINFC_STATUS_OK, // Status
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Driver tells NFC Controller to disable the eSE.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EseDisableCommand = SimSequenceStep::NciControlWrite(
|
||||
L"NFCEE_MODE_SET_CMD: DISABLE",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.3, NFCEE_MODE_SET_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtModeSetCmdOid,
|
||||
{
|
||||
EseNfceeId, // NFCEE ID
|
||||
PH_NCINFC_EXT_NFCEEMODE_DISABLE, // NFCEE mode (enable)
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// NFC Controller responds that the eSE was disabled successfully.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EseDisableResponse = SimSequenceStep::NciControlRead(
|
||||
L"NFCEE_MODE_SET_RSP: DISABLE",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.3, NFCEE_MODE_SET_RSP
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlRsp,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtModeSetCmdOid,
|
||||
{
|
||||
PH_NCINFC_STATUS_OK, // Status
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Driver tells NFC Controller to power on the eSE.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EsePowerOnCommand = SimSequenceStep::NciControlWrite(
|
||||
L"NFCEE_POWER_AND_LINK_CNTRL_CMD (eSE): Power always on",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.3, NFCEE_POWER_AND_LINK_CNTRL_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtPowerAndLinkCtrlCmdOid,
|
||||
{
|
||||
EseNfceeId, // NFCEE ID
|
||||
phNciNfc_PLM_PowerSupplyAlwaysOn, // NFCEE power mode (power always on)
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Success.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EsePowerOnResponse = SimSequenceStep::NciControlRead(
|
||||
L"NFCEE_POWER_AND_LINK_CNTRL_RSP (eSE): Power always on",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.3, NFCEE_POWER_AND_LINK_CNTRL_RSP
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlRsp,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtPowerAndLinkCtrlCmdOid,
|
||||
{
|
||||
PH_NCINFC_STATUS_OK, // Status
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Driver tells NFC Controller to power on the eSE and to keep the communication link open.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EsePowerAndLinkOnCommand = SimSequenceStep::NciControlWrite(
|
||||
L"NFCEE_POWER_AND_LINK_CNTRL_CMD (eSE): Power always on",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.3, NFCEE_POWER_AND_LINK_CNTRL_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtPowerAndLinkCtrlCmdOid,
|
||||
{
|
||||
EseNfceeId, // NFCEE ID
|
||||
phNciNfc_PLM_PowerNfccLinkAlwaysOn, // NFCEE power mode (power and link always on)
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Success.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EsePowerAndLinkOnResponse = SimSequenceStep::NciControlRead(
|
||||
L"NFCEE_POWER_AND_LINK_CNTRL_RSP (eSE): Power always on",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 9.3, NFCEE_POWER_AND_LINK_CNTRL_RSP
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlRsp,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtPowerAndLinkCtrlCmdOid,
|
||||
{
|
||||
PH_NCINFC_STATUS_OK, // Status
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Driver tells NFC Controller that it can power off the eSE.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EsePowerOffCommand = SimSequenceStep::NciControlWrite(
|
||||
L"NFCEE_POWER_AND_LINK_CNTRL_CMD (eSE): NFCC decides",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 2.0, Section 10.6, NFCEE_POWER_AND_LINK_CNTRL_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtPowerAndLinkCtrlCmdOid,
|
||||
{
|
||||
EseNfceeId, // NFCEE ID
|
||||
phNciNfc_PLM_NfccDecides, // NFCEE power mode (NFCC decides)
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Success.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EsePowerOffResponse = SimSequenceStep::NciControlRead(
|
||||
L"NFCEE_POWER_AND_LINK_CNTRL_RSP (eSE): NFCC decides",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 2.0, Section 10.6, NFCEE_POWER_AND_LINK_CNTRL_RSP
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlRsp,
|
||||
phNciNfc_e_CoreNfceeMgtGid,
|
||||
phNciNfc_e_NfceeMgtPowerAndLinkCtrlCmdOid,
|
||||
{
|
||||
PH_NCINFC_STATUS_OK, // Status
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Driver sets the default routing table.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::SetDefaultRoutingTableCommand = SimSequenceStep::NciControlWrite(
|
||||
L"RF_SET_LISTEN_MODE_ROUTING_CMD (default routing table)",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 6.3.2, NFCEE_POWER_AND_LINK_CNTRL_CMD
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlCmd,
|
||||
phNciNfc_e_CoreRfMgtGid,
|
||||
phNciNfc_e_RfMgtRfSetRoutingCmdOid,
|
||||
{
|
||||
0, // More to come? (last message)
|
||||
2, // Number of routing entries (that follow)
|
||||
phNciNfc_e_LstnModeRtngProtocolBased, // Type
|
||||
3, // Length of value
|
||||
phHciNfc_e_HostControllerID, // NFEE ID
|
||||
0x00, // Power state
|
||||
phNfc_RfProtocolsIsoDepProtocol, // Protocol
|
||||
|
||||
phNciNfc_e_LstnModeRtngProtocolBased, // Type
|
||||
3, // Length of value
|
||||
phHciNfc_e_HostControllerID, // NFCEE ID
|
||||
0x00, // Power state
|
||||
phNfc_RfProtocolsNfcDepProtocol, // Protocol
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Success.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::SetDefaultRoutingTableResponse = SimSequenceStep::NciControlRead(
|
||||
L"RF_SET_LISTEN_MODE_ROUTING_RSP (default routing table)",
|
||||
{
|
||||
// NFC Controller Interface (NCI), Version 1.1, Section 6.3.2, RF_SET_LISTEN_MODE_ROUTING_RSP
|
||||
phNciNfc_e_NciCoreMsgTypeCntrlRsp,
|
||||
phNciNfc_e_CoreRfMgtGid,
|
||||
phNciNfc_e_RfMgtRfSetRoutingCmdOid,
|
||||
{
|
||||
PH_NCINFC_STATUS_OK, // Status
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Driver resets the eSE.
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EseResetCommand = SimSequenceStep::HciWrite(
|
||||
L"[HCI] EVT_ABORT (eSE)",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 12.2.2.2, EVT_ABORT
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
EseApduPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeEvent, // Message type
|
||||
PHHCINFC_EVT_ABORT, // Event ID
|
||||
{
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// eSE provides the ATR (e.g. because the eSE was reset with EVT_ABORT).
|
||||
const SimSequenceStep SEInitializationSequences::WithEse::EseAtrEvent = SimSequenceStep::HciRead(
|
||||
L"[HCI] EVT_ATR (eSE)",
|
||||
{
|
||||
// ETSI Host Controller Interface (HCI), Version 12.1.0, Section 12.3.2.3, EVT_ATR
|
||||
HciNetworkConnectionId, // Connection ID
|
||||
EseApduPipeId, // Pipe ID
|
||||
phHciNfc_e_HcpMsgTypeEvent, // Message type
|
||||
PHHCINFC_EVT_ATR, // Event ID
|
||||
{
|
||||
// ATR
|
||||
0x3B, 0x8F, 0x80, 0x01, 0x4D, 0x53, 0x46, 0x54, 0x20, 0x56, 0x30, 0x2E, 0x30, 0x2E, 0x30, 0x20, 0x20, 0x20, 0x20, 0x44
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const SimSequenceStep
|
||||
SEInitializationSequences::Common::InitializeStartSequence_Nci1[2] =
|
||||
{
|
||||
PreNfceeDiscovery,
|
||||
NfceeDiscoverCommand_Nci1,
|
||||
};
|
||||
|
||||
const SimSequenceStep
|
||||
SEInitializationSequences::Common::InitializeStartSequence_Nci2[2] =
|
||||
{
|
||||
PreNfceeDiscovery,
|
||||
NfceeDiscoverCommand_Nci2,
|
||||
};
|
||||
|
||||
const SimSequenceView
|
||||
SEInitializationSequences::Common::InitializeStartSequence(bool isNci2)
|
||||
{
|
||||
if (isNci2)
|
||||
{
|
||||
return InitializeStartSequence_Nci2;
|
||||
}
|
||||
|
||||
return InitializeStartSequence_Nci1;
|
||||
}
|
||||
|
||||
const SimSequenceStep
|
||||
SEInitializationSequences::Common::InitializeEndSequence[1] =
|
||||
{
|
||||
NfceeDiscoveryComplete,
|
||||
};
|
||||
|
||||
const SimSequenceView
|
||||
SEInitializationSequences::NoSEs::InitializeSequence_Nci1[3] =
|
||||
{
|
||||
Common::InitializeStartSequence_Nci1,
|
||||
NfceeDiscoverResponse,
|
||||
Common::InitializeEndSequence,
|
||||
};
|
||||
|
||||
const SimSequenceView
|
||||
SEInitializationSequences::NoSEs::InitializeSequence_Nci2[3] =
|
||||
{
|
||||
Common::InitializeStartSequence_Nci2,
|
||||
NfceeDiscoverResponse,
|
||||
Common::InitializeEndSequence,
|
||||
};
|
||||
|
||||
const SimSequenceView
|
||||
SEInitializationSequences::NoSEs::InitializeSequence(bool isNci2)
|
||||
{
|
||||
if (isNci2)
|
||||
{
|
||||
return InitializeSequence_Nci2;
|
||||
}
|
||||
|
||||
return InitializeSequence_Nci1;
|
||||
}
|
||||
|
||||
const SimSequenceView
|
||||
SEInitializationSequences::WithEse::InitializeSequence_Nci1[32] =
|
||||
{
|
||||
Common::InitializeStartSequence_Nci1,
|
||||
|
||||
NfceeDiscoverResponse,
|
||||
|
||||
HciNetworkEnumeration,
|
||||
HciNetworkCreateConnectionCommand,
|
||||
HciNetworkCreateConnectionResponse,
|
||||
|
||||
EseEnumeration,
|
||||
EseSupportsNfcA,
|
||||
EseSupportsNfcB,
|
||||
EseSupportsNfcF,
|
||||
|
||||
OpenAdminPipeCommand,
|
||||
HciNetworkCredit,
|
||||
OpenAdminPipeResponse,
|
||||
|
||||
SetWhitelistCommand,
|
||||
HciNetworkCredit,
|
||||
SetWhitelistResponse,
|
||||
|
||||
SetHostTypeCommand,
|
||||
HciNetworkCredit,
|
||||
SetHostTypeResponse,
|
||||
|
||||
GetSessionIdCommand,
|
||||
HciNetworkCredit,
|
||||
GetSessionIdResponse,
|
||||
|
||||
EseEnableCommand,
|
||||
EseEnableResponse,
|
||||
|
||||
GetHostListCommand,
|
||||
HciNetworkCredit,
|
||||
GetHostListResponse,
|
||||
|
||||
GetHostTypeListCommand,
|
||||
HciNetworkCredit,
|
||||
GetHostTypeListResponse,
|
||||
|
||||
Common::InitializeEndSequence,
|
||||
|
||||
// Driver disables all the SEs to save power, until there is a client handle that requires them.
|
||||
EseDisableCommand,
|
||||
EseDisableResponse,
|
||||
};
|
||||
|
||||
const SimSequenceView
|
||||
SEInitializationSequences::WithEse::ClientConnectedSequence_Nci1[4] =
|
||||
{
|
||||
EsePowerAndLinkOnCommand,
|
||||
EsePowerAndLinkOnResponse,
|
||||
|
||||
EseEnableCommand,
|
||||
EseEnableResponse,
|
||||
};
|
||||
|
||||
const SimSequenceView
|
||||
SEInitializationSequences::WithEse::GetAtrSequence_Nci1[2] =
|
||||
{
|
||||
EseResetCommand,
|
||||
EseAtrEvent,
|
||||
};
|
||||
|
||||
const SimSequenceView
|
||||
SEInitializationSequences::WithEse::ClientDisconnectedSequence_Nci1[4] =
|
||||
{
|
||||
EsePowerOffCommand,
|
||||
EsePowerOffResponse,
|
||||
|
||||
EseDisableCommand,
|
||||
EseDisableResponse,
|
||||
};
|
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All Rights Reserved
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Simulation/SimSequenceView.h>
|
||||
#include <Simulation/SimSequenceStep.h>
|
||||
|
||||
// NCI command/response sequences relating to NFCEE enumeration.
|
||||
struct SEInitializationSequences
|
||||
{
|
||||
static const SimSequenceStep HciNetworkCredit;
|
||||
|
||||
struct Common
|
||||
{
|
||||
static const SimSequenceStep PreNfceeDiscovery;
|
||||
static const SimSequenceStep NfceeDiscoverCommand_Nci1;
|
||||
static const SimSequenceStep NfceeDiscoverCommand_Nci2;
|
||||
static const SimSequenceStep NfceeDiscoveryComplete;
|
||||
|
||||
static const SimSequenceStep InitializeStartSequence_Nci1[2];
|
||||
static const SimSequenceStep InitializeStartSequence_Nci2[2];
|
||||
static const SimSequenceView InitializeStartSequence(bool isNci2);
|
||||
|
||||
static const SimSequenceStep InitializeEndSequence[1];
|
||||
};
|
||||
|
||||
struct NoSEs
|
||||
{
|
||||
static const SimSequenceStep NfceeDiscoverResponse;
|
||||
|
||||
static const SimSequenceView InitializeSequence_Nci1[3];
|
||||
static const SimSequenceView InitializeSequence_Nci2[3];
|
||||
static const SimSequenceView InitializeSequence(bool isNci2);
|
||||
};
|
||||
|
||||
struct WithEse
|
||||
{
|
||||
// Initialize steps.
|
||||
static const SimSequenceStep NfceeDiscoverResponse;
|
||||
static const SimSequenceStep HciNetworkEnumeration;
|
||||
static const SimSequenceStep HciNetworkCreateConnectionCommand;
|
||||
static const SimSequenceStep HciNetworkCreateConnectionResponse;
|
||||
static const SimSequenceStep EseEnumeration;
|
||||
static const SimSequenceStep EseSupportsNfcA;
|
||||
static const SimSequenceStep EseSupportsNfcB;
|
||||
static const SimSequenceStep EseSupportsNfcF;
|
||||
static const SimSequenceStep OpenAdminPipeCommand;
|
||||
static const SimSequenceStep OpenAdminPipeResponse;
|
||||
static const SimSequenceStep SetWhitelistCommand;
|
||||
static const SimSequenceStep SetWhitelistResponse;
|
||||
static const SimSequenceStep SetHostTypeCommand;
|
||||
static const SimSequenceStep SetHostTypeResponse;
|
||||
static const SimSequenceStep GetSessionIdCommand;
|
||||
static const SimSequenceStep GetSessionIdResponse;
|
||||
static const SimSequenceStep GetHostListCommand;
|
||||
static const SimSequenceStep GetHostListResponse;
|
||||
static const SimSequenceStep GetHostTypeListCommand;
|
||||
static const SimSequenceStep GetHostTypeListResponse;
|
||||
|
||||
// Enable and disable command/responses.
|
||||
static const SimSequenceStep EseEnableCommand;
|
||||
static const SimSequenceStep EseEnableResponse;
|
||||
static const SimSequenceStep EseDisableCommand;
|
||||
static const SimSequenceStep EseDisableResponse;
|
||||
|
||||
// Power and link control command/responses.
|
||||
static const SimSequenceStep EsePowerOnCommand;
|
||||
static const SimSequenceStep EsePowerOnResponse;
|
||||
static const SimSequenceStep EsePowerAndLinkOnCommand;
|
||||
static const SimSequenceStep EsePowerAndLinkOnResponse;
|
||||
static const SimSequenceStep EsePowerOffCommand;
|
||||
static const SimSequenceStep EsePowerOffResponse;
|
||||
|
||||
// Client connect and disconnect steps.
|
||||
static const SimSequenceStep SetDefaultRoutingTableCommand;
|
||||
static const SimSequenceStep SetDefaultRoutingTableResponse;
|
||||
static const SimSequenceStep EseResetCommand;
|
||||
static const SimSequenceStep EseAtrEvent;
|
||||
|
||||
// Sequences
|
||||
static const SimSequenceView InitializeSequence_Nci1[32];
|
||||
static const SimSequenceView ClientConnectedSequence_Nci1[4];
|
||||
static const SimSequenceView GetAtrSequence_Nci1[2];
|
||||
static const SimSequenceView ClientDisconnectedSequence_Nci1[4];
|
||||
};
|
||||
};
|
|
@ -37,7 +37,7 @@ AirplaneModeTests::RadioStateBasicTest()
|
|||
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
|
||||
|
||||
// Verify NCI is initialized.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::InitializeNoSEs::Sequence_Nci1);
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence_Nci1);
|
||||
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
|
||||
// Open radio manager
|
||||
|
@ -162,6 +162,7 @@ AirplaneModeTests::RadioStateBasicTest()
|
|||
nfpSubInterface.Reset();
|
||||
|
||||
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStop::Sequence);
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Power::D0Exit);
|
||||
|
||||
// Stop NFC Controller.
|
||||
LOG_COMMENT(L"# Stop NFC Controller.");
|
||||
|
|
|
@ -36,6 +36,10 @@ class InitTests
|
|||
TEST_METHOD_PROPERTY(L"Category", L"Reliability")
|
||||
END_TEST_METHOD()
|
||||
|
||||
BEGIN_TEST_METHOD(InitAndDeinitWithEseNci1Test)
|
||||
TEST_METHOD_PROPERTY(L"Category", L"GoldenPath")
|
||||
END_TEST_METHOD()
|
||||
|
||||
BEGIN_TEST_METHOD(DiscoveryInitAndDeinitNci1Test)
|
||||
TEST_METHOD_PROPERTY(L"Category", L"GoldenPath")
|
||||
END_TEST_METHOD()
|
||||
|
@ -60,7 +64,7 @@ InitTests::InitAndDeinitTest(bool isNci2)
|
|||
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
|
||||
|
||||
// Verify NCI is initialized.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::InitializeNoSEs::Sequence(isNci2));
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence(isNci2));
|
||||
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
|
||||
// Stop NFC Controller.
|
||||
|
@ -98,12 +102,12 @@ InitTests::InitAndDeinitNci1WithSlowIoTest()
|
|||
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
|
||||
|
||||
// Run through the first half of the initialization sequence, stopping just before the GetConfigCommand step.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::InitializeNoSEs::Sequence_Nci1, 5);
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence_Nci1, 5);
|
||||
|
||||
// Manually process the GetConfigCommand step.
|
||||
LOG_COMMENT(L"# Manually processing GetConfigCommand step.");
|
||||
NciSimCallbackMessage message = simConnector.ReceiveLibNfcThreadCallback();
|
||||
SimSequenceRunner::VerifyStep(InitSequences::InitializeNoSEs::GetConfigCommand, message);
|
||||
SimSequenceRunner::VerifyStep(InitSequences::Initialize::GetConfigCommand, message);
|
||||
|
||||
// Don't send the NCI write complete message, until after the NCI response timer will have expired.
|
||||
LOG_COMMENT(L"Waiting for timeout to trigger.");
|
||||
|
@ -111,7 +115,7 @@ InitTests::InitAndDeinitNci1WithSlowIoTest()
|
|||
simConnector.SendNciWriteCompleted();
|
||||
|
||||
// Process the remainder of the initialization sequence.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::InitializeNoSEs::Sequence_Nci1 + 6, std::size(InitSequences::InitializeNoSEs::Sequence_Nci1) - 6);
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence_Nci1 + 6, std::size(InitSequences::Initialize::NoSEsSequence_Nci1) - 6);
|
||||
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
|
||||
// Allow device to drop out of D0, so that NCI is deinitialized.
|
||||
|
@ -123,6 +127,31 @@ InitTests::InitAndDeinitNci1WithSlowIoTest()
|
|||
VERIFY_IS_TRUE(ioStopHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
}
|
||||
|
||||
// Tests NFC controller initialization and deinitialization with an eSE for NCI 1.1.
|
||||
void
|
||||
InitTests::InitAndDeinitWithEseNci1Test()
|
||||
{
|
||||
LOG_COMMENT(L"# Open connection to NCI Simulator Driver.");
|
||||
NciSimConnector simConnector;
|
||||
|
||||
// Start NFC Controller.
|
||||
LOG_COMMENT(L"# Start NFC Controller.");
|
||||
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
|
||||
|
||||
// Verify NCI is initialized.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::WithEseSequence_Nci1);
|
||||
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
|
||||
// Stop NFC Controller.
|
||||
LOG_COMMENT(L"# Stop NFC Controller.");
|
||||
std::shared_ptr<IoOperation> ioStopHost = simConnector.StopHostAsync();
|
||||
|
||||
// Verify NCI is uninitialized.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Uninitialize::Sequence_Nci1);
|
||||
VERIFY_IS_TRUE(ioStopHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
}
|
||||
|
||||
// Tests entering and exiting RF discovery mode.
|
||||
void
|
||||
InitTests::DiscoveryInitAndDeinitTest(bool isNci2)
|
||||
{
|
||||
|
@ -134,7 +163,7 @@ InitTests::DiscoveryInitAndDeinitTest(bool isNci2)
|
|||
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
|
||||
|
||||
// Verify NCI is initialized.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::InitializeNoSEs::Sequence(isNci2));
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence(isNci2));
|
||||
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
|
||||
// Try to find the smartcard (NFC) interface and open it.
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All Rights Reserved
|
||||
//
|
||||
|
||||
#include "Precomp.h"
|
||||
|
||||
#include <IOHelpers\DriverHandleFactory.h>
|
||||
#include <IOHelpers\IoOperation.h>
|
||||
#include <Simulation\SimSequenceRunner.h>
|
||||
#include <SimulationSequences\InitSequences.h>
|
||||
#include <SimulationSequences\SEInitializationSequences.h>
|
||||
|
||||
#include "TestLogging.h"
|
||||
|
||||
using namespace ::winrt::Windows::Devices::SmartCards;
|
||||
|
||||
class SETests
|
||||
{
|
||||
TEST_CLASS(SETests);
|
||||
|
||||
BEGIN_TEST_METHOD(EseClientConnectDisconnectNci1Test)
|
||||
TEST_METHOD_PROPERTY(L"Category", L"GoldenPath")
|
||||
END_TEST_METHOD()
|
||||
};
|
||||
|
||||
void
|
||||
SETests::EseClientConnectDisconnectNci1Test()
|
||||
{
|
||||
LOG_COMMENT(L"# Open connection to NCI Simulator Driver.");
|
||||
NciSimConnector simConnector;
|
||||
|
||||
// Start NFC Controller.
|
||||
LOG_COMMENT(L"# Start NFC Controller.");
|
||||
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
|
||||
|
||||
// Verify NCI is initialized.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::WithEseSequence_Nci1);
|
||||
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
|
||||
// Open eSE interface.
|
||||
std::shared_ptr<Async::AsyncTaskBase<UniqueHandle>> openEseTask = DriverHandleFactory::OpenSmartcardHandleAsync(simConnector.DeviceId().c_str(), SmartCardReaderKind::EmbeddedSE);
|
||||
|
||||
// Verify eSE is enabled.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Power::D0Entry);
|
||||
SimSequenceRunner::Run(simConnector, SEInitializationSequences::WithEse::ClientConnectedSequence_Nci1);
|
||||
|
||||
// When the first client connects to the eSE interface, the driver retrieves the eSE's ATR.
|
||||
// Check if this is the first connection by waiting for either a new NCI packet or handle creation to complete.
|
||||
std::shared_ptr<Async::AsyncTaskBase<void>> waitForLibNfcCallback = simConnector.WhenLibNfcThreadCallbackAvailableAsync();
|
||||
|
||||
size_t waitResult = Async::WaitForAnyWithTimeout(/*timeout(ms)*/ 5'000, waitForLibNfcCallback, openEseTask);
|
||||
switch (waitResult)
|
||||
{
|
||||
case 0:
|
||||
VERIFY_FAIL(L"Open eSE handle timed out");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Process the GetAtr sequence.
|
||||
SimSequenceRunner::Run(simConnector, SEInitializationSequences::WithEse::GetAtrSequence_Nci1);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// eSE handle opened without running the GetAtr sequence.
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait for eSE interface to finish opening.
|
||||
UniqueHandle eseInterface = std::move(openEseTask->Get());
|
||||
|
||||
// Close eSE interface handle asynchronously.
|
||||
std::shared_ptr<Async::AsyncTaskBase<void>> closeEseTask = DriverHandleFactory::CloseHandleAsync(std::move(eseInterface));
|
||||
|
||||
// Verify eSE is disabled.
|
||||
SimSequenceRunner::Run(simConnector, SEInitializationSequences::WithEse::ClientDisconnectedSequence_Nci1);
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Power::D0Exit);
|
||||
|
||||
// Wait for eSE to finish closing.
|
||||
closeEseTask->Get();
|
||||
|
||||
// Stop NFC Controller.
|
||||
LOG_COMMENT(L"# Stop NFC Controller.");
|
||||
std::shared_ptr<IoOperation> ioStopHost = simConnector.StopHostAsync();
|
||||
|
||||
// Verify NCI is uninitialized.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Uninitialize::Sequence_Nci1);
|
||||
VERIFY_IS_TRUE(ioStopHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
}
|
|
@ -50,7 +50,7 @@ TagTests::SimpleNdefSubscriptionTest()
|
|||
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
|
||||
|
||||
// Verify NCI is initialized.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::InitializeNoSEs::Sequence_Nci1);
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence_Nci1);
|
||||
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
|
||||
// Open handle for NDEF subscription.
|
||||
|
@ -73,7 +73,9 @@ TagTests::SimpleNdefSubscriptionTest()
|
|||
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStart::Sequence_Nci1);
|
||||
|
||||
// Ensure subscription receives the tag's message.
|
||||
IoOperation::Result ioGetMessageResult = ioGetMessage->WaitForResult(/*wait (ms)*/ 1'000);
|
||||
VERIFY_IS_TRUE(ioGetMessage->Wait(/*wait (ms)*/ 1'000));
|
||||
|
||||
IoOperationResult ioGetMessageResult = ioGetMessage->Get();
|
||||
VERIFY_WIN32_SUCCEEDED(ioGetMessageResult.ErrorCode);
|
||||
|
||||
// Verify message is correct.
|
||||
|
@ -107,7 +109,7 @@ TagTests::NdefSubscriptionWithEarlyTagArrivalTest()
|
|||
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
|
||||
|
||||
// Verify NCI is initialized.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::InitializeNoSEs::Sequence_Nci1);
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence_Nci1);
|
||||
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
|
||||
// Open handle for NDEF subscription.
|
||||
|
@ -139,7 +141,9 @@ TagTests::NdefSubscriptionWithEarlyTagArrivalTest()
|
|||
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStart::Sequence_Nci1);
|
||||
|
||||
// Ensure subscription receives the tag's message.
|
||||
IoOperation::Result ioGetMessageResult = ioGetMessage->WaitForResult(/*wait (ms)*/ 1'000);
|
||||
VERIFY_IS_TRUE(ioGetMessage->Wait(/*wait (ms)*/ 1'000));
|
||||
|
||||
IoOperationResult ioGetMessageResult = ioGetMessage->Get();
|
||||
VERIFY_WIN32_SUCCEEDED(ioGetMessageResult.ErrorCode);
|
||||
|
||||
// Verify message is correct.
|
||||
|
@ -173,7 +177,7 @@ TagTests::SimpleNdefSubscriptionTestWithSlowIO()
|
|||
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
|
||||
|
||||
// Verify NCI is initialized.
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::InitializeNoSEs::Sequence_Nci1);
|
||||
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence_Nci1);
|
||||
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
|
||||
|
||||
// Open handle for NDEF subscription.
|
||||
|
@ -208,7 +212,9 @@ TagTests::SimpleNdefSubscriptionTestWithSlowIO()
|
|||
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStart::Sequence_Nci1);
|
||||
|
||||
// Ensure subscription receives the tag's message.
|
||||
IoOperation::Result ioGetMessageResult = ioGetMessage->WaitForResult(/*wait (ms)*/ 1'000);
|
||||
VERIFY_IS_TRUE(ioGetMessage->Wait(/*wait (ms)*/ 1'000));
|
||||
|
||||
IoOperationResult ioGetMessageResult = ioGetMessage->Get();
|
||||
VERIFY_WIN32_SUCCEEDED(ioGetMessageResult.ErrorCode);
|
||||
|
||||
// Verify message is correct.
|
||||
|
|
Загрузка…
Ссылка в новой задаче