diff options
| author | Wei Mao <[email protected]> | 2017-03-17 19:47:04 -0700 |
|---|---|---|
| committer | Wei Mao <[email protected]> | 2017-03-17 19:47:04 -0700 |
| commit | 1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (patch) | |
| tree | bf5d9c5b0b4cba1b81726b9f78c4d5ff5c636fea /SPB/SpbTestTool/exe | |
| parent | da21c8784c83c5fd614f3030323e229d6a5fb10e (diff) | |
Fix cases
Diffstat (limited to 'SPB/SpbTestTool/exe')
| -rw-r--r-- | SPB/SpbTestTool/exe/SpbTestTool.vcxproj | 204 | ||||
| -rw-r--r-- | SPB/SpbTestTool/exe/SpbTestTool.vcxproj.Filters | 28 | ||||
| -rw-r--r-- | SPB/SpbTestTool/exe/command.cpp | 660 | ||||
| -rw-r--r-- | SPB/SpbTestTool/exe/command.h | 638 | ||||
| -rw-r--r-- | SPB/SpbTestTool/exe/internal.h | 99 | ||||
| -rw-r--r-- | SPB/SpbTestTool/exe/main.cpp | 633 | ||||
| -rw-r--r-- | SPB/SpbTestTool/exe/util.cpp | 250 |
7 files changed, 2512 insertions, 0 deletions
diff --git a/SPB/SpbTestTool/exe/SpbTestTool.vcxproj b/SPB/SpbTestTool/exe/SpbTestTool.vcxproj new file mode 100644 index 00000000..88f1e6a5 --- /dev/null +++ b/SPB/SpbTestTool/exe/SpbTestTool.vcxproj @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{D98724B9-FEB8-4D51-B807-1D83E324A9AD}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{418E967E-17B4-4EA7-9D97-735BA0A2EE70}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>SpbTestTool</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>SpbTestTool</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>SpbTestTool</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>SpbTestTool</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys;$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="command.cpp" /> + <ClCompile Include="main.cpp" /> + <ClCompile Include="util.cpp" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/SPB/SpbTestTool/exe/SpbTestTool.vcxproj.Filters b/SPB/SpbTestTool/exe/SpbTestTool.vcxproj.Filters new file mode 100644 index 00000000..e2c07bad --- /dev/null +++ b/SPB/SpbTestTool/exe/SpbTestTool.vcxproj.Filters @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{E51F9248-08FA-42B8-80B9-2B287C503100}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{CC896E5F-EEB8-4743-8F57-FAD8C296E752}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{CEA4D39C-0E96-45C5-97EF-3245169C1997}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="command.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="util.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/SPB/SpbTestTool/exe/command.cpp b/SPB/SpbTestTool/exe/command.cpp new file mode 100644 index 00000000..fa559266 --- /dev/null +++ b/SPB/SpbTestTool/exe/command.cpp @@ -0,0 +1,660 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + command.cpp + +Abstract: + + This module contains the class definitions for the various + SpbTestTool commands. + +Environment: + + user-mode + +Revision History: + +--*/ + +#include "internal.h" + +long CCommand::s_Index = 1; + +VOID +PrintCommands() +{ + printf("\n"); + printf("Commands:\n"); + printf(" open open handle to SPB controller\n"); + printf(" close close handle to SPB controller\n"); + printf(" lock lock the bus for exclusive access\n"); + printf(" unlock unlock the bus\n"); + printf(" lockconn lock the shared connection for exclusive access -\n"); + printf(" this primitive is used to synchronize with op-region\n"); + printf(" accesses by firmware\n"); + printf(" unlockconn unlock the shared connection\n"); + printf(" write {} write byte array to peripheral\n"); + printf(" > write {01 02 03}\n"); + printf(" read <numBytes> read <numBytes> from peripheral\n"); + printf(" > read 5\n"); + printf(" writeread {} <numBytes> atomically write byte array to peripheral\n"); + printf(" and read <numBytes> back\n"); + printf(" > writeread {01 02 03} 5\n"); + printf(" fullduplex {} <numBytes> simultaneously write byte array to peripheral\n"); + printf(" and read <numBytes> back\n"); + printf(" > full duplex {01 02 03} 5\n"); + printf(" signal inform the SpbTestTool driver that the\n"); + printf(" interrupt has been handled\n"); + printf(" help print command list\n"); + printf("\n"); +} + +PCCommand +CCommand::_ParseCommand( + _In_ __drv_when(return != nullptr, __drv_aliasesMem) list<string> *Parameters + ) +{ + string tag; + string name; + + PCCommand command = nullptr; + + if (Parameters->front()[0] == L'@') + { + if (PopStringParameter(Parameters, &tag) == false) + { + printf("Error - could not pop tag\n"); + return nullptr; + } + } + + if (PopStringParameter(Parameters, &name) == false) + { + return nullptr; + } + + if(_stricmp(name.c_str(), "open") == 0) + { + command = new COpenCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "close") == 0) + { + command = new CCloseCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "lock") == 0) + { + command = new CLockCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "unlock") == 0) + { + command = new CUnlockCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "lockconn") == 0) + { + command = new CLockConnectionCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "unlockconn") == 0) + { + command = new CUnlockConnectionCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "read") == 0) + { + command = new CReadCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "write") == 0) + { + command = new CWriteCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "writeread") == 0) + { + command = new CWriteReadCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "fullduplex") == 0) + { + command = new CFullDuplexCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "signal") == 0) + { + command = new CSignalInterruptCommand(Parameters, tag); + } + else if(_stricmp(name.c_str(), "help") == 0) + { + PrintCommands(); + return nullptr; + } + else + { + printf("unrecognized command %s\n", name.c_str()); + PrintCommands(); + return nullptr; + } + + if (command->Parse() == false) + { + command->DetachParameter(); //avoid double deletion + delete command; + return nullptr; + } + + return command; +} + +bool +COpenCommand::Execute( + VOID + ) +{ + // + // Open peripheral target + // + + ULONG bytesReturned; + + if (File == nullptr) + { + return false; + } + + if ((DeviceIoControl( + File, + IOCTL_SPBTESTTOOL_OPEN, + nullptr, + 0, + nullptr, + 0, + &bytesReturned, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesReturned); + } + + return true; +} + +void +COpenCommand::Complete( + _In_ DWORD Status, + _In_ DWORD /* Information */ + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", GetLastError()); + } + else + { + printf("Peripheral target opened\n"); + } +} + +bool +CCloseCommand::Execute( + VOID + ) +{ + // + // Close peripheral target + // + + ULONG bytesReturned; + + if (File == nullptr) + { + return false; + } + + if ((DeviceIoControl( + File, + IOCTL_SPBTESTTOOL_CLOSE, + nullptr, + 0, + nullptr, + 0, + &bytesReturned, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesReturned); + } + + return true; +} + +void +CCloseCommand::Complete( + _In_ DWORD Status, + _In_ DWORD /* Information */ + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", GetLastError()); + } + else + { + printf("Peripheral target closed\n"); + } +} + +bool +CLockCommand::Execute( + VOID + ) +{ + // + // Lock controller for peripheral target + // + + ULONG bytesReturned; + + if (File == nullptr) + { + return false; + } + + if ((DeviceIoControl( + File, + IOCTL_SPBTESTTOOL_LOCK, + nullptr, + 0, + nullptr, + 0, + &bytesReturned, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesReturned); + } + + return true; +} + +void +CLockCommand::Complete( + _In_ DWORD Status, + _In_ DWORD /* Information */ + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", GetLastError()); + } + else + { + printf("Controller locked\n"); + } +} + +bool +CUnlockCommand::Execute( + VOID + ) +{ + // + // Unlock controller + // + + ULONG bytesReturned; + + if (File == nullptr) + { + return false; + } + + if ((DeviceIoControl( + File, + IOCTL_SPBTESTTOOL_UNLOCK, + nullptr, + 0, + nullptr, + 0, + &bytesReturned, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesReturned); + } + + return true; +} + +void +CUnlockCommand::Complete( + _In_ DWORD Status, + _In_ DWORD /* Information */ + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", GetLastError()); + } + else + { + printf("Controller unlocked\n"); + } +} + +bool +CLockConnectionCommand::Execute( + VOID + ) +{ + // + // Lock connection for peripheral target + // + + ULONG bytesReturned; + + if (File == nullptr) + { + return false; + } + + if ((DeviceIoControl( + File, + IOCTL_SPBTESTTOOL_LOCK_CONNECTION, + nullptr, + 0, + nullptr, + 0, + &bytesReturned, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesReturned); + } + + return true; +} + +void +CLockConnectionCommand::Complete( + _In_ DWORD Status, + _In_ DWORD /* Information */ + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", GetLastError()); + } + else + { + printf("Peripheral target locked\n"); + } +} + +bool +CUnlockConnectionCommand::Execute( + VOID + ) +{ + // + // Unlock connection + // + + ULONG bytesReturned; + + if (File == nullptr) + { + return false; + } + + if ((DeviceIoControl( + File, + IOCTL_SPBTESTTOOL_UNLOCK_CONNECTION, + nullptr, + 0, + nullptr, + 0, + &bytesReturned, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesReturned); + } + + return true; +} + +void +CUnlockConnectionCommand::Complete( + _In_ DWORD Status, + _In_ DWORD /* Information */ + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", GetLastError()); + } + else + { + printf("Peripheral target unlocked\n"); + } +} + +bool +CReadCommand::Execute( + VOID + ) +{ + ULONG bytesRead; + + if (File == nullptr) + { + return false; + } + + if ((ReadFile(File, + Buffer, + Length, + &bytesRead, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesRead); + } + + return true; +} + +void +CReadCommand::Complete( + _In_ DWORD Status, + _In_ DWORD Information + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", Status); + } + else + { + printf("%u bytes read\n", Information); + PrintBytes(Information, Buffer); + } +} + +bool +CWriteCommand::Execute( + VOID + ) +{ + ULONG bytesWritten; + + if (File == nullptr) + { + return false; + } + + if ((WriteFile(File, + Buffer, + Length, + &bytesWritten, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesWritten); + } + + return true; +} + + +void +CWriteCommand::Complete( + _In_ DWORD Status, + _In_ DWORD Information + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", Status); + } + else + { + printf("%u bytes written\n", Information); + } +} + +bool +CWriteReadCommand::Execute( + VOID + ) +{ + ULONG bytesTransferred; + + if (File == nullptr) + { + return false; + } + + if ((DeviceIoControl(File, + IOCTL_SPBTESTTOOL_WRITEREAD, + WriteBuffer, + WriteLength, + Buffer, + ReadLength, + &bytesTransferred, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesTransferred); + } + + return true; +} + +void +CWriteReadCommand::Complete( + _In_ DWORD Status, + _In_ DWORD Information + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", GetLastError()); + } + else + { + printf("%u bytes returned\n", Information); + PrintBytes(Information, Buffer); + } +} + +bool +CFullDuplexCommand::Execute( + VOID + ) +{ + ULONG bytesTransferred; + + if (File == nullptr) + { + return false; + } + + if ((DeviceIoControl(File, + IOCTL_SPBTESTTOOL_FULL_DUPLEX, + WriteBuffer, + WriteLength, + Buffer, + ReadLength, + &bytesTransferred, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesTransferred); + } + + return true; +} + +void +CFullDuplexCommand::Complete( + _In_ DWORD Status, + _In_ DWORD Information + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", GetLastError()); + } + else + { + printf("%u bytes returned\n", Information); + PrintBytes(Information, Buffer); + } +} + +bool +CSignalInterruptCommand::Execute( + VOID + ) +{ + // + // Signal interrupt + // + + ULONG bytesReturned; + + if (File == nullptr) + { + return false; + } + + if ((DeviceIoControl( + File, + IOCTL_SPBTESTTOOL_SIGNAL_INTERRUPT, + nullptr, + 0, + nullptr, + 0, + &bytesReturned, + &Overlapped) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + FakeCompletion(GetLastError(), bytesReturned); + } + + return true; +} + +void +CSignalInterruptCommand::Complete( + _In_ DWORD Status, + _In_ DWORD /* Information */ + ) +{ + if (Status != NO_ERROR) + { + printf("Error %u\n", GetLastError()); + } + else + { + printf("Interrupt signalled\n"); + } +} diff --git a/SPB/SpbTestTool/exe/command.h b/SPB/SpbTestTool/exe/command.h new file mode 100644 index 00000000..5e2633bd --- /dev/null +++ b/SPB/SpbTestTool/exe/command.h @@ -0,0 +1,638 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + command.h + +Abstract: + + This module contains the class declarations for the various + SpbTestTool commands. + +Environment: + + user-mode + +Revision History: + +--*/ + +typedef struct CCommand CCommand, *PCCommand; + +pair<ULONG, PBYTE> +ParseBuffer( + _In_ list<string> *Parameters, + _In_ list<string>::iterator Start + ); + +VOID +PrintCommands(); + +struct CCommand +{ +public: + + long Index; + string Type; + list<string> *Parameters; + + // + // File handle this command is being run against (if any). + // + + HANDLE File; + + // + // Overlapped structure for this command to use. + // + + OVERLAPPED Overlapped; + + // + // Handle to the thread for this command (if run asynchronously) + // The thread is signalled when the command is complete. + // + + HANDLE Thread; + + // + // Common parameters. + // + + string Address; + PBYTE Buffer; + + static long s_Index; + + CCommand( + _In_ string Type, + _In_ __drv_aliasesMem list<string> *Tokens + ) : Type(Type), + Thread(nullptr), + Parameters(Tokens), + Address(""), + Buffer(nullptr), + File(nullptr) + { + ZeroMemory(&Overlapped, sizeof(OVERLAPPED)); + Index = s_Index; + s_Index += 1; + return; + } + + virtual + ~CCommand( + void + ) + { + delete[] Buffer; + delete Parameters; + } + + virtual + bool + Parse( + void + ) + { + File = g_Peripheral; + return true; + } + + void + DetachParameter( + void + ) + { + Parameters = nullptr; + } + + + typedef + void + (FN_PARSE)( + _In_ list<string>::const_iterator &Iterator + ); + +public: + + static + PCCommand + _ParseCommand( + _In_ __drv_when(return != nullptr, __drv_aliasesMem) list<string> *Tokens + ); + +public: + + VOID + FakeCompletion( + _In_ DWORD Status, + _In_ DWORD Information + ) + { + Overlapped.Internal = Status == NO_ERROR ? Status : HRESULT_FROM_WIN32(Status); + Overlapped.InternalHigh = Information; + SetEvent(Overlapped.hEvent); + } + + virtual + bool + Execute( + VOID + ) = 0; + + virtual + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ) + { + printf("%s completed with status %u, information %u\n", + Type.c_str(), + Status, + Information); + } + + virtual + bool + Cancel( + VOID + ) + { + if (File != nullptr) + { + return CancelIoEx(File, &Overlapped) ? true : false; + } + else + { + return false; + } + } +}; + +class COpenCommand : public CCommand +{ +private: + +public: + COpenCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("open", Parameters) + { + return; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + +class CCloseCommand : public CCommand +{ +private: + +public: + CCloseCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("close", Parameters) + { + return; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + +class CLockCommand : public CCommand +{ +private: + +public: + CLockCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("lock", Parameters) + { + return; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + +class CUnlockCommand : public CCommand +{ +private: + +public: + CUnlockCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("unlock", Parameters) + { + return; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + +class CLockConnectionCommand : public CCommand +{ +private: + +public: + CLockConnectionCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("lockconn", Parameters) + { + return; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + +class CUnlockConnectionCommand : public CCommand +{ +private: + +public: + CUnlockConnectionCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("unlockconn", Parameters) + { + return; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + +class CReadCommand : public CCommand +{ +private: + ULONG Length; + +public: + + CReadCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("read", Parameters) + { + return; + } + + bool + Parse( + void + ) + { + if (CCommand::Parse() == false) + { + return false; + } + + if (PopNumberParameter(Parameters, 10, &Length) == false) + { + printf("Length required\n"); + return false; + } + + if (Length > 0) + { + Buffer = new BYTE[Length]; + ZeroMemory(Buffer, Length); + } + else + { + Buffer = nullptr; + } + + return true; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + + +class CWriteCommand : public CCommand +{ +private: + ULONG Length; + +public: + + CWriteCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("write", Parameters) + { + return; + } + + bool + Parse( + VOID + ) + { + if (CCommand::Parse() == false) + { + return false; + } + + pair<ULONG, PBYTE> buf; + + if (PopBufferParameter(Parameters, &buf) == false) + { + printf("Buffer required\n"); + return false; + } + + Length = buf.first; + Buffer = buf.second; + + return true; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + +class CWriteReadCommand : public CCommand +{ +private: + ULONG WriteLength; + ULONG ReadLength; + + PBYTE WriteBuffer; + +public: + + CWriteReadCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("writeread", Parameters) + { + WriteBuffer = NULL; + return; + } + + ~CWriteReadCommand( + void + ) + { + delete[] WriteBuffer; + } + + bool + Parse( + void + ) + { + if (CCommand::Parse() == false) + { + return false; + } + + pair<ULONG, PBYTE> buf; + + if (PopBufferParameter(Parameters, &buf) == false) + { + printf("Buffer required\n"); + return false; + } + + WriteLength = buf.first; + WriteBuffer = buf.second; + + if (PopNumberParameter(Parameters, 10, &ReadLength) == false) + { + printf("Length required\n"); + return false; + } + + if (ReadLength > 0) + { + Buffer = new BYTE[ReadLength]; + ZeroMemory(Buffer, ReadLength); + } + else + { + Buffer = nullptr; + } + + return true; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + +class CFullDuplexCommand : public CCommand +{ +private: + ULONG WriteLength; + ULONG ReadLength; + + PBYTE WriteBuffer; + +public: + + CFullDuplexCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("fullduplex", Parameters) + { + WriteBuffer = NULL; + return; + } + + ~CFullDuplexCommand( + void + ) + { + delete[] WriteBuffer; + } + + bool + Parse( + void + ) + { + if (CCommand::Parse() == false) + { + return false; + } + + pair<ULONG, PBYTE> buf; + + if (PopBufferParameter(Parameters, &buf) == false) + { + printf("Buffer required\n"); + return false; + } + + WriteLength = buf.first; + WriteBuffer = buf.second; + + if (PopNumberParameter(Parameters, 10, &ReadLength) == false) + { + printf("Length required\n"); + return false; + } + + if (ReadLength > 0) + { + Buffer = new BYTE[ReadLength]; + ZeroMemory(Buffer, ReadLength); + } + else + { + Buffer = nullptr; + } + + return true; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + +class CSignalInterruptCommand : public CCommand +{ +private: + +public: + CSignalInterruptCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("signal", Parameters) + { + return; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; + +class CWaitOnInterruptCommand : public CCommand +{ +private: + +public: + CWaitOnInterruptCommand( + _In_ __drv_aliasesMem list<string> *Parameters, + _In_opt_ string Tag + ) : CCommand("waitoninterrupt", Parameters) + { + return; + } + + bool + Execute( + VOID + ); + + void + Complete( + _In_ DWORD Status, + _In_ DWORD Information + ); +}; diff --git a/SPB/SpbTestTool/exe/internal.h b/SPB/SpbTestTool/exe/internal.h new file mode 100644 index 00000000..268186c0 --- /dev/null +++ b/SPB/SpbTestTool/exe/internal.h @@ -0,0 +1,99 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + internal.h + +Abstract: + + This module contains the internal type definitations and + helper function declarations for the SpbTestTool app. + +Environment: + + user-mode + +Revision History: + +--*/ + +#include <string> +#include <map> +#include <list> +#include <map> +#include <functional> + +#include <iomanip> + +#include <cstdlib> + +#include <stdexcept> + +#include <math.h> + +#include <wchar.h> +#include <windows.h> +#include <winioctl.h> +#include <specstrings.h> + +#include "spbtestioctl.h" + +using namespace std; + +// +// Global Variables +// + +extern HANDLE g_Peripheral; + +typedef pair<ULONG, PBYTE> BUFPAIR; +typedef list<BUFPAIR> BUFLIST; + +VOID +PrintBytes( + _In_ ULONG BufferCb, + _In_reads_bytes_(BufferCb) BYTE Buffer[] + ); + +_Success_(return) +bool +PopStringParameter( + _Inout_ list<string> *Parameters, + _Out_ string *Value, + _Out_opt_ bool *Present = nullptr + ); + +typedef pair<ULONG,ULONG> bounds; + +_Success_(return) +bool +PopNumberParameter( + _Inout_ list<string> *Parameters, + _In_ ULONG Radix, + _Out_ ULONG *Value, + _In_opt_ pair<ULONG,ULONG> Bounds = bounds(0,0), + _Out_opt_ bool *Present = nullptr + ); + +_Success_(return) +bool +ParseNumber( + _In_ const string &String, + _In_ ULONG Radix, + _Out_ ULONG *Value, + _In_opt_ bounds Bounds = bounds(0,0) + ); + +_Success_(return) +bool +PopBufferParameter( + _Inout_ list<string> *Parameters, + _Out_ pair<ULONG, PBYTE> *Value + ); + + +#define countof(x) (sizeof(x) / sizeof(x[0])) + +#include "command.h" diff --git a/SPB/SpbTestTool/exe/main.cpp b/SPB/SpbTestTool/exe/main.cpp new file mode 100644 index 00000000..ce9e994a --- /dev/null +++ b/SPB/SpbTestTool/exe/main.cpp @@ -0,0 +1,633 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + main.cpp + +Abstract: + + This module contains the main entry point for the SpbTestTool + app. It facilitates accepting input, building commands, and + printing output. + +Environment: + + user-mode + +Revision History: + +--*/ + +#include "internal.h" + +DWORD WINAPI InterruptNotificationThread( + _In_ LPVOID pvData + ); + +bool +ReadCommandFromStream( + _In_ FILE* InputStream, + _Inout_ list<string> *Tokens + ); + +VOID +PrintUsage( + _In_ PCSTR exeName + ); + +DWORD +RunCommand( + _In_ PCCommand Command + ); + +HANDLE g_Peripheral = nullptr; +HANDLE g_Event = nullptr; +HANDLE g_InterruptNotificationThread = nullptr; +PCCommand g_CurrentCommand = nullptr; +bool g_WaitOnInterrupt = true; + +BOOL +WINAPI +OnControlKey( + _In_ DWORD ControlType + ); + +void +__cdecl +main( + _In_ ULONG ArgumentsCe, + _In_reads_(ArgumentsCe) PCSTR Arguments[] + ) +{ + FILE* inputStream = stdin; + bool prompt = true; + + PCSTR peripheralPath = nullptr; + PCSTR inputPath = nullptr; + + // + // Parse the command line arguments. + // + + ULONG arg = 1; + + while (arg < ArgumentsCe) + { + if ((Arguments[arg][0] != '/') && + (Arguments[arg][0] != '-')) + { + PrintUsage(Arguments[0]); + goto exit; + } + else + { + if (tolower(Arguments[arg][1]) == 'p') + { + arg++; + if (arg == ArgumentsCe) + { + PrintUsage(Arguments[0]); + goto exit; + } + peripheralPath = Arguments[arg]; + } + else if (tolower(Arguments[arg][1]) == 'i') + { + arg++; + if (arg == ArgumentsCe) + { + PrintUsage(Arguments[0]); + goto exit; + } + inputPath = Arguments[arg]; + } + else + { + PrintUsage(Arguments[0]); + goto exit; + } + } + + arg++; + } + + // + // Open the input file if specified + // + + if (inputPath != nullptr) + { + errno_t error; + + printf("Opening %s as command input file\n", inputPath); + error = fopen_s(&inputStream, inputPath, "r"); + + if (error != 0) + { + printf("Error opening input file %s - %d\n", inputPath, error); + goto exit; + } + + if (inputStream == nullptr) + { + printf("Error opening input file %s - %d\n", inputPath, error); + goto exit; + } + + prompt = false; + } + + // + // Open peripheral driver + // + + if (peripheralPath == nullptr) + { + g_Peripheral = CreateFileW( + SPBTESTTOOL_USERMODE_PATH, + (GENERIC_READ | GENERIC_WRITE), + 0, + nullptr, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + nullptr); + } + else + { + printf("Opening %s as peripheral driver path \n", peripheralPath); + g_Peripheral = CreateFileA( + peripheralPath, + (GENERIC_READ | GENERIC_WRITE), + 0, + nullptr, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + nullptr); + } + + if (g_Peripheral == INVALID_HANDLE_VALUE) + { + printf("Error opening peripheral driver - %u\n", GetLastError()); + goto exit; + } + + setvbuf(inputStream, nullptr, _IONBF, 0); + setvbuf(stdout, nullptr, _IONBF, 0); + setvbuf(stderr, nullptr, _IONBF, 0); + + // + // Setup a control-C handler. + // + + if (SetConsoleCtrlHandler(OnControlKey, true) == FALSE) + { + printf("Error setting ctrl-C handler - %u\n", GetLastError()); + goto exit; + } + + // + // Setup an overlapped structure to use with each I/O. + // + + g_Event = CreateEvent(nullptr, true, false, nullptr); + + if (g_Event == nullptr) + { + printf("error creating I/O event - %u\n", GetLastError()); + goto exit; + } + + // + // Create interrupt notification thread. + // + + g_InterruptNotificationThread = CreateThread( + nullptr, + 0, + &InterruptNotificationThread, + nullptr, + 0, + nullptr); + + if (g_InterruptNotificationThread == nullptr) + { + printf("error creating interrupt notification thread - %u\n", GetLastError()); + goto exit; + } + + // + // Loop reading commands off the command line and parsing them. + // EOF causes an exit. + // + + do + { + list<string> *tokens = new list<string>(); + PCCommand command; + + if (prompt) + { + printf("> "); + fflush(stdout); + } + + if (ReadCommandFromStream(inputStream, tokens) == false) + { + delete tokens; + break; + } + + if (tokens->empty()) + { + delete tokens; + continue; + } + + command = CCommand::_ParseCommand(tokens); + + if (command == nullptr) + { + delete tokens; + continue; + } + + g_CurrentCommand = command; + + RunCommand(command); + + g_CurrentCommand = nullptr; + + // + // A reference to the tokens list is saved by + // the command and will be freed when the command + // is deleted. + // + + delete command; + + } + while (feof(inputStream) == 0); + +exit: + + if (prompt == false) + { + fclose(inputStream); + } + + if (g_InterruptNotificationThread != nullptr) + { + WaitForSingleObject(g_InterruptNotificationThread, INFINITE); + CloseHandle(g_InterruptNotificationThread); + } + + CloseHandle(g_Peripheral); + + if (g_Event != nullptr) + { + CloseHandle(g_Event); + } + + return; +} + +DWORD WINAPI InterruptNotificationThread( + _In_ LPVOID pvData + ) +{ + DWORD status; + DWORD bytesReturned; + OVERLAPPED ov = {0}; + + UNREFERENCED_PARAMETER(pvData); + + ov.hEvent = CreateEvent(nullptr, false, false, nullptr); + + if (ov.hEvent == nullptr) + { + printf("error creating overlapped event for interrupt thread - %u\n", GetLastError()); + goto exit; + } + + while (g_WaitOnInterrupt == true) + { + if ((DeviceIoControl( + g_Peripheral, + IOCTL_SPBTESTTOOL_WAIT_ON_INTERRUPT, + nullptr, + 0, + nullptr, + 0, + nullptr, + &ov) == TRUE) || + (GetLastError() != ERROR_IO_PENDING)) + { + printf("failed to pend WaitOnInterrupt IOCTL- %u\n", GetLastError()); + goto exit; + } + + status = WaitForSingleObject(ov.hEvent, INFINITE); + + switch (status) + { + // DeviceIoControl completed. + case WAIT_OBJECT_0: + + if (!GetOverlappedResult(g_Peripheral, &ov, &bytesReturned, FALSE)) + { + printf("GetOverlappedResult failed with status: %u\n\n", GetLastError()); + } + else + { + printf("\n\n"); + printf(" ** Interrupt detected. Please acknowledge or disable **\n"); + printf(" *** and type 'signal' to inform the SpbTestTool driver ***\n"); + printf(" ** that the interrupt has been handled. **\n"); + printf("\n"); + } + break; + + default: + // Error in the WaitForSingleObject; abort. + // This indicates a problem with the OVERLAPPED + // structure's event handle. + printf("WaitOnInterrupt unexpected return %u\n\n", status); + break; + } + } + +exit: + + return 0; +} + +VOID +PrintUsage( + _In_ PCSTR exeName + ) +{ + printf("Usage: %s [/p <driver_path>] [/i <script_name>]\n", + exeName); +} + +DWORD +RunCommand( + _In_ PCCommand Command + ) +{ + + DWORD status; + DWORD bytesTransferred; + + Command->Overlapped.hEvent = g_Event; + + if (Command->Execute() == true) + { + if (GetOverlappedResult(Command->File, + &(Command->Overlapped), + &bytesTransferred, + true) == FALSE) + { + status = GetLastError(); + } + else + { + status = NO_ERROR; + } + + Command->Complete(status, bytesTransferred); + } + else + { + status = GetLastError(); + } + + return status; +} + + +bool +ReadLine( + _In_ FILE* InputStream, + _In_ ULONG BufferCch, + _Out_writes_(BufferCch) CHAR Buffer[] + ) +{ + ULONG i; + + for(i = 0; i < BufferCch - 1; i += 1) + { + if (fread(&(Buffer[i]), sizeof(CHAR), 1, InputStream) == 0) + { + return false; + } + + fputc(Buffer[i], stdout); + + if (Buffer[i] == '\n') + { + Buffer[i] = '\0'; + return true; + } + else if (Buffer[i] == '\b') + { + Buffer[i] = '\0'; + i -= 2; + } + } + + return false; +} + +bool +ReadCommandFromStream( + _In_ FILE* InputStream, + _Inout_ list<string> *Tokens + ) +{ + CHAR buffer[255]; + + if (ReadLine(InputStream, + sizeof(buffer) - 1, + buffer) == false) + { + return false; + } + + string currentLine(buffer); + string token; + + list<string> tokens; + + Tokens->clear(); + + string::size_type i; + long start; + + for(i = 0, start = -1; + i < currentLine.length() + 1; + i += 1) + { + wchar_t c; + + if (i < currentLine.length()) + { + c = currentLine[i]; + } + else + { + c = L'\0'; + } + + if (iswspace(c) || (c == L'\0')) + { + if (start == -1) + { + // + // not tracking a token - whitespace is skipped. + // + } + else + { + // + // tracking a token - whitespace or NUL terminates it. + // if the last character was a } then split the token. + // + + if (currentLine[i-1] == '}') + { + token.assign(currentLine, start, i - start - 1); + Tokens->insert(Tokens->end(), token); + Tokens->insert(Tokens->end(), string("}")); + } + else + { + token.assign(currentLine, start, i - start); + Tokens->insert(Tokens->end(), token); + } + + start = -1; + } + } + else if (start == -1) + { + // + // first character of a token. If it's { then split the token. + // + + if (currentLine[i] == '{') + { + Tokens->insert(Tokens->end(), string("{")); + } + else if (currentLine[i] == '}') + { + Tokens->insert(Tokens->end(), string("}")); + } + else + { + start = (long) i; + } + } + else + { + // + // tracking a token - non whitespace is included. + // + } + } + + return true; +} + +VOID +PrintBytes( + _In_ ULONG BufferCb, + _In_reads_bytes_(BufferCb) BYTE Buffer[] + ) +{ + ULONG index = 0; + + for(index = 0; index < BufferCb; index += 16) + { + printf(" "); + for(ULONG i = index; i < (index + 16); i += 1) + { + if (i < BufferCb) + { + if ((i != index) && (i % 8 == 0)) + { + printf("- "); + } + + printf("%02x ", Buffer[i]); + } + else + { + if ((i != index) && (i % 8 == 0)) + { + printf(" "); + } + printf(" "); + } + } + + printf(" : "); + + for(ULONG i = index; i < (index + 16); i += 1) + { + if (i < BufferCb) + { + if ((i != index) && (i % 8 == 0)) + { + printf(" "); + } + + if (isprint(Buffer[i])) + { + printf("%c", Buffer[i]); + } + else + { + printf("."); + } + } + else + { + printf(" "); + } + } + + printf("\n"); + } +} + +BOOL +WINAPI +OnControlKey( + _In_ DWORD ControlType + ) +{ + if (ControlType == CTRL_C_EVENT) + { + // + // If there's a current command then attempt to cancel it. + // + + if (g_CurrentCommand != nullptr) + { + g_CurrentCommand->Cancel(); + return TRUE; + } + + // + // Stop the interrupt notification thread + // + + g_WaitOnInterrupt = false; + CancelIo(g_Peripheral); + } + + return FALSE; +} diff --git a/SPB/SpbTestTool/exe/util.cpp b/SPB/SpbTestTool/exe/util.cpp new file mode 100644 index 00000000..fe6067c9 --- /dev/null +++ b/SPB/SpbTestTool/exe/util.cpp @@ -0,0 +1,250 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + util.cpp + +Abstract: + + This module contains the internal helper function definitions + for the SpbTestTool app. + +Environment: + + user-mode + +Revision History: + +--*/ + +#include "internal.h" + +_Success_(return) +bool +PopStringParameter( + _Inout_ list<string> *Parameters, + _Out_ string *Value, + _Out_opt_ bool *Present + ) +{ + if (Parameters->empty()) + { + if (Present != nullptr) + { + *Present = false; + *Value = string(""); + return true; + } + else + { + printf("Missing required parameter\n"); + return false; + } + } + + if (Present != nullptr) + { + *Present = true; + } + + *Value = Parameters->front(); + Parameters->pop_front(); + return true; +} + +_Success_(return) +bool +ParseNumber( + _In_ const string &String, + _In_ ULONG Radix, + _Out_ ULONG *Value, + _In_opt_ bounds Bounds + ) +{ + PSTR end; + +#pragma prefast(suppress:__WARNING_MISSING_ZERO_TERMINATION2 ,"zero-termination is checked below") + *Value = strtoul(String.c_str(), &end, Radix); + + // + // Make sure the entire string parsed. + // + + if (*end != '\0') + { + printf("Value %s is not a number\n", String.c_str()); + return false; + } + + // + // See if we should do a bounds check. + // + + if ((Bounds.first != 0) || (Bounds.second != 0)) + { + if ((*Value < Bounds.first) || + (*Value > Bounds.second)) + { + printf("Value %s is out of bounds\n", String.c_str()); + return false; + } + } + + return true; +} + +_Success_(return) +bool +PopNumberParameter( + _Inout_ list<string> *Parameters, + _In_ ULONG Radix, + _Out_ ULONG *Value, + _In_opt_ bounds Bounds, + _Out_opt_ bool *Present + ) +{ + string s; + + bool found = PopStringParameter(Parameters, &s, Present); + + if ((Present != nullptr) && (*Present == false)) + { + *Value = Bounds.first; + return true; + } + else if (found == false) + { + return false; + } + + return ParseNumber(s, Radix, Value, Bounds); +} + +_Success_(return) +bool +PopBufferParameter( + _Inout_ list<string> *Parameters, + _Out_ pair<ULONG, PBYTE> *Value + ) +{ + ULONG length = 0; + PBYTE buffer = nullptr; + + // + // Check for an explict length + // + + if (Parameters->front() != "{") + { + if (PopNumberParameter(Parameters, 10, &length) == false) + { + printf("Length expected\n"); + return false; + } + + // + // Consume any leading { + // + + if ((Parameters->empty() == false) && + (Parameters->front() == "{")) + { + Parameters->pop_front(); + } + } + else + { + string tmp; + if (PopStringParameter(Parameters, &tmp) == false) + { + return false; + } + else if (tmp != "{") + { + printf("output buffer must start with {\n"); + return false; + } + + // + // Count values until the trailing } - assume one byte per value + // + + list<string>::iterator i; + + for(i = Parameters->begin(); + ((i != Parameters->end()) && (*i != "}")); + i++) + { + length += 1; + } + + if (*i != "}") + { + printf("output buffer must end with }\n"); + return false; + } + } + + if (length != 0) + { + ULONG b = 0; + bool bufferEnd = false; + + // + // Allocate the buffer. + // + + buffer = new BYTE[length]; + + for(b = 0; b < length; b += 1) + { + ULONG value = 0; + + if (bufferEnd == false) + { + string nextElement; + + PopStringParameter(Parameters, &nextElement); + + if (nextElement == "}") + { + value = 0; + bufferEnd = true; + } + else if (ParseNumber(nextElement, 16, &value, bounds(0, 0xff)) == false) + { + printf("invalid byte value %s\n", nextElement.c_str()); + delete [] buffer; + return false; + } + } + + buffer[b] = (BYTE) value; + } + + if (bufferEnd == false) + { + string end; + + if (PopStringParameter(Parameters, &end) == false) + { + printf("unclosed buffer\n"); + delete [] buffer; + return false; + } + else if (end != "}") + { + printf("buffer has too many initializers\n"); + delete [] buffer; + return false; + } + } + } + + Value->first = length; + Value->second = buffer; + + return true; +} |
