├── .clang-format ├── .github └── workflows │ └── build.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── ExternalAnalyzerSDK.cmake └── src ├── HdlcAnalyzer.cpp ├── HdlcAnalyzer.h ├── HdlcAnalyzerResults.cpp ├── HdlcAnalyzerResults.h ├── HdlcAnalyzerSettings.cpp ├── HdlcAnalyzerSettings.h ├── HdlcSimulationDataGenerator.cpp └── HdlcSimulationDataGenerator.h /.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 | -------------------------------------------------------------------------------- /.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@v3 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@v3 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@v3 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@v3 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@v3 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@v3 49 | - name: Build 50 | run: | 51 | cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release 52 | cmake --build ${{github.workspace}}/build 53 | env: 54 | CC: gcc-10 55 | CXX: g++-10 56 | - name: Upload Linux build 57 | uses: actions/upload-artifact@v3 58 | with: 59 | name: linux 60 | path: ${{github.workspace}}/build/Analyzers/*.so 61 | publish: 62 | needs: [windows, macos, linux] 63 | runs-on: ubuntu-latest 64 | steps: 65 | - name: download individual builds 66 | uses: actions/download-artifact@v3 67 | with: 68 | path: ${{github.workspace}}/artifacts 69 | - name: zip 70 | run: | 71 | cd ${{github.workspace}}/artifacts 72 | zip -r ${{github.workspace}}/analyzer.zip . 73 | - uses: actions/upload-artifact@v3 74 | with: 75 | name: all-platforms 76 | path: ${{github.workspace}}/artifacts/** 77 | - name: create release 78 | uses: softprops/action-gh-release@v1 79 | if: startsWith(github.ref, 'refs/tags/') 80 | with: 81 | files: ${{github.workspace}}/analyzer.zip -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.11) 2 | project(hdlc_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/HdlcAnalyzer.cpp 18 | src/HdlcAnalyzer.h 19 | src/HdlcAnalyzerResults.cpp 20 | src/HdlcAnalyzerResults.h 21 | src/HdlcAnalyzerSettings.cpp 22 | src/HdlcAnalyzerSettings.h 23 | src/HdlcSimulationDataGenerator.cpp 24 | src/HdlcSimulationDataGenerator.h 25 | ) 26 | 27 | add_analyzer_plugin(hdlc_analyzer SOURCES ${SOURCES}) 28 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Saleae High-Level Data Link Control (HDLC) Analyzer 2 | 3 | Saleae High-Level Data Link Control (HDLC) 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\hdlc_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 | -------------------------------------------------------------------------------- /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/HdlcAnalyzer.cpp: -------------------------------------------------------------------------------- 1 | #include "HdlcAnalyzer.h" 2 | #include "HdlcAnalyzerSettings.h" 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | HdlcAnalyzer::HdlcAnalyzer() 9 | : Analyzer2(), 10 | mSettings( new HdlcAnalyzerSettings() ), 11 | mSimulationInitilized( false ), 12 | mResults( 0 ), 13 | mHdlc( 0 ), 14 | mSampleRateHz( 0 ), 15 | mSamplesInHalfPeriod( 0 ), 16 | mSamplesInAFlag( 0 ), 17 | mSamplesIn8Bits( 0 ), 18 | mPreviousBitState( BIT_LOW ), 19 | mConsecutiveOnes( 0 ), 20 | mReadingFrame( false ), 21 | mAbortFrame( false ), 22 | mCurrentFrameIsSFrame( false ), 23 | mFoundEndFlag( false ), 24 | mEndFlagFrame(), 25 | mAbtFrame() 26 | { 27 | SetAnalyzerSettings( mSettings.get() ); 28 | } 29 | 30 | HdlcAnalyzer::~HdlcAnalyzer() 31 | { 32 | KillThread(); 33 | } 34 | 35 | void HdlcAnalyzer::SetupAnalyzer() 36 | { 37 | mHdlc = GetAnalyzerChannelData( mSettings->mInputChannel ); 38 | 39 | double halfPeriod = ( 1.0 / double( mSettings->mBitRate ) ) * 1000000.0; 40 | mSampleRateHz = GetSampleRate(); 41 | mSamplesInHalfPeriod = U64( ( mSampleRateHz * halfPeriod ) / 1000000.0 ); 42 | mSamplesInAFlag = mSamplesInHalfPeriod * 7; 43 | mSamplesIn8Bits = mSamplesInHalfPeriod * 8; 44 | 45 | mPreviousBitState = mHdlc->GetBitState(); 46 | mConsecutiveOnes = 0; 47 | mReadingFrame = false; 48 | mAbortFrame = false; 49 | mCurrentFrameIsSFrame = false; 50 | mFoundEndFlag = false; 51 | 52 | mResultFrames.clear(); 53 | mCurrentFrameBytes.clear(); 54 | } 55 | 56 | void HdlcAnalyzer::CommitFrames() 57 | { 58 | for( U32 i = 0; i < mResultFrames.size(); ++i ) 59 | { 60 | Frame frame = mResultFrames.at( i ); 61 | mResults->AddFrame( frame ); 62 | } 63 | } 64 | 65 | void HdlcAnalyzer::WorkerThread() 66 | { 67 | SetupAnalyzer(); 68 | 69 | if( mSettings->mTransmissionMode == HDLC_TRANSMISSION_BIT_SYNC ) 70 | { 71 | // Synchronize 72 | mHdlc->AdvanceToNextEdge(); 73 | } 74 | 75 | // Main loop 76 | for( ;; ) 77 | { 78 | ProcessHDLCFrame(); 79 | 80 | CommitFrames(); 81 | mResultFrames.clear(); 82 | 83 | mResults->CommitResults(); 84 | ReportProgress( mHdlc->GetSampleNumber() ); 85 | CheckIfThreadShouldExit(); 86 | } 87 | } 88 | 89 | // 90 | /////////////// SYNC BIT TRAMISSION /////////////////////////////////////////////// 91 | // 92 | 93 | void HdlcAnalyzer::ProcessHDLCFrame() 94 | { 95 | mCurrentFrameBytes.clear(); 96 | 97 | HdlcByte addressByte = ProcessFlags(); 98 | 99 | ProcessAddressField( addressByte ); 100 | ProcessControlField(); 101 | ProcessInfoAndFcsField(); 102 | 103 | if( mAbortFrame ) // The frame has been aborted at some point 104 | { 105 | AddFrameToResults( mAbtFrame ); 106 | if( mSettings->mTransmissionMode == HDLC_TRANSMISSION_BIT_SYNC ) 107 | { 108 | // After abortion, synchronize again 109 | mHdlc->AdvanceToNextEdge(); 110 | } 111 | } 112 | else 113 | { 114 | AddFrameToResults( mEndFlagFrame ); 115 | } 116 | 117 | // Reset state bool variables 118 | mReadingFrame = false; 119 | mAbortFrame = false; 120 | mCurrentFrameIsSFrame = false; 121 | } 122 | 123 | HdlcByte HdlcAnalyzer::ProcessFlags() 124 | { 125 | HdlcByte addressByte; 126 | if( mSettings->mTransmissionMode == HDLC_TRANSMISSION_BIT_SYNC ) 127 | { 128 | BitSyncProcessFlags(); 129 | mReadingFrame = true; 130 | addressByte = ReadByte(); 131 | } 132 | else 133 | { 134 | mReadingFrame = true; 135 | addressByte = ByteAsyncProcessFlags(); 136 | } 137 | 138 | return addressByte; 139 | } 140 | 141 | // Interframe time fill: ISO/IEC 13239:2002(E) pag. 21 142 | void HdlcAnalyzer::BitSyncProcessFlags() 143 | { 144 | bool flagEncountered = false; 145 | vector flags; 146 | for( ;; ) 147 | { 148 | if( AbortComing() ) 149 | { 150 | // Show fill flags 151 | for( U32 i = 0; i < flags.size(); ++i ) 152 | { 153 | Frame frame = CreateFrame( HDLC_FIELD_FLAG, flags.at( i ).startSample, flags.at( i ).endSample, HDLC_FLAG_FILL ); 154 | AddFrameToResults( frame ); 155 | } 156 | flags.clear(); 157 | 158 | mAbtFrame = CreateFrame( HDLC_ABORT_SEQ, mHdlc->GetSampleNumber(), mHdlc->GetSampleNumber() + mSamplesIn8Bits ); 159 | 160 | mHdlc->AdvanceToNextEdge(); 161 | flagEncountered = false; 162 | mAbortFrame = true; 163 | 164 | break; 165 | } 166 | 167 | if( FlagComing() ) 168 | { 169 | HdlcByte bs; 170 | bs.value = 0; 171 | 172 | bs.startSample = mHdlc->GetSampleNumber(); 173 | mHdlc->AdvanceToNextEdge(); 174 | bs.endSample = mHdlc->GetSampleNumber(); 175 | 176 | flags.push_back( bs ); 177 | 178 | if( mHdlc->WouldAdvancingCauseTransition( mSamplesInHalfPeriod * 1.5 ) ) 179 | { 180 | mHdlc->Advance( mSamplesInHalfPeriod * 0.5 ); 181 | mPreviousBitState = mHdlc->GetBitState(); 182 | mHdlc->AdvanceToNextEdge(); 183 | } 184 | else 185 | { 186 | mHdlc->Advance( mSamplesInHalfPeriod * 0.5 ); 187 | mPreviousBitState = mHdlc->GetBitState(); 188 | mHdlc->Advance( mSamplesInHalfPeriod * 0.5 ); 189 | } 190 | 191 | flagEncountered = true; 192 | } 193 | else // non-flag 194 | { 195 | if( flagEncountered ) 196 | { 197 | break; 198 | } 199 | else // non-flag byte before a byte-flag is ignored 200 | { 201 | mHdlc->AdvanceToNextEdge(); 202 | } 203 | } 204 | } 205 | 206 | if( !mAbortFrame ) 207 | { 208 | for( U32 i = 0; i < flags.size(); ++i ) 209 | { 210 | Frame frame = CreateFrame( HDLC_FIELD_FLAG, flags.at( i ).startSample, flags.at( i ).endSample, HDLC_FLAG_FILL ); 211 | if( i == flags.size() - 1 ) 212 | { 213 | frame.mData1 = HDLC_FLAG_START; 214 | } 215 | AddFrameToResults( frame ); 216 | } 217 | } 218 | } 219 | 220 | // Read bit with bit-stuffing 221 | BitState HdlcAnalyzer::BitSyncReadBit() 222 | { 223 | // Re-sync 224 | if( mHdlc->GetSampleOfNextEdge() < mHdlc->GetSampleNumber() + mSamplesInHalfPeriod * 0.20 ) 225 | { 226 | mHdlc->AdvanceToNextEdge(); 227 | } 228 | 229 | BitState ret; 230 | 231 | mHdlc->Advance( mSamplesInHalfPeriod * 0.5 ); 232 | BitState bit = mHdlc->GetBitState(); // sample the bit 233 | 234 | if( bit == mPreviousBitState ) 235 | { 236 | mConsecutiveOnes++; 237 | if( mReadingFrame && mConsecutiveOnes == 5 ) 238 | { 239 | U64 currentPos = mHdlc->GetSampleNumber(); 240 | 241 | // Check for 0-bit insertion (i.e. line toggle) 242 | if( mHdlc->GetSampleOfNextEdge() < currentPos + mSamplesInHalfPeriod ) 243 | { 244 | // Advance to the next edge to re-synchronize the analyzer 245 | mHdlc->AdvanceToNextEdge(); 246 | // Mark the bit-stuffing 247 | mResults->AddMarker( mHdlc->GetSampleNumber(), AnalyzerResults::Dot, mSettings->mInputChannel ); 248 | mHdlc->Advance( mSamplesInHalfPeriod * 0.5 ); 249 | 250 | mPreviousBitState = mHdlc->GetBitState(); 251 | mConsecutiveOnes = 0; 252 | } 253 | else // Abort! 254 | { 255 | mConsecutiveOnes = 0; 256 | mAbtFrame = CreateFrame( HDLC_ABORT_SEQ, mHdlc->GetSampleNumber(), mHdlc->GetSampleNumber() + mSamplesIn8Bits ); 257 | mAbortFrame = true; 258 | } 259 | } 260 | else 261 | { 262 | mPreviousBitState = bit; 263 | } 264 | 265 | ret = BIT_HIGH; 266 | } 267 | else // bit changed so it's a 0 268 | { 269 | mConsecutiveOnes = 0; 270 | mPreviousBitState = bit; 271 | ret = BIT_LOW; 272 | } 273 | 274 | mHdlc->Advance( mSamplesInHalfPeriod * 0.5 ); 275 | 276 | // Re-sync 277 | if( mHdlc->GetSampleOfNextEdge() < mHdlc->GetSampleNumber() + mSamplesInHalfPeriod * 0.20 ) 278 | { 279 | mHdlc->AdvanceToNextEdge(); 280 | } 281 | 282 | return ret; 283 | } 284 | 285 | bool HdlcAnalyzer::FlagComing() 286 | { 287 | return !mHdlc->WouldAdvancingCauseTransition( mSamplesInAFlag - mSamplesInHalfPeriod * 0.5 ) && 288 | mHdlc->WouldAdvancingCauseTransition( mSamplesInAFlag + mSamplesInHalfPeriod * 0.5 ); 289 | } 290 | 291 | bool HdlcAnalyzer::AbortComing() 292 | { 293 | return !mHdlc->WouldAdvancingCauseTransition( mSamplesInAFlag + mSamplesInHalfPeriod * 0.5 ); 294 | } 295 | 296 | HdlcByte HdlcAnalyzer::BitSyncReadByte() 297 | { 298 | if( mReadingFrame && AbortComing() ) 299 | { 300 | // Create "Abort Frame" frame 301 | U64 startSample = mHdlc->GetSampleNumber(); 302 | mHdlc->Advance( mSamplesIn8Bits ); 303 | U64 endSample = mHdlc->GetSampleNumber(); 304 | 305 | mAbtFrame = CreateFrame( HDLC_ABORT_SEQ, startSample + mSamplesInHalfPeriod, endSample ); 306 | 307 | mAbortFrame = true; 308 | HdlcByte b; 309 | b.startSample = 0; 310 | b.endSample = 0; 311 | b.value = 0; 312 | return b; 313 | } 314 | 315 | if( mReadingFrame && FlagComing() ) 316 | { 317 | U64 startSample = mHdlc->GetSampleNumber(); 318 | mHdlc->AdvanceToNextEdge(); 319 | U64 endSample = mHdlc->GetSampleNumber(); 320 | mFoundEndFlag = true; 321 | HdlcByte bs = { startSample, endSample, HDLC_FLAG_VALUE }; 322 | return bs; 323 | } 324 | 325 | U64 byteValue = 0; 326 | DataBuilder dbyte; 327 | dbyte.Reset( &byteValue, AnalyzerEnums::LsbFirst, 8 ); 328 | U64 startSample = mHdlc->GetSampleNumber(); 329 | for( U32 i = 0; i < 8; ++i ) 330 | { 331 | BitState bit = BitSyncReadBit(); 332 | if( mAbortFrame ) 333 | { 334 | HdlcByte b; 335 | b.startSample = 0; 336 | b.endSample = 0; 337 | b.value = 0; 338 | return b; 339 | } 340 | dbyte.AddBit( bit ); 341 | } 342 | U64 endSample = mHdlc->GetSampleNumber() - mSamplesInHalfPeriod; 343 | HdlcByte bs = { startSample, endSample, U8( byteValue ), false }; 344 | mCurrentFrameBytes.push_back( bs.value ); 345 | return bs; 346 | } 347 | 348 | // 349 | /////////////// ASYNC BYTE TRAMISSION /////////////////////////////////////////////// 350 | // 351 | 352 | // Interframe time fill: ISO/IEC 13239:2002(E) pag. 21 353 | HdlcByte HdlcAnalyzer::ByteAsyncProcessFlags() 354 | { 355 | bool flagEncountered = false; 356 | // Read bytes until non-flag byte 357 | vector readBytes; 358 | 359 | for( ;; ) 360 | { 361 | HdlcByte asyncByte = ReadByte(); 362 | if( ( asyncByte.value != HDLC_FLAG_VALUE ) && flagEncountered ) 363 | { 364 | readBytes.push_back( asyncByte ); 365 | break; 366 | } 367 | else if( asyncByte.value == HDLC_FLAG_VALUE ) 368 | { 369 | readBytes.push_back( asyncByte ); 370 | flagEncountered = true; 371 | } 372 | if( mAbortFrame ) 373 | { 374 | GenerateFlagsFrames( readBytes ); 375 | HdlcByte b; 376 | b.startSample = 0; 377 | b.endSample = 0; 378 | b.value = 0; 379 | return b; 380 | } 381 | } 382 | 383 | GenerateFlagsFrames( readBytes ); 384 | 385 | HdlcByte nonFlagByte = readBytes.back(); 386 | return nonFlagByte; 387 | } 388 | 389 | void HdlcAnalyzer::GenerateFlagsFrames( vector readBytes ) 390 | { 391 | // 2) Generate the flag frames and return non-flag byte after the flags 392 | for( U32 i = 0; i < readBytes.size() - 1; ++i ) 393 | { 394 | HdlcByte asyncByte = readBytes[ i ]; 395 | 396 | Frame frame = CreateFrame( HDLC_FIELD_FLAG, asyncByte.startSample, asyncByte.endSample ); 397 | 398 | if( i == readBytes.size() - 2 ) // start flag 399 | { 400 | frame.mData1 = HDLC_FLAG_START; 401 | } 402 | else // fill flag 403 | { 404 | frame.mData1 = HDLC_FLAG_FILL; 405 | } 406 | 407 | AddFrameToResults( frame ); 408 | } 409 | } 410 | 411 | void HdlcAnalyzer::ProcessAddressField( HdlcByte byteAfterFlag ) 412 | { 413 | if( mAbortFrame ) 414 | { 415 | return; 416 | } 417 | 418 | if( mSettings->mHdlcAddr == HDLC_BASIC_ADDRESS_FIELD ) 419 | { 420 | U8 flag = ( byteAfterFlag.escaped ) ? HDLC_ESCAPED_BYTE : 0; 421 | Frame frame = 422 | CreateFrame( HDLC_FIELD_BASIC_ADDRESS, byteAfterFlag.startSample, byteAfterFlag.endSample, byteAfterFlag.value, 0, flag ); 423 | AddFrameToResults( frame ); 424 | 425 | // Put a marker in the beggining of the HDLC frame 426 | mResults->AddMarker( frame.mStartingSampleInclusive, AnalyzerResults::Start, mSettings->mInputChannel ); 427 | } 428 | else // HDLC_EXTENDED_ADDRESS_FIELD 429 | { 430 | int i = 0; 431 | HdlcByte addressByte = byteAfterFlag; 432 | // Put a marker in the beggining of the HDLC frame 433 | mResults->AddMarker( addressByte.startSample, AnalyzerResults::Start, mSettings->mInputChannel ); 434 | for( ;; ) 435 | { 436 | U8 flag = ( addressByte.escaped ) ? HDLC_ESCAPED_BYTE : 0; 437 | Frame frame = 438 | CreateFrame( HDLC_FIELD_EXTENDED_ADDRESS, addressByte.startSample, addressByte.endSample, addressByte.value, i++, flag ); 439 | AddFrameToResults( frame ); 440 | 441 | U8 lsbBit = addressByte.value & 0x01; 442 | if( !lsbBit ) // End of Extended Address Field? 443 | { 444 | return; 445 | } 446 | 447 | // Next address byte 448 | addressByte = ReadByte(); 449 | if( mAbortFrame ) 450 | { 451 | return; 452 | } 453 | } 454 | } 455 | } 456 | 457 | void HdlcAnalyzer::ProcessControlField() 458 | { 459 | if( mAbortFrame ) 460 | { 461 | return; 462 | } 463 | 464 | if( mSettings->mHdlcControl == HDLC_BASIC_CONTROL_FIELD ) // Basic Control Field of 1 byte 465 | { 466 | HdlcByte controlByte = ReadByte(); 467 | if( mAbortFrame ) 468 | { 469 | return; 470 | } 471 | 472 | U8 flag = ( controlByte.escaped ) ? HDLC_ESCAPED_BYTE : 0; 473 | Frame frame = CreateFrame( HDLC_FIELD_BASIC_CONTROL, controlByte.startSample, controlByte.endSample, controlByte.value, 0, flag ); 474 | AddFrameToResults( frame ); 475 | 476 | HdlcFrameType frameType = GetFrameType( controlByte.value ); 477 | mCurrentFrameIsSFrame = ( frameType == HDLC_S_FRAME ); 478 | } 479 | else // Extended Control Field 480 | { 481 | // Read first byte and check type of frame 482 | HdlcByte byte0 = ReadByte(); 483 | if( mAbortFrame ) 484 | { 485 | return; 486 | } 487 | HdlcFrameType frameType = GetFrameType( byte0.value ); 488 | U8 flag = ( byte0.escaped ) ? HDLC_ESCAPED_BYTE : 0; 489 | 490 | Frame frame0 = CreateFrame( HDLC_FIELD_EXTENDED_CONTROL, byte0.startSample, byte0.endSample, byte0.value, 0, flag ); 491 | AddFrameToResults( frame0 ); 492 | 493 | mCurrentFrameIsSFrame = ( frameType == HDLC_S_FRAME ); 494 | 495 | if( frameType != HDLC_U_FRAME ) 496 | { 497 | U32 ctlBytes = 0; 498 | switch( mSettings->mHdlcControl ) 499 | { 500 | case HDLC_EXTENDED_CONTROL_FIELD_MOD_128: 501 | ctlBytes = 2; 502 | break; 503 | case HDLC_EXTENDED_CONTROL_FIELD_MOD_32768: 504 | ctlBytes = 4; 505 | break; 506 | case HDLC_EXTENDED_CONTROL_FIELD_MOD_2147483648: 507 | ctlBytes = 8; 508 | break; 509 | } 510 | for( U32 i = 1; i < ctlBytes; ++i ) 511 | { 512 | HdlcByte byte = ReadByte(); 513 | if( mAbortFrame ) 514 | { 515 | return; 516 | } 517 | U8 flag = ( byte.escaped ) ? HDLC_ESCAPED_BYTE : 0; 518 | Frame frame = CreateFrame( HDLC_FIELD_EXTENDED_CONTROL, byte.startSample, byte.endSample, byte.value, i, flag ); 519 | AddFrameToResults( frame ); 520 | } 521 | } 522 | } 523 | } 524 | 525 | vector HdlcAnalyzer::ReadProcessAndFcsField() 526 | { 527 | vector infoAndFcs; 528 | for( ;; ) 529 | { 530 | HdlcByte asyncByte = ReadByte(); 531 | if( mAbortFrame ) 532 | { 533 | return infoAndFcs; 534 | } 535 | if( ( asyncByte.value == HDLC_FLAG_VALUE ) && mFoundEndFlag ) // End of frame found 536 | { 537 | mEndFlagFrame = CreateFrame( HDLC_FIELD_FLAG, asyncByte.startSample, asyncByte.endSample, HDLC_FLAG_END ); 538 | mFoundEndFlag = false; 539 | break; 540 | } 541 | else // information or fcs byte 542 | { 543 | infoAndFcs.push_back( asyncByte ); 544 | } 545 | } 546 | 547 | return infoAndFcs; 548 | } 549 | 550 | void HdlcAnalyzer::ProcessInfoAndFcsField() 551 | { 552 | if( mAbortFrame ) 553 | { 554 | return; 555 | } 556 | 557 | vector informationAndFcs = ReadProcessAndFcsField(); 558 | 559 | InfoAndFcsField( informationAndFcs ); 560 | } 561 | 562 | void HdlcAnalyzer::InfoAndFcsField( const vector& informationAndFcs ) 563 | { 564 | vector information = informationAndFcs; 565 | vector fcs; 566 | 567 | if( !mAbortFrame ) 568 | { 569 | // split information and fcs vector 570 | switch( mSettings->mHdlcFcs ) 571 | { 572 | case HDLC_CRC8: 573 | { 574 | if( !information.empty() ) 575 | { 576 | fcs.push_back( information.back() ); 577 | information.pop_back(); 578 | } 579 | break; 580 | } 581 | case HDLC_CRC16: 582 | { 583 | if( information.size() >= 2 ) 584 | { 585 | fcs.insert( fcs.end(), information.end() - 2, information.end() ); 586 | information.erase( information.end() - 2, information.end() ); 587 | } 588 | break; 589 | } 590 | case HDLC_CRC32: 591 | { 592 | if( information.size() >= 4 ) 593 | { 594 | fcs.insert( fcs.end(), information.end() - 4, information.end() ); 595 | information.erase( information.end() - 4, information.end() ); 596 | } 597 | break; 598 | } 599 | } 600 | } 601 | 602 | ProcessInformationField( information ); 603 | 604 | if( !mAbortFrame ) 605 | { 606 | if( !fcs.empty() ) 607 | { 608 | ProcessFcsField( fcs ); 609 | } 610 | } 611 | } 612 | 613 | void HdlcAnalyzer::ProcessInformationField( const vector& information ) 614 | { 615 | for( U32 i = 0; i < information.size(); ++i ) 616 | { 617 | HdlcByte byte = information.at( i ); 618 | U8 flag = ( byte.escaped ) ? HDLC_ESCAPED_BYTE : 0; 619 | Frame frame = CreateFrame( HDLC_FIELD_INFORMATION, byte.startSample, byte.endSample, byte.value, i, flag ); 620 | AddFrameToResults( frame ); 621 | } 622 | } 623 | 624 | void HdlcAnalyzer::AddFrameToResults( const Frame& frame ) 625 | { 626 | mResultFrames.push_back( frame ); 627 | } 628 | 629 | void HdlcAnalyzer::ProcessFcsField( const vector& fcs ) 630 | { 631 | vector calculatedFcs; 632 | vector readFcs = HdlcBytesToVectorBytes( fcs ); 633 | 634 | switch( mSettings->mHdlcFcs ) 635 | { 636 | case HDLC_CRC8: 637 | { 638 | if( !mCurrentFrameBytes.empty() ) 639 | { 640 | mCurrentFrameBytes.pop_back(); 641 | } 642 | calculatedFcs = HdlcSimulationDataGenerator::Crc8( mCurrentFrameBytes ); 643 | break; 644 | } 645 | case HDLC_CRC16: 646 | { 647 | if( mCurrentFrameBytes.size() >= 2 ) 648 | { 649 | mCurrentFrameBytes.erase( mCurrentFrameBytes.end() - 2, mCurrentFrameBytes.end() ); 650 | } 651 | calculatedFcs = HdlcSimulationDataGenerator::Crc16( mCurrentFrameBytes ); 652 | break; 653 | } 654 | case HDLC_CRC32: 655 | { 656 | if( mCurrentFrameBytes.size() >= 4 ) 657 | { 658 | mCurrentFrameBytes.erase( mCurrentFrameBytes.end() - 4, mCurrentFrameBytes.end() ); 659 | } 660 | calculatedFcs = HdlcSimulationDataGenerator::Crc32( mCurrentFrameBytes ); 661 | break; 662 | } 663 | } 664 | 665 | Frame frame = CreateFrame( HDLC_FIELD_FCS, fcs.front().startSample, fcs.back().endSample, VectorToValue( readFcs ), 666 | VectorToValue( calculatedFcs ) ); 667 | 668 | if( calculatedFcs != readFcs ) 669 | { 670 | frame.mFlags = DISPLAY_AS_ERROR_FLAG; 671 | } 672 | 673 | AddFrameToResults( frame ); 674 | 675 | // Put a marker in the end of the HDLC frame 676 | mResults->AddMarker( frame.mEndingSampleInclusive, AnalyzerResults::Stop, mSettings->mInputChannel ); 677 | } 678 | 679 | HdlcByte HdlcAnalyzer::ReadByte() 680 | { 681 | return ( mSettings->mTransmissionMode == HDLC_TRANSMISSION_BYTE_ASYNC ) ? ByteAsyncReadByte() : BitSyncReadByte(); 682 | } 683 | 684 | HdlcByte HdlcAnalyzer::ByteAsyncReadByte() 685 | { 686 | HdlcByte ret = ByteAsyncReadByte_(); 687 | 688 | if( mReadingFrame && ( ret.value == HDLC_FLAG_VALUE ) ) 689 | { 690 | mFoundEndFlag = true; 691 | } 692 | 693 | // Check for escape character 694 | if( mReadingFrame && ( ret.value == HDLC_ESCAPE_SEQ_VALUE ) ) // escape byte read 695 | { 696 | U64 startSampleEsc = ret.startSample; 697 | ret = ByteAsyncReadByte_(); 698 | 699 | if( ret.value == HDLC_FLAG_VALUE ) // abort sequence = ESCAPE_BYTE + FLAG_BYTE (0x7D-0x7E) 700 | { 701 | // Create "Abort Frame" frame 702 | mAbtFrame = CreateFrame( HDLC_ABORT_SEQ, startSampleEsc, ret.endSample ); 703 | mAbortFrame = true; 704 | return ret; 705 | } 706 | else 707 | { 708 | // Real data: with the bit-5 inverted (that's what we use for the crc) 709 | U8 complimented = HdlcAnalyzerSettings::Bit5Inv( ret.value ); 710 | mCurrentFrameBytes.push_back( complimented ); 711 | // ret.value = complimented; 712 | ret.startSample = startSampleEsc; 713 | ret.escaped = true; 714 | return ret; 715 | } 716 | } 717 | 718 | if( mReadingFrame && ( ret.value != HDLC_FLAG_VALUE ) ) 719 | { 720 | mCurrentFrameBytes.push_back( ret.value ); 721 | } 722 | 723 | return ret; 724 | } 725 | 726 | HdlcByte HdlcAnalyzer::ByteAsyncReadByte_() 727 | { 728 | // Line must be HIGH here 729 | if( mHdlc->GetBitState() == BIT_LOW ) 730 | { 731 | mHdlc->AdvanceToNextEdge(); 732 | } 733 | 734 | mHdlc->AdvanceToNextEdge(); // high->low transition (start bit) 735 | 736 | mHdlc->Advance( mSamplesInHalfPeriod * 0.5 ); 737 | 738 | U64 byteStartSample = mHdlc->GetSampleNumber() + mSamplesInHalfPeriod * 0.5; 739 | 740 | U64 byteValue2 = 0; 741 | DataBuilder dbyte; 742 | dbyte.Reset( &byteValue2, AnalyzerEnums::LsbFirst, 8 ); 743 | 744 | for( U32 i = 0; i < 8; ++i ) 745 | { 746 | mHdlc->Advance( mSamplesInHalfPeriod ); 747 | dbyte.AddBit( mHdlc->GetBitState() ); 748 | } 749 | 750 | U8 byteValue = U8( byteValue2 ); 751 | 752 | U64 byteEndSample = mHdlc->GetSampleNumber() + mSamplesInHalfPeriod * 0.5; 753 | 754 | mHdlc->Advance( mSamplesInHalfPeriod ); 755 | 756 | HdlcByte asyncByte = { byteStartSample, byteEndSample, byteValue, false }; 757 | 758 | return asyncByte; 759 | } 760 | 761 | 762 | // 763 | ///////////////////////////// Helper functions /////////////////////////////////////////// 764 | // 765 | 766 | // "Ctor" for the Frame class 767 | Frame HdlcAnalyzer::CreateFrame( U8 mType, U64 mStartingSampleInclusive, U64 mEndingSampleInclusive, U64 mData1, U64 mData2, 768 | U8 mFlags ) const 769 | { 770 | Frame frame; 771 | frame.mStartingSampleInclusive = mStartingSampleInclusive; 772 | frame.mEndingSampleInclusive = mEndingSampleInclusive; 773 | frame.mType = mType; 774 | frame.mData1 = mData1; 775 | frame.mData2 = mData2; 776 | frame.mFlags = mFlags; 777 | return frame; 778 | } 779 | 780 | vector HdlcAnalyzer::HdlcBytesToVectorBytes( const vector& asyncBytes ) const 781 | { 782 | vector ret; 783 | for( U32 i = 0; i < asyncBytes.size(); ++i ) 784 | { 785 | if( asyncBytes[ i ].escaped ) 786 | ret.push_back( HdlcAnalyzerSettings::Bit5Inv( asyncBytes[ i ].value ) ); 787 | else 788 | ret.push_back( asyncBytes[ i ].value ); 789 | } 790 | return ret; 791 | } 792 | 793 | U64 HdlcAnalyzer::VectorToValue( const vector& v ) const 794 | { 795 | U64 value = 0; 796 | U32 j = 8 * ( v.size() - 1 ); 797 | for( U32 i = 0; i < v.size(); ++i ) 798 | { 799 | value |= ( v.at( i ) << j ); 800 | j -= 8; 801 | } 802 | return value; 803 | } 804 | 805 | HdlcFrameType HdlcAnalyzer::GetFrameType( U8 value ) 806 | { 807 | if( value & 0x01 ) 808 | { 809 | if( value & 0x02 ) 810 | { 811 | return HDLC_U_FRAME; 812 | } 813 | else 814 | { 815 | return HDLC_S_FRAME; 816 | } 817 | } 818 | else // bit-0 = 0 819 | { 820 | return HDLC_I_FRAME; 821 | } 822 | } 823 | 824 | bool HdlcAnalyzer::NeedsRerun() 825 | { 826 | return false; 827 | } 828 | 829 | void HdlcAnalyzer::SetupResults() 830 | { 831 | mResults.reset( new HdlcAnalyzerResults( this, mSettings.get() ) ); 832 | SetAnalyzerResults( mResults.get() ); 833 | mResults->AddChannelBubblesWillAppearOn( mSettings->mInputChannel ); 834 | } 835 | 836 | U32 HdlcAnalyzer::GenerateSimulationData( U64 minimum_sample_index, U32 device_sample_rate, 837 | SimulationChannelDescriptor** simulation_channels ) 838 | { 839 | if( mSimulationInitilized == false ) 840 | { 841 | mSimulationDataGenerator.Initialize( GetSimulationSampleRate(), mSettings.get() ); 842 | mSimulationInitilized = true; 843 | } 844 | 845 | return mSimulationDataGenerator.GenerateSimulationData( minimum_sample_index, device_sample_rate, simulation_channels ); 846 | } 847 | 848 | U32 HdlcAnalyzer::GetMinimumSampleRateHz() 849 | { 850 | return mSettings->mBitRate * 4; 851 | } 852 | 853 | const char* HdlcAnalyzer::GetAnalyzerName() const 854 | { 855 | return "HDLC"; 856 | } 857 | 858 | const char* GetAnalyzerName() 859 | { 860 | return "HDLC"; 861 | } 862 | 863 | Analyzer* CreateAnalyzer() 864 | { 865 | return new HdlcAnalyzer(); 866 | } 867 | 868 | void DestroyAnalyzer( Analyzer* analyzer ) 869 | { 870 | delete analyzer; 871 | } 872 | -------------------------------------------------------------------------------- /src/HdlcAnalyzer.h: -------------------------------------------------------------------------------- 1 | #ifndef HDLC_ANALYZER_H 2 | #define HDLC_ANALYZER_H 3 | 4 | #include 5 | #include "HdlcAnalyzerResults.h" 6 | #include "HdlcSimulationDataGenerator.h" 7 | 8 | struct HdlcByte 9 | { 10 | U64 startSample; 11 | U64 endSample; 12 | U8 value; 13 | bool escaped; 14 | }; 15 | 16 | class HdlcAnalyzerSettings; 17 | class HdlcAnalyzer : public Analyzer2 18 | { 19 | public: 20 | HdlcAnalyzer(); 21 | virtual ~HdlcAnalyzer(); 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 | virtual void SetupResults(); 31 | 32 | static HdlcFrameType GetFrameType( U8 value ); 33 | 34 | protected: 35 | void SetupAnalyzer(); 36 | 37 | // Functions to read and process a HDLC frame 38 | void ProcessHDLCFrame(); 39 | HdlcByte ProcessFlags(); 40 | void ProcessAddressField( HdlcByte byteAfterFlag ); 41 | void ProcessControlField(); 42 | void ProcessInfoAndFcsField(); 43 | vector ReadProcessAndFcsField(); 44 | void InfoAndFcsField( const vector& informationAndFcs ); 45 | void ProcessInformationField( const vector& information ); 46 | void ProcessFcsField( const vector& fcs ); 47 | HdlcByte ReadByte(); 48 | 49 | // Bit Sync Transmission functions 50 | void BitSyncProcessFlags(); 51 | BitState BitSyncReadBit(); 52 | HdlcByte BitSyncReadByte(); 53 | HdlcByte BitSyncProcessFirstByteAfterFlag( HdlcByte firstAddressByte ); 54 | bool FlagComing(); 55 | bool AbortComing(); 56 | 57 | // Byte Async Transmission functions 58 | HdlcByte ByteAsyncProcessFlags(); 59 | void GenerateFlagsFrames( vector readBytes ); 60 | HdlcByte ByteAsyncReadByte(); 61 | HdlcByte ByteAsyncReadByte_(); 62 | 63 | // Helper functions 64 | Frame CreateFrame( U8 mType, U64 mStartingSampleInclusive, U64 mEndingSampleInclusive, U64 mData1 = 0, U64 mData2 = 0, 65 | U8 mFlags = 0 ) const; 66 | vector HdlcBytesToVectorBytes( const vector& asyncBytes ) const; 67 | U64 VectorToValue( const vector& v ) const; 68 | 69 | void AddFrameToResults( const Frame& frame ); 70 | void CommitFrames(); 71 | 72 | protected: 73 | std::auto_ptr mSettings; 74 | std::auto_ptr mResults; 75 | AnalyzerChannelData* mHdlc; 76 | 77 | U32 mSampleRateHz; 78 | U64 mSamplesInHalfPeriod; 79 | U64 mSamplesInAFlag; 80 | U32 mSamplesIn8Bits; 81 | 82 | vector mCurrentFrameBytes; 83 | 84 | BitState mPreviousBitState; 85 | U32 mConsecutiveOnes; 86 | bool mReadingFrame; 87 | bool mAbortFrame; 88 | bool mCurrentFrameIsSFrame; 89 | bool mFoundEndFlag; 90 | 91 | Frame mEndFlagFrame; 92 | Frame mAbtFrame; 93 | 94 | vector mResultFrames; 95 | 96 | HdlcSimulationDataGenerator mSimulationDataGenerator; 97 | bool mSimulationInitilized; 98 | }; 99 | 100 | extern "C" ANALYZER_EXPORT const char* __cdecl GetAnalyzerName(); 101 | extern "C" ANALYZER_EXPORT Analyzer* __cdecl CreateAnalyzer(); 102 | extern "C" ANALYZER_EXPORT void __cdecl DestroyAnalyzer( Analyzer* analyzer ); 103 | 104 | #endif // HDLC_ANALYZER_H 105 | -------------------------------------------------------------------------------- /src/HdlcAnalyzerResults.cpp: -------------------------------------------------------------------------------- 1 | #include "HdlcAnalyzerResults.h" 2 | #include 3 | #include "HdlcAnalyzer.h" 4 | #include "HdlcAnalyzerSettings.h" 5 | #include 6 | #include 7 | 8 | HdlcAnalyzerResults::HdlcAnalyzerResults( HdlcAnalyzer* analyzer, HdlcAnalyzerSettings* settings ) 9 | : AnalyzerResults(), mSettings( settings ), mAnalyzer( analyzer ) 10 | { 11 | } 12 | 13 | HdlcAnalyzerResults::~HdlcAnalyzerResults() 14 | { 15 | } 16 | 17 | void HdlcAnalyzerResults::GenerateBubbleText( U64 frame_index, Channel& /*channel*/, DisplayBase display_base ) 18 | { 19 | GenBubbleText( frame_index, display_base, false ); 20 | } 21 | 22 | void HdlcAnalyzerResults::GenBubbleText( U64 frame_index, DisplayBase display_base, bool tabular ) 23 | { 24 | if( !tabular ) 25 | ClearResultStrings(); 26 | 27 | Frame frame = GetFrame( frame_index ); 28 | 29 | switch( frame.mType ) 30 | { 31 | case HDLC_FIELD_FLAG: 32 | GenFlagFieldString( frame, tabular ); 33 | break; 34 | case HDLC_FIELD_BASIC_ADDRESS: 35 | case HDLC_FIELD_EXTENDED_ADDRESS: 36 | GenAddressFieldString( frame, display_base, tabular ); 37 | break; 38 | case HDLC_FIELD_BASIC_CONTROL: 39 | case HDLC_FIELD_EXTENDED_CONTROL: 40 | GenControlFieldString( frame, display_base, tabular ); 41 | break; 42 | case HDLC_FIELD_INFORMATION: 43 | GenInformationFieldString( frame, display_base, tabular ); 44 | break; 45 | case HDLC_FIELD_FCS: 46 | GenFcsFieldString( frame, display_base, tabular ); 47 | break; 48 | case HDLC_ABORT_SEQ: 49 | GenAbortFieldString( tabular ); 50 | break; 51 | } 52 | } 53 | 54 | void HdlcAnalyzerResults::GenFlagFieldString( const Frame& frame, bool tabular ) 55 | { 56 | char* flagTypeStr = 0; 57 | switch( frame.mData1 ) 58 | { 59 | case HDLC_FLAG_START: 60 | flagTypeStr = "Start"; 61 | break; 62 | case HDLC_FLAG_END: 63 | flagTypeStr = "End"; 64 | break; 65 | case HDLC_FLAG_FILL: 66 | flagTypeStr = "Fill"; 67 | break; 68 | } 69 | 70 | if( !tabular ) 71 | { 72 | AddResultString( "F" ); 73 | AddResultString( "FL" ); 74 | AddResultString( "FLAG" ); 75 | AddResultString( flagTypeStr, " FLAG" ); 76 | AddResultString( flagTypeStr, " Flag Delimiter" ); 77 | } 78 | else 79 | AddTabularText( flagTypeStr, " Flag Delimiter" ); 80 | } 81 | 82 | string HdlcAnalyzerResults::GenEscapedString( const Frame& frame ) 83 | { 84 | stringstream ss; 85 | if( frame.mFlags & HDLC_ESCAPED_BYTE ) 86 | { 87 | char dataStr[ 32 ]; 88 | AnalyzerHelpers::GetNumberString( frame.mData1, Hexadecimal, 8, dataStr, 32 ); 89 | char dataInvStr[ 32 ]; 90 | AnalyzerHelpers::GetNumberString( HdlcAnalyzerSettings::Bit5Inv( frame.mData1 ), Hexadecimal, 8, dataInvStr, 32 ); 91 | 92 | ss << " - ESCAPED: 0x7D-" << dataStr << "=" << dataInvStr; 93 | } 94 | 95 | return ss.str(); 96 | } 97 | 98 | void HdlcAnalyzerResults::GenAddressFieldString( const Frame& frame, DisplayBase display_base, bool tabular ) 99 | { 100 | char addressStr[ 64 ]; 101 | AnalyzerHelpers::GetNumberString( frame.mData1, display_base, 8, addressStr, 64 ); 102 | char byteNumber[ 64 ]; 103 | AnalyzerHelpers::GetNumberString( frame.mData2, Decimal, 8, byteNumber, 64 ); 104 | 105 | string escStr = GenEscapedString( frame ); 106 | 107 | if( !tabular ) 108 | { 109 | AddResultString( "A" ); 110 | AddResultString( "AD" ); 111 | AddResultString( "ADDR" ); 112 | AddResultString( "ADDR ", byteNumber, "[", addressStr, "]", escStr.c_str() ); 113 | AddResultString( "Address ", byteNumber, "[", addressStr, "]", escStr.c_str() ); 114 | } 115 | else 116 | AddTabularText( "Address ", byteNumber, "[", addressStr, "]", escStr.c_str() ); 117 | } 118 | 119 | void HdlcAnalyzerResults::GenInformationFieldString( const Frame& frame, const DisplayBase display_base, bool tabular ) 120 | { 121 | char informationStr[ 64 ]; 122 | AnalyzerHelpers::GetNumberString( frame.mData1, display_base, 8, informationStr, 64 ); 123 | char numberStr[ 64 ]; 124 | AnalyzerHelpers::GetNumberString( frame.mData2, Decimal, 32, numberStr, 64 ); 125 | 126 | string escStr = GenEscapedString( frame ); 127 | 128 | if( !tabular ) 129 | { 130 | AddResultString( "I" ); 131 | AddResultString( "I ", numberStr ); 132 | AddResultString( "I ", numberStr, " [", informationStr, "]", escStr.c_str() ); 133 | AddResultString( "Info ", numberStr, " [", informationStr, "]", escStr.c_str() ); 134 | } 135 | else 136 | AddTabularText( "Info ", numberStr, " [", informationStr, "]", escStr.c_str() ); 137 | } 138 | 139 | void HdlcAnalyzerResults::GenControlFieldString( const Frame& frame, DisplayBase display_base, bool tabular ) 140 | { 141 | char byteStr[ 64 ]; 142 | AnalyzerHelpers::GetNumberString( frame.mData1, display_base, 8, byteStr, 64 ); 143 | 144 | char ctlNumStr[ 64 ]; 145 | AnalyzerHelpers::GetNumberString( frame.mData2, Decimal, 8, ctlNumStr, 64 ); 146 | 147 | string escStr = GenEscapedString( frame ); 148 | 149 | char* frameTypeStr = 0; 150 | if( frame.mData2 != 0 ) 151 | { 152 | frameTypeStr = ""; 153 | } 154 | else 155 | { 156 | switch( HdlcAnalyzer::GetFrameType( frame.mData1 ) ) 157 | { 158 | case HDLC_I_FRAME: 159 | frameTypeStr = " - I-Frame"; 160 | break; 161 | case HDLC_S_FRAME: 162 | frameTypeStr = " - S-Frame"; 163 | break; 164 | case HDLC_U_FRAME: 165 | frameTypeStr = " - U-Frame"; 166 | break; 167 | } 168 | } 169 | 170 | stringstream ss; 171 | ss << "CTL" << ctlNumStr << " ["; 172 | 173 | if( !tabular ) 174 | { 175 | AddResultString( "C", ctlNumStr ); 176 | AddResultString( "CTL", ctlNumStr ); 177 | AddResultString( ss.str().c_str(), byteStr, "]", escStr.c_str() ); 178 | AddResultString( ss.str().c_str(), byteStr, "]", frameTypeStr, escStr.c_str() ); 179 | ss.str( "" ); 180 | ss << "Control" << ctlNumStr << " ["; 181 | 182 | AddResultString( ss.str().c_str(), byteStr, "]", frameTypeStr, escStr.c_str() ); 183 | } 184 | else 185 | { 186 | ss.str( "" ); 187 | ss << "Control" << ctlNumStr << " ["; 188 | AddTabularText( ss.str().c_str(), byteStr, "]", frameTypeStr, escStr.c_str() ); 189 | } 190 | } 191 | 192 | void HdlcAnalyzerResults::GenFcsFieldString( const Frame& frame, DisplayBase display_base, bool tabular ) 193 | { 194 | U32 fcsBits = 0; 195 | char* crcTypeStr = 0; 196 | switch( mSettings->mHdlcFcs ) 197 | { 198 | case HDLC_CRC8: 199 | fcsBits = 8; 200 | crcTypeStr = "8 "; 201 | break; 202 | case HDLC_CRC16: 203 | fcsBits = 16; 204 | crcTypeStr = "16"; 205 | break; 206 | case HDLC_CRC32: 207 | fcsBits = 32; 208 | crcTypeStr = "32"; 209 | break; 210 | } 211 | 212 | char readFcsStr[ 128 ]; 213 | AnalyzerHelpers::GetNumberString( frame.mData1, display_base, fcsBits, readFcsStr, 128 ); 214 | char calcFcsStr[ 128 ]; 215 | AnalyzerHelpers::GetNumberString( frame.mData2, display_base, fcsBits, calcFcsStr, 128 ); 216 | 217 | stringstream fieldNameStr; 218 | if( frame.mFlags & DISPLAY_AS_ERROR_FLAG ) 219 | { 220 | fieldNameStr << "!"; 221 | } 222 | 223 | fieldNameStr << "FCS CRC" << crcTypeStr; 224 | 225 | if( !tabular ) 226 | { 227 | AddResultString( "CRC" ); 228 | AddResultString( fieldNameStr.str().c_str() ); 229 | } 230 | 231 | if( frame.mFlags & DISPLAY_AS_ERROR_FLAG ) 232 | { 233 | fieldNameStr << " ERROR"; 234 | } 235 | else 236 | { 237 | fieldNameStr << " OK"; 238 | } 239 | 240 | if( !tabular ) 241 | { 242 | AddResultString( fieldNameStr.str().c_str() ); 243 | } 244 | 245 | if( frame.mFlags & DISPLAY_AS_ERROR_FLAG ) 246 | { 247 | fieldNameStr << " - CALC CRC[" << calcFcsStr << "] != READ CRC[" << readFcsStr << "]"; 248 | } 249 | 250 | if( !tabular ) 251 | AddResultString( fieldNameStr.str().c_str() ); 252 | else 253 | AddTabularText( fieldNameStr.str().c_str() ); 254 | } 255 | 256 | void HdlcAnalyzerResults::GenAbortFieldString( bool tabular ) 257 | { 258 | char* seq = 0; 259 | if( mSettings->mTransmissionMode == HDLC_TRANSMISSION_BIT_SYNC ) 260 | { 261 | seq = "(>=7 1-bits)"; 262 | } 263 | else 264 | { 265 | seq = "(0x7D-0x7F)"; 266 | } 267 | 268 | if( !tabular ) 269 | { 270 | AddResultString( "AB!" ); 271 | AddResultString( "ABORT!" ); 272 | AddResultString( "ABORT SEQUENCE!", seq ); 273 | } 274 | else 275 | { 276 | AddTabularText( "ABORT SEQUENCE!", seq ); 277 | } 278 | } 279 | 280 | string HdlcAnalyzerResults::EscapeByteStr( const Frame& frame ) 281 | { 282 | if( ( mSettings->mTransmissionMode == HDLC_TRANSMISSION_BYTE_ASYNC ) && ( frame.mFlags & HDLC_ESCAPED_BYTE ) ) 283 | { 284 | return string( "0x7D-" ); 285 | } 286 | else 287 | { 288 | return string( "" ); 289 | } 290 | } 291 | 292 | void HdlcAnalyzerResults::GenerateExportFile( const char* file, DisplayBase display_base, U32 /*export_type_user_id*/ ) 293 | { 294 | ofstream fileStream( file, ios::out ); 295 | 296 | U64 triggerSample = mAnalyzer->GetTriggerSample(); 297 | U32 sampleRate = mAnalyzer->GetSampleRate(); 298 | 299 | const char* sepChar = " "; 300 | 301 | U8 fcsBits = 0; 302 | switch( mSettings->mHdlcFcs ) 303 | { 304 | case HDLC_CRC8: 305 | fcsBits = 8; 306 | break; 307 | case HDLC_CRC16: 308 | fcsBits = 16; 309 | break; 310 | case HDLC_CRC32: 311 | fcsBits = 32; 312 | break; 313 | } 314 | 315 | fileStream << "Time[s],Address,Control,Information,FCS" << endl; 316 | 317 | char escapeStr[ 5 ]; 318 | AnalyzerHelpers::GetNumberString( HDLC_ESCAPE_SEQ_VALUE, display_base, 8, escapeStr, 5 ); 319 | 320 | U64 numFrames = GetNumFrames(); 321 | U64 frameNumber = 0; 322 | 323 | U32 numberOfControlBytes = 0; 324 | switch( mSettings->mHdlcControl ) 325 | { 326 | case HDLC_BASIC_CONTROL_FIELD: 327 | numberOfControlBytes = 1; 328 | break; 329 | case HDLC_EXTENDED_CONTROL_FIELD_MOD_128: 330 | numberOfControlBytes = 2; 331 | break; 332 | case HDLC_EXTENDED_CONTROL_FIELD_MOD_32768: 333 | numberOfControlBytes = 4; 334 | break; 335 | case HDLC_EXTENDED_CONTROL_FIELD_MOD_2147483648: 336 | numberOfControlBytes = 8; 337 | break; 338 | } 339 | 340 | if( numFrames == 0 ) 341 | { 342 | UpdateExportProgressAndCheckForCancel( frameNumber, numFrames ); 343 | return; 344 | } 345 | 346 | for( ;; ) 347 | { 348 | bool doAbortFrame = false; 349 | // Re-sync to start reading HDLC frames from the Address Byte 350 | Frame firstAddressFrame; 351 | for( ;; ) 352 | { 353 | firstAddressFrame = GetFrame( frameNumber ); 354 | 355 | // Check for abort 356 | if( firstAddressFrame.mType == HDLC_FIELD_BASIC_ADDRESS || 357 | firstAddressFrame.mType == HDLC_FIELD_EXTENDED_ADDRESS ) // It's and address frame 358 | { 359 | break; 360 | } 361 | else 362 | { 363 | frameNumber++; 364 | if( frameNumber >= numFrames ) 365 | { 366 | UpdateExportProgressAndCheckForCancel( frameNumber, numFrames ); 367 | return; 368 | } 369 | } 370 | } 371 | 372 | // 1) Time [s] 373 | char timeStr[ 64 ]; 374 | AnalyzerHelpers::GetTimeString( firstAddressFrame.mStartingSampleInclusive, triggerSample, sampleRate, timeStr, 64 ); 375 | fileStream << timeStr << ","; 376 | 377 | // 2) Address Field 378 | if( mSettings->mHdlcAddr == HDLC_BASIC_ADDRESS_FIELD ) 379 | { 380 | firstAddressFrame = GetFrame( frameNumber ); 381 | if( firstAddressFrame.mType != HDLC_FIELD_BASIC_ADDRESS ) 382 | { 383 | fileStream << "," << endl; 384 | continue; 385 | } 386 | 387 | char addressStr[ 64 ]; 388 | AnalyzerHelpers::GetNumberString( firstAddressFrame.mData1, display_base, 8, addressStr, 64 ); 389 | fileStream << EscapeByteStr( firstAddressFrame ) << addressStr << ","; 390 | } 391 | else // Check for extended address 392 | { 393 | Frame nextAddress = firstAddressFrame; 394 | for( ;; ) 395 | { 396 | // Check for abort 397 | if( nextAddress.mType == HDLC_ABORT_SEQ ) 398 | { 399 | fileStream << "," << endl; 400 | doAbortFrame = true; 401 | break; 402 | } 403 | 404 | if( nextAddress.mType != HDLC_FIELD_EXTENDED_ADDRESS ) // ERROR 405 | { 406 | fileStream << "," << endl; 407 | break; 408 | } 409 | 410 | bool endOfAddress = ( ( nextAddress.mData1 & 0x01 ) == 0 ); 411 | 412 | char addressStr[ 64 ]; 413 | AnalyzerHelpers::GetNumberString( nextAddress.mData1, display_base, 8, addressStr, 64 ); 414 | string sep = ( endOfAddress && nextAddress.mData2 == 0 ) ? string() : string( sepChar ); 415 | fileStream << sep << EscapeByteStr( nextAddress ) << addressStr; 416 | 417 | if( endOfAddress ) // no more bytes of address? 418 | { 419 | fileStream << ","; 420 | break; 421 | } 422 | else 423 | { 424 | frameNumber++; 425 | if( frameNumber >= numFrames ) 426 | { 427 | UpdateExportProgressAndCheckForCancel( frameNumber, numFrames ); 428 | return; 429 | } 430 | nextAddress = GetFrame( frameNumber ); 431 | } 432 | } 433 | } 434 | 435 | if( doAbortFrame ) 436 | { 437 | continue; 438 | } 439 | 440 | // 3) Control Field 441 | bool isUFrame = false; 442 | for( U32 i = 0; i < numberOfControlBytes; ++i ) 443 | { 444 | frameNumber++; 445 | if( frameNumber >= numFrames ) 446 | { 447 | UpdateExportProgressAndCheckForCancel( frameNumber, numFrames ); 448 | return; 449 | } 450 | 451 | Frame controlFrame = GetFrame( frameNumber ); 452 | 453 | // Check for abort 454 | if( controlFrame.mType == HDLC_ABORT_SEQ ) 455 | { 456 | doAbortFrame = true; 457 | fileStream << "," << endl; 458 | break; 459 | } 460 | 461 | if( !( controlFrame.mType == HDLC_FIELD_BASIC_CONTROL || controlFrame.mType == HDLC_FIELD_EXTENDED_CONTROL ) ) // ERROR 462 | { 463 | fileStream << "," << endl; 464 | continue; 465 | } 466 | 467 | if( i == 0 ) 468 | { 469 | isUFrame = HdlcAnalyzer::GetFrameType( controlFrame.mData1 ) == HDLC_U_FRAME; 470 | } 471 | 472 | char controlStr[ 64 ]; 473 | AnalyzerHelpers::GetNumberString( controlFrame.mData1, display_base, 8, controlStr, 64 ); 474 | string sep = ( isUFrame || mSettings->mHdlcControl == HDLC_BASIC_CONTROL_FIELD ) ? string() : string( sepChar ); 475 | fileStream << sep.c_str() << EscapeByteStr( controlFrame ) << controlStr; 476 | 477 | if( i == 0 && isUFrame ) 478 | { 479 | break; 480 | } 481 | } 482 | 483 | if( doAbortFrame ) 484 | { 485 | continue; 486 | } 487 | 488 | fileStream << ","; 489 | 490 | frameNumber++; 491 | if( frameNumber >= numFrames ) 492 | { 493 | UpdateExportProgressAndCheckForCancel( frameNumber, numFrames ); 494 | return; 495 | } 496 | 497 | // 5) Information Fields 498 | for( ;; ) 499 | { 500 | Frame infoFrame = GetFrame( frameNumber ); 501 | 502 | // Check for abort 503 | if( infoFrame.mType == HDLC_ABORT_SEQ ) 504 | { 505 | doAbortFrame = true; 506 | fileStream << "," << endl; 507 | break; 508 | } 509 | 510 | // Check for flag 511 | if( infoFrame.mType == HDLC_FIELD_FLAG ) 512 | { 513 | fileStream << ","; 514 | break; 515 | } 516 | 517 | // Check for info byte 518 | if( infoFrame.mType == HDLC_FIELD_INFORMATION ) // ERROR 519 | { 520 | char infoByteStr[ 64 ]; 521 | AnalyzerHelpers::GetNumberString( infoFrame.mData1, display_base, 8, infoByteStr, 64 ); 522 | fileStream << sepChar << EscapeByteStr( infoFrame ) << infoByteStr; 523 | frameNumber++; 524 | if( frameNumber >= numFrames ) 525 | { 526 | UpdateExportProgressAndCheckForCancel( frameNumber, numFrames ); 527 | return; 528 | } 529 | } 530 | else 531 | { 532 | fileStream << ","; 533 | break; 534 | } 535 | } 536 | 537 | if( doAbortFrame ) 538 | { 539 | continue; 540 | } 541 | 542 | // 6) FCS Field 543 | Frame fcsFrame = GetFrame( frameNumber ); 544 | if( fcsFrame.mType != HDLC_FIELD_FCS ) 545 | { 546 | fileStream << "," << endl; 547 | } 548 | else // HDLC_FIELD_FCS Frame 549 | { 550 | char fcsStr[ 128 ]; 551 | AnalyzerHelpers::GetNumberString( fcsFrame.mData1, display_base, fcsBits, fcsStr, 128 ); 552 | fileStream << fcsStr << endl; 553 | } 554 | 555 | frameNumber++; 556 | if( frameNumber >= numFrames ) 557 | { 558 | UpdateExportProgressAndCheckForCancel( frameNumber, numFrames ); 559 | return; 560 | } 561 | 562 | if( UpdateExportProgressAndCheckForCancel( frameNumber, numFrames ) ) 563 | { 564 | return; 565 | } 566 | } 567 | 568 | UpdateExportProgressAndCheckForCancel( frameNumber, numFrames ); 569 | } 570 | 571 | void HdlcAnalyzerResults::GenerateFrameTabularText( U64 frame_index, DisplayBase display_base ) 572 | { 573 | ClearTabularText(); 574 | GenBubbleText( frame_index, display_base, true ); 575 | } 576 | 577 | void HdlcAnalyzerResults::GeneratePacketTabularText( U64 packet_id, DisplayBase display_base ) 578 | { 579 | ClearResultStrings(); 580 | AddResultString( "not supported" ); 581 | } 582 | 583 | void HdlcAnalyzerResults::GenerateTransactionTabularText( U64 transaction_id, DisplayBase display_base ) 584 | { 585 | ClearResultStrings(); 586 | AddResultString( "not supported" ); 587 | } 588 | -------------------------------------------------------------------------------- /src/HdlcAnalyzerResults.h: -------------------------------------------------------------------------------- 1 | #ifndef HDLC_ANALYZER_RESULTS 2 | #define HDLC_ANALYZER_RESULTS 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class HdlcAnalyzer; 10 | class HdlcAnalyzerSettings; 11 | 12 | class HdlcAnalyzerResults : public AnalyzerResults 13 | { 14 | public: 15 | HdlcAnalyzerResults( HdlcAnalyzer* analyzer, HdlcAnalyzerSettings* settings ); 16 | virtual ~HdlcAnalyzerResults(); 17 | 18 | virtual void GenerateBubbleText( U64 frame_index, Channel& channel, DisplayBase display_base ); 19 | virtual void GenerateExportFile( const char* file, DisplayBase display_base, U32 export_type_user_id ); 20 | 21 | virtual void GenerateFrameTabularText( U64 frame_index, DisplayBase display_base ); 22 | virtual void GeneratePacketTabularText( U64 packet_id, DisplayBase display_base ); 23 | virtual void GenerateTransactionTabularText( U64 transaction_id, DisplayBase display_base ); 24 | 25 | protected: // functions 26 | void GenBubbleText( U64 frame_index, DisplayBase display_base, bool tabular ); 27 | 28 | void GenFlagFieldString( const Frame& frame, bool tabular ); 29 | void GenAddressFieldString( const Frame& frame, DisplayBase display_base, bool tabular ); 30 | void GenControlFieldString( const Frame& frame, DisplayBase display_base, bool tabular ); 31 | void GenInformationFieldString( const Frame& frame, DisplayBase display_base, bool tabular ); 32 | void GenFcsFieldString( const Frame& frame, DisplayBase display_base, bool tabular ); 33 | void GenAbortFieldString( bool tabular ); 34 | 35 | string EscapeByteStr( const Frame& frame ); 36 | string GenEscapedString( const Frame& frame ); 37 | 38 | protected: // vars 39 | HdlcAnalyzerSettings* mSettings; 40 | HdlcAnalyzer* mAnalyzer; 41 | }; 42 | 43 | #endif // HDLC_ANALYZER_RESULTS 44 | -------------------------------------------------------------------------------- /src/HdlcAnalyzerSettings.cpp: -------------------------------------------------------------------------------- 1 | #include "HdlcAnalyzerSettings.h" 2 | #include 3 | 4 | HdlcAnalyzerSettings::HdlcAnalyzerSettings() 5 | : mInputChannel( UNDEFINED_CHANNEL ), 6 | mBitRate( 2000000 ), 7 | mTransmissionMode( HDLC_TRANSMISSION_BIT_SYNC ), 8 | mHdlcAddr( HDLC_BASIC_ADDRESS_FIELD ), 9 | mHdlcControl( HDLC_BASIC_CONTROL_FIELD ), 10 | mHdlcFcs( HDLC_CRC16 ) 11 | { 12 | mInputChannelInterface.reset( new AnalyzerSettingInterfaceChannel() ); 13 | mInputChannelInterface->SetTitleAndTooltip( "HDLC", "Standard HDLC" ); 14 | mInputChannelInterface->SetChannel( mInputChannel ); 15 | 16 | mBitRateInterface.reset( new AnalyzerSettingInterfaceInteger() ); 17 | mBitRateInterface->SetTitleAndTooltip( "Baud Rate", "Specify the baud rate in symbols per second." ); 18 | mBitRateInterface->SetMax( 6000000 ); 19 | mBitRateInterface->SetMin( 1 ); 20 | mBitRateInterface->SetInteger( mBitRate ); 21 | 22 | mHdlcTransmissionInterface.reset( new AnalyzerSettingInterfaceNumberList() ); 23 | mHdlcTransmissionInterface->SetTitleAndTooltip( "Transmission Mode", "Specify the transmission mode of the HDLC frames" ); 24 | mHdlcTransmissionInterface->AddNumber( HDLC_TRANSMISSION_BIT_SYNC, "Bit Synchronous", "Bit-oriented transmission using bit stuffing" ); 25 | mHdlcTransmissionInterface->AddNumber( HDLC_TRANSMISSION_BYTE_ASYNC, "Byte Asynchronous", 26 | "Byte asynchronous transmission using byte stuffing (Also known as start/stop mode)" ); 27 | mHdlcTransmissionInterface->SetNumber( mTransmissionMode ); 28 | 29 | mHdlcAddrInterface.reset( new AnalyzerSettingInterfaceNumberList() ); 30 | mHdlcAddrInterface->SetTitleAndTooltip( "Address Field Type", "Specify the address field type of an HDLC frame." ); 31 | mHdlcAddrInterface->AddNumber( HDLC_BASIC_ADDRESS_FIELD, "Basic", "Basic Address Field (8 bits)" ); 32 | mHdlcAddrInterface->AddNumber( HDLC_EXTENDED_ADDRESS_FIELD, "Extended", "Extended Address Field (8 or more bits)" ); 33 | mHdlcAddrInterface->SetNumber( mHdlcAddr ); 34 | 35 | mHdlcControlInterface.reset( new AnalyzerSettingInterfaceNumberList() ); 36 | mHdlcControlInterface->SetTitleAndTooltip( "Control Field Format", "Specify the Control Field type of a HDLC frame." ); 37 | mHdlcControlInterface->AddNumber( HDLC_BASIC_CONTROL_FIELD, "Basic - Modulo 8", "Control Field of 8 bits" ); 38 | mHdlcControlInterface->AddNumber( HDLC_EXTENDED_CONTROL_FIELD_MOD_128, "Extended - Modulo 128", "Control Field of 16 bits" ); 39 | mHdlcControlInterface->AddNumber( HDLC_EXTENDED_CONTROL_FIELD_MOD_32768, "Extended - Modulo 32768", "Control Field of 32 bits" ); 40 | mHdlcControlInterface->AddNumber( HDLC_EXTENDED_CONTROL_FIELD_MOD_2147483648, "Extended - Modulo 2147483648", 41 | "Control Field of 64 bits" ); 42 | mHdlcControlInterface->SetNumber( mHdlcControl ); 43 | 44 | mHdlcFcsInterface.reset( new AnalyzerSettingInterfaceNumberList() ); 45 | mHdlcFcsInterface->SetTitleAndTooltip( "FCS Type", "Specify the Frame Check Sequence of an HDLC frame" ); 46 | mHdlcFcsInterface->AddNumber( HDLC_CRC8, "CRC-8", "8-bit Cyclic Redundancy Check" ); 47 | mHdlcFcsInterface->AddNumber( HDLC_CRC16, "CRC-16-CCITT", "16-bit Cyclic Redundancy Check" ); 48 | mHdlcFcsInterface->AddNumber( HDLC_CRC32, "CRC-32", "32-bit Cyclic Redundancy Check" ); 49 | mHdlcFcsInterface->SetNumber( mHdlcFcs ); 50 | 51 | AddInterface( mInputChannelInterface.get() ); 52 | AddInterface( mBitRateInterface.get() ); 53 | AddInterface( mHdlcTransmissionInterface.get() ); 54 | AddInterface( mHdlcAddrInterface.get() ); 55 | AddInterface( mHdlcControlInterface.get() ); 56 | AddInterface( mHdlcFcsInterface.get() ); 57 | 58 | AddExportOption( 0, "Export as text/csv file" ); 59 | AddExportExtension( 0, "text", "txt" ); 60 | AddExportExtension( 0, "csv", "csv" ); 61 | 62 | ClearChannels(); 63 | AddChannel( mInputChannel, "HDLC", false ); 64 | } 65 | 66 | HdlcAnalyzerSettings::~HdlcAnalyzerSettings() 67 | { 68 | } 69 | 70 | U8 HdlcAnalyzerSettings::Bit5Inv( U8 value ) 71 | { 72 | return value ^ 0x20; 73 | } 74 | 75 | bool HdlcAnalyzerSettings::SetSettingsFromInterfaces() 76 | { 77 | mInputChannel = mInputChannelInterface->GetChannel(); 78 | mBitRate = mBitRateInterface->GetInteger(); 79 | mTransmissionMode = HdlcTransmissionModeType( U32( mHdlcTransmissionInterface->GetNumber() ) ); 80 | mHdlcAddr = HdlcAddressType( U32( mHdlcAddrInterface->GetNumber() ) ); 81 | mHdlcControl = HdlcControlType( U32( mHdlcControlInterface->GetNumber() ) ); 82 | mHdlcFcs = HdlcFcsType( U32( mHdlcFcsInterface->GetNumber() ) ); 83 | 84 | ClearChannels(); 85 | AddChannel( mInputChannel, "HDLC", true ); 86 | 87 | return true; 88 | } 89 | 90 | void HdlcAnalyzerSettings::UpdateInterfacesFromSettings() 91 | { 92 | mInputChannelInterface->SetChannel( mInputChannel ); 93 | mBitRateInterface->SetInteger( mBitRate ); 94 | mHdlcTransmissionInterface->SetNumber( mTransmissionMode ); 95 | mHdlcAddrInterface->SetNumber( mHdlcAddr ); 96 | mHdlcControlInterface->SetNumber( mHdlcControl ); 97 | mHdlcFcsInterface->SetNumber( mHdlcFcs ); 98 | } 99 | 100 | void HdlcAnalyzerSettings::LoadSettings( const char* settings ) 101 | { 102 | SimpleArchive text_archive; 103 | text_archive.SetString( settings ); 104 | 105 | text_archive >> mInputChannel; 106 | text_archive >> mBitRate; 107 | text_archive >> *( U32* )&mTransmissionMode; 108 | text_archive >> *( U32* )&mHdlcAddr; 109 | text_archive >> *( U32* )&mHdlcControl; 110 | text_archive >> *( U32* )&mHdlcFcs; 111 | 112 | ClearChannels(); 113 | AddChannel( mInputChannel, "HDLC", true ); 114 | 115 | UpdateInterfacesFromSettings(); 116 | } 117 | 118 | const char* HdlcAnalyzerSettings::SaveSettings() 119 | { 120 | SimpleArchive text_archive; 121 | 122 | text_archive << mInputChannel; 123 | text_archive << mBitRate; 124 | text_archive << U32( mTransmissionMode ); 125 | text_archive << U32( mHdlcAddr ); 126 | text_archive << U32( mHdlcControl ); 127 | text_archive << U32( mHdlcFcs ); 128 | 129 | return SetReturnString( text_archive.GetString() ); 130 | } 131 | -------------------------------------------------------------------------------- /src/HdlcAnalyzerSettings.h: -------------------------------------------------------------------------------- 1 | #ifndef HDLC_ANALYZER_SETTINGS 2 | #define HDLC_ANALYZER_SETTINGS 3 | 4 | #include 5 | #include 6 | 7 | ///////////////////////////////////// 8 | 9 | // NOTE: terminology: 10 | // * HDLC Frame == Saleae Logic Packet 11 | // * HDLC Field == Saleae Logic Frame 12 | // * HDLC transactions not supported 13 | 14 | // Inner frames types of HDLC frame (address, control, data, fcs, etc) 15 | enum HdlcFieldType 16 | { 17 | HDLC_FIELD_FLAG = 0, 18 | HDLC_FIELD_BASIC_ADDRESS, 19 | HDLC_FIELD_EXTENDED_ADDRESS, 20 | HDLC_FIELD_BASIC_CONTROL, 21 | HDLC_FIELD_EXTENDED_CONTROL, 22 | HDLC_FIELD_INFORMATION, 23 | HDLC_FIELD_FCS, 24 | HDLC_ABORT_SEQ 25 | }; 26 | // Transmission mode (bit stuffing or byte stuffing) 27 | enum HdlcTransmissionModeType 28 | { 29 | HDLC_TRANSMISSION_BIT_SYNC = 0, 30 | HDLC_TRANSMISSION_BYTE_ASYNC 31 | }; 32 | // Types of HDLC frames (Information, Supervisory and Unnumbered) 33 | enum HdlcFrameType 34 | { 35 | HDLC_I_FRAME = 0, 36 | HDLC_S_FRAME = 1, 37 | HDLC_U_FRAME = 3 38 | }; 39 | // Address Field type 40 | enum HdlcAddressType 41 | { 42 | HDLC_BASIC_ADDRESS_FIELD = 0, 43 | HDLC_EXTENDED_ADDRESS_FIELD 44 | }; 45 | // Control Field Type 46 | enum HdlcControlType 47 | { 48 | HDLC_BASIC_CONTROL_FIELD, 49 | HDLC_EXTENDED_CONTROL_FIELD_MOD_128, 50 | HDLC_EXTENDED_CONTROL_FIELD_MOD_32768, 51 | HDLC_EXTENDED_CONTROL_FIELD_MOD_2147483648 52 | }; 53 | // Frame Check Sequence algorithm 54 | enum HdlcFcsType 55 | { 56 | HDLC_CRC8 = 0, 57 | HDLC_CRC16 = 1, 58 | HDLC_CRC32 = 2 59 | }; 60 | // Flag Field Type (Start, End or Fill) 61 | enum HdlcFlagType 62 | { 63 | HDLC_FLAG_START = 0, 64 | HDLC_FLAG_END = 1, 65 | HDLC_FLAG_FILL = 2 66 | }; 67 | 68 | 69 | // Special values for Byte Asynchronous Transmission 70 | #define HDLC_FLAG_VALUE 0x7E 71 | #define HDLC_ESCAPE_SEQ_VALUE 0x7D 72 | #define HDLC_FILL_VALUE 0xFF 73 | // For Frame::mFlag 74 | #define HDLC_ESCAPED_BYTE ( 1 << 0 ) 75 | 76 | ///////////////////////////////////// 77 | 78 | class HdlcAnalyzerSettings : public AnalyzerSettings 79 | { 80 | public: 81 | HdlcAnalyzerSettings(); 82 | virtual ~HdlcAnalyzerSettings(); 83 | 84 | virtual bool SetSettingsFromInterfaces(); 85 | void UpdateInterfacesFromSettings(); 86 | virtual void LoadSettings( const char* settings ); 87 | virtual const char* SaveSettings(); 88 | 89 | static U8 Bit5Inv( U8 value ); 90 | 91 | Channel mInputChannel; 92 | U32 mBitRate; 93 | 94 | HdlcTransmissionModeType mTransmissionMode; 95 | HdlcAddressType mHdlcAddr; 96 | HdlcControlType mHdlcControl; 97 | HdlcFcsType mHdlcFcs; 98 | 99 | protected: 100 | std::auto_ptr mInputChannelInterface; 101 | std::auto_ptr mBitRateInterface; 102 | std::auto_ptr mHdlcAddrInterface; 103 | std::auto_ptr mHdlcTransmissionInterface; 104 | std::auto_ptr mHdlcControlInterface; 105 | std::auto_ptr mHdlcFcsInterface; 106 | }; 107 | 108 | #endif // HDLC_ANALYZER_SETTINGS 109 | -------------------------------------------------------------------------------- /src/HdlcSimulationDataGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "HdlcSimulationDataGenerator.h" 2 | #include "HdlcAnalyzerSettings.h" 3 | #include 4 | #include 5 | #include 6 | 7 | HdlcSimulationDataGenerator::HdlcSimulationDataGenerator() 8 | : mSettings( 0 ), 9 | mSimulationSampleRateHz( 0 ), 10 | mFrameNumber( 0 ), 11 | mAbortByte( 0 ), 12 | mWrongFramesSeparation( 0 ), 13 | mControlValue( 0 ), 14 | mAddresByteValue( 0 ), 15 | mInformationByteValue( 0 ), 16 | mSamplesInHalfPeriod( 0 ), 17 | mSamplesInAFlag( 0 ) 18 | 19 | { 20 | mFrameTypes[ 0 ] = HDLC_I_FRAME; 21 | mFrameTypes[ 1 ] = HDLC_S_FRAME; 22 | mFrameTypes[ 2 ] = HDLC_U_FRAME; 23 | } 24 | 25 | HdlcSimulationDataGenerator::~HdlcSimulationDataGenerator() 26 | { 27 | } 28 | 29 | void HdlcSimulationDataGenerator::Initialize( U32 simulation_sample_rate, HdlcAnalyzerSettings* settings ) 30 | { 31 | mSimulationSampleRateHz = simulation_sample_rate; 32 | mSettings = settings; 33 | 34 | mHdlcSimulationData.SetChannel( mSettings->mInputChannel ); 35 | mHdlcSimulationData.SetSampleRate( simulation_sample_rate ); 36 | mHdlcSimulationData.SetInitialBitState( BIT_LOW ); 37 | 38 | // Initialize rng seed 39 | srand( 5 ); 40 | 41 | mSamplesInHalfPeriod = U64( simulation_sample_rate / double( mSettings->mBitRate ) ); 42 | mSamplesInAFlag = mSamplesInHalfPeriod * 7; 43 | 44 | mHdlcSimulationData.Advance( mSamplesInHalfPeriod * 8 ); // Advance 4 periods 45 | GenerateAbortFramesIndexes(); 46 | mAbortByte = 0; 47 | mFrameNumber = 0; 48 | mWrongFramesSeparation = ( rand() % 10 ) + 10; // [15..30] 49 | 50 | mControlValue = 0; 51 | mAddresByteValue = 0; 52 | mInformationByteValue = 0; 53 | } 54 | 55 | void HdlcSimulationDataGenerator::GenerateAbortFramesIndexes() 56 | { 57 | mAbortFramesIndexes.push_back( rand() % 50 ); 58 | mAbortFramesIndexes.push_back( rand() % 50 ); 59 | mAbortFramesIndexes.push_back( rand() % 50 ); 60 | mAbortFramesIndexes.push_back( rand() % 50 ); 61 | mAbortFramesIndexes.push_back( rand() % 50 ); 62 | mAbortFramesIndexes.push_back( rand() % 50 ); 63 | } 64 | 65 | bool HdlcSimulationDataGenerator::ContainsElement( U32 index ) const 66 | { 67 | for( U32 i = 0; i < mAbortFramesIndexes.size(); ++i ) 68 | { 69 | if( mAbortFramesIndexes.at( i ) == index ) 70 | { 71 | return true; 72 | } 73 | } 74 | return false; 75 | } 76 | 77 | U32 HdlcSimulationDataGenerator::GenerateSimulationData( U64 largest_sample_requested, U32 sample_rate, 78 | SimulationChannelDescriptor** simulation_channel ) 79 | { 80 | U64 adjusted_largest_sample_requested = 81 | AnalyzerHelpers::AdjustSimulationTargetSample( largest_sample_requested, sample_rate, mSimulationSampleRateHz ); 82 | 83 | while( mHdlcSimulationData.GetCurrentSampleNumber() < adjusted_largest_sample_requested ) 84 | { 85 | // Two consecutive flags 86 | CreateFlag(); 87 | CreateFlag(); 88 | 89 | HdlcFrameType frameType = mFrameTypes[ mFrameNumber % 3 ]; 90 | U32 sizeOfInformation = ( frameType == HDLC_S_FRAME ) ? 0 : ( ( rand() % 4 ) + 1 ); 91 | U64 addressBytes = ( ( rand() % 4 ) + 1 ); 92 | 93 | vector address = GenAddressField( mSettings->mHdlcAddr, addressBytes, mAddresByteValue++ ); 94 | vector control = GenControlField( frameType, mSettings->mHdlcControl, mControlValue++ ); 95 | vector information = GenInformationField( sizeOfInformation, mInformationByteValue++ ); 96 | 97 | CreateHDLCFrame( address, control, information ); 98 | 99 | // Two consecutive flags 100 | CreateFlag(); 101 | CreateFlag(); 102 | 103 | mFrameNumber++; 104 | } 105 | 106 | *simulation_channel = &mHdlcSimulationData; 107 | return 1; 108 | } 109 | 110 | void HdlcSimulationDataGenerator::CreateFlag() 111 | { 112 | if( mSettings->mTransmissionMode == HDLC_TRANSMISSION_BIT_SYNC ) 113 | { 114 | CreateFlagBitSeq(); 115 | } 116 | else // HDLC_TRANSMISSION_BYTE_ASYNC 117 | { 118 | CreateAsyncByte( HDLC_FLAG_VALUE ); 119 | } 120 | } 121 | 122 | 123 | vector HdlcSimulationDataGenerator::GenAddressField( HdlcAddressType addressType, U64 addressBytes, U8 value ) const 124 | { 125 | vector addrRet; 126 | if( addressType == HDLC_BASIC_ADDRESS_FIELD ) 127 | { 128 | addrRet.push_back( value ); 129 | } 130 | else // addressType == HDLC_EXTENDED_ADDRESS_FIELD 131 | { 132 | for( U32 i = 0; i < addressBytes; ++i ) 133 | { 134 | U8 mask = ( i == addressBytes - 1 ) ? 0x00 : 0x01; // EA bit (Lsb is set to 1 to extend the address recursively) 135 | U8 extValue = ( value & 0xFE ) | mask; 136 | addrRet.push_back( extValue ); 137 | } 138 | } 139 | return addrRet; 140 | } 141 | 142 | // ISO/IEC 13239:2002(E) page 26 143 | vector HdlcSimulationDataGenerator::GenControlField( HdlcFrameType frameType, HdlcControlType controlType, U8 value ) const 144 | { 145 | vector controlRet; 146 | U8 ctrl; 147 | switch( frameType ) 148 | { 149 | case HDLC_I_FRAME: 150 | ctrl = ( value & 0xFE ) | U8( frameType ); 151 | break; 152 | case HDLC_S_FRAME: 153 | ctrl = ( value & 0xFC ) | U8( frameType ); 154 | break; 155 | case HDLC_U_FRAME: 156 | ctrl = value | U8( HDLC_U_FRAME ); 157 | } 158 | 159 | switch( frameType ) 160 | { 161 | case HDLC_I_FRAME: 162 | case HDLC_S_FRAME: 163 | { 164 | // first byte 165 | controlRet.push_back( ctrl ); 166 | switch( controlType ) 167 | { 168 | case HDLC_EXTENDED_CONTROL_FIELD_MOD_128: 169 | controlRet.push_back( value ); // second byte 170 | break; 171 | case HDLC_EXTENDED_CONTROL_FIELD_MOD_32768: 172 | controlRet.push_back( value ); // second byte 173 | controlRet.push_back( value ); // third byte 174 | controlRet.push_back( value ); // fourth byte 175 | break; 176 | case HDLC_EXTENDED_CONTROL_FIELD_MOD_2147483648: 177 | controlRet.push_back( value ); // second byte 178 | controlRet.push_back( value ); // third byte 179 | controlRet.push_back( value ); // fourth byte 180 | controlRet.push_back( value ); // fifth byte 181 | controlRet.push_back( value ); // sixth byte 182 | controlRet.push_back( value ); // seventh byte 183 | controlRet.push_back( value ); // eighth byte 184 | break; 185 | } 186 | break; 187 | } 188 | case HDLC_U_FRAME: // U frames are always of 8 bits 189 | { 190 | controlRet.push_back( ctrl ); 191 | break; 192 | } 193 | } 194 | return controlRet; 195 | } 196 | 197 | vector HdlcSimulationDataGenerator::GenInformationField( U16 size, U8 value ) const 198 | { 199 | vector informationRet( size, value ); 200 | return informationRet; 201 | } 202 | 203 | void HdlcSimulationDataGenerator::CreateHDLCFrame( const vector& address, const vector& control, const vector& information ) 204 | { 205 | vector allFields; 206 | 207 | allFields.insert( allFields.end(), address.begin(), address.end() ); 208 | allFields.insert( allFields.end(), control.begin(), control.end() ); 209 | allFields.insert( allFields.end(), information.begin(), information.end() ); 210 | 211 | // Calculate the crc of the address, control and data fields 212 | vector fcs = GenFcs( mSettings->mHdlcFcs, allFields ); 213 | allFields.insert( allFields.end(), fcs.begin(), fcs.end() ); 214 | 215 | // Transmit the frame in bit-sync or byte-async 216 | if( mSettings->mTransmissionMode == HDLC_TRANSMISSION_BIT_SYNC ) 217 | { 218 | TransmitBitSync( allFields ); 219 | } 220 | else 221 | { 222 | TransmitByteAsync( allFields ); 223 | } 224 | } 225 | 226 | vector HdlcSimulationDataGenerator::GenFcs( HdlcFcsType fcsType, const vector& stream ) const 227 | { 228 | vector crcRet; 229 | switch( fcsType ) 230 | { 231 | case HDLC_CRC8: 232 | crcRet = Crc8( stream ); 233 | break; 234 | case HDLC_CRC16: 235 | crcRet = Crc16( stream ); 236 | break; 237 | case HDLC_CRC32: 238 | crcRet = Crc32( stream ); 239 | break; 240 | } 241 | return crcRet; 242 | } 243 | 244 | void HdlcSimulationDataGenerator::TransmitBitSync( const vector& stream ) 245 | { 246 | // Opening flag 247 | CreateFlagBitSeq(); 248 | 249 | bool abortFrame = ContainsElement( mFrameNumber ); 250 | 251 | U8 consecutiveOnes = 0; 252 | BitState previousBit = BIT_LOW; 253 | // For each byte of the stream 254 | U32 index = 0; 255 | for( U32 s = 0; s < stream.size(); ++s ) 256 | { 257 | bool abortThisByte = ( mAbortByte == s ); 258 | if( abortFrame && abortThisByte ) 259 | { 260 | // Sync bit abort sequence = 7 or more consecutive 1 261 | for( U32 j = 0; j < 7; ++j ) 262 | { 263 | CreateSyncBit( BIT_HIGH ); 264 | } 265 | mAbortByte++; 266 | return; 267 | } 268 | 269 | // For each bit of the byte stream 270 | BitExtractor bit_extractor( stream[ s ], AnalyzerEnums::LsbFirst, 8 ); 271 | for( U32 i = 0; i < 8; ++i ) 272 | { 273 | BitState bit = bit_extractor.GetNextBit(); 274 | CreateSyncBit( bit ); 275 | 276 | if( bit == BIT_HIGH ) 277 | { 278 | if( previousBit == BIT_HIGH ) 279 | { 280 | consecutiveOnes++; 281 | } 282 | else 283 | { 284 | consecutiveOnes = 0; 285 | } 286 | } 287 | else // bit low 288 | { 289 | consecutiveOnes = 0; 290 | } 291 | 292 | if( consecutiveOnes == 4 ) // if five 1s in a row, then insert a 0 and continue 293 | { 294 | CreateSyncBit( BIT_LOW ); 295 | consecutiveOnes = 0; 296 | previousBit = BIT_LOW; 297 | } 298 | else 299 | { 300 | previousBit = bit; 301 | } 302 | index++; 303 | } 304 | } 305 | 306 | // Closing flag 307 | CreateFlagBitSeq(); 308 | } 309 | 310 | void HdlcSimulationDataGenerator::CreateFlagBitSeq() 311 | { 312 | mHdlcSimulationData.Transition(); 313 | 314 | mHdlcSimulationData.Advance( mSamplesInAFlag ); 315 | mHdlcSimulationData.Transition(); 316 | 317 | mHdlcSimulationData.Advance( mSamplesInHalfPeriod ); 318 | } 319 | 320 | // Maps the bit to the signal using NRZI 321 | void HdlcSimulationDataGenerator::CreateSyncBit( BitState bitState ) 322 | { 323 | if( bitState == BIT_LOW ) // BIT_LOW == transition, BIT_HIGH == no transition 324 | { 325 | mHdlcSimulationData.Transition(); 326 | } 327 | mHdlcSimulationData.Advance( mSamplesInHalfPeriod ); 328 | } 329 | 330 | void HdlcSimulationDataGenerator::TransmitByteAsync( const vector& stream ) 331 | { 332 | // Opening flag 333 | CreateAsyncByte( HDLC_FLAG_VALUE ); 334 | 335 | bool abortFrame = ContainsElement( mFrameNumber ); 336 | 337 | for( U32 i = 0; i < stream.size(); ++i ) 338 | { 339 | bool abortThisByte = ( mAbortByte == i ); 340 | if( abortFrame && abortThisByte ) // Abort the frame: ABORT SEQUENCE = ESCAPE + FLAG 341 | { 342 | CreateAsyncByte( HDLC_ESCAPE_SEQ_VALUE ); 343 | CreateAsyncByte( HDLC_FLAG_VALUE ); 344 | AsyncByteFill( 7 ); 345 | mAbortByte++; 346 | return; 347 | } 348 | 349 | const U8 byte = stream[ i ]; 350 | switch( byte ) 351 | { 352 | case HDLC_FLAG_VALUE: // 0x7E 353 | CreateAsyncByte( HDLC_ESCAPE_SEQ_VALUE ); // 7D escape 354 | CreateAsyncByte( HdlcAnalyzerSettings::Bit5Inv( HDLC_FLAG_VALUE ) ); // 5E 355 | break; 356 | case HDLC_ESCAPE_SEQ_VALUE: // 0x7D 357 | CreateAsyncByte( HDLC_ESCAPE_SEQ_VALUE ); // 7D escape 358 | CreateAsyncByte( HdlcAnalyzerSettings::Bit5Inv( HDLC_ESCAPE_SEQ_VALUE ) ); // 5D 359 | break; 360 | default: 361 | CreateAsyncByte( byte ); // normal byte 362 | } 363 | 364 | // Fill between bytes (0 to 7 bits of value 1) 365 | AsyncByteFill( rand() % 8 ); 366 | } 367 | 368 | // Closing flag 369 | CreateAsyncByte( HDLC_FLAG_VALUE ); 370 | } 371 | 372 | void HdlcSimulationDataGenerator::AsyncByteFill( U32 N ) 373 | { 374 | // 0) If the line is not high we must set it high 375 | if( mHdlcSimulationData.GetCurrentBitState() == BIT_LOW ) 376 | { 377 | mHdlcSimulationData.Transition(); 378 | } 379 | // 1) Fill N high periods 380 | mHdlcSimulationData.Advance( mSamplesInHalfPeriod * N ); 381 | } 382 | 383 | // ISO/IEC 13239:2002(E) page 17 384 | void HdlcSimulationDataGenerator::CreateAsyncByte( U8 byte ) 385 | { 386 | // 0) If the line is not high we must set it high 387 | if( mHdlcSimulationData.GetCurrentBitState() == BIT_LOW ) 388 | { 389 | mHdlcSimulationData.Transition(); 390 | mHdlcSimulationData.Advance( mSamplesInHalfPeriod ); 391 | } 392 | 393 | // 1) Start bit (BIT_HIGH -> BIT_LOW) 394 | mHdlcSimulationData.TransitionIfNeeded( BIT_LOW ); 395 | mHdlcSimulationData.Advance( mSamplesInHalfPeriod ); 396 | 397 | // 2) Transmit byte 398 | BitExtractor bit_extractor( byte, AnalyzerEnums::LsbFirst, 8 ); 399 | for( U32 i = 0; i < 8; ++i ) 400 | { 401 | BitState bit = bit_extractor.GetNextBit(); 402 | mHdlcSimulationData.TransitionIfNeeded( bit ); 403 | mHdlcSimulationData.Advance( mSamplesInHalfPeriod ); 404 | } 405 | 406 | // 3) Stop bit (BIT_LOW -> BIT_HIGH) 407 | mHdlcSimulationData.TransitionIfNeeded( BIT_HIGH ); 408 | mHdlcSimulationData.Advance( mSamplesInHalfPeriod ); 409 | } 410 | 411 | // 412 | ////////////////////// Static functions ///////////////////////////////////////////////////// 413 | // 414 | 415 | vector HdlcSimulationDataGenerator::BytesVectorToBitsVector( const vector& v, U32 numberOfBits ) 416 | { 417 | vector bitsRet; 418 | U32 vectorIndex = 0; 419 | U8 byte; 420 | bool getByte = true; 421 | U8 bytePos = 0x80; 422 | for( U32 i = 0; i < numberOfBits; ++i ) 423 | { 424 | if( getByte ) 425 | { 426 | byte = v.at( vectorIndex ); 427 | bytePos = 0x80; 428 | vectorIndex++; 429 | } 430 | 431 | BitState bit = ( byte & bytePos ) ? BIT_HIGH : BIT_LOW; 432 | bitsRet.push_back( bit ); 433 | 434 | bytePos >>= 1; 435 | 436 | getByte = ( ( i + 1 ) % 8 == 0 ); 437 | } 438 | 439 | return bitsRet; 440 | } 441 | 442 | vector HdlcSimulationDataGenerator::CrcDivision( const vector& stream, const vector& genPoly, U32 crcNumber ) 443 | { 444 | vector dataBits = BytesVectorToBitsVector( stream, stream.size() * 8 ); 445 | vector polyBits = BytesVectorToBitsVector( genPoly, crcNumber + 1 ); 446 | 447 | U32 dataIndex = 0; 448 | U32 dataLimit = dataBits.size() - ( polyBits.size() - 1 ); 449 | while( dataIndex < dataLimit ) 450 | { 451 | // Advance one-position or 0-bits 452 | bool zeroBits = true; 453 | while( zeroBits ) 454 | { 455 | zeroBits = ( ( dataBits.at( dataIndex ) == BIT_LOW ) && ( dataIndex < dataLimit ) ); 456 | if( zeroBits ) 457 | { 458 | dataIndex++; 459 | } 460 | } 461 | 462 | if( dataIndex < dataLimit ) 463 | { 464 | for( U32 bitIndex = 0; bitIndex < polyBits.size(); ++bitIndex ) 465 | { 466 | BitState bit = dataBits.at( dataIndex + bitIndex ); 467 | BitState polyBit = polyBits.at( bitIndex ); 468 | 469 | dataBits[ dataIndex + bitIndex ] = BitState( bit ^ polyBit ); 470 | } 471 | } 472 | 473 | dataIndex++; 474 | } 475 | 476 | // put the crc result in the vector of bytes 477 | vector crcRet; 478 | U8 offset = crcNumber; 479 | for( U32 s = 0; s < crcNumber / 8; ++s ) 480 | { 481 | U64 byteValue = 0; 482 | DataBuilder dbyte; 483 | dbyte.Reset( &byteValue, AnalyzerEnums::MsbFirst, 8 ); 484 | for( U32 i = dataBits.size() - offset; i < dataBits.size() - offset + 8; ++i ) 485 | { 486 | dbyte.AddBit( dataBits.at( i ) ); 487 | } 488 | offset -= 8; 489 | crcRet.push_back( byteValue ); 490 | } 491 | 492 | return crcRet; 493 | } 494 | 495 | vector HdlcSimulationDataGenerator::Crc8( const vector& stream ) 496 | { 497 | vector result = stream; 498 | result.push_back( 0x00 ); 499 | 500 | // ISO/IEC 13239:2002(E) page 14 501 | // CRC8 Divisor (9 bits) - x**8 + x**2 + x + 1 502 | vector divisor; 503 | divisor.push_back( 0x83 ); 504 | divisor.push_back( 0x80 ); 505 | 506 | vector crc8Ret = CrcDivision( result, divisor, 8 ); 507 | return crc8Ret; 508 | } 509 | 510 | vector HdlcSimulationDataGenerator::Crc16( const vector& stream ) 511 | { 512 | vector result = stream; 513 | 514 | // Append 16 0-bits 515 | result.push_back( 0x00 ); 516 | result.push_back( 0x00 ); 517 | 518 | // ISO/IEC 13239:2002(E) page 14 519 | // CRC16 Divisor (17 bits) - x**16 + x**12 + x**5 + 1 (0x1021) 520 | vector divisor; 521 | divisor.push_back( 0x88 ); 522 | divisor.push_back( 0x10 ); 523 | divisor.push_back( 0x80 ); 524 | 525 | vector crc16Ret = CrcDivision( result, divisor, 16 ); 526 | 527 | return crc16Ret; 528 | } 529 | 530 | vector HdlcSimulationDataGenerator::Crc32( const vector& stream ) 531 | { 532 | vector result = stream; 533 | // Append 32 0-bits 534 | result.push_back( 0x00 ); 535 | result.push_back( 0x00 ); 536 | result.push_back( 0x00 ); 537 | result.push_back( 0x00 ); 538 | 539 | // ISO/IEC 13239:2002(E) page 13 540 | // CRC32 Divisor (33 bits) 541 | vector divisor; 542 | divisor.push_back( 0x82 ); 543 | divisor.push_back( 0x60 ); 544 | divisor.push_back( 0x8E ); 545 | divisor.push_back( 0xDB ); 546 | divisor.push_back( 0x80 ); 547 | 548 | vector crc32Ret = CrcDivision( result, divisor, 32 ); 549 | return crc32Ret; 550 | } 551 | -------------------------------------------------------------------------------- /src/HdlcSimulationDataGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef HDLC_SIMULATION_DATA_GENERATOR 2 | #define HDLC_SIMULATION_DATA_GENERATOR 3 | 4 | #include 5 | #include "HdlcAnalyzerSettings.h" 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | class HdlcSimulationDataGenerator 12 | { 13 | public: 14 | HdlcSimulationDataGenerator(); 15 | ~HdlcSimulationDataGenerator(); 16 | 17 | void Initialize( U32 simulation_sample_rate, HdlcAnalyzerSettings* settings ); 18 | U32 GenerateSimulationData( U64 newest_sample_requested, U32 sample_rate, SimulationChannelDescriptor** simulation_channel ); 19 | 20 | static vector Crc8( const vector& stream ); 21 | static vector Crc16( const vector& stream ); 22 | static vector Crc32( const vector& stream ); 23 | static vector CrcDivision( const vector& stream, const vector& genPoly, U32 crcNumber ); 24 | static vector BytesVectorToBitsVector( const vector& v, U32 numberOfBits ); 25 | 26 | protected: 27 | void CreateHDLCFrame( const vector& address, const vector& control, const vector& information ); 28 | void CreateFlag(); 29 | 30 | // Sync Transmission 31 | void CreateFlagBitSeq(); 32 | void CreateSyncBit( BitState bitState ); 33 | void TransmitBitSync( const vector& stream ); 34 | 35 | // Async transmission 36 | void TransmitByteAsync( const vector& stream ); 37 | void CreateAsyncByte( U8 byte ); 38 | void AsyncByteFill( U32 N ); 39 | 40 | // Helper functions 41 | bool AbortFrameAndGenIndex( U32 N ); 42 | vector GenFcs( HdlcFcsType fcsType, const vector& stream ) const; 43 | 44 | void GenerateAbortFramesIndexes(); 45 | bool ContainsElement( U32 index ) const; 46 | 47 | vector GenAddressField( HdlcAddressType addressType, U64 addressBytes, U8 value ) const; 48 | vector GenControlField( HdlcFrameType frameType, HdlcControlType controlType, U8 value ) const; 49 | vector GenInformationField( U16 size, U8 value ) const; 50 | 51 | HdlcAnalyzerSettings* mSettings; 52 | U32 mSimulationSampleRateHz; 53 | 54 | vector mAbortFramesIndexes; 55 | U32 mFrameNumber; 56 | U32 mAbortByte; 57 | U32 mWrongFramesSeparation; 58 | 59 | U8 mControlValue; 60 | U8 mAddresByteValue; 61 | U8 mInformationByteValue; 62 | 63 | HdlcFrameType mFrameTypes[ 3 ]; 64 | 65 | SimulationChannelDescriptor mHdlcSimulationData; 66 | 67 | U64 mSamplesInHalfPeriod; 68 | U64 mSamplesInAFlag; 69 | }; 70 | #endif // HDLC_SIMULATION_DATA_GENERATOR --------------------------------------------------------------------------------