This change adds tests for initializing NCI with an eSE and for
connecting/disconnecting an eSE client handle.
This commit is contained in:
Chris Gunn 2018-12-11 15:30:14 -08:00
Родитель 9e221cfa4b
Коммит 5eb4d43180
26 изменённых файлов: 1938 добавлений и 208 удалений

Просмотреть файл

@ -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.