├── .gitignore ├── src ├── USBLookupTables.cpp ├── USBLookupTables.h ├── USBAnalyzerSettings.h ├── USBSimulationDataGenerator.h ├── USBAnalyzerResults.h ├── USBAnalyzer.h ├── USBAnalyzerSettings.cpp ├── USBAnalyzer.cpp ├── USBTypes.h ├── USBEnums.h ├── USBControlTransfers.h ├── USBTypes.cpp ├── USBControlTransfers.cpp └── USBAnalyzerResults.cpp ├── CMakeLists.txt ├── .clang-format ├── LICENSE ├── cmake └── ExternalAnalyzerSDK.cmake ├── README.md └── .github └── workflows └── build.yml /.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /src/USBLookupTables.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saleae/usb-analyzer/HEAD/src/USBLookupTables.cpp -------------------------------------------------------------------------------- /src/USBLookupTables.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_LOOKUP_TABLES_H 2 | #define USB_LOOKUP_TABLES_H 3 | 4 | #include 5 | 6 | #include "USBEnums.h" 7 | 8 | std::string GetPIDName( USB_PID pid ); 9 | const char* GetDescriptorName( U8 descriptor ); 10 | const char* GetRequestName( U8 request ); 11 | const char* GetHIDRequestName( U8 request ); 12 | const char* GetHIDCountryName( U8 countryCode ); 13 | const char* GetCDCRequestName( U8 request ); 14 | const char* GetCDCEthFeatureSelectorName( U8 feature ); 15 | const char* GetCDCATMFeatureSelectorName( U8 feature ); 16 | const char* GetCDCDescriptorSubtypeName( U8 subtype ); 17 | const char* GetLangName( U16 langID ); 18 | const char* GetVendorName( U16 vendorID ); 19 | const char* GetUSBClassName( U8 classCode ); 20 | 21 | std::string GetHIDUsagePageName( U16 usagePage ); 22 | std::string GetHIDUsageName( U16 usagePage, U16 usageID ); 23 | 24 | #endif // USB_LOOKUP_TABLES_H -------------------------------------------------------------------------------- /src/USBAnalyzerSettings.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_ANALYZER_SETTINGS_H 2 | #define USB_ANALYZER_SETTINGS_H 3 | 4 | #include 5 | #include 6 | 7 | #include "USBTypes.h" 8 | 9 | class USBAnalyzerSettings : public AnalyzerSettings 10 | { 11 | public: 12 | USBAnalyzerSettings(); 13 | virtual ~USBAnalyzerSettings(); 14 | 15 | virtual bool SetSettingsFromInterfaces(); 16 | virtual void LoadSettings( const char* settings ); 17 | virtual const char* SaveSettings(); 18 | 19 | void UpdateInterfacesFromSettings(); 20 | 21 | Channel mDPChannel; 22 | Channel mDMChannel; 23 | 24 | USBSpeed mSpeed; 25 | USBDecodeLevel mDecodeLevel; 26 | 27 | protected: 28 | AnalyzerSettingInterfaceChannel mDPChannelInterface; 29 | AnalyzerSettingInterfaceChannel mDMChannelInterface; 30 | 31 | AnalyzerSettingInterfaceNumberList mSpeedInterface; 32 | AnalyzerSettingInterfaceNumberList mDecodeLevelInterface; 33 | }; 34 | 35 | #endif // USB_ANALYZER_SETTINGS_H 36 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.11) 2 | project(usb_analyzer) 3 | 4 | add_definitions( -DLOGIC2 ) 5 | 6 | set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum supported MacOS version" FORCE) 7 | 8 | # enable generation of compile_commands.json, helpful for IDEs to locate include files. 9 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 10 | 11 | # custom CMake Modules are located in the cmake directory. 12 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 13 | 14 | include(ExternalAnalyzerSDK) 15 | 16 | set(SOURCES 17 | src/USBAnalyzer.cpp 18 | src/USBAnalyzer.h 19 | src/USBAnalyzerResults.cpp 20 | src/USBAnalyzerResults.h 21 | src/USBAnalyzerSettings.cpp 22 | src/USBAnalyzerSettings.h 23 | src/USBControlTransfers.cpp 24 | src/USBControlTransfers.h 25 | src/USBEnums.h 26 | src/USBLookupTables.cpp 27 | src/USBLookupTables.h 28 | src/USBSimulationDataGenerator.cpp 29 | src/USBSimulationDataGenerator.h 30 | src/USBTypes.cpp 31 | src/USBTypes.h 32 | ) 33 | 34 | add_analyzer_plugin(usb_analyzer SOURCES ${SOURCES}) 35 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Logic style 2 | Language: Cpp 3 | # manually added flags 4 | FixNamespaceComments: 'false' 5 | SortIncludes: 'false' 6 | 7 | 8 | # flags copied from web editor, https://zed0.co.uk/clang-format-configurator/ 9 | AllowShortBlocksOnASingleLine: 'false' 10 | AllowShortCaseLabelsOnASingleLine: 'false' 11 | AllowShortFunctionsOnASingleLine: None 12 | AllowShortIfStatementsOnASingleLine: 'false' 13 | AllowShortLoopsOnASingleLine: 'false' 14 | AlwaysBreakAfterReturnType: None 15 | AlwaysBreakTemplateDeclarations: 'true' 16 | BreakBeforeBraces: Allman 17 | ColumnLimit: '140' 18 | ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' 19 | ContinuationIndentWidth: '4' 20 | Cpp11BracedListStyle: 'false' 21 | IndentWidth: '4' 22 | KeepEmptyLinesAtTheStartOfBlocks: 'false' 23 | MaxEmptyLinesToKeep: '2' 24 | NamespaceIndentation: All 25 | PointerAlignment: Left 26 | SpaceBeforeParens: Never 27 | SpaceInEmptyParentheses: 'false' 28 | SpacesInCStyleCastParentheses: 'true' 29 | SpacesInParentheses: 'true' 30 | SpacesInSquareBrackets: 'true' 31 | TabWidth: '4' 32 | UseTab: Never 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Saleae 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/USBSimulationDataGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_SIMULATION_DATA_GENERATOR_H 2 | #define USB_SIMULATION_DATA_GENERATOR_H 3 | 4 | #include 5 | 6 | #include "USBTypes.h" 7 | 8 | class USBAnalyzerSettings; 9 | 10 | class USBSimulationDataGenerator 11 | { 12 | public: 13 | USBSimulationDataGenerator(); 14 | ~USBSimulationDataGenerator(); 15 | 16 | void Initialize( U32 simulation_sample_rate, USBAnalyzerSettings* settings ); 17 | U32 GenerateSimulationData( U64 newest_sample_requested, U32 sample_rate, SimulationChannelDescriptor** simulation_channels ); 18 | 19 | protected: 20 | USBAnalyzerSettings* mSettings; 21 | U32 mSimulationSampleRateHz; 22 | 23 | ClockGenerator mClockGenerator; 24 | 25 | SimulationChannelDescriptorGroup mUSBSimulationChannels; 26 | SimulationChannelDescriptor* mDP; 27 | SimulationChannelDescriptor* mDM; 28 | 29 | const U16* mpCurrSimData; 30 | const U16* mpSimDataLoopHere; 31 | U16 mFrameCnt; 32 | 33 | // used to keep track of the 1ms frames of the USB bus 34 | double mAccuDur; 35 | 36 | void ResetFrameDuration() 37 | { 38 | mAccuDur = 0; 39 | } 40 | 41 | // general outputs 42 | void SetJ(); // sets the lines into J state 43 | void SetK(); // sets the lines into K state 44 | void OutSE0( const double dur ); 45 | void OutJ( const double dur ); 46 | void OutK( const double dur ); 47 | void OutReset(); 48 | void OutFillFrame(); // outputs idle until the end of the 1ms frame 49 | const U16* OutPacket( const U16* pPacket ); 50 | 51 | // LS outputs 52 | void OutLSKeepAlive(); 53 | 54 | // FS outputs 55 | void OutFSSOF(); 56 | }; 57 | 58 | #endif // USB_SIMULATION_DATA_GENERATOR_H 59 | -------------------------------------------------------------------------------- /src/USBAnalyzerResults.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_ANALYZER_RESULTS_H 2 | #define USB_ANALYZER_RESULTS_H 3 | 4 | #include 5 | 6 | #include "USBTypes.h" 7 | 8 | class USBAnalyzer; 9 | class USBAnalyzerSettings; 10 | 11 | class USBAnalyzerResults : public AnalyzerResults 12 | { 13 | public: 14 | USBAnalyzerResults( USBAnalyzer* analyzer, USBAnalyzerSettings* settings ); 15 | virtual ~USBAnalyzerResults(); 16 | 17 | virtual void GenerateBubbleText( U64 frame_index, Channel& channel, DisplayBase display_base ); 18 | virtual void GenerateExportFile( const char* file, DisplayBase display_base, U32 export_type_user_id ); 19 | 20 | void GenerateExportFileControlTransfers( const char* file, DisplayBase display_base ); 21 | void GenerateExportFilePackets( const char* file, DisplayBase display_base ); 22 | void GenerateExportFileBytes( const char* file, DisplayBase display_base ); 23 | void GenerateExportFileSignals( const char* file, DisplayBase display_base ); 24 | 25 | virtual void GenerateFrameTabularText( U64 frame_index, DisplayBase display_base ); 26 | virtual void GeneratePacketTabularText( U64 packet_id, DisplayBase display_base ); 27 | virtual void GenerateTransactionTabularText( U64 transaction_id, DisplayBase display_base ); 28 | 29 | void AddStringDescriptor( int addr, int id, const std::string& stringdesc ) 30 | { 31 | mAllStringDescriptors[ std::make_pair( addr, id ) ] = stringdesc; 32 | } 33 | 34 | double GetSampleTime( S64 sample ) const; 35 | std::string GetSampleTimeStr( S64 sample ) const; 36 | 37 | typedef std::map, std::string> USBStringContainer; 38 | 39 | protected: // functions 40 | protected: // vars 41 | USBAnalyzerSettings* mSettings; 42 | 43 | public: 44 | USBAnalyzer* mAnalyzer; 45 | 46 | USBStringContainer mAllStringDescriptors; 47 | }; 48 | 49 | #endif // USB_ANALYZER_RESULTS_H 50 | -------------------------------------------------------------------------------- /cmake/ExternalAnalyzerSDK.cmake: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | 3 | # Use the C++11 standard 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | set(CMAKE_CXX_STANDARD_REQUIRED YES) 7 | 8 | if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY OR NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) 9 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/) 10 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/) 11 | endif() 12 | 13 | # Fetch the Analyzer SDK if the target does not already exist. 14 | if(NOT TARGET Saleae::AnalyzerSDK) 15 | FetchContent_Declare( 16 | analyzersdk 17 | GIT_REPOSITORY https://github.com/saleae/AnalyzerSDK.git 18 | GIT_TAG master 19 | GIT_SHALLOW True 20 | GIT_PROGRESS True 21 | ) 22 | 23 | FetchContent_GetProperties(analyzersdk) 24 | 25 | if(NOT analyzersdk_POPULATED) 26 | FetchContent_Populate(analyzersdk) 27 | include(${analyzersdk_SOURCE_DIR}/AnalyzerSDKConfig.cmake) 28 | 29 | if(APPLE OR WIN32) 30 | get_target_property(analyzersdk_lib_location Saleae::AnalyzerSDK IMPORTED_LOCATION) 31 | if(CMAKE_LIBRARY_OUTPUT_DIRECTORY) 32 | file(COPY ${analyzersdk_lib_location} DESTINATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) 33 | else() 34 | message(WARNING "Please define CMAKE_RUNTIME_OUTPUT_DIRECTORY and CMAKE_LIBRARY_OUTPUT_DIRECTORY if you want unit tests to locate ${analyzersdk_lib_location}") 35 | endif() 36 | endif() 37 | 38 | endif() 39 | endif() 40 | 41 | function(add_analyzer_plugin TARGET) 42 | set(options ) 43 | set(single_value_args ) 44 | set(multi_value_args SOURCES) 45 | cmake_parse_arguments( _p "${options}" "${single_value_args}" "${multi_value_args}" ${ARGN} ) 46 | 47 | 48 | add_library(${TARGET} MODULE ${_p_SOURCES}) 49 | target_link_libraries(${TARGET} PRIVATE Saleae::AnalyzerSDK) 50 | 51 | set(ANALYZER_DESTINATION "Analyzers") 52 | install(TARGETS ${TARGET} RUNTIME DESTINATION ${ANALYZER_DESTINATION} 53 | LIBRARY DESTINATION ${ANALYZER_DESTINATION}) 54 | 55 | set_target_properties(${TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${ANALYZER_DESTINATION} 56 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${ANALYZER_DESTINATION}) 57 | endfunction() -------------------------------------------------------------------------------- /src/USBAnalyzer.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_ANALYZER_H 2 | #define USB_ANALYZER_H 3 | 4 | #include 5 | 6 | #include "USBAnalyzerSettings.h" 7 | #include "USBAnalyzerResults.h" 8 | #include "USBSimulationDataGenerator.h" 9 | 10 | #include "USBTypes.h" 11 | #include "USBControlTransfers.h" 12 | 13 | class USBAnalyzer : public Analyzer2 14 | { 15 | public: 16 | USBAnalyzer(); 17 | virtual ~USBAnalyzer(); 18 | virtual void WorkerThread(); 19 | 20 | virtual U32 GenerateSimulationData( U64 newest_sample_requested, U32 sample_rate, SimulationChannelDescriptor** simulation_channels ); 21 | virtual U32 GetMinimumSampleRateHz(); 22 | 23 | virtual const char* GetAnalyzerName() const; 24 | virtual bool NeedsRerun(); 25 | 26 | std::string GetTimeStr( U64 sample ) 27 | { 28 | char time_str[ 128 ]; 29 | AnalyzerHelpers::GetTimeString( sample, GetTriggerSample(), GetSampleRate(), time_str, sizeof( time_str ) ); 30 | 31 | return time_str; 32 | } 33 | 34 | protected: // functions 35 | virtual void SetupResults(); 36 | 37 | struct USBPipe 38 | { 39 | int addr; 40 | int endp; 41 | 42 | USBPipe() 43 | { 44 | Clear(); 45 | } 46 | 47 | void Clear() 48 | { 49 | addr = endp = 0; 50 | } 51 | 52 | bool operator<( const USBPipe& rhs ) const 53 | { 54 | if( addr == rhs.addr ) 55 | return endp < rhs.endp; 56 | 57 | return addr < rhs.addr; 58 | } 59 | }; 60 | 61 | // address to packet handler 62 | typedef std::map USBPipeHandler; 63 | 64 | USBPipeHandler mCtrlTransPacketHandlers; 65 | USBPipe mCtrlTransLastPipe; 66 | 67 | U64 SendPacketToHandler( USBPacket& pckt ); 68 | 69 | void ResetUSB() 70 | { 71 | mCtrlTransPacketHandlers.clear(); 72 | mCtrlTransLastPipe.Clear(); 73 | } 74 | 75 | protected: // vars 76 | USBAnalyzerSettings mSettings; 77 | std::auto_ptr mResults; 78 | 79 | AnalyzerChannelData* mDP; 80 | AnalyzerChannelData* mDM; 81 | 82 | USBSimulationDataGenerator mSimulationDataGenerator; 83 | 84 | bool mSimulationInitilized; 85 | }; 86 | 87 | extern "C" ANALYZER_EXPORT const char* __cdecl GetAnalyzerName(); 88 | extern "C" ANALYZER_EXPORT Analyzer* __cdecl CreateAnalyzer(); 89 | extern "C" ANALYZER_EXPORT void __cdecl DestroyAnalyzer( Analyzer* analyzer ); 90 | 91 | #endif // USB_ANALYZER_H -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Saleae USB Analyzer 2 | 3 | Saleae USB Analyzer 4 | 5 | ## Getting Started 6 | 7 | The following documentation describes how to build this analyzer locally. For more detailed information about the Analyzer SDK, debugging, CI builds, and more, check out the readme in the Sample Analyzer repository. 8 | 9 | https://github.com/saleae/SampleAnalyzer 10 | 11 | ### MacOS 12 | 13 | Dependencies: 14 | 15 | - XCode with command line tools 16 | - CMake 3.13+ 17 | - git 18 | 19 | Install command line tools after XCode is installed: 20 | 21 | ``` 22 | xcode-select --install 23 | ``` 24 | 25 | Then open XCode, open Preferences from the main menu, go to locations, and select the only option under 'Command line tools'. 26 | 27 | Install CMake on MacOS: 28 | 29 | 1. Download the binary distribution for MacOS, `cmake-*-Darwin-x86_64.dmg` 30 | 2. Install the usual way by dragging into applications. 31 | 3. Open a terminal and run the following: 32 | 33 | ``` 34 | /Applications/CMake.app/Contents/bin/cmake-gui --install 35 | ``` 36 | 37 | _Note: Errors may occur if older versions of CMake are installed._ 38 | 39 | Build the analyzer: 40 | 41 | ``` 42 | mkdir build 43 | cd build 44 | cmake .. 45 | cmake --build . 46 | ``` 47 | 48 | ### Ubuntu 18.04+ 49 | 50 | Dependencies: 51 | 52 | - CMake 3.13+ 53 | - gcc 4.8+ 54 | - git 55 | 56 | Misc dependencies: 57 | 58 | ``` 59 | sudo apt-get install build-essential 60 | ``` 61 | 62 | Build the analyzer: 63 | 64 | ``` 65 | mkdir build 66 | cd build 67 | cmake .. 68 | cmake --build . 69 | ``` 70 | 71 | ### Windows 72 | 73 | Dependencies: 74 | 75 | - Visual Studio 2019 76 | - CMake 3.13+ 77 | - git 78 | 79 | **Visual Studio 2019** 80 | 81 | _Note - newer and older versions of Visual Studio are likely to work._ 82 | 83 | Setup options: 84 | 85 | - Workloads > Desktop & Mobile > "Desktop development with C++" 86 | 87 | Note - if CMake has any problems with the MSVC compiler, it's likely a component is missing. 88 | 89 | **CMake** 90 | 91 | Download and install the latest CMake release here. 92 | https://cmake.org/download/ 93 | 94 | **git** 95 | 96 | Download and install git here. 97 | https://git-scm.com/ 98 | 99 | Build the analyzer: 100 | 101 | ``` 102 | mkdir build 103 | cd build 104 | cmake .. -A x64 105 | ``` 106 | 107 | Then, open the newly created solution file located here: `build\usb_analyzer.sln` 108 | 109 | Optionally, build from the command line without opening Visual Studio: 110 | 111 | ``` 112 | cmake --build . 113 | ``` 114 | 115 | The built analyzer DLLs will be located here: 116 | 117 | `build\Analyzers\Debug` 118 | 119 | `build\Analyzers\Release` 120 | 121 | For debug and release builds, respectively. 122 | 123 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | tags: 7 | - '*' 8 | pull_request: 9 | branches: [master] 10 | 11 | jobs: 12 | windows: 13 | runs-on: windows-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Build 17 | run: | 18 | cmake -B ${{github.workspace}}/build -A x64 19 | cmake --build ${{github.workspace}}/build --config Release 20 | - name: Upload windows build 21 | uses: actions/upload-artifact@v4 22 | with: 23 | name: windows 24 | path: ${{github.workspace}}/build/Analyzers/Release/*.dll 25 | macos: 26 | runs-on: macos-latest 27 | steps: 28 | - uses: actions/checkout@v4 29 | - name: Build 30 | run: | 31 | cmake -B ${{github.workspace}}/build/x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=x86_64 32 | cmake --build ${{github.workspace}}/build/x86_64 33 | cmake -B ${{github.workspace}}/build/arm64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=arm64 34 | cmake --build ${{github.workspace}}/build/arm64 35 | - name: Upload MacOS x86_64 build 36 | uses: actions/upload-artifact@v4 37 | with: 38 | name: macos_x86_64 39 | path: ${{github.workspace}}/build/x86_64/Analyzers/*.so 40 | - name: Upload MacOS arm64 build 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: macos_arm64 44 | path: ${{github.workspace}}/build/arm64/Analyzers/*.so 45 | linux: 46 | runs-on: ubuntu-latest 47 | steps: 48 | - uses: actions/checkout@v4 49 | - name: Pull pre-built builder image 50 | run: docker pull ghcr.io/saleae/analyzer-build-image:latest 51 | - name: Build inside container 52 | run: | 53 | docker run --rm \ 54 | -v ${{ github.workspace }}:/app \ 55 | -w /app \ 56 | ghcr.io/saleae/analyzer-build-image:latest \ 57 | bash -c 'cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build' 58 | - name: Upload Linux build 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: linux 62 | path: ${{github.workspace}}/build/Analyzers/*.so 63 | publish: 64 | needs: [windows, macos, linux] 65 | runs-on: ubuntu-latest 66 | steps: 67 | - name: download individual builds 68 | uses: actions/download-artifact@v4 69 | with: 70 | path: ${{github.workspace}}/artifacts 71 | - name: zip 72 | run: | 73 | cd ${{github.workspace}}/artifacts 74 | zip -r ${{github.workspace}}/analyzer.zip . 75 | - uses: actions/upload-artifact@v4 76 | with: 77 | name: all-platforms 78 | path: ${{github.workspace}}/artifacts/** 79 | - name: create release 80 | uses: softprops/action-gh-release@v1 81 | if: startsWith(github.ref, 'refs/tags/') 82 | with: 83 | files: ${{github.workspace}}/analyzer.zip -------------------------------------------------------------------------------- /src/USBAnalyzerSettings.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "USBAnalyzerSettings.h" 4 | #include "USBAnalyzerResults.h" 5 | #include "USBTypes.h" 6 | 7 | USBAnalyzerSettings::USBAnalyzerSettings() 8 | : mDMChannel( UNDEFINED_CHANNEL ), mDPChannel( UNDEFINED_CHANNEL ), mSpeed( LOW_SPEED ), mDecodeLevel( OUT_CONTROL_TRANSFERS ) 9 | { 10 | // init the interface 11 | mDPChannelInterface.SetTitleAndTooltip( "D+", "USB D+ (green)" ); 12 | mDPChannelInterface.SetChannel( mDPChannel ); 13 | 14 | mDMChannelInterface.SetTitleAndTooltip( "D-", "USB D- (white)" ); 15 | mDMChannelInterface.SetChannel( mDMChannel ); 16 | 17 | mSpeedInterface.SetTitleAndTooltip( "USB bit-rate", "USB data bit-rate" ); 18 | mSpeedInterface.AddNumber( LOW_SPEED, "Low speed (1.5 Mbps)", "Low speed (1.5 mbit/s)" ); 19 | mSpeedInterface.AddNumber( FULL_SPEED, "Full speed (12 Mbps)", "Full speed (12 mbit/s)" ); 20 | 21 | mSpeedInterface.SetNumber( mSpeed ); 22 | 23 | mDecodeLevelInterface.SetTitleAndTooltip( "USB decode level", "Type of decoded USB output" ); 24 | mDecodeLevelInterface.AddNumber( OUT_CONTROL_TRANSFERS, "Control transfers", "Decodes the standard USB enpoint 0 control transfers." ); 25 | mDecodeLevelInterface.AddNumber( OUT_PACKETS, "Packets", "Decode all the fields of USB packets" ); 26 | mDecodeLevelInterface.AddNumber( OUT_BYTES, "Bytes", "Decode the data as raw bytes" ); 27 | mDecodeLevelInterface.AddNumber( OUT_SIGNALS, "Signals", "Decode the USB signal states: J, K and SE0" ); 28 | 29 | mDecodeLevelInterface.SetNumber( OUT_CONTROL_TRANSFERS ); 30 | 31 | // add the interface 32 | AddInterface( &mDPChannelInterface ); 33 | AddInterface( &mDMChannelInterface ); 34 | AddInterface( &mSpeedInterface ); 35 | AddInterface( &mDecodeLevelInterface ); 36 | 37 | // describe export 38 | AddExportOption( 0, "Export as text file" ); 39 | AddExportExtension( 0, "text", "txt" ); 40 | 41 | ClearChannels(); 42 | 43 | AddChannel( mDPChannel, "D+", false ); 44 | AddChannel( mDMChannel, "D-", false ); 45 | } 46 | 47 | USBAnalyzerSettings::~USBAnalyzerSettings() 48 | { 49 | } 50 | 51 | bool USBAnalyzerSettings::SetSettingsFromInterfaces() 52 | { 53 | if( mDPChannelInterface.GetChannel() == UNDEFINED_CHANNEL ) 54 | { 55 | SetErrorText( "Please select an input for the D+ channel." ); 56 | return false; 57 | } 58 | 59 | if( mDMChannelInterface.GetChannel() == UNDEFINED_CHANNEL ) 60 | { 61 | SetErrorText( "Please select an input for the D- channel." ); 62 | return false; 63 | } 64 | 65 | mDPChannel = mDPChannelInterface.GetChannel(); 66 | mDMChannel = mDMChannelInterface.GetChannel(); 67 | mSpeed = USBSpeed( int( mSpeedInterface.GetNumber() ) ); 68 | mDecodeLevel = USBDecodeLevel( int( mDecodeLevelInterface.GetNumber() ) ); 69 | 70 | if( mDMChannel == mDPChannel ) 71 | { 72 | SetErrorText( "Please select different inputs for the D- and D+ channels." ); 73 | return false; 74 | } 75 | 76 | ClearChannels(); 77 | 78 | AddChannel( mDPChannel, "D+", true ); 79 | AddChannel( mDMChannel, "D-", true ); 80 | 81 | return true; 82 | } 83 | 84 | void USBAnalyzerSettings::UpdateInterfacesFromSettings() 85 | { 86 | mDPChannelInterface.SetChannel( mDPChannel ); 87 | mDMChannelInterface.SetChannel( mDMChannel ); 88 | mSpeedInterface.SetNumber( mSpeed ); 89 | mDecodeLevelInterface.SetNumber( mDecodeLevel ); 90 | } 91 | 92 | void USBAnalyzerSettings::LoadSettings( const char* settings ) 93 | { 94 | SimpleArchive text_archive; 95 | text_archive.SetString( settings ); 96 | 97 | text_archive >> mDPChannel; 98 | text_archive >> mDMChannel; 99 | int s; 100 | text_archive >> s; 101 | mSpeed = USBSpeed( s ); 102 | 103 | text_archive >> s; 104 | mDecodeLevel = USBDecodeLevel( s ); 105 | 106 | ClearChannels(); 107 | 108 | AddChannel( mDPChannel, "D+", true ); 109 | AddChannel( mDMChannel, "D-", true ); 110 | 111 | UpdateInterfacesFromSettings(); 112 | } 113 | 114 | const char* USBAnalyzerSettings::SaveSettings() 115 | { 116 | SimpleArchive text_archive; 117 | 118 | text_archive << mDPChannel; 119 | text_archive << mDMChannel; 120 | text_archive << mSpeed; 121 | text_archive << mDecodeLevel; 122 | 123 | return SetReturnString( text_archive.GetString() ); 124 | } 125 | -------------------------------------------------------------------------------- /src/USBAnalyzer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "USBAnalyzer.h" 7 | #include "USBAnalyzerSettings.h" 8 | 9 | USBAnalyzer::USBAnalyzer() : mSimulationInitilized( false ) 10 | { 11 | SetAnalyzerSettings( &mSettings ); 12 | } 13 | 14 | USBAnalyzer::~USBAnalyzer() 15 | { 16 | KillThread(); 17 | } 18 | 19 | void USBAnalyzer::SetupResults() 20 | { 21 | // reset the results 22 | mResults.reset( new USBAnalyzerResults( this, &mSettings ) ); 23 | SetAnalyzerResults( mResults.get() ); 24 | 25 | // set which channels will carry bubbles 26 | mResults->AddChannelBubblesWillAppearOn( mSettings.mDPChannel ); 27 | mResults->AddChannelBubblesWillAppearOn( mSettings.mDMChannel ); 28 | } 29 | 30 | bool FrameLessThan( const Frame& lhs, const Frame& rhs ) 31 | { 32 | return lhs.mStartingSampleInclusive < rhs.mStartingSampleInclusive; 33 | } 34 | 35 | U64 USBAnalyzer::SendPacketToHandler( USBPacket& pckt ) 36 | { 37 | if( pckt.IsTokenPacket() ) 38 | { 39 | mCtrlTransLastPipe.addr = pckt.GetAddress(); 40 | mCtrlTransLastPipe.endp = pckt.GetEndpoint(); 41 | } 42 | 43 | // only control transfers and no SOF or PRE packets 44 | if( mCtrlTransLastPipe.endp == 0 && pckt.mPID != PID_SOF && pckt.mPID != PID_PRE ) 45 | { 46 | // do we have this address/enpoint already? 47 | USBPipeHandler::iterator srch( mCtrlTransPacketHandlers.find( mCtrlTransLastPipe ) ); 48 | 49 | // is this a new address? 50 | if( srch == mCtrlTransPacketHandlers.end() ) 51 | { 52 | srch = mCtrlTransPacketHandlers.insert( std::make_pair( mCtrlTransLastPipe, USBControlTransferPacketHandler() ) ).first; 53 | srch->second.Init( mResults.get(), mCtrlTransLastPipe.addr ); 54 | } 55 | 56 | return srch->second.HandleControlTransfer( pckt ); 57 | } 58 | 59 | return pckt.AddPacketFrames( mResults.get() ); 60 | } 61 | 62 | void USBAnalyzer::WorkerThread() 63 | { 64 | // get the channel pointers 65 | mDP = GetAnalyzerChannelData( mSettings.mDPChannel ); 66 | mDM = GetAnalyzerChannelData( mSettings.mDMChannel ); 67 | 68 | USBSignalFilter sf( this, mResults.get(), &mSettings, mDP, mDM, mSettings.mSpeed ); 69 | 70 | const double BIT_DUR = mSettings.mSpeed == FULL_SPEED ? FS_BIT_DUR : LS_BIT_DUR; 71 | const double SAMPLE_DUR = 1e9 / GetSampleRate(); // 1 sample duration in ns 72 | const double BIT_SAMPLES = BIT_DUR / SAMPLE_DUR; 73 | 74 | ResetUSB(); 75 | 76 | USBSignalState s; 77 | USBPacket pckt; 78 | U64 lastFrameEnd = 0; 79 | while( sf.HasMoreData() ) 80 | { 81 | s = sf.GetState(); 82 | 83 | if( mSettings.mDecodeLevel == OUT_SIGNALS ) 84 | { 85 | s.AddFrame( mResults.get() ); 86 | } 87 | else 88 | { 89 | if( lastFrameEnd == 0 ) 90 | lastFrameEnd = s.mSampleBegin; 91 | 92 | // if this is a data signal 93 | if( sf.IsDataSignal( s ) ) 94 | { 95 | // try reading an entire USB packet by parsing subsequent data signals 96 | if( sf.GetPacket( pckt, s ) ) 97 | { 98 | if( mSettings.mDecodeLevel == OUT_CONTROL_TRANSFERS ) 99 | lastFrameEnd = SendPacketToHandler( pckt ); 100 | else if( mSettings.mDecodeLevel == OUT_PACKETS ) 101 | lastFrameEnd = pckt.AddPacketFrames( mResults.get() ); 102 | else if( mSettings.mDecodeLevel == OUT_BYTES ) 103 | lastFrameEnd = pckt.AddRawByteFrames( mResults.get() ); 104 | } 105 | else 106 | { 107 | lastFrameEnd = pckt.AddErrorFrame( mResults.get() ); 108 | } 109 | } 110 | else if( mSettings.mSpeed == LOW_SPEED // is this a LS Keep-alive? 111 | && s.mState == S_SE0 && s.GetNumBits( LOW_SPEED ) == 2 ) 112 | { 113 | Frame f; 114 | f.mStartingSampleInclusive = lastFrameEnd; 115 | f.mEndingSampleInclusive = s.mSampleEnd; 116 | f.mType = FT_KeepAlive; 117 | f.mFlags = FF_None; 118 | f.mData1 = f.mData2 = 0; 119 | 120 | mResults->AddFrame( f ); 121 | mResults->CommitResults(); 122 | 123 | lastFrameEnd = s.mSampleEnd; 124 | } 125 | else if( s.mState == S_SE0 && s.mDur > 1e7 ) 126 | { // Reset? dur > 10 ms 127 | 128 | Frame f; 129 | f.mStartingSampleInclusive = lastFrameEnd; 130 | f.mEndingSampleInclusive = s.mSampleEnd; 131 | f.mType = FT_Reset; 132 | f.mFlags = FF_None; 133 | f.mData1 = f.mData2 = 0; 134 | 135 | mResults->AddFrame( f ); 136 | mResults->CommitResults(); 137 | 138 | lastFrameEnd = s.mSampleEnd; 139 | 140 | ResetUSB(); 141 | } 142 | else if( s.mState == S_J ) 143 | { // Idle 144 | 145 | lastFrameEnd = s.mSampleEnd; 146 | } 147 | } 148 | 149 | ReportProgress( s.mSampleEnd ); 150 | CheckIfThreadShouldExit(); 151 | } 152 | } 153 | 154 | bool USBAnalyzer::NeedsRerun() 155 | { 156 | return false; 157 | } 158 | 159 | U32 USBAnalyzer::GenerateSimulationData( U64 minimum_sample_index, U32 device_sample_rate, 160 | SimulationChannelDescriptor** simulation_channels ) 161 | { 162 | if( !mSimulationInitilized ) 163 | { 164 | mSimulationDataGenerator.Initialize( GetSimulationSampleRate(), &mSettings ); 165 | mSimulationInitilized = true; 166 | } 167 | 168 | return mSimulationDataGenerator.GenerateSimulationData( minimum_sample_index, device_sample_rate, simulation_channels ); 169 | } 170 | 171 | U32 USBAnalyzer::GetMinimumSampleRateHz() 172 | { 173 | return 24000000; // full 24MHz 174 | } 175 | 176 | const char* USBAnalyzer::GetAnalyzerName() const 177 | { 178 | return ::GetAnalyzerName(); 179 | } 180 | 181 | const char* GetAnalyzerName() 182 | { 183 | return "USB LS and FS"; 184 | } 185 | 186 | Analyzer* CreateAnalyzer() 187 | { 188 | return new USBAnalyzer(); 189 | } 190 | 191 | void DestroyAnalyzer( Analyzer* analyzer ) 192 | { 193 | delete analyzer; 194 | } 195 | -------------------------------------------------------------------------------- /src/USBTypes.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_TYPES_H 2 | #define USB_TYPES_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "USBEnums.h" 13 | 14 | class USBAnalyzerResults; 15 | class USBControlTransferParser; 16 | 17 | struct USBPacket 18 | { 19 | U64 mSampleBegin; 20 | U64 mSampleEnd; 21 | 22 | // data member contains all the data in the packet starting from the SYNC field all the way to the CRC 23 | // so: 24 | // data[0] SYNC 25 | // data[1] PID 26 | // data[2..n-3] payload (for packets > 4 bytes) 27 | // data[n-2..n-1] CRC (for packets > 4 bytes) 28 | // data[2..3] address, endpoint and CRC (for packets == 4 bytes) 29 | std::vector mData; 30 | 31 | // sample number of the individual bits 32 | // the last element if this vector will hold the ending sample of the last data bit 33 | // this means the number of elements in the vector will be == num_bytes*8 + 1 34 | std::vector mBitBeginSamples; 35 | 36 | USB_PID mPID; 37 | U16 mCRC; // used for both 16 and 5 bit CRC values 38 | 39 | void Clear(); 40 | 41 | U16 GetLastWord() const 42 | { 43 | return ( mData.back() << 8 ) | *( mData.end() - 2 ); 44 | } 45 | 46 | U8 GetAddress() const 47 | { 48 | return mData[ 2 ] & 0x7F; 49 | } 50 | 51 | U8 GetEndpoint() const 52 | { 53 | return ( GetLastWord() >> 7 ) & 0xf; 54 | } 55 | 56 | U16 GetFrameNum() const 57 | { 58 | return GetLastWord() & 0x7ff; 59 | } 60 | 61 | bool IsTokenPacket() const 62 | { 63 | return mPID == PID_IN || mPID == PID_OUT || mPID == PID_SETUP; 64 | } 65 | 66 | bool IsSOFPacket() const 67 | { 68 | return mPID == PID_SOF; 69 | } 70 | 71 | bool IsDataPacket() const 72 | { 73 | return mPID == PID_DATA0 || mPID == PID_DATA1; 74 | } 75 | 76 | bool IsHandshakePacket() const 77 | { 78 | return mPID == PID_ACK || mPID == PID_NAK || mPID == PID_STALL; 79 | } 80 | 81 | bool IsPIDValid() const; 82 | 83 | static U8 CalcCRC5( U16 data ); 84 | U16 CalcCRC16() const; 85 | 86 | void AddSyncAndPidFrames( USBAnalyzerResults* pResults, USBFrameFlags flagPID = FF_None ); 87 | void AddEOPFrame( USBAnalyzerResults* pResults ); 88 | void AddCRC16Frame( USBAnalyzerResults* pResults ); 89 | 90 | U64 AddPacketFrames( USBAnalyzerResults* pResults, USBFrameFlags flagPID = FF_None ); 91 | U64 AddRawByteFrames( USBAnalyzerResults* pResults ); 92 | U64 AddErrorFrame( USBAnalyzerResults* pResults ); 93 | 94 | // control transfer decoders 95 | // these are defined in USBControlTransfer.cpp 96 | U64 AddSetupPacketFrame( USBAnalyzerResults* pResults, USBControlTransferParser& parser, U8 address ); 97 | void AddStandardSetupPacketFrame( USBAnalyzerResults* pResults, USBControlTransferParser& parser, U8 address ); 98 | void AddClassSetupPacketFrame( USBAnalyzerResults* pResults, USBControlTransferParser& parser, U8 address ); 99 | void AddVendorSetupPacketFrame( USBAnalyzerResults* pResults, USBControlTransferParser& parser, U8 address ); 100 | U64 AddDataStageFrames( USBAnalyzerResults* pResults, USBControlTransferParser& parser, U8 address ); 101 | 102 | Frame GetDataPayloadField( int ndx, int bcnt, U8 address, const char* name, USBCtrlTransFieldType fldHandler = Fld_None, 103 | U8 flags = 0 ) const; 104 | U32 GetDataPayload( int ndx, int bcnt ) const; 105 | 106 | Frame GetHIDItem( int offset, int bcnt, U8* pItem, U16 indentLevel, U16 usagePage, U8 flags ) const; 107 | }; 108 | 109 | const double FS_BIT_DUR = ( 1000 / 12.0 ); // 83.3 ns 110 | const double LS_BIT_DUR = ( 1000 / 1.5 ); // 666.7 ns 111 | 112 | struct USBSignalState 113 | { 114 | U64 mSampleBegin; 115 | U64 mSampleEnd; 116 | 117 | USBState mState; 118 | double mDur; // in nano sec 119 | 120 | bool IsDurationFS() const 121 | { 122 | return mDur > FS_BIT_DUR * .3 && mDur < FS_BIT_DUR * 7.5; 123 | } 124 | 125 | bool IsDurationLS() const 126 | { 127 | return mDur > LS_BIT_DUR * .7 && mDur < LS_BIT_DUR * 7.3; 128 | } 129 | 130 | bool IsData( const USBSpeed speed ) const 131 | { 132 | return ( speed == LOW_SPEED ? IsDurationLS() : IsDurationFS() ) && ( mState == S_J || mState == S_K ); 133 | } 134 | 135 | int GetNumBits( USBSpeed speed ) const 136 | { 137 | const double BIT_DUR = ( speed == FULL_SPEED ? FS_BIT_DUR : LS_BIT_DUR ); 138 | return int( mDur / BIT_DUR + 0.5 ); 139 | } 140 | 141 | void AddFrame( USBAnalyzerResults* res ); 142 | }; 143 | 144 | class USBAnalyzer; 145 | class USBAnalyzerResults; 146 | class USBAnalyzerSettings; 147 | 148 | class USBSignalFilter 149 | { 150 | private: 151 | AnalyzerChannelData* mDP; 152 | AnalyzerChannelData* mDM; 153 | 154 | USBAnalyzer* mAnalyzer; 155 | USBAnalyzerResults* mResults; 156 | USBAnalyzerSettings* mSettings; 157 | 158 | USBSpeed mSpeed; // LS or FS 159 | bool mExpectLowSpeed; // this is set to true after a PRE packet 160 | const double mSampleDur; // in ns 161 | U64 mStateStartSample; // used for filtered signal state start between calls 162 | 163 | bool SkipNoise( AnalyzerChannelData* pNearer, AnalyzerChannelData* pFurther ); 164 | U64 DoFilter( AnalyzerChannelData* mDP, AnalyzerChannelData* mDM ); 165 | 166 | public: 167 | USBSignalFilter( USBAnalyzer* pAnalyzer, USBAnalyzerResults* pResults, USBAnalyzerSettings* pSettings, AnalyzerChannelData* pDP, 168 | AnalyzerChannelData* pDM, USBSpeed speed ); 169 | 170 | bool HasMoreData(); 171 | USBSignalState GetState(); 172 | bool IsDataSignal( const USBSignalState& s ); 173 | bool GetPacket( USBPacket& pckt, USBSignalState& sgnl ); 174 | USBSpeed GetCurrSpeed() const 175 | { 176 | return mSpeed; 177 | } 178 | }; 179 | 180 | std::string int2str_sal( const U64 i, DisplayBase base, const int max_bits = 8 ); 181 | 182 | inline std::string int2str( const U64 i ) 183 | { 184 | return int2str_sal( i, Decimal, 64 ); 185 | } 186 | 187 | /* 188 | #ifdef _WINDOWS 189 | # include 190 | #endif 191 | 192 | // debugging helper functions -- Windows only!!! 193 | inline void debug(const std::string& str) 194 | { 195 | #if !defined(NDEBUG) && defined(_WINDOWS) 196 | ::OutputDebugStringA(("----- " + str + "\n").c_str()); 197 | #endif 198 | } 199 | 200 | inline void debug(const char* str) 201 | { 202 | #if !defined(NDEBUG) && defined(_WINDOWS) 203 | debug(std::string(str)); 204 | #endif 205 | } 206 | */ 207 | 208 | #endif // USB_TYPES_H -------------------------------------------------------------------------------- /src/USBEnums.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_ENUMS_H 2 | #define USB_ENUMS_H 3 | 4 | enum USBFrameTypes // analyzer frames, NOT USB 1ms frame 5 | { 6 | FT_Signal, // low-level signals: J, K, SE0 or SE1 7 | 8 | FT_SYNC, // USB Sync field 9 | FT_PID, // USB PID 10 | FT_FrameNum, // SOF's frame number field 11 | FT_AddrEndp, // address & endpoint 12 | FT_EOP, // USB End Of Packet 13 | FT_Reset, // USB reset 14 | FT_CRC5, 15 | FT_CRC16, 16 | FT_Idle, 17 | FT_KeepAlive, // Low speed keep alive signals 18 | 19 | FT_Byte, // used in Bytes decode mode and for data payload of packets 20 | 21 | FT_Error, // invalid packet 22 | 23 | FT_ControlTransferField, 24 | FT_HIDReportDescriptorItem, 25 | }; 26 | 27 | // these are used by the exporter to help with formatting 28 | // since we only have 6 bits available in the mFlags member, and we need more 29 | // we don't actually use these ase bit flags but as distinct values/codes 30 | enum USBFrameFlags 31 | { 32 | FF_None, 33 | 34 | FF_FieldIncomplete, // descriptor field or HID report item which spans two packets 35 | 36 | FF_SetupBegin, 37 | 38 | FF_DataBegin, 39 | FF_DataDescriptor, 40 | FF_DataInNAKed, 41 | FF_DataOutNAKed, 42 | FF_DataEnd, 43 | 44 | FF_StatusBegin, 45 | FF_StatusOutNAKed, 46 | FF_StatusInNAKed, 47 | FF_StatusEnd, 48 | 49 | FF_UnexpectedPacket, 50 | }; 51 | 52 | // valid USB low and full speed PIDs 53 | // PIDs used on high speed connection are commented out 54 | enum USB_PID 55 | { 56 | PID_Unknown = 0x00, 57 | 58 | PID_IN = 0x69, 59 | PID_OUT = 0xE1, 60 | PID_SOF = 0xA5, 61 | PID_SETUP = 0x2D, 62 | 63 | PID_DATA0 = 0xC3, 64 | PID_DATA1 = 0x4B, 65 | // PID_DATA2 = 0x87, 66 | // PID_MDATA = 0x0F, 67 | 68 | PID_ACK = 0xD2, 69 | PID_NAK = 0x5A, 70 | PID_STALL = 0x1E, 71 | // PID_NYET = 0x96, 72 | 73 | PID_PRE = 0x3C, 74 | // PID_ERR = 0x3C, 75 | // PID_SPLIT = 0x78, 76 | // PID_PING = 0xB4, 77 | }; 78 | 79 | enum USBRequestCode 80 | { 81 | GET_STATUS = 0x00, 82 | CLEAR_FEATURE = 0x01, 83 | SET_FEATURE = 0x03, 84 | SET_ADDRESS = 0x05, 85 | GET_DESCRIPTOR = 0x06, 86 | SET_DESCRIPTOR = 0x07, 87 | GET_CONFIGURATION = 0x08, 88 | SET_CONFIGURATION = 0x09, 89 | GET_INTERFACE = 0x0A, 90 | SET_INTERFACE = 0x11, 91 | SYNCH_FRAME = 0x12, 92 | }; 93 | 94 | enum USBHIDRequestCode 95 | { 96 | GET_REPORT = 0x01, 97 | GET_IDLE = 0x02, 98 | GET_PROTOCOL = 0x03, 99 | SET_REPORT = 0x09, 100 | SET_IDLE = 0x0A, 101 | SET_PROTOCOL = 0x0B, 102 | }; 103 | 104 | enum USBCDCRequestCode 105 | { 106 | SEND_ENCAPSULATED_COMMAND = 0x00, 107 | GET_ENCAPSULATED_RESPONSE = 0x01, 108 | SET_COMM_FEATURE = 0x02, 109 | GET_COMM_FEATURE = 0x03, 110 | CLEAR_COMM_FEATURE = 0x04, 111 | SET_AUX_LINE_STATE = 0x10, 112 | SET_HOOK_STATE = 0x11, 113 | PULSE_SETUP = 0x12, 114 | SEND_PULSE = 0x13, 115 | SET_PULSE_TIME = 0x14, 116 | RING_AUX_JACK = 0x15, 117 | SET_LINE_CODING = 0x20, 118 | GET_LINE_CODING = 0x21, 119 | SET_CONTROL_LINE_STATE = 0x22, 120 | SEND_BREAK = 0x23, 121 | SET_RINGER_PARMS = 0x30, 122 | GET_RINGER_PARMS = 0x31, 123 | SET_OPERATION_PARMS = 0x32, 124 | GET_OPERATION_PARMS = 0x33, 125 | SET_LINE_PARMS = 0x34, 126 | GET_LINE_PARMS = 0x35, 127 | DIAL_DIGITS = 0x36, 128 | SET_UNIT_PARAMETER = 0x37, 129 | GET_UNIT_PARAMETER = 0x38, 130 | CLEAR_UNIT_PARAMETER = 0x39, 131 | GET_PROFILE = 0x3A, 132 | SET_ETHERNET_MULTICAST_FILTERS = 0x40, 133 | SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x41, 134 | GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER = 0x42, 135 | SET_ETHERNET_PACKET_FILTER = 0x43, 136 | GET_ETHERNET_STATISTIC = 0x44, 137 | SET_ATM_DATA_FORMAT = 0x50, 138 | GET_ATM_DEVICE_STATISTICS = 0x51, 139 | SET_ATM_DEFAULT_VC = 0x52, 140 | GET_ATM_VC_STATISTICS = 0x53, 141 | }; 142 | 143 | enum USBDescriptorType 144 | { 145 | DT_Undefined = 0x00, 146 | 147 | // standard 148 | DT_DEVICE = 0x01, 149 | DT_CONFIGURATION = 0x02, 150 | DT_STRING = 0x03, 151 | DT_INTERFACE = 0x04, 152 | DT_ENDPOINT = 0x05, 153 | DT_DEVICE_QUALIFIER = 0x06, 154 | DT_OTHER_SPEED_CONFIGURATION = 0x07, 155 | DT_INTERFACE_POWER = 0x08, 156 | 157 | // HID 158 | DT_HID = 0x21, 159 | DT_HID_REPORT = 0x22, 160 | DT_HID_PHYS = 0x23, 161 | 162 | // CDC 163 | DT_CDC_CS_INTERFACE = 0x24, 164 | DT_CDC_CS_ENDPOINT = 0x25, 165 | }; 166 | 167 | enum USBCDCDescriptorSubtype 168 | { 169 | DST_HEADER = 0x00, 170 | DST_CALL_MANAGEMENT, 171 | DST_ABSTRACT_CONTROL_MANAGEMENT, 172 | DST_DIRECT_LINE_MANAGEMENT, 173 | DST_TELEPHONE_RINGER, 174 | DST_TELEPHONE_CALL_AND_LINE_STATE, 175 | DST_UNION, 176 | DST_COUNTRY_SELECTION, 177 | DST_TELEPHONE_OPERATIONAL_MODES, 178 | DST_USB_TERMINAL, 179 | DST_NETWORK_CHANNEL_TERMINAL, 180 | DST_PROTOCOL_UNIT, 181 | DST_EXTENSION_UNIT, 182 | DST_MULTI_CHANNEL_MANAGEMENT, 183 | DST_CAPI_CONTROL_MANAGEMENT, 184 | DST_ETHERNET_NETWORKING, 185 | DST_ATM_NETWORKING, 186 | 187 | DST_Undefined = 0xff, 188 | }; 189 | 190 | enum USBCtrlTransFieldType 191 | { 192 | Fld_None, 193 | 194 | Fld_bmRequestType, 195 | Fld_bmRequestType_NoData, 196 | Fld_bRequest_Standard, 197 | Fld_bRequest_HID, 198 | Fld_bRequest_CDC, 199 | Fld_bRequest_Class, 200 | Fld_bRequest_Vendor, 201 | Fld_wValue_Descriptor, 202 | Fld_wValue_Address, 203 | Fld_wValue_HIDGetIdle, 204 | Fld_wValue_HIDSetIdle, 205 | Fld_wValue_HIDSetProtocol, 206 | Fld_wValue_HIDGetSetReport, 207 | Fld_HID_bCountryCode, 208 | Fld_bDescriptorType, 209 | Fld_bDescriptorType_Other, 210 | Fld_bMaxPower, 211 | Fld_wLANGID, 212 | Fld_wIndex_InterfaceNum, 213 | Fld_wIndex_Endpoint, 214 | Fld_wVendorId, 215 | Fld_bmAttributes_Endpoint, 216 | Fld_bmAttributes_Config, 217 | Fld_bEndpointAddress, 218 | Fld_BCD, 219 | Fld_ClassCode, 220 | Fld_Wchar, 221 | Fld_String, 222 | Fld_HIDSubClass, 223 | Fld_HIDProtocol, 224 | 225 | Fld_CDC_DescriptorSubtype, 226 | Fld_CDC_bmCapabilities_Call, 227 | Fld_CDC_bmCapabilities_AbstractCtrl, 228 | Fld_CDC_bmCapabilities_DataLine, 229 | Fld_CDC_bRingerVolSteps, 230 | Fld_CDC_bmCapabilities_TelOpModes, 231 | Fld_CDC_bmCapabilities_TelCallStateRep, 232 | Fld_CDC_bmOptions, 233 | Fld_CDC_bPhysicalInterface, 234 | Fld_CDC_bProtocol, 235 | Fld_CDC_bmCapabilities_MultiChannel, 236 | Fld_CDC_bmCapabilities_CAPIControl, 237 | Fld_CDC_bmEthernetStatistics, 238 | Fld_CDC_wNumberMCFilters, 239 | Fld_CDC_bmDataCapabilities, 240 | Fld_CDC_bmATMDeviceStatistics, 241 | 242 | Fld_CDC_Data_AbstractState, 243 | Fld_CDC_Data_CountrySetting, 244 | 245 | Fld_CDC_dwDTERate, 246 | Fld_CDC_bCharFormat, 247 | Fld_CDC_bParityType, 248 | Fld_CDC_bDataBits, 249 | 250 | Fld_CDC_dwRingerBitmap, 251 | Fld_CDC_OperationMode, 252 | Fld_CDC_dwLineState, 253 | Fld_CDC_dwCallState, 254 | 255 | Fld_CDC_wValue_CommFeatureSelector, 256 | Fld_CDC_wValue_DisconnectConnect, 257 | Fld_CDC_wValue_RelayConfig, 258 | Fld_CDC_wValue_EnableDisable, 259 | Fld_CDC_wValue_Cycles, 260 | Fld_CDC_wValue_Timing, 261 | Fld_CDC_wValue_NumberOfRings, 262 | Fld_CDC_wValue_ControlSignalBitmap, 263 | Fld_CDC_wValue_DurationOfBreak, 264 | Fld_CDC_wValue_OperationParms, 265 | Fld_CDC_wValue_LineStateChange, 266 | Fld_CDC_wValue_UnitParameterStructure, 267 | Fld_CDC_wValue_NumberOfFilters, 268 | Fld_CDC_wValue_FilterNumber, 269 | Fld_CDC_wValue_PacketFilterBitmap, 270 | Fld_CDC_wValue_EthFeatureSelector, 271 | Fld_CDC_wValue_ATMDataFormat, 272 | Fld_CDC_wValue_ATMFeatureSelector, 273 | Fld_CDC_wValue_ATMVCFeatureSelector, 274 | }; 275 | 276 | enum USBState 277 | { 278 | S_K, 279 | S_J, 280 | S_SE0, 281 | S_SE1, 282 | }; 283 | 284 | enum USBSpeed 285 | { 286 | LOW_SPEED, // 1.5 mbit/s 287 | FULL_SPEED, // 12 mbit/s 288 | }; 289 | 290 | enum USBDecodeLevel 291 | { 292 | OUT_PACKETS, 293 | OUT_BYTES, 294 | OUT_SIGNALS, 295 | OUT_CONTROL_TRANSFERS, 296 | }; 297 | 298 | enum USBClassCodes 299 | { 300 | CC_DeferredToInterface = 0x00, 301 | CC_Audio = 0x01, 302 | CC_CommunicationsAndCDCControl = 0x02, 303 | CC_HID = 0x03, 304 | CC_Physical = 0x05, 305 | CC_Image = 0x06, 306 | CC_Printer = 0x07, 307 | CC_MassStorage = 0x08, 308 | CC_Hub = 0x09, 309 | CC_CDCData = 0x0A, 310 | CC_SmartCard = 0x0B, 311 | CC_ContentSecurity = 0x0D, 312 | CC_Video = 0x0E, 313 | CC_PersonalHealthcare = 0x0F, 314 | CC_AudioVideo = 0x10, 315 | CC_Diagnostic = 0xDC, 316 | CC_WirelessController = 0xE0, 317 | CC_Miscellaneous = 0xEF, 318 | CC_ApplicationSpecific = 0xFE, 319 | CC_VendorSpecific = 0xFF, 320 | }; 321 | 322 | #endif // USB_ENUMS_H 323 | -------------------------------------------------------------------------------- /src/USBControlTransfers.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_CONTROL_TRANSFERS_H 2 | #define USB_CONTROL_TRANSFERS_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "USBEnums.h" 10 | 11 | struct USBRequest 12 | { 13 | U8 bmRequestType; 14 | U8 bRequest; 15 | U16 wValue; 16 | U16 wIndex; 17 | U16 wLength; 18 | 19 | USBRequest() 20 | { 21 | Clear(); 22 | } 23 | 24 | void Clear() 25 | { 26 | bmRequestType = 0; 27 | bRequest = 0; 28 | wValue = 0; 29 | wIndex = 0; 30 | wLength = 0; 31 | } 32 | 33 | void SetFromPacket( USBPacket& p ); 34 | 35 | U8 GetRequestedDescriptor() const 36 | { 37 | return wValue >> 8; 38 | } // only valid when bRequest == GET_DESCRIPTOR 39 | U8 GetRequestedDescriptorIndex() const 40 | { 41 | return wValue & 0xff; 42 | } // only valid when bRequest == GET_DESCRIPTOR && GetRequestedDescriptor() == DT_STRING 43 | 44 | bool IsStandardRequest() const 45 | { 46 | return ( bmRequestType & 0x60 ) == 0x00; 47 | } 48 | bool IsClassRequest() const 49 | { 50 | return ( bmRequestType & 0x60 ) == 0x20; 51 | } 52 | bool IsVendorRequest() const 53 | { 54 | return ( bmRequestType & 0x60 ) == 0x40; 55 | } 56 | 57 | bool IsRecipientDevice() const 58 | { 59 | return ( bmRequestType & 0x1f ) == 0x00; 60 | } 61 | bool IsRecipientInterface() const 62 | { 63 | return ( bmRequestType & 0x1f ) == 0x01; 64 | } 65 | bool IsRecipientEndpoint() const 66 | { 67 | return ( bmRequestType & 0x1f ) == 0x02; 68 | } 69 | bool IsRecipientOther() const 70 | { 71 | return ( bmRequestType & 0x1f ) == 0x03; 72 | } 73 | 74 | U8 GetInterfaceNum() const 75 | { 76 | return wValue & 0xff; 77 | } 78 | 79 | bool IsRequestedStandardDescriptor() const 80 | { 81 | return IsStandardRequest() && bRequest == GET_DESCRIPTOR && GetRequestedDescriptor() >= DT_DEVICE && 82 | GetRequestedDescriptor() <= DT_INTERFACE_POWER; 83 | } 84 | 85 | bool IsRequestedHIDReportDescriptor() const 86 | { 87 | return IsStandardRequest() && bRequest == GET_DESCRIPTOR && GetRequestedDescriptor() == DT_HID_REPORT; 88 | } 89 | }; 90 | 91 | /* 92 | 93 | // Control transfer descriptor structures - these are here only for reference 94 | 95 | struct USBDeviceDescriptor 96 | { 97 | U8 bLength; 98 | U8 bDescriptorType; 99 | U16 bcdUSB; 100 | U8 bDeviceClass; 101 | U8 bDeviceSubClass; 102 | U8 bDeviceProtocol; 103 | U8 bMaxPacketSize0; 104 | U16 idVendor; 105 | U16 idProduct; 106 | U16 bcdDevice; 107 | U8 iManufacturer; 108 | U8 iProduct; 109 | U8 iSerialNumber; 110 | U8 bNumConfigurations; 111 | }; 112 | 113 | struct USBConfigurationDescriptor 114 | { 115 | U8 bLength; 116 | U8 bDescriptorType; 117 | U16 wTotalLength; 118 | U8 bNumInterfaces; 119 | U8 bConfigurationValue; 120 | U8 iConfiguration; 121 | U8 bmAttributes; 122 | U8 bMaxPower; 123 | }; 124 | 125 | struct USBInterfaceDescriptor 126 | { 127 | U8 bLength; 128 | U8 bDescriptorType; 129 | U8 bInterfaceNumber; 130 | U8 bAlternateSetting; 131 | U8 bNumEndpoints; 132 | U8 bInterfaceClass; 133 | U8 bInterfaceSubClass; 134 | U8 bInterfaceProtocol; 135 | U8 iInterface; 136 | }; 137 | 138 | struct USBEndpointDescriptor 139 | { 140 | U8 bLength; 141 | U8 bDescriptorType; 142 | U8 bEndpointAddress; 143 | U8 bmAttributes; 144 | U8 wMaxPacketSize; 145 | U8 bInterval; 146 | }; 147 | */ 148 | 149 | class USBCtrlTransFieldFrame : public Frame 150 | { 151 | public: 152 | USBCtrlTransFieldFrame() 153 | { 154 | mType = FT_ControlTransferField; 155 | mFlags = FF_None; 156 | } 157 | 158 | void PackFrame( U32 data, U8 numBytes, U8 address, USBCtrlTransFieldType formatter, const char* name ); 159 | 160 | U32 GetData() const 161 | { 162 | return mData1 & 0xffffffff; 163 | } 164 | 165 | U8 GetNumBytes() const 166 | { 167 | return ( mData1 >> 32 ) & 0xff; 168 | } 169 | 170 | USBCtrlTransFieldType GetFormatter() const 171 | { 172 | return USBCtrlTransFieldType( ( mData1 >> 40 ) & 0xff ); 173 | } 174 | 175 | U8 GetAddress() const 176 | { 177 | return ( mData1 >> 48 ) & 0xff; 178 | } 179 | 180 | const char* GetFieldName() const 181 | { 182 | return ( const char* )mData2; 183 | } 184 | }; 185 | 186 | class USBHidRepDescItemFrame : public Frame 187 | { 188 | public: 189 | USBHidRepDescItemFrame() 190 | { 191 | mType = FT_HIDReportDescriptorItem; 192 | mFlags = FF_None; 193 | mData1 = mData2 = 0; 194 | } 195 | 196 | void PackFrame( const U8* pItem, U16 indentLevel, U16 usagePage ); 197 | 198 | const U8* GetItem() const 199 | { 200 | return ( const U8* )&mData1; 201 | } 202 | 203 | U16 GetIndentLevel() const 204 | { 205 | return mData2 & 0xffff; 206 | } 207 | 208 | U16 GetUsagePage() const 209 | { 210 | return ( U16 )( mData2 >> 16 ); 211 | } 212 | }; 213 | 214 | // describes data structures 215 | struct USBStructField 216 | { 217 | const char* name; 218 | int numBytes; 219 | USBCtrlTransFieldType formatter; 220 | }; 221 | 222 | class USBControlTransferParser 223 | { 224 | private: 225 | int mDescBytes; // size of this descriptor in bytes; equal to Descriptor.bLength 226 | USBDescriptorType mDescType; 227 | USBCDCDescriptorSubtype mDescSubtype; 228 | int mParsedOffset; // number of bytes we have already parsed from the current descriptor 229 | U32 mLeftover; // the LS byte of the previous packet in case a field spans two packets 230 | 231 | USBAnalyzerResults* pResults; 232 | U8 mAddress; 233 | 234 | USBRequest mRequest; 235 | 236 | std::u16string utf16StringDescriptor; 237 | 238 | 239 | // these are only valid during a ParsePacket call, and invalid before and after 240 | USBPacket* pPacket; 241 | int mPacketOffset; // index of the data byte of the current packet 242 | int mPacketDataBytes; // number of bytes in the current packet 243 | 244 | // we store the class IDs for the device and the interfaces 245 | U8 mInterfaceNumber; // the last parsed interface number 246 | typedef std::map USBInterfaceClassesContainer; 247 | 248 | USBInterfaceClassesContainer mInterfaceClasses; 249 | 250 | // used for the HID report descriptor parser 251 | U8 mHidRepDescItem[ 5 ]; 252 | U8 mHidRepDescBytes; 253 | int mHidIndentLevel; 254 | int mHidItemCnt; 255 | std::vector mHidUsagePageStack; 256 | 257 | USBClassCodes GetClassCodeForInterface( U8 iface ) const; 258 | 259 | bool IsCDCClassRequest() const; 260 | 261 | bool ParseStringDescriptor(); 262 | void ParseStructure( USBStructField* descFields ); 263 | void ParseStandardDescriptor(); 264 | 265 | void SetHIDUsagePage( U16 usagePage ) 266 | { 267 | if( mHidUsagePageStack.empty() ) 268 | mHidUsagePageStack.push_back( 0 ); 269 | 270 | mHidUsagePageStack.back() = usagePage; 271 | } 272 | 273 | U16 GetHIDUsagePage() 274 | { 275 | if( mHidUsagePageStack.empty() ) 276 | return 0; 277 | 278 | return mHidUsagePageStack.back(); 279 | } 280 | 281 | void PushHIDUsagePage() 282 | { 283 | mHidUsagePageStack.push_back( GetHIDUsagePage() ); 284 | } 285 | 286 | void PopHIDUsagePage() 287 | { 288 | if( !mHidUsagePageStack.empty() ) 289 | mHidUsagePageStack.pop_back(); 290 | } 291 | 292 | void ParseCDCDataStage(); 293 | void ParseHIDReportDescriptor(); 294 | void ParseUnknownResponse(); 295 | 296 | public: 297 | USBControlTransferParser() 298 | { 299 | ResetParser(); 300 | } 301 | 302 | void SetAnalyzerResults( USBAnalyzerResults* pres ) 303 | { 304 | pResults = pres; 305 | } 306 | 307 | void ResetParser(); 308 | 309 | void SetAddress( U8 address ) 310 | { 311 | mAddress = address; 312 | } 313 | 314 | void SetRequest( USBPacket& packet ) 315 | { 316 | mRequest.SetFromPacket( packet ); 317 | } 318 | 319 | void ParseDataPacket( USBPacket& packet ); 320 | 321 | U8 GetClassForInterface( U8 iface ) const 322 | { 323 | // get the interface class 324 | USBInterfaceClassesContainer::const_iterator srch( mInterfaceClasses.find( iface ) ); 325 | if( srch != mInterfaceClasses.end() ) 326 | return srch->second; 327 | 328 | return 0; 329 | } 330 | }; 331 | 332 | 333 | class USBControlTransferPacketHandler 334 | { 335 | private: 336 | enum ControlTransferLastPacketReceived 337 | { 338 | // setup stage 339 | CTS_SetupToken, 340 | CTS_SetupData, 341 | CTS_SetupAck, 342 | 343 | // data stage 344 | CTS_DataInToken, 345 | CTS_DataOutToken, 346 | CTS_DataInData, 347 | CTS_DataOutData, 348 | CTS_DataEnd, 349 | 350 | // status stage 351 | CTS_StatusInToken, 352 | CTS_StatusOutToken, 353 | CTS_StatusInDataEmpty, 354 | CTS_StatusOutDataEmpty, 355 | CTS_StatusInNAKed, 356 | CTS_StatusOutDataNAKed, 357 | CTS_StatusEnd, 358 | }; 359 | 360 | // control transfer state 361 | ControlTransferLastPacketReceived mCtrlTransLastReceived; 362 | USBRequestCode mCtrlTransRequest; 363 | bool mCtrlTransDeviceToHost; 364 | USBControlTransferParser mCtrlTransParser; 365 | int mAddress; 366 | 367 | USBAnalyzerResults* mResults; 368 | 369 | public: 370 | void Init( USBAnalyzerResults* pResults, int addr ); 371 | 372 | U64 ResetControlTransferParser( USBPacket& pckt, USBFrameFlags flag = FF_UnexpectedPacket ); 373 | U64 HandleControlTransfer( USBPacket& pckt ); 374 | }; 375 | 376 | inline int GetNumHIDItemDataBytes( U8 firstByte ) 377 | { 378 | U8 retVal = firstByte & 0x03; 379 | return retVal == 3 ? 4 : retVal; 380 | } 381 | 382 | inline bool IsStandardDescriptor( U8 descType ) 383 | { 384 | return descType >= DT_DEVICE && descType <= DT_INTERFACE_POWER; 385 | } 386 | 387 | inline bool IsHIDItemCollection( U8 firstByte ) 388 | { 389 | return ( firstByte & 0xfc ) == 0xa0; 390 | } 391 | inline bool IsHIDItemEndCollection( U8 firstByte ) 392 | { 393 | return ( firstByte & 0xfc ) == 0xc0; 394 | } 395 | inline bool IsHIDItemPush( U8 firstByte ) 396 | { 397 | return ( firstByte & 0xfc ) == 0xa4; 398 | } 399 | inline bool IsHIDItemPop( U8 firstByte ) 400 | { 401 | return ( firstByte & 0xfc ) == 0xb4; 402 | } 403 | inline bool IsHIDItemUsagePage( U8 firstByte ) 404 | { 405 | return ( firstByte & 0xfc ) == 0x04; 406 | } 407 | 408 | #endif // USB_CONTROL_TRANSFERS_H 409 | -------------------------------------------------------------------------------- /src/USBTypes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "USBAnalyzer.h" 5 | #include "USBAnalyzerResults.h" 6 | #include "USBTypes.h" 7 | 8 | std::string GetPIDName( USB_PID pid ) 9 | { 10 | switch( pid ) 11 | { 12 | case PID_IN: 13 | return "IN"; 14 | case PID_OUT: 15 | return "OUT"; 16 | case PID_SOF: 17 | return "SOF"; 18 | case PID_SETUP: 19 | return "SETUP"; 20 | case PID_DATA0: 21 | return "DATA0"; 22 | case PID_DATA1: 23 | return "DATA1"; 24 | case PID_ACK: 25 | return "ACK"; 26 | case PID_NAK: 27 | return "NAK"; 28 | case PID_STALL: 29 | return "STALL"; 30 | case PID_PRE: 31 | return "PRE"; 32 | } 33 | 34 | return ""; 35 | } 36 | 37 | void USBPacket::Clear() 38 | { 39 | mData.clear(); 40 | mBitBeginSamples.clear(); 41 | mSampleBegin = mSampleEnd = 0; 42 | mPID = PID_Unknown; 43 | mCRC = 0; 44 | } 45 | 46 | bool USBPacket::IsPIDValid() const 47 | { 48 | return mPID == PID_IN || mPID == PID_OUT || mPID == PID_SOF || mPID == PID_SETUP || mPID == PID_DATA0 || mPID == PID_DATA1 || 49 | mPID == PID_ACK || mPID == PID_NAK || mPID == PID_STALL || mPID == PID_PRE; 50 | } 51 | 52 | U8 USBPacket::CalcCRC5( U16 data ) 53 | { 54 | U8 crc_register = 0x1f; 55 | U8 polynom = 0x14; // 0b10100 56 | 57 | U8 data_bit, crc_bit; 58 | U16 shift_register; 59 | 60 | // only the lower 11 bits of the 16 bit number 61 | for( shift_register = 1; shift_register <= 0x400; shift_register <<= 1 ) 62 | { 63 | data_bit = ( data & shift_register ) ? 1 : 0; 64 | crc_bit = crc_register & 1; 65 | 66 | crc_register >>= 1; 67 | 68 | if( data_bit ^ crc_bit ) 69 | crc_register ^= polynom; 70 | } 71 | 72 | return ( ~crc_register ) & 0x1f; 73 | } 74 | 75 | U16 USBPacket::CalcCRC16() const 76 | { 77 | size_t counter; 78 | U16 crc_register = 0xffff; 79 | U16 polynom = 0xA001; 80 | U8 shift_register, data_bit, crc_bit; 81 | 82 | for( counter = 2; counter < mData.size() - 2; counter++ ) 83 | { 84 | for( shift_register = 0x01; shift_register > 0x00; shift_register <<= 1 ) 85 | { 86 | data_bit = ( mData[ counter ] & shift_register ) ? 1 : 0; 87 | crc_bit = crc_register & 1; 88 | 89 | crc_register >>= 1; 90 | 91 | if( data_bit ^ crc_bit ) 92 | crc_register ^= polynom; 93 | } 94 | } 95 | 96 | return ~crc_register; 97 | } 98 | 99 | void USBPacket::AddSyncAndPidFrames( USBAnalyzerResults* pResults, USBFrameFlags flagPID ) 100 | { 101 | // make the SYNC and PID analyzer frames for this packet 102 | Frame f; 103 | 104 | // SYNC 105 | f.mStartingSampleInclusive = mBitBeginSamples.front(); 106 | f.mEndingSampleInclusive = *( mBitBeginSamples.begin() + 8 ); 107 | f.mType = FT_SYNC; 108 | f.mData1 = f.mData2 = 0; 109 | f.mFlags = FF_None; 110 | pResults->AddFrame( f ); 111 | 112 | // PID 113 | f.mStartingSampleInclusive = *( mBitBeginSamples.begin() + 8 ); 114 | f.mEndingSampleInclusive = *( mBitBeginSamples.begin() + 16 ); 115 | f.mType = FT_PID; 116 | f.mData1 = mPID; 117 | f.mData2 = 0; 118 | f.mFlags = flagPID; 119 | pResults->AddFrame( f ); 120 | } 121 | 122 | void USBPacket::AddEOPFrame( USBAnalyzerResults* pResults ) 123 | { 124 | Frame f; 125 | 126 | // add the EOP frame 127 | f.mStartingSampleInclusive = mBitBeginSamples.back(); 128 | // EOP is 2 bits SE0 and one bit J, so add another bit 129 | f.mEndingSampleInclusive = mSampleEnd; 130 | f.mData1 = f.mData2 = 0; 131 | f.mFlags = FF_None; 132 | f.mType = FT_EOP; 133 | pResults->AddFrame( f ); 134 | } 135 | 136 | void USBPacket::AddCRC16Frame( USBAnalyzerResults* pResults ) 137 | { 138 | Frame f; 139 | 140 | // CRC16 141 | f.mStartingSampleInclusive = *( mBitBeginSamples.end() - 17 ); 142 | f.mEndingSampleInclusive = mBitBeginSamples.back(); 143 | 144 | f.mType = FT_CRC16; 145 | f.mData1 = mCRC; 146 | f.mData2 = CalcCRC16(); 147 | pResults->AddFrame( f ); 148 | } 149 | 150 | U64 USBPacket::AddPacketFrames( USBAnalyzerResults* pResults, USBFrameFlags flagPID ) 151 | { 152 | AddSyncAndPidFrames( pResults, flagPID ); 153 | 154 | // make the analyzer frames for this packet 155 | Frame f; 156 | f.mFlags = FF_None; 157 | 158 | // do the payload & CRC frames 159 | if( IsTokenPacket() || IsSOFPacket() ) 160 | { 161 | // address/endpoint or frame number 162 | f.mStartingSampleInclusive = *( mBitBeginSamples.begin() + 16 ); 163 | f.mEndingSampleInclusive = *( mBitBeginSamples.begin() + 27 ); 164 | 165 | // is this a SOF packet? 166 | if( mPID == PID_SOF ) 167 | { 168 | f.mType = FT_FrameNum; 169 | f.mData1 = GetFrameNum(); 170 | f.mData2 = 0; 171 | } 172 | else 173 | { 174 | f.mType = FT_AddrEndp; 175 | f.mData1 = GetAddress(); 176 | f.mData2 = GetEndpoint(); 177 | } 178 | 179 | pResults->AddFrame( f ); 180 | 181 | // CRC5 182 | f.mStartingSampleInclusive = *( mBitBeginSamples.begin() + 27 ); 183 | f.mEndingSampleInclusive = mBitBeginSamples.back(); 184 | 185 | f.mType = FT_CRC5; 186 | f.mData1 = mCRC; 187 | f.mData2 = CalcCRC5( GetLastWord() & 0x7ff ); 188 | pResults->AddFrame( f ); 189 | } 190 | else if( IsDataPacket() ) 191 | { 192 | // raw data 193 | size_t bc; 194 | f.mType = FT_Byte; 195 | f.mData2 = 0; 196 | for( bc = 2; bc < mData.size() - 2; ++bc ) 197 | { 198 | f.mStartingSampleInclusive = *( mBitBeginSamples.begin() + bc * 8 ); 199 | f.mEndingSampleInclusive = *( mBitBeginSamples.begin() + ( bc + 1 ) * 8 ); 200 | f.mData1 = mData[ bc ]; 201 | 202 | pResults->AddFrame( f ); 203 | } 204 | 205 | AddCRC16Frame( pResults ); 206 | } 207 | 208 | if( mPID != PID_PRE ) 209 | AddEOPFrame( pResults ); 210 | 211 | pResults->CommitResults(); 212 | 213 | return mSampleEnd; 214 | } 215 | 216 | U64 USBPacket::AddRawByteFrames( USBAnalyzerResults* pResults ) 217 | { 218 | // raw data 219 | size_t bc; 220 | Frame f; 221 | f.mType = FT_Byte; 222 | f.mData2 = 0; 223 | f.mFlags = FF_None; 224 | std::string bytes_row; 225 | for( bc = 0; bc < mData.size(); ++bc ) 226 | { 227 | bytes_row += int2str_sal( mData[ bc ], Hexadecimal, 8 ) + ", "; 228 | 229 | f.mStartingSampleInclusive = *( mBitBeginSamples.begin() + bc * 8 ); 230 | f.mEndingSampleInclusive = *( mBitBeginSamples.begin() + ( bc + 1 ) * 8 ); 231 | f.mData1 = mData[ bc ]; 232 | pResults->AddFrame( f ); 233 | } 234 | 235 | // add the EOP frame 236 | f.mStartingSampleInclusive = mBitBeginSamples.back(); 237 | // EOP is 2 bits SE0 and one bit J, so add another bit 238 | f.mEndingSampleInclusive = mSampleEnd; 239 | f.mData1 = f.mData2 = 0; 240 | f.mFlags = FF_None; 241 | f.mType = FT_EOP; 242 | pResults->AddFrame( f ); 243 | 244 | pResults->CommitResults(); 245 | 246 | return f.mEndingSampleInclusive; 247 | } 248 | 249 | U64 USBPacket::AddErrorFrame( USBAnalyzerResults* pResults ) 250 | { 251 | // add the Error frame -- parser can't decode the packet 252 | Frame f; 253 | f.mStartingSampleInclusive = mSampleBegin; 254 | f.mEndingSampleInclusive = mSampleEnd; 255 | f.mData1 = f.mData2 = 0; 256 | f.mFlags = FF_None; 257 | f.mType = FT_Error; 258 | pResults->AddFrame( f ); 259 | 260 | pResults->CommitResults(); 261 | 262 | return f.mEndingSampleInclusive; 263 | } 264 | 265 | void USBSignalState::AddFrame( USBAnalyzerResults* res ) 266 | { 267 | Frame f; 268 | f.mStartingSampleInclusive = mSampleBegin; 269 | f.mEndingSampleInclusive = mSampleEnd; 270 | f.mType = FT_Signal; 271 | f.mData1 = mState; 272 | f.mData2 = 0; 273 | 274 | res->AddFrame( f ); 275 | res->CommitResults(); 276 | } 277 | 278 | USBSignalFilter::USBSignalFilter( USBAnalyzer* pAnalyzer, USBAnalyzerResults* pResults, USBAnalyzerSettings* pSettings, 279 | AnalyzerChannelData* pDP, AnalyzerChannelData* pDM, USBSpeed speed ) 280 | : mAnalyzer( pAnalyzer ), 281 | mResults( pResults ), 282 | mSettings( pSettings ), 283 | mDP( pDP ), 284 | mDM( pDM ), 285 | mSpeed( speed ), 286 | mExpectLowSpeed( false ), 287 | mSampleDur( 1e9 / mAnalyzer->GetSampleRate() ) 288 | { 289 | mStateStartSample = mDP->GetSampleNumber(); 290 | } 291 | 292 | bool USBSignalFilter::SkipNoise( AnalyzerChannelData* pNearer, AnalyzerChannelData* pFurther ) 293 | { 294 | if( mSampleDur > 20 // sample rate < 50Mhz? 295 | || mSpeed == FULL_SPEED ) 296 | return false; 297 | 298 | // up to 20ns 299 | const U32 IGNORE_PULSE_SAMPLES = mSampleDur == 10 ? 2 : 1; 300 | 301 | // skip the glitch 302 | if( pNearer->WouldAdvancingCauseTransition( IGNORE_PULSE_SAMPLES ) ) 303 | { 304 | pNearer->AdvanceToNextEdge(); 305 | pFurther->AdvanceToAbsPosition( pNearer->GetSampleNumber() ); 306 | 307 | return true; 308 | } 309 | 310 | return false; 311 | } 312 | 313 | U64 USBSignalFilter::DoFilter( AnalyzerChannelData* mDP, AnalyzerChannelData* mDM ) 314 | { 315 | AnalyzerChannelData* pFurther; 316 | AnalyzerChannelData* pNearer; 317 | U64 next_edge_further; 318 | U64 next_edge_nearer; 319 | 320 | // this loop consumes all short (1 sample) pulses caused by noise and/or high speed signals 321 | do 322 | { 323 | if( mDP->GetSampleOfNextEdge() > mDM->GetSampleOfNextEdge() ) 324 | pFurther = mDP, pNearer = mDM; 325 | else 326 | pFurther = mDM, pNearer = mDP; 327 | 328 | next_edge_further = pFurther->GetSampleOfNextEdge(); 329 | next_edge_nearer = pNearer->GetSampleOfNextEdge(); 330 | 331 | pNearer->AdvanceToNextEdge(); 332 | pFurther->AdvanceToAbsPosition( next_edge_nearer ); 333 | } while( SkipNoise( pNearer, pFurther ) ); 334 | 335 | const int FILTER_THLD = mSettings->mSpeed == LOW_SPEED ? 300 : 50; // filtering threshold in ns 336 | 337 | U64 diff_samples = next_edge_further - next_edge_nearer; 338 | // if there's a pulse on pNearer and no transition on pFurther 339 | if( !pNearer->WouldAdvancingToAbsPositionCauseTransition( next_edge_further ) 340 | // if the transitions happened withing FILTER_THLD time of eachother 341 | && diff_samples * mSampleDur <= FILTER_THLD ) 342 | { 343 | for( ;; ) 344 | { 345 | pNearer->AdvanceToAbsPosition( next_edge_further ); 346 | pFurther->AdvanceToAbsPosition( next_edge_further ); 347 | 348 | if( !SkipNoise( pFurther, pNearer ) ) 349 | break; 350 | 351 | pFurther->AdvanceToNextEdge(); 352 | next_edge_further = pFurther->GetSampleNumber(); 353 | } 354 | 355 | // return the filtered position of the transition 356 | return ( next_edge_nearer + next_edge_further ) / 2; 357 | } 358 | 359 | // return state up until the nearer transition 360 | return next_edge_nearer; 361 | } 362 | 363 | USBSignalState USBSignalFilter::GetState() 364 | { 365 | USBSignalState ret_val; 366 | 367 | ret_val.mSampleBegin = mStateStartSample; 368 | 369 | // determine the USB signal state 370 | BitState dp_state = mDP->GetBitState(); 371 | BitState dm_state = mDM->GetBitState(); 372 | if( dp_state == dm_state ) 373 | ret_val.mState = dp_state == BIT_LOW ? S_SE0 : S_SE1; 374 | else 375 | ret_val.mState = ( mSpeed == LOW_SPEED ? ( dp_state == BIT_LOW ? S_J : S_K ) : ( dp_state == BIT_LOW ? S_K : S_J ) ); 376 | 377 | // do the filtering and remember the sample begin for the next iteration 378 | mStateStartSample = DoFilter( mDP, mDM ); 379 | 380 | ret_val.mDur = ( mStateStartSample - ret_val.mSampleBegin ) * mSampleDur; 381 | ret_val.mSampleEnd = mStateStartSample; 382 | 383 | return ret_val; 384 | } 385 | 386 | bool USBSignalFilter::HasMoreData() 387 | { 388 | return mDP->DoMoreTransitionsExistInCurrentData() || mDM->DoMoreTransitionsExistInCurrentData(); 389 | } 390 | 391 | bool USBSignalFilter::IsDataSignal( const USBSignalState& s ) 392 | { 393 | if( mExpectLowSpeed ) 394 | return ( s.IsData( FULL_SPEED ) && s.GetNumBits( FULL_SPEED ) == 1 ) || ( s.IsData( LOW_SPEED ) && s.GetNumBits( LOW_SPEED ) == 1 ); 395 | 396 | return s.IsData( mSpeed ) && s.GetNumBits( mSpeed ) == 1; 397 | } 398 | 399 | bool USBSignalFilter::GetPacket( USBPacket& pckt, USBSignalState& sgnl ) 400 | { 401 | pckt.Clear(); 402 | 403 | const U8 bits2add[] = { 0, 1, 1, 1, 1, 1, 1 }; 404 | 405 | // a PRE packet switched us into low speed mode, so now we need to check 406 | // if this packet is low or full speed 407 | if( mExpectLowSpeed ) 408 | { 409 | if( sgnl.IsData( FULL_SPEED ) && sgnl.GetNumBits( FULL_SPEED ) == 1 ) 410 | { 411 | mSpeed = FULL_SPEED; 412 | mExpectLowSpeed = false; // switch back to full speed 413 | } 414 | else 415 | { 416 | mSpeed = LOW_SPEED; 417 | } 418 | } 419 | 420 | const double BIT_DUR = ( mSpeed == FULL_SPEED ? FS_BIT_DUR : LS_BIT_DUR ); 421 | const double SAMPLE_DUR = 1e9 / mAnalyzer->GetSampleRate(); // 1 sample duration in ns 422 | const double BIT_SAMPLES = BIT_DUR / SAMPLE_DUR; 423 | 424 | std::vector bits; 425 | 426 | pckt.mSampleBegin = sgnl.mSampleBegin; // default for bad packets 427 | 428 | bool is_stuff_bit = false; 429 | bool is_pre_packet = false; 430 | while( sgnl.IsData( mSpeed ) && !is_pre_packet ) 431 | { 432 | // get the number of bits in this signal 433 | int num_bits = sgnl.GetNumBits( mSpeed ); 434 | 435 | const U8* add_begin = bits2add; 436 | const U8* add_end = bits2add + num_bits; 437 | 438 | // mind the stuffing bit 439 | if( is_stuff_bit ) 440 | ++add_begin; 441 | 442 | // now add the data bits 443 | if( ( is_stuff_bit && num_bits > 1 ) || ( num_bits > 0 ) ) 444 | bits.insert( bits.end(), add_begin, add_end ); 445 | 446 | // do the bit markers and remember the samples at which a bit begins 447 | int bc; 448 | for( bc = 0; bc < num_bits; ++bc ) 449 | { 450 | if( !is_stuff_bit || bc > 0 ) 451 | pckt.mBitBeginSamples.push_back( sgnl.mSampleBegin + U64( BIT_SAMPLES * bc + .5 ) ); 452 | 453 | mResults->AddMarker( sgnl.mSampleBegin + U64( BIT_SAMPLES * ( bc + .5 ) + .5 ), 454 | bc == 0 ? ( is_stuff_bit ? AnalyzerResults::ErrorX : AnalyzerResults::Zero ) : AnalyzerResults::One, 455 | mSettings->mDPChannel ); 456 | } 457 | 458 | // check if this is a PRE token, in which case we switch to low-speed, 459 | // return and wait for the next packet 460 | if( mSpeed == FULL_SPEED && bits.size() == 16 ) // 8 bits for SYNC and 8 bits for PRE PID 461 | { 462 | const U8 preArr[ 16 ] = { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0 }; // SYNC and PRE as they appear on the bus 463 | if( std::equal( bits.begin(), bits.end(), preArr ) ) 464 | { 465 | mSpeed = LOW_SPEED; 466 | mExpectLowSpeed = true; 467 | is_pre_packet = true; 468 | } 469 | } 470 | 471 | // set the stuff bit flag for the next state 472 | is_stuff_bit = ( num_bits == 7 ); 473 | 474 | // get the next signal state 475 | sgnl = GetState(); 476 | } 477 | 478 | pckt.mSampleEnd = sgnl.mSampleEnd; // default for bad packets 479 | 480 | // add another element to mBitBeginSamples to mark the end of the last bit 481 | pckt.mBitBeginSamples.push_back( sgnl.mSampleBegin ); 482 | 483 | // check the number of bits 484 | if( bits.empty() || ( bits.size() % 8 ) != 0 || ( pckt.mBitBeginSamples.size() % 8 ) != 1 ) 485 | { 486 | return false; 487 | } 488 | 489 | // remember the begin & end samples for the entire packet 490 | pckt.mSampleBegin = pckt.mBitBeginSamples.front(); 491 | pckt.mSampleEnd = sgnl.mSampleEnd + S64( BIT_DUR / SAMPLE_DUR + 0.5 ); 492 | 493 | // make bytes out of these bits 494 | U8 val = 0; 495 | std::vector::iterator i( bits.begin() ); 496 | while( i != bits.end() ) 497 | { 498 | // least significant bit first 499 | val >>= 1; 500 | if( *i ) 501 | val |= 0x80; 502 | 503 | ++i; 504 | 505 | // do we have a full byte? 506 | if( ( ( i - bits.begin() ) % 8 ) == 0 ) 507 | pckt.mData.push_back( val ); 508 | } 509 | 510 | // extract the PID 511 | if( pckt.mData.size() > 1 ) 512 | pckt.mPID = USB_PID( pckt.mData[ 1 ] ); 513 | 514 | // extract the CRC fields 515 | if( pckt.mData.size() >= 4 ) 516 | { 517 | U16 last_word = ( pckt.mData.back() << 8 ) | *( pckt.mData.end() - 2 ); 518 | 519 | if( pckt.mData.size() == 4 ) 520 | pckt.mCRC = last_word >> 11; 521 | else 522 | pckt.mCRC = last_word; 523 | } 524 | 525 | return ( pckt.IsTokenPacket() && pckt.mData.size() == 4 ) || ( pckt.IsDataPacket() && pckt.mData.size() >= 4 ) || 526 | ( pckt.IsHandshakePacket() && pckt.mData.size() == 2 ) || ( pckt.mPID == PID_PRE && pckt.mData.size() == 2 ) || 527 | ( pckt.IsSOFPacket() && pckt.mData.size() == 4 ); 528 | } 529 | 530 | std::string int2str_sal( const U64 i, DisplayBase base, const int max_bits ) 531 | { 532 | char number_str[ 256 ]; 533 | AnalyzerHelpers::GetNumberString( i, base, max_bits, number_str, sizeof( number_str ) ); 534 | return number_str; 535 | } 536 | -------------------------------------------------------------------------------- /src/USBControlTransfers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "USBAnalyzer.h" 11 | #include "USBAnalyzerResults.h" 12 | #include "USBTypes.h" 13 | #include "USBLookupTables.h" 14 | 15 | void USBCtrlTransFieldFrame::PackFrame( U32 data, U8 numBytes, U8 address, USBCtrlTransFieldType formatter, const char* name ) 16 | { 17 | // mData1 format: 18 | // 19 | // 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 20 | // 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 21 | // -------- -address -format- numBytes ---------------data---------------- 22 | 23 | mData1 = data; 24 | mData1 |= U64( numBytes ) << 32; 25 | mData1 |= U64( formatter ) << 40; 26 | mData1 |= U64( address ) << 48; 27 | 28 | mData2 = ( U64 )name; 29 | } 30 | 31 | void USBHidRepDescItemFrame::PackFrame( const U8* pItem, U16 indentLevel, U16 usagePage ) 32 | { 33 | // mData1 contains the 1 to 5 bytes of the HID item 34 | U8 itemSize = GetNumHIDItemDataBytes( pItem[ 0 ] ) + 1; 35 | memcpy( &mData1, pItem, itemSize ); 36 | 37 | // mData2 format: 38 | // 39 | // 66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 40 | // 32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 41 | // ----------------- ----------------- ----usagePage---- ---indentLevel--- 42 | 43 | // contains indentLevel and usagePage 44 | mData2 = usagePage; 45 | mData2 <<= 16; 46 | mData2 |= indentLevel; 47 | } 48 | 49 | U32 USBPacket::GetDataPayload( int offset, int bcnt ) const 50 | { 51 | U32 ret_val = 0; 52 | 53 | if( bcnt == 1 ) 54 | ret_val = mData[ offset + 2 ]; 55 | else if( bcnt == 2 ) 56 | ret_val = ( mData[ offset + 3 ] << 8 ) | mData[ offset + 2 ]; 57 | else if( bcnt == 3 ) 58 | ret_val = ( mData[ offset + 4 ] << 16 ) | ( mData[ offset + 3 ] << 8 ) | mData[ offset + 2 ]; 59 | else if( bcnt == 4 ) 60 | ret_val = ( mData[ offset + 5 ] << 24 ) | ( mData[ offset + 4 ] << 16 ) | ( mData[ offset + 3 ] << 8 ) | mData[ offset + 2 ]; 61 | 62 | return ret_val; 63 | } 64 | 65 | Frame USBPacket::GetDataPayloadField( int offset, int bcnt, U8 address, const char* name, USBCtrlTransFieldType formatter, U8 flags ) const 66 | { 67 | USBCtrlTransFieldFrame f; 68 | f.mFlags = flags; 69 | f.mStartingSampleInclusive = mBitBeginSamples[ 16 + offset * 8 ]; // first data bit 70 | f.mEndingSampleInclusive = mBitBeginSamples[ 16 + ( offset + bcnt ) * 8 ]; // first bit after 71 | 72 | f.PackFrame( GetDataPayload( offset, bcnt ), bcnt, address, formatter, name ); 73 | 74 | return f; 75 | } 76 | 77 | Frame USBPacket::GetHIDItem( int offset, int bcnt, U8* pItem, U16 indentLevel, U16 usagePage, U8 flags ) const 78 | { 79 | USBHidRepDescItemFrame f; 80 | f.mFlags = flags; 81 | f.mStartingSampleInclusive = mBitBeginSamples[ 16 + offset * 8 ]; // first data bit 82 | f.mEndingSampleInclusive = mBitBeginSamples[ 16 + ( offset + bcnt ) * 8 ]; // first bit after 83 | 84 | if( ( flags & 0x3F ) != FF_FieldIncomplete ) 85 | f.PackFrame( pItem, indentLevel, usagePage ); 86 | 87 | return f; 88 | } 89 | 90 | void USBPacket::AddStandardSetupPacketFrame( USBAnalyzerResults* pResults, USBControlTransferParser& parser, U8 address ) 91 | { 92 | U8 bRequestType = GetDataPayload( 0, 1 ); 93 | U8 bRequest = GetDataPayload( 1, 1 ); 94 | U16 wIndex = GetDataPayload( 4, 2 ); 95 | U16 wLength = GetDataPayload( 6, 2 ); 96 | 97 | bool isRecipientInterface = ( bRequestType & 0x1f ) == 1; 98 | bool isRecipientEndpoint = ( bRequestType & 0x1f ) == 2; 99 | 100 | if( wLength ) 101 | pResults->AddFrame( GetDataPayloadField( 0, 1, address, "bmRequestType", Fld_bmRequestType, FF_SetupBegin ) ); 102 | else 103 | pResults->AddFrame( GetDataPayloadField( 0, 1, address, "bmRequestType", Fld_bmRequestType_NoData, FF_SetupBegin ) ); 104 | 105 | pResults->AddFrame( GetDataPayloadField( 1, 1, address, "bRequest", Fld_bRequest_Standard ) ); 106 | 107 | if( bRequest == SET_DESCRIPTOR || bRequest == GET_DESCRIPTOR ) 108 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue", Fld_wValue_Descriptor ) ); 109 | else if( bRequest == SET_ADDRESS ) 110 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue", Fld_wValue_Address ) ); 111 | else 112 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue" ) ); 113 | 114 | U8 hiByte = GetDataPayload( 3, 1 ); 115 | U8 loByte = GetDataPayload( 2, 1 ); 116 | if( isRecipientInterface ) 117 | { 118 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex", Fld_wIndex_InterfaceNum ) ); 119 | } 120 | else if( isRecipientEndpoint ) 121 | { 122 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex", Fld_wIndex_Endpoint ) ); 123 | } 124 | else if( bRequest == GET_DESCRIPTOR ) 125 | { 126 | if( hiByte == DT_STRING && loByte != 0 ) 127 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex", Fld_wLANGID ) ); 128 | else 129 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex" ) ); 130 | } 131 | else 132 | { 133 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex" ) ); 134 | } 135 | 136 | pResults->AddFrame( GetDataPayloadField( 6, 2, address, "wLength" ) ); 137 | } 138 | 139 | void USBPacket::AddClassSetupPacketFrame( USBAnalyzerResults* pResults, USBControlTransferParser& parser, U8 address ) 140 | { 141 | U8 bRequestType = GetDataPayload( 0, 1 ); 142 | U8 bRequest = GetDataPayload( 1, 1 ); 143 | U16 wIndex = GetDataPayload( 4, 2 ); 144 | U16 wLength = GetDataPayload( 6, 2 ); 145 | 146 | bool isRecipientInterface = ( bRequestType & 0x1f ) == 1; 147 | bool isRecipientEndpoint = ( bRequestType & 0x1f ) == 2; 148 | 149 | U8 interfaceClassCode = 0; 150 | 151 | if( isRecipientInterface ) 152 | interfaceClassCode = parser.GetClassForInterface( ( U8 )wIndex ); 153 | 154 | bool isCDC = interfaceClassCode == CC_CDCData || interfaceClassCode == CC_CommunicationsAndCDCControl; 155 | 156 | if( wLength ) 157 | pResults->AddFrame( GetDataPayloadField( 0, 1, address, "bmRequestType", Fld_bmRequestType, FF_SetupBegin ) ); 158 | else 159 | pResults->AddFrame( GetDataPayloadField( 0, 1, address, "bmRequestType", Fld_bmRequestType_NoData, FF_SetupBegin ) ); 160 | 161 | USBCtrlTransFieldType fldType = Fld_bRequest_Class; 162 | if( interfaceClassCode == CC_HID ) 163 | fldType = Fld_bRequest_HID; 164 | else if( interfaceClassCode == CC_CDCData || interfaceClassCode == CC_CommunicationsAndCDCControl ) 165 | fldType = Fld_bRequest_CDC; 166 | 167 | pResults->AddFrame( GetDataPayloadField( 1, 1, address, "bRequest", fldType ) ); 168 | 169 | if( interfaceClassCode == CC_HID ) 170 | { 171 | if( bRequest == SET_IDLE ) 172 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue", Fld_wValue_HIDSetIdle ) ); 173 | else if( bRequest == GET_IDLE ) 174 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue", Fld_wValue_HIDGetIdle ) ); 175 | else if( bRequest == SET_PROTOCOL ) 176 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue", Fld_wValue_HIDSetProtocol ) ); 177 | else if( bRequest == SET_REPORT || bRequest == GET_REPORT ) 178 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue", Fld_wValue_HIDGetSetReport ) ); 179 | else 180 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue" ) ); 181 | } 182 | else if( isCDC ) 183 | { 184 | USBCtrlTransFieldType fldType = Fld_None; 185 | 186 | if( bRequest == SET_COMM_FEATURE || bRequest == GET_COMM_FEATURE || bRequest == CLEAR_COMM_FEATURE ) 187 | fldType = Fld_CDC_wValue_CommFeatureSelector; 188 | else if( bRequest == SET_AUX_LINE_STATE ) 189 | fldType = Fld_CDC_wValue_DisconnectConnect; 190 | else if( bRequest == SET_HOOK_STATE ) 191 | fldType = Fld_CDC_wValue_RelayConfig; 192 | else if( bRequest == PULSE_SETUP ) 193 | fldType = Fld_CDC_wValue_EnableDisable; 194 | else if( bRequest == SEND_PULSE ) 195 | fldType = Fld_CDC_wValue_Cycles; 196 | else if( bRequest == SET_PULSE_TIME ) 197 | fldType = Fld_CDC_wValue_Timing; 198 | else if( bRequest == RING_AUX_JACK ) 199 | fldType = Fld_CDC_wValue_NumberOfRings; 200 | else if( bRequest == SET_CONTROL_LINE_STATE ) 201 | fldType = Fld_CDC_wValue_ControlSignalBitmap; 202 | else if( bRequest == SEND_BREAK ) 203 | fldType = Fld_CDC_wValue_DurationOfBreak; 204 | else if( bRequest == SET_OPERATION_PARMS ) 205 | fldType = Fld_CDC_wValue_OperationParms; 206 | else if( bRequest == SET_LINE_PARMS ) 207 | fldType = Fld_CDC_wValue_LineStateChange; 208 | else if( bRequest == SET_UNIT_PARAMETER || bRequest == GET_UNIT_PARAMETER || bRequest == CLEAR_UNIT_PARAMETER ) 209 | fldType = Fld_CDC_wValue_UnitParameterStructure; 210 | else if( bRequest == SET_ETHERNET_MULTICAST_FILTERS ) 211 | fldType = Fld_CDC_wValue_NumberOfFilters; 212 | else if( bRequest == SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER || bRequest == GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER ) 213 | fldType = Fld_CDC_wValue_FilterNumber; 214 | else if( bRequest == SET_ETHERNET_PACKET_FILTER ) 215 | fldType = Fld_CDC_wValue_PacketFilterBitmap; 216 | else if( bRequest == GET_ETHERNET_STATISTIC ) 217 | fldType = Fld_CDC_wValue_EthFeatureSelector; 218 | else if( bRequest == SET_ATM_DATA_FORMAT ) 219 | fldType = Fld_CDC_wValue_ATMDataFormat; 220 | else if( bRequest == GET_ATM_DEVICE_STATISTICS ) 221 | fldType = Fld_CDC_wValue_ATMFeatureSelector; 222 | else if( bRequest == GET_ATM_VC_STATISTICS ) 223 | fldType = Fld_CDC_wValue_ATMVCFeatureSelector; 224 | 225 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue", fldType ) ); 226 | } 227 | else 228 | { 229 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue" ) ); 230 | } 231 | 232 | U8 hiByte = GetDataPayload( 3, 1 ); 233 | U8 loByte = GetDataPayload( 2, 1 ); 234 | if( isRecipientInterface ) 235 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex", Fld_wIndex_InterfaceNum ) ); 236 | else if( isRecipientEndpoint ) 237 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex", Fld_wIndex_Endpoint ) ); 238 | else 239 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex" ) ); 240 | 241 | pResults->AddFrame( GetDataPayloadField( 6, 2, address, "wLength" ) ); 242 | } 243 | 244 | void USBPacket::AddVendorSetupPacketFrame( USBAnalyzerResults* pResults, USBControlTransferParser& parser, U8 address ) 245 | { 246 | U8 bRequestType = GetDataPayload( 0, 1 ); 247 | U8 bRequest = GetDataPayload( 1, 1 ); 248 | U16 wIndex = GetDataPayload( 4, 2 ); 249 | U16 wLength = GetDataPayload( 6, 2 ); 250 | 251 | bool isRecipientInterface = ( bRequestType & 0x1f ) == 1; 252 | bool isRecipientEndpoint = ( bRequestType & 0x1f ) == 2; 253 | 254 | if( wLength ) 255 | pResults->AddFrame( GetDataPayloadField( 0, 1, address, "bmRequestType", Fld_bmRequestType, FF_SetupBegin ) ); 256 | else 257 | pResults->AddFrame( GetDataPayloadField( 0, 1, address, "bmRequestType", Fld_bmRequestType_NoData, FF_SetupBegin ) ); 258 | 259 | pResults->AddFrame( GetDataPayloadField( 1, 1, address, "bRequest", Fld_bRequest_Vendor ) ); 260 | 261 | pResults->AddFrame( GetDataPayloadField( 2, 2, address, "wValue" ) ); 262 | 263 | U8 hiByte = GetDataPayload( 3, 1 ); 264 | U8 loByte = GetDataPayload( 2, 1 ); 265 | if( isRecipientInterface ) 266 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex", Fld_wIndex_InterfaceNum ) ); 267 | else if( isRecipientEndpoint ) 268 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex", Fld_wIndex_Endpoint ) ); 269 | else 270 | pResults->AddFrame( GetDataPayloadField( 4, 2, address, "wIndex" ) ); 271 | 272 | pResults->AddFrame( GetDataPayloadField( 6, 2, address, "wLength" ) ); 273 | } 274 | 275 | U64 USBPacket::AddSetupPacketFrame( USBAnalyzerResults* pResults, USBControlTransferParser& parser, U8 address ) 276 | { 277 | AddSyncAndPidFrames( pResults ); 278 | 279 | U8 bRequestType = GetDataPayload( 0, 1 ); 280 | 281 | if( ( ( bRequestType >> 5 ) & 0x03 ) == 0 ) 282 | AddStandardSetupPacketFrame( pResults, parser, address ); 283 | else if( ( ( bRequestType >> 5 ) & 0x03 ) == 1 ) 284 | AddClassSetupPacketFrame( pResults, parser, address ); 285 | else if( ( ( bRequestType >> 5 ) & 0x03 ) == 2 ) 286 | AddVendorSetupPacketFrame( pResults, parser, address ); 287 | 288 | AddCRC16Frame( pResults ); 289 | AddEOPFrame( pResults ); 290 | 291 | pResults->CommitResults(); 292 | 293 | return mSampleEnd; 294 | } 295 | 296 | U64 USBPacket::AddDataStageFrames( USBAnalyzerResults* pResults, USBControlTransferParser& parser, U8 address ) 297 | { 298 | AddSyncAndPidFrames( pResults ); 299 | 300 | parser.ParseDataPacket( *this ); 301 | 302 | AddCRC16Frame( pResults ); 303 | AddEOPFrame( pResults ); 304 | 305 | pResults->CommitResults(); 306 | 307 | return mSampleEnd; 308 | } 309 | 310 | void USBRequest::SetFromPacket( USBPacket& p ) 311 | { 312 | bmRequestType = p.GetDataPayload( 0, 1 ); 313 | bRequest = p.GetDataPayload( 1, 1 ); 314 | wValue = p.GetDataPayload( 2, 2 ); 315 | wIndex = p.GetDataPayload( 4, 2 ); 316 | wLength = p.GetDataPayload( 5, 2 ); 317 | } 318 | 319 | void USBControlTransferParser::ResetParser() 320 | { 321 | mParsedOffset = mDescBytes = 0; 322 | mDescType = DT_Undefined; 323 | mDescSubtype = DST_Undefined; 324 | mLeftover = 0; 325 | 326 | mRequest.Clear(); 327 | 328 | mAddress = 0; 329 | 330 | pPacket = NULL; 331 | mPacketDataBytes = mPacketOffset = 0; 332 | 333 | mHidRepDescBytes = 0; 334 | memset( mHidRepDescItem, 0, sizeof mHidRepDescItem ); 335 | mHidIndentLevel = mHidItemCnt = 0; 336 | mHidUsagePageStack.clear(); 337 | } 338 | 339 | USBClassCodes USBControlTransferParser::GetClassCodeForInterface( U8 iface ) const 340 | { 341 | USBInterfaceClassesContainer::const_iterator srch( mInterfaceClasses.find( iface ) ); 342 | 343 | if( srch == mInterfaceClasses.end() ) 344 | return CC_DeferredToInterface; 345 | 346 | return srch->second; 347 | } 348 | 349 | bool USBControlTransferParser::IsCDCClassRequest() const 350 | { 351 | if( mRequest.IsClassRequest() && mRequest.IsRecipientInterface() ) 352 | { 353 | USBClassCodes classCode = GetClassCodeForInterface( mRequest.GetInterfaceNum() ); 354 | 355 | return classCode == CC_CDCData || classCode == CC_CommunicationsAndCDCControl; 356 | } 357 | 358 | return false; 359 | } 360 | 361 | bool USBControlTransferParser::ParseStringDescriptor() 362 | { 363 | // if this is a supported language table desriptor or actual string descriptor 364 | if( mRequest.GetRequestedDescriptorIndex() == 0 ) 365 | { 366 | while( mDescBytes > mParsedOffset && mPacketDataBytes > mPacketOffset ) 367 | { 368 | pResults->AddFrame( pPacket->GetDataPayloadField( mPacketOffset, 2, mAddress, "wLANGID", Fld_wLANGID ) ); 369 | mPacketOffset += 2; 370 | mParsedOffset += 2; 371 | } 372 | } 373 | else 374 | { 375 | if( mParsedOffset == 2 ) 376 | utf16StringDescriptor.clear(); 377 | 378 | // the actual UNICODE string 379 | while( mDescBytes > mParsedOffset && mPacketDataBytes > mPacketOffset ) 380 | { 381 | char16_t code_unit = static_cast( pPacket->GetDataPayload( mPacketOffset, 2 ) ); 382 | utf16StringDescriptor.push_back( code_unit ); 383 | 384 | pResults->AddFrame( pPacket->GetDataPayloadField( mPacketOffset, 2, mAddress, "wchar", Fld_Wchar ) ); 385 | mPacketOffset += 2; 386 | mParsedOffset += 2; 387 | } 388 | 389 | // do we have the entire string? 390 | if( mDescBytes == mParsedOffset ) 391 | { 392 | std::wstring_convert, char16_t> convert; 393 | std::string utf8_string_descriptor = convert.to_bytes( utf16StringDescriptor ); 394 | pResults->AddStringDescriptor( mAddress, mRequest.GetRequestedDescriptorIndex(), utf8_string_descriptor ); 395 | } 396 | } 397 | // return true if we've finished parsing the string descriptor, according to the parsed bLength 398 | return mDescBytes == mParsedOffset; 399 | } 400 | 401 | void USBControlTransferParser::ParseUnknownResponse() 402 | { 403 | USBCtrlTransFieldFrame f; 404 | f.mFlags = FF_None; 405 | f.mType = FT_ControlTransferField; 406 | 407 | while( mPacketDataBytes > mPacketOffset ) // more data in packet? 408 | { 409 | f.mStartingSampleInclusive = *( pPacket->mBitBeginSamples.begin() + ( mPacketOffset + 2 ) * 8 ); 410 | f.mEndingSampleInclusive = *( pPacket->mBitBeginSamples.begin() + ( mPacketOffset + 3 ) * 8 ); 411 | 412 | f.PackFrame( pPacket->mData[ mPacketOffset + 2 ], 1, mAddress, Fld_None, "byte" ); 413 | 414 | pResults->AddFrame( f ); 415 | 416 | ++mPacketOffset; 417 | ++mParsedOffset; 418 | } 419 | } 420 | 421 | USBStructField DeviceDescriptorFields[] = { 422 | //{"bLength", 1, Fld_None}, 423 | //{"bDescriptorType", 1, Fld_None}, 424 | { "bcdUSB", 2, Fld_BCD }, 425 | { "bDeviceClass", 1, Fld_ClassCode }, 426 | { "bDeviceSubClass", 1, Fld_None }, 427 | { "bDeviceProtocol", 1, Fld_None }, 428 | { "bMaxPacketSize0", 1, Fld_None }, 429 | { "idVendor", 2, Fld_wVendorId }, 430 | { "idProduct", 2, Fld_None }, 431 | { "bcdDevice", 2, Fld_BCD }, 432 | { "iManufacturer", 1, Fld_String }, 433 | { "iProduct", 1, Fld_String }, 434 | { "iSerialNumber", 1, Fld_String }, 435 | { "bNumConfigurations", 1, Fld_None }, 436 | 437 | { NULL, 0, Fld_None }, 438 | }; 439 | 440 | USBStructField DeviceQualifierDescriptorFields[] = { 441 | //{"bLength", 1, Fld_None}, 442 | //{"bDescriptorType", 1, Fld_None}, 443 | { "bcdUSB", 2, Fld_BCD }, 444 | { "bDeviceClass", 1, Fld_ClassCode }, 445 | { "bDeviceSubClass", 1, Fld_None }, 446 | { "bDeviceProtocol", 1, Fld_None }, 447 | { "bMaxPacketSize0", 1, Fld_None }, 448 | { "bNumConfigurations", 1, Fld_None }, 449 | { "bReserved", 1, Fld_None }, 450 | 451 | { NULL, 0, Fld_None }, 452 | }; 453 | 454 | USBStructField ConfigurationDescriptorFields[] = { 455 | //{"bLength", 1, Fld_None}, 456 | //{"bDescriptorType", 1, Fld_None}, 457 | { "wTotalLength", 2, Fld_None }, 458 | { "bNumInterfaces", 1, Fld_None }, 459 | { "bConfigurationValue", 1, Fld_None }, 460 | { "iConfiguration", 1, Fld_String }, 461 | { "bmAttributes", 1, Fld_bmAttributes_Config }, 462 | { "bMaxPower", 1, Fld_bMaxPower }, 463 | 464 | { NULL, 0, Fld_None }, 465 | }; 466 | 467 | USBStructField InterfaceDescriptorFields[] = { 468 | //{"bLength", 1, Fld_None}, 469 | //{"bDescriptorType", 1, Fld_None}, 470 | { "bInterfaceNumber", 1, Fld_None }, 471 | { "bAlternateSetting", 1, Fld_None }, 472 | { "bNumEndpoints", 1, Fld_None }, 473 | { "bInterfaceClass", 1, Fld_ClassCode }, 474 | { "bInterfaceSubClass", 1, Fld_None }, 475 | { "bInterfaceProtocol", 1, Fld_None }, 476 | { "iInterface", 1, Fld_String }, 477 | 478 | { NULL, 0, Fld_None }, 479 | }; 480 | 481 | USBStructField EndpointDescriptorFields[] = { 482 | //{"bLength", 1, Fld_None}, 483 | //{"bDescriptorType", 1, Fld_None}, 484 | { "bEndpointAddress", 1, Fld_bEndpointAddress }, 485 | { "bmAttributes", 1, Fld_bmAttributes_Endpoint }, 486 | { "wMaxPacketSize", 2, Fld_None }, 487 | { "bInterval", 1, Fld_None }, 488 | 489 | { NULL, 0, Fld_None }, 490 | }; 491 | 492 | USBStructField HIDDescriptorFields[] = { 493 | //{"bLength", 1, Fld_None}, 494 | //{"bDescriptorType", 1, Fld_None}, 495 | { "bcdHID", 2, Fld_BCD }, 496 | { "bCountryCode", 1, Fld_HID_bCountryCode }, 497 | { "bNumDescriptors", 1, Fld_None }, 498 | { "bDescriptorType", 1, Fld_bDescriptorType }, 499 | { "wDescriptorLength", 2, Fld_None }, 500 | 501 | // these are optional and depend of the number of HID class descriptors for this interface 502 | // we have enough for 16 503 | { "bDescriptorType", 1, Fld_bDescriptorType }, 504 | { "wDescriptorLength", 2, Fld_None }, 505 | { "bDescriptorType", 1, Fld_bDescriptorType }, 506 | { "wDescriptorLength", 2, Fld_None }, 507 | { "bDescriptorType", 1, Fld_bDescriptorType }, 508 | { "wDescriptorLength", 2, Fld_None }, 509 | { "bDescriptorType", 1, Fld_bDescriptorType }, 510 | { "wDescriptorLength", 2, Fld_None }, 511 | { "bDescriptorType", 1, Fld_bDescriptorType }, 512 | { "wDescriptorLength", 2, Fld_None }, 513 | { "bDescriptorType", 1, Fld_bDescriptorType }, 514 | { "wDescriptorLength", 2, Fld_None }, 515 | { "bDescriptorType", 1, Fld_bDescriptorType }, 516 | { "wDescriptorLength", 2, Fld_None }, 517 | { "bDescriptorType", 1, Fld_bDescriptorType }, 518 | { "wDescriptorLength", 2, Fld_None }, 519 | { "bDescriptorType", 1, Fld_bDescriptorType }, 520 | { "wDescriptorLength", 2, Fld_None }, 521 | { "bDescriptorType", 1, Fld_bDescriptorType }, 522 | { "wDescriptorLength", 2, Fld_None }, 523 | { "bDescriptorType", 1, Fld_bDescriptorType }, 524 | { "wDescriptorLength", 2, Fld_None }, 525 | { "bDescriptorType", 1, Fld_bDescriptorType }, 526 | { "wDescriptorLength", 2, Fld_None }, 527 | { "bDescriptorType", 1, Fld_bDescriptorType }, 528 | { "wDescriptorLength", 2, Fld_None }, 529 | { "bDescriptorType", 1, Fld_bDescriptorType }, 530 | { "wDescriptorLength", 2, Fld_None }, 531 | { "bDescriptorType", 1, Fld_bDescriptorType }, 532 | { "wDescriptorLength", 2, Fld_None }, 533 | { "bDescriptorType", 1, Fld_bDescriptorType }, 534 | { "wDescriptorLength", 2, Fld_None }, 535 | 536 | { NULL, 0, Fld_None }, 537 | }; 538 | 539 | // 540 | // CDC descriptors 541 | // 542 | 543 | USBStructField CDCHeaderFields[] = { 544 | //{"bLength", 1, Fld_None}, 545 | //{"bDescriptorType", 1, Fld_None}, 546 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 547 | 548 | { "bcdCDC", 2, Fld_BCD }, 549 | 550 | { NULL, 0, Fld_None }, 551 | }; 552 | 553 | USBStructField CDCCallManagementFields[] = { 554 | //{"bLength", 1, Fld_None}, 555 | //{"bDescriptorType", 1, Fld_None}, 556 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 557 | 558 | { "bmCapabilities", 1, Fld_CDC_bmCapabilities_Call }, 559 | { "bDataInterface", 1, Fld_None }, 560 | 561 | { NULL, 0, Fld_None }, 562 | }; 563 | 564 | USBStructField CDCAbstractControlManagementFields[] = { 565 | //{"bLength", 1, Fld_None}, 566 | //{"bDescriptorType", 1, Fld_None}, 567 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 568 | 569 | { "bmCapabilities", 1, Fld_CDC_bmCapabilities_AbstractCtrl }, 570 | 571 | { NULL, 0, Fld_None }, 572 | }; 573 | 574 | USBStructField CDCDirectLineManagementFields[] = { 575 | //{"bLength", 1, Fld_None}, 576 | //{"bDescriptorType", 1, Fld_None}, 577 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 578 | 579 | { "bmCapabilities", 1, Fld_CDC_bmCapabilities_DataLine }, 580 | 581 | { NULL, 0, Fld_None }, 582 | }; 583 | 584 | USBStructField CDCTelephoneRingerFields[] = { 585 | //{"bLength", 1, Fld_None}, 586 | //{"bDescriptorType", 1, Fld_None}, 587 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 588 | 589 | { "bRingerVolSteps", 1, Fld_CDC_bRingerVolSteps }, 590 | { "bNumRingerPatterns", 1, Fld_None }, 591 | 592 | { NULL, 0, Fld_None }, 593 | }; 594 | 595 | USBStructField CDCTelephoneOperationalModesFields[] = { 596 | //{"bLength", 1, Fld_None}, 597 | //{"bDescriptorType", 1, Fld_None}, 598 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 599 | 600 | { "bmCapabilities", 1, Fld_CDC_bmCapabilities_TelOpModes }, 601 | 602 | { NULL, 0, Fld_None }, 603 | }; 604 | 605 | USBStructField CDCTelephoneCallStateReportingFields[] = { 606 | //{"bLength", 1, Fld_None}, 607 | //{"bDescriptorType", 1, Fld_None}, 608 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 609 | 610 | { "bmCapabilities", 1, Fld_CDC_bmCapabilities_TelCallStateRep }, 611 | 612 | { NULL, 0, Fld_None }, 613 | }; 614 | 615 | USBStructField CDCUnionFields[] = { 616 | //{"bLength", 1, Fld_None}, 617 | //{"bDescriptorType", 1, Fld_None}, 618 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 619 | 620 | { "bMasterInterface", 1, Fld_None }, 621 | { "bSlaveInterface0", 1, Fld_None }, 622 | { "bSlaveInterface1", 1, Fld_None }, 623 | { "bSlaveInterface2", 1, Fld_None }, 624 | { "bSlaveInterface3", 1, Fld_None }, 625 | { "bSlaveInterface4", 1, Fld_None }, 626 | { "bSlaveInterface5", 1, Fld_None }, 627 | { "bSlaveInterface6", 1, Fld_None }, 628 | { "bSlaveInterface7", 1, Fld_None }, 629 | { "bSlaveInterface8", 1, Fld_None }, 630 | { "bSlaveInterface9", 1, Fld_None }, 631 | { "bSlaveInterface10", 1, Fld_None }, 632 | { "bSlaveInterface11", 1, Fld_None }, 633 | { "bSlaveInterface12", 1, Fld_None }, 634 | { "bSlaveInterface13", 1, Fld_None }, 635 | { "bSlaveInterface14", 1, Fld_None }, 636 | { "bSlaveInterface15", 1, Fld_None }, 637 | { "bSlaveInterface16", 1, Fld_None }, 638 | { "bSlaveInterface17", 1, Fld_None }, 639 | 640 | { NULL, 0, Fld_None }, 641 | }; 642 | 643 | USBStructField CDCCountrySelectionFields[] = { 644 | //{"bLength", 1, Fld_None}, 645 | //{"bDescriptorType", 1, Fld_None}, 646 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 647 | 648 | { "iCountryCodeRelDate", 1, Fld_String }, 649 | { "wCountryCode0", 2, Fld_None }, 650 | { "wCountryCode1", 2, Fld_None }, 651 | { "wCountryCode2", 2, Fld_None }, 652 | { "wCountryCode3", 2, Fld_None }, 653 | { "wCountryCode4", 2, Fld_None }, 654 | { "wCountryCode5", 2, Fld_None }, 655 | { "wCountryCode6", 2, Fld_None }, 656 | { "wCountryCode7", 2, Fld_None }, 657 | { "wCountryCode8", 2, Fld_None }, 658 | { "wCountryCode9", 2, Fld_None }, 659 | { "wCountryCode10", 2, Fld_None }, 660 | { "wCountryCode11", 2, Fld_None }, 661 | { "wCountryCode12", 2, Fld_None }, 662 | { "wCountryCode13", 2, Fld_None }, 663 | { "wCountryCode14", 2, Fld_None }, 664 | { "wCountryCode15", 2, Fld_None }, 665 | { "wCountryCode16", 2, Fld_None }, 666 | { "wCountryCode17", 2, Fld_None }, 667 | 668 | { NULL, 0, Fld_None }, 669 | }; 670 | 671 | USBStructField CDCUSBTerminalFields[] = { 672 | //{"bLength", 1, Fld_None}, 673 | //{"bDescriptorType", 1, Fld_None}, 674 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 675 | 676 | { "bEntityId", 1, Fld_None }, 677 | { "bInInterfaceNo", 1, Fld_None }, 678 | { "bOutInterfaceNo", 1, Fld_None }, 679 | { "bmOptions", 1, Fld_CDC_bmOptions }, 680 | { "bChildId0", 1, Fld_None }, 681 | { "bChildId1", 1, Fld_None }, 682 | { "bChildId2", 1, Fld_None }, 683 | { "bChildId3", 1, Fld_None }, 684 | { "bChildId4", 1, Fld_None }, 685 | { "bChildId5", 1, Fld_None }, 686 | { "bChildId6", 1, Fld_None }, 687 | { "bChildId7", 1, Fld_None }, 688 | { "bChildId8", 1, Fld_None }, 689 | { "bChildId9", 1, Fld_None }, 690 | { "bChildId10", 1, Fld_None }, 691 | { "bChildId11", 1, Fld_None }, 692 | { "bChildId12", 1, Fld_None }, 693 | { "bChildId13", 1, Fld_None }, 694 | { "bChildId14", 1, Fld_None }, 695 | { "bChildId15", 1, Fld_None }, 696 | { "bChildId16", 1, Fld_None }, 697 | { "bChildId17", 1, Fld_None }, 698 | 699 | { NULL, 0, Fld_None }, 700 | }; 701 | 702 | USBStructField CDCNetworkChannelTerminalFields[] = { 703 | //{"bLength", 1, Fld_None}, 704 | //{"bDescriptorType", 1, Fld_None}, 705 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 706 | 707 | { "bEntityId", 1, Fld_None }, 708 | { "iName", 1, Fld_String }, 709 | { "bChannelIndex", 1, Fld_None }, 710 | { "bPhysicalInterface", 1, Fld_CDC_bPhysicalInterface }, 711 | 712 | { NULL, 0, Fld_None }, 713 | }; 714 | 715 | USBStructField CDCProtocolUnitFields[] = { 716 | //{"bLength", 1, Fld_None}, 717 | //{"bDescriptorType", 1, Fld_None}, 718 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 719 | 720 | { "bEntityId", 1, Fld_None }, 721 | { "bProtocol", 1, Fld_CDC_bProtocol }, 722 | { "bOutInterfaceNo", 1, Fld_None }, 723 | { "bmOptions", 1, Fld_CDC_bmOptions }, 724 | { "bChildId0", 1, Fld_None }, 725 | { "bChildId1", 1, Fld_None }, 726 | { "bChildId2", 1, Fld_None }, 727 | { "bChildId3", 1, Fld_None }, 728 | { "bChildId4", 1, Fld_None }, 729 | { "bChildId5", 1, Fld_None }, 730 | { "bChildId6", 1, Fld_None }, 731 | { "bChildId7", 1, Fld_None }, 732 | { "bChildId8", 1, Fld_None }, 733 | { "bChildId9", 1, Fld_None }, 734 | { "bChildId10", 1, Fld_None }, 735 | { "bChildId11", 1, Fld_None }, 736 | { "bChildId12", 1, Fld_None }, 737 | { "bChildId13", 1, Fld_None }, 738 | { "bChildId14", 1, Fld_None }, 739 | { "bChildId15", 1, Fld_None }, 740 | { "bChildId16", 1, Fld_None }, 741 | { "bChildId17", 1, Fld_None }, 742 | 743 | { NULL, 0, Fld_None }, 744 | }; 745 | 746 | USBStructField CDCExtensionUnitFields[] = { 747 | //{"bLength", 1, Fld_None}, 748 | //{"bDescriptorType", 1, Fld_None}, 749 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 750 | 751 | { "bEntityId", 1, Fld_None }, 752 | { "bExtensionCode", 1, Fld_None }, 753 | { "iName", 1, Fld_String }, 754 | { "bChildId0", 1, Fld_None }, 755 | { "bChildId1", 1, Fld_None }, 756 | { "bChildId2", 1, Fld_None }, 757 | { "bChildId3", 1, Fld_None }, 758 | { "bChildId4", 1, Fld_None }, 759 | { "bChildId5", 1, Fld_None }, 760 | { "bChildId6", 1, Fld_None }, 761 | { "bChildId7", 1, Fld_None }, 762 | { "bChildId8", 1, Fld_None }, 763 | { "bChildId9", 1, Fld_None }, 764 | { "bChildId10", 1, Fld_None }, 765 | { "bChildId11", 1, Fld_None }, 766 | { "bChildId12", 1, Fld_None }, 767 | { "bChildId13", 1, Fld_None }, 768 | { "bChildId14", 1, Fld_None }, 769 | { "bChildId15", 1, Fld_None }, 770 | { "bChildId16", 1, Fld_None }, 771 | { "bChildId17", 1, Fld_None }, 772 | 773 | { NULL, 0, Fld_None }, 774 | }; 775 | 776 | USBStructField CDCMultiChannelFields[] = { 777 | //{"bLength", 1, Fld_None}, 778 | //{"bDescriptorType", 1, Fld_None}, 779 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 780 | 781 | { "bmCapabilities", 1, Fld_CDC_bmCapabilities_MultiChannel }, 782 | 783 | { NULL, 0, Fld_None }, 784 | }; 785 | 786 | USBStructField CDCCAPIControlFields[] = { 787 | //{"bLength", 1, Fld_None}, 788 | //{"bDescriptorType", 1, Fld_None}, 789 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 790 | 791 | { "bmCapabilities", 1, Fld_CDC_bmCapabilities_CAPIControl }, 792 | 793 | { NULL, 0, Fld_None }, 794 | }; 795 | 796 | USBStructField CDCEthernetNetworkingFields[] = { 797 | //{"bLength", 1, Fld_None}, 798 | //{"bDescriptorType", 1, Fld_None}, 799 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 800 | 801 | { "iMACAddress", 1, Fld_String }, 802 | { "bmEthernetStatistics", 4, Fld_CDC_bmEthernetStatistics }, 803 | { "wMaxSegmentSize", 2, Fld_None }, 804 | { "wNumberMCFilters", 2, Fld_CDC_wNumberMCFilters }, 805 | { "bNumberPowerFilters", 2, Fld_None }, 806 | 807 | { NULL, 0, Fld_None }, 808 | }; 809 | 810 | USBStructField CDCATMNetworkingFields[] = { 811 | //{"bLength", 1, Fld_None}, 812 | //{"bDescriptorType", 1, Fld_None}, 813 | { "bDescriptorSubtype", 1, Fld_CDC_DescriptorSubtype }, 814 | 815 | { "iEndSystemIdentifier", 1, Fld_String }, 816 | { "bmDataCapabilities", 1, Fld_CDC_bmDataCapabilities }, 817 | { "bmATMDeviceStatistics", 1, Fld_CDC_bmATMDeviceStatistics }, 818 | { "wType2MaxSegmentSize", 2, Fld_None }, 819 | { "wType3MaxSegmentSize", 2, Fld_None }, 820 | { "wMaxVC", 2, Fld_None }, 821 | 822 | { NULL, 0, Fld_None }, 823 | }; 824 | 825 | // 826 | // CDC data payloads 827 | // 828 | 829 | USBStructField CDCLineCodingFields[] = { 830 | { "dwDTERate", 4, Fld_CDC_dwDTERate }, 831 | { "bCharFormat", 1, Fld_CDC_bCharFormat }, 832 | { "bParityType", 1, Fld_CDC_bParityType }, 833 | { "bDataBits", 1, Fld_CDC_bDataBits }, 834 | 835 | { NULL, 0, Fld_None }, 836 | }; 837 | 838 | USBStructField CDCAbstractStateFields[] = { 839 | { "ABSTRACT_STATE", 2, Fld_CDC_Data_AbstractState }, 840 | 841 | { NULL, 0, Fld_None }, 842 | }; 843 | 844 | USBStructField CDCCountrySettingFields[] = { 845 | { "COUNTRY_SETTING", 2, Fld_CDC_Data_CountrySetting }, 846 | 847 | { NULL, 0, Fld_None }, 848 | }; 849 | 850 | USBStructField CDCRingerConfigFields[] = { 851 | { "dwRingerBitmap", 4, Fld_CDC_dwRingerBitmap }, 852 | 853 | { NULL, 0, Fld_None }, 854 | }; 855 | 856 | USBStructField CDCOperationModeFields[] = { 857 | { "Operation mode", 4, Fld_CDC_OperationMode }, 858 | 859 | { NULL, 0, Fld_None }, 860 | }; 861 | 862 | USBStructField CDCLineParmsFields[] = { 863 | { "wLength", 2, Fld_None }, 864 | { "dwRingerBitmap", 4, Fld_CDC_dwRingerBitmap }, 865 | { "dwLineState", 4, Fld_CDC_dwLineState }, 866 | { "dwCallState0", 4, Fld_CDC_dwCallState }, 867 | { "dwCallState1", 4, Fld_CDC_dwCallState }, 868 | { "dwCallState2", 4, Fld_CDC_dwCallState }, 869 | { "dwCallState3", 4, Fld_CDC_dwCallState }, 870 | { "dwCallState4", 4, Fld_CDC_dwCallState }, 871 | { "dwCallState5", 4, Fld_CDC_dwCallState }, 872 | { "dwCallState6", 4, Fld_CDC_dwCallState }, 873 | { "dwCallState7", 4, Fld_CDC_dwCallState }, 874 | { "dwCallState8", 4, Fld_CDC_dwCallState }, 875 | { "dwCallState9", 4, Fld_CDC_dwCallState }, 876 | { "dwCallState10", 4, Fld_CDC_dwCallState }, 877 | { "dwCallState11", 4, Fld_CDC_dwCallState }, 878 | { "dwCallState12", 4, Fld_CDC_dwCallState }, 879 | { "dwCallState13", 4, Fld_CDC_dwCallState }, 880 | { "dwCallState14", 4, Fld_CDC_dwCallState }, 881 | { "dwCallState15", 4, Fld_CDC_dwCallState }, 882 | { "dwCallState16", 4, Fld_CDC_dwCallState }, 883 | { "dwCallState17", 4, Fld_CDC_dwCallState }, 884 | { "dwCallState18", 4, Fld_CDC_dwCallState }, 885 | { "dwCallState19", 4, Fld_CDC_dwCallState }, 886 | 887 | { NULL, 0, Fld_None }, 888 | }; 889 | 890 | USBStructField CDCUnitParameterFields[] = { 891 | { "bEntityId", 1, Fld_None }, 892 | { "bParameterIndex", 1, Fld_None }, 893 | 894 | { NULL, 0, Fld_None }, 895 | }; 896 | 897 | USBStructField CDCUnsignedIntFields[] = { 898 | { "uint32", 4, Fld_None }, 899 | 900 | { NULL, 0, Fld_None }, 901 | }; 902 | 903 | USBStructField CDCATMDefaultVCFields[] = { 904 | { "VPI", 1, Fld_None }, 905 | { "VCI", 2, Fld_None }, 906 | 907 | { NULL, 0, Fld_None }, 908 | }; 909 | 910 | void USBControlTransferParser::ParseStructure( USBStructField* descFields ) 911 | { 912 | int descFldCnt = 0; 913 | int descFldOffset = 2; // we already handled bLength and bDescriptorType in the caller 914 | 915 | // find the first non-parsed or partially parsed descriptor field in this packet 916 | while( descFldOffset < mParsedOffset && descFields[ descFldCnt ].numBytes != 0 ) // haven't reached the last field? 917 | { 918 | int fldBytes = descFields[ descFldCnt ].numBytes; 919 | 920 | // did we get the LS byte in the previous packet? 921 | if( fldBytes > 1 && descFldOffset + fldBytes > mParsedOffset ) 922 | { 923 | U8 bytesRemaining = mParsedOffset - descFldOffset; 924 | 925 | USBCtrlTransFieldFrame f; 926 | f.mFlags = FF_None; 927 | f.mStartingSampleInclusive = pPacket->mBitBeginSamples[ 16 ]; 928 | f.mEndingSampleInclusive = pPacket->mBitBeginSamples[ 16 + bytesRemaining * 8 ]; 929 | 930 | U32 newVal = pPacket->GetDataPayload( 0, bytesRemaining ) << ( fldBytes - bytesRemaining ) * 8; 931 | newVal = newVal | mLeftover; 932 | f.PackFrame( newVal, 2, mAddress, descFields[ descFldCnt ].formatter, descFields[ descFldCnt ].name ); 933 | 934 | pResults->AddFrame( f ); 935 | 936 | ++mPacketOffset; 937 | ++mParsedOffset; 938 | } 939 | 940 | descFldOffset += fldBytes; 941 | ++descFldCnt; 942 | } 943 | 944 | while( descFields[ descFldCnt ].numBytes != 0 // haven't reached the last field? 945 | && mDescBytes > mParsedOffset // more bytes in descriptor? 946 | && mPacketDataBytes > mPacketOffset // more data in packet? 947 | && mDescBytes >= 948 | mParsedOffset + 949 | descFields[ descFldCnt ].numBytes ) // the next field won't consume more than we have in the received descriptor 950 | { 951 | int fldBytes = descFields[ descFldCnt ].numBytes; 952 | 953 | USBCtrlTransFieldType formatter = descFields[ descFldCnt ].formatter; 954 | 955 | // get the interface number and interface class/subclass 956 | if( descFields == InterfaceDescriptorFields ) 957 | { 958 | if( descFldCnt == 0 ) // bInterfaceNumber 959 | mInterfaceNumber = pPacket->GetDataPayload( mPacketOffset, 1 ); 960 | else if( descFldCnt == 3 ) // bInterfaceClass 961 | mInterfaceClasses[ mInterfaceNumber ] = ( USBClassCodes )pPacket->GetDataPayload( mPacketOffset, 1 ); 962 | else if( descFldCnt == 4 && mInterfaceClasses[ mInterfaceNumber ] == CC_HID ) // bInterfaceSubClass 963 | formatter = Fld_HIDSubClass; 964 | else if( descFldCnt == 5 && mInterfaceClasses[ mInterfaceNumber ] == CC_HID ) // bInterfaceProtocol 965 | formatter = Fld_HIDProtocol; 966 | } 967 | 968 | // does this field spill over into the next packet? 969 | U8 flags = 0; 970 | if( fldBytes > mPacketDataBytes - mPacketOffset ) 971 | { 972 | fldBytes = mPacketDataBytes - mPacketOffset; 973 | mLeftover = pPacket->GetDataPayload( mPacketOffset, fldBytes ); 974 | 975 | flags = FF_FieldIncomplete; 976 | } 977 | 978 | pResults->AddFrame( 979 | pPacket->GetDataPayloadField( mPacketOffset, fldBytes, mAddress, descFields[ descFldCnt ].name, formatter, flags ) ); 980 | 981 | mPacketOffset += fldBytes; 982 | mParsedOffset += fldBytes; 983 | descFldOffset += fldBytes; 984 | 985 | ++descFldCnt; 986 | } 987 | } 988 | 989 | void USBControlTransferParser::ParseStandardDescriptor() 990 | { 991 | USBStructField* descFields = NULL; 992 | if( mDescType == DT_DEVICE ) 993 | descFields = DeviceDescriptorFields; 994 | else if( mDescType == DT_DEVICE_QUALIFIER ) 995 | descFields = DeviceQualifierDescriptorFields; 996 | else if( mDescType == DT_CONFIGURATION || mDescType == DT_OTHER_SPEED_CONFIGURATION ) 997 | descFields = ConfigurationDescriptorFields; 998 | else if( mDescType == DT_INTERFACE ) 999 | descFields = InterfaceDescriptorFields; 1000 | else if( mDescType == DT_ENDPOINT ) 1001 | descFields = EndpointDescriptorFields; 1002 | else if( mDescType == DT_HID && mInterfaceClasses[ mInterfaceNumber ] == CC_HID ) 1003 | descFields = HIDDescriptorFields; 1004 | else if( mDescType == DT_CDC_CS_INTERFACE || 1005 | mDescType == DT_CDC_CS_ENDPOINT && ( mInterfaceClasses[ mInterfaceNumber ] == CC_CommunicationsAndCDCControl || 1006 | mInterfaceClasses[ mInterfaceNumber ] == CC_CDCData ) ) 1007 | { 1008 | if( mDescSubtype == DST_HEADER ) 1009 | descFields = CDCHeaderFields; 1010 | else if( mDescSubtype == DST_CALL_MANAGEMENT ) 1011 | descFields = CDCCallManagementFields; 1012 | else if( mDescSubtype == DST_ABSTRACT_CONTROL_MANAGEMENT ) 1013 | descFields = CDCAbstractControlManagementFields; 1014 | else if( mDescSubtype == DST_DIRECT_LINE_MANAGEMENT ) 1015 | descFields = CDCDirectLineManagementFields; 1016 | else if( mDescSubtype == DST_TELEPHONE_RINGER ) 1017 | descFields = CDCTelephoneRingerFields; 1018 | else if( mDescSubtype == DST_TELEPHONE_CALL_AND_LINE_STATE ) 1019 | descFields = CDCTelephoneCallStateReportingFields; 1020 | else if( mDescSubtype == DST_UNION ) 1021 | descFields = CDCUnionFields; 1022 | else if( mDescSubtype == DST_COUNTRY_SELECTION ) 1023 | descFields = CDCCountrySelectionFields; 1024 | else if( mDescSubtype == DST_TELEPHONE_OPERATIONAL_MODES ) 1025 | descFields = CDCTelephoneOperationalModesFields; 1026 | else if( mDescSubtype == DST_USB_TERMINAL ) 1027 | descFields = CDCUSBTerminalFields; 1028 | else if( mDescSubtype == DST_NETWORK_CHANNEL_TERMINAL ) 1029 | descFields = CDCNetworkChannelTerminalFields; 1030 | else if( mDescSubtype == DST_PROTOCOL_UNIT ) 1031 | descFields = CDCProtocolUnitFields; 1032 | else if( mDescSubtype == DST_EXTENSION_UNIT ) 1033 | descFields = CDCExtensionUnitFields; 1034 | else if( mDescSubtype == DST_MULTI_CHANNEL_MANAGEMENT ) 1035 | descFields = CDCMultiChannelFields; 1036 | else if( mDescSubtype == DST_CAPI_CONTROL_MANAGEMENT ) 1037 | descFields = CDCCAPIControlFields; 1038 | else if( mDescSubtype == DST_ETHERNET_NETWORKING ) 1039 | descFields = CDCEthernetNetworkingFields; 1040 | else if( mDescSubtype == DST_ATM_NETWORKING ) 1041 | descFields = CDCATMNetworkingFields; 1042 | } 1043 | 1044 | if( descFields ) 1045 | ParseStructure( descFields ); 1046 | 1047 | // parse the rest of the descriptor or packet as raw bytes 1048 | 1049 | while( mDescBytes > mParsedOffset // more bytes in descriptor? 1050 | && mPacketDataBytes > mPacketOffset ) // more data in packet? 1051 | { 1052 | USBCtrlTransFieldFrame f; 1053 | f.mFlags = FF_None; 1054 | f.mStartingSampleInclusive = *( pPacket->mBitBeginSamples.begin() + ( mPacketOffset + 2 ) * 8 ); 1055 | f.mEndingSampleInclusive = *( pPacket->mBitBeginSamples.begin() + ( mPacketOffset + 3 ) * 8 ); 1056 | 1057 | f.PackFrame( pPacket->mData[ mPacketOffset + 2 ], 1, mAddress, Fld_None, "byte" ); 1058 | 1059 | pResults->AddFrame( f ); 1060 | 1061 | ++mPacketOffset; 1062 | ++mParsedOffset; 1063 | } 1064 | 1065 | // reset the parser if we have completeted parsing the descriptor 1066 | if( mDescBytes == mParsedOffset ) 1067 | { 1068 | mParsedOffset = 0; 1069 | mDescType = DT_Undefined; 1070 | } 1071 | } 1072 | 1073 | void USBControlTransferParser::ParseHIDReportDescriptor() 1074 | { 1075 | // more bytes in the packet? 1076 | while( mPacketDataBytes > mPacketOffset ) 1077 | { 1078 | int itemStartOffset = mPacketOffset; 1079 | 1080 | // we need to have at least the first byte of the item to get the item size 1081 | if( mHidRepDescBytes == 0 ) 1082 | mHidRepDescItem[ mHidRepDescBytes++ ] = pPacket->GetDataPayload( mPacketOffset++, 1 ); 1083 | 1084 | U8 itemSize = GetNumHIDItemDataBytes( mHidRepDescItem[ 0 ] ) + 1; 1085 | 1086 | // do we have the entire item in this packet? 1087 | if( itemSize - mHidRepDescBytes <= mPacketDataBytes - mPacketOffset ) 1088 | { 1089 | // we have the entire item - copy it to the item buffer 1090 | while( mHidRepDescBytes < itemSize ) 1091 | mHidRepDescItem[ mHidRepDescBytes++ ] = pPacket->GetDataPayload( mPacketOffset++, 1 ); 1092 | 1093 | // end collection decreases the indent level 1094 | if( IsHIDItemEndCollection( mHidRepDescItem[ 0 ] ) && mHidIndentLevel > 0 ) 1095 | --mHidIndentLevel; 1096 | else if( IsHIDItemUsagePage( mHidRepDescItem[ 0 ] ) ) 1097 | SetHIDUsagePage( *( U16* )( mHidRepDescItem + 1 ) ); 1098 | else if( IsHIDItemPush( mHidRepDescItem[ 0 ] ) ) 1099 | PushHIDUsagePage(); 1100 | else if( IsHIDItemPop( mHidRepDescItem[ 0 ] ) ) 1101 | PopHIDUsagePage(); 1102 | 1103 | // make the frame with all the data 1104 | pResults->AddFrame( pPacket->GetHIDItem( itemStartOffset, mPacketOffset - itemStartOffset, mHidRepDescItem, mHidIndentLevel, 1105 | GetHIDUsagePage(), mHidItemCnt == 0 ? FF_DataDescriptor : FF_None ) ); 1106 | 1107 | // collection increases the indent level 1108 | if( IsHIDItemCollection( mHidRepDescItem[ 0 ] ) ) 1109 | ++mHidIndentLevel; 1110 | 1111 | // start with a new packet 1112 | mHidRepDescBytes = 0; 1113 | memset( mHidRepDescItem, 0, sizeof mHidRepDescItem ); 1114 | 1115 | mHidItemCnt++; 1116 | } 1117 | else 1118 | { 1119 | // we don't have the entire item, so just make a frame and store what data we do have 1120 | pResults->AddFrame( pPacket->GetHIDItem( itemStartOffset, mPacketOffset - itemStartOffset, mHidRepDescItem, mHidIndentLevel, 1121 | GetHIDUsagePage(), FF_FieldIncomplete ) ); 1122 | while( mPacketDataBytes > mPacketOffset ) 1123 | mHidRepDescItem[ mHidRepDescBytes++ ] = pPacket->GetDataPayload( mPacketOffset++, 1 ); 1124 | } 1125 | } 1126 | } 1127 | 1128 | void USBControlTransferParser::ParseCDCDataStage() 1129 | { 1130 | USBCDCRequestCode reqCode = ( USBCDCRequestCode )mRequest.bRequest; 1131 | 1132 | if( reqCode == GET_COMM_FEATURE || reqCode == SET_COMM_FEATURE ) 1133 | { 1134 | mDescBytes = mRequest.wLength; 1135 | mParsedOffset = 0; 1136 | 1137 | if( mRequest.wValue == 1 ) // ABSTRACT_STATE 1138 | ParseStructure( CDCAbstractStateFields ); 1139 | else if( mRequest.wValue == 2 ) // COUNTRY_SETTING 1140 | ParseStructure( CDCCountrySettingFields ); 1141 | else 1142 | ParseUnknownResponse(); 1143 | } 1144 | else if( reqCode == SET_LINE_CODING || reqCode == GET_LINE_CODING ) 1145 | { 1146 | mDescBytes = mRequest.wLength; 1147 | mParsedOffset = 0; 1148 | ParseStructure( CDCLineCodingFields ); 1149 | } 1150 | else if( reqCode == SET_RINGER_PARMS || reqCode == GET_RINGER_PARMS ) 1151 | { 1152 | mDescBytes = mRequest.wLength; 1153 | mParsedOffset = 0; 1154 | ParseStructure( CDCRingerConfigFields ); 1155 | } 1156 | else if( reqCode == GET_OPERATION_PARMS ) 1157 | { 1158 | mDescBytes = mRequest.wLength; 1159 | mParsedOffset = 0; 1160 | ParseStructure( CDCOperationModeFields ); 1161 | } 1162 | else if( reqCode == SET_LINE_PARMS || reqCode == GET_LINE_PARMS ) 1163 | { 1164 | mDescBytes = mRequest.wLength; 1165 | mParsedOffset = 0; 1166 | ParseStructure( CDCLineParmsFields ); 1167 | } 1168 | else if( reqCode == SET_UNIT_PARAMETER || reqCode == GET_UNIT_PARAMETER ) 1169 | { 1170 | mDescBytes = mRequest.wLength; 1171 | mParsedOffset = 0; 1172 | ParseStructure( CDCUnitParameterFields ); 1173 | } 1174 | else if( reqCode == GET_ETHERNET_STATISTIC || reqCode == GET_ATM_DEVICE_STATISTICS || reqCode == GET_ATM_VC_STATISTICS ) 1175 | { 1176 | mDescBytes = mRequest.wLength; 1177 | mParsedOffset = 0; 1178 | ParseStructure( CDCUnsignedIntFields ); 1179 | } 1180 | else if( reqCode == SET_ATM_DEFAULT_VC ) 1181 | { 1182 | mDescBytes = mRequest.wLength; 1183 | mParsedOffset = 0; 1184 | ParseStructure( CDCATMDefaultVCFields ); 1185 | } 1186 | else 1187 | { 1188 | ParseUnknownResponse(); 1189 | } 1190 | } 1191 | 1192 | void USBControlTransferParser::ParseDataPacket( USBPacket& packet ) 1193 | { 1194 | pPacket = &packet; 1195 | mPacketOffset = 0; 1196 | mPacketDataBytes = packet.mData.size() - 4; 1197 | 1198 | if( mRequest.IsRequestedStandardDescriptor() ) 1199 | { 1200 | while( mPacketDataBytes > mPacketOffset ) 1201 | { 1202 | U8 interfaceClass = mInterfaceClasses[ mInterfaceNumber ]; 1203 | 1204 | if( mParsedOffset == 0 ) // are we just starting with this descriptor? 1205 | { 1206 | // handle the bLength field 1207 | pResults->AddFrame( packet.GetDataPayloadField( mPacketOffset, 1, mAddress, "bLength", Fld_None, FF_DataDescriptor ) ); 1208 | mDescBytes = packet.GetDataPayload( mPacketOffset, 1 ); 1209 | ++mPacketOffset; 1210 | ++mParsedOffset; 1211 | } 1212 | else if( mParsedOffset == 1 ) 1213 | { 1214 | mDescType = USBDescriptorType( packet.GetDataPayload( mPacketOffset, 1 ) ); 1215 | 1216 | if( IsStandardDescriptor( mDescType ) || interfaceClass == CC_HID || interfaceClass == CC_CommunicationsAndCDCControl || 1217 | interfaceClass == CC_CDCData ) 1218 | pResults->AddFrame( packet.GetDataPayloadField( mPacketOffset, 1, mAddress, "bDescriptorType", Fld_bDescriptorType ) ); 1219 | else 1220 | pResults->AddFrame( 1221 | packet.GetDataPayloadField( mPacketOffset, 1, mAddress, "bDescriptorType", Fld_bDescriptorType_Other ) ); 1222 | 1223 | ++mPacketOffset; 1224 | ++mParsedOffset; 1225 | } 1226 | else if( mParsedOffset == 2 && ( interfaceClass == CC_CommunicationsAndCDCControl || interfaceClass == CC_CDCData ) && 1227 | ( mDescType == DT_CDC_CS_INTERFACE || mDescType == DT_CDC_CS_ENDPOINT ) ) 1228 | { 1229 | mDescSubtype = USBCDCDescriptorSubtype( packet.GetDataPayload( mPacketOffset, 1 ) ); 1230 | pResults->AddFrame( 1231 | packet.GetDataPayloadField( mPacketOffset, 1, mAddress, "bDescriptorSubtype", Fld_CDC_DescriptorSubtype ) ); 1232 | 1233 | ++mPacketOffset; 1234 | ++mParsedOffset; 1235 | } 1236 | else 1237 | { 1238 | if( mDescType == DT_STRING ) 1239 | { 1240 | bool detected_complete_descriptor = ParseStringDescriptor(); 1241 | if( detected_complete_descriptor && mPacketDataBytes > mPacketOffset ) 1242 | { 1243 | // we finished parsing the complete string descriptor, according to bLength, however there are still bytes left in 1244 | // the packet. 1245 | std::cerr << "String descriptor length shorter than packet length. Packet length: " << mPacketDataBytes 1246 | << " processed bytes: " << mPacketOffset << " reported descriptor length: " << mDescBytes << "\n"; 1247 | break; 1248 | } 1249 | } 1250 | else 1251 | { 1252 | ParseStandardDescriptor(); 1253 | } 1254 | } 1255 | } 1256 | } 1257 | else if( mRequest.IsRequestedHIDReportDescriptor() ) 1258 | { 1259 | ParseHIDReportDescriptor(); 1260 | } 1261 | else if( IsCDCClassRequest() ) 1262 | { 1263 | ParseCDCDataStage(); 1264 | } 1265 | else 1266 | { 1267 | ParseUnknownResponse(); 1268 | } 1269 | } 1270 | 1271 | void USBControlTransferPacketHandler::Init( USBAnalyzerResults* pResults, int address ) 1272 | { 1273 | mResults = pResults; 1274 | mAddress = address; 1275 | 1276 | mCtrlTransLastReceived = CTS_StatusEnd; 1277 | mCtrlTransParser.SetAnalyzerResults( mResults ); 1278 | } 1279 | 1280 | U64 USBControlTransferPacketHandler::ResetControlTransferParser( USBPacket& pckt, USBFrameFlags flag ) 1281 | { 1282 | mCtrlTransLastReceived = CTS_StatusEnd; 1283 | mCtrlTransParser.ResetParser(); 1284 | return pckt.AddPacketFrames( mResults, flag ); 1285 | } 1286 | 1287 | U64 USBControlTransferPacketHandler::HandleControlTransfer( USBPacket& pckt ) 1288 | { 1289 | // 1290 | // setup stage 1291 | // 1292 | 1293 | if( pckt.mPID == PID_SETUP ) 1294 | { 1295 | USBFrameFlags flag = mCtrlTransLastReceived == CTS_StatusEnd ? FF_None : FF_UnexpectedPacket; 1296 | mCtrlTransLastReceived = CTS_SetupToken; 1297 | return pckt.AddPacketFrames( mResults, flag ); 1298 | } 1299 | 1300 | if( mCtrlTransLastReceived == CTS_SetupToken ) 1301 | { 1302 | // we must get a DATA0 after the SETUP pid 1303 | if( pckt.mPID != PID_DATA0 ) 1304 | return ResetControlTransferParser( pckt ); 1305 | 1306 | // remember the request code and the response direction 1307 | mCtrlTransRequest = USBRequestCode( pckt.GetDataPayload( 1, 1 ) ); 1308 | mCtrlTransDeviceToHost = ( pckt.GetDataPayload( 0, 1 ) & 0x80 ) != 0; 1309 | 1310 | mCtrlTransParser.ResetParser(); 1311 | mCtrlTransParser.SetRequest( pckt ); 1312 | mCtrlTransParser.SetAddress( mAddress ); 1313 | 1314 | mCtrlTransLastReceived = CTS_SetupData; 1315 | return pckt.AddSetupPacketFrame( mResults, mCtrlTransParser, mAddress ); 1316 | } 1317 | else if( mCtrlTransLastReceived == CTS_SetupData ) 1318 | { 1319 | // the DATA0 setup request must be ACKed by the device 1320 | if( pckt.mPID != PID_ACK ) 1321 | return ResetControlTransferParser( pckt ); 1322 | 1323 | mCtrlTransLastReceived = CTS_SetupAck; 1324 | return pckt.AddPacketFrames( mResults ); 1325 | } 1326 | 1327 | // 1328 | // data stage 1329 | // 1330 | 1331 | if( mCtrlTransLastReceived == CTS_SetupAck || mCtrlTransLastReceived == CTS_DataEnd ) 1332 | { 1333 | if( pckt.mPID != PID_IN && pckt.mPID != PID_OUT ) 1334 | return ResetControlTransferParser( pckt ); 1335 | 1336 | USBFrameFlags flag = mCtrlTransLastReceived == CTS_SetupAck ? FF_DataBegin : FF_None; 1337 | 1338 | if( mCtrlTransDeviceToHost ) 1339 | mCtrlTransLastReceived = pckt.mPID == PID_IN ? CTS_DataInToken : CTS_StatusOutToken; 1340 | else 1341 | mCtrlTransLastReceived = pckt.mPID == PID_OUT ? CTS_DataOutToken : CTS_StatusInToken; 1342 | 1343 | if( mCtrlTransLastReceived == CTS_StatusOutToken || mCtrlTransLastReceived == CTS_StatusInToken ) 1344 | flag = FF_StatusBegin; 1345 | 1346 | return pckt.AddPacketFrames( mResults, flag ); 1347 | } 1348 | else if( mCtrlTransLastReceived == CTS_DataInToken ) 1349 | { 1350 | if( pckt.mPID == PID_NAK ) 1351 | { 1352 | mCtrlTransLastReceived = CTS_DataEnd; 1353 | return pckt.AddPacketFrames( mResults, FF_DataInNAKed ); 1354 | } 1355 | 1356 | if( pckt.mPID == PID_STALL ) 1357 | return ResetControlTransferParser( pckt, FF_StatusEnd ); 1358 | 1359 | if( pckt.mPID != PID_DATA0 && pckt.mPID != PID_DATA1 ) 1360 | return ResetControlTransferParser( pckt ); 1361 | 1362 | mCtrlTransLastReceived = CTS_DataInData; 1363 | 1364 | return pckt.AddDataStageFrames( mResults, mCtrlTransParser, mAddress ); 1365 | } 1366 | else if( mCtrlTransLastReceived == CTS_DataOutToken ) 1367 | { 1368 | if( pckt.mPID != PID_DATA0 && pckt.mPID != PID_DATA1 ) 1369 | return ResetControlTransferParser( pckt ); 1370 | 1371 | mCtrlTransLastReceived = CTS_DataOutData; 1372 | 1373 | return pckt.AddDataStageFrames( mResults, mCtrlTransParser, mAddress ); 1374 | } 1375 | else if( mCtrlTransLastReceived == CTS_DataInData ) 1376 | { 1377 | // a host can only ACK the data in packet 1378 | if( pckt.mPID != PID_ACK ) 1379 | return ResetControlTransferParser( pckt ); 1380 | 1381 | mCtrlTransLastReceived = CTS_DataEnd; 1382 | 1383 | return pckt.AddPacketFrames( mResults ); 1384 | } 1385 | else if( mCtrlTransLastReceived == CTS_DataOutData ) 1386 | { 1387 | if( pckt.mPID == PID_STALL ) 1388 | return ResetControlTransferParser( pckt, FF_DataEnd ); 1389 | 1390 | if( pckt.mPID != PID_NAK && pckt.mPID != PID_ACK ) 1391 | return ResetControlTransferParser( pckt ); 1392 | 1393 | mCtrlTransLastReceived = CTS_DataEnd; 1394 | 1395 | return pckt.AddPacketFrames( mResults, pckt.mPID == PID_NAK ? FF_DataOutNAKed : FF_None ); 1396 | } 1397 | 1398 | // 1399 | // status stage - IN/OUT tokens of the status stage are handled in the first block of the data stage 1400 | // 1401 | 1402 | if( mCtrlTransLastReceived == CTS_StatusInToken ) 1403 | { 1404 | if( pckt.mPID != PID_DATA0 && pckt.mPID != PID_DATA1 && pckt.mPID != PID_STALL && pckt.mPID != PID_NAK ) 1405 | return ResetControlTransferParser( pckt ); 1406 | 1407 | USBFrameFlags flag; 1408 | if( pckt.mPID == PID_STALL ) 1409 | { 1410 | mCtrlTransLastReceived = CTS_StatusEnd; 1411 | flag = FF_StatusEnd; 1412 | } 1413 | else if( pckt.mPID == PID_NAK ) 1414 | { 1415 | mCtrlTransLastReceived = CTS_StatusInNAKed; 1416 | flag = FF_StatusInNAKed; 1417 | } 1418 | else 1419 | { // DATA0/1 1420 | mCtrlTransLastReceived = CTS_StatusInDataEmpty; 1421 | flag = FF_None; 1422 | } 1423 | 1424 | return pckt.AddPacketFrames( mResults, flag ); 1425 | } 1426 | else if( mCtrlTransLastReceived == CTS_StatusOutToken ) 1427 | { 1428 | if( pckt.mPID != PID_DATA0 && pckt.mPID != PID_DATA1 ) 1429 | return ResetControlTransferParser( pckt ); 1430 | 1431 | mCtrlTransLastReceived = CTS_StatusOutDataEmpty; 1432 | 1433 | return pckt.AddPacketFrames( mResults ); 1434 | } 1435 | else if( mCtrlTransLastReceived == CTS_StatusInDataEmpty ) 1436 | { 1437 | if( pckt.mPID != PID_ACK ) 1438 | return ResetControlTransferParser( pckt ); 1439 | 1440 | mCtrlTransLastReceived = CTS_StatusEnd; 1441 | 1442 | return pckt.AddPacketFrames( mResults, FF_StatusEnd ); 1443 | } 1444 | else if( mCtrlTransLastReceived == CTS_StatusOutDataEmpty ) 1445 | { 1446 | if( pckt.mPID != PID_ACK && pckt.mPID != PID_STALL && pckt.mPID != PID_NAK ) 1447 | return ResetControlTransferParser( pckt ); 1448 | 1449 | USBFrameFlags flag; 1450 | if( pckt.mPID == PID_ACK || pckt.mPID == PID_STALL ) 1451 | { 1452 | mCtrlTransLastReceived = CTS_StatusEnd; 1453 | flag = FF_StatusEnd; 1454 | } 1455 | else 1456 | { 1457 | mCtrlTransLastReceived = CTS_StatusOutDataNAKed; 1458 | flag = FF_StatusOutNAKed; 1459 | } 1460 | 1461 | return pckt.AddPacketFrames( mResults, flag ); 1462 | } 1463 | else if( mCtrlTransLastReceived == CTS_StatusOutDataNAKed ) 1464 | { 1465 | if( pckt.mPID != PID_OUT ) 1466 | return ResetControlTransferParser( pckt ); 1467 | 1468 | mCtrlTransLastReceived = CTS_StatusOutToken; 1469 | 1470 | return pckt.AddPacketFrames( mResults ); 1471 | } 1472 | else if( mCtrlTransLastReceived == CTS_StatusInNAKed ) 1473 | { 1474 | if( pckt.mPID != PID_IN ) 1475 | return ResetControlTransferParser( pckt ); 1476 | 1477 | mCtrlTransLastReceived = CTS_StatusInToken; 1478 | 1479 | return pckt.AddPacketFrames( mResults ); 1480 | } 1481 | 1482 | assert( mCtrlTransLastReceived == CTS_StatusEnd ); 1483 | 1484 | return ResetControlTransferParser( pckt, FF_None ); 1485 | } 1486 | -------------------------------------------------------------------------------- /src/USBAnalyzerResults.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "USBAnalyzerResults.h" 11 | #include "USBAnalyzer.h" 12 | #include "USBAnalyzerSettings.h" 13 | #include "USBLookupTables.h" 14 | 15 | std::string GetCollectionData( U8 data ) 16 | { 17 | switch( data ) 18 | { 19 | case 0x00: 20 | return "Physical"; 21 | case 0x01: 22 | return "Application"; 23 | case 0x02: 24 | return "Logical"; 25 | case 0x03: 26 | return "Report"; 27 | case 0x04: 28 | return "Named Array"; 29 | case 0x05: 30 | return "Usage Switch"; 31 | case 0x06: 32 | return "Usage Modifier"; 33 | } 34 | 35 | if( data >= 0x07 && data <= 0x7F ) 36 | return "Reserved"; 37 | 38 | return "Vendor-defined"; 39 | } 40 | 41 | std::string GetInputData( U8 data1, U8 data2 ) 42 | { 43 | std::string retVal; 44 | 45 | retVal += data1 & 0x01 ? "Constant" : "Data"; 46 | retVal += ','; 47 | retVal += data1 & 0x02 ? "Variable" : "Array"; 48 | retVal += ','; 49 | retVal += data1 & 0x04 ? "Relative" : "Absolute"; 50 | retVal += ','; 51 | retVal += data1 & 0x08 ? "Wrap" : "No wrap"; 52 | retVal += ','; 53 | retVal += data1 & 0x10 ? "Non Linear" : "Linear"; 54 | retVal += ','; 55 | retVal += data1 & 0x20 ? "No Preferred" : "Preferred State"; 56 | retVal += ','; 57 | retVal += data1 & 0x40 ? "Null State" : "No Null position"; 58 | retVal += ','; 59 | 60 | retVal += data2 & 0x01 ? "Buffered Bytes" : "Bit Field"; 61 | 62 | return retVal; 63 | } 64 | 65 | std::string GetOutputAndFeatureData( U8 data1, U8 data2 ) 66 | { 67 | std::string retVal; 68 | 69 | retVal += data1 & 0x01 ? "Constant" : "Data"; 70 | retVal += ','; 71 | retVal += data1 & 0x02 ? "Variable" : "Array"; 72 | retVal += ','; 73 | retVal += data1 & 0x04 ? "Relative" : "Absolute"; 74 | retVal += ','; 75 | retVal += data1 & 0x08 ? "Wrap" : "No wrap"; 76 | retVal += ','; 77 | retVal += data1 & 0x10 ? "Non Linear" : "Linear"; 78 | retVal += ','; 79 | retVal += data1 & 0x20 ? "No Preferred" : "Preferred State"; 80 | retVal += ','; 81 | retVal += data1 & 0x40 ? "Null State" : "No Null position"; 82 | retVal += ','; 83 | retVal += data1 & 0x80 ? "Volatile" : "Non Volatile"; 84 | retVal += ','; 85 | 86 | retVal += data2 & 0x01 ? "Buffered Bytes" : "Bit Field"; 87 | 88 | return retVal; 89 | } 90 | 91 | std::string GetHIDItemUsage( U16 usagePage, const U8* pItem ) 92 | { 93 | // do we have an extended usage? 94 | if( GetNumHIDItemDataBytes( *pItem ) == 4 ) 95 | { 96 | U16 usagePage = *( U16* )( pItem + 3 ); 97 | U16 usageID = *( U16* )( pItem + 1 ); 98 | return GetHIDUsageName( usagePage, usageID ); 99 | } 100 | 101 | return GetHIDUsageName( usagePage, *( U16* )( pItem + 1 ) ); 102 | } 103 | 104 | std::string GetSignedDataValue( const U8* pItem, DisplayBase display_base ) 105 | { 106 | int numBytes = GetNumHIDItemDataBytes( pItem[ 0 ] ); // number of data bytes 107 | 108 | if( numBytes == 0 ) 109 | return "0"; 110 | 111 | int sVal; 112 | U64 uVal; 113 | 114 | if( numBytes == 1 ) 115 | { 116 | sVal = S8( pItem[ 1 ] ); 117 | uVal = pItem[ 1 ]; 118 | } 119 | else if( numBytes == 2 ) 120 | { 121 | sVal = *( S16* )( pItem + 1 ); 122 | uVal = *( U16* )( pItem + 1 ); 123 | } 124 | else 125 | { 126 | sVal = *( S32* )( pItem + 1 ); 127 | uVal = *( U32* )( pItem + 1 ); 128 | } 129 | 130 | std::string retVal; 131 | 132 | if( display_base == Decimal ) 133 | { 134 | // we can't use AnalyzerHelpers::GetNumberString because we need signed values 135 | char buff[ 32 ]; 136 | sprintf( buff, "%i", sVal ); 137 | retVal = buff; 138 | } 139 | else 140 | { 141 | retVal = int2str_sal( uVal, display_base, numBytes * 8 ); 142 | } 143 | 144 | return retVal; 145 | } 146 | 147 | std::string GetUnitExponent( U8 data ) 148 | { 149 | if( data > 0xF0 ) 150 | return "undefined"; 151 | 152 | const char* results[] = { "0", "1", "2", "3", "4", "5", "6", "7", "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1" }; 153 | 154 | return results[ data ]; 155 | } 156 | 157 | std::string GetUnit( const U8* pItem ) 158 | { 159 | U32 val = *( U32* )( pItem + 1 ); 160 | 161 | U8 firstNibble = val & 0x0f; 162 | 163 | // branch by quality measures 164 | if( val & 0x000000f0 ) // Length 165 | { 166 | switch( firstNibble ) 167 | { 168 | case 1: 169 | return "Centimeter"; 170 | case 2: 171 | return "Radian"; 172 | case 3: 173 | return "Inch"; 174 | case 4: 175 | return "Degree"; 176 | } 177 | } 178 | else if( val & 0x00000f00 ) 179 | { // Mass 180 | 181 | if( firstNibble == 1 || firstNibble == 2 ) 182 | return "Gram"; 183 | else if( firstNibble == 3 || firstNibble == 4 ) 184 | return "Slug"; 185 | } 186 | else if( val & 0x0000f000 ) 187 | { // Time 188 | 189 | if( firstNibble >= 1 || firstNibble <= 4 ) 190 | return "Second"; 191 | } 192 | else if( val & 0x000f0000 ) 193 | { // Temperature 194 | 195 | if( firstNibble == 1 || firstNibble == 2 ) 196 | return "Kelvin"; 197 | else if( firstNibble == 3 || firstNibble == 4 ) 198 | return "Fahrenheit"; 199 | } 200 | else if( val & 0x00f00000 ) 201 | { // Current 202 | 203 | if( firstNibble >= 1 || firstNibble <= 4 ) 204 | return "Ampere"; 205 | } 206 | else if( val & 0x0f000000 ) 207 | { // Luminosity 208 | 209 | if( firstNibble >= 1 || firstNibble <= 4 ) 210 | return "Candela"; 211 | } 212 | 213 | return "Undefined Unit"; 214 | } 215 | 216 | 217 | USBAnalyzerResults::USBAnalyzerResults( USBAnalyzer* analyzer, USBAnalyzerSettings* settings ) 218 | : mSettings( settings ), mAnalyzer( analyzer ) 219 | { 220 | } 221 | 222 | USBAnalyzerResults::~USBAnalyzerResults() 223 | { 224 | } 225 | 226 | double USBAnalyzerResults::GetSampleTime( S64 sample ) const 227 | { 228 | return ( sample - mAnalyzer->GetTriggerSample() ) / double( mAnalyzer->GetSampleRate() ); 229 | } 230 | 231 | std::string USBAnalyzerResults::GetSampleTimeStr( S64 sample ) const 232 | { 233 | char time_str[ 128 ]; 234 | AnalyzerHelpers::GetTimeString( sample, mAnalyzer->GetTriggerSample(), mAnalyzer->GetSampleRate(), time_str, sizeof( time_str ) ); 235 | 236 | // remove trailing zeros 237 | char* pEnd = strchr( time_str, 0 ) - 1; 238 | while( pEnd > time_str && *pEnd == '0' ) 239 | { 240 | *pEnd = '\0'; 241 | --pEnd; 242 | } 243 | 244 | return time_str; 245 | } 246 | 247 | void GetHIDReportDescriptorItemFrameDesc( const Frame& frm, DisplayBase display_base, std::vector& results ) 248 | { 249 | if( ( frm.mFlags & 0x3F ) == FF_FieldIncomplete ) 250 | { 251 | results.push_back( "" ); 252 | results.push_back( "" ); 253 | results.push_back( "" ); 254 | return; 255 | } 256 | 257 | const USBHidRepDescItemFrame& f( static_cast( frm ) ); 258 | 259 | std::string indent( f.GetIndentLevel() * 4, ' ' ); 260 | 261 | const U8* pItem = f.GetItem(); 262 | U8 itemSize = GetNumHIDItemDataBytes( pItem[ 0 ] ) + 1; 263 | 264 | // make the raw values (always HEX) 265 | std::string rawVal; 266 | for( int cnt = 0; cnt < itemSize; cnt++ ) 267 | { 268 | if( cnt ) 269 | rawVal += ' '; 270 | 271 | rawVal += int2str_sal( pItem[ cnt ], Hexadecimal, 8 ); 272 | } 273 | 274 | size_t padding_chars; 275 | if( rawVal.size() >= 15 ) 276 | padding_chars = 1; 277 | else 278 | padding_chars = 16 - rawVal.size(); 279 | 280 | std::string padding( padding_chars, ' ' ); 281 | std::string desc; 282 | 283 | const U8 firstByte = *pItem; 284 | const U8 tagType = ( firstByte & 0xfc ); 285 | const U8 bType = ( firstByte >> 2 ) & 0x03; 286 | const U8 bTag = firstByte >> 4; 287 | 288 | if( bType == 0 ) // Main items 289 | { 290 | if( bTag == 0x0A ) 291 | desc = "Collection (" + GetCollectionData( pItem[ 1 ] ) + ")"; 292 | else if( bTag == 0x0C ) 293 | desc = "End Collection"; 294 | else if( bTag == 0x08 ) 295 | desc = "Input (" + GetInputData( pItem[ 1 ], pItem[ 2 ] ) + ")"; 296 | else if( bTag == 0x09 ) 297 | desc = "Output (" + GetOutputAndFeatureData( pItem[ 1 ], pItem[ 2 ] ) + ")"; 298 | else if( bTag == 0x0B ) 299 | desc = "Feature (" + GetOutputAndFeatureData( pItem[ 1 ], pItem[ 2 ] ) + ")"; 300 | else 301 | desc = "Unknown Main item. bTag=" + int2str_sal( bTag, display_base, 4 ); 302 | } 303 | else if( bType == 1 ) 304 | { // Global 305 | 306 | if( bTag == 0x00 ) 307 | desc = "Usage Page (" + GetHIDUsagePageName( ( pItem[ 2 ] << 8 ) | pItem[ 1 ] ) + ")"; 308 | else if( bTag == 0x01 ) 309 | desc = "Logical Minimum (" + GetSignedDataValue( pItem, display_base ) + ")"; 310 | else if( bTag == 0x02 ) 311 | desc = "Logical Maximum (" + GetSignedDataValue( pItem, display_base ) + ")"; 312 | else if( bTag == 0x03 ) 313 | desc = "Physical Minimum (" + GetSignedDataValue( pItem, display_base ) + ")"; 314 | else if( bTag == 0x04 ) 315 | desc = "Physical Maximum (" + GetSignedDataValue( pItem, display_base ) + ")"; 316 | else if( bTag == 0x05 ) 317 | desc = "Unit Exponent (" + GetUnitExponent( pItem[ 1 ] ) + ")"; 318 | else if( bTag == 0x06 ) 319 | desc = "Unit (" + GetUnit( pItem ) + ")"; 320 | else if( bTag == 0x07 ) 321 | desc = "Report Size (" + int2str_sal( pItem[ 1 ], display_base, 8 ) + ")"; 322 | else if( bTag == 0x08 ) 323 | desc = "Report ID (" + int2str_sal( pItem[ 1 ], display_base, 8 ) + ")"; 324 | else if( bTag == 0x09 ) 325 | desc = "Report Count (" + int2str_sal( pItem[ 1 ], display_base, 8 ) + ")"; 326 | else if( bTag == 0x0A ) 327 | desc = "Push"; 328 | else if( bTag == 0x0B ) 329 | desc = "Pop"; 330 | else 331 | desc = "Unknown Global item bTag=" + int2str_sal( bTag, display_base, 4 ); 332 | } 333 | else if( bType == 2 ) 334 | { // Local 335 | 336 | if( bTag == 0 ) 337 | desc = "Usage (" + GetHIDItemUsage( f.GetUsagePage(), pItem ) + ")"; 338 | else if( bTag == 1 ) 339 | desc = "Usage Minimum (" + GetHIDItemUsage( f.GetUsagePage(), pItem ) + ")"; 340 | else if( bTag == 2 ) 341 | desc = "Usage Maximum (" + GetHIDItemUsage( f.GetUsagePage(), pItem ) + ")"; 342 | else if( bTag == 3 ) 343 | desc = "Designator Index (" + int2str_sal( pItem[ 1 ], display_base, 8 ) + ")"; 344 | else if( bTag == 4 ) 345 | desc = "Designator Minimum (" + int2str_sal( pItem[ 1 ], display_base, 8 ) + ")"; 346 | else if( bTag == 5 ) 347 | desc = "Designator Maximum (" + int2str_sal( pItem[ 1 ], display_base, 8 ) + ")"; 348 | else if( bTag == 7 ) 349 | desc = "String Index (" + int2str_sal( pItem[ 1 ], display_base, 8 ) + ")"; 350 | else if( bTag == 8 ) 351 | desc = "String Minimum (" + int2str_sal( pItem[ 1 ], display_base, 8 ) + ")"; 352 | else if( bTag == 9 ) 353 | desc = "String Maximum (" + int2str_sal( pItem[ 1 ], display_base, 8 ) + ")"; 354 | else if( bTag == 10 ) 355 | desc = "Delimiter (" + int2str_sal( pItem[ 1 ], display_base, 8 ) + ")"; 356 | else 357 | desc = "Unknown Local item bTag=" + int2str_sal( bTag, display_base, 4 ); 358 | } 359 | else 360 | { 361 | desc = "Unknown item type (" + int2str_sal( tagType, Hexadecimal, 8 ) + ")"; 362 | } 363 | 364 | results.push_back( rawVal + padding + indent + desc ); 365 | results.push_back( desc ); 366 | results.push_back( rawVal + desc ); 367 | results.push_back( rawVal ); 368 | } 369 | 370 | void GetCtrlTransFrameDesc( const Frame& frm, DisplayBase display_base, std::vector& results, 371 | const USBAnalyzerResults::USBStringContainer& stringDescriptors ) 372 | { 373 | const USBCtrlTransFieldFrame& f( static_cast( frm ) ); 374 | 375 | // create value string for the general case 376 | U16 bcnt = f.GetNumBytes(); 377 | U32 val = f.GetData(); 378 | std::string val_str = int2str_sal( val, display_base, bcnt * 8 ); 379 | 380 | // handle details for specific fields 381 | std::string desc; 382 | USBCtrlTransFieldType formatter = f.GetFormatter(); 383 | if( formatter == Fld_bRequest_Standard ) 384 | { 385 | desc = " "; 386 | desc += GetRequestName( val ); 387 | } 388 | else if( formatter == Fld_bRequest_Class ) 389 | { 390 | desc = " (Class request)"; 391 | } 392 | else if( formatter == Fld_bRequest_HID ) 393 | { 394 | desc = " "; 395 | desc += GetHIDRequestName( val ); 396 | desc += " (HID class)"; 397 | } 398 | else if( formatter == Fld_bRequest_CDC ) 399 | { 400 | desc = " "; 401 | desc += GetCDCRequestName( val ); 402 | desc += " (CDC class)"; 403 | } 404 | else if( formatter == Fld_bRequest_Vendor ) 405 | { 406 | desc = " (Vendor request)"; 407 | } 408 | else if( formatter == Fld_bmRequestType || formatter == Fld_bmRequestType_NoData ) 409 | { 410 | desc = " Data direction="; 411 | if( formatter == Fld_bmRequestType_NoData ) 412 | desc += "No data"; 413 | else 414 | desc += ( val & 0x80 ) ? "Device to host" : "Host to device"; 415 | 416 | desc += ", Type="; 417 | switch( ( val & 0x60 ) >> 5 ) 418 | { 419 | case 0: 420 | desc += "Standard"; 421 | break; 422 | case 1: 423 | desc += "Class"; 424 | break; 425 | case 2: 426 | desc += "Vendor"; 427 | break; 428 | case 3: 429 | desc += "Reserved"; 430 | break; 431 | } 432 | 433 | desc += ", Recipient="; 434 | switch( val & 0x1f ) 435 | { 436 | case 0: 437 | desc += "Device"; 438 | break; 439 | case 1: 440 | desc += "Interface"; 441 | break; 442 | case 2: 443 | desc += "Endpoint"; 444 | break; 445 | case 3: 446 | desc += "Other"; 447 | break; 448 | default: 449 | desc += "Reserved"; 450 | break; 451 | } 452 | } 453 | else if( formatter == Fld_wValue_Address ) 454 | { 455 | desc += " Address=" + int2str_sal( val, display_base, 8 ); 456 | } 457 | else if( formatter == Fld_wValue_Descriptor ) 458 | { 459 | U8 descriptor = ( val >> 8 ) & 0xff; 460 | U8 index = val & 0xff; 461 | 462 | desc = " Descriptor="; 463 | desc += GetDescriptorName( descriptor ); 464 | desc += ", Index=" + int2str_sal( index, display_base, 8 ); 465 | } 466 | else if( formatter == Fld_wValue_HIDSetIdle ) 467 | { 468 | U8 duration = ( val >> 8 ) & 0xff; 469 | U8 reportID = val & 0xff; 470 | 471 | desc = " Duration="; 472 | if( duration == 0 ) 473 | desc += "Indefinite"; 474 | else 475 | desc += int2str( duration ) + "ms"; 476 | 477 | desc += ", Report ID=" + int2str_sal( reportID, display_base, 8 ); 478 | } 479 | else if( formatter == Fld_wValue_HIDGetIdle ) 480 | { 481 | desc = " Report ID=" + int2str_sal( val & 0xff, display_base, 8 ); 482 | } 483 | else if( formatter == Fld_wValue_HIDSetProtocol ) 484 | { 485 | desc = " Protocol="; 486 | if( val == 0 ) 487 | desc += "Boot protocol"; 488 | else if( val == 1 ) 489 | desc += "Report protocol"; 490 | else 491 | desc += ""; 492 | } 493 | else if( formatter == Fld_wValue_HIDGetSetReport ) 494 | { 495 | U8 reportType = ( val >> 8 ) & 0xff; 496 | U8 reportID = val & 0xff; 497 | 498 | desc = " Report type="; 499 | if( reportType == 1 ) 500 | desc += "Input"; 501 | else if( reportType == 2 ) 502 | desc += "Output"; 503 | else if( reportType == 3 ) 504 | desc += "Feature"; 505 | else 506 | desc += "Reserved"; 507 | 508 | desc += ", Report ID=" + int2str_sal( reportID, display_base, 8 ); 509 | } 510 | else if( formatter == Fld_bDescriptorType ) 511 | { 512 | desc = " "; 513 | desc += GetDescriptorName( val & 0xff ); 514 | } 515 | else if( formatter == Fld_bDescriptorType_Other ) 516 | { 517 | desc = " "; 518 | } 519 | else if( formatter == Fld_Wchar ) 520 | { 521 | // utf-8 encode the utf-16 character. 522 | std::u16string utf_16_str; 523 | char16_t u16_char = static_cast( val ); 524 | utf_16_str.push_back( u16_char ); 525 | std::wstring_convert, char16_t> convert; 526 | std::string utf8_str = convert.to_bytes( utf_16_str ); 527 | desc = std::string( " char='" ) + utf8_str + '\''; 528 | } 529 | else if( formatter == Fld_wLANGID ) 530 | { 531 | desc = " Language=" + std::string( GetLangName( val ) ); 532 | } 533 | else if( formatter == Fld_wVendorId ) 534 | { 535 | desc = " Vendor=" + std::string( GetVendorName( val ) ); 536 | } 537 | else if( formatter == Fld_bMaxPower ) 538 | { 539 | desc += " " + int2str( val * 2 ) + "mA"; 540 | } 541 | else if( formatter == Fld_bmAttributes_Endpoint ) 542 | { 543 | desc = " "; 544 | switch( val & 0x03 ) 545 | { 546 | case 0: 547 | desc += "Control"; 548 | break; 549 | case 1: 550 | desc += "Isochronous"; 551 | break; 552 | case 2: 553 | desc += "Bulk"; 554 | break; 555 | case 3: 556 | desc += "Interrupt"; 557 | break; 558 | } 559 | 560 | if( ( val & 0x03 ) == 1 ) // if isochronous 561 | { 562 | desc += ", "; 563 | switch( ( val >> 2 ) & 0x03 ) 564 | { 565 | case 0: 566 | desc += "No Synchronization"; 567 | break; 568 | case 1: 569 | desc += "Asynchronous"; 570 | break; 571 | case 2: 572 | desc += "Adaptive"; 573 | break; 574 | case 3: 575 | desc += "Synchronous"; 576 | break; 577 | } 578 | 579 | desc += ", "; 580 | switch( ( val >> 4 ) & 0x03 ) 581 | { 582 | case 0: 583 | desc += "Data endpoint"; 584 | break; 585 | case 1: 586 | desc += "Feedback endpoint"; 587 | break; 588 | case 2: 589 | desc += "Implicit feedback Data endpoint"; 590 | break; 591 | case 3: 592 | desc += "Reserved"; 593 | break; 594 | } 595 | } 596 | } 597 | else if( formatter == Fld_bmAttributes_Config ) 598 | { 599 | desc = ( val & 0x40 ) ? " Self powered" : " Bus powered"; 600 | desc += ", Remote wakeup "; 601 | desc += ( val & 0x20 ) ? "supported" : "unsupported"; 602 | } 603 | else if( formatter == Fld_bEndpointAddress || formatter == Fld_wIndex_Endpoint ) 604 | { 605 | desc = " Endpoint=" + int2str( val & 0x0F ); 606 | desc += ", Direction="; 607 | desc += ( val & 0x80 ) == 0 ? "OUT" : "IN"; 608 | } 609 | else if( formatter == Fld_BCD ) 610 | { 611 | desc = " "; 612 | if( val & 0xf000 ) 613 | desc += int2str( val >> 12 ); 614 | 615 | desc += int2str( ( val >> 8 ) & 0x0f ); 616 | desc += "."; 617 | desc += int2str( ( val >> 4 ) & 0x0f ); 618 | desc += int2str( val & 0x0f ); 619 | } 620 | else if( formatter == Fld_ClassCode ) 621 | { 622 | desc = " "; 623 | desc += GetUSBClassName( ( U8 )val ); 624 | } 625 | else if( formatter == Fld_HIDSubClass ) 626 | { 627 | if( val == 0 ) 628 | desc = " None"; 629 | else if( val == 1 ) 630 | desc = " Boot Interface"; 631 | else 632 | desc = " Reserved"; 633 | } 634 | else if( formatter == Fld_HIDProtocol ) 635 | { 636 | if( val == 0 ) 637 | desc = " None"; 638 | else if( val == 1 ) 639 | desc = " Keyboard"; 640 | else if( val == 2 ) 641 | desc = " Mouse"; 642 | else 643 | desc = " Reserved"; 644 | } 645 | else if( formatter == Fld_wIndex_InterfaceNum ) 646 | { 647 | desc = " Interface=" + int2str_sal( val & 0xff, display_base, 8 ); 648 | } 649 | else if( formatter == Fld_HID_bCountryCode ) 650 | { 651 | desc = " Country="; 652 | desc += GetHIDCountryName( ( U8 )val ); 653 | } 654 | else if( formatter == Fld_String ) 655 | { 656 | if( val != 0 ) 657 | { 658 | USBAnalyzerResults::USBStringContainer::const_iterator srch( 659 | stringDescriptors.find( std::make_pair( f.GetAddress(), ( int )val ) ) ); 660 | if( srch != stringDescriptors.end() ) 661 | desc = " " + srch->second; 662 | } 663 | } 664 | else if( formatter == Fld_CDC_wValue_CommFeatureSelector ) 665 | { 666 | if( val == 0 ) 667 | desc = " RESERVED"; 668 | else if( val == 1 ) 669 | desc = " ABSTRACT_STATE"; 670 | else if( val == 2 ) 671 | desc = " COUNTRY_SETTING"; 672 | } 673 | else if( formatter == Fld_CDC_wValue_DisconnectConnect ) 674 | { 675 | if( val == 0 ) 676 | desc = " Disconnect"; 677 | else if( val == 1 ) 678 | desc = " Connect"; 679 | } 680 | else if( formatter == Fld_CDC_wValue_RelayConfig ) 681 | { 682 | if( val == 0 ) 683 | desc = " ON_HOOK"; 684 | else if( val == 1 ) 685 | desc = " OFF_HOOK"; 686 | else if( val == 2 ) 687 | desc = " SNOOPING"; 688 | } 689 | else if( formatter == Fld_CDC_wValue_EnableDisable ) 690 | { 691 | if( val == 0xffff ) 692 | desc = " Disengage the holding circuit"; 693 | else 694 | desc = " Prepare for a pulse-dialing cycle"; 695 | } 696 | else if( formatter == Fld_CDC_wValue_Cycles ) 697 | { 698 | desc = " Number of cycles"; 699 | } 700 | else if( formatter == Fld_CDC_wValue_Timing ) 701 | { 702 | U8 hi = ( val >> 8 ) & 0xff; 703 | U8 lo = val & 0xff; 704 | 705 | desc = " Break time=" + int2str( hi ) + "ms, make time=" + int2str( lo ); 706 | } 707 | else if( formatter == Fld_CDC_wValue_NumberOfRings ) 708 | { 709 | desc = " Number of rings"; 710 | } 711 | else if( formatter == Fld_CDC_wValue_ControlSignalBitmap ) 712 | { 713 | desc = ( val & 2 ) ? " Activate carrier" : " Deactivate carrier"; 714 | desc += ( val & 1 ) ? ", DTE Present" : ", DTE Not Present"; 715 | } 716 | else if( formatter == Fld_CDC_wValue_DurationOfBreak ) 717 | { 718 | if( val == 0xffff ) 719 | desc = " Break until receive SEND_BREAK with wValue of 0"; 720 | else 721 | desc = " Duration of break " + int2str( val ) + "ms"; 722 | } 723 | else if( formatter == Fld_CDC_wValue_OperationParms || formatter == Fld_CDC_OperationMode ) 724 | { 725 | if( val == 0 ) 726 | desc = " Simple Mode"; 727 | else if( val == 1 ) 728 | desc = " Standalone Mode"; 729 | else if( val == 2 ) 730 | desc = " Host Centric Mode"; 731 | } 732 | else if( formatter == Fld_CDC_wValue_LineStateChange ) 733 | { 734 | if( val == 0 ) 735 | desc = " Drop the active call on the line."; 736 | else if( val == 1 ) 737 | desc = " Start a new call on the line."; 738 | else if( val == 2 ) 739 | desc = " Apply ringing to the line."; 740 | else if( val == 3 ) 741 | desc = " Remove ringing from the line."; 742 | else if( val == 4 ) 743 | desc = " Switch to a specific call on the line."; 744 | } 745 | else if( formatter == Fld_CDC_wValue_UnitParameterStructure ) 746 | { 747 | desc = " bEntityId=" + int2str_sal( val & 0xff, display_base, 8 ); 748 | desc += ", bParameterIndex=" + int2str_sal( val >> 8, display_base, 8 ); 749 | } 750 | else if( formatter == Fld_CDC_wValue_NumberOfFilters ) 751 | { 752 | desc = " Number of filters"; 753 | } 754 | else if( formatter == Fld_CDC_wValue_FilterNumber ) 755 | { 756 | desc = " Filter number"; 757 | } 758 | else if( formatter == Fld_CDC_wValue_PacketFilterBitmap ) 759 | { 760 | desc = " PACKET_TYPE_MULTICAST="; 761 | desc += ( ( val & 0x10 ) ? "1" : "0" ); 762 | desc += ", PACKET_TYPE_BROADCAST="; 763 | desc += ( ( val & 0x08 ) ? "1" : "0" ); 764 | desc += ", PACKET_TYPE_DIRECTED="; 765 | desc += ( ( val & 0x04 ) ? "1" : "0" ); 766 | desc += ", PACKET_TYPE_ALL_MULTICAST="; 767 | desc += ( ( val & 0x02 ) ? "1" : "0" ); 768 | desc += ", PACKET_TYPE_PROMISCUOUS="; 769 | desc += ( ( val & 0x01 ) ? "1" : "0" ); 770 | } 771 | else if( formatter == Fld_CDC_wValue_EthFeatureSelector ) 772 | { 773 | desc = " "; 774 | desc += GetCDCEthFeatureSelectorName( val ); 775 | } 776 | else if( formatter == Fld_CDC_wValue_ATMDataFormat ) 777 | { 778 | if( val == 1 ) 779 | desc = " Concatenated ATM cells"; 780 | else if( val == 2 ) 781 | desc = " ATM header template + concatenated ATM cell payloads"; 782 | else if( val == 3 ) 783 | desc = " AAL 5 SDU"; 784 | } 785 | else if( formatter == Fld_CDC_wValue_ATMFeatureSelector ) 786 | { 787 | desc = " "; 788 | desc += GetCDCATMFeatureSelectorName( val ); 789 | } 790 | else if( formatter == Fld_CDC_wValue_ATMVCFeatureSelector ) 791 | { 792 | if( val == 1 ) 793 | desc = " VC_US_CELLS_SENT"; 794 | else if( val == 2 ) 795 | desc = " VC_DS_CELLS_RECEIVED"; 796 | } 797 | else if( formatter == Fld_CDC_DescriptorSubtype ) 798 | { 799 | desc = " "; 800 | desc += GetCDCDescriptorSubtypeName( val ); 801 | } 802 | else if( formatter == Fld_CDC_bmCapabilities_Call ) 803 | { 804 | desc = ( val & 0x02 ) ? " Call management over a Data Class interface" : " Call management only over the Comm Class interface"; 805 | desc += ", "; 806 | desc += ( val & 0x01 ) ? "Device handles call management itself" : "Device doesn't handle call management itself"; 807 | } 808 | else if( formatter == Fld_CDC_bmCapabilities_AbstractCtrl ) 809 | { 810 | desc = " Network_Connection notification "; 811 | desc += ( val & 0x08 ) ? "supported" : "not supported"; 812 | desc += "; Send_Break request "; 813 | desc += ( val & 0x04 ) ? "supported" : "not supported"; 814 | desc += "; Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding and the notification Serial_State "; 815 | desc += ( val & 0x02 ) ? "supported" : "not supported"; 816 | desc += "; Set_Comm_Feature, Clear_Comm_Feature and Get_Comm_Feature "; 817 | desc += ( val & 0x01 ) ? "supported" : "not supported"; 818 | } 819 | else if( formatter == Fld_CDC_bmCapabilities_DataLine ) 820 | { 821 | if( val & 0x04 ) 822 | desc = "Device requires extra Pulse_Setup request during pulse dialing sequence to disengage holding circuit"; 823 | if( val & 0x02 ) 824 | desc += 825 | ( desc.empty() ? "" : "; " ) + 826 | std::string( 827 | "Device supports the request combination of Set_Aux_Line_State, Ring_Aux_Jack, and notification Aux_Jack_Hook_State" ); 828 | if( val & 0x01 ) 829 | desc += ( desc.empty() ? "" : "; " ) + 830 | std::string( "Device supports the request combination of Pulse_Setup, Send_Pulse, and Set_Pulse_Time" ); 831 | if( !desc.empty() ) 832 | desc = " " + desc; 833 | } 834 | else if( formatter == Fld_CDC_bRingerVolSteps ) 835 | { 836 | desc = " "; 837 | if( val == 0 ) 838 | desc += "256 discrete volume steps"; 839 | else 840 | desc = int2str( val ) + " discrete volume steps"; 841 | } 842 | else if( formatter == Fld_CDC_bmCapabilities_TelOpModes ) 843 | { 844 | desc = ( val & 0x04 ) ? " Supports Computer Centric mode" : " Does not support Computer Centric mode"; 845 | desc += "; "; 846 | desc += ( val & 0x02 ) ? "Supports Standalone mode" : "Does not support Standalone mode"; 847 | desc += "; "; 848 | desc += ( val & 0x01 ) ? "Supports Simple mode" : "Does not support Simple mode"; 849 | } 850 | else if( formatter == Fld_CDC_bmCapabilities_TelCallStateRep ) 851 | { 852 | desc = ( val & 0x20 ) ? " Supports line state change notification." : " Does not support line state change notification"; 853 | desc += "; "; 854 | desc = ( val & 0x10 ) ? "Can report DTMF digits input remotely over the telephone line" 855 | : "Cannot report DTMF digits input remotely over the telephone line"; 856 | desc += "; "; 857 | desc = ( val & 0x08 ) ? "Reports only incoming ringing" : "Reports incoming distinctive ringing patterns"; 858 | desc += "; "; 859 | desc += ( val & 0x04 ) ? "Reports caller ID information" : "Does not report caller ID"; 860 | desc += "; "; 861 | desc += ( val & 0x02 ) ? "Reports ringback, busy, and fast busy states." : "Reports only dialing state"; 862 | desc += "; "; 863 | desc += ( val & 0x01 ) ? "Reports interrupted dialtone in addition to normal dialtone" : "Reports only dialtone"; 864 | } 865 | else if( formatter == Fld_CDC_bmOptions ) 866 | { 867 | desc = ( val & 0x01 ) ? " Wrapper used" : " No wrapper used"; 868 | } 869 | else if( formatter == Fld_CDC_bPhysicalInterface ) 870 | { 871 | if( val == 0 ) 872 | desc = " None"; 873 | else if( val == 1 ) 874 | desc = " ISDN"; 875 | else if( val >= 2 && val <= 200 ) 876 | desc = " RESERVED"; 877 | else 878 | desc = " Vendor specific"; 879 | } 880 | else if( formatter == Fld_CDC_bProtocol ) 881 | { 882 | if( val == 0x00 ) 883 | desc = " No class specific protocol required"; 884 | else if( val == 0x30 ) 885 | desc = " Physical interface protocol for ISDN BRI"; 886 | else if( val == 0x31 ) 887 | desc = " HDLC"; 888 | else if( val == 0x32 ) 889 | desc = " Transparent"; 890 | else if( val == 0x50 ) 891 | desc = " Management protocol for Q.921 data link protocol"; 892 | else if( val == 0x51 ) 893 | desc = " Data link protocol for Q.931"; 894 | else if( val == 0x52 ) 895 | desc = " TEI-multiplexor for Q.921 data link protocol"; 896 | else if( val == 0x90 ) 897 | desc = " Data compression procedures"; 898 | else if( val == 0x91 ) 899 | desc = " Euro-ISDN protocol control"; 900 | else if( val == 0x92 ) 901 | desc = " V.24 rate adaptation to ISDN"; 902 | else if( val == 0x93 ) 903 | desc = " CAPI Commands"; 904 | else if( val == 0xfd ) 905 | desc = " Host based driver"; 906 | else if( val == 0xfe ) 907 | desc = " The protocol(s) are described using a Protocol Unit Functional Descriptors on Communication Class Interface."; 908 | else if( val == 0xff ) 909 | desc = " Vendor-specific"; 910 | else 911 | desc = " RESERVED"; 912 | } 913 | else if( formatter == Fld_CDC_bmCapabilities_MultiChannel ) 914 | { 915 | if( val & 0x04 ) 916 | desc = "Device supports the request Set_Unit_Parameter"; 917 | if( val & 0x02 ) 918 | desc += ( desc.empty() ? "" : "; " ) + std::string( "Device supports the request Clear_Unit_Parameter" ); 919 | if( val & 0x01 ) 920 | desc += ( desc.empty() ? "" : "; " ) + std::string( "Device stores Unit parameters in non-volatile memory" ); 921 | if( !desc.empty() ) 922 | desc = " " + desc; 923 | } 924 | else if( formatter == Fld_CDC_bmCapabilities_CAPIControl ) 925 | { 926 | if( val & 0x01 ) 927 | desc = " Device is an Intelligent CAPI device"; 928 | else 929 | desc = " Device is an Simple CAPI device"; 930 | } 931 | else if( formatter == Fld_CDC_bmEthernetStatistics ) 932 | { 933 | if( val & 0x00000001 ) 934 | desc = "XMIT_OK"; 935 | if( val & 0x00000002 ) 936 | desc += ( desc.empty() ? "" : ", " ) + std::string( "RVC_OK" ); 937 | if( val & 0x00000004 ) 938 | desc += ( desc.empty() ? "" : ", " ) + std::string( "XMIT_ERROR" ); 939 | if( val & 0x00000008 ) 940 | desc += ( desc.empty() ? "" : ", " ) + std::string( "RCV_ERROR" ); 941 | if( val & 0x00000010 ) 942 | desc += ( desc.empty() ? "" : ", " ) + std::string( "RCV_NO_BUFFER" ); 943 | if( val & 0x00000020 ) 944 | desc += ( desc.empty() ? "" : ", " ) + std::string( "DIRECTED_BYTES_XMIT" ); 945 | if( val & 0x00000040 ) 946 | desc += ( desc.empty() ? "" : ", " ) + std::string( "DIRECTED_FRAMES_XMIT" ); 947 | if( val & 0x00000080 ) 948 | desc += ( desc.empty() ? "" : ", " ) + std::string( "MULTICAST_BYTES_XMIT" ); 949 | if( val & 0x00000100 ) 950 | desc += ( desc.empty() ? "" : ", " ) + std::string( "MULTICAST_FRAMES_XMIT" ); 951 | if( val & 0x00000200 ) 952 | desc += ( desc.empty() ? "" : ", " ) + std::string( "BROADCAST_BYTES_XMIT" ); 953 | if( val & 0x00000400 ) 954 | desc += ( desc.empty() ? "" : ", " ) + std::string( "BROADCAST_FRAMES_XMIT" ); 955 | if( val & 0x00000800 ) 956 | desc += ( desc.empty() ? "" : ", " ) + std::string( "DIRECTED_BYTES_RCV" ); 957 | if( val & 0x00001000 ) 958 | desc += ( desc.empty() ? "" : ", " ) + std::string( "DIRECTED_FRAMES_RCV" ); 959 | if( val & 0x00002000 ) 960 | desc += ( desc.empty() ? "" : ", " ) + std::string( "MULTICAST_BYTES_RCV" ); 961 | if( val & 0x00004000 ) 962 | desc += ( desc.empty() ? "" : ", " ) + std::string( "MULTICAST_FRAMES_RCV" ); 963 | if( val & 0x00008000 ) 964 | desc += ( desc.empty() ? "" : ", " ) + std::string( "BROADCAST_BYTES_RCV" ); 965 | if( val & 0x00010000 ) 966 | desc += ( desc.empty() ? "" : ", " ) + std::string( "BROADCAST_FRAMES_RCV" ); 967 | if( val & 0x00020000 ) 968 | desc += ( desc.empty() ? "" : ", " ) + std::string( "RCV_CRC_ERROR" ); 969 | if( val & 0x00040000 ) 970 | desc += ( desc.empty() ? "" : ", " ) + std::string( "TRANSMIT_QUEUE_LENGTH" ); 971 | if( val & 0x00080000 ) 972 | desc += ( desc.empty() ? "" : ", " ) + std::string( "RCV_ERROR_ALIGNMENT" ); 973 | if( val & 0x00100000 ) 974 | desc += ( desc.empty() ? "" : ", " ) + std::string( "XMIT_ONE_COLLISION" ); 975 | if( val & 0x00200000 ) 976 | desc += ( desc.empty() ? "" : ", " ) + std::string( "XMIT_MORE_COLLISIONS" ); 977 | if( val & 0x00400000 ) 978 | desc += ( desc.empty() ? "" : ", " ) + std::string( "XMIT_DEFERRED" ); 979 | if( val & 0x00800000 ) 980 | desc += ( desc.empty() ? "" : ", " ) + std::string( "XMIT_MAX_COLLISIONS" ); 981 | if( val & 0x01000000 ) 982 | desc += ( desc.empty() ? "" : ", " ) + std::string( "RCV_OVERRUN" ); 983 | if( val & 0x02000000 ) 984 | desc += ( desc.empty() ? "" : ", " ) + std::string( "XMIT_UNDERRUN" ); 985 | if( val & 0x04000000 ) 986 | desc += ( desc.empty() ? "" : ", " ) + std::string( "XMIT_HEARTBEAT_FAILURE" ); 987 | if( val & 0x08000000 ) 988 | desc += ( desc.empty() ? "" : ", " ) + std::string( "XMIT_TIMES_CRS_LOST" ); 989 | if( val & 0x10000000 ) 990 | desc += ( desc.empty() ? "" : ", " ) + std::string( "XMIT_LATE_COLLISIONS" ); 991 | 992 | if( !desc.empty() ) 993 | desc = " " + desc; 994 | } 995 | else if( formatter == Fld_CDC_wNumberMCFilters ) 996 | { 997 | desc = " Number of multicase filters=" + int2str( val & 0x7fff ) + "; "; 998 | if( val & 0x8000 ) 999 | desc += "The device uses imperfect multicast address filtering (hashing)"; 1000 | else 1001 | desc += "The device performs perfect multicast address filtering (no hashing)"; 1002 | } 1003 | else if( formatter == Fld_CDC_bmDataCapabilities ) 1004 | { 1005 | if( val & 0x08 ) 1006 | desc = "Type 3 - AAL5 SDU"; 1007 | if( val & 0x04 ) 1008 | desc += ( desc.empty() ? "" : ", " ) + std::string( "Type 2 - ATM header template + concatenated ATM cell payloads" ); 1009 | if( val & 0x02 ) 1010 | desc += ( desc.empty() ? "" : ", " ) + std::string( "Type 1 - Concatenated ATM cells" ); 1011 | 1012 | if( !desc.empty() ) 1013 | desc = " " + desc; 1014 | } 1015 | else if( formatter == Fld_CDC_bmATMDeviceStatistics ) 1016 | { 1017 | if( val & 0x10 ) 1018 | desc = "Device counts upstream cells sent on a per VC basis (VC_US_CELLS_SENT)"; 1019 | if( val & 0x08 ) 1020 | desc += ( desc.empty() ? "" : ", " ) + 1021 | std::string( "Device counts downstream cells received on a per VC basis (VC_DS_CELLS_RECEIVED)" ); 1022 | if( val & 0x04 ) 1023 | desc += ( desc.empty() ? "" : ", " ) + 1024 | std::string( "Device counts cells with HEC error detected and corrected (DS_CELLS_HEC_ERROR_CORRECTED)" ); 1025 | if( val & 0x02 ) 1026 | desc += ( desc.empty() ? "" : ", " ) + std::string( "Device counts upstream cells sent (US_CELLS_SENT)" ); 1027 | if( val & 0x01 ) 1028 | desc += ( desc.empty() ? "" : ", " ) + std::string( "Device counts downstream cells received (DS_CELLS_RECEIVED)" ); 1029 | 1030 | if( !desc.empty() ) 1031 | desc = " " + desc; 1032 | } 1033 | else if( formatter == Fld_CDC_Data_AbstractState ) 1034 | { 1035 | desc = " "; 1036 | desc += ( val & 0x02 ) ? "Enables multiplexing" : "Disables multiplexing"; 1037 | desc += "; "; 1038 | desc += ( val & 0x01 ) ? "All of the endpoints in this interface will not accept data from the host or offer data to the host" 1039 | : "The endpoints in this interface will continue to accept/offer data"; 1040 | } 1041 | else if( formatter == Fld_CDC_Data_CountrySetting ) 1042 | { 1043 | desc = " Country code"; 1044 | } 1045 | else if( formatter == Fld_CDC_dwDTERate ) 1046 | { 1047 | desc = " " + int2str( val ) + " bps"; 1048 | } 1049 | else if( formatter == Fld_CDC_bCharFormat ) 1050 | { 1051 | if( val == 0 ) 1052 | desc = " 1 Stop Bit"; 1053 | else if( val == 1 ) 1054 | desc = " 1.5 Stop Bits"; 1055 | else if( val == 2 ) 1056 | desc = " 2 Stop Bits"; 1057 | } 1058 | else if( formatter == Fld_CDC_bParityType ) 1059 | { 1060 | if( val == 0 ) 1061 | desc = " None"; 1062 | else if( val == 1 ) 1063 | desc = " Odd"; 1064 | else if( val == 2 ) 1065 | desc = " Even"; 1066 | else if( val == 3 ) 1067 | desc = " Mark"; 1068 | else if( val == 4 ) 1069 | desc = " Space"; 1070 | } 1071 | else if( formatter == Fld_CDC_bDataBits ) 1072 | { 1073 | desc = " " + int2str( val ) + " bits"; 1074 | } 1075 | else if( formatter == Fld_CDC_dwRingerBitmap ) 1076 | { 1077 | desc = " "; 1078 | if( val & 0x80000000UL ) 1079 | { 1080 | desc += int2str_sal( ( val >> 8 ) & 0xff, display_base, 8 ) + " ringer volume; "; 1081 | desc += int2str_sal( val & 0xff, display_base, 8 ) + " ringer pattern"; 1082 | } 1083 | else 1084 | { 1085 | desc += "A ringer does not exist"; 1086 | } 1087 | } 1088 | else if( formatter == Fld_CDC_dwLineState ) 1089 | { 1090 | desc = " "; 1091 | if( val & 0x80000000UL ) 1092 | desc += "Line is active"; 1093 | else 1094 | desc += "No activity on the line"; 1095 | 1096 | if( ( val & 0xff ) == 0xff ) 1097 | desc += "; No call exists on the line"; 1098 | else 1099 | desc += "; Active call is " + int2str_sal( val & 0xff, display_base, 8 ); 1100 | } 1101 | else if( formatter == Fld_CDC_dwCallState ) 1102 | { 1103 | desc = " "; 1104 | if( val & 0x80000000UL ) 1105 | desc += "No active call"; 1106 | else 1107 | desc += "Call is active"; 1108 | 1109 | desc += "; "; 1110 | 1111 | U8 callStateValue = val & 0xff; 1112 | if( callStateValue == 0 ) 1113 | desc += "Call is idle"; 1114 | else if( callStateValue == 1 ) 1115 | desc += "Typical dial tone"; 1116 | else if( callStateValue == 2 ) 1117 | desc += "Interrupted dial tone"; 1118 | else if( callStateValue == 3 ) 1119 | desc += "Dialing is in progress"; 1120 | else if( callStateValue == 4 ) 1121 | desc += "Ringback"; 1122 | else if( callStateValue == 5 ) 1123 | desc += "Connected"; 1124 | else if( callStateValue == 6 ) 1125 | desc += "Incoming call"; 1126 | 1127 | desc += "; "; 1128 | 1129 | U8 callStateChange = ( val >> 8 ) & 0xff; 1130 | if( callStateChange == 1 ) 1131 | desc += "Call has become idle"; 1132 | else if( callStateChange == 2 ) 1133 | desc += "Dialing"; 1134 | else if( callStateChange == 3 ) 1135 | desc += "Ringback"; 1136 | else if( callStateChange == 4 ) 1137 | desc += "Connected"; 1138 | else if( callStateChange == 5 ) 1139 | desc += "Incomming call"; 1140 | } 1141 | 1142 | const char* fieldName = f.GetFieldName(); 1143 | const char* isIncomplete = ( f.mFlags & 0x3F ) == FF_FieldIncomplete ? " (incomplete)" : ""; 1144 | 1145 | results.push_back( fieldName + std::string( "=" ) + val_str + desc + isIncomplete ); 1146 | results.push_back( fieldName + std::string( "=" ) + val_str ); 1147 | results.push_back( fieldName + desc ); 1148 | results.push_back( fieldName ); 1149 | results.push_back( val_str ); 1150 | results.push_back( desc ); 1151 | } 1152 | 1153 | void GetFrameDesc( const Frame& f, DisplayBase display_base, std::vector& results, 1154 | const USBAnalyzerResults::USBStringContainer& stringDescriptors ) 1155 | { 1156 | results.clear(); 1157 | 1158 | if( f.mType == FT_Signal ) 1159 | { 1160 | std::string result; 1161 | if( f.mData1 == S_J ) 1162 | result = "J"; 1163 | else if( f.mData1 == S_K ) 1164 | result = "K"; 1165 | else if( f.mData1 == S_SE0 ) 1166 | result = "SE0"; 1167 | else if( f.mData1 == S_SE1 ) 1168 | result = "SE1"; 1169 | 1170 | results.push_back( result ); 1171 | } 1172 | else if( f.mType == FT_EOP ) 1173 | { 1174 | results.push_back( "EOP" ); 1175 | } 1176 | else if( f.mType == FT_Reset ) 1177 | { 1178 | results.push_back( "Reset" ); 1179 | } 1180 | else if( f.mType == FT_Idle ) 1181 | { 1182 | results.push_back( "Idle" ); 1183 | } 1184 | else if( f.mType == FT_SYNC ) 1185 | { 1186 | results.push_back( "SYNC" ); 1187 | } 1188 | else if( f.mType == FT_PID ) 1189 | { 1190 | results.push_back( "PID " + GetPIDName( USB_PID( f.mData1 ) ) ); 1191 | results.push_back( GetPIDName( USB_PID( f.mData1 ) ) ); 1192 | } 1193 | else if( f.mType == FT_FrameNum ) 1194 | { 1195 | results.push_back( "Frame # " + int2str_sal( f.mData1, display_base, 11 ) ); 1196 | results.push_back( "F # " + int2str_sal( f.mData1, display_base, 11 ) ); 1197 | results.push_back( "Frame #" ); 1198 | results.push_back( int2str_sal( f.mData1, display_base, 11 ) ); 1199 | } 1200 | else if( f.mType == FT_AddrEndp ) 1201 | { 1202 | results.push_back( "Address=" + int2str_sal( f.mData1, display_base, 7 ) + 1203 | " Endpoint=" + int2str_sal( f.mData2, display_base, 5 ) ); 1204 | results.push_back( "Addr=" + int2str_sal( f.mData1, display_base, 7 ) + " Endp=" + int2str_sal( f.mData2, display_base, 5 ) ); 1205 | results.push_back( "A:" + int2str_sal( f.mData1, display_base, 7 ) + " E:" + int2str_sal( f.mData2, display_base, 5 ) ); 1206 | results.push_back( int2str_sal( f.mData1, display_base, 7 ) + " " + int2str_sal( f.mData2, display_base, 5 ) ); 1207 | } 1208 | else if( f.mType == FT_Byte ) 1209 | { 1210 | results.push_back( "Byte " + int2str_sal( f.mData1, display_base, 8 ) ); 1211 | results.push_back( int2str_sal( f.mData1, display_base, 8 ) ); 1212 | } 1213 | else if( f.mType == FT_KeepAlive ) 1214 | { 1215 | results.push_back( "Keep alive" ); 1216 | results.push_back( "KA" ); 1217 | } 1218 | else if( f.mType == FT_CRC5 || f.mType == FT_CRC16 ) 1219 | { 1220 | const int num_bits = f.mType == FT_CRC5 ? 5 : 16; 1221 | results.push_back( "CRC" ); 1222 | if( f.mData1 == f.mData2 ) 1223 | { 1224 | results.push_back( "CRC OK " + int2str_sal( f.mData1, display_base, num_bits ) ); 1225 | results.push_back( "CRC OK" ); 1226 | } 1227 | else 1228 | { 1229 | results.push_back( "CRC Bad! Rcvd: " + int2str_sal( f.mData1, display_base, num_bits ) + 1230 | " Calc: " + int2str_sal( f.mData2, display_base, num_bits ) ); 1231 | results.push_back( "CRC Bad! Rcvd: " + int2str_sal( f.mData1, display_base, num_bits ) ); 1232 | results.push_back( "CRC Bad" ); 1233 | } 1234 | 1235 | results.push_back( int2str_sal( f.mData1, display_base, num_bits ) ); 1236 | } 1237 | else if( f.mType == FT_Error ) 1238 | { 1239 | results.push_back( "Error packet" ); 1240 | results.push_back( "Error" ); 1241 | results.push_back( "Err" ); 1242 | results.push_back( "E" ); 1243 | } 1244 | else if( f.mType == FT_ControlTransferField ) 1245 | { 1246 | GetCtrlTransFrameDesc( f, display_base, results, stringDescriptors ); 1247 | } 1248 | else if( f.mType == FT_HIDReportDescriptorItem ) 1249 | { 1250 | GetHIDReportDescriptorItemFrameDesc( f, display_base, results ); 1251 | } 1252 | } 1253 | 1254 | void USBAnalyzerResults::GenerateBubbleText( U64 frame_index, Channel& channel, DisplayBase display_base ) 1255 | { 1256 | ClearResultStrings(); 1257 | Frame f = GetFrame( frame_index ); 1258 | std::vector results; 1259 | 1260 | GetFrameDesc( f, display_base, results, mAllStringDescriptors ); 1261 | 1262 | for( std::vector::iterator ri( results.begin() ); ri != results.end(); ++ri ) 1263 | AddResultString( ri->c_str() ); 1264 | } 1265 | 1266 | void USBAnalyzerResults::GenerateExportFileControlTransfers( const char* file, DisplayBase display_base ) 1267 | { 1268 | std::ofstream file_stream( file, std::ios::out ); 1269 | 1270 | U64 trigger_sample = mAnalyzer->GetTriggerSample(); 1271 | U32 sample_rate = mAnalyzer->GetSampleRate(); 1272 | 1273 | Frame f; 1274 | const U64 num_frames = GetNumFrames(); 1275 | std::vector results; 1276 | U8 address = 0; 1277 | for( U64 fcnt = 0; fcnt < num_frames; fcnt++ ) 1278 | { 1279 | // get the frame 1280 | f = GetFrame( fcnt ); 1281 | 1282 | if( UpdateExportProgressAndCheckForCancel( fcnt, num_frames ) ) 1283 | return; 1284 | 1285 | if( f.mType == FT_AddrEndp ) 1286 | address = U8( f.mData1 ); 1287 | 1288 | if( f.mFlags == FF_StatusBegin ) 1289 | file_stream << "STATUS time: " << GetSampleTimeStr( f.mStartingSampleInclusive ) << std::endl; 1290 | else if( f.mFlags == FF_DataBegin ) 1291 | file_stream << "DATA time: " << GetSampleTimeStr( f.mStartingSampleInclusive ) << std::endl; 1292 | else if( f.mFlags == FF_DataDescriptor ) 1293 | file_stream << "Descriptor time: " << GetSampleTimeStr( f.mStartingSampleInclusive ) << std::endl; 1294 | else if( f.mFlags == FF_SetupBegin ) 1295 | file_stream << std::endl 1296 | << "SETUP address: " + int2str_sal( address, display_base, 7 ) + " time: " 1297 | << GetSampleTimeStr( f.mStartingSampleInclusive ) << std::endl; 1298 | 1299 | if( ( f.mType == FT_ControlTransferField || f.mType == FT_HIDReportDescriptorItem ) && f.mFlags != FF_FieldIncomplete ) 1300 | { 1301 | GetFrameDesc( f, display_base, results, mAllStringDescriptors ); 1302 | 1303 | // output the packet 1304 | file_stream << "\t" << results.front() << std::endl; 1305 | } 1306 | else if( f.mType == FT_Reset ) 1307 | { 1308 | file_stream << std::endl << "USB RESET Time: " << GetSampleTimeStr( f.mStartingSampleInclusive ) << std::endl; 1309 | } 1310 | 1311 | if( f.mFlags == FF_StatusEnd ) 1312 | file_stream << "\t" << GetPIDName( USB_PID( f.mData1 ) ) << std::endl; 1313 | else if( f.mFlags == FF_DataInNAKed ) 1314 | file_stream << "\t' 1315 | << std::endl; 1316 | else if( f.mFlags == FF_DataOutNAKed ) 1317 | file_stream << "\t' 1318 | << std::endl; 1319 | else if( f.mFlags == FF_StatusInNAKed ) 1320 | file_stream << "\t' 1321 | << std::endl; 1322 | else if( f.mFlags == FF_StatusOutNAKed ) 1323 | file_stream << "\t' 1324 | << std::endl; 1325 | else if( f.mFlags == FF_UnexpectedPacket ) 1326 | file_stream << "Unexpected packet " << GetPIDName( USB_PID( f.mData1 ) ) 1327 | << ". Time: " << GetSampleTimeStr( f.mStartingSampleInclusive ) << std::endl; 1328 | } 1329 | 1330 | // end 1331 | UpdateExportProgressAndCheckForCancel( num_frames, num_frames ); 1332 | } 1333 | 1334 | void USBAnalyzerResults::GenerateExportFilePackets( const char* file, DisplayBase display_base ) 1335 | { 1336 | std::ofstream file_stream( file, std::ios::out ); 1337 | 1338 | U64 trigger_sample = mAnalyzer->GetTriggerSample(); 1339 | U32 sample_rate = mAnalyzer->GetSampleRate(); 1340 | 1341 | // header 1342 | file_stream << "Time [s],PID,Address,Endpoint,Frame #,Data,CRC" << std::endl; 1343 | 1344 | Frame f; 1345 | char time_str[ 128 ]; 1346 | time_str[ 0 ] = '\0'; 1347 | const U64 num_frames = GetNumFrames(); 1348 | std::string PID, Address, Endpoint, FrameNum, Data, CRC; 1349 | for( U64 fcnt = 0; fcnt < num_frames; fcnt++ ) 1350 | { 1351 | // get the frame 1352 | f = GetFrame( fcnt ); 1353 | 1354 | if( UpdateExportProgressAndCheckForCancel( fcnt, num_frames ) ) 1355 | return; 1356 | 1357 | // start of a new packet? 1358 | if( f.mType == FT_SYNC ) 1359 | { 1360 | // make the time string 1361 | AnalyzerHelpers::GetTimeString( f.mStartingSampleInclusive, trigger_sample, sample_rate, time_str, sizeof( time_str ) ); 1362 | 1363 | // reset packet fields 1364 | PID.clear(), Address.clear(), Endpoint.clear(), FrameNum.clear(), Data.clear(), CRC.clear(); 1365 | } 1366 | else if( f.mType == FT_PID ) 1367 | { 1368 | PID = GetPIDName( USB_PID( f.mData1 ) ); 1369 | 1370 | // output the PRE packet because it does not have an EOP 1371 | if( f.mData1 == PID_PRE ) 1372 | file_stream << time_str << "," << PID << ",,,,," << std::endl; 1373 | } 1374 | else if( f.mType == FT_AddrEndp ) 1375 | { 1376 | Address = int2str_sal( f.mData1, display_base, 7 ); 1377 | Endpoint = int2str_sal( f.mData2, display_base, 5 ); 1378 | } 1379 | else if( f.mType == FT_FrameNum ) 1380 | { 1381 | FrameNum = int2str_sal( f.mData1, display_base, 11 ); 1382 | } 1383 | else if( f.mType == FT_Byte ) 1384 | { 1385 | Data += ( Data.empty() ? "" : " " ) + int2str_sal( f.mData1, display_base, 8 ); 1386 | } 1387 | else if( f.mType == FT_CRC5 || f.mType == FT_CRC16 ) 1388 | { 1389 | CRC = int2str_sal( f.mData1, display_base, f.mType == FT_CRC5 ? 5 : 16 ); 1390 | } 1391 | else if( f.mType == FT_EOP ) 1392 | { 1393 | // output the packet 1394 | file_stream << time_str << "," << PID << "," << Address << "," << Endpoint << "," << FrameNum << "," << Data << "," << CRC 1395 | << std::endl; 1396 | } 1397 | else if( f.mType == FT_Error ) 1398 | { 1399 | // make the time string 1400 | AnalyzerHelpers::GetTimeString( f.mStartingSampleInclusive, trigger_sample, sample_rate, time_str, sizeof( time_str ) ); 1401 | 1402 | file_stream << time_str << ",Parsing error,,,,," << std::endl; 1403 | } 1404 | } 1405 | 1406 | // end 1407 | UpdateExportProgressAndCheckForCancel( num_frames, num_frames ); 1408 | } 1409 | 1410 | void USBAnalyzerResults::GenerateExportFileBytes( const char* file, DisplayBase display_base ) 1411 | { 1412 | std::ofstream file_stream( file, std::ios::out ); 1413 | 1414 | U64 trigger_sample = mAnalyzer->GetTriggerSample(); 1415 | U32 sample_rate = mAnalyzer->GetSampleRate(); 1416 | 1417 | // header 1418 | file_stream << "Time [s],Byte" << std::endl; 1419 | 1420 | Frame f; 1421 | char time_str[ 128 ]; 1422 | time_str[ 0 ] = '\0'; 1423 | const U64 num_frames = GetNumFrames(); 1424 | for( U64 fcnt = 0; fcnt < num_frames; fcnt++ ) 1425 | { 1426 | // get the frame 1427 | f = GetFrame( fcnt ); 1428 | 1429 | if( UpdateExportProgressAndCheckForCancel( fcnt, num_frames ) ) 1430 | return; 1431 | 1432 | // start of a new packet? 1433 | if( f.mType == FT_Byte ) 1434 | { 1435 | // make the time string 1436 | AnalyzerHelpers::GetTimeString( f.mStartingSampleInclusive, trigger_sample, sample_rate, time_str, sizeof( time_str ) ); 1437 | 1438 | // output byte and timestamp 1439 | file_stream << time_str << "," << int2str_sal( f.mData1, display_base, 8 ) << std::endl; 1440 | } 1441 | } 1442 | 1443 | // end 1444 | UpdateExportProgressAndCheckForCancel( num_frames, num_frames ); 1445 | } 1446 | 1447 | void USBAnalyzerResults::GenerateExportFileSignals( const char* file, DisplayBase display_base ) 1448 | { 1449 | std::ofstream file_stream( file, std::ios::out ); 1450 | 1451 | U64 trigger_sample = mAnalyzer->GetTriggerSample(); 1452 | U32 sample_rate = mAnalyzer->GetSampleRate(); 1453 | 1454 | // header 1455 | file_stream << "Time [s],Signal,Duration [ns]" << std::endl; 1456 | 1457 | Frame f; 1458 | char time_str[ 128 ]; 1459 | time_str[ 0 ] = '\0'; 1460 | const U64 num_frames = GetNumFrames(); 1461 | for( U64 fcnt = 0; fcnt < num_frames; fcnt++ ) 1462 | { 1463 | // get the frame 1464 | f = GetFrame( fcnt ); 1465 | 1466 | if( UpdateExportProgressAndCheckForCancel( fcnt, num_frames ) ) 1467 | return; 1468 | 1469 | // make the time string 1470 | AnalyzerHelpers::GetTimeString( f.mStartingSampleInclusive, trigger_sample, sample_rate, time_str, sizeof( time_str ) ); 1471 | 1472 | // output timestamp 1473 | file_stream << time_str << ","; 1474 | 1475 | // start of a new packet? 1476 | if( f.mType == FT_Signal ) 1477 | { 1478 | if( f.mData1 == S_J ) 1479 | file_stream << 'J'; 1480 | else if( f.mData1 == S_K ) 1481 | file_stream << 'K'; 1482 | else if( f.mData1 == S_SE0 ) 1483 | file_stream << "SE0"; 1484 | else if( f.mData1 == S_SE1 ) 1485 | file_stream << "SE1"; 1486 | 1487 | file_stream << ',' << ( f.mEndingSampleInclusive - f.mStartingSampleInclusive ) / ( sample_rate / 1e9 ) << std::endl; 1488 | } 1489 | } 1490 | 1491 | // end 1492 | UpdateExportProgressAndCheckForCancel( num_frames, num_frames ); 1493 | } 1494 | 1495 | void USBAnalyzerResults::GenerateExportFile( const char* file, DisplayBase display_base, U32 export_type_user_id ) 1496 | { 1497 | if( mSettings->mDecodeLevel == OUT_CONTROL_TRANSFERS ) 1498 | GenerateExportFileControlTransfers( file, display_base ); 1499 | else if( mSettings->mDecodeLevel == OUT_PACKETS ) 1500 | GenerateExportFilePackets( file, display_base ); 1501 | else if( mSettings->mDecodeLevel == OUT_BYTES ) 1502 | GenerateExportFileBytes( file, display_base ); 1503 | else if( mSettings->mDecodeLevel == OUT_SIGNALS ) 1504 | GenerateExportFileSignals( file, display_base ); 1505 | } 1506 | 1507 | void USBAnalyzerResults::GenerateFrameTabularText( U64 frame_index, DisplayBase display_base ) 1508 | { 1509 | ClearTabularText(); 1510 | Frame f = GetFrame( frame_index ); 1511 | std::vector results; 1512 | 1513 | // GetFrameDesc(f, display_base, results); 1514 | 1515 | results.clear(); 1516 | 1517 | if( f.mType == FT_Signal ) 1518 | { 1519 | std::string result; 1520 | if( f.mData1 == S_J ) 1521 | result = "J"; 1522 | else if( f.mData1 == S_K ) 1523 | result = "K"; 1524 | else if( f.mData1 == S_SE0 ) 1525 | result = "SE0"; 1526 | else if( f.mData1 == S_SE1 ) 1527 | result = "SE1"; 1528 | 1529 | results.push_back( result ); 1530 | } 1531 | else if( f.mType == FT_EOP ) 1532 | { 1533 | results.push_back( "EOP" ); 1534 | } 1535 | else if( f.mType == FT_Reset ) 1536 | { 1537 | results.push_back( "Reset" ); 1538 | } 1539 | else if( f.mType == FT_Idle ) 1540 | { 1541 | results.push_back( "Idle" ); 1542 | } 1543 | else if( f.mType == FT_SYNC ) 1544 | { 1545 | results.push_back( "SYNC" ); 1546 | } 1547 | else if( f.mType == FT_PID ) 1548 | { 1549 | results.push_back( "PID " + GetPIDName( USB_PID( f.mData1 ) ) ); 1550 | } 1551 | else if( f.mType == FT_FrameNum ) 1552 | { 1553 | results.push_back( "Frame # " + int2str_sal( f.mData1, display_base, 11 ) ); 1554 | } 1555 | else if( f.mType == FT_AddrEndp ) 1556 | { 1557 | results.push_back( "Address=" + int2str_sal( f.mData1, display_base, 7 ) + 1558 | " Endpoint=" + int2str_sal( f.mData2, display_base, 5 ) ); 1559 | } 1560 | else if( f.mType == FT_Byte ) 1561 | { 1562 | results.push_back( "Byte " + int2str_sal( f.mData1, display_base, 8 ) ); 1563 | } 1564 | else if( f.mType == FT_KeepAlive ) 1565 | { 1566 | results.push_back( "Keep alive" ); 1567 | } 1568 | else if( f.mType == FT_CRC5 || f.mType == FT_CRC16 ) 1569 | { 1570 | const int num_bits = f.mType == FT_CRC5 ? 5 : 16; 1571 | if( f.mData1 == f.mData2 ) 1572 | { 1573 | results.push_back( "CRC OK " + int2str_sal( f.mData1, display_base, num_bits ) ); 1574 | } 1575 | else 1576 | { 1577 | results.push_back( "CRC Bad! Rcvd: " + int2str_sal( f.mData1, display_base, num_bits ) + 1578 | " Calc: " + int2str_sal( f.mData2, display_base, num_bits ) ); 1579 | } 1580 | } 1581 | else if( f.mType == FT_Error ) 1582 | { 1583 | results.push_back( "Error packet" ); 1584 | } 1585 | else if( f.mType == FT_ControlTransferField ) 1586 | { 1587 | // hijack the bubble text generator for this. 1588 | std::vector bubble_results; 1589 | GetCtrlTransFrameDesc( f, display_base, bubble_results, mAllStringDescriptors ); 1590 | if( bubble_results.size() > 0 ) 1591 | results.push_back( *bubble_results.begin() ); 1592 | } 1593 | else if( f.mType == FT_HIDReportDescriptorItem ) 1594 | { 1595 | // hijack the bubble text generator for this. 1596 | std::vector bubble_results; 1597 | GetHIDReportDescriptorItemFrameDesc( f, display_base, bubble_results ); 1598 | if( bubble_results.size() > 0 ) 1599 | results.push_back( *bubble_results.begin() ); 1600 | } 1601 | 1602 | for( std::vector::iterator ri( results.begin() ); ri != results.end(); ++ri ) 1603 | AddTabularText( ri->c_str() ); 1604 | } 1605 | 1606 | void USBAnalyzerResults::GeneratePacketTabularText( U64 packet_id, DisplayBase display_base ) 1607 | { 1608 | ClearResultStrings(); 1609 | AddResultString( "not supported" ); 1610 | } 1611 | 1612 | void USBAnalyzerResults::GenerateTransactionTabularText( U64 transaction_id, DisplayBase display_base ) 1613 | { 1614 | ClearResultStrings(); 1615 | AddResultString( "not supported" ); 1616 | } 1617 | --------------------------------------------------------------------------------