diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 90b0888..e7d5fbd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,14 +2,14 @@ name: Build on: push: - branches: [master] + branches: [master, main] tags: - '*' pull_request: - branches: [master] + branches: [master, main] jobs: - windows: + windows-x86_64: runs-on: windows-latest steps: - uses: actions/checkout@v4 @@ -17,10 +17,23 @@ jobs: run: | cmake -B ${{github.workspace}}/build -A x64 cmake --build ${{github.workspace}}/build --config Release - - name: Upload windows build + - name: Upload windows x86_64 build uses: actions/upload-artifact@v4 with: - name: windows + name: windows_x86_64 + path: ${{github.workspace}}/build/Analyzers/Release/*.dll + windows-arm64: + runs-on: windows-11-arm + steps: + - uses: actions/checkout@v4 + - name: Build + run: | + cmake -B ${{github.workspace}}/build -A ARM64 + cmake --build ${{github.workspace}}/build --config Release + - name: Upload windows arm64 build + uses: actions/upload-artifact@v4 + with: + name: windows_arm64 path: ${{github.workspace}}/build/Analyzers/Release/*.dll macos: runs-on: macos-latest @@ -42,24 +55,44 @@ jobs: with: name: macos_arm64 path: ${{github.workspace}}/build/arm64/Analyzers/*.so - linux: + linux-x86_64: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Build + - name: Pull pre-built builder image + run: docker pull ghcr.io/saleae/analyzer-build-image:linux-x86_64 + - name: Build inside container + run: | + docker run --rm \ + -v ${{ github.workspace }}:/app \ + -w /app \ + ghcr.io/saleae/analyzer-build-image:linux-x86_64 \ + bash -c 'cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build' + - name: Upload Linux x86_64 build + uses: actions/upload-artifact@v4 + with: + name: linux_x86_64 + path: ${{github.workspace}}/build/Analyzers/*.so + linux-arm64: + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/checkout@v4 + - name: Pull pre-built builder image + run: docker pull ghcr.io/saleae/analyzer-build-image:linux-arm64 + - name: Build inside container run: | - cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release - cmake --build ${{github.workspace}}/build - env: - CC: gcc-10 - CXX: g++-10 - - name: Upload Linux build + docker run --rm \ + -v ${{ github.workspace }}:/app \ + -w /app \ + ghcr.io/saleae/analyzer-build-image:linux-arm64 \ + bash -c 'cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build' + - name: Upload Linux arm64 build uses: actions/upload-artifact@v4 with: - name: linux + name: linux_arm64 path: ${{github.workspace}}/build/Analyzers/*.so publish: - needs: [windows, macos, linux] + needs: [windows-x86_64, windows-arm64, macos, linux-x86_64, linux-arm64] runs-on: ubuntu-latest steps: - name: download individual builds @@ -78,4 +111,4 @@ jobs: uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') with: - files: ${{github.workspace}}/analyzer.zip \ No newline at end of file + files: ${{github.workspace}}/analyzer.zip diff --git a/CMakeLists.txt b/CMakeLists.txt index ef4a440..ccaaf41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,8 @@ project(SimpleSerialAnalyzer) add_definitions( -DLOGIC2 ) +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum supported MacOS version" FORCE) + # enable generation of compile_commands.json, helpful for IDEs to locate include files. set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/docs/Analyzer_API.md b/docs/Analyzer_API.md index 18a044c..d375c0e 100644 --- a/docs/Analyzer_API.md +++ b/docs/Analyzer_API.md @@ -1,96 +1,96 @@ # C++ Analyzer API -- [C++ Analyzer API](#c---analyzer-api) - * [Writing your Analyzer’s Code](#writing-your-analyzer-s-code) +- [C++ Analyzer API](#c-analyzer-api) + * [Writing your Analyzer’s Code](#writing-your-analyzers-code) - [Analyzer Settings](#analyzer-settings) - * [{YourName}AnalyzerSettings.h](#-yourname-analyzersettingsh) + * [{YourName}AnalyzerSettings.h](#yournameanalyzersettingsh) + [User-modifiable Analyzer Settings](#user-modifiable-analyzer-settings) + [Analyzer Settings Interfaces Objects](#analyzer-settings-interfaces-objects) - * [{YourName}AnalyzerSettings.cpp](#-yourname-analyzersettingscpp) + * [{YourName}AnalyzerSettings.cpp](#yournameanalyzersettingscpp) + [The Constructor](#the-constructor) + [Setting up each AnalyzerSettingInterface object](#setting-up-each-analyzersettinginterface-object) - - [```AnalyzerSettingInterface``` Object Options](#---analyzersettinginterface----object-options) - * [```AnalyzerSettingInterfaceChannel```](#---analyzersettinginterfacechannel---) - * [```AnalyzerSettingInterfaceNumberList```](#---analyzersettinginterfacenumberlist---) - * [```AnalyzerSettingInterfaceInteger```](#---analyzersettinginterfaceinteger---) - * [```AnalyzerSettingInterfaceText```](#---analyzersettinginterfacetext---) - * [```AnalyzerSettingInterfaceBool```](#---analyzersettinginterfacebool---) + - [```AnalyzerSettingInterface``` Object Options](#analyzersettinginterface-object-options) + * [```AnalyzerSettingInterfaceChannel```](#analyzersettinginterfacechannel) + * [```AnalyzerSettingInterfaceNumberList```](#analyzersettinginterfacenumberlist) + * [```AnalyzerSettingInterfaceInteger```](#analyzersettinginterfaceinteger) + * [```AnalyzerSettingInterfaceText```](#analyzersettinginterfacetext) + * [```AnalyzerSettingInterfaceBool```](#analyzersettinginterfacebool) + [Specifying Export Options](#specifying-export-options) + [Specifying which channels are in use](#specifying-which-channels-are-in-use) + [AnalyzerSettings Destructor](#analyzersettings-destructor) - + [```{YourName}AnalyzerSettings::SetSettingsFromInterfaces()```](#----yourname-analyzersettings--setsettingsfrominterfaces-----) - + [```{YourName}AnalyzerSettings::UpdateInterfacesFromSettings()```](#----yourname-analyzersettings--updateinterfacesfromsettings-----) - + [```{YourName}AnalyzerSettings::LoadSettings()```](#----yourname-analyzersettings--loadsettings-----) - + [```{YourName}AnalyzerSettings::SaveSettings()```](#----yourname-analyzersettings--savesettings-----) -- [```AnalyzerResults```](#---analyzerresults---) - * [{YourName}AnalyzerResults.h](#-yourname-analyzerresultsh) - * [{YourName}AnalyzerResults.cpp](#-yourname-analyzerresultscpp) - * [Frames, Packets, and Transactions](#frames--packets--and-transactions) + + [```{YourName}AnalyzerSettings::SetSettingsFromInterfaces()```](#yournameanalyzersettingssetsettingsfrominterfaces) + + [```{YourName}AnalyzerSettings::UpdateInterfacesFromSettings()```](#yournameanalyzersettingsupdateinterfacesfromsettings) + + [```{YourName}AnalyzerSettings::LoadSettings()```](#yournameanalyzersettingsloadsettings) + + [```{YourName}AnalyzerSettings::SaveSettings()```](#yournameanalyzersettingssavesettings) +- [```AnalyzerResults```](#analyzerresults) + * [{YourName}AnalyzerResults.h](#yournameanalyzerresultsh) + * [{YourName}AnalyzerResults.cpp](#yournameanalyzerresultscpp) + * [Frames, Packets, and Transactions](#frames-packets-and-transactions) + [Frame](#frame) - [Frame Member Variables](#frame-member-variables) - + [```{YourName}AnalyzerResults::GenerateBubbleText()```](#----yourname-analyzerresults--generatebubbletext-----) - + [```{YourName}AnalyzerResults::GenerateExportFile()```](#----yourname-analyzerresults--generateexportfile-----) - + [```SerialAnalyzerResults::GenerateFrameTabularText()```](#---serialanalyzerresults--generateframetabulartext-----) - + [```SerialAnalyzerResults::GeneratePacketTabularText()```](#---serialanalyzerresults--generatepackettabulartext-----) - + [```SerialAnalyzerResults::GenerateTransactionTabularText()```](#---serialanalyzerresults--generatetransactiontabulartext-----) + + [```{YourName}AnalyzerResults::GenerateBubbleText()```](#yournameanalyzerresultsgeneratebubbletext) + + [```{YourName}AnalyzerResults::GenerateExportFile()```](#yournameanalyzerresultsgenerateexportfile) + + [```{YourName}AnalyzerResults::GenerateFrameTabularText()```](#yournameanalyzerresultsgenerateframetabulartext) + + [```{YourName}AnalyzerResults::GeneratePacketTabularText()```](#yournameanalyzerresultsgeneratepackettabulartext) + + [```{YourName}AnalyzerResults::GenerateTransactionTabularText()```](#yournameanalyzerresultsgeneratetransactiontabulartext) - [Analyzer](#analyzer) - * [{YourName}Analyzer.h](#-yourname-analyzerh) - * [{YourName}Analyzer.cpp](#-yourname-analyzercpp) + * [{YourName}Analyzer.h](#yournameanalyzerh) + * [{YourName}Analyzer.cpp](#yournameanalyzercpp) * [Constructor](#constructor) * [Destructor](#destructor) - * [```{YourName}Analyzer::WorkerThread()```](#----yourname-analyzer--workerthread-----) - * [```bool {YourName}Analyzer::NeedsRerun()```](#---bool--yourname-analyzer--needsrerun-----) - * [```Analyzer::GenerateSimulationData()```](#---analyzer--generatesimulationdata-----) - * [```U32 SerialAnalyzer::GetMinimumSampleRateHz()```](#---u32-serialanalyzer--getminimumsampleratehz-----) - * [```{YourName}Analyzer::GetAnalyzerName()```](#----yourname-analyzer--getanalyzername-----) - * [```GetAnalyzerName()```](#---getanalyzername-----) - * [```Analyzer* CreateAnalyzer()```](#---analyzer--createanalyzer-----) - * [```DestroyAnalyzer( Analyzer* analyzer )```](#---destroyanalyzer--analyzer--analyzer-----) - * [```{YourName}Analyzer::WorkerThread()```](#----yourname-analyzer--workerthread------1) + * [```{YourName}Analyzer::WorkerThread()```](#yournameanalyzerworkerthread) + * [```bool {YourName}Analyzer::NeedsRerun()```](#bool-yournameanalyzerneedsrerun) + * [```{YourName}Analyzer::GenerateSimulationData()```](#yournameanalyzergeneratesimulationdata) + * [```U32 {YourName}Analyzer::GetMinimumSampleRateHz()```](#u32-yournameanalyzergetminimumsampleratehz) + * [```{YourName}Analyzer::GetAnalyzerName()```](#yournameanalyzergetanalyzername) + * [```GetAnalyzerName()```](#getanalyzername) + * [```Analyzer* CreateAnalyzer()```](#analyzer-createanalyzer) + * [```DestroyAnalyzer( Analyzer* analyzer )```](#destroyanalyzer-analyzer-analyzer-) + * [```{YourName}Analyzer::WorkerThread()```](#yournameanalyzerworkerthread-1) - [Traversing the Data](#traversing-the-data) - * [```AnalyzerChannelData```](#---analyzerchanneldata---) - + [```AnalyzerChannelData ```– State](#---analyzerchanneldata------state) - + [```AnalyzerChannelData ```– Basic Traversal](#---analyzerchanneldata------basic-traversal) - + [```AnalyzerChannelData ```– Advanced Traversal (looking ahead without moving)](#---analyzerchanneldata------advanced-traversal--looking-ahead-without-moving-) - + [```AnalyzerChannelData ```– Keeping track of the smallest pulse.](#---analyzerchanneldata------keeping-track-of-the-smallest-pulse) + * [```AnalyzerChannelData```](#analyzerchanneldata) + + [```AnalyzerChannelData ```– State](#analyzerchanneldata---state) + + [```AnalyzerChannelData ```– Basic Traversal](#analyzerchanneldata---basic-traversal) + + [```AnalyzerChannelData ```– Advanced Traversal (looking ahead without moving)](#analyzerchanneldata---advanced-traversal-looking-ahead-without-moving) + + [```AnalyzerChannelData ```– Keeping track of the smallest pulse.](#analyzerchanneldata---keeping-track-of-the-smallest-pulse) * [Filling in Frames](#filling-in-frames) * [Saving Frames](#saving-frames) * [Adding Markers](#adding-markers) * [Packets and Transactions](#packets-and-transactions) - [Utilities](#utilities) - * [```BitExtractor```](#---bitextractor---) - * [```DataBuilder```](#---databuilder---) -- [```AnalyzerHelpers```](#---analyzerhelpers---) - * [```DisplayBase```](#---displaybase---) - * [```GetNumberString()```](#---getnumberstring-----) - * [```GetTimeString()```](#---gettimestring-----) -- [```SimulationDataGenerator```](#---simulationdatagenerator---) - * [{YourName}SimulationDataGenerator.cpp](#-yourname-simulationdatageneratorcpp) - + [Constructor/Destructor](#constructor-destructor) - + [```{YourName}SimulationDataGenerator::Initialize()```](#----yourname-simulationdatagenerator--initialize-----) - - [```BitState```](#---bitstate---) - - [Sample Rate (samples per second)](#sample-rate--samples-per-second-) + * [```BitExtractor```](#bitextractor) + * [```DataBuilder```](#databuilder) +- [```AnalyzerHelpers```](#analyzerhelpers) + * [```DisplayBase```](#displaybase) + * [```GetNumberString()```](#getnumberstring) + * [```GetTimeString()```](#gettimestring) +- [```SimulationDataGenerator```](#simulationdatagenerator) + * [{YourName}SimulationDataGenerator.cpp](#yournamesimulationdatageneratorcpp) + + [Constructor/Destructor](#constructordestructor) + + [```{YourName}SimulationDataGenerator::Initialize()```](#yournamesimulationdatageneratorinitialize) + - [```BitState```](#bitstate) + - [Sample Rate (samples per second)](#sample-rate-samples-per-second) - [Sample Number](#sample-number) - + [```SimulationChannelDescriptor```](#---simulationchanneldescriptor---) - - [```Advance()```](#---advance-----) - - [```Transition()```](#---transition-----) - - [```TransitionIfNeeded()```](#---transitionifneeded-----) - - [```GetCurrentBitState()```](#---getcurrentbitstate-----) - - [```GetCurrentSampleNumber()```](#---getcurrentsamplenumber-----) - - [```ClockGenerator```](#---clockgenerator---) - - [```Init( double target_frequency, U32 sample_rate_hz );```](#---init--double-target-frequency--u32-sample-rate-hz------) - - [```AdvanceByHalfPeriod( double multiple = 1.0 );```](#---advancebyhalfperiod--double-multiple---10------) - - [```AdvanceByTimeS( double time_s );```](#---advancebytimes--double-time-s------) - + [```{YourName}SimulationDataGenerator::Initialize()```](#----yourname-simulationdatagenerator--initialize------1) - + [```{YourName}SimulationDataGenerator::GenerateSimulationData()```](#----yourname-simulationdatagenerator--generatesimulationdata-----) + + [```SimulationChannelDescriptor```](#simulationchanneldescriptor) + - [```Advance()```](#advance) + - [```Transition()```](#transition) + - [```TransitionIfNeeded()```](#transitionifneeded) + - [```GetCurrentBitState()```](#getcurrentbitstate) + - [```GetCurrentSampleNumber()```](#getcurrentsamplenumber) + - [```ClockGenerator```](#clockgenerator) + - [```Init( double target_frequency, U32 sample_rate_hz );```](#init-double-target_frequency-u32-sample_rate_hz-) + - [```AdvanceByHalfPeriod( double multiple = 1.0 );```](#advancebyhalfperiod-double-multiple--10-) + - [```AdvanceByTimeS( double time_s );```](#advancebytimes-double-time_s-) + + [```{YourName}SimulationDataGenerator::Initialize()```](#yournamesimulationdatageneratorinitialize-1) + + [```{YourName}SimulationDataGenerator::GenerateSimulationData()```](#yournamesimulationdatageneratorgeneratesimulationdata) * [Simulating Multiple Channels](#simulating-multiple-channels) + [Examples of generating simulation data](#examples-of-generating-simulation-data) - - [```SerialSimulationDataGenerator::CreateSerialByte()```](#---serialsimulationdatagenerator--createserialbyte-----) - - [```I2cSimulationDataGenerator::CreateBit()```](#---i2csimulationdatagenerator--createbit-----) - - [```I2cSimulationDataGenerator::CreateI2cTransaction()```](#---i2csimulationdatagenerator--createi2ctransaction-----) - - [```SpiSimulationDataGenerator::OutputWord_CPHA1()```](#---spisimulationdatagenerator--outputword-cpha1-----) - - [```SpiSimulationDataGenerator::CreateSpiTransaction()```](#---spisimulationdatagenerator--createspitransaction-----) - - [```SpiSimulationDataGenerator::GenerateSimulationData()```](#---spisimulationdatagenerator--generatesimulationdata-----) + - [```SerialSimulationDataGenerator::CreateSerialByte()```](#serialsimulationdatageneratorcreateserialbyte) + - [```I2cSimulationDataGenerator::CreateBit()```](#i2csimulationdatageneratorcreatebit) + - [```I2cSimulationDataGenerator::CreateI2cTransaction()```](#i2csimulationdatageneratorcreatei2ctransaction) + - [```SpiSimulationDataGenerator::OutputWord_CPHA1()```](#spisimulationdatageneratoroutputword_cpha1) + - [```SpiSimulationDataGenerator::CreateSpiTransaction()```](#spisimulationdatageneratorcreatespitransaction) + - [```SpiSimulationDataGenerator::GenerateSimulationData()```](#spisimulationdatageneratorgeneratesimulationdata) This is the original documentation for the Saleae C++ Analyzer API. It has not been updated since the original release, and some parts are out of date. Please refer to support, as well as Saleae's other open source protocol analyzers for reference. Changes that need to be reflected in this documentation: diff --git a/readme.md b/readme.md index e9d0663..1e38970 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,7 @@ - [Saleae Analyzer SDK Sample Analyzer](#saleae-analyzer-sdk-sample-analyzer) - [Renaming your Analyzer](#renaming-your-analyzer) - [Cloud Building & Publishing](#cloud-building--publishing) - - [Apple Silicon Support](#apple-silicon-support) + - [ARM64 Support](#arm64-support) - [Prerequisites](#prerequisites) - [Windows](#windows) - [MacOS](#macos) @@ -49,7 +49,7 @@ API documentation can be found in [docs/Analyzer_API.md](docs/Analyzer_API.md). This example repository includes support for GitHub actions, which is a continuous integration service from GitHub. The file located at `.github\workflows\build.yml` contains the configuration. -When building in CI, the release version of the analyzer is built for Windows, Linux, and MacOS. The built analyzer files are available for every CI build. Additionally, GitHub releases are automatically created for any tagged commits, making it easy to share pre-built binaries with others once your analyzer is complete. +When building in CI, the release version of the analyzer is built for Windows (x86_64 and ARM64), Linux (x86_64 and ARM64), and MacOS (x86_64 and ARM64). Linux builds use a pre-built Docker container for a reliable, reproducible build environment. The built analyzer files are available for every CI build. Additionally, GitHub releases are automatically created for any tagged commits, making it easy to share pre-built binaries with others once your analyzer is complete. Learn how to tag a commit here: https://stackoverflow.com/questions/18216991/create-a-tag-in-a-github-repository @@ -88,21 +88,19 @@ xattr -r -d com.apple.quarantine libSimpleSerialAnalyzer.so To verify the flag was removed, run the first command again and verify the quarantine flag is no longer present. -### Apple Silicon Support +### ARM64 Support -Logic 2 now supports Apple Silicon natively! +Logic 2 supports ARM64 natively on macOS, Windows, and Linux. -The included Github Actions integration, documented [here](#cloud-building---publishing), will automatically build your analyzer for both x86_64 and arm64 architectures, for MacOS. +The included GitHub Actions integration, documented [here](#cloud-building---publishing), will automatically build your analyzer for both x86_64 and ARM64 architectures across all three platforms. -When you build your custom analyzer on a Mac, by default it will compile for the architecture of the system. +When building locally, CMake defaults to your host architecture on all platforms. -Unfortunately, universal binaries are not currently supported. +Unfortunately, universal binaries are not currently supported on macOS. -You can optionally cross build your analyzer using an x86_64 host system targeting arm64, or from a arm64 host system targeting x86_64. +#### Cross-Compilation -To cross build, you will need to create a new build directory (for example `build/x86_64` or `build/arm64`). Then use the CMake variable [CMAKE_OSX_ARCHITECTURES](https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_ARCHITECTURES.html). - -Examples: +On macOS, you can cross-compile by creating a separate build directory and using the [CMAKE_OSX_ARCHITECTURES](https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_ARCHITECTURES.html) variable: ```bash mkdir -p build/arm64 @@ -119,6 +117,8 @@ cd ../.. # built analyzer will be located at SampleAnalyzer/build/x86_64/Analyzers/libSimpleSerialAnalyzer.so ``` +On Windows, you can target ARM64 by passing `-A ARM64` to CMake instead of `-A x64`. + ## Prerequisites ### Windows @@ -181,7 +181,7 @@ _Note: Errors may occur if older versions of CMake are installed._ Dependencies: - CMake 3.13+ -- gcc 5+ +- gcc - git Misc dependencies: @@ -190,6 +190,8 @@ Misc dependencies: sudo apt-get install build-essential ``` +Note: CI builds use a pre-built Docker container (`ghcr.io/saleae/analyzer-build-image`) for a consistent build environment. You don't need Docker installed for local development. + ## Building your Analyzer ### Windows @@ -225,6 +227,14 @@ cmake --build . # built analyzer will be located at SampleAnalyzer/build/Analyzers/libSimpleSerialAnalyzer.so ``` +You can also build inside the same Docker container used by CI for a consistent environment: + +```bash +docker pull ghcr.io/saleae/analyzer-build-image:linux-x86_64 +docker run --rm -v $(pwd):/app -w /app ghcr.io/saleae/analyzer-build-image:linux-x86_64 \ + bash -c 'cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build' +``` + ## Debugging Although the exact debugging process varies slightly from platform to platform, part of the process is the same for all platforms.