├── .gitignore ├── src ├── RFFEUtil.h ├── RFFEAnalyzerSettings.h ├── RFFESimulationDataGenerator.h ├── .clang-format ├── RFFEUtil.cpp ├── RFFEAnalyzerResults.h ├── RFFEAnalyzerSettings.cpp ├── RFFEAnalyzer.h ├── RFFESimulationDataGenerator.cpp ├── RFFEAnalyzerResults.cpp └── RFFEAnalyzer.cpp ├── CMakeLists.txt ├── LICENSE ├── .github └── workflows │ └── build.yml ├── cmake └── ExternalAnalyzerSDK.cmake └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /src/RFFEUtil.h: -------------------------------------------------------------------------------- 1 | #ifndef RFFE_UTIL 2 | #define RFFE_UTIL 3 | 4 | #include 5 | #include 6 | #include "RFFEAnalyzerResults.h" 7 | 8 | class RFFEUtil { 9 | public: 10 | static RFFEAnalyzerResults::RffeCommandFieldType decodeRFFECmdFrame(U8 cmd); 11 | static U8 byteCount(U8 cmd); 12 | static bool CalcParity(U64 val); 13 | }; 14 | 15 | // Parity Lookup Table 16 | static const U8 ParityTable256[256] = { 17 | #define P2(n) n, n ^ 1, n ^ 1, n 18 | #define P4(n) P2(n), P2(n ^ 1), P2(n ^ 1), P2(n) 19 | #define P6(n) P4(n), P4(n ^ 1), P4(n ^ 1), P4(n) 20 | P6(1), P6(0), P6(0), P6(1)}; 21 | 22 | #endif // RFFE_UTIL 23 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.13) 2 | 3 | project(RffeAnalyzer) 4 | 5 | add_definitions( -DLOGIC2 ) 6 | 7 | # enable generation of compile_commands.json, helpful for IDEs to locate include files. 8 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 9 | 10 | # custom CMake Modules are located in the cmake directory. 11 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 12 | 13 | include(ExternalAnalyzerSDK) 14 | 15 | set(SOURCES 16 | src/RffeUtil.cpp 17 | src/RffeUtil.h 18 | src/RffeAnalyzer.cpp 19 | src/RffeAnalyzer.h 20 | src/RffeAnalyzerResults.cpp 21 | src/RffeAnalyzerResults.h 22 | src/RffeAnalyzerSettings.cpp 23 | src/RffeAnalyzerSettings.h 24 | src/RffeSimulationDataGenerator.cpp 25 | src/RffeSimulationDataGenerator.h 26 | ) 27 | 28 | add_analyzer_plugin(${PROJECT_NAME} SOURCES ${SOURCES}) 29 | -------------------------------------------------------------------------------- /src/RFFEAnalyzerSettings.h: -------------------------------------------------------------------------------- 1 | #ifndef RFFE_ANALYZER_SETTINGS 2 | #define RFFE_ANALYZER_SETTINGS 3 | 4 | #include 5 | #include 6 | 7 | class RFFEAnalyzerSettings : public AnalyzerSettings { 8 | public: 9 | RFFEAnalyzerSettings(); 10 | virtual ~RFFEAnalyzerSettings(); 11 | 12 | virtual bool SetSettingsFromInterfaces(); 13 | void UpdateInterfacesFromSettings(); 14 | virtual void LoadSettings(const char *settings); 15 | virtual const char *SaveSettings(); 16 | 17 | Channel mSclkChannel; 18 | Channel mSdataChannel; 19 | bool mShowParityInReport; 20 | bool mShowBusParkInReport; 21 | 22 | protected: 23 | std::auto_ptr mSclkChannelInterface; 24 | std::auto_ptr mSdataChannelInterface; 25 | std::auto_ptr mShowParityInReportInterface; 26 | std::auto_ptr mShowBusParkInReportInterface; 27 | }; 28 | 29 | #endif // RFFE_ANALYZER_SETTINGS 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Robert Chapman 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/RFFESimulationDataGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef RFFE_SIMULATION_DATA_GENERATOR 2 | #define RFFE_SIMULATION_DATA_GENERATOR 3 | 4 | #include 5 | #include 6 | #include 7 | #include "RFFEAnalyzerResults.h" 8 | 9 | class RFFEAnalyzerSettings; 10 | 11 | class RFFESimulationDataGenerator { 12 | public: 13 | RFFESimulationDataGenerator(); 14 | ~RFFESimulationDataGenerator(); 15 | 16 | void Initialize(U32 simulation_sample_rate, RFFEAnalyzerSettings *settings); 17 | U32 GenerateSimulationData(U64 newest_sample_requested, U32 sample_rate, SimulationChannelDescriptor **simulation_channels); 18 | 19 | protected: 20 | RFFEAnalyzerSettings *mSettings; 21 | U32 mSimulationSampleRateHz; 22 | 23 | protected: // RFFE specific functions 24 | void CreateRffeTransaction(); 25 | void CreateSSC(); 26 | void CreateSlaveAddress(U8 addr); 27 | void CreateByteFrame(U8 byte); 28 | void CreateByte(U8 cmd); 29 | void CreateBits(U8 bits, U8 data); 30 | void CreateParity(U8 byte); 31 | void CreateBusPark(); 32 | U8 CreateRandomData(); 33 | 34 | protected: // RFFE specific vars 35 | ClockGenerator mClockGenerator; 36 | SimulationChannelDescriptorGroup mRffeSimulationChannels; 37 | SimulationChannelDescriptor *mSclk; 38 | SimulationChannelDescriptor *mSdata; 39 | 40 | private: 41 | U8 mLSFRData; 42 | }; 43 | 44 | #endif // RFFE_SIMULATION_DATA_GENERATOR 45 | -------------------------------------------------------------------------------- /src/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: true 6 | AlignEscapedNewlinesLeft: false 7 | AlignOperands: true 8 | AlignTrailingComments: true 9 | AllowAllParametersOfDeclarationOnNextLine: true 10 | AllowShortBlocksOnASingleLine: false 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortIfStatementsOnASingleLine: false 13 | AllowShortLoopsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: false 15 | AlwaysBreakAfterDefinitionReturnType: false 16 | AlwaysBreakTemplateDeclarations: false 17 | AlwaysBreakBeforeMultilineStrings: false 18 | BreakBeforeBinaryOperators: None 19 | BreakBeforeTernaryOperators: true 20 | BreakConstructorInitializersBeforeComma: false 21 | BinPackParameters: true 22 | BinPackArguments: true 23 | ColumnLimit: 160 24 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 25 | ConstructorInitializerIndentWidth: 4 26 | DerivePointerAlignment: false 27 | ExperimentalAutoDetectBinPacking: false 28 | IndentCaseLabels: true 29 | IndentWrappedFunctionNames: false 30 | IndentFunctionDeclarationAfterType: false 31 | MaxEmptyLinesToKeep: 1 32 | KeepEmptyLinesAtTheStartOfBlocks: true 33 | NamespaceIndentation: None 34 | ObjCBlockIndentWidth: 2 35 | ObjCSpaceAfterProperty: false 36 | ObjCSpaceBeforeProtocolList: true 37 | PenaltyBreakBeforeFirstCallParameter: 19 38 | PenaltyBreakComment: 300 39 | PenaltyBreakString: 1000 40 | PenaltyBreakFirstLessLess: 120 41 | PenaltyExcessCharacter: 1000000 42 | PenaltyReturnTypeOnItsOwnLine: 60 43 | PointerAlignment: Right 44 | SpacesBeforeTrailingComments: 1 45 | Cpp11BracedListStyle: true 46 | Standard: Cpp11 47 | IndentWidth: 2 48 | TabWidth: 8 49 | UseTab: Never 50 | BreakBeforeBraces: Attach 51 | SpacesInParentheses: false 52 | SpacesInSquareBrackets: false 53 | SpacesInAngles: false 54 | SpaceInEmptyParentheses: false 55 | SpacesInCStyleCastParentheses: false 56 | SpaceAfterCStyleCast: false 57 | SpacesInContainerLiterals: true 58 | SpaceBeforeAssignmentOperators: true 59 | ContinuationIndentWidth: 4 60 | CommentPragmas: '^ IWYU pragma:' 61 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 62 | SpaceBeforeParens: ControlStatements 63 | DisableFormat: false 64 | ... 65 | 66 | -------------------------------------------------------------------------------- /.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@v2 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@v2 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@v2 29 | - name: Build 30 | run: | 31 | cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release 32 | cmake --build ${{github.workspace}}/build 33 | - name: Upload MacOS build 34 | uses: actions/upload-artifact@v2 35 | with: 36 | name: macos 37 | path: ${{github.workspace}}/build/Analyzers/*.so 38 | linux: 39 | runs-on: ubuntu-latest 40 | steps: 41 | - uses: actions/checkout@v2 42 | - name: Build 43 | run: | 44 | cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release 45 | cmake --build ${{github.workspace}}/build 46 | - name: Upload Linux build 47 | uses: actions/upload-artifact@v2 48 | with: 49 | name: linux 50 | path: ${{github.workspace}}/build/Analyzers/*.so 51 | publish: 52 | needs: [windows, macos, linux] 53 | runs-on: ubuntu-latest 54 | steps: 55 | - name: download individual builds 56 | uses: actions/download-artifact@v2 57 | with: 58 | path: ${{github.workspace}}/artifacts 59 | - name: zip 60 | run: | 61 | cd ${{github.workspace}}/artifacts 62 | zip -r ${{github.workspace}}/analyzer.zip . 63 | - uses: actions/upload-artifact@v2 64 | with: 65 | name: all-platforms 66 | path: ${{github.workspace}}/artifacts/** 67 | - name: create release 68 | uses: softprops/action-gh-release@v1 69 | if: startsWith(github.ref, 'refs/tags/') 70 | with: 71 | files: ${{github.workspace}}/analyzer.zip -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Saleae RFFE v2.0 Analyzer 2 | 3 | Saleae Analyzer for the MIPI RFFE v2.0 interface. 4 | 5 | See www.mipi.org for details on RFFE. 6 | See www.saleae.com for details on the Saleae logic analyzer. 7 | 8 | See the Saleae reference Analyzer for details on how to build and update 9 | your own Analyzer plugin. For possibly out of date details on how to build 10 | the RFFE Analyzer, see the copy of the Saleae instructions below. 11 | 12 | ## Prerequisites 13 | 14 | ### Windows 15 | 16 | Dependencies: 17 | 18 | - Visual Studio 2017 (or newer) with C++ 19 | - CMake 3.13+ 20 | 21 | **Visual Studio 2017** 22 | 23 | _Note - newer versions of Visual Studio should be fine._ 24 | 25 | Setup options: 26 | 27 | - Programming Languages > Visual C++ > select all sub-components. 28 | 29 | Note - if CMake has any problems with the MSVC compiler, it's likely a component is missing. 30 | 31 | **CMake** 32 | 33 | Download and install the latest CMake release here. 34 | https://cmake.org/download/ 35 | 36 | ### MacOS 37 | 38 | Dependencies: 39 | 40 | - XCode with command line tools 41 | - CMake 3.13+ 42 | 43 | Installing command line tools after XCode is installed: 44 | 45 | ``` 46 | xcode-select --install 47 | ``` 48 | 49 | Then open XCode, open Preferences from the main menu, go to locations, and select the only option under 'Command line tools'. 50 | 51 | Installing CMake on MacOS: 52 | 53 | 1. Download the binary distribution for MacOS, `cmake-*-Darwin-x86_64.dmg` 54 | 2. Install the usual way by dragging into applications. 55 | 3. Open a terminal and run the following: 56 | 57 | ``` 58 | /Applications/CMake.app/Contents/bin/cmake-gui --install 59 | ``` 60 | 61 | _Note: Errors may occur if older versions of CMake are installed._ 62 | 63 | ### Linux 64 | 65 | Dependencies: 66 | 67 | - CMake 3.13+ 68 | - gcc 5+ 69 | 70 | Misc dependencies: 71 | 72 | ``` 73 | sudo apt-get install build-essential 74 | ``` 75 | 76 | ## Building your Analyzer 77 | 78 | ### Windows 79 | 80 | ```bat 81 | mkdir build 82 | cd build 83 | cmake .. -A x64 84 | cmake --build . 85 | :: built analyzer will be located at SampleAnalyzer\build\Analyzers\Debug\SimpleSerialAnalyzer.dll 86 | ``` 87 | 88 | ### MacOS 89 | 90 | ```bash 91 | mkdir build 92 | cd build 93 | cmake .. 94 | cmake --build . 95 | # built analyzer will be located at SampleAnalyzer/build/Analyzers/libSimpleSerialAnalyzer.so 96 | ``` 97 | 98 | ### Linux 99 | 100 | ```bash 101 | mkdir build 102 | cd build 103 | cmake .. 104 | cmake --build . 105 | # built analyzer will be located at SampleAnalyzer/build/Analyzers/libSimpleSerialAnalyzer.so 106 | ``` 107 | -------------------------------------------------------------------------------- /src/RFFEUtil.cpp: -------------------------------------------------------------------------------- 1 | #include "RFFEUtil.h" 2 | 3 | RFFEAnalyzerResults::RffeCommandFieldType RFFEUtil::decodeRFFECmdFrame(U8 cmd) { 4 | if (cmd < 0x10) { 5 | return RFFEAnalyzerResults::RffeTypeExtWrite; 6 | } else if ((cmd >= 0x10) && (cmd < 0x1c)) { 7 | return RFFEAnalyzerResults::RffeTypeReserved; 8 | } else if (cmd == 0x1c) { 9 | return RFFEAnalyzerResults::RffeTypeMasterRead; 10 | } else if (cmd == 0x1d) { 11 | return RFFEAnalyzerResults::RffeTypeMasterWrite; 12 | } else if (cmd == 0x1e) { 13 | return RFFEAnalyzerResults::RffeTypeMasterHandoff; 14 | } else if (cmd == 0x1f) { 15 | return RFFEAnalyzerResults::RffeTypeInterrupt; 16 | } else if ((cmd >= 0x20) && (cmd < 0x30)) { 17 | return RFFEAnalyzerResults::RffeTypeExtRead; 18 | } else if ((cmd >= 0x30) && (cmd < 0x38)) { 19 | return RFFEAnalyzerResults::RffeTypeExtLongWrite; 20 | } else if ((cmd >= 0x38) && (cmd < 0x40)) { 21 | return RFFEAnalyzerResults::RffeTypeExtLongRead; 22 | } else if ((cmd >= 0x40) && (cmd < 0x60)) { 23 | return RFFEAnalyzerResults::RffeTypeNormalWrite; 24 | } else if ((cmd >= 0x60) && (cmd < 0x80)) { 25 | return RFFEAnalyzerResults::RffeTypeNormalRead; 26 | } else { 27 | return RFFEAnalyzerResults::RffeTypeWrite0; 28 | } 29 | } 30 | 31 | // Note: This returns the number of bytes expected MINUS one 32 | // (This is due to how command lengths are encoded in the RFFE Commands 33 | U8 RFFEUtil::byteCount(U8 cmd) { 34 | if (cmd < 0x10) { // ExtWr 35 | return (cmd & 0x0f); 36 | } else if ((cmd >= 0x10) && (cmd < 0x1C)) { // Rsvd 37 | return 0; 38 | } else if ((cmd >= 0x1c) && (cmd < 0x1e)) { // Master Rd/Wr 39 | return 1; // 2 bytes 40 | } else if (cmd == 0x1e) { // Master Handoff 41 | return 0; // 1 byte 42 | } else if (cmd == 0x1f) { // Interrupt - non-byte sized length, handle as special case 43 | return 0; 44 | } else if ((cmd >= 0x20) && (cmd < 0x30)) { // ExtRd 45 | return (cmd & 0x0F); 46 | } else if ((cmd >= 0x30) && (cmd < 0x40)) { // Long Rd/Wr 47 | return (cmd & 0x07); 48 | } else if ((cmd >= 0x40) && (cmd < 0x80)) { // Rd/Wr 49 | return 0; 50 | } else { // Write0 51 | return 0; 52 | } 53 | } 54 | 55 | // Take a 32 bit unsigned so we can handle SA+Cmd 56 | bool RFFEUtil::CalcParity(U64 val) { 57 | U8 c; 58 | U64 v; 59 | 60 | c = 1; 61 | v = val; 62 | 63 | // Add one to the bit count until we have zeroed 64 | // out all the bits in the passed val. Initialized 65 | // to '1' for odd parity 66 | while (v) { 67 | c += 1; 68 | v &= (v - 1); 69 | } 70 | return (c & 0x1); 71 | } 72 | -------------------------------------------------------------------------------- /src/RFFEAnalyzerResults.h: -------------------------------------------------------------------------------- 1 | #ifndef RFFE_ANALYZER_RESULTS 2 | #define RFFE_ANALYZER_RESULTS 3 | 4 | #include 5 | 6 | #define RFFE_PARITY_ERROR_FLAG (0x1 << 0) 7 | #define RFFE_INVALID_CMD_ERROR_FLAG (0x1 << 1) 8 | #define RFFE_INCOMPLETE_PACKET_ERROR_FLAG (0x1 << 2) 9 | #define RFFE_INVALID_MASTER_ID (0x1 << 3) 10 | 11 | class RFFEAnalyzer; 12 | class RFFEAnalyzerSettings; 13 | 14 | class RFFEAnalyzerResults : public AnalyzerResults { 15 | public: 16 | RFFEAnalyzerResults(RFFEAnalyzer *analyzer, RFFEAnalyzerSettings *settings); 17 | virtual ~RFFEAnalyzerResults(); 18 | 19 | virtual void GenerateBubbleText(U64 frame_index, Channel &channel, DisplayBase display_base); 20 | virtual void GenerateExportFile(const char *file, DisplayBase display_base, U32 export_type_user_id); 21 | 22 | virtual void GenerateFrameTabularText(U64 frame_index, DisplayBase display_base); 23 | virtual void GeneratePacketTabularText(U64 packet_id, DisplayBase display_base); 24 | virtual void GenerateTransactionTabularText(U64 transaction_id, DisplayBase display_base); 25 | 26 | public: 27 | enum RffeFrameType { 28 | RffeSSCField, 29 | RffeSAField, 30 | RffeCommandField, 31 | RffeExByteCountField, 32 | RffeExLongByteCountField, 33 | RffeAddressField, 34 | RffeAddressHiField, 35 | RffeAddressLoField, 36 | RffeShortDataField, 37 | RffeDataField, 38 | RffeMasterHandoffAckField, 39 | RffeISIField, 40 | RffeIntSlotField, 41 | RffeParityField, 42 | RffeBusParkField, 43 | RffeErrorCaseField, 44 | }; 45 | 46 | enum RffeCommandFieldType { 47 | RffeTypeExtWrite, 48 | RffeTypeReserved, 49 | RffeTypeMasterRead, 50 | RffeTypeMasterWrite, 51 | RffeTypeMasterHandoff, 52 | RffeTypeInterrupt, 53 | RffeTypeExtRead, 54 | RffeTypeExtLongWrite, 55 | RffeTypeExtLongRead, 56 | RffeTypeNormalWrite, 57 | RffeTypeNormalRead, 58 | RffeTypeWrite0, 59 | }; 60 | 61 | protected: 62 | RFFEAnalyzerSettings *mSettings; 63 | RFFEAnalyzer *mAnalyzer; 64 | }; 65 | 66 | 67 | // Map RffeFrameType to Descriptive Strings 68 | static const char *RffeFrameString[] = { 69 | "SSCField", 70 | "SAField", 71 | "CommandField", 72 | "ExByteCountField", 73 | "ExLongByteCountField", 74 | "AddressField", 75 | "AddressHiField", 76 | "AddressLoField", 77 | "ShortDataField", 78 | "DataField", 79 | "MasterHandoffAckField", 80 | "ISIField", 81 | "IntSlotField", 82 | "ParityField", 83 | "BusParkField", 84 | "ErrorCaseField", 85 | }; 86 | 87 | // Map RffeCommandFieldType to Descriptive Strings 88 | static const char *RffeCommandFieldStringShort[] = { 89 | "EW", "-", "MR", "MW", "MH", "I", "ER", "EWL", "ERL", "W", "R", "W0", 90 | }; 91 | 92 | static const char *RffeCommandFieldStringMid[] = { 93 | "ExtWr", "Rsvd", "MstrRd", "MstrWr", "MstrHand", "Interrupt", "ExtRd", "ExtWrLng", "ExtRdLng", "Wr", "Rd", "Wr0", 94 | }; 95 | 96 | #endif // RFFE_ANALYZER_RESULTS 97 | -------------------------------------------------------------------------------- /src/RFFEAnalyzerSettings.cpp: -------------------------------------------------------------------------------- 1 | #include "RFFEAnalyzerSettings.h" 2 | #include 3 | 4 | RFFEAnalyzerSettings::RFFEAnalyzerSettings() : mSclkChannel(UNDEFINED_CHANNEL), mSdataChannel(UNDEFINED_CHANNEL) { 5 | mSclkChannelInterface.reset(new AnalyzerSettingInterfaceChannel()); 6 | mSclkChannelInterface->SetTitleAndTooltip("SCLK", "Specify the SCLK Signal(RFFEv1.10a)"); 7 | mSclkChannelInterface->SetChannel(mSclkChannel); 8 | AddInterface(mSclkChannelInterface.get()); 9 | 10 | mSdataChannelInterface.reset(new AnalyzerSettingInterfaceChannel()); 11 | mSdataChannelInterface->SetTitleAndTooltip("SDATA", "Specify the SDATA Signal(RFFEv1.10a)"); 12 | mSdataChannelInterface->SetChannel(mSdataChannel); 13 | AddInterface(mSdataChannelInterface.get()); 14 | 15 | mShowParityInReportInterface.reset(new AnalyzerSettingInterfaceBool()); 16 | mShowParityInReportInterface->SetTitleAndTooltip("Show Parity in Report?", "Check if you want parity information in the exported file"); 17 | AddInterface(mShowParityInReportInterface.get()); 18 | 19 | mShowBusParkInReportInterface.reset(new AnalyzerSettingInterfaceBool()); 20 | mShowBusParkInReportInterface->SetTitleAndTooltip("Show BusPark in Report?", "Check if you want bus park information in the exported file"); 21 | AddInterface(mShowBusParkInReportInterface.get()); 22 | 23 | AddExportOption(0, "Export as csv/text file"); 24 | AddExportExtension(0, "csv", "csv"); 25 | AddExportExtension(0, "text", "txt"); 26 | 27 | ClearChannels(); 28 | AddChannel(mSclkChannel, "SCLK", false); 29 | AddChannel(mSdataChannel, "SDATA", false); 30 | } 31 | 32 | RFFEAnalyzerSettings::~RFFEAnalyzerSettings() { 33 | } 34 | 35 | bool RFFEAnalyzerSettings::SetSettingsFromInterfaces() { 36 | mSclkChannel = mSclkChannelInterface->GetChannel(); 37 | mSdataChannel = mSdataChannelInterface->GetChannel(); 38 | mShowParityInReport = mShowParityInReportInterface->GetValue(); 39 | mShowBusParkInReport = mShowBusParkInReportInterface->GetValue(); 40 | 41 | ClearChannels(); 42 | AddChannel(mSclkChannel, "SCLK", true); 43 | AddChannel(mSdataChannel, "SDATA", true); 44 | 45 | return true; 46 | } 47 | 48 | void RFFEAnalyzerSettings::UpdateInterfacesFromSettings() { 49 | mSclkChannelInterface->SetChannel(mSclkChannel); 50 | mSdataChannelInterface->SetChannel(mSdataChannel); 51 | mShowParityInReportInterface->SetValue(mShowParityInReport); 52 | mShowBusParkInReportInterface->SetValue(mShowBusParkInReport); 53 | } 54 | 55 | void RFFEAnalyzerSettings::LoadSettings(const char *settings) { 56 | SimpleArchive text_archive; 57 | text_archive.SetString(settings); 58 | 59 | text_archive >> mSclkChannel; 60 | text_archive >> mSdataChannel; 61 | text_archive >> mShowParityInReport; 62 | text_archive >> mShowBusParkInReport; 63 | 64 | ClearChannels(); 65 | AddChannel(mSclkChannel, "SCLK", true); 66 | AddChannel(mSdataChannel, "SDATA", true); 67 | 68 | UpdateInterfacesFromSettings(); 69 | } 70 | 71 | const char *RFFEAnalyzerSettings::SaveSettings() { 72 | SimpleArchive text_archive; 73 | 74 | text_archive << mSclkChannel; 75 | text_archive << mSdataChannel; 76 | text_archive << mShowParityInReport; 77 | text_archive << mShowBusParkInReport; 78 | 79 | return SetReturnString(text_archive.GetString()); 80 | } 81 | -------------------------------------------------------------------------------- /src/RFFEAnalyzer.h: -------------------------------------------------------------------------------- 1 | #ifndef RFFE_ANALYZER_H 2 | #define RFFE_ANALYZER_H 3 | 4 | #include 5 | #include "RFFEAnalyzerResults.h" 6 | #include "RFFESimulationDataGenerator.h" 7 | 8 | #pragma warning(push) 9 | // warning C4275: non dll-interface class 'Analyzer2' used 10 | // as base for dll-interface class 'RFFEAnalyzer' 11 | #pragma warning(disable : 4275) 12 | 13 | #define UNEXPECTED_SSC_EXCEPTION 101 14 | 15 | class RFFEAnalyzerSettings; 16 | 17 | class ANALYZER_EXPORT RFFEAnalyzer : public Analyzer2 { 18 | public: 19 | RFFEAnalyzer(); 20 | virtual ~RFFEAnalyzer(); 21 | virtual void SetupResults(); 22 | virtual void WorkerThread(); 23 | 24 | virtual U32 GenerateSimulationData(U64 newest_sample_requested, U32 sample_rate, SimulationChannelDescriptor **simulation_channels); 25 | virtual U32 GetMinimumSampleRateHz(); 26 | 27 | virtual const char *GetAnalyzerName() const; 28 | virtual bool NeedsRerun(); 29 | 30 | #pragma warning(push) 31 | // warning C4251: 'RFFEAnalyzer::<...>' : class <...> needs to have dll-interface 32 | // to be used by clients of class 33 | #pragma warning(disable : 4251) 34 | 35 | protected: // vars 36 | std::auto_ptr mSettings; 37 | std::auto_ptr mResults; 38 | AnalyzerChannelData *mSclk; 39 | AnalyzerChannelData *mSdata; 40 | 41 | RFFESimulationDataGenerator mSimulationDataGenerator; 42 | bool mSimulationInitilized; 43 | 44 | // 45 | U32 mSampleRateHz; 46 | 47 | protected: 48 | // Packet Level Searchs 49 | U8 FindStartSeqCondition(); 50 | U8 FindCommandFrame(); 51 | void FindByteFrame(RFFEAnalyzerResults::RffeFrameType type); 52 | U8 FindISI(); 53 | void FindInterruptSlots(); 54 | void FindParity(bool expParity, U64 extra_data); 55 | void FindBusPark(); 56 | 57 | // Bit Level Waveform Parsing 58 | void GotoNextTransition(); 59 | void GotoSclkEdge(BitState); 60 | BitState GetNextBit(U8 idx); 61 | U64 GetBitStream(U8 len); 62 | 63 | // Physical Layer Checks 64 | bool CheckClockRate(); 65 | 66 | // Interface to the Results/Output 67 | void FillInFrame(RFFEAnalyzerResults::RffeFrameType type, U64 frame_data, U64 extra_data, U32 idx_start, U32 idx_end, U8 flags); 68 | 69 | private: 70 | // -------------------------------------- 71 | // The sampling and storing of chunks of 72 | // RFFE Data are managed in member variables. 73 | // These get handed back and forth between 74 | // a variety of methods so keep them here as 75 | // a common working set of variables 76 | // -------------------------------------- 77 | // RFFE Cmd Type we are in the middle of - ReadExtended, Write0, etc... 78 | RFFEAnalyzerResults::RffeCommandFieldType mRffeCmdType; 79 | 80 | // Used to store the current and previous state of the bus 81 | // (on a transition by transition basis) 82 | U64 mSamplePosition; 83 | 84 | BitState mSclkCurrent; 85 | BitState mSdataCurrent; 86 | BitState mSclkPrevious; 87 | BitState mSdataPrevious; 88 | 89 | bool mUnexpectedSSC; 90 | U64 mUnexpectedSSCStart; 91 | 92 | // Used to store sample offsets that need to be handed to the AnalyzerResults 93 | // objects to indicate the start/stop sample points for annotations in the 94 | // waveform display. 95 | U64 mSampleClkOffsets[16]; 96 | U64 mSampleDataOffsets[16]; 97 | AnalyzerResults::MarkerType mSampleMarker[16]; 98 | 99 | #pragma warning(pop) 100 | }; 101 | #pragma warning(pop) 102 | 103 | extern "C" ANALYZER_EXPORT const char *__cdecl GetAnalyzerName(); 104 | extern "C" ANALYZER_EXPORT Analyzer *__cdecl CreateAnalyzer(); 105 | extern "C" ANALYZER_EXPORT void __cdecl DestroyAnalyzer(Analyzer *analyzer); 106 | 107 | #endif // RFFE_ANALYZER_H 108 | -------------------------------------------------------------------------------- /src/RFFESimulationDataGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "RFFESimulationDataGenerator.h" 2 | #include "RFFEAnalyzerSettings.h" 3 | #include "RFFEUtil.h" 4 | 5 | #include 6 | 7 | RFFESimulationDataGenerator::RFFESimulationDataGenerator() { 8 | mLSFRData = 0xE1; // Must be non-zero (or we get stuck) 9 | } 10 | 11 | RFFESimulationDataGenerator::~RFFESimulationDataGenerator() { 12 | } 13 | 14 | void RFFESimulationDataGenerator::Initialize(U32 simulation_sample_rate, RFFEAnalyzerSettings *settings) { 15 | mSimulationSampleRateHz = simulation_sample_rate; 16 | mSettings = settings; 17 | 18 | mClockGenerator.Init(simulation_sample_rate / 10, simulation_sample_rate); 19 | 20 | if (settings->mSclkChannel != UNDEFINED_CHANNEL) 21 | mSclk = mRffeSimulationChannels.Add(settings->mSclkChannel, mSimulationSampleRateHz, BIT_LOW); 22 | else 23 | mSclk = NULL; 24 | 25 | if (settings->mSdataChannel != UNDEFINED_CHANNEL) 26 | mSdata = mRffeSimulationChannels.Add(settings->mSdataChannel, mSimulationSampleRateHz, BIT_LOW); 27 | else 28 | mSdata = NULL; 29 | 30 | // insert 10 bit-periods of idle 31 | mRffeSimulationChannels.AdvanceAll(mClockGenerator.AdvanceByHalfPeriod(10.0)); 32 | } 33 | 34 | U32 RFFESimulationDataGenerator::GenerateSimulationData(U64 largest_sample_requested, U32 sample_rate, SimulationChannelDescriptor **simulation_channels) { 35 | U64 adjusted_largest_sample_requested = AnalyzerHelpers::AdjustSimulationTargetSample(largest_sample_requested, sample_rate, mSimulationSampleRateHz); 36 | 37 | while (mSclk->GetCurrentSampleNumber() < adjusted_largest_sample_requested) { 38 | CreateRffeTransaction(); 39 | 40 | mRffeSimulationChannels.AdvanceAll(mClockGenerator.AdvanceByHalfPeriod(80.0)); 41 | } 42 | 43 | *simulation_channels = mRffeSimulationChannels.GetArray(); 44 | return mRffeSimulationChannels.GetCount(); 45 | } 46 | 47 | void RFFESimulationDataGenerator::CreateRffeTransaction() { 48 | U8 cmd; 49 | U8 sa_addrs[] = {0x5}; 50 | 51 | for (U32 adr = 0; adr < sizeof(sa_addrs) / sizeof(sa_addrs[0]); adr++) { 52 | for (U32 i = 0; i < 256; i += 1) { 53 | CreateSSC(); 54 | CreateSlaveAddress(sa_addrs[adr]); 55 | cmd = i & 0xff; 56 | CreateByteFrame(cmd); 57 | 58 | switch (RFFEUtil::decodeRFFECmdFrame(cmd)) { 59 | case RFFEAnalyzerResults::RffeTypeExtWrite: 60 | CreateByteFrame(CreateRandomData()); 61 | for (U32 i = 0; i <= RFFEUtil::byteCount(cmd); i += 1) { 62 | CreateByteFrame(CreateRandomData()); 63 | } 64 | CreateBusPark(); 65 | break; 66 | case RFFEAnalyzerResults::RffeTypeReserved: 67 | CreateBusPark(); 68 | break; 69 | 70 | case RFFEAnalyzerResults::RffeTypeMasterRead: 71 | CreateByteFrame(CreateRandomData()); 72 | CreateBusPark(); 73 | for (U32 i = 0; i <= RFFEUtil::byteCount(cmd); i += 1) { 74 | CreateByteFrame(CreateRandomData()); 75 | } 76 | CreateBusPark(); 77 | break; 78 | case RFFEAnalyzerResults::RffeTypeMasterWrite: 79 | CreateByteFrame(CreateRandomData()); 80 | for (U32 i = 0; i <= RFFEUtil::byteCount(cmd); i += 1) { 81 | CreateByteFrame(CreateRandomData()); 82 | } 83 | CreateBusPark(); 84 | break; 85 | case RFFEAnalyzerResults::RffeTypeMasterHandoff: 86 | CreateBusPark(); 87 | for (U32 i = 0; i <= RFFEUtil::byteCount(cmd); i += 1) { 88 | CreateByteFrame((CreateRandomData() & 0x18) | 0x80); // Mask Out bits that are always zero and always set the ACK bit 89 | } 90 | CreateBusPark(); 91 | break; 92 | case RFFEAnalyzerResults::RffeTypeInterrupt: 93 | CreateBusPark(); 94 | CreateBits(2, 0x3); // Always indicate interrupts 95 | CreateBusPark(); 96 | for (U32 i = 0; i < 16; i += 1) { 97 | CreateBits(2, CreateRandomData() & 0x2); // Interrupts are 1 bit of interrupt followed by a 0/BP 98 | } 99 | break; 100 | case RFFEAnalyzerResults::RffeTypeExtRead: 101 | CreateByteFrame(CreateRandomData()); 102 | CreateBusPark(); 103 | for (U32 i = 0; i <= RFFEUtil::byteCount(cmd); i += 1) { 104 | CreateByteFrame(CreateRandomData()); 105 | } 106 | CreateBusPark(); 107 | break; 108 | case RFFEAnalyzerResults::RffeTypeExtLongWrite: 109 | CreateByteFrame(CreateRandomData()); 110 | CreateByteFrame(CreateRandomData()); 111 | for (U32 i = 0; i <= RFFEUtil::byteCount(cmd); i += 1) { 112 | CreateByteFrame(CreateRandomData()); 113 | } 114 | CreateBusPark(); 115 | break; 116 | case RFFEAnalyzerResults::RffeTypeExtLongRead: 117 | CreateByteFrame(CreateRandomData()); 118 | CreateByteFrame(CreateRandomData()); 119 | CreateBusPark(); 120 | for (U32 i = 0; i <= RFFEUtil::byteCount(cmd); i += 1) { 121 | CreateByteFrame(CreateRandomData()); 122 | } 123 | CreateBusPark(); 124 | break; 125 | case RFFEAnalyzerResults::RffeTypeNormalWrite: 126 | CreateByteFrame(CreateRandomData()); 127 | CreateBusPark(); 128 | break; 129 | case RFFEAnalyzerResults::RffeTypeNormalRead: 130 | CreateBusPark(); 131 | CreateByteFrame(CreateRandomData()); 132 | CreateBusPark(); 133 | break; 134 | case RFFEAnalyzerResults::RffeTypeWrite0: 135 | CreateBusPark(); 136 | break; 137 | } 138 | } 139 | } 140 | } 141 | 142 | void RFFESimulationDataGenerator::CreateSSC() { 143 | if (mSclk->GetCurrentBitState() == BIT_HIGH) { 144 | mSclk->Transition(); 145 | } 146 | 147 | if (mSdata->GetCurrentBitState() == BIT_HIGH) { 148 | mSdata->Transition(); 149 | } 150 | 151 | mRffeSimulationChannels.AdvanceAll(mClockGenerator.AdvanceByHalfPeriod(2.0)); 152 | 153 | // sdata pulse for 1-clock cycle 154 | mSdata->Transition(); 155 | mRffeSimulationChannels.AdvanceAll(mClockGenerator.AdvanceByHalfPeriod(2.0)); 156 | mSdata->Transition(); 157 | // sdata and sclk state low for 1-clock cycle 158 | mRffeSimulationChannels.AdvanceAll(mClockGenerator.AdvanceByHalfPeriod(2.0)); 159 | } 160 | 161 | void RFFESimulationDataGenerator::CreateSlaveAddress(U8 addr) { 162 | CreateBits(4, addr & 0x0f); 163 | } 164 | 165 | void RFFESimulationDataGenerator::CreateByteFrame(U8 byte) { 166 | CreateByte(byte); 167 | CreateParity(byte); 168 | } 169 | 170 | void RFFESimulationDataGenerator::CreateByte(U8 cmd) { 171 | CreateBits(8, cmd); 172 | } 173 | 174 | void RFFESimulationDataGenerator::CreateParity(U8 byte) { 175 | CreateBits(1, ParityTable256[byte]); // Use a different algorithm for generating parity than we have for checking it 176 | } 177 | 178 | void RFFESimulationDataGenerator::CreateBusPark() { 179 | CreateBits(1, 0); 180 | } 181 | 182 | void RFFESimulationDataGenerator::CreateBits(U8 bits, U8 cmd) { 183 | BitState bit; 184 | U8 idx = 0x1 << (bits - 1); 185 | 186 | for (U32 i = 0; i < bits; i += 1) { 187 | mSclk->Transition(); 188 | mRffeSimulationChannels.AdvanceAll(mClockGenerator.AdvanceByHalfPeriod(.5)); 189 | 190 | if (cmd & idx) { 191 | bit = BIT_HIGH; 192 | } else { 193 | bit = BIT_LOW; 194 | } 195 | mSdata->TransitionIfNeeded(bit); 196 | 197 | mRffeSimulationChannels.AdvanceAll(mClockGenerator.AdvanceByHalfPeriod(.5)); 198 | mSclk->Transition(); 199 | 200 | mRffeSimulationChannels.AdvanceAll(mClockGenerator.AdvanceByHalfPeriod(1.0)); 201 | 202 | idx = idx >> 0x1; 203 | } 204 | } 205 | 206 | U8 RFFESimulationDataGenerator::CreateRandomData() { 207 | U8 lsb; 208 | 209 | lsb = mLSFRData & 0x1; 210 | mLSFRData >>= 1; 211 | if (lsb) { 212 | mLSFRData ^= 0xB8; // Maximum period polynomial for Galois LFSR of 8 bits 213 | } 214 | return mLSFRData; 215 | } 216 | -------------------------------------------------------------------------------- /src/RFFEAnalyzerResults.cpp: -------------------------------------------------------------------------------- 1 | #include "RFFEAnalyzerResults.h" 2 | #include 3 | #include "RFFEAnalyzer.h" 4 | #include "RFFEAnalyzerSettings.h" 5 | #include 6 | #include 7 | 8 | RFFEAnalyzerResults::RFFEAnalyzerResults(RFFEAnalyzer *analyzer, RFFEAnalyzerSettings *settings) : AnalyzerResults(), mSettings(settings), mAnalyzer(analyzer) { 9 | } 10 | 11 | RFFEAnalyzerResults::~RFFEAnalyzerResults() { 12 | } 13 | 14 | // 15 | void RFFEAnalyzerResults::GenerateBubbleText(U64 frame_index, Channel &channel, DisplayBase display_base) { 16 | char number_str[8]; 17 | char results_str[16]; 18 | 19 | channel = channel; 20 | 21 | ClearResultStrings(); 22 | Frame frame = GetFrame(frame_index); 23 | 24 | switch (frame.mType) { 25 | case RffeSSCField: { 26 | AddResultString("SSC"); 27 | } break; 28 | 29 | case RffeSAField: { 30 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 4, number_str, 8); 31 | snprintf(results_str, sizeof(results_str), "SA:%s", number_str); 32 | AddResultString("SA"); 33 | AddResultString(results_str); 34 | } break; 35 | 36 | case RffeCommandField: { 37 | AddResultString(RffeCommandFieldStringShort[frame.mData1]); 38 | AddResultString(RffeCommandFieldStringMid[frame.mData1]); 39 | } break; 40 | 41 | case RffeExByteCountField: { 42 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 4, number_str, 8); 43 | snprintf(results_str, sizeof(results_str), "BC:%s", number_str); 44 | AddResultString("BC"); 45 | AddResultString(results_str); 46 | } break; 47 | 48 | case RffeExLongByteCountField: { 49 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 3, number_str, 8); 50 | snprintf(results_str, sizeof(results_str), "BC:%s", number_str); 51 | AddResultString("BC"); 52 | AddResultString(results_str); 53 | } break; 54 | 55 | case RffeAddressField: { 56 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 8, number_str, 8); 57 | snprintf(results_str, sizeof(results_str), "A:%s", number_str); 58 | AddResultString("A"); 59 | AddResultString(results_str); 60 | } break; 61 | 62 | case RffeAddressHiField: { 63 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 8, number_str, 8); 64 | snprintf(results_str, sizeof(results_str), "AH:%s", number_str); 65 | AddResultString("A"); 66 | AddResultString(results_str); 67 | 68 | } break; 69 | 70 | case RffeAddressLoField: { 71 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 8, number_str, 8); 72 | snprintf(results_str, sizeof(results_str), "AL:%s", number_str); 73 | AddResultString("A"); 74 | AddResultString(results_str); 75 | } break; 76 | 77 | case RffeShortDataField: { 78 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 7, number_str, 8); 79 | snprintf(results_str, sizeof(results_str), "D:%s", number_str); 80 | AddResultString("D"); 81 | AddResultString(results_str); 82 | } break; 83 | 84 | case RffeDataField: { 85 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 8, number_str, 8); 86 | snprintf(results_str, sizeof(results_str), "D:%s", number_str); 87 | AddResultString("D"); 88 | AddResultString(results_str); 89 | } break; 90 | 91 | case RffeMasterHandoffAckField: { 92 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 8, number_str, 8); 93 | snprintf(results_str, sizeof(results_str), "MHAck:%s", number_str); 94 | AddResultString("MHA"); 95 | AddResultString(results_str); 96 | } break; 97 | 98 | case RffeISIField: { 99 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 2, number_str, 4); 100 | AddResultString("ISI"); 101 | AddResultString("ISI"); 102 | } break; 103 | 104 | case RffeIntSlotField: { 105 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 1, number_str, 4); 106 | snprintf(results_str, sizeof(results_str), "INT%d", U8(frame.mData2)); 107 | AddResultString("I"); 108 | AddResultString(results_str); 109 | } break; 110 | 111 | case RffeParityField: { 112 | AnalyzerHelpers::GetNumberString(frame.mData1, Decimal, 1, number_str, 4); 113 | snprintf(results_str, sizeof(results_str), "P:%s", number_str); 114 | AddResultString("P"); 115 | AddResultString(results_str); 116 | } break; 117 | 118 | case RffeBusParkField: { 119 | AddResultString("B"); 120 | AddResultString("BP"); 121 | } break; 122 | 123 | case RffeErrorCaseField: 124 | default: { 125 | char number1_str[20]; 126 | char number2_str[20]; 127 | 128 | AnalyzerHelpers::GetNumberString(frame.mData1, Hexadecimal, 32, number1_str, 10); 129 | AnalyzerHelpers::GetNumberString(frame.mData2, Hexadecimal, 32, number2_str, 10); 130 | snprintf(results_str, sizeof(results_str), "E:%s - %s", number1_str, number2_str); 131 | AddResultString("E"); 132 | AddResultString(results_str); 133 | } break; 134 | } 135 | } 136 | 137 | void RFFEAnalyzerResults::GenerateExportFile(const char *file, DisplayBase display_base, U32 export_type_user_id) { 138 | U64 first_frame_id; 139 | U64 last_frame_id; 140 | U64 address; 141 | char time_str[16]; 142 | char packet_str[16]; 143 | char sa_str[8]; 144 | char type_str[16]; 145 | char addr_str[16]; 146 | char parity_str[8]; 147 | char parityCmd_str[8]; 148 | char bc_str[8]; 149 | char data_str[8]; 150 | bool show_parity = mSettings->mShowParityInReport; 151 | bool show_buspark = mSettings->mShowBusParkInReport; 152 | char payload_str[256]; 153 | char results_str[256]; 154 | Frame frame; 155 | void *f = AnalyzerHelpers::StartFile(file); 156 | 157 | export_type_user_id = export_type_user_id; 158 | 159 | U64 trigger_sample = mAnalyzer->GetTriggerSample(); 160 | U32 sample_rate = mAnalyzer->GetSampleRate(); 161 | 162 | if (show_parity) { 163 | snprintf(results_str, sizeof(results_str), "Time[s],Packet ID,SA,Type,Adr,BC,CmdP,Payload\n"); 164 | } else { 165 | snprintf(results_str, sizeof(results_str), "Time[s],Packet ID,SA,Type,Adr,BC,Payload\n"); 166 | } 167 | AnalyzerHelpers::AppendToFile((U8 *)results_str, (U32)strlen(results_str), f); 168 | 169 | U64 num_packets = GetNumPackets(); 170 | for (U32 i = 0; i < num_packets; i++) { 171 | // package id 172 | AnalyzerHelpers::GetNumberString(i, Decimal, 0, packet_str, 16); 173 | 174 | snprintf(sa_str, 8, ""); 175 | snprintf(type_str, 8, ""); 176 | snprintf(addr_str, 8, ""); 177 | snprintf(parity_str, 8, ""); 178 | snprintf(parityCmd_str, 8, ""); 179 | snprintf(bc_str, 8, ""); 180 | snprintf(data_str, 8, ""); 181 | snprintf(payload_str, 256, ""); 182 | snprintf(results_str, 256, ""); 183 | address = 0x0; 184 | 185 | GetFramesContainedInPacket(i, &first_frame_id, &last_frame_id); 186 | for (U64 j = first_frame_id; j <= last_frame_id; j++) { 187 | frame = GetFrame(j); 188 | 189 | switch (frame.mType) { 190 | case RffeSSCField: 191 | // starting time using SSC as marker 192 | AnalyzerHelpers::GetTimeString(frame.mStartingSampleInclusive, trigger_sample, sample_rate, time_str, 16); 193 | break; 194 | 195 | case RffeSAField: 196 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 4, sa_str, 8); 197 | break; 198 | 199 | case RffeCommandField: 200 | snprintf(type_str, sizeof(type_str), "%s", RffeCommandFieldStringMid[frame.mData1]); 201 | if (frame.mData1 == RffeTypeNormalWrite || frame.mData1 == RffeTypeNormalRead) { 202 | snprintf(bc_str, sizeof(bc_str), "0x0"); 203 | } else if (frame.mData1 == RffeTypeWrite0) { 204 | snprintf(bc_str, sizeof(bc_str), "0x0"); 205 | snprintf(addr_str, sizeof(addr_str), "0x0"); 206 | } 207 | break; 208 | 209 | case RffeExByteCountField: 210 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 4, bc_str, 8); 211 | break; 212 | 213 | case RffeExLongByteCountField: 214 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 3, bc_str, 8); 215 | break; 216 | 217 | case RffeAddressField: 218 | address = frame.mData1; 219 | AnalyzerHelpers::GetNumberString(address, display_base, sizeof(addr_str), addr_str, 16); 220 | break; 221 | 222 | case RffeAddressHiField: 223 | address = (frame.mData1 << 8); 224 | AnalyzerHelpers::GetNumberString(address, display_base, sizeof(addr_str), addr_str, 16); 225 | break; 226 | 227 | case RffeAddressLoField: 228 | address |= frame.mData1; 229 | AnalyzerHelpers::GetNumberString(address, display_base, sizeof(addr_str), addr_str, 16); 230 | break; 231 | 232 | case RffeShortDataField: 233 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 7, data_str, 8); 234 | snprintf(payload_str, sizeof(payload_str), "%s", data_str); 235 | break; 236 | 237 | case RffeDataField: 238 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 8, data_str, 8); 239 | // Gather up all the data bytes into the payload 240 | if (strlen(payload_str) == 0) { 241 | snprintf(payload_str, sizeof(payload_str), "%s", data_str); 242 | } else { 243 | snprintf(payload_str, sizeof(payload_str), "%s %s", payload_str, data_str); 244 | } 245 | break; 246 | 247 | case RffeParityField: 248 | if (show_parity) { 249 | AnalyzerHelpers::GetNumberString(frame.mData1, Decimal, 1, parity_str, 4); 250 | if (frame.mData2) { 251 | // Data Parity 252 | if (strlen(payload_str) == 0) { 253 | snprintf(payload_str, sizeof(payload_str), "P%s", parity_str); 254 | } else { 255 | snprintf(payload_str, sizeof(payload_str), "%s P%s", payload_str, parity_str); 256 | } 257 | } else { 258 | snprintf(parityCmd_str, sizeof(parityCmd_str), "P%s", parity_str); // CmdParity 259 | } 260 | } 261 | break; 262 | 263 | case RffeBusParkField: 264 | if (show_buspark) { 265 | if (strlen(payload_str) == 0) { 266 | snprintf(payload_str, sizeof(payload_str), "BP"); 267 | } else { 268 | snprintf(payload_str, sizeof(payload_str), "%s BP", payload_str); 269 | } 270 | } 271 | break; 272 | 273 | case RffeErrorCaseField: 274 | default: 275 | char number1_str[20]; 276 | char number2_str[20]; 277 | 278 | AnalyzerHelpers::GetNumberString(frame.mData1, Hexadecimal, 32, number1_str, 10); 279 | AnalyzerHelpers::GetNumberString(frame.mData2, Hexadecimal, 32, number2_str, 10); 280 | snprintf(payload_str, sizeof(payload_str), "E:%s - %s ", number1_str, number2_str); 281 | break; 282 | } 283 | } 284 | 285 | if (show_parity) { 286 | snprintf(results_str, sizeof(results_str), "%s,%s,%s,%s,%s,%s,%s,%s\n", time_str, packet_str, sa_str, type_str, addr_str, bc_str, parityCmd_str, 287 | payload_str); 288 | } else { 289 | snprintf(results_str, sizeof(results_str), "%s,%s,%s,%s,%s,%s,%s\n", time_str, packet_str, sa_str, type_str, addr_str, bc_str, payload_str); 290 | } 291 | AnalyzerHelpers::AppendToFile((U8 *)results_str, (U32)strlen(results_str), f); 292 | 293 | if (UpdateExportProgressAndCheckForCancel(i, num_packets) == true) { 294 | AnalyzerHelpers::EndFile(f); 295 | return; 296 | } 297 | } 298 | } 299 | 300 | void RFFEAnalyzerResults::GenerateFrameTabularText(U64 frame_index, DisplayBase display_base) { 301 | char time_str[16]; 302 | char sa_str[8]; 303 | char type_str[16]; 304 | char parity_str[8]; 305 | char parityCmd_str[8]; 306 | char addr_str[8]; 307 | char bc_str[8]; 308 | char data_str[8]; 309 | char frame_str[32]; 310 | Frame frame; 311 | 312 | U64 trigger_sample = mAnalyzer->GetTriggerSample(); 313 | U32 sample_rate = mAnalyzer->GetSampleRate(); 314 | 315 | ClearTabularText(); 316 | 317 | frame = GetFrame(frame_index); 318 | 319 | switch (frame.mType) { 320 | case RffeSSCField: 321 | // starting time using SSC as marker 322 | AnalyzerHelpers::GetTimeString(frame.mStartingSampleInclusive, trigger_sample, sample_rate, time_str, 16); 323 | snprintf(frame_str, sizeof(frame_str), "SSC"); 324 | break; 325 | 326 | case RffeSAField: 327 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 4, sa_str, 8); 328 | snprintf(frame_str, sizeof(frame_str), "SA: %s", sa_str); 329 | break; 330 | 331 | case RffeCommandField: 332 | snprintf(type_str, sizeof(type_str), "%s", RffeCommandFieldStringMid[frame.mData1]); 333 | snprintf(frame_str, sizeof(frame_str), "Type: %s", type_str); 334 | break; 335 | 336 | case RffeExByteCountField: 337 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 4, bc_str, 8); 338 | snprintf(frame_str, sizeof(frame_str), "ExByteCount: %s", bc_str); 339 | break; 340 | 341 | case RffeExLongByteCountField: 342 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 3, bc_str, 8); 343 | snprintf(frame_str, sizeof(frame_str), "ExLongByteCount: %s", bc_str); 344 | break; 345 | 346 | case RffeAddressField: 347 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 8, addr_str, 8); 348 | snprintf(frame_str, sizeof(frame_str), "Addr: %s", addr_str); 349 | break; 350 | 351 | case RffeAddressHiField: 352 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 8, addr_str, 8); 353 | snprintf(frame_str, sizeof(frame_str), "AddrHi: %s", addr_str); 354 | break; 355 | 356 | case RffeAddressLoField: 357 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 8, addr_str, 8); 358 | snprintf(frame_str, sizeof(frame_str), "AddrLo: %s", addr_str); 359 | break; 360 | 361 | case RffeShortDataField: 362 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 7, data_str, 8); 363 | snprintf(frame_str, sizeof(frame_str), "DataShort: %s", data_str); 364 | break; 365 | 366 | case RffeDataField: 367 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 8, data_str, 8); 368 | snprintf(frame_str, sizeof(frame_str), "Data: %s", data_str); 369 | break; 370 | 371 | case RffeParityField: 372 | if (frame.mData2 == 1) { 373 | AnalyzerHelpers::GetNumberString(frame.mData1, Decimal, 1, parity_str, 4); 374 | snprintf(frame_str, sizeof(frame_str), "DataParity: %s", parity_str); 375 | } else { 376 | AnalyzerHelpers::GetNumberString(frame.mData1, Decimal, 1, parityCmd_str, 4); 377 | snprintf(frame_str, sizeof(frame_str), "CmdParity: %s", parityCmd_str); 378 | } 379 | break; 380 | 381 | case RffeBusParkField: 382 | snprintf(frame_str, sizeof(frame_str), "BP"); 383 | break; 384 | 385 | case RffeErrorCaseField: 386 | default: 387 | char number1_str[20]; 388 | char number2_str[20]; 389 | 390 | AnalyzerHelpers::GetNumberString(frame.mData1, Hexadecimal, 32, number1_str, 10); 391 | AnalyzerHelpers::GetNumberString(frame.mData2, Hexadecimal, 32, number2_str, 10); 392 | snprintf(frame_str, sizeof(frame_str), "Error: %s - %s", number1_str, number2_str); 393 | break; 394 | } 395 | 396 | AddTabularText(frame_str); 397 | } 398 | 399 | void RFFEAnalyzerResults::GeneratePacketTabularText(U64 packet_id, DisplayBase display_base) { 400 | packet_id = packet_id; 401 | display_base = display_base; 402 | 403 | ClearResultStrings(); 404 | AddResultString("not supported yet"); 405 | } 406 | 407 | void RFFEAnalyzerResults::GenerateTransactionTabularText(U64 transaction_id, DisplayBase display_base) { 408 | transaction_id = transaction_id; 409 | display_base = display_base; 410 | 411 | ClearResultStrings(); 412 | AddResultString("not supported yet"); 413 | } 414 | -------------------------------------------------------------------------------- /src/RFFEAnalyzer.cpp: -------------------------------------------------------------------------------- 1 | #include "RFFEAnalyzer.h" 2 | #include "RFFEAnalyzerSettings.h" 3 | #include "RFFEUtil.h" 4 | #include 5 | 6 | // ============================================================================== 7 | // Boilerplate for API 8 | // ============================================================================== 9 | RFFEAnalyzer::RFFEAnalyzer() : Analyzer2(), mSettings(new RFFEAnalyzerSettings()), mSimulationInitilized(false) { 10 | SetAnalyzerSettings(mSettings.get()); 11 | 12 | // Setup the default state on the bus 13 | mSclkCurrent = BIT_LOW; 14 | mSclkPrevious = BIT_LOW; 15 | mSdataCurrent = BIT_LOW; 16 | mSdataPrevious = BIT_LOW; 17 | mUnexpectedSSC = false; 18 | } 19 | 20 | RFFEAnalyzer::~RFFEAnalyzer() { 21 | KillThread(); 22 | } 23 | 24 | void RFFEAnalyzer::SetupResults() { 25 | mResults.reset(new RFFEAnalyzerResults(this, mSettings.get())); 26 | SetAnalyzerResults(mResults.get()); 27 | mResults->AddChannelBubblesWillAppearOn(mSettings->mSdataChannel); 28 | } 29 | 30 | // ============================================================================== 31 | // Main data parsing method 32 | // ============================================================================== 33 | void RFFEAnalyzer::WorkerThread() { 34 | U8 byte_count; 35 | 36 | mSampleRateHz = GetSampleRate(); 37 | 38 | mSdata = GetAnalyzerChannelData(mSettings->mSdataChannel); 39 | mSclk = GetAnalyzerChannelData(mSettings->mSclkChannel); 40 | 41 | mResults->CancelPacketAndStartNewPacket(); 42 | 43 | while (1) { 44 | try { 45 | // Look for an SSC 46 | // This method only returns false if there is no more data to be scanned 47 | // in which case, we call the Cancel and wait for new data method in the 48 | // API 49 | if (!FindStartSeqCondition()) { 50 | mResults->CancelPacketAndStartNewPacket(); 51 | break; 52 | } 53 | 54 | // Find and parse the Slave Address and the RFFE Command 55 | // Return ByteCount field - depending on the command it may or may not be 56 | // relevent 57 | byte_count = FindCommandFrame(); 58 | 59 | // We know what kind of packet we are handling now, and various parameters 60 | // including the number of data bytes. Go ahead and handle the different 61 | // cases 62 | switch (mRffeCmdType) { 63 | case RFFEAnalyzerResults::RffeTypeExtWrite: 64 | FindByteFrame(RFFEAnalyzerResults::RffeAddressField); 65 | for (U32 i = 0; i <= byte_count; i += 1) { 66 | FindByteFrame(RFFEAnalyzerResults::RffeDataField); 67 | } 68 | break; 69 | case RFFEAnalyzerResults::RffeTypeReserved: 70 | break; 71 | case RFFEAnalyzerResults::RffeTypeMasterRead: 72 | FindByteFrame(RFFEAnalyzerResults::RffeAddressField); 73 | FindBusPark(); 74 | for (U32 i = 0; i <= byte_count; i += 1) { 75 | FindByteFrame(RFFEAnalyzerResults::RffeDataField); 76 | } 77 | break; 78 | case RFFEAnalyzerResults::RffeTypeMasterWrite: 79 | FindByteFrame(RFFEAnalyzerResults::RffeAddressField); 80 | for (U32 i = 0; i <= byte_count; i += 1) { 81 | FindByteFrame(RFFEAnalyzerResults::RffeDataField); 82 | } 83 | break; 84 | case RFFEAnalyzerResults::RffeTypeMasterHandoff: 85 | FindBusPark(); 86 | for (U32 i = 0; i <= byte_count; i += 1) { 87 | FindByteFrame(RFFEAnalyzerResults::RffeDataField); 88 | } 89 | break; 90 | case RFFEAnalyzerResults::RffeTypeInterrupt: 91 | FindBusPark(); 92 | if (FindISI()) { 93 | FindInterruptSlots(); 94 | } 95 | break; 96 | case RFFEAnalyzerResults::RffeTypeExtRead: 97 | FindByteFrame(RFFEAnalyzerResults::RffeAddressField); 98 | FindBusPark(); 99 | for (U32 i = 0; i <= byte_count; i += 1) { 100 | FindByteFrame(RFFEAnalyzerResults::RffeDataField); 101 | } 102 | break; 103 | case RFFEAnalyzerResults::RffeTypeExtLongWrite: 104 | FindByteFrame(RFFEAnalyzerResults::RffeAddressHiField); 105 | FindByteFrame(RFFEAnalyzerResults::RffeAddressLoField); 106 | for (U32 i = 0; i <= byte_count; i += 1) { 107 | FindByteFrame(RFFEAnalyzerResults::RffeDataField); 108 | } 109 | break; 110 | case RFFEAnalyzerResults::RffeTypeExtLongRead: 111 | FindByteFrame(RFFEAnalyzerResults::RffeAddressHiField); 112 | FindByteFrame(RFFEAnalyzerResults::RffeAddressLoField); 113 | FindBusPark(); 114 | for (U32 i = 0; i <= byte_count; i += 1) { 115 | FindByteFrame(RFFEAnalyzerResults::RffeDataField); 116 | } 117 | break; 118 | case RFFEAnalyzerResults::RffeTypeNormalWrite: 119 | FindByteFrame(RFFEAnalyzerResults::RffeDataField); 120 | break; 121 | case RFFEAnalyzerResults::RffeTypeNormalRead: 122 | FindBusPark(); 123 | FindByteFrame(RFFEAnalyzerResults::RffeDataField); 124 | break; 125 | case RFFEAnalyzerResults::RffeTypeWrite0: 126 | break; 127 | } 128 | 129 | // Finish up with a Bus Park (except for interrupts) 130 | if (mRffeCmdType != RFFEAnalyzerResults::RffeTypeInterrupt) { 131 | FindBusPark(); 132 | } 133 | 134 | } catch (int exception) { 135 | if (exception == UNEXPECTED_SSC_EXCEPTION) { 136 | // Do nothing, this can happen 137 | } 138 | } 139 | 140 | // Commit the Result and call the API Required finished? method. 141 | mResults->CommitPacketAndStartNewPacket(); 142 | CheckIfThreadShouldExit(); 143 | } 144 | } 145 | 146 | // ============================================================================== 147 | // Worker thread support methods 148 | // ============================================================================== 149 | U8 RFFEAnalyzer::FindStartSeqCondition() { 150 | bool ssc_possible = 0; 151 | U8 flags = 0; 152 | 153 | // Check for no more data, and return error status if none remains 154 | if (!mSclk->DoMoreTransitionsExistInCurrentData()) 155 | return 0; 156 | if (!mSdata->DoMoreTransitionsExistInCurrentData()) 157 | return 0; 158 | 159 | // Scan for an SSC 160 | if (mUnexpectedSSC) { 161 | flags |= (DISPLAY_AS_ERROR_FLAG | DISPLAY_AS_WARNING_FLAG | RFFE_INCOMPLETE_PACKET_ERROR_FLAG); 162 | mUnexpectedSSC = false; // Reset our unexpected SSC state 163 | mSampleClkOffsets[0] = mUnexpectedSSCStart; // The unexpected SSC logic 164 | // saved the sdata rising edge 165 | // position 166 | mSampleDataOffsets[0] = mUnexpectedSSCStart; // For the Marker 167 | } else { 168 | while (1) { 169 | GotoNextTransition(); 170 | 171 | if (mSclkCurrent == BIT_HIGH) { 172 | ssc_possible = 0; 173 | } else if (mSclkCurrent == BIT_LOW && mSclkPrevious == BIT_LOW && mSdataCurrent == BIT_HIGH && mSdataPrevious == BIT_LOW) { 174 | ssc_possible = 1; 175 | mSampleClkOffsets[0] = mSamplePosition; // For the Frame Boundaries 176 | mSampleDataOffsets[0] = mSamplePosition; // For the Marker 177 | } else if (ssc_possible && mSclkCurrent == BIT_LOW && mSdataCurrent == BIT_LOW) { 178 | break; // SSC! 179 | } 180 | } 181 | // TODO: Here is where we could check RFFE SSC Pulse width, if we were so 182 | // inclined 183 | // ssc_pulse_width_in_samples = sdata_fedge_sample - sdata_redge_sample; 184 | } 185 | 186 | // SSC is complete at the rising edge of the SCLK 187 | GotoSclkEdge(BIT_HIGH); 188 | mSampleClkOffsets[1] = mSamplePosition; 189 | 190 | // TODO: Here is where we could check SSC to SCLK rising edge width, again, if 191 | // we were so inclined 192 | // ssc_2_sclk_delay_in_samples = mSamplePosition - sdata_fedge_sample; 193 | 194 | // Setup the 'Start' Marker and send off the Frame to the AnalyzerResults 195 | mSampleMarker[0] = AnalyzerResults::Start; 196 | FillInFrame(RFFEAnalyzerResults::RffeSSCField, 0, 0, 0, 1, flags); 197 | 198 | return 1; 199 | } 200 | 201 | // ------------------------------------------------------------------------------ 202 | U8 RFFEAnalyzer::FindCommandFrame() { 203 | U8 byte_count = 0; 204 | U8 flags = 0; 205 | U64 RffeID; 206 | U64 RffeCmd; 207 | 208 | // Get RFFE SA+Command (4 + 8 bits) and decode the fields 209 | // Why grab all 12 bits? So we can calculate parity across the SA+Cmd field 210 | // after we are done parsing the Command 211 | RffeCmd = GetBitStream(12); 212 | 213 | // Now look at the RFFE command and decode the various options. 214 | mRffeCmdType = RFFEUtil::decodeRFFECmdFrame((U8)(RffeCmd & 0xFF)); 215 | byte_count = RFFEUtil::byteCount((U8)RffeCmd); 216 | RffeID = (RffeCmd & 0xF00) >> 8; 217 | 218 | // Check for an invalid Master address, if this is a Master Command 219 | if ((mRffeCmdType == RFFEAnalyzerResults::RffeTypeMasterRead || mRffeCmdType == RFFEAnalyzerResults::RffeTypeMasterWrite || 220 | mRffeCmdType == RFFEAnalyzerResults::RffeTypeMasterHandoff) && 221 | (RffeID > 0x3)) { 222 | flags = RFFE_INVALID_MASTER_ID; 223 | } 224 | // Log the Master or Slave Address 225 | FillInFrame(RFFEAnalyzerResults::RffeSAField, RffeID, 0, 0, 4, flags); 226 | flags = 0; 227 | 228 | switch (mRffeCmdType) { 229 | case RFFEAnalyzerResults::RffeTypeReserved: 230 | // 8 Bit Reserved Cmd Type 231 | flags |= (DISPLAY_AS_ERROR_FLAG | DISPLAY_AS_WARNING_FLAG | RFFE_INVALID_CMD_ERROR_FLAG); 232 | FillInFrame(RFFEAnalyzerResults::RffeCommandField, mRffeCmdType, 0, 4, 12, flags); 233 | break; 234 | case RFFEAnalyzerResults::RffeTypeMasterRead: 235 | case RFFEAnalyzerResults::RffeTypeMasterWrite: 236 | case RFFEAnalyzerResults::RffeTypeMasterHandoff: 237 | case RFFEAnalyzerResults::RffeTypeInterrupt: 238 | // Interrupt/Master commands - 8 Bit RFFE Command 239 | FillInFrame(RFFEAnalyzerResults::RffeCommandField, mRffeCmdType, 0, 4, 12, flags); 240 | break; 241 | case RFFEAnalyzerResults::RffeTypeExtWrite: 242 | case RFFEAnalyzerResults::RffeTypeExtRead: 243 | // 4 Bit Command w/ 4 bit Byte Count 244 | FillInFrame(RFFEAnalyzerResults::RffeCommandField, mRffeCmdType, 0, 4, 8, flags); 245 | FillInFrame(RFFEAnalyzerResults::RffeExByteCountField, (RffeCmd & 0x0F), 0, 8, 12, flags); 246 | break; 247 | case RFFEAnalyzerResults::RffeTypeExtLongWrite: 248 | case RFFEAnalyzerResults::RffeTypeExtLongRead: 249 | // 5 Bit Command w/ 3 bit Byte Count 250 | FillInFrame(RFFEAnalyzerResults::RffeCommandField, mRffeCmdType, 0, 4, 9, flags); 251 | FillInFrame(RFFEAnalyzerResults::RffeExLongByteCountField, (RffeCmd & 0x07), 0, 9, 12, flags); 252 | break; 253 | case RFFEAnalyzerResults::RffeTypeNormalWrite: 254 | case RFFEAnalyzerResults::RffeTypeNormalRead: 255 | // 3 Bit Command w/ 5 bit Addr 256 | FillInFrame(RFFEAnalyzerResults::RffeCommandField, mRffeCmdType, 0, 4, 7, flags); 257 | FillInFrame(RFFEAnalyzerResults::RffeAddressField, (RffeCmd & 0x1F), 0, 7, 12, flags); 258 | break; 259 | case RFFEAnalyzerResults::RffeTypeWrite0: 260 | // 1 Bit Command w/ 7 bit Write Data 261 | FillInFrame(RFFEAnalyzerResults::RffeCommandField, mRffeCmdType, 0, 4, 5, flags); 262 | FillInFrame(RFFEAnalyzerResults::RffeShortDataField, (RffeCmd & 0x7F), 0, 5, 12, flags); 263 | break; 264 | } 265 | 266 | // Check Parity - Parity bit covers the full SA/Command field (12 bits) 267 | FindParity(RFFEUtil::CalcParity(RffeCmd), 0); 268 | 269 | return byte_count; 270 | } 271 | 272 | // ------------------------------------------------------------------------------ 273 | U8 RFFEAnalyzer::FindISI() { 274 | U64 byte = GetBitStream(2); 275 | FillInFrame(RFFEAnalyzerResults::RffeISIField, byte, 0, 0, 2, 0); 276 | FindBusPark(); 277 | return (byte & 0x2); // Return the ISI bit 278 | } 279 | 280 | // ------------------------------------------------------------------------------ 281 | void RFFEAnalyzer::FindInterruptSlots() { 282 | for (S8 i = 15; i >= 0; i -= 1) { 283 | U64 byte = GetBitStream(1); 284 | FillInFrame(RFFEAnalyzerResults::RffeIntSlotField, byte, i, 0, 1, 0); // Send int number as a note 285 | FindBusPark(); 286 | } 287 | } 288 | 289 | // ------------------------------------------------------------------------------ 290 | void RFFEAnalyzer::FindByteFrame(RFFEAnalyzerResults::RffeFrameType type) { 291 | U64 byte = GetBitStream(8); 292 | FillInFrame(type, byte, 0, 0, 8, 0); 293 | FindParity(RFFEUtil::CalcParity(byte), 1); 294 | } 295 | 296 | // ------------------------------------------------------------------------------ 297 | void RFFEAnalyzer::FindParity(bool expParity, U64 extra_data) { 298 | BitState bitstate; 299 | bool data_parity; 300 | U64 parity_value; 301 | U8 flags = 0; 302 | 303 | // Get the Parity Bit on the next sample clock 304 | bitstate = GetNextBit(0); 305 | 306 | // Store away tailing sample position as the end of the Parity bit 307 | mSampleClkOffsets[1] = mSamplePosition; 308 | 309 | if (bitstate == BIT_HIGH) { 310 | parity_value = 1; 311 | data_parity = true; 312 | mSampleMarker[0] = AnalyzerResults::One; 313 | } else { 314 | parity_value = 0; 315 | data_parity = false; 316 | mSampleMarker[0] = AnalyzerResults::Zero; 317 | } 318 | 319 | if (data_parity != expParity) { 320 | flags |= (DISPLAY_AS_ERROR_FLAG | DISPLAY_AS_WARNING_FLAG | RFFE_PARITY_ERROR_FLAG); 321 | mSampleMarker[0] = AnalyzerResults::ErrorDot; 322 | } 323 | 324 | FillInFrame(RFFEAnalyzerResults::RffeParityField, parity_value, extra_data, 0, 1, flags); 325 | } 326 | 327 | // ------------------------------------------------------------------------------ 328 | void RFFEAnalyzer::FindBusPark() { 329 | U64 half_clk; 330 | 331 | // Mark this as a stop 332 | mSampleMarker[0] = AnalyzerResults::Stop; 333 | 334 | // Enter at the rising edge of SCLK 335 | mSampleClkOffsets[0] = mSamplePosition; 336 | 337 | // Goto Falling 338 | GotoSclkEdge(BIT_LOW); 339 | 340 | // Now at falling edge of clk 341 | mSampleDataOffsets[0] = mSamplePosition; 342 | 343 | // Now the bus park is offically complete, but for display 344 | // purposes it would look better if we had the Bus Park 345 | // 'Bubble' extend for what would be the full clock period. 346 | half_clk = mSampleDataOffsets[0] - mSampleClkOffsets[0]; 347 | 348 | // If there is another clock edge less thank a 1/2 clock period out 349 | // (plus a little) then extend the Bus Park to that edge. 350 | // Otherwise edge the Bus Park for the 1/2 clock period from the 351 | // previous SClk Rising -> Falling 352 | if (mSclk->WouldAdvancingCauseTransition((U32)(half_clk + 2))) { 353 | GotoSclkEdge(BIT_HIGH); 354 | mSampleClkOffsets[1] = mSclk->GetSampleNumber(); 355 | } else { 356 | mSampleClkOffsets[1] = mSampleDataOffsets[0] + half_clk; 357 | } 358 | 359 | FillInFrame(RFFEAnalyzerResults::RffeBusParkField, 0, 0, 0, 1, 0); 360 | } 361 | 362 | // ============================================================================== 363 | // Advance to the next transition on the bus (SCLK or SDATA transition) 364 | // ============================================================================== 365 | void RFFEAnalyzer::GotoNextTransition() { 366 | U64 SclkEdgeSample; 367 | U64 SdataEdgeSample; 368 | 369 | // Store the previous Transition bus state 370 | mSclkPrevious = mSclkCurrent; 371 | mSdataPrevious = mSdataCurrent; 372 | 373 | // Look for a transition on SDATA without a clock transition 374 | SclkEdgeSample = mSclk->GetSampleOfNextEdge(); 375 | SdataEdgeSample = mSdata->GetSampleOfNextEdge(); 376 | 377 | if (SclkEdgeSample > SdataEdgeSample) { 378 | // Sclk is further out the sData 379 | mSamplePosition = SdataEdgeSample; 380 | mSclk->AdvanceToAbsPosition(SdataEdgeSample); 381 | mSdata->AdvanceToAbsPosition(SdataEdgeSample); 382 | } else { 383 | // Sdata transition is further out than Sclk 384 | mSamplePosition = SclkEdgeSample; 385 | mSclk->AdvanceToAbsPosition(SclkEdgeSample); 386 | mSdata->AdvanceToAbsPosition(SclkEdgeSample); 387 | } 388 | 389 | // Update the current transition bus state 390 | mSclkCurrent = mSclk->GetBitState(); 391 | mSdataCurrent = mSdata->GetBitState(); 392 | } 393 | 394 | // ============================================================================== 395 | void RFFEAnalyzer::GotoSclkEdge(BitState edge_type) { 396 | bool ssc_possible = 0; 397 | 398 | // Scan for the next falling edge on SCLK while watching for SSCs 399 | while (1) { 400 | GotoNextTransition(); 401 | if (mSclkCurrent == edge_type && mSclkPrevious != edge_type) { 402 | break; 403 | } 404 | 405 | // Unexpected SSC monitoring 406 | if (mSclkCurrent == BIT_HIGH) { 407 | ssc_possible = 0; 408 | } else if (mSclkCurrent == BIT_LOW && mSclkPrevious == BIT_LOW && mSdataCurrent == BIT_HIGH && mSdataPrevious == BIT_LOW) { 409 | mUnexpectedSSCStart = mSamplePosition; 410 | ssc_possible = 1; 411 | } else if (ssc_possible && mSclkCurrent == BIT_LOW && mSdataCurrent == BIT_LOW) { 412 | mUnexpectedSSC = true; // !!! 413 | throw UNEXPECTED_SSC_EXCEPTION; 414 | } 415 | } 416 | } 417 | 418 | // ============================================================================== 419 | BitState RFFEAnalyzer::GetNextBit(U8 idx) { 420 | BitState data; 421 | 422 | // Previous FindSSC or GetNextBit left us at the rising edge of the SCLK 423 | // Grab this as the current sample point for delimiting the frame. 424 | mSampleClkOffsets[idx] = mSamplePosition; 425 | 426 | // Goto the next SCLK falling edge, sample SDATA and 427 | // put a marker to indicate that this is the sampled edge 428 | GotoSclkEdge(BIT_LOW); 429 | data = mSdataCurrent; 430 | 431 | mSampleDataOffsets[idx] = mSamplePosition; 432 | mResults->AddMarker(mSamplePosition, AnalyzerResults::DownArrow, mSettings->mSclkChannel); 433 | 434 | GotoSclkEdge(BIT_HIGH); 435 | 436 | // Return the sData Value sampled on the falling edge 437 | return data; 438 | } 439 | 440 | // -------------------------------------- 441 | U64 RFFEAnalyzer::GetBitStream(U8 len) { 442 | U64 data; 443 | U32 i; 444 | BitState state; 445 | DataBuilder data_builder; 446 | 447 | data_builder.Reset(&data, AnalyzerEnums::MsbFirst, len); 448 | 449 | // starting at rising edge of clk 450 | for (i = 0; i < len; i++) { 451 | state = GetNextBit(i); 452 | data_builder.AddBit(state); 453 | 454 | if (state == BIT_HIGH) { 455 | mSampleMarker[i] = AnalyzerResults::One; 456 | } else { 457 | mSampleMarker[i] = AnalyzerResults::Zero; 458 | } 459 | } 460 | mSampleClkOffsets[i] = mSamplePosition; 461 | 462 | return data; 463 | } 464 | 465 | // ============================================================================== 466 | // Physical Layer checks, if we so choose to implement them. 467 | // ============================================================================== 468 | bool RFFEAnalyzer::CheckClockRate() { 469 | // TODO: Compare the clock pulse width based on sample 470 | // rate against the spec. 471 | return true; 472 | } 473 | 474 | // ============================================================================== 475 | // Results and Screen Markers 476 | // ============================================================================== 477 | void RFFEAnalyzer::FillInFrame(RFFEAnalyzerResults::RffeFrameType type, U64 frame_data, U64 extra_data, U32 idx_start, U32 idx_end, U8 flags) { 478 | Frame frame; 479 | 480 | frame.mType = (U8)type; 481 | frame.mData1 = frame_data; 482 | frame.mData2 = extra_data; // Additional Data (could be used for AnalyzerResults if required) 483 | frame.mStartingSampleInclusive = mSampleClkOffsets[idx_start]; 484 | frame.mEndingSampleInclusive = mSampleClkOffsets[idx_end]; 485 | frame.mFlags = flags; 486 | 487 | // Add Markers to the SDATA stream while we are creating the Frame 488 | // That is if the Frame is non-zero length and also merits a marker. 489 | for (U32 i = idx_start; i < idx_end; i += 1) { 490 | mResults->AddMarker(mSampleDataOffsets[i], mSampleMarker[i], mSettings->mSdataChannel); 491 | } 492 | 493 | mResults->AddFrame(frame); 494 | 495 | // New FrameV2 code. 496 | FrameV2 frame_v2; 497 | // you can add any number of key value pairs. Each will get it's own column in the data table. 498 | frame_v2.AddString("type", RffeFrameString[type]); 499 | frame_v2.AddInteger("data", frame_data); 500 | frame_v2.AddInteger("extra_data", extra_data); 501 | frame_v2.AddInteger("flags", flags); 502 | mResults->AddFrameV2(frame_v2, "frame", frame.mStartingSampleInclusive, frame.mEndingSampleInclusive); 503 | 504 | mResults->CommitResults(); 505 | ReportProgress(frame.mEndingSampleInclusive); 506 | } 507 | 508 | // ============================================================================== 509 | // Boilerplate for the API 510 | // ============================================================================== 511 | bool RFFEAnalyzer::NeedsRerun() { 512 | return false; 513 | } 514 | 515 | // -------------------------------------- 516 | U32 RFFEAnalyzer::GenerateSimulationData(U64 minimum_sample_index, U32 device_sample_rate, SimulationChannelDescriptor **simulation_channels) { 517 | if (mSimulationInitilized == false) { 518 | mSimulationDataGenerator.Initialize(GetSimulationSampleRate(), mSettings.get()); 519 | mSimulationInitilized = true; 520 | } 521 | 522 | return mSimulationDataGenerator.GenerateSimulationData(minimum_sample_index, device_sample_rate, simulation_channels); 523 | } 524 | 525 | // -------------------------------------- 526 | U32 RFFEAnalyzer::GetMinimumSampleRateHz() { 527 | return 50000000; 528 | } 529 | 530 | // -------------------------------------- 531 | const char *RFFEAnalyzer::GetAnalyzerName() const { 532 | return "RFFEv2.0"; 533 | } 534 | 535 | // -------------------------------------- 536 | const char *GetAnalyzerName() { 537 | return "RFFEv2.0"; 538 | } 539 | 540 | // -------------------------------------- 541 | Analyzer *CreateAnalyzer() { 542 | return new RFFEAnalyzer(); 543 | } 544 | 545 | // -------------------------------------- 546 | void DestroyAnalyzer(Analyzer *analyzer) { 547 | delete analyzer; 548 | } 549 | --------------------------------------------------------------------------------