├── .gitignore ├── .gitmodules ├── LICENSE ├── appveyor.yml ├── meson.build ├── scripts ├── travis-install-linux.sh └── travis-install-osx.sh └── source ├── DshotAnalyzer.cpp ├── DshotAnalyzer.h ├── DshotAnalyzerResults.cpp ├── DshotAnalyzerResults.h ├── DshotAnalyzerSettings.cpp ├── DshotAnalyzerSettings.h ├── DshotSimulationDataGenerator.cpp └── DshotSimulationDataGenerator.h /.gitignore: -------------------------------------------------------------------------------- 1 | debug 2 | deploy 3 | release 4 | include 5 | lib 6 | 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sdk"] 2 | path = sdk 3 | url = https://github.com/saleae/AnalyzerSDK.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2020 Michael Corcoran 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 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # we use a custom clone script because appveyor doesn't fetch submodules 2 | clone_script: 3 | # for windows 4 | - cmd: git clone -q --recursive https://github.com/%APPVEYOR_REPO_NAME%.git %APPVEYOR_BUILD_FOLDER% 5 | - cmd: cd %APPVEYOR_BUILD_FOLDER% 6 | - cmd: git checkout -qf %APPVEYOR_REPO_COMMIT% 7 | # for linux/macos 8 | - sh: git clone -q --recursive https://github.com/${APPVEYOR_REPO_NAME}.git ${APPVEYOR_BUILD_FOLDER} 9 | - sh: cd ${APPVEYOR_BUILD_FOLDER} 10 | - sh: git checkout -qf ${APPVEYOR_REPO_COMMIT} 11 | # get the current version 12 | - ps: if($env:APPVEYOR_REPO_TAG -eq "true") {$env:GIT_REV = $env:APPVEYOR_REPO_TAG_NAME} else {$env:GIT_REV = $env:APPVEYOR_REPO_COMMIT} 13 | 14 | environment: 15 | matrix: 16 | - arch: x86 17 | compiler: msvc2019 18 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 19 | REL_PLATFORM: win-x86 20 | - arch: x64 21 | compiler: msvc2019 22 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 23 | REL_PLATFORM: win-x86_64 24 | - arch: x64 25 | APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu 26 | REL_PLATFORM: linux-x86_64 27 | - arch: x64 28 | APPVEYOR_BUILD_WORKER_IMAGE: macOS 29 | REL_PLATFORM: macos-x86_64 30 | 31 | platform: 32 | - x64 33 | 34 | install: 35 | # Set paths to dependencies (based on architecture) 36 | - cmd: if %arch%==x86 (set PYTHON_ROOT=C:\python37) else (set PYTHON_ROOT=C:\python37-x64) 37 | # Print out dependency paths 38 | - cmd: echo Using Python at %PYTHON_ROOT% 39 | # Add necessary paths to PATH variable 40 | - cmd: set PATH=%cd%;%PYTHON_ROOT%;%PYTHON_ROOT%\Scripts;%PATH% 41 | - sh: export PATH=~/venv3.8.1/bin:$PATH 42 | # Install meson and ninja 43 | - pip install ninja meson 44 | # Set up the build environment 45 | - cmd: if %compiler%==msvc2015 ( call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %arch% ) 46 | - cmd: if %compiler%==msvc2017 ( call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" %arch% ) 47 | 48 | build_script: 49 | - cmd: echo Building on %arch% with %compiler% 50 | - sh: echo Building on $arch with $compiler 51 | - meson --backend=ninja builddir 52 | - ninja -C builddir 53 | # zip up the binaries 54 | - cmd: pushd builddir & 7z a -tzip "logic-dshot-%REL_PLATFORM%-%GIT_REV%.zip" "*.dll" && popd & exit 0 55 | - sh: pushd builddir; tar -cvJf logic-dshot-${REL_PLATFORM}-${GIT_REV}.tar.xz $(ls *.so *.dylib 2>/dev/null); popd 56 | 57 | after_build: 58 | - ps: ls builddir 59 | 60 | artifacts: 61 | - path: 'builddir/logic-dshot-*.zip' 62 | - path: 'builddir/logic-dshot-*.tar.xz' 63 | 64 | deploy: 65 | provider: GitHub 66 | description: 'Automatic build' 67 | auth_token: 68 | secure: 3TUmiiZ1SUAb9WChqNzfe58XztZeD/iUposBU5MEfJNdI/sp8kbDJK916gYZW032 69 | draft: true 70 | prerelease: false 71 | force_update: true 72 | on: 73 | appveyor_repo_tag: true 74 | 75 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('DshotAnalyzer', 'cpp', 2 | default_options: ['cpp_std=c++17']) 3 | 4 | cxx = meson.get_compiler('cpp') 5 | 6 | if host_machine.cpu_family() == 'x86_64' and host_machine.system() != 'darwin' 7 | analyzer_name = 'Analyzer64' 8 | else 9 | analyzer_name = 'Analyzer' 10 | endif 11 | 12 | sdk_lib = cxx.find_library(analyzer_name, dirs: meson.current_source_dir() + '/sdk/lib') 13 | 14 | source = [ 15 | 'source/DshotAnalyzer.cpp', 16 | 'source/DshotAnalyzerResults.cpp', 17 | 'source/DshotAnalyzerSettings.cpp', 18 | 'source/DshotSimulationDataGenerator.cpp', 19 | ] 20 | includes = include_directories('source', 'sdk/include') 21 | libs = 'sdk/lib' 22 | shared_library('DShotAnalyzer', source, include_directories: includes, dependencies: sdk_lib) 23 | 24 | -------------------------------------------------------------------------------- /scripts/travis-install-linux.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test 6 | sudo add-apt-repository -y ppa:beineri/opt-qt58-trusty 7 | sudo apt-get update -y 8 | sudo apt-get install -y gcc-5 g++-5 tree qt58qbs 9 | 10 | mkdir -p ~/bin 11 | ln -fs /usr/bin/gcc-5 ~/bin/gcc 12 | ln -fs /usr/bin/g++-5 ~/bin/g++ 13 | 14 | gcc --version 15 | g++ --version 16 | 17 | exit 0 18 | -------------------------------------------------------------------------------- /scripts/travis-install-osx.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | brew update 6 | brew install qbs tree 7 | 8 | clang --version 9 | clang++ --version 10 | 11 | exit 0 12 | -------------------------------------------------------------------------------- /source/DshotAnalyzer.cpp: -------------------------------------------------------------------------------- 1 | #include "DshotAnalyzer.h" 2 | #include "DshotAnalyzerSettings.h" 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | DshotAnalyzer::DshotAnalyzer() 10 | : Analyzer(), 11 | mSettings( new DshotAnalyzerSettings() ), 12 | mSimulationInitilized( false ) 13 | { 14 | SetAnalyzerSettings( mSettings.get() ); 15 | } 16 | 17 | DshotAnalyzer::~DshotAnalyzer() 18 | { 19 | KillThread(); 20 | } 21 | 22 | double DshotAnalyzer::proportionOfBit(U32 width) 23 | { 24 | return static_cast(width) / mSamplesPerBit; 25 | } 26 | 27 | void DshotAnalyzer::WorkerThread() 28 | { 29 | mResults.reset( new DshotAnalyzerResults( this, mSettings.get() ) ); 30 | SetAnalyzerResults( mResults.get() ); 31 | mResults->AddChannelBubblesWillAppearOn( mSettings->mInputChannel ); 32 | 33 | mSampleRateHz = GetSampleRate(); 34 | 35 | mSerial = GetAnalyzerChannelData( mSettings->mInputChannel ); 36 | mSamplesPerBit = mSampleRateHz / (mSettings->mDshotRate * 1000); 37 | 38 | if( mSerial->GetBitState() == BIT_HIGH ) 39 | mSerial->AdvanceToNextEdge(); 40 | 41 | uint32_t width = 0; 42 | 43 | for (;;) { 44 | uint16_t data = 0; 45 | uint64_t starting_sample = 0; 46 | int i; 47 | for (i = sizeof(data) * 8 - 1; i >= 0; i--) { 48 | mSerial->AdvanceToNextEdge(); //rising edge of first bit 49 | uint64_t rising_sample = mSerial->GetSampleNumber(); 50 | if (!starting_sample) 51 | starting_sample = rising_sample; 52 | mSerial->AdvanceToNextEdge(); 53 | uint64_t falling_sample = mSerial->GetSampleNumber(); 54 | 55 | width = falling_sample - rising_sample; 56 | bool set = proportionOfBit(width) > 0.5; 57 | // check if low pulse is too long / next bit is too far away 58 | bool error = i > 0 && proportionOfBit(mSerial->GetSampleOfNextEdge() - falling_sample) > 1.5; 59 | // check if high pulse is too short 60 | error |= proportionOfBit(width) < 0.2; 61 | 62 | if (set) 63 | data |= 1 << i; 64 | 65 | AnalyzerResults::MarkerType marker; 66 | if (error) { 67 | marker = AnalyzerResults::ErrorX; 68 | } else if (i == 4) { // telem request 69 | if (set) 70 | marker = AnalyzerResults::Start; 71 | else 72 | marker = AnalyzerResults::Stop; 73 | } else { // channel bits or crc 74 | if (set) 75 | marker = AnalyzerResults::One; 76 | else 77 | marker = AnalyzerResults::Zero; 78 | } 79 | mResults->AddMarker(rising_sample + width / 2, marker, mSettings->mInputChannel); 80 | 81 | if (error) 82 | break; 83 | } 84 | 85 | if (i >= 0) { // message ended early / bit was errored 86 | mResults->CommitResults(); 87 | continue; 88 | } 89 | 90 | uint16_t chan = data & 0xffe0; 91 | uint8_t crc = ((chan >> 4 ) & 0xf) ^ 92 | ((chan >> 8 ) & 0xf) ^ 93 | ((chan >> 12) & 0xf); 94 | bool crcok = (data & 0xf) == crc; 95 | chan >>= 5; 96 | 97 | mSerial->Advance(mSamplesPerBit - width); // end of low pulse 98 | 99 | if (!crcok) 100 | mResults->AddMarker(mSerial->GetSampleNumber(), AnalyzerResults::ErrorX, mSettings->mInputChannel); 101 | 102 | //we have a byte to save. 103 | Frame frame; 104 | frame.mData1 = chan; 105 | frame.mFlags = (crcok ? 0 : DISPLAY_AS_ERROR_FLAG) | ((data & 0x10) > 0); // error flag | telem request 106 | frame.mStartingSampleInclusive = starting_sample; 107 | frame.mEndingSampleInclusive = mSerial->GetSampleNumber(); 108 | 109 | mResults->AddFrame(frame); 110 | mResults->CommitResults(); 111 | ReportProgress(frame.mEndingSampleInclusive); 112 | } 113 | } 114 | 115 | bool DshotAnalyzer::NeedsRerun() 116 | { 117 | return false; 118 | } 119 | 120 | U32 DshotAnalyzer::GenerateSimulationData( U64 minimum_sample_index, U32 device_sample_rate, SimulationChannelDescriptor** simulation_channels ) 121 | { 122 | if( mSimulationInitilized == false ) 123 | { 124 | mSimulationDataGenerator.Initialize( GetSimulationSampleRate(), mSettings.get() ); 125 | mSimulationInitilized = true; 126 | } 127 | 128 | return mSimulationDataGenerator.GenerateSimulationData( minimum_sample_index, device_sample_rate, simulation_channels ); 129 | } 130 | 131 | U32 DshotAnalyzer::GetMinimumSampleRateHz() 132 | { 133 | return mSettings->mDshotRate * 4000; 134 | } 135 | 136 | const char* DshotAnalyzer::GetAnalyzerName() const 137 | { 138 | return "Dshot"; 139 | } 140 | 141 | const char* GetAnalyzerName() 142 | { 143 | return "Dshot"; 144 | } 145 | 146 | Analyzer* CreateAnalyzer() 147 | { 148 | return new DshotAnalyzer(); 149 | } 150 | 151 | void DestroyAnalyzer( Analyzer* analyzer ) 152 | { 153 | delete analyzer; 154 | } -------------------------------------------------------------------------------- /source/DshotAnalyzer.h: -------------------------------------------------------------------------------- 1 | #ifndef DSHOT_ANALYZER_H 2 | #define DSHOT_ANALYZER_H 3 | 4 | #include 5 | #include "DshotAnalyzerResults.h" 6 | #include "DshotSimulationDataGenerator.h" 7 | 8 | class DshotAnalyzerSettings; 9 | class ANALYZER_EXPORT DshotAnalyzer : public Analyzer 10 | { 11 | public: 12 | DshotAnalyzer(); 13 | virtual ~DshotAnalyzer(); 14 | virtual void WorkerThread(); 15 | 16 | virtual U32 GenerateSimulationData( U64 newest_sample_requested, U32 sample_rate, SimulationChannelDescriptor** simulation_channels ); 17 | virtual U32 GetMinimumSampleRateHz(); 18 | 19 | virtual const char* GetAnalyzerName() const; 20 | virtual bool NeedsRerun(); 21 | 22 | protected: //vars 23 | std::unique_ptr< DshotAnalyzerSettings > mSettings; 24 | std::unique_ptr< DshotAnalyzerResults > mResults; 25 | AnalyzerChannelData* mSerial; 26 | 27 | DshotSimulationDataGenerator mSimulationDataGenerator; 28 | bool mSimulationInitilized; 29 | 30 | //Serial analysis vars: 31 | U32 mSampleRateHz; 32 | U32 mSamplesPerBit; 33 | U32 mStartOfStopBitOffset; 34 | U32 mEndOfStopBitOffset; 35 | 36 | double proportionOfBit(U32 width); 37 | }; 38 | 39 | extern "C" ANALYZER_EXPORT const char* __cdecl GetAnalyzerName(); 40 | extern "C" ANALYZER_EXPORT Analyzer* __cdecl CreateAnalyzer( ); 41 | extern "C" ANALYZER_EXPORT void __cdecl DestroyAnalyzer( Analyzer* analyzer ); 42 | 43 | #endif //DSHOT_ANALYZER_H 44 | -------------------------------------------------------------------------------- /source/DshotAnalyzerResults.cpp: -------------------------------------------------------------------------------- 1 | #include "DshotAnalyzerResults.h" 2 | #include 3 | #include "DshotAnalyzer.h" 4 | #include "DshotAnalyzerSettings.h" 5 | #include 6 | #include 7 | 8 | DshotAnalyzerResults::DshotAnalyzerResults( DshotAnalyzer* analyzer, DshotAnalyzerSettings* settings ) 9 | : AnalyzerResults(), 10 | mSettings( settings ), 11 | mAnalyzer( analyzer ) 12 | { 13 | } 14 | 15 | DshotAnalyzerResults::~DshotAnalyzerResults() 16 | { 17 | } 18 | 19 | void DshotAnalyzerResults::GenerateBubbleText( U64 frame_index, Channel& channel, DisplayBase display_base ) 20 | { 21 | ClearResultStrings(); 22 | Frame frame = GetFrame(frame_index); 23 | 24 | char number_str[128]; 25 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 11, number_str, 128); 26 | const char *telem_str = frame.mFlags & 1 ? " (telem req.)" : ""; 27 | const char *error_str = frame.mFlags & DISPLAY_AS_ERROR_FLAG ? "!" : ""; 28 | 29 | // widest display 30 | AddResultString(error_str, number_str, telem_str); 31 | // middle 32 | AddResultString(error_str, number_str); 33 | // shortest 34 | if (frame.mFlags & DISPLAY_AS_ERROR_FLAG) 35 | AddResultString(error_str); 36 | else 37 | AddResultString(number_str); 38 | } 39 | 40 | void DshotAnalyzerResults::GenerateExportFile( const char* file, DisplayBase display_base, U32 export_type_user_id ) 41 | { 42 | std::ofstream file_stream( file, std::ios::out ); 43 | 44 | U64 trigger_sample = mAnalyzer->GetTriggerSample(); 45 | U32 sample_rate = mAnalyzer->GetSampleRate(); 46 | 47 | file_stream << "Time [s],Value" << std::endl; 48 | 49 | U64 num_frames = GetNumFrames(); 50 | for( U32 i=0; i < num_frames; i++ ) 51 | { 52 | Frame frame = GetFrame( i ); 53 | 54 | char time_str[128]; 55 | AnalyzerHelpers::GetTimeString( frame.mStartingSampleInclusive, trigger_sample, sample_rate, time_str, 128 ); 56 | 57 | char number_str[128]; 58 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 11, number_str, 128); 59 | 60 | file_stream << time_str << "," << number_str << std::endl; 61 | 62 | if( UpdateExportProgressAndCheckForCancel( i, num_frames ) == true ) 63 | { 64 | file_stream.close(); 65 | return; 66 | } 67 | } 68 | 69 | file_stream.close(); 70 | } 71 | 72 | void DshotAnalyzerResults::GenerateFrameTabularText( U64 frame_index, DisplayBase display_base ) 73 | { 74 | Frame frame = GetFrame( frame_index ); 75 | ClearResultStrings(); 76 | 77 | char number_str[128]; 78 | AnalyzerHelpers::GetNumberString(frame.mData1, display_base, 11, number_str, 128); 79 | AddResultString( number_str ); 80 | } 81 | 82 | void DshotAnalyzerResults::GeneratePacketTabularText( U64 packet_id, DisplayBase display_base ) 83 | { 84 | ClearResultStrings(); 85 | AddResultString( "not supported" ); 86 | } 87 | 88 | void DshotAnalyzerResults::GenerateTransactionTabularText( U64 transaction_id, DisplayBase display_base ) 89 | { 90 | ClearResultStrings(); 91 | AddResultString( "not supported" ); 92 | } -------------------------------------------------------------------------------- /source/DshotAnalyzerResults.h: -------------------------------------------------------------------------------- 1 | #ifndef DSHOT_ANALYZER_RESULTS 2 | #define DSHOT_ANALYZER_RESULTS 3 | 4 | #include 5 | 6 | class DshotAnalyzer; 7 | class DshotAnalyzerSettings; 8 | 9 | class DshotAnalyzerResults : public AnalyzerResults 10 | { 11 | public: 12 | DshotAnalyzerResults( DshotAnalyzer* analyzer, DshotAnalyzerSettings* settings ); 13 | virtual ~DshotAnalyzerResults(); 14 | 15 | virtual void GenerateBubbleText( U64 frame_index, Channel& channel, DisplayBase display_base ); 16 | virtual void GenerateExportFile( const char* file, DisplayBase display_base, U32 export_type_user_id ); 17 | 18 | virtual void GenerateFrameTabularText(U64 frame_index, DisplayBase display_base ); 19 | virtual void GeneratePacketTabularText( U64 packet_id, DisplayBase display_base ); 20 | virtual void GenerateTransactionTabularText( U64 transaction_id, DisplayBase display_base ); 21 | 22 | protected: //functions 23 | 24 | protected: //vars 25 | DshotAnalyzerSettings* mSettings; 26 | DshotAnalyzer* mAnalyzer; 27 | }; 28 | 29 | #endif //DSHOT_ANALYZER_RESULTS 30 | -------------------------------------------------------------------------------- /source/DshotAnalyzerSettings.cpp: -------------------------------------------------------------------------------- 1 | #include "DshotAnalyzerSettings.h" 2 | #include 3 | 4 | 5 | DshotAnalyzerSettings::DshotAnalyzerSettings() 6 | : mInputChannel( UNDEFINED_CHANNEL ), 7 | mDshotRate( 300 ) 8 | { 9 | mInputChannelInterface.reset( new AnalyzerSettingInterfaceChannel() ); 10 | mInputChannelInterface->SetTitleAndTooltip( "Serial", "Standard Dshot" ); 11 | mInputChannelInterface->SetChannel( mInputChannel ); 12 | 13 | mDshotRateInterface.reset( new AnalyzerSettingInterfaceNumberList() ); 14 | mDshotRateInterface->SetTitleAndTooltip( "Bit Rate (kbits/s)", "Specify the bit rate in kbits per second." ); 15 | mDshotRateInterface->ClearNumbers(); 16 | mDshotRateInterface->AddNumber(150, "Dshot150", "150 kbit/s"); 17 | mDshotRateInterface->AddNumber(300, "Dshot300", "300 kbit/s"); 18 | mDshotRateInterface->AddNumber(600, "Dshot600", "600 kbit/s"); 19 | mDshotRateInterface->AddNumber(1200, "Dshot1200", "1200 kbit/s"); 20 | mDshotRateInterface->SetNumber(mDshotRate); 21 | 22 | AddInterface( mInputChannelInterface.get() ); 23 | AddInterface( mDshotRateInterface.get() ); 24 | 25 | AddExportOption( 0, "Export as text/csv file" ); 26 | AddExportExtension( 0, "text", "txt" ); 27 | AddExportExtension( 0, "csv", "csv" ); 28 | 29 | ClearChannels(); 30 | AddChannel( mInputChannel, "Serial", false ); 31 | } 32 | 33 | DshotAnalyzerSettings::~DshotAnalyzerSettings() 34 | { 35 | } 36 | 37 | bool DshotAnalyzerSettings::SetSettingsFromInterfaces() 38 | { 39 | mInputChannel = mInputChannelInterface->GetChannel(); 40 | mDshotRate = mDshotRateInterface->GetNumber(); 41 | 42 | ClearChannels(); 43 | AddChannel( mInputChannel, "Dshot", true ); 44 | 45 | return true; 46 | } 47 | 48 | void DshotAnalyzerSettings::UpdateInterfacesFromSettings() 49 | { 50 | mInputChannelInterface->SetChannel( mInputChannel ); 51 | mDshotRateInterface->SetNumber(mDshotRate); 52 | } 53 | 54 | void DshotAnalyzerSettings::LoadSettings( const char* settings ) 55 | { 56 | SimpleArchive text_archive; 57 | text_archive.SetString( settings ); 58 | 59 | text_archive >> mInputChannel; 60 | text_archive >> mDshotRate; 61 | 62 | ClearChannels(); 63 | AddChannel( mInputChannel, "Dshot", true ); 64 | 65 | UpdateInterfacesFromSettings(); 66 | } 67 | 68 | const char* DshotAnalyzerSettings::SaveSettings() 69 | { 70 | SimpleArchive text_archive; 71 | 72 | text_archive << mInputChannel; 73 | text_archive << mDshotRate; 74 | 75 | return SetReturnString( text_archive.GetString() ); 76 | } 77 | -------------------------------------------------------------------------------- /source/DshotAnalyzerSettings.h: -------------------------------------------------------------------------------- 1 | #ifndef DSHOT_ANALYZER_SETTINGS 2 | #define DSHOT_ANALYZER_SETTINGS 3 | 4 | #include 5 | #include 6 | 7 | class DshotAnalyzerSettings : public AnalyzerSettings 8 | { 9 | public: 10 | DshotAnalyzerSettings(); 11 | virtual ~DshotAnalyzerSettings(); 12 | 13 | virtual bool SetSettingsFromInterfaces(); 14 | void UpdateInterfacesFromSettings(); 15 | virtual void LoadSettings( const char* settings ); 16 | virtual const char* SaveSettings(); 17 | 18 | Channel mInputChannel; 19 | U32 mDshotRate; 20 | 21 | protected: 22 | std::unique_ptr< AnalyzerSettingInterfaceChannel > mInputChannelInterface; 23 | std::unique_ptr< AnalyzerSettingInterfaceNumberList > mDshotRateInterface; 24 | }; 25 | 26 | #endif //DSHOT_ANALYZER_SETTINGS 27 | -------------------------------------------------------------------------------- /source/DshotSimulationDataGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "DshotSimulationDataGenerator.h" 2 | #include "DshotAnalyzerSettings.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | DshotSimulationDataGenerator::DshotSimulationDataGenerator() : 10 | mChannelRadians(0) 11 | { 12 | } 13 | 14 | DshotSimulationDataGenerator::~DshotSimulationDataGenerator() 15 | { 16 | } 17 | 18 | void DshotSimulationDataGenerator::Initialize( U32 simulation_sample_rate, DshotAnalyzerSettings* settings ) 19 | { 20 | mSimulationSampleRateHz = simulation_sample_rate; 21 | mSettings = settings; 22 | 23 | mSerialSimulationData.SetChannel( mSettings->mInputChannel ); 24 | mSerialSimulationData.SetSampleRate( simulation_sample_rate ); 25 | mSerialSimulationData.SetInitialBitState( BIT_HIGH ); 26 | } 27 | 28 | U32 DshotSimulationDataGenerator::GenerateSimulationData( U64 largest_sample_requested, U32 sample_rate, SimulationChannelDescriptor** simulation_channel ) 29 | { 30 | U64 adjusted_largest_sample_requested = AnalyzerHelpers::AdjustSimulationTargetSample( largest_sample_requested, sample_rate, mSimulationSampleRateHz ); 31 | 32 | while(mSerialSimulationData.GetCurrentSampleNumber() < adjusted_largest_sample_requested) 33 | CreateChannelUpdate(); 34 | 35 | *simulation_channel = &mSerialSimulationData; 36 | return 1; 37 | } 38 | 39 | void DshotSimulationDataGenerator::CreateChannelUpdate() 40 | { 41 | uint32_t samples_per_bit = mSimulationSampleRateHz / (mSettings->mDshotRate * 1000); 42 | 43 | uint16_t channel = 0; 44 | 45 | uint16_t chan_val = (2047.0 / 2.0) + (2047.0 / 2.0) * std::sin(mChannelRadians); 46 | bool telem = chan_val > 2045; 47 | chan_val <<= 5; 48 | uint8_t crc = ((chan_val >> 4 ) & 0xf) ^ 49 | ((chan_val >> 8 ) & 0xf) ^ 50 | ((chan_val >> 12) & 0xf); 51 | 52 | channel |= chan_val; 53 | channel |= (telem & 1) << 4; 54 | channel |= (crc & 0xf); 55 | mChannelRadians += 0.1; // TODO: set frequency 56 | 57 | mSerialSimulationData.TransitionIfNeeded(BIT_LOW); 58 | mSerialSimulationData.Advance(samples_per_bit * 10); 59 | 60 | U32 width = 1e6 / mSettings->mDshotRate; 61 | uint32_t dshot_true = 0.75 * width; 62 | uint32_t dshot_false = 0.375 * dshot_true; 63 | for (int i = sizeof(channel) * 8 - 1; i >= 0; i--) { 64 | uint32_t high = (channel & 1 << i) ? dshot_true : dshot_false; 65 | uint32_t low = width - high; 66 | mSerialSimulationData.TransitionIfNeeded(BIT_HIGH); 67 | mSerialSimulationData.Advance(static_cast(mSimulationSampleRateHz) * (high * 1e-9)); 68 | mSerialSimulationData.TransitionIfNeeded(BIT_LOW); 69 | mSerialSimulationData.Advance(static_cast(mSimulationSampleRateHz) * (low * 1e-9)); 70 | } 71 | 72 | //lets pad the end a bit for the stop bit: 73 | mSerialSimulationData.Advance(samples_per_bit); 74 | } 75 | -------------------------------------------------------------------------------- /source/DshotSimulationDataGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef DSHOT_SIMULATION_DATA_GENERATOR 2 | #define DSHOT_SIMULATION_DATA_GENERATOR 3 | 4 | #include 5 | #include 6 | class DshotAnalyzerSettings; 7 | 8 | class DshotSimulationDataGenerator 9 | { 10 | public: 11 | DshotSimulationDataGenerator(); 12 | ~DshotSimulationDataGenerator(); 13 | 14 | void Initialize( U32 simulation_sample_rate, DshotAnalyzerSettings* settings ); 15 | U32 GenerateSimulationData( U64 newest_sample_requested, U32 sample_rate, SimulationChannelDescriptor** simulation_channel ); 16 | 17 | protected: 18 | DshotAnalyzerSettings* mSettings; 19 | U32 mSimulationSampleRateHz; 20 | 21 | protected: 22 | void CreateChannelUpdate(); 23 | 24 | double mChannelRadians; 25 | SimulationChannelDescriptor mSerialSimulationData; 26 | 27 | }; 28 | #endif //DSHOT_SIMULATION_DATA_GENERATOR --------------------------------------------------------------------------------