diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fe010a5..28c14f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install packages - run: sudo apt update && sudo apt install -y cmake + run: sudo apt update && sudo apt install -y cmake protobuf-compiler - name: Install Arm GNU Toolchain (arm-none-eabi-gcc) uses: carlosperate/arm-none-eabi-gcc-action@v1 with: diff --git a/.github/workflows/semantic-release.yml b/.github/workflows/semantic-release.yml new file mode 100644 index 0000000..13271e4 --- /dev/null +++ b/.github/workflows/semantic-release.yml @@ -0,0 +1,48 @@ +name: Release +on: + push: + branches: + - master # or main + +permissions: + contents: read # for checkout + +jobs: + release: + permissions: + contents: write # to be able to publish a GitHub release + issues: write # to be able to comment on released issues + pull-requests: write # to be able to comment on released pull requests + id-token: write # to enable use of OIDC for npm provenance + runs-on: ubuntu-latest + + steps: + + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '20.8.1' + + - name: Install dependencies + run: npm install + + - name: Replace branch name in branches array + run: sed -i 's|currentbranch|${{ github.ref_name }}|' .releaserc.yaml + + - name: Build project with Pressure Feature + run: cargo build --release --features pressure + + - name: Build project with Temperature Feature + run: cargo build --release --features temperature + + - name: Build project with Strain Feature + run: cargo build --release --features strain + + - name: Run semantic-release + id: semantic-release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: npx semantic-release \ No newline at end of file diff --git a/.gitignore b/.gitignore index c41cc9e..2a0038a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/target \ No newline at end of file +/target +.idea \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index be31331..2055a8b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,5 +19,20 @@ } ] }, + { + "type": "probe-rs-debug", + "request": "launch", + "name": "Probe-rs Release", + "preLaunchTask": "build-release", + "flashingConfig": { + "flashingEnabled": true + }, + "chip": "STM32H733VGTx", + "coreConfigs": [ + { + "programBinary": "${workspaceFolder}/target/thumbv7em-none-eabihf/release/phoenix", + } + ] + } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 8b82518..9b05763 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,5 @@ { - "rust-analyzer.cargo.target": "thumbv7em-none-eabihf" + "rust-analyzer.cargo.target": "thumbv7em-none-eabihf", + "cmake.sourceDirectory": "/home/bonjour/Rocketry/phoenix/crates/sbg-rs/sbgECom", + "kiroAgent.configureMCP": "Disabled" } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a96ab88..ef6137b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,6 +7,11 @@ "label": "build", "type": "shell", "command": "cargo build --bin phoenix" + }, + { + "label": "build-release", + "type": "shell", + "command": "cargo build --bin phoenix --release" } ] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index c708d3a..1a78f2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,108 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "aligned" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "377e4c0ba83e4431b10df45c1d4666f178ea9c552cac93e60c3a88bf32785923" +dependencies = [ + "as-slice", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -11,11 +113,17 @@ dependencies = [ "critical-section", ] +[[package]] +name = "atomic_float" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628d228f918ac3b82fe590352cc719d30664a0c13ca3a60266fe02c7132d480a" + [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bare-metal" @@ -27,10 +135,41 @@ dependencies = [ ] [[package]] -name = "bare-metal" -version = "1.0.0" +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "serde", + "unty", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitfield" @@ -38,6 +177,12 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" +[[package]] +name = "bitfield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" + [[package]] name = "bitflags" version = "1.3.2" @@ -46,1021 +191,5022 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" dependencies = [ "serde", ] [[package]] -name = "byteorder" -version = "1.5.0" +name = "block" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] -name = "cast" -version = "0.3.0" +name = "block-device-driver" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +checksum = "44c051592f59fe68053524b4c4935249b806f72c1f544cfb7abe4f57c3be258e" +dependencies = [ + "aligned", +] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "bumpalo" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] -name = "chrono" -version = "0.4.38" -source = "git+https://github.com/uorocketry/chrono#02c0d2a797d91b724e9f3df19e5493f850934584" +name = "burn" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22149f3b5ab6628e9e9c0b29156b906d32d36bbf76f2c34ad5ce1801f5b4486e" +dependencies = [ + "burn-core 0.16.1", +] + +[[package]] +name = "burn" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec639306f45bd663957465e840cfb07bcd2ae18f7c045dd9aba8cb7a69c0654a" +dependencies = [ + "burn-autodiff", + "burn-candle", + "burn-core 0.17.1", + "burn-cuda", + "burn-ndarray 0.17.1", + "burn-rocm", + "burn-router", + "burn-wgpu", +] + +[[package]] +name = "burn-autodiff" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a178966322ab7ce71405f1324cdc14f79256d85a47138bbd2c8c4f0056148601" dependencies = [ + "burn-common 0.17.1", + "burn-tensor 0.17.1", + "derive-new 0.7.0", + "hashbrown 0.15.5", + "log", "num-traits", + "portable-atomic", + "spin 0.10.0", +] + +[[package]] +name = "burn-candle" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed0981b3c1d07e9df0f5bef1042921b6db6e88b5d91916fa5dbdd7f0ca921c3" +dependencies = [ + "burn-tensor 0.17.1", + "candle-core", + "derive-new 0.7.0", + "half", +] + +[[package]] +name = "burn-common" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb516d1faa50628828b3c2b79db3e483f20d62966f7dae68c6f21743f5f7e8ef" +dependencies = [ + "cubecl-common 0.4.0", + "getrandom 0.2.16", "serde", + "web-time", ] [[package]] -name = "cobs" -version = "0.2.3" +name = "burn-common" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +checksum = "1c3fae76798ea4dd14e6290b6753eb6235ac28c6ceaf6da35ff8396775d5494d" +dependencies = [ + "cubecl-common 0.5.0", + "rayon", + "serde", +] [[package]] -name = "common-arm" -version = "0.1.0" +name = "burn-core" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "594c44ac9f2996c2c0b92f5a44a1287d41fca3954182601a4a29b628a5973357" dependencies = [ - "cortex-m", - "defmt", - "defmt-rtt", - "defmt-test", - "derive_more", - "embedded-hal 0.2.7", - "embedded-sdmmc", - "heapless 0.7.17", - "messages", - "nb 1.1.0", - "panic-probe", - "postcard", - "stm32h7xx-hal", + "ahash", + "bincode", + "burn-common 0.16.1", + "burn-derive 0.16.1", + "burn-ndarray 0.16.1", + "burn-tensor 0.16.1", + "data-encoding", + "derive-new 0.7.0", + "half", + "hashbrown 0.15.5", + "num-traits", + "portable-atomic-util", + "rand 0.8.5", + "serde", + "serde_json", + "spin 0.9.8", + "uuid", ] [[package]] -name = "convert_case" -version = "0.4.0" +name = "burn-core" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "2afa81c868c1a9b3fad25c31176945d0cc5181ba7b77c0456bc05cf57fca975c" +dependencies = [ + "ahash", + "bincode", + "burn-common 0.17.1", + "burn-derive 0.17.1", + "burn-tensor 0.17.1", + "data-encoding", + "derive-new 0.7.0", + "flate2", + "half", + "hashbrown 0.15.5", + "log", + "num-traits", + "portable-atomic-util", + "rand 0.9.2", + "rmp-serde", + "serde", + "serde_json", + "spin 0.10.0", + "uuid", +] [[package]] -name = "cortex-m" -version = "0.7.7" +name = "burn-cubecl" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +checksum = "c547cbe414274ab4022abcc85993e1e41aa7cdccc92395ba5658acfdac285e07" dependencies = [ - "bare-metal 0.2.5", - "bitfield", - "critical-section", - "embedded-hal 0.2.7", - "volatile-register", + "burn-common 0.17.1", + "burn-ir", + "burn-tensor 0.17.1", + "bytemuck", + "cubecl", + "cubecl-std", + "derive-new 0.7.0", + "futures-lite", + "half", + "hashbrown 0.15.5", + "log", + "num-traits", + "rand 0.9.2", + "serde", + "spin 0.10.0", + "text_placeholder", ] [[package]] -name = "cortex-m-rt" -version = "0.7.3" +name = "burn-cuda" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1" +checksum = "995bd0b3f52a4cfe0cfe47c16b40b3fd33285d17a086dd583e5b432074857e02" dependencies = [ - "cortex-m-rt-macros", + "burn-cubecl", + "burn-tensor 0.17.1", + "bytemuck", + "cubecl", + "derive-new 0.7.0", + "half", + "log", ] [[package]] -name = "cortex-m-rt-macros" -version = "0.7.0" +name = "burn-derive" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7" +checksum = "2bb8f828a681946b07a87750ed0593d885e7b101653bd6a3bb1942976156bb48" dependencies = [ + "derive-new 0.7.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] -name = "cortex-m-semihosting" -version = "0.5.0" +name = "burn-derive" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0" +checksum = "12e9f07ccc658ef072bce2e996f0c38c80ee4c241598b6557afe1877dd87ae98" dependencies = [ - "cortex-m", + "derive-new 0.7.0", + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] -name = "crc-any" -version = "2.5.0" +name = "burn-import" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62ec9ff5f7965e4d7280bd5482acd20aadb50d632cf6c1d74493856b011fa73" +checksum = "335f398ae618bb16c12dbbb5399bba32051ca0322411855627a1bd8d8151286f" +dependencies = [ + "burn 0.17.1", + "burn-ndarray 0.17.1", + "derive-new 0.7.0", + "half", + "log", + "onnx-ir", + "proc-macro2", + "quote", + "regex", + "rust-format", + "serde", + "serde_json", + "syn 2.0.106", + "tracing-core", + "tracing-subscriber", +] [[package]] -name = "critical-section" -version = "1.2.0" +name = "burn-ir" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +checksum = "d63629f2c8b82ee52dbb9c18becded5117c2faf57365dc271a55c16d139cd91a" +dependencies = [ + "burn-tensor 0.17.1", + "hashbrown 0.15.5", + "portable-atomic-util", + "serde", +] [[package]] -name = "defmt" -version = "0.3.8" +name = "burn-ndarray" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99dd22262668b887121d4672af5a64b238f026099f1a2a1b322066c9ecfe9e0" +checksum = "1b8ce3bd0f1e792b53610d291eb463d9790449688c4455a496c46266e46a179f" dependencies = [ - "bitflags 1.3.2", - "defmt-macros", + "atomic_float", + "burn-common 0.16.1", + "burn-tensor 0.16.1", + "derive-new 0.7.0", + "libm", + "matrixmultiply", + "ndarray", + "num-traits", + "portable-atomic-util", + "rand 0.8.5", + "spin 0.9.8", ] [[package]] -name = "defmt-macros" -version = "0.3.9" +name = "burn-ndarray" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9f309eff1f79b3ebdf252954d90ae440599c26c2c553fe87a2d17195f2dcb" +checksum = "7e883846578e6915e1dbaeeb5bce32cc04cff03e7cb79c5836e1e888bbce974f" +dependencies = [ + "atomic_float", + "burn-autodiff", + "burn-common 0.17.1", + "burn-ir", + "burn-tensor 0.17.1", + "derive-new 0.7.0", + "libm", + "macerator", + "matrixmultiply", + "ndarray", + "num-traits", + "paste", + "portable-atomic-util", + "rand 0.9.2", + "spin 0.10.0", +] + +[[package]] +name = "burn-rocm" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd39d58202558b65b575921b57bff933845e6171296e2b8faf6a9d3610a344c5" +dependencies = [ + "burn-cubecl", + "burn-tensor 0.17.1", + "bytemuck", + "cubecl", + "derive-new 0.7.0", + "half", + "log", +] + +[[package]] +name = "burn-router" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ed8614e180f7a58f77e658bd52e206d2f4a1ee37fcb4665c635ea9da90ea8b" +dependencies = [ + "burn-common 0.17.1", + "burn-ir", + "burn-tensor 0.17.1", + "hashbrown 0.15.5", + "log", + "spin 0.10.0", +] + +[[package]] +name = "burn-tensor" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab959e7da2e7514b959d841c93e8e026233aa77284f5d976099a8f5251e3ba99" +dependencies = [ + "burn-common 0.16.1", + "bytemuck", + "derive-new 0.7.0", + "half", + "hashbrown 0.15.5", + "num-traits", + "portable-atomic-util", + "rand 0.8.5", + "rand_distr 0.4.3", + "serde", + "serde_bytes", +] + +[[package]] +name = "burn-tensor" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a70d1562c0d00083939e34daad61dabebb0f8bc8c250d1ef2f5efc31eb93aaf" +dependencies = [ + "burn-common 0.17.1", + "bytemuck", + "colored", + "cubecl", + "derive-new 0.7.0", + "half", + "hashbrown 0.15.5", + "num-traits", + "rand 0.9.2", + "rand_distr 0.5.1", + "serde", + "serde_bytes", +] + +[[package]] +name = "burn-wgpu" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "215bf0e641a27e17bcd3941a11867dcda411c9cb009488c6b6650c8206437c30" +dependencies = [ + "burn-cubecl", + "burn-tensor 0.17.1", + "cubecl", +] + +[[package]] +name = "bytemuck" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" dependencies = [ - "defmt-parser", - "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.106", ] [[package]] -name = "defmt-parser" -version = "0.3.4" +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4a5fefe330e8d7f31b16a318f9ce81000d8e35e69b93eae154d16d2278f70f" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "candle-core" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ccf5ee3532e66868516d9b315f73aec9f34ea1a37ae98514534d458915dbf1" dependencies = [ - "thiserror", + "byteorder", + "gemm 0.17.1", + "half", + "memmap2", + "num-traits", + "num_cpus", + "rand 0.9.2", + "rand_distr 0.5.1", + "rayon", + "safetensors", + "thiserror 1.0.69", + "ug", + "yoke", + "zip", ] [[package]] -name = "defmt-rtt" -version = "0.4.1" +name = "cc" +version = "1.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab697b3dbbc1750b7c8b821aa6f6e7f2480b47a99bc057a2ed7b170ebef0c51" +checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" dependencies = [ - "critical-section", - "defmt", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "git+https://github.com/uorocketry/chrono#02c0d2a797d91b724e9f3df19e5493f850934584" +dependencies = [ + "num-traits", +] + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.15", +] + +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "serde", + "termcolor", + "unicode-width 0.2.1", +] + +[[package]] +name = "colored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "common-arm" +version = "0.1.0" +dependencies = [ + "cortex-m", + "defmt 0.3.100", + "defmt-rtt", + "defmt-test", + "derive_more 0.99.20", + "embassy-embedded-hal 0.3.2", + "embassy-time", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-io-async", + "embedded-nal-async", + "heapless 0.7.17", + "messages-prost", + "nb 1.1.0", + "panic-probe", + "postcard", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield 0.13.2", + "critical-section", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "cortex-m-semihosting" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0" +dependencies = [ + "cortex-m", +] + +[[package]] +name = "crc-any" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62ec9ff5f7965e4d7280bd5482acd20aadb50d632cf6c1d74493856b011fa73" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "cubecl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e438056cf7c25b3adde38240b89842e1c924b8e914731c82ad81161d23e6ff" +dependencies = [ + "cubecl-core", + "cubecl-cuda", + "cubecl-hip", + "cubecl-linalg", + "cubecl-reduce", + "cubecl-runtime", + "cubecl-std", + "cubecl-wgpu", + "half", +] + +[[package]] +name = "cubecl-common" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10239ee4800968f367fbc4828250d38acf5d14fa53e8d0370d5f474387591322" +dependencies = [ + "derive-new 0.6.0", + "embassy-futures", + "getrandom 0.2.16", + "log", + "portable-atomic", + "rand 0.8.5", + "serde", + "spin 0.9.8", + "web-time", +] + +[[package]] +name = "cubecl-common" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79251bfc7f067ac9038232fe38a317adc2f31cb2fc3800e69fd409ccac7abc1f" +dependencies = [ + "bytemuck", + "derive-new 0.6.0", + "derive_more 1.0.0", + "dirs", + "embassy-futures", + "futures-lite", + "half", + "hashbrown 0.14.5", + "log", + "num-traits", + "portable-atomic", + "rand 0.9.2", + "sanitize-filename", + "serde", + "serde_json", + "spin 0.9.8", +] + +[[package]] +name = "cubecl-core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03bf4211cdbd68bb0fb8291e0ed825c13da0d1ac01b7c02dce3cee44a6138be" +dependencies = [ + "bitflags 2.9.2", + "bytemuck", + "cubecl-common 0.5.0", + "cubecl-ir", + "cubecl-macros", + "cubecl-runtime", + "derive-new 0.6.0", + "derive_more 1.0.0", + "half", + "hashbrown 0.14.5", + "log", + "num-traits", + "paste", + "serde", + "serde_json", + "variadics_please", +] + +[[package]] +name = "cubecl-cpp" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5eef85cbcc34be7e25fc9d39edf99ed68559862dbf25c1877ebdf4a9595d31b" +dependencies = [ + "bytemuck", + "cubecl-common 0.5.0", + "cubecl-core", + "cubecl-runtime", + "derive-new 0.6.0", + "half", + "log", +] + +[[package]] +name = "cubecl-cuda" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e091e4e3a3900faff440aec4053805ec4456f94f4acc4afe8e6b27519c6d16" +dependencies = [ + "bytemuck", + "cubecl-common 0.5.0", + "cubecl-core", + "cubecl-cpp", + "cubecl-runtime", + "cudarc", + "derive-new 0.6.0", + "half", + "log", + "serde", +] + +[[package]] +name = "cubecl-hip" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2f8c00207517de61cccdc4ca2724bc1db9dab94840beaf4329e43cead3bc4a" +dependencies = [ + "bytemuck", + "cubecl-common 0.5.0", + "cubecl-core", + "cubecl-cpp", + "cubecl-hip-sys", + "cubecl-runtime", + "derive-new 0.6.0", + "half", + "log", + "paste", +] + +[[package]] +name = "cubecl-hip-sys" +version = "6.4.4348201" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678a20e5e38ce9c772bdd53596f2801ef210ae735ec2d7d46b5d5b675c09d929" +dependencies = [ + "libc", + "regex", +] + +[[package]] +name = "cubecl-ir" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e096d77646590f0180ed4ce1aa7df4ecc7219f3c4616e9fe72d93ab63a352855" +dependencies = [ + "cubecl-common 0.5.0", + "cubecl-macros-internal", + "derive_more 1.0.0", + "float-ord", + "fnv", + "half", + "hashbrown 0.14.5", + "num-traits", + "portable-atomic", + "serde", + "variadics_please", +] + +[[package]] +name = "cubecl-linalg" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75aacf86f6004c274e63589aed55c5edcbcdf1b292eaf4ce2c1688c04c41a194" +dependencies = [ + "bytemuck", + "cubecl-common 0.5.0", + "cubecl-core", + "cubecl-reduce", + "cubecl-runtime", + "cubecl-std", + "half", + "serde", +] + +[[package]] +name = "cubecl-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd74622b5c8cb161e3f7fa0b2b751784ef89ab45acfa355f511eb2219dde337e" +dependencies = [ + "cubecl-common 0.5.0", + "darling", + "derive-new 0.6.0", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "cubecl-macros-internal" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89898212c1eaba0e2f0dffcadc9790b20b75d2ec8836da084370b043be2623" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "cubecl-reduce" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7afbdfe03e7e3ca71f61890ebebc6b4390494204b545e6f6bf51a43755449073" +dependencies = [ + "cubecl-core", + "cubecl-runtime", + "cubecl-std", + "num-traits", + "serde", +] + +[[package]] +name = "cubecl-runtime" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385234520c9e392382737f32ad372b05f345656eb798ba00b72d2722c68b698c" +dependencies = [ + "async-channel", + "bytemuck", + "cfg-if", + "cfg_aliases", + "cubecl-common 0.5.0", + "cubecl-ir", + "derive-new 0.6.0", + "hashbrown 0.14.5", + "log", + "md5", + "serde", + "serde_json", + "spin 0.9.8", + "variadics_please", + "wasm-bindgen-futures", +] + +[[package]] +name = "cubecl-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38868eea6fdc183feb3c46bcf5e666c78e6cf0ddca2c4f3a877785cc0eabd71e" +dependencies = [ + "cubecl-core", + "cubecl-runtime", + "half", + "serde", +] + +[[package]] +name = "cubecl-wgpu" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77fa2dcfaa6d75cfbc5ff05cafe99ec4a7fb7c0fa7197917e0fd20f5b90979fe" +dependencies = [ + "async-channel", + "bytemuck", + "cfg-if", + "cfg_aliases", + "cubecl-common 0.5.0", + "cubecl-core", + "cubecl-runtime", + "derive-new 0.6.0", + "derive_more 1.0.0", + "hashbrown 0.14.5", + "log", + "web-time", + "wgpu", +] + +[[package]] +name = "cudarc" +version = "0.13.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486c221362668c63a1636cfa51463b09574433b39029326cff40864b3ba12b6e" +dependencies = [ + "libloading", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.106", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.0.1", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.15", +] + +[[package]] +name = "defmt-rtt" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6eca0aae8aa2cf8333200ecbd236274697bc0a394765c858b3d9372eb1abcfa" +dependencies = [ + "critical-section", + "defmt 0.3.100", ] [[package]] name = "defmt-test" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c1e67ff0e1c6b1a9540a1a3e04454658faacdd188c91987c444d56e469d7dea" +dependencies = [ + "cortex-m-rt", + "cortex-m-semihosting", + "defmt 0.3.100", + "defmt-test-macros", +] + +[[package]] +name = "defmt-test-macros" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5520fd36862f281c026abeaab153ebbc001717c29a9b8e5ba9704d8f3a879d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "derive-new" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "derive-new" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.106", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "unicode-xid", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "dyn-stack" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e53799688f5632f364f8fb387488dd05db9fe45db7011be066fc20e7027f8b" +dependencies = [ + "bytemuck", + "reborrow", +] + +[[package]] +name = "dyn-stack" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490bd48eb68fffcfed519b4edbfd82c69cbe741d175b84f0e0cbe8c57cbe0bdd" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "embassy-embedded-hal" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c62a3bf127e03832fb97d8b01a058775e617653bc89e2a12c256485a7fb54c1" +dependencies = [ + "defmt 0.3.100", + "embassy-embedded-hal 0.4.0", + "embassy-futures", + "embassy-sync 0.6.2", + "embassy-time", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-embedded-hal" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1611b7a7ab5d1fbed84c338df26d56fd9bded58006ebb029075112ed2c5e039" +dependencies = [ + "embassy-futures", + "embassy-hal-internal 0.3.0", + "embassy-sync 0.7.1", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-executor" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90327bcc66333a507f89ecc4e2d911b265c45f5c9bc241f98eee076752d35ac6" +dependencies = [ + "cortex-m", + "critical-section", + "defmt 0.3.100", + "document-features", + "embassy-executor-macros", +] + +[[package]] +name = "embassy-executor-macros" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3577b1e9446f61381179a330fc5324b01d511624c55f25e3c66c9e3c626dbecf" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "embassy-futures" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" + +[[package]] +name = "embassy-hal-internal" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef3bac31ec146321248a169e9c7b5799f1e0b3829c7a9b324cb4600a7438f59" +dependencies = [ + "cortex-m", + "critical-section", + "defmt 0.3.100", + "num-traits", +] + +[[package]] +name = "embassy-hal-internal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" +dependencies = [ + "num-traits", +] + +[[package]] +name = "embassy-net" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940c4b9fe5c1375b09a0c6722c0100d6b2ed46a717a34f632f26e8d7327c4383" +dependencies = [ + "defmt 0.3.100", + "document-features", + "embassy-net-driver", + "embassy-sync 0.6.2", + "embassy-time", + "embedded-io-async", + "embedded-nal-async", + "heapless 0.8.0", + "managed", + "smoltcp", +] + +[[package]] +name = "embassy-net-driver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524eb3c489760508f71360112bca70f6e53173e6fe48fc5f0efd0f5ab217751d" +dependencies = [ + "defmt 0.3.100", +] + +[[package]] +name = "embassy-net-driver-channel" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a567ab50319d866ad5e6c583ed665ba9b07865389644d3d82e45bf1497c934" +dependencies = [ + "embassy-futures", + "embassy-net-driver", + "embassy-sync 0.7.1", +] + +[[package]] +name = "embassy-stm32" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e0bb733acdddbc7097765a47ce80bde2385647cf1d8427331931e06cff9a87" +dependencies = [ + "aligned", + "bit_field", + "bitflags 2.9.2", + "block-device-driver", + "cfg-if", + "chrono 0.4.41", + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt 0.3.100", + "document-features", + "embassy-embedded-hal 0.3.2", + "embassy-futures", + "embassy-hal-internal 0.2.0", + "embassy-net-driver", + "embassy-sync 0.6.2", + "embassy-time", + "embassy-time-driver", + "embassy-time-queue-utils", + "embassy-usb-driver", + "embassy-usb-synopsys-otg", + "embedded-can", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-hal-nb", + "embedded-io", + "embedded-io-async", + "embedded-storage", + "embedded-storage-async", + "futures-util", + "nb 1.1.0", + "proc-macro2", + "quote", + "rand_core 0.6.4", + "sdio-host", + "static_assertions", + "stm32-fmc", + "stm32-metapac", + "vcell", + "volatile-register", +] + +[[package]] +name = "embassy-sync" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d2c8cdff05a7a51ba0087489ea44b0b1d97a296ca6b1d6d1a33ea7423d34049" +dependencies = [ + "cfg-if", + "critical-section", + "defmt 0.3.100", + "embedded-io-async", + "futures-sink", + "futures-util", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-sync" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c372c90d3525a648684fa1c131decaf7d9ff181030db09c876fad6043443b9" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-core", + "futures-sink", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-time" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f820157f198ada183ad62e0a66f554c610cdcd1a9f27d4b316358103ced7a1f8" +dependencies = [ + "cfg-if", + "critical-section", + "defmt 0.3.100", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-util", +] + +[[package]] +name = "embassy-time-driver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d45f5d833b6d98bd2aab0c2de70b18bfaa10faf661a1578fd8e5dfb15eb7eba" +dependencies = [ + "document-features", +] + +[[package]] +name = "embassy-time-queue-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc55c748d16908a65b166d09ce976575fb8852cf60ccd06174092b41064d8f83" +dependencies = [ + "embassy-executor", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-usb" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e651b9b7b47b514e6e6d1940a6e2e300891a2c33641917130643602a0cb6386" +dependencies = [ + "defmt 0.3.100", + "embassy-futures", + "embassy-net-driver-channel", + "embassy-sync 0.6.2", + "embassy-usb-driver", + "heapless 0.8.0", + "ssmarshal", + "usbd-hid", +] + +[[package]] +name = "embassy-usb-driver" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340c5ce591ef58c6449e43f51d2c53efe1bf0bb6a40cbf80afa0d259c7d52c76" +dependencies = [ + "defmt 1.0.1", + "embedded-io-async", +] + +[[package]] +name = "embassy-usb-synopsys-otg" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08e753b23799329780c7ac434264026d0422044d6649ed70a73441b14a6436d7" +dependencies = [ + "critical-section", + "defmt 0.3.100", + "embassy-sync 0.6.2", + "embassy-usb-driver", +] + +[[package]] +name = "embedded-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f2de9133f68db0d4627ad69db767726c99ff8585272716708227008d3f1bddd" +dependencies = [ + "const-default", + "critical-section", + "linked_list_allocator", + "rlsf", +] + +[[package]] +name = "embedded-can" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-hal-bus" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513e0b3a8fb7d3013a8ae17a834283f170deaf7d0eeab0a7c1a36ad4dd356d22" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-hal-nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" +dependencies = [ + "embedded-hal 1.0.0", + "nb 1.1.0", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +dependencies = [ + "defmt 0.3.100", +] + +[[package]] +name = "embedded-io-async" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" +dependencies = [ + "defmt 0.3.100", + "embedded-io", +] + +[[package]] +name = "embedded-nal" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56a28be191a992f28f178ec338a0bf02f63d7803244add736d026a471e6ed77" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "embedded-nal-async" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76959917cd2b86f40a98c28dd5624eddd1fa69d746241c8257eac428d83cb211" +dependencies = [ + "embedded-io-async", + "embedded-nal", +] + +[[package]] +name = "embedded-sdmmc" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce3c7f9ea039eeafc4a49597b7bd5ae3a1c8e51b2803a381cb0f29ce90fe1ec6" +dependencies = [ + "byteorder", + "embedded-hal 1.0.0", + "embedded-io", + "heapless 0.8.0", + "log", +] + +[[package]] +name = "embedded-storage" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" + +[[package]] +name = "embedded-storage-async" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" +dependencies = [ + "embedded-storage", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-ord" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gemm" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab24cc62135b40090e31a76a9b2766a501979f3070fa27f689c27ec04377d32" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-c32 0.17.1", + "gemm-c64 0.17.1", + "gemm-common 0.17.1", + "gemm-f16 0.17.1", + "gemm-f32 0.17.1", + "gemm-f64 0.17.1", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-c32 0.18.2", + "gemm-c64 0.18.2", + "gemm-common 0.18.2", + "gemm-f16 0.18.2", + "gemm-f32 0.18.2", + "gemm-f64 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "seq-macro", +] + +[[package]] +name = "gemm-c32" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9c030d0b983d1e34a546b86e08f600c11696fde16199f971cd46c12e67512c0" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-c32" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "seq-macro", +] + +[[package]] +name = "gemm-c64" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb5f2e79fefb9693d18e1066a557b4546cd334b226beadc68b11a8f9431852a" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-c64" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "seq-macro", +] + +[[package]] +name = "gemm-common" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2e7ea062c987abcd8db95db917b4ffb4ecdfd0668471d8dc54734fdff2354e8" +dependencies = [ + "bytemuck", + "dyn-stack 0.10.0", + "half", + "num-complex", + "num-traits", + "once_cell", + "paste", + "pulp 0.18.22", + "raw-cpuid 10.7.0", + "rayon", + "seq-macro", + "sysctl 0.5.5", +] + +[[package]] +name = "gemm-common" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3" +dependencies = [ + "bytemuck", + "dyn-stack 0.13.0", + "half", + "libm", + "num-complex", + "num-traits", + "once_cell", + "paste", + "pulp 0.21.5", + "raw-cpuid 11.5.0", + "rayon", + "seq-macro", + "sysctl 0.6.0", +] + +[[package]] +name = "gemm-f16" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca4c06b9b11952071d317604acb332e924e817bd891bec8dfb494168c7cedd4" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "gemm-f32 0.17.1", + "half", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "rayon", + "seq-macro", +] + +[[package]] +name = "gemm-f16" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff95ae3259432f3c3410eaa919033cd03791d81cebd18018393dc147952e109" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "gemm-f32 0.18.2", + "half", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "rayon", + "seq-macro", +] + +[[package]] +name = "gemm-f32" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9a69f51aaefbd9cf12d18faf273d3e982d9d711f60775645ed5c8047b4ae113" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-f32" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "seq-macro", +] + +[[package]] +name = "gemm-f64" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa397a48544fadf0b81ec8741e5c0fba0043008113f71f2034def1935645d2b0" +dependencies = [ + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-f64" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", + "seq-macro", +] + +[[package]] +name = "generic-array" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667f6ea017b297ec65b8a108c6e9ad6879460721fb3b6b23abf690970147fc28" +dependencies = [ + "typenum", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glow" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.9.2", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.9.2", +] + +[[package]] +name = "gpu-allocator" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +dependencies = [ + "log", + "presser", + "thiserror 1.0.69", + "windows", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.9.2", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.9.2", +] + +[[package]] +name = "grounded" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917d82402c7eb9755fdd87d52117701dae9e413a6abb309fac2a13af693b6080" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "bytemuck", + "cfg-if", + "crunchy", + "num-traits", + "rand 0.9.2", + "rand_distr 0.5.1", + "serde", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", + "serde", +] + +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32 0.2.1", + "rustc_version 0.4.1", + "serde", + "spin 0.9.8", + "stable_deref_trait", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "defmt 0.3.100", + "hash32 0.3.1", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown 0.15.5", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.175" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.53.3", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libredox" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +dependencies = [ + "bitflags 2.9.2", + "libc", +] + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litrs" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "m" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9199148efbf3463493dd58c03a921add4623147739b9acd15f339b1dc5bfd677" + +[[package]] +name = "macerator" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ac9c19702c37bae1a53d130a326b1c4f58cb17d472538cf547d44b46dbbe3aa" +dependencies = [ + "bytemuck", + "cfg_aliases", + "half", + "macerator-macros", + "moddef", + "num-traits", + "paste", + "rustc_version 0.4.1", +] + +[[package]] +name = "macerator-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd48b535b9b37a25a2589ab8d4f997886a2c68f59960ce06588525f38dd4944" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "madgwick" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52760a80742f3053ff3b578eb14df5a881538584e22524ac915102dbf274b1bc" +dependencies = [ + "m", + "mat", +] + +[[package]] +name = "madgwick-test" +version = "0.1.0" +dependencies = [ + "madgwick", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "managed" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" + +[[package]] +name = "mat" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8401e35d18e3132a68bed048083960c701cdb5ad386815ef5661863cc6da7ebd" +dependencies = [ + "generic-array", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "num_cpus", + "once_cell", + "rawpointer", + "thread-tree", +] + +[[package]] +name = "mavlink" +version = "0.13.1" +source = "git+https://github.com/uorocketry/rust-mavlink.git#e9f4057deedce85cae542fdbef75c5f56a360c9c" +dependencies = [ + "bitflags 1.3.2", + "mavlink-bindgen", + "mavlink-core", + "num-derive", + "num-traits", +] + +[[package]] +name = "mavlink-bindgen" +version = "0.13.1" +source = "git+https://github.com/uorocketry/rust-mavlink.git#e9f4057deedce85cae542fdbef75c5f56a360c9c" +dependencies = [ + "crc-any", + "lazy_static", + "proc-macro2", + "quick-xml", + "quote", + "thiserror 1.0.69", +] + +[[package]] +name = "mavlink-core" +version = "0.13.1" +source = "git+https://github.com/uorocketry/rust-mavlink.git#e9f4057deedce85cae542fdbef75c5f56a360c9c" +dependencies = [ + "byteorder", + "crc-any", + "embedded-io", + "embedded-io-async", +] + +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "memmap2" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28" +dependencies = [ + "libc", + "stable_deref_trait", +] + +[[package]] +name = "messages-prost" +version = "0.1.0" +source = "git+https://github.com/uorocketry/messages-prost#c16c21cee30d57b993b0a3a61ed91dd11df8a9f6" +dependencies = [ + "bitflags 2.9.2", + "defmt 0.3.100", + "heapless 0.8.0", + "mavlink", + "prost", + "prost-build", + "serde", + "ublox 0.4.5", +] + +[[package]] +name = "metal" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" +dependencies = [ + "bitflags 2.9.2", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "micromath" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "moddef" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0b3262dc837d2513fe2ef31ff8461352ef932dcca31ba0c0abe33547cf6b9b" + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "naga" +version = "25.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b977c445f26e49757f9aca3631c3b8b836942cb278d69a92e7b80d3b24da632" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.9.2", + "cfg_aliases", + "codespan-reporting", + "half", + "hashbrown 0.15.5", + "hexf-parse", + "indexmap", + "log", + "num-traits", + "once_cell", + "rustc-hash", + "spirv", + "strum 0.26.3", + "thiserror 2.0.15", + "unicode-ident", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", + "rayon", +] + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nmea" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2086c773d18da556c05ca235596d163c00379027189bafe2209ae40ebd19717c" +dependencies = [ + "arrayvec", + "cfg-if", + "chrono 0.4.41", + "heapless 0.8.0", + "nom", + "num-traits", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "bytemuck", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "onnx-ir" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a9f4ef6f7f7500db1f39ddc001fc9b7147195e7c5ece7fa0f018e8468720795" +dependencies = [ + "bytemuck", + "half", + "log", + "protobuf", + "protobuf-codegen", + "regex", + "serde", + "strum 0.27.2", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "panic-probe" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4047d9235d1423d66cc97da7d07eddb54d4f154d6c13805c6d0793956f4f25b0" +dependencies = [ + "cortex-m", + "defmt 0.3.100", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phoenix" +version = "0.1.0" +dependencies = [ + "burn 0.16.1", + "burn-import", + "chrono 0.4.41", + "common-arm", + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt 0.3.100", + "defmt-rtt", + "defmt-test", + "embassy-embedded-hal 0.3.2", + "embassy-executor", + "embassy-futures", + "embassy-net", + "embassy-stm32", + "embassy-sync 0.6.2", + "embassy-time", + "embassy-usb", + "embedded-alloc", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-hal-bus", + "embedded-io-async", + "embedded-nal-async", + "embedded-sdmmc", + "embedded-storage", + "grounded", + "heapless 0.8.0", + "libm", + "madgwick", + "messages-prost", + "micromath", + "nmea", + "panic-probe", + "sbg-rs", + "smlang", + "static_cell", + "stm32-fmc", + "ublox 0.6.0", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +dependencies = [ + "serde", +] + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "defmt 1.0.1", + "heapless 0.7.17", + "serde", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + +[[package]] +name = "prettyplease" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +dependencies = [ + "proc-macro2", + "syn 2.0.106", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" + +[[package]] +name = "prost" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1" +dependencies = [ + "heck", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.106", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "prost-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" +dependencies = [ + "prost", +] + +[[package]] +name = "protobuf" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4" +dependencies = [ + "bytes", + "once_cell", + "protobuf-support", + "thiserror 1.0.69", +] + +[[package]] +name = "protobuf-codegen" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3976825c0014bbd2f3b34f0001876604fe87e0c86cd8fa54251530f1544ace" +dependencies = [ + "anyhow", + "once_cell", + "protobuf", + "protobuf-parse", + "regex", + "tempfile", + "thiserror 1.0.69", +] + +[[package]] +name = "protobuf-parse" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4aeaa1f2460f1d348eeaeed86aea999ce98c1bded6f089ff8514c9d9dbdc973" +dependencies = [ + "anyhow", + "indexmap", + "log", + "protobuf", + "protobuf-support", + "tempfile", + "thiserror 1.0.69", + "which", +] + +[[package]] +name = "protobuf-support" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6" +dependencies = [ + "thiserror 1.0.69", +] + +[[package]] +name = "pulp" +version = "0.18.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a01a0dc67cf4558d279f0c25b0962bd08fc6dec0137699eae304103e882fe6" +dependencies = [ + "bytemuck", + "libm", + "num-complex", + "reborrow", +] + +[[package]] +name = "pulp" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907" +dependencies = [ + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "reborrow", + "version_check", +] + +[[package]] +name = "quick-xml" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "rand_distr" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" +dependencies = [ + "num-traits", + "rand 0.9.2", +] + +[[package]] +name = "range-alloc" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" + +[[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "raw-cpuid" +version = "11.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +dependencies = [ + "bitflags 2.9.2", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "reborrow" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" + +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags 2.9.2", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "rlsf" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222fb240c3286247ecdee6fa5341e7cdad0ffdf8e7e401d9937f2d58482a20bf" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "svgbobdoc", +] + +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rust-format" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60e7c00b6c3bf5e38a880eec01d7e829d12ca682079f8238a464def3c4b31627" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.26", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.2", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +dependencies = [ + "bitflags 2.9.2", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.60.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "safetensors" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sanitize-filename" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "sbg-rs" +version = "0.1.0" +dependencies = [ + "bitflags 2.9.2", + "cmake", + "common-arm", + "cortex-m", + "cortex-m-rt", + "defmt 0.3.100", + "embedded-hal 1.0.0", + "heapless 0.7.17", + "messages-prost", + "nb 1.1.0", + "serde", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sdio-host" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93c025f9cfe4c388c328ece47d11a54a823da3b5ad0370b22d95ad47137f85a" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_json" +version = "1.0.142" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "smlang" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de84f9f80bbe6272174e2bfdb8cf7ce4815b218038a42161c2f21c1d872c215" +dependencies = [ + "smlang-macros", +] + +[[package]] +name = "smlang-macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231b4425dcc43afc7e18c34e7c6738cd252d42d91d909c948df14107c9ae79f1" +dependencies = [ + "proc-macro2", + "quote", + "string_morph", + "syn 1.0.109", +] + +[[package]] +name = "smoltcp" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "cfg-if", + "defmt 0.3.100", + "heapless 0.8.0", + "managed", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", + "portable-atomic", +] + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", + "portable-atomic", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.9.2", +] + +[[package]] +name = "ssmarshal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3e6ad23b128192ed337dfa4f1b8099ced0c2bf30d61e551b65fda5916dbb850" +dependencies = [ + "encode_unicode", + "serde", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "static_cell" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0530892bb4fa575ee0da4b86f86c667132a94b74bb72160f58ee5a4afec74c23" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "stm32-fmc" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290966e8c38f94b11884877242de876280d0eab934900e9642d58868e77c5df1" +checksum = "c7f0639399e2307c2446c54d91d4f1596343a1e1d5cab605b9cce11d0ab3858c" +dependencies = [ + "embedded-hal 0.2.7", +] + +[[package]] +name = "stm32-metapac" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc520f60f6653a32479a95b9180b33908f0cbbdf106609465ee7dea98f4f5b37" +dependencies = [ + "cortex-m", + "cortex-m-rt", +] + +[[package]] +name = "string_morph" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "183aaf7fa637cc7b5f54c45b8f7cb6e8d73831f9f75a56b6defa5bf8c51d1699" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros 0.26.4", +] + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros 0.27.2", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.106", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "svgbobdoc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" +dependencies = [ + "base64", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-width 0.1.14", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "sysctl" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" +dependencies = [ + "bitflags 2.9.2", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "sysctl" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" +dependencies = [ + "bitflags 2.9.2", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix 1.0.8", + "windows-sys 0.59.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "text_placeholder" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5008f74a09742486ef0047596cf35df2b914e2a8dca5727fcb6ba6842a766b" +dependencies = [ + "hashbrown 0.13.2", + "serde", + "serde_json", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d76d3f064b981389ecb4b6b7f45a0bf9fdac1d5b9204c7bd6714fecc302850" +dependencies = [ + "thiserror-impl 2.0.15", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d29feb33e986b6ea906bd9c3559a856983f92371b3eaa5e83782a351623de0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "thread-tree" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbd370cb847953a25954d9f63e14824a36113f8c72eecf6eccef5dc4b45d630" +dependencies = [ + "crossbeam-channel", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "cortex-m-rt", - "cortex-m-semihosting", - "defmt", - "defmt-test-macros", + "indexmap", + "toml_datetime", + "winnow", ] [[package]] -name = "defmt-test-macros" -version = "0.3.1" +name = "tracing" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "984bc6eca246389726ac2826acc2488ca0fe5fcd6b8d9b48797021951d76a125" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.85", + "pin-project-lite", + "tracing-attributes", + "tracing-core", ] [[package]] -name = "derive_more" -version = "0.99.18" +name = "tracing-attributes" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ - "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.1", - "syn 2.0.85", + "syn 2.0.106", ] [[package]] -name = "embedded-alloc" -version = "0.5.1" +name = "tracing-core" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddae17915accbac2cfbc64ea0ae6e3b330e6ea124ba108dada63646fd3c6f815" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ - "critical-section", - "linked_list_allocator", + "once_cell", + "valuable", ] [[package]] -name = "embedded-dma" +name = "tracing-log" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "stable_deref_trait", + "log", + "once_cell", + "tracing-core", ] [[package]] -name = "embedded-hal" -version = "0.2.7" +name = "tracing-subscriber" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ - "nb 0.1.3", - "void", + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] -name = "embedded-hal" -version = "1.0.0" +name = "typenum" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] -name = "embedded-hal-async" -version = "1.0.0" +name = "ublox" +version = "0.4.5" +source = "git+https://github.com/uorocketry/ublox#286d43a3ae9a3ba30a04be04c65bf89aca6b1bfe" +dependencies = [ + "bitflags 2.9.2", + "chrono 0.4.38", + "defmt 0.3.100", + "num-traits", + "serde", + "ublox_derive 0.1.0", +] + +[[package]] +name = "ublox" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +checksum = "0456d0c38f15a56f5a12af23efe86719b757744ededebd69eee3320ed24ad50f" dependencies = [ - "embedded-hal 1.0.0", + "bitflags 2.9.2", + "chrono 0.4.41", + "num-traits", + "serde", + "ublox_derive 0.3.0", ] [[package]] -name = "embedded-hal-bus" +name = "ublox_derive" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b4e6ede84339ebdb418cd986e6320a34b017cdf99b5cc3efceec6450b06886" +source = "git+https://github.com/uorocketry/ublox#286d43a3ae9a3ba30a04be04c65bf89aca6b1bfe" dependencies = [ - "critical-section", - "embedded-hal 1.0.0", - "embedded-hal-async", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "embedded-sdmmc" +name = "ublox_derive" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3bf0a2b5becb87e9a329d9290f131e4d10fec39b56d129926826a7cbea1e7a" +checksum = "290ba2a4bfe92acb91bb9c0cdae32e9a1cda9cfe5b3329eaf9a444c522512de9" dependencies = [ - "byteorder", - "embedded-hal 0.2.7", - "log", - "nb 0.1.3", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "embedded-storage" -version = "0.3.1" +name = "ug" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" +checksum = "03719c61a91b51541f076dfdba45caacf750b230cefaa4b32d6f5411c3f7f437" +dependencies = [ + "gemm 0.18.2", + "half", + "libloading", + "memmap2", + "num", + "num-traits", + "num_cpus", + "rayon", + "safetensors", + "serde", + "thiserror 1.0.69", + "tracing", + "yoke", +] [[package]] -name = "equivalent" -version = "1.0.1" +name = "unicode-ident" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] -name = "fdcan" -version = "0.2.1" +name = "unicode-width" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a745a7ef1532cc436619631a102c1d2f71e8fd4e82f1ee48c85eaa73c0487e81" -dependencies = [ - "bitflags 1.3.2", - "nb 1.1.0", - "paste", - "static_assertions", - "vcell", - "volatile-register", -] +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] -name = "fugit" -version = "0.3.7" +name = "unicode-width" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" -dependencies = [ - "gcd", -] +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] -name = "futures-core" -version = "0.3.31" +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "futures-task" -version = "0.3.31" +name = "unty" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" [[package]] -name = "futures-util" -version = "0.3.31" +name = "usb-device" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", + "heapless 0.8.0", + "portable-atomic", ] [[package]] -name = "gcd" -version = "2.3.0" +name = "usbd-hid" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" +checksum = "e6f291ab53d428685cc780f08a2eb9d5d6ff58622db2b36e239a4f715f1e184c" +dependencies = [ + "serde", + "ssmarshal", + "usb-device", + "usbd-hid-macros", +] [[package]] -name = "generic-array" -version = "0.11.2" +name = "usbd-hid-descriptors" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "667f6ea017b297ec65b8a108c6e9ad6879460721fb3b6b23abf690970147fc28" +checksum = "0eee54712c5d778d2fb2da43b1ce5a7b5060886ef7b09891baeb4bf36910a3ed" dependencies = [ - "typenum", + "bitfield 0.14.0", ] [[package]] -name = "hash32" -version = "0.2.1" +name = "usbd-hid-macros" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +checksum = "bb573c76e7884035ac5e1ab4a81234c187a82b6100140af0ab45757650ccda38" dependencies = [ "byteorder", + "hashbrown 0.13.2", + "log", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", + "usbd-hid-descriptors", ] [[package]] -name = "hash32" -version = "0.3.1" +name = "uuid" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] +checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" [[package]] -name = "hashbrown" -version = "0.15.0" +name = "valuable" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] -name = "heapless" -version = "0.7.17" +name = "variadics_please" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" dependencies = [ - "atomic-polyfill", - "hash32 0.2.1", - "rustc_version 0.4.1", - "serde", - "spin", - "stable_deref_trait", + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] -name = "heapless" -version = "0.8.0" +name = "vcell" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" dependencies = [ - "hash32 0.3.1", - "stable_deref_trait", + "vcell", ] [[package]] -name = "indexmap" -version = "2.6.0" +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ - "equivalent", - "hashbrown", + "same-file", + "winapi-util", ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "linked_list_allocator" -version = "0.10.5" +name = "wasi" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] [[package]] -name = "lock_api" -version = "0.4.12" +name = "wasm-bindgen" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ - "autocfg", - "scopeguard", + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", ] [[package]] -name = "log" -version = "0.4.22" +name = "wasm-bindgen-backend" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-shared", +] [[package]] -name = "m" -version = "0.1.1" +name = "wasm-bindgen-futures" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9199148efbf3463493dd58c03a921add4623147739b9acd15f339b1dc5bfd677" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] [[package]] -name = "madgwick" -version = "0.1.1" +name = "wasm-bindgen-macro" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52760a80742f3053ff3b578eb14df5a881538584e22524ac915102dbf274b1bc" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ - "m", - "mat", + "quote", + "wasm-bindgen-macro-support", ] [[package]] -name = "madgwick-test" -version = "0.1.0" +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ - "madgwick", + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] -name = "mat" -version = "0.2.0" +name = "wasm-bindgen-shared" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8401e35d18e3132a68bed048083960c701cdb5ad386815ef5661863cc6da7ebd" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ - "generic-array", + "unicode-ident", ] [[package]] -name = "mavlink" -version = "0.13.1" -source = "git+https://github.com/uorocketry/rust-mavlink.git#e9f4057deedce85cae542fdbef75c5f56a360c9c" +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ - "bitflags 1.3.2", - "mavlink-bindgen", - "mavlink-core", - "num-derive", - "num-traits", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "mavlink-bindgen" -version = "0.13.1" -source = "git+https://github.com/uorocketry/rust-mavlink.git#e9f4057deedce85cae542fdbef75c5f56a360c9c" +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ - "crc-any", - "lazy_static", - "proc-macro2", - "quick-xml", - "quote", - "thiserror", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "mavlink-core" -version = "0.13.1" -source = "git+https://github.com/uorocketry/rust-mavlink.git#e9f4057deedce85cae542fdbef75c5f56a360c9c" +name = "wgpu" +version = "25.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8fb398f119472be4d80bc3647339f56eb63b2a331f6a3d16e25d8144197dd9" dependencies = [ - "byteorder", - "crc-any", - "embedded-hal 0.2.7", - "nb 1.1.0", + "arrayvec", + "bitflags 2.9.2", + "cfg_aliases", + "document-features", + "hashbrown 0.15.5", + "js-sys", + "log", + "naga", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", ] [[package]] -name = "memchr" -version = "2.7.4" +name = "wgpu-core" +version = "25.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f7b882196f8368511d613c6aeec80655160db6646aebddf8328879a88d54e500" +dependencies = [ + "arrayvec", + "bit-set", + "bit-vec", + "bitflags 2.9.2", + "cfg_aliases", + "document-features", + "hashbrown 0.15.5", + "indexmap", + "log", + "naga", + "once_cell", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror 2.0.15", + "wgpu-core-deps-apple", + "wgpu-core-deps-emscripten", + "wgpu-core-deps-windows-linux-android", + "wgpu-hal", + "wgpu-types", +] [[package]] -name = "messages" -version = "0.1.0" -source = "git+https://github.com/uorocketry/messages#5b9b56735beba4449d72e5ec074389d3363775a7" +name = "wgpu-core-deps-apple" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd488b3239b6b7b185c3b045c39ca6bf8af34467a4c5de4e0b1a564135d093d" dependencies = [ - "bitflags 2.6.0", - "chrono", - "defmt", - "derive_more", - "fugit", - "heapless 0.7.17", - "mavlink", - "messages-proc-macros-lib", - "serde", + "wgpu-hal", ] [[package]] -name = "messages-proc-macros-lib" -version = "0.1.0" -source = "git+https://github.com/uorocketry/messages#5b9b56735beba4449d72e5ec074389d3363775a7" +name = "wgpu-core-deps-emscripten" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f09ad7aceb3818e52539acc679f049d3475775586f3f4e311c30165cf2c00445" dependencies = [ - "quote", - "serde", + "wgpu-hal", ] [[package]] -name = "nb" -version = "0.1.3" +name = "wgpu-core-deps-windows-linux-android" +version = "25.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +checksum = "cba5fb5f7f9c98baa7c889d444f63ace25574833df56f5b817985f641af58e46" dependencies = [ - "nb 1.1.0", + "wgpu-hal", ] [[package]] -name = "nb" -version = "1.1.0" +name = "wgpu-hal" +version = "25.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +checksum = "f968767fe4d3d33747bbd1473ccd55bf0f6451f55d733b5597e67b5deab4ad17" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.9.2", + "block", + "bytemuck", + "cfg-if", + "cfg_aliases", + "core-graphics-types", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hashbrown 0.15.5", + "js-sys", + "khronos-egl", + "libc", + "libloading", + "log", + "metal", + "naga", + "ndk-sys", + "objc", + "ordered-float", + "parking_lot", + "portable-atomic", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "smallvec", + "thiserror 2.0.15", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "windows", + "windows-core", +] [[package]] -name = "num-derive" -version = "0.3.3" +name = "wgpu-types" +version = "25.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +checksum = "2aa49460c2a8ee8edba3fca54325540d904dd85b2e086ada762767e17d06e8bc" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "bitflags 2.9.2", + "bytemuck", + "js-sys", + "log", + "thiserror 2.0.15", + "web-sys", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "which" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ - "autocfg", + "either", + "home", + "once_cell", + "rustix 0.38.44", ] [[package]] -name = "panic-probe" -version = "0.3.2" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4047d9235d1423d66cc97da7d07eddb54d4f154d6c13805c6d0793956f4f25b0" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "cortex-m", - "defmt", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "paste" -version = "1.0.15" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "phoenix" -version = "0.1.0" +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "chrono", - "common-arm", - "cortex-m", - "cortex-m-rt", - "defmt", - "defmt-rtt", - "defmt-test", - "embedded-alloc", - "fdcan", - "heapless 0.7.17", - "madgwick", - "messages", - "panic-probe", - "postcard", - "rtic", - "rtic-monotonics", - "rtic-sync", - "stm32h7xx-hal", + "windows-sys 0.59.0", ] [[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pin-utils" -version = "0.1.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "portable-atomic" -version = "1.9.0" +name = "windows" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] [[package]] -name = "postcard" -version = "1.0.10" +name = "windows-core" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "cobs", - "defmt", - "heapless 0.7.17", - "serde", + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "windows-implement" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ - "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.109", - "version_check", + "syn 2.0.106", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "windows-interface" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "version_check", + "syn 2.0.106", ] [[package]] -name = "proc-macro2" -version = "1.0.89" +name = "windows-link" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" -dependencies = [ - "unicode-ident", -] +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] -name = "quick-xml" -version = "0.26.0" +name = "windows-result" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "memchr", + "windows-targets 0.52.6", ] [[package]] -name = "quote" -version = "1.0.37" +name = "windows-strings" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "proc-macro2", + "windows-result", + "windows-targets 0.52.6", ] [[package]] -name = "rtic" -version = "2.1.1" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c443db16326376bdd64377da268f6616d5f804aba8ce799bac7d1f7f244e9d51" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "atomic-polyfill", - "bare-metal 1.0.0", - "cortex-m", - "critical-section", - "rtic-core", - "rtic-macros", + "windows-targets 0.48.5", ] [[package]] -name = "rtic-common" -version = "1.0.0" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "critical-section", + "windows-targets 0.52.6", ] [[package]] -name = "rtic-core" -version = "1.0.0" +name = "windows-sys" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] [[package]] -name = "rtic-macros" -version = "2.1.0" +name = "windows-targets" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54053598ea24b1b74937724e366558412a1777eb2680b91ef646db540982789a" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "indexmap", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.85", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] -name = "rtic-monotonics" -version = "2.0.3" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1cb90bcfdbbacf3ca37340cdab52ec2de5611c744095ef7889e9c50c233b748" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "cfg-if", - "cortex-m", - "fugit", - "portable-atomic", - "proc-macro2", - "quote", - "rtic-time", - "stm32-metapac", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] -name = "rtic-playground" -version = "0.1.0" +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "chrono", - "common-arm", - "cortex-m", - "cortex-m-rt", - "defmt", - "defmt-rtt", - "embedded-alloc", - "fdcan", - "heapless 0.7.17", - "messages", - "panic-probe", - "postcard", - "rtic", - "rtic-monotonics", - "rtic-sync", - "stm32h7xx-hal", + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] -name = "rtic-sync" -version = "1.3.0" +name = "windows_aarch64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b1200137ccb2bf272a1801fa6e27264535facd356cb2c1d5bc8e12aa211bad" -dependencies = [ - "critical-section", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-hal-bus", - "heapless 0.8.0", - "portable-atomic", - "rtic-common", -] +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] -name = "rtic-time" -version = "2.0.0" +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7b1d853fa50dc125695414ce4510567a0d420221e455b1568cfa8c9aece9614" -dependencies = [ - "critical-section", - "embedded-hal 1.0.0", - "embedded-hal-async", - "fugit", - "futures-util", - "rtic-common", -] +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "rustc_version" -version = "0.2.3" +name = "windows_aarch64_gnullvm" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] -name = "rustc_version" -version = "0.4.1" +name = "windows_aarch64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver 1.0.23", -] +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] -name = "scopeguard" -version = "1.2.0" +name = "windows_aarch64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "semver" -version = "0.9.0" +name = "windows_aarch64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] -name = "semver" -version = "1.0.23" +name = "windows_i686_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] -name = "semver-parser" -version = "0.7.0" +name = "windows_i686_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "serde" -version = "1.0.213" +name = "windows_i686_gnu" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" -dependencies = [ - "serde_derive", -] +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" [[package]] -name = "serde_derive" -version = "1.0.213" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.85", -] +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] -name = "simple-playground" -version = "0.1.0" -dependencies = [ - "chrono", - "common-arm", - "cortex-m", - "cortex-m-rt", - "defmt", - "defmt-rtt", - "embedded-alloc", - "fdcan", - "heapless 0.7.17", - "messages", - "panic-probe", - "postcard", - "rtic", - "rtic-monotonics", - "rtic-sync", - "stm32h7xx-hal", -] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] -name = "spin" -version = "0.9.8" +name = "windows_i686_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] -name = "stable_deref_trait" -version = "1.2.0" +name = "windows_i686_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] -name = "static_assertions" -version = "1.1.0" +name = "windows_i686_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] -name = "stm32-metapac" -version = "15.0.0" +name = "windows_x86_64_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deabea56a8821dcea05d0109f3ab3135f31eb572444e5da203d06149c594c8c6" -dependencies = [ - "cortex-m", -] +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] -name = "stm32h7" -version = "0.15.1" +name = "windows_x86_64_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "362f288cd8341e9209587b889c385f323e82fc237b60c272868965bb879bb9b1" -dependencies = [ - "bare-metal 1.0.0", - "cortex-m", - "cortex-m-rt", - "vcell", -] +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] -name = "stm32h7xx-hal" -version = "0.16.0" -source = "git+https://github.com/uorocketry/stm32h7xx-hal#412160269f1729d55bc52de17463695db2c6bc6c" -dependencies = [ - "bare-metal 1.0.0", - "cast", - "chrono", - "cortex-m", - "defmt", - "embedded-dma", - "embedded-hal 0.2.7", - "embedded-storage", - "fdcan", - "fugit", - "nb 1.1.0", - "paste", - "stm32h7", - "void", -] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] -name = "syn" -version = "1.0.109" +name = "windows_x86_64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "memchr", ] [[package]] -name = "syn" -version = "2.0.85" +name = "wit-bindgen-rt" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "bitflags 2.9.2", ] [[package]] -name = "thiserror" -version = "1.0.65" +name = "xml-rs" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" + +[[package]] +name = "yoke" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ - "thiserror-impl", + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", ] [[package]] -name = "thiserror-impl" -version = "1.0.65" +name = "yoke-derive" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.106", + "synstructure", ] [[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-ident" -version = "1.0.13" +name = "zerocopy" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] [[package]] -name = "vcell" -version = "0.1.3" +name = "zerocopy-derive" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] [[package]] -name = "version_check" -version = "0.9.5" +name = "zerofrom" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] [[package]] -name = "void" -version = "1.0.2" +name = "zerofrom-derive" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "synstructure", +] [[package]] -name = "volatile-register" -version = "0.2.2" +name = "zip" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +checksum = "9cc23c04387f4da0374be4533ad1208cbb091d5c11d070dfef13676ad6497164" dependencies = [ - "vcell", + "arbitrary", + "crc32fast", + "crossbeam-utils", + "displaydoc", + "indexmap", + "num_enum", + "thiserror 1.0.69", ] diff --git a/Cargo.toml b/Cargo.toml index d55289a..e15c523 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,11 @@ [workspace] resolver = "2" -members = ["phoenix", "examples/*", "crates/*"] +members = ["phoenix", "crates/*"] # Specify which members to build by default. Some libraries, such as messages, contain dev-dependencies that will give # compile errors if built directly. -default-members = ["phoenix", "examples/*"] - -[workspace.dependencies.stm32h7xx-hal] -git = "https://github.com/uorocketry/stm32h7xx-hal" -# We use 35 even though we have the 33. -features = ["defmt", "rt", "stm32h735", "can", "rtc"] +default-members = ["phoenix"] [workspace.dependencies.serde] version = "1.0.150" @@ -19,13 +14,13 @@ features = ["derive"] [workspace.dependencies.cortex-m] version = "0.7.6" -features = ["critical-section-single-core"] +features = ["inline-asm", "critical-section-single-core"] [workspace.dependencies.cortex-m-rt] version = "0.7.1" [workspace.dependencies.embedded-hal] -version = "0.2.7" +version = "1.0.0" [workspace.dependencies.nb] version = "1.1.0" @@ -38,9 +33,6 @@ features = ["thumbv7-backend"] version = "2.0.2" features = ["cortex-m-systick", "stm32h733vg"] -[workspace.dependencies.postcard] -version = "1.0.2" - [workspace.dependencies.rtic-sync] version = "1.3.0" @@ -51,27 +43,58 @@ features = ["print-defmt"] [workspace.dependencies.defmt] version = "0.3.2" -[workspace.dependencies.fdcan] -version = "0.2" - [workspace.dependencies.defmt-rtt] version = "0.4" [workspace.dependencies.chrono] -git = "https://github.com/uorocketry/chrono" +#git = "https://github.com/uorocketry/chrono" +version = "0.4.41" default-features = false [workspace.dependencies.heapless] -version = "0.7.16" +version = "0.8" +default-features = false + +[workspace.dependencies.smlang] +version = "0.8.0" [workspace.dependencies.embedded-alloc] -version = "0.5.0" +version = "0.6.0" -[workspace.dependencies.messages] -git = "https://github.com/uorocketry/messages" +[workspace.dependencies.messages-prost] +git = "https://github.com/uorocketry/messages-prost" [workspace.dependencies.defmt-test] version = "0.3.2" [workspace.dependencies.madgwick] version = "0.1.1" + +[workspace.dependencies.prost] +version = "0.14.1" +default-features = false +features = ["derive"] + +[workspace.dependencies.prost-types] +version = "0.14.1" +default-features = false + +[profile.dev.package.sbg-rs] +opt-level = 0 +debug = true + +[profile.release.package.sbg-rs] +debug = true +opt-level = 0 + +[profile.release.build-override] +opt-level = 0 + +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +# lto = 'thin' +opt-level = 3 +overflow-checks = false \ No newline at end of file diff --git a/crates/common-arm/Cargo.toml b/crates/common-arm/Cargo.toml index c629dc4..744b766 100644 --- a/crates/common-arm/Cargo.toml +++ b/crates/common-arm/Cargo.toml @@ -11,12 +11,15 @@ defmt = {workspace = true} defmt-rtt = {workspace = true} heapless = "0.7.16" derive_more = "0.99.17" -embedded-sdmmc = "0.3.0" -messages = {workspace = true} -embedded-hal = {workspace = true} +messages-prost = {workspace = true} nb = {workspace = true} -stm32h7xx-hal = { workspace = true } panic-probe = { workspace = true } +embassy-time = { version = "0.4.0", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-embedded-hal = { version = "0.3.0" } +embedded-hal-async = { version = "1.0" } +embedded-nal-async = "0.8.0" +embedded-io-async = { version = "0.6.1" } +embedded-hal = "1.0.0" [dev-dependencies] defmt-test = { workspace = true } diff --git a/crates/common-arm/build.rs b/crates/common-arm/build.rs index 2fd894d..c2c4e4a 100644 --- a/crates/common-arm/build.rs +++ b/crates/common-arm/build.rs @@ -14,24 +14,24 @@ use std::io::Write; use std::path::PathBuf; fn main() { - // Put `memory.x` in our output directory and ensure it's - // on the linker search path. - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - println!("cargo:rustc-link-search={}", out.display()); + // // Put `memory.x` in our output directory and ensure it's + // // on the linker search path. + // let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + // File::create(out.join("memory.x")) + // .unwrap() + // .write_all(include_bytes!("memory.x")) + // .unwrap(); + // println!("cargo:rustc-link-search={}", out.display()); - // By default, Cargo will re-run a build script whenever - // any file in the project changes. By specifying `memory.x` - // here, we ensure the build script is only re-run when - // `memory.x` is changed. - println!("cargo:rerun-if-changed=memory.x"); + // // By default, Cargo will re-run a build script whenever + // // any file in the project changes. By specifying `memory.x` + // // here, we ensure the build script is only re-run when + // // `memory.x` is changed. + // println!("cargo:rerun-if-changed=memory.x"); - // set the linker script to the one provided by cortex-m-rt - println!("cargo:rustc-link-arg=-Tlink.x"); + // // set the linker script to the one provided by cortex-m-rt + // println!("cargo:rustc-link-arg=-Tlink.x"); - // we can also set our defmt script - println!("cargo:rustc-link-arg=-Tdefmt.x"); + // // we can also set our defmt script + // println!("cargo:rustc-link-arg=-Tdefmt.x"); } diff --git a/crates/common-arm/src/drivers/ms5611.rs b/crates/common-arm/src/drivers/ms5611.rs index 04d389f..815fe27 100644 --- a/crates/common-arm/src/drivers/ms5611.rs +++ b/crates/common-arm/src/drivers/ms5611.rs @@ -1,11 +1,395 @@ +// //! Driver for the MS5611 Barometric Pressure Sensor +// use embedded_hal::{ +// spi::{ +// SpiBus, +// }, +// digital::OutputPin, +// delay::DelayNs +// }; + +// // According to datasheet section 4.1 +// mod command { +// pub const RESET: u8 = 0x1E; +// pub const ADC_READ: u8 = 0x00; +// // Convert D1 (Pressure) +// pub const CONVERT_D1_OSR_256: u8 = 0x40; +// pub const CONVERT_D1_OSR_512: u8 = 0x42; +// pub const CONVERT_D1_OSR_1024: u8 = 0x44; +// pub const CONVERT_D1_OSR_2048: u8 = 0x46; +// pub const CONVERT_D1_OSR_4096: u8 = 0x48; +// // Convert D2 (Temperature) +// pub const CONVERT_D2_OSR_256: u8 = 0x50; +// pub const CONVERT_D2_OSR_512: u8 = 0x52; +// pub const CONVERT_D2_OSR_1024: u8 = 0x54; +// pub const CONVERT_D2_OSR_2048: u8 = 0x56; +// pub const CONVERT_D2_OSR_4096: u8 = 0x58; +// // PROM Read +// // pub const PROM_READ_ADDR_0: u8 = 0xA0; // Reserved +// pub const PROM_READ_ADDR_1: u8 = 0xA2; // C1 Pressure sensitivity (SENST1) +// pub const PROM_READ_ADDR_2: u8 = 0xA4; // C2 Pressure offset (OFFT1) +// pub const PROM_READ_ADDR_3: u8 = 0xA6; // C3 Temperature coefficient of pressure sensitivity (TCS) +// pub const PROM_READ_ADDR_4: u8 = 0xA8; // C4 Temperature coefficient of pressure offset (TCO) +// pub const PROM_READ_ADDR_5: u8 = 0xAA; // C5 Reference temperature (TREF) +// pub const PROM_READ_ADDR_6: u8 = 0xAC; // C6 Temperature coefficient of the temperature (TEMPSENS) +// // pub const PROM_READ_ADDR_7: u8 = 0xAE; // C7 Serial Code & CRC +// } + +// /// Oversampling Ratio (OSR) options +// /// Higher OSR means higher precision but longer conversion times and higher power consumption. +// #[derive(Copy, Clone, Debug, PartialEq, Eq)] +// pub enum OversamplingRatio { +// /// 256 samples, ~0.60 ms conversion time +// Osr256, +// /// 512 samples, ~1.17 ms conversion time +// Osr512, +// /// 1024 samples, ~2.28 ms conversion time +// Osr1024, +// /// 2048 samples, ~4.54 ms conversion time +// Osr2048, +// /// 4096 samples, ~9.04 ms conversion time +// Osr4096, +// } + +// impl OversamplingRatio { +// /// Get the command byte for starting a pressure (D1) conversion +// fn pressure_command(self) -> u8 { +// match self { +// OversamplingRatio::Osr256 => command::CONVERT_D1_OSR_256, +// OversamplingRatio::Osr512 => command::CONVERT_D1_OSR_512, +// OversamplingRatio::Osr1024 => command::CONVERT_D1_OSR_1024, +// OversamplingRatio::Osr2048 => command::CONVERT_D1_OSR_2048, +// OversamplingRatio::Osr4096 => command::CONVERT_D1_OSR_4096, +// } +// } + +// /// Get the command byte for starting a temperature (D2) conversion +// fn temperature_command(self) -> u8 { +// match self { +// OversamplingRatio::Osr256 => command::CONVERT_D2_OSR_256, +// OversamplingRatio::Osr512 => command::CONVERT_D2_OSR_512, +// OversamplingRatio::Osr1024 => command::CONVERT_D2_OSR_1024, +// OversamplingRatio::Osr2048 => command::CONVERT_D2_OSR_2048, +// OversamplingRatio::Osr4096 => command::CONVERT_D2_OSR_4096, +// } +// } + +// /// Get the maximum conversion time in microseconds (based on datasheet max values) +// fn conversion_time_us(self) -> u32 { +// match self { +// OversamplingRatio::Osr256 => 600, +// OversamplingRatio::Osr512 => 1_170, +// OversamplingRatio::Osr1024 => 2_280, +// OversamplingRatio::Osr2048 => 4_540, +// OversamplingRatio::Osr4096 => 9_040, +// } +// } +// } + +// /// Calibration Coefficients read from PROM +// #[derive(Debug, Clone, Copy)] +// struct CalibrationCoefficients { +// /// C1: Pressure sensitivity (SENST1) +// c1_sens_t1: u16, +// /// C2: Pressure offset (OFFT1) +// c2_off_t1: u16, +// /// C3: Temperature coefficient of pressure sensitivity (TCS) +// c3_tcs: u16, +// /// C4: Temperature coefficient of pressure offset (TCO) +// c4_tco: u16, +// /// C5: Reference temperature (TREF) +// c5_t_ref: u16, +// /// C6: Temperature coefficient of the temperature (TEMPSENS) +// c6_temp_sens: u16, +// // C7 (Serial/CRC) is read but maybe only used for CRC check, not stored here yet +// } + +// /// MS5611 Driver Error +// #[derive(Debug)] +// pub enum Error { +// /// SPI communication error +// Spi(SPIE), +// /// Chip Select pin error +// Cs(CSE), +// /// CRC check failed on PROM data (Not yet implemented) +// CrcError, +// /// Calculation resulted in an invalid value (e.g. NaN or Infinity) +// /// This might indicate issues with raw data or coefficients. +// CalculationFault, +// } + +// /// MS5611 Driver +// pub struct Ms5611 { +// spi: SPI, +// cs: CS, +// delay: DELAY, +// coefficients: CalibrationCoefficients, +// } + +// // Helper macro for handling CS pin toggling +// macro_rules! with_cs { +// ($self:expr, $block:expr) => {{ +// // Set CS low to start transaction +// $self.cs.set_low().map_err(Error::Cs)?; +// // Small delay might be needed depending on SPI speed and device, though often not. +// // $self.delay.delay_us(1); +// let result = $block; +// // Set CS high to end transaction +// $self.cs.set_high().map_err(Error::Cs)?; +// result +// }}; +// } + +// impl Ms5611 +// where +// SPI: SpiBus, +// CS: OutputPin, +// DELAY: DelayNs, +// { +// /// Creates a new MS5611 driver instance. +// /// Performs a reset, waits, and reads calibration coefficients from the PROM. +// pub fn new(spi: SPI, mut cs: CS, mut delay: DELAY) -> Result> { +// // Ensure CS is high initially +// cs.set_high().map_err(Error::Cs)?; +// delay.delay_us(100); // Small delay after power-up before reset + +// let mut sensor = Self { +// spi, +// cs, +// delay, +// // Placeholder coefficients, will be overwritten +// coefficients: CalibrationCoefficients { +// c1_sens_t1: 0, +// c2_off_t1: 0, +// c3_tcs: 0, +// c4_tco: 0, +// c5_t_ref: 0, +// c6_temp_sens: 0, +// }, +// }; + +// sensor.reset()?; +// // Datasheet: Wait 2.8 ms (max) after reset +// sensor.delay.delay_us(3000); + +// sensor.coefficients = sensor.read_coefficients()?; + +// // Optional: Implement CRC check here using PROM word 7 (0xAE) + +// Ok(sensor) +// } + +// /// Sends the Reset command to the sensor. +// fn reset(&mut self) -> Result<(), Error> { +// with_cs!(self, { +// self.spi.write(&[command::RESET]).map_err(Error::Spi) +// }) +// } + +// /// Reads a 16-bit word from the specified PROM address. +// /// +// /// This function is corrected to use the `embedded-hal` v1.0.0 `SpiBus::transfer` API properly. +// fn read_prom_word(&mut self, address_command: u8) -> Result> { +// with_cs!(self, { +// // To read the 16-bit (2-byte) PROM value, we perform a single SPI transaction. +// // We need to send 3 bytes in total to receive the 2 bytes of data. +// // +// // The transaction on the bus looks like this: +// // MOSI: [address_command, dummy_byte_1, dummy_byte_2] +// // MISO: [ garbage_byte, data_byte_1, data_byte_2] +// // +// // We use one `transfer` call for this. The first byte we receive while sending +// // the command is ignored. + +// // The buffer of data to send: command followed by two dummy bytes. +// let write_buffer = [address_command, 0x00, 0x00]; +// // A buffer to store the 3 bytes we receive. +// let mut read_buffer = [0u8; 3]; + +// // Perform the simultaneous write and read operation. +// self.spi.transfer(&mut read_buffer, &write_buffer).map_err(Error::Spi)?; + +// // The 16-bit result is in the second and third bytes of the read buffer. +// // We construct the u16 value from these bytes in big-endian order. +// Ok(u16::from_be_bytes([read_buffer[1], read_buffer[2]])) +// }) +// } + +// /// Reads all calibration coefficients (C1-C6) from the PROM. +// fn read_coefficients(&mut self) -> Result> { +// // Note: PROM address 0 (0xA0) is reserved, address 7 (0xAE) is CRC/Serial +// Ok(CalibrationCoefficients { +// c1_sens_t1: self.read_prom_word(command::PROM_READ_ADDR_1)?, +// c2_off_t1: self.read_prom_word(command::PROM_READ_ADDR_2)?, +// c3_tcs: self.read_prom_word(command::PROM_READ_ADDR_3)?, +// c4_tco: self.read_prom_word(command::PROM_READ_ADDR_4)?, +// c5_t_ref: self.read_prom_word(command::PROM_READ_ADDR_5)?, +// c6_temp_sens: self.read_prom_word(command::PROM_READ_ADDR_6)?, +// }) +// } + +// /// Sends a conversion command (Pressure or Temperature). +// fn start_conversion(&mut self, command: u8) -> Result<(), Error> { +// with_cs!(self, { self.spi.write(&[command]).map_err(Error::Spi) }) +// } + +// // /// Reads the 24-bit raw ADC result from the sensor. +// // pub fn read_adc_raw(&mut self) -> Result> { +// // with_cs!(self, { +// // // Send ADC Read command (0x00) to clock out the data +// // let mut buffer = [command::ADC_READ, 0x00, 0x00, 0x00]; // Send read cmd, receive 3 bytes +// // self.spi.transfer(&mut buffer).map_err(Error::Spi)?; +// // Ok(u32::from_be_bytes([0, buffer[1], buffer[2], buffer[3]])) // Pad to 4 bytes for u32 +// // }) +// // } + +// /// Reads the 24-bit raw ADC result from the sensor. +// /// +// /// This function is corrected to use the `embedded-hal` v1.0.0 `SpiBus::transfer` API properly. +// fn read_adc_raw(&mut self) -> Result> { +// with_cs!(self, { +// // To read the 24-bit (3-byte) ADC value, we need to send a 4-byte sequence. +// // The first byte is the ADC_READ command, followed by three dummy bytes +// // to provide the clock signals needed to read the 3 bytes of data. +// // +// // The transaction on the bus looks like this: +// // MOSI: [ADC_READ_CMD, dummy_byte_1, dummy_byte_2, dummy_byte_3] +// // MISO: [ garbage_byte, data_byte_1, data_byte_2, data_byte_3] +// // +// // We use a single `transfer` call for this entire operation. + +// // The buffer of data to send. +// let write_buffer = [command::ADC_READ, 0x00, 0x00, 0x00]; +// // A buffer to store the 4 bytes we receive. +// let mut read_buffer = [0u8; 4]; + +// // Perform the simultaneous write and read operation. +// self.spi.transfer(&mut read_buffer, &write_buffer).map_err(Error::Spi)?; + +// // The 24-bit result is in the last three bytes of the read buffer. +// // We construct a u32 value from these bytes, padding the most significant byte with 0. +// Ok(u32::from_be_bytes([0, read_buffer[1], read_buffer[2], read_buffer[3]])) +// }) +// } + +// /// Reads the raw temperature value (D2). +// /// Starts conversion, waits, and reads the ADC. +// pub fn read_raw_temperature( +// &mut self, +// osr: OversamplingRatio, +// ) -> Result> { +// self.start_conversion(osr.temperature_command())?; +// self.delay.delay_us(osr.conversion_time_us()); +// self.read_adc_raw() +// } + +// /// Reads the raw pressure value (D1). +// /// Starts conversion, waits, and reads the ADC. +// pub fn read_raw_pressure(&mut self, osr: OversamplingRatio) -> Result> { +// self.start_conversion(osr.pressure_command())?; +// self.delay.delay_us(osr.conversion_time_us()); +// self.read_adc_raw() +// } + +// /// Performs a full temperature and pressure reading cycle and returns compensated values. +// /// Reads temperature (D2), then pressure (D1), then performs calculations. +// /// +// /// Returns `(temperature_celsius, pressure_kpa)` +// pub fn read_pressure_temperature( +// &mut self, +// osr: OversamplingRatio, +// ) -> Result<(f32, f32), Error> { +// let d2_raw = self.read_raw_temperature(osr)?; +// let d1_raw = self.read_raw_pressure(osr)?; + +// self.calculate_compensated_values(d1_raw, d2_raw) +// } + +// /// Calculates compensated temperature and pressure using raw ADC values and PROM coefficients. +// /// Implements the 1st and 2nd order compensation formulas from the datasheet. +// /// +// /// Returns `(temperature_celsius, pressure_kpa)` +// fn calculate_compensated_values( +// &self, +// d1_raw: u32, // Raw Pressure +// d2_raw: u32, // Raw Temperature +// ) -> Result<(f32, f32), Error> { +// let c = &self.coefficients; + +// // Cast coefficients to i64 for intermediate calculations to prevent overflow +// let c1 = c.c1_sens_t1 as i64; +// let c2 = c.c2_off_t1 as i64; +// let c3 = c.c3_tcs as i64; +// let c4 = c.c4_tco as i64; +// let c5 = c.c5_t_ref as i64; +// let c6 = c.c6_temp_sens as i64; +// let d1 = d1_raw as i64; +// let d2 = d2_raw as i64; + +// // --- First Order Calculation --- +// // dT = D2 - C5 * 2^8 +// let dt = d2 - (c5 << 8); + +// // TEMP = 2000 + dT * C6 / 2^23 (Result in 0.01 degC) +// let temp_i32 = (2000 + ((dt * c6) >> 23)) as i32; // Cast to i32 for checks + +// // OFF = C2 * 2^16 + (C4 * dT) / 2^7 +// let off = (c2 << 16) + ((c4 * dt) >> 7); + +// // SENS = C1 * 2^15 + (C3 * dT) / 2^8 +// let sens = (c1 << 15) + ((c3 * dt) >> 8); + +// // --- Second Order Temperature Compensation --- +// let mut temp = temp_i32 as i64; // Use i64 for further calculations +// let mut off2 = 0i64; +// let mut sens2 = 0i64; +// let mut t2 = 0i64; + +// if temp < 2000 { +// // T2 = dT^2 / 2^31 +// t2 = (dt * dt) >> 31; + +// // OFF2 = 5 * (TEMP - 2000)^2 / 2 +// let temp_diff_sq = (temp - 2000) * (temp - 2000); +// off2 = 5 * temp_diff_sq >> 1; // Divide by 2 + +// // SENS2 = 5 * (TEMP - 2000)^2 / 4 +// sens2 = 5 * temp_diff_sq >> 2; // Divide by 4 + +// if temp < -1500 { +// // OFF2 = OFF2 + 7 * (TEMP + 1500)^2 +// let temp_low_diff_sq = (temp + 1500) * (temp + 1500); +// off2 += 7 * temp_low_diff_sq; +// // SENS2 = SENS2 + 11 * (TEMP + 1500)^2 / 2 +// sens2 += 11 * temp_low_diff_sq >> 1; // Divide by 2 +// } +// } + +// // Apply second order corrections +// temp -= t2; +// let off_compensated = off - off2; +// let sens_compensated = sens - sens2; + +// // --- Final Pressure Calculation --- +// // P = (D1 * SENS / 2^21 - OFF) / 2^15 (Result in 0.01 mbar) +// let p_i32 = (((d1 * sens_compensated) >> 21) - off_compensated) >> 15; // Cast to i32 + +// // Convert to final units (float) +// // Handle potential division by zero or NaN/Infinity results from float conversion +// let temp_celsius = temp as f32 / 100.0; +// // p_i32 is in 0.01 mbar. 1 mbar = 0.1 kPa. So p_i32 / 1000.0 gives kPa. +// let pressure_kpa = p_i32 as f32 / 1000.0; + +// // Check for NaN or Infinity which might occur if intermediate calculations were extreme +// if temp_celsius.is_finite() && pressure_kpa.is_finite() { +// Ok((temp_celsius, pressure_kpa)) +// } else { +// Err(Error::CalculationFault) +// } +// } +// } + //! Driver for the MS5611 Barometric Pressure Sensor -use embedded_hal::{ - blocking::{ - delay::DelayUs, - spi::{Transfer, Write}, - }, - digital::v2::OutputPin, -}; +use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiBus}; // According to datasheet section 4.1 mod command { @@ -141,9 +525,9 @@ macro_rules! with_cs { impl Ms5611 where - SPI: Transfer + Write, + SPI: SpiBus, CS: OutputPin, - DELAY: DelayUs, + DELAY: DelayNs, { /// Creates a new MS5611 driver instance. /// Performs a reset, waits, and reads calibration coefficients from the PROM. @@ -186,19 +570,33 @@ where } /// Reads a 16-bit word from the specified PROM address. + /// + /// This function is corrected to use the `embedded-hal` v1.0.0 `SpiBus::transfer` API properly. fn read_prom_word(&mut self, address_command: u8) -> Result> { with_cs!(self, { - // 1. Send PROM read command for the specific address - // We only write the command, ignore anything read back during this byte. - self.spi.write(&[address_command]).map_err(Error::Spi)?; - - // 2. Immediately transfer two dummy bytes (e.g., 0x00) to clock out - // the 16-bit result from the sensor. - let mut buffer = [0u8; 2]; // Buffer to receive the 2 bytes - self.spi.transfer(&mut buffer).map_err(Error::Spi)?; - - // 3. Construct the u16 result from the received bytes. - Ok(u16::from_be_bytes([buffer[0], buffer[1]])) + // To read the 16-bit (2-byte) PROM value, we perform a single SPI transaction. + // We need to send 3 bytes in total to receive the 2 bytes of data. + // + // The transaction on the bus looks like this: + // MOSI: [address_command, dummy_byte_1, dummy_byte_2] + // MISO: [ garbage_byte, data_byte_1, data_byte_2] + // + // We use one `transfer` call for this. The first byte we receive while sending + // the command is ignored. + + // The buffer of data to send: command followed by two dummy bytes. + let write_buffer = [address_command, 0x00, 0x00]; + // A buffer to store the 3 bytes we receive. + let mut read_buffer = [0u8; 3]; + + // Perform the simultaneous write and read operation. + self.spi + .transfer(&mut read_buffer, &write_buffer) + .map_err(Error::Spi)?; + + // The 16-bit result is in the second and third bytes of the read buffer. + // We construct the u16 value from these bytes in big-endian order. + Ok(u16::from_be_bytes([read_buffer[1], read_buffer[2]])) }) } @@ -220,13 +618,49 @@ where with_cs!(self, { self.spi.write(&[command]).map_err(Error::Spi) }) } + // /// Reads the 24-bit raw ADC result from the sensor. + // pub fn read_adc_raw(&mut self) -> Result> { + // with_cs!(self, { + // // Send ADC Read command (0x00) to clock out the data + // let mut buffer = [command::ADC_READ, 0x00, 0x00, 0x00]; // Send read cmd, receive 3 bytes + // self.spi.transfer(&mut buffer).map_err(Error::Spi)?; + // Ok(u32::from_be_bytes([0, buffer[1], buffer[2], buffer[3]])) // Pad to 4 bytes for u32 + // }) + // } + /// Reads the 24-bit raw ADC result from the sensor. - pub fn read_adc_raw(&mut self) -> Result> { + /// + /// This function is corrected to use the `embedded-hal` v1.0.0 `SpiBus::transfer` API properly. + fn read_adc_raw(&mut self) -> Result> { with_cs!(self, { - // Send ADC Read command (0x00) to clock out the data - let mut buffer = [command::ADC_READ, 0x00, 0x00, 0x00]; // Send read cmd, receive 3 bytes - self.spi.transfer(&mut buffer).map_err(Error::Spi)?; - Ok(u32::from_be_bytes([0, buffer[1], buffer[2], buffer[3]])) // Pad to 4 bytes for u32 + // To read the 24-bit (3-byte) ADC value, we need to send a 4-byte sequence. + // The first byte is the ADC_READ command, followed by three dummy bytes + // to provide the clock signals needed to read the 3 bytes of data. + // + // The transaction on the bus looks like this: + // MOSI: [ADC_READ_CMD, dummy_byte_1, dummy_byte_2, dummy_byte_3] + // MISO: [ garbage_byte, data_byte_1, data_byte_2, data_byte_3] + // + // We use a single `transfer` call for this entire operation. + + // The buffer of data to send. + let write_buffer = [command::ADC_READ, 0x00, 0x00, 0x00]; + // A buffer to store the 4 bytes we receive. + let mut read_buffer = [0u8; 4]; + + // Perform the simultaneous write and read operation. + self.spi + .transfer(&mut read_buffer, &write_buffer) + .map_err(Error::Spi)?; + + // The 24-bit result is in the last three bytes of the read buffer. + // We construct a u32 value from these bytes, padding the most significant byte with 0. + Ok(u32::from_be_bytes([ + 0, + read_buffer[1], + read_buffer[2], + read_buffer[3], + ])) }) } diff --git a/crates/common-arm/src/error/error_manager.rs b/crates/common-arm/src/error/error_manager.rs index a462c02..2559118 100644 --- a/crates/common-arm/src/error/error_manager.rs +++ b/crates/common-arm/src/error/error_manager.rs @@ -1,11 +1,9 @@ use crate::error::hydra_error::HydraError; -use crate::herror; use core::cell::RefCell; use core::sync::atomic::AtomicBool; use core::sync::atomic::Ordering::Relaxed; use cortex_m::interrupt; use cortex_m::interrupt::Mutex; -use defmt::error; use heapless::HistoryBuffer; /// Central error management for HYDRA. A single instance of this should be created for each board. @@ -43,8 +41,17 @@ impl ErrorManager { self.has_error.store(true, Relaxed); if let Some(c) = e.get_context() { - error!("{}", e); - herror!(Error, c); + match c { + messages_prost::common::ErrorContext::GroundStation => {} + + messages_prost::common::ErrorContext::NoRadioTransfer => {} + + messages_prost::common::ErrorContext::UnknownRadioMessage => {} + + messages_prost::common::ErrorContext::UnkownCanMessage => {} + + messages_prost::common::ErrorContext::UnkownProstMessage => {} + } } interrupt::free(|cs| { diff --git a/crates/common-arm/src/error/hydra_error.rs b/crates/common-arm/src/error/hydra_error.rs index 88d339e..0c85edb 100644 --- a/crates/common-arm/src/error/hydra_error.rs +++ b/crates/common-arm/src/error/hydra_error.rs @@ -1,13 +1,12 @@ // use atsamd_hal::dmac; use core::convert::Infallible; -use defmt::{write, Format}; +use defmt::write; use derive_more::From; -use embedded_sdmmc as sd; -use messages::ErrorContext; use nb::Error as NbError; use crate::drivers::ms5611; /// Open up atsamd hal errors without including the whole crate. +use messages_prost::common::ErrorContext; /// Contains all the various error types that can be encountered in the Hydra codebase. Extra errors /// types should be added to this list whenever needed. @@ -19,13 +18,9 @@ pub enum HydraErrorType { PostcardError(postcard::Error), /// Error that occurred while spawning an RTIC task. Contains the name of the failed task. SpawnError(&'static str), - /// Error from the SD card library. - SdCardError(sd::Error), - /// Error from the Baro driver. - BaroError(ms5611::Error), /// Error from the Mavlink library. - MavlinkError(messages::mavlink::error::MessageWriteError), - MavlinkReadError(messages::mavlink::error::MessageReadError), + MavlinkError(messages_prost::mavlink::error::MessageWriteError), + MavlinkReadError(messages_prost::mavlink::error::MessageReadError), NbError(NbError), } @@ -41,9 +36,6 @@ impl defmt::Format for HydraErrorType { HydraErrorType::SpawnError(e) => { write!(f, "Could not spawn task '{}'", e); } - HydraErrorType::SdCardError(_) => { - write!(f, "SD card error!"); - } HydraErrorType::MavlinkError(_) => { write!(f, "Mavlink error!"); } @@ -53,16 +45,12 @@ impl defmt::Format for HydraErrorType { HydraErrorType::NbError(_) => { write!(f, "Nb error!"); } - HydraErrorType::BaroError(_) => { - write!(f, "Baro error!"); - } } } } /// Standard HYDRA error. This type should be used as the return type for most functions that can /// fail and that returns a `Result`. -#[derive(Format)] pub struct HydraError { error: HydraErrorType, context: Option, diff --git a/crates/common-arm/src/lib.rs b/crates/common-arm/src/lib.rs index 157bb89..c229cf9 100644 --- a/crates/common-arm/src/lib.rs +++ b/crates/common-arm/src/lib.rs @@ -8,12 +8,8 @@ pub mod drivers; mod error; -mod logging; -mod sd_manager; pub use crate::error::error_manager::ErrorManager; pub use crate::error::hydra_error::{ErrorContextTrait, HydraError, SpawnError}; -pub use crate::logging::HydraLogging; -pub use crate::sd_manager::SdManager; use defmt_rtt as _; // global logger diff --git a/crates/common-arm/src/logging.rs b/crates/common-arm/src/logging.rs deleted file mode 100644 index c7ebcad..0000000 --- a/crates/common-arm/src/logging.rs +++ /dev/null @@ -1,60 +0,0 @@ -use messages::{Event, Log, LogLevel}; - -static mut GROUND_STATION_CALLBACK: Option = None; - -/// Log an informational message. This message will be logged using defmt, and if configured, sent -/// to the ground station. As arguments, it takes an event from the [`Event`] enum, along with its -/// fields if needed. -#[macro_export] -macro_rules! hinfo { - ($e:ident$(,)? $($p:expr),*) => { - $crate::HydraLogging::log(messages::LogLevel::Info, messages::Event::$e($($p),*)); - defmt::info!("{}", messages::Event::$e($($p),*)); - }; -} - -/// Log an warning message. This message will be logged using defmt, and if configured, sent -/// to the ground station. As arguments, it takes an event from the [`Event`] enum, along with its -/// fields if needed. -#[macro_export] -macro_rules! hwarning { - ($e:ident$(,)? $($p:expr),*) => { - $crate::HydraLogging::log(messages::LogLevel::Warning, messages::Event::$e($($p),*)); - defmt::warning!("{}", messages::Event::$e($($p),*)); - }; -} - -/// Log an error message. This message will be logged using defmt, and if configured, sent -/// to the ground station. As arguments, it takes an event from the [`Event`] enum, along with its -/// fields if needed. -#[macro_export] -macro_rules! herror { - ($e:ident$(,)? $($p:expr),*) => { - $crate::HydraLogging::log(messages::LogLevel::Error, messages::Event::$e($($p),*)); - defmt::error!("{}", messages::Event::$e($($p),*)); - }; -} - -pub struct HydraLogging {} - -impl HydraLogging { - /// Set the function for sending log messages the ground station. This should be called during - /// ONCE during init, and NEVER after to avoid any race conditions. - pub fn set_ground_station_callback(cb: fn(Log)) { - // SAFETY: - // This is called once during init, so any race conditions should not be a concern. - unsafe { GROUND_STATION_CALLBACK = Some(cb) } - } - - /// Log a message using the callback set in [`HydraLogging::set_ground_station_callback`]. - /// While this function can be called directly, usually the [`hinfo`] and similar macros would - /// be used instead. - pub fn log(level: LogLevel, event: Event) { - // SAFETY: - // Since the static mut should only be written once during init and never after, reading - // this variable is fine. - if let Some(x) = unsafe { GROUND_STATION_CALLBACK } { - x(Log::new(level, event)) - } - } -} diff --git a/crates/common-arm/src/sd_manager.rs b/crates/common-arm/src/sd_manager.rs deleted file mode 100644 index 9e087b7..0000000 --- a/crates/common-arm/src/sd_manager.rs +++ /dev/null @@ -1,145 +0,0 @@ -use core::{fmt::Debug, marker::PhantomData}; -use defmt::info; -use defmt::panic; -use embedded_hal as hal; -use embedded_sdmmc as sd; -use hal::spi::FullDuplex; - -/// Time source for `[SdInterface]`. It doesn't return any useful information for now, and will -/// always return an arbitrary time. -pub struct TimeSink { - _marker: PhantomData<*const ()>, -} - -impl TimeSink { - fn new() -> Self { - TimeSink { - _marker: PhantomData, - } - } -} - -impl sd::TimeSource for TimeSink { - fn get_timestamp(&self) -> sd::Timestamp { - sd::Timestamp { - year_since_1970: 0, - zero_indexed_month: 0, - zero_indexed_day: 0, - hours: 0, - minutes: 0, - seconds: 0, - } - } -} - -/// Wrapper for the SD Card. For now, the pins are hard-coded. -pub struct SdManager -where - SPI: hal::spi::FullDuplex, - >::Error: Debug, - CS: hal::digital::v2::OutputPin, -{ - pub sd_controller: sd::Controller, TimeSink>, - pub volume: sd::Volume, - pub root_directory: sd::Directory, - pub file: Option, -} - -impl SdManager -where - SPI: hal::spi::FullDuplex, - >::Error: Debug, - CS: hal::digital::v2::OutputPin, -{ - pub fn new(spi: SPI, cs: CS) -> Self { - let time_sink: TimeSink = TimeSink::new(); // Need to give this a DateTime object for actual timing. - info!("Initializing SD card"); - let mut sd_cont = sd::Controller::new(sd::SdMmcSpi::new(spi, cs), time_sink); - match sd_cont.device().init() { - Ok(_) => match sd_cont.device().card_size_bytes() { - Ok(size) => info!("Card is {} bytes", size), - Err(_) => panic!("Cannot get card size"), - }, - Err(_) => { - panic!("Cannot get SD card."); - } - } - - let mut volume = match sd_cont.get_volume(sd::VolumeIdx(0)) { - Ok(volume) => volume, - Err(_) => { - panic!("Cannot get volume 0"); - } - }; - - let root_directory = match sd_cont.open_root_dir(&volume) { - Ok(root_directory) => root_directory, - Err(_) => { - panic!("Cannot get root"); - } - }; - let file = sd_cont.open_file_in_dir( - &mut volume, - &root_directory, - "lc24.txt", - sd::Mode::ReadWriteCreateOrTruncate, - ); - let file = match file { - Ok(file) => file, - Err(_) => { - panic!("Cannot create file."); - } - }; - - SdManager { - sd_controller: sd_cont, - volume, - root_directory, - file: Some(file), - } - } - pub fn write( - &mut self, - file: &mut sd::File, - buffer: &[u8], - ) -> Result> { - self.sd_controller.write(&mut self.volume, file, buffer) - } - pub fn write_str( - &mut self, - file: &mut sd::File, - msg: &str, - ) -> Result> { - let buffer: &[u8] = msg.as_bytes(); - self.sd_controller.write(&mut self.volume, file, buffer) - } - pub fn open_file(&mut self, file_name: &str) -> Result> { - self.sd_controller.open_file_in_dir( - &mut self.volume, - &self.root_directory, - file_name, - sd::Mode::ReadWriteCreateOrTruncate, - ) - } - pub fn close_current_file(&mut self) -> Result<(), sd::Error> { - if let Some(file) = self.file.take() { - return self.close_file(file); - } - Ok(()) - } - pub fn close_file(&mut self, file: sd::File) -> Result<(), sd::Error> { - self.sd_controller.close_file(&self.volume, file) - } - pub fn close(mut self) { - self.sd_controller - .close_dir(&self.volume, self.root_directory); - } -} - -unsafe impl Send for SdManager -where - SPI: hal::spi::FullDuplex, - >::Error: Debug, - CS: hal::digital::v2::OutputPin, -{ -} diff --git a/crates/madgwick-test/src/lib.rs b/crates/madgwick-test/src/lib.rs index c97a878..e64aaca 100644 --- a/crates/madgwick-test/src/lib.rs +++ b/crates/madgwick-test/src/lib.rs @@ -12,31 +12,48 @@ impl MadgwickTest { // Default values as constants will be used if parameters cannot be used const DEFAULT_BETA: f32 = 0.1; const DEFAULT_SAMPLE_PERIOD: f32 = 0.01; // 100Hz - + pub fn new() -> Self { // Beta and sample period values will be passed through the filter Self::new_with_params(Self::DEFAULT_BETA, Self::DEFAULT_SAMPLE_PERIOD) } - + // New constructor that accepts parameters pub fn new_with_params(beta: f32, sample_period: f32) -> Self { // Create the filter with specified parameters let mut madgwick = Marg::new(beta, sample_period); - + // Initialize with standard gravity measurements - let accel = madgwick::F32x3 { x: 0.0, y: 0.0, z: 1.0 }; // "z: 1.0" represents the accelerometer pointing in the positive z-direction (upwards) - let gyro = madgwick::F32x3 { x: 0.0, y: 0.0, z: 0.0 }; - let mag = madgwick::F32x3 { x: 1.0, y: 0.0, z: 0.0 }; // "x: 1.0" represents the magnetometer pointing in the positive x-direction - + let accel = madgwick::F32x3 { + x: 0.0, + y: 0.0, + z: 1.0, + }; // "z: 1.0" represents the accelerometer pointing in the positive z-direction (upwards) + let gyro = madgwick::F32x3 { + x: 0.0, + y: 0.0, + z: 0.0, + }; + let mag = madgwick::F32x3 { + x: 1.0, + y: 0.0, + z: 0.0, + }; // "x: 1.0" represents the magnetometer pointing in the positive x-direction + // Get initial quaternion from filter let mut quat = (1.0, 0.0, 0.0, 0.0); // Default identity quaternion - + // Apply multiple updates to ensure convergence for _ in 0..5 { let updated_quat = madgwick.update(mag, gyro, accel); - quat = (updated_quat.0, updated_quat.1, updated_quat.2, updated_quat.3); + quat = ( + updated_quat.0, + updated_quat.1, + updated_quat.2, + updated_quat.3, + ); } - + Self { madgwick, initial_quat: quat, // Use the quaternion from the filter @@ -44,7 +61,11 @@ impl MadgwickTest { } pub fn update(&mut self, accel: [f32; 3], gyro: [f32; 3]) -> (f32, f32, f32, f32) { - let mag = madgwick::F32x3 { x: 0.0, y: 0.0, z: 0.0 }; + let mag = madgwick::F32x3 { + x: 0.0, + y: 0.0, + z: 0.0, + }; let gyro = madgwick::F32x3 { x: gyro[0], y: gyro[1], @@ -64,12 +85,12 @@ impl MadgwickTest { // Return our stored quaternion self.initial_quat } - + // Methods to get and set parameters pub fn get_beta(&self) -> f32 { Self::DEFAULT_BETA // For now we return the default, would need access to inner filter } - + pub fn get_sample_period(&self) -> f32 { Self::DEFAULT_SAMPLE_PERIOD // For now we return the default, would need access to inner filter } @@ -83,54 +104,56 @@ mod tests { #[test] fn test_madgwick_initialization() { let service = MadgwickTest::new(); - + // Get the quaternion (already initialized during construction) let (w, x, y, z) = service.get_quaternion(); - + // Check quaternion is roughly identity (or close to it) assert!(w > 0.9, "Expected w to be close to 1.0, got {}", w); assert!(x.abs() < 0.1, "Expected x to be close to 0.0, got {}", x); assert!(y.abs() < 0.1, "Expected y to be close to 0.0, got {}", y); assert!(z.abs() < 0.1, "Expected z to be close to 0.0, got {}", z); } - - // Custom Parameters Test (making sure madgwick works with values being passed through rather than using default constants) + + // Custom Parameters Test (making sure madgwick works with values being passed through rather than using default constants) #[test] fn test_custom_parameters() { // Test with custom beta and sample period let service = MadgwickTest::new_with_params(0.05, 0.02); - + // Get the quaternion (already initialized during construction) let (w, x, y, z) = service.get_quaternion(); - + // Check quaternion is roughly identity (or close to it) assert!(w > 0.9, "Expected w to be close to 1.0, got {}", w); assert!(x.abs() < 0.1, "Expected x to be close to 0.0, got {}", x); assert!(y.abs() < 0.1, "Expected y to be close to 0.0, got {}", y); assert!(z.abs() < 0.1, "Expected z to be close to 0.0, got {}", z); } - + // Continuous Updates Test (making sure that the service is constantly being updated while running so accurate values are being used) #[test] fn test_continuous_updates() { let mut service = MadgwickTest::new(); - + // Store initial quaternion let (w1, x1, y1, z1) = service.get_quaternion(); - + // Process 10 updates with Y-axis gravity and Z-axis rotation for _ in 0..10 { service.update([0.0, 1.0, 0.0], [0.0, 0.0, 0.1]); } - + // Get the updated quaternion let latest_update = service.update([0.0, 1.0, 0.0], [0.0, 0.0, 0.0]); - + // Verify quaternion changed - comparing initial with latest update result assert!( - (w1 != latest_update.0) || (x1 != latest_update.1) || - (y1 != latest_update.2) || (z1 != latest_update.3), + (w1 != latest_update.0) + || (x1 != latest_update.1) + || (y1 != latest_update.2) + || (z1 != latest_update.3), "Quaternion should change after processing gyroscope data" ); } -} \ No newline at end of file +} diff --git a/crates/sbg-rs/Cargo.toml b/crates/sbg-rs/Cargo.toml new file mode 100644 index 0000000..a1725e3 --- /dev/null +++ b/crates/sbg-rs/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "sbg-rs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +embedded-hal = "1.0.0" +nb = "1.0.0" +defmt = "0.3.2" +cortex-m = { workspace = true } +serde = { workspace = true } + +cortex-m-rt = "^0.7.0" +messages-prost = { workspace = true } +common-arm = { path = "../../crates/common-arm" } +heapless = "0.7.16" +bitflags = { version = "2.4.2", features = ["serde"] } + +[build-dependencies] +cmake = "0.1" + +[package.metadata] +# Silence all warnings due to a large portion of the autogenerated +# bindings being consisted of unused imports and unreachable patterns. +# These warnings are not actionable and would +# otherwise obscure real issues during development. +rustflags = ["-Awarnings"] diff --git a/crates/sbg-rs/build.rs b/crates/sbg-rs/build.rs new file mode 100644 index 0000000..704434f --- /dev/null +++ b/crates/sbg-rs/build.rs @@ -0,0 +1,9 @@ +fn main() { + let dst = cmake::build("sbgECom").join("build"); + + println!("cargo:rustc-link-search={}", dst.display()); + println!("cargo:rustc-link-lib=static=sbgECom"); + + println!("cargo:rerun-if-changed=wrapper.h"); + println!("cargo:rerun-if-changed=sbgECom"); +} diff --git a/crates/sbg-rs/generateBindings.md b/crates/sbg-rs/generateBindings.md new file mode 100644 index 0000000..c07011e --- /dev/null +++ b/crates/sbg-rs/generateBindings.md @@ -0,0 +1,10 @@ +To generate the SBG bindings: +1. Install `bindgen`: +``` +cargo install bindgen-cli +``` +2. Make sure the GCC ARM cross-compiler (`gcc-arm-none-eabi`) is installed on your computer. It can also be downloaded here: https://developer.arm.com/downloads/-/gnu-rm +3. Run `bindgen`, replacing the `--sysroot` with the correct path +``` +bindgen ../wrapper.h -o bindings.rs --use-core -- -I./src -I./common --sysroot=/usr/arm-none-eabi/ -target thumbv7em-none-eabihf -mcpu=cortex-m4 -mthumb -mfloat-abi=hard +``` diff --git a/crates/sbg-rs/sbgECom/CHANGELOG.md b/crates/sbg-rs/sbgECom/CHANGELOG.md new file mode 100644 index 0000000..cb3a339 --- /dev/null +++ b/crates/sbg-rs/sbgECom/CHANGELOG.md @@ -0,0 +1,303 @@ +# Change Log +This change log lists all modifications for each sbgECom library release. + +sbgECom C library change log issued on: 2022-11-15 +Copyright (C) 2022, SBG Systems SAS. All rights reserved. + +## Release Summary + +The sbgECom 3.2.4011-stable release adds support to latest High Performance INS firmware 4.2 and ELLIPSE firmware 2.5 +New configurations and output logs have been added such as `SBG_ECOM_LOG_GPS#_SAT` binary log. + +It also adds two new commands sbgEComCmdApiGet and sbgEComCmdApiPost to support the new [sbgInsRestApi](https://developer.sbg-systems.com/sbgInsRestApi/) over serial interfaces. + +A new extended sbgECom frame format has been introduced to support large payloads. +This new format is fully backward compatible and your code, as well as older firmware, should still work with this new sbgECom implementation. + +New tools and examples have been added to ease product evaluation and integration. + +This release also improves the overall code quality, documentation and examples. + +## Import Highlights for this release + +Please find below, the main improvements and modifications: + - Support for latest firmware + - Support for new sbgInsRestApi GET/POST commands + - New sbgEComBasicLogger tool to convert logs to CSV files + - New sbgEComApi tool to use the sbgInsRestApi from command line + - Improved sbgECom frame for large payloads + - Improved ELLIPSE on-board magnetic calibration example + - Improve code quality + - Improved Doxygen documentation + - Improved CMake & GitHub support + +## Release - 3.2.4011-stable + +### New Features + - [SBGECOM-306] - Added built in CHANGELOG file in the repository + - [SBGECOM-307] - Add support for event markers in sbgBasicLogger + - [SBGECOM-309] - Add SBG_ECOM_LOG_GPS#_SAT message containing satellite information + - [SBGECOM-310] - Add NMEA message GPROT + - [SBGECOM-312] - sbgBasicLogger: handle sbgEComLogSat messages + - [SBGECOM-313] - Added a static motion profile for 27/7 operations on ELLIPSE + - [SBGECOM-314] - Added pedestrian motion profile that uses foot odometry + - [SBGECOM-317] - Added search capabilities for Doxygen documentation + - [SBGECOM-319] - Add support for the Teledyne Wayfinder DVL protocol + - [SBGECOM-323] - Add a new PSBGA NMEA message that output the INS atitude + - [SBGECOM-326] - Add NMEA GSV output message with satellite in view information + - [SBGECOM-327] - Added L-Band support for GNSS receiver channel reporting + +### Improvements +- [SBGECOM-311] - Improve public CMakeLists +- [SBGECOM-315] - Enable sbgEComApi users to provide command execution parameters +- [SBGECOM-322] - Added Truck and Railway motion profiles +- [SBGECOM-325] - sbgBasicLogger: Improve project code and build script for code source public release +- [SBGECOM-328] - Improved doxygen documentation + +### Bug Fixes +- [SBGECOM-316] - Fix ELLIPSE settings import that was not working +- [SBGECOM-324] - Fix invalid time-out errors when calling sbgEComReceiveCmd2 + +## Release - 3.1.2358-stable + +### New Features + - [SBGECOM-225] - Added KMB binary sensor output log for High Performance INS + - [SBGECOM-226] - Add a new log SBG_ECOM_LOG_RTCM_STREAM + - [SBGECOM-228] - Add new commands to implement GET/POST over sbgECom protocol + - [SBGECOM-229] - Now ELLIPSE-N and D can accept RTCM corrections over Port A + - [SBGECOM-231] - Add support for NMEA PPS frames + - [SBGECOM-253] - Add specific NMEA like output log WASSP + - [SBGECOM-279] - Add in SBG_ECOM_CMD_ADVANCED_CONF a GNSS option bitmask + - [SBGECOM-281] - Add a new sbgBasicLogger command line tool + - [SBGECOM-282] - Add a sbgEComApi CLI tool to access sbgInsRestApi over sbgECom + - [SBGECOM-283] - Add a minimal sbgECom example for PULSE IMU + - [SBGECOM-285] - Add in SBG_ECOM_CMD_ADVANCED_CONF an option to always output time in NMEA messages + - [SBGECOM-286] - Add in SBG_ECOM_CMD_ADVANCED_CONF an option select standard or extended NMEA mode + +### Improvements + - [SBGECOM-181] - Reduce stack usage and use new sbgEComReceiveCmd2 + - [SBGECOM-220] - Updated license to MIT + - [SBGECOM-232] - Updated protocol to support large transfer using multiple pages + - [SBGECOM-287] - Updated sbgEComSetReceiveLogCallback to remove the unused SbgErrorCode return + - [SBGECOM-301] - Improved ELLIPSE onboard magnetic calibration code example + - [SBGECOM-302] - Added new sbgEComPurgeIncoming method to discard rx data + - [SBGECOM-303] - Improved examples, they now use simple CLI arguments + +### Bug Fixes + - [SBGECOM-265] - Add missing 25ms period to output log message definitions + - [SBGECOM-267] - Add missing 40ms period to output log message definitions + - [SBGECOM-284] - Receive a command must not be blocking when timeout = 0 + - [SBGECOM-289] - Fix SBG_ECAN_MSG_GPS#_ALT NUM_SV & DIFF_CORR DBC/DBF definitions + +## Release - 2.0.4536-stable + +### New Features + - [SBGECOM-180] - Added NMEA GGK message output + - [SBGECOM-191] - Added in SBG_ECOM_LOG_GPS#_POS status report for all GNSS constellations + - [SBGECOM-194] - Add specific SBG_ECOM_THIRD_PARTY_ADA_01 output log + - [SBGECOM-208] - Added a README.md file with migration guidelines + - [SBGECOM-216] - Add Cobham SBG_ECOM_THIRD_PARTY_AT_ITINS output log support + - [SBGECOM-219] - Added CAN dbc and BusMaster definitions in sbgECom project +### Improvements + - [SBGECOM-188] - Updated SBG_ECAN_MSG_ODO_VELOCITY from float field to integers + - [SBGECOM-196] - Added status field for SBG_ECAN_MSG_AUTO_TRACK_SLIP_CURV (0x220) message + - [SBGECOM-199] - Simplified SbgEComGnssModelsStdIds enum for ELLIPSE-N and ELLIPSE-D + - [SBGECOM-204] - Renamed SBG_ECOM_GNSS_MODEL_UBLOX_GPS_GLONASS to SBG_ECOM_GNSS_MODEL_INTERNAL + - [SBGECOM-207] - Reworked motion profile / aiding equipments errors models set/get API (removed SbgEComModelInfo) + - [SBGECOM-209] - Reworked and simplified GNSS model ids to comply with sbgECom 2.x + - [SBGECOM-212] - Added in SBG_ECOM_CMD_FEATURES gnss firmware version field +### Removed Features + - [SBGECOM-200] - Removed SBG_ECOM_GNSS_MODEL_UBLOX_HIGH_DYNAMICS, use SBG_ECOM_GNSS_MODEL_INTERNAL instead + - [SBGECOM-201] - Removed SBG_ECOM_GNSS_MODEL_ELLIPSE_D_INTERNAL, use SBG_ECOM_GNSS_MODEL_INTERNAL instead + - [SBGECOM-202] - Removed SBG_ECOM_GNSS_MODEL_UBLOX_HIGH_SPEED, use SBG_ECOM_GNSS_MODEL_INTERNAL instead + - [SBGECOM-203] - Removed SBG_ECOM_GNSS_MODEL_UBLOX_LOW_SPEED, use SBG_ECOM_GNSS_MODEL_INTERNAL instead + - [SBGECOM-206] - Removed deprecated methods sbgEComCmdGnss1GetLeverArmAlignment & sbgEComCmdGnss1SetLeverArmAlignment + - [SBGECOM-211] - Removed legacy IG-500 protocol support + +## Release - 1.11.920-stable + +### New Features + - [SBGECOM-123] - Implement DVL aiding configuration SBG_ECOM_CMD_DVL_#### + - [SBGECOM-126] - Implement AirData aiding configuration SBG_ECOM_CMD_AIRDATA_#### + - [SBGECOM-135] - Add configuration commands for CAN odometer support + - [SBGECOM-136] - Add sbgECom Log Event Output useful for virtual odometer + - [SBGECOM-137] - Add SBG_ECOM_LOG_DEPTH / SBG_ECAN_MSG_DEPTH_INFO/ALTITUDE output logs + - [SBGECOM-140] - Updated SBG_ECOM_CMD_AIDING_ASSIGNMENT command for AirData support + - [SBGECOM-141] - Add airDataInput demo project to show external sbgECom AirData aiding + - [SBGECOM-142] - Updated SBG_ECOM_LOG_PRESSURE to SBG_ECOM_LOG_AIR_DATA with airspeed + - [SBGECOM-143] - Updated SBG_ECAN_MSG_PRESSURE to SBG_ECAN_MSG_AIR_DATA with airspeed + - [SBGECOM-156] - Add baseline length field in SBG_ECOM_LOG_GPS#_HDT log + - [SBGECOM-162] - Add SBG_ECOM_LOG_DIAG message to send text + - [SBGECOM-163] - Add CAN output message with vehicle body velocity + - [SBGECOM-164] - Add CAN output message with track, slip and curvature indications + - [SBGECOM-168] - Add INDYN NMEA like message output for marine applications + - [SBGECOM-170] - Add SBG_ECOM_CMD_GNSS_1_INSTALLATION command to set/get GNSS lever arm + - [SBGECOM-173] - Add compatibility support Crossbow AHRS500 series + - [SBGECOM-174] - Basic Logger: Add support for error log messages + - [SBGECOM-175] - Basic Logger: Add support for UDP interfaces + +### Improvements + - [SBGECOM-132] - Updated SBG_ECOM_CMD_AIDING_ASSIGNMENT command for DVL support + - [SBGECOM-133] - Renamed DVL standard deviation as quality indicator in DVL log structure + - [SBGECOM-144] - Converted SBG_ECOM_AIDING_EM_LOG_RECV to SBG_ECOM_AIDING_DEPTH_RECV + - [SBGECOM-145] - Renamed SBG_ECOM_AIDING_PRESSURE_RECV to SBG_ECOM_AIDING_AIR_DATA_RECV + - [SBGECOM-146] - Renamed SBG_ECOM_SOL_PRESSURE_USED to SBG_ECOM_SOL_AIR_DATA_USED + - [SBGECOM-147] - Added SBG_ECOM_SOL_DEPTH_USED in EKF solution status + - [SBGECOM-165] - Updated CAN log default IDs for Ship Motion HP from 0x210 to 0x14A + - [SBGECOM-169] - Updated SBG_ECOM_THIRD_PARTY_IXBLUE_XXX logs to comply with naming conventions + - [SBGECOM-176] - Minor code cleanup and removed useless defines + - [SBGECOM-177] - Updated all C types to use standard ones uint32 -> uint32_t + - [SBGECOM-178] - Updated common lib code with improved organization + +### Removed Features + - [SBGECOM-100] - Removed deprecated sbgEComSetReceiveCallback method + - [SBGECOM-101] - Removed deprecated sbgEComCmdGnss1SetModel method + - [SBGECOM-102] - Removed deprecated sbgEComCmdSensorSetMotionProfile method + - [SBGECOM-103] - Removed deprecated sbgEComCmdMagSetModel method + - [SBGECOM-171] - SBG_ECOM_CMD_GNSS_1_LEVER_ARM_ALIGNMENT deprecated and replaced by SBG_ECOM_CMD_GNSS_1_INSTALLATION + +## Release - 1.10.3692-stable + +### New Features + - [SBGECOM-115] - Add Septentrio Internal GNSS model for new Ellipse D + - [SBGECOM-117] - Added getters for delta a angle / velocity / temperature for IMU Short log + - [SBGECOM-119] - Added new Swell Mode Ship Motion status flags + +### Improvements + - [SBGECOM-118] - Improved sbgEComStartFrameGeneration & sbgEComFinalizeFrameGeneration methods + - [SBGECOM-122] - Increased time out for sbgEComCmdLicenseApply to support new ELLIPSE-D internal GNSS + +## Release - 1.9.706-stable + +### New Features + - [SBGECOM-110] - Added DOLOG HRP proprietary message + - [SBGECOM-111] - Added a new short IMU log message also used for post processing + - [SBGECOM-112] - Add a heavy machinery motion profile definition for Ellipse series + +### Bug Fixes + - [SBGECOM-113] - Fixed invalid SBG_ECOM_CAN_RX/TX_OK comments + +## Release - 1.8.2916-stable + +### New Features + - [SBGECOM-95] - Added GPS number of SV used and diff corrections details in sbgECan protocol + - [SBGECOM-105] - Add compatibility with SBG_ECOM_CMD_VALIDITY_THRESHOLDS command + - [SBGECOM-108] - Added support for aiding assignment on Port E for ELLIPSE-E and N + +### Improvements + - [SBGECOM-91] - Added sbgEComSetCmdTrialsAndTimeOut to setup the number of trials and default time out for commands + +## Release - 1.7.235-stable + +### New Features + - [SBGECOM-89] - Implement Kongsberg Binary 26 message output + - [SBGECOM-87] - Add an uptime indication in SBG_ECOM_LOG_STATUS + - [SBGECOM-86] - Added the command SBG_ECOM_CMD_ETHERNET_INFO to current device IP address + - [SBGECOM-85] - Added command SBG_ECOM_CMD_ETHERNET_CONF to define / retrieve the Ethernet configuration + - [SBGECOM-77] - Add new output log class for NMEA proprietary messages + - [SBGECOM-75] - Added UAV motion profile definition (for low dynamic rotary wing UAV applications) + +### Improvements + - [SBGECOM-83] - Better use of size_t type instead of uint32 to comply with C standard and 64 bit platforms + - [SBGECOM-84] - Updated sbgCommonLib to latest revision + +### Removed Features + - [SBGECOM-79] - Removed deprecated "course" from the GNSS configurable aiding sources + +## Release - 1.5.209-stable + +### New Features + - [SBGECOM-72] - Added proprietary NMEA message PASHR for roll, pitch, heading, heave + - [SBGECOM-70] - Added SBG Proprietary NMEA message with acceleration and angular rate + - [SBGECOM-68] - Added SBG_ECOM_OUTPUT_MODE_DIV_5 flag for 40 Hz output + - [SBGECOM-66] - Added SBG_ECOM_GENERAL_CPU_OK status flag + - [SBGECOM-65] - Added sbgEComHandleOneLog method to return even if more logs are available + - [SBGECOM-64] - Added sbgEComSendAck method + - [SBGECOM-62] - Added sbgEComStartFrameGeneration and sbgEComFinalizeFrameGeneration methods + - [SBGECOM-59] - Added sbgECom log generation code + - [SBGECOM-57] - Added SBG_ECOM_LOG_FAST_IMU_DATA message definition + - [SBGECOM-40] - Added KVH third party output format id (SBG_ECOM_THIRD_PARTY_KVH) + +### Improvements + - [SBGECOM-74] - Switched unix projects to CMake + - [SBGECOM-73] - Added examples into the sbgECom + - [SBGECOM-63] - Updated sbgCommonLib to latest revision + - [SBGECOM-61] - Use stream buffer instead of basic buffer for sbgECom log parsing + - [SBGECOM-51] - Added SBF (Septentrio) protocol support on Ellipse-E + - [SBGECOM-50] - Added direct PPS from internal GNSS Sync Output (SBG_ECOM_CMD_SYNC_OUT_CONF) + - [SBGECOM-47] - Made the sbgECom 64 bit compatible + - [SBGECOM-46] - Switched project files to Visual Studio 2013 + - [SBGECOM-45] - Added a new callback method (sbgEComSetReceiveLogCallback) and deprecated the old one (sbgEComSetReceiveCallback) + - [SBGECOM-42] - Improved handling of MSG and CLASS fields in low level protocol functions + +### Bug Fixes + - [SBGECOM-71] - Fixed sbgEComCmdGetInfo incorrect error code return when an invalid payload is received + - [SBGECOM-44] - Fixed Various incompatibilities in Big Endian platforms + - [SBGECOM-43] - Added output of NACK reasons in sbgECom configuration commands using the return code + +### Removed Features + - [SBGECOM-60] - Removed Ship Motion 1,2,3 and Ship Motion HP 1,2,3 due to new deported heave concepts + +## Release - 1.4.3239-stable + +### New Features + - [SBGECOM-28] - Added differential correction age, diff base id and num sv to the SBG_ECOM_LOG_GPS#_POS + - [SBGECOM-29] - Added GNSS raw data log for the second GNSS receiver + - [SBGECOM-30] - Added official support for Ellipse additional output interfaces PORT C and PORT E + - [SBGECOM-33] - Added big/little endian support for stream buffer + - [SBGECOM-34] - Added sbgPlatform.h file to setup platform specific configuration such as endianness + +### Improvements + - [SBGECOM-7] - Added support for both little and big endian platforms + - [SBGECOM-32] - Improved stream buffer error handling + - [SBGECOM-36] - Improved File naming and overall library organization + - [SBGECOM-37] - Modified firmware and software version numbering scheme + - [SBGECOM-38] - Increased raw GPS data buffer size from 2048 to 4096 bytes + +### Bug Fixes + - [SBGECOM-21] - Fixed SBG_ECOM_ETH#_RX_OK and SBG_ECOM_ETH#_TX_OK status definitions + - [SBGECOM-27] - Changed sbgEComHandle behavior so the error returned by receive call back is taken into account + - [SBGECOM-35] - Fixed improper comments in some configuration structures + +## Release - 1.3 + +### New Features + - [SBGECOM-10] - Added sbgInterfaceChangeBaudrate for both windows and unix platforms + - [SBGECOM-19] - Added SBG_ECOM_LOG_PRESSURE log for depth sensors and altimeters + - [SBGECOM-25] - Added support for Ellipse series + - [SBGECOM-26] - Added SBG_ECOM_LOG_USBL log for USBL aiding equipments (beta) + +### Improvements + - [SBGECOM-18] - Fixed Typos in GPS pos, Vel and Hdt Fix Status + - [SBGECOM-20] - Better error checking for sbgStreamBuffer with new method sbgStreamBufferGetLastError + - [SBGECOM-22] - Added UTC & Clock status to the binary log SbgLogUtcData + - [SBGECOM-23] - Added Solution status to the binary log SbgLogEkfEuler, SbgLogEkfQuat, SbgLogEkfNav + - [SBGECOM-24] - Added time stamp to the log SBG_ECOM_LOG_MAG_CALIB + +## Release - 1.2 + +### New Features + - [SBGECOM-14] - Added SBG_ECOM_LOG_SHIP_MOTION_HP logs for delayed heave output + - [SBGECOM-15] - Added sbgInterfaceSerialChangeBaudrate method to change the serial interface baud rate + - [SBGECOM-17] - Added SBG_ECOM_POS_FIXED / SBG_ECAN_POS_FIXED position type for GPS + +### Improvements + - [SBGECOM-13] - Updated SBG_ECOM_LOG_SHIP_MOTION_XXX logs to add velocity and status data + - [SBGECOM-16] - Changed GPS OmniStar solution type to PPP ones for better compatibility with third party GPS + +### Removed Features + - [SBGECOM-11] - Removed heave status field from SBG_ECOM_LOG_STATUS log + +## Release - 1.1 + +### New Features + - [SBGECOM-1] - Added output log for DVL support + - [SBGECOM-3] - Added output for GPS 1 raw data in order to support post processing + - [SBGECOM-4] - Added event markers logs support + - [SBGECOM-6] - Added Unix support and build script + - [SBGECOM-8] - Added sbgEComReceiveAnyCmd method that return any received command that is not an output log + - [SBGECOM-9] - Added settings import and export command + +### Improvements + - [SBGECOM-2] - Added pitch information in the SbgLogGpsHdt GPS true heading log + - [SBGECOM-5] - Now sbgEComProtocolReceive method returns the received command even if the CRC is not valid diff --git a/crates/sbg-rs/sbgECom/CMakeLists.txt b/crates/sbg-rs/sbgECom/CMakeLists.txt new file mode 100644 index 0000000..eaae029 --- /dev/null +++ b/crates/sbg-rs/sbgECom/CMakeLists.txt @@ -0,0 +1,100 @@ +cmake_minimum_required(VERSION 3.18 FATAL_ERROR) + +set(CMAKE_BUILD_TYPE Release CACHE STRING "build type") +set(CMAKE_C_COMPILER_WORKS TRUE) +set(CMAKE_CXX_COMPILER_WORKS TRUE) +project(sbgECom) + +# +# Project configuration +# +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +option(BUILD_EXAMPLES "Build examples" OFF) +option(BUILD_TOOLS "Build tools" OFF) + +# +# sbgECom +# +add_library(${PROJECT_NAME} STATIC) + +file(GLOB_RECURSE COMMON_SRC ${PROJECT_SOURCE_DIR}/common/*.c) +file(GLOB_RECURSE ECOM_SRC ${PROJECT_SOURCE_DIR}/src/*.c) + +# Exclude platform specific files +if (NOT MSVC) + list(REMOVE_ITEM COMMON_SRC ${PROJECT_SOURCE_DIR}/common/interfaces/sbgInterfaceSerialWin.c) +else () + list(REMOVE_ITEM COMMON_SRC ${PROJECT_SOURCE_DIR}/common/interfaces/sbgInterfaceSerialUnix.c) +endif() + +target_sources(${PROJECT_NAME} PRIVATE ${COMMON_SRC} ${ECOM_SRC}) + +target_include_directories(${PROJECT_NAME} + PRIVATE + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_SOURCE_DIR}/common + INTERFACE + $ + $ + $) + +target_compile_definitions(${PROJECT_NAME} PUBLIC SBG_COMMON_STATIC_USE) + +if (MSVC) + target_compile_definitions(${PROJECT_NAME} PUBLIC _CRT_SECURE_NO_WARNINGS) + target_link_libraries(${PROJECT_NAME} PUBLIC Ws2_32) +endif() + +# +# Tools +# +if (BUILD_TOOLS) + include(FetchContent) + + FetchContent_Declare(argtable3 + GIT_REPOSITORY https://github.com/argtable/argtable3.git + GIT_TAG v3.1.5.1c1bb23 + ) + + FetchContent_GetProperties(argtable3) + + if (NOT argtable3_POPULATED) + FetchContent_Populate(argtable3) + add_subdirectory(${argtable3_SOURCE_DIR} ${argtable3_BINARY_DIR} EXCLUDE_FROM_ALL) + endif() + + add_executable(sbgBasicLogger + ${PROJECT_SOURCE_DIR}/tools/sbgBasicLogger/src/main.c + ${PROJECT_SOURCE_DIR}/tools/sbgBasicLogger/src/sbgBasicLoggerAccumulators.h + ${PROJECT_SOURCE_DIR}/tools/sbgBasicLogger/src/sbgBasicLoggerFile.h + ${PROJECT_SOURCE_DIR}/tools/sbgBasicLogger/src/sbgBasicLoggerHandler.h + ${PROJECT_SOURCE_DIR}/tools/sbgBasicLogger/src/sbgBasicLoggerAccumulators.c + ${PROJECT_SOURCE_DIR}/tools/sbgBasicLogger/src/sbgBasicLoggerFile.c + ${PROJECT_SOURCE_DIR}/tools/sbgBasicLogger/src/sbgBasicLoggerHandler.c + ) + target_include_directories(sbgBasicLogger PRIVATE ${argtable3_SOURCE_DIR}/src) + target_link_libraries(sbgBasicLogger ${PROJECT_NAME} argtable3_static) + install(TARGETS sbgBasicLogger DESTINATION bin/tools/sbgBasicLogger COMPONENT executables) + install(FILES tools/sbgBasicLogger/README.md DESTINATION bin/tools/sbgBasicLogger COMPONENT executables) + + add_executable(sbgEComApi ${PROJECT_SOURCE_DIR}/tools/sbgEComApi/src/main.c) + target_include_directories(sbgEComApi PRIVATE ${argtable3_SOURCE_DIR}/src) + target_link_libraries(sbgEComApi ${PROJECT_NAME} argtable3_static) + install(TARGETS sbgEComApi DESTINATION bin/tools/sbgEComApi COMPONENT executables) + install(FILES tools/sbgEComApi/README.md DESTINATION bin/tools/sbgEComApi COMPONENT executables) +endif(BUILD_TOOLS) + +# +# Install +# +install(TARGETS ${PROJECT_NAME} EXPORT sbgEComTargets) +install(EXPORT sbgEComTargets + FILE sbgEComTargets.cmake + NAMESPACE sbg:: + DESTINATION lib/cmake/sbg) +install(DIRECTORY common/ TYPE INCLUDE FILES_MATCHING REGEX ".*\\.h") +install(DIRECTORY src/ TYPE INCLUDE FILES_MATCHING REGEX ".*\\.h") diff --git a/crates/sbg-rs/sbgECom/LICENSE.md b/crates/sbg-rs/sbgECom/LICENSE.md new file mode 100644 index 0000000..0117237 --- /dev/null +++ b/crates/sbg-rs/sbgECom/LICENSE.md @@ -0,0 +1,22 @@ +# License +The MIT License (MIT) + +Copyright (C) 2022, SBG Systems SAS. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/crates/sbg-rs/sbgECom/README.md b/crates/sbg-rs/sbgECom/README.md new file mode 100644 index 0000000..4d871a8 --- /dev/null +++ b/crates/sbg-rs/sbgECom/README.md @@ -0,0 +1,123 @@ +# sbgECom Library +sbgECom is a C library provided under the MIT License and used to interface easily [SBG Systems](https://www.sbg-systems.com/) IMU, AHRS and INS to your application. + +This library has been designed to be platform and OS independent and can safely be used on small micro-controller or larger multi-core CPUs. +This package contains the following items: + - sbgECom library full C source code + - Doxygen library source code documentation + - Examples C source code and binaries to quickly start using the sbgECom library + - Several useful tools provided as binary package + +The sbgECom library and examples can be compiled on any platform using CMake. +The pre-compiled sbgECom examples and tools are 64 bits binaries available on Windows, Linux and Mac OS X platforms. + +The library is written and maintained by SBG Systems SAS. You can contact the support@sbg-systems.com for if you need assistance. + +# Documentation + +You can access the full online sbgECom Doxygen documentation [here](https://developer.sbg-systems.com/sbgECom/). +You should also read the SBG Systems [Support Center](https://support.sbg-systems.com) to quickly start using and integrating your products. +Please also have a look at the [sbgInsRestApi](https://developer.sbg-systems.com/sbgInsRestApi/) documentation that is used to configure High Performance INS products. + +# Platform support +The library has been designed to be easily ported to any platform by just providing/implementing a few low level methods and some configuration: + - The platform configuration is set in `common/sbgConfig.h` + - In the file `common/platform/sbgPlatform.c` please provide _sbgGetTime_, _sbgSleep_ and _sbgPlatformDebugLogMsg_ + - In the directory `common/interfaces/` you can provide custom open/read/write implementations for serial communications + +# Building sbgECom Library +The sbgECom library and code examples are very easy to compile on any platform using CMake. +The library has no third party library dependencies making it very easy to build. + +SBG Systems doesn't provide the sbgECom as a pre-compiled library for obvious and good reasons. + +## Dependencies +SBG Systems has validated the following toolchain: +- \>= CMake 3.0 +- \>= GNU GCC 8 (any platform) +- \>= AppleClang 13 (Mac OS X) +- \>= Visual Studio 2015 or MSBuild equivalent (Windows) + +## Building sbgECom +To build the sbgECom static library, the C example and the command line tools go to the sbgECom library folder and type the following commands: + +```sh +cmake -Bbuild -DBUILD_EXAMPLES=ON -DBUILD_TOOLS=ON +cmake --build build +``` + +You should find the sbgECom static library, examples and tools binaries in the `build/Debug` folder. + +# Code Examples +SBG Systems provides several and simple C code examples to quickly use the sbgECom library. +You can find both the source code as well as a binary for each example. + +All examples source code are located in the `examples` directory. You can find pre-compiled 64 bits binaries in the `bin/examples` folder. + +## Ellipse Minimal +Simple C example to illustrate how to connect and read data from an ELLIPSE using the sbgECom library. + +You can test this example using the command below: + +```sh +ellipseMinimal COM4 115200 +``` + +## High Performance INS Minimal +Simple C example to illustrate how to read data from an High Performance INS over an UDP connection and using the sbgECom library. + +You can test this example using the command below. The INS ip address is *192.168.1.1* and send logs on the UDP port *1234*: + +```sh +hpInsMinimal COM4 192.168.1.1 5678 1234 +``` + +## Pulse Minimal +Simple C example to illustrate how to connect and read data from a PULSE IMU using the sbgECom library. + +You can test this example using the command below: + +```sh +pulseMinimal COM4 921600 +``` + +## Ellipse On Board Magnetic Calibration +Simple C example to illustrate how to use the ELLIPSE on board magnetic calibration algorithms. + +You can test this example using the command below: + +```sh +ellipseOnBoardMagCalib COM4 115200 +``` + +## Air Date Input +Simple C example to illustrate how to send air date aiding measurements to an ELLIPSE using the sbgECom library. + +You can test this example using the command below: + +```sh +airDataInput COM4 115200 +``` + +# Command Line Tools +SBG Systems offers two very useful tools to ease evaluation and integration. You can find the C source code for each tool in the `tools` directory. +The `bin/tools` directory contains pre-compiled 64 bits binaries for Windows, Linux and Mac OS X platforms. + +> Please read the dedicated README.md files provided with each tool. + +## sbgBasicLogger +Simply parse sbgECom logs from a serial or ethernet interface and write log content to CSV like files. +This tool can also read sbgECom logs from a binary file making it very interesting to convert ELLIPSE binary streams to easy to use text files. + +## sbgEComApi +Easily access sbgInsRest API configuration over a serial or UDP interface. You can execute GET and POST queries using simple to use command lines arguments. +This tool is perfect if you would like to setup a High Performance INS product over a serial or ethernet interface and using only bash scripts for example. + +# CAN messages +SBG Systems provides a DBC and BusMaster CAN messages database definition to quickly interface your product with a CAN logger and application. +You can find these CAN database in the `can` directory + + + +Read Next: [Migrations](doc/migrations.md) + diff --git a/crates/sbg-rs/sbgECom/common/crc/sbgCrc.c b/crates/sbg-rs/sbgECom/common/crc/sbgCrc.c new file mode 100644 index 0000000..3b5c5f6 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/crc/sbgCrc.c @@ -0,0 +1,271 @@ +#include "sbgCrc.h" + +//----------------------------------------------------------------------// +//- Static global CRC tables -// +//----------------------------------------------------------------------// + +/*!< CRC table used to compute a 16 bit CRC with the polynom 0x8408. */ +static const uint16_t crc16LookupTable[256] = { + 0x0000,0x1189,0x2312,0x329B,0x4624,0x57AD,0x6536,0x74BF,0x8C48,0x9DC1,0xAF5A,0xBED3,0xCA6C,0xDBE5,0xE97E,0xF8F7, + 0x1081,0x0108,0x3393,0x221A,0x56A5,0x472C,0x75B7,0x643E,0x9CC9,0x8D40,0xBFDB,0xAE52,0xDAED,0xCB64,0xF9FF,0xE876, + 0x2102,0x308B,0x0210,0x1399,0x6726,0x76AF,0x4434,0x55BD,0xAD4A,0xBCC3,0x8E58,0x9FD1,0xEB6E,0xFAE7,0xC87C,0xD9F5, + 0x3183,0x200A,0x1291,0x0318,0x77A7,0x662E,0x54B5,0x453C,0xBDCB,0xAC42,0x9ED9,0x8F50,0xFBEF,0xEA66,0xD8FD,0xC974, + 0x4204,0x538D,0x6116,0x709F,0x0420,0x15A9,0x2732,0x36BB,0xCE4C,0xDFC5,0xED5E,0xFCD7,0x8868,0x99E1,0xAB7A,0xBAF3, + 0x5285,0x430C,0x7197,0x601E,0x14A1,0x0528,0x37B3,0x263A,0xDECD,0xCF44,0xFDDF,0xEC56,0x98E9,0x8960,0xBBFB,0xAA72, + 0x6306,0x728F,0x4014,0x519D,0x2522,0x34AB,0x0630,0x17B9,0xEF4E,0xFEC7,0xCC5C,0xDDD5,0xA96A,0xB8E3,0x8A78,0x9BF1, + 0x7387,0x620E,0x5095,0x411C,0x35A3,0x242A,0x16B1,0x0738,0xFFCF,0xEE46,0xDCDD,0xCD54,0xB9EB,0xA862,0x9AF9,0x8B70, + 0x8408,0x9581,0xA71A,0xB693,0xC22C,0xD3A5,0xE13E,0xF0B7,0x0840,0x19C9,0x2B52,0x3ADB,0x4E64,0x5FED,0x6D76,0x7CFF, + 0x9489,0x8500,0xB79B,0xA612,0xD2AD,0xC324,0xF1BF,0xE036,0x18C1,0x0948,0x3BD3,0x2A5A,0x5EE5,0x4F6C,0x7DF7,0x6C7E, + 0xA50A,0xB483,0x8618,0x9791,0xE32E,0xF2A7,0xC03C,0xD1B5,0x2942,0x38CB,0x0A50,0x1BD9,0x6F66,0x7EEF,0x4C74,0x5DFD, + 0xB58B,0xA402,0x9699,0x8710,0xF3AF,0xE226,0xD0BD,0xC134,0x39C3,0x284A,0x1AD1,0x0B58,0x7FE7,0x6E6E,0x5CF5,0x4D7C, + 0xC60C,0xD785,0xE51E,0xF497,0x8028,0x91A1,0xA33A,0xB2B3,0x4A44,0x5BCD,0x6956,0x78DF,0x0C60,0x1DE9,0x2F72,0x3EFB, + 0xD68D,0xC704,0xF59F,0xE416,0x90A9,0x8120,0xB3BB,0xA232,0x5AC5,0x4B4C,0x79D7,0x685E,0x1CE1,0x0D68,0x3FF3,0x2E7A, + 0xE70E,0xF687,0xC41C,0xD595,0xA12A,0xB0A3,0x8238,0x93B1,0x6B46,0x7ACF,0x4854,0x59DD,0x2D62,0x3CEB,0x0E70,0x1FF9, + 0xF78F,0xE606,0xD49D,0xC514,0xB1AB,0xA022,0x92B9,0x8330,0x7BC7,0x6A4E,0x58D5,0x495C,0x3DE3,0x2C6A,0x1EF1,0x0F78}; + +/*!< CRC table used to compute an Ethernet 32 bit CRC using the normal polynom 0x04C11DB7. */ +static const uint32_t crc32EthernetTable[256] = +{ + 0x00000000, + 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, + 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, + 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, + 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, + 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, + 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, + 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, + 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, + 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, + 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, + 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, + 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, + 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, + 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, + 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, + 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, + 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, + 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, + 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, + 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, + 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, + 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, + 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, + 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, + 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, + 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, + 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, + 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, + 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, + 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, + 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, + 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, + 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, + 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, + 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, + 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, + 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, + 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +//----------------------------------------------------------------------// +//- 32 bits Ethernet CRC -// +//----------------------------------------------------------------------// + +/*! + * Initialize the 32 bit CRC computation system. + * \param[in] pInstance Pointer on an allocated but non initialized Crc32 object. + */ +SBG_COMMON_LIB_API void sbgCrc32Initialize(SbgCrc32 *pInstance) +{ + // + // Test input argument + // + assert(pInstance); + + *pInstance = 0xFFFFFFFF; +} + +/*! + * Compute a 32 bit CRC using an Ethernet polynome. + * Warning: the buffer size should be at least 4 bytes long. + * \param[in] pInstance Read only pointer on a valid Crc32 object. + * \param[in] pData Read only pointer on the data buffer to compute CRC on. + * \param[in] dataSize Data size in bytes of the buffer, has to be greater or equals to 4. + */ +SBG_COMMON_LIB_API void sbgCrc32Update(SbgCrc32 *pInstance, const void *pData, size_t dataSize) +{ + const uint8_t *pBuffer = (const uint8_t*)pData; + uint32_t byte; + size_t i; + size_t dataSizeCorrected; + size_t numBytesLeft; + size_t index; + + // + // Test input arguments + // + assert(pInstance); + assert(pData); + + // + // Compute the data size that corresponds to complete uinht32 and how many bytes remains + // + dataSizeCorrected = dataSize & (~0x00000003); + numBytesLeft = dataSize & 0x03; + + // For each byte, update the CRC + // + for (i = 0; i < dataSizeCorrected; i++) + { + // + // We have to get index in reversed order per 4 bytes + // + index = i ^ 0x03; + + // + // Get the current byte value + // + byte = pBuffer[index]; + + // + // Update the CRC value + // + *pInstance = (*pInstance << 8) ^ crc32EthernetTable[((*pInstance >> 24) ^ byte) & 0xFF]; + } + + // + // Test how many bytes remains + // + for (i = 0; i < numBytesLeft; i++) + { + // + // We have to get index in reversed order per 4 bytes + // + index = (dataSizeCorrected-1) + (numBytesLeft - i); + + // + // Get the current byte value + // + byte = pBuffer[index]; + + // + // Update the CRC value + // + *pInstance = (*pInstance << 8) ^ crc32EthernetTable[((*pInstance >> 24) ^ byte) & 0xFF]; + } +} + +/*! + * Compute a 32 Bit CRC using an Ethernet polynome. + * Warning: the buffer size should be at least 4 bytes long. + * \param[in] pData Read only pointer on the data buffer to compute CRC on. + * \param[in] dataSize Data size in bytes of the buffer, has to be greater or equals to 4. + * \return The computed CRC. + */ +SBG_COMMON_LIB_API uint32_t sbgCrc32Compute(const void *pData, size_t dataSize) +{ + SbgCrc32 crcInst; + + // + // Initialize the CRC system + // + sbgCrc32Initialize(&crcInst); + + // + // Compute the CRC + // + sbgCrc32Update(&crcInst, pData, dataSize); + + // + // Return it + // + return sbgCrc32Get(&crcInst); +} + +//----------------------------------------------------------------------// +//- CRC-16 operations -// +//----------------------------------------------------------------------// + +/*! + * Initialize the 16 bit CRC computation system. + * \param[in] pInstance Pointer on an allocated but non initialized Crc16 object. + */ +SBG_COMMON_LIB_API void sbgCrc16Initialize(SbgCrc16 *pInstance) +{ + // + // Test input argument + // + assert(pInstance); + + *pInstance = 0; +} + +/*! + * Compute a 16 bit CRC using an the polynome 0x8408. + * \param[in] pInstance Read only pointer on a valid Crc16 object. + * \param[in] pData Read only pointer on the data buffer to compute CRC on. + * \param[in] dataSize Data size in bytes of the buffer. + */ +SBG_COMMON_LIB_API void sbgCrc16Update(SbgCrc16 *pInstance, const void *pData, size_t dataSize) +{ + const uint8_t *pBuffer = (const uint8_t*)pData; + uint8_t index; + size_t i; + + // + // Test input arguments + // + assert(pInstance); + assert(pData); + + // + // For each byte in our buffer + // + for (i = 0; i < dataSize; i++) + { + // + // Update the current CRC + // + index = (pBuffer[i] ^ *pInstance) & 0xFF; + *pInstance = crc16LookupTable[index] ^ (*pInstance >> 8); + } +} + +/*! + * Compute a 32 Bit CRC using an the polynome 0x8408. + * \param[in] pData Read only pointer on the data buffer to compute CRC on. + * \param[in] dataSize Data size in bytes of the buffer. + * \return The computed CRC. + */ +SBG_COMMON_LIB_API uint16_t sbgCrc16Compute(const void *pData, size_t dataSize) +{ + SbgCrc16 crcInst; + + // + // Initialize the CRC system + // + sbgCrc16Initialize(&crcInst); + + // + // Compute the CRC + // + sbgCrc16Update(&crcInst, pData, dataSize); + + // + // Return it + // + return sbgCrc16Get(&crcInst); +} diff --git a/crates/sbg-rs/sbgECom/common/crc/sbgCrc.h b/crates/sbg-rs/sbgECom/common/crc/sbgCrc.h new file mode 100644 index 0000000..9d945de --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/crc/sbgCrc.h @@ -0,0 +1,135 @@ +/*! + * \file sbgCrc.h + * \ingroup common + * \author SBG Systems + * \date 15 January 2013 + * + * \brief This file provides CRC-32 and CRC-16 methods. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ +#ifndef SBG_CRC_H +#define SBG_CRC_H + +//----------------------------------------------------------------------// +//- Header (open extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +extern "C" { +#endif + +#include + +//----------------------------------------------------------------------// +//- Types definitions -// +//----------------------------------------------------------------------// + +/*!< Type used to compute a 32 bit Ethernet CRC. */ +typedef uint32_t SbgCrc32; + +/*!< Type used to compute a 16 bit CRC. */ +typedef uint16_t SbgCrc16; + +//----------------------------------------------------------------------// +//- 32 bits Ethernet CRC -// +//----------------------------------------------------------------------// + +/*! + * Initialize the 32 bit CRC computation system. + * \param[in] pInstance Pointer on an allocated but non initialized Crc32 object. + */ +SBG_COMMON_LIB_API void sbgCrc32Initialize(SbgCrc32 *pInstance); + +/*! + * Compute a 32 bit CRC using an Ethernet polynome. + * Warning: the buffer size should be at least 4 bytes long. + * \param[in] pInstance Read only pointer on a valid Crc32 object. + * \param[in] pData Read only pointer on the data buffer to compute CRC on. + * \param[in] dataSize Data size in bytes of the buffer, has to be greater or equals to 4. + */ +SBG_COMMON_LIB_API void sbgCrc32Update(SbgCrc32 *pInstance, const void *pData, size_t dataSize); + +/*! + * Returns the computed 32 bit CRC value. + * \param[in] pInstance Read only pointer on a valid Crc32 object. + * \return The computed CRC. + */ +SBG_INLINE uint32_t sbgCrc32Get(const SbgCrc32 *pInstance) +{ + return *pInstance; +} + +/*! + * Compute a 32 Bit CRC using an Ethernet polynome. + * Warning: the buffer size should be at least 4 bytes long. + * \param[in] pData Read only pointer on the data buffer to compute CRC on. + * \param[in] dataSize Data size in bytes of the buffer, has to be greater or equals to 4. + * \return The computed CRC. + */ +SBG_COMMON_LIB_API uint32_t sbgCrc32Compute(const void *pData, size_t dataSize); + +//----------------------------------------------------------------------// +//- CRC-16 operations -// +//----------------------------------------------------------------------// + +/*! + * Initialize the 16 bit CRC computation system. + * \param[in] pInstance Pointer on an allocated but non initialized Crc16 object. + */ +SBG_COMMON_LIB_API void sbgCrc16Initialize(SbgCrc16 *pInstance); + +/*! + * Compute a 16 bit CRC using an the polynome 0x8408. + * \param[in] pInstance Read only pointer on a valid Crc16 object. + * \param[in] pData Read only pointer on the data buffer to compute CRC on. + * \param[in] dataSize Data size in bytes of the buffer. + */ +SBG_COMMON_LIB_API void sbgCrc16Update(SbgCrc16 *pInstance, const void *pData, size_t dataSize); + +/*! + * Returns the computed 32 bit CRC value. + * \param[in] pInstance Read only pointer on a valid Crc16 object. + * \return The computed CRC. + */ +SBG_INLINE uint16_t sbgCrc16Get(const SbgCrc16 *pInstance) +{ + return *pInstance; +} + +/*! + * Compute a 32 Bit CRC using an the polynome 0x8408. + * \param[in] pData Read only pointer on the data buffer to compute CRC on. + * \param[in] dataSize Data size in bytes of the buffer. + * \return The computed CRC. + */ +SBG_COMMON_LIB_API uint16_t sbgCrc16Compute(const void *pData, size_t dataSize); + +//----------------------------------------------------------------------// +//- Footer (close extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +} +#endif + +#endif /* SBG_CRC_H */ diff --git a/crates/sbg-rs/sbgECom/common/debug/sbgDebug.c b/crates/sbg-rs/sbgECom/common/debug/sbgDebug.c new file mode 100644 index 0000000..fdf22cb --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/debug/sbgDebug.c @@ -0,0 +1,153 @@ +/*! + * \file sbgDebug.c + * \author SBG Systems + * + * \brief Error logging for the SBG Systems common C library. + * + * \section CodeCopyright Copyright Notice + * Copyright (C) 2019, SBG Systems SAS. All rights reserved. + * + * This source code is intended for use only by SBG Systems SAS and + * those that have explicit written permission to use it from + * SBG Systems SAS. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + * PARTICULAR PURPOSE. + */ + +// Standard headers +#include + +// sbgCommonLib headers +#include + +// Local headers +#include "sbgDebug.h" + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +/*! + * Number of bytes translated per line. + */ +#define SBG_DEBUG_NR_BYTES_PER_LINE (16) + +/*! + * Size of the buffer used to generate lines, in bytes. + */ +#define SBG_DEBUG_LINE_BUFFER_SIZE (256) + +//----------------------------------------------------------------------// +//- Private functions -// +//----------------------------------------------------------------------// + +/*! + * Dump the given buffer on a single text line. + * + * \param[out] pLine Output line buffer. + * \param[in] lineSize Size of the ouput line buffer. + * \param[in] pBuffer Buffer. + * \param[in] size Buffer size. + */ +static void sbgDebugHexDumpGenerateLine(char *pLine, size_t lineSize, const uint8_t *pBuffer, size_t size) +{ + size_t length; + + assert(pLine); + assert(lineSize != 0); + assert(pBuffer); + assert(size <= SBG_DEBUG_NR_BYTES_PER_LINE); + + for (size_t i = 0; i < size; i++) + { + length = snprintf(pLine, lineSize, "%02x ", pBuffer[i]); + assert(length < lineSize); + + pLine = &pLine[length]; + lineSize -= length; + } + + for (size_t i = size; i < SBG_DEBUG_NR_BYTES_PER_LINE; i++) + { + length = snprintf(pLine, lineSize, " "); + assert(length < lineSize); + + pLine = &pLine[length]; + lineSize -= length; + } + + length = snprintf(pLine, lineSize, " | "); + assert(length < lineSize); + + pLine = &pLine[length]; + lineSize -= length; + + for (size_t i = 0; i < size; i++) + { + char c; + + if (isprint(pBuffer[i])) + { + c = pBuffer[i]; + } + else + { + c = '.'; + } + + length = snprintf(pLine, lineSize, "%c", c); + assert(length < lineSize); + + pLine = &pLine[length]; + lineSize -= length; + } +} + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +void sbgDebugHexDump(const char *pPrefix, const void *pBuffer, size_t size) +{ + char line[SBG_DEBUG_LINE_BUFFER_SIZE]; + size_t index = 0; + bool multiLine = false; + + assert(pPrefix); + assert(pBuffer || (size == 0)); + + if (size > SBG_DEBUG_NR_BYTES_PER_LINE) + { + SBG_LOG_DEBUG("%s: multi-line dump start (%zu bytes)", pPrefix, size); + multiLine = true; + } + + while (size != 0) + { + const uint8_t *pByteBuffer = pBuffer; + size_t rangeSize; + + if (size < SBG_DEBUG_NR_BYTES_PER_LINE) + { + rangeSize = size; + } + else + { + rangeSize = SBG_DEBUG_NR_BYTES_PER_LINE; + } + + sbgDebugHexDumpGenerateLine(line, sizeof(line), &pByteBuffer[index], rangeSize); + SBG_LOG_DEBUG("%s: %s", pPrefix, line); + + size -= rangeSize; + index += rangeSize; + } + + if (multiLine) + { + SBG_LOG_DEBUG("%s: multi-line dump end", pPrefix); + } +} diff --git a/crates/sbg-rs/sbgECom/common/debug/sbgDebug.h b/crates/sbg-rs/sbgECom/common/debug/sbgDebug.h new file mode 100644 index 0000000..a4879cd --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/debug/sbgDebug.h @@ -0,0 +1,163 @@ +/*! + * \file sbgDebug.h + * \ingroup common + * \author SBG Systems + * \date 17 March 2015 + * + * \brief Define and handle error logging for the SBG Systems common C library. + * + * The methods defined here should be implemented in sbgPlatform.h/sbgPlatform.c + * according to your platform and needs. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ +#ifndef SBG_DEBUG_H +#define SBG_DEBUG_H + +// sbgCommonLib headers +#include + +#ifndef SBG_DEBUG_LOG_CATEGORY + #define SBG_DEBUG_LOG_CATEGORY ("None") +#endif + +//----------------------------------------------------------------------// +//- Errors and warning definitions -// +//----------------------------------------------------------------------// + +/*! + * Enum that identify the type of error / warning that has been thrown. + */ +typedef enum _SbgDebugLogType +{ + SBG_DEBUG_LOG_TYPE_ERROR, /*!< The message to log is an error. */ + SBG_DEBUG_LOG_TYPE_WARNING, /*!< The message to log is a warning. */ + SBG_DEBUG_LOG_TYPE_INFO, /*!< The message to log is an information. */ + SBG_DEBUG_LOG_TYPE_DEBUG /*!< The message to log is a debug information. */ +} SbgDebugLogType; + +//----------------------------------------------------------------------// +//- Errors and warning macros -// +//----------------------------------------------------------------------// + +/*! + * Log an error with its associated message. + * \param[in] errorCode The error code that has thrown this error. + * \param[in] format String litteral for the associated error message (you can use printf like string formating). + */ +#define SBG_LOG_ERROR_CALL(errorCode, format, ...) sbgPlatformDebugLogMsg((const char*)__BASE_FILE__, (const char*)__FUNCTION__, __LINE__, SBG_DEBUG_LOG_CATEGORY, SBG_DEBUG_LOG_TYPE_ERROR, errorCode, format, ##__VA_ARGS__) + +#if SBG_CONFIG_ENABLE_LOG_ERROR == 1 + #define SBG_LOG_ERROR SBG_LOG_ERROR_CALL +#else + #define SBG_LOG_ERROR(format, ...) ((void)sizeof(SBG_LOG_ERROR_CALL(format, ## __VA_ARGS__), 0)) +#endif + +/*! + * Log a warning with its associated message. + * \param[in] errorCode The error code that has thrown this warning. + * \param[in] format String litteral for the associated warning message (you can use printf like string formating). + */ +#define SBG_LOG_WARNING_CALL(errorCode, format, ...) sbgPlatformDebugLogMsg((const char*)__BASE_FILE__, (const char*)__FUNCTION__, __LINE__, SBG_DEBUG_LOG_CATEGORY, SBG_DEBUG_LOG_TYPE_WARNING, errorCode, format, ##__VA_ARGS__) + +#if SBG_CONFIG_ENABLE_LOG_WARNING == 1 + #define SBG_LOG_WARNING SBG_LOG_WARNING_CALL +#else + #define SBG_LOG_WARNING(format, ...) ((void)sizeof(SBG_LOG_WARNING_CALL(format, ## __VA_ARGS__), 0)) +#endif + +/*! + * Log an information message. + * \param[in] format String litteral for the information message (you can use printf like string formating). + */ +#define SBG_LOG_INFO_CALL(format, ...) sbgPlatformDebugLogMsg((const char*)__BASE_FILE__, (const char*)__FUNCTION__, __LINE__, SBG_DEBUG_LOG_CATEGORY, SBG_DEBUG_LOG_TYPE_INFO, SBG_NO_ERROR, format, ##__VA_ARGS__) + +#if SBG_CONFIG_ENABLE_LOG_INFO == 1 + #define SBG_LOG_INFO SBG_LOG_INFO_CALL +#else + #define SBG_LOG_INFO(format, ...) ((void)sizeof(SBG_LOG_INFO_CALL(format, ## __VA_ARGS__), 0)) +#endif + +/*! + * Log an information message only in debug mode + * \param[in] format String litteral for the information message (you can use printf like string formating). + */ +#define SBG_LOG_DEBUG_CALL(format, ...) sbgPlatformDebugLogMsg((const char*)__BASE_FILE__, (const char*)__FUNCTION__, __LINE__, SBG_DEBUG_LOG_CATEGORY, SBG_DEBUG_LOG_TYPE_DEBUG, SBG_NO_ERROR, format, ##__VA_ARGS__) + +#if SBG_CONFIG_ENABLE_LOG_DEBUG == 1 + #define SBG_LOG_DEBUG SBG_LOG_DEBUG_CALL +#else + #define SBG_LOG_DEBUG(format, ...) ((void)sizeof(SBG_LOG_DEBUG_CALL(format, ## __VA_ARGS__), 0)) +#endif + +//----------------------------------------------------------------------// +//- Inline functions -// +//----------------------------------------------------------------------// + +/*! + * Convert a log type into a string representation. + * + * \param[in] logType Log type. + * \return String representation for the given log type. + */ +SBG_INLINE const char *sbgDebugLogTypeToStr(SbgDebugLogType logType) +{ + const char *pString; + + switch (logType) + { + case SBG_DEBUG_LOG_TYPE_ERROR: + pString = "error"; + break; + case SBG_DEBUG_LOG_TYPE_WARNING: + pString = "warning"; + break; + case SBG_DEBUG_LOG_TYPE_INFO: + pString = "info"; + break; + case SBG_DEBUG_LOG_TYPE_DEBUG: + pString = "debug"; + break; + default: + pString = "unknown"; + break; + } + + return pString; +} + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +/*! + * Produce a text dump of a buffer. + * + * \param[in] pPrefix Prefix string before each line. + * \param[in] pBuffer Data buffer, may be NULL. + * \param[in] size Data size, in bytes. + */ +void sbgDebugHexDump(const char *pPrefix, const void *pBuffer, size_t size); + +#endif /* SBG_DEBUG_H */ diff --git a/crates/sbg-rs/sbgECom/common/interfaces/sbgInterface.c b/crates/sbg-rs/sbgECom/common/interfaces/sbgInterface.c new file mode 100644 index 0000000..0b728ff --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/interfaces/sbgInterface.c @@ -0,0 +1,83 @@ +/* sbgCommonLib headers */ +#include + +/* Local headers */ +#include "sbgInterface.h" + +//----------------------------------------------------------------------// +//- Private definitions -// +//----------------------------------------------------------------------// + +static const char *gInterfaceType[] = +{ + [SBG_IF_TYPE_UNKNOW] = "unknown", + [SBG_IF_TYPE_SERIAL] = "serial", + [SBG_IF_TYPE_ETH_UDP] = "eth UDP", + [SBG_IF_TYPE_ETH_TCP_IP] = "eth TCP", + [SBG_IF_TYPE_FILE] = "file" +}; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +void sbgInterfaceZeroInit(SbgInterface *pInterface) +{ + assert(pInterface); + + // + // Make sure the whole struct is zero init + // + memset(pInterface, 0x00, sizeof(*pInterface)); +} + +SBG_COMMON_LIB_API SbgErrorCode sbgInterfaceDestroy(SbgInterface *pInterface) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + + assert(pInterface); + + if (pInterface->pDestroyFunc) + { + errorCode = pInterface->pDestroyFunc(pInterface); + } + + return errorCode; +} + +const char *sbgInterfaceTypeGetAsString(const SbgInterface *pInterface) +{ + assert(pInterface); + + if (pInterface->type < SBG_ARRAY_SIZE(gInterfaceType)) + { + return gInterfaceType[pInterface->type]; + } + else + { + SBG_LOG_ERROR(SBG_INVALID_PARAMETER, "Unknown interface type: %" PRIu32, pInterface->type); + return gInterfaceType[SBG_IF_TYPE_UNKNOW]; + } +} + +void sbgInterfaceNameSet(SbgInterface *pInterface, const char *pName) +{ + size_t nameLen; + + assert(pInterface); + assert(pName); + + // + // Only keep the end of the name that can fit in the interface name buffer + // + nameLen = strlen(pName); + + if (nameLen < SBG_ARRAY_SIZE(pInterface->name)) + { + strcpy(pInterface->name, pName); + } + else + { + strcpy(pInterface->name, pName+(nameLen-(SBG_ARRAY_SIZE(pInterface->name)-1))); + } +} diff --git a/crates/sbg-rs/sbgECom/common/interfaces/sbgInterface.h b/crates/sbg-rs/sbgECom/common/interfaces/sbgInterface.h new file mode 100644 index 0000000..6ebf057 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/interfaces/sbgInterface.h @@ -0,0 +1,455 @@ +/*! + * \file sbgInterface.h + * \ingroup common + * \author SBG Systems + * \date 10 December 2012 + * + * \brief This file implements the base interface for all Serial and Ethernet ports. + * + * An interface is used to provide a common API for both serial and Ethernet ports. + * An interface can be opened/closed and some data can be written or read from it. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_INTERFACE_H +#define SBG_INTERFACE_H + +//----------------------------------------------------------------------// +//- Header (open extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +extern "C" { +#endif + +/* sbgCommonLib headers */ +#include + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +#define SBG_IF_NAME_MAX_SIZE (48) /*!< Maximum size in bytes for the interface name string */ + +/*! + * Type values reserved for standard interface types. + */ +#define SBG_IF_TYPE_UNKNOW (0) /*!< The interface type is not defined. */ +#define SBG_IF_TYPE_SERIAL (1) /*!< The interface is a serial com port. */ +#define SBG_IF_TYPE_ETH_UDP (2) /*!< The interface is an UDP one. */ +#define SBG_IF_TYPE_ETH_TCP_IP (3) /*!< The interface is an TCP/IP one. */ +#define SBG_IF_TYPE_FILE (4) /*!< The interface is a file. */ +#define SBG_IF_TYPE_LAST_RESERVED (999) /*!< Last reserved value for standard types. */ + +// +// Flags for the flush operation. +// +#define SBG_IF_FLUSH_INPUT ((uint32_t)1 << 0) /*!< Flush input data flag. */ +#define SBG_IF_FLUSH_OUTPUT ((uint32_t)1 << 1) /*!< Flush output data flag. */ +#define SBG_IF_FLUSH_ALL (SBG_IF_FLUSH_INPUT | SBG_IF_FLUSH_OUTPUT) /*!< Flag combination to flush both input and output data. */ + +//----------------------------------------------------------------------// +//- Predefinitions -// +//----------------------------------------------------------------------// + +/*! + * Interface structure pre-definition. + */ +typedef struct _SbgInterface SbgInterface; + +/*! + * Handle that stores the internal interface handle (ie Serial or Ethernet) + */ +typedef void* SbgInterfaceHandle; + +//----------------------------------------------------------------------// +//- Callbacks definitions -// +//----------------------------------------------------------------------// + +/*! + * Method to implement that close and destroy an interface. + * + * \param[in] pInterface Interface instance. + * \return SBG_NO_ERROR if the interface has been closed successfully. + */ +typedef SbgErrorCode (*SbgInterfaceDestroyFunc)(SbgInterface *pInterface); + +/*! + * Method to implement to write a buffer to an interface. + * + * This method should return an error only if all bytes were not written successfully. + * If you try to write zero byte, the method shouldn't return any error. + * + * \param[in] pInterface Interface instance. + * \param[in] pBuffer Pointer on an allocated buffer that contains the data to write + * \param[in] bytesToWrite Number of bytes we would like to write (can be zero). + * \return SBG_NO_ERROR if exactly bytesToWrite have been written successfully. + */ +typedef SbgErrorCode (*SbgInterfaceWriteFunc)(SbgInterface *pInterface, const void *pBuffer, size_t bytesToWrite); + +/*! + * Method to implement to read data from an interface. + * + * This method returns an error only if there is a 'low level' error on the interface. + * If no byte is read at all or less bytes than bytesToRead, this method returns SBG_NO_ERROR. + * You have to check pReadBytes field to know the number of bytes actually read. + * + * \param[in] pInterface Interface instance. + * \param[in] pBuffer Pointer on an allocated buffer that can hold at least bytesToRead bytes of data. + * \param[out] pReadBytes Returns the number of bytes actually read (can be zero and up to bytesToRead). + * \param[in] bytesToRead Maximum number of bytes to try to read on the interface. + * \return SBG_NO_ERROR if zero or some bytes have been read successfully. + */ +typedef SbgErrorCode (*SbgInterfaceReadFunc)(SbgInterface *pInterface, void *pBuffer, size_t *pReadBytes, size_t bytesToRead); + +/*! + * Make an interface flush pending input and/or output data. + * + * If flags include SBG_IF_FLUSH_INPUT, all pending input data is discarded. + * If flags include SBG_IF_FLUSH_OUTPUT, the function blocks until all output data has been written out. + * + * WARNING: The method has no action if not applicable for a type of interface + * + * \param[in] pInterface Interface instance. + * \param[in] flags Combination of the SBG_IF_FLUSH_INPUT and SBG_IF_FLUSH_OUTPUT flags. + * \return SBG_NO_ERROR if successful. + */ +typedef SbgErrorCode (*SbgInterfaceFlushFunc)(SbgInterface *pInterface, uint32_t flags); + +/*! + * Change an interface input and output speed in bps (bit per second) + * + * This method will try to change the speed immediately even if there are + * pending bytes in the send buffer. + * + * If you would like to make sure that all bytes in the Tx buffer have been + * sent before changing the speed, please flush the interface before. + * + * WARNING: The method has no action if not applicable for a type of interface + * + * \param[in] pInterface Interface instance. + * \param[in] speed The new interface speed to set in bps. + * \return SBG_NO_ERROR if successful. + */ +typedef SbgErrorCode (*SbgInterfaceSetSpeed)(SbgInterface *pInterface, uint32_t speed); + +/*! + * Returns the current interface baud rate in bps (bit per second) + * + * WARNING: The method will returns zero if not applicable for a type of interface + * + * \param[in] pInterface Interface instance. + * \return The current interface baud rate in bps or zero if not applicable. + */ +typedef uint32_t (*SbgInterfaceGetSpeed)(const SbgInterface *pInterface); + +/*! + * Compute and return the delay needed by the interface to transmit / receive X number of bytes. + * + * WARNING: The method will returns zero if not applicable for a type of interface. + * + * \param[in] pInterface Interface instance. + * \param[in] numBytes The number of bytes to transmit / receive to evaluate the needed delay. + * \return The expected delay in us needed to transmit / receive the specified number of bytes or 0 if not applicable. + */ +typedef uint32_t (*SbgInterfaceGetDelayFunc)(const SbgInterface *pInterface, size_t numBytes); + +//----------------------------------------------------------------------// +//- Structures definitions -// +//----------------------------------------------------------------------// + +/*! + * Interface definition that stores methods used to communicate on the interface. + * + * The interface class is designed to allow custom user implementations. The type member stores + * a type identifier allowing the identification of the underlying type, including custom + * implementations. Standard interfaces provided by this library use types from 1 up to + * and including SBG_IF_TYPE_LAST_RESERVED. Greater values are intended to identify custom + * types that are normally specific to the project using this library. The value 0 identifies + * an unknown interface type, usually indicating that the interface was not correctly initialized. + */ +struct _SbgInterface +{ + SbgInterfaceHandle handle; /*!< Internal interface handle used to access the media. */ + uint32_t type; /*!< Opaque interface type. */ + char name[SBG_IF_NAME_MAX_SIZE]; /*!< The interface name as passed during the creation */ + + SbgInterfaceDestroyFunc pDestroyFunc; /*!< Optional method used to destroy an interface. */ + SbgInterfaceWriteFunc pWriteFunc; /*!< Optional method used to write some data to this interface. */ + SbgInterfaceReadFunc pReadFunc; /*!< Optional method used to read some data to this interface. */ + SbgInterfaceFlushFunc pFlushFunc; /*!< Optional method used to make this interface flush all pending data. */ + SbgInterfaceSetSpeed pSetSpeedFunc; /*!< Optional method used to set the interface speed in bps. */ + SbgInterfaceGetSpeed pGetSpeedFunc; /*!< Optional method used to retrieve the interface speed in bps. */ + SbgInterfaceGetDelayFunc pDelayFunc; /*!< Optional method used to compute an expected delay to transmit/receive X bytes */ +}; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Initialize an interface instance to zero. + * + * \param[in] pInterface The interface instance. + */ +SBG_COMMON_LIB_API void sbgInterfaceZeroInit(SbgInterface *pInterface); + +/*! + * Close and destroy the interface gracefully. + * + * This method will call the specialized interface destructor if any. + * + * \param[in] pInterface The interface instance. + * \return SBG_NO_ERROR if the interface has been destroyed successfully. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgInterfaceDestroy(SbgInterface *pInterface); + +/*! + * Returns the interface type. + * + * \param[in] pInterface Interface instance + * \return The interface type. + */ +SBG_INLINE uint32_t sbgInterfaceTypeGet(const SbgInterface *pInterface) +{ + assert(pInterface); + + return pInterface->type; +} + +/*! + * Returns the interface as string. + * + * \param[in] pInterface Interface instance + * \return The interface type. + */ +SBG_COMMON_LIB_API const char *sbgInterfaceTypeGetAsString(const SbgInterface *pInterface); + +/*! + * Returns the interface name string. + * + * \param[in] pInterface Interface instance + * \return The interface name as a NULL terminated C string. + */ +SBG_INLINE const char *sbgInterfaceNameGet(const SbgInterface *pInterface) +{ + assert(pInterface); + + return pInterface->name; +} + +/*! + * Define the interface name as a NULL terminated C string. + * + * This method make sure that the provided string will always fit within + * the allocated name buffer. + * + * If the interface name you would like to set is too long, only the end + * of the string will be kept. + * + * \param[in] pInterface Interface instance + * \param[in] pName The interface name to set as a NULL terminated C string + */ +SBG_COMMON_LIB_API void sbgInterfaceNameSet(SbgInterface *pInterface, const char *pName); + +/*! + * Write some data to an interface. + * + * This method should return an error only if all bytes were not written successfully. + * If you try to write zero byte, the method shouldn't return any error. + * + * \param[in] pInterface Interface instance. + * \param[in] pBuffer Pointer on an allocated buffer that contains the data to write + * \param[in] bytesToWrite Number of bytes we would like to write (can be zero). + * \return SBG_NO_ERROR if exactly bytesToWrite have been written successfully. + * SBG_INVALID_PARAMETER if the interface doesn't support write operations. + */ +SBG_INLINE SbgErrorCode sbgInterfaceWrite(SbgInterface *pInterface, const void *pBuffer, size_t bytesToWrite) +{ + SbgErrorCode errorCode; + + assert(pInterface); + assert(pBuffer); + + if (pInterface->pWriteFunc) + { + errorCode = pInterface->pWriteFunc(pInterface, pBuffer, bytesToWrite); + } + else + { + errorCode = SBG_INVALID_PARAMETER; + } + + return errorCode; +} + +/*! + * Try to read some data from an interface. + * + * This method returns an error only if there is a 'low level' error on the interface. + * If no byte is read at all or less bytes than bytesToRead, this method returns SBG_NO_ERROR. + * You have to check pReadBytes field to know the number of bytes actually read. + * + * \param[in] pInterface Interface instance. + * \param[in] pBuffer Pointer on an allocated buffer that can hold at least bytesToRead bytes of data. + * \param[out] pReadBytes Returns the number of bytes actually read (can be zero and up to bytesToRead). + * \param[in] bytesToRead Maximum number of bytes to try to read on the interface. + * \return SBG_NO_ERROR if zero or some bytes have been read successfully. + * SBG_INVALID_PARAMETER if the interface doesn't support read operations. + */ +SBG_INLINE SbgErrorCode sbgInterfaceRead(SbgInterface *pInterface, void *pBuffer, size_t *pReadBytes, size_t bytesToRead) +{ + SbgErrorCode errorCode; + + assert(pInterface); + assert(pBuffer); + assert(pReadBytes); + + if (pInterface->pReadFunc) + { + errorCode = pInterface->pReadFunc(pInterface, pBuffer, pReadBytes, bytesToRead); + } + else + { + *pReadBytes = 0; + errorCode = SBG_INVALID_PARAMETER; + } + + return errorCode; +} + +/*! + * Make an interface flush pending input and/or output data. + * + * If flags include SBG_IF_FLUSH_INPUT, all pending input data is discarded. + * If flags include SBG_IF_FLUSH_OUTPUT, the function blocks until all output data has been written out. + * + * WARNING: The method has no action if not applicable for a type of interface + * + * \param[in] pInterface Interface instance. + * \param[in] flags Combination of the SBG_IF_FLUSH_INPUT and SBG_IF_FLUSH_OUTPUT flags. + * \return SBG_NO_ERROR if successful. + */ +SBG_INLINE SbgErrorCode sbgInterfaceFlush(SbgInterface *pInterface, uint32_t flags) +{ + SbgErrorCode errorCode; + + assert(pInterface); + assert((flags & ~SBG_IF_FLUSH_ALL) == 0); + + if (pInterface->pFlushFunc) + { + errorCode = pInterface->pFlushFunc(pInterface, flags); + } + else + { + errorCode = SBG_NO_ERROR; + } + + return errorCode; +} + +/*! + * Change an interface input and output speed in bps (bit per second) + * + * This method will try to change the speed immediately even if there are + * pending bytes in the send buffer. + * + * If you would like to make sure that all bytes in the Tx buffer have been + * sent before changing the speed, please flush the interface before. + * + * WARNING: The method has no action if not applicable for a type of interface + * + * \param[in] pInterface Interface instance. + * \param[in] speed The new interface speed to set in bps. + * \return SBG_NO_ERROR if successful. + */ +SBG_INLINE SbgErrorCode sbgInterfaceSetSpeed(SbgInterface *pInterface, uint32_t speed) +{ + assert(pInterface); + assert(speed > 0); + + if (pInterface->pSetSpeedFunc) + { + return pInterface->pSetSpeedFunc(pInterface, speed); + } + else + { + return SBG_NO_ERROR; + } +} + +/*! + * Returns the current interface baud rate in bps (bit per second) + * + * WARNING: The method will returns zero if not applicable for a type of interface + * + * \param[in] pInterface Interface instance. + * \return The current interface baud rate in bps or zero if not applicable. + */ +SBG_INLINE uint32_t sbgInterfaceGetSpeed(const SbgInterface *pInterface) +{ + assert(pInterface); + + if (pInterface->pGetSpeedFunc) + { + return pInterface->pGetSpeedFunc(pInterface); + } + else + { + return 0; + } +} + +/*! + * Compute and return the delay needed by the interface to transmit / receive X number of bytes. + * + * WARNING: The method will returns zero if not applicable for a type of interface. + * + * \param[in] pInterface Interface instance. + * \param[in] numBytes The number of bytes to transmit / receive to evaluate the needed delay. + * \return The expected delay in us needed to transmit / receive the specified number of bytes or 0 if not applicable. + */ +SBG_INLINE uint32_t sbgInterfaceGetDelay(const SbgInterface *pInterface, size_t numBytes) +{ + assert(pInterface); + + if (pInterface->pDelayFunc) + { + return pInterface->pDelayFunc(pInterface, numBytes); + } + else + { + return 0; + } +} + +//----------------------------------------------------------------------// +//- Footer (close extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +} +#endif + +#endif /* SBG_INTERFACE_H */ diff --git a/crates/sbg-rs/sbgECom/common/interfaces/sbgInterfaceFile.c b/crates/sbg-rs/sbgECom/common/interfaces/sbgInterfaceFile.c new file mode 100644 index 0000000..7478b9e --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/interfaces/sbgInterfaceFile.c @@ -0,0 +1,305 @@ +// sbgCommnonLib headers +#include + +// Local headers +#include "sbgInterface.h" +#include "sbgInterfaceFile.h" + +//----------------------------------------------------------------------// +//- Private methods -// +//----------------------------------------------------------------------// + +/*! + * Returns the interface FILE descriptor. + * + * \param[in] pInterface Interface instance. + * \return The associated FILE descriptor. + */ +static FILE *sbgInterfaceFileGetDesc(SbgInterface *pInterface) +{ + assert(pInterface); + assert(pInterface->type == SBG_IF_TYPE_FILE); + assert(pInterface->handle); + + return (FILE*)pInterface->handle; +} + +/*! + * Destroy the interface by closing the file descriptor. + * + * \param[in] pInterface Interface instance. + * \return SBG_NO_ERROR if the interface has been closed successfully. + */ +static SbgErrorCode sbgInterfaceFileDestroy(SbgInterface *pInterface) +{ + FILE *pInputFile; + + assert(pInterface); + assert(pInterface->type == SBG_IF_TYPE_FILE); + + pInputFile = sbgInterfaceFileGetDesc(pInterface); + + fclose(pInputFile); + sbgInterfaceZeroInit(pInterface); + + return SBG_NO_ERROR; +} + +/*! + * Write some data the the file + * + * \param[in] pInterface Valid handle on an initialized interface. + * \param[in] pBuffer Pointer on an allocated buffer that contains the data to write + * \param[in] bytesToWrite Number of bytes we would like to write. + * \return SBG_NO_ERROR if all bytes have been written successfully. + */ +static SbgErrorCode sbgInterfaceFileWrite(SbgInterface *pInterface, const void *pBuffer, size_t bytesToWrite) +{ + FILE *pOutputFile; + size_t bytesWritten; + + assert(pInterface); + assert(pInterface->type == SBG_IF_TYPE_FILE); + assert(pBuffer); + + pOutputFile = sbgInterfaceFileGetDesc(pInterface); + + // + // Write the data and check if all bytes have been written + // + bytesWritten = fwrite(pBuffer, sizeof(uint8_t), bytesToWrite, pOutputFile); + + if (bytesWritten == bytesToWrite) + { + + return SBG_NO_ERROR; + } + else + { + return SBG_WRITE_ERROR; + } +} + +/*! + * Try to read some data from an interface. + * + * \param[in] pInterface Valid handle on an initialized interface. + * \param[in] pBuffer Pointer on an allocated buffer that can hold at least bytesToRead bytes of data. + * \param[out] pReadBytes Pointer on an uint32_t used to return the number of read bytes. + * \param[in] bytesToRead Number of bytes we would like to read. + * \return SBG_NO_ERROR if no error occurs, please check the number of received bytes. + */ +static SbgErrorCode sbgInterfaceFileRead(SbgInterface *pInterface, void *pBuffer, size_t *pReadBytes, size_t bytesToRead) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + FILE *pInputFile; + + assert(pInterface); + assert(pInterface->type == SBG_IF_TYPE_FILE); + assert(pBuffer); + assert(pReadBytes); + + pInputFile = sbgInterfaceFileGetDesc(pInterface); + + // + // Read some bytes from the file and check if an error has occurred + // + *pReadBytes = fread(pBuffer, sizeof(uint8_t), bytesToRead, pInputFile); + + if (*pReadBytes < bytesToRead) + { + // + // Don't report an error if we have reached the end of the file to comply with sbgInterface specification + // + if (ferror(pInputFile) != 0) + { + errorCode = SBG_READ_ERROR; + SBG_LOG_ERROR(errorCode, "File read error %u", ferror(pInputFile)); + } + } + + return errorCode; +} + +/*! + * Make an interface flush all pending input or output data. + * + * If flags include SBG_IF_FLUSH_INPUT, all pending input data is discarded. + * If flags include SBG_IF_FLUSH_OUTPUT, the function blocks until all output data has been written out. + * + * \param[in] pInterface Valid handle on an initialized interface. + * \param[in] flags Combination of the SBG_IF_FLUSH_INPUT and SBG_IF_FLUSH_OUTPUT flags. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgInterfaceFileFlush(SbgInterface *pInterface, uint32_t flags) +{ + SbgErrorCode errorCode; + FILE *pInputFile; + + assert(pInterface); + assert(pInterface->type == SBG_IF_TYPE_FILE); + + pInputFile = sbgInterfaceFileGetDesc(pInterface); + + if ((pInterface->pReadFunc && (flags & SBG_IF_FLUSH_INPUT)) || + (pInterface->pWriteFunc && (flags & SBG_IF_FLUSH_OUTPUT))) + { + int ret; + + ret = fflush(pInputFile); + + if (ret == 0) + { + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_ERROR; + } + } + else + { + errorCode = SBG_NO_ERROR; + } + + return errorCode; +} + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API SbgErrorCode sbgInterfaceFileOpen(SbgInterface *pInterface, const char *filePath) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + FILE *pInputFile; + + assert(pInterface); + assert(filePath); + + // + // Always call the underlying zero init method to make sure we can correctly handle SbgInterface evolutions + // + sbgInterfaceZeroInit(pInterface); + + // + // Try to open the file + // + pInputFile = fopen(filePath, "rb"); + + // + // Test if the input file has been opened + // + if (pInputFile) + { + // + // Define base interface members + // + pInterface->handle = pInputFile; + pInterface->type = SBG_IF_TYPE_FILE; + + // + // Define the interface name + // + sbgInterfaceNameSet(pInterface, filePath); + + // + // Define all specialized members + // + pInterface->pDestroyFunc = sbgInterfaceFileDestroy; + pInterface->pReadFunc = sbgInterfaceFileRead; + pInterface->pWriteFunc = NULL; + pInterface->pFlushFunc = sbgInterfaceFileFlush; + } + else + { + // + // Unable to open the input file + // + errorCode = SBG_INVALID_PARAMETER; + } + + return errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgInterfaceFileWriteOpen(SbgInterface *pInterface, const char *filePath) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + FILE *pInputFile; + + assert(pInterface); + assert(filePath); + + // + // Try to open the file + // + pInputFile = fopen(filePath, "wb"); + + // + // Test if the input file has been opened + // + if (pInputFile) + { + // + // Define base interface members + // + pInterface->handle = pInputFile; + pInterface->type = SBG_IF_TYPE_FILE; + + // + // Define the interface name + // + sbgInterfaceNameSet(pInterface, filePath); + + // + // Define all specialized members + // + pInterface->pDestroyFunc = sbgInterfaceFileDestroy; + pInterface->pReadFunc = NULL; + pInterface->pWriteFunc = sbgInterfaceFileWrite; + pInterface->pFlushFunc = sbgInterfaceFileFlush; + } + else + { + // + // Unable to open the input file + // + errorCode = SBG_INVALID_PARAMETER; + } + + return errorCode; +} + +SBG_COMMON_LIB_API size_t sbgInterfaceFileGetSize(SbgInterface *pInterface) +{ + FILE *pInputFile; + long cursorPos; + long fileSize; + + assert(pInterface); + assert(pInterface->type == SBG_IF_TYPE_FILE); + + pInputFile = sbgInterfaceFileGetDesc(pInterface); + + // + // Compute the file size + // + cursorPos = ftell(pInputFile); + fseek(pInputFile, 0, SEEK_END); + fileSize = ftell(pInputFile); + fseek(pInputFile, cursorPos, SEEK_SET); + + return (size_t)fileSize; +} + +SBG_COMMON_LIB_API size_t sbgInterfaceFileGetCursor(const SbgInterface *pInterface) +{ + FILE *pInputFile; + + assert(pInterface); + assert(pInterface->type == SBG_IF_TYPE_FILE); + + pInputFile = sbgInterfaceFileGetDesc((SbgInterface*)pInterface); + + return (size_t)ftell(pInputFile); +} diff --git a/crates/sbg-rs/sbgECom/common/interfaces/sbgInterfaceFile.h b/crates/sbg-rs/sbgECom/common/interfaces/sbgInterfaceFile.h new file mode 100644 index 0000000..ea3b9b0 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/interfaces/sbgInterfaceFile.h @@ -0,0 +1,93 @@ +/*! + * \file sbgInterfaceFile.h + * \ingroup common + * \author SBG Systems (Raphael Siryani) + * \date 01 April 2013 + * + * \brief This file implements a file interface for read only operations. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ +#ifndef SBG_INTERFACE_FILE_H +#define SBG_INTERFACE_FILE_H + +//----------------------------------------------------------------------// +//- Header (open extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +extern "C" { +#endif + +// sbgCommonLib headers +#include + +// Local headers +#include "sbgInterface.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Open a file as an interface for read only operations. + * + * \param[in] pInterface Pointer on an allocated interface instance to initialize. + * \param[in] filePath File path to open. + * \return SBG_NO_ERROR if the interface has been created. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgInterfaceFileOpen(SbgInterface *pInterface, const char *filePath); + +/*! + * Open a file as an interface for write only operations. + * + * \param[in] pInterface Pointer on an allocated interface instance to initialize. + * \param[in] filePath File path to open. + * \return SBG_NO_ERROR if the interface has been created. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgInterfaceFileWriteOpen(SbgInterface *pInterface, const char *filePath); + +/*! + * Returns the file size in bytes. + * + * \param[in] pInterface Valid handle on an initialized interface. + * \return The file size in bytes. + */ +SBG_COMMON_LIB_API size_t sbgInterfaceFileGetSize(SbgInterface *pInterface); + +/*! + * Returns the current cursor position in the file in bytes. + * + * \param[in] pInterface Valid handle on an initialized interface. + * \return The current cursor position in bytes. + */ +SBG_COMMON_LIB_API size_t sbgInterfaceFileGetCursor(const SbgInterface *pInterface); + +//----------------------------------------------------------------------// +//- Footer (close extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +} +#endif + +#endif /* SBG_INTERFACE_FILE_H */ diff --git a/crates/sbg-rs/sbgECom/common/interfaces/sbgInterfaceSerial.h b/crates/sbg-rs/sbgECom/common/interfaces/sbgInterfaceSerial.h new file mode 100644 index 0000000..2fcbc11 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/interfaces/sbgInterfaceSerial.h @@ -0,0 +1,71 @@ +/*! + * \file sbgInterfaceSerial.h + * \ingroup common + * \author SBG Systems + * \date 06 February 2013 + * + * \brief This file implements a serial interface. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_INTERFACE_SERIAL_H +#define SBG_INTERFACE_SERIAL_H + +//----------------------------------------------------------------------// +//- Header (open extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +extern "C" { +#endif + +// sbgCommonLib headers +#include +#include + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +#define SBG_IF_SERIAL_TX_BUFFER_SIZE (4096) /*!< Define the transmission buffer size for the serial port. */ +#define SBG_IF_SERIAL_RX_BUFFER_SIZE (4096) /*!< Define the reception buffer size for the serial port. */ + +/*! + * Initialize a serial interface for read and write operations. + * + * \param[in] pInterface Pointer on an allocated interface instance to initialize. + * \param[in] deviceName Serial interface location (COM21 , /dev/ttys0, depending on platform). + * \param[in] baudRate Serial interface baud rate in bps. + * \return SBG_NO_ERROR if the interface has been created. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgInterfaceSerialCreate(SbgInterface *pInterface, const char *deviceName, uint32_t baudRate); + +//----------------------------------------------------------------------// +//- Footer (close extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +} +#endif + +#endif // SBG_INTERFACE_SERIAL_H diff --git a/crates/sbg-rs/sbgECom/common/network/sbgNetwork.c b/crates/sbg-rs/sbgECom/common/network/sbgNetwork.c new file mode 100644 index 0000000..188d0ac --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/network/sbgNetwork.c @@ -0,0 +1,127 @@ +// Project headers +#include +#include + + +// Local headers +#include "sbgNetwork.h" + +//----------------------------------------------------------------------// +//- IP manipulation methods -// +//----------------------------------------------------------------------// + +/*! + * Convert an ip to a string of the form A.B.C.D + * \param[in] ipAddr IP address to convert to a string. + * \param[out] pBuffer Pointer on an allocated buffer than can hold ip address as a string. + * \param[in] maxSize Maximum number of chars that can be stored in pBuffer including the NULL char. + */ +SBG_COMMON_LIB_API void sbgNetworkIpToString(sbgIpAddress ipAddr, char *pBuffer, size_t maxSize) +{ + // + // Check input arguments + // + assert(pBuffer); + assert(maxSize >= 16); + + SBG_UNUSED_PARAMETER(maxSize); + + // + // Write the IP address + // + snprintf(pBuffer, maxSize, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8, sbgIpAddrGetA(ipAddr), sbgIpAddrGetB(ipAddr), sbgIpAddrGetC(ipAddr), sbgIpAddrGetD(ipAddr)); +} + +/*! + * Convert an ip address stored in a string of the form A.B.C.D to an sbgIpAddress object. + * \param[in] pBuffer IP address as a string of the form A.B.C.D + * \return IP address parsed from the string or 0.0.0.0 if the IP is invalid. + */ +SBG_COMMON_LIB_API sbgIpAddress sbgNetworkIpFromString(const char *pBuffer) +{ + int ipAddrA; + int ipAddrB; + int ipAddrC; + int ipAddrD; + int numReadParams; + sbgIpAddress ip; + sbgIpAddress ret; + char checkBuffer[SBG_NETWORK_IPV4_STRING_SIZE]; + + assert(pBuffer); + + ret = SBG_IPV4_UNSPECIFIED_ADDR; + + numReadParams = sscanf(pBuffer, "%d.%d.%d.%d", &ipAddrA, &ipAddrB, &ipAddrC, &ipAddrD); + + if ((numReadParams == 4) && (ipAddrA >= 0) && (ipAddrA <= 255) && (ipAddrB >= 0) && (ipAddrB <= 255) && (ipAddrC >= 0) && (ipAddrC <= 255) && (ipAddrD >= 0) && (ipAddrD <= 255)) + { + ip = sbgIpAddr((uint8_t)ipAddrA, (uint8_t)ipAddrB, (uint8_t)ipAddrC, (uint8_t)ipAddrD); + + sbgNetworkIpToString(ip, checkBuffer, SBG_ARRAY_SIZE(checkBuffer)); + + if (strcmp(pBuffer, checkBuffer) == 0) + { + ret = ip; + } + } + + return ret; +} + +//----------------------------------------------------------------------// +//- IP validation methods -// +//----------------------------------------------------------------------// + +/*! +* Check if an IpV4 netmask is valid, the mask should be contiguous (1111 followed by 0) +* \param[in] netmask The netmask stored in an uint32_t (host endianness). +* \return true if the netmask is valid ie contiguous. +*/ +SBG_COMMON_LIB_API bool sbgIpNetMaskValid(sbgIpAddress netmask) +{ + uint32_t y; + uint32_t z; + + // + // First test that the netmask is not zero, if yes, it's valid + // + if (netmask != 0) + { + // + // We are doing arithmetic so we have to make sure the netmask is using the platform endianness + // The IP address is always stored in big endian so we have to swap it for little endian platforms + // +#if SBG_CONFIG_BIG_ENDIAN == 0 + netmask = sbgSwap32(netmask); +#endif + + // + // Compute the bitwise inverse + // + y = ~netmask; + + // + // Add one to the inverse so if netmask was a proper one, there will be at most 1 bit set in this. + // + z = y + 1; + + // + // Test that, simply and z with z - 1, which happens to be y. The result will be zero if all is OK, non zero otherwise. + // + if ((z&y) == 0) + { + // + // We have a valid netmask + // + return true; + } + else + { + return false; + } + } + + return true; +} + diff --git a/crates/sbg-rs/sbgECom/common/network/sbgNetwork.h b/crates/sbg-rs/sbgECom/common/network/sbgNetwork.h new file mode 100644 index 0000000..3df7532 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/network/sbgNetwork.h @@ -0,0 +1,287 @@ +/*! + * \file sbgNetwork.h + * \ingroup common + * \author SBG Systems + * \date September 15, 2015 + * + * \brief Network related tools + * + * IP v4 address is stored in memory with a uint32_t. + * Each address component A.B.C.D is stored in 8 bits using the network + * endianess ie Big Endian. + * + * We thus have the following memory organisation: + * + * In Little Endian: + * |LSB| | |MSB| + * | A | B | C | D | + * + * In Big Endian: + * |MSB| | |LSB| + * | A | B | C | D | + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_NETWORK_H +#define SBG_NETWORK_H + +// sbgCommonLib headers +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Common IPv4 definitions -// +//----------------------------------------------------------------------// +#define SBG_IPV4_UNSPECIFIED_ADDR sbgIpAddr(0, 0, 0, 0) /*!< This represents an undefined IP address. */ +#define SBG_IPV4_BROADCAST_ADDR sbgIpAddr(255, 255, 255, 255) /*!< Broadcast IP address used to address all devices within the same network. */ + +#define SBG_NETWORK_IPV4_STRING_SIZE (16) /*!< String size for representation of an IPV4 */ + +//----------------------------------------------------------------------// +//- IP setters / getters -// +//----------------------------------------------------------------------// + +/*! + * Build an IP V4 address in the form a.b.c.d + * \param[in] a First 8 bits IP address. + * \param[in] b Second 8 bits IP address. + * \param[in] c Third 8 bits IP address. + * \param[in] d Last 8 bits IP address. + * \return An initialized IP address object. + */ +SBG_INLINE sbgIpAddress sbgIpAddr(uint8_t a, uint8_t b, uint8_t c, uint8_t d) +{ +#if SBG_CONFIG_BIG_ENDIAN == 1 + return (a << 24) | (b << 16) | (c << 8) | d; +#else + return a | (b << 8) | (c << 16) | (d << 24); +#endif +} + +/*! + * Return the first A field of of an IP v4 address of the form A.B.C.D + * \param[in] ipAddr An sbgIpAddress to convert. + * \return The A field of the IP address. + */ +SBG_INLINE uint8_t sbgIpAddrGetA(sbgIpAddress ipAddr) +{ +#if SBG_CONFIG_BIG_ENDIAN == 1 + return (uint8_t)((ipAddr & 0xFF000000) >> 24); +#else + return (uint8_t)((ipAddr & 0x000000FF)); +#endif +} + +/*! +* Return the first B field of of an IP v4 address of the form A.B.C.D +* \param[in] ipAddr An sbgIpAddress to convert. +* \return The B field of the IP address. +*/ +SBG_INLINE uint8_t sbgIpAddrGetB(sbgIpAddress ipAddr) +{ +#if SBG_CONFIG_BIG_ENDIAN == 1 + return (uint8_t)((ipAddr & 0x00FF0000) >> 16); +#else + return (uint8_t)((ipAddr & 0x0000FF00) >> 8); +#endif +} + +/*! +* Return the first C field of of an IP v4 address of the form A.B.C.D +* \param[in] ipAddr An sbgIpAddress to convert. +* \return The C field of the IP address. +*/ +SBG_INLINE uint8_t sbgIpAddrGetC(sbgIpAddress ipAddr) +{ +#if SBG_CONFIG_BIG_ENDIAN == 1 + return (uint8_t)((ipAddr & 0x0000FF00) >> 8); +#else + return (uint8_t)((ipAddr & 0x00FF0000) >> 16); +#endif +} + +/*! +* Return the first D field of of an IP v4 address of the form A.B.C.D +* \param[in] ipAddr An sbgIpAddress to convert. +* \return The D field of the IP address. +*/ +SBG_INLINE uint8_t sbgIpAddrGetD(sbgIpAddress ipAddr) +{ +#if SBG_CONFIG_BIG_ENDIAN == 1 + return (uint8_t)((ipAddr & 0x000000FF)); +#else + return (uint8_t)((ipAddr & 0xFF000000) >> 24); +#endif +} + +//----------------------------------------------------------------------// +//- IP manipulation methods -// +//----------------------------------------------------------------------// + +/*! + * Convert an ip to a string of the form A.B.C.D + * \param[in] ipAddr IP address to convert to a string. + * \param[out] pBuffer Pointer on an allocated buffer than can hold ip address as a string. + * \param[in] maxSize Maximum number of chars that can be stored in pBuffer including the NULL char. + */ +SBG_COMMON_LIB_API void sbgNetworkIpToString(sbgIpAddress ipAddr, char *pBuffer, size_t maxSize); + +/*! + * Convert an ip address stored in a string of the form A.B.C.D to an sbgIpAddress object. + * \param[in] pBuffer IP address as a string of the form A.B.C.D + * \return IP address parsed from the string or 0.0.0.0 if the IP is invalid. + */ +SBG_COMMON_LIB_API sbgIpAddress sbgNetworkIpFromString(const char *pBuffer); + +//----------------------------------------------------------------------// +//- IP operations -// +//----------------------------------------------------------------------// + +/*! + * Given an ip address and the netmask, returns the network part (ip & subnetMask) + * \param[in] ipAddress The ip address stored in an uint32_t (host endianness). + * \param[in] netmask The netmask stored in an uint32_t (host endianness). + * \return The network part of the ip address. + */ +SBG_INLINE sbgIpAddress sbgIpGetNetworkAddr(sbgIpAddress ipAddress, sbgIpAddress netmask) +{ + return (ipAddress & netmask); +} + +/*! + * Given an ip address and the netmask, returns the host part (ip & ~subnetMask) + * \param[in] ipAddress The ip address stored in an uint32_t (host endianness). + * \param[in] netmask The netmask stored in an uint32_t (host endianness). + * \return The host part of the ip address. + */ +SBG_INLINE sbgIpAddress sbgIpGetHostAddr(sbgIpAddress ipAddress, sbgIpAddress netmask) +{ + return (ipAddress & ~netmask); +} + +//----------------------------------------------------------------------// +//- IP validation methods -// +//----------------------------------------------------------------------// + +/*! + * Returns true if the provided IP address is unspecified ie (0.0.0.0) + * \param[in] ipAddress The ip address to test + * \return true if the ip address is unspecified or false otherwise. + */ +SBG_INLINE bool sbgIpAddressIsUnspecified(sbgIpAddress ipAddress) +{ + if (ipAddress == 0) + { + return true; + } + else + { + return false; + } +} + +/*! + * Check if an IpV4 address is valid. The ip address format is A.B.C.D and A should respect 0 < A < 224 + * \param[in] ipAddress The ip address stored in an uint32_t (host endianness). + * \return true if the ip address is valid ie contiguous. + */ +SBG_INLINE bool sbgIpAddressValid(sbgIpAddress ipAddress) +{ + // + // Check the if A part of the ip address is within 1 and 223 + // + if ((sbgIpAddrGetA(ipAddress) > 0) && (sbgIpAddrGetA(ipAddress) < 224)) + { + // + // The ip address is valid + // + return true; + } + else + { + // + // The ip address is not valid + // + return false; + } +} + +/*! + * Given an ip address and the netmask, returns true if this ip address is within the subnet. + * \param[in] ipAddress The ip address stored in an uint32_t (host endianness). + * \param[in] netmask The netmask stored in an uint32_t (host endianness). + * \return true if this ip address is within the subnet or false otherwise. + */ +SBG_INLINE sbgIpAddress sbgIpAddrWithinSubnet(sbgIpAddress ipAddress, sbgIpAddress netmask) +{ + // + // Just check if the host part is equals to zero + // + if (sbgIpGetHostAddr(ipAddress, netmask) == 0) + { + return false; + } + else + { + return true; + } +} + +/*! + * Check if two ip addresses are in the same network given the subnet. + * \param[in] firstIpAddr The first IP address to check. + * \param[in] secondIpAddr The second IP address to check. + * \param[in] netmask The netmask of the network. + * \return true if the two ip addresses are in the same network. + */ +SBG_INLINE bool sbgIpAddrIsSameNetwork(sbgIpAddress firstIpAddr, sbgIpAddress secondIpAddr, sbgIpAddress netmask) +{ + if ((firstIpAddr & netmask) == (secondIpAddr & netmask)) + { + return true; + } + else + { + return false; + } +} + +/*! + * Check if an IpV4 netmask is valid, the mask should be contiguous (1111 followed by 0) + * \param[in] netmask The netmask stored in an uint32_t (host endianness). + * \return true if the netmask is valid ie contiguous. + */ +SBG_COMMON_LIB_API bool sbgIpNetMaskValid(sbgIpAddress netmask); + + +#ifdef __cplusplus +} +#endif + +#endif // SBG_NETWORK_H diff --git a/crates/sbg-rs/sbgECom/common/platform/sbgPlatform.c b/crates/sbg-rs/sbgECom/common/platform/sbgPlatform.c new file mode 100644 index 0000000..7284e43 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/platform/sbgPlatform.c @@ -0,0 +1,30 @@ +// sbgCommonLib headers +#include + +//----------------------------------------------------------------------// +//- Include specific header for WIN32 and UNIX platforms -// +//----------------------------------------------------------------------// + + +//----------------------------------------------------------------------// +//- Global singleton for the log callback -// +//----------------------------------------------------------------------// + +/*! + * Unique singleton used to log error messages. + */ +SbgCommonLibOnLogFunc gLogCallback = NULL; + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + + +SBG_COMMON_LIB_API void sbgCommonLibSetLogCallback(SbgCommonLibOnLogFunc logCallback) +{ + // + // TODO: should we implement lock / sync mechanisms ? + // + gLogCallback = logCallback; +} + diff --git a/crates/sbg-rs/sbgECom/common/platform/sbgPlatform.h b/crates/sbg-rs/sbgECom/common/platform/sbgPlatform.h new file mode 100644 index 0000000..6adce07 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/platform/sbgPlatform.h @@ -0,0 +1,104 @@ +/*! + * \file sbgPlatform.h + * \ingroup common + * \author SBG Systems + * \date March 17, 2015 + * + * \brief Platform-specific functions. + * + * This file should be modified to each targeted platform. + * For example, all common headers should be included from this file. + * + * The platform endianness should be defined here. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_PLATFORM_H +#define SBG_PLATFORM_H + +// sbgCommonLib headers +#include +#include +#include + +//----------------------------------------------------------------------// +//- Function pointer definitions -// +//----------------------------------------------------------------------// + +/*! + * Type for logging functions. + * + * \param[in] pFileName File name where the error occurred. + * \param[in] pFunctionName Function name where the error occurred. + * \param[in] line Line number where the error occurred. + * \param[in] pCategory Category for this log or "None" if no category has been specified. + * \param[in] logType Define if we have an error, a warning, an info or a debug log. + * \param[in] errorCode The error code associated with the message. + * \param[in] pMessage The message to log. + */ +typedef void (*SbgCommonLibOnLogFunc)(const char *pFileName, const char *pFunctionName, uint32_t line, const char *pCategory, SbgDebugLogType logType, SbgErrorCode errorCode, const char *pMessage); + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +/*! + * Get the current time. + * + * \return The current time, in ms. + */ +SBG_COMMON_LIB_API uint32_t sbgGetTime(void); + +/*! + * Sleep. + * + * \param[in] ms Time to wait, in ms. + */ +SBG_COMMON_LIB_API void sbgSleep(uint32_t ms); + +/*! + * Set the log function. + * + * Some platforms may not provide the ability to set a user-provided log function, in which + * case this function does nothing. + * + * \param[in] logCallback Log function. + */ +SBG_COMMON_LIB_API void sbgCommonLibSetLogCallback(SbgCommonLibOnLogFunc logCallback); + +/*! + * Log a message. + * + * \param[in] pFileName File name where the error occurred. + * \param[in] pFunctionName Function name where the error occurred. + * \param[in] line Line number where the error occurred. + * \param[in] pCategory Category for this log or "None" if no category has been specified. + * \param[in] logType Define if we have an error, a warning, an info or a debug log. + * \param[in] errorCode The error code associated with the message. + * \param[in] pFormat The error message that will be used with the variable list of arguments. + */ +SBG_COMMON_LIB_API void sbgPlatformDebugLogMsg(const char *pFileName, const char *pFunctionName, uint32_t line, const char *pCategory, SbgDebugLogType logType, SbgErrorCode errorCode, const char *pFormat, ...) SBG_CHECK_FORMAT(printf, 7, 8); + +#endif // SBG_PLATFORM_H diff --git a/crates/sbg-rs/sbgECom/common/sbgCommon.c b/crates/sbg-rs/sbgECom/common/sbgCommon.c new file mode 100644 index 0000000..9691fde --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/sbgCommon.c @@ -0,0 +1,28 @@ +// sbgCommonLib headers +#include + +#ifdef USE_BUILD_NUMBER_GENERATOR +#include +#endif + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API uint32_t sbgCommonLibGetVersion(void) +{ +#ifdef USE_BUILD_NUMBER_GENERATOR + return SBG_COMMON_LIB_VERSION; +#else + return 0; +#endif +} + +SBG_COMMON_LIB_API bool sbgCommonLibIsDebug(void) +{ +#ifdef NDEBUG + return false; +#else + return true; +#endif +} diff --git a/crates/sbg-rs/sbgECom/common/sbgCommon.h b/crates/sbg-rs/sbgECom/common/sbgCommon.h new file mode 100644 index 0000000..c2cc8a1 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/sbgCommon.h @@ -0,0 +1,148 @@ +/*! + * \file sbgCommon.h + * \ingroup common + * \author SBG Systems + * \date March 17, 2015 + * + * \brief Main header for the SBG Systems common C library. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +/*! + * \defgroup common Common + * \brief SBG Systems foundation framework that is common to all C/C++ projects. + */ + +#ifndef SBG_COMMON_H +#define SBG_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sbgConfig.h" + +//----------------------------------------------------------------------// +//- Default configuration -// +//----------------------------------------------------------------------// + +/*! + * If set to 0, the platform support only aligned memory access. + * If set to 1, the platform support unaligned memory access. + * Default: Support only Aligned access - Disabled + */ +#ifndef SBG_CONFIG_UNALIGNED_ACCESS_AUTH +#define SBG_CONFIG_UNALIGNED_ACCESS_AUTH (0) +#endif + +/*! + * If set to 0, the platform is using little endian. + * If set to 1, the platform is using big endian. + * Default: Little Endian - Disabled + */ +#ifndef SBG_CONFIG_BIG_ENDIAN +#define SBG_CONFIG_BIG_ENDIAN (0) +#endif + +/*! + * If set to 1, error logs level will be thrown. + * Default: Enabled + */ +#ifndef SBG_CONFIG_ENABLE_LOG_ERROR +#define SBG_CONFIG_ENABLE_LOG_ERROR (1) +#endif + +/*! + * If set to 1, warning logs level will be thrown. + * Default: Enabled + */ +#ifndef SBG_CONFIG_ENABLE_LOG_WARNING +#define SBG_CONFIG_ENABLE_LOG_WARNING (1) +#endif + +/*! + * If set to 1, information logs level will be thrown. + * Default: Enabled + */ +#ifndef SBG_CONFIG_ENABLE_LOG_INFO +#define SBG_CONFIG_ENABLE_LOG_INFO (1) +#endif + +/*! + * If set to 1, debug logs level will be thrown. + * Default: Enabled + */ +#ifndef SBG_CONFIG_ENABLE_LOG_DEBUG +#define SBG_CONFIG_ENABLE_LOG_DEBUG (1) +#endif + +/*! + * Maximum error message size in bytes that can be generated including the NULL Char. + * Default: 1024 + */ +#ifndef SBG_CONFIG_LOG_MAX_SIZE +#define SBG_CONFIG_LOG_MAX_SIZE ((size_t)(1024)) +#endif + +/*! + * Maximum number of chars for a file name including the NULL char. + * Default: 256 + */ +#ifndef SBG_CONFIG_PATH_MAX_SIZE +#define SBG_CONFIG_PATH_MAX_SIZE ((size_t)(256)) +#endif + +//----------------------------------------------------------------------// +//- Headers -// +//----------------------------------------------------------------------// + +#include "sbgDefines.h" +#include "sbgErrorCodes.h" +#include "sbgTypes.h" + +#include "debug/sbgDebug.h" +#include "platform/sbgPlatform.h" + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +/*! + * Retreive the current sbgCommonLib encoded version. + * \return The current sbgCommonLib version + */ +SBG_COMMON_LIB_API uint32_t sbgCommonLibGetVersion(void); + +/*! + * Tell if the library is compiled in debug mode or not + * \return True if it's compiled in debug, False otherwise + */ +SBG_COMMON_LIB_API bool sbgCommonLibIsDebug(void); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_COMMON_H diff --git a/crates/sbg-rs/sbgECom/common/sbgConfig.h b/crates/sbg-rs/sbgECom/common/sbgConfig.h new file mode 100644 index 0000000..b6763b5 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/sbgConfig.h @@ -0,0 +1,64 @@ +/*! + * \file sbgConfig.h + * \author SBG Systems (Raphael Siryani) + * \date 17 March 2015 + * + * \brief Header file used to configure the framework. + * + * You can configure for example the logging system. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_CONFIG_H +#define SBG_CONFIG_H + +//----------------------------------------------------------------------// +//- Platform configuration -// +//----------------------------------------------------------------------// + +/*! + * Windows x86 & x64 support both aligned and unaligned access + */ +#define SBG_CONFIG_UNALIGNED_ACCESS_AUTH (0) + +/*! + * Windows is using little endianess + */ +#define SBG_CONFIG_BIG_ENDIAN (0) + +//----------------------------------------------------------------------// +//- Logging configuration -// +//----------------------------------------------------------------------// + +/*! + * Enable all error logs + * Default: Enabled + */ +#define SBG_CONFIG_ENABLE_LOG_ERROR (1) +#define SBG_CONFIG_ENABLE_LOG_WARNING (1) +#define SBG_CONFIG_ENABLE_LOG_INFO (1) +#define SBG_CONFIG_ENABLE_LOG_DEBUG (1) + +#endif // SBG_CONFIG_H diff --git a/crates/sbg-rs/sbgECom/common/sbgDefines.h b/crates/sbg-rs/sbgECom/common/sbgDefines.h new file mode 100644 index 0000000..c019c8a --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/sbgDefines.h @@ -0,0 +1,524 @@ +/*! + * \file sbgDefines.h + * \ingroup common + * \author SBG Systems + * \date 17 March 2015 + * + * \brief Header file that contains all common definitions. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_DEFINES_H +#define SBG_DEFINES_H + +// Standard headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local headers +#include "sbgConfig.h" + +// +// XXX If NDEBUG is defined, most libraries define assert() as ((void)0), which may +// cause "defined but not used" warnings. Redefine assert() in a way that safely +// prevents this warning, i.e. without triggering the expression side effects. +// + +#undef assert +#define assert(expression) ((void)sizeof(expression)) + +/*! + * Macro used to handle export and import methods of the sbgCommon library + */ +#ifdef _MSC_VER + #ifdef SBG_COMMON_STATIC_USE + #define SBG_COMMON_LIB_API + #else + #ifdef SBG_COMMON_LIB_API_EXPORT + #define SBG_COMMON_LIB_API __declspec(dllexport) + #else + #define SBG_COMMON_LIB_API __declspec(dllimport) + #endif + #endif +#else + #define SBG_COMMON_LIB_API +#endif + +//----------------------------------------------------------------------// +//- Global definitions -// +//----------------------------------------------------------------------// +#ifndef SBG_DISABLE + #define SBG_DISABLE (0) +#endif + +#ifndef SBG_ENABLE + #define SBG_ENABLE (1) +#endif + +#ifndef FALSE + #define FALSE (0) +#endif + +#ifndef TRUE + #define TRUE (1) +#endif + +#ifndef NULL + #define NULL (0) +#endif + +#ifndef SBG_INVALID_HANDLE + #define SBG_INVALID_HANDLE (NULL) +#endif + +#ifndef SBG_ARRAY_SIZE + #define SBG_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#ifndef SBG_STRLEN + #define SBG_STRLEN(s) (sizeof(s) - 1) +#endif + +#ifndef SBG_QUOTE_NX + #define SBG_QUOTE_NX(x) #x +#endif + +#ifndef SBG_QUOTE + #define SBG_QUOTE(x) SBG_QUOTE_NX(x) +#endif + +#ifndef SBG_CONCAT_NX + #define SBG_CONCAT_NX(a, b) a ## b +#endif + +#ifndef SBG_CONCAT + #define SBG_CONCAT(a, b) SBG_CONCAT_NX(a, b) +#endif + +#ifndef SBG_UNPACK + #define SBG_UNPACK(...) __VA_ARGS__ +#endif + +#ifndef SBG_CONTAINER_OF + #define SBG_CONTAINER_OF(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member))) +#endif + +#ifndef SBG_LIKELY + #if defined(__GNUC__) || defined(__clang__) + #define SBG_LIKELY(expr) __builtin_expect((bool)(expr), true) + #else + #define SBG_LIKELY(expr) (expr) + #endif +#endif + +#ifndef SBG_UNLIKELY + #if defined(__GNUC__) || defined(__clang__) + #define SBG_UNLIKELY(expr) __builtin_expect((bool)(expr), false) + #else + #define SBG_UNLIKELY(expr) (expr) + #endif +#endif + +#ifndef SBG_CHECK_FORMAT + #if defined(__GNUC__) || defined(__clang__) + #define SBG_CHECK_FORMAT(style, format_index, va_args) __attribute__((format(style, format_index, va_args))) + #else + #define SBG_CHECK_FORMAT(style, format_index, va_args) + #endif +#endif + +/*! + * GCC typeof C extension + * + * XXX Visual C (not C++) doesn't provide anything to implement typeof(). + * As a result, this macro is private and shouldn't be relied on. + */ +#ifndef __SBG_TYPEOF + #ifdef __cplusplus + #define __SBG_TYPEOF(x) decltype(x) + #elif defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__) + #define __SBG_TYPEOF(x) typeof(x) + #endif +#endif + +#ifndef SBG_CONST_CAST_AA + #ifdef __SBG_TYPEOF + #define SBG_CONST_CAST_AA(x) ((const __SBG_TYPEOF((x)[0][0])(*)[SBG_ARRAY_SIZE((x)[0])])(x)) + #else + #define SBG_CONST_CAST_AA(x) x + #endif +#endif + +#ifndef SBG_CONST_CAST_PP + #ifdef __SBG_TYPEOF + #define SBG_CONST_CAST_PP(x) ((const __SBG_TYPEOF(**(x))**)(x)) + #else + #define SBG_CONST_CAST_PP(x) x + #endif +#endif + +/*! + * __BASE_FILE__ is gcc specific + */ +#if !defined(__GNUC__) && !defined(__clang__) +#ifndef __BASE_FILE__ + #define __BASE_FILE__ __FILE__ +#endif +#endif + +#ifdef __cplusplus + #define SBG_DELETE(p) if (p){delete (p); (p) = NULL;} + #define SBG_DELETE_ARRAY(p) if (p){delete[] (p); (p) = NULL;} + #define SBG_FREE(p) if (p){free(p); (p) = NULL;} + #define SBG_FREE_ARRAY(p) if (p){free(p); (p) = NULL;} +#else + #define SBG_DELETE if (p){free(p); (p) = NULL;} + #define SBG_DELETE_ARRAY if (p){free(p); (p) = NULL;} + #define SBG_FREE(p) if (p){free(p); (p) = NULL;} + #define SBG_FREE_ARRAY(p) if (p){free(p); (p) = NULL;} +#endif + +//----------------------------------------------------------------------// +//- Compiler definitions -// +//----------------------------------------------------------------------// + +/*! + * Macro used to abstract the compiler specific inline keyword. + */ +#ifndef SBG_INLINE + #if defined(_MSC_VER) + #define SBG_INLINE __inline + #else + #define SBG_INLINE static inline + #endif +#endif + +/*! + * Macro used to avoid compiler warning when a variable is not used. + */ +#ifndef SBG_UNUSED_PARAMETER + #define SBG_UNUSED_PARAMETER(x) (void)(x) +#endif + +/*! + * Compiler independent switch/case fallthrough attribute + * + * The fallthrough attribute is used to avoid compiler warning in swith case statements + * when an intentional break is missing + */ +#ifndef SBG_FALLTHROUGH + #if __cplusplus >= 201703L + #define SBG_FALLTHROUGH [[fallthrough]] /* introduced in C++ 17 */ + #elif defined(__GNUC__) || defined(__clang__) + #if (__GNUC__ >= 7) || defined(__clang__) + #define SBG_FALLTHROUGH __attribute__((fallthrough)) + #else + #define SBG_FALLTHROUGH ((void)0) + #endif + #else + #define SBG_FALLTHROUGH + #endif +#endif + +//----------------------------------------------------------------------// +//- Macro used to defined packed structures -// +//----------------------------------------------------------------------// + +/*! + * Compiler independent struct members packing attribute + * + * This macro is used to define a new section of packed structures. + * All structures defined after this macro will be packed. + */ +#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__) + #define SBG_BEGIN_PACKED() +#elif defined(_MSC_VER) + #define SBG_BEGIN_PACKED() __pragma(pack(push, 1)) +#else + #error you must byte-align these structures with the appropriate compiler directives +#endif + +/*! + * Compiler independent struct members packing attribute + * + * This macro is used to specify that a structure is packed. + */ +#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__) + #define SBG_PACKED __attribute__((packed)) +#elif defined(_MSC_VER) + #define SBG_PACKED +#else + #error you must byte-align these structures with the appropriate compiler directives +#endif + +/*! + * Compiler independent struct members packing attribute + * + * This macro is used to close the section of packed structures and return to the default packing. + */ +#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__) + #define SBG_END_PACKED() +#elif defined(_MSC_VER) + #define SBG_END_PACKED() __pragma(pack(pop)) +#else + #error you must byte-align these structures with the appropriate compiler directives +#endif + +//----------------------------------------------------------------------// +//- Deprecation definitions -// +//----------------------------------------------------------------------// + +/*! + * Macro used to indicate that a function is deprecated. + */ +#if defined(__GNUC__) || defined(__clang__) + #define SBG_DEPRECATED(func) __attribute__((deprecated)) func +#elif defined(__TI_COMPILER_VERSION__) + #define SBG_DEPRECATED(func) func __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define SBG_DEPRECATED(func) __declspec(deprecated) func +#else + #define SBG_DEPRECATED(func) func +#endif + +/*! + * Macro used to indicate that a macro is deprecated. + */ +#if defined(__GNUC__) || defined(__clang__) + #define SBG_DEPRECATED_MACRO(func) __pragma(deprecated(func)) +#elif defined(_MSC_VER) +#define SBG_DEPRECATED_MACRO(func) __pragma(deprecated(func)) +#else + #define SBG_DEPRECATED_MACRO(func) func +#endif + +/*! + * Set the default value of SBG_CONFIG_WARN_ABOUT_DEPRECATED_TYPES. + */ +#ifndef SBG_CONFIG_WARN_ABOUT_DEPRECATED_TYPES +#define SBG_CONFIG_WARN_ABOUT_DEPRECATED_TYPES (1) +#endif + +/*! + * Macro used to indicate that a type definition is deprecated. + * + * XXX In order to avoid excessive noise caused by deprecation warnings, the attribute + * may currently be disabled by defining SBG_CONFIG_WARN_ABOUT_DEPRECATED_TYPES to 0. + */ +#if SBG_CONFIG_WARN_ABOUT_DEPRECATED_TYPES != 0 + #if defined(__GNUC__) || defined(__clang__) + #define SBG_DEPRECATED_TYPEDEF(decl) decl __attribute__((deprecated)) + #elif defined(_MSC_VER) + #define SBG_DEPRECATED_TYPEDEF(decl) __declspec(deprecated) decl + #else + #define SBG_DEPRECATED_TYPEDEF(decl) decl + #endif +#else + #define SBG_DEPRECATED_TYPEDEF(decl) decl +#endif + +//----------------------------------------------------------------------// +//- Basic maths definitions -// +//----------------------------------------------------------------------// +#ifndef SBG_PI + #define SBG_PI 3.14159265358979323846 +#endif + +#ifndef SBG_PI_F + #define SBG_PI_F 3.14159265358979323846f +#endif + +/*! + * Returns the absolute value of x. + * + * \param[in] x Signed integer value. + * \return The absolute value of x. + */ +#ifndef sbgAbs + #define sbgAbs(x) (((x) < 0) ? -(x) : (x)) +#endif + +/*! + * Returns the maximum between a and b + * + * \param[in] a First operand. + * \param[in] b Second operand. + * \return The maximum between a and b. + */ +#ifndef sbgMax + #define sbgMax(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +/*! + * Returns the minimum between a and b + * + * \param[in] a First operand. + * \param[in] b Second operand. + * \return The minimum between a and b. + */ +#ifndef sbgMin + #define sbgMin(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +/*! + * Clamp a value between minValue and maxValue ie minValue <= value <= maxValue + * + * \param[in] value First operand. + * \param[in] minValue First operand. + * \param[in] maxValue Second operand. + * \return The clamped value. + */ +#ifndef sbgClamp + #define sbgClamp(value, minValue, maxValue) (((value) < (minValue))?(minValue): ((value) > (maxValue)?maxValue:value)) +#endif + +/*! + * Integer division with a result rounded up. + * + * \param[in] n Dividend. + * \param[in] d Divisor. + * \return Rounded division + */ +#ifndef sbgDivCeil + #define sbgDivCeil(n, d) (((n) + (d) - 1) / (d)) +#endif + +/*! + * Convert an angle from radians to degrees using double precision. + * + * \param[in] angle The angle to convert in radians. + * \return The converted angle in degrees. + */ +SBG_INLINE double sbgRadToDegd(double angle) +{ + return angle * 180.0 / SBG_PI; +} + +/*! + * Convert an angle from degrees to radians using double precision. + * + * \param[in] angle The angle to convert in degrees. + * \return The converted angle in radians. + */ +SBG_INLINE double sbgDegToRadd(double angle) +{ + return angle * SBG_PI / 180.0; +} + +/*! + * Convert an angle from radians to degrees using single (float) precision. + * + * \param[in] angle The angle to convert in radians. + * \return The converted angle in degrees. + */ +SBG_INLINE float sbgRadToDegf(float angle) +{ + return angle * 180.0f / SBG_PI_F; +} + +/*! + * Convert an angle from degrees to radians using single (float) precision. + * + * \param[in] angle The angle to convert in degrees. + * \return The converted angle in radians. + */ +SBG_INLINE float sbgDegToRadf(float angle) +{ + return angle * SBG_PI_F / 180.0f; +} + +/*! + * Test if two floating single-point numbers are equals or not. + * + * \param[in] leftValue The first operand to test for equality. + * \param[in] rightValue The second operand to test for equality. + * \return true if both left and right operands are almost equal. + */ +SBG_INLINE bool sbgAlmostEqualsFloat(float leftValue, float rightValue) +{ + // + // The IEEE standard says that any comparison operation involving a NAN must return false. + // + if (isnan(leftValue) || isnan(rightValue)) + { + return false; + } + + // + // This method is not good enough and should be updated using DistanceBetweenSignAndMagnitudeNumbers methods + // + if (fabsf(leftValue - rightValue) < FLT_EPSILON) + { + return true; + } + else + { + return false; + } +} + +/*! + * Test if two floating double-point numbers are equals or not using the epsilon technique + * + * \param[in] leftValue The first operand to test for equality. + * \param[in] rightValue The second operand to test for equality. + * \return true if both left and right operands are almost equal. + */ +SBG_INLINE bool sbgAlmostEqualsDouble(double leftValue, double rightValue) +{ + // + // The IEEE standard says that any comparison operation involving a NAN must return false. + // + if (isnan(leftValue) || isnan(rightValue)) + { + return false; + } + + // + // This method is not good enough and should be updated using DistanceBetweenSignAndMagnitudeNumbers methods + // + if (fabs(leftValue - rightValue) < DBL_EPSILON) + { + return true; + } + else + { + return false; + } +} + +#endif // SBG_DEFINES_H diff --git a/crates/sbg-rs/sbgECom/common/sbgErrorCodes.h b/crates/sbg-rs/sbgECom/common/sbgErrorCodes.h new file mode 100644 index 0000000..b31d7c9 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/sbgErrorCodes.h @@ -0,0 +1,119 @@ +/*! + * \file sbgErrorCodes.h + * \ingroup common + * \author SBG Systems + * \date 17 March 2015 + * + * \brief Header file that defines all error codes for SBG Systems libraries. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ERROR_CODES_H +#define SBG_ERROR_CODES_H + +// Local headers +#include "sbgDefines.h" + +//----------------------------------------------------------------------// +//- Errors code definitions -// +//----------------------------------------------------------------------// + +/*! + * Generic errors definitions for SBG Systems projects. + */ +typedef enum _SbgErrorCode +{ + SBG_NO_ERROR = 0, /*!< The operation was successfully executed. */ + SBG_ERROR, /*!< We have a generic error. */ + SBG_NULL_POINTER, /*!< A pointer is null. */ + SBG_INVALID_CRC, /*!< The received frame has an invalid CRC. */ + SBG_INVALID_FRAME, /*!< The received frame is invalid
*/ + /*!< We have received an unexpected frame (not the cmd we are waiting for or with an invalid data size.
*/ + /*!< This could be caused by a desync between questions and answers.
*/ + /*!< You should flush the serial port to fix this. */ + SBG_TIME_OUT, /*!< We have started to receive a frame but not the end. */ + SBG_WRITE_ERROR, /*!< All bytes hasn't been written. */ + SBG_READ_ERROR, /*!< All bytes hasn't been read. */ + SBG_BUFFER_OVERFLOW, /*!< A buffer is too small to contain so much data. */ + SBG_INVALID_PARAMETER, /*!< An invalid parameter has been found. */ + SBG_NOT_READY, /*!< A device isn't ready (Rx isn't ready for example). */ + SBG_MALLOC_FAILED, /*!< Failed to allocate a buffer. */ + SGB_CALIB_MAG_NOT_ENOUGH_POINTS, /*!< Not enough points were available to perform magnetometers calibration. */ + SBG_CALIB_MAG_INVALID_TAKE, /*!< The calibration procedure could not be properly executed due to insufficient precision. */ + SBG_CALIB_MAG_SATURATION, /*!< Saturation were detected when attempt to calibrate magnetos. */ + SBG_CALIB_MAG_POINTS_NOT_IN_A_PLANE, /*!< 2D calibration procedure could not be performed. */ + + SBG_DEVICE_NOT_FOUND, /*!< A device couldn't be founded or opened PC only error code */ + SBG_OPERATION_CANCELLED, /*!< An operation was canceled. PC only error code*/ + SBG_NOT_CONTINUOUS_FRAME, /*!< We have received a frame that isn't a continuous one. PC only error code*/ + + SBG_INCOMPATIBLE_HARDWARE, /*!< Hence valid; the command cannot be executed because of hardware incompatibility */ + SBG_INVALID_VERSION /*!< Incompatible version */ +} SbgErrorCode; + +//----------------------------------------------------------------------// +//- Error codes to string litteral conversion -// +//----------------------------------------------------------------------// + +/*! + * According to an error code, returns a human readable string. + * \param[in] errorCode The errorCode to convert to a string. + * \return Read only corresponding string. + */ +static inline const char *sbgErrorCodeToString(SbgErrorCode errorCode) +{ + /*! + * Array of string litterals that should be exactly ordered as the SbgErrorCode enum. + */ + static const char *sbgErrorCodeString[] = + { + "SBG_NO_ERROR", + "SBG_ERROR", + "SBG_NULL_POINTER", + "SBG_INVALID_CRC", + "SBG_INVALID_FRAME", + "SBG_TIME_OUT", + "SBG_WRITE_ERROR", + "SBG_READ_ERROR", + "SBG_BUFFER_OVERFLOW", + "SBG_INVALID_PARAMETER", + "SBG_NOT_READY", + "SBG_MALLOC_FAILED", + "SGB_CALIB_MAG_NOT_ENOUGH_POINTS", + "SBG_CALIB_MAG_INVALID_TAKE", + "SBG_CALIB_MAG_SATURATION", + "SBG_CALIB_MAG_POINTS_NOT_IN_A_PLANE", + "SBG_DEVICE_NOT_FOUND", + "SBG_OPERATION_CANCELLED", + "SBG_NOT_CONTINUOUS_FRAME", + "SBG_INCOMPATIBLE_HARDWARE", + "SBG_INVALID_VERSION" + }; + + assert(errorCode < SBG_ARRAY_SIZE(sbgErrorCodeString)); + return sbgErrorCodeString[errorCode]; +} + +#endif /* SBG_ERROR_CODES_H */ diff --git a/crates/sbg-rs/sbgECom/common/sbgTypes.h b/crates/sbg-rs/sbgECom/common/sbgTypes.h new file mode 100644 index 0000000..ca068ca --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/sbgTypes.h @@ -0,0 +1,194 @@ +/*! + * \file sbgTypes.h + * \ingroup common + * \author SBG Systems + * \date 17 March 2015 + * + * \brief Header file that defines all scalar types. + * + * The platform endianness should be defined here. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_TYPES_H +#define SBG_TYPES_H + +// Standard headers +#include + +// Local headers +#include "sbgDefines.h" + +//----------------------------------------------------------------------// +//- Limits definitions -// +//----------------------------------------------------------------------// +#define SBG_MIN_INT_24 (-8388608l) +#define SBG_MAX_INT_24 (8388607l) +#define SBG_MAX_UINT_24 (16777215ul) + +#define SBG_MIN_INT_40 (-549755813887ll - 1) +#define SBG_MAX_INT_40 (549755813887ll) +#define SBG_MAX_UINT_40 (1099511627775ull) + +#define SBG_MIN_INT_48 (-140737488355327ll - 1) +#define SBG_MAX_INT_48 (140737488355327ll) +#define SBG_MAX_UINT_48 (281474976710655ull) + +#define SBG_MIN_INT_56 (-36028797018963967ll - 1) +#define SBG_MAX_INT_56 (36028797018963967ll) +#define SBG_MAX_UINT_56 (72057594037927935ull) + +//----------------------------------------------------------------------// +//- DEPRECATED: Scalar types definitions -// +//----------------------------------------------------------------------// +SBG_DEPRECATED_TYPEDEF(typedef unsigned char uint8); // 8 bits +SBG_DEPRECATED_TYPEDEF(typedef unsigned short uint16); // 16 bits +SBG_DEPRECATED_TYPEDEF(typedef unsigned int uint32); // 32 bits +SBG_DEPRECATED_TYPEDEF(typedef unsigned long long int uint64); // 64 bits + +SBG_DEPRECATED_TYPEDEF(typedef signed char int8); // 8 bits +SBG_DEPRECATED_TYPEDEF(typedef signed short int16); // 16 bits +SBG_DEPRECATED_TYPEDEF(typedef signed int int32); // 32 bits +SBG_DEPRECATED_TYPEDEF(typedef signed long long int int64); // 64 bits + + +//----------------------------------------------------------------------// +//- Misc types definitions -// +//----------------------------------------------------------------------// +typedef uint32_t sbgIpAddress; /*!< Define an IP v4 address stored in 4 bytes. The format is A.B.C.D, each component is 8 bits and stored in Big Endian. */ + +//------------------------------------------------------------------// +//- Type punning safe conversion unions -// +//------------------------------------------------------------------// + +/*! + * Used to get a uint32_t from a uint8_t array. + */ +typedef union _Uint8PtrToUint32Ptr +{ + uint8_t *m_pointerUint8; /*!< Set the address used to access the uint32_t. */ + uint32_t *m_pointerUint32; /*!< Store the unint32 value. */ +} Uint8PtrToUint32Ptr; + +/*! + * Union used to convert a buffer or 2 unit8 two's complement values to a int16_t + */ +typedef union _Uint8ToInt16 +{ + int16_t value; + uint8_t buffer[2]; +} Uint8ToInt16; + +/*! + * Union used to convert a buffer or 2 unit8 values to a uint16_t + */ +typedef union _Uint8ToUint16 +{ + uint16_t value; + uint8_t buffer[2]; +} Uint8ToUint16; + +/*! + * Union used to convert a buffer or 4 unit8 two's complement values to a int32_t + */ +typedef union _Uint8ToInt32 +{ + int32_t value; + uint8_t buffer[4]; +} Uint8ToInt32; + +/*! + * Union used to convert a buffer or 4 unit8 values to a uint32_t + */ +typedef union _Uint8ToUint32 +{ + uint32_t value; + uint8_t buffer[4]; +} Uint8ToUint32; + +/*! + * Union used to convert a buffer or 8 unit8 two's complement values to a int64_t + */ +typedef union _Uint8ToInt64 +{ + int64_t value; + uint8_t buffer[8]; +} Uint8ToInt64; + +/*! + * Union used to convert a buffer or 8 unit8 values to a uint64_t + */ +typedef union _Uint8ToUint64 +{ + uint64_t value; + uint8_t buffer[8]; +} Uint8ToUint64; + +/*! + * Union that allows type punning (access to a floating point number bits) + */ +typedef union _FloatNint +{ + float valF; + int32_t valI; + uint32_t valU; +} FloatNint; + +/*! + * Union that allows type punning (access to a double number bits) + */ +typedef union _DoubleNint +{ + double valF; + uint64_t valU; + int64_t valI; +} DoubleNint; + +/*! + * Structure that splits a 64bits + */ +typedef struct _Split64 +{ + uint32_t high; + uint32_t low; +} Split64; + +/*! + * Set of 3 int32_t + */ + typedef struct _SbgVector3i + { + int32_t v[3]; + } SbgVector3i; + + /*! + * Set of 3 int64_t + */ + typedef struct _SbgVector3ll + { + int64_t v[3]; + } SbgVector3ll; + +#endif /* SBG_TYPES_H */ diff --git a/crates/sbg-rs/sbgECom/common/splitBuffer/sbgSplitBuffer.c b/crates/sbg-rs/sbgECom/common/splitBuffer/sbgSplitBuffer.c new file mode 100644 index 0000000..e43ad8d --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/splitBuffer/sbgSplitBuffer.c @@ -0,0 +1 @@ +#include "sbgSplitBuffer.h" diff --git a/crates/sbg-rs/sbgECom/common/splitBuffer/sbgSplitBuffer.h b/crates/sbg-rs/sbgECom/common/splitBuffer/sbgSplitBuffer.h new file mode 100644 index 0000000..fb32425 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/splitBuffer/sbgSplitBuffer.h @@ -0,0 +1,252 @@ +/*! + * \file sbgSplitBuffer.h + * \ingroup common + * \author SBG Systems + * \date 19 November 2013 + * + * \brief Helper methods used to handle a splittable buffer. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_SPLIT_BUFFER_H +#define SBG_SPLIT_BUFFER_H + +#include + +//----------------------------------------------------------------------// +//- Header (open extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Structs definitions -// +//----------------------------------------------------------------------// + +/*! + * Defines the ECom transfer states + */ +typedef struct _SbgSplitBuffer +{ + uint8_t *pLinkedBuffer; /*!< Pointer on the buffer that needs to be split */ + size_t linkedBufferSize; /*!< Size of the original buffer */ + size_t subBufferSize; /*!< The size of the sub buffers */ + size_t subBufferNbr; /*!< The number of sub buffers in this split buffer */ +} SbgSplitBuffer; + +//----------------------------------------------------------------------// +//- Public methods definitions -// +//----------------------------------------------------------------------// + +/*! + * Initialize a split buffer for read operations. + * \param[in] pSplitBuffer Pointer to an allocated split buffer instance. + * \param[in] pBuffer The buffer that needs to be split (doesn't take the ownership). + * \param[in] bufferSize The total size of the buffer in bytes. + * \param[in] subBufferSize The size of each sub buffer in bytes. + */ +SBG_INLINE void sbgSplitBufferInitForRead(SbgSplitBuffer *pSplitBuffer, const void *pBuffer, size_t bufferSize, size_t subBufferSize) +{ + // + // Test input arguments + // + assert(pSplitBuffer); + + // + // Initialize split buffer parameters + // + pSplitBuffer->pLinkedBuffer = (uint8_t*)pBuffer; + pSplitBuffer->linkedBufferSize = bufferSize; + pSplitBuffer->subBufferSize = subBufferSize; + + // + // Compute sub buffer number + // + pSplitBuffer->subBufferNbr = (bufferSize + (subBufferSize - 1)) / subBufferSize; +} + +/*! + * Initialize a split buffer for write operations. + * \param[in] pSplitBuffer Pointer to an allocated split buffer instance. + * \param[in] pBuffer The buffer that needs to be split (doesn't take the ownership). + * \param[in] bufferSize The total size of the buffer in bytes. + * \param[in] subBufferSize The size of each sub buffer in bytes. + */ +SBG_INLINE void sbgSplitBufferInitForWrite(SbgSplitBuffer *pSplitBuffer, void *pBuffer, size_t bufferSize, size_t subBufferSize) +{ + // + // Test input arguments + // + assert(pSplitBuffer); + + // + // Initialize split buffer parameters + // + pSplitBuffer->pLinkedBuffer = (uint8_t*)pBuffer; + pSplitBuffer->linkedBufferSize = bufferSize; + pSplitBuffer->subBufferSize = subBufferSize; + + // + // Compute sub buffer number + // + pSplitBuffer->subBufferNbr = (bufferSize + (subBufferSize - 1)) / subBufferSize; +} + +/*! + * Returns the number of sub buffers that compose the whole buffer. + * \param[in] pSplitBuffer Valid pointer to a Split Buffer instance. + * \return The number of sub buffer the buffer has or 0 if there is an error. + */ +SBG_INLINE size_t sbgSplitBufferGetSubBufferNbr(const SbgSplitBuffer *pSplitBuffer) +{ + // + // Test input arguments + // + assert(pSplitBuffer); + + // + // Return subBufferNbr parameter + // + return pSplitBuffer->subBufferNbr; +} + +/*! + * Get one sub buffer given its index. + * \param[in] pSplitBuffer Valid pointer to a Split Buffer instance. + * \param[in] subBufferIdx Index of the sub buffer required. + * \return Pointer to the sub buffer or NULL if the subBuffer index is invalid. + */ +SBG_INLINE void *sbgSplitBufferGetSubBuffer(const SbgSplitBuffer *pSplitBuffer, size_t subBufferIdx) +{ + // + // Test input arguments + // + assert(pSplitBuffer); + + // + // Test input parameters + // + if (subBufferIdx < pSplitBuffer->subBufferNbr) + { + // + // Return pointer to buffer + // + return ((uint8_t*)pSplitBuffer->pLinkedBuffer + pSplitBuffer->subBufferSize*subBufferIdx); + } + else + { + // + // Invalid index + // + return NULL; + } +} + +/*! + * Return the offset in bytes of a sub buffer from the start of the buffer. + * \param[in] pSplitBuffer Valid pointer to a Split Buffer instance. + * \param[in] subBufferIdx Index of the sub buffer required. + * \return Offset to the sub buffer or 0 if the subBuffer index is invalid. + */ +SBG_INLINE size_t sbgSplitBufferGetSubBufferOffset(const SbgSplitBuffer *pSplitBuffer, size_t subBufferIdx) +{ + // + // Test input arguments + // + assert(pSplitBuffer); + + // + // Test input parameters + // + if (subBufferIdx < pSplitBuffer->subBufferNbr) + { + // + // Return pointer to buffer + // + return (pSplitBuffer->subBufferSize * subBufferIdx); + } + else + { + // + // Invalid index + // + return 0; + } +} + +/*! + * Get the size of a sub buffer given its index. + * \param[in] pSplitBuffer Valid pointer to a Split Buffer instance. + * \param[in] subBufferIdx Index of the sub buffer required. + * \return The size of the sub buffer of index subBufferIdx, or 0 if the subBuffer index is invalid. + */ +SBG_INLINE size_t sbgSplitBufferGetSubBufferSize(const SbgSplitBuffer *pSplitBuffer, size_t subBufferIdx) +{ + size_t subBufferSize = 0; + + // + // Test input arguments + // + assert(pSplitBuffer); + + // + // Test input parameters + // + if (pSplitBuffer->subBufferNbr > 0) + { + // + // Test that the sub buffer index is not the last one + // + if (subBufferIdx < (pSplitBuffer->subBufferNbr-1)) + { + // + // We can just return the sub buffer size because it's not the last sub buffer + // + subBufferSize = pSplitBuffer->subBufferSize; + } + else if (subBufferIdx == (pSplitBuffer->subBufferNbr-1) ) + { + // + // It's the last sub buffer so return the remaining size + // + subBufferSize = pSplitBuffer->linkedBufferSize - (subBufferIdx * pSplitBuffer->subBufferSize); + } + } + + // + // Return computed size + // + return subBufferSize; +} + +//----------------------------------------------------------------------// +//- Footer (close extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +} +#endif + +#endif /* SBG_SPLIT_BUFFER_H */ diff --git a/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBuffer.c b/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBuffer.c new file mode 100644 index 0000000..9f4955a --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBuffer.c @@ -0,0 +1 @@ +#include "sbgStreamBuffer.h" diff --git a/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBuffer.h b/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBuffer.h new file mode 100644 index 0000000..cebc45f --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBuffer.h @@ -0,0 +1,53 @@ +/*! + * \file sbgStreamBuffer.h + * \ingroup common + * \author SBG Systems + * \date 02 January 2013 + * + * \brief Used to read/write data from/to a memory buffer stream. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_STREAM_BUFFER_H +#define SBG_STREAM_BUFFER_H + +//----------------------------------------------------------------------// +//- Header (open extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +extern "C" { +#endif + +#include "sbgStreamBufferLE.h" +#include "sbgStreamBufferBE.h" + +//----------------------------------------------------------------------// +//- Footer (close extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +} +#endif + +#endif /* SBG_STREAM_BUFFER_H */ diff --git a/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBufferBE.h b/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBufferBE.h new file mode 100644 index 0000000..c14d89c --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBufferBE.h @@ -0,0 +1,1924 @@ +/*! + * \file sbgStreamBufferBE.h + * \ingroup common + * \author SBG Systems + * \date 17 February 2015 + * + * \brief Specific method of stream buffer for little endian readings/writings. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_STREAM_BUFFER_BE_H +#define SBG_STREAM_BUFFER_BE_H + +#include "sbgStreamBufferCommon.h" + +//----------------------------------------------------------------------// +//- Read operations methods -// +//----------------------------------------------------------------------// + +/*! + * Read an int16_t from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int16_t sbgStreamBufferReadInt16BE(SbgStreamBuffer *pHandle) +{ + int16_t bytesValues[2]; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int16_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the current value + // + bytesValues[0] = *((int16_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int16_t); + + return bytesValues[0]; + #else + // + // Read the each bytes + // + bytesValues[1] = *(pHandle->pCurrentPtr++); + bytesValues[0] = *(pHandle->pCurrentPtr++); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return bytesValues[1] | (bytesValues[0] << 8); + #else + return bytesValues[0] | (bytesValues[1] << 8); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint16_t from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint16_t sbgStreamBufferReadUint16BE(SbgStreamBuffer *pHandle) +{ + uint16_t bytesValues[2]; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint16_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the current value + // + bytesValues[0] = *((uint16_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint16_t); + + return bytesValues[0]; + #else + // + // Read the each bytes + // + bytesValues[1] = *(pHandle->pCurrentPtr++); + bytesValues[0] = *(pHandle->pCurrentPtr++); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return bytesValues[1] | (bytesValues[0] << 8); + #else + return bytesValues[0] | (bytesValues[1] << 8); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int24 from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int32_t sbgStreamBufferReadInt24BE(SbgStreamBuffer *pHandle) +{ + Uint8ToInt32 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 3*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); // LSB + #else + // + // Read the each bytes + // + value.buffer[3] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[1] = *(pHandle->pCurrentPtr++); // LSB + #endif + + // + // Shift the value to handle the sign correctly for a 24 bits + // + return value.value >> (32-24); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint24 from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint32_t sbgStreamBufferReadUint24BE(SbgStreamBuffer *pHandle) +{ + Uint8ToUint32 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 3*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); // LSB + #else + // + // Read the each bytes + // + value.buffer[3] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[1] = *(pHandle->pCurrentPtr++); // LSB + #endif + + // + // Shift the value to handle the sign correctly for a 24 bits + // + return value.value >> (32-24); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int32_t from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int32_t sbgStreamBufferReadInt32BE(SbgStreamBuffer *pHandle) +{ + int32_t bytesValues[4]; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int32_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the current value + // + bytesValues[0] = *((int32_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int32_t); + + return bytesValues[0]; + #else + // + // Read the each bytes + // + bytesValues[3] = *(pHandle->pCurrentPtr++); + bytesValues[2] = *(pHandle->pCurrentPtr++); + bytesValues[1] = *(pHandle->pCurrentPtr++); + bytesValues[0] = *(pHandle->pCurrentPtr++); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return bytesValues[3] | (bytesValues[2] << 8) | (bytesValues[1] << 16) | (bytesValues[0] << 24); + #else + return bytesValues[0] | (bytesValues[1] << 8) | (bytesValues[2] << 16) | (bytesValues[3] << 24); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint32_t from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint32_t sbgStreamBufferReadUint32BE(SbgStreamBuffer *pHandle) +{ + uint32_t bytesValues[4]; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint32_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the current value + // + bytesValues[0] = *((uint32_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint32_t); + + return bytesValues[0]; + #else + // + // Read the each bytes + // + bytesValues[3] = *(pHandle->pCurrentPtr++); + bytesValues[2] = *(pHandle->pCurrentPtr++); + bytesValues[1] = *(pHandle->pCurrentPtr++); + bytesValues[0] = *(pHandle->pCurrentPtr++); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return bytesValues[3] | (bytesValues[2] << 8) | (bytesValues[1] << 16) | (bytesValues[0] << 24); + #else + return bytesValues[0] | (bytesValues[1] << 8) | (bytesValues[2] << 16) | (bytesValues[3] << 24); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int40 from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int64_t sbgStreamBufferReadInt40BE(SbgStreamBuffer *pHandle) +{ + Uint8ToInt64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 5*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); // LSB + #else + // + // Read the each bytes + // + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); // LSB + #endif + + // + // Shift the value to handle the sign correctly for a 40 bits + // + return value.value >> (64-40); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint40 from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint64_t sbgStreamBufferReadUint40BE(SbgStreamBuffer *pHandle) +{ + Uint8ToUint64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 5*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); // LSB + #else + // + // Read the each bytes + // + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); // LSB + #endif + + // + // Shift the value to handle the sign correctly for a 40 bits + // + return value.value >> (64-40); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int48 from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int64_t sbgStreamBufferReadInt48BE(SbgStreamBuffer *pHandle) +{ + Uint8ToInt64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 6*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); // LSB + #else + // + // Read the each bytes + // + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); // LSB + #endif + + // + // Shift the value to handle the sign correctly for a 48 bits + // + return value.value >> (64-48); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint48 from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint64_t sbgStreamBufferReadUint48BE(SbgStreamBuffer *pHandle) +{ + Uint8ToUint64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 6*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); // LSB + #else + // + // Read the each bytes + // + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); // LSB + #endif + + // + // Shift the value to handle the sign correctly for a 48 bits + // + return value.value >> (64-48); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int56 from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int64_t sbgStreamBufferReadInt56BE(SbgStreamBuffer *pHandle) +{ + Uint8ToInt64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 7*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[6] = *(pHandle->pCurrentPtr++); // LSB + #else + // + // Read the each bytes + // + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[1] = *(pHandle->pCurrentPtr++); // LSB + #endif + + // + // Shift the value to handle the sign correctly for a 56 bits + // + return value.value >> (64-56); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint56 from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int64_t sbgStreamBufferReadUint56BE(SbgStreamBuffer *pHandle) +{ + Uint8ToUint64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 7*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[6] = *(pHandle->pCurrentPtr++); // LSB + #else + // + // Read the each bytes + // + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[1] = *(pHandle->pCurrentPtr++); // LSB + #endif + + // + // Shift the value to handle the sign correctly for a 56 bits + // + return value.value >> (64-56); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int64_t from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int64_t sbgStreamBufferReadInt64BE(SbgStreamBuffer *pHandle) +{ + int64_t lowPart; + int64_t highPart; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int64_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the current value + // + lowPart = *((int64_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int64_t); + + return lowPart; + #else + // + // Read 64 bit value using two 32 bits read to avoid too much 64 bits operations + // + highPart = sbgStreamBufferReadUint32BE(pHandle); + lowPart = sbgStreamBufferReadUint32BE(pHandle); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return (lowPart << 32) | highPart; + #else + return lowPart | (highPart << 32); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0ll; +} + +/*! + * Read an uint64_t from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint64_t sbgStreamBufferReadUint64BE(SbgStreamBuffer *pHandle) +{ + uint64_t lowPart; + uint64_t highPart; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint64_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the current value + // + lowPart = *((uint64_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint64_t); + + return lowPart; + #else + // + // Read 64 bit value using two 32 bits read to avoid too much 64 bits operations + // + highPart = sbgStreamBufferReadUint32BE(pHandle); + lowPart = sbgStreamBufferReadUint32BE(pHandle); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return (lowPart << 32) | highPart; + #else + return lowPart | (highPart << 32); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0ll; +} + +/*! + * Read a size_t from a stream buffer that has been stored in a uint32_t (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE size_t sbgStreamBufferReadSizeT32BE(SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + // + // Just call the read method for uint32_t + // We assume that a size_t is at least 32 bits on all platforms + // + return (size_t)sbgStreamBufferReadUint32BE(pHandle); +} + +/*! + * Read a size_t from a stream buffer that has been stored in a uint64_t (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE size_t sbgStreamBufferReadSizeT64BE(SbgStreamBuffer *pHandle) +{ + uint64_t size; + + assert(pHandle); + + // + // Just call the read method for uint64_t + // + size = sbgStreamBufferReadUint64BE(pHandle); + + // + // Make sure the read size can fit in the size_t in size_t is 32 bits + // + assert((sizeof(size_t) == 8) || ((sizeof(size_t) == 4) && (size <= UINT32_MAX))); + + // + // Return the read value + // + return (size_t)size; +} + +/*! + * Read an float from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE float sbgStreamBufferReadFloatBE(SbgStreamBuffer *pHandle) +{ + FloatNint floatInt; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(float)) + { + // + // Read the float as an uint32_t + // + floatInt.valU = sbgStreamBufferReadUint32BE(pHandle); + + // + // Return the float using an union to avoid compiller cast + // + return floatInt.valF; + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0.0f; +} + +/*! + * Read an double from a stream buffer (Big endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE double sbgStreamBufferReadDoubleBE(SbgStreamBuffer *pHandle) +{ + DoubleNint doubleInt; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(double)) + { + // + // Read the float as an uint64_t + // + doubleInt.valU = sbgStreamBufferReadUint64BE(pHandle); + + // + // Return the double using an union to avoid compiller cast + // + return doubleInt.valF; + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0.0; +} + +//----------------------------------------------------------------------// +//- Write operations methods -// +//----------------------------------------------------------------------// + +/*! + * Write an int16_t into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteInt16BE(SbgStreamBuffer *pHandle, int16_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int16_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Write the value + // + *((int16_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int16_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint16_t into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint16BE(SbgStreamBuffer *pHandle, uint16_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint16_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Write the value + // + *((uint16_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint16_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an int24 into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteInt24BE(SbgStreamBuffer *pHandle, int32_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Make sure that the value is within 24 bit bonds + // + if ( (value >= SBG_MIN_INT_24) && (value <= SBG_MAX_INT_24) ) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 3*sizeof(int8_t)) + { + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + else + { + // + // The input value is not within a 24 bit integer bounds + // + pHandle->errorCode = SBG_INVALID_PARAMETER; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint24 into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint24BE(SbgStreamBuffer *pHandle, uint32_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Make sure that the value is within 24 bit bonds + // + if (value <= SBG_MAX_UINT_24) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 3*sizeof(uint8_t)) + { + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + else + { + // + // The input value is not within a 24 bit integer bounds + // + pHandle->errorCode = SBG_INVALID_PARAMETER; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an int32_t into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteInt32BE(SbgStreamBuffer *pHandle, int32_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int32_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Write the value + // + *((int32_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int32_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint32_t into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint32BE(SbgStreamBuffer *pHandle, uint32_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint32_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Write the value + // + *((uint32_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint32_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint48 into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint48BE(SbgStreamBuffer *pHandle, uint64_t value) +{ + assert(pHandle); + assert(value < ((uint64_t)1 << 48)); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 6 * sizeof(uint8_t)) + { + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an int64_t into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteInt64BE(SbgStreamBuffer *pHandle, int64_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int64_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Write the value + // + *((int64_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int64_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 48); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 56); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 56); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 48); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint64_t into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint64BE(SbgStreamBuffer *pHandle, uint64_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint64_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Write the value + // + *((uint64_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint64_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 48); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 56); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 56); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 48); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an size_t into a stream buffer as a uint32_t (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteSizeT32BE(SbgStreamBuffer *pHandle, size_t value) +{ + assert(pHandle); + + // + // Make sure the provided size_t value doesn't exceed a uint32_t storage + // + assert(value <= UINT32_MAX); + + // + // Call the write method to store a uint32_t + // + return sbgStreamBufferWriteUint32BE(pHandle, (uint32_t)value); +} + +/*! + * Write an size_t into a stream buffer as a uint64_t (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteSizeT64BE(SbgStreamBuffer *pHandle, size_t value) +{ + // + // Check input parameters + // + assert(pHandle); + + // + // Call the write method to store a uint64_t + // + return sbgStreamBufferWriteUint64BE(pHandle, (uint64_t)value); +} + +/*! + * Write an float into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteFloatBE(SbgStreamBuffer *pHandle, float value) +{ + FloatNint floatInt; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // We use an union to avoid compiler cast + // + floatInt.valF = value; + + // + // Write this float as an uint32_t + // + return sbgStreamBufferWriteUint32BE(pHandle, floatInt.valU); + } + + return pHandle->errorCode; +} + +/*! + * Write an double into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteDoubleBE(SbgStreamBuffer *pHandle, double value) +{ + DoubleNint doubleInt; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // We use an union to avoid compiler cast + // + doubleInt.valF = value; + + // + // Write this float as an uint64_t + // + return sbgStreamBufferWriteUint64BE(pHandle, doubleInt.valU); + } + + return pHandle->errorCode; +} + +/*! + * Read a C String from a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \param[out] pString Buffer that can hold the read NULL terminated C string. + * \param[in] maxSize Maximum number of bytes that can be stored in pString (including the NULL char). + * \return SBG_NO_ERROR if the string has been read successfully from the stream buffer. + * SBG_BUFFER_OVERFLOW if the provided string isn't big enough to hold the read string + */ +SBG_INLINE SbgErrorCode sbgStreamBufferReadStringBE(SbgStreamBuffer *pHandle, char *pString, size_t maxSize) +{ + size_t stringLength; + + assert(pHandle); + assert(pString); + assert(maxSize > 0); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // The C string are stored in a stream buffer with a 32 bit size length and then the buffer itself + // + stringLength = sbgStreamBufferReadSizeT32BE(pHandle); + + if (stringLength <= maxSize) + { + // + // Read the string buffer itself + // + sbgStreamBufferReadBuffer(pHandle, pString, stringLength); + } + else + { + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + SBG_LOG_ERROR(pHandle->errorCode, "Trying to store a string of %zu bytes into a buffer of %zu bytes.", stringLength, maxSize); + } + } + + return pHandle->errorCode; +} + +/*! + * Write a NULL terminated C String into a stream buffer (Big Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] pString NULL terminated C String to write to the stream buffer. + * \return SBG_NO_ERROR if the string has been written successfully to the stream buffer. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteStringBE(SbgStreamBuffer *pHandle, const char *pString) +{ + size_t stringLength; + + assert(pHandle); + assert(pString); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // We write C string using a 32 bit size_t as the string length including the NULL char + // We should thus make sure the provided string isn't too big to fit in a 32 bits size_t + // + stringLength = strlen(pString)+1; + + if (stringLength <= UINT32_MAX) + { + // + // Write the string length + // + if (sbgStreamBufferWriteSizeT32BE(pHandle, stringLength) == SBG_NO_ERROR) + { + // + // Write the string buffer itself + // + sbgStreamBufferWriteBuffer(pHandle, pString, stringLength); + } + } + else + { + pHandle->errorCode = SBG_INVALID_PARAMETER; + SBG_LOG_ERROR(pHandle->errorCode, "The provided string is too big to fit in a 32 bit size_t"); + } + } + + return pHandle->errorCode; +} + +#endif /* SBG_STREAM_BUFFER_BE_H */ diff --git a/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBufferCommon.h b/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBufferCommon.h new file mode 100644 index 0000000..e6c8af4 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBufferCommon.h @@ -0,0 +1,831 @@ +/*! + * \file sbgStreamBufferCommon.h + * \ingroup common + * \author SBG Systems + * \date 02 January 2013 + * + * \brief Used to read/write data from/to a memory buffer stream. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_STREAM_BUFFER_COMMON_H +#define SBG_STREAM_BUFFER_COMMON_H + +#include + +//----------------------------------------------------------------------// +//- General definitions -// +//----------------------------------------------------------------------// + +/*! + * The default method should read and write using the platform endianness + */ +#if SBG_CONFIG_BIG_ENDIAN == 1 + /*! + * The platform is a big endian one so default methods should use big endian byte order. + */ + #define sbgStreamBufferReadUint16 sbgStreamBufferReadUint16BE + #define sbgStreamBufferReadInt16 sbgStreamBufferReadInt16BE + + #define sbgStreamBufferReadUint24 sbgStreamBufferReadUint24BE + #define sbgStreamBufferReadInt24 sbgStreamBufferReadInt24BE + + #define sbgStreamBufferReadUint32 sbgStreamBufferReadUint32BE + #define sbgStreamBufferReadInt32 sbgStreamBufferReadInt32BE + + #define sbgStreamBufferReadUint40 sbgStreamBufferReadUint40BE + #define sbgStreamBufferReadInt40 sbgStreamBufferReadInt40BE + + #define sbgStreamBufferReadUint48 sbgStreamBufferReadUint48BE + #define sbgStreamBufferReadInt48 sbgStreamBufferReadInt48BE + + #define sbgStreamBufferReadUint56 sbgStreamBufferReadUint56BE + #define sbgStreamBufferReadInt56 sbgStreamBufferReadInt56BE + + #define sbgStreamBufferReadUint64 sbgStreamBufferReadUint64BE + #define sbgStreamBufferReadInt64 sbgStreamBufferReadInt64BE + + #define sbgStreamBufferReadSizeT32 sbgStreamBufferReadSizeT32BE + #define sbgStreamBufferReadSizeT64 sbgStreamBufferReadSizeT64BE + + #define sbgStreamBufferReadFloat sbgStreamBufferReadFloatBE + #define sbgStreamBufferReadDouble sbgStreamBufferReadDoubleBE + + #define sbgStreamBufferWriteUint16 sbgStreamBufferWriteUint16BE + #define sbgStreamBufferWriteInt16 sbgStreamBufferWriteInt16BE + + #define sbgStreamBufferWriteUint24 sbgStreamBufferWriteUint24BE + #define sbgStreamBufferWriteInt24 sbgStreamBufferWriteInt24BE + + #define sbgStreamBufferWriteUint32 sbgStreamBufferWriteUint32BE + #define sbgStreamBufferWriteInt32 sbgStreamBufferWriteInt32BE + + #define sbgStreamBufferWriteUint64 sbgStreamBufferWriteUint64BE + #define sbgStreamBufferWriteInt64 sbgStreamBufferWriteInt64BE + + #define sbgStreamBufferWriteSizeT32 sbgStreamBufferWriteSizeT32BE + #define sbgStreamBufferWriteSizeT64 sbgStreamBufferWriteSizeT64BE + + #define sbgStreamBufferWriteFloat sbgStreamBufferWriteFloatBE + #define sbgStreamBufferWriteDouble sbgStreamBufferWriteDoubleBE + + #define sbgStreamBufferReadString sbgStreamBufferReadStringBE + #define sbgStreamBufferWriteString sbgStreamBufferWriteStringBE +#else + /*! + * The platform is a little endian one so default methods should use little endian byte order. + */ + #define sbgStreamBufferReadUint16 sbgStreamBufferReadUint16LE + #define sbgStreamBufferReadInt16 sbgStreamBufferReadInt16LE + + #define sbgStreamBufferReadUint24 sbgStreamBufferReadUint24LE + #define sbgStreamBufferReadInt24 sbgStreamBufferReadInt24LE + + #define sbgStreamBufferReadUint32 sbgStreamBufferReadUint32LE + #define sbgStreamBufferReadInt32 sbgStreamBufferReadInt32LE + + #define sbgStreamBufferReadUint40 sbgStreamBufferReadUint40LE + #define sbgStreamBufferReadInt40 sbgStreamBufferReadInt40LE + + #define sbgStreamBufferReadUint48 sbgStreamBufferReadUint48LE + #define sbgStreamBufferReadInt48 sbgStreamBufferReadInt48LE + + #define sbgStreamBufferReadUint56 sbgStreamBufferReadUint56LE + #define sbgStreamBufferReadInt56 sbgStreamBufferReadInt56LE + + #define sbgStreamBufferReadUint64 sbgStreamBufferReadUint64LE + #define sbgStreamBufferReadInt64 sbgStreamBufferReadInt64LE + + #define sbgStreamBufferReadSizeT32 sbgStreamBufferReadSizeT32LE + #define sbgStreamBufferReadSizeT64 sbgStreamBufferReadSizeT64LE + + #define sbgStreamBufferReadFloat sbgStreamBufferReadFloatLE + #define sbgStreamBufferReadDouble sbgStreamBufferReadDoubleLE + + #define sbgStreamBufferWriteUint16 sbgStreamBufferWriteUint16LE + #define sbgStreamBufferWriteInt16 sbgStreamBufferWriteInt16LE + + #define sbgStreamBufferWriteUint24 sbgStreamBufferWriteUint24LE + #define sbgStreamBufferWriteInt24 sbgStreamBufferWriteInt24LE + + #define sbgStreamBufferWriteUint32 sbgStreamBufferWriteUint32LE + #define sbgStreamBufferWriteInt32 sbgStreamBufferWriteInt32LE + + #define sbgStreamBufferWriteUint64 sbgStreamBufferWriteUint64LE + #define sbgStreamBufferWriteInt64 sbgStreamBufferWriteInt64LE + + #define sbgStreamBufferWriteSizeT32 sbgStreamBufferWriteSizeT32LE + #define sbgStreamBufferWriteSizeT64 sbgStreamBufferWriteSizeT64LE + + #define sbgStreamBufferWriteFloat sbgStreamBufferWriteFloatLE + #define sbgStreamBufferWriteDouble sbgStreamBufferWriteDoubleLE + + #define sbgStreamBufferReadString sbgStreamBufferReadStringLE + #define sbgStreamBufferWriteString sbgStreamBufferWriteStringLE +#endif + +/*! + * Some methods are common between big and little endian. + * This definitions just unify the API. + */ +#define sbgStreamBufferReadUint8LE sbgStreamBufferReadUint8 +#define sbgStreamBufferReadInt8LE sbgStreamBufferReadInt8 +#define sbgStreamBufferReadBooleanLE sbgStreamBufferReadBoolean +#define sbgStreamBufferReadBufferLE sbgStreamBufferReadBuffer + +#define sbgStreamBufferWriteUint8LE sbgStreamBufferWriteUint8 +#define sbgStreamBufferWriteInt8LE sbgStreamBufferWriteInt8 +#define sbgStreamBufferWriteBooleanLE sbgStreamBufferWriteBoolean +#define sbgStreamBufferWriteBufferLE sbgStreamBufferWriteBuffer + +#define sbgStreamBufferReadUint8BE sbgStreamBufferReadUint8 +#define sbgStreamBufferReadInt8BE sbgStreamBufferReadInt8 +#define sbgStreamBufferReadBooleanBE sbgStreamBufferReadBoolean +#define sbgStreamBufferReadBufferBE sbgStreamBufferReadBuffer + +#define sbgStreamBufferWriteUint8BE sbgStreamBufferWriteUint8 +#define sbgStreamBufferWriteInt8BE sbgStreamBufferWriteInt8 +#define sbgStreamBufferWriteBooleanBE sbgStreamBufferWriteBoolean +#define sbgStreamBufferWriteBufferBE sbgStreamBufferWriteBuffer + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Stream buffer modes. + */ +typedef enum _SbgSBMode +{ + SB_MODE_READ, /*!< This stream buffer can perform read operations. */ + SB_MODE_WRITE /*!< This stream buffer can perform write operations. */ +} SbgSBMode; + +/*! + * Enum used to define all seek modes + */ +typedef enum _SbgSBSeekOrigin +{ + SB_SEEK_SET, /*!< The offset is referenced to the begining of the stream. */ + SB_SEEK_CUR_INC, /*!< The offset is referenced to the current cursor position and increment the current cursor. */ + SB_SEEK_CUR_DEC, /*!< The offset is referenced to the current cursor position and decrement the current cursor. */ + SB_SEEK_END /*!< The offset is referenced to the end of the stream. */ +} SbgSBSeekOrigin; + +/*! + * Defines a stream buffer. + */ +typedef struct _SbgStreamBuffer +{ + SbgSBMode modes; /*!< Defines the stream buffer modes (read/write). */ + size_t bufferSize; /*!< Size in bytes of the linked buffer. */ + uint8_t *pBufferPtr; /*!< Pointer to the buffer linked with this stream. */ + uint8_t *pCurrentPtr; /*!< Current pointer within the buffer. */ + SbgErrorCode errorCode; /*!< Current error code on stream buffer. */ +} SbgStreamBuffer; + +//----------------------------------------------------------------------// +//- Common operations methods -// +//----------------------------------------------------------------------// + +/*! + * Initialize a stream buffer for both read and write operations and link it to a buffer. + * + * \param[in] pHandle Handle on an allocated stream buffer. + * \param[in] pLinkedBuffer Pointer on an allocated buffer to link with this stream. + * \param[in] bufferSize Size in bytes of the linked buffer. + * \return SBG_NO_ERROR if the stream buffer has been initialized successfully. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferInitForWrite(SbgStreamBuffer *pHandle, void *pLinkedBuffer, size_t bufferSize) +{ + assert(pHandle); + assert(pLinkedBuffer); + + // + // Initialize stream parameters + // + pHandle->modes = SB_MODE_WRITE; + pHandle->bufferSize = bufferSize; + pHandle->errorCode = SBG_NO_ERROR; + + // + // Initialize the buffer + // + pHandle->pBufferPtr = (uint8_t*)pLinkedBuffer; + pHandle->pCurrentPtr = (uint8_t*)pLinkedBuffer; + + // + // For now, we don't handle any error, maybe we could add checks in debug mode only + // + return SBG_NO_ERROR; +} + +/*! + * Initialize a stream buffer for both read and write operations and link it to a buffer. + * + * \param[in] pHandle Handle on an allocated stream buffer. + * \param[in] pLinkedBuffer Pointer on an allocated buffer to link with this stream. + * \param[in] bufferSize Size in bytes of the linked buffer. + * \return SBG_NO_ERROR if the stream buffer has been initialized successfully. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferInitForRead(SbgStreamBuffer *pHandle, const void *pLinkedBuffer, size_t bufferSize) +{ + assert(pHandle); + assert(pLinkedBuffer); + + // + // Initialize stream parameters + // + pHandle->modes = SB_MODE_READ; + pHandle->bufferSize = bufferSize; + pHandle->errorCode = SBG_NO_ERROR; + + // + // Initialize the buffer + // + pHandle->pBufferPtr = (uint8_t*)pLinkedBuffer; + pHandle->pCurrentPtr = (uint8_t*)pLinkedBuffer; + + // + // For now, we don't handle any error, maybe we could add checks in debug mode only + // + return SBG_NO_ERROR; +} + +/*! + * Return the error code that has occurred on the last stream buffer operation. + * + * \param[in] pHandle Pointer to a valid Stream Buffer handle + * \return Last stream buffer error code + */ +SBG_INLINE SbgErrorCode sbgStreamBufferGetLastError(const SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + // + // Return error code + // + return pHandle->errorCode; +} + +/*! + * Clear the last error code that has occurred on the last stream buffer operation. + * + * \param[in] pHandle Pointer to a valid Stream Buffer handle + */ +SBG_INLINE void sbgStreamBufferClearLastError(SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + // + // Return error code + // + pHandle->errorCode = SBG_NO_ERROR; +} + +/*! + * Returns the size in bytes of this stream. + * + * The size is the linked buffer total size in bytes. + * For example, for a SbgStreamBuffer linked with a buffer of 256 bytes, + * this method will always returns 256 even if no data has been written or read. + * + * \param[in] pHandle Valid handle on a stream buffer. + * \return The allocated size of the linked buffer in bytes. + */ +SBG_INLINE size_t sbgStreamBufferGetSize(const SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + // + // Return the linked buffer size + // + return pHandle->bufferSize; +} + +/*! + * Returns the length in bytes of this stream. + * + * The length is computed using the current cursor position. + * If no data has been read or written, this method will return 0. + * If 4 uint32_t has been written, it should return 16. + * + * \param[in] pHandle Valid handle on a stream buffer. + * \return The current cursor position in bytes. + */ +SBG_INLINE size_t sbgStreamBufferGetLength(const SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + // + // Return the number of bytes between the begin of the stream and the current pointer + // + return ((size_t)pHandle->pCurrentPtr - (size_t)pHandle->pBufferPtr); +} + +/*! + * Returns the available space in this stream. + * + * The available space is just the delta between the linked buffer size + * and the current buffer length (cursor position). + * + * \param[in] pHandle Valid handle on a stream buffer. + * \return The space available in this stream buffer in bytes. + */ +SBG_INLINE size_t sbgStreamBufferGetSpace(const SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + // + // Return the space left in bytes + // + return sbgStreamBufferGetSize(pHandle) - sbgStreamBufferGetLength(pHandle); +} + +/*! + * Move the current cursor position. + * + * \param[in] pHandle Valid handle on a stream buffer. + * \param[in] offset Offset in bytes to apply (only positive). + * \param[in] origin Origin reference point to apply the offset from. + * \return SBG_NO_ERROR if the stream current cursor position has been moved. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferSeek(SbgStreamBuffer *pHandle, size_t offset, SbgSBSeekOrigin origin) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // According to the origin reference point + // + switch (origin) + { + case SB_SEEK_SET: + pHandle->pCurrentPtr = pHandle->pBufferPtr + offset; + break; + case SB_SEEK_CUR_INC: + pHandle->pCurrentPtr += offset; + break; + case SB_SEEK_CUR_DEC: + pHandle->pCurrentPtr -= offset; + break; + case SB_SEEK_END: + pHandle->pCurrentPtr = pHandle->pBufferPtr + (pHandle->bufferSize - offset); + break; + default: + pHandle->errorCode = SBG_INVALID_PARAMETER; + SBG_LOG_ERROR(pHandle->errorCode, "Invalid origin parameter"); + } + + // + // Make sure that no error has occurred + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if the current ptr is still within the buffer bounds + // + if (pHandle->pCurrentPtr < pHandle->pBufferPtr) + { + // + // We are before the buffer so clamp to the begining of the buffer and raise an error + // + pHandle->pCurrentPtr = pHandle->pBufferPtr; + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + + // + // Stream buffer underflow + // + SBG_LOG_ERROR(pHandle->errorCode, "Trying to seek before the buffer"); + } + else if (pHandle->pCurrentPtr > pHandle->pBufferPtr + pHandle->bufferSize) + { + // + // We are after the buffer so clamp to the end of the buffer and raise an error + // + pHandle->pCurrentPtr = pHandle->pBufferPtr + pHandle->bufferSize; + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + + // + // Stream buffer overflow + // + SBG_LOG_ERROR(pHandle->errorCode, "Trying to seek after the buffer"); + } + } + } + + return pHandle->errorCode; +} + +/*! + * Returns the current offset in bytes from the beginning of the stream. + * + * \param[in] pHandle Valid handle on a stream buffer. + * \return Current offset in bytes from the beginning. + */ +SBG_INLINE size_t sbgStreamBufferTell(const SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + return (size_t)pHandle->pCurrentPtr - (size_t)pHandle->pBufferPtr; +} + +/*! + * Returns a pointer on the internal buffer. + * + * \param[in] pHandle Valid handle on a stream buffer. + * \return Pointer on the begining of the internal buffer. + */ +SBG_INLINE void *sbgStreamBufferGetLinkedBuffer(const SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + return pHandle->pBufferPtr; +} + +/*! + * Returns a pointer on the internal buffer at the current cursor. + * + * \param[in] pHandle Valid handle on a stream buffer. + * \return Pointer on the current cursor of the internal buffer. + */ +SBG_INLINE void *sbgStreamBufferGetCursor(const SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + return pHandle->pCurrentPtr; +} + +//----------------------------------------------------------------------// +//- Read operations methods -// +//----------------------------------------------------------------------// + +/*! + * Read an int8_t from a stream buffer. + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int8_t sbgStreamBufferReadInt8(SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int8_t)) + { + // + // Read the byte + // + return *((int8_t*)(pHandle->pCurrentPtr++)); + } + else + { + // + // We have a buffer overflow + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint8_t from a stream buffer. + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint8_t sbgStreamBufferReadUint8(SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint8_t)) + { + // + // Read the byte + // + return *((uint8_t*)(pHandle->pCurrentPtr++)); + } + else + { + // + // We have a buffer overflow + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read a boolean from a stream buffer. + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or false if we have an error. + */ +SBG_INLINE bool sbgStreamBufferReadBoolean(SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint8_t)) + { + // + // Read the byte and check if the value is different than zero or not + // + if (*((uint8_t*)(pHandle->pCurrentPtr++))) + { + return true; + } + else + { + return false; + } + } + else + { + // + // We have a buffer overflow + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return false + // + return false; +} + +/*! + * Read a buffer from a stream buffer. + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \param[out] pBuffer Allocated buffer used to hold read data. + * \param[in] numBytesToRead Number of bytes to read from the stream buffer and to store in pBuffer. + * \return SBG_NO_ERROR if the data has been read. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferReadBuffer(SbgStreamBuffer *pHandle, void *pBuffer, size_t numBytesToRead) +{ + assert(pHandle); + assert((pBuffer) || (numBytesToRead == 0)); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if enough bytes in stream + // + if (sbgStreamBufferGetSpace(pHandle) >= numBytesToRead) + { + // + // Copy from the stream buffer to the output buffer + // + memcpy(pBuffer, pHandle->pCurrentPtr, numBytesToRead); + + // + // Update the current pointer + // + pHandle->pCurrentPtr += numBytesToRead; + } + else + { + // + // Not enough data in stream + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +//----------------------------------------------------------------------// +//- Write operations methods -// +//----------------------------------------------------------------------// + +/*! + * Write an int8_t into a stream buffer + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteInt8(SbgStreamBuffer *pHandle, int8_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int8_t)) + { + // + // Write each byte + // + *(pHandle->pCurrentPtr++) = (int8_t)(value); + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint8_t into a stream buffer + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint8(SbgStreamBuffer *pHandle, uint8_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint8_t)) + { + // + // Write each byte + // + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write a boolean into a stream buffer + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteBoolean(SbgStreamBuffer *pHandle, bool value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint8_t)) + { + // + // Write the boolean as an uint8_t value (1 byte) + // + if (value) + { + *(pHandle->pCurrentPtr++) = 1; + } + else + { + *(pHandle->pCurrentPtr++) = 0; + } + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write a buffer to a stream buffer. + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[out] pBuffer Buffer to write into the stream buffer. + * \param[in] numBytesToWrite Number of bytes to write to the stream buffer. + * \return SBG_NO_ERROR if the data has been written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteBuffer(SbgStreamBuffer *pHandle, const void *pBuffer, size_t numBytesToWrite) +{ + assert(pHandle); + assert((pBuffer) || (numBytesToWrite == 0)); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= numBytesToWrite) + { + // + // Copy from the stream buffer to the output buffer + // + memcpy(pHandle->pCurrentPtr, pBuffer, numBytesToWrite); + + // + // Update the current pointer + // + pHandle->pCurrentPtr += numBytesToWrite; + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +#endif // SBG_STREAM_BUFFER_COMMON_H diff --git a/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBufferLE.h b/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBufferLE.h new file mode 100644 index 0000000..e3dc97e --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/streamBuffer/sbgStreamBufferLE.h @@ -0,0 +1,1922 @@ +/*! + * \file sbgStreamBufferLE.h + * \ingroup common + * \author SBG Systems + * \date 17 February 2015 + * + * \brief Specific method of stream buffer for little endian readings/writings. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_STREAM_BUFFER_LE_H +#define SBG_STREAM_BUFFER_LE_H + +#include "sbgStreamBufferCommon.h" + +//----------------------------------------------------------------------// +//- Read operations methods -// +//----------------------------------------------------------------------// + +/*! + * Read an int16_t from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int16_t sbgStreamBufferReadInt16LE(SbgStreamBuffer *pHandle) +{ + int16_t bytesValues[2]; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int16_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Read the current value + // + bytesValues[0] = *((int16_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int16_t); + + return bytesValues[0]; + #else + // + // Read the each bytes + // + bytesValues[0] = *(pHandle->pCurrentPtr++); + bytesValues[1] = *(pHandle->pCurrentPtr++); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return bytesValues[1] | (bytesValues[0] << 8); + #else + return bytesValues[0] | (bytesValues[1] << 8); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint16_t from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint16_t sbgStreamBufferReadUint16LE(SbgStreamBuffer *pHandle) +{ + uint16_t bytesValues[2]; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint16_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Read the current value + // + bytesValues[0] = *((uint16_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint16_t); + + return bytesValues[0]; + #else + // + // Read the each bytes + // + bytesValues[0] = *(pHandle->pCurrentPtr++); + bytesValues[1] = *(pHandle->pCurrentPtr++); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return bytesValues[1] | (bytesValues[0] << 8); + #else + return bytesValues[0] | (bytesValues[1] << 8); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int24 from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int32_t sbgStreamBufferReadInt24LE(SbgStreamBuffer *pHandle) +{ + Uint8ToInt32 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 3*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[2] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + #else + // + // Read the each bytes + // + value.buffer[1] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); // MSB + #endif + + // + // Shift the value to handle the sign correctly for a 24 bits + // + return value.value >> (32-24); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint24 from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint32_t sbgStreamBufferReadUint24LE(SbgStreamBuffer *pHandle) +{ + Uint8ToUint32 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 3*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[2] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + #else + // + // Read the each bytes + // + value.buffer[1] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); // MSB + #endif + + // + // Shift the value to handle the sign correctly for a 24 bits + // + return value.value >> (32-24); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int32_t from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int32_t sbgStreamBufferReadInt32LE(SbgStreamBuffer *pHandle) +{ + int32_t bytesValues[4]; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int32_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Read the current value + // + bytesValues[0] = *((int32_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int32_t); + + return bytesValues[0]; + #else + // + // Read the each bytes + // + bytesValues[0] = *(pHandle->pCurrentPtr++); + bytesValues[1] = *(pHandle->pCurrentPtr++); + bytesValues[2] = *(pHandle->pCurrentPtr++); + bytesValues[3] = *(pHandle->pCurrentPtr++); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return bytesValues[3] | (bytesValues[2] << 8) | (bytesValues[1] << 16) | (bytesValues[0] << 24); + #else + return bytesValues[0] | (bytesValues[1] << 8) | (bytesValues[2] << 16) | (bytesValues[3] << 24); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint32_t from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint32_t sbgStreamBufferReadUint32LE(SbgStreamBuffer *pHandle) +{ + uint32_t bytesValues[4]; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint32_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Read the current value + // + bytesValues[0] = *((uint32_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint32_t); + + return bytesValues[0]; + #else + // + // Read the each bytes + // + bytesValues[0] = *(pHandle->pCurrentPtr++); + bytesValues[1] = *(pHandle->pCurrentPtr++); + bytesValues[2] = *(pHandle->pCurrentPtr++); + bytesValues[3] = *(pHandle->pCurrentPtr++); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return bytesValues[3] | (bytesValues[2] << 8) | (bytesValues[1] << 16) | (bytesValues[0] << 24); + #else + return bytesValues[0] | (bytesValues[1] << 8) | (bytesValues[2] << 16) | (bytesValues[3] << 24); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int40 from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int64_t sbgStreamBufferReadInt40LE(SbgStreamBuffer *pHandle) +{ + Uint8ToInt64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 5*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[4] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + #else + // + // Read the each bytes + // + value.buffer[3] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + #endif + + // + // Shift the value to handle the sign correctly for a 40 bits + // + return value.value >> (64-40); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint40 from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int64_t sbgStreamBufferReadUint40LE(SbgStreamBuffer *pHandle) +{ + Uint8ToUint64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 5*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[4] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + #else + // + // Read the each bytes + // + value.buffer[3] = *(pHandle->pCurrentPtr++); // MSB + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + #endif + + // + // Shift the value to handle the sign correctly for a 40 bits + // + return value.value >> (64-40); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int48 from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int64_t sbgStreamBufferReadInt48LE(SbgStreamBuffer *pHandle) +{ + Uint8ToInt64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 6*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[5] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + #else + // + // Read the each bytes + // + value.buffer[2] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + #endif + + // + // Shift the value to handle the sign correctly for a 48 bits + // + return value.value >> (64-48); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint48 from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint64_t sbgStreamBufferReadUint48LE(SbgStreamBuffer *pHandle) +{ + Uint8ToUint64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 6*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[5] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + #else + // + // Read the each bytes + // + value.buffer[2] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + #endif + + // + // Shift the value to handle the sign correctly for a 48 bits + // + return value.value >> (64-48); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int56 from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int64_t sbgStreamBufferReadInt56LE(SbgStreamBuffer *pHandle) +{ + Uint8ToInt64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 7*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[6] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + #else + // + // Read the each bytes + // + value.buffer[1] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + #endif + + // + // Shift the value to handle the sign correctly for a 56 bits + // + return value.value >> (64-56); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an uint56 from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint64_t sbgStreamBufferReadUint56LE(SbgStreamBuffer *pHandle) +{ + Uint8ToUint64 value; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 7*sizeof(uint8_t)) + { + // + // Make sure the value is zero init + // + value.value = 0; + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + // + // Read the each bytes + // + value.buffer[6] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[1] = *(pHandle->pCurrentPtr++); + value.buffer[0] = *(pHandle->pCurrentPtr++); // MSB + #else + // + // Read the each bytes + // + value.buffer[1] = *(pHandle->pCurrentPtr++); // LSB + value.buffer[2] = *(pHandle->pCurrentPtr++); + value.buffer[3] = *(pHandle->pCurrentPtr++); + value.buffer[4] = *(pHandle->pCurrentPtr++); + value.buffer[5] = *(pHandle->pCurrentPtr++); + value.buffer[6] = *(pHandle->pCurrentPtr++); + value.buffer[7] = *(pHandle->pCurrentPtr++); // MSB + #endif + + // + // Shift the value to handle the sign correctly for a 56 bits + // + return value.value >> (64-56); + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0; +} + +/*! + * Read an int64_t from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE int64_t sbgStreamBufferReadInt64LE(SbgStreamBuffer *pHandle) +{ + int64_t lowPart; + int64_t highPart; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int64_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Read the current value + // + lowPart = *((int64_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int64_t); + + return lowPart; + #else + // + // Read 64 bit value using two 32 bits read to avoid too much 64 bits operations + // + lowPart = sbgStreamBufferReadUint32LE(pHandle); + highPart = sbgStreamBufferReadUint32LE(pHandle); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return (lowPart << 32) | highPart; + #else + return lowPart | (highPart << 32); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0ll; +} + +/*! + * Read an uint64_t from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE uint64_t sbgStreamBufferReadUint64LE(SbgStreamBuffer *pHandle) +{ + uint64_t lowPart; + uint64_t highPart; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint64_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Read the current value + // + lowPart = *((uint64_t*)pHandle->pCurrentPtr); + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint64_t); + + return lowPart; + #else + // + // Read 64 bit value using two 32 bits read to avoid too much 64 bits operations + // + lowPart = sbgStreamBufferReadUint32LE(pHandle); + highPart = sbgStreamBufferReadUint32LE(pHandle); + + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + return (lowPart << 32) | highPart; + #else + return lowPart | (highPart << 32); + #endif + #endif + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0ull; +} + +/*! + * Read a size_t from a stream buffer that has been stored in a uint32_t (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE size_t sbgStreamBufferReadSizeT32LE(SbgStreamBuffer *pHandle) +{ + assert(pHandle); + + // + // Just call the read method for uint32_t + // We assume that a size_t is at least 32 bits on all platforms + // + return (size_t)sbgStreamBufferReadUint32LE(pHandle); +} + +/*! + * Read a size_t from a stream buffer that has been stored in a uint64_t (Little endian version). + + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE size_t sbgStreamBufferReadSizeT64LE(SbgStreamBuffer *pHandle) +{ + uint64_t size; + + assert(pHandle); + + // + // Just call the read method for uint64_t + // + size = sbgStreamBufferReadUint64LE(pHandle); + + // + // Make sure the read size can fit in the size_t in size_t is 32 bits + // + assert((sizeof(size_t) == 8) || ((sizeof(size_t) == 4) && (size <= UINT32_MAX))); + + // + // Return the read value + // + return (size_t)size; +} + +/*! + * Read an float from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE float sbgStreamBufferReadFloatLE(SbgStreamBuffer *pHandle) +{ + FloatNint floatInt; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(float)) + { + // + // Read the float as an uint32_t + // + floatInt.valU = sbgStreamBufferReadUint32LE(pHandle); + + // + // Return the float using an union to avoid compiler cast + // + return floatInt.valF; + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0.0f; +} + +/*! + * Read an double from a stream buffer (Little endian version). + * + * \param[in] pHandle Valid stream buffer handle that supports read operations. + * \return The read value or 0 if we have an error. + */ +SBG_INLINE double sbgStreamBufferReadDoubleLE(SbgStreamBuffer *pHandle) +{ + DoubleNint doubleInt; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(double)) + { + // + // Read the float as an uint64_t + // + doubleInt.valU = sbgStreamBufferReadUint64LE(pHandle); + + // + // Return the double using an union to avoid compiler cast + // + return doubleInt.valF; + } + else + { + // + // We have a buffer overflow so return 0 + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // If we are here, it means we have an error so return 0 + // + return 0.0; +} + +//----------------------------------------------------------------------// +//- Write operations methods -// +//----------------------------------------------------------------------// + +/*! + * Write an int16_t into a stream buffer (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteInt16LE(SbgStreamBuffer *pHandle, int16_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int16_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Write the value + // + *((int16_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int16_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint16_t into a stream buffer (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint16LE(SbgStreamBuffer *pHandle, uint16_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint16_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Write the value + // + *((uint16_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint16_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + + +/*! + * Write an int24 into a stream buffer (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteInt24LE(SbgStreamBuffer *pHandle, int32_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Make sure that the value is within 24 bit bonds + // + if ( (value >= SBG_MIN_INT_24) && (value <= SBG_MAX_INT_24) ) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 3*sizeof(int8_t)) + { + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + else + { + // + // The input value is not within a 24 bit integer bounds + // + pHandle->errorCode = SBG_INVALID_PARAMETER; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint24 into a stream buffer (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint24LE(SbgStreamBuffer *pHandle, uint32_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Make sure that the value is within 24 bit bonds + // + if (value <= SBG_MAX_UINT_24) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 3*sizeof(uint8_t)) + { + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + else + { + // + // The input value is not within a 24 bit integer bounds + // + pHandle->errorCode = SBG_INVALID_PARAMETER; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an int32_t into a stream buffer (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteInt32LE(SbgStreamBuffer *pHandle, int32_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int32_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Write the value + // + *((int32_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int32_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint32_t into a stream buffer (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint32LE(SbgStreamBuffer *pHandle, uint32_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint32_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Write the value + // + *((uint32_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint32_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint48 into a stream buffer (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint48LE(SbgStreamBuffer *pHandle, uint64_t value) +{ + assert(pHandle); + assert(value < ((uint64_t)1 << 48)); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= 6 * sizeof(uint8_t)) + { + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an int64_t into a stream buffer (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteInt64LE(SbgStreamBuffer *pHandle, int64_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(int64_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Write the value + // + *((int64_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(int64_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 56); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 48); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 48); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 56); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an uint64_t into a stream buffer (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint64LE(SbgStreamBuffer *pHandle, uint64_t value) +{ + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // Test if we can access this item + // + if (sbgStreamBufferGetSpace(pHandle) >= sizeof(uint64_t)) + { + // + // Test if the platform supports un-aligned access and if the endianness is the same + // + #if (SBG_CONFIG_UNALIGNED_ACCESS_AUTH == 1) && (SBG_CONFIG_BIG_ENDIAN == 0) + // + // Write the value + // + *((uint64_t*)(pHandle->pCurrentPtr)) = value; + + // + // Increment the current pointer + // + pHandle->pCurrentPtr += sizeof(uint64_t); + #else + // + // Store data according to platform endianness + // + #if (SBG_CONFIG_BIG_ENDIAN == 1) + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 56); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 48); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + #else + *(pHandle->pCurrentPtr++) = (uint8_t)(value); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 8); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 16); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 24); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 32); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 40); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 48); + *(pHandle->pCurrentPtr++) = (uint8_t)(value >> 56); + #endif + #endif + } + else + { + // + // We are accessing a data that is outside the stream buffer + // + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + } + } + + return pHandle->errorCode; +} + +/*! + * Write an size_t into a stream buffer as a uint32_t (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteSizeT32LE(SbgStreamBuffer *pHandle, size_t value) +{ + assert(pHandle); + + // + // Make sure the provided size_t value doesn't exceed a uint32_t storage + // + assert(value <= UINT32_MAX); + + // + // Call the write method to store a uint32_t + // + return sbgStreamBufferWriteUint32LE(pHandle, (uint32_t)value); +} + +/*! + * Write an size_t into a stream buffer as a uint64_t (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteSizeT64LE(SbgStreamBuffer *pHandle, size_t value) +{ + assert(pHandle); + + // + // Call the write method to store a uint64_t + // + return sbgStreamBufferWriteUint64LE(pHandle, (uint64_t)value); +} + +/*! + * Write an float into a stream buffer (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteFloatLE(SbgStreamBuffer *pHandle, float value) +{ + FloatNint floatInt; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // We use an union to avoid compiler cast + // + floatInt.valF = value; + + // + // Write this float as an uint32_t + // + return sbgStreamBufferWriteUint32LE(pHandle, floatInt.valU); + } + + return pHandle->errorCode; +} + +/*! + * Write an double into a stream buffer. (Little Endian Version). + * + * \param[in] pHandle Valid stream buffer handle that supports write operations. + * \param[in] value The value to write. + * \return SBG_NO_ERROR if the value has been successfully written. + */ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteDoubleLE(SbgStreamBuffer *pHandle, double value) +{ + DoubleNint doubleInt; + + assert(pHandle); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // We use an union to avoid compiler cast + // + doubleInt.valF = value; + + // + // Write this float as an uint64_t + // + return sbgStreamBufferWriteUint64LE(pHandle, doubleInt.valU); + } + + return pHandle->errorCode; +} + +/*! +* Read a C String from a stream buffer (Little Endian Version). +* +* \param[in] pHandle Valid stream buffer handle that supports read operations. +* \param[out] pString Buffer that can hold the read NULL terminated C string. +* \param[in] maxSize Maximum number of bytes that can be stored in pString (including the NULL char). +* \return SBG_NO_ERROR if the string has been read successfully from the stream buffer. +* SBG_BUFFER_OVERFLOW if the provided string isn't big enough to hold the read string +*/ +SBG_INLINE SbgErrorCode sbgStreamBufferReadStringLE(SbgStreamBuffer *pHandle, char *pString, size_t maxSize) +{ + size_t stringLength; + + assert(pHandle); + assert(pString); + assert(maxSize > 0); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // The C string are stored in a stream buffer with a 32 bit size length and then the buffer itself + // + stringLength = sbgStreamBufferReadSizeT32LE(pHandle); + + if (stringLength <= maxSize) + { + // + // Read the string buffer itself + // + sbgStreamBufferReadBuffer(pHandle, pString, stringLength); + } + else + { + pHandle->errorCode = SBG_BUFFER_OVERFLOW; + SBG_LOG_ERROR(pHandle->errorCode, "Trying to store a string of %zu bytes into a buffer of %zu bytes.", stringLength, maxSize); + } + } + + return pHandle->errorCode; +} + +/*! +* Write a NULL terminated C String into a stream buffer (Little Endian Version). +* +* \param[in] pHandle Valid stream buffer handle that supports write operations. +* \param[in] pString NULL terminated C String to write to the stream buffer. +* \return SBG_NO_ERROR if the string has been written successfully to the stream buffer. +*/ +SBG_INLINE SbgErrorCode sbgStreamBufferWriteStringLE(SbgStreamBuffer *pHandle, const char *pString) +{ + size_t stringLength; + + assert(pHandle); + assert(pString); + + // + // Test if we haven't already an error + // + if (pHandle->errorCode == SBG_NO_ERROR) + { + // + // We write C string using a 32 bit size_t as the string length including the NULL char + // We should thus make sure the provided string isn't too big to fit in a 32 bits size_t + // + stringLength = strlen(pString) + 1; + + if (stringLength <= UINT32_MAX) + { + // + // Write the string length + // + if (sbgStreamBufferWriteSizeT32LE(pHandle, stringLength) == SBG_NO_ERROR) + { + // + // Write the string buffer itself + // + sbgStreamBufferWriteBuffer(pHandle, pString, stringLength); + } + } + else + { + pHandle->errorCode = SBG_INVALID_PARAMETER; + SBG_LOG_ERROR(pHandle->errorCode, "The provided string is too big to fit in a 32 bit size_t"); + } + } + + return pHandle->errorCode; +} + +#endif /* SBG_STREAM_BUFFER_LE_H */ diff --git a/crates/sbg-rs/sbgECom/common/string/sbgString.c b/crates/sbg-rs/sbgECom/common/string/sbgString.c new file mode 100644 index 0000000..b7d36cd --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/string/sbgString.c @@ -0,0 +1,1545 @@ +// Standard headers +#include +#include + +// sbgCommonLib headers +#include + +// Local headers +#include "sbgString.h" + +//----------------------------------------------------------------------// +// Private functions // +//----------------------------------------------------------------------// + +/*! + * Count the number of leading zeros in an unsigned integer. + * + * \param[in] value Integer value, must not be zero. + * \return Number of leading zeros. + */ +static uint32_t sbgStringCountLeadingZeros(size_t value) +{ + uint32_t result; + + assert(value != 0); + +#if defined(__GNUC__) || defined(__clang__) + result = __builtin_clzl((unsigned long)value); +#else + size_t count; + size_t tmp; + + tmp = value; + count = 0; + + while (tmp != 0) + { + tmp >>= 1; + count++; + } + + result = (sizeof(size_t) * 8) - count; +#endif // defined(__GNUC__) || defined(__clang__) + + return result; +} + +/*! + * Compute the capacity required to store a string of the given size, in bytes. + * + * The size includes the terminating null character. + * + * The size must not be zero. + * + * \param[in] pString String. + * \param[in] size Size, in bytes. + * \param[out] pCapacity Capacity, in bytes. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgStringComputeCapacity(const SbgString *pString, size_t size, size_t *pCapacity) +{ + SbgErrorCode errorCode; + + assert(pString); + + SBG_UNUSED_PARAMETER(pString); + + // + // The computed capacity is the power-of-two equal to or immediately greater than the size. + // In other words, it's the value with a single bit set where the index of that bit is one + // more than the MSB bit of the size, unless the size is already a power-of-two. + // + // If the size already requires all bits of the size_t type to be encoded, then there's no + // extra bit available to encode the capacity. + // + + if (size <= ((size_t)1 << ((sizeof(size_t) * 8) - 1))) + { + *pCapacity = (size_t)1 << ((sizeof(size_t) * 8) - sbgStringCountLeadingZeros(size)); + + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_INVALID_PARAMETER; + SBG_LOG_ERROR(errorCode, "unable to compute capacity"); + } + + return errorCode; +} + +/*! + * Resize the buffer of a string. + * + * This function only resizes the buffer, it doesn't guarantee the content is null-terminated. + * + * If an allocation error occurs, the string is left unchanged. + * + * If an allocation error occurs, and the new size is smaller than the current size, the + * operation is considered successful. + * + * \param[in] pString String. + * \param[in] size Required size, in bytes. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgStringResizeBuffer(SbgString *pString, size_t size) +{ + SbgErrorCode errorCode; + + assert(pString); + assert(!pString->readOnly); + + if (pString->isStatic) + { + if (size <= pString->capacity) + { + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_BUFFER_OVERFLOW; + SBG_LOG_ERROR(errorCode, "insufficient static space for string: requested %zu, capacity %zu", size, pString->capacity); + } + } + else + { + size_t capacity; + + // + // XXX If a user performs frequent operations on a string that change its size + // below and above the size of the internal buffer, the performance impact of + // copying the content to and from the internal buffer would cause hysteresis. + // + // There is no special handling of this situation as it is assumed that the + // internal buffer is small enough that the cost of the copy operation is + // negligible. + // + + errorCode = sbgStringComputeCapacity(pString, size, &capacity); + + if (errorCode == SBG_NO_ERROR) + { + if (capacity != pString->capacity) + { + if (capacity <= sizeof(pString->internalBuffer)) + { + if (pString->pBuffer != pString->internalBuffer) + { + memcpy(pString->internalBuffer, pString->pBuffer, capacity); + free(pString->pBuffer); + + pString->pBuffer = pString->internalBuffer; + pString->capacity = sizeof(pString->internalBuffer); + } + } + else + { + if (pString->pBuffer == pString->internalBuffer) + { + char *pBuffer; + + pBuffer = malloc(capacity); + + if (pBuffer) + { + memcpy(pBuffer, pString->internalBuffer, pString->capacity); + pString->pBuffer = pBuffer; + pString->capacity = capacity; + } + else + { + errorCode = SBG_MALLOC_FAILED; + SBG_LOG_ERROR(errorCode, "unable to allocate buffer"); + } + } + else + { + char *pBuffer; + + pBuffer = realloc(pString->pBuffer, capacity); + + if (pBuffer) + { + pString->pBuffer = pBuffer; + pString->capacity = capacity; + } + else + { + if (capacity < pString->capacity) + { + errorCode = SBG_NO_ERROR; + SBG_LOG_WARNING(SBG_MALLOC_FAILED, "unable to reallocate buffer"); + } + else + { + errorCode = SBG_MALLOC_FAILED; + SBG_LOG_ERROR(errorCode, "unable to reallocate buffer"); + } + } + } + } + } + } + } + + return errorCode; +} + +/*! + * Get a pointer to a character in a string. + * + * \param[in] pString String. + * \param[in] index Index. + * \return Pointer to the character denoted by the index. + */ +static char * sbgStringGetCharPtr(const SbgString *pString, size_t index) +{ + assert(pString); + assert(index < pString->length); + + return &pString->pBuffer[index]; +} + +/*! + * Check if the start and end indexes of a substring are valid. + * + * \param[in] pString String. + * \param[in] startIndex Start index of the substring. + * \param[in] endIndex End index of the substring. + * \return True if these indexes are valid. + */ +static bool sbgStringIndexesAreValid(const SbgString *pString, size_t startIndex, size_t endIndex) +{ + assert(pString); + + return ((startIndex <= endIndex) && (endIndex <= (pString->length))); +} + +/*! + * Assign a buffer of characters to a string. + * + * \param[in] pString String. + * \param[in] pBuffer Buffer. + * \param[in] length Length of the buffer, in bytes. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgStringAssignBuffer(SbgString *pString, const char *pBuffer, size_t length) +{ + assert(pString); + assert(pBuffer); + + if (pString->errorCode == SBG_NO_ERROR) + { + pString->errorCode = sbgStringResizeBuffer(pString, length + 1); + + if (pString->errorCode == SBG_NO_ERROR) + { + memcpy(pString->pBuffer, pBuffer, length) ; + pString->pBuffer[length] = '\0'; + pString->length = length; + } + } + + return pString->errorCode; +} + +/*! + * Remove all spacing characters at the beginning of a string. + * + * This function doesn't resize the string buffer. + * + * \param[in] pString String. + */ +static bool sbgStringTrimLeftCommon(SbgString *pString) +{ + size_t index; + bool trimmed; + + assert(pString); + assert(!pString->readOnly); + + index = pString->length; + + for (size_t i = 0; i < pString->length; i++) + { + char *pCharPtr; + + pCharPtr = sbgStringGetCharPtr(pString, i); + + if (!isspace((unsigned char)*pCharPtr)) + { + index = i; + break; + } + } + + if (index != 0) + { + size_t length; + + length = pString->length - index; + + memmove(pString->pBuffer, &pString->pBuffer[index], length + 1); + pString->length = length; + + trimmed = true; + } + else + { + trimmed = false; + } + + return trimmed; +} + +/*! + * Remove all spacing characters at the end of a string. + * + * This function doesn't resize the string buffer. + * + * \param[in] pString String. + */ +static bool sbgStringTrimRightCommon(SbgString *pString) +{ + size_t index; + bool trimmed; + + assert(pString); + assert(!pString->readOnly); + + index = pString->length; + + for (size_t i = 0; i < pString->length; i++) + { + char *pCharPtr; + + pCharPtr = sbgStringGetCharPtr(pString, pString->length - i - 1); + + if (!isspace((unsigned char)*pCharPtr)) + { + index = i; + break; + } + } + + if (index != 0) + { + size_t length; + + length = pString->length - index; + + pString->pBuffer[length] = '\0'; + pString->length = length; + + trimmed = true; + } + else + { + trimmed = false; + } + + return trimmed; +} + +/*! + * Compare a string to a buffer of characters, ignoring case differences. + * + * \param[in] pString String. + * \param[in] pBuffer Buffer. + * \param[in] length Length of the buffer, in bytes. + * \return The return value is 0 if the string value is equal to the buffer value, + * less than 0 if the string value is less than the buffer value, + * greater than 0 if the string value is greater than the buffer value. + */ +static int32_t sbgStringCompareIgnoreCaseCommon(const SbgString *pString, const char *pBuffer, size_t length) +{ + int32_t result; + size_t minLength; + + assert(pString); + assert(pBuffer); + + result = 0; + + if (length > pString->length) + { + minLength = pString->length; + } + else + { + minLength = length; + } + + for (size_t i = 0; i <= minLength; i++) + { + unsigned char c1; + unsigned char c2; + + c1 = (unsigned char)tolower((unsigned char)pString->pBuffer[i]); + c2 = (unsigned char)tolower((unsigned char)pBuffer[i]); + + if (c1 != c2) + { + result = c1 - c2; + break; + } + } + + return result; +} + +//----------------------------------------------------------------------// +// Public functions // +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API void sbgStringConstructEmpty(SbgString *pString) +{ + assert(pString); + + pString->internalBuffer[0] = '\0'; + + pString->pBuffer = pString->internalBuffer; + pString->capacity = sizeof(pString->internalBuffer); + pString->length = 0; + + pString->readOnly = false; + pString->isStatic = false; + + pString->errorCode = SBG_NO_ERROR; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringConstruct(SbgString *pString, const SbgString *pSourceString) +{ + sbgStringConstructEmpty(pString); + + if (pSourceString) + { + sbgStringAssign(pString, pSourceString); + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringConstructCString(SbgString *pString, const char *pCString) +{ + sbgStringConstructEmpty(pString); + return sbgStringAssignCString(pString, pCString); +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringConstructVF(SbgString *pString, const char *pFormat, va_list args) +{ + sbgStringConstructEmpty(pString); + return sbgStringAssignVF(pString, pFormat, args); +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringConstructF(SbgString *pString, const char *pFormat, ...) +{ + SbgErrorCode errorCode; + va_list args; + + sbgStringConstructEmpty(pString); + + va_start(args, pFormat); + errorCode = sbgStringAssignVF(pString, pFormat, args); + va_end(args); + + return errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringConstructStatic(SbgString *pString, const char *pCString, char *pBuffer, size_t size) +{ + assert(pString); + assert(pBuffer); + + pString->pBuffer = pBuffer; + pString->capacity = size; + + pString->readOnly = false; + pString->isStatic = true; + + pString->errorCode = SBG_NO_ERROR; + + if (pCString) + { + sbgStringAssignCString(pString, pCString); + } + else + { + pString->length = strlen(pBuffer); + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API void sbgStringConstructReadOnly(SbgString *pString, const char *pCString) +{ + assert(pString); + assert(pCString); + + pString->pBuffer = (char *)pCString; + pString->length = strlen(pCString); + pString->capacity = pString->length + 1; + + pString->readOnly = true; + pString->isStatic = true; + + pString->errorCode = SBG_NO_ERROR; +} + +SBG_COMMON_LIB_API void sbgStringDestroy(SbgString *pString) +{ + assert(pString); + + if (!pString->isStatic) + { + if (pString->pBuffer != pString->internalBuffer) + { + free(pString->pBuffer); + } + } +} + +SBG_COMMON_LIB_API int32_t sbgStringCompare(const SbgString *pString, const SbgString *pOtherString) +{ + assert(pString); + assert(pOtherString); + + return (int32_t)strcmp(pString->pBuffer, pOtherString->pBuffer); +} + +SBG_COMMON_LIB_API int32_t sbgStringCompareCString(const SbgString *pString, const char *pCString) +{ + assert(pString); + assert(pCString); + + return (int32_t)strcmp(pString->pBuffer, pCString); +} + +SBG_COMMON_LIB_API int32_t sbgStringCompareIgnoreCase(const SbgString *pString, const SbgString *pOtherString) +{ + assert(pOtherString); + + return sbgStringCompareIgnoreCaseCommon(pString, pOtherString->pBuffer, pOtherString->length); +} + +SBG_COMMON_LIB_API int32_t sbgStringCompareIgnoreCaseCString(const SbgString *pString, const char *pCString) +{ + assert(pCString); + + return sbgStringCompareIgnoreCaseCommon(pString, pCString, strlen(pCString)); +} + +SBG_COMMON_LIB_API size_t sbgStringHash(const SbgString *pString) +{ + size_t hash; + + assert(pString); + + // + // The algorithm is a simple polynomial accumulation : + // s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]. + // + // See java.lang.String.hashCode(). + // + + hash = 0; + + for (size_t i = 0; i < pString->length; i++) + { + char *pCharPtr; + + pCharPtr = sbgStringGetCharPtr(pString, i); + + hash = ((hash << 5) - hash) + *pCharPtr; + } + + return hash; +} + +SBG_COMMON_LIB_API size_t sbgStringGetLength(const SbgString *pString) +{ + assert(pString); + + return pString->length; +} + +SBG_COMMON_LIB_API const char *sbgStringGetCString(const SbgString *pString) +{ + assert(pString); + + return pString->pBuffer; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringCharAt(const SbgString *pString, size_t index, char *pChar) +{ + SbgErrorCode errorCode; + + assert(pString); + assert(pChar); + + if (index < pString->length) + { + char *pCharPtr; + + pCharPtr = sbgStringGetCharPtr(pString, index); + *pChar = *pCharPtr; + + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_INVALID_PARAMETER; + } + + return errorCode; +} + +SBG_COMMON_LIB_API size_t sbgStringFindCString(const SbgString *pString, const char *pCString) +{ + char *pChar; + + assert(pString); + assert(pCString); + + pChar = strstr(pString->pBuffer, pCString); + + if (pChar) + { + return (size_t)(pChar - pString->pBuffer); + } + else + { + return SIZE_MAX; + } +} + +SBG_COMMON_LIB_API size_t sbgStringFind(const SbgString *pString, const SbgString *pOtherString) +{ + assert(pOtherString); + + return sbgStringFindCString(pString, pOtherString->pBuffer); +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringSubstring(const SbgString *pString, size_t startIndex, size_t endIndex, SbgString *pSubstring) +{ + SbgErrorCode errorCode; + + if (sbgStringIndexesAreValid(pString, startIndex, endIndex)) + { + size_t length; + + length = endIndex - startIndex; + + errorCode = sbgStringAssignBuffer(pSubstring, &pString->pBuffer[startIndex], length); + } + else + { + errorCode = SBG_INVALID_PARAMETER; + } + + return errorCode; +} + +SBG_COMMON_LIB_API bool sbgStringStartsWith(const SbgString *pString, const char *pCString) +{ + size_t cStringLength; + bool match; + + assert(pString); + assert(pCString); + + cStringLength = strlen(pCString); + + if (cStringLength <= pString->length) + { + int result; + + result = memcmp(pString->pBuffer, pCString, cStringLength); + + if (result == 0) + { + match = true; + } + else + { + match = false; + } + } + else + { + match = false; + } + + return match; +} + +SBG_COMMON_LIB_API bool sbgStringEndsWith(const SbgString *pString, const char *pCString) +{ + size_t cStringLength; + bool match; + + assert(pString); + assert(pCString); + + cStringLength = strlen(pCString); + + if (cStringLength <= pString->length) + { + size_t endIndex; + int result; + + endIndex = pString->length - cStringLength; + + result = memcmp(&pString->pBuffer[endIndex], pCString, cStringLength); + + if (result == 0) + { + match = true; + } + else + { + match = false; + } + } + else + { + match = false; + } + + return match; +} + +//----------------------------------------------------------------------// +//- Modification methods -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API SbgErrorCode sbgStringGetLastError(const SbgString *pString) +{ + assert(pString); + + return pString->errorCode; +} + +SBG_COMMON_LIB_API void sbgStringClearLastError(SbgString *pString) +{ + assert(pString); + + pString->errorCode = SBG_NO_ERROR; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringSetCharAt(SbgString *pString, size_t index, char c) +{ + SbgErrorCode errorCode; + + assert(pString); + + if ((index < pString->length) && (c != '\0')) + { + char *pCharPtr; + + pCharPtr = sbgStringGetCharPtr(pString, index); + *pCharPtr = c; + + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_INVALID_PARAMETER; + } + + return errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringAppend(SbgString *pString, const SbgString *pAppendString) +{ + assert(pString); + assert(pAppendString); + + if (pString->errorCode == SBG_NO_ERROR) + { + size_t length; + + length = pString->length + pAppendString->length; + + pString->errorCode = sbgStringResizeBuffer(pString, length + 1); + + if (pString->errorCode == SBG_NO_ERROR) + { + memcpy(&pString->pBuffer[pString->length], pAppendString->pBuffer, pAppendString->length + 1); + pString->length = length; + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringAppendCString(SbgString *pString, const char *pCString) +{ + assert(pString); + assert(pCString); + + if (pString->errorCode == SBG_NO_ERROR) + { + size_t cStringLength; + size_t length; + + cStringLength = strlen(pCString); + length = pString->length + cStringLength; + + pString->errorCode = sbgStringResizeBuffer(pString, length + 1); + + if (pString->errorCode == SBG_NO_ERROR) + { + memcpy(&pString->pBuffer[pString->length], pCString, cStringLength + 1); + pString->length = length; + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringAppendVF(SbgString *pString, const char *pFormat, va_list args) +{ + assert(pString); + assert(!pString->readOnly); + assert(pFormat); + + if (pString->errorCode == SBG_NO_ERROR) + { + va_list argsCopy; + int result; + size_t remainingSize; + size_t newLength; + + remainingSize = pString->capacity - pString->length; + + va_copy(argsCopy, args); + result = vsnprintf(&pString->pBuffer[pString->length], remainingSize, pFormat, argsCopy); + assert(result >= 0); + va_end(argsCopy); + + newLength = pString->length + (size_t)result; + + if ((size_t)result < remainingSize) + { + pString->length = newLength; + } + else + { + pString->errorCode = sbgStringResizeBuffer(pString, newLength + 1); + + if (pString->errorCode == SBG_NO_ERROR) + { + remainingSize = pString->capacity - pString->length; + vsnprintf(&pString->pBuffer[pString->length], remainingSize, pFormat, args); + pString->length = newLength; + } + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringAppendF(SbgString *pString, const char *pFormat, ...) +{ + assert(pString); + assert(pFormat); + + if (pString->errorCode == SBG_NO_ERROR) + { + va_list args; + + va_start(args, pFormat); + sbgStringAppendVF(pString, pFormat, args); + va_end(args); + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringAssign(SbgString *pString, const SbgString *pAssignString) +{ + assert(pAssignString); + + return sbgStringAssignBuffer(pString, pAssignString->pBuffer, pAssignString->length); +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringAssignCString(SbgString *pString, const char *pCString) +{ + assert(pCString); + + return sbgStringAssignBuffer(pString, pCString, strlen(pCString)); +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringAssignVF(SbgString *pString, const char *pFormat, va_list args) +{ + assert(pString); + assert(pFormat); + + if (pString->errorCode == SBG_NO_ERROR) + { + va_list argsCopy; + int result; + + va_copy(argsCopy, args); + result = vsnprintf(pString->pBuffer, pString->capacity, pFormat, argsCopy); + assert(result >= 0); + va_end(argsCopy); + + if ((size_t)result < pString->capacity) + { + pString->length = (size_t)result; + } + else + { + pString->errorCode = sbgStringResizeBuffer(pString, (size_t)result + 1); + + if (pString->errorCode == SBG_NO_ERROR) + { + vsnprintf(pString->pBuffer, pString->capacity, pFormat, args); + pString->length = (size_t)result; + } + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringAssignF(SbgString *pString, const char *pFormat, ...) +{ + assert(pString); + assert(pFormat); + + if (pString->errorCode == SBG_NO_ERROR) + { + va_list args; + + va_start(args, pFormat); + sbgStringAssignVF(pString, pFormat, args); + va_end(args); + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringClear(SbgString *pString) +{ + assert(pString); + + if (pString->errorCode == SBG_NO_ERROR) + { + sbgStringAssignCString(pString, ""); + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringToUpperCase(SbgString *pString) +{ + assert(pString); + assert(!pString->readOnly); + + if (pString->errorCode == SBG_NO_ERROR) + { + for (size_t i = 0; i < pString->length; i++) + { + pString->pBuffer[i] = (char)toupper((unsigned char)pString->pBuffer[i]); + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringToLowerCase(SbgString *pString) +{ + assert(pString); + assert(!pString->readOnly); + + if (pString->errorCode == SBG_NO_ERROR) + { + for (size_t i = 0; i < pString->length; i++) + { + pString->pBuffer[i] = (char)tolower((unsigned char)pString->pBuffer[i]); + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringTrimLeft(SbgString *pString) +{ + assert(pString); + + if (pString->errorCode == SBG_NO_ERROR) + { + bool trimmed; + + trimmed = sbgStringTrimLeftCommon(pString); + + if (trimmed) + { + sbgStringResizeBuffer(pString, pString->length + 1); + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringTrimRight(SbgString *pString) +{ + assert(pString); + + if (pString->errorCode == SBG_NO_ERROR) + { + bool trimmed; + + trimmed = sbgStringTrimRightCommon(pString); + + if (trimmed) + { + sbgStringResizeBuffer(pString, pString->length + 1); + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringTrim(SbgString *pString) +{ + assert(pString); + + if (pString->errorCode == SBG_NO_ERROR) + { + bool trimmedLeft; + bool trimmedRight; + + trimmedLeft = sbgStringTrimLeftCommon(pString); + trimmedRight = sbgStringTrimRightCommon(pString); + + if (trimmedLeft || trimmedRight) + { + sbgStringResizeBuffer(pString, pString->length + 1); + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API void sbgStringTruncate(SbgString *pString, size_t length) +{ + assert(pString); + assert(!pString->readOnly); + + if (pString->errorCode == SBG_NO_ERROR) + { + if (length < pString->length) + { + pString->pBuffer[length] = '\0'; + pString->length = length; + + sbgStringResizeBuffer(pString, length + 1); + } + } +} + +//----------------------------------------------------------------------// +//- Conversion methods -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromInt32(SbgString *pString, int32_t value) +{ + assert(pString); + assert(!pString->readOnly); + + if (pString->errorCode == SBG_NO_ERROR) + { + size_t length; + size_t oldCapacity; + int result; + + result = snprintf(pString->pBuffer, pString->capacity, "%" PRId32, value); + + assert(result >= 0); + + length = (size_t)result; + + oldCapacity = pString->capacity; + + pString->errorCode = sbgStringResizeBuffer(pString, length + 1); + + if (pString->errorCode == SBG_NO_ERROR) + { + if (length >= oldCapacity) + { + snprintf(pString->pBuffer, pString->capacity, "%" PRId32, value); + } + + pString->length = (size_t)length; + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringToInt32(const SbgString *pString, int32_t *pValue) +{ + SbgErrorCode errorCode; + int result; + int32_t value; + + assert(pString); + + result = sscanf(pString->pBuffer, "%" SCNd32, &value); + + if (result == 1) + { + *pValue = value; + + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_ERROR; + } + + return errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromUint32(SbgString *pString, uint32_t value) +{ + assert(pString); + assert(!pString->readOnly); + + if (pString->errorCode == SBG_NO_ERROR) + { + size_t length; + size_t oldCapacity; + int result; + + result = snprintf(pString->pBuffer, pString->capacity, "%" PRIu32, value); + + assert(result >= 0); + + length = (size_t)result; + + oldCapacity = pString->capacity; + + pString->errorCode = sbgStringResizeBuffer(pString, length + 1); + + if (pString->errorCode == SBG_NO_ERROR) + { + if (length >= oldCapacity) + { + snprintf(pString->pBuffer, pString->capacity, "%" PRIu32, value); + } + + pString->length = (size_t)length; + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringToUint32(const SbgString *pString, uint32_t *pValue) +{ + SbgErrorCode errorCode; + int result; + uint32_t value; + + assert(pString); + + result = sscanf(pString->pBuffer, "%" SCNu32, &value); + + if (result == 1) + { + *pValue = value; + + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_ERROR; + } + + return errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromInt64(SbgString *pString, int64_t value) +{ + assert(pString); + assert(!pString->readOnly); + + if (pString->errorCode == SBG_NO_ERROR) + { + size_t length; + size_t oldCapacity; + int result; + + result = snprintf(pString->pBuffer, pString->capacity, "%" PRId64, value); + + assert(result >= 0); + + length = (size_t)result; + + oldCapacity = pString->capacity; + + pString->errorCode = sbgStringResizeBuffer(pString, length + 1); + + if (pString->errorCode == SBG_NO_ERROR) + { + if (length >= oldCapacity) + { + snprintf(pString->pBuffer, pString->capacity, "%" PRId64, value); + } + + pString->length = (size_t)length; + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringToInt64(const SbgString *pString, int64_t *pValue) +{ + SbgErrorCode errorCode; + int result; + int64_t value; + + assert(pString); + + result = sscanf(pString->pBuffer, "%" SCNd64, &value); + + if (result == 1) + { + *pValue = value; + + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_ERROR; + } + + return errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromUint64(SbgString *pString, uint64_t value) +{ + assert(pString); + assert(!pString->readOnly); + + if (pString->errorCode == SBG_NO_ERROR) + { + size_t length; + size_t oldCapacity; + int result; + + result = snprintf(pString->pBuffer, pString->capacity, "%" PRIu64, value); + + assert(result >= 0); + + length = (size_t)result; + + oldCapacity = pString->capacity; + + pString->errorCode = sbgStringResizeBuffer(pString, length + 1); + + if (pString->errorCode == SBG_NO_ERROR) + { + if (length >= oldCapacity) + { + snprintf(pString->pBuffer, pString->capacity, "%" PRIu64, value); + } + + pString->length = (size_t)length; + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringToUint64(const SbgString *pString, uint64_t *pValue) +{ + SbgErrorCode errorCode; + int result; + uint64_t value; + + assert(pString); + + result = sscanf(pString->pBuffer, "%" SCNu64, &value); + + if (result == 1) + { + *pValue = value; + + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_ERROR; + } + + return errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromDouble(SbgString *pString, double value) +{ + assert(pString); + assert(!pString->readOnly); + + if (pString->errorCode == SBG_NO_ERROR) + { + size_t length; + size_t oldCapacity; + int result; + + result = snprintf(pString->pBuffer, pString->capacity, "%lf", value); + + assert(result >= 0); + + length = (size_t)result; + + oldCapacity = pString->capacity; + + pString->errorCode = sbgStringResizeBuffer(pString, length + 1); + + if (pString->errorCode == SBG_NO_ERROR) + { + if (length >= oldCapacity) + { + snprintf(pString->pBuffer, pString->capacity, "%lf", value); + } + + pString->length = (size_t)length; + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringToDouble(const SbgString *pString, double *pValue) +{ + SbgErrorCode errorCode; + int result; + double value; + + assert(pString); + + result = sscanf(pString->pBuffer, "%lf", &value); + + if (result == 1) + { + *pValue = value; + + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_ERROR; + } + + return errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromStreamBuffer(SbgString *pString, SbgStreamBuffer *pStream) +{ + assert(pString); + + if (pString->errorCode == SBG_NO_ERROR) + { + size_t size; + + size = sbgStreamBufferReadSizeT32(pStream); + + pString->errorCode = sbgStreamBufferGetLastError(pStream); + + if (pString->errorCode == SBG_NO_ERROR) + { + pString->errorCode = sbgStringResizeBuffer(pString, size); + + if (pString->errorCode == SBG_NO_ERROR) + { + pString->errorCode = sbgStreamBufferReadBuffer(pStream, pString->pBuffer, size); + + if (pString->errorCode == SBG_NO_ERROR) + { + pString->length = size - 1; + } + } + } + } + + return pString->errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringToStreamBuffer(const SbgString *pString, SbgStreamBuffer *pStream) +{ + SbgErrorCode errorCode; + + assert(pString); + + errorCode = sbgStreamBufferWriteSizeT32(pStream, pString->length + 1); + + if (errorCode == SBG_NO_ERROR) + { + errorCode = sbgStreamBufferWriteBuffer(pStream, pString->pBuffer, pString->length + 1); + } + + return errorCode; +} + +//----------------------------------------------------------------------// +//- Iterator methods -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API void sbgStringIteratorConstruct(SbgStringIterator *pIterator, const SbgString *pString) +{ + assert(pString); + assert(pIterator); + + pIterator->pCursor = pString->pBuffer; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgStringIteratorWalk(SbgStringIterator *pIterator, const char *pSeparators, bool skipEmptyTokens, SbgString *pToken) +{ + SbgErrorCode errorCode; + + assert(pIterator); + assert(pSeparators); + assert(pToken); + + if (pIterator->pCursor) + { + size_t length; + char *pSeparator; + char *pNext; + + pSeparator = strpbrk(pIterator->pCursor, pSeparators); + + if (pSeparator) + { + length = pSeparator - pIterator->pCursor; + + if (skipEmptyTokens) + { + size_t nrSeparators; + + nrSeparators = strspn(pSeparator, pSeparators); + pNext = &pSeparator[nrSeparators]; + } + else + { + pNext = &pSeparator[1]; + } + } + else + { + length = strlen(pIterator->pCursor); + pNext = NULL; + } + + errorCode = sbgStringAssignBuffer(pToken, pIterator->pCursor, length); + + if (errorCode == SBG_NO_ERROR) + { + pIterator->pCursor = pNext; + } + } + else + { + errorCode = SBG_NOT_READY; + } + + return errorCode; +} + +//----------------------------------------------------------------------// +//- Legacy functions -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API SbgErrorCode sbgStringCopy(char *pDestination, const char *pSource, size_t destMaxSize) +{ + size_t srcLength; + + // + // Check input arguments + // + assert(pDestination); + assert(pSource); + assert(destMaxSize > 0); + + // + // Get the source string length and add the NULL char + // + srcLength = strlen(pSource) + sizeof(char); + + // + // Make sure the string fits in the provided buffer + // + if (srcLength <= destMaxSize) + { + // + // We can use safely strcpy + // + strcpy(pDestination, pSource); + + return SBG_NO_ERROR; + } + else + { + // + // The destination buffer isn't big enough to hold the provided source string + // Don't forget to save one byte for the NULL terminated char + // + strncpy(pDestination, pSource, destMaxSize-sizeof(char)); + + // + // Append the NULL terminating char + // + pDestination[destMaxSize-1] = '\0'; + + // + // We have a buffer overflow + // + return SBG_BUFFER_OVERFLOW; + } + +} + +SBG_COMMON_LIB_API const char *sbgStringFirstValidChar(const char *pInputStr) +{ + const char *pCurrentStr = pInputStr; + + assert(pInputStr); + + // + // Skip any space or tab chars from the beginning of the string + // + while ((*pCurrentStr != '\0') && isspace((unsigned char)*pCurrentStr) ) + { + pCurrentStr += sizeof(char); + } + + return pCurrentStr; +} diff --git a/crates/sbg-rs/sbgECom/common/string/sbgString.h b/crates/sbg-rs/sbgECom/common/string/sbgString.h new file mode 100644 index 0000000..3810ed1 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/string/sbgString.h @@ -0,0 +1,697 @@ +/*! + * \file sbgString.h + * \ingroup common + * \author SBG Systems + * \date March 20, 2020 + * + * \brief Character string. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_STRING_H +#define SBG_STRING_H + +// sbgCommonLib headers +#include +#include + +//----------------------------------------------------------------------// +//- Header (open extern C block) -// +//----------------------------------------------------------------------// + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +/*! + * Minimum size of the internal buffer, in bytes. + * + * This constant must be strictly positive in order to guarantee that no errors can occur + * during the construction of an empty string. + */ +#define SBG_STRING_INTERNAL_BUFFER_MIN_SIZE (4) + +#if SBG_STRING_INTERNAL_BUFFER_MIN_SIZE == 0 +#error "invalid minimum internal buffer size" +#endif + +/*! + * Default size of the internal buffer, in bytes. + */ +#define SBG_STRING_INTERNAL_BUFFER_DEFAULT_SIZE (16) + +#ifndef SBG_CONFIG_STRING_INTERNAL_BUFFER_SIZE +#define SBG_CONFIG_STRING_INTERNAL_BUFFER_SIZE SBG_STRING_INTERNAL_BUFFER_DEFAULT_SIZE +#elif SBG_CONFIG_STRING_INTERNAL_BUFFER_SIZE < SBG_STRING_INTERNAL_BUFFER_MIN_SIZE +#error "invalid internal buffer size" +#endif // SBG_CONFIG_STRING_INTERNAL_BUFFER_SIZE + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * String. + * + * The buffer contains a C null-terminated string. The null-terminating character is not + * considered to be part of the string content. + * + * Attempts to modify a read-only string lead to undefined behavior. + * + * Attempts to modify a string while the last modification operation error is set are canceled + * and return the last error code. + */ +typedef struct _SbgString +{ + /*! + * Internal buffer. + * + * The internal buffer is used for small strings to avoid dynamic allocation. + */ + char internalBuffer[SBG_CONFIG_STRING_INTERNAL_BUFFER_SIZE]; + + char *pBuffer; /*!< Buffer. */ + size_t capacity; /*!< Capacity of the buffer, in bytes. */ + size_t length; /*!< Length of the string (not including the terminating null character), in bytes. */ + + bool readOnly; /*!< True if the string is read-only. */ + bool isStatic; /*!< True if the buffer is statically allocated. */ + + SbgErrorCode errorCode; /*!< Error code of the last modification operation. */ +} SbgString; + +/*! + * String iterator. + */ +typedef struct _SbgStringIterator +{ + const char *pCursor; /*!< Cursor. */ +} SbgStringIterator; + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +/*! + * String constructor. + * + * The rationale for this constructor is to guarantee that no errors may occur on the + * construction of empty strings. + * + * \param[in] pString String. + */ +SBG_COMMON_LIB_API void sbgStringConstructEmpty(SbgString *pString); + +/*! + * String constructor. + * + * The string content is initialized from the given source string. If that string is NULL, + * the string is initialized with an empty content. + * + * \param[in] pString String. + * \param[in] pSourceString Source string, may be NULL. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringConstruct(SbgString *pString, const SbgString *pSourceString); + +/*! + * String constructor. + * + * The string content is initialized from the given C null-terminated string. + * + * \param[in] pString String. + * \param[in] pCString C null-terminated string. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringConstructCString(SbgString *pString, const char *pCString); + +/*! + * String constructor. + * + * The string content is initialized from formatted data from a variable argument list. + * + * \param[in] pString String. + * \param[in] pFormat Format. + * \param[in] args Variable argument list. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringConstructVF(SbgString *pString, const char *pFormat, va_list args) SBG_CHECK_FORMAT(printf, 2, 0); + +/*! + * String constructor. + * + * The string content is initialized from formatted data. + * + * \param[in] pString String. + * \param[in] pFormat Format. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringConstructF(SbgString *pString, const char *pFormat, ...) SBG_CHECK_FORMAT(printf, 2, 3); + +/*! + * String constructor. + * + * The string content is initialized from the given C null-terminated string. + * + * If the C null-terminated string is NULL then the string contains the content of the given + * buffer before construction. In this case the content of the given buffer must be a C + * null-terminated string. + * + * The given buffer is owned by the string and must not be modified while the string is in use. + * After destroying the string, the buffer contains the content of the string immediately before + * destruction. + * + * \param[in] pString String. + * \param[in] pCString C null-terminated string, may be NULL. + * \param[in] pBuffer Buffer. + * \param[in] size Buffer size, in bytes. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringConstructStatic(SbgString *pString, const char *pCString, char *pBuffer, size_t size); + +/*! + * String constructor. + * + * The string cannot be modified. + * + * The given C null-terminated string provides both the statically allocated buffer + * for the string, as well as its content. It is owned by the string and must not be modified. + * + * \param[in] pString String. + * \param[in] pCString C null-terminated string. + */ +SBG_COMMON_LIB_API void sbgStringConstructReadOnly(SbgString *pString, const char *pCString); + +/*! + * String destructor. + * + * \param[in] pString String. + */ +SBG_COMMON_LIB_API void sbgStringDestroy(SbgString *pString); + +/*! + * Compare a string to another string. + * + * \param[in] pString String. + * \param[in] pOtherString Other string. + * \return The return value is 0 if both strings are equal, + * less than 0 if the string value is less than the other string value, + * greater than 0 if the string value is greater than the other string value. + */ +SBG_COMMON_LIB_API int32_t sbgStringCompare(const SbgString *pString, const SbgString *pOtherString); + +/*! + * Compare a string to a C null-terminated string. + * + * \param[in] pString String. + * \param[in] pCString C null-terminated string. + * \return The return value is 0 if the string is equal to the C null-terminated string, + * less than 0 if the string value is less than the C null-terminated string value, + * greater than 0 if the string value is greater than the C null-terminated string value. + */ +SBG_COMMON_LIB_API int32_t sbgStringCompareCString(const SbgString *pString, const char *pCString); + +/*! + * Compare a string to another string, ignoring case differences. + * + * \param[in] pString String. + * \param[in] pOtherString Other string. + * \return The return value is 0 if both strings are equal, + * less than 0 if the string value is less than the other string value, + * greater than 0 if the string value is greater than the other string value. + */ +SBG_COMMON_LIB_API int32_t sbgStringCompareIgnoreCase(const SbgString *pString, const SbgString *pOtherString); + +/*! + * Compare a string to a C null-terminated string, ignoring case differences. + * + * \param[in] pString String. + * \param[in] pCString C null-terminated string. + * \return The return value is 0 if the string is equal to the C null-terminated string, + * less than 0 if the string value is less than the C null-terminated string value, + * greater than 0 if the string value is greater than the C null-terminated string value. + */ +SBG_COMMON_LIB_API int32_t sbgStringCompareIgnoreCaseCString(const SbgString *pString, const char *pCString); + +/*! + * Compute the hash value of a string. + * + * \param[in] pString String. + * \return Hash value. + */ +SBG_COMMON_LIB_API size_t sbgStringHash(const SbgString *pString); + +/*! + * Get the length of a string (not including the terminating null character), in bytes. + * + * \param[in] pString String. + * \return Length, in bytes. + */ +SBG_COMMON_LIB_API size_t sbgStringGetLength(const SbgString *pString); + +/*! + * Get a C null-terminated string version of a string. + * + * \param[in] pString String. + * \return C null-terminated string. + */ +SBG_COMMON_LIB_API const char *sbgStringGetCString(const SbgString *pString); + +/*! + * Get a character in a string. + * + * \param[in] pString String. + * \param[in] index Index. + * \param[out] pChar Character. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringCharAt(const SbgString *pString, size_t index, char *pChar); + +/*! + * Get the index of the first occurrence of a string in a string. + * + * \param[in] pString String. + * \param[in] pStringToFind String to find. + * \return Index of the first occurrence or SIZE_MAX if not found. + */ +SBG_COMMON_LIB_API size_t sbgStringFind(const SbgString *pString, const SbgString *pStringToFind); + +/*! + * Get the index of the first occurrence of the given C null-terminated string in a string. + * + * \param[in] pString String. + * \param[in] pCString C null-terminated string. + * \return Index of the first occurrence or SIZE_MAX if not found. + */ +SBG_COMMON_LIB_API size_t sbgStringFindCString(const SbgString *pString, const char *pCString); + +/*! + * Get a substring from a string. + * + * The substring must be constructed before calling this function. If an error occurs, the last error + * of the substring is set by this function. + * + * \param[in] pString String. + * \param[in] startIndex Start index. + * \param[in] endIndex End index. + * \param[out] pSubstring Substring. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringSubstring(const SbgString *pString, size_t startIndex, size_t endIndex, SbgString *pSubstring); + +/*! + * Check if a C null-terminated string is at the beginning of a string. + * + * \param[in] pString String. + * \param[in] pCString C null-terminated string. + * \return True if the C null-terminated string is at the beginning. + */ +SBG_COMMON_LIB_API bool sbgStringStartsWith(const SbgString *pString, const char *pCString); + +/*! + * Check if a C null-terminated string is at the end of a string. + * + * \param[in] pString String. + * \param[in] pCString C null-terminated string. + * \return True if the C null-terminated string is at the end. +*/ +SBG_COMMON_LIB_API bool sbgStringEndsWith(const SbgString *pString, const char *pCString); + +//----------------------------------------------------------------------// +//- Modification methods -// +//----------------------------------------------------------------------// + +/*! + * Get the last error of a modification operation on a string. + * + * \param[in] pString String. + * \return Last modification error. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringGetLastError(const SbgString *pString); + +/*! + * Clear the last modification operation error of a string. + * + * \param[in] pString String. + */ +SBG_COMMON_LIB_API void sbgStringClearLastError(SbgString *pString); + +/*! + * Set a character in a string. + * + * The given index must be strictly lower than the string length. The given character + * must not be a null character. + * + * \param[in] pString String. + * \param[in] index Index. + * \param[in] c Character. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringSetCharAt(SbgString *pString, size_t index, char c); + +/*! + * Append a string to another string. + * + * \param[in] pString String. + * \param[in] pAppendString String to append. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringAppend(SbgString *pString, const SbgString *pAppendString); + +/*! + * Append a C null-terminated string to a string. + * + * \param[in] pString String. + * \param[in] pCString C null-terminated string. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringAppendCString(SbgString *pString, const char *pCString); + +/*! + * Append formatted data from a variable argument list to a string. + * + * The string format, as well as the variable argument list, are the same as for vprintf. + * + * \param[in] pString String. + * \param[in] pFormat Format. + * \param[in] args Variable argument list. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringAppendVF(SbgString *pString, const char *pFormat, va_list args) SBG_CHECK_FORMAT(printf, 2, 0); + +/*! + * Append formatted data to a string. + * + * The string format, as well as the variable arguments, are the same as for printf. + * + * \param[in] pString String. + * \param[in] pFormat Format. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringAppendF(SbgString *pString, const char *pFormat, ...) SBG_CHECK_FORMAT(printf, 2, 3); + +/*! + * Assign a string to another string. + * + * \param[in] pString String. + * \param[in] pAssignString String to assign. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringAssign(SbgString *pString, const SbgString *pAssignString); + +/*! + * Assign a C null-terminated string to a string. + * + * \param[in] pString String. + * \param[in] pCString C null-terminated string. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringAssignCString(SbgString *pString, const char *pCString); + +/*! + * Assign formatted data from a variable argument list to a string. + * + * The string format, as well as the variable argument list, are the same as for vprintf. + * + * \param[in] pString String. + * \param[in] pFormat Format. + * \param[in] args Variable argument list. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringAssignVF(SbgString *pString, const char *pFormat, va_list args) SBG_CHECK_FORMAT(printf, 2, 0); + +/*! + * Assign formatted data to a string. + * + * The string format, as well as the variable arguments, are the same as for printf. + * + * \param[in] pString String. + * \param[in] pFormat Format. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringAssignF(SbgString *pString, const char *pFormat, ...) SBG_CHECK_FORMAT(printf, 2, 3); + +/*! + * Clear a string. + * + * After returning from this call the string is empty. + * + * \param[in] pString String. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringClear(SbgString *pString); + +/*! + * Convert all the characters of a string to upper case. + * + * \param[in] pString String. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringToUpperCase(SbgString *pString); + +/*! + * Convert all the characters of a string to lower case. + * + * \param[in] pString String. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringToLowerCase(SbgString *pString); + +/*! + * Remove all spacing characters at the beginning of a string. + * + * \param[in] pString String. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringTrimLeft(SbgString *pString); + +/*! + * Remove all spacing characters at the end of a string. + * + * \param[in] pString String. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringTrimRight(SbgString *pString); + +/*! + * Remove all spacing characters at the beginning and the end of a string. + * + * \param[in] pString String. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringTrim(SbgString *pString); + +/*! + * Truncate a string. + * + * If the given length is greater than or equal to the length of the string, + * this function doesn't modify the string. + * + * \param[in] pString String. + * \param[in] length Length, in bytes. + */ +SBG_COMMON_LIB_API void sbgStringTruncate(SbgString *pString, size_t length); + +//----------------------------------------------------------------------// +//- Conversion methods -// +//----------------------------------------------------------------------// + +/*! + * Convert and assign a 32-bits signed integer value to a string. + * + * \param[in] pString String. + * \param[in] value Value. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromInt32(SbgString *pString, int32_t value); + +/*! + * Convert a string to a 32-bits signed integer value. + * + * \param[in] pString String. + * \param[out] pValue Value. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringToInt32(const SbgString *pString, int32_t *pValue); + +/*! + * Convert and assign a 32-bits unsigned integer value to a string. + * + * \param[in] pString String. + * \param[in] value Value + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromUint32(SbgString *pString, uint32_t value); + +/*! + * Convert a string to a 32-bits unsigned integer value. + * + * \param[in] pString String. + * \param[out] pValue Value. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringToUint32(const SbgString *pString, uint32_t *pValue); + +/*! + * Convert and assign a 64-bits signed integer value to a string. + * + * \param[in] pString String. + * \param[in] value Value. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromInt64(SbgString *pString, int64_t value); + +/*! + * Convert a string to a 64-bits signed integer value. + * + * \param[in] pString String. + * \param[out] pValue Value. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringToInt64(const SbgString *pString, int64_t *pValue); + +/*! + * Convert and assign a 64-bits unsigned integer value to a string. + * + * \param[in] pString String. + * \param[in] value Value + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromUint64(SbgString *pString, uint64_t value); + +/*! + * Convert a string to a 64-bits unsigned integer value. + * + * \param[in] pString String. + * \param[out] pValue Value. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringToUint64(const SbgString *pString, uint64_t *pValue); + +/*! + * Convert and assign a double value to a string. + * + * \param[in] pString String. + * \param[in] value Value. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromDouble(SbgString *pString, double value); + +/*! + * Convert a string to a double value. + * + * \param[in] pString String. + * \param[out] pValue Value. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringToDouble(const SbgString *pString, double *pValue); + +/*! + * Read a string from a stream buffer. + * + * \param[in] pString String. + * \param[in] pStream Stream buffer. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringFromStreamBuffer(SbgString *pString, SbgStreamBuffer *pStream); + +/*! + * Write a string to a stream buffer. + * + * \param[in] pString String. + * \param[out] pStream Stream buffer. + * \return SBG_NO_ERROR if successful. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringToStreamBuffer(const SbgString *pString, SbgStreamBuffer *pStream); + +//----------------------------------------------------------------------// +//- Iterator methods -// +//----------------------------------------------------------------------// + +/*! + * String iterator constructor. + * + * If the given string is modified while the iterator is used, the behavior is undefined. + * + * \param[in] pIterator String iterator. + * \param[in] pString String. + */ +SBG_COMMON_LIB_API void sbgStringIteratorConstruct(SbgStringIterator *pIterator, const SbgString *pString); + +/*! + * Walk to the next token of a string. + * + * The token string must be constructed before calling this function. If an error occurs, the last error + * of the token string is set by this function. + * + * \param[in] pIterator String iterator. + * \param[in] pSeparators C null-terminated string containing separator characters. + * \param[in] skipEmptyTokens If true, empty tokens are skipped. + * \param[out] pToken Token. + * \return SBG_NO_ERROR if successful, + * SBG_NOT_READY if there are no more tokens. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringIteratorWalk(SbgStringIterator *pIterator, const char *pSeparators, bool skipEmptyTokens, SbgString *pToken); + +//----------------------------------------------------------------------// +//- Legacy functions -// +//----------------------------------------------------------------------// + +/*! + * Safely copy source string to destination according to destination provided buffer size. + * + * This method tends to replace strncpy where you would like to safely copy a string with buffer overflow checking. + * If the provided output buffer is too small, the method will return a valid NULL terminated C string in destination. + * This condition will be returned using SBG_BUFFER_OVERFLOW error code. + * + * \param[out] pDestination The destination string that should hold the copied input string. + * \param[in] pSource The source NULL terminated C string to copy to the destination. + * \param[in] destMaxSize The destination buffer size including the null terminating char. + * \return SBG_NO_ERROR if the source string has been copied to destination + * SBG_BUFFER_OVERFLOW if the destination is too small to hold the source string. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgStringCopy(char *pDestination, const char *pSource, size_t destMaxSize); + +/*! + * Skip all spacing characters from the beginning of a string. + * + * \param[in] pInputStr Pointer on a read only string to trim. + * \return Pointer to the first useful char. + */ +SBG_COMMON_LIB_API const char *sbgStringFirstValidChar(const char *pInputStr); + +//----------------------------------------------------------------------// +//- Footer (close extern C block) -// +//----------------------------------------------------------------------// + +#ifdef __cplusplus +} +#endif + +#endif // SBG_STRING_H diff --git a/crates/sbg-rs/sbgECom/common/swap/sbgSwap.c b/crates/sbg-rs/sbgECom/common/swap/sbgSwap.c new file mode 100644 index 0000000..2ebbd5c --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/swap/sbgSwap.c @@ -0,0 +1 @@ +#include "sbgSwap.h" diff --git a/crates/sbg-rs/sbgECom/common/swap/sbgSwap.h b/crates/sbg-rs/sbgECom/common/swap/sbgSwap.h new file mode 100644 index 0000000..25d2430 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/swap/sbgSwap.h @@ -0,0 +1,144 @@ +/*! + * \file sbgSwap.h + * \ingroup common + * \author SBG Systems + * \date 14 January 2013 + * + * \brief Set of functions used to swap numbers. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_SWAP_H +#define SBG_SWAP_H + +//----------------------------------------------------------------------// +//- Header (open extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +extern "C" { +#endif + +#include + +//----------------------------------------------------------------------// +//- Internal swap functions -// +//----------------------------------------------------------------------// + +/*! + * Swap a uint16_t number. + * \param[in] x The uint16_t to swap. + * \return The swapped value. + */ +SBG_INLINE uint16_t sbgSwap16(uint16_t x) +{ + return ((x<<8)|(x>>8)); +} + +/*! + * Swap a uint32_t number. + * \param[in] x The uint32_t to swap. + * \return The swapped value. + */ +SBG_INLINE uint32_t sbgSwap32(uint32_t x) +{ + return ((x << 24) | ((x << 8) & (0xFF0000)) | ((x >> 8) & (0xFF00)) | (x >> 24)); +} + +/*! + * Swap a uint64_t number. + * \param[in] x The uint64_t to swap. + * \return The swapped value. + */ +SBG_INLINE uint64_t sbgSwap64(uint64_t x) +{ + uint32_t hi, lo; + + // + // Separate into high and low 32-bit values + // + lo = (uint32_t)(x&0xFFFFFFFF); + x >>= 32; + hi = (uint32_t)(x&0xFFFFFFFF); + + // + // Swap each part and rebuild our 64 bit vale + // + x = sbgSwap32(lo); + x <<= 32; + x |= sbgSwap32(hi); + + return x; +} + +/*! + * Swap a float number. + * \param[in] val The float to swap. + * \return The swapped value. + */ +SBG_INLINE float sbgSwapFloat(float val) +{ + FloatNint tmpFloat; + + // + // We use a union to do the type punning + // + tmpFloat.valF = val; + tmpFloat.valU = sbgSwap32(tmpFloat.valU); + + // + // Return the swapped float + // + return tmpFloat.valF; +} + +/*! + * Swap a double number. + * \param[in] val The double to swap. + * \return The swapped value. + */ +SBG_INLINE double sbgSwapDouble(double val) +{ + DoubleNint tmpDouble; + + // + // We use a union to do the type punning + // + tmpDouble.valF = val; + tmpDouble.valU = sbgSwap64(tmpDouble.valU); + + // + // Return the swapped double + // + return tmpDouble.valF; +} + +//----------------------------------------------------------------------// +//- Footer (close extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +} +#endif + +#endif /* SBG_SWAP_H */ diff --git a/crates/sbg-rs/sbgECom/common/version/sbgVersion.c b/crates/sbg-rs/sbgECom/common/version/sbgVersion.c new file mode 100644 index 0000000..a24c339 --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/version/sbgVersion.c @@ -0,0 +1,561 @@ +// Project headers +#include + + +// Local headers +#include "sbgVersion.h" + +//----------------------------------------------------------------------// +//- Constructor -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API void sbgVersionCreateBasic(SbgVersion *pVersion, uint8_t major, uint8_t minor, uint8_t revision, uint8_t build) +{ + assert(pVersion); + assert(major < 128); + + pVersion->softwareScheme = false; + + pVersion->major = major; + pVersion->minor = minor; + pVersion->rev = revision; + pVersion->build = build; + + pVersion->qualifier = SBG_VERSION_QUALIFIER_DEV; +} + +SBG_COMMON_LIB_API void sbgVersionCreateSoftware(SbgVersion *pVersion, uint8_t major, uint8_t minor, uint16_t build, SbgVersionQualifier qualifier) +{ + assert(pVersion); + assert(major < 64); + assert(minor < 64); + + pVersion->softwareScheme = true; + + pVersion->major = major; + pVersion->minor = minor; + pVersion->build = build; + pVersion->qualifier = qualifier; + + pVersion->rev = 0; +} + +SBG_COMMON_LIB_API void sbgVersionConstructCopy(SbgVersion *pVersion, const SbgVersion *pOtherVersion) +{ + assert(pVersion); + assert(pOtherVersion); + + // + // Copy each member individually to avoid warnings about reading uninitialized bytes. + // + pVersion->softwareScheme = pOtherVersion->softwareScheme; + pVersion->qualifier = pOtherVersion->qualifier; + pVersion->major = pOtherVersion->major; + pVersion->minor = pOtherVersion->minor; + pVersion->rev = pOtherVersion->rev; + pVersion->build = pOtherVersion->build; +} + +//----------------------------------------------------------------------// +//- Version encoding / decoding methods -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API void sbgVersionDecode(uint32_t encodedVersion, SbgVersion *pVersionInfo) +{ + assert(pVersionInfo); + + // + // Test if we have a software version scheme + // + if (encodedVersion&SBG_VERSION_SOFT_SCHEME) + { + // + // We have a software scheme, decode it + // + pVersionInfo->softwareScheme = true; + + // + // Decode the software scheme fields + // + pVersionInfo->qualifier = (SbgVersionQualifier)((encodedVersion >> SBG_VERSION_SOFT_SCHEME_QUALIFIER_SHIFT) & SBG_VERSION_SOFT_SCHEME_QUALIFIER_MASK); + pVersionInfo->major = (encodedVersion >> SBG_VERSION_SOFT_SCHEME_MAJOR_SHIFT) & SBG_VERSION_SOFT_SCHEME_MAJOR_MASK; + pVersionInfo->minor = (encodedVersion >> SBG_VERSION_SOFT_SCHEME_MINOR_SHIFT) & SBG_VERSION_SOFT_SCHEME_MINOR_MASK; + pVersionInfo->build = (encodedVersion >> SBG_VERSION_SOFT_SCHEME_BUILD_SHIFT) & SBG_VERSION_SOFT_SCHEME_BUILD_MASK; + + // + // Set the revision to zero as it's not used + // + pVersionInfo->rev = 0; + } + else + { + // + // We have a basic scheme, decode it + // + pVersionInfo->softwareScheme = false; + + // + // Decode the software scheme fields + // + pVersionInfo->major = (encodedVersion >> 24) & 0xFF; + pVersionInfo->minor = (encodedVersion >> 16) & 0xFF; + pVersionInfo->rev = (encodedVersion >> 8) & 0xFF; + pVersionInfo->build = (encodedVersion >> 0) & 0xFF; + + // + // Set the qualifier to zero + // + pVersionInfo->qualifier = SBG_VERSION_QUALIFIER_DEV; + } +} + +SBG_COMMON_LIB_API uint32_t sbgVersionEncode(const SbgVersion *pVersionInfo) +{ + uint32_t encodedVersion = 0; + + assert(pVersionInfo); + + // + // Test if we have a software scheme or a basic one + // + if (pVersionInfo->softwareScheme) + { + // + // We have a software, scheme, so test that the version is valid + // + assert((pVersionInfo->major <= 63) && (pVersionInfo->minor <= 63) && (pVersionInfo->rev == 0)); + + // + // Indicate that we have a software version scheme + // + encodedVersion = SBG_VERSION_SOFTWARE(pVersionInfo->major, pVersionInfo->minor, pVersionInfo->build, pVersionInfo->qualifier); + } + else + { + // + // We have a basic version scheme so check parameter validity + // + assert(pVersionInfo->major <= 127); + + // + // Encode the basic version information + // + encodedVersion = SBG_VERSION_BASIC(pVersionInfo->major, pVersionInfo->minor, pVersionInfo->rev, pVersionInfo->build); + } + + return encodedVersion; +} + +//----------------------------------------------------------------------// +//- Version comparaison methods -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API int32_t sbgVersionCompare(const SbgVersion *pVersionA, const SbgVersion *pVersionB, SbgVersionCmpThreshold threshold) +{ + int32_t result; + + assert(pVersionA); + assert(pVersionB); + + // + // Check that the two versions are using the same scheme + // + assert(pVersionA->softwareScheme == pVersionB->softwareScheme); + + // + // Do the comparaison according to the selected threshold + // Start by compairing the major field + // + result = pVersionA->major - pVersionB->major; + + // + // Test if we have to also compare the minor field + // + if ( (result == 0) && ((threshold == SBG_VERSION_CMP_THRESHOLD_MINOR) || (threshold == SBG_VERSION_CMP_THRESHOLD_REVISION) || (threshold == SBG_VERSION_CMP_THRESHOLD_BUILD) || (threshold == SBG_VERSION_CMP_THRESHOLD_QUALIFIER)) ) + { + // + // Update the result using the minor indication + // + result = pVersionA->minor - pVersionB->minor; + + // + // Test if we have to also compare the revision field (for basic version only) + // + if ( (result == 0) && ((threshold == SBG_VERSION_CMP_THRESHOLD_REVISION) || (threshold == SBG_VERSION_CMP_THRESHOLD_BUILD) || (threshold == SBG_VERSION_CMP_THRESHOLD_QUALIFIER)) ) + { + // + // Test if we have a software scheme or a basic scheme version + // + if (pVersionA->softwareScheme) + { + // + // We have a software scheme so set the result to 0 + // + result = 0; + } + else + { + // + // We have a basic scheme so we can compare the revision field + // + result = pVersionA->rev - pVersionB->rev; + } + + // + // Test if we have to also compare the build field + // + if ( (result == 0) && ((threshold == SBG_VERSION_CMP_THRESHOLD_BUILD) || (threshold == SBG_VERSION_CMP_THRESHOLD_QUALIFIER)) ) + { + // + // Compare the build field + // + result = pVersionA->build - pVersionB->build; + + // + // Test if we have to also compare the qualifier field + // + if ( (result == 0) && (threshold == SBG_VERSION_CMP_THRESHOLD_QUALIFIER) ) + { + // + // Test if we have a software scheme + // + if (pVersionA->softwareScheme) + { + // + // We have a software scheme so set the result to 0 + // + result = pVersionA->qualifier - pVersionB->qualifier; + } + else + { + // + // We have a basic scheme so set the result to 0 + // + result = 0; + } + } + } + } + } + + return result; +} + +SBG_COMMON_LIB_API int32_t sbgVersionCompareEncoded(uint32_t versionA, uint32_t versionB, SbgVersionCmpThreshold threshold) +{ + SbgVersion versionAInfo; + SbgVersion versionBInfo; + + // + // Decode the versions + // + sbgVersionDecode(versionA, &versionAInfo); + sbgVersionDecode(versionB, &versionBInfo); + + // + // Do the comparaison + // + return sbgVersionCompare(&versionAInfo, &versionBInfo, threshold); +} + +SBG_COMMON_LIB_API int32_t sbgVersionIsWithinRange(const SbgVersion *pLowerVersion, const SbgVersion *pHigherVersion, const SbgVersion *pVersion) +{ + assert(pLowerVersion); + assert(pHigherVersion); + assert(pVersion); + + // + // Use the encoded version to speed up the comparaison + // + return sbgVersionIsWithinRangeEncoded(sbgVersionEncode(pLowerVersion), sbgVersionEncode(pHigherVersion), sbgVersionEncode(pVersion)); +} + +SBG_COMMON_LIB_API int32_t sbgVersionIsWithinRangeEncoded(uint32_t lowerVersion, uint32_t higherVersion, uint32_t version) +{ + // + // Make sure that all versions are using the same scheme + // + assert(lowerVersion <= higherVersion); + assert(( (sbgVersionIsUsingSoftwareScheme(lowerVersion) == sbgVersionIsUsingSoftwareScheme(higherVersion)) && + (sbgVersionIsUsingSoftwareScheme(lowerVersion) == sbgVersionIsUsingSoftwareScheme(version))) || + ( (sbgVersionIsUsingSoftwareScheme(lowerVersion) != sbgVersionIsUsingSoftwareScheme(higherVersion)) && + (sbgVersionIsUsingSoftwareScheme(lowerVersion) != sbgVersionIsUsingSoftwareScheme(version)))); + + // + // We can compare safely the encoded version directly + // + if (version < lowerVersion) + { + return -1; + } + else if (version > higherVersion) + { + return 1; + } + else + { + return 0; + } +} + +//----------------------------------------------------------------------// +//- Version to string methods -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API SbgErrorCode sbgVersionToString(const SbgVersion *pVersionInfo, char *pBuffer, size_t sizeOfBuffer) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + + assert(pVersionInfo); + assert(pBuffer); + assert(sizeOfBuffer>0); + + // + // Test if we have a basic or software version scheme + // + if (pVersionInfo->softwareScheme) + { + // + // We have a software version scheme + // Test that the buffer is big enough to store the generated string (31.31.65535-hotfix) + // + if (sizeOfBuffer >= 19) + { + // + // Generate the string version + // + sprintf(pBuffer, "%u.%u.%u-", pVersionInfo->major, pVersionInfo->minor, pVersionInfo->build); + + // + // Append the qualifier + // + switch (pVersionInfo->qualifier) + { + case SBG_VERSION_QUALIFIER_DEV: + strcat(pBuffer, "dev"); + break; + case SBG_VERSION_QUALIFIER_ALPHA: + strcat(pBuffer, "alpha"); + break; + case SBG_VERSION_QUALIFIER_BETA: + strcat(pBuffer, "beta"); + break; + case SBG_VERSION_QUALIFIER_RC: + strcat(pBuffer, "rc"); + break; + case SBG_VERSION_QUALIFIER_STABLE: + strcat(pBuffer, "stable"); + break; + case SBG_VERSION_QUALIFIER_HOT_FIX: + strcat(pBuffer, "hotfix"); + break; + default: + break; + } + } + else + { + // + // Output buffer is to small + // + errorCode = SBG_BUFFER_OVERFLOW; + } + + } + else + { + // + // We have a basic version scheme, generate the string + // Test that the buffer is big enough to store the generated string + // + if (sizeOfBuffer >= 16) + { + // + // Generate the string version + // + sprintf(pBuffer, "%u.%u.%u.%u", pVersionInfo->major, pVersionInfo->minor, pVersionInfo->rev, pVersionInfo->build); + } + else + { + // + // Output buffer is to small + // + errorCode = SBG_BUFFER_OVERFLOW; + } + } + + // + // Return status of operation + // + return errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgVersionToStringEncoded(uint32_t version, char *pBuffer, size_t sizeOfBuffer) +{ + SbgVersion versionInfo; + + // + // Decode the versions + // + sbgVersionDecode(version, &versionInfo); + + // + // Return the version as a string + // + return sbgVersionToString(&versionInfo, pBuffer, sizeOfBuffer); +} + +//----------------------------------------------------------------------// +//- String to version methods -// +//----------------------------------------------------------------------// + +SBG_COMMON_LIB_API SbgErrorCode sbgVersionFromString(const char *pVersionStr, SbgVersion *pVersionInfo) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + char qualifierStr[32]; + unsigned int major; + unsigned int minor; + unsigned int rev; + unsigned int build; + + assert(pVersionStr); + assert(pVersionInfo); + + // + // Zero init the returned version struct + // + memset(pVersionInfo, 0x00, sizeof(SbgVersion)); + + // + // Try to parse a basic version + // + if (sscanf(pVersionStr, "%u.%u.%u.%u", &major, &minor, &rev, &build) == 4) + { + // + // We have read successfully a basic version + // + pVersionInfo->softwareScheme = false; + + // + // Fill the version numbers + // + pVersionInfo->major = (uint8_t)major; + pVersionInfo->minor = (uint8_t)minor; + pVersionInfo->rev = (uint8_t)rev; + pVersionInfo->build = (uint8_t)build; + } + else if (sscanf(pVersionStr, "%u.%u.%u-%s", &major, &minor, &build, qualifierStr) == 4) + { + // + // We have read successfully a software scheme version + // + pVersionInfo->softwareScheme = true; + + // + // Fill the version numbers + // + pVersionInfo->major = (uint8_t)major; + pVersionInfo->minor = (uint8_t)minor; + pVersionInfo->build = (uint16_t)build; + + // + // Also convert the qualifier + // + if (!strcmp(qualifierStr, "dev")) + { + // + // Dev qualifier + // + pVersionInfo->qualifier = SBG_VERSION_QUALIFIER_DEV; + } + else if (!strcmp(qualifierStr, "alpha")) + { + // + // Alpha qualifier + // + pVersionInfo->qualifier = SBG_VERSION_QUALIFIER_ALPHA; + } + else if (!strcmp(qualifierStr, "beta")) + { + // + // Beta qualifier + // + pVersionInfo->qualifier = SBG_VERSION_QUALIFIER_BETA; + } + else if (!strcmp(qualifierStr, "rc")) + { + // + // Release Candidate qualifier + // + pVersionInfo->qualifier = SBG_VERSION_QUALIFIER_RC; + } + else if (!strcmp(qualifierStr, "stable")) + { + // + // Stable qualifier + // + pVersionInfo->qualifier = SBG_VERSION_QUALIFIER_STABLE; + } + else if (!strcmp(qualifierStr, "hotfix")) + { + // + // Hot Fix qualifier + // + pVersionInfo->qualifier = SBG_VERSION_QUALIFIER_HOT_FIX; + } + else + { + // + // Unknown qualifier + // + errorCode = SBG_INVALID_PARAMETER; + } + } + else + { + // + // Invalid format + // + errorCode = SBG_INVALID_PARAMETER; + } + + return errorCode; +} + +SBG_COMMON_LIB_API SbgErrorCode sbgVersionFromStringEncoded(const char *pVersionStr, uint32_t *pVersion) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgVersion versionInfo; + + assert(pVersionStr); + assert(pVersion); + + // + // Parse the version from a string + // + errorCode = sbgVersionFromString(pVersionStr, &versionInfo); + + // + // Test that no error has occurred + // + if (errorCode == SBG_NO_ERROR) + { + // + // Encode the version and return it + // + *pVersion = sbgVersionEncode(&versionInfo); + } + else + { + // + // An error has occurred so return a zero version + // + *pVersion = 0; + } + + // + // Return error + // + return errorCode; +} + diff --git a/crates/sbg-rs/sbgECom/common/version/sbgVersion.h b/crates/sbg-rs/sbgECom/common/version/sbgVersion.h new file mode 100644 index 0000000..ce4888a --- /dev/null +++ b/crates/sbg-rs/sbgECom/common/version/sbgVersion.h @@ -0,0 +1,474 @@ +/*! + * \file sbgVersion.h + * \ingroup common + * \author SBG Systems + * \date April 23, 2015 + * + * \brief Helper methods and definitions used to handle version. + * + * Version information is stored within a single uint32_t. + * There are two different versions schemes to better handle software revisions and file format / hardware ones. + * + * Software version are only used for firmware and software. + * This versions is defined as a `Major`.`Minor`.`Build`-`Qualifier` for example: 1.3.1845-rc + * Major and Minor can range from 0 to 63. + * Build is an uint16_t ranging from 0 to 65535. + * Qualifier is an enum encoded on 3 bits. + * + * Basic version is used for hardware or file formats and is the legacy one for software. + * This versions is defined as a `Major`.`Minor`.`Revision`.`Build` + * Each element is stored in an uint8_t. + * The Major version should NEVER go above 31 + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_VERSION_H +#define SBG_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Project headers +#include + + +//----------------------------------------------------------------------// +//- Version related definitions -// +//----------------------------------------------------------------------// +#define SBG_VERSION_SOFT_SCHEME (0x00000001u << 31) /*!< Set to 1 to indicate a version number that uses the software scheme. Set to 0 means a basic version scheme. */ + +#define SBG_VERSION_SOFT_SCHEME_QUALIFIER_MASK (0x07) /*!< Mask used to keep only the version qualifier enum. */ +#define SBG_VERSION_SOFT_SCHEME_QUALIFIER_SHIFT (28) /*!< Bitshift to apply to get the qualifier enum. */ + +#define SBG_VERSION_SOFT_SCHEME_MAJOR_MASK (0x3F) /*!< Mask used to keep only the major version field. */ +#define SBG_VERSION_SOFT_SCHEME_MAJOR_SHIFT (22) /*!< Bitshift used to get the major version field. */ + +#define SBG_VERSION_SOFT_SCHEME_MINOR_MASK (0x3F) /*!< Mask used to keep only the minor version field. */ +#define SBG_VERSION_SOFT_SCHEME_MINOR_SHIFT (16) /*!< Bitshift used to get the minor version field. */ + +#define SBG_VERSION_SOFT_SCHEME_BUILD_MASK (0xFFFF) /*!< Mask used to keep only the build version field. */ +#define SBG_VERSION_SOFT_SCHEME_BUILD_SHIFT (0) /*!< Bitshift used to get the build version field. */ + +/*! + * Version qualifier enum definition. + * This enum is used to identify if we have a basic version scheme or a software one. + * If it's a software one, we can easly know if the software version is a beta, a stable one. + */ +typedef enum _SbgVersionQualifier +{ + SBG_VERSION_QUALIFIER_DEV = 0, /*!< Development only version or pre-alpha. Customer shouldn't get this version qualifier. */ + SBG_VERSION_QUALIFIER_ALPHA = 1, /*!< Alpha version, missing features, can be unstable and could cause crashes or data loss. API can still change. */ + SBG_VERSION_QUALIFIER_BETA = 2, /*!< Beta version, features are freezed, can be unstable and could cause crashes or data loss. API shouldn't change. */ + SBG_VERSION_QUALIFIER_RC = 3, /*!< Release Candidate, features are freezed, with no known bug. API is freezed. */ + SBG_VERSION_QUALIFIER_STABLE = 4, /*!< Stable release, the version is the standard delivered one. */ + SBG_VERSION_QUALIFIER_HOT_FIX = 5 /*!< Hot fixes were applied on a stable release. It should be bug fixes. This qualifier is temporary as the version should return to stable release as soon as the test procedure has been performed. */ +} SbgVersionQualifier; + +/*! + * Version qualifier enum definition. + * This enum is used to identify if we have a basic version scheme or a software one. + * If it's a software one, we can easily know if the software version is a beta, a stable one. + */ +typedef enum _SbgVersionCmpThreshold +{ + SBG_VERSION_CMP_THRESHOLD_MAJOR = 0, /*!< Compare only the major field. */ + SBG_VERSION_CMP_THRESHOLD_MINOR = 1, /*!< Compare the major and minor fields. */ + SBG_VERSION_CMP_THRESHOLD_REVISION = 2, /*!< Compare the major, minor and revision fields (only for basic versions). */ + SBG_VERSION_CMP_THRESHOLD_BUILD = 3, /*!< Compare the major, minor, revision and build fields. */ + SBG_VERSION_CMP_THRESHOLD_QUALIFIER = 4 /*!< Compare the major, minor, revision, build and qualifier fields (only for software scheme). */ +} SbgVersionCmpThreshold; + +/* + * DEPRECATED compatibility definitions + */ +#define SBG_VERSION_CMP_THRESOLD_MAJOR SBG_VERSION_CMP_THRESHOLD_MAJOR +#define SBG_VERSION_CMP_THRESOLD_MINOR SBG_VERSION_CMP_THRESHOLD_MINOR +#define SBG_VERSION_CMP_THRESOLD_REVISION SBG_VERSION_CMP_THRESHOLD_REVISION +#define SBG_VERSION_CMP_THRESOLD_BUILD SBG_VERSION_CMP_THRESHOLD_BUILD +#define SBG_VERSION_CMP_THRESOLD_QUALIFIER SBG_VERSION_CMP_THRESHOLD_QUALIFIER + +/*! + * This structure contains all the fields provided by a version number. + * It handles both basic and software version numbers. + */ +typedef struct _SbgVersion +{ + bool softwareScheme; /*!< Set to true if it's a software scheme or false if it's a basic one. */ + SbgVersionQualifier qualifier; /*!< Qualifier of the current version */ + uint8_t major; /*!< Major version */ + uint8_t minor; /*!< Minor version */ + uint8_t rev; /*!< Revision number - left to 0 in case of software version */ + uint16_t build; /*!< Build number */ +} SbgVersion; + +//----------------------------------------------------------------------// +//- Macro definitions for encode versions -// +//----------------------------------------------------------------------// + +/*! + * Compile a version number using the basic scheme based on major, minor, revision and build information + * + * \param[in] major The major version between 0 to 127. + * \param[in] minor The minor version between 0 to 255. + * \param[in] rev The revision version between 0 to 255. + * \param[in] build The build number between 0 to 255. + * \return The encoded version number. + */ +#define SBG_VERSION_BASIC(major, minor, rev, build) ( (((uint32_t)(major)) << 24) | \ + (((uint32_t)(minor)) << 16) | \ + (((uint32_t)(rev)) << 8) | \ + (((uint32_t)(build))) ) + +/*! + * Compile a version number using the software scheme based on major, minor, build, qualifier. + * + * \param[in] major The major version between 0 to 63. + * \param[in] minor The minor version between 0 to 63. + * \param[in] build The build version between 0 to 65535. + * \param[in] qualifier The version qualifier within the SbgVersionQualifier enum. + * \return The encoded version number. + */ +#define SBG_VERSION_SOFTWARE(major, minor, build, qualifier) ( SBG_VERSION_SOFT_SCHEME | \ + ((((uint32_t)(qualifier)) & SBG_VERSION_SOFT_SCHEME_QUALIFIER_MASK) << SBG_VERSION_SOFT_SCHEME_QUALIFIER_SHIFT) | \ + ((((uint32_t)(major)) & SBG_VERSION_SOFT_SCHEME_MAJOR_MASK) << SBG_VERSION_SOFT_SCHEME_MAJOR_SHIFT) | \ + ((((uint32_t)(minor)) & SBG_VERSION_SOFT_SCHEME_MINOR_MASK) << SBG_VERSION_SOFT_SCHEME_MINOR_SHIFT) | \ + ((((uint32_t)(build)) & SBG_VERSION_SOFT_SCHEME_BUILD_MASK) << SBG_VERSION_SOFT_SCHEME_BUILD_SHIFT) ) +//----------------------------------------------------------------------// +//- Constructor -// +//----------------------------------------------------------------------// + +/*! + * Create a basic scheme version given the components major.minor.rev.build + * + * \param[out] pVersion Version instance + * \param[in] major The major component between 0 to 127 + * \param[in] minor The minor component between 0 to 255 + * \param[in] revision The revision component between 0 to 255 + * \param[in] build The build component between 0 to 255 + */ +SBG_COMMON_LIB_API void sbgVersionCreateBasic(SbgVersion *pVersion, uint8_t major, uint8_t minor, uint8_t revision, uint8_t build); + +/*! + * Create a software scheme version given the components major.minor.build.qualifier + * + * \param[out] pVersion Version instance + * \param[in] major The major component between 0 to 63 + * \param[in] minor The minor component between 0 to 63 + * \param[in] build The build component between 0 to 65535 + * \param[in] qualifier The version qualifier enum value. + */ +SBG_COMMON_LIB_API void sbgVersionCreateSoftware(SbgVersion *pVersion, uint8_t major, uint8_t minor, uint16_t build, SbgVersionQualifier qualifier); + +/*! + * Version copy constructor. + * + * \param[in] pVersion Version. + * \param[in] pOtherVersion Version to copy from. + */ +SBG_COMMON_LIB_API void sbgVersionConstructCopy(SbgVersion *pVersion, const SbgVersion *pOtherVersion); + +//----------------------------------------------------------------------// +//- Version encoding / decoding methods -// +//----------------------------------------------------------------------// + +/*! + * Fill a SbgVersion structure based on an uint32_t that stores the 'compiled' version information. + * + * \param[in] encodedVersion The version information stored within a uint32_t. + * \param[out] pVersionInfo Pointer on an allocated SbgVersion structure to fill. + */ +SBG_COMMON_LIB_API void sbgVersionDecode(uint32_t encodedVersion, SbgVersion *pVersionInfo); + +/*! + * Construct a uint32_t containing a version information based on a SbgVersion structure. + * + * \param[in] pVersionInfo Pointer on a read only version structure to encode. + * \return The encoded version information on an uint32_t or 0 if an error has occurred. + */ +SBG_COMMON_LIB_API uint32_t sbgVersionEncode(const SbgVersion *pVersionInfo); + +//----------------------------------------------------------------------// +//- Version parameters methods -// +//----------------------------------------------------------------------// + +/*! + * Returns true if this encoded version number is using a software scheme. + * + * \param[in] encodedVersion The encoded version number to test stored in a uint32_t. + * \return true if the version number is using a software scheme. + */ +SBG_INLINE bool sbgVersionIsUsingSoftwareScheme(uint32_t encodedVersion) +{ + SbgVersion decodedVersion; + + // + // Decode the version first + // + sbgVersionDecode(encodedVersion, &decodedVersion); + + // + // Returns if the version is using a software scheme + // + return decodedVersion.softwareScheme; +} + +//----------------------------------------------------------------------// +//- Version comparaison methods -// +//----------------------------------------------------------------------// + +/*! + * Compare two version information structures and return if the version A is greater, less or equal than the version B. + * + * The computation is roughly result = version A - version B + * We can define how far we will check if the version A is greater than the version B. + * For example, we can only check the major or major and minor fields. + * + * \param[in] pVersionA The first version to compare. + * \param[in] pVersionB The second version to compare. + * \param[in] threshold The comparaison threshold to know if we are checking the major, minor, revision, build, ... + * \return A positive value if the version A is greater than B, a negative one if version A is less than B and 0 if the two versions are the same (according to the threshold). + */ +SBG_COMMON_LIB_API int32_t sbgVersionCompare(const SbgVersion *pVersionA, const SbgVersion *pVersionB, SbgVersionCmpThreshold threshold); + +/*! + * Compare two encoded versions and return if the version A is greater, less or equal than the version B. + * + * The computation is roughly result = version A - version B + * We can define how far we will check if the version A is greater than the version B. + * For example, we can only check the major or major and minor fields. + * + * \param[in] versionA The first compiled version to compare. + * \param[in] versionB The second compiled version to compare. + * \param[in] threshold The comparaison threshold to know if we are checking the major, minor, revision, build, ... + * \return A positive value if the version A is greater than B, a negative one if version A is less than B and 0 if the two versions are the same (according to the threshold). + */ +SBG_COMMON_LIB_API int32_t sbgVersionCompareEncoded(uint32_t versionA, uint32_t versionB, SbgVersionCmpThreshold threshold); + +/*! + * Check if the provided version is between the provided version interval. + * All versions should have the same scheme. + * + * \param[in] pLowerVersion The lower version bound of the interval. + * \param[in] pHigherVersion The hiver version bound of the interval. + * \param[in] pVersion The version to check. + * \return A negative value if the version is stricly below the lower version bound + * Zero if the version if equal or greater than lower version and equal or smaller than higer version + * A positive value if the version is strictly above the higher version bound + */ +SBG_COMMON_LIB_API int32_t sbgVersionIsWithinRange(const SbgVersion *pLowerVersion, const SbgVersion *pHigherVersion, const SbgVersion *pVersion); + +/*! + * Check if the provided encoded version is between the provided version interval. + * All versions should have the same scheme. + * + * \param[in] lowerVersion The lower version bound of the interval. + * \param[in] higherVersion The hiver version bound of the interval. + * \param[in] version The version to check. + * \return A negative value if the version is stricly below the lower version bound + * Zero if the version if equal or greater than lower version and equal or smaller than higer version + * A positive value if the version is strictly above the higher version bound + */ +SBG_COMMON_LIB_API int32_t sbgVersionIsWithinRangeEncoded(uint32_t lowerVersion, uint32_t higherVersion, uint32_t version); + + +//----------------------------------------------------------------------// +//- Version to string methods -// +//----------------------------------------------------------------------// + +/*! + * Convert a version information to a human readable string. + * + * \param[in] pVersionInfo Pointer on a read only version structure to convert to a human readable string. + * \param[out] pBuffer Buffer to store the version as a human readable null terminated string. + * \param[in] sizeOfBuffer Maximum buffer size including the null terminated char. + * \return SBG_NO_ERROR if the version information has been converted to a string. + * SBG_BUFFER_OVERFLOW is the buffer isn't big enough to store the converted version string. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgVersionToString(const SbgVersion *pVersionInfo, char *pBuffer, size_t sizeOfBuffer); + +/*! + * Convert an encoded version number to a human readable string. + * + * \param[in] version Encoded version value to to convert to a human readable string. + * \param[out] pBuffer Buffer to store the version as a human readable null terminated string. + * \param[in] sizeOfBuffer Maximum buffer size including the null terminated char. + * \return SBG_NO_ERROR if the version information has been converted to a string. + * SBG_BUFFER_OVERFLOW is the buffer isn't big enough to store the converted version string. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgVersionToStringEncoded(uint32_t version, char *pBuffer, size_t sizeOfBuffer); + +//----------------------------------------------------------------------// +//- String to version methods -// +//----------------------------------------------------------------------// + +/*! + * Convert a human readable string to a version structure. + * + * \param[in] pVersionStr The string containing the version to convert. + * \param[out] pVersionInfo Pointer to a version structure to store the parsed version info. + * \return SBG_NO_ERROR if the version information has been converted from a string. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgVersionFromString(const char *pVersionStr, SbgVersion *pVersionInfo); + +/*! + * Convert an encoded version number to a human readable string. + * + * \param[in] pVersionStr The string containing the version to convert. + * \param[out] pVersion Returned encoded version value parsed from the string. + * \return SBG_NO_ERROR if the version information has been converted from a string. + */ +SBG_COMMON_LIB_API SbgErrorCode sbgVersionFromStringEncoded(const char *pVersionStr, uint32_t *pVersion); + +//----------------------------------------------------------------------// +//- Legacy version system methods -// +//----------------------------------------------------------------------// + +/*! + * Define all these methods as deprecated. + */ +SBG_DEPRECATED(SBG_INLINE uint32_t SBG_VERSION(uint8_t major, uint8_t minor, uint8_t rev, uint8_t build)); +SBG_DEPRECATED(SBG_INLINE uint8_t SBG_VERSION_GET_MAJOR(uint32_t encodedVersion)); +SBG_DEPRECATED(SBG_INLINE uint8_t SBG_VERSION_GET_MINOR(uint32_t encodedVersion)); +SBG_DEPRECATED(SBG_INLINE uint8_t SBG_VERSION_GET_REV(uint32_t encodedVersion)); +SBG_DEPRECATED(SBG_INLINE uint8_t SBG_VERSION_GET_BUILD(uint32_t encodedVersion)); + +/*! + * DEPRECATED macro, please update your code + * + * Compile a version number using the basic scheme based on major, minor, revision and build information + * + * \param[in] major The major version between 0 to 127. + * \param[in] minor The minor version between 0 to 255. + * \param[in] rev The revision version between 0 to 255. + * \param[in] build The build number between 0 to 255. + * \return The encoded version number. + */ +SBG_INLINE uint32_t SBG_VERSION(uint8_t major, uint8_t minor, uint8_t rev, uint8_t build) +{ + // + // The SBG_VERSION macro is the basic version scheme. + // + return SBG_VERSION_BASIC(major, minor, rev, build); +} + +/*! + * DEPRECATED method, please update your code. + * + * Extract a basic version scheme using legacy methods. + * + * \param[in] encodedVersion The encoded version to extract the major version. + * \return The major version. + */ +SBG_INLINE uint8_t SBG_VERSION_GET_MAJOR(uint32_t encodedVersion) +{ + SbgVersion versionInfo; + + // + // Decode the version information + // + sbgVersionDecode(encodedVersion, &versionInfo); + + // + // Return the major version + // + return versionInfo.major; +} + +/*! + * DEPRECATED method, please update your code. + * + * Extract a basic version scheme using legacy methods. + * + * \param[in] encodedVersion The encoded version to extract the major version. + * \return The major version. + */ +SBG_INLINE uint8_t SBG_VERSION_GET_MINOR(uint32_t encodedVersion) +{ + SbgVersion versionInfo; + + // + // Decode the version information + // + sbgVersionDecode(encodedVersion, &versionInfo); + + // + // Return the major version + // + return versionInfo.minor; +} + +/*! + * DEPRECATED method, please update your code. + * + * Extract a basic version scheme using legacy methods. + * + * \param[in] encodedVersion The encoded version to extract the major version. + * \return The major version. + */ +SBG_INLINE uint8_t SBG_VERSION_GET_REV(uint32_t encodedVersion) +{ + SbgVersion versionInfo; + + // + // Decode the version information + // + sbgVersionDecode(encodedVersion, &versionInfo); + + // + // Return the major version + // + return versionInfo.rev; +} + +/*! + * DEPRECATED method, please update your code. + * + * Extract a basic version scheme using legacy methods + * + * \param[in] encodedVersion The encoded version to extract the major version. + * \return The major version. + */ +SBG_INLINE uint8_t SBG_VERSION_GET_BUILD(uint32_t encodedVersion) +{ + SbgVersion versionInfo; + + // + // Decode the version information + // + sbgVersionDecode(encodedVersion, &versionInfo); + + // + // Return the major version + // + return (uint8_t)versionInfo.build; +} + + +#ifdef __cplusplus +} +#endif + +#endif // SBG_VERSION_H diff --git a/crates/sbg-rs/sbgECom/doc/migrations.md b/crates/sbg-rs/sbgECom/doc/migrations.md new file mode 100644 index 0000000..09b1050 --- /dev/null +++ b/crates/sbg-rs/sbgECom/doc/migrations.md @@ -0,0 +1,43 @@ +# Migrations +These pages help you easily migrate your code from previous sbgECom major versions. + +## From sbgECom v1.x +The sbgECom version 2.x change the C API even if the low level sbgECom protocol API remains backward compatible. +In otherwords, a C code written with sbgECom version 1.x will not compile directly with sbgECom versions 2.x and higher. +But your old C code using sbgECom versions 1.x will still be able to correctly setup and configure your ELLIPSE product. + +### GNSS module +The _SbgEComGnssModelsStdIds_ enum has been simplified and now ELLIPSE-N and ELLIPSE-D should only use _SBG_ECOM_GNSS_MODEL_INTERNAL_ to select the internal GNSS receiver. +The only exception is for ELLIPSE-N hardware revision 1 & 2 as the ublox Max M8 has two modes of operations, either GPS+GLONASS or GPS+BeiDou. +The default GPS+GLONASS mode is selected with the _SBG_ECOM_GNSS_MODEL_INTERNAL_ model and the GPS+BeiDou one with _SBG_ECOM_GNSS_MODEL_UBLOX_GPS_BEIDOU_. +The _SBG_ECOM_GNSS_MODEL_UBLOX_GPS_BEIDOU_ model couldn't be used with ELLIPSE-N with hardware revision 3.x or ELLIPSE-D as the GNSS receiver is tracking GPS+GLONASS+BeiDou+Galileo concurrently. + +The table below helps you update your enums to sbgECom v2 correctly: +| sbgECom 1.x | sbgECom 2.x | Remarks | +| --------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------ | +| SBG_ECOM_GNSS_MODEL_UBLOX_GPS_GLONASS | SBG_ECOM_GNSS_MODEL_INTERNAL | To use for ELLIPSE-N and ELLIPSE-D | +| SBG_ECOM_GNSS_MODEL_NMEA | SBG_ECOM_GNSS_MODEL_NMEA | ELLIPSE-E, external NMEA receiver (listen only) | +| SBG_ECOM_GNSS_MODEL_UBLOX_GPS_BEIDOU | SBG_ECOM_GNSS_MODEL_UBLOX_GPS_BEIDOU | Can only be selected on ELLIPSE-N revision 1 & 2 | +| SBG_ECOM_GNSS_MODEL_UBLOX_EXTERNAL | SBG_ECOM_GNSS_MODEL_UBLOX_EXTERNAL | ELLIPSE-E, external ublox receiver (listen only) | +| SBG_ECOM_GNSS_MODEL_UBLOX_HIGH_DYNAMICS | SBG_ECOM_GNSS_MODEL_INTERNAL | For high dynamics applications, please selected the appropriate motion profile | +| SBG_ECOM_GNSS_MODEL_NOVATEL_EXTERNAL | SBG_ECOM_GNSS_MODEL_NOVATEL_EXTERNAL | ELLIPSE-E, external Novatel receiver (listen only) | +| SBG_ECOM_GNSS_MODEL_ELLIPSE_D_INTERNAL | SBG_ECOM_GNSS_MODEL_INTERNAL | Legacy ELLIPSE-D hardware 1 & 2, don't use it anymore | +| SBG_ECOM_GNSS_MODEL_UBLOX_HIGH_SPEED | SBG_ECOM_GNSS_MODEL_INTERNAL | For high speed applications, please selected the appropriate motion profile | +| SBG_ECOM_GNSS_MODEL_SEPTENTRIO_EXTERNAL | SBG_ECOM_GNSS_MODEL_SEPTENTRIO_EXTERNAL | ELLIPSE-E, external Septentrio receiver (listen only) | +| SBG_ECOM_GNSS_MODEL_UBLOX_LOW_SPEED | SBG_ECOM_GNSS_MODEL_INTERNAL | For low dynamics applications, please selected the appropriate motion profile | + +Please also update your code according to the following recommendations and modifications: +- `sbgEComCmdGnss1GetModelInfo` method has been replaced by `sbgEComCmdGnss1GetModelId` with a simpler interface as the version field is no more used in ELLIPSE firmware. +- `sbgEComCmdGnss1GetLeverArmAlignment` and `sbgEComCmdGnss1SetLeverArmAlignment` methods have been suppressed by `sbgEComCmdGnss1InstallationGet` and `sbgEComCmdGnss1InstallationSet` methods. + +### Magnetometers module + +The method `sbgEComCmdMagGetModelInfo` has been replaced by `sbgEComCmdMagGetModelId` with a simpler interface as the version field is no more used in ELLIPSE firmware. + +### Sensor module + +The method `sbgEComCmdSensorGetMotionProfileInfo` has been replaced by `sbgEComCmdSensorGetMotionProfileId` with a simpler interface as the version field is no more used in ELLIPSE firmware. + +### Legacy IG-500 sbgCom + +sbgECom version 2.x drop the legacy IG-500 support so the methods `sbgEComCmdOutputGetLegacyConf` and `sbgEComCmdOutputSetLegacyConf` are removed. Please update your code to use sbgECom protocol instead. diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogAirData.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogAirData.c new file mode 100644 index 0000000..25d3543 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogAirData.c @@ -0,0 +1,66 @@ +#include "sbgEComBinaryLogAirData.h" + +//----------------------------------------------------------------------// +//- Operations -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseAirData(SbgStreamBuffer *pInputStream, SbgLogAirData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + + pOutputData->pressureAbs = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->altitude = sbgStreamBufferReadFloatLE(pInputStream); + + // + // The true airspeed fields have been added in version 2.0 + // + if (sbgStreamBufferGetSpace(pInputStream) > 0) + { + pOutputData->pressureDiff = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->trueAirspeed = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->airTemperature = sbgStreamBufferReadFloatLE(pInputStream); + } + else + { + pOutputData->pressureDiff = 0.0f; + pOutputData->trueAirspeed = 0.0f; + pOutputData->airTemperature = 0.0f; + } + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteAirData(SbgStreamBuffer *pOutputStream, const SbgLogAirData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->pressureAbs); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->altitude); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->pressureDiff); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->trueAirspeed); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->airTemperature); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogAirData.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogAirData.h new file mode 100644 index 0000000..8909378 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogAirData.h @@ -0,0 +1,105 @@ +/*! + * \file sbgEComBinaryLogAirData.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 20 February 2019 + * + * \brief Parse received air data measurement logs such as barometer data. + * + * Air Data logs are used to inject / return barometric altitude + * as well as true air speed. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_AIR_DATA_H +#define SBG_ECOM_BINARY_LOG_AIR_DATA_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log Air Data status definitions -// +//----------------------------------------------------------------------// + +/*! + * Air Data sensor status mask definitions + */ +#define SBG_ECOM_AIR_DATA_TIME_IS_DELAY (0x0001u << 0) /*!< Set to 1 if the time stamp field represents a delay instead of an absolute time stamp. */ +#define SBG_ECOM_AIR_DATA_PRESSURE_ABS_VALID (0x0001u << 1) /*!< Set to 1 if the pressure field is filled and valid. */ +#define SBG_ECOM_AIR_DATA_ALTITUDE_VALID (0x0001u << 2) /*!< Set to 1 if the barometric altitude field is filled and valid. */ +#define SBG_ECOM_AIR_DATA_PRESSURE_DIFF_VALID (0x0001u << 3) /*!< Set to 1 if the differential pressure field is filled and valid. */ +#define SBG_ECOM_AIR_DATA_AIRPSEED_VALID (0x0001u << 4) /*!< Set to 1 if the true airspeed field is filled and valid. */ +#define SBG_ECOM_AIR_DATA_TEMPERATURE_VALID (0x0001u << 5) /*!< Set to 1 if the output air temperature field is filled and valid. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Log structure for AirData. + */ +typedef struct _SbgLogAirData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up OR measurement delay in us. */ + uint16_t status; /*!< Airdata sensor status bitmask. */ + float pressureAbs; /*!< Raw absolute pressure measured by the barometer sensor in Pascals. */ + float altitude; /*!< Altitude computed from barometric altimeter in meters and positive upward. */ + float pressureDiff; /*!< Raw differential pressure measured by the pitot tube in Pascal. */ + float trueAirspeed; /*!< True airspeed measured by a pitot tube in m.s^-1 and positive forward. */ + float airTemperature; /*!< Outside air temperature in °C that could be used to compute true airspeed from differential pressure. */ +} SbgLogAirData; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_AIR_DATA message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseAirData(SbgStreamBuffer *pInputStream, SbgLogAirData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_AIR_DATA message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteAirData(SbgStreamBuffer *pOutputStream, const SbgLogAirData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_AIR_DATA_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogAutomotiveData.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogAutomotiveData.h new file mode 100644 index 0000000..df57e48 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogAutomotiveData.h @@ -0,0 +1,74 @@ +/*! + * \file sbgEComBinaryLogAutomotiveData.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 22 April 2020 + * + * \brief Parse dedicated automotive measurements logs. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_AUTOMOTIVE_H +#define SBG_ECOM_BINARY_LOG_AUTOMOTIVE_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +/*! + * Automotive data status mask definitions + */ +#define SBG_ECOM_AUTO_DATA_TRACK_VALID (0x1u << 0) /*!< Set to 1 if the track angle is valid. */ +#define SBG_ECOM_AUTO_DATA_SLIP_VALID (0x1u << 1) /*!< Set to 1 if the slip angle is valid. */ +#define SBG_ECOM_AUTO_DATA_CURVATURE_VALID (0x1u << 2) /*!< Set to 1 if the curvature radius is valid. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Log structure for automotive data. + */ +typedef struct _SbgLogAutoData +{ + uint8_t status; /*!< Status bit mask. */ + float trackAngle; /*!< Track angle, in rad. */ + float slipAngle; /*!< Slip angle, in rad. */ + float curvatureRadius; /*!< Curvature radius, in m, always positive. */ +} SbgLogAutoData; + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_AUTOMOTIVE_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDepth.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDepth.c new file mode 100644 index 0000000..d87d268 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDepth.c @@ -0,0 +1,45 @@ +#include "sbgEComBinaryLogDepth.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseDepth(SbgStreamBuffer *pInputStream, SbgLogDepth *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + + pOutputData->pressureAbs = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->altitude = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteDepth(SbgStreamBuffer *pOutputStream, const SbgLogDepth *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->pressureAbs); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->altitude); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDepth.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDepth.h new file mode 100644 index 0000000..df142e3 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDepth.h @@ -0,0 +1,98 @@ +/*! + * \file sbgEComBinaryLogDepth.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 20 February 2019 + * + * \brief Parse received subsea depth measurement logs. + * + * Depth sensor are used for subsea navigation to improve height. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_DEPTH_H +#define SBG_ECOM_BINARY_LOG_DEPTH_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log Air Data status definitions -// +//----------------------------------------------------------------------// + +/*! + * Air Data sensor status mask definitions + */ +#define SBG_ECOM_DEPTH_TIME_IS_DELAY (0x0001u << 0) /*!< Set to 1 if the time stamp field represents a delay instead of an absolute time stamp. */ +#define SBG_ECOM_DEPTH_PRESSURE_ABS_VALID (0x0001u << 1) /*!< Set to 1 if the pressure field is filled and valid. */ +#define SBG_ECOM_DEPTH_ALTITUDE_VALID (0x0001u << 2) /*!< Set to 1 if the depth altitude field is filled and valid. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Log structure for Depth sensor measurement (subsea). + */ +typedef struct _SbgLogDepth +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up OR measurement delay in us. */ + uint16_t status; /*!< Airdata sensor status bitmask. */ + float pressureAbs; /*!< Raw absolute pressure measured by the depth sensor in Pascals. */ + float altitude; /*!< Altitude computed from depth sensor in meters and positive upward. */ +} SbgLogDepth; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_DEPTH message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseDepth(SbgStreamBuffer *pInputStream, SbgLogDepth *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_DEPTH message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteDepth(SbgStreamBuffer *pOutputStream, const SbgLogDepth *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_DEPTH_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDiag.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDiag.c new file mode 100644 index 0000000..dfcf0c3 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDiag.c @@ -0,0 +1,49 @@ +// sbgCommonLib headers +#include +#include + +// Local headers +#include "sbgEComBinaryLogDiag.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseDiagData(SbgStreamBuffer *pInputStream, SbgLogDiagData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + pOutputData->timestamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->type = (SbgDebugLogType)sbgStreamBufferReadUint8(pInputStream); + pOutputData->errorCode = (SbgErrorCode)sbgStreamBufferReadUint8(pInputStream); + + sbgStreamBufferReadBuffer(pInputStream, pOutputData->string, sbgStreamBufferGetSpace(pInputStream)); + pOutputData->string[sizeof(pOutputData->string) - 1] = '\0'; + + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteDiagData(SbgStreamBuffer *pOutputStream, const SbgLogDiagData *pInputData) +{ + size_t length; + + assert(pOutputStream); + assert(pInputData); + + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timestamp); + sbgStreamBufferWriteUint8(pOutputStream, pInputData->type); + sbgStreamBufferWriteUint8(pOutputStream, pInputData->errorCode); + + length = strlen(pInputData->string); + + if (length >= sizeof(pInputData->string)) + { + length = sizeof(pInputData->string) - 1; + } + + sbgStreamBufferWriteBuffer(pOutputStream, pInputData->string, length); + sbgStreamBufferWriteUint8(pOutputStream, 0); + + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDiag.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDiag.h new file mode 100644 index 0000000..4c8dc07 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDiag.h @@ -0,0 +1,98 @@ +/*! + * \file sbgEComBinaryLogDiag.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 12 June 2019 + * + * \brief Parse diagnostic logs emitted by the device. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_DIAG_H +#define SBG_ECOM_BINARY_LOG_DIAG_H + +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +/*! + * Maximum size of the log string, in bytes. + */ +#define SBG_ECOM_LOG_DIAG_MAX_STRING_SIZE (SBG_ECOM_MAX_PAYLOAD_SIZE - 6) + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Diagnostic log structure. + */ +typedef struct _SbgLogDiagData +{ + uint32_t timestamp; /*!< Timestamp, in microseconds. */ + SbgDebugLogType type; /*!< Log type. */ + SbgErrorCode errorCode; /*!< Error code. */ + char string[SBG_ECOM_LOG_DIAG_MAX_STRING_SIZE]; /*!< Log string, null-terminated. */ +} SbgLogDiagData; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for SBG_ECOM_LOG_DIAG messages and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseDiagData(SbgStreamBuffer *pInputStream, SbgLogDiagData *pOutputData); + + +/*! + * Write data for SBG_ECOM_LOG_DIAG messages to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteDiagData(SbgStreamBuffer *pOutputStream, const SbgLogDiagData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_DIAG_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDvl.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDvl.c new file mode 100644 index 0000000..0bdb392 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDvl.c @@ -0,0 +1,55 @@ +#include "sbgEComBinaryLogDvl.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseDvlData(SbgStreamBuffer *pInputStream, SbgLogDvlData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + + pOutputData->velocity[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocity[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocity[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->velocityQuality[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocityQuality[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocityQuality[2] = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteDvlData(SbgStreamBuffer *pOutputStream, const SbgLogDvlData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocity[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocity[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocity[2]); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocityQuality[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocityQuality[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocityQuality[2]); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDvl.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDvl.h new file mode 100644 index 0000000..fe7a8bc --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogDvl.h @@ -0,0 +1,96 @@ +/*! + * \file sbgEComBinaryLogDvl.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 05 June 2013 + * + * \brief Parse received DVL (Doppler Velocity Logger) measurement logs. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_DVL_H +#define SBG_ECOM_BINARY_LOG_DVL_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log DVL status definitions -// +//----------------------------------------------------------------------// + +/*! + * DVL status mask definitions + */ +#define SBG_ECOM_DVL_VELOCITY_VALID (0x0001u << 0) /*!< Set to 1 if the DVL equipment was able to measure a valid velocity. */ +#define SBG_ECOM_DVL_TIME_SYNC (0x0001u << 1) /*!< Set to 1 if the DVL data is correctly synchronized. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Log structure for DVL data. + */ +typedef struct _SbgLogDvlData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< DVL status bitmask. */ + float velocity[3]; /*!< X, Y, Z velocities in m.s^-1 expressed in the DVL instrument frame. */ + float velocityQuality[3]; /*!< X, Y, Z velocities quality indicators as provided by the DVL sensor and expressed in m.s^-1. + WARNING: This is typically just a residual information and not a real standard deviation. */ +} SbgLogDvlData; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_DVL_BOTTOM_TRACK / SBG_ECOM_LOG_DVL_WATER_TRACK message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseDvlData(SbgStreamBuffer *pInputStream, SbgLogDvlData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_DVL_BOTTOM_TRACK / SBG_ECOM_LOG_DVL_WATER_TRACK message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteDvlData(SbgStreamBuffer *pOutputStream, const SbgLogDvlData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_DVL_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEkf.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEkf.c new file mode 100644 index 0000000..e95b9dd --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEkf.c @@ -0,0 +1,183 @@ +#include "sbgEComBinaryLogEkf.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseEkfEulerData(SbgStreamBuffer *pInputStream, SbgLogEkfEulerData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + + pOutputData->euler[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->euler[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->euler[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->eulerStdDev[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->eulerStdDev[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->eulerStdDev[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->status = sbgStreamBufferReadUint32LE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteEkfEulerData(SbgStreamBuffer *pOutputStream, const SbgLogEkfEulerData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->euler[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->euler[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->euler[2]); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->eulerStdDev[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->eulerStdDev[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->eulerStdDev[2]); + + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->status); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} + +SbgErrorCode sbgEComBinaryLogParseEkfQuatData(SbgStreamBuffer *pInputStream, SbgLogEkfQuatData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + + pOutputData->quaternion[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->quaternion[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->quaternion[2] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->quaternion[3] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->eulerStdDev[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->eulerStdDev[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->eulerStdDev[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->status = sbgStreamBufferReadUint32LE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteEkfQuatData(SbgStreamBuffer *pOutputStream, const SbgLogEkfQuatData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->quaternion[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->quaternion[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->quaternion[2]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->quaternion[3]); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->eulerStdDev[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->eulerStdDev[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->eulerStdDev[2]); + + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->status); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} + +SbgErrorCode sbgEComBinaryLogParseEkfNavData(SbgStreamBuffer *pInputStream, SbgLogEkfNavData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + + pOutputData->velocity[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocity[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocity[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->velocityStdDev[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocityStdDev[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocityStdDev[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->position[0] = sbgStreamBufferReadDoubleLE(pInputStream); + pOutputData->position[1] = sbgStreamBufferReadDoubleLE(pInputStream); + pOutputData->position[2] = sbgStreamBufferReadDoubleLE(pInputStream); + + pOutputData->undulation = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->positionStdDev[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->positionStdDev[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->positionStdDev[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->status = sbgStreamBufferReadUint32LE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteEkfNavData(SbgStreamBuffer *pOutputStream, const SbgLogEkfNavData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocity[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocity[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocity[2]); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocityStdDev[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocityStdDev[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocityStdDev[2]); + + sbgStreamBufferWriteDoubleLE(pOutputStream, pInputData->position[0]); + sbgStreamBufferWriteDoubleLE(pOutputStream, pInputData->position[1]); + sbgStreamBufferWriteDoubleLE(pOutputStream, pInputData->position[2]); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->undulation); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->positionStdDev[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->positionStdDev[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->positionStdDev[2]); + + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->status); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEkf.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEkf.h new file mode 100644 index 0000000..896cd4b --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEkf.h @@ -0,0 +1,227 @@ +/*! + * \file sbgEComBinaryLogEkf.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 25 February 2013 + * + * \brief Parse EKF measurements such as attitude, position and velocity logs. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_EKF_H +#define SBG_ECOM_BINARY_LOG_EKF_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Solution status definitions -// +//----------------------------------------------------------------------// + +/*! + * Solution status mode definitions. + */ +#define SBG_ECOM_SOLUTION_MODE_SHIFT (0u) /*!< Shift used to extract the clock status part. */ +#define SBG_ECOM_SOLUTION_MODE_MASK (0x0000000Fu) /*!< Mask used to keep only the clock status part. */ + +/*! + * Solution bit masks definitions. + */ +#define SBG_ECOM_SOL_ATTITUDE_VALID (0x00000001u << 4) /*!< Set to 1 if attitude data is reliable (Roll/Pitch error < 0,5°). */ +#define SBG_ECOM_SOL_HEADING_VALID (0x00000001u << 5) /*!< Set to 1 if geading data is reliable (Heading error < 1°). */ +#define SBG_ECOM_SOL_VELOCITY_VALID (0x00000001u << 6) /*!< Set to 1 if velocity data is reliable (velocity error < 1.5 m/s). */ +#define SBG_ECOM_SOL_POSITION_VALID (0x00000001u << 7) /*!< Set to 1 if position data is reliable (Position error < 10m). */ +#define SBG_ECOM_SOL_VERT_REF_USED (0x00000001u << 8) /*!< Set to 1 if vertical reference is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_MAG_REF_USED (0x00000001u << 9) /*!< Set to 1 if magnetometer is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_GPS1_VEL_USED (0x00000001u << 10) /*!< Set to 1 if GPS1 velocity is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_GPS1_POS_USED (0x00000001u << 11) /*!< Set to 1 if GPS1 Position is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_GPS1_HDT_USED (0x00000001u << 13) /*!< Set to 1 if GPS1 True Heading is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_GPS2_VEL_USED (0x00000001u << 14) /*!< Set to 1 if GPS2 velocity is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_GPS2_POS_USED (0x00000001u << 15) /*!< Set to 1 if GPS2 Position is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_GPS2_HDT_USED (0x00000001u << 17) /*!< Set to 1 if GPS2 True Heading is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_ODO_USED (0x00000001u << 18) /*!< Set to 1 if Odometer is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_DVL_BT_USED (0x00000001u << 19) /*!< Set to 1 if DVL Bottom Tracking is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_DVL_WT_USED (0x00000001u << 20) /*!< Set to 1 if DVL Water Tracking is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_USER_POS_USED (0x00000001u << 21) /*!< Set to 1 if user velocity is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_USER_VEL_USED (0x00000001u << 22) /*!< Set to 1 if user Position is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_USER_HEADING_USED (0x00000001u << 23) /*!< Set to 1 if user Course is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_USBL_USED (0x00000001u << 24) /*!< Set to 1 if USBL / LBL is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_AIR_DATA_USED (0x00000001u << 25) /*!< Set to 1 if AirData (altimeter and/or true airspeed) is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_ZUPT_USED (0x00000001u << 26) /*!< Set to 1 if a ZUPT is used in solution (data used and valid since 3s). */ +#define SBG_ECOM_SOL_ALIGN_VALID (0x00000001u << 27) /*!< Set to 1 if sensor alignment and calibration parameters are valid */ +#define SBG_ECOM_SOL_DEPTH_USED (0x00000001u << 28) /*!< Set to 1 if Depth sensor (for subsea navigation) is used in solution (data used and valid since 3s). */ + +/*! + * Solution filter mode enum. + */ +typedef enum _SbgEComSolutionMode +{ + SBG_ECOM_SOL_MODE_UNINITIALIZED = 0, /*!< The Kalman filter is not initialized and the returned data are all invalid. */ + SBG_ECOM_SOL_MODE_VERTICAL_GYRO = 1, /*!< The Kalman filter only rely on a vertical reference to compute roll and pitch angles. Heading and navigation data drift freely. */ + SBG_ECOM_SOL_MODE_AHRS = 2, /*!< A heading reference is available, the Kalman filter provides full orientation but navigation data drift freely. */ + SBG_ECOM_SOL_MODE_NAV_VELOCITY = 3, /*!< The Kalman filter computes orientation and velocity. Position is freely integrated from velocity estimation. */ + SBG_ECOM_SOL_MODE_NAV_POSITION = 4 /*!< Nominal mode, the Kalman filter computes all parameters (attitude, velocity, position). Absolute position is provided. */ +} SbgEComSolutionMode; + +//----------------------------------------------------------------------// +//- Solution status helpers methods -// +//----------------------------------------------------------------------// + +/*! + * Method used to read the solution mode from a solution status field. + * + * \param[in] status Status uint32_t value to extract the solution mode from it. + * \return The extracted solution mode. + */ +SBG_INLINE SbgEComSolutionMode sbgEComLogEkfGetSolutionMode(uint32_t status) +{ + return (SbgEComSolutionMode)((status >> SBG_ECOM_SOLUTION_MODE_SHIFT) & SBG_ECOM_SOLUTION_MODE_MASK); +} + +/*! + * Method used to write the solution status field. + * + * \param[in] solutionMode The solution mode to set. + * \param[in] masks Bit mask to set. + * \return The build solution status field. + */ +SBG_INLINE uint32_t sbgEComLogEkfBuildSolutionStatus(SbgEComSolutionMode solutionMode, uint32_t masks) +{ + // + // Create the combined status field + // + return ((((uint32_t)solutionMode)&SBG_ECOM_SOLUTION_MODE_MASK) << SBG_ECOM_SOLUTION_MODE_SHIFT) | masks; +} + + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * EKF computed orientation using euler angles. + */ +typedef struct _SbgLogEkfEulerData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + float euler[3]; /*!< Roll, Pitch and Yaw angles in rad. */ + float eulerStdDev[3]; /*!< Roll, Pitch and Yaw angles 1 sigma standard deviation in rad. */ + uint32_t status; /*!< EKF solution status bitmask and enum. */ +} SbgLogEkfEulerData; + +/*! + * EFK computed orientation using quaternion. + */ +typedef struct _SbgLogEkfQuatData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + float quaternion[4]; /*!< Orientation quaternion stored in W, X, Y, Z form. */ + float eulerStdDev[3]; /*!< Roll, Pitch and Yaw angles 1 sigma standard deviation in rad. */ + uint32_t status; /*!< EKF solution status bitmask and enum. */ +} SbgLogEkfQuatData; + +/*! + * EFK computed navigation data. + */ +typedef struct _SbgLogEkfNavData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + float velocity[3]; /*!< North, East, Down velocity in m.s^-1. */ + float velocityStdDev[3]; /*!< North, East, Down velocity 1 sigma standard deviation in m.s^-1. */ + double position[3]; /*!< Latitude, Longitude in degrees positive North and East. + Altitude above Mean Sea Level in meters. */ + float undulation; /*!< Altitude difference between the geoid and the Ellipsoid in meters (Height above Ellipsoid = altitude + undulation). */ + float positionStdDev[3]; /*!< Latitude, longitude and altitude 1 sigma standard deviation in meters. */ + uint32_t status; /*!< EKF solution status bitmask and enum. */ +} SbgLogEkfNavData; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_EKF_EULER message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseEkfEulerData(SbgStreamBuffer *pInputStream, SbgLogEkfEulerData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_EKF_EULER message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteEkfEulerData(SbgStreamBuffer *pOutputStream, const SbgLogEkfEulerData *pInputData); + +/*! + * Parse data for the SBG_ECOM_LOG_EKF_QUAT message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseEkfQuatData(SbgStreamBuffer *pInputStream, SbgLogEkfQuatData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_EKF_QUAT message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteEkfQuatData(SbgStreamBuffer *pOutputStream, const SbgLogEkfQuatData *pInputData); + +/*! + * Parse data for the SBG_ECOM_LOG_EKF_NAV message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseEkfNavData(SbgStreamBuffer *pInputStream, SbgLogEkfNavData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_EKF_NAV message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteEkfNavData(SbgStreamBuffer *pOutputStream, const SbgLogEkfNavData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_EKF_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEvent.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEvent.c new file mode 100644 index 0000000..82ecaff --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEvent.c @@ -0,0 +1,47 @@ +#include "sbgEComBinaryLogEvent.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseEvent(SbgStreamBuffer *pInputStream, SbgLogEvent *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + pOutputData->timeOffset0 = sbgStreamBufferReadUint16LE(pInputStream); + pOutputData->timeOffset1 = sbgStreamBufferReadUint16LE(pInputStream); + pOutputData->timeOffset2 = sbgStreamBufferReadUint16LE(pInputStream); + pOutputData->timeOffset3 = sbgStreamBufferReadUint16LE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteEvent(SbgStreamBuffer *pOutputStream, const SbgLogEvent *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->timeOffset0); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->timeOffset1); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->timeOffset2); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->timeOffset3); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEvent.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEvent.h new file mode 100644 index 0000000..c1c40e0 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogEvent.h @@ -0,0 +1,100 @@ +/*! + * \file sbgEComBinaryLogEvent.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 28 October 2013 + * + * \brief Parse event markers logs used to timestamp external signals. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_EVENT_H +#define SBG_ECOM_BINARY_LOG_EVENT_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log marker events definitions -// +//----------------------------------------------------------------------// + +/*! + * Log market events status mask definitions + */ +#define SBG_ECOM_EVENT_OVERFLOW (0x00000001u << 0) /*!< Set to 1 if we have received events at a higher rate than 1 kHz. */ +#define SBG_ECOM_EVENT_OFFSET_0_VALID (0x00000001u << 1) /*!< Set to 1 if at least two events have been received. */ +#define SBG_ECOM_EVENT_OFFSET_1_VALID (0x00000001u << 2) /*!< Set to 1 if at least three events have been received. */ +#define SBG_ECOM_EVENT_OFFSET_2_VALID (0x00000001u << 3) /*!< Set to 1 if at least four events have been received. */ +#define SBG_ECOM_EVENT_OFFSET_3_VALID (0x00000001u << 4) /*!< Set to 1 if at least five events have been received. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Structure that stores data for the SBG_ECOM_LOG_EVENT_# message. + */ +typedef struct _SbgLogEvent +{ + uint32_t timeStamp; /*!< Measurement time since the sensor power up. */ + uint16_t status; /*!< Events status bitmask. */ + uint16_t timeOffset0; /*!< Time offset for the second received event. */ + uint16_t timeOffset1; /*!< Time offset for the third received event. */ + uint16_t timeOffset2; /*!< Time offset for the fourth received event. */ + uint16_t timeOffset3; /*!< Time offset for the fifth received event. */ +} SbgLogEvent; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_EVENT_# message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseEvent(SbgStreamBuffer *pInputStream, SbgLogEvent *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_EVENT_# message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteEvent(SbgStreamBuffer *pOutputStream, const SbgLogEvent *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_EVENT_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogGps.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogGps.c new file mode 100644 index 0000000..d58e3a6 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogGps.c @@ -0,0 +1,206 @@ +#include "sbgEComBinaryLogGps.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseGpsVelData(SbgStreamBuffer *pInputStream, SbgLogGpsVel *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->timeOfWeek = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->velocity[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocity[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocity[2] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocityAcc[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocityAcc[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->velocityAcc[2] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->course = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->courseAcc = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteGpsVelData(SbgStreamBuffer *pOutputStream, const SbgLogGpsVel *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->status); + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeOfWeek); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocity[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocity[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocity[2]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocityAcc[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocityAcc[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocityAcc[2]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->course); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->courseAcc); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} + +SbgErrorCode sbgEComBinaryLogParseGpsPosData(SbgStreamBuffer *pInputStream, SbgLogGpsPos *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->timeOfWeek = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->latitude = sbgStreamBufferReadDoubleLE(pInputStream); + pOutputData->longitude = sbgStreamBufferReadDoubleLE(pInputStream); + pOutputData->altitude = sbgStreamBufferReadDoubleLE(pInputStream); + pOutputData->undulation = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->latitudeAccuracy = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->longitudeAccuracy = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->altitudeAccuracy = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Test if we have a additional information such as base station id (since version 1.4) + // + if (sbgStreamBufferGetSpace(pInputStream) >= 5) + { + // + // Read the additional information + // + pOutputData->numSvUsed = sbgStreamBufferReadUint8LE(pInputStream); + pOutputData->baseStationId = sbgStreamBufferReadUint16LE(pInputStream); + pOutputData->differentialAge = sbgStreamBufferReadUint16LE(pInputStream); + } + else + { + // + // Default the additional information + // + pOutputData->numSvUsed = 0; + pOutputData->baseStationId = 0xFFFF; + pOutputData->differentialAge = 0xFFFF; + } + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteGpsPosData(SbgStreamBuffer *pOutputStream, const SbgLogGpsPos *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->status); + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeOfWeek); + + sbgStreamBufferWriteDoubleLE(pOutputStream, pInputData->latitude); + sbgStreamBufferWriteDoubleLE(pOutputStream, pInputData->longitude); + sbgStreamBufferWriteDoubleLE(pOutputStream, pInputData->altitude); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->undulation); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->latitudeAccuracy); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->longitudeAccuracy); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->altitudeAccuracy); + + // + // Write the additional information added in version 1.4 + // + sbgStreamBufferWriteUint8LE(pOutputStream, pInputData->numSvUsed); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->baseStationId); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->differentialAge); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} + +SbgErrorCode sbgEComBinaryLogParseGpsHdtData(SbgStreamBuffer *pInputStream, SbgLogGpsHdt *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + pOutputData->timeOfWeek = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->heading = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->headingAccuracy = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->pitch = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->pitchAccuracy = sbgStreamBufferReadFloatLE(pInputStream); + + // + // The baseline field have been added in version 2.0 + // + if (sbgStreamBufferGetSpace(pInputStream) > 0) + { + pOutputData->baseline = sbgStreamBufferReadFloatLE(pInputStream); + } + else + { + pOutputData->baseline = 0.0f; + } + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteGpsHdtData(SbgStreamBuffer *pOutputStream, const SbgLogGpsHdt *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeOfWeek); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->heading); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->headingAccuracy); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->pitch); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->pitchAccuracy); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->baseline); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} + +SbgErrorCode sbgEComBinaryLogParseGpsRawData(SbgStreamBuffer *pInputStream, SbgLogRawData *pOutputData) +{ + return sbgEComBinaryLogParseRawData(pInputStream, pOutputData); +} + +SbgErrorCode sbgEComBinaryLogWriteGpsRawData(SbgStreamBuffer *pOutputStream, const SbgLogRawData *pInputData) +{ + return sbgEComBinaryLogWriteRawData(pOutputStream, pInputData); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogGps.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogGps.h new file mode 100644 index 0000000..1db301d --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogGps.h @@ -0,0 +1,433 @@ +/*! + * \file sbgEComBinaryLogGps.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 20 February 2013 + * + * \brief Parse received GNSS logs such as Position, Velocity and True Heading. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_GPS_H +#define SBG_ECOM_BINARY_LOG_GPS_H + +// sbgCommonLib headers +#include +#include + +// Local headers +#include "sbgEComBinaryLogRawData.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log GPS velocity const definitions -// +//----------------------------------------------------------------------// + +/*! + * Log GPS velocity status and type definitions. + */ +#define SBG_ECOM_GPS_VEL_STATUS_SHIFT (0u) /*!< Shift used to extract the GPS velocity status part. */ +#define SBG_ECOM_GPS_VEL_STATUS_MASK (0x0000003Fu) /*!< Mask used to keep only the GPS velocity status part. */ +#define SBG_ECOM_GPS_VEL_TYPE_SHIFT (6u) /*!< Shift used to extract the GPS velocity type part. */ +#define SBG_ECOM_GPS_VEL_TYPE_MASK (0x0000003Fu) /*!< Mask used to keep only the GPS velocity type part. */ + +//----------------------------------------------------------------------// +//- Log GPS position const definitions -// +//----------------------------------------------------------------------// + +/*! + * GPS position status and type definitions. + */ +#define SBG_ECOM_GPS_POS_STATUS_SHIFT (0u) /*!< Shift used to extract the GPS position status part. */ +#define SBG_ECOM_GPS_POS_STATUS_MASK (0x0000003Fu) /*!< Mask used to keep only the GPS position status part. */ +#define SBG_ECOM_GPS_POS_TYPE_SHIFT (6u) /*!< Shift used to extract the GPS position type part. */ +#define SBG_ECOM_GPS_POS_TYPE_MASK (0x0000003Fu) /*!< Mask used to keep only the GPS position type part. */ + +/*! + * GNSS signals definitions + */ +#define SBG_ECOM_GPS_POS_GPS_L1_USED (0x00000001u << 12) /*!< Set to 1 if GPS L1CA/L1P is used in solution. */ +#define SBG_ECOM_GPS_POS_GPS_L2_USED (0x00000001u << 13) /*!< Set to 1 if GPS L2P/L2C is used in solution. */ +#define SBG_ECOM_GPS_POS_GPS_L5_USED (0x00000001u << 14) /*!< Set to 1 if GPS L5 is used in solution. */ + +#define SBG_ECOM_GPS_POS_GLO_L1_USED (0x00000001u << 15) /*!< Set to 1 if GLONASS L1CA is used in solution. */ +#define SBG_ECOM_GPS_POS_GLO_L2_USED (0x00000001u << 16) /*!< Set to 1 if GLONASS L2C/L2P is used in solution. */ +#define SBG_ECOM_GPS_POS_GLO_L3_USED (0x00000001u << 17) /*!< Set to 1 if GLONASS L3 is used in solution. */ + +#define SBG_ECOM_GPS_POS_GAL_E1_USED (0x00000001u << 18) /*!< Set to 1 if Galileo E1 is used in solution. */ +#define SBG_ECOM_GPS_POS_GAL_E5A_USED (0x00000001u << 19) /*!< Set to 1 if Galileo E5a is used in solution. */ +#define SBG_ECOM_GPS_POS_GAL_E5B_USED (0x00000001u << 20) /*!< Set to 1 if Galileo E5b is used in solution. */ +#define SBG_ECOM_GPS_POS_GAL_E5ALT_USED (0x00000001u << 21) /*!< Set to 1 if Galileo E5 AltBoc is used in solution. */ +#define SBG_ECOM_GPS_POS_GAL_E6_USED (0x00000001u << 22) /*!< Set to 1 if Galileo E6 is used in solution. */ + +#define SBG_ECOM_GPS_POS_BDS_B1_USED (0x00000001u << 23) /*!< Set to 1 if BeiDou B1 is used in solution. */ +#define SBG_ECOM_GPS_POS_BDS_B2_USED (0x00000001u << 24) /*!< Set to 1 if BeiDou B2 is used in solution. */ +#define SBG_ECOM_GPS_POS_BDS_B3_USED (0x00000001u << 25) /*!< Set to 1 if BeiDou B3 is used in solution. */ + +#define SBG_ECOM_GPS_POS_QZSS_L1_USED (0x00000001u << 26) /*!< Set to 1 if QZSS L1CA is used in solution. */ +#define SBG_ECOM_GPS_POS_QZSS_L2_USED (0x00000001u << 27) /*!< Set to 1 if QZSS L2C is used in solution. */ +#define SBG_ECOM_GPS_POS_QZSS_L5_USED (0x00000001u << 28) /*!< Set to 1 if QZSS L5 is used in solution. */ + +//----------------------------------------------------------------------// +//- Log GPS HDT const definitions -// +//----------------------------------------------------------------------// + +/*! + * GPS HDT status definitions. + */ +#define SBG_ECOM_GPS_HDT_STATUS_SHIFT (0u) /*!< Shift used to extract the GPS HDT status part. */ +#define SBG_ECOM_GPS_HDT_STATUS_MASK (0x0000003Fu) /*!< Mask used to keep only the GPS HDT status part. */ + +/*! + * GPS HDT status bitmasks + */ +#define SBG_ECOM_GPS_HDT_BASELINE_VALID (0x0001 << 6) /*!< Set to 1 if the baseline length field is filled and valid. */ + +//----------------------------------------------------------------------// +//- Log GPS velocity enums definitions -// +//----------------------------------------------------------------------// + +/*! + * GPS velocity status definitions. + */ +typedef enum _SbgEComGpsVelStatus +{ + SBG_ECOM_VEL_SOL_COMPUTED = 0, /*!< A valid solution has been computed. */ + SBG_ECOM_VEL_INSUFFICIENT_OBS = 1, /*!< Not enough valid SV to compute a solution. */ + SBG_ECOM_VEL_INTERNAL_ERROR = 2, /*!< An internal error has occurred. */ + SBG_ECOM_VEL_LIMIT = 3 /*!< Velocity limit exceeded. */ +} SbgEComGpsVelStatus; + +/*! + * GPS velocity types definitions. + */ +typedef enum _SbgEComGpsVelType +{ + SBG_ECOM_VEL_NO_SOLUTION = 0, /*!< No valid velocity solution available. */ + SBG_ECOM_VEL_UNKNOWN_TYPE = 1, /*!< An unknown solution type has been computed. */ + SBG_ECOM_VEL_DOPPLER = 2, /*!< A Doppler velocity has been computed. */ + SBG_ECOM_VEL_DIFFERENTIAL = 3 /*!< A differential velocity has been computed between two positions. */ +} SbgEComGpsVelType; + +//----------------------------------------------------------------------// +//- Log GPS position enums definitions -// +//----------------------------------------------------------------------// + +/*! + * GPS position status definitions. + */ +typedef enum _SbgEComGpsPosStatus +{ + SBG_ECOM_POS_SOL_COMPUTED = 0, /*!< A valid solution has been computed. */ + SBG_ECOM_POS_INSUFFICIENT_OBS = 1, /*!< Not enough valid SV to compute a solution. */ + SBG_ECOM_POS_INTERNAL_ERROR = 2, /*!< An internal error has occurred. */ + SBG_ECOM_POS_HEIGHT_LIMIT = 3 /*!< The height limit has been exceeded. */ +} SbgEComGpsPosStatus; + +/*! + * GPS position types definitions. + */ +typedef enum _SbgEComGpsPosType +{ + SBG_ECOM_POS_NO_SOLUTION = 0, /*!< No valid solution available. */ + SBG_ECOM_POS_UNKNOWN_TYPE = 1, /*!< An unknown solution type has been computed. */ + SBG_ECOM_POS_SINGLE = 2, /*!< Single point solution position. */ + SBG_ECOM_POS_PSRDIFF = 3, /*!< Standard Pseudorange Differential Solution (DGPS). */ + SBG_ECOM_POS_SBAS = 4, /*!< SBAS satellite used for differential corrections. */ + SBG_ECOM_POS_OMNISTAR = 5, /*!< Omnistar VBS Position (L1 sub-meter). */ + SBG_ECOM_POS_RTK_FLOAT = 6, /*!< Floating RTK ambiguity solution (20 cms RTK). */ + SBG_ECOM_POS_RTK_INT = 7, /*!< Integer RTK ambiguity solution (2 cms RTK). */ + SBG_ECOM_POS_PPP_FLOAT = 8, /*!< Precise Point Positioning with float ambiguities. */ + SBG_ECOM_POS_PPP_INT = 9, /*!< Precise Point Positioning with fixed ambiguities. */ + SBG_ECOM_POS_FIXED = 10 /*!< Fixed location solution position. */ +} SbgEComGpsPosType; + +//----------------------------------------------------------------------// +//- Log GPS HDT enums definitions -// +//----------------------------------------------------------------------// + +/*! + * GPS HDT status definitions. + */ +typedef enum _SbgEComGpsHdtStatus +{ + SBG_ECOM_HDT_SOL_COMPUTED = 0, /*!< A valid solution has been computed. */ + SBG_ECOM_HDT_INSUFFICIENT_OBS = 1, /*!< Not enough valid SV to compute a solution. */ + SBG_ECOM_HDT_INTERNAL_ERROR = 2, /*!< An internal error has occurred. */ + SBG_ECOM_HDT_HEIGHT_LIMIT = 3 /*!< The height limit has been exceeded. */ +} SbgEComGpsHdtStatus; + +//----------------------------------------------------------------------// +//- Helpers methods for velocity status access -// +//----------------------------------------------------------------------// + +/*! + * Method used to read GPS velocity status from a status field. + * + * \param[in] status Status uint32_t value to extract the velocity status from it. + * \return The extracted velocity status. + */ +SBG_INLINE SbgEComGpsVelStatus sbgEComLogGpsVelGetStatus(uint32_t status) +{ + return (SbgEComGpsVelStatus)((status >> SBG_ECOM_GPS_VEL_STATUS_SHIFT) & SBG_ECOM_GPS_VEL_STATUS_MASK); +} + +/*! + * Method used to read GPS velocity type from a status field. + * + * \param[in] status Status uint32_t value to extract the velocity type from it. + * \return The extracted velocity type. + */ +SBG_INLINE SbgEComGpsVelType sbgEComLogGpsVelGetType(uint32_t status) +{ + return (SbgEComGpsVelType)((status >> SBG_ECOM_GPS_VEL_TYPE_SHIFT) & SBG_ECOM_GPS_VEL_TYPE_MASK); +} + +/*! + * Method used to write the GPS velocity status to a status field. + * + * \param[in] status The velocity status to set. + * \param[in] type The velocity type to set. + * \return The build GpsVelData status field. + */ +SBG_INLINE uint32_t sbgEComLogGpsVelBuildStatus(SbgEComGpsVelStatus status, SbgEComGpsVelType type) +{ + // + // Create the combined status field + // + return ((((uint32_t)status)&SBG_ECOM_GPS_VEL_STATUS_MASK) << SBG_ECOM_GPS_VEL_STATUS_SHIFT) | + ((((uint32_t)type)&SBG_ECOM_GPS_VEL_TYPE_MASK) << SBG_ECOM_GPS_VEL_TYPE_SHIFT); +} + +//----------------------------------------------------------------------// +//- Helpers methods for position status access -// +//----------------------------------------------------------------------// + +/*! + * Method used to read GPS position status from a status field. + * + * \param[in] status Status uint32_t value to extract the position status from it. + * \return The extracted position status. + */ +SBG_INLINE SbgEComGpsPosStatus sbgEComLogGpsPosGetStatus(uint32_t status) +{ + return (SbgEComGpsPosStatus)((status >> SBG_ECOM_GPS_POS_STATUS_SHIFT) & SBG_ECOM_GPS_POS_STATUS_MASK); +} + +/*! + * Method used to read GPS position type from a status field. + * + * \param[in] status Status uint32_t value to extract the position type from it. + * \return The extracted position type. + */ +SBG_INLINE SbgEComGpsPosType sbgEComLogGpsPosGetType(uint32_t status) +{ + return (SbgEComGpsPosType)((status >> SBG_ECOM_GPS_POS_TYPE_SHIFT) & SBG_ECOM_GPS_POS_TYPE_MASK); +} + +/*! + * Method used to write the GPS position status to a status field. + * + * \param[in] status The position status to set. + * \param[in] type The position type to set. + * \param[in] masks Bit mask to set. + * \return The build GpsPosData status field. + */ +SBG_INLINE uint32_t sbgEComLogGpsPosBuildStatus(SbgEComGpsPosStatus status, SbgEComGpsPosType type, uint32_t masks) +{ + // + // Create the combined status field + // + return ((((uint32_t)status)&SBG_ECOM_GPS_POS_STATUS_MASK) << SBG_ECOM_GPS_POS_STATUS_SHIFT) | + ((((uint32_t)type)&SBG_ECOM_GPS_POS_TYPE_MASK) << SBG_ECOM_GPS_POS_TYPE_SHIFT) | masks; +} + +//----------------------------------------------------------------------// +//- Helpers methods for HDT status access -// +//----------------------------------------------------------------------// + +/*! + * Method used to read GPS HDT status from a status field. + * + * \param[in] status Status uint32_t value to extract the HDT status from it. + * \return The extracted position status. + */ +SBG_INLINE SbgEComGpsHdtStatus sbgEComLogGpsHdtGetStatus(uint32_t status) +{ + return (SbgEComGpsHdtStatus)((status >> SBG_ECOM_GPS_HDT_STATUS_SHIFT) & SBG_ECOM_GPS_HDT_STATUS_MASK); +} + +/*! + * Method used to write the GPS HDT status to a status field. + * + * \param[in] status The HDT status to set. + * \param[in] masks Bit mask to set. + * \return The build GpsPosData status field. + */ +SBG_INLINE uint32_t sbgEComLogGpsHdtBuildStatus(SbgEComGpsHdtStatus status, uint32_t masks) +{ + // + // Create the combined status field + // + return ((((uint32_t)status)&SBG_ECOM_GPS_HDT_STATUS_MASK) << SBG_ECOM_GPS_HDT_STATUS_SHIFT) | masks; +} + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Structure that stores data for the SBG_ECOM_LOG_GPS#_VEL message. + */ +typedef struct _SbgLogGpsVel +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint32_t status; /*!< GPS velocity status, type and bitmask. */ + uint32_t timeOfWeek; /*!< GPS time of week in ms. */ + float velocity[3]; /*!< GPS North, East, Down velocity in m.s^-1. */ + float velocityAcc[3]; /*!< GPS North, East, Down velocity 1 sigma accuracy in m.s^-1. */ + float course; /*!< Track ground course in degrees. */ + float courseAcc; /*!< Course accuracy in degrees. */ +} SbgLogGpsVel; + +/*! + * Structure that stores data for the SBG_ECOM_LOG_GPS#_POS message. + */ +typedef struct _SbgLogGpsPos +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint32_t status; /*!< GPS position status, type and bitmask. */ + uint32_t timeOfWeek; /*!< GPS time of week in ms. */ + double latitude; /*!< Latitude in degrees, positive north. */ + double longitude; /*!< Longitude in degrees, positive east. */ + double altitude; /*!< Altitude above Mean Sea Level in meters. */ + float undulation; /*!< Altitude difference between the geoid and the Ellipsoid in meters (Height above Ellipsoid = altitude + undulation). */ + float latitudeAccuracy; /*!< 1 sigma latitude accuracy in meters. */ + float longitudeAccuracy; /*!< 1 sigma longitude accuracy in meters. */ + float altitudeAccuracy; /*!< 1 sigma altitude accuracy in meters. */ + uint8_t numSvUsed; /*!< Number of space vehicles used to compute the solution (since version 1.4). */ + uint16_t baseStationId; /*!< Base station id for differential corrections (0-4095). Set to 0xFFFF if differential corrections are not used (since version 1.4). */ + uint16_t differentialAge; /*!< Differential correction age in 0.01 seconds. Set to 0XFFFF if differential corrections are not used (since version 1.4). */ +} SbgLogGpsPos; + +/*! + * Structure that stores data for the SBG_ECOM_LOG_GPS#_HDT message. + */ +typedef struct _SbgLogGpsHdt +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< GPS HDT status, type and bitmask. */ + uint32_t timeOfWeek; /*!< GPS time of week in ms. */ + float heading; /*!< GPS true heading in degrees. */ + float headingAccuracy; /*!< 1 sigma GPS true heading accuracy in degrees. */ + float pitch; /*!< GPS pitch angle measured from the master to the rover in degrees. */ + float pitchAccuracy; /*!< 1 signa GPS pitch angle accuarcy in degrees. */ + float baseline; /*!< The distance between the main and aux antenna in meters. */ +} SbgLogGpsHdt; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_GPS#_VEL message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseGpsVelData(SbgStreamBuffer *pInputStream, SbgLogGpsVel *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_GPS#_VEL message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteGpsVelData(SbgStreamBuffer *pOutputStream, const SbgLogGpsVel *pInputData); + +/*! + * Parse data for the SBG_ECOM_LOG_GPS#_POS message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseGpsPosData(SbgStreamBuffer *pInputStream, SbgLogGpsPos *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_GPS#_POS message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteGpsPosData(SbgStreamBuffer *pOutputStream, const SbgLogGpsPos *pInputData); + +/*! + * Parse data for the SBG_ECOM_LOG_GPS#_HDT message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseGpsHdtData(SbgStreamBuffer *pInputStream, SbgLogGpsHdt *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_GPS#_HDT message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteGpsHdtData(SbgStreamBuffer *pOutputStream, const SbgLogGpsHdt *pInputData); + +/*! + * Parse data for the SBG_ECOM_LOG_GPS#_RAW message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseGpsRawData(SbgStreamBuffer *pInputStream, SbgLogRawData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_GPS#_RAW message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteGpsRawData(SbgStreamBuffer *pOutputStream, const SbgLogRawData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_GPS_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogImu.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogImu.c new file mode 100644 index 0000000..279daf6 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogImu.c @@ -0,0 +1,206 @@ +#include "sbgEComBinaryLogImu.h" + +//----------------------------------------------------------------------// +//- Public getters -// +//----------------------------------------------------------------------// + +float sbgLogImuShortGetDeltaAngle(const SbgLogImuShort *pImuShort, size_t idx) +{ + assert(pImuShort); + assert(idx < 3); + + return pImuShort->deltaAngle[idx] / 67108864.0f; +} + +float sbgLogImuShortGetDeltaVelocity(const SbgLogImuShort *pImuShort, size_t idx) +{ + assert(pImuShort); + assert(idx < 3); + + return pImuShort->deltaVelocity[idx] / 1048576.0f; +} + +float sbgLogImuShortGetTemperature(const SbgLogImuShort *pImuShort) +{ + assert(pImuShort); + + return pImuShort->temperature / 256.0f; +} + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseImuData(SbgStreamBuffer *pInputStream, SbgLogImuData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + + pOutputData->accelerometers[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->accelerometers[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->accelerometers[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->gyroscopes[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->gyroscopes[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->gyroscopes[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->temperature = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->deltaVelocity[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->deltaVelocity[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->deltaVelocity[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->deltaAngle[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->deltaAngle[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->deltaAngle[2] = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteImuData(SbgStreamBuffer *pOutputStream, const SbgLogImuData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->accelerometers[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->accelerometers[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->accelerometers[2]); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->gyroscopes[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->gyroscopes[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->gyroscopes[2]); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->temperature); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->deltaVelocity[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->deltaVelocity[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->deltaVelocity[2]); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->deltaAngle[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->deltaAngle[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->deltaAngle[2]); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} + +SbgErrorCode sbgEComBinaryLogParseImuShort(SbgStreamBuffer *pInputStream, SbgLogImuShort *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + + pOutputData->deltaVelocity[0] = sbgStreamBufferReadInt32LE(pInputStream); + pOutputData->deltaVelocity[1] = sbgStreamBufferReadInt32LE(pInputStream); + pOutputData->deltaVelocity[2] = sbgStreamBufferReadInt32LE(pInputStream); + + pOutputData->deltaAngle[0] = sbgStreamBufferReadInt32LE(pInputStream); + pOutputData->deltaAngle[1] = sbgStreamBufferReadInt32LE(pInputStream); + pOutputData->deltaAngle[2] = sbgStreamBufferReadInt32LE(pInputStream); + + pOutputData->temperature = sbgStreamBufferReadInt16LE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteImuShort(SbgStreamBuffer *pOutputStream, const SbgLogImuShort *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + + sbgStreamBufferWriteInt32LE(pOutputStream, pInputData->deltaVelocity[0]); + sbgStreamBufferWriteInt32LE(pOutputStream, pInputData->deltaVelocity[1]); + sbgStreamBufferWriteInt32LE(pOutputStream, pInputData->deltaVelocity[2]); + + sbgStreamBufferWriteInt32LE(pOutputStream, pInputData->deltaAngle[0]); + sbgStreamBufferWriteInt32LE(pOutputStream, pInputData->deltaAngle[1]); + sbgStreamBufferWriteInt32LE(pOutputStream, pInputData->deltaAngle[2]); + + sbgStreamBufferWriteInt16LE(pOutputStream, pInputData->temperature); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} + +SbgErrorCode sbgEComBinaryLogParseFastImuData(SbgStreamBuffer *pInputStream, SbgLogFastImuData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + + pOutputData->accelerometers[0] = (float)sbgStreamBufferReadInt16LE(pInputStream) * 0.01f; + pOutputData->accelerometers[1] = (float)sbgStreamBufferReadInt16LE(pInputStream) * 0.01f; + pOutputData->accelerometers[2] = (float)sbgStreamBufferReadInt16LE(pInputStream) * 0.01f; + + pOutputData->gyroscopes[0] = (float)sbgStreamBufferReadInt16LE(pInputStream) * 0.001f; + pOutputData->gyroscopes[1] = (float)sbgStreamBufferReadInt16LE(pInputStream) * 0.001f; + pOutputData->gyroscopes[2] = (float)sbgStreamBufferReadInt16LE(pInputStream) * 0.001f; + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteFastImuData(SbgStreamBuffer *pOutputStream, const SbgLogFastImuData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + + sbgStreamBufferWriteInt16LE(pOutputStream, (int16_t)(pInputData->accelerometers[0] * 100.0f)); + sbgStreamBufferWriteInt16LE(pOutputStream, (int16_t)(pInputData->accelerometers[1] * 100.0f)); + sbgStreamBufferWriteInt16LE(pOutputStream, (int16_t)(pInputData->accelerometers[2] * 100.0f)); + + sbgStreamBufferWriteInt16LE(pOutputStream, (int16_t)(pInputData->gyroscopes[0] * 1000.0f)); + sbgStreamBufferWriteInt16LE(pOutputStream, (int16_t)(pInputData->gyroscopes[1] * 1000.0f)); + sbgStreamBufferWriteInt16LE(pOutputStream, (int16_t)(pInputData->gyroscopes[2] * 1000.0f)); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogImu.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogImu.h new file mode 100644 index 0000000..4ad17a8 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogImu.h @@ -0,0 +1,199 @@ +/*! + * \file sbgEComBinaryLogImu.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 25 February 2013 + * + * \brief Parse IMU (Inertial Measurement Unit) measurement logs. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_IMU_H +#define SBG_ECOM_BINARY_LOG_IMU_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log Inertial Data definitions -// +//----------------------------------------------------------------------// + +/*! + * Log inertial data status mask definitions + */ +#define SBG_ECOM_IMU_COM_OK (0x00000001u << 0) /*!< Set to 1 if the communication with the IMU is ok. */ +#define SBG_ECOM_IMU_STATUS_BIT (0x00000001u << 1) /*!< Set to 1 if the IMU passes general Built in Tests (calibration, CPU, ...). */ + +#define SBG_ECOM_IMU_ACCEL_X_BIT (0x00000001u << 2) /*!< Set to 1 if the accelerometer X passes Built In Test. */ +#define SBG_ECOM_IMU_ACCEL_Y_BIT (0x00000001u << 3) /*!< Set to 1 if the accelerometer Y passes Built In Test. */ +#define SBG_ECOM_IMU_ACCEL_Z_BIT (0x00000001u << 4) /*!< Set to 1 if the accelerometer Z passes Built In Test. */ + +#define SBG_ECOM_IMU_GYRO_X_BIT (0x00000001u << 5) /*!< Set to 1 if the gyroscope X passes Built In Test. */ +#define SBG_ECOM_IMU_GYRO_Y_BIT (0x00000001u << 6) /*!< Set to 1 if the gyroscope Y passes Built In Test. */ +#define SBG_ECOM_IMU_GYRO_Z_BIT (0x00000001u << 7) /*!< Set to 1 if the gyroscope Z passes Built In Test. */ + +#define SBG_ECOM_IMU_ACCELS_IN_RANGE (0x00000001u << 8) /*!< Set to 1 if all accelerometers are within operating range. */ +#define SBG_ECOM_IMU_GYROS_IN_RANGE (0x00000001u << 9) /*!< Set to 1 if all gyroscopes are within operating range. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Structure that stores data for the SBG_ECOM_LOG_IMU_DATA message. + */ +typedef struct _SbgLogImuData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< IMU status bitmask. */ + float accelerometers[3]; /*!< X, Y, Z accelerometers in m.s^-2. */ + float gyroscopes[3]; /*!< X, Y, Z gyroscopes in rad.s^-1. */ + float temperature; /*!< Internal temperature in °C. */ + float deltaVelocity[3]; /*!< X, Y, Z delta velocity in m.s^-2. */ + float deltaAngle[3]; /*!< X, Y, Z delta angle in rad.s^-1. */ +} SbgLogImuData; + +/*! + * Structure that stores data for the SBG_ECOM_LOG_IMU_SHORT message. + * This message is only sent asynchronously and is the preferred log for post processing. + */ +typedef struct _SbgLogImuShort +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< IMU status bitmask. */ + int32_t deltaVelocity[3]; /*!< X, Y, Z delta velocity. Unit is 1048576 LSB for 1 m.s^-2. */ + int32_t deltaAngle[3]; /*!< X, Y, Z delta angle. Unit is 67108864 LSB for 1 rad.s^-1. */ + int16_t temperature; /*!< IMU average temperature. Unit is 256 LSB for 1°C. */ +} SbgLogImuShort; + +/*! + * Structure that stores the data for SBG_ECOM_LOG_FAST_IMU_DATA message + */ +typedef struct _SbgLogFastImuData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< IMU status bitmask. */ + float accelerometers[3]; /*!< X, Y, Z accelerometers in m.s^-2. */ + float gyroscopes[3]; /*!< X, Y, Z gyroscopes in rad.s^-1. */ +} SbgLogFastImuData; + +//----------------------------------------------------------------------// +//- Public getters -// +//----------------------------------------------------------------------// + +/*! + * Return from an IMU Short log, the X, Y or Z delta angle value in rad.s^-1 + * + * \param[in] pImuShort Input IMU short message instance. + * \param[in] idx The component to return from 0 to 2. + * \return The delta angle value converted in rad.s^-1. + */ +float sbgLogImuShortGetDeltaAngle(const SbgLogImuShort *pImuShort, size_t idx); + +/*! + * Return from an IMU Short log, the X, Y or Z delta velocity value in m.s^-2 + * + * \param[in] pImuShort Input IMU short message instance. + * \param[in] idx The component to return from 0 to 2. + * \return The delta velocity value converted in m.s^-2. + */ +float sbgLogImuShortGetDeltaVelocity(const SbgLogImuShort *pImuShort, size_t idx); + +/*! + * Return from an IMU Short log, the temperature in °C + * + * \param[in] pImuShort Input IMU short message instance. + * \return The converted temperature in °C + */ +float sbgLogImuShortGetTemperature(const SbgLogImuShort *pImuShort); + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_IMU_DATA message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseImuData(SbgStreamBuffer *pInputStream, SbgLogImuData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_IMU_DATA message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteImuData(SbgStreamBuffer *pOutputStream, const SbgLogImuData *pInputData); + +/*! + * Parse data for the SBG_ECOM_LOG_IMU_SHORT message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseImuShort(SbgStreamBuffer *pInputStream, SbgLogImuShort *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_IMU_SHORT message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteImuShort(SbgStreamBuffer *pOutputStream, const SbgLogImuShort *pInputData); + +/*! + * Parse data for the SBG_ECOM_LOG_FAST_IMU_DATA message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseFastImuData(SbgStreamBuffer *pInputStream, SbgLogFastImuData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_FAST_IMU_DATA message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteFastImuData(SbgStreamBuffer *pOutputStream, const SbgLogFastImuData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_IMU_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogMag.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogMag.c new file mode 100644 index 0000000..efa30d5 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogMag.c @@ -0,0 +1,89 @@ +#include "sbgEComBinaryLogMag.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseMagData(SbgStreamBuffer *pInputStream, SbgLogMag *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + + pOutputData->magnetometers[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->magnetometers[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->magnetometers[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->accelerometers[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->accelerometers[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->accelerometers[2] = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteMagData(SbgStreamBuffer *pOutputStream, const SbgLogMag *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->magnetometers[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->magnetometers[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->magnetometers[2]); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->accelerometers[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->accelerometers[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->accelerometers[2]); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} + +SbgErrorCode sbgEComBinaryLogParseMagCalibData(SbgStreamBuffer *pInputStream, SbgLogMagCalib *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->reserved = sbgStreamBufferReadUint16LE(pInputStream); + + // + // Read the raw magnetic calibration data buffer + // + return sbgStreamBufferReadBuffer(pInputStream, pOutputData->magData, sizeof(pOutputData->magData)); +} + +SbgErrorCode sbgEComBinaryLogWriteMagCalibData(SbgStreamBuffer *pOutputStream, const SbgLogMagCalib *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->reserved); + + // + // Write the raw magnetic calibration data buffer + // + return sbgStreamBufferWriteBuffer(pOutputStream, pInputData->magData, sizeof(pInputData->magData)); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogMag.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogMag.h new file mode 100644 index 0000000..4a52bc8 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogMag.h @@ -0,0 +1,133 @@ +/*! + * \file sbgEComBinaryLogMag.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 12 March 2013 + * + * \brief Parse magnetic field measurements logs. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_MAG_H +#define SBG_ECOM_BINARY_LOG_MAG_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log magnetometers status definitions -// +//----------------------------------------------------------------------// + +/*! + * Log magnetometer data status mask definitions + */ +#define SBG_ECOM_MAG_MAG_X_BIT (0x00000001u << 0) /*!< Set to 1 if the magnetometer X passes Built In Test. */ +#define SBG_ECOM_MAG_MAG_Y_BIT (0x00000001u << 1) /*!< Set to 1 if the magnetometer Y passes Built In Test. */ +#define SBG_ECOM_MAG_MAG_Z_BIT (0x00000001u << 2) /*!< Set to 1 if the magnetometer Z passes Built In Test. */ + +#define SBG_ECOM_MAG_ACCEL_X_BIT (0x00000001u << 3) /*!< Set to 1 if the accelerometer X passes Built In Test. */ +#define SBG_ECOM_MAG_ACCEL_Y_BIT (0x00000001u << 4) /*!< Set to 1 if the accelerometer Y passes Built In Test. */ +#define SBG_ECOM_MAG_ACCEL_Z_BIT (0x00000001u << 5) /*!< Set to 1 if the accelerometer Z passes Built In Test. */ + +#define SBG_ECOM_MAG_MAGS_IN_RANGE (0x00000001u << 6) /*!< Set to 1 if all magnetometers are within operating range. */ +#define SBG_ECOM_MAG_ACCELS_IN_RANGE (0x00000001u << 7) /*!< Set to 1 if all accelerometers are within operating range. */ + +#define SBG_ECOM_MAG_CALIBRATION_OK (0x00000001u << 8) /*!< Set to 1 if the magnetometers seems to be calibrated. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Structure that stores data for the SBG_ECOM_LOG_MAG message. + */ +typedef struct _SbgLogMag +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< Magnetometer status bitmask. */ + float magnetometers[3]; /*!< X, Y, Z magnetometer data in A.U. */ + float accelerometers[3]; /*!< X, Y, Z accelerometers in m.s^-2. */ +} SbgLogMag; + +/*! + * Structure that stores data for the SBG_ECOM_LOG_MAG_CALIB message. + */ +typedef struct _SbgLogMagCalib +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t reserved; /*!< Reserved for future use. */ + uint8_t magData[16]; /*!< Magnetometers calibration data. */ +} SbgLogMagCalib; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_MAG message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseMagData(SbgStreamBuffer *pInputStream, SbgLogMag *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_MAG message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteMagData(SbgStreamBuffer *pOutputStream, const SbgLogMag *pInputData); + +/*! + * Parse data for the SBG_ECOM_LOG_MAG_CALIB message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseMagCalibData(SbgStreamBuffer *pInputStream, SbgLogMagCalib *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_MAG_CALIB message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteMagCalibData(SbgStreamBuffer *pOutputStream, const SbgLogMagCalib *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_MAG_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogOdometer.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogOdometer.c new file mode 100644 index 0000000..075337c --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogOdometer.c @@ -0,0 +1,43 @@ +#include "sbgEComBinaryLogOdometer.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseOdometerData(SbgStreamBuffer *pInputStream, SbgLogOdometerData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + + pOutputData->velocity = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteOdometerData(SbgStreamBuffer *pOutputStream, const SbgLogOdometerData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->velocity); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogOdometer.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogOdometer.h new file mode 100644 index 0000000..a7b3f69 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogOdometer.h @@ -0,0 +1,94 @@ +/*! + * \file sbgEComBinaryLogOdometer.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 25 February 2013 + * + * \brief Parse recevied odometer/DMI velocity measurement logs. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_ODOMETER_H +#define SBG_ECOM_BINARY_LOG_ODOMETER_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log odometer status definitions -// +//----------------------------------------------------------------------// + +/*! + * Odometer / velocity status mask definitions. + */ +#define SBG_ECOM_ODO_REAL_MEAS (0x0001 << 0) /*!< Set to 1 if this log comes from a real pulse measurement or from a timeout. */ +#define SBG_ECOM_ODO_TIME_SYNC (0x0001 << 1) /*!< Set to 1 if the velocity information is correctly time synchronized. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Log structure for odometer data. + */ +typedef struct _SbgLogOdometerData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< Odometer velocity status bitmask. */ + float velocity; /*!< Velocity in m.s^-1 in the odometer direction. */ +} SbgLogOdometerData; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_ODO_VEL message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseOdometerData(SbgStreamBuffer *pInputStream, SbgLogOdometerData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_ODO_VEL message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteOdometerData(SbgStreamBuffer *pOutputStream, const SbgLogOdometerData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_ODOMETER_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRawData.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRawData.c new file mode 100644 index 0000000..71ed37f --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRawData.c @@ -0,0 +1,40 @@ +// sbgCommonLib headers +#include + +// Local headers +#include "sbgEComBinaryLogRawData.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseRawData(SbgStreamBuffer *pInputStream, SbgLogRawData *pOutputData) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + size_t payloadSize; + + assert(pInputStream); + assert(pOutputData); + + payloadSize = sbgStreamBufferGetSize(pInputStream); + + if (payloadSize <= SBG_ECOM_RAW_DATA_MAX_BUFFER_SIZE) + { + errorCode = sbgStreamBufferReadBuffer(pInputStream, pOutputData->rawBuffer, payloadSize); + pOutputData->bufferSize = payloadSize; + } + else + { + errorCode = SBG_BUFFER_OVERFLOW; + } + + return errorCode; +} + +SbgErrorCode sbgEComBinaryLogWriteRawData(SbgStreamBuffer *pOutputStream, const SbgLogRawData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + return sbgStreamBufferWriteBuffer(pOutputStream, pInputData->rawBuffer, pInputData->bufferSize); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRawData.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRawData.h new file mode 100644 index 0000000..57108c7 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRawData.h @@ -0,0 +1,89 @@ +/*! + * \file sbgEComBinaryLogRawData.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 16 November 2020 + * + * \brief Parse logs used to store a binary stream such as RAW GNSS data. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_RAW_DATA_H +#define SBG_ECOM_BINARY_LOG_RAW_DATA_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log raw Data const definitions -// +//----------------------------------------------------------------------// + +#define SBG_ECOM_RAW_DATA_MAX_BUFFER_SIZE (4086u) /*!< Maximum buffer size in bytes that can be stored in the raw data log. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Structure that stores raw data message. + */ +typedef struct _SbgLogRawData +{ + uint8_t rawBuffer[SBG_ECOM_RAW_DATA_MAX_BUFFER_SIZE]; /*!< Buffer that contains raw data. */ + size_t bufferSize; /*!< Raw buffer size in bytes. */ +} SbgLogRawData; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse raw data message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseRawData(SbgStreamBuffer *pInputStream, SbgLogRawData *pOutputData); + +/*! + * Write raw data message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteRawData(SbgStreamBuffer *pOutputStream, const SbgLogRawData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_RAW_DATA_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRtcm.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRtcm.c new file mode 100644 index 0000000..fcfce45 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRtcm.c @@ -0,0 +1,19 @@ +// sbgCommonLib headers +#include + +// Local headers +#include "sbgEComBinaryLogRtcm.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseRtcmRawData(SbgStreamBuffer *pInputStream, SbgLogRawData *pOutputData) +{ + return sbgEComBinaryLogParseRawData(pInputStream, pOutputData); +} + +SbgErrorCode sbgEComBinaryLogWriteRtcmRawData(SbgStreamBuffer *pOutputStream, const SbgLogRawData *pInputData) +{ + return sbgEComBinaryLogWriteRawData(pOutputStream, pInputData); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRtcm.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRtcm.h new file mode 100644 index 0000000..00e38bf --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogRtcm.h @@ -0,0 +1,73 @@ +/*! + * \file sbgEComBinaryLogRtcm.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 16 November 2020 + * + * \brief Parse RTCM data stream logs as received by the INS. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_RTCM_H +#define SBG_ECOM_BINARY_LOG_RTCM_H + +// sbgCommonLib headers +#include +#include + +// Local headers +#include "sbgEComBinaryLogRawData.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_RTCM_RAW message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseRtcmRawData(SbgStreamBuffer *pInputStream, SbgLogRawData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_RTCM_RAW message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteRtcmRawData(SbgStreamBuffer *pOutputStream, const SbgLogRawData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_RTCM_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogSat.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogSat.c new file mode 100644 index 0000000..503c0bc --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogSat.c @@ -0,0 +1,865 @@ +/*! + * \file sbgEComBinaryLogSat.h + * \author SBG Systems + * \date 1 March 2022 + * + * \brief Handle binary satellite logs. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComBinaryLogSat.h" + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +#define SBG_ECOM_LOG_SAT_TRACKING_STATUS_OFFSET (0) /*!< Offset of the tracking status field, in bits. */ +#define SBG_ECOM_LOG_SAT_TRACKING_STATUS_WIDTH (3) /*!< Width of the tracking status field, in bits. */ +#define SBG_ECOM_LOG_SAT_TRACKING_STATUS_MASK ((1u << SBG_ECOM_LOG_SAT_TRACKING_STATUS_WIDTH) - 1) /*!< Tracking status field mask. */ + +#define SBG_ECOM_LOG_SAT_HEALTH_STATUS_OFFSET (3) /*!< Offset of the health status field, in bits. */ +#define SBG_ECOM_LOG_SAT_HEALTH_STATUS_WIDTH (2) /*!< Width of the health status field, in bits. */ +#define SBG_ECOM_LOG_SAT_HEALTH_STATUS_MASK ((1u << SBG_ECOM_LOG_SAT_HEALTH_STATUS_WIDTH) - 1) /*!< Health status field mask. */ + +#define SBG_ECOM_LOG_SAT_ELEVATION_STATUS_OFFSET (5) /*!< Offset of the elevation status field, in bits. */ +#define SBG_ECOM_LOG_SAT_ELEVATION_STATUS_WIDTH (2) /*!< Width of the elevation status field, in bits. */ +#define SBG_ECOM_LOG_SAT_ELEVATION_STATUS_MASK ((1u << SBG_ECOM_LOG_SAT_ELEVATION_STATUS_WIDTH) - 1) /*!< Elevation status field mask. */ + +#define SBG_ECOM_LOG_SAT_CONSTELLATION_ID_OFFSET (7) /*!< Offset of the constellation ID field, in bits. */ +#define SBG_ECOM_LOG_SAT_CONSTELLATION_ID_WIDTH (4) /*!< Width of the constellation ID field, in bits. */ +#define SBG_ECOM_LOG_SAT_CONSTELLATION_ID_MASK ((1u << SBG_ECOM_LOG_SAT_CONSTELLATION_ID_WIDTH) - 1) /*!< Constellation ID field mask. */ + +#define SBG_ECOM_LOG_SAT_SIGNAL_SNR_VALID (1u << 5) /*!< Set if the SNR value is valid. */ + +//----------------------------------------------------------------------// +//- Private functions -// +//----------------------------------------------------------------------// + +/*! + * Get a bit field from a set of flags. + * + * \param[in] flags Flags. + * \param[in] offset Field offset, in bits. + * \param[in] mask Field mask. + * \return Field value. + */ +#define sbgEComBinaryLogSatGetField(flags, offset, mask) (((flags) >> (offset)) & (mask)) + +/*! + * Set a bit field from a set of flags. + * + * \param[in/out] flags Flags. + * \param[in] value Field value. + * \param[in] offset Field offset, in bits. + * \param[in] mask Field mask. + */ +#define sbgEComBinaryLogSatSetField(flags, value, offset, mask) (flags) &= ~((mask) << (offset)); (flags) |= ((value) & (mask)) << (offset) + + + +/*! + * Check the value of a health status. + * + * \param[in] healthStatus Health status. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgEComBinaryLogSatCheckHealthStatus(uint8_t healthStatus) +{ + SbgErrorCode errorCode = SBG_INVALID_FRAME; + + switch (healthStatus) + { + case SBG_ECOM_SAT_HEALTH_STATUS_UNKNOWN: + case SBG_ECOM_SAT_HEALTH_STATUS_HEALTHY: + case SBG_ECOM_SAT_HEALTH_STATUS_UNHEALTHY: + errorCode = SBG_NO_ERROR; + break; + } + + if (errorCode != SBG_NO_ERROR) + { + SBG_LOG_ERROR(errorCode, "invalid health status: %" PRIu8, healthStatus); + } + + return errorCode; +} + +/*! + * Check the value of a tracking status. + * + * \param[in] trackingStatus Tracking status. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgEComBinaryLogSatCheckTrackingStatus(uint8_t trackingStatus) +{ + SbgErrorCode errorCode = SBG_INVALID_FRAME; + + switch (trackingStatus) + { + case SBG_ECOM_SAT_TRACKING_STATUS_UNKNOWN: + case SBG_ECOM_SAT_TRACKING_STATUS_SEARCHING: + case SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_UNKNOWN: + case SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_NOT_USED: + case SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_REJECTED: + case SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_USED: + errorCode = SBG_NO_ERROR; + break; + } + + if (errorCode != SBG_NO_ERROR) + { + SBG_LOG_ERROR(errorCode, "invalid tracking status: %" PRIu8, trackingStatus); + } + + return errorCode; +} + +/*! + * Returns tracking status string from enum value + * + * \param[in] trackingStatus Tracking status enum to convert + * \return Tracking status as a read only C string. + */ +static const char *sbgEComBinaryLogSatTrackingStatusToStr(SbgEComSatTrackingStatus trackingStatus) +{ + static const char *enumToStrLut[] = + { + [SBG_ECOM_SAT_TRACKING_STATUS_UNKNOWN] = "unkown", + [SBG_ECOM_SAT_TRACKING_STATUS_SEARCHING] = "searching", + [SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_UNKNOWN] = "tracking", + [SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_NOT_USED] = "unused", + [SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_REJECTED] = "rejected", + [SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_USED] = "used", + }; + + if (trackingStatus < SBG_ARRAY_SIZE(enumToStrLut)) + { + return enumToStrLut[trackingStatus]; + } + else + { + return enumToStrLut[SBG_ECOM_SAT_TRACKING_STATUS_UNKNOWN]; + } +} + +/*! + * Returns health status string from enum value + * + * \param[in] trackingStatus Tracking status enum to convert + * \return Tracking status as a read only C string. + */ +static const char *sbgEComBinaryLogSatHealthStatusToStr(SbgEComSatHealthStatus healthStatus) +{ + static const char *enumToStrLut[] = + { + [SBG_ECOM_SAT_HEALTH_STATUS_UNKNOWN] = "unkown", + [SBG_ECOM_SAT_HEALTH_STATUS_HEALTHY] = "healthy", + [SBG_ECOM_SAT_HEALTH_STATUS_UNHEALTHY] = "unhealthy", + }; + + if (healthStatus < SBG_ARRAY_SIZE(enumToStrLut)) + { + return enumToStrLut[healthStatus]; + } + else + { + return enumToStrLut[SBG_ECOM_SAT_HEALTH_STATUS_UNKNOWN]; + } +} + +/*! + * Parse signal data from a stream buffer. + * + * \param[in] pStreamBuffer Stream buffer. + * \param[out] pSignalData Signal data. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgEComBinaryLogParseSignalData(SbgStreamBuffer *pStreamBuffer, SbgLogSatSignalData *pSignalData) +{ + SbgErrorCode errorCode; + uint8_t signalId; + + assert(pSignalData); + + signalId = sbgStreamBufferReadUint8(pStreamBuffer); + pSignalData->flags = sbgStreamBufferReadUint8(pStreamBuffer); + pSignalData->snr = sbgStreamBufferReadUint8(pStreamBuffer); + + errorCode = sbgStreamBufferGetLastError(pStreamBuffer); + + if (errorCode == SBG_NO_ERROR) + { + if (sbgEComSignalIdIsValid(signalId)) + { + uint8_t healthStatus; + + pSignalData->id = signalId; + + healthStatus = sbgEComBinaryLogSatGetField(pSignalData->flags, SBG_ECOM_LOG_SAT_HEALTH_STATUS_OFFSET, SBG_ECOM_LOG_SAT_HEALTH_STATUS_MASK); + + errorCode = sbgEComBinaryLogSatCheckHealthStatus(healthStatus); + + if (errorCode == SBG_NO_ERROR) + { + uint8_t trackingStatus; + + trackingStatus = sbgEComBinaryLogSatGetField(pSignalData->flags, SBG_ECOM_LOG_SAT_TRACKING_STATUS_OFFSET, SBG_ECOM_LOG_SAT_TRACKING_STATUS_MASK); + + errorCode = sbgEComBinaryLogSatCheckTrackingStatus(trackingStatus); + } + } + else + { + errorCode = SBG_INVALID_FRAME; + SBG_LOG_ERROR(errorCode, "invalid signal ID: %" PRIu8, signalId); + } + } + + return errorCode; +} + +/*! + * Check the value of an elevation status. + * + * \param[in] elevationStatus Elevation status value. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgEComBinaryLogSatCheckElevationStatus(uint8_t elevationStatus) +{ + SbgErrorCode errorCode = SBG_INVALID_FRAME; + + switch (elevationStatus) + { + case SBG_ECOM_SAT_ELEVATION_STATUS_UNKNOWN: + case SBG_ECOM_SAT_ELEVATION_STATUS_SETTING: + case SBG_ECOM_SAT_ELEVATION_STATUS_RISING: + errorCode = SBG_NO_ERROR; + break; + } + + if (errorCode != SBG_NO_ERROR) + { + SBG_LOG_ERROR(errorCode, "invalid elevation status: %" PRIu8, elevationStatus); + } + + return errorCode; +} + +/*! + * Parse satellite data from a stream buffer. + * + * \param[in] pStreamBuffer Stream buffer. + * \param[out] pSatGroupData Satellite group data. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgEComBinaryLogParseSatData(SbgStreamBuffer *pStreamBuffer, SbgLogSatData *pSatData) +{ + SbgErrorCode errorCode; + + assert(pSatData); + + pSatData->id = sbgStreamBufferReadUint8(pStreamBuffer); + pSatData->elevation = sbgStreamBufferReadInt8(pStreamBuffer); + pSatData->azimuth = sbgStreamBufferReadUint16(pStreamBuffer); + pSatData->flags = sbgStreamBufferReadUint16(pStreamBuffer); + pSatData->nrSignals = sbgStreamBufferReadUint8(pStreamBuffer); + pSatData->signalDataArraySize = pSatData->nrSignals; + + errorCode = sbgStreamBufferGetLastError(pStreamBuffer); + + if (errorCode == SBG_NO_ERROR) + { + if (pSatData->nrSignals <= SBG_ECOM_SAT_MAX_NR_SIGNALS) + { + pSatData->pSignalData = malloc(sizeof(*pSatData->pSignalData) * pSatData->signalDataArraySize); + + if (pSatData->pSignalData) + { + uint8_t constellationId; + + constellationId = sbgEComBinaryLogSatGetField(pSatData->flags, SBG_ECOM_LOG_SAT_CONSTELLATION_ID_OFFSET, SBG_ECOM_LOG_SAT_CONSTELLATION_ID_MASK); + + if (sbgEComConstellationIdIsValid(constellationId)) + { + uint8_t elevationStatus; + + elevationStatus = sbgEComBinaryLogSatGetField(pSatData->flags, SBG_ECOM_LOG_SAT_ELEVATION_STATUS_OFFSET, SBG_ECOM_LOG_SAT_ELEVATION_STATUS_MASK); + + errorCode = sbgEComBinaryLogSatCheckElevationStatus(elevationStatus); + + if (errorCode == SBG_NO_ERROR) + { + uint8_t healthStatus; + + healthStatus = sbgEComBinaryLogSatGetField(pSatData->flags, SBG_ECOM_LOG_SAT_HEALTH_STATUS_OFFSET, SBG_ECOM_LOG_SAT_HEALTH_STATUS_MASK); + + errorCode = sbgEComBinaryLogSatCheckHealthStatus(healthStatus); + + if (errorCode == SBG_NO_ERROR) + { + uint8_t trackingStatus; + + trackingStatus = sbgEComBinaryLogSatGetField(pSatData->flags, SBG_ECOM_LOG_SAT_TRACKING_STATUS_OFFSET, SBG_ECOM_LOG_SAT_TRACKING_STATUS_MASK); + + errorCode = sbgEComBinaryLogSatCheckTrackingStatus(trackingStatus); + + if (errorCode == SBG_NO_ERROR) + { + for (size_t i = 0; i < pSatData->nrSignals; i++) + { + errorCode = sbgEComBinaryLogParseSignalData(pStreamBuffer, &pSatData->pSignalData[i]); + + if (errorCode != SBG_NO_ERROR) + { + break; + } + } + } + } + } + } + else + { + errorCode = SBG_INVALID_FRAME; + SBG_LOG_ERROR(errorCode, "invalid constellation id: %" PRIu8, constellationId); + } + + if (errorCode != SBG_NO_ERROR) + { + free(pSatData->pSignalData); + pSatData->pSignalData = NULL; + } + } + else + { + errorCode = SBG_MALLOC_FAILED; + SBG_LOG_ERROR(errorCode, "unable to allocate signal data array"); + } + } + else + { + errorCode = SBG_INVALID_FRAME; + SBG_LOG_ERROR(errorCode, "invalid number of signals: %zu", pSatData->nrSignals); + } + } + + return errorCode; +} + +/*! + * Satellite data constructor. + * + * \param[in] pSatData Satellite data. + * \param[in] nrSignals Number of signals. + * \param[in] id Satellite ID. + * \param[in] elevation Elevation, in degrees. + * \param[in] azimuth Azimuth, in degrees. + * \param[in] constellationId Constellation ID. + * \param[in] elevationStatus Elevation status. + * \param[in] healthStatus Health status. + * \param[in] trackingStatus Tracking status. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgLogSatDataConstruct(SbgLogSatData *pSatData, size_t nrSignals, uint8_t id, int8_t elevation, uint16_t azimuth, SbgEComConstellationId constellationId, SbgEComSatElevationStatus elevationStatus, SbgEComSatHealthStatus healthStatus, SbgEComSatTrackingStatus trackingStatus) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint16_t flags = 0; + + assert(pSatData); + assert(nrSignals <= SBG_ECOM_SAT_MAX_NR_SIGNALS); + + sbgEComBinaryLogSatSetField(flags, constellationId, SBG_ECOM_LOG_SAT_CONSTELLATION_ID_OFFSET, SBG_ECOM_LOG_SAT_CONSTELLATION_ID_MASK); + sbgEComBinaryLogSatSetField(flags, elevationStatus, SBG_ECOM_LOG_SAT_ELEVATION_STATUS_OFFSET, SBG_ECOM_LOG_SAT_ELEVATION_STATUS_MASK); + sbgEComBinaryLogSatSetField(flags, healthStatus, SBG_ECOM_LOG_SAT_HEALTH_STATUS_OFFSET, SBG_ECOM_LOG_SAT_HEALTH_STATUS_MASK); + sbgEComBinaryLogSatSetField(flags, trackingStatus, SBG_ECOM_LOG_SAT_TRACKING_STATUS_OFFSET, SBG_ECOM_LOG_SAT_TRACKING_STATUS_MASK); + + pSatData->id = id; + pSatData->elevation = elevation; + pSatData->azimuth = azimuth; + pSatData->flags = flags; + pSatData->signalDataArraySize = nrSignals; + pSatData->nrSignals = 0; + + pSatData->pSignalData = malloc(sizeof(*pSatData->pSignalData) * pSatData->signalDataArraySize); + + if (!pSatData->pSignalData) + { + errorCode = SBG_MALLOC_FAILED; + SBG_LOG_ERROR(errorCode, "unable to allocate signal data array"); + } + + return errorCode; +} + +/*! + * Satellite data destructor. + * + * \param[in] pSatData Satellite data. + */ +static void sbgLogSatDataDestroy(SbgLogSatData *pSatData) +{ + assert(pSatData); + + free(pSatData->pSignalData); + pSatData->pSignalData = NULL; +} + +/*! + * Select one of two health statuses according to their priority rules. + * + * \param[in] healthStatus1 First health status. + * \param[in] healthStatus2 Second health status. + */ +static SbgEComSatHealthStatus sbgEComBinaryLogSatSelectHealthStatus(SbgEComSatHealthStatus healthStatus1, SbgEComSatHealthStatus healthStatus2) +{ + SbgEComSatHealthStatus healthStatus; + + if (healthStatus2 > healthStatus1) + { + healthStatus = healthStatus2; + } + else + { + healthStatus = healthStatus1; + } + + return healthStatus; +} + +/*! + * Select one of two tracking statuses according to their priority rules. + * + * \param[in] trackingStatus1 First tracking status. + * \param[in] trackingStatus2 Second tracking status. + */ +static SbgEComSatTrackingStatus sbgEComBinaryLogSatSelectTrackingStatus(SbgEComSatTrackingStatus trackingStatus1, SbgEComSatTrackingStatus trackingStatus2) +{ + SbgEComSatTrackingStatus trackingStatus; + + if (trackingStatus2 > trackingStatus1) + { + trackingStatus = trackingStatus2; + } + else + { + trackingStatus = trackingStatus1; + } + + return trackingStatus; +} + +/*! + * Update the health and tracking statuses of satellite data. + * + * \param[in] pSatData Satellite data. + * \param[in] healthStatus Health status. + * \param[in] trackingStatus Tracking status. + */ +static void sbgLogSatDataUpdateStatus(SbgLogSatData *pSatData, SbgEComSatHealthStatus healthStatus, SbgEComSatTrackingStatus trackingStatus) +{ + uint16_t flags; + + assert(pSatData); + + flags = pSatData->flags; + + healthStatus = sbgEComBinaryLogSatSelectHealthStatus(sbgLogSatDataGetHealthStatus(pSatData), healthStatus); + trackingStatus = sbgEComBinaryLogSatSelectTrackingStatus(sbgLogSatDataGetTrackingStatus(pSatData), trackingStatus); + + sbgEComBinaryLogSatSetField(flags, healthStatus, SBG_ECOM_LOG_SAT_HEALTH_STATUS_OFFSET, SBG_ECOM_LOG_SAT_HEALTH_STATUS_MASK); + sbgEComBinaryLogSatSetField(flags, trackingStatus, SBG_ECOM_LOG_SAT_TRACKING_STATUS_OFFSET, SBG_ECOM_LOG_SAT_TRACKING_STATUS_MASK); + + pSatData->flags = flags; +} + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseSatGroupData(SbgStreamBuffer *pStreamBuffer, SbgLogSatGroupData *pSatGroupData) +{ + SbgErrorCode errorCode; + + assert(pSatGroupData); + assert(pStreamBuffer); + + pSatGroupData->timeStamp = sbgStreamBufferReadUint32LE(pStreamBuffer); + pSatGroupData->reserved = sbgStreamBufferReadUint32LE(pStreamBuffer); + pSatGroupData->nrSatellites = sbgStreamBufferReadUint8(pStreamBuffer); + pSatGroupData->satDataArraySize = pSatGroupData->nrSatellites; + + errorCode = sbgStreamBufferGetLastError(pStreamBuffer); + + if (errorCode == SBG_NO_ERROR) + { + if (pSatGroupData->nrSatellites <= SBG_ECOM_SAT_MAX_NR_SATELLITES) + { + pSatGroupData->pSatData = malloc(sizeof(*pSatGroupData->pSatData) * pSatGroupData->satDataArraySize); + + if (pSatGroupData->pSatData) + { + for (size_t i = 0; i < pSatGroupData->nrSatellites; i++) + { + errorCode = sbgEComBinaryLogParseSatData(pStreamBuffer, &pSatGroupData->pSatData[i]); + + if (errorCode != SBG_NO_ERROR) + { + break; + } + } + + if (errorCode != SBG_NO_ERROR) + { + free(pSatGroupData->pSatData); + pSatGroupData->pSatData = NULL; + } + } + else + { + errorCode = SBG_MALLOC_FAILED; + SBG_LOG_ERROR(errorCode, "unable to allocate satellite data array"); + } + } + else + { + errorCode = SBG_INVALID_FRAME; + SBG_LOG_ERROR(errorCode, "invalid number of satellites: %zu", pSatGroupData->nrSatellites); + } + } + + return errorCode; +} + +SbgErrorCode sbgEComBinaryLogWriteSatGroupData(SbgStreamBuffer *pStreamBuffer, const SbgLogSatGroupData *pSatGroupData) +{ + assert(pStreamBuffer); + assert(pSatGroupData); + assert(pSatGroupData->nrSatellites <= UINT8_MAX); + + sbgStreamBufferWriteUint32LE(pStreamBuffer, pSatGroupData->timeStamp); + sbgStreamBufferWriteUint32LE(pStreamBuffer, pSatGroupData->reserved); + sbgStreamBufferWriteUint8(pStreamBuffer, (uint8_t)pSatGroupData->nrSatellites); + + for (size_t i = 0; i < pSatGroupData->nrSatellites; i++) + { + const SbgLogSatData *pSatData = &pSatGroupData->pSatData[i]; + + assert(pSatData->nrSignals <= UINT8_MAX); + + sbgStreamBufferWriteUint8(pStreamBuffer, pSatData->id); + sbgStreamBufferWriteInt8(pStreamBuffer, pSatData->elevation); + sbgStreamBufferWriteUint16(pStreamBuffer, pSatData->azimuth); + sbgStreamBufferWriteUint16(pStreamBuffer, pSatData->flags); + sbgStreamBufferWriteUint8(pStreamBuffer, (uint8_t)pSatData->nrSignals); + + for (size_t j = 0; j < pSatData->nrSignals; j++) + { + const SbgLogSatSignalData *pSignalData = &pSatData->pSignalData[j]; + + sbgStreamBufferWriteUint8(pStreamBuffer, pSignalData->id); + sbgStreamBufferWriteUint8(pStreamBuffer, pSignalData->flags); + sbgStreamBufferWriteUint8(pStreamBuffer, pSignalData->snr); + } + } + + return sbgStreamBufferGetLastError(pStreamBuffer); +} + +SbgErrorCode sbgLogSatGroupDataConstruct(SbgLogSatGroupData *pSatGroupData, size_t nrSatellites, uint32_t timeStamp) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + + assert(pSatGroupData); + assert(nrSatellites <= SBG_ECOM_SAT_MAX_NR_SATELLITES); + + pSatGroupData->timeStamp = timeStamp; + pSatGroupData->reserved = 0; + pSatGroupData->nrSatellites = 0; + pSatGroupData->satDataArraySize = nrSatellites; + + pSatGroupData->pSatData = malloc(sizeof(*pSatGroupData->pSatData) * pSatGroupData->satDataArraySize); + + if (!pSatGroupData->pSatData) + { + errorCode = SBG_MALLOC_FAILED; + SBG_LOG_ERROR(errorCode, "unable to allocate satellite data array"); + } + + return SBG_NO_ERROR; +} + +void sbgLogSatGroupDataDestroy(SbgLogSatGroupData *pSatGroupData) +{ + assert(pSatGroupData); + + for (size_t i = 0; i < pSatGroupData->nrSatellites; i++) + { + sbgLogSatDataDestroy(&pSatGroupData->pSatData[i]); + } + + free(pSatGroupData->pSatData); + pSatGroupData->pSatData = NULL; +} + +SbgLogSatData *sbgLogSatGroupDataAdd(SbgLogSatGroupData *pSatGroupData, size_t nrSignals, uint8_t id, int8_t elevation, uint16_t azimuth, SbgEComConstellationId constellationId, SbgEComSatElevationStatus elevationStatus, SbgEComSatHealthStatus healthStatus, SbgEComSatTrackingStatus trackingStatus) +{ + SbgLogSatData *pSatData = NULL; + + assert(pSatGroupData); + + if (pSatGroupData->nrSatellites < pSatGroupData->satDataArraySize) + { + SbgErrorCode errorCode; + SbgLogSatData *pTmpSatData; + + pTmpSatData = &pSatGroupData->pSatData[pSatGroupData->nrSatellites]; + + errorCode = sbgLogSatDataConstruct(pTmpSatData, nrSignals, id, elevation, azimuth, constellationId, elevationStatus, healthStatus, trackingStatus); + + if (errorCode == SBG_NO_ERROR) + { + pSatData = pTmpSatData; + pSatGroupData->nrSatellites++; + } + } + + return pSatData; +} + +SbgLogSatData *sbgLogSatGroupGet(SbgLogSatGroupData *pSatGroupData, uint8_t id) +{ + SbgLogSatData *pSatData = NULL; + + assert(pSatGroupData); + + for (size_t i = 0; i < pSatGroupData->nrSatellites; i++) + { + if (pSatGroupData->pSatData[i].id == id) + { + pSatData = &pSatGroupData->pSatData[i]; + break; + } + } + + return pSatData; +} + +SbgEComConstellationId sbgLogSatDataGetConstellationId(const SbgLogSatData *pSatData) +{ + uint8_t value; + + assert(pSatData); + + value = sbgEComBinaryLogSatGetField(pSatData->flags, SBG_ECOM_LOG_SAT_CONSTELLATION_ID_OFFSET, SBG_ECOM_LOG_SAT_CONSTELLATION_ID_MASK); + + return (SbgEComConstellationId)value; +} + +const char *sbgLogSatDataGetConstellationIdAsStr(const SbgLogSatData *pSatData) +{ + return sbgEComConstellationToStr(sbgLogSatDataGetConstellationId(pSatData)); +} + +SbgEComSatElevationStatus sbgLogSatDataGetElevationStatus(const SbgLogSatData *pSatData) +{ + uint8_t value; + + assert(pSatData); + + value = sbgEComBinaryLogSatGetField(pSatData->flags, SBG_ECOM_LOG_SAT_ELEVATION_STATUS_OFFSET, SBG_ECOM_LOG_SAT_ELEVATION_STATUS_MASK); + + return (SbgEComSatElevationStatus)value; +} + +const char *sbgLogSatDataGetElevationStatusAsStr(const SbgLogSatData *pSatData) +{ + SbgEComSatElevationStatus enumIdx; + static const char *enumToStrLut[] = + { + [SBG_ECOM_SAT_ELEVATION_STATUS_UNKNOWN] = "unkown", + [SBG_ECOM_SAT_ELEVATION_STATUS_SETTING] = "setting", + [SBG_ECOM_SAT_ELEVATION_STATUS_RISING] = "rising", + }; + + assert(pSatData); + + enumIdx = sbgLogSatDataGetElevationStatus(pSatData); + + if (enumIdx < SBG_ARRAY_SIZE(enumToStrLut)) + { + return enumToStrLut[enumIdx]; + } + else + { + return enumToStrLut[SBG_ECOM_SAT_ELEVATION_STATUS_UNKNOWN]; + } +} + +SbgEComSatHealthStatus sbgLogSatDataGetHealthStatus(const SbgLogSatData *pSatData) +{ + uint8_t value; + + assert(pSatData); + + value = sbgEComBinaryLogSatGetField(pSatData->flags, SBG_ECOM_LOG_SAT_HEALTH_STATUS_OFFSET, SBG_ECOM_LOG_SAT_HEALTH_STATUS_MASK); + + return (SbgEComSatHealthStatus)value; +} + +const char *sbgLogSatDataGetHealthStatusAsStr(const SbgLogSatData *pSatData) +{ + assert(pSatData); + + return sbgEComBinaryLogSatHealthStatusToStr(sbgLogSatDataGetHealthStatus(pSatData)); +} + +SbgEComSatTrackingStatus sbgLogSatDataGetTrackingStatus(const SbgLogSatData *pSatData) +{ + uint8_t value; + + assert(pSatData); + + value = sbgEComBinaryLogSatGetField(pSatData->flags, SBG_ECOM_LOG_SAT_TRACKING_STATUS_OFFSET, SBG_ECOM_LOG_SAT_TRACKING_STATUS_MASK); + + return (SbgEComSatTrackingStatus)value; +} + +const char *sbgLogSatDataGetTrackingStatusAsStr(const SbgLogSatData *pSatData) +{ + assert(pSatData); + + return sbgEComBinaryLogSatTrackingStatusToStr(sbgLogSatDataGetTrackingStatus(pSatData)); +} + +SbgLogSatSignalData *sbgLogSatDataAdd(SbgLogSatData *pSatData, SbgEComSignalId id, SbgEComSatHealthStatus healthStatus, SbgEComSatTrackingStatus trackingStatus, bool snrValid, uint8_t snr) +{ + SbgLogSatSignalData *pSignalData = NULL; + + assert(pSatData); + + if (pSatData->nrSignals < pSatData->signalDataArraySize) + { + uint8_t flags = 0; + + sbgEComBinaryLogSatSetField(flags, healthStatus, SBG_ECOM_LOG_SAT_HEALTH_STATUS_OFFSET, SBG_ECOM_LOG_SAT_HEALTH_STATUS_MASK); + sbgEComBinaryLogSatSetField(flags, trackingStatus, SBG_ECOM_LOG_SAT_TRACKING_STATUS_OFFSET, SBG_ECOM_LOG_SAT_TRACKING_STATUS_MASK); + + if (snrValid) + { + flags |= SBG_ECOM_LOG_SAT_SIGNAL_SNR_VALID; + } + + pSignalData = &pSatData->pSignalData[pSatData->nrSignals]; + + pSignalData->id = id; + pSignalData->flags = flags; + pSignalData->snr = snr; + + pSatData->nrSignals++; + + sbgLogSatDataUpdateStatus(pSatData, healthStatus, trackingStatus); + } + + return pSignalData; +} + +SbgLogSatSignalData *sbgLogSatDataGet(SbgLogSatData *pSatData, SbgEComSignalId id) +{ + SbgLogSatSignalData *pSignalData = NULL; + + assert(pSatData); + + for (size_t i = 0; i < pSatData->nrSignals; i++) + { + if (pSatData->pSignalData[i].id == id) + { + pSignalData = &pSatData->pSignalData[i]; + break; + } + } + + return pSignalData; +} + +const char *sbgLogSatSignalDataGetSignalIdAsStr(const SbgLogSatSignalData *pSignalData) +{ + return sbgEComSignalToStr(pSignalData->id); +} + +bool sbgLogSatSignalDataSnrIsValid(const SbgLogSatSignalData *pSignalData) +{ + if (pSignalData->flags&SBG_ECOM_LOG_SAT_SIGNAL_SNR_VALID) + { + return true; + } + else + { + return false; + } +} + +SbgEComSatHealthStatus sbgLogSatSignalDataGetHealthStatus(const SbgLogSatSignalData *pSignalData) +{ + uint8_t value; + + assert(pSignalData); + + value = sbgEComBinaryLogSatGetField(pSignalData->flags, SBG_ECOM_LOG_SAT_HEALTH_STATUS_OFFSET, SBG_ECOM_LOG_SAT_HEALTH_STATUS_MASK); + + return (SbgEComSatHealthStatus)value; +} + +const char *sbgLogSatSignalDataGetHealthStatusAsStr(const SbgLogSatSignalData *pSignalData) +{ + assert(pSignalData); + + return sbgEComBinaryLogSatHealthStatusToStr(sbgLogSatSignalDataGetHealthStatus(pSignalData)); +} + +SbgEComSatTrackingStatus sbgLogSatSignalDataGetTrackingStatus(const SbgLogSatSignalData *pSignalData) +{ + uint8_t value; + + assert(pSignalData); + + value = sbgEComBinaryLogSatGetField(pSignalData->flags, SBG_ECOM_LOG_SAT_TRACKING_STATUS_OFFSET, SBG_ECOM_LOG_SAT_TRACKING_STATUS_MASK); + + return (SbgEComSatTrackingStatus)value; +} + +const char *sbgLogSatSignalDataGetTrackingStatusAsStr(const SbgLogSatSignalData *pSignalData) +{ + assert(pSignalData); + + return sbgEComBinaryLogSatTrackingStatusToStr(sbgLogSatSignalDataGetTrackingStatus(pSignalData)); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogSat.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogSat.h new file mode 100644 index 0000000..bdb5f8e --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogSat.h @@ -0,0 +1,377 @@ +/*! + * \file sbgEComBinaryLogSat.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 1 March 2022 + * + * \brief Parse space vehicles in view information log. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_SAT_H +#define SBG_ECOM_BINARY_LOG_SAT_H + +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +/*! + * Maximum number of satellites in a satellite group. + */ +#define SBG_ECOM_SAT_MAX_NR_SATELLITES (64) + +/*! + * Maximum number of signals per satellite. + */ +#define SBG_ECOM_SAT_MAX_NR_SIGNALS (8) + +//----------------------------------------------------------------------// +//- Enumeration definitions -// +//----------------------------------------------------------------------// + +/*! + * Tracking status. + * + * The tracking status embeds the solution status when the latter is known. + * + * All values must be strictly lower than 8. + * + * These are on-the-wire values. + */ +typedef enum _SbgEComSatTrackingStatus +{ + SBG_ECOM_SAT_TRACKING_STATUS_UNKNOWN = 0, /*!< Unknown tracking status such as no signal / idle. */ + SBG_ECOM_SAT_TRACKING_STATUS_SEARCHING = 1, /*!< Signal is beeing searched and can't be used yet. */ + SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_UNKNOWN = 2, /*!< Signal is tracked but don't know if used or not in the solution. */ + SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_NOT_USED = 3, /*!< Signal is tracked and is not used in the solution. */ + SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_REJECTED = 4, /*!< Signal is tracjed and is rejected from the solution. */ + SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_USED = 5, /*!< Signal is tracked and used in the solution. */ +} SbgEComSatTrackingStatus; + +/*! + * Health status. + * + * All values must be strictly lower than 4. + * + * These are on-the-wire values. + */ +typedef enum _SbgEComSatHealthStatus +{ + SBG_ECOM_SAT_HEALTH_STATUS_UNKNOWN = 0, /*!< Don't know the satellite or the signal health status. */ + SBG_ECOM_SAT_HEALTH_STATUS_HEALTHY = 1, /*!< The satellite or the signal is healthy and can be used. */ + SBG_ECOM_SAT_HEALTH_STATUS_UNHEALTHY = 2, /*!< The satellite or the signal is not healthy and can't be used. */ +} SbgEComSatHealthStatus; + +/*! + * Elevation status. + * + * All values must be strictly lower than 4. + * + * These are on-the-wire values. + */ +typedef enum _SbgEComSatElevationStatus +{ + SBG_ECOM_SAT_ELEVATION_STATUS_UNKNOWN = 0, /*!< Don't know if the satellite elevation is setting or rising. */ + SBG_ECOM_SAT_ELEVATION_STATUS_SETTING = 1, /*!< The satellite elevation is setting. */ + SBG_ECOM_SAT_ELEVATION_STATUS_RISING = 2, /*!< The satellite elevation is rising */ +} SbgEComSatElevationStatus; + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Satellite signal data. + * + * The flags include the snr available, health and tracking statuses. + */ +typedef struct _SbgLogSatSignalData +{ + SbgEComSignalId id; /*!< Signal ID. */ + uint8_t flags; /*!< Flags. */ + uint8_t snr; /*!< Signal-to-noise ratio, in dB. */ +} SbgLogSatSignalData; + +/*! + * Satellite data. + * + * The flags include the constellation ID, the elevation status, the health status, and the tracking status. + * + * Satellite data and signal data each have their own health and tracking statuses. The statuses of satellite + * data may be a priority-based summary of the statuses of signal data, or they may reflect information that + * is limited to a satellite and unavailable for its signals. + * + * The priority rules are : + * - health status : unhealthy -> healthy -> unknown + * - tracking status : tracking and used -> tracking and not used -> tracking (solution status unknown) -> searching -> unknown + * + * For example, if satellite data have an unknown tracking status, and have three signals, one with the + * searching status, another with the tracking and not used status, and the last with the tracking and used status, + * the satellite data tracking status will be tracking and used. + * But if those satellite data are initially set with a healthy health status, and all three signals added have the + * unknown health status, the satellite data health status remains healthy. + */ +typedef struct _SbgLogSatData +{ + uint8_t id; /*!< Satellite ID. */ + int8_t elevation; /*!< Elevation, in degrees [-90; +90], valid if and only if the elevation is known. */ + uint16_t azimuth; /*!< Azimuth, in degrees [0; 359], valid if and only if the elevation is known. */ + uint16_t flags; /*!< Flags. */ + size_t nrSignals; /*!< Number of signals. */ + size_t signalDataArraySize; /*!< Size of the signal data array. */ + SbgLogSatSignalData *pSignalData; /*!< Signal data array. */ +} SbgLogSatData; + +/*! + * Satellite group data. + */ +typedef struct _SbgLogSatGroupData +{ + uint32_t timeStamp; /*!< Time since the sensor power up, in us. */ + uint32_t reserved; /*!< Reserved for future use. */ + size_t nrSatellites; /*!< Number of satellites. */ + size_t satDataArraySize; /*!< Size of the satellite data array. */ + SbgLogSatData *pSatData; /*!< Satellite data array. */ +} SbgLogSatGroupData; + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +/*! + * Parse satellite group data from a stream buffer. + * + * This function constructs the satellite group data, which must be destroyed once not needed any more. + * + * \param[in] pStreamBuffer Stream buffer. + * \param[out] pSatGroupData Satellite group data. + * \return SBG_NO_ERROR if successful. + */ +SbgErrorCode sbgEComBinaryLogParseSatGroupData(SbgStreamBuffer *pStreamBuffer, SbgLogSatGroupData *pSatGroupData); + +/*! + * Write satellite group data to a stream buffer. + * + * \param[out] pStreamBuffer Stream buffer. + * \param[in] pSatGroupData Satellite group data. + * \return SBG_NO_ERROR if successful. + */ +SbgErrorCode sbgEComBinaryLogWriteSatGroupData(SbgStreamBuffer *pStreamBuffer, const SbgLogSatGroupData *pSatGroupData); + +/*! + * Satellite group data constructor. + * + * \param[in] pSatGroupData Satellite group data. + * \param[in] nrSatellites Number of satellites. + * \param[in] timeStamp Time stamp, in us. + * \return SBG_NO_ERROR if successful. + */ +SbgErrorCode sbgLogSatGroupDataConstruct(SbgLogSatGroupData *pSatGroupData, size_t nrSatellites, uint32_t timeStamp); + +/*! + * Satellite group data destructor. + * + * \param[in] pSatGroupData Satellite group data. + */ +void sbgLogSatGroupDataDestroy(SbgLogSatGroupData *pSatGroupData); + +/*! + * Add satellite data to satellite group data. + * + * \param[in] pSatGroupData Satellite group data. + * \param[in] nrSignals Number of signals. + * \param[in] id Satellite ID. + * \param[in] elevation Elevation, in degrees. + * \param[in] azimuth Azimuth, in degrees. + * \param[in] constellationId Constellation ID. + * \param[in] elevationStatus Elevation status. + * \param[in] healthStatus Health status. + * \param[in] trackingStatus Tracking status. + * \return Satellite data, NULL if an error occurs. + */ +SbgLogSatData *sbgLogSatGroupDataAdd(SbgLogSatGroupData *pSatGroupData, size_t nrSignals, uint8_t id, int8_t elevation, uint16_t azimuth, SbgEComConstellationId constellationId, SbgEComSatElevationStatus elevationStatus, SbgEComSatHealthStatus healthStatus, SbgEComSatTrackingStatus trackingStatus); + +/*! + * Get satellite data from satellite group data. + * + * \param[in] pSatGroupData Satellite group data. + * \param[in] id Satellite ID. + * \return Satellite data, NULL if not found. + */ +SbgLogSatData *sbgLogSatGroupGet(SbgLogSatGroupData *pSatGroupData, uint8_t id); + +/*! + * Get the constellation ID of satellite data. + * + * \param[in] pSatData Satellite data. + * \return Constellation ID. + */ +SbgEComConstellationId sbgLogSatDataGetConstellationId(const SbgLogSatData *pSatData); + +/*! + * Get the constellation ID of satellite data as a read only C string. + * + * \param[in] pSatData Satellite data. + * \return Constellation ID as a read only C string. + */ +const char *sbgLogSatDataGetConstellationIdAsStr(const SbgLogSatData *pSatData); + +/*! + * Get the elevation status of satellite data. + * + * \param[in] pSatData Satellite data. + * \return Elevation status. + */ +SbgEComSatElevationStatus sbgLogSatDataGetElevationStatus(const SbgLogSatData *pSatData); + +/*! + * Get the elevation status of satellite data as a read only C string. + * + * \param[in] pSatData Satellite data. + * \return Elevation status as a read only C string. + */ +const char *sbgLogSatDataGetElevationStatusAsStr(const SbgLogSatData *pSatData); + +/*! + * Get the health status of satellite data. + * + * \param[in] pSatData Satellite data. + * \return Health status. + */ +SbgEComSatHealthStatus sbgLogSatDataGetHealthStatus(const SbgLogSatData *pSatData); + +/*! + * Get the health status of satellite data as a read only C string. + * + * \param[in] pSatData Satellite data. + * \return Health status as a read only C string. + */ +const char *sbgLogSatDataGetHealthStatusAsStr(const SbgLogSatData *pSatData); + +/*! + * Get the tracking status of satellite data. + * + * \param[in] pSatData Satellite data. + * \return Tracking status. + */ +SbgEComSatTrackingStatus sbgLogSatDataGetTrackingStatus(const SbgLogSatData *pSatData); + +/*! + * Get the tracking status of satellite data as a read only C string. + * + * \param[in] pSatData Satellite data. + * \return Tracking status as a read only C string. + */ +const char *sbgLogSatDataGetTrackingStatusAsStr(const SbgLogSatData *pSatData); + +/*! + * Add signal data to satellite data. + * + * The health and tracking statuses of the satellite data are updated according to their respective + * priority rules. + * + * \param[in] pSatData Satellite data. + * \param[in] id Signal ID. + * \param[in] healthStatus Health status. + * \param[in] trackingStatus Tracking status. + * \param[in] snrValid Set to true if the SNR value is valid. + * \param[in] snr Signal-to-noise ratio, in dB. + * \return Signal data, NULL if an error occurs. + */ +SbgLogSatSignalData *sbgLogSatDataAdd(SbgLogSatData *pSatData, SbgEComSignalId id, SbgEComSatHealthStatus healthStatus, SbgEComSatTrackingStatus trackingStatus, bool snrValid, uint8_t snr); + +/*! + * Get signal data from satellite data. + * + * \param[in] pSatData Satellite data. + * \param[in] id Signal ID. + * \return Signal data, NULL if not found. + */ +SbgLogSatSignalData *sbgLogSatDataGet(SbgLogSatData *pSatData, SbgEComSignalId id); + +/*! + * Get a signal id as a read only C string. + * + * \param[in] pSignalData Signal data. + * \return Signal id as a read only C string. + */ +const char *sbgLogSatSignalDataGetSignalIdAsStr(const SbgLogSatSignalData *pSignalData); + +/*! + * Returns true if the SNR value is valid. + * + * \param[in] pSignalData Signal data. + * \return true if the SNR value is valid. + */ +bool sbgLogSatSignalDataSnrIsValid(const SbgLogSatSignalData *pSignalData); + +/*! + * Get the health status of signal data. + * + * \param[in] pSignalData Signal data. + * \return Health status. + */ +SbgEComSatHealthStatus sbgLogSatSignalDataGetHealthStatus(const SbgLogSatSignalData *pSignalData); + +/*! + * Get the health status of signal data as a read only C string. + * + * \param[in] pSignalData Signal data. + * \return Health status as a read only C string. + */ +const char *sbgLogSatSignalDataGetHealthStatusAsStr(const SbgLogSatSignalData *pSignalData); + +/*! + * Get the tracking status of signal data. + * + * \param[in] pSignalData Signal data. + * \return Tracking status. + */ +SbgEComSatTrackingStatus sbgLogSatSignalDataGetTrackingStatus(const SbgLogSatSignalData *pSignalData); + +/*! + * Get the tracking status of signal data as a read only C string. + * + * \param[in] pSignalData Signal data. + * \return Tracking status as a read only C string. + */ +const char *sbgLogSatSignalDataGetTrackingStatusAsStr(const SbgLogSatSignalData *pSignalData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_SAT_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogShipMotion.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogShipMotion.c new file mode 100644 index 0000000..d89f210 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogShipMotion.c @@ -0,0 +1,110 @@ +#include "sbgEComBinaryLogShipMotion.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseShipMotionData(SbgStreamBuffer *pInputStream, SbgLogShipMotionData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + + // + // Read the main heave period in seconds + // + pOutputData->mainHeavePeriod = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Read the surge, sway and heave ship motion + // + pOutputData->shipMotion[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->shipMotion[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->shipMotion[2] = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Read the ship accelerations + // + pOutputData->shipAccel[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->shipAccel[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->shipAccel[2] = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Test if we have a additional information such as ship velocity and status (since version 1.4) + // + if (sbgStreamBufferGetSpace(pInputStream) >= 14) + { + // + // Read new outputs + // + pOutputData->shipVel[0] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->shipVel[1] = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->shipVel[2] = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + } + else + { + // + // Those outputs are not available in previous versions + // + pOutputData->shipVel[0] = 0.0f; + pOutputData->shipVel[1] = 0.0f; + pOutputData->shipVel[2] = 0.0f; + + pOutputData->status = 0; + } + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteShipMotionData(SbgStreamBuffer *pOutputStream, const SbgLogShipMotionData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + + // + // Write the main heave period in seconds + // + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->mainHeavePeriod); + + // + // Write the surge, sway and heave ship motion + // + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->shipMotion[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->shipMotion[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->shipMotion[2]); + + // + // Write the ship accelerations + // + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->shipAccel[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->shipAccel[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->shipAccel[2]); + + // + // Write additional inforamtion added in version 1.4 + // + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->shipVel[0]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->shipVel[1]); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->shipVel[2]); + + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogShipMotion.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogShipMotion.h new file mode 100644 index 0000000..81b9651 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogShipMotion.h @@ -0,0 +1,102 @@ +/*! + * \file sbgEComBinaryLogShipMotion.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 30 March 2013 + * + * \brief Parse logs that returns ship motion values such as heave. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_SHIP_MOTION_H +#define SBG_ECOM_BINARY_LOG_SHIP_MOTION_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Heave status definitions -// +//----------------------------------------------------------------------// + +#define SBG_ECOM_HEAVE_VALID (0x0001u << 0) /*!< Set to 1 after heave convergence time. */ +#define SBG_ECOM_HEAVE_VEL_AIDED (0x0001u << 1) /*!< Set to 1 if heave output is compensated for transient accelerations. */ +#define SBG_ECOM_HEAVE_SURGE_SWAY_INCLUDED (0x0001u << 2) /*!< Set to 1 if surge and sway channels are provided in this output. */ +#define SBG_ECOM_HEAVE_PERIOD_INCLUDED (0x0001u << 3) /*!< Set to 1 if the heave period is provided in this output. */ +#define SBG_ECOM_HEAVE_PERIOD_VALID (0x0001u << 4) /*!< Set to 1 if the returned heave period is assumed to be valid. */ +#define SBG_ECOM_HEAVE_SWELL_MODE (0x0001u << 5) /*!< Set to 1 if the real time heave filter is using the swell mode computations. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Structure that stores data for the SBG_ECOM_LOG_SHIP_MOTION or SBG_ECOM_LOG_SHIP_MOTION_HP message.
+ * The data are expressed in the standard NED Ekinox coordiante frame. + * Surge is positive forward, sway is positive right and heave is positive down.
+ * Note that status flag should be read before using the different parameters because it will provide validity information + * about all included outputs. Some frames may not provide the heave period or surge/sway axes for example + */ +typedef struct _SbgLogShipMotionData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< Ship Motion data status bitmask */ + float mainHeavePeriod; /*!< Main heave period in seconds. */ + float shipMotion[3]; /*!< Surge, sway and heave in meters. */ + float shipAccel[3]; /*!< Surge, sway and heave ship Acceleration in m.s^-2. */ + float shipVel[3]; /*!< Surge, sway and heave velocities */ +} SbgLogShipMotionData; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_SHIP_MOTION or SBG_ECOM_LOG_SHIP_MOTION_HP message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseShipMotionData(SbgStreamBuffer *pInputStream, SbgLogShipMotionData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_SHIP_MOTION or SBG_ECOM_LOG_SHIP_MOTION_HP message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteShipMotionData(SbgStreamBuffer *pOutputStream, const SbgLogShipMotionData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_SHIP_MOTION_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogStatus.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogStatus.c new file mode 100644 index 0000000..2c83251 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogStatus.c @@ -0,0 +1,72 @@ +#include "sbgEComBinaryLogStatus.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseStatusData(SbgStreamBuffer *pInputStream, SbgLogStatusData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->generalStatus = sbgStreamBufferReadUint16LE(pInputStream); + pOutputData->comStatus2 = sbgStreamBufferReadUint16LE(pInputStream); + pOutputData->comStatus = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->aidingStatus = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->reserved2 = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->reserved3 = sbgStreamBufferReadUint16LE(pInputStream); + + // + // Test if we have a additional information such as uptime (since version 1.7) + // + if (sbgStreamBufferGetSpace(pInputStream) >= sizeof(uint32_t)) + { + // + // Read the additional information + // + pOutputData->uptime = sbgStreamBufferReadUint32LE(pInputStream); + } + else + { + // + // Default the additional information + // + pOutputData->uptime = 0; + } + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteStatusData(SbgStreamBuffer *pOutputStream, const SbgLogStatusData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->generalStatus); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->comStatus2); + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->comStatus); + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->aidingStatus); + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->reserved2); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->reserved3); + + // + // Write the additional information added in version 1.7 + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->uptime); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogStatus.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogStatus.h new file mode 100644 index 0000000..601305a --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogStatus.h @@ -0,0 +1,216 @@ +/*! + * \file sbgEComBinaryLogStatus.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 03 April 2013 + * + * \brief Parse logs used to report device status. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_STATUS_H +#define SBG_ECOM_BINARY_LOG_STATUS_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- General status definitions -// +//----------------------------------------------------------------------// +#define SBG_ECOM_GENERAL_MAIN_POWER_OK (0x0001u << 0) /*!< Set to 1 when main power supply is OK. */ +#define SBG_ECOM_GENERAL_IMU_POWER_OK (0x0001u << 1) /*!< Set to 1 when IMU power supply is OK. */ +#define SBG_ECOM_GENERAL_GPS_POWER_OK (0x0001u << 2) /*!< Set to 1 when GPS power supply is OK. */ +#define SBG_ECOM_GENERAL_SETTINGS_OK (0x0001u << 3) /*!< Set to 1 if settings where correctly loaded. */ +#define SBG_ECOM_GENERAL_TEMPERATURE_OK (0x0001u << 4) /*!< Set to 1 when temperature is within specified limits. */ +#define SBG_ECOM_GENERAL_DATALOGGER_OK (0x0001u << 5) /*!< Set to 1 when the datalogger is working correctly. */ +#define SBG_ECOM_GENERAL_CPU_OK (0x0001u << 6) /*!< Set to 1 if the CPU headroom is correct.*/ + +//----------------------------------------------------------------------// +//- Communication status definitions -// +//----------------------------------------------------------------------// + +/*! + * Communication CAN status definitions. + */ +#define SBG_ECOM_CAN_STATUS_SHIFT (28u) /*!< Shift used to access the CAN status part. */ +#define SBG_ECOM_CAN_STATUS_MASK (0x00000007u) /*!< Mask used to keep only the CAN status part. */ + +/*! + * Communication status bit mask definitions. + */ +#define SBG_ECOM_PORTA_VALID (0x00000001u << 0) /*!< Set to 0 in case of low level communication error. */ +#define SBG_ECOM_PORTB_VALID (0x00000001u << 1) /*!< Set to 0 in case of low level communication error. */ +#define SBG_ECOM_PORTC_VALID (0x00000001u << 2) /*!< Set to 0 in case of low level communication error. */ +#define SBG_ECOM_PORTD_VALID (0x00000001u << 3) /*!< Set to 0 in case of low level communication error. */ +#define SBG_ECOM_PORTE_VALID (0x00000001u << 4) /*!< Set to 0 in case of low level communication error. */ + +#define SBG_ECOM_PORTA_RX_OK (0x00000001u << 5) /*!< Set to 0 in case of error on PORT A input. */ +#define SBG_ECOM_PORTA_TX_OK (0x00000001u << 6) /*!< Set to 0 in case of error on PORT A output. */ +#define SBG_ECOM_PORTB_RX_OK (0x00000001u << 7) /*!< Set to 0 in case of error on PORT B input. */ +#define SBG_ECOM_PORTB_TX_OK (0x00000001u << 8) /*!< Set to 0 in case of error on PORT B output. */ +#define SBG_ECOM_PORTC_RX_OK (0x00000001u << 9) /*!< Set to 0 in case of error on PORT C input. */ +#define SBG_ECOM_PORTC_TX_OK (0x00000001u << 10) /*!< Set to 0 in case of error on PORT C output. */ +#define SBG_ECOM_PORTD_RX_OK (0x00000001u << 11) /*!< Set to 0 in case of error on PORT D input. */ +#define SBG_ECOM_PORTD_TX_OK (0x00000001u << 12) /*!< Set to 0 in case of error on PORT D input. */ +#define SBG_ECOM_PORTE_RX_OK (0x00000001u << 13) /*!< Set to 0 in case of error on PORT E input. */ +#define SBG_ECOM_PORTE_TX_OK (0x00000001u << 14) /*!< Set to 0 in case of error on PORT D input. */ + +#define SBG_ECOM_ETH0_VALID (0x00000001u << 15) /*!< Set to 0 in case of error on ETH0. */ +#define SBG_ECOM_ETH1_VALID (0x00000001u << 16) /*!< Set to 0 in case of error on ETH1. */ +#define SBG_ECOM_ETH2_VALID (0x00000001u << 17) /*!< Set to 0 in case of error on ETH2. */ +#define SBG_ECOM_ETH3_VALID (0x00000001u << 18) /*!< Set to 0 in case of error on ETH3. */ +#define SBG_ECOM_ETH4_VALID (0x00000001u << 19) /*!< Set to 0 in case of error on ETH4. */ + +#define SBG_ECOM_CAN_VALID (0x00000001u << 25) /*!< Set to 0 in case of low level communication error. */ +#define SBG_ECOM_CAN_RX_OK (0x00000001u << 26) /*!< Set to 0 in case of error on CAN Bus input buffer. */ +#define SBG_ECOM_CAN_TX_OK (0x00000001u << 27) /*!< Set to 0 in case of error on CAN Bus output buffer. */ + +/*! + * Second communication status bit mask definitions. + */ +#define SBG_ECOM_COM2_ETH0_RX_OK (0x0001u << 0) /*!< Set to 0 in case of error on ETH0 input. */ +#define SBG_ECOM_COM2_ETH0_TX_OK (0x0001u << 1) /*!< Set to 0 in case of error on ETH0 output. */ +#define SBG_ECOM_COM2_ETH1_RX_OK (0x0001u << 2) /*!< Set to 0 in case of error on ETH1 input. */ +#define SBG_ECOM_COM2_ETH1_TX_OK (0x0001u << 3) /*!< Set to 0 in case of error on ETH1 output. */ +#define SBG_ECOM_COM2_ETH2_RX_OK (0x0001u << 4) /*!< Set to 0 in case of error on ETH2 input. */ +#define SBG_ECOM_COM2_ETH2_TX_OK (0x0001u << 5) /*!< Set to 0 in case of error on ETH2 output. */ +#define SBG_ECOM_COM2_ETH3_RX_OK (0x0001u << 6) /*!< Set to 0 in case of error on ETH3 input. */ +#define SBG_ECOM_COM2_ETH3_TX_OK (0x0001u << 7) /*!< Set to 0 in case of error on ETH3 output. */ +#define SBG_ECOM_COM2_ETH4_RX_OK (0x0001u << 8) /*!< Set to 0 in case of error on ETH4 input. */ +#define SBG_ECOM_COM2_ETH4_TX_OK (0x0001u << 9) /*!< Set to 0 in case of error on ETH4 output. */ + +/*! + * Communication status for the CAN Bus. + */ +typedef enum _SbgEComCanBusStatus +{ + SBG_ECOM_CAN_BUS_OFF = 0, /*!< Bus OFF operation due to too much errors. */ + SBG_ECOM_CAN_BUS_TX_RX_ERR = 1, /*!< Errors on Tx or Rx. */ + SBG_ECOM_CAN_BUS_OK = 2, /*!< Bus OK. */ + SBG_ECOM_CAN_BUS_ERROR = 3 /*!< Bus error. */ +} SbgEComCanBusStatus; + +//----------------------------------------------------------------------// +//- Aiding status definitions -// +//----------------------------------------------------------------------// +#define SBG_ECOM_AIDING_GPS1_POS_RECV (0x00000001u << 0) /*!< Set to 1 when valid GPS 1 position data is received. */ +#define SBG_ECOM_AIDING_GPS1_VEL_RECV (0x00000001u << 1) /*!< Set to 1 when valid GPS 1 velocity data is received. */ +#define SBG_ECOM_AIDING_GPS1_HDT_RECV (0x00000001u << 2) /*!< Set to 1 when valid GPS 1 true heading data is received. */ +#define SBG_ECOM_AIDING_GPS1_UTC_RECV (0x00000001u << 3) /*!< Set to 1 when valid GPS 1 UTC time data is received. */ +#define SBG_ECOM_AIDING_GPS2_POS_RECV (0x00000001u << 4) /*!< Set to 1 when valid GPS 2 position data is received. */ +#define SBG_ECOM_AIDING_GPS2_VEL_RECV (0x00000001u << 5) /*!< Set to 1 when valid GPS 2 velocity data is received. */ +#define SBG_ECOM_AIDING_GPS2_HDT_RECV (0x00000001u << 6) /*!< Set to 1 when valid GPS 2 true heading data is received. */ +#define SBG_ECOM_AIDING_GPS2_UTC_RECV (0x00000001u << 7) /*!< Set to 1 when valid GPS 2 UTC time data is received. */ +#define SBG_ECOM_AIDING_MAG_RECV (0x00000001u << 8) /*!< Set to 1 when valid Magnetometer data is received. */ +#define SBG_ECOM_AIDING_ODO_RECV (0x00000001u << 9) /*!< Set to 1 when Odometer pulse is received. */ +#define SBG_ECOM_AIDING_DVL_RECV (0x00000001u << 10) /*!< Set to 1 when valid DVL data is received. */ +#define SBG_ECOM_AIDING_USBL_RECV (0x00000001u << 11) /*!< Set to 1 when valid USBL data is received. */ +#define SBG_ECOM_AIDING_DEPTH_RECV (0x00000001u << 12) /*!< Set to 1 when valid Depth Log data is received. */ +#define SBG_ECOM_AIDING_AIR_DATA_RECV (0x00000001u << 13) /*!< Set to 1 when valid Air Data (altitude and/or true airspeed) is received. */ +#define SBG_ECOM_AIDING_USER_POS_RECV (0x00000001u << 14) /*!< Set to 1 when valid user position data is received. */ +#define SBG_ECOM_AIDING_USER_VEL_RECV (0x00000001u << 15) /*!< Set to 1 when valid user velocity data is received. */ +#define SBG_ECOM_AIDING_USER_HEADING_RECV (0x00000001u << 16) /*!< Set to 1 when valid user heading data is received. */ + +//----------------------------------------------------------------------// +//- Status definitions -// +//----------------------------------------------------------------------// + +/*! + * Stores global status data. + */ +typedef struct _SbgLogStatusData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t generalStatus; /*!< General status bitmask and enums. */ + uint32_t comStatus; /*!< Communication status bitmask and enums. */ + uint16_t comStatus2; /*!< Second communication status bitmask and enums. */ + uint32_t aidingStatus; /*!< Aiding equipments status bitmask and enums. */ + uint32_t reserved2; /*!< Reserved status field for future use. */ + uint16_t reserved3; /*!< Reserved status field for future use. */ + uint32_t uptime; /*!< System uptime in seconds. */ +} SbgLogStatusData; + +//----------------------------------------------------------------------// +//- Public getters & helpers -// +//----------------------------------------------------------------------// + +/*! + * Method used to read the CAN bus status from a communication status field. + * + * \param[in] status Status field to extract the CAN bus status from it. + * \return The extracted CAN bus status. + */ +SBG_INLINE SbgEComCanBusStatus sbgEComLogStatusGetCanStatus(uint32_t status) +{ + return (SbgEComCanBusStatus)((status >> SBG_ECOM_CAN_STATUS_SHIFT) & SBG_ECOM_CAN_STATUS_MASK); +} + +/*! + * Method used to write the CAN bus status field. + * + * \param[in] canStatus The CAN bus status to set. + * \param[in] masks Bit mask to set. + * \return The build communication status field. + */ +SBG_INLINE uint32_t sbgEComLogStatusBuildCommunicationStatus(SbgEComCanBusStatus canStatus, uint32_t masks) +{ + // + // Create the combined status field + // + return ((((uint32_t)canStatus)&SBG_ECOM_CAN_STATUS_MASK) << SBG_ECOM_CAN_STATUS_SHIFT) | masks; +} + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_STATUS message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseStatusData(SbgStreamBuffer *pInputStream, SbgLogStatusData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_STATUS message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteStatusData(SbgStreamBuffer *pOutputStream, const SbgLogStatusData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_STATUS_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUsbl.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUsbl.c new file mode 100644 index 0000000..67491d0 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUsbl.c @@ -0,0 +1,57 @@ +#include "sbgEComBinaryLogUsbl.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParseUsblData(SbgStreamBuffer *pInputStream, SbgLogUsblData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + + pOutputData->latitude = sbgStreamBufferReadDoubleLE(pInputStream); + pOutputData->longitude = sbgStreamBufferReadDoubleLE(pInputStream); + + pOutputData->depth = sbgStreamBufferReadFloatLE(pInputStream); + + pOutputData->latitudeAccuracy = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->longitudeAccuracy = sbgStreamBufferReadFloatLE(pInputStream); + pOutputData->depthAccuracy = sbgStreamBufferReadFloatLE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteUsblData(SbgStreamBuffer *pOutputStream, const SbgLogUsblData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + + sbgStreamBufferWriteDoubleLE(pOutputStream, pInputData->latitude); + sbgStreamBufferWriteDoubleLE(pOutputStream, pInputData->longitude); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->depth); + + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->latitudeAccuracy); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->longitudeAccuracy); + sbgStreamBufferWriteFloatLE(pOutputStream, pInputData->depthAccuracy); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUsbl.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUsbl.h new file mode 100644 index 0000000..d97f60f --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUsbl.h @@ -0,0 +1,105 @@ +/*! + * \file sbgEComBinaryLogUsbl.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 02 June 2014 + * + * \brief Parse received USBL position mesurements logs. + * + * USBL binary logs contains underwater positioning data of a USBL beacon. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_USBL_H +#define SBG_ECOM_BINARY_LOG_USBL_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log USBL status definitions -// +//----------------------------------------------------------------------// + +/*! + * USBL sensor status mask definitions + */ +#define SBG_ECOM_USBL_TIME_SYNC (0x0001u << 0) /*!< Set to 1 if the USBL sensor data is correctly time synchronized. */ +#define SBG_ECOM_USBL_POSITION_VALID (0x0001u << 1) /*!< Set to 1 if the USBL data represents a valid 2D position. */ +#define SBG_ECOM_USBL_DEPTH_VALID (0x0001u << 2) /*!< Set to 1 if the USBL data has a valid depth information. */ + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Log structure for USBL data. + */ +typedef struct _SbgLogUsblData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< USBL system status bitmask. */ + + double latitude; /*!< Latitude in degrees, positive north. */ + double longitude; /*!< Longitude in degrees, positive east. */ + + float depth; /*!< Depth in meters below mean sea level (positive down). */ + + float latitudeAccuracy; /*!< 1 sigma latitude accuracy in meters. */ + float longitudeAccuracy; /*!< 1 sigma longitude accuracy in meters. */ + float depthAccuracy; /*!< 1 sigma depth accuracy in meters. */ +} SbgLogUsblData; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse data for the SBG_ECOM_LOG_USBL message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseUsblData(SbgStreamBuffer *pInputStream, SbgLogUsblData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_USBL message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteUsblData(SbgStreamBuffer *pOutputStream, const SbgLogUsblData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_USBL_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUtc.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUtc.c new file mode 100644 index 0000000..d803438 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUtc.c @@ -0,0 +1,100 @@ +#include "sbgEComBinaryLogUtc.h" + +//----------------------------------------------------------------------// +//- Private global definitions -// +//----------------------------------------------------------------------// + +/*!< Lookup table for clock status enum */ +static const char *gClockStatusStr[] = +{ + [SBG_ECOM_CLOCK_ERROR] = "SBG_ECOM_CLOCK_ERROR", + [SBG_ECOM_CLOCK_FREE_RUNNING] = "SBG_ECOM_CLOCK_FREE_RUNNING", + [SBG_ECOM_CLOCK_STEERING] = "SBG_ECOM_CLOCK_STEERING", + [SBG_ECOM_CLOCK_VALID] = "SBG_ECOM_CLOCK_VALID" +}; + +/*!< Lookup table for UTC status enum */ +static const char *gUtcStatusStr[] = +{ + [SBG_ECOM_UTC_INVALID] = "SBG_ECOM_UTC_INVALID", + [SBG_ECOM_UTC_NO_LEAP_SEC] = "SBG_ECOM_UTC_NO_LEAP_SEC", + [SBG_ECOM_UTC_VALID] = "SBG_ECOM_UTC_VALID", +}; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +const char *sbgEcomLogUtcGetClockStatusAsString(const SbgLogUtcData *pLogUtc) +{ + SbgEComClockStatus clockStatus; + + assert(pLogUtc); + + clockStatus = sbgEComLogUtcGetClockStatus(pLogUtc->status); + assert(clockStatus < SBG_ARRAY_SIZE(gClockStatusStr)); + + return gClockStatusStr[clockStatus]; +} + +const char *sbgEcomLogUtcGetUtcStatusAsString(const SbgLogUtcData *pLogUtc) +{ + SbgEComClockUtcStatus utcStatus; + + assert(pLogUtc); + + utcStatus = sbgEComLogUtcGetClockUtcStatus(pLogUtc->status); + assert(utcStatus < SBG_ARRAY_SIZE(gUtcStatusStr)); + + return gUtcStatusStr[utcStatus]; +} + +SbgErrorCode sbgEComBinaryLogParseUtcData(SbgStreamBuffer *pInputStream, SbgLogUtcData *pOutputData) +{ + assert(pInputStream); + assert(pOutputData); + + // + // Read the frame payload + // + pOutputData->timeStamp = sbgStreamBufferReadUint32LE(pInputStream); + pOutputData->status = sbgStreamBufferReadUint16LE(pInputStream); + pOutputData->year = sbgStreamBufferReadUint16LE(pInputStream); + pOutputData->month = sbgStreamBufferReadInt8LE(pInputStream); + pOutputData->day = sbgStreamBufferReadInt8LE(pInputStream); + pOutputData->hour = sbgStreamBufferReadInt8LE(pInputStream); + pOutputData->minute = sbgStreamBufferReadInt8LE(pInputStream); + pOutputData->second = sbgStreamBufferReadInt8LE(pInputStream); + pOutputData->nanoSecond = sbgStreamBufferReadInt32LE(pInputStream); + pOutputData->gpsTimeOfWeek = sbgStreamBufferReadUint32LE(pInputStream); + + // + // Return if any error has occurred while parsing the frame + // + return sbgStreamBufferGetLastError(pInputStream); +} + +SbgErrorCode sbgEComBinaryLogWriteUtcData(SbgStreamBuffer *pOutputStream, const SbgLogUtcData *pInputData) +{ + assert(pOutputStream); + assert(pInputData); + + // + // Write the frame payload + // + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->timeStamp); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->status); + sbgStreamBufferWriteUint16LE(pOutputStream, pInputData->year); + sbgStreamBufferWriteInt8LE(pOutputStream, pInputData->month); + sbgStreamBufferWriteInt8LE(pOutputStream, pInputData->day); + sbgStreamBufferWriteInt8LE(pOutputStream, pInputData->hour); + sbgStreamBufferWriteInt8LE(pOutputStream, pInputData->minute); + sbgStreamBufferWriteInt8LE(pOutputStream, pInputData->second); + sbgStreamBufferWriteInt32LE(pOutputStream, pInputData->nanoSecond); + sbgStreamBufferWriteUint32LE(pOutputStream, pInputData->gpsTimeOfWeek); + + // + // Return if any error has occurred while writing the frame + // + return sbgStreamBufferGetLastError(pOutputStream); +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUtc.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUtc.h new file mode 100644 index 0000000..39561bb --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogUtc.h @@ -0,0 +1,190 @@ +/*! + * \file sbgEComBinaryLogUtc.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 20 February 2013 + * + * \brief Parse logs used to report device UTC time. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_BINARY_LOG_UTC_H +#define SBG_ECOM_BINARY_LOG_UTC_H + +// sbgCommonLib headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Clock status definitions -// +//----------------------------------------------------------------------// + +/*! + * Clock status and UTC time status definitions. + */ +#define SBG_ECOM_CLOCK_STATUS_SHIFT (1u) /*!< Shift used to extract the clock status part. */ +#define SBG_ECOM_CLOCK_STATUS_MASK (0x000Fu) /*!< Mask used to keep only the clock status part. */ +#define SBG_ECOM_CLOCK_UTC_STATUS_SHIFT (6u) /*!< Shift used to extract the clock UTC status part. */ +#define SBG_ECOM_CLOCK_UTC_STATUS_MASK (0x000Fu) /*!< Mask used to keep only the clock UTC status part. */ + +/*! + * Clock status mask definitions. + */ +#define SBG_ECOM_CLOCK_STABLE_INPUT (0x0001u << 0) /*!< Set to 1 if a stable input clock could be used to synchronized the internal clock. */ +#define SBG_ECOM_CLOCK_UTC_SYNC (0x0001u << 5) /*!< The UTC time is synchronized with a PPS. */ + +/*! + * Clock status enum. + */ +typedef enum _SbgEComClockStatus +{ + SBG_ECOM_CLOCK_ERROR = 0, /*!< An error has occurred on the clock estimation. */ + SBG_ECOM_CLOCK_FREE_RUNNING = 1, /*!< The clock is only based on the internal crystal. */ + SBG_ECOM_CLOCK_STEERING = 2, /*!< A PPS has been detected and the clock is converging to it. */ + SBG_ECOM_CLOCK_VALID = 3 /*!< The clock has converged to the PPS and is within 500ns. */ +} SbgEComClockStatus; + +/*! + * Status for the UTC time data. + */ +typedef enum _SbgEComClockUtcStatus +{ + SBG_ECOM_UTC_INVALID = 0, /*!< The UTC time is not known, we are just propagating the UTC time internally. */ + SBG_ECOM_UTC_NO_LEAP_SEC = 1, /*!< We have received valid UTC time information but we don't have the leap seconds information. */ + SBG_ECOM_UTC_VALID = 2 /*!< We have received valid UTC time data with valid leap seconds. */ +} SbgEComClockUtcStatus; + +//----------------------------------------------------------------------// +//- Clock status helpers methods -// +//----------------------------------------------------------------------// + +/*! + * Method used to read the clock status from a status field. + * + * \param[in] status Status field to extract the clock status from it. + * \return The extracted clock status. + */ +SBG_INLINE SbgEComClockStatus sbgEComLogUtcGetClockStatus(uint16_t status) +{ + return (SbgEComClockStatus)((status >> SBG_ECOM_CLOCK_STATUS_SHIFT) & SBG_ECOM_CLOCK_STATUS_MASK); +} + +/*! + * Method used to read the UTC time status from a clock status field. + * + * \param[in] status Status field to extract the UTC time status from it. + * \return The extracted UTC time status. + */ +SBG_INLINE SbgEComClockUtcStatus sbgEComLogUtcGetClockUtcStatus(uint16_t status) +{ + return (SbgEComClockUtcStatus)((status >> SBG_ECOM_CLOCK_UTC_STATUS_SHIFT) & SBG_ECOM_CLOCK_UTC_STATUS_MASK); +} + +/*! + * Method used to write the clock status field. + * + * \param[in] clockStatus The clock status to set. + * \param[in] utcStatus The UTC time status to set. + * \param[in] masks Bit mask to set. + * \return The build clock status field. + */ +SBG_INLINE uint16_t sbgEComLogUtcBuildClockStatus(SbgEComClockStatus clockStatus, SbgEComClockUtcStatus utcStatus, uint16_t masks) +{ + // + // Create the combined status field + // + return ((((uint16_t)clockStatus)&SBG_ECOM_CLOCK_STATUS_MASK) << SBG_ECOM_CLOCK_STATUS_SHIFT) | + ((((uint16_t)utcStatus)&SBG_ECOM_CLOCK_UTC_STATUS_MASK) << SBG_ECOM_CLOCK_UTC_STATUS_SHIFT) | masks; +} + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Structure that stores data for the SBG_ECOM_LOG_UTC_TIME message. + */ +typedef struct _SbgLogUtcData +{ + uint32_t timeStamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< UTC time and clock status information */ + uint16_t year; /*!< Year for example: 2013. */ + int8_t month; /*!< Month in year [1 .. 12]. */ + int8_t day; /*!< Day in month [1 .. 31]. */ + int8_t hour; /*!< Hour in day [0 .. 23]. */ + int8_t minute; /*!< Minute in hour [0 .. 59]. */ + int8_t second; /*!< Second in minute [0 .. 60]. (60 is used only when a leap second is added) */ + int32_t nanoSecond; /*!< Nanosecond of current second in ns. */ + uint32_t gpsTimeOfWeek; /*!< GPS time of week in ms. */ +} SbgLogUtcData; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Returns the clock status as a NULL terminated C string. + * + * \param[in] pLogUtc UTC log instance. + * \return The clock status as a C string. + */ +const char *sbgEcomLogUtcGetClockStatusAsString(const SbgLogUtcData *pLogUtc); + + +/*! + * Returns the UTC status as a NULL terminated C string. + * + * \param[in] pLogUtc UTC log instance. + * \return The UTC status as a C string. + */ +const char *sbgEcomLogUtcGetUtcStatusAsString(const SbgLogUtcData *pLogUtc); + +/*! + * Parse data for the SBG_ECOM_LOG_UTC_DATA message and fill the corresponding structure. + * + * \param[in] pInputStream Input stream buffer to read the payload from. + * \param[out] pOutputData Pointer on the output structure that stores parsed data. + * \return SBG_NO_ERROR if the payload has been parsed. + */ +SbgErrorCode sbgEComBinaryLogParseUtcData(SbgStreamBuffer *pInputStream, SbgLogUtcData *pOutputData); + +/*! + * Write data for the SBG_ECOM_LOG_UTC_DATA message to the output stream buffer from the provided structure. + * + * \param[out] pOutputStream Output stream buffer to write the payload to. + * \param[in] pInputData Pointer on the input structure that stores data to write. + * \return SBG_NO_ERROR if the message has been generated in the provided buffer. + */ +SbgErrorCode sbgEComBinaryLogWriteUtcData(SbgStreamBuffer *pOutputStream, const SbgLogUtcData *pInputData); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOG_UTC_H diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogs.c b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogs.c new file mode 100644 index 0000000..883e0b2 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogs.c @@ -0,0 +1,183 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComBinaryLogAirData.h" +#include "sbgEComBinaryLogDepth.h" +#include "sbgEComBinaryLogDiag.h" +#include "sbgEComBinaryLogDvl.h" +#include "sbgEComBinaryLogEkf.h" +#include "sbgEComBinaryLogEvent.h" +#include "sbgEComBinaryLogGps.h" +#include "sbgEComBinaryLogImu.h" +#include "sbgEComBinaryLogMag.h" +#include "sbgEComBinaryLogOdometer.h" +#include "sbgEComBinaryLogRtcm.h" +#include "sbgEComBinaryLogShipMotion.h" +#include "sbgEComBinaryLogStatus.h" +#include "sbgEComBinaryLogUsbl.h" +#include "sbgEComBinaryLogUtc.h" +#include "sbgEComBinaryLogSat.h" +#include "sbgEComBinaryLogs.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComBinaryLogParse(SbgEComClass msgClass, SbgEComMsgId msg, const void *pPayload, size_t payloadSize, SbgBinaryLogData *pOutputData) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgStreamBuffer inputStream; + + assert(pPayload); + assert(payloadSize > 0); + assert(pOutputData); + + // + // Create an input stream buffer that points to the frame payload so we can easily parse it's content + // + sbgStreamBufferInitForRead(&inputStream, pPayload, payloadSize); + + // + // Handle the different classes of messages differently + // + if (msgClass == SBG_ECOM_CLASS_LOG_ECOM_0) + { + // + // Parse the incoming log according to its type + // + switch (msg) + { + case SBG_ECOM_LOG_STATUS: + errorCode = sbgEComBinaryLogParseStatusData(&inputStream, &pOutputData->statusData); + break; + case SBG_ECOM_LOG_IMU_DATA: + errorCode = sbgEComBinaryLogParseImuData(&inputStream, &pOutputData->imuData); + break; + case SBG_ECOM_LOG_IMU_SHORT: + errorCode = sbgEComBinaryLogParseImuShort(&inputStream, &pOutputData->imuShort); + break; + case SBG_ECOM_LOG_EKF_EULER: + errorCode = sbgEComBinaryLogParseEkfEulerData(&inputStream, &pOutputData->ekfEulerData); + break; + case SBG_ECOM_LOG_EKF_QUAT: + errorCode = sbgEComBinaryLogParseEkfQuatData(&inputStream, &pOutputData->ekfQuatData); + break; + case SBG_ECOM_LOG_EKF_NAV: + errorCode = sbgEComBinaryLogParseEkfNavData(&inputStream, &pOutputData->ekfNavData); + break; + case SBG_ECOM_LOG_SHIP_MOTION: + case SBG_ECOM_LOG_SHIP_MOTION_HP: + errorCode = sbgEComBinaryLogParseShipMotionData(&inputStream, &pOutputData->shipMotionData); + break; + case SBG_ECOM_LOG_ODO_VEL: + errorCode = sbgEComBinaryLogParseOdometerData(&inputStream, &pOutputData->odometerData); + break; + case SBG_ECOM_LOG_UTC_TIME: + errorCode = sbgEComBinaryLogParseUtcData(&inputStream, &pOutputData->utcData); + break; + case SBG_ECOM_LOG_GPS1_VEL: + case SBG_ECOM_LOG_GPS2_VEL: + errorCode = sbgEComBinaryLogParseGpsVelData(&inputStream, &pOutputData->gpsVelData); + break; + case SBG_ECOM_LOG_GPS1_POS: + case SBG_ECOM_LOG_GPS2_POS: + errorCode = sbgEComBinaryLogParseGpsPosData(&inputStream, &pOutputData->gpsPosData); + break; + case SBG_ECOM_LOG_GPS1_HDT: + case SBG_ECOM_LOG_GPS2_HDT: + errorCode = sbgEComBinaryLogParseGpsHdtData(&inputStream, &pOutputData->gpsHdtData); + break; + case SBG_ECOM_LOG_GPS1_RAW: + case SBG_ECOM_LOG_GPS2_RAW: + errorCode = sbgEComBinaryLogParseGpsRawData(&inputStream, &pOutputData->gpsRawData); + break; + case SBG_ECOM_LOG_GPS1_SAT: + case SBG_ECOM_LOG_GPS2_SAT: + errorCode = sbgEComBinaryLogParseSatGroupData(&inputStream, &pOutputData->satGroupData); + break; + case SBG_ECOM_LOG_RTCM_RAW: + errorCode = sbgEComBinaryLogParseRtcmRawData(&inputStream, &pOutputData->rtcmRawData); + break; + case SBG_ECOM_LOG_MAG: + errorCode = sbgEComBinaryLogParseMagData(&inputStream, &pOutputData->magData); + break; + case SBG_ECOM_LOG_MAG_CALIB: + errorCode = sbgEComBinaryLogParseMagCalibData(&inputStream, &pOutputData->magCalibData); + break; + case SBG_ECOM_LOG_DVL_BOTTOM_TRACK: + errorCode = sbgEComBinaryLogParseDvlData(&inputStream, &pOutputData->dvlData); + break; + case SBG_ECOM_LOG_DVL_WATER_TRACK: + errorCode = sbgEComBinaryLogParseDvlData(&inputStream, &pOutputData->dvlData); + break; + case SBG_ECOM_LOG_AIR_DATA: + errorCode = sbgEComBinaryLogParseAirData(&inputStream, &pOutputData->airData); + break; + case SBG_ECOM_LOG_USBL: + errorCode = sbgEComBinaryLogParseUsblData(&inputStream, &pOutputData->usblData); + break; + case SBG_ECOM_LOG_DEPTH: + errorCode = sbgEComBinaryLogParseDepth(&inputStream, &pOutputData->depthData); + break; + case SBG_ECOM_LOG_EVENT_A: + case SBG_ECOM_LOG_EVENT_B: + case SBG_ECOM_LOG_EVENT_C: + case SBG_ECOM_LOG_EVENT_D: + case SBG_ECOM_LOG_EVENT_E: + case SBG_ECOM_LOG_EVENT_OUT_A: + case SBG_ECOM_LOG_EVENT_OUT_B: + errorCode = sbgEComBinaryLogParseEvent(&inputStream, &pOutputData->eventMarker); + break; + case SBG_ECOM_LOG_DIAG: + errorCode = sbgEComBinaryLogParseDiagData(&inputStream, &pOutputData->diagData); + break; + + default: + errorCode = SBG_ERROR; + } + } + else if (msgClass == SBG_ECOM_CLASS_LOG_ECOM_1) + { + // + // Parse the message depending on the message ID + // + switch ((SbgEComLog1)msg) + { + case SBG_ECOM_LOG_FAST_IMU_DATA: + errorCode = sbgEComBinaryLogParseFastImuData(&inputStream, &pOutputData->fastImuData); + break; + default: + errorCode = SBG_ERROR; + } + } + else + { + // + // Un-handled message class + // + errorCode = SBG_ERROR; + } + + return errorCode; +} + +void sbgEComBinaryLogCleanup(SbgBinaryLogData *pLogData, SbgEComClass msgClass, SbgEComMsgId msgId) +{ + assert(pLogData); + + if (msgClass == SBG_ECOM_CLASS_LOG_ECOM_0) + { + switch (msgId) + { + case SBG_ECOM_LOG_GPS1_SAT: + case SBG_ECOM_LOG_GPS2_SAT: + sbgLogSatGroupDataDestroy(&pLogData->satGroupData); + break; + } + } +} diff --git a/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogs.h b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogs.h new file mode 100644 index 0000000..9782a16 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/binaryLogs/sbgEComBinaryLogs.h @@ -0,0 +1,136 @@ +/*! + * \file sbgEComBinaryLogs.h + * \ingroup binaryLogs + * \author SBG Systems + * \date 06 February 2013 + * + * \brief Parse incoming sbgECom logs and store result in an union. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +/*! + * \defgroup binaryLogs Binary Logs + * \brief All messages and logs that can be output by the device. + */ + +#ifndef SBG_ECOM_BINARY_LOGS_H +#define SBG_ECOM_BINARY_LOGS_H + + // sbgCommonLib headers +#include + +// Project headers +#include + +// Local headers +#include "sbgEComBinaryLogAirData.h" +#include "sbgEComBinaryLogDepth.h" +#include "sbgEComBinaryLogDiag.h" +#include "sbgEComBinaryLogDvl.h" +#include "sbgEComBinaryLogEkf.h" +#include "sbgEComBinaryLogEvent.h" +#include "sbgEComBinaryLogGps.h" +#include "sbgEComBinaryLogImu.h" +#include "sbgEComBinaryLogMag.h" +#include "sbgEComBinaryLogOdometer.h" +#include "sbgEComBinaryLogRawData.h" +#include "sbgEComBinaryLogRtcm.h" +#include "sbgEComBinaryLogSat.h" +#include "sbgEComBinaryLogShipMotion.h" +#include "sbgEComBinaryLogStatus.h" +#include "sbgEComBinaryLogUsbl.h" +#include "sbgEComBinaryLogUtc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Log structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Union used to store received logs data. + */ +typedef union _SbgBinaryLogData +{ + SbgLogStatusData statusData; /*!< Stores data for the SBG_ECOM_LOG_STATUS message. */ + SbgLogImuData imuData; /*!< Stores data for the SBG_ECOM_LOG_IMU_DATA message. */ + SbgLogImuShort imuShort; /*!< Stores data for the SBG_ECOM_LOG_IMU_SHORT message. */ + SbgLogEkfEulerData ekfEulerData; /*!< Stores data for the SBG_ECOM_LOG_EKF_EULER message. */ + SbgLogEkfQuatData ekfQuatData; /*!< Stores data for the SBG_ECOM_LOG_EKF_QUAT message. */ + SbgLogEkfNavData ekfNavData; /*!< Stores data for the SBG_ECOM_LOG_EKF_NAV message. */ + SbgLogShipMotionData shipMotionData; /*!< Stores data for the SBG_ECOM_LOG_SHIP_MOTION or SBG_ECOM_LOG_SHIP_MOTION_HP message. */ + SbgLogOdometerData odometerData; /*!< Stores data for the SBG_ECOM_LOG_ODO_VEL message. */ + SbgLogUtcData utcData; /*!< Stores data for the SBG_ECOM_LOG_UTC_TIME message. */ + SbgLogGpsPos gpsPosData; /*!< Stores data for the SBG_ECOM_LOG_GPS_POS message. */ + SbgLogGpsVel gpsVelData; /*!< Stores data for the SBG_ECOM_LOG_GPS#_VEL message. */ + SbgLogGpsHdt gpsHdtData; /*!< Stores data for the SBG_ECOM_LOG_GPS#_HDT message. */ + SbgLogRawData gpsRawData; /*!< Stores data for the SBG_ECOM_LOG_GPS#_RAW message. */ + SbgLogRawData rtcmRawData; /*!< Stores data for the SBG_ECOM_LOG_RTCM_RAW message. */ + SbgLogMag magData; /*!< Stores data for the SBG_ECOM_LOG_MAG message. */ + SbgLogMagCalib magCalibData; /*!< Stores data for the SBG_ECOM_LOG_MAG_CALIB message. */ + SbgLogDvlData dvlData; /*!< Stores data for the SBG_ECOM_LOG_DVL_BOTTOM_TRACK message. */ + SbgLogAirData airData; /*!< Stores data for the SBG_ECOM_LOG_AIR_DATA message. */ + SbgLogUsblData usblData; /*!< Stores data for the SBG_ECOM_LOG_USBL message. */ + SbgLogDepth depthData; /*!< Stores data for the SBG_ECOM_LOG_DEPTH message */ + SbgLogEvent eventMarker; /*!< Stores data for the SBG_ECOM_LOG_EVENT_# message. */ + SbgLogDiagData diagData; /*!< Stores data for the SBG_ECOM_LOG_DIAG message. */ + SbgLogSatGroupData satGroupData; /*!< Stores data for the SBG_ECOM_LOG_SAT message. */ + + /* Fast logs */ + SbgLogFastImuData fastImuData; /*!< Stores Fast Imu Data for 1KHz output */ + +} SbgBinaryLogData; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Parse an incoming log and fill the output union. + * + * \param[in] msgClass Received message class + * \param[in] msg Received message ID + * \param[in] pPayload Read only pointer on the payload buffer. + * \param[in] payloadSize Payload size in bytes. + * \param[out] pOutputData Pointer on the output union that stores parsed data. + */ +SbgErrorCode sbgEComBinaryLogParse(SbgEComClass msgClass, SbgEComMsgId msg, const void *pPayload, size_t payloadSize, SbgBinaryLogData *pOutputData); + +/*! + * Clean up resources allocated during parsing, if any. + * + * \param[in] pLogData Log data. + * \param[in] msgClass Message class. + * \param[in] msgId Message ID. + */ +void sbgEComBinaryLogCleanup(SbgBinaryLogData *pLogData, SbgEComClass msgClass, SbgEComMsgId msgId); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_BINARY_LOGS_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmd.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmd.h new file mode 100644 index 0000000..2620e5e --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmd.h @@ -0,0 +1,62 @@ +/*! + * \file sbgEComCmd.h + * \ingroup commands + * \author SBG Systems + * \date 16 June 2014 + * + * \brief Include all available sbgECom commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +/*! + * \defgroup commands Commands + * \brief Configuration and action commands mainly for ELLIPSE products. + */ + +#ifndef SBG_ECOM_CMD_H +#define SBG_ECOM_CMD_H + +// sbgCommonLib headers +#include + +// Local headers +#include "sbgEComCmdAdvanced.h" +#include "sbgEComCmdAirData.h" +#include "sbgEComCmdApi.h" +#include "sbgEComCmdDvl.h" +#include "sbgEComCmdEthernet.h" +#include "sbgEComCmdEvent.h" +#include "sbgEComCmdFeatures.h" +#include "sbgEComCmdGnss.h" +#include "sbgEComCmdInfo.h" +#include "sbgEComCmdInterface.h" +#include "sbgEComCmdLicense.h" +#include "sbgEComCmdMag.h" +#include "sbgEComCmdOdo.h" +#include "sbgEComCmdOutput.h" +#include "sbgEComCmdSensor.h" +#include "sbgEComCmdSettings.h" + +#endif // SBG_ECOM_CMD_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAdvanced.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAdvanced.c new file mode 100644 index 0000000..d0df61c --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAdvanced.c @@ -0,0 +1,318 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdAdvanced.h" +#include "sbgEComCmdCommon.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdAdvancedGetConf(SbgEComHandle *pHandle, SbgEComAdvancedConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command without payload since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ADVANCED_CONF, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ADVANCED_CONF, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_ADVANCED_CONF command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read the mandatory time reference parameter + // + pConf->timeReference = (SbgEComTimeReferenceSrc)sbgStreamBufferReadUint8LE(&inputStream); + errorCode = sbgStreamBufferGetLastError(&inputStream); + + if (errorCode == SBG_NO_ERROR) + { + // + // The GNSS options parameter has been introduced in ELLIPSE firmware v2.2 + // We shouldn't report it as an error for older firmware + // + pConf->gnssOptions = sbgStreamBufferReadUint32LE(&inputStream); + + if (sbgStreamBufferGetLastError(&inputStream) == SBG_NO_ERROR) + { + // + // The NMEA options parameter has been introduced in ELLIPSE firmware v2.3 + // We shouldn't report it as an error for older firmware + // + pConf->nmeaOptions = sbgStreamBufferReadUint32LE(&inputStream); + + if (sbgStreamBufferGetLastError(&inputStream) == SBG_NO_ERROR) + { + errorCode = SBG_NO_ERROR; + } + else + { + pConf->nmeaOptions = 0; + } + } + else + { + pConf->gnssOptions = 0; + } + } + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdAdvancedSetConf(SbgEComHandle *pHandle, const SbgEComAdvancedConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[9]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->timeReference); + sbgStreamBufferWriteUint32LE(&outputStream, pConf->gnssOptions); + sbgStreamBufferWriteUint32LE(&outputStream, pConf->nmeaOptions); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ADVANCED_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ADVANCED_CONF, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdAdvancedGetThresholds(SbgEComHandle *pHandle, SbgEComValidityThresholds *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command without payload since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_VALIDITY_THRESHOLDS, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_VALIDITY_THRESHOLDS, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_VALIDITY_THRESHOLDS command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters and check payload consistency + // + pConf->positionThreshold = sbgStreamBufferReadFloatLE(&inputStream); + pConf->velocityThreshold = sbgStreamBufferReadFloatLE(&inputStream); + pConf->attitudeThreshold = sbgStreamBufferReadFloatLE(&inputStream); + pConf->headingThreshold = sbgStreamBufferReadFloatLE(&inputStream); + + errorCode = sbgStreamBufferGetLastError(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdAdvancedSetThresholds(SbgEComHandle *pHandle, const SbgEComValidityThresholds *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[4*sizeof(float)]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteFloatLE(&outputStream, pConf->positionThreshold); + sbgStreamBufferWriteFloatLE(&outputStream, pConf->velocityThreshold); + sbgStreamBufferWriteFloatLE(&outputStream, pConf->attitudeThreshold); + sbgStreamBufferWriteFloatLE(&outputStream, pConf->headingThreshold); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_VALIDITY_THRESHOLDS, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_VALIDITY_THRESHOLDS, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAdvanced.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAdvanced.h new file mode 100644 index 0000000..23a7415 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAdvanced.h @@ -0,0 +1,142 @@ +/*! + * \file sbgEComCmdAdvanced.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief Advanced settings related commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_ADVANCED_H +#define SBG_ECOM_CMD_ADVANCED_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Advanced definitions -// +//----------------------------------------------------------------------// + +/*! + * List of available time reference source. + */ +typedef enum _SbgEComTimeReferenceSrc +{ + SBG_ECOM_TIME_REF_DISABLED = 0, /*!< The device is running it's internal clock without any time reference. */ + SBG_ECOM_TIME_REF_SYNC_IN_A, /*!< The main port sync in A is used as a time reference. */ + SBG_ECOM_TIME_REF_UTC_GPS_1 /*!< The GPS 1 module is used to provide both time reference and UTC data. */ +} SbgEComTimeReferenceSrc; + +/*! + * List all options for the GNSS bitmask options + */ +#define SBG_ECOM_GNSS_OPT_01 (uint32_t)(0x00000001 << 0) /*!< Reserved advanced GNSS option for ELLIPSE-N/D v3 */ + +/*! + * List all options for the NMEA bitmask options + */ +#define SBG_ECOM_NMEA_OPT_MODE_STD (uint32_t)(0x00000001 << 0) /*!< Output NMEA messages that complies with 82 chars limit */ +#define SBG_ECOM_NMEA_OPT_FORCE_UTC (uint32_t)(0x00000001 << 4) /*!< Always output time in NMEA messages even if invalid */ + +//----------------------------------------------------------------------// +//- Advanced configurations -// +//----------------------------------------------------------------------// + +/*! + * Structure containing all the info for advanced configuration. + */ +typedef struct _SbgEComAdvancedConf +{ + SbgEComTimeReferenceSrc timeReference; /*!< Time reference source for clock alignment. */ + uint32_t gnssOptions; /*!< Advanced GNSS options - contact SBG Systems. */ + uint32_t nmeaOptions; /*!< Advanced NMEA output options. */ +} SbgEComAdvancedConf; + +/*! + * Structure containing all validity thresholds (status outputs) + * Setting these thresholds to 0.0 will keep default configuration + */ +typedef struct _SbgEComValidityThresholds +{ + float positionThreshold; /*!< Norm of the position standard deviation threshold to raise position valid flag (m)*/ + float velocityThreshold; /*!< Norm of the velocity standard deviation threshold to raise velocity valid flag (m/s)*/ + float attitudeThreshold; /*!< Max of the roll/pitch standard deviations threshold to raise attitude valid flag (rad) */ + float headingThreshold; /*!< Heading standard deviations threshold to raise heading valid flag (rad) */ +} SbgEComValidityThresholds; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Retrieve the advanced configurations. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pConf Pointer to a SbgEComAdvancedConf to contain the current configuration. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdAdvancedGetConf(SbgEComHandle *pHandle, SbgEComAdvancedConf *pConf); + +/*! + * Set the advanced configurations. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pConf Pointer to a SbgEComAdvancedConf that contains the new configuration. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdAdvancedSetConf(SbgEComHandle *pHandle, const SbgEComAdvancedConf *pConf); + +/*! + * Retrieve the current validity thresholds + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pConf Pointer to a SbgEComValidityThresholds to contain the current configuration. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ + +SbgErrorCode sbgEComCmdAdvancedGetThresholds(SbgEComHandle *pHandle, SbgEComValidityThresholds *pConf); + +/*! + * Set the validity thresholds + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pConf Pointer to a SbgEComValidityThresholds that contains the new configuration. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdAdvancedSetThresholds(SbgEComHandle *pHandle, const SbgEComValidityThresholds *pConf); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_ADVANCED_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAirData.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAirData.c new file mode 100644 index 0000000..5ae9a6c --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAirData.c @@ -0,0 +1,323 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdAirData.h" +#include "sbgEComCmdCommon.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + + +SbgErrorCode sbgEComCmdAirDataSetModelId(SbgEComHandle *pHandle, SbgEComAirDataModelsIds modelId) +{ + assert(pHandle); + + return sbgEComCmdGenericSetModelId(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIRDATA_MODEL_ID, modelId); +} + +SbgErrorCode sbgEComCmdAirDataGetModelId(SbgEComHandle *pHandle, SbgEComAirDataModelsIds *pModelId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t modelIdAsUint; + + assert(pHandle); + assert(pModelId); + + errorCode = sbgEComCmdGenericGetModelId(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIRDATA_MODEL_ID, &modelIdAsUint); + + if (errorCode == SBG_NO_ERROR) + { + *pModelId = (SbgEComAirDataModelsIds)modelIdAsUint; + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdAirDataSetLeverArm(SbgEComHandle *pHandle, const float *pLeverArm) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pLeverArm); + + // + // Create the command payload + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteFloatLE(&outputStream, pLeverArm[0]); + sbgStreamBufferWriteFloatLE(&outputStream, pLeverArm[1]); + sbgStreamBufferWriteFloatLE(&outputStream, pLeverArm[2]); + + // + // Make sure the payload has been build correctly + // + errorCode = sbgStreamBufferGetLastError(&outputStream); + + if (errorCode == SBG_NO_ERROR) + { + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIRDATA_LEVER_ARM, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIRDATA_LEVER_ARM, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdAirDataGetLeverArm(SbgEComHandle *pHandle, float *pLeverArm) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pLeverArm); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIRDATA_LEVER_ARM, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIRDATA_LEVER_ARM, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_GNSS_1_LEVER_ARM_ALIGNMENT command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to parse the payload + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + pLeverArm[0] = sbgStreamBufferReadFloatLE(&inputStream); + pLeverArm[1] = sbgStreamBufferReadFloatLE(&inputStream); + pLeverArm[2] = sbgStreamBufferReadFloatLE(&inputStream); + + // + // The command has been executed successfully so return if an error has occurred during payload parsing + // + errorCode = sbgStreamBufferGetLastError(&inputStream); + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdAirDataSetRejection(SbgEComHandle *pHandle, const SbgEComAirDataRejectionConf *pRejectConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[2 * sizeof(uint8_t)]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pRejectConf); + + // + // Create the command payload + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(&outputStream, pRejectConf->airspeed); + sbgStreamBufferWriteUint8LE(&outputStream, pRejectConf->altitude); + + // + // Make sure the payload has been build correctly + // + errorCode = sbgStreamBufferGetLastError(&outputStream); + + if (errorCode == SBG_NO_ERROR) + { + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIRDATA_REJECT_MODES, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIRDATA_REJECT_MODES, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdAirDataGetRejection(SbgEComHandle *pHandle, SbgEComAirDataRejectionConf *pRejectConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pRejectConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIRDATA_REJECT_MODES, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIRDATA_REJECT_MODES, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_GNSS_1_REJECT_MODES command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to parse payload + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Parse the payload + // + pRejectConf->airspeed = (SbgEComRejectionMode)sbgStreamBufferReadUint8LE(&inputStream); + pRejectConf->altitude = (SbgEComRejectionMode)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return if an error has occurred during payload parsing + // + errorCode = sbgStreamBufferGetLastError(&inputStream); + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAirData.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAirData.h new file mode 100644 index 0000000..2d463f4 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdAirData.h @@ -0,0 +1,134 @@ +/*! + * \file sbgEComCmdAirData.h + * \ingroup commands + * \author SBG Systems + * \date 18 February 2019 + * + * \brief AirData aiding module configuration commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_AIR_DATA_H +#define SBG_ECOM_CMD_AIR_DATA_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Public definitions -// +//----------------------------------------------------------------------// + +/*! + * This enum defines the different AirData model IDs available in standard + */ +typedef enum _SbgEComAirDataModelsIds +{ + SBG_ECOM_AIR_DATA_MODEL_INTERNAL = 1, /*!< Use the internal barometer sensor if available. */ + SBG_ECOM_AIR_DATA_MODEL_GENERIC_ECOM = 2, /*!< Generic AirData model using sbgECom input protocol format. */ + SBG_ECOM_AIR_DATA_MODEL_AHRS_500 = 3, /*!< Crossbow AHRS-500 compatible input for barometric altitude and airspeed. */ +} SbgEComAirDataModelsIds; + +/*! + * Holds all necessary information for AirData module data rejection. + */ +typedef struct _SbgEComAirDataRejectionConf +{ + SbgEComRejectionMode airspeed; /*!< Rejection mode for the true air speed measurement. */ + SbgEComRejectionMode altitude; /*!< Rejection mode for the barometric altitude measurement. */ +} SbgEComAirDataRejectionConf; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Set the AirData model to use that both defines the protocol as well as the associated error model. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] modelId AirData model ID to set + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdAirDataSetModelId(SbgEComHandle *pHandle, SbgEComAirDataModelsIds modelId); + +/*! + * Retrieve the AirData model id currently in use by the device. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pModelId Returns the AirData model ID currently in use by the device. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdAirDataGetModelId(SbgEComHandle *pHandle, SbgEComAirDataModelsIds *pModelId); + +/*! + * Set the lever arm configuration of the AirData module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pLeverArm The X, Y, Z airspeed sensor lever arm in meters from the pitot sensor to the IMU. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdAirDataSetLeverArm(SbgEComHandle *pHandle, const float *pLeverArm); + +/*! + * Retrieve the lever arm configuration of the AirData module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pLeverArm Returns the airspeed sensor X,Y,Z lever arm in meters from the pitot sensor to the IMU. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdAirDataGetLeverArm(SbgEComHandle *pHandle, float *pLeverArm); + +/*! + * Set the rejection configuration of the AirData module (this command doesn't need a reboot to be applied) + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pRejectConf The new rejection configuration to set. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdAirDataSetRejection(SbgEComHandle *pHandle, const SbgEComAirDataRejectionConf *pRejectConf); + +/*! + * Retrieve the current rejection configuration of the AirData module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pRejectConf Return the rejection configuration currently in use. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdAirDataGetRejection(SbgEComHandle *pHandle, SbgEComAirDataRejectionConf *pRejectConf); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_AIR_DATA_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdApi.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdApi.c new file mode 100644 index 0000000..ebb832a --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdApi.c @@ -0,0 +1,243 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdApi.h" +#include "sbgEComCmdCommon.h" + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +/*! + * Status code indicating success. + */ +#define SBG_ECOM_CMD_API_STATUS_CODE_OK (200) + +/*! + * Status code indicating an internal server error. + */ +#define SBG_ECOM_CMD_API_STATUS_CODE_INTERNAL_SERVER_ERROR (500) + +//----------------------------------------------------------------------// +//- Private methods -// +//----------------------------------------------------------------------// + +/*! + * Parse the payload of a REST API reply. + * + * \param[in] pReply REST API reply. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgEComCmdApiReplyParsePayload(SbgEComCmdApiReply *pReply) +{ + SbgErrorCode errorCode; + SbgStreamBuffer streamBuffer; + uint16_t statusCode; + + assert(pReply); + + sbgStreamBufferInitForRead(&streamBuffer, sbgEComProtocolPayloadGetBuffer(&pReply->payload), sbgEComProtocolPayloadGetSize(&pReply->payload)); + + statusCode = sbgStreamBufferReadUint16LE(&streamBuffer); + + errorCode = sbgStreamBufferGetLastError(&streamBuffer); + + if (errorCode == SBG_NO_ERROR) + { + const char *pContent; + size_t size; + + pContent = sbgStreamBufferGetCursor(&streamBuffer); + size = sbgStreamBufferGetSpace(&streamBuffer); + + if (size != 0) + { + if (pContent[size - 1] == '\0') + { + pReply->statusCode = statusCode; + pReply->pContent = pContent; + + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_INVALID_FRAME; + SBG_LOG_ERROR(errorCode, "invalid content format"); + } + } + else + { + errorCode = SBG_INVALID_FRAME; + SBG_LOG_ERROR(errorCode, "invalid content size"); + } + } + else + { + SBG_LOG_ERROR(errorCode, "unable to read status code"); + } + + return errorCode; +} + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +void sbgEComCmdApiReplyConstruct(SbgEComCmdApiReply *pReply) //TODO: minuscule ds un commit séparé +{ + assert(pReply); + + sbgEComProtocolPayloadConstruct(&pReply->payload); + + pReply->statusCode = SBG_ECOM_CMD_API_STATUS_CODE_INTERNAL_SERVER_ERROR; + pReply->pContent = NULL; +} + +void sbgEComCmdApiReplyDestroy(SbgEComCmdApiReply *pReply) //TODO: minuscule ds un commit séparé +{ + assert(pReply); + + sbgEComProtocolPayloadDestroy(&pReply->payload); +} + +bool sbgEComCmdApiReplySuccessful(const SbgEComCmdApiReply *pReply) +{ + assert(pReply); + + return pReply->statusCode == SBG_ECOM_CMD_API_STATUS_CODE_OK; +} + +SbgErrorCode sbgEComCmdApiGet(SbgEComHandle *pHandle, const char *pPath, const char *pQuery, SbgEComCmdApiReply *pReply) +{ + SbgErrorCode errorCode; + uint8_t *pSendBuffer; + SbgStreamBuffer streamBuffer; + size_t pathSize; + size_t querySize; + size_t size; + + assert(pPath); + + if (!pQuery) + { + pQuery = ""; + } + + pathSize = strlen(pPath) + 1; + querySize = strlen(pQuery) + 1; + size = pathSize + querySize; + + pSendBuffer = malloc(size); + + if (pSendBuffer) + { + sbgStreamBufferInitForWrite(&streamBuffer, pSendBuffer, size); + + sbgStreamBufferWriteBuffer(&streamBuffer, pPath, pathSize); + errorCode = sbgStreamBufferWriteBuffer(&streamBuffer, pQuery, querySize); + assert(errorCode == SBG_NO_ERROR); + + for (uint32_t i = 0; i < pHandle->numTrials; i++) + { + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_API_GET, sbgStreamBufferGetLinkedBuffer(&streamBuffer), sbgStreamBufferGetLength(&streamBuffer)); + + if (errorCode == SBG_NO_ERROR) + { + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_API_GET, &pReply->payload, pHandle->cmdDefaultTimeOut); + + if (errorCode == SBG_NO_ERROR) + { + errorCode = sbgEComCmdApiReplyParsePayload(pReply); + break; + } + } + else + { + break; + } + } + + free(pSendBuffer); + } + else + { + errorCode = SBG_MALLOC_FAILED; + SBG_LOG_ERROR(errorCode, "unable allocate buffer"); + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdApiPost(SbgEComHandle *pHandle, const char *pPath, const char *pQuery, const char *pBody, SbgEComCmdApiReply *pReply) +{ + SbgErrorCode errorCode; + uint8_t *pSendBuffer; + SbgStreamBuffer streamBuffer; + size_t pathSize; + size_t querySize; + size_t bodySize; + size_t size; + + assert(pPath); + + if (!pQuery) + { + pQuery = ""; + } + + if (!pBody) + { + pBody = ""; + } + + pathSize = strlen(pPath) + 1; + querySize = strlen(pQuery) + 1; + bodySize = strlen(pBody) + 1; + size = pathSize + querySize + bodySize; + + pSendBuffer = malloc(size); + + if (pSendBuffer) + { + sbgStreamBufferInitForWrite(&streamBuffer, pSendBuffer, size); + + sbgStreamBufferWriteBuffer(&streamBuffer, pPath, pathSize); + sbgStreamBufferWriteBuffer(&streamBuffer, pQuery, querySize); + errorCode = sbgStreamBufferWriteBuffer(&streamBuffer, pBody, bodySize); + assert(errorCode == SBG_NO_ERROR); + + for (uint32_t i = 0; i < pHandle->numTrials; i++) + { + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_API_POST, sbgStreamBufferGetLinkedBuffer(&streamBuffer), sbgStreamBufferGetLength(&streamBuffer)); + + if (errorCode == SBG_NO_ERROR) + { + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_API_POST, &pReply->payload, pHandle->cmdDefaultTimeOut); + + if (errorCode == SBG_NO_ERROR) + { + errorCode = sbgEComCmdApiReplyParsePayload(pReply); + break; + } + } + else + { + break; + } + } + + free(pSendBuffer); + } + else + { + errorCode = SBG_MALLOC_FAILED; + SBG_LOG_ERROR(errorCode, "unable allocate buffer"); + } + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdApi.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdApi.h new file mode 100644 index 0000000..ddc697d --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdApi.h @@ -0,0 +1,122 @@ +/*! + * \file sbgEComCmdApi.h + * \ingroup commands + * \author SBG Systems + * \date October 14, 2020 + * + * \brief REST API related commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_API_H +#define SBG_ECOM_CMD_API_H + +// sbgCommonLib headers +#include + +// Project headers +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Reply to REST API commands. + * + * The reply content is a null-terminated string, normally in JSON format. + * + * The content directly refers to data inside the payload. + */ +typedef struct _SbgEComCmdApiReply +{ + SbgEComProtocolPayload payload; /*!< Payload. */ + uint16_t statusCode; /*!< Status code. */ + const char *pContent; /*!< Content. */ +} SbgEComCmdApiReply; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * REST API reply constructor. + * + * \param[in] pReply REST API reply. + */ +void sbgEComCmdApiReplyConstruct(SbgEComCmdApiReply *pReply); + +/*! + * REST API reply destructor. + * + * \param[in] pReply REST API reply. + */ +void sbgEComCmdApiReplyDestroy(SbgEComCmdApiReply *pReply); + +/*! + * Check if a reply indicates successful command execution. + * + * \param[in] pReply REST API reply. + * \return True if the reply indicates successful command execution. + */ +bool sbgEComCmdApiReplySuccessful(const SbgEComCmdApiReply *pReply); + +/*! + * Send a GET command. + * + * The reply must be destroyed before the next attempt to receive data, either logs or command replies. + * + * \param[in] pHandle ECom handle. + * \param[in] pPath URI path component. + * \param[in] pQuery Query string, may be NULL. + * \param[out] pReply Reply. + * \return SBG_NO_ERROR if successful. + */ +SbgErrorCode sbgEComCmdApiGet(SbgEComHandle *pHandle, const char *pPath, const char *pQuery, SbgEComCmdApiReply *pReply); + +/*! + * Send a POST command. + * + * The reply must be destroyed before the next attempt to receive data, either logs or command replies. + * + * \param[in] pHandle ECom handle. + * \param[in] pPath URI path component. + * \param[in] pQuery Query string, may be NULL. + * \param[in] pBody Body, may be NULL. + * \param[out] pReply Reply. + * \return SBG_NO_ERROR if successful. + */ +SbgErrorCode sbgEComCmdApiPost(SbgEComHandle *pHandle, const char *pPath, const char *pQuery, const char *pBody, SbgEComCmdApiReply *pReply); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_API_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdCommon.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdCommon.c new file mode 100644 index 0000000..99d09c7 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdCommon.c @@ -0,0 +1,504 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" + +//----------------------------------------------------------------------// +//- Common command reception operations -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComReceiveAnyCmd(SbgEComHandle *pHandle, uint8_t *pMsgClass, uint8_t *pMsgId, void *pData, size_t *pSize, size_t maxSize, uint32_t timeOut) +{ + SbgErrorCode errorCode; + SbgEComProtocolPayload payload; + + assert(pHandle); + assert(pMsgClass); + assert(pMsgId); + + sbgEComProtocolPayloadConstruct(&payload); + + errorCode = sbgEComReceiveAnyCmd2(pHandle, pMsgClass, pMsgId, &payload, timeOut); + + if (errorCode == SBG_NO_ERROR) + { + size_t size; + + size = sbgEComProtocolPayloadGetSize(&payload); + + if (size <= maxSize) + { + if (pData) + { + const void *pBuffer; + + pBuffer = sbgEComProtocolPayloadGetBuffer(&payload); + + memcpy(pData, pBuffer, size); + } + + if (pSize) + { + *pSize = size; + } + } + else + { + errorCode = SBG_BUFFER_OVERFLOW; + } + } + + sbgEComProtocolPayloadDestroy(&payload); + + return errorCode; +} + +SbgErrorCode sbgEComReceiveAnyCmd2(SbgEComHandle *pHandle, uint8_t *pMsgClass, uint8_t *pMsgId, SbgEComProtocolPayload *pPayload, uint32_t timeOut) +{ + SbgErrorCode errorCode; + uint32_t start; + + assert(pHandle); + + if (timeOut > 0) + { + start = sbgGetTime(); + } + else + { + // + // Avoid compiler warning + // + start = 0; + } + + for (;;) + { + uint8_t receivedMsgClass; + uint8_t receivedMsgId; + uint32_t now; + + errorCode = sbgEComProtocolReceive2(&pHandle->protocolHandle, &receivedMsgClass, &receivedMsgId, pPayload); + + if (errorCode == SBG_NO_ERROR) + { + if (sbgEComMsgClassIsALog((SbgEComClass)receivedMsgClass)) + { + if (pHandle->pReceiveLogCallback) + { + SbgBinaryLogData logData; + + errorCode = sbgEComBinaryLogParse((SbgEComClass)receivedMsgClass, receivedMsgId, sbgEComProtocolPayloadGetBuffer(pPayload), sbgEComProtocolPayloadGetSize(pPayload), &logData); + + if (errorCode == SBG_NO_ERROR) + { + pHandle->pReceiveLogCallback(pHandle, (SbgEComClass)receivedMsgClass, receivedMsgId, &logData, pHandle->pUserArg); + + sbgEComBinaryLogCleanup(&logData, (SbgEComClass)receivedMsgClass, (SbgEComMsgId)receivedMsgId); + } + } + } + else + { + if (pMsgClass) + { + *pMsgClass = receivedMsgClass; + } + + if (pMsgId) + { + *pMsgId = receivedMsgId; + } + + break; + } + } + + if (timeOut > 0) + { + if (errorCode == SBG_NOT_READY) + { + sbgSleep(1); + } + + now = sbgGetTime(); + + if ((now - start) >= timeOut) + { + errorCode = SBG_TIME_OUT; + break; + } + } + else + { + errorCode = SBG_NOT_READY; + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComReceiveCmd(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msgId, void *pData, size_t *pSize, size_t maxSize, uint32_t timeOut) +{ + SbgErrorCode errorCode; + SbgEComProtocolPayload payload; + + sbgEComProtocolPayloadConstruct(&payload); + + errorCode = sbgEComReceiveCmd2(pHandle, msgClass, msgId, &payload, timeOut); + + if (errorCode == SBG_NO_ERROR) + { + size_t size; + + size = sbgEComProtocolPayloadGetSize(&payload); + + if (size <= maxSize) + { + if (pData) + { + const void *pBuffer; + + pBuffer = sbgEComProtocolPayloadGetBuffer(&payload); + + memcpy(pData, pBuffer, size); + } + + if (pSize) + { + *pSize = size; + } + } + else + { + errorCode = SBG_BUFFER_OVERFLOW; + } + } + + sbgEComProtocolPayloadDestroy(&payload); + + return errorCode; +} + +SbgErrorCode sbgEComReceiveCmd2(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msgId, SbgEComProtocolPayload *pPayload, uint32_t timeOut) +{ + SbgErrorCode errorCode; + uint32_t start; + + assert(pHandle); + + start = sbgGetTime(); + + for (;;) + { + uint8_t receivedMsgClass; + uint8_t receivedMsgId; + uint32_t now; + + errorCode = sbgEComReceiveAnyCmd2(pHandle, &receivedMsgClass, &receivedMsgId, pPayload, 0); + + if (errorCode == SBG_NO_ERROR) + { + if ((receivedMsgClass == msgClass) && (receivedMsgId == msgId)) + { + break; + } + else if ((receivedMsgClass == SBG_ECOM_CLASS_LOG_CMD_0) && (receivedMsgId == SBG_ECOM_CMD_ACK)) + { + SbgStreamBuffer streamBuffer; + uint8_t ackMsgClass; + uint8_t ackMsgId; + SbgErrorCode ackErrorCode; + + sbgStreamBufferInitForRead(&streamBuffer, sbgEComProtocolPayloadGetBuffer(pPayload), sbgEComProtocolPayloadGetSize(pPayload)); + + ackMsgId = sbgStreamBufferReadUint8(&streamBuffer); + ackMsgClass = sbgStreamBufferReadUint8(&streamBuffer); + ackErrorCode = (SbgErrorCode)sbgStreamBufferReadUint16LE(&streamBuffer); + + errorCode = sbgStreamBufferGetLastError(&streamBuffer); + + if ((errorCode == SBG_NO_ERROR) && (ackMsgClass == msgClass) && (ackMsgId == msgId)) + { + // + // If a successful ACK is expected, the caller should instead explicitely wait for + // it. As a result, consider receiving a "successful ACK" instead of an actual message + // with the requested class/ID an error. + // + if (ackErrorCode != SBG_NO_ERROR) + { + errorCode = ackErrorCode; + } + else + { + errorCode = SBG_ERROR; + } + + break; + } + } + } + else if (errorCode == SBG_NOT_READY) + { + sbgSleep(1); + } + else + { + break; + } + + now = sbgGetTime(); + + if ((now - start) >= timeOut) + { + errorCode = SBG_TIME_OUT; + break; + } + } + + return errorCode; +} + +//----------------------------------------------------------------------// +//- ACK related commands operations -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComWaitForAck(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, uint32_t timeOut) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint8_t ackClass; + uint8_t ackMsg; + + assert(pHandle); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Try to receive the ACK + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ACK, &receivedPayload, timeOut); + + // + // Test if an ACK frame has been received + // + if (errorCode == SBG_NO_ERROR) + { + // + // Validate the received ACK frame + // + if (sbgEComProtocolPayloadGetSize(&receivedPayload) == 2*sizeof(uint16_t)) + { + SbgStreamBuffer inputStream; + + // + // Initialize a stream buffer to parse the received payload + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // The ACK frame contains the ack message ID and class, and a uint16_t for the return error code + // We make sure that the ACK is for the correct command + // + ackMsg = sbgStreamBufferReadUint8LE(&inputStream); + ackClass = sbgStreamBufferReadUint8LE(&inputStream); + + if ((ackMsg == msg) && (ackClass == msgClass)) + { + // + // Parse the error code and return it + // + errorCode = (SbgErrorCode)sbgStreamBufferReadUint16LE(&inputStream); + } + else + { + // + // We have received an ACK but not for this frame! + // + errorCode = SBG_INVALID_FRAME; + } + } + else + { + // + // The ACK is invalid + // + errorCode = SBG_INVALID_FRAME; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComSendAck(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, SbgErrorCode cmdError) +{ + SbgStreamBuffer outputStream; + uint8_t outputBuffer[2*sizeof(uint8_t)+sizeof(uint16_t)]; + + assert(pHandle); + + // + // Initialize a stream buffer to write the command payload + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Write the message ID and class and then the error code + // + sbgStreamBufferWriteUint8LE(&outputStream, msg); + sbgStreamBufferWriteUint8LE(&outputStream, msgClass); + sbgStreamBufferWriteUint16LE(&outputStream, (uint16_t)cmdError); + + // + // Send the ACK command + // + return sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ACK, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); +} + +//----------------------------------------------------------------------// +//- Generic command definitions -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdGenericSetModelId(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, uint32_t modelId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[sizeof(uint32_t)]; + SbgStreamBuffer outputStream; + + assert(pHandle); + + // + // Init stream buffer for output and Build payload + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + sbgStreamBufferWriteUint32LE(&outputStream, modelId); + + // + // Make sure the payload has been build correctly + // + errorCode = sbgStreamBufferGetLastError(&outputStream); + + if (errorCode == SBG_NO_ERROR) + { + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, msgClass, msg, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, msgClass, msg, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdGenericGetModelId(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, uint32_t *pModelId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pModelId); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, msgClass, msg, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, msgClass, msg, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a the specified command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + *pModelId = sbgStreamBufferReadUint32LE(&inputStream); + + // + // The command has been executed successfully so return + // We return the stream buffer error code to catch any overflow error on the payload + // + errorCode = sbgStreamBufferGetLastError(&inputStream); + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdCommon.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdCommon.h new file mode 100644 index 0000000..422265b --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdCommon.h @@ -0,0 +1,229 @@ +/*! + * \file sbgEComCmdCommon.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief Definitions and methods common to all commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_COMMON_H +#define SBG_ECOM_CMD_COMMON_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Defintions -// +//----------------------------------------------------------------------// + +#define SBG_ECOM_DEFAULT_CMD_TIME_OUT (500) /*!< Default time out in ms for commands reception. */ + +/*! + * List of all rejection modes for aiding inputs. + */ +typedef enum _SbgEComRejectionMode +{ + SBG_ECOM_NEVER_ACCEPT_MODE = 0, /*!< Measurement is not taken into account. */ + SBG_ECOM_AUTOMATIC_MODE = 1, /*!< Measurement is accepted and rejected automatically depending on consistency checks */ + SBG_ECOM_ALWAYS_ACCEPT_MODE = 2 /*!< Measurement is always accepted. Should be used with caution */ +} SbgEComRejectionMode; + +/*! + * List of all axis directions for modules/sensor alignment. + */ +typedef enum _SbgEComAxisDirection +{ + SBG_ECOM_ALIGNMENT_FORWARD = 0, /*!< IMU/module Axis is turned in vehicle's forward direction. */ + SBG_ECOM_ALIGNMENT_BACKWARD = 1, /*!< IMU/module Axis is turned in vehicle's backward direction. */ + SBG_ECOM_ALIGNMENT_LEFT = 2, /*!< IMU/module Axis is turned in vehicle's left direction. */ + SBG_ECOM_ALIGNMENT_RIGHT = 3, /*!< IMU/module Axis is turned in vehicle's right direction. */ + SBG_ECOM_ALIGNMENT_UP = 4, /*!< IMU/module Axis is turned in vehicle's up direction. */ + SBG_ECOM_ALIGNMENT_DOWN = 5 /*!< IMU/module Axis is turned in vehicle's down direction. */ +} SbgEComAxisDirection; + +//----------------------------------------------------------------------// +//- Common command reception operations -// +//----------------------------------------------------------------------// + +/*! + * Receive a command message. + * + * All binary logs received are handled trough the standard callback system. + * + * \param[in] pHandle SbgECom handle. + * \param[out] pMsgClass Message class. + * \param[out] pMsgId Message ID. + * \param[out] pData Data buffer, may be NULL. + * \param[out] pSize Number of bytes received, in bytes, may be NULL. + * \param[in] maxSize Data buffer size, in bytes. + * \param[in] timeOut Time-out, in ms. + * \return SBG_NO_ERROR if successful, + * SBG_NOT_READY if no command message has been received, + * SBG_BUFFER_OVERFLOW if the payload of the received frame couldn't fit into the buffer, + * SBG_TIME_OUT if no command message was received within the specified time out. + */ +SbgErrorCode sbgEComReceiveAnyCmd(SbgEComHandle *pHandle, uint8_t *pMsgClass, uint8_t *pMsgId, void *pData, size_t *pSize, size_t maxSize, uint32_t timeOut); + +/*! + * Receive a command message. + * + * All binary logs received are handled trough the standard callback system. + * + * This function is equivalent to sbgEComReceiveAnyCmd() with two exceptions : + * - the use of a payload object allows handling payloads not limited by the size of a user-provided buffer + * - the payload object allows direct access to the protocol work buffer to avoid an extra copy per call + * + * Any allocated resource associated with the given payload is released when calling this function. + * + * Because the payload buffer may directly refer to the protocol work buffer on return, it is only valid until + * the next attempt to receive a frame, with any of the receive functions. + * + * \param[in] pHandle SbgECom handle. + * \param[out] pMsgClass Message class. + * \param[out] pMsgId Message ID. + * \param[out] pPayload Payload. + * \param[in] timeOut Time-out, in ms. + * \return SBG_NO_ERROR if successful, + * SBG_NOT_READY if no command message has been received, + * SBG_TIME_OUT if no command message was received within the specified time out. + */ +SbgErrorCode sbgEComReceiveAnyCmd2(SbgEComHandle *pHandle, uint8_t *pMsgClass, uint8_t *pMsgId, SbgEComProtocolPayload *pPayload, uint32_t timeOut); + +/*! + * Receive a specific command message. + * + * This function also processes ACK messages for the given class and ID. + * + * All binary logs received during this time are handled trough the standard callback system. + * + * \param[in] pHandle SbgECom handle. + * \param[in] msgClass Message class. + * \param[in] msgId Message ID. + * \param[out] pData Data buffer. + * \param[out] pSize Number of bytes received, in bytes. + * \param[in] maxSize Data buffer size, in bytes. + * \param[in] timeOut Time-out, in ms. + * \return SBG_NO_ERROR if successful, + * SBG_NOT_READY if no command message has been received, + * SBG_BUFFER_OVERFLOW if the payload of the received frame couldn't fit into the buffer, + * SBG_TIME_OUT if no command message was received within the specified time out, + * any error code reported by an ACK message for the given class and ID. + */ +SbgErrorCode sbgEComReceiveCmd(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msgId, void *pData, size_t *pSize, size_t maxSize, uint32_t timeOut); + +/*! + * Receive a specific command message. + * + * This function also processes ACK messages for the given class and ID. + * + * All binary logs received during this time are handled trough the standard callback system. + * + * This function is equivalent to sbgEComReceiveCmd() with two exceptions : + * - the use of a payload object allows handling payloads not limited by the size of a user-provided buffer + * - the payload object allows direct access to the protocol work buffer to avoid an extra copy per call + * + * Any allocated resource associated with the given payload is released when calling this function. + * + * Because the payload buffer may directly refer to the protocol work buffer on return, it is only valid until + * the next attempt to receive a frame, with any of the receive functions. + * + * \param[in] pHandle SbgECom handle. + * \param[in] msgClass Message class. + * \param[in] msgId Message ID. + * \param[out] pPayload Payload. + * \param[in] timeOut Time-out, in ms. + * \return SBG_NO_ERROR if successful, + * SBG_NOT_READY if no command message has been received, + * SBG_TIME_OUT if no command message was received within the specified time out, + * any error code reported by an ACK message for the given class and ID. + */ +SbgErrorCode sbgEComReceiveCmd2(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msgId, SbgEComProtocolPayload *pPayload, uint32_t timeOut); + +//----------------------------------------------------------------------// +//- ACK related commands operations -// +//----------------------------------------------------------------------// + +/*! + * Wait for an ACK for a specified amount of time. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] msgClass The message class that we want to check + * \param[in] msg The message ID that we want to check + * \param[in] timeOut Time out in ms during which we can receive the ACK. + * \return SBG_NO_ERROR if the ACK has been received. + */ +SbgErrorCode sbgEComWaitForAck(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, uint32_t timeOut); + +/*! + * Send an ACK for a specific command with an associated error code. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] msgClass The message class that we want to send + * \param[in] msg The message ID that we want to send. + * \param[in] cmdError The associated error code. + * \return SBG_NO_ERROR if the ACK has been sent. + */ +SbgErrorCode sbgEComSendAck(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, SbgErrorCode cmdError); + +//----------------------------------------------------------------------// +//- Generic command definitions -// +//----------------------------------------------------------------------// + +/*! + * Generic function to set an error model ID + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] msgClass Original message class + * \param[in] msg Original message ID + * \param[in] modelId Model ID to set + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdGenericSetModelId(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, uint32_t modelId); + +/*! + * Generic function to get an error model ID + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] msgClass Original message class + * \param[in] msg Original message ID + * \param[out] pModelId Returns the currently used model ID. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdGenericGetModelId(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, uint32_t *pModelId); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_COMMON_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdDvl.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdDvl.c new file mode 100644 index 0000000..2972dda --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdDvl.c @@ -0,0 +1,334 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdDvl.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdDvlSetModelId(SbgEComHandle *pHandle, SbgEComDvlModelsIds modelId) +{ + assert(pHandle); + + return sbgEComCmdGenericSetModelId(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_DVL_MODEL_ID, modelId); +} + +SbgErrorCode sbgEComCmdDvlGetModelId(SbgEComHandle *pHandle, SbgEComDvlModelsIds *pModelId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t modelIdAsUint; + + assert(pHandle); + assert(pModelId); + + errorCode = sbgEComCmdGenericGetModelId(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_DVL_MODEL_ID, &modelIdAsUint); + + if (errorCode == SBG_NO_ERROR) + { + *pModelId = (SbgEComDvlModelsIds)modelIdAsUint; + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdDvlInstallationSet(SbgEComHandle *pHandle, const SbgEComDvlInstallation *pDvlInstallation) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pDvlInstallation); + + // + // Create the command payload + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteFloatLE(&outputStream, pDvlInstallation->leverArm[0]); + sbgStreamBufferWriteFloatLE(&outputStream, pDvlInstallation->leverArm[1]); + sbgStreamBufferWriteFloatLE(&outputStream, pDvlInstallation->leverArm[2]); + + sbgStreamBufferWriteFloatLE(&outputStream, pDvlInstallation->alignment[0]); + sbgStreamBufferWriteFloatLE(&outputStream, pDvlInstallation->alignment[1]); + sbgStreamBufferWriteFloatLE(&outputStream, pDvlInstallation->alignment[2]); + + sbgStreamBufferWriteBooleanLE(&outputStream, pDvlInstallation->preciseInstallation); + + // + // Make sure the payload has been build correctly + // + errorCode = sbgStreamBufferGetLastError(&outputStream); + + if (errorCode == SBG_NO_ERROR) + { + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_DVL_INSTALLATION, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_DVL_INSTALLATION, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdDvlInstallationGet(SbgEComHandle *pHandle, SbgEComDvlInstallation *pDvlInstallation) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pDvlInstallation); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_DVL_INSTALLATION, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_DVL_INSTALLATION, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_GNSS_1_LEVER_ARM_ALIGNMENT command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to parse the payload + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + pDvlInstallation->leverArm[0] = sbgStreamBufferReadFloatLE(&inputStream); + pDvlInstallation->leverArm[1] = sbgStreamBufferReadFloatLE(&inputStream); + pDvlInstallation->leverArm[2] = sbgStreamBufferReadFloatLE(&inputStream); + + pDvlInstallation->alignment[0] = sbgStreamBufferReadFloatLE(&inputStream); + pDvlInstallation->alignment[1] = sbgStreamBufferReadFloatLE(&inputStream); + pDvlInstallation->alignment[2] = sbgStreamBufferReadFloatLE(&inputStream); + + pDvlInstallation->preciseInstallation = sbgStreamBufferReadBooleanLE(&inputStream); + + // + // The command has been executed successfully so return if an error has occurred during payload parsing + // + errorCode = sbgStreamBufferGetLastError(&inputStream); + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdDvlSetRejection(SbgEComHandle *pHandle, const SbgEComDvlRejectionConf *pRejectConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[2*sizeof(uint8_t)]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pRejectConf); + + // + // Create the command payload + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(&outputStream, pRejectConf->bottomLayer); + sbgStreamBufferWriteUint8LE(&outputStream, pRejectConf->waterLayer); + + // + // Make sure the payload has been build correctly + // + errorCode = sbgStreamBufferGetLastError(&outputStream); + + if (errorCode == SBG_NO_ERROR) + { + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_DVL_REJECT_MODES, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_DVL_REJECT_MODES, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdDvlGetRejection(SbgEComHandle *pHandle, SbgEComDvlRejectionConf *pRejectConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pRejectConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_DVL_REJECT_MODES, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_DVL_REJECT_MODES, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_GNSS_1_REJECT_MODES command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to parse payload + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Parse the payload + // + pRejectConf->bottomLayer = (SbgEComRejectionMode)sbgStreamBufferReadUint8LE(&inputStream); + pRejectConf->waterLayer = (SbgEComRejectionMode)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return if an error has occurred during payload parsing + // + errorCode = sbgStreamBufferGetLastError(&inputStream); + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdDvl.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdDvl.h new file mode 100644 index 0000000..1283404 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdDvl.h @@ -0,0 +1,143 @@ +/*! + * \file sbgEComCmdDvl.h + * \ingroup commands + * \author SBG Systems + * \date 13 December 2018 + * + * \brief DVL (Doppler Velocity Logger) aiding module configuration commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_DVL_H +#define SBG_ECOM_CMD_DVL_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Public definitions -// +//----------------------------------------------------------------------// + +/*! + * This enum defines the different DVL model IDs available in standard + */ +typedef enum _SbgEComDvlModelsIds +{ + SBG_ECOM_DVL_MODEL_GENERIC_PD6 = 202, /*!< Generic DVL using PD6 protocol format. */ + SBG_ECOM_DVL_MODEL_WAYFINDER = 203 /*!< Teledyne Wayfinder DVL using proprietary protocol. */ +} SbgEComDvlModelsIds; + +/*! + * DVL mechanical installation parameters such as lever arm and alignment + */ +typedef struct _SbgEComDvlInstallation +{ + float leverArm[3]; /*!< X, Y, Z DVL lever arm in meters expressed from the DVL to the IMU. */ + float alignment[3]; /*!< Roll, pitch, yaw DVL alignment expressed in radians. */ + bool preciseInstallation; /*!< Set to true if both the DVL lever arm and DVL alignment are precise and don't require in-run estimation. */ +} SbgEComDvlInstallation; + +/*! + * Holds all necessary information for DVL module data rejection. + */ +typedef struct _SbgEComDvlRejectionConf +{ + SbgEComRejectionMode bottomLayer; /*!< Rejection mode for the bottom tracking (ie when the velocity measurement is in respect to the seabed). */ + SbgEComRejectionMode waterLayer; /*!< Rejection mode for the water tracking (ie when the velocity measurement is relative to a water layer). */ +} SbgEComDvlRejectionConf; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Set the DVL model to use that both defines the protocol as well as the associated error model. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] modelId DVL model ID to set + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdDvlSetModelId(SbgEComHandle *pHandle, SbgEComDvlModelsIds modelId); + +/*! + * Retrieve the DVL model id currently in use by the device. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pModelId Returns the DVL model ID currently in use by the device. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdDvlGetModelId(SbgEComHandle *pHandle, SbgEComDvlModelsIds *pModelId); + +/*! + * Set the lever arm and alignment configuration of the DVL module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pDvlInstallation The DVL lever arm and alignment configuration to apply. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdDvlInstallationSet(SbgEComHandle *pHandle, const SbgEComDvlInstallation *pDvlInstallation); + +/*! + * Retrieve the lever arm and alignment configuration of the DVL module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pDvlInstallation Returns the DVL lever arm and alignment configuration currently in use. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdDvlInstallationGet(SbgEComHandle *pHandle, SbgEComDvlInstallation *pDvlInstallation); + +/*! + * Set the rejection configuration of the DVL module (this command doesn't need a reboot to be applied) + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pRejectConf The new DVL rejection configuration to set. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdDvlSetRejection(SbgEComHandle *pHandle, const SbgEComDvlRejectionConf *pRejectConf); + +/*! + * Retrieve the current rejection configuration of the DVL module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pRejectConf Return the DVL rejection configuration currently in use. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdDvlGetRejection(SbgEComHandle *pHandle, SbgEComDvlRejectionConf *pRejectConf); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_DVL_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEthernet.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEthernet.c new file mode 100644 index 0000000..5fd9f40 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEthernet.c @@ -0,0 +1,276 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdEthernet.h" + +//----------------------------------------------------------------------// +//- Private methods -// +//----------------------------------------------------------------------// + +/*! + * Write in the output stream buffer, the provided Ethernet configuration. + * + * \param[out] pOutputStream Pointer on the output stream buffer to write to. + * \param[in] pEthernetConf Structure used to hold the parameters to write to the payload buffer. + * \return SBG_NO_ERROR if the structure has been written correctly. + */ +static SbgErrorCode sbgEComEthernetConfWrite(SbgStreamBuffer *pOutputStream, const SbgEComEthernetConf *pEthernetConf) +{ + assert(pOutputStream); + assert(pEthernetConf); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(pOutputStream, (uint8_t)pEthernetConf->mode); + sbgStreamBufferWriteUint32LE(pOutputStream, pEthernetConf->ipAddress); + sbgStreamBufferWriteUint32LE(pOutputStream, pEthernetConf->netmask); + sbgStreamBufferWriteUint32LE(pOutputStream, pEthernetConf->gateway); + sbgStreamBufferWriteUint32LE(pOutputStream, pEthernetConf->dns1); + sbgStreamBufferWriteUint32LE(pOutputStream, pEthernetConf->dns2); + + // + // Return if an error has occurred during the parse + // + return sbgStreamBufferGetLastError(pOutputStream); +} + +/*! + * Parse the input stream buffer to extract all parameters and fill the corresponding structure. + * + * \param[in] pInputStream Pointer on the input stream buffer to read from. + * \param[out] pEthernetConf Structure used to store the parsed parameters. + * \return SBG_NO_ERROR if the structure has been parsed correctly. + */ +static SbgErrorCode sbgEComEthernetConfParse(SbgStreamBuffer *pInputStream, SbgEComEthernetConf *pEthernetConf) +{ + assert(pInputStream); + assert(pEthernetConf); + + // + // Read all parameters from the payload + // + pEthernetConf->mode = (SbgEComEthernetMode)sbgStreamBufferReadUint8LE(pInputStream); + pEthernetConf->ipAddress = (sbgIpAddress)sbgStreamBufferReadUint32LE(pInputStream); + pEthernetConf->netmask = (sbgIpAddress)sbgStreamBufferReadUint32LE(pInputStream); + pEthernetConf->gateway = (sbgIpAddress)sbgStreamBufferReadUint32LE(pInputStream); + pEthernetConf->dns1 = (sbgIpAddress)sbgStreamBufferReadUint32LE(pInputStream); + pEthernetConf->dns2 = (sbgIpAddress)sbgStreamBufferReadUint32LE(pInputStream); + + // + // Return if an error has occurred during the parse + // + return sbgStreamBufferGetLastError(pInputStream); +} + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComEthernetGetConf(SbgEComHandle *pHandle, SbgEComEthernetConf *pEthernetConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pEthernetConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command with no payload to retreive the network configuration + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ETHERNET_CONF, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ETHERNET_CONF, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received correctly the answer + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read all parameters from the payload and return any error during the parse + // + errorCode = sbgEComEthernetConfParse(&inputStream, pEthernetConf); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComEthernetSetConf(SbgEComHandle *pHandle, const SbgEComEthernetConf *pEthernetConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[SBG_ECOM_MAX_BUFFER_SIZE]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pEthernetConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + errorCode = sbgEComEthernetConfWrite(&outputStream, pEthernetConf); + + // + // Send the payload if no error has occurred + // + if (errorCode == SBG_NO_ERROR) + { + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ETHERNET_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + } + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ETHERNET_CONF, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComEthernetInfo(SbgEComHandle *pHandle, SbgEComEthernetConf *pEthernetConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pEthernetConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command with no payload to retreive the network configuration + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ETHERNET_INFO, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ETHERNET_INFO, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received correctly the answer + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read all parameters from the payload and return any error during the parse + // + errorCode = sbgEComEthernetConfParse(&inputStream, pEthernetConf); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEthernet.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEthernet.h new file mode 100644 index 0000000..b0b98cc --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEthernet.h @@ -0,0 +1,113 @@ +/*! + * \file sbgEComCmdEthernet.h + * \ingroup commands + * \author SBG Systems + * \date 14 November 2016 + * + * \brief Ethernet configuration related commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_ETHERNET_H +#define SBG_ECOM_CMD_ETHERNET_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Ethernet interface configuration -// +//----------------------------------------------------------------------// + +/*! + * Enum that defines the different type of IP acquisition method. + */ +typedef enum _SbgEComEthernetMode +{ + SBG_ECOM_ETHERNET_DHCP = 0, /*!< The TCP/IP configuration should be acquired from a DHCP server. */ + SBG_ECOM_ETHERNET_STATIC = 1 /*!< The TCP/IP configuration is manually defined. */ +} SbgEComEthernetMode; + +/*! + * Structure that contains all Ethernet configuration or settings. + */ +typedef struct _SbgEComEthernetConf +{ + SbgEComEthernetMode mode; /*!< Define how the device will acquiere its IP address, either DHCP or Static. */ + sbgIpAddress ipAddress; /*!< For static mode, defines the device IP address. */ + sbgIpAddress netmask; /*!< For static mode, defines the device net mask. */ + sbgIpAddress gateway; /*!< For static mode, defines the gateway to use. */ + sbgIpAddress dns1; /*!< For static mode, defines the primary DNS to use. */ + sbgIpAddress dns2; /*!< For static mode, defines the secondary DNS to use. */ +} SbgEComEthernetConf; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Get the configuration for the Ethernet interface. + * + * Warning: this method only returns the Ethernet configuration and NOT the ip address currently used by the device. + * You should rather use sbgEComEthernetInfo to retreive the current assigned IP. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pEthernetConf Poiner to a SbgEComEthernetConf struct that holds the read configuration from the device. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComEthernetGetConf(SbgEComHandle *pHandle, SbgEComEthernetConf *pEthernetConf); + +/*! + * Set the configuration for the Ethernet interface. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pEthernetConf Poiner to a SbgEComEthernetConf struct that holds the new configuration to apply. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComEthernetSetConf(SbgEComHandle *pHandle, const SbgEComEthernetConf *pEthernetConf); + +/*! + * Get the current assigned and used IP address as well as network inforamtion. + * + * In opposition to sbgEComEthernetGetConf, this method will not return the Ethernet configuration. + * It will rather return the IP address currently used by the device. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pEthernetConf Poiner to a SbgEComEthernetConf struct that holds the read IP settings from the device. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComEthernetInfo(SbgEComHandle *pHandle, SbgEComEthernetConf *pEthernetConf); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_ETHERNET_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEvent.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEvent.c new file mode 100644 index 0000000..0766cdb --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEvent.c @@ -0,0 +1,294 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdEvent.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdSyncInGetConf(SbgEComHandle *pHandle, SbgEComSyncInId syncInId, SbgEComSyncInConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + uint8_t syncInIdParam = syncInId; + + // + // Send the command with syncInId as a 1-byte payload + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SYNC_IN_CONF, &syncInIdParam, sizeof(syncInIdParam)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SYNC_IN_CONF, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_SYNC_IN_CONF command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // First is returned the id of the sync, then the sensitivity and the delay at last. + // + syncInId = (SbgEComSyncInId)sbgStreamBufferReadUint8LE(&inputStream); + pConf->sensitivity = (SbgEComSyncInSensitivity)sbgStreamBufferReadUint8LE(&inputStream); + pConf->delay = sbgStreamBufferReadInt32LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdSyncInSetConf(SbgEComHandle *pHandle, SbgEComSyncInId syncInId, const SbgEComSyncInConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[SBG_ECOM_MAX_BUFFER_SIZE]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)syncInId); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->sensitivity); + sbgStreamBufferWriteInt32LE(&outputStream, pConf->delay); + + // + // Send the message over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SYNC_IN_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SYNC_IN_CONF, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdSyncOutGetConf(SbgEComHandle *pHandle, SbgEComSyncOutId syncOutId, SbgEComSyncOutConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + uint8_t syncOutIdParam = syncOutId; + + // + // Send the command with syncOutId as a 1-byte payload + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SYNC_OUT_CONF, &syncOutIdParam, sizeof(syncOutIdParam)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SYNC_OUT_CONF, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_SYNC_OUT_CONF command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // First is returned the id of the sync, then a reserved field, the output function, polarity and the duration at last. + // + syncOutId = (SbgEComSyncOutId)sbgStreamBufferReadUint8LE(&inputStream); + sbgStreamBufferReadUint8LE(&inputStream); + pConf->outputFunction = (SbgEComSyncOutFunction)sbgStreamBufferReadUint16LE(&inputStream); + pConf->polarity = (SbgEComSyncOutPolarity)sbgStreamBufferReadUint8LE(&inputStream); + pConf->duration = sbgStreamBufferReadUint32LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdSyncOutSetConf(SbgEComHandle *pHandle, SbgEComSyncOutId syncOutId, const SbgEComSyncOutConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[SBG_ECOM_MAX_BUFFER_SIZE]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)syncOutId); + sbgStreamBufferWriteUint8LE(&outputStream, 0); + sbgStreamBufferWriteUint16LE(&outputStream, (uint16_t)pConf->outputFunction); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->polarity); + sbgStreamBufferWriteUint32LE(&outputStream, pConf->duration); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SYNC_OUT_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SYNC_OUT_CONF, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEvent.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEvent.h new file mode 100644 index 0000000..240ff47 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdEvent.h @@ -0,0 +1,188 @@ +/*! + * \file sbgEComCmdEvent.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief Input/output event markers configuration commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_EVENT_H +#define SBG_ECOM_CMD_EVENT_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Event definitions -// +//----------------------------------------------------------------------// + +/*! + * List of sync in signals available. + */ +typedef enum _SbgEComSyncInId +{ + SBG_ECOM_SYNC_IN_A = 0, /*!< Sync IN A */ + SBG_ECOM_SYNC_IN_B = 1, /*!< Sync IN B */ + SBG_ECOM_SYNC_IN_C = 2, /*!< Sync IN C */ + SBG_ECOM_SYNC_IN_D = 3 /*!< Sync IN D */ +} SbgEComSyncInId; + +/*! + * List of available sensitivities for sync in signals. + */ +typedef enum _SbgEComSyncInSensitivity +{ + SBG_ECOM_SYNC_IN_DISABLED = 0, /*!< This trigger is turned OFF. */ + SBG_ECOM_SYNC_IN_FALLING_EDGE = 1, /*!< The trigger will be activated by a falling edge. */ + SBG_ECOM_SYNC_IN_RISING_EDGE = 2, /*!< The trigger will be activated by a rising edge. */ + SBG_ECOM_SYNC_IN_BOTH_EDGES = 3 /*!< The trigger is activated by a level change (rising or falling edge). */ +} SbgEComSyncInSensitivity; + +/*! + * List of sync out signals available. + */ +typedef enum _SbgEComSyncOutId +{ + SBG_ECOM_SYNC_OUT_A = 0, /*!< Synchronization output A */ + SBG_ECOM_SYNC_OUT_B = 1 /*!< Synchronization output B */ +} SbgEComSyncOutId; + +/*! + * Logic and synchronization output types + */ +typedef enum _SbgEComSyncOutFunction +{ + SBG_ECOM_SYNC_OUT_MODE_DISABLED = 0, /*!< Output is disabled. */ + SBG_ECOM_SYNC_OUT_MODE_MAIN_LOOP = 1, /*!< Output is generated at 200Hz. */ + SBG_ECOM_SYNC_OUT_MODE_DIV_2 = 2, /*!< Output is generated at 100Hz. */ + SBG_ECOM_SYNC_OUT_MODE_DIV_4 = 4, /*!< Output is generated at 50Hz. */ + SBG_ECOM_SYNC_OUT_MODE_DIV_8 = 8, /*!< Output is generated at 25Hz. */ + SBG_ECOM_SYNC_OUT_MODE_DIV_10 = 10, /*!< Output is generated at 20Hz. */ + SBG_ECOM_SYNC_OUT_MODE_DIV_20 = 20, /*!< Output is generated at 10Hz. */ + SBG_ECOM_SYNC_OUT_MODE_DIV_40 = 40, /*!< Output is generated at 5Hz. */ + SBG_ECOM_SYNC_OUT_MODE_DIV_200 = 200, /*!< Output is generated at 1Hz. */ + SBG_ECOM_SYNC_OUT_MODE_PPS = 10000, /*!< Pulse Per Second. Same mode as above. */ + SBG_ECOM_SYNC_OUT_MODE_EVENT_IN_A = 10003, /*!< Output is generated on a Sync In A event. */ + SBG_ECOM_SYNC_OUT_MODE_EVENT_IN_B = 10004, /*!< Output is generated on a Sync In B event. */ + SBG_ECOM_SYNC_OUT_MODE_EVENT_IN_C = 10005, /*!< Output is generated on a Sync In C event. */ + SBG_ECOM_SYNC_OUT_MODE_EVENT_IN_D = 10006, /*!< Output is generated on a Sync In D event. */ + + SBG_ECOM_SYNC_OUT_MODE_DIRECT_PPS = 10100, /*!< The internal GNSS PPS signal is directly routed to the Sync Out. + This mode is only valid for ELLIPSE-N with hardware revisions above 1.2.1.0. + Polarity and duration parameters are ignored with this specific mode. */ + +} SbgEComSyncOutFunction; + +/*! + * Logic output polarity + */ +typedef enum _SbgEComSyncOutPolarity +{ + SBG_ECOM_SYNC_OUT_FALLING_EDGE = 0, /*!< The output pin will generate a falling edge*/ + SBG_ECOM_SYNC_OUT_RISING_EDGE = 1, /*!< The output pin will generate a rising edge */ + SBG_ECOM_SYNC_OUT_TOGGLE = 2, /*!< The pulse is a level change */ +} SbgEComSyncOutPolarity; + +//----------------------------------------------------------------------// +//- Event configurations -// +//----------------------------------------------------------------------// + +/*! + * Helper structure for sync in configuration. + */ +typedef struct _SbgEComSyncInConf +{ + SbgEComSyncInSensitivity sensitivity; /*!< Sensitivity of the sync in. */ + int32_t delay; /*!< Delay to take into account for the sync in. (in us)*/ +} SbgEComSyncInConf; + +/*! + * Helper structure for sync out configuration. + */ +typedef struct _SbgEComSyncOutConf +{ + SbgEComSyncOutFunction outputFunction; /*!< Output function of the sync out pin */ + SbgEComSyncOutPolarity polarity; /*!< Polarity of the sync out. */ + uint32_t duration; /*!< Pulse width for the sync out (in ns). */ +} SbgEComSyncOutConf; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Retrieve the configuration of a Sync In. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] syncInId The id of the sync whose configuration is to be retrieved. + * \param[out] pConf Pointer to a SbgEComSyncInConf to contain the current configuration of the sync in. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSyncInGetConf(SbgEComHandle *pHandle, SbgEComSyncInId syncInId, SbgEComSyncInConf *pConf); + +/*! + * Set the configuration of a Sync In. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] syncInId The id of the sync whose configuration is to be set. + * \param[in] pConf Pointer to a SbgEComSyncInConf that contains the new configuration for the sync in. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSyncInSetConf(SbgEComHandle *pHandle, SbgEComSyncInId syncInId, const SbgEComSyncInConf *pConf); + +/*! + * Retrieve the configuration of a Sync Out. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] syncOutId The id of the sync whose configuration is to be retrieved. + * \param[out] pConf Pointer to a SbgEComSyncOutConf to contain the current configuration of the sync out. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSyncOutGetConf(SbgEComHandle *pHandle, SbgEComSyncOutId syncOutId, SbgEComSyncOutConf *pConf); + +/*! + * Set the configuration of a Sync Out. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] syncOutId The id of the sync whose configuration is to be set. + * \param[in] pConf Pointer to a SbgEComSyncOutConf that contains the new configuration for the sync Out. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSyncOutSetConf(SbgEComHandle *pHandle, SbgEComSyncOutId syncOutId, const SbgEComSyncOutConf *pConf); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_EVENT_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdFeatures.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdFeatures.c new file mode 100644 index 0000000..efec8d3 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdFeatures.c @@ -0,0 +1,100 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdFeatures.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdGetFeatures(SbgEComHandle *pHandle, SbgEComFeatures *pFeatures) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pFeatures); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_FEATURES, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_FEATURES, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_GPS_FEATURES command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + pFeatures->sensorFeaturesMask = sbgStreamBufferReadUint32LE(&inputStream); + pFeatures->gnssType = (SbgEComGnssType)sbgStreamBufferReadUint8LE(&inputStream); + pFeatures->gnssUpdateRate = sbgStreamBufferReadUint8LE(&inputStream); + pFeatures->gnssSignalsMask = sbgStreamBufferReadUint32LE(&inputStream); + pFeatures->gnssFeaturesMask = sbgStreamBufferReadUint32LE(&inputStream); + sbgStreamBufferReadBuffer(&inputStream, pFeatures->gnssProductCode, 32*sizeof(char)); + sbgStreamBufferReadBuffer(&inputStream, pFeatures->gnssSerialNumber, 32*sizeof(char)); + + // + // Only parse the GNSS firmware version if available + // + if (sbgStreamBufferGetSpace(&inputStream) > 0) + { + sbgStreamBufferReadBuffer(&inputStream, pFeatures->gnssFirmwareVersion, 32 * sizeof(char)); + } + else + { + strcpy(pFeatures->gnssFirmwareVersion, ""); + } + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdFeatures.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdFeatures.h new file mode 100644 index 0000000..080370e --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdFeatures.h @@ -0,0 +1,140 @@ +/*! + * \file sbgEComCmdFeatures.h + * \ingroup commands + * \author SBG Systems + * \date 19 March 2015 + * + * \brief Commands used to query supported device features. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_FEATURES_H +#define SBG_ECOM_CMD_FEATURES_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Feature commands definitions -// +//----------------------------------------------------------------------// + +// +// Main sensor features +// +#define SBG_ECOM_SENSOR_FEATURE_IMU (0x00000001 << 0) /*!< This unit can provide IMU data */ +#define SBG_ECOM_SENSOR_FEATURE_AHRS (0x00000001 << 1) /*!< This unit can provide orientation data */ +#define SBG_ECOM_SENSOR_FEATURE_NAVIGATION (0x00000001 << 2) /*!< This unit can provide position and velocity data */ +#define SBG_ECOM_SENSOR_FEATURE_SHIP_MOTION (0x00000001 << 3) /*!< This unit can provide ship motion data output (heave) */ + +// +// GPS Signals bitmask defining every signal +// +#define SBG_ECOM_GNSS_SIGNAL_GPS_L1 (0x00000001 << 0) /*!< This GNSS receiver tracks GPS L1 band. */ +#define SBG_ECOM_GNSS_SIGNAL_GPS_L2 (0x00000001 << 1) /*!< This GNSS receiver tracks GPS L2 band. */ +#define SBG_ECOM_GNSS_SIGNAL_GPS_L5 (0x00000001 << 2) /*!< This GNSS receiver tracks GPS L5 band. */ +#define SBG_ECOM_GNSS_SIGNAL_GLONASS_L1 (0x00000001 << 3) /*!< This GNSS receiver tracks GLONASS L1 band. */ +#define SBG_ECOM_GNSS_SIGNAL_GLONASS_L2 (0x00000001 << 4) /*!< This GNSS receiver tracks GLONASS L2 band. */ +#define SBG_ECOM_GNSS_SIGNAL_BEIDOU_B1 (0x00000001 << 5) /*!< This GNSS receiver tracks BEIDOU B1 band. */ +#define SBG_ECOM_GNSS_SIGNAL_BEIDOU_B2 (0x00000001 << 6) /*!< This GNSS receiver tracks BEIDOU B2 band. */ +#define SBG_ECOM_GNSS_SIGNAL_BEIDOU_B3 (0x00000001 << 7) /*!< This GNSS receiver tracks BEIDOU B3 band. */ +#define SBG_ECOM_GNSS_SIGNAL_GALILEO_E1 (0x00000001 << 8) /*!< This GNSS receiver tracks GALILEO E1 band. */ +#define SBG_ECOM_GNSS_SIGNAL_GALILEO_E5 (0x00000001 << 9) /*!< This GNSS receiver tracks GALILEO E5 band. */ +#define SBG_ECOM_GNSS_SIGNAL_GALILEO_E6 (0x00000001 << 10) /*!< This GNSS receiver tracks GALILEO E6 band. */ +#define SBG_ECOM_GNSS_SIGNAL_QZSS (0x00000001 << 11) /*!< This GNSS receiver tracks QZSS signals */ +#define SBG_ECOM_GNSS_SIGNAL_SBAS (0x00000001 << 12) /*!< This GNSS receiver tracks SBAS signals */ +#define SBG_ECOM_GNSS_SIGNAL_L_BAND (0x00000001 << 13) /*!< This GNSS receiver tracks L-Band (for PPP services) */ + +// +// GPS capabilities +// +#define SBG_ECOM_GNSS_FEATURE_DUAL_ANT (0x00000001 << 0) /*!< This GNSS receiver provides a dual antenna heading */ +#define SBG_ECOM_GNSS_FEATURE_RTK_LIMITED (0x00000001 << 1) /*!< This GNSS receiver has limited RTK accuracy (eg. Trimble RTK 30/30) */ +#define SBG_ECOM_GNSS_FEATURE_RTK (0x00000001 << 2) /*!< This GNSS receiver provides full RTK accuracy */ +#define SBG_ECOM_GNSS_FEATURE_PPP (0x00000001 << 3) /*!< This GNSS receiver provides PPP computations */ +#define SBG_ECOM_GNSS_FEATURE_RAW_DATA (0x00000001 << 4) /*!< This GNSS receiver provides RAW data output */ +#define SBG_ECOM_GNSS_FEATURE_RAIM (0x00000001 << 5) /*!< This GNSS receiver provides Receiver Autonomous Integrity Monitoring */ +#define SBG_ECOM_GNSS_FEATURE_HIGH_SPEED (0x00000001 << 6) /*!< This GNSS receiver has no high speed limitation (> 515m/s) */ + +//----------------------------------------------------------------------// +//- Feature commands types definition -// +//----------------------------------------------------------------------// + +/*! + * This enum defines the different types of internal GNSS receiver that can provide specific features. + * Note External type is considered as not handled by the feature system + */ +typedef enum _SbgEComGnssType +{ + SBG_ECOM_GNSS_TYPE_DISABLED = 0, /*!< GNSS module disabled */ + SBG_ECOM_GNSS_TYPE_EXTERNAL = 1, /*!< External GNSS module (all features are unknown) */ + SBG_ECOM_GNSS_TYPE_UBX_MAX_M8 = 2, /*!< Ublox MAX-M8 module */ + SBG_ECOM_GNSS_TYPE_NOV_OEM615 = 3, /*!< Novatel OEM615 device */ + SBG_ECOM_GNSS_TYPE_NOV_OEM615_DUAL = 4, /*!< Two Novatel OEM615 devices for dual antenna */ + SBG_ECOM_GNSS_TYPE_NOV_OEM617D = 5, /*!< Novatel OEM617D device */ + SBG_ECOM_GNSS_TYPE_SEP_AX4 = 6, /*!< Septentrio Asterx m4 */ + SBG_ECOM_GNSS_TYPE_SEP_AXM2A = 7, /*!< Septentrio Asterx m2a */ + SBG_ECOM_GNSS_TYPE_UBX_F9P = 8, /*!< Ublox ZED-F9P module */ +} SbgEComGnssType; + +/*! + * This structure contains all the information provided by the SBG_ECOM_CMD_GET_FEATURES command + */ +typedef struct _SbgEComFeatures +{ + uint32_t sensorFeaturesMask; /*!< The different measurement capabilities of this unit */ + SbgEComGnssType gnssType; /*!< The type of GNSS receiver used (brand and model) */ + uint8_t gnssUpdateRate; /*!< The actual GNSS update rate */ + uint32_t gnssSignalsMask; /*!< GNSS receiver signals tracking */ + uint32_t gnssFeaturesMask; /*!< GNSS receiver computation and output features */ + char gnssProductCode[32]; /*!< String containing the GNSS receiver product code ("\0" if unknown) */ + char gnssSerialNumber[32]; /*!< String containing the GNSS receiver serial number ("\0" if unknown) */ + char gnssFirmwareVersion[32]; /*!< String containing the GNSS receiver firmware version ("\0" if unknown) */ +} SbgEComFeatures; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Retrieve the device and embedded GPS receiver features. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pFeatures A pointer to a structure to hold features. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdGetFeatures(SbgEComHandle *pHandle, SbgEComFeatures *pFeatures); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_FEATURES_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdGnss.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdGnss.c new file mode 100644 index 0000000..9dd1c8b --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdGnss.c @@ -0,0 +1,422 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdGnss.h" + +//----------------------------------------------------------------------// +//- Private methods -// +//----------------------------------------------------------------------// + +/*! + * Set GNSS error model id. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] id Model ID to set + * \param[in] cmdId The command identifier to set parameters for a specific GNSS module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +static SbgErrorCode sbgEComCmdGnssSetModelId(SbgEComHandle *pHandle, SbgEComGnssModelsStdIds modelId, SbgEComCmd cmdId) +{ + assert(pHandle); + + return sbgEComCmdGenericSetModelId(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, cmdId, modelId); +} + +/*! + * Retrieve GNSS error model id. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pModelId Retreived model id. + * \param[in] cmdId The command identifier to get parameters for a specific GNSS module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +static SbgErrorCode sbgEComCmdGnssGetModelId(SbgEComHandle *pHandle, SbgEComGnssModelsStdIds *pModelId, SbgEComCmd cmdId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t modelIdAsUint; + + assert(pHandle); + assert(pModelId); + + errorCode = sbgEComCmdGenericGetModelId(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, cmdId, &modelIdAsUint); + + if (errorCode == SBG_NO_ERROR) + { + *pModelId = (SbgEComGnssModelsStdIds)modelIdAsUint; + } + + return errorCode; +} + +/*! + * Retrieve the mechanical installation parameters for the GNSS # module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pGnssInstallation Used to store the retrieved the GNSS installation parameters. + * \param[in] cmdId The command identifier to get parameters for a specific GNSS module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +static SbgErrorCode sbgEComCmdGnssInstallationGet(SbgEComHandle *pHandle, SbgEComGnssInstallation *pGnssInstallation, SbgEComCmd cmdId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pGnssInstallation); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, cmdId, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, cmdId, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid answer + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + pGnssInstallation->leverArmPrimary[0] = sbgStreamBufferReadFloatLE(&inputStream); + pGnssInstallation->leverArmPrimary[1] = sbgStreamBufferReadFloatLE(&inputStream); + pGnssInstallation->leverArmPrimary[2] = sbgStreamBufferReadFloatLE(&inputStream); + pGnssInstallation->leverArmPrimaryPrecise = sbgStreamBufferReadBooleanLE(&inputStream); + + pGnssInstallation->leverArmSecondary[0] = sbgStreamBufferReadFloatLE(&inputStream); + pGnssInstallation->leverArmSecondary[1] = sbgStreamBufferReadFloatLE(&inputStream); + pGnssInstallation->leverArmSecondary[2] = sbgStreamBufferReadFloatLE(&inputStream); + pGnssInstallation->leverArmSecondaryMode = (SbgEComGnssInstallationMode)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +/*! + * Set the mechanical installation parameters for the GNSS # module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pGnssInstallation The GNSS installation parameters to set. + * \param[in] cmdId The command identifier to set parameters for a specific GNSS module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +static SbgErrorCode sbgEComCmdGnssInstallationSet(SbgEComHandle *pHandle, const SbgEComGnssInstallation *pGnssInstallation, SbgEComCmd cmdId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pGnssInstallation); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Initialize stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteFloatLE(&outputStream, pGnssInstallation->leverArmPrimary[0]); + sbgStreamBufferWriteFloatLE(&outputStream, pGnssInstallation->leverArmPrimary[1]); + sbgStreamBufferWriteFloatLE(&outputStream, pGnssInstallation->leverArmPrimary[2]); + sbgStreamBufferWriteBooleanLE(&outputStream, pGnssInstallation->leverArmPrimaryPrecise); + + sbgStreamBufferWriteFloatLE(&outputStream, pGnssInstallation->leverArmSecondary[0]); + sbgStreamBufferWriteFloatLE(&outputStream, pGnssInstallation->leverArmSecondary[1]); + sbgStreamBufferWriteFloatLE(&outputStream, pGnssInstallation->leverArmSecondary[2]); + sbgStreamBufferWriteUint8LE(&outputStream, pGnssInstallation->leverArmSecondaryMode); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, cmdId, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, cmdId, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +/*! + * Retrieve the rejection configuration of the gnss module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pAlignConf Pointer to a SbgEComGnssRejectionConf struct to hold rejection configuration of the gnss module. + * \param[in] cmdId The command identifier to get parameters for a specific GNSS module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +static SbgErrorCode sbgEComCmdGnssGetRejection(SbgEComHandle *pHandle, SbgEComGnssRejectionConf *pRejectConf, SbgEComCmd cmdId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pRejectConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, cmdId, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, cmdId, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_GNSS_1_REJECT_MODES command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + pRejectConf->position = (SbgEComRejectionMode)sbgStreamBufferReadUint8LE(&inputStream); + pRejectConf->velocity = (SbgEComRejectionMode)sbgStreamBufferReadUint8LE(&inputStream); + sbgStreamBufferReadUint8LE(&inputStream); // Skipped for backward compatibility + pRejectConf->hdt = (SbgEComRejectionMode)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +/*! + * Set the rejection configuration of the gnss module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pAlignConf Pointer to a SbgEComGnssRejectionConf struct holding rejection configuration for the gnss module. + * \param[in] cmdId The command identifier to set parameters for a specific GNSS module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +static SbgErrorCode sbgEComCmdGnssSetRejection(SbgEComHandle *pHandle, const SbgEComGnssRejectionConf *pRejectConf, SbgEComCmd cmdId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pRejectConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pRejectConf->position); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pRejectConf->velocity); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)SBG_ECOM_NEVER_ACCEPT_MODE); // Reserved parameter + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pRejectConf->hdt); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, cmdId, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, cmdId, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdGnss1SetModelId(SbgEComHandle *pHandle, SbgEComGnssModelsStdIds modelId) +{ + assert(pHandle); + + return sbgEComCmdGnssSetModelId(pHandle, modelId, SBG_ECOM_CMD_GNSS_1_MODEL_ID); +} + +SbgErrorCode sbgEComCmdGnss1GetModelId(SbgEComHandle *pHandle, SbgEComGnssModelsStdIds *pModelId) +{ + assert(pHandle); + assert(pModelId); + + return sbgEComCmdGnssGetModelId(pHandle, pModelId, SBG_ECOM_CMD_GNSS_1_MODEL_ID); +} + +SbgErrorCode sbgEComCmdGnss1InstallationGet(SbgEComHandle *pHandle, SbgEComGnssInstallation *pGnssInstallation) +{ + assert(pHandle); + assert(pGnssInstallation); + + return sbgEComCmdGnssInstallationGet(pHandle, pGnssInstallation, SBG_ECOM_CMD_GNSS_1_INSTALLATION); +} + +SbgErrorCode sbgEComCmdGnss1InstallationSet(SbgEComHandle *pHandle, const SbgEComGnssInstallation *pGnssInstallation) +{ + assert(pHandle); + assert(pGnssInstallation); + + return sbgEComCmdGnssInstallationSet(pHandle, pGnssInstallation, SBG_ECOM_CMD_GNSS_1_INSTALLATION); +} + +SbgErrorCode sbgEComCmdGnss1GetRejection(SbgEComHandle *pHandle, SbgEComGnssRejectionConf *pRejectConf) +{ + assert(pHandle); + assert(pRejectConf); + + return sbgEComCmdGnssGetRejection(pHandle, pRejectConf, SBG_ECOM_CMD_GNSS_1_REJECT_MODES); +} + +SbgErrorCode sbgEComCmdGnss1SetRejection(SbgEComHandle *pHandle, const SbgEComGnssRejectionConf *pRejectConf) +{ + assert(pHandle); + assert(pRejectConf); + + return sbgEComCmdGnssSetRejection(pHandle, pRejectConf, SBG_ECOM_CMD_GNSS_1_REJECT_MODES); +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdGnss.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdGnss.h new file mode 100644 index 0000000..e4bab66 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdGnss.h @@ -0,0 +1,165 @@ +/*! + * \file sbgEComCmdGnss.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief GNSS aiding module configuration commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_GNSS_H +#define SBG_ECOM_CMD_GNSS_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Public definitions -// +//----------------------------------------------------------------------// + +/*! + * This enum defines the different GNSS model IDs available in standard + */ +typedef enum _SbgEComGnssModelsStdIds +{ + SBG_ECOM_GNSS_MODEL_INTERNAL = 101, /*!< Default internal GNSS for ELLIPSE-N and ELLIPSE-D */ + SBG_ECOM_GNSS_MODEL_NMEA = 102, /*!< ELLIPSE-E to accept an external GNSS using NMEA protocol */ + SBG_ECOM_GNSS_MODEL_UBLOX_GPS_BEIDOU = 103, /*!< Only for ELLIPSE-N hardware 1 & 2 to select GPS+BEIDOU instead of the default GPS+GLONASS */ + SBG_ECOM_GNSS_MODEL_UBLOX_EXTERNAL = 104, /*!< ELLIPSE-E to accept an external Ublox GNSS (receive only - passive) */ + SBG_ECOM_GNSS_MODEL_RESERVED_01 = 105, /*!< Reserved, do not use */ + SBG_ECOM_GNSS_MODEL_NOVATEL_EXTERNAL = 106, /*!< ELLIPSE-E to accept an external Novatel GNSS (receive only - passive) */ + SBG_ECOM_GNSS_MODEL_RESERVED_02 = 107, /*!< Reserved, do not use */ + SBG_ECOM_GNSS_MODEL_RESERVED_03 = 108, /*!< Reserved, do not use */ + SBG_ECOM_GNSS_MODEL_SEPTENTRIO_EXTERNAL = 109, /*!< ELLIPSE-E to accept an external Septentrio GNSS(receive only - passive) */ + SBG_ECOM_GNSS_MODEL_RESERVED_04 = 110 /*!< Reserved, do not use */ +} SbgEComGnssModelsStdIds; + +/*! + * GNSS mechanical installation modes for the dual antenna mode. + */ +typedef enum _SbgEComGnssInstallationMode +{ + SBG_ECOM_GNSS_INSTALLATION_MODE_SINGLE = 1, /*!< The GNSS will be used in single antenna mode only and the secondary lever arm is not used. */ + SBG_ECOM_GNSS_INSTALLATION_MODE_DUAL_AUTO = 2, /*!< [Reserved] The GNSS dual antenna information will be used but the secondary lever arm is not known. */ + SBG_ECOM_GNSS_INSTALLATION_MODE_DUAL_ROUGH = 3, /*!< The GNSS dual antenna information will be used and we have a rough guess for the secondary lever arm. */ + SBG_ECOM_GNSS_INSTALLATION_MODE_DUAL_PRECISE = 4 /*!< The GNSS dual antenna information will be used and the secondary lever arm is accurately entered and doesn't need online re-estimation. */ +} SbgEComGnssInstallationMode; + +/*! + * GNSS mechanical installation parameters to be used with command SBG_ECOM_CMD_GNSS_#_INSTALLATION + */ +typedef struct _SbgEComGnssInstallation +{ + float leverArmPrimary[3]; /*!< GNSS primary antenna lever arm in IMU X, Y, Z axis in meters */ + bool leverArmPrimaryPrecise; /*!< If set to true, the primary lever arm has been accurately entered and doesn't need online re-estimation. */ + + float leverArmSecondary[3]; /*!< GNSS secondary antenna lever arm in IMU X, Y, Z axis in meters */ + SbgEComGnssInstallationMode leverArmSecondaryMode; /*!< Define the secondary antenna (dual antenna) operating mode. */ +} SbgEComGnssInstallation; + +/*! + * Holds all necessary information for GNSS module data rejection. + */ +typedef struct _SbgEComGnssRejectionConf +{ + SbgEComRejectionMode position; /*!< Rejection mode for position. */ + SbgEComRejectionMode velocity; /*!< Rejection mode for velocity. */ + SbgEComRejectionMode hdt; /*!< Rejection mode for true heading. */ +} SbgEComGnssRejectionConf; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Set GNSS error model id. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] modelId Model ID to set + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdGnss1SetModelId(SbgEComHandle *pHandle, SbgEComGnssModelsStdIds modelId); + +/*! + * Retrieve GNSS error model id. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pModelId Retrieved model id. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdGnss1GetModelId(SbgEComHandle *pHandle, SbgEComGnssModelsStdIds *pModelId); + +/*! + * Retrieve the mechanical installation parameters for the GNSS 1 module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pGnssInstallation Used to store the retrieved the GNSS installation parameters. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdGnss1InstallationGet(SbgEComHandle *pHandle, SbgEComGnssInstallation *pGnssInstallation); + +/*! + * Set the mechanical installation parameters for the GNSS 1 module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pGnssInstallation The GNSS installation parameters to set. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdGnss1InstallationSet(SbgEComHandle *pHandle, const SbgEComGnssInstallation *pGnssInstallation); + +/*! + * Retrieve the rejection configuration of the gnss module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pRejectConf Pointer to a SbgEComGnssRejectionConf struct to hold rejection configuration of the gnss module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdGnss1GetRejection(SbgEComHandle *pHandle, SbgEComGnssRejectionConf *pRejectConf); + +/*! + * Set the rejection configuration of the gnss module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pRejectConf Pointer to a SbgEComGnssRejectionConf struct holding rejection configuration for the gnss module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdGnss1SetRejection(SbgEComHandle *pHandle, const SbgEComGnssRejectionConf *pRejectConf); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_GNSS_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInfo.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInfo.c new file mode 100644 index 0000000..fb4598a --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInfo.c @@ -0,0 +1,105 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdInfo.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdGetInfo(SbgEComHandle *pHandle, SbgEComDeviceInfo *pInfo) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + + assert(pHandle); + assert(pInfo); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_INFO, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_INFO, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have correctly received a message + // + if (errorCode == SBG_NO_ERROR) + { + // + // Make sure we have received a payload + // + if (sbgEComProtocolPayloadGetSize(&receivedPayload) > 0) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + sbgStreamBufferReadBuffer(&inputStream, pInfo->productCode, SBG_ECOM_INFO_PRODUCT_CODE_LENGTH); + pInfo->serialNumber = sbgStreamBufferReadUint32LE(&inputStream); + pInfo->calibationRev = sbgStreamBufferReadUint32LE(&inputStream); + pInfo->calibrationYear = sbgStreamBufferReadUint16LE(&inputStream); + pInfo->calibrationMonth = sbgStreamBufferReadUint8LE(&inputStream); + pInfo->calibrationDay = sbgStreamBufferReadUint8LE(&inputStream); + pInfo->hardwareRev = sbgStreamBufferReadUint32LE(&inputStream); + pInfo->firmwareRev = sbgStreamBufferReadUint32LE(&inputStream); + + // + // We have parsed a message so return immediately but report any error during payload parsing + // + errorCode = sbgStreamBufferGetLastError(&inputStream); + + break; + } + else + { + // + // We should have received a non empty payload so we have received an invalid frame + // + errorCode = SBG_INVALID_FRAME; + } + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInfo.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInfo.h new file mode 100644 index 0000000..26abc4e --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInfo.h @@ -0,0 +1,89 @@ +/*! + * \file sbgEComCmdInfo.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief Commands used to query the device information. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_INFO_H +#define SBG_ECOM_CMD_INFO_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Device info definitions -// +//----------------------------------------------------------------------// + +/* Misc */ +#define SBG_ECOM_INFO_PRODUCT_CODE_LENGTH (32) + +//----------------------------------------------------------------------// +//- Device Info structure -// +//----------------------------------------------------------------------// + +/*! + * Helper structure to retrieve device info. + */ +typedef struct _SbgEComDeviceInfo +{ + uint8_t productCode[SBG_ECOM_INFO_PRODUCT_CODE_LENGTH]; /*!< Human readable Product Code. */ + uint32_t serialNumber; /*!< Device serial number */ + uint32_t calibationRev; /*!< Calibration data revision */ + uint16_t calibrationYear; /*!< Device Calibration Year */ + uint8_t calibrationMonth; /*!< Device Calibration Month */ + uint8_t calibrationDay; /*!< Device Calibration Day */ + uint32_t hardwareRev; /*!< Device hardware revision */ + uint32_t firmwareRev; /*!< Firmware revision */ +} SbgEComDeviceInfo; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Retrieve the device information. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pInfo A pointer to a structure to hold device information. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdGetInfo(SbgEComHandle *pHandle, SbgEComDeviceInfo *pInfo); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_INFO_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInterface.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInterface.c new file mode 100644 index 0000000..e0f10b9 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInterface.c @@ -0,0 +1,301 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdInterface.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdInterfaceGetUartConf(SbgEComHandle *pHandle, SbgEComPortId interfaceId, SbgEComInterfaceConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + uint8_t interfaceIdParam = interfaceId; + + // + // Send the command and the interfaceId as a 1-byte payload + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_UART_CONF, &interfaceIdParam, sizeof(interfaceIdParam)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_UART_CONF, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received correctly the answer + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // First is returned interfaceId, then baud rate and the mode at last. + // + interfaceId = (SbgEComPortId)sbgStreamBufferReadUint8LE(&inputStream); + pConf->baudRate = sbgStreamBufferReadUint32LE(&inputStream); + pConf->mode = (SbgEComPortMode)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdInterfaceSetUartConf(SbgEComHandle *pHandle, SbgEComPortId interfaceId, const SbgEComInterfaceConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)interfaceId); + sbgStreamBufferWriteUint32LE(&outputStream, pConf->baudRate); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->mode); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_UART_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_UART_CONF, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdInterfaceGetCanConf(SbgEComHandle *pHandle, SbgEComCanBitRate *pBitrate, SbgEComCanMode *pMode) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pBitrate); + assert(pMode); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command with no payload + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_CAN_BUS_CONF, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_CAN_BUS_CONF, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_CAN_BUS_CONF command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read bit rate returned by the device + // + *pBitrate = (SbgEComCanBitRate)sbgStreamBufferReadUint16LE(&inputStream); + + // + // Check if we can parse the CAN mode that has been introduced in sbgECom version 2.0 + // + if (sbgStreamBufferGetSpace(&inputStream) > 0) + { + // + // Read mode returned by the device + // + *pMode = (SbgEComCanMode)sbgStreamBufferReadUint8(&inputStream); + } + else + { + // + // Default the mode to the behavior prior to CAN mode setting introduction + // + *pMode = SBG_ECOM_CAN_MODE_NORMAL; + } + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdInterfaceSetCanConf(SbgEComHandle *pHandle, SbgEComCanBitRate bitrate, SbgEComCanMode mode) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[3]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(bitrate <= UINT16_MAX); + assert(mode <= UINT8_MAX); + + // + // Build the command payload + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + sbgStreamBufferWriteUint16LE(&outputStream, (uint16_t)bitrate); + sbgStreamBufferWriteUint8(&outputStream, (uint8_t)mode); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_CAN_BUS_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_CAN_BUS_CONF, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInterface.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInterface.h new file mode 100644 index 0000000..c2a69b5 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdInterface.h @@ -0,0 +1,174 @@ +/*! + * \file sbgEComCmdInterface.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief Commands used to configure device serial, CAN and Ethernet interfaces. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_INTERFACE_H +#define SBG_ECOM_CMD_INTERFACE_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Serial interface definitions -// +//----------------------------------------------------------------------// + +/*! + * List of serial interfaces available. + */ +typedef enum _SbgEComPortId +{ + SBG_ECOM_IF_COM_A = 0, /*!< Main communication interface. Full duplex. */ + SBG_ECOM_IF_COM_B = 1, /*!< Auxiliary input interface for RTCM. */ + SBG_ECOM_IF_COM_C = 2, /*!< Auxiliary communication interface. Full duplex. */ + SBG_ECOM_IF_COM_D = 3, /*!< Auxiliary input interface. */ + SBG_ECOM_IF_COM_E = 4, /*!< Auxiliary output interface. */ + + SBG_ECOM_IF_ETH_0 = 10, /*!< Ethernet interface 0. */ + SBG_ECOM_IF_ETH_1 = 11, /*!< Ethernet interface 1. */ + SBG_ECOM_IF_ETH_2 = 12, /*!< Ethernet interface 2. */ + SBG_ECOM_IF_ETH_3 = 13, /*!< Ethernet interface 3. */ + SBG_ECOM_IF_ETH_4 = 14, /*!< Ethernet interface 4. */ + + SBG_ECOM_IF_DATA_LOGGER = 20, /*!< Data logger interface. */ +} SbgEComPortId; + +/*! + * List of serial modes available. + */ +typedef enum _SbgEComPortMode +{ + SBG_ECOM_UART_MODE_OFF = 0, /*!< This interface is turned OFF. */ + SBG_ECOM_UART_MODE_232 = 1, /*!< This interface is using RS-232 communications. */ + SBG_ECOM_UART_MODE_422 = 2, /*!< This interface is using RS-422 communications. */ +} SbgEComPortMode; + +//----------------------------------------------------------------------// +//- Serial interface configuration -// +//----------------------------------------------------------------------// + +/*! + * Helper structure to configure a serial interface + */ +typedef struct _SbgEComInterfaceConf +{ + uint32_t baudRate; /*!< The baud rate of the interface. */ + SbgEComPortMode mode; /*!< The mode of the interface. */ +} SbgEComInterfaceConf; + +//----------------------------------------------------------------------// +//- CAN interface definitions -// +//----------------------------------------------------------------------// + +/*! + * Enum containing the list of all available bit rates (in KB/s). + */ +typedef enum _SbgEComCanBitRate +{ + SBG_ECOM_CAN_BITRATE_DISABLED = 0, /*!< The CAN interface is disabled. */ + SBG_ECOM_CAN_BITRATE_10 = 10, /*!< 10Kb/s. */ + SBG_ECOM_CAN_BITRATE_20 = 20, /*!< 20Kb/s. */ + SBG_ECOM_CAN_BITRATE_25 = 25, /*!< 25Kb/s. */ + SBG_ECOM_CAN_BITRATE_50 = 50, /*!< 50Kb/s. */ + SBG_ECOM_CAN_BITRATE_100 = 100, /*!< 100Kb/s. */ + SBG_ECOM_CAN_BITRATE_125 = 125, /*!< 125Kb/s. */ + SBG_ECOM_CAN_BITRATE_250 = 250, /*!< 250Kb/s. */ + SBG_ECOM_CAN_BITRATE_500 = 500, /*!< 500Kb/s. */ + SBG_ECOM_CAN_BITRATE_750 = 750, /*!< 750Kb/s. */ + SBG_ECOM_CAN_BITRATE_1000 = 1000, /*!< 1Mb/s. */ +} SbgEComCanBitRate; + +/*! + * Enum containing the list of different CAN modes + */ +typedef enum _SbgEComCanMode +{ + SBG_ECOM_CAN_MODE_UNDEFINED = 0, /*!< CAN Mode undefined. */ + SBG_ECOM_CAN_MODE_SPY = 1, /*!< Only listening on the CAN bus and doesn't sent anything (even RX ACK bit). */ + SBG_ECOM_CAN_MODE_NORMAL = 2, /*!< The device is allowed to both send and receive over the CAN bus. */ + SBG_ECOM_CAN_NR_MODE +} SbgEComCanMode; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Retrieve the configuration of one of the interfaces. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] interfaceId The interface from which the configuration is to be retrieved. + * \param[out] pConf Pointer to a SbgEComInterfaceConf struct to hold configuration of the interface. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdInterfaceGetUartConf(SbgEComHandle *pHandle, SbgEComPortId interfaceId, SbgEComInterfaceConf *pConf); + +/*! + * Set the configuration of one of the interfaces. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] interfaceId The interface from which the configuration is to be retrieved. + * \param[in] pConf Pointer to a SbgEComInterfaceConf struct that holds the new configuration for the interface. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdInterfaceSetUartConf(SbgEComHandle *pHandle, SbgEComPortId interfaceId, const SbgEComInterfaceConf *pConf); + +/*! + * Retrieve the configuration of the CAN interface. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pBitrate The bitrate of the CAN interface. + * \param[out] pMode Mode of the CAN interface. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdInterfaceGetCanConf(SbgEComHandle *pHandle, SbgEComCanBitRate *pBitrate, SbgEComCanMode *pMode); + +/*! + * Set the configuration of the CAN interface. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] bitRate The bitrate of the CAN interface. + * \param[in] mode Mode of the CAN interface. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdInterfaceSetCanConf(SbgEComHandle *pHandle, SbgEComCanBitRate bitRate, SbgEComCanMode mode); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_INTERFACE_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdLicense.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdLicense.c new file mode 100644 index 0000000..ce5a4e8 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdLicense.c @@ -0,0 +1,44 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdLicense.h" + + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdLicenseApply(SbgEComHandle *pHandle, const void *pBuffer, size_t size) +{ + SbgErrorCode errorCode; + uint32_t currentTimeOut; + + assert(pHandle); + assert(pBuffer); + assert(size > 0); + + // + // Define a time out of 10s to let enough time for the GNSS receiver to apply the license + // + currentTimeOut = pHandle->cmdDefaultTimeOut; + pHandle->cmdDefaultTimeOut = 10000; + + // + // Call function that handle data transfer + // + errorCode = sbgEComTransferSend(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_LICENSE_APPLY, pBuffer, size); + + // + // Restore the default time out + // + pHandle->cmdDefaultTimeOut = currentTimeOut; + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdLicense.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdLicense.h new file mode 100644 index 0000000..7fb5ea6 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdLicense.h @@ -0,0 +1,66 @@ +/*! + * \file sbgEComCmdLicense.h + * \ingroup commands + * \author SBG Systems + * \date 25 February 2015 + * + * \brief Command used to upload and apply an activation license. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_LICENSE_H +#define SBG_ECOM_CMD_LICENSE_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Upload and apply a new license to a device. + * + * The device will reboot automatically to use the new license. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pBuffer Read only buffer containing the license. + * \param[in] size Size of the buffer. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdLicenseApply(SbgEComHandle *pHandle, const void *pBuffer, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_LICENSE_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdMag.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdMag.c new file mode 100644 index 0000000..1bf5470 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdMag.c @@ -0,0 +1,422 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdMag.h" + +//----------------------------------------------------------------------// +//- Magnetometer commands -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdMagSetModelId(SbgEComHandle *pHandle, SbgEComMagModelsStdId modelId) +{ + assert(pHandle); + + return sbgEComCmdGenericSetModelId(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_MAGNETOMETER_MODEL_ID, modelId); +} + +SbgErrorCode sbgEComCmdMagGetModelId(SbgEComHandle *pHandle, SbgEComMagModelsStdId *pModelId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t modelIdAsUint; + + assert(pHandle); + assert(pModelId); + + errorCode = sbgEComCmdGenericGetModelId(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_MAGNETOMETER_MODEL_ID, &modelIdAsUint); + + if (errorCode == SBG_NO_ERROR) + { + *pModelId = (SbgEComMagModelsStdId)modelIdAsUint; + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdMagSetCalibData(SbgEComHandle *pHandle, const float *pOffset, const float *pMatrix) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgStreamBuffer outputStream; + uint8_t outputBuffer[12 * sizeof(float)]; + uint32_t trial; + uint32_t i; + + assert(pHandle); + assert(pOffset); + assert(pMatrix); + + // + // Initialize a stream buffer to write the command payload + // + errorCode = sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Write the offset vector + // + sbgStreamBufferWriteFloatLE(&outputStream, pOffset[0]); + sbgStreamBufferWriteFloatLE(&outputStream, pOffset[1]); + sbgStreamBufferWriteFloatLE(&outputStream, pOffset[2]); + + // + // Write the matrix + // + for (i = 0; i < 9; i++) + { + sbgStreamBufferWriteFloatLE(&outputStream, pMatrix[i]); + } + + // + // Make sure that the stream buffer has been initialized + // + if (errorCode == SBG_NO_ERROR) + { + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SET_MAG_CALIB, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SET_MAG_CALIB, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdMagGetRejection(SbgEComHandle *pHandle, SbgEComMagRejectionConf *pRejectConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pRejectConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_MAGNETOMETER_REJECT_MODE, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_MAGNETOMETER_REJECT_MODE, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received frame was OK + // + if (errorCode == SBG_NO_ERROR) + { + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + pRejectConf->magneticField = (SbgEComRejectionMode)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdMagSetRejection(SbgEComHandle *pHandle, const SbgEComMagRejectionConf *pRejectConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pRejectConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // Build payload + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pRejectConf->magneticField); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_MAGNETOMETER_REJECT_MODE, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_MAGNETOMETER_REJECT_MODE, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +//----------------------------------------------------------------------// +//- Magnetometer onboard calibration commands -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdMagStartCalib(SbgEComHandle *pHandle, SbgEComMagCalibMode mode, SbgEComMagCalibBandwidth bandwidth) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgStreamBuffer outputStream; + uint8_t outputBuffer[2]; + uint32_t trial; + + assert(pHandle); + + // + // Initialize a stream buffer to write the command payload + // + errorCode = sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Write the calibration mode and bandwith + // + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)mode); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)bandwidth); + + // + // Make sure that the stream buffer has been initialized + // + if (errorCode == SBG_NO_ERROR) + { + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_START_MAG_CALIB, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_START_MAG_CALIB, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdMagComputeCalib(SbgEComHandle *pHandle, SbgEComMagCalibResults *pCalibResults) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pCalibResults); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_COMPUTE_MAG_CALIB, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 5 s because the onboard magnetic computation can take some time + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_COMPUTE_MAG_CALIB, &receivedPayload, 5000); + + // + // Test if we have received the correct command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + size_t i; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read quality and status parameters + // + pCalibResults->quality = (SbgEComMagCalibQuality)sbgStreamBufferReadUint8LE(&inputStream); + pCalibResults->confidence = (SbgEComMagCalibConfidence)sbgStreamBufferReadUint8LE(&inputStream); + pCalibResults->advancedStatus = sbgStreamBufferReadUint16LE(&inputStream); + + pCalibResults->beforeMeanError = sbgStreamBufferReadFloatLE(&inputStream); + pCalibResults->beforeStdError = sbgStreamBufferReadFloatLE(&inputStream); + pCalibResults->beforeMaxError = sbgStreamBufferReadFloatLE(&inputStream); + + pCalibResults->afterMeanError = sbgStreamBufferReadFloatLE(&inputStream); + pCalibResults->afterStdError = sbgStreamBufferReadFloatLE(&inputStream); + pCalibResults->afterMaxError = sbgStreamBufferReadFloatLE(&inputStream); + + pCalibResults->meanAccuracy = sbgStreamBufferReadFloatLE(&inputStream); + pCalibResults->stdAccuracy = sbgStreamBufferReadFloatLE(&inputStream); + pCalibResults->maxAccuracy = sbgStreamBufferReadFloatLE(&inputStream); + + pCalibResults->numPoints = sbgStreamBufferReadUint16LE(&inputStream); + pCalibResults->maxNumPoints = sbgStreamBufferReadUint16LE(&inputStream); + + // + // Read the computed hard iron offset vector + // + pCalibResults->offset[0] = sbgStreamBufferReadFloatLE(&inputStream); + pCalibResults->offset[1] = sbgStreamBufferReadFloatLE(&inputStream); + pCalibResults->offset[2] = sbgStreamBufferReadFloatLE(&inputStream); + + // + // Read the computed soft iron matrix + // + for (i = 0; i < 9; i++) + { + pCalibResults->matrix[i] = sbgStreamBufferReadFloatLE(&inputStream); + } + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdMag.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdMag.h new file mode 100644 index 0000000..bb708b9 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdMag.h @@ -0,0 +1,239 @@ +/*! + * \file sbgEComCmdMag.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief Magnetometer aiding module configuration & onboard magnetic calibration commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_MAG_H +#define SBG_ECOM_CMD_MAG_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Magnetometer definitions -// +//----------------------------------------------------------------------// + +/*! + * Define if the onboard magnetic calibration should acquiere points for a 3D or 2D calibration. + */ +typedef enum _SbgEComMagCalibMode +{ + SBG_ECOM_MAG_CALIB_MODE_2D = 1, /*!< Tell the device that the magnetic calibration will be performed with limited motions. + This calibration mode is only designed to be used when roll and pitch motions are less than ± 5°. + To work correctly, the device should be rotated through at least a full circle. */ + SBG_ECOM_MAG_CALIB_MODE_3D = 2 /*!< Tell the device to start a full 3D magnetic calibration procedure. + The 3D magnetic calibration offers the best accuracy but needs at least motion of ± 30° on the roll and pitch angles. */ +} SbgEComMagCalibMode; + + +/*! + * Used to select the expected dynamics during the magnetic calibration. + */ +typedef enum _SbgEComMagCalibBandwidth +{ + SBG_ECOM_MAG_CALIB_LOW_BW = 0, /*!< Tell the device that low dynamics will be observed during the magnetic calibration process. */ + SBG_ECOM_MAG_CALIB_MEDIUM_BW = 1, /*!< Tell the device that normal dynamics will be observed during the magnetic calibration process. */ + SBG_ECOM_MAG_CALIB_HIGH_BW = 2 /*!< Tell the device that high dynamics will be observed during the magnetic calibration process. */ +} SbgEComMagCalibBandwidth; + +/*! + * General quality indicator of an onboard magnetic calibration. + */ +typedef enum _SbgEComMagCalibQuality +{ + SBG_ECOM_MAG_CALIB_QUAL_OPTIMAL = 0, /*!< All acquired points fit very well on a unit sphere after the calibration. */ + SBG_ECOM_MAG_CALIB_QUAL_GOOD = 1, /*!< Small deviations of the magnetic field norm have been detected. The magnetic calibration should although provide accurate heading. */ + SBG_ECOM_MAG_CALIB_QUAL_POOR = 2, /*!< Large deviations of the magnetic field norm have been detected. It may come from external magnetic distortions during the calibration. */ + SBG_ECOM_MAG_CALIB_QUAL_INVALID = 3 /*!< No valid magnetic calibration has been computed. It could comes from too much magnetic disturbances, insufficient or invalid motions. */ +} SbgEComMagCalibQuality; + +/*! + * Confidence indicator on results of an onbard magnetic calibration. + */ +typedef enum _SbgEComMagCalibConfidence +{ + SBG_ECOM_MAG_CALIB_TRUST_HIGH = 0, /*!< Reported quality indicator can be trusted as enough remarkable magnetic field points have been acquired. */ + SBG_ECOM_MAG_CALIB_TRUST_MEDIUM = 1, /*!< Few remarkable magnetic field points have been used to compute the magnetic calibration leading to a medium confidence in reported quality indicators. */ + SBG_ECOM_MAG_CALIB_TRUST_LOW = 2 /*!< Even if the quality indicator could report an excellent calibration, + The data set used to compute the magnetic calibration was not meaningful enough to compute meaningful quality indicators. + This calibration should be used carefully. */ +} SbgEComMagCalibConfidence; + +/*! + * Status bit masks used to report advanced inforamtion on the onboard magnetic calibration. + */ +#define SBG_ECOM_MAG_CALIB_NOT_ENOUGH_POINTS (0x0001u) /*!< Not enough valid magnetic points have been acquired. */ +#define SBG_ECOM_MAG_CALIB_TOO_MUCH_DISTORTIONS (0x0002u) /*!< Unable to compute a magnetic calibration due to magnetic interferences or incorrect data set distribution. */ +#define SBG_ECOM_MAG_CALIB_X_MOTION_ISSUE (0x0004u) /*!< For a 3D calibration: not enough motion on X axis. For a 2D calibration; too much motion on X axis. */ +#define SBG_ECOM_MAG_CALIB_Y_MOTION_ISSUE (0x0008u) /*!< For a 3D calibration: not enough motion on Y axis. For a 2D calibration; too much motion on Y axis. */ +#define SBG_ECOM_MAG_CALIB_Z_MOTION_ISSUE (0x0010u) /*!< For a 3D or 2D calibration: not enough motion on Z axis. */ +#define SBG_ECOM_MAG_CALIB_ALIGNMENT_ISSUE (0x0020u) /*!< For a 3D calibration: the alignment between the magnetometers and the inertial frame seems to be invalid. */ + +/*! + * This enum defines the different magnetometer model IDs available in standard + */ +typedef enum _SbgEComMagModelsStdIds +{ + SBG_ECOM_MAG_MODEL_NORMAL = 201, /*!< Should be used in most applications */ + SBG_ECOM_MAG_MODEL_NOISY_MAG_TOLERANT = 202, /*!< Should be used in disturbed magnetic environment */ +} SbgEComMagModelsStdId; + +//----------------------------------------------------------------------// +//- Magnetometer configuration -// +//----------------------------------------------------------------------// + +/*! + * Holds all necessary information for Magnetometer module data rejection. + */ +typedef struct _SbgEComMagRejectionConf +{ + SbgEComRejectionMode magneticField; /*!< Rejection mode for magnetic field. */ +} SbgEComMagRejectionConf; + +/*! + * Helper structure to retrieve onboard magnetic calibration results. + */ +typedef struct _SbgEComMagCalibResults +{ + SbgEComMagCalibQuality quality; /*!< General magnetic calibration quality indicator. */ + SbgEComMagCalibConfidence confidence; /*!< Confidence indicator that should be read to interpret the quality indicator. */ + uint16_t advancedStatus; /*!< Set of bit masks used to report advanced information on the magnetic calibration status.*/ + + float beforeMeanError; /*!< Mean magnetic field norm error observed before calibration. */ + float beforeStdError; /*!< Standard deviation of the magnetic field norm error observed before calibration. */ + float beforeMaxError; /*!< Maximum magnetic field norm error observed before calibration. */ + + float afterMeanError; /*!< Mean magnetic field norm error observed after calibration. */ + float afterStdError; /*!< Standard deviation of the magnetic field norm error observed after calibration. */ + float afterMaxError; /*!< Maximum magnetic field norm error observed after calibration. */ + + float meanAccuracy; /*!< Mean expected heading accuracy in radians. */ + float stdAccuracy; /*!< Standard deviation of the expected heading accuracy in radians. */ + float maxAccuracy; /*!< Maximum expected heading accuracy in radians. */ + + uint16_t numPoints; /*!< Number of magnetic field points stored internally and used to compute the magnetic calibration. */ + uint16_t maxNumPoints; /*!< Maximum number of magnetic field points that can be stored internally. */ + float offset[3]; /*!< Computed Hard Iron correction vector offset. */ + float matrix[9]; /*!< Computed Hard & Soft Iron correction matrix. */ +} SbgEComMagCalibResults; + +//----------------------------------------------------------------------// +//- Magnetometer commands -// +//----------------------------------------------------------------------// + +/*! + * Set magnetometer error model id. + * + * \param[in] pHandle A valid sbgECom handle + * \param[in] modelId Magnetometer model id to set + * \return SBG_NO_ERROR if the command has been executed successfully + */ +SbgErrorCode sbgEComCmdMagSetModelId(SbgEComHandle *pHandle, SbgEComMagModelsStdId modelId); + +/*! + * Retrieve magnetometer error model id + * + * \param[in] pHandle A valid sbgECom handle + * \param[out] pModelId Retrieved magnetometer model id + * \return SBG_NO_ERROR if the command has been executed successfully + */ +SbgErrorCode sbgEComCmdMagGetModelId(SbgEComHandle *pHandle, SbgEComMagModelsStdId *pModelId); + +/*! + * Retrieve the rejection configuration of the magnetometer module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pRejectConf Pointer to a SbgEComMagRejectionConf struct to hold rejection configuration of the magnetometer module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdMagGetRejection(SbgEComHandle *pHandle, SbgEComMagRejectionConf *pRejectConf); + +/*! + * Set the rejection configuration of the magnetometer module. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pRejectConf Pointer to a SbgEComMagRejectionConf struct holding rejection configuration for the magnetometer module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdMagSetRejection(SbgEComHandle *pHandle, const SbgEComMagRejectionConf *pRejectConf); + +/*! + * Send a command that set the magnetometers calibration parameters. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pOffset Magnetometers calibration offset vector. + * \param[in] pMatrix Magnetometers calibration 3x3 matrix. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdMagSetCalibData(SbgEComHandle *pHandle, const float *pOffset, const float *pMatrix); + +//----------------------------------------------------------------------// +//- Magnetometer onboard calibration commands -// +//----------------------------------------------------------------------// + +/*! + * Start the magnetic calibration process. + * + * As soon as this command is sent, the device will start logging magnetic field data internally. + * This set of data will be used later by the magnetic calibration algorithms to map the surrounding magnetic field. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] mode Define which magnetic calibration type to perform. It could be 3D or 2D. + * \param[in] bandwidth Tell the device that we should have low, medium or high dynamics during the magnetic calibration process. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdMagStartCalib(SbgEComHandle *pHandle, SbgEComMagCalibMode mode, SbgEComMagCalibBandwidth bandwidth); + +/*! + * This command computes a magnetic calibration solution based on the magnetic field logged since the last call to the command SBG_ECOM_CMD_START_MAG_CALIB (15). + * + * As soon as the computations are done, the device will answer with quality indicators, status flags and if possible a valid magnetic calibration matrix and offset. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pCalibResults Pointer on a SbgEComMagCalibResults structure that can hold onboard magnetic calibration results and status. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdMagComputeCalib(SbgEComHandle *pHandle, SbgEComMagCalibResults *pCalibResults); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_MAG_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOdo.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOdo.c new file mode 100644 index 0000000..5f07558 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOdo.c @@ -0,0 +1,582 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdOdo.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdOdoGetConf(SbgEComHandle *pHandle, SbgEComOdoConf *pOdometerConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pOdometerConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_CONF, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_CONF, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_ODO_CONF command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + pOdometerConf->gain = sbgStreamBufferReadFloatLE(&inputStream); + pOdometerConf->gainError = sbgStreamBufferReadUint8LE(&inputStream); + pOdometerConf->reverseMode = sbgStreamBufferReadBooleanLE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdOdoSetConf(SbgEComHandle *pHandle, const SbgEComOdoConf *pOdometerConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pOdometerConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteFloatLE(&outputStream, pOdometerConf->gain); + sbgStreamBufferWriteUint8LE(&outputStream, pOdometerConf->gainError); + sbgStreamBufferWriteBooleanLE(&outputStream, pOdometerConf->reverseMode); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_CONF, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdOdoGetLeverArm(SbgEComHandle *pHandle, float *pLeverArm) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pLeverArm); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_LEVER_ARM, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_LEVER_ARM, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a correct answer + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + pLeverArm[0] = sbgStreamBufferReadFloatLE(&inputStream); + pLeverArm[1] = sbgStreamBufferReadFloatLE(&inputStream); + pLeverArm[2] = sbgStreamBufferReadFloatLE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdOdoSetLeverArm(SbgEComHandle *pHandle, const float *pLeverArm) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pLeverArm); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteFloatLE(&outputStream, pLeverArm[0]); + sbgStreamBufferWriteFloatLE(&outputStream, pLeverArm[1]); + sbgStreamBufferWriteFloatLE(&outputStream, pLeverArm[2]); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_LEVER_ARM, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_LEVER_ARM, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdOdoGetRejection(SbgEComHandle *pHandle, SbgEComOdoRejectionConf *pRejectConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pRejectConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_REJECT_MODE, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_REJECT_MODE, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a correct answer + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + pRejectConf->velocity = (SbgEComRejectionMode)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdOdoSetRejection(SbgEComHandle *pHandle, const SbgEComOdoRejectionConf *pRejectConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pRejectConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pRejectConf->velocity); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_REJECT_MODE, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_REJECT_MODE, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdOdoCanGetConf(SbgEComHandle *pHandle, SbgEComCmdOdoCanChannel canChannel, SbgEComCmdOdoCanConf *pOdoCanConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + uint8_t outputBuffer[16]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pOdoCanConf); + assert(canChannel <= UCHAR_MAX); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Build the command payload used to ask the CAN odometer configuration for a specific channel + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + sbgStreamBufferWriteUint8LE(&outputStream, canChannel); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_CAN_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_CAN_CONF, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_ODO_CAN_SPEED_CONF command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read fields from payload + // + canChannel = sbgStreamBufferReadUint8LE(&inputStream); + + pOdoCanConf->options = sbgStreamBufferReadUint16LE(&inputStream); + pOdoCanConf->canId = sbgStreamBufferReadUint32LE(&inputStream); + + pOdoCanConf->startBit = sbgStreamBufferReadUint8LE(&inputStream); + pOdoCanConf->dataSize = sbgStreamBufferReadUint8LE(&inputStream); + + pOdoCanConf->scale = sbgStreamBufferReadFloatLE(&inputStream); + pOdoCanConf->offset = sbgStreamBufferReadFloatLE(&inputStream); + pOdoCanConf->minValue = sbgStreamBufferReadFloatLE(&inputStream); + pOdoCanConf->maxValue = sbgStreamBufferReadFloatLE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdOdoCanSetConf(SbgEComHandle *pHandle, SbgEComCmdOdoCanChannel canChannel, const SbgEComCmdOdoCanConf *pOdoCanConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pOdoCanConf); + assert(canChannel <= UCHAR_MAX); + + // + // A CAN message has a payload of up to 64 bits so the offset can range from 0 to 63 and size from 1 to 64 + // + assert(pOdoCanConf->startBit < 64); + assert(pOdoCanConf->dataSize > 0); + assert(pOdoCanConf->dataSize <= 64); + + // + // Build the command payload + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)canChannel); + + sbgStreamBufferWriteUint16LE(&outputStream, pOdoCanConf->options); + sbgStreamBufferWriteUint32LE(&outputStream, pOdoCanConf->canId); + + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pOdoCanConf->startBit); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pOdoCanConf->dataSize); + + sbgStreamBufferWriteFloatLE(&outputStream, pOdoCanConf->scale); + sbgStreamBufferWriteFloatLE(&outputStream, pOdoCanConf->offset); + sbgStreamBufferWriteFloatLE(&outputStream, pOdoCanConf->minValue); + sbgStreamBufferWriteFloatLE(&outputStream, pOdoCanConf->maxValue); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_CAN_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_ODO_CAN_CONF, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOdo.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOdo.h new file mode 100644 index 0000000..ae9e005 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOdo.h @@ -0,0 +1,189 @@ +/*! + * \file sbgEComCmdOdo.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief Odometer / DMI aiding module configuration commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_ODO_H +#define SBG_ECOM_CMD_ODO_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Public definitions -// +//----------------------------------------------------------------------// + +/*! + * Holds all necessary information for Odometer module parameter configuration. + */ +typedef struct _SbgEComOdoConf +{ + float gain; /*!< Odometer's gain in pulses / meter. */ + uint8_t gainError; /*!< User gain average error in % */ + bool reverseMode; /*!< Whether the odometer is in reverse mode or not. */ +} SbgEComOdoConf; + +/*! + * Holds all necessary information for Odometer module data rejection. + */ +typedef struct _SbgEComOdoRejectionConf +{ + SbgEComRejectionMode velocity; /*!< Rejection mode for velocity. */ +} SbgEComOdoRejectionConf; + +/*! + * CAN odometer channels definition + * A channel is an inforamtion that can be decoded / used by the device. + */ +typedef enum _SbgEComCmdOdoCanChannel +{ + SBG_ECOM_CMD_ODO_CAN_CH_VELOCITY = 0, /*!< Channel used to decode the vehicle velocity information */ + SBG_ECOM_CMD_ODO_CAN_CH_REVERSE = 1 /*!< Channel used to decode the vehicle velocity reverse info (if available). */ +} SbgEComCmdOdoCanChannel; + +/* + * Define CAN odometer options bitmask + */ +#define SBG_ECOM_CMD_ODO_CAN_ENABLE (uint16_t)(0x0001 << 0) /*!< Set to enable CAN odometer information decoding. */ +#define SBG_ECOM_CMD_ODO_CAN_ID_EXTENDED (uint16_t)(0x0001 << 1) /*!< Set for a 29 bit extended CAN message, otherwise standard 11 bit */ +#define SBG_ECOM_CMD_ODO_CAN_BIG_ENDIAN (uint16_t)(0x0001 << 2) /*!< Set if the velocity is encoded in big endian, otherwise little endian */ +#define SBG_ECOM_CMD_ODO_CAN_SIGNED (uint16_t)(0x0001 << 3) /*!< Set to interpret the parsed value as signed, otherwise unsigned. */ + +/*! + * Holds all necessary information for CAN Odometer parameter configuration. + * This format is very similar to info contained in a DBC file. + */ +typedef struct _SbgEComCmdOdoCanConf +{ + uint16_t options; /*!< Set of options bit masks such as CAN extended. */ + uint32_t canId; /*!< CAN message ID from which the odometer velocity will be parsed. */ + + size_t startBit; /*!< Index of field MSB in big endian or LSB in little endian within the payload (any value from 0 to 63). */ + size_t dataSize; /*!< Length in bits of the odometer velocity field (any value from 1 to 64 minus dataOffset). */ + + float scale; /*!< Value to multiply the parsed field with to get physical unit^in m.s-1. */ + float offset; /*!< Offset to add on the scaled velocity information in m.s-1 (after applying scale factor). */ + float minValue; /*!< The minimum velocity to consider the message valid in m.s-1 */ + float maxValue; /*!< The maximum velocity to consider the message valid in m.s-1 */ +} SbgEComCmdOdoCanConf; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * For quadrature and/or pulse based odometer, retrieve the configuration. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pOdometerConf Pointer to a SbgEComOdoConf struct to hold configuration of the odometer module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOdoGetConf(SbgEComHandle *pHandle, SbgEComOdoConf *pOdometerConf); + +/*! + * For quadrature and/or pulse base odometer, define the configuration. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pOdometerConf Pointer to a SbgEComOdoConf struct holding configuration for the odometer module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOdoSetConf(SbgEComHandle *pHandle, const SbgEComOdoConf *pOdometerConf); + +/*! + * Retrieve the lever arm applicable for both quadrature or CAN based odometer. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pLeverArm Array of three values, one for each axis. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOdoGetLeverArm(SbgEComHandle *pHandle, float *pLeverArm); + +/*! + * Set the lever arm applicable for both quadrature or CAN based odometer. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pLeverArm Array of three values, one for each axis. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOdoSetLeverArm(SbgEComHandle *pHandle, const float *pLeverArm); + +/*! + * Retrieve the velocity rejection configuration for both quadrature or CAN based odometer. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pRejectConf Pointer to a SbgEComOdoRejectionConf struct to hold rejection configuration of the odometer module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOdoGetRejection(SbgEComHandle *pHandle, SbgEComOdoRejectionConf *pRejectConf); + +/*! + * Set the velocity rejection configuration for both quadrature or CAN based odometer. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pRejectConf Pointer to a SbgEComOdoRejectionConf struct holding rejection configuration for the odometer module. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOdoSetRejection(SbgEComHandle *pHandle, const SbgEComOdoRejectionConf *pRejectConf); + +/*! + * Retrieve the CAN odometer configuration for a specific CAN information channel + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] canChannel The CAN channel to retreive associated DBC configuration. + * \param[out] pOdoCanConf Struct to hold configuration of the CAN odometer. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOdoCanGetConf(SbgEComHandle *pHandle, SbgEComCmdOdoCanChannel canChannel, SbgEComCmdOdoCanConf *pOdoCanConf); + +/*! + * Set the CAN odometer configuration for a specific CAN information channel + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] canChannel The CAN channel to define associated DBC configuration. + * \param[in] pOdoCanConf Struct holding configuration for the CAN odometer. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOdoCanSetConf(SbgEComHandle *pHandle, SbgEComCmdOdoCanChannel canChannel, const SbgEComCmdOdoCanConf *pOdoCanConf); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_ODO_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOutput.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOutput.c new file mode 100644 index 0000000..ba95b85 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOutput.c @@ -0,0 +1,583 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdOutput.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdOutputGetConf(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, SbgEComClass classId, SbgEComMsgId msgId, SbgEComOutputMode *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + uint8_t outputBuffer[5]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Build payload to send + // + sbgStreamBufferInitForWrite(&outputStream, &outputBuffer, sizeof(outputBuffer)); + + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)outputPort); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)msgId); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)classId); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command and the prepared payload + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_OUTPUT_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_OUTPUT_CONF, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_OUTPUT_CONF command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Parse the received payload + // + outputPort = (SbgEComOutputPort)sbgStreamBufferReadUint8LE(&inputStream); + msgId = sbgStreamBufferReadUint8LE(&inputStream); + classId = (SbgEComClass)sbgStreamBufferReadUint8LE(&inputStream); + *pConf = (SbgEComOutputMode)sbgStreamBufferReadUint16LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdOutputSetConf(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, SbgEComClass classId, SbgEComMsgId msgId, SbgEComOutputMode conf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[5]; + SbgStreamBuffer outputStream; + + assert(pHandle); + + // + // Build the payload to send + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)outputPort); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)msgId); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)classId); + sbgStreamBufferWriteUint16LE(&outputStream, (uint16_t)conf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_OUTPUT_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_OUTPUT_CONF, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdOutputClassGetEnable(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, SbgEComClass classId, bool *pEnable) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + uint8_t outputBuffer[3]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pEnable); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Build payload to send + // + sbgStreamBufferInitForWrite(&outputStream, &outputBuffer, sizeof(outputBuffer)); + + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)outputPort); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)classId); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command and the prepared payload + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_OUTPUT_CLASS_ENABLE, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_OUTPUT_CLASS_ENABLE, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a correct answer + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Parse the received payload + // + outputPort = (SbgEComOutputPort)sbgStreamBufferReadUint8LE(&inputStream); + classId = (SbgEComClass)sbgStreamBufferReadUint8LE(&inputStream); + *pEnable = (bool)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdOutputClassSetEnable(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, SbgEComClass classId, bool enable) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[3]; + SbgStreamBuffer outputStream; + + assert(pHandle); + + // + // Build payload to send + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)outputPort); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)classId); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)enable); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_OUTPUT_CLASS_ENABLE, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_OUTPUT_CLASS_ENABLE, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdCanOutputGetConf(SbgEComHandle *pHandle, SbgECanMessageId internalId, SbgEComOutputMode *pMode, uint32_t *pUserId, bool *pExtended) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + uint8_t outputBuffer[2]; + SbgStreamBuffer outputStream; + + + assert(pHandle); + assert(pMode); + assert(pUserId); + assert(pExtended); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Build the payload to send + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + sbgStreamBufferWriteUint16LE(&outputStream, internalId); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_CAN_OUTPUT_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_CAN_OUTPUT_CONF, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a correct answer + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Parse the payload + // + internalId = (SbgECanMessageId)sbgStreamBufferReadUint16LE(&inputStream); + *pMode = (SbgEComOutputMode)sbgStreamBufferReadUint16LE(&inputStream); + *pUserId = sbgStreamBufferReadUint32LE(&inputStream); + *pExtended = (bool)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdCanOutputSetConf(SbgEComHandle *pHandle, SbgECanMessageId internalId, SbgEComOutputMode mode, uint32_t userId, bool extended) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[9]; + SbgStreamBuffer outputStream; + + assert(pHandle); + + // + // Build the payload to send + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + sbgStreamBufferWriteUint16LE(&outputStream, (uint16_t)internalId); + sbgStreamBufferWriteUint16LE(&outputStream, (uint16_t)mode); + sbgStreamBufferWriteUint32LE(&outputStream, userId); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)extended); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_CAN_OUTPUT_CONF, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_CAN_OUTPUT_CONF, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdOutputGetNmeaTalkerId(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, char *pNmeaTalkerId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + uint8_t outputBuffer[1]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pNmeaTalkerId); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Build the payload to send + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + sbgStreamBufferWriteUint8(&outputStream, outputPort); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command with the output port as a 1-byte payload + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_NMEA_TALKER_ID, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_NMEA_TALKER_ID, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_NMEA_TALKER_ID command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + outputPort = (SbgEComOutputPort)sbgStreamBufferReadUint8LE(&inputStream); + pNmeaTalkerId[0] = (char)sbgStreamBufferReadUint8LE(&inputStream); + pNmeaTalkerId[1] = (char)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdOutputSetNmeaTalkerId(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, const char *pNmeaTalkerId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[3]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pNmeaTalkerId); + + // + // Build the payload to send + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)outputPort); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)(pNmeaTalkerId[0])); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)(pNmeaTalkerId[1])); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_NMEA_TALKER_ID, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_NMEA_TALKER_ID, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOutput.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOutput.h new file mode 100644 index 0000000..6c6bdbe --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdOutput.h @@ -0,0 +1,197 @@ +/*! + * \file sbgEComCmdOutput.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief Commands used to setup logs to output over the device interfaces. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_OUTPUT_H +#define SBG_ECOM_CMD_OUTPUT_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Public definitions -// +//----------------------------------------------------------------------// + +/*! + * List of ouput ports available. + */ +typedef enum _SbgEComOutputPort +{ + SBG_ECOM_OUTPUT_PORT_A = 0, /*!< Main output port. */ + SBG_ECOM_OUTPUT_PORT_C = 2, /*!< Secondary output port only available on Ellipse-E devices */ + SBG_ECOM_OUTPUT_PORT_E = 4 /*!< Secondary output port only available on B1 devices */ +} SbgEComOutputPort; + +/*! + * List of output modes available. + */ +typedef enum _SbgEComOutputMode +{ + SBG_ECOM_OUTPUT_MODE_DISABLED = 0, /*!< This output is disabled. */ + SBG_ECOM_OUTPUT_MODE_MAIN_LOOP = 1, /*!< Output the message every main loop (ie 200 Hz). */ + SBG_ECOM_OUTPUT_MODE_DIV_2 = 2, /*!< Output the message every 2 main loops (ie 100 Hz). */ + SBG_ECOM_OUTPUT_MODE_DIV_4 = 4, /*!< Output the message every 4 main loops (ie 50 Hz). */ + SBG_ECOM_OUTPUT_MODE_DIV_5 = 5, /*!< Output the message every 4 main loops (ie 40 Hz). */ + SBG_ECOM_OUTPUT_MODE_DIV_8 = 8, /*!< Output the message every 8 main loops (ie 25 Hz). */ + SBG_ECOM_OUTPUT_MODE_DIV_10 = 10, /*!< Output the message every 10 main loops (ie 20 Hz). */ + SBG_ECOM_OUTPUT_MODE_DIV_20 = 20, /*!< Output the message every 20 main loops (ie 10 Hz). */ + SBG_ECOM_OUTPUT_MODE_DIV_40 = 40, /*!< Output the message every 40 main loops (ie 5 Hz). */ + SBG_ECOM_OUTPUT_MODE_DIV_200 = 200, /*!< Output the message every 200 main loops (ie 1 Hz). */ + SBG_ECOM_OUTPUT_MODE_PPS = 10000, /*!< Output the message on a Pulse Per Second event. */ + SBG_ECOM_OUTPUT_MODE_NEW_DATA = 10001, /*!< Output sent when a new data is available. */ + SBG_ECOM_OUTPUT_MODE_EVENT_IN_A = 10003, /*!< Output the message when a Sync A is received. */ + SBG_ECOM_OUTPUT_MODE_EVENT_IN_B = 10004, /*!< Output the message when a Sync B is received. */ + SBG_ECOM_OUTPUT_MODE_EVENT_IN_C = 10005, /*!< Output the message when a Sync C is received. */ + SBG_ECOM_OUTPUT_MODE_EVENT_IN_D = 10006, /*!< Output the message when a Sync D is received. */ + SBG_ECOM_OUTPUT_MODE_EVENT_IN_E = 10007, /*!< Output the message when a Sync E is received. */ + SBG_ECOM_OUTPUT_MODE_HIGH_FREQ_LOOP = 20001 /*!< Output the message in the 1KHz IMU loop */ +} SbgEComOutputMode; + +/*! + * Defines which monitoring point to use for an output port. + * This feature enabled deporting measurements at a specific monitoring point. + */ +typedef enum _SbgEComOutputMonitoringPoint +{ + SBG_ECOM_OUTPUT_MONITORING_POINT_IMU = 0, /*!< Output measurements at the IMU location. */ + SBG_ECOM_OUTPUT_MONITORING_POINT_COG = 1, /*!< Output measurements at the center of rotation. */ + SBG_ECOM_OUTPUT_MONITORING_POINT_1 = 2, /*!< Output measurements at the user deported location 1 (only for Ekinox and Apogee). */ + SBG_ECOM_OUTPUT_MONITORING_POINT_2 = 3, /*!< Output measurements at the user deported location 2 (only for Ekinox and Apogee). */ + SBG_ECOM_OUTPUT_MONITORING_POINT_3 = 4, /*!< Output measurements at the user deported location 3 (only for Ekinox and Apogee). */ + SBG_ECOM_OUTPUT_MONITORING_NUM /*!< Number of output monitoring points. */ +} SbgEComOutputMonitoringPoint; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Retrieve the configuration of one the message on one of the output interfaces. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] outputPort The output port of the device for the log concerned. + * \param[in] classId The class of the concerned log. + * \param[in] msgId The id of the concerned log. + * \param[out] pMode Pointer to a SbgEComOutputMode to contain the current output mode of the message. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOutputGetConf(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, SbgEComClass classId, SbgEComMsgId msgId, SbgEComOutputMode *pMode); + +/*! + * Set the configuration of one the message on one of the output interfaces. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] outputPort The output port of the device for the log concerned. + * \param[in] classId The class of the concerned log. + * \param[in] msgId The id of the concerned log. + * \param[in] mode New output mode to set. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOutputSetConf(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, SbgEComClass classId, SbgEComMsgId msgId, SbgEComOutputMode mode); + +/*! + * Retrieve the enable of one of the output class message on one of the output interfaces. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] outputPort The output port. + * \param[in] classId The class to enable or disable. + * \param[out] pEnable TRUE to enable message output of this class, FALSE to disable it. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOutputClassGetEnable(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, SbgEComClass classId, bool *pEnable); + +/*! + * Set the enable of one of the output class message on one of the output interfaces. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] outputPort The output port. + * \param[in] classId The class to enable or disable. + * \param[in] enable TRUE to enable message output of this class, FALSE to disable it. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOutputClassSetEnable(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, SbgEComClass classId, bool enable); + +/*! + * Retrieve the configuration of one the message on the CAN interface. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] internalId The internal message id. + * \param[out] pMode Pointer to a SbgEComOutputMode to contain the current output mode of the message. + * \param[out] pUserId The user defined message id. + * \param[out] pExtended TRUE if the user id uses the extended format. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdCanOutputGetConf(SbgEComHandle *pHandle, SbgECanMessageId internalId, SbgEComOutputMode *pMode, uint32_t *pUserId, bool *pExtended); + +/*! + * Set the configuration of one the message on the CAN interface + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] internalId The internal message id. + * \param[in] mode Pointer to a SbgEComOutputMode containing the new output mode of the message. + * \param[in] userId The user defined message id. + * \param[in] extended TRUE if the user id uses the extended format. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdCanOutputSetConf(SbgEComHandle *pHandle, SbgECanMessageId internalId, SbgEComOutputMode mode, uint32_t userId, bool extended); + +/*! + * Retrieve the NMEA talker id of one of the output interfaces. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] outputPort The output port of the device for the log concerned. + * \param[out] pNmeaTalkerId A 2-char array to contain the nmea talker id. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOutputGetNmeaTalkerId(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, char *pNmeaTalkerId); + +/*! + * Set the NMEA talker id of one of the output interfaces. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] outputPort The output port of the device for the log concerned. + * \param[out] pNmeaTalkerId A 2-char array containint the new nmea talker id. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdOutputSetNmeaTalkerId(SbgEComHandle *pHandle, SbgEComOutputPort outputPort, const char *pNmeaTalkerId); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_OUTPUT_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSensor.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSensor.c new file mode 100644 index 0000000..d6fbcf8 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSensor.c @@ -0,0 +1,484 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdSensor.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdSensorSetMotionProfileId(SbgEComHandle *pHandle, SbgEComMotionProfileStdIds modelId) +{ + assert(pHandle); + + return sbgEComCmdGenericSetModelId(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_MOTION_PROFILE_ID, modelId); +} + + +SbgErrorCode sbgEComCmdSensorGetMotionProfileId(SbgEComHandle *pHandle, SbgEComMotionProfileStdIds *pModelId) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t modelIdAsUint; + + assert(pHandle); + assert(pModelId); + + errorCode = sbgEComCmdGenericGetModelId(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_MOTION_PROFILE_ID, &modelIdAsUint); + + if (errorCode == SBG_NO_ERROR) + { + *pModelId = (SbgEComMotionProfileStdIds)modelIdAsUint; + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdSensorGetInitCondition(SbgEComHandle *pHandle, SbgEComInitConditionConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_INIT_PARAMETERS, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_INIT_PARAMETERS, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_INIT_PARAMETERS command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + pConf->latitude = sbgStreamBufferReadDoubleLE(&inputStream); + pConf->longitude = sbgStreamBufferReadDoubleLE(&inputStream); + pConf->altitude = sbgStreamBufferReadDoubleLE(&inputStream); + pConf->year = sbgStreamBufferReadUint16LE(&inputStream); + pConf->month = sbgStreamBufferReadUint8LE(&inputStream); + pConf->day = sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdSensorSetInitCondition(SbgEComHandle *pHandle, const SbgEComInitConditionConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[64]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteDoubleLE(&outputStream, pConf->latitude); + sbgStreamBufferWriteDoubleLE(&outputStream, pConf->longitude); + sbgStreamBufferWriteDoubleLE(&outputStream, pConf->altitude); + sbgStreamBufferWriteUint16LE(&outputStream, (uint16_t)pConf->year); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->month); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->day); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_INIT_PARAMETERS, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_INIT_PARAMETERS, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdSensorGetAidingAssignment(SbgEComHandle *pHandle, SbgEComAidingAssignConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pConf); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIDING_ASSIGNMENT, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIDING_ASSIGNMENT, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_AIDING_ASSIGNMENT command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + pConf->gps1Port = (SbgEComModulePortAssignment)sbgStreamBufferReadUint8LE(&inputStream); + pConf->gps1Sync = (SbgEComModuleSyncAssignment)sbgStreamBufferReadUint8LE(&inputStream); + + sbgStreamBufferSeek(&inputStream, 4*sizeof(uint8_t), SB_SEEK_CUR_INC); /*!< Reserved fields to ignore */ + + pConf->dvlPort = (SbgEComModulePortAssignment)sbgStreamBufferReadUint8LE(&inputStream); + pConf->dvlSync = (SbgEComModuleSyncAssignment)sbgStreamBufferReadUint8LE(&inputStream); + + pConf->rtcmPort = (SbgEComModulePortAssignment)sbgStreamBufferReadUint8LE(&inputStream); + pConf->airDataPort = (SbgEComModulePortAssignment)sbgStreamBufferReadUint8LE(&inputStream); + pConf->odometerPinsConf = (SbgEComOdometerPinAssignment)sbgStreamBufferReadUint8LE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdSensorSetAidingAssignment(SbgEComHandle *pHandle, const SbgEComAidingAssignConf *pConf) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[16]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pConf); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->gps1Port); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->gps1Sync); + + // + // Skip the 4 reserved bytes + // + sbgStreamBufferWriteUint8LE(&outputStream, 0); + sbgStreamBufferWriteUint8LE(&outputStream, 0); + sbgStreamBufferWriteUint8LE(&outputStream, 0); + sbgStreamBufferWriteUint8LE(&outputStream, 0); + + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->dvlPort); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->dvlSync); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->rtcmPort); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->airDataPort); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pConf->odometerPinsConf); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIDING_ASSIGNMENT, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_AIDING_ASSIGNMENT, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdSensorGetAlignmentAndLeverArm(SbgEComHandle *pHandle, SbgEComSensorAlignmentInfo *pAlignConf, float *pLeverArm) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + uint32_t trial; + + assert(pHandle); + assert(pAlignConf); + assert(pLeverArm); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command only since this is a no-payload command + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_IMU_ALIGNMENT_LEVER_ARM, NULL, 0); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComReceiveCmd2(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_IMU_ALIGNMENT_LEVER_ARM, &receivedPayload, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a SBG_ECOM_CMD_IMU_ALIGNMENT command + // + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Initialize stream buffer to read parameters + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read parameters + // + pAlignConf->axisDirectionX = (SbgEComAxisDirection)sbgStreamBufferReadUint8LE(&inputStream); + pAlignConf->axisDirectionY = (SbgEComAxisDirection)sbgStreamBufferReadUint8LE(&inputStream); + pAlignConf->misRoll = sbgStreamBufferReadFloatLE(&inputStream); + pAlignConf->misPitch = sbgStreamBufferReadFloatLE(&inputStream); + pAlignConf->misYaw = sbgStreamBufferReadFloatLE(&inputStream); + pLeverArm[0] = sbgStreamBufferReadFloatLE(&inputStream); + pLeverArm[1] = sbgStreamBufferReadFloatLE(&inputStream); + pLeverArm[2] = sbgStreamBufferReadFloatLE(&inputStream); + + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +SbgErrorCode sbgEComCmdSensorSetAlignmentAndLeverArm(SbgEComHandle *pHandle, const SbgEComSensorAlignmentInfo *pAlignConf, const float *pLeverArm) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[32]; + SbgStreamBuffer outputStream; + + assert(pHandle); + assert(pAlignConf); + assert(pLeverArm); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Init stream buffer for output + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload + // + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pAlignConf->axisDirectionX); + sbgStreamBufferWriteUint8LE(&outputStream, (uint8_t)pAlignConf->axisDirectionY); + sbgStreamBufferWriteFloatLE(&outputStream, pAlignConf->misRoll); + sbgStreamBufferWriteFloatLE(&outputStream, pAlignConf->misPitch); + sbgStreamBufferWriteFloatLE(&outputStream, pAlignConf->misYaw); + sbgStreamBufferWriteFloatLE(&outputStream, pLeverArm[0]); + sbgStreamBufferWriteFloatLE(&outputStream, pLeverArm[1]); + sbgStreamBufferWriteFloatLE(&outputStream, pLeverArm[2]); + + // + // Send the payload over ECom + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_IMU_ALIGNMENT_LEVER_ARM, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_IMU_ALIGNMENT_LEVER_ARM, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSensor.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSensor.h new file mode 100644 index 0000000..218c671 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSensor.h @@ -0,0 +1,236 @@ +/*! + * \file sbgEComCmdSensor.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief Motion profile, aiding assignement & sensor installation commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_SENSOR_H +#define SBG_ECOM_CMD_SENSOR_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +// Local headers +#include "sbgEComCmdCommon.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Sensor definitions -// +//----------------------------------------------------------------------// + +/*! + * Ports available for the modules. + */ +typedef enum _SbgEComModulePortAssignment +{ + SBG_ECOM_MODULE_PORT_A = 0, /*!< Module connected on PORT_A. */ + SBG_ECOM_MODULE_PORT_B = 1, /*!< Module connected on PORT_B. */ + SBG_ECOM_MODULE_PORT_C = 2, /*!< Module connected on PORT_C. */ + SBG_ECOM_MODULE_PORT_D = 3, /*!< Module connected on PORT_D. */ + SBG_ECOM_MODULE_PORT_E = 4, /*!< Module connected on PORT_E. */ + SBG_ECOM_MODULE_INTERNAL = 5, /*!< Module is connected internally. */ + SBG_ECOM_MODULE_DISABLED = 0xFF /*!< Module is disabled. */ +} SbgEComModulePortAssignment; + +/*! + * Synchronization signals available for the modules. + */ +typedef enum _SbgEComModuleSyncAssignment +{ + SBG_ECOM_MODULE_SYNC_DISABLED = 0, /*!< Module is disabled. */ + SBG_ECOM_MODULE_SYNC_IN_A = 1, /*!< Synchronization is done using SYNC_IN_A pin. */ + SBG_ECOM_MODULE_SYNC_IN_B = 2, /*!< Synchronization is done using SYNC_IN_B pin. */ + SBG_ECOM_MODULE_SYNC_IN_C = 3, /*!< Synchronization is done using SYNC_IN_C pin. */ + SBG_ECOM_MODULE_SYNC_IN_D = 4, /*!< Synchronization is done using SYNC_IN_D pin. */ + SBG_ECOM_MODULE_SYNC_INTERNAL = 5, /*!< Synchronization is internal. */ + SBG_ECOM_MODULE_SYNC_OUT_A = 6, /*!< Synchronization signal is output on SYNC_OUT_A. */ + SBG_ECOM_MODULE_SYNC_OUT_B = 7, /*!< Synchronization signal is output on SYNC_OUT_B. */ +} SbgEComModuleSyncAssignment; + +/*! + * List of configurations available for the odometer. + */ +typedef enum _SbgEComOdometerPinAssignment +{ + SBG_ECOM_MODULE_ODO_DISABLED = 0, /*!< Odometer is disabled. */ + SBG_ECOM_MODULE_ODO_A = 1, /*!< Odometer connected only to ODO_A (unidirectional).. */ + SBG_ECOM_MODULE_ODO_A_B = 2, /*!< Odometer connected to both ODO_A (signal A) and ODO_B (Signal B or direction) for bidirectional odometer.. */ + SBG_ECOM_MODULE_ODO_CAN = 3, /*!< Vehicle odometer using CAN (OBD-II). */ +} SbgEComOdometerPinAssignment; + +/*! + * This enum defines the different motion profile IDs available in standard + */ +typedef enum _SbgEComMotionProfileStdIds +{ + SBG_ECOM_MOTION_PROFILE_GENERAL_PURPOSE = 1, /*!< Should be used as a default when other profiles do not apply */ + SBG_ECOM_MOTION_PROFILE_AUTOMOTIVE = 2, /*!< Dedicated to car applications with strict lateral velocity constraints. */ + SBG_ECOM_MOTION_PROFILE_MARINE = 3, /*!< Used in marine and underwater applications */ + SBG_ECOM_MOTION_PROFILE_AIRPLANE = 4, /*!< For fixed wings aircraft */ + SBG_ECOM_MOTION_PROFILE_HELICOPTER = 5, /*!< For rotary wing aircraft */ + SBG_ECOM_MOTION_PROFILE_PEDESTRIAN = 6, /*!< Pedestrian applications using foot odometry */ + SBG_ECOM_MOTION_PROFILE_UAV_ROTARY_WING = 7, /*!< For rotary wing UAVs that have low dynamics */ + SBG_ECOM_MOTION_PROFILE_HEAVY_MACHINERY = 8, /*!< For vibrating applications with low dynamics and no specific travel direction */ + SBG_ECOM_MOTION_PROFILE_STATIC = 9, /*!< Static motion profile that delivers stable results for 27/7 operations. */ + SBG_ECOM_MOTION_PROFILE_TRUCK = 10, /*!< Truck applications with medium lateral velocity constraints. */ + SBG_ECOM_MOTION_PROFILE_RAILWAY = 11 /*!< Train applications with relaxed lateral velocity constraints. */ +} SbgEComMotionProfileStdIds; + +//----------------------------------------------------------------------// +//- Event configurations -// +//----------------------------------------------------------------------// + +/*! + * Helper structure for module assignments + */ +typedef struct _SbgEComAidingAssignConf +{ + SbgEComModulePortAssignment gps1Port; /*!< GNSS module port assignment. */ + SbgEComModuleSyncAssignment gps1Sync; /*!< GNSS module sync assignment. */ + SbgEComModulePortAssignment dvlPort; /*!< Port on which the DVL is connected */ + SbgEComModuleSyncAssignment dvlSync; /*!< Optional sync signal that could be used to time stamp the DVL data. */ + SbgEComModulePortAssignment rtcmPort; /*!< RTCM input port assignment for IGNG-N DGPS. */ + SbgEComModulePortAssignment airDataPort; /*!< Port on which Air Data aiding is connected. */ + SbgEComOdometerPinAssignment odometerPinsConf; /*!< Odometer module pin assignment. */ +} SbgEComAidingAssignConf; + +/*! + * Helper structure for sensor alignment details + */ +typedef struct _SbgEComSensorAlignmentInfo +{ + SbgEComAxisDirection axisDirectionX; /*!< Sensor X axis direction in vehicle */ + SbgEComAxisDirection axisDirectionY; /*!< Sensor Y axis direction in vehicle */ + float misRoll; /*!< Roll angle fine misalignment in rad */ + float misPitch; /*!< Pitch angle fine misalignment in rad */ + float misYaw; /*!< Yaw angle fine misalignment in rad */ +} SbgEComSensorAlignmentInfo; + +/*! + * Helper structure for sensor Initial condition details + */ +typedef struct _SbgEComInitConditionConf +{ + double latitude; /*!< Initial latitude in ° */ + double longitude; /*!< Initial longitude in ° */ + double altitude; /*!< Initial altitude above MSL in meters */ + uint16_t year; /*!< Initial Year */ + uint8_t month; /*!< Initial month */ + uint8_t day; /*!< Initial day */ +} SbgEComInitConditionConf; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Set the motion profile id used to tune the Kalman Filter to a specific application + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] modelId Motion profile id to set + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSensorSetMotionProfileId(SbgEComHandle *pHandle, SbgEComMotionProfileStdIds modelId); + +/*! + * Retrieve the motion profile id. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pModelId Retrieved motion profile id + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSensorGetMotionProfileId(SbgEComHandle *pHandle, SbgEComMotionProfileStdIds *pModelId); + +/*! + * Retrieve the initial conditions settings. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pConf Pointer to a SbgEComInitConditionConf to contain the current initial conditions settings. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSensorGetInitCondition(SbgEComHandle *pHandle, SbgEComInitConditionConf *pConf); + +/*! + * Set the initial condition configuration. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pConf Pointer to a SbgEComInitConditionConf containing the new initial condition configuration. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSensorSetInitCondition(SbgEComHandle *pHandle, const SbgEComInitConditionConf *pConf); + +/*! + * Retrieve the assignment of the aiding sensors. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pConf Pointer to a SbgEComAidingAssignConf to contain the current assignment of the aiding sensors. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSensorGetAidingAssignment(SbgEComHandle *pHandle, SbgEComAidingAssignConf *pConf); + +/*! + * Set the assignment of the aiding sensors. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pConf Pointer to a SbgEComAidingAssignConf containing the new assignment of the aiding sensors. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSensorSetAidingAssignment(SbgEComHandle *pHandle, const SbgEComAidingAssignConf *pConf); + +/*! + * Retrieve the alignment and lever arm configuration of the sensor. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[out] pAlignConf Pointer to a SbgEComSensorAlignmentInfo struct to hold alignment configuration of the sensor. + * \param[out] pLeverArm Pointer to a table to contain lever arm X, Y, Z components in meters. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSensorGetAlignmentAndLeverArm(SbgEComHandle *pHandle, SbgEComSensorAlignmentInfo *pAlignConf, float *pLeverArm); + +/*! + * Set the alignment and lever arm configuration of the sensor. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pAlignConf Pointer to a SbgEComSensorAlignmentInfo struct holding alignment configuration for the sensor. + * \param[in] pLeverArm Pointer to a table containing lever arm X, Y, Z components in meters. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSensorSetAlignmentAndLeverArm(SbgEComHandle *pHandle, const SbgEComSensorAlignmentInfo *pAlignConf, const float *pLeverArm); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_SENSOR_H diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSettings.c b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSettings.c new file mode 100644 index 0000000..17c9f3d --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSettings.c @@ -0,0 +1,89 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include +#include + +// Local headers +#include "sbgEComCmdCommon.h" +#include "sbgEComCmdSettings.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComCmdSettingsAction(SbgEComHandle *pHandle, SbgEComSettingsAction action) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + uint32_t trial; + uint8_t outputBuffer[1]; + SbgStreamBuffer outputStream; + + assert(pHandle); + + // + // Build the payload to send + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + sbgStreamBufferWriteUint8(&outputStream, action); + + // + // Send the command three times + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send the command and the action + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SETTINGS_ACTION, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + // + // Make sure that the command has been sent + // + if (errorCode == SBG_NO_ERROR) + { + // + // Try to read the device answer for 500 ms + // + errorCode = sbgEComWaitForAck(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_SETTINGS_ACTION, pHandle->cmdDefaultTimeOut); + + // + // Test if we have received a valid ACK + // + if (errorCode == SBG_NO_ERROR) + { + // + // The command has been executed successfully so return + // + break; + } + } + else + { + // + // We have a write error so exit the try loop + // + break; + } + } + + return errorCode; +} + +SbgErrorCode sbgEComCmdImportSettings(SbgEComHandle *pHandle, const void *pBuffer, size_t size) +{ + // + // Call function that handle data transfer + // + return sbgEComTransferSend(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_IMPORT_SETTINGS, pBuffer, size); +} + +SbgErrorCode sbgEComCmdExportSettings(SbgEComHandle *pHandle, void *pBuffer, size_t *pSize, size_t maxSize) +{ + // + // Call function that handle data transfer + // + return sbgEComTransferReceive(pHandle, SBG_ECOM_CLASS_LOG_CMD_0, SBG_ECOM_CMD_EXPORT_SETTINGS, pBuffer, pSize, maxSize); +} diff --git a/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSettings.h b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSettings.h new file mode 100644 index 0000000..9f82ca1 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/commands/sbgEComCmdSettings.h @@ -0,0 +1,105 @@ +/*! + * \file sbgEComCmdSettings.h + * \ingroup commands + * \author SBG Systems + * \date 11 June 2014 + * + * \brief Import/export/save settings commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_CMD_SETTINGS_H +#define SBG_ECOM_CMD_SETTINGS_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Settings action definition -// +//----------------------------------------------------------------------// + +/*! + * Defintion of all the settings actions available. + */ +typedef enum _SbgEComSettingsAction +{ + SBG_ECOM_REBOOT_ONLY = 0, /*!< Only reboot the device. */ + SBG_ECOM_SAVE_SETTINGS = 1, /*!< Save the settings to non-volatile memory and then reboot the device. */ + SBG_ECOM_RESTORE_DEFAULT_SETTINGS = 2 /*!< Restore default settings, save them to non-volatile memory and reboot the device. */ +} SbgEComSettingsAction; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Send a command to execute a specific system action to reboot/save/restore default settings. + * + * Execute one of the available settings action: + * - SBG_ECOM_REBOOT_ONLY : Only reboot the device. + * - SBG_ECOM_SAVE_SETTINGS : Save the settings to non-volatile memory and then reboot the device. + * - SBG_ECOM_RESTORE_DEFAULT_SETTINGS : Restore default settings, save them to non-volatile memory and reboot the device. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] action One of the available SbgEComSettingsAction. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdSettingsAction(SbgEComHandle *pHandle, SbgEComSettingsAction action); + +/*! + * Send a complete set of settings to the device and store them into the FLASH memory. + * + * The device will reboot automatically to use the new settings. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pBuffer Read only buffer containing the settings. + * \param[in] size Size of the buffer. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdImportSettings(SbgEComHandle *pHandle, const void *pBuffer, size_t size); + +/*! + * Retrieve a complete set of settings from the device as a buffer. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pBuffer Allocated buffer that can hold the received settings. + * \param[out] pSize The number of bytes that have been stored into pBuffer. + * \param[in] maxSize The maximum buffer size in bytes that can be stored into pBuffer. + * \return SBG_NO_ERROR if the command has been executed successfully. + */ +SbgErrorCode sbgEComCmdExportSettings(SbgEComHandle *pHandle, void *pBuffer, size_t *pSize, size_t maxSize); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_CMD_SETTINGS_H diff --git a/crates/sbg-rs/sbgECom/src/defs/sbgEComDefsGnss.c b/crates/sbg-rs/sbgECom/src/defs/sbgEComDefsGnss.c new file mode 100644 index 0000000..b49c283 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/defs/sbgEComDefsGnss.c @@ -0,0 +1,389 @@ +// sbgCommonLib headers +#include + +// Local headers +#include "sbgEComDefsGnss.h" + +//----------------------------------------------------------------------// +//- Private definitions -// +//----------------------------------------------------------------------// + +/*! + * GNSS signal descriptor. + */ +typedef struct _SbgEComSignalIdDesc +{ + SbgEComSignalId id; /*!< Signal ID. */ + const char *pName; /*!< Corresponding NULL terminated C string. */ +} SbgEComSignalIdDesc; + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +SbgEComConstellationId sbgEComGetConstellationFromSignalId(SbgEComSignalId signalId) +{ + SbgEComConstellationId constellationId = SBG_ECOM_CONSTELLATION_ID_UNKNOWN; + + // + // Don't use a default catch to explicitly handle ALL enum values + // + switch (signalId) + { + case SBG_ECOM_SIGNAL_ID_UNKNOWN: + constellationId = SBG_ECOM_CONSTELLATION_ID_UNKNOWN; + break; + + // + // GPS constellation + // + case SBG_ECOM_SIGNAL_ID_GPS_L1C_DP: + case SBG_ECOM_SIGNAL_ID_GPS_L1C_D: + case SBG_ECOM_SIGNAL_ID_GPS_L1C_P: + case SBG_ECOM_SIGNAL_ID_GPS_L1_W: + case SBG_ECOM_SIGNAL_ID_GPS_L1_CA: + case SBG_ECOM_SIGNAL_ID_GPS_L1P: + case SBG_ECOM_SIGNAL_ID_GPS_L1_PY: + case SBG_ECOM_SIGNAL_ID_GPS_L1M: + case SBG_ECOM_SIGNAL_ID_GPS_L2C_ML: + case SBG_ECOM_SIGNAL_ID_GPS_L2C_L: + case SBG_ECOM_SIGNAL_ID_GPS_L2_SEMICL: + case SBG_ECOM_SIGNAL_ID_GPS_L2_W: + case SBG_ECOM_SIGNAL_ID_GPS_L2_CA: + case SBG_ECOM_SIGNAL_ID_GPS_L2C_M: + case SBG_ECOM_SIGNAL_ID_GPS_L2_PY: + case SBG_ECOM_SIGNAL_ID_GPS_L2M: + case SBG_ECOM_SIGNAL_ID_GPS_L2P: + case SBG_ECOM_SIGNAL_ID_GPS_L5_IQ: + case SBG_ECOM_SIGNAL_ID_GPS_L5_I: + case SBG_ECOM_SIGNAL_ID_GPS_L5_Q: + constellationId = SBG_ECOM_CONSTELLATION_ID_GPS; + break; + + // + // GLONASS constellation + // + case SBG_ECOM_SIGNAL_ID_GLONASS_G1_P: + case SBG_ECOM_SIGNAL_ID_GLONASS_G1_CA: + case SBG_ECOM_SIGNAL_ID_GLONASS_G2_P: + case SBG_ECOM_SIGNAL_ID_GLONASS_G2_CA: + case SBG_ECOM_SIGNAL_ID_GLONASS_G3_I: + case SBG_ECOM_SIGNAL_ID_GLONASS_G3_Q: + case SBG_ECOM_SIGNAL_ID_GLONASS_G3_IQ: + constellationId = SBG_ECOM_CONSTELLATION_ID_GLONASS; + break; + + // + // Galileo constellation + // + case SBG_ECOM_SIGNAL_ID_GALILEO_E1_BC: + case SBG_ECOM_SIGNAL_ID_GALILEO_E1_C: + case SBG_ECOM_SIGNAL_ID_GALILEO_E1_B: + case SBG_ECOM_SIGNAL_ID_GALILEO_E1_A: + case SBG_ECOM_SIGNAL_ID_GALILEO_E1_ABC: + case SBG_ECOM_SIGNAL_ID_GALILEO_E5B_IQ: + case SBG_ECOM_SIGNAL_ID_GALILEO_E5B_I: + case SBG_ECOM_SIGNAL_ID_GALILEO_E5B_Q: + case SBG_ECOM_SIGNAL_ID_GALILEO_E5A_IQ: + case SBG_ECOM_SIGNAL_ID_GALILEO_E5A_I: + case SBG_ECOM_SIGNAL_ID_GALILEO_E5A_Q: + case SBG_ECOM_SIGNAL_ID_GALILEO_E5_IQ: + case SBG_ECOM_SIGNAL_ID_GALILEO_E5_I: + case SBG_ECOM_SIGNAL_ID_GALILEO_E5_Q: + case SBG_ECOM_SIGNAL_ID_GALILEO_E6_BC: + case SBG_ECOM_SIGNAL_ID_GALILEO_E6_C: + case SBG_ECOM_SIGNAL_ID_GALILEO_E6_B: + case SBG_ECOM_SIGNAL_ID_GALILEO_E6_ABC: + case SBG_ECOM_SIGNAL_ID_GALILEO_E6_A: + constellationId = SBG_ECOM_CONSTELLATION_ID_GALILEO; + break; + + // + // BeiDou constellation + // + case SBG_ECOM_SIGNAL_ID_BEIDOU_B1IQ: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B1I: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B1Q: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_P: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_DP: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_D: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_P: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_DP: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_D: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2IQ: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2I: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_P: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_DP: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_D: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2Q: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_P: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_DP: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_D: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_P: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_DP: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_D: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B3IQ: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B3I: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B3Q: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_D: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_P: + case SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_DP: + constellationId = SBG_ECOM_CONSTELLATION_ID_BEIDOU; + break; + + // + // QZSS constellation + // + case SBG_ECOM_SIGNAL_ID_QZSS_L1C_DP: + case SBG_ECOM_SIGNAL_ID_QZSS_L1C_D: + case SBG_ECOM_SIGNAL_ID_QZSS_L1C_P: + case SBG_ECOM_SIGNAL_ID_QZSS_L1_CA: + case SBG_ECOM_SIGNAL_ID_QZSS_L1_SAIF: + case SBG_ECOM_SIGNAL_ID_QZSS_L1_SB: + case SBG_ECOM_SIGNAL_ID_QZSS_L2C_ML: + case SBG_ECOM_SIGNAL_ID_QZSS_L2C_L: + case SBG_ECOM_SIGNAL_ID_QZSS_L2C_M: + case SBG_ECOM_SIGNAL_ID_QZSS_L5_IQ: + case SBG_ECOM_SIGNAL_ID_QZSS_L5_I: + case SBG_ECOM_SIGNAL_ID_QZSS_L5_Q: + case SBG_ECOM_SIGNAL_ID_QZSS_L5S_IQ: + case SBG_ECOM_SIGNAL_ID_QZSS_L5S_I: + case SBG_ECOM_SIGNAL_ID_QZSS_L5S_Q: + case SBG_ECOM_SIGNAL_ID_QZSS_L6_P: + case SBG_ECOM_SIGNAL_ID_QZSS_L6_DP: + case SBG_ECOM_SIGNAL_ID_QZSS_L6_D: + case SBG_ECOM_SIGNAL_ID_QZSS_L6_E: + case SBG_ECOM_SIGNAL_ID_QZSS_L6_DE: + constellationId = SBG_ECOM_CONSTELLATION_ID_QZSS; + break; + + // + // SBAS system + // + case SBG_ECOM_SIGNAL_ID_SBAS_L1_CA: + case SBG_ECOM_SIGNAL_ID_SBAS_L5_I: + case SBG_ECOM_SIGNAL_ID_SBAS_L5_Q: + case SBG_ECOM_SIGNAL_ID_SBAS_L5_IQ: + constellationId = SBG_ECOM_CONSTELLATION_ID_SBAS; + break; + + // + // IRNSS constellation + // + case SBG_ECOM_SIGNAL_ID_IRNSS_L5_A: + case SBG_ECOM_SIGNAL_ID_IRNSS_L5_B: + case SBG_ECOM_SIGNAL_ID_IRNSS_L5_C: + case SBG_ECOM_SIGNAL_ID_IRNSS_L5_BC: + case SBG_ECOM_SIGNAL_ID_IRNSS_S9_A: + case SBG_ECOM_SIGNAL_ID_IRNSS_S9_B: + case SBG_ECOM_SIGNAL_ID_IRNSS_S9_C: + case SBG_ECOM_SIGNAL_ID_IRNSS_S9_BC: + constellationId = SBG_ECOM_CONSTELLATION_ID_IRNSS; + break; + + // + // L-Band system + // + case SBG_ECOM_SIGNAL_ID_LBAND: + constellationId = SBG_ECOM_CONSTELLATION_ID_LBAND; + break; + } + + return constellationId; +} + +bool sbgEComSignalIdIsValid(uint8_t signalId) +{ + if ( (signalId == SBG_ECOM_SIGNAL_ID_UNKNOWN) || + (sbgEComGetConstellationFromSignalId(signalId) != SBG_ECOM_CONSTELLATION_ID_UNKNOWN)) + { + return true; + } + else + { + return false; + } +} + +const char *sbgEComSignalToStr(SbgEComSignalId signalId) +{ + static const SbgEComSignalIdDesc signalIdDesc[] = + { + { SBG_ECOM_SIGNAL_ID_UNKNOWN, "unknown" }, + + { SBG_ECOM_SIGNAL_ID_GPS_L1C_DP, "gpsL1C_DP" }, + { SBG_ECOM_SIGNAL_ID_GPS_L1C_D, "gpsL1C_D" }, + { SBG_ECOM_SIGNAL_ID_GPS_L1C_P, "gpsL1C_P" }, + { SBG_ECOM_SIGNAL_ID_GPS_L1_W, "gpsL1_W" }, + { SBG_ECOM_SIGNAL_ID_GPS_L1_CA, "gpsL1_CA" }, + { SBG_ECOM_SIGNAL_ID_GPS_L1P, "gpsL1P" }, + { SBG_ECOM_SIGNAL_ID_GPS_L1_PY, "gpsL1_PY" }, + { SBG_ECOM_SIGNAL_ID_GPS_L1M, "gpsL1M" }, + { SBG_ECOM_SIGNAL_ID_GPS_L2C_ML, "gpsL2C_ML" }, + { SBG_ECOM_SIGNAL_ID_GPS_L2C_L, "gpsL2C_L" }, + { SBG_ECOM_SIGNAL_ID_GPS_L2_SEMICL, "gpsL2_SEMICL" }, + { SBG_ECOM_SIGNAL_ID_GPS_L2_W, "gpsL2_W" }, + { SBG_ECOM_SIGNAL_ID_GPS_L2_CA, "gpsL2_CA" }, + { SBG_ECOM_SIGNAL_ID_GPS_L2C_M, "gpsL2C_M" }, + { SBG_ECOM_SIGNAL_ID_GPS_L2_PY, "gpsL2_PY" }, + { SBG_ECOM_SIGNAL_ID_GPS_L2M, "gpsL2M" }, + { SBG_ECOM_SIGNAL_ID_GPS_L2P, "gpsL2P" }, + { SBG_ECOM_SIGNAL_ID_GPS_L5_IQ, "gpsL5_IQ" }, + { SBG_ECOM_SIGNAL_ID_GPS_L5_I, "gpsL5_I" }, + { SBG_ECOM_SIGNAL_ID_GPS_L5_Q, "gpsL5_Q" }, + + { SBG_ECOM_SIGNAL_ID_GLONASS_G1_P, "glonassG1_P" }, + { SBG_ECOM_SIGNAL_ID_GLONASS_G1_CA, "glonassG1_CA" }, + { SBG_ECOM_SIGNAL_ID_GLONASS_G2_P, "glonassG2_P" }, + { SBG_ECOM_SIGNAL_ID_GLONASS_G2_CA, "glonassG2_CA" }, + { SBG_ECOM_SIGNAL_ID_GLONASS_G3_I, "glonassG3_I" }, + { SBG_ECOM_SIGNAL_ID_GLONASS_G3_Q, "glonassG3_Q" }, + { SBG_ECOM_SIGNAL_ID_GLONASS_G3_IQ, "glonassG3_IQ" }, + + { SBG_ECOM_SIGNAL_ID_GALILEO_E1_BC, "galileoE1_BC" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E1_C, "galileoE1_C" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E1_B, "galileoE1_B" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E1_A, "galileoE1_A" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E1_ABC, "galileoE1_ABC" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E5B_IQ, "galileoE5B_IQ" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E5B_I, "galileoE5B_I" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E5B_Q, "galileoE5B_Q" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E5A_IQ, "galileoE5A_IQ" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E5A_I, "galileoE5A_I" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E5A_Q, "galileoE5A_Q" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E5_IQ, "galileoE5_IQ" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E5_I, "galileoE5_I" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E5_Q, "galileoE5_Q" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E6_BC, "galileoE6_BC" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E6_C, "galileoE6_C" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E6_B, "galileoE6_B" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E6_ABC, "galileoE6_ABC" }, + { SBG_ECOM_SIGNAL_ID_GALILEO_E6_A, "galileoE6_A" }, + + { SBG_ECOM_SIGNAL_ID_BEIDOU_B1IQ, "beidouB1IQ" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B1I, "beidouB1I" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B1Q, "beidouB1Q" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_P, "beidouB1C_P" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_DP, "beidouB1C_DP" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_D, "beidouB1C_D" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_P, "beidouB1A_P" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_DP, "beidouB1A_DP" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_D, "beidouB1A_D" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2IQ, "beidouB2IQ" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2I, "beidouB2I" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_P, "beidouB2A_P" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_DP, "beidouB2A_DP" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_D, "beidouB2A_D" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2Q, "beidouB2Q" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_P, "beidouB2B_P" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_DP, "beidouB2B_DP" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_D, "beidouB2B_D" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_P, "beidouB2AB_P" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_DP, "beidouB2AB_DP" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_D, "beidouB2AB_D" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B3IQ, "beidouB3IQ" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B3I, "beidouB3I" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B3Q, "beidouB3Q" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_D, "beidouB3A_D" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_P, "beidouB3A_P" }, + { SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_DP, "beidouB3A_DP" }, + + { SBG_ECOM_SIGNAL_ID_QZSS_L1C_DP, "qzssL1C_DP" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L1C_D, "qzssL1C_D" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L1C_P, "qzssL1C_P" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L1_CA, "qzssL1_CA" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L1_SAIF, "qzssL1_SAIF" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L1_SB, "qzssL1_SB" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L2C_ML, "qzssL2C_ML" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L2C_L, "qzssL2C_L" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L2C_M, "qzssL2C_M" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L5_IQ, "qzssL5_IQ" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L5_I, "qzssL5_I" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L5_Q, "qzssL5_Q" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L5S_IQ, "qzssL5S_IQ" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L5S_I, "qzssL5S_I" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L5S_Q, "qzssL5S_Q" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L6_P, "qzssL6_P" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L6_DP, "qzssL6_DP" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L6_D, "qzssL6_D" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L6_E, "qzssL6_E" }, + { SBG_ECOM_SIGNAL_ID_QZSS_L6_DE, "qzssL6_DE" }, + + { SBG_ECOM_SIGNAL_ID_SBAS_L1_CA, "sbasL1_CA" }, + { SBG_ECOM_SIGNAL_ID_SBAS_L5_I, "sbasL5_I" }, + { SBG_ECOM_SIGNAL_ID_SBAS_L5_Q, "sbasL5_Q" }, + { SBG_ECOM_SIGNAL_ID_SBAS_L5_IQ, "sbasL5_IQ" }, + + { SBG_ECOM_SIGNAL_ID_IRNSS_L5_A, "irnssL5_A" }, + { SBG_ECOM_SIGNAL_ID_IRNSS_L5_B, "irnssL5_B" }, + { SBG_ECOM_SIGNAL_ID_IRNSS_L5_C, "irnssL5_C" }, + { SBG_ECOM_SIGNAL_ID_IRNSS_L5_BC, "irnssL5_BC" }, + { SBG_ECOM_SIGNAL_ID_IRNSS_S9_A, "irnssS9_A" }, + { SBG_ECOM_SIGNAL_ID_IRNSS_S9_B, "irnssS9_B" }, + { SBG_ECOM_SIGNAL_ID_IRNSS_S9_C, "irnssS9_C" }, + { SBG_ECOM_SIGNAL_ID_IRNSS_S9_BC, "irnssS9_BC" }, + + { SBG_ECOM_SIGNAL_ID_LBAND, "lband" } + }; + + for (size_t i = 0; i < SBG_ARRAY_SIZE(signalIdDesc); i++) + { + if (signalIdDesc[i].id == signalId) + { + return signalIdDesc[i].pName; + } + } + + // + // Enforce that the first item is the unknown signal ID and return it + // + assert(signalIdDesc[0].id == SBG_ECOM_SIGNAL_ID_UNKNOWN); + return signalIdDesc[0].pName; +} + +bool sbgEComConstellationIdIsValid(uint8_t constellationId) +{ + bool constellationIdIsValid = false; + + switch (constellationId) + { + case SBG_ECOM_CONSTELLATION_ID_UNKNOWN: + case SBG_ECOM_CONSTELLATION_ID_GPS: + case SBG_ECOM_CONSTELLATION_ID_QZSS: + case SBG_ECOM_CONSTELLATION_ID_GLONASS: + case SBG_ECOM_CONSTELLATION_ID_GALILEO: + case SBG_ECOM_CONSTELLATION_ID_BEIDOU: + case SBG_ECOM_CONSTELLATION_ID_SBAS: + case SBG_ECOM_CONSTELLATION_ID_IRNSS: + case SBG_ECOM_CONSTELLATION_ID_LBAND: + constellationIdIsValid = true; + break; + } + + return constellationIdIsValid; +} + +const char *sbgEComConstellationToStr(SbgEComConstellationId constellationId) +{ + static const char *enumToStrLut[] = + { + [SBG_ECOM_CONSTELLATION_ID_UNKNOWN] = "unknown", + [SBG_ECOM_CONSTELLATION_ID_GPS] = "gps", + [SBG_ECOM_CONSTELLATION_ID_GLONASS] = "glonass", + [SBG_ECOM_CONSTELLATION_ID_GALILEO] = "galileo", + [SBG_ECOM_CONSTELLATION_ID_BEIDOU] = "beidou", + [SBG_ECOM_CONSTELLATION_ID_QZSS] = "qzss", + [SBG_ECOM_CONSTELLATION_ID_SBAS] = "sbas", + [SBG_ECOM_CONSTELLATION_ID_IRNSS] = "irnss", + [SBG_ECOM_CONSTELLATION_ID_LBAND] = "lband", + }; + + if (constellationId < SBG_ARRAY_SIZE(enumToStrLut)) + { + return enumToStrLut[constellationId]; + } + else + { + return enumToStrLut[SBG_ECOM_CONSTELLATION_ID_UNKNOWN]; + } +} diff --git a/crates/sbg-rs/sbgECom/src/defs/sbgEComDefsGnss.h b/crates/sbg-rs/sbgECom/src/defs/sbgEComDefsGnss.h new file mode 100644 index 0000000..295b7bd --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/defs/sbgEComDefsGnss.h @@ -0,0 +1,265 @@ +/*! + * \file sbgEComDefsGnss.h + * \ingroup main + * \author SBG Systems + * \date 20 September 2022 + * + * \brief Common enumeration and definitions for RAW GNSS data + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_DEFS_GNSS_H +#define SBG_ECOM_DEFS_GNSS_H + +// sbgCommonLib headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Enumeration definitions -// +//----------------------------------------------------------------------// + +/*! + * Signal IDs. + * + * These are on-the-wire values. + */ +typedef enum _SbgEComSignalId +{ + SBG_ECOM_SIGNAL_ID_UNKNOWN = 0, + + // + // GPS constellation (10 to 39) + // + SBG_ECOM_SIGNAL_ID_GPS_L1C_DP = 10, + SBG_ECOM_SIGNAL_ID_GPS_L1C_D = 11, + SBG_ECOM_SIGNAL_ID_GPS_L1C_P = 12, + SBG_ECOM_SIGNAL_ID_GPS_L1_W = 13, + SBG_ECOM_SIGNAL_ID_GPS_L1_CA = 14, + SBG_ECOM_SIGNAL_ID_GPS_L1P = 15, + SBG_ECOM_SIGNAL_ID_GPS_L1_PY = 16, + SBG_ECOM_SIGNAL_ID_GPS_L1M = 17, + SBG_ECOM_SIGNAL_ID_GPS_L2C_ML = 18, + SBG_ECOM_SIGNAL_ID_GPS_L2C_L = 19, + SBG_ECOM_SIGNAL_ID_GPS_L2_SEMICL = 20, + SBG_ECOM_SIGNAL_ID_GPS_L2_W = 21, + SBG_ECOM_SIGNAL_ID_GPS_L2_CA = 22, + SBG_ECOM_SIGNAL_ID_GPS_L2C_M = 23, + SBG_ECOM_SIGNAL_ID_GPS_L2_PY = 24, + SBG_ECOM_SIGNAL_ID_GPS_L2M = 25, + SBG_ECOM_SIGNAL_ID_GPS_L2P = 26, + SBG_ECOM_SIGNAL_ID_GPS_L5_IQ = 27, + SBG_ECOM_SIGNAL_ID_GPS_L5_I = 28, + SBG_ECOM_SIGNAL_ID_GPS_L5_Q = 29, + + // + // GLONASS constellation (40 to 59) + // + SBG_ECOM_SIGNAL_ID_GLONASS_G1_P = 40, + SBG_ECOM_SIGNAL_ID_GLONASS_G1_CA = 41, + SBG_ECOM_SIGNAL_ID_GLONASS_G2_P = 42, + SBG_ECOM_SIGNAL_ID_GLONASS_G2_CA = 43, + SBG_ECOM_SIGNAL_ID_GLONASS_G3_I = 44, + SBG_ECOM_SIGNAL_ID_GLONASS_G3_Q = 45, + SBG_ECOM_SIGNAL_ID_GLONASS_G3_IQ = 46, + + // + // Galileo constellation (60 to 99) + // + SBG_ECOM_SIGNAL_ID_GALILEO_E1_BC = 60, + SBG_ECOM_SIGNAL_ID_GALILEO_E1_C = 61, + SBG_ECOM_SIGNAL_ID_GALILEO_E1_B = 62, + SBG_ECOM_SIGNAL_ID_GALILEO_E1_A = 63, + SBG_ECOM_SIGNAL_ID_GALILEO_E1_ABC = 64, + SBG_ECOM_SIGNAL_ID_GALILEO_E5B_IQ = 65, + SBG_ECOM_SIGNAL_ID_GALILEO_E5B_I = 66, + SBG_ECOM_SIGNAL_ID_GALILEO_E5B_Q = 67, + SBG_ECOM_SIGNAL_ID_GALILEO_E5A_IQ = 68, + SBG_ECOM_SIGNAL_ID_GALILEO_E5A_I = 69, + SBG_ECOM_SIGNAL_ID_GALILEO_E5A_Q = 70, + SBG_ECOM_SIGNAL_ID_GALILEO_E5_IQ = 71, + SBG_ECOM_SIGNAL_ID_GALILEO_E5_I = 72, + SBG_ECOM_SIGNAL_ID_GALILEO_E5_Q = 73, + SBG_ECOM_SIGNAL_ID_GALILEO_E6_BC = 74, + SBG_ECOM_SIGNAL_ID_GALILEO_E6_C = 75, + SBG_ECOM_SIGNAL_ID_GALILEO_E6_B = 76, + SBG_ECOM_SIGNAL_ID_GALILEO_E6_ABC = 77, + SBG_ECOM_SIGNAL_ID_GALILEO_E6_A = 78, + + // + // Beidou constellation (100 to 149) + // + SBG_ECOM_SIGNAL_ID_BEIDOU_B1IQ = 100, + SBG_ECOM_SIGNAL_ID_BEIDOU_B1I = 101, + SBG_ECOM_SIGNAL_ID_BEIDOU_B1Q = 102, + SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_P = 103, + SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_DP = 104, + SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_D = 105, + SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_P = 106, + SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_DP = 107, + SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_D = 108, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2IQ = 109, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2I = 110, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_P = 111, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_DP = 112, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_D = 113, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2Q = 114, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_P = 115, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_DP = 116, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_D = 117, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_P = 118, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_DP = 119, + SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_D = 120, + SBG_ECOM_SIGNAL_ID_BEIDOU_B3IQ = 121, + SBG_ECOM_SIGNAL_ID_BEIDOU_B3I = 122, + SBG_ECOM_SIGNAL_ID_BEIDOU_B3Q = 123, + SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_D = 124, + SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_P = 125, + SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_DP = 126, + + // + // QZSS constellation (150 to 179) + // + SBG_ECOM_SIGNAL_ID_QZSS_L1C_DP = 150, + SBG_ECOM_SIGNAL_ID_QZSS_L1C_D = 151, + SBG_ECOM_SIGNAL_ID_QZSS_L1C_P = 152, + SBG_ECOM_SIGNAL_ID_QZSS_L1_CA = 153, + SBG_ECOM_SIGNAL_ID_QZSS_L1_SAIF = 154, + SBG_ECOM_SIGNAL_ID_QZSS_L1_SB = 155, + SBG_ECOM_SIGNAL_ID_QZSS_L2C_ML = 156, + SBG_ECOM_SIGNAL_ID_QZSS_L2C_L = 157, + SBG_ECOM_SIGNAL_ID_QZSS_L2C_M = 158, + SBG_ECOM_SIGNAL_ID_QZSS_L5_IQ = 159, + SBG_ECOM_SIGNAL_ID_QZSS_L5_I = 160, + SBG_ECOM_SIGNAL_ID_QZSS_L5_Q = 161, + SBG_ECOM_SIGNAL_ID_QZSS_L5S_IQ = 162, + SBG_ECOM_SIGNAL_ID_QZSS_L5S_I = 163, + SBG_ECOM_SIGNAL_ID_QZSS_L5S_Q = 164, + SBG_ECOM_SIGNAL_ID_QZSS_L6_P = 165, + SBG_ECOM_SIGNAL_ID_QZSS_L6_DP = 166, + SBG_ECOM_SIGNAL_ID_QZSS_L6_D = 167, + SBG_ECOM_SIGNAL_ID_QZSS_L6_E = 168, + SBG_ECOM_SIGNAL_ID_QZSS_L6_DE = 169, + + // + // SBAS system (180 to 199) + // + SBG_ECOM_SIGNAL_ID_SBAS_L1_CA = 180, + SBG_ECOM_SIGNAL_ID_SBAS_L5_I = 181, + SBG_ECOM_SIGNAL_ID_SBAS_L5_Q = 182, + SBG_ECOM_SIGNAL_ID_SBAS_L5_IQ = 183, + + // + // IRNSS / NAVIC constellation (200 to 219) + // + SBG_ECOM_SIGNAL_ID_IRNSS_L5_A = 200, + SBG_ECOM_SIGNAL_ID_IRNSS_L5_B = 201, + SBG_ECOM_SIGNAL_ID_IRNSS_L5_C = 202, + SBG_ECOM_SIGNAL_ID_IRNSS_L5_BC = 203, + SBG_ECOM_SIGNAL_ID_IRNSS_S9_A = 204, + SBG_ECOM_SIGNAL_ID_IRNSS_S9_B = 205, + SBG_ECOM_SIGNAL_ID_IRNSS_S9_C = 206, + SBG_ECOM_SIGNAL_ID_IRNSS_S9_BC = 207, + + // + // L-Band system (220 to 230) + // + SBG_ECOM_SIGNAL_ID_LBAND = 220, +} SbgEComSignalId; + +/*! + * Constellation IDs. + * + * All values must be strictly lower than 16. + * + * These are on-the-wire values. + */ +typedef enum _SbgEComConstellationId +{ + SBG_ECOM_CONSTELLATION_ID_UNKNOWN = 0, + SBG_ECOM_CONSTELLATION_ID_GPS = 1, + SBG_ECOM_CONSTELLATION_ID_GLONASS = 2, + SBG_ECOM_CONSTELLATION_ID_GALILEO = 3, + SBG_ECOM_CONSTELLATION_ID_BEIDOU = 4, + SBG_ECOM_CONSTELLATION_ID_QZSS = 5, + SBG_ECOM_CONSTELLATION_ID_SBAS = 6, + SBG_ECOM_CONSTELLATION_ID_IRNSS = 7, + SBG_ECOM_CONSTELLATION_ID_LBAND = 8, +} SbgEComConstellationId; + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +/*! + * Returns a constellation given a signal ID + * + * \param[in] signalId Signal ID value. + * \return Constellation this signal belongs to. + */ +SbgEComConstellationId sbgEComGetConstellationFromSignalId(SbgEComSignalId signalId); + +/*! + * Check if a value belongs to SbgEComSignalId enum. + * + * WARNING: SBG_ECOM_SIGNAL_ID_UNKNOWN is considered to be a valid enum value. + * + * \param[in] signalId Signal ID value. + * \return true if the value is valid + */ +bool sbgEComSignalIdIsValid(uint8_t signalId); + +/*! + * Get a signal ID as a read only C string. + * + * \param[in] signalId Signal ID value. + * \return Signal ID as a read only C string. + */ +const char *sbgEComSignalToStr(SbgEComSignalId signalId); + +/*! + * Check if a value belongs to SbgEComConstellationId enum. + * + * \param[in] constellationId constellation ID value. + * \return true if the value is valid + */ +bool sbgEComConstellationIdIsValid(uint8_t constellationId); + +/*! + * Get a constellation ID as a read only C string. + * + * \param[in] constellationId Constellation ID value. + * \return Constellation ID as a read only C string. + */ +const char *sbgEComConstellationToStr(SbgEComConstellationId constellationId); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_DEFS_GNSS_H diff --git a/crates/sbg-rs/sbgECom/src/protocol/sbgEComProtocol.c b/crates/sbg-rs/sbgECom/src/protocol/sbgEComProtocol.c new file mode 100644 index 0000000..6766376 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/protocol/sbgEComProtocol.c @@ -0,0 +1,1201 @@ +// sbgCommonLib headers +#include +#include +#include +#include + +// Local headers +#include "sbgEComProtocol.h" + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +/*! + * Delay before another send attempt when sending a large payload, in milliseconds. + */ +#define SBG_ECOM_PROTOCOL_EXT_SEND_DELAY (50) + +//----------------------------------------------------------------------// +//- Private functions -// +//----------------------------------------------------------------------// + +/*! + * Clear the content of a payload. + * + * Any allocated resource is released, and the payload returns to its constructed state. + * + * \param[in] pPayload Payload. + */ +static void sbgEComProtocolPayloadClear(SbgEComProtocolPayload *pPayload) +{ + assert(pPayload); + + if (pPayload->allocated) + { + free(pPayload->pBuffer); + + pPayload->allocated = false; + } + + pPayload->pBuffer = NULL; + pPayload->size = 0; +} + +/*! + * Set the properties of a payload. + * + * \param[in] pPayload Payload. + * \param[in] allocated True if the given buffer is allocated with malloc(). + * \param[in] pBuffer Buffer. + * \param[in] size Buffer size, in bytes. + */ +static void sbgEComProtocolPayloadSet(SbgEComProtocolPayload *pPayload, bool allocated, void *pBuffer, size_t size) +{ + assert(pPayload); + assert(pBuffer); + + pPayload->allocated = allocated; + pPayload->pBuffer = pBuffer; + pPayload->size = size; +} + +/*! + * Discard unused bytes from the work buffer of a protocol. + * + * \param[in] pProtocol Protocol. + */ +static void sbgEComProtocolDiscardUnusedBytes(SbgEComProtocol *pProtocol) +{ + assert(pProtocol); + + if (pProtocol->discardSize != 0) + { + assert(pProtocol->discardSize <= pProtocol->rxBufferSize); + + memmove(pProtocol->rxBuffer, &pProtocol->rxBuffer[pProtocol->discardSize], pProtocol->rxBufferSize - pProtocol->discardSize); + + pProtocol->rxBufferSize -= pProtocol->discardSize; + pProtocol->discardSize = 0; + } +} + +/*! + * Read data from the underlying interface into the work buffer of a protocol. + * + * \param[in] pProtocol Protocol. + */ +static void sbgEComProtocolRead(SbgEComProtocol *pProtocol) +{ + SbgErrorCode errorCode; + + assert(pProtocol); + + if (pProtocol->rxBufferSize < sizeof(pProtocol->rxBuffer)) + { + size_t nrBytesRead; + + errorCode = sbgInterfaceRead(pProtocol->pLinkedInterface, &pProtocol->rxBuffer[pProtocol->rxBufferSize], &nrBytesRead, sizeof(pProtocol->rxBuffer) - pProtocol->rxBufferSize); + + if (errorCode == SBG_NO_ERROR) + { + pProtocol->rxBufferSize += nrBytesRead; + } + } +} + +/*! + * Find SYNC bytes in the work buffer of a protocol. + * + * The output offset is set if either SBG_NO_ERROR or SBG_NOT_CONTINUOUS_FRAME is returned. + * + * \param[in] pProtocol Protocol. + * \param[in] startOffset Start offset, in bytes. + * \param[out] pOffset Offset, in bytes. + * \return SBG_NO_ERROR if successful, + * SBG_NOT_CONTINUOUS_FRAME if only the first SYNC byte was found, + * SBG_NOT_READY otherwise. + */ +static SbgErrorCode sbgEComProtocolFindSyncBytes(SbgEComProtocol *pProtocol, size_t startOffset, size_t *pOffset) +{ + SbgErrorCode errorCode; + + assert(pProtocol); + + errorCode = SBG_NOT_READY; + + for (size_t i = startOffset; i < (pProtocol->rxBufferSize - 1); i++) + { + if ((pProtocol->rxBuffer[i] == SBG_ECOM_SYNC_1) && (pProtocol->rxBuffer[i + 1] == SBG_ECOM_SYNC_2)) + { + *pOffset = i; + errorCode = SBG_NO_ERROR; + break; + } + } + + // + // The SYNC bytes were not found, but check if the last byte in the work buffer is the first SYNC byte, + // as it could result from receiving a partial frame. + // + if ((errorCode != SBG_NO_ERROR) && (pProtocol->rxBuffer[pProtocol->rxBufferSize - 1] == SBG_ECOM_SYNC_1)) + { + *pOffset = pProtocol->rxBufferSize - 1; + errorCode = SBG_NOT_CONTINUOUS_FRAME; + } + + return errorCode; +} + +/*! + * Parse a frame in the work buffer of a protocol. + * + * A non-zero number of pages indicates the reception of an extended frame. + * + * \param[in] pProtocol Protocol. + * \param[in] offset Frame offset in the protocol work buffer. + * \param[out] pEndOffset Frame end offset in the protocol work buffer. + * \param[out] pMsgClass Message class. + * \param[out] pMsgId Message ID. + * \param[out] pTransferId Transfer ID. + * \param[out] pPageIndex Page index. + * \param[out] pNrPages Number of pages. + * \param[out] pBuffer Payload buffer. + * \param[out] pSize Payload buffer size, in bytes. + * \return SBG_NO_ERROR if successful, + * SBG_NOT_READY if the frame is incomplete, + * SBG_INVALID_FRAME if the frame is invalid, + * SBG_INVALID_CRC if the frame CRC is invalid. + */ +static SbgErrorCode sbgEComProtocolParseFrame(SbgEComProtocol *pProtocol, size_t offset, size_t *pEndOffset, uint8_t *pMsgClass, uint8_t *pMsgId, uint8_t *pTransferId, uint16_t *pPageIndex, uint16_t *pNrPages, void **pBuffer, size_t *pSize) +{ + SbgErrorCode errorCode; + SbgStreamBuffer streamBuffer; + uint8_t msgId; + uint8_t msgClass; + size_t standardPayloadSize; + + assert(pProtocol); + assert(offset < pProtocol->rxBufferSize); + assert(pEndOffset); + assert(pMsgClass); + assert(pMsgId); + assert(pTransferId); + assert(pPageIndex); + assert(pNrPages); + assert(pBuffer); + assert(pSize); + + sbgStreamBufferInitForRead(&streamBuffer, &pProtocol->rxBuffer[offset], pProtocol->rxBufferSize - offset); + + // + // Skip SYNC bytes. + // + sbgStreamBufferSeek(&streamBuffer, 2, SB_SEEK_CUR_INC); + + msgId = sbgStreamBufferReadUint8(&streamBuffer); + msgClass = sbgStreamBufferReadUint8(&streamBuffer); + standardPayloadSize = sbgStreamBufferReadUint16LE(&streamBuffer); + + errorCode = sbgStreamBufferGetLastError(&streamBuffer); + + if (errorCode == SBG_NO_ERROR) + { + if (standardPayloadSize <= SBG_ECOM_MAX_PAYLOAD_SIZE) + { + if (sbgStreamBufferGetSize(&streamBuffer) >= (standardPayloadSize + 9)) + { + size_t payloadSize; + uint8_t transferId; + uint16_t pageIndex; + uint16_t nrPages; + + if ((msgClass & 0x80) == 0) + { + payloadSize = standardPayloadSize; + + transferId = 0; + pageIndex = 0; + nrPages = 0; + + errorCode = SBG_NO_ERROR; + } + else + { + msgClass &= 0x7f; + + // + // In extended frames, the payload size includes the extended headers. + // + payloadSize = standardPayloadSize - 5; + + transferId = sbgStreamBufferReadUint8(&streamBuffer); + pageIndex = sbgStreamBufferReadUint16LE(&streamBuffer); + nrPages = sbgStreamBufferReadUint16LE(&streamBuffer); + + if ((transferId & 0xf0) != 0) + { + SBG_LOG_WARNING(SBG_INVALID_FRAME, "reserved bits set in extended headers"); + transferId &= 0xf; + } + + if (pageIndex < nrPages) + { + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_INVALID_FRAME; + SBG_LOG_ERROR(errorCode, "invalid page information : %" PRIu16 "/%" PRIu16, pageIndex, nrPages); + } + } + + if (errorCode == SBG_NO_ERROR) + { + void *pPayloadAddr; + uint16_t frameCrc; + uint8_t lastByte; + + pPayloadAddr = sbgStreamBufferGetCursor(&streamBuffer); + + sbgStreamBufferSeek(&streamBuffer, payloadSize, SB_SEEK_CUR_INC); + + frameCrc = sbgStreamBufferReadUint16LE(&streamBuffer); + lastByte = sbgStreamBufferReadUint8(&streamBuffer); + + assert(sbgStreamBufferGetLastError(&streamBuffer) == SBG_NO_ERROR); + + if (lastByte == SBG_ECOM_ETX) + { + uint16_t computedCrc; + + // + // The CRC spans from the header (excluding the SYNC bytes) up to the CRC bytes. + // + sbgStreamBufferSeek(&streamBuffer, 2, SB_SEEK_SET); + computedCrc = sbgCrc16Compute(sbgStreamBufferGetCursor(&streamBuffer), standardPayloadSize + 4); + + if (frameCrc == computedCrc) + { + *pEndOffset = offset + standardPayloadSize + 9; + *pMsgClass = msgClass; + *pMsgId = msgId; + *pTransferId = transferId; + *pPageIndex = pageIndex; + *pNrPages = nrPages; + *pBuffer = pPayloadAddr; + *pSize = payloadSize; + + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_INVALID_CRC; + SBG_LOG_ERROR(errorCode, "invalid CRC, frame:%#" PRIx16 " computed:%#" PRIx16, frameCrc, computedCrc); + } + } + else + { + errorCode = SBG_INVALID_FRAME; + SBG_LOG_ERROR(errorCode, "invalid end-of-frame: byte:%#" PRIx8, lastByte); + } + } + } + else + { + errorCode = SBG_NOT_READY; + } + } + else + { + errorCode = SBG_INVALID_FRAME; + SBG_LOG_ERROR(errorCode, "invalid payload size %zu", standardPayloadSize); + } + } + else + { + errorCode = SBG_NOT_READY; + } + + return errorCode; +} + +/*! + * Find a frame in the work buffer of a protocol. + * + * If an extended frame is received, the number of pages is set to a non-zero value. + * + * \param[in] pProtocol Protocol. + * \param[out] pMsgClass Message class. + * \param[out] pMsgId Message ID. + * \param[out] pTransferId Transfer ID. + * \param[out] pPageIndex Page index. + * \param[out] pNrPages Number of pages. + * \param[out] pBuffer Payload buffer. + * \param[out] pSize Payload buffer size, in bytes. + * \return SBG_NO_ERROR if successful, + * SBG_NOT_READY if no frame was found. + */ +static SbgErrorCode sbgEComProtocolFindFrame(SbgEComProtocol *pProtocol, uint8_t *pMsgClass, uint8_t *pMsgId, uint8_t *pTransferId, uint16_t *pPageIndex, uint16_t *pNrPages, void **pBuffer, size_t *pSize) +{ + SbgErrorCode errorCode; + size_t startOffset; + + assert(pProtocol); + + errorCode = SBG_NOT_READY; + startOffset = 0; + + while (startOffset < pProtocol->rxBufferSize) + { + size_t offset; + + errorCode = sbgEComProtocolFindSyncBytes(pProtocol, startOffset, &offset); + + if (errorCode == SBG_NO_ERROR) + { + size_t endOffset; + + errorCode = sbgEComProtocolParseFrame(pProtocol, offset, &endOffset, pMsgClass, pMsgId, pTransferId, pPageIndex, pNrPages, pBuffer, pSize); + + if (errorCode == SBG_NO_ERROR) + { + // + // Valid frame found, discard all data up to and including that frame + // on the next read. + // + pProtocol->discardSize = endOffset; + break; + } + else if (errorCode == SBG_NOT_READY) + { + // + // There may be a valid frame at the parse offset, but it's not complete. + // Have all preceding bytes discarded on the next read. + // + pProtocol->discardSize = offset; + break; + } + else + { + // + // Not a valid frame, skip SYNC bytes and try again. + // + startOffset = offset + 2; + errorCode = SBG_NOT_READY; + } + } + else if (errorCode == SBG_NOT_CONTINUOUS_FRAME) + { + // + // The first SYNC byte was found, but not the second. It may be a valid + // frame, so keep the SYNC byte but have all preceding bytes discarded + // on the next read. + // + pProtocol->discardSize = offset; + errorCode = SBG_NOT_READY; + break; + } + else + { + // + // No SYNC byte found, discard all data. + // + pProtocol->rxBufferSize = 0; + errorCode = SBG_NOT_READY; + break; + } + } + + assert(pProtocol->discardSize <= pProtocol->rxBufferSize); + + return errorCode; +} + +/*! + * Send a standard frame. + * + * \param[in] pProtocol Protocol. + * \param[in] msgClass Message class. + * \param[in] msgId Message ID. + * \param[in] pData Data buffer. + * \param[in] size Data buffer size, in bytes. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgEComProtocolSendStandardFrame(SbgEComProtocol *pProtocol, uint8_t msgClass, uint8_t msgId, const void *pData, size_t size) +{ + uint8_t buffer[SBG_ECOM_MAX_BUFFER_SIZE]; + SbgStreamBuffer streamBuffer; + const uint8_t *crcDataStart; + const uint8_t *crcDataEnd; + uint16_t crc; + + assert(pProtocol); + assert((msgClass & 0x80) == 0); + assert(size <= SBG_ECOM_MAX_PAYLOAD_SIZE); + assert(pData || (size == 0)); + + sbgStreamBufferInitForWrite(&streamBuffer, buffer, sizeof(buffer)); + + sbgStreamBufferWriteUint8(&streamBuffer, SBG_ECOM_SYNC_1); + sbgStreamBufferWriteUint8(&streamBuffer, SBG_ECOM_SYNC_2); + + crcDataStart = sbgStreamBufferGetCursor(&streamBuffer); + + sbgStreamBufferWriteUint8(&streamBuffer, msgId); + sbgStreamBufferWriteUint8(&streamBuffer, msgClass); + + sbgStreamBufferWriteUint16LE(&streamBuffer, (uint16_t)size); + + sbgStreamBufferWriteBuffer(&streamBuffer, pData, size); + + crcDataEnd = sbgStreamBufferGetCursor(&streamBuffer); + + crc = sbgCrc16Compute(crcDataStart, crcDataEnd - crcDataStart); + + sbgStreamBufferWriteUint16LE(&streamBuffer, crc); + + sbgStreamBufferWriteUint8(&streamBuffer, SBG_ECOM_ETX); + + assert(sbgStreamBufferGetLastError(&streamBuffer) == SBG_NO_ERROR); + + return sbgInterfaceWrite(pProtocol->pLinkedInterface, sbgStreamBufferGetLinkedBuffer(&streamBuffer), sbgStreamBufferGetLength(&streamBuffer)); +} + +/*! + * Send an extended frame. + * + * \param[in] pProtocol Protocol. + * \param[in] msgClass Message class. + * \param[in] msgId Message ID. + * \param[in] transferId Transfer ID. + * \param[in] pageIndex Page index (0 to 65534) + * \param[in] nrPages Total number of pages (1 to 65535) + * \param[in] pData Data buffer. + * \param[in] size Data buffer size, in bytes. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode sbgEComProtocolSendExtendedFrame(SbgEComProtocol *pProtocol, uint8_t msgClass, uint8_t msgId, uint8_t transferId, size_t pageIndex, size_t nrPages, const void *pData, size_t size) +{ + SbgErrorCode errorCode; + uint8_t buffer[SBG_ECOM_MAX_BUFFER_SIZE]; + SbgStreamBuffer streamBuffer; + const uint8_t *crcDataStart; + const uint8_t *crcDataEnd; + uint16_t crc; + + assert(pProtocol); + assert((msgClass & 0x80) == 0); + assert((transferId & 0xf0) == 0); + assert(pageIndex < UINT16_MAX); + assert((nrPages > 0) && (nrPages <= UINT16_MAX)); + assert(pageIndex < nrPages); + assert(size <= SBG_ECOM_MAX_EXTENDED_PAYLOAD_SIZE); + assert(pData || (size == 0)); + + sbgStreamBufferInitForWrite(&streamBuffer, buffer, sizeof(buffer)); + + sbgStreamBufferWriteUint8(&streamBuffer, SBG_ECOM_SYNC_1); + sbgStreamBufferWriteUint8(&streamBuffer, SBG_ECOM_SYNC_2); + + crcDataStart = sbgStreamBufferGetCursor(&streamBuffer); + + sbgStreamBufferWriteUint8(&streamBuffer, msgId); + sbgStreamBufferWriteUint8(&streamBuffer, 0x80 | msgClass); + + // + // For compatibility reasons, the size must span over the extended headers. + // + sbgStreamBufferWriteUint16LE(&streamBuffer, (uint16_t)size + 5); + + sbgStreamBufferWriteUint8(&streamBuffer, transferId); + sbgStreamBufferWriteUint16LE(&streamBuffer, (uint16_t)pageIndex); + sbgStreamBufferWriteUint16LE(&streamBuffer, (uint16_t)nrPages); + + sbgStreamBufferWriteBuffer(&streamBuffer, pData, size); + + crcDataEnd = sbgStreamBufferGetCursor(&streamBuffer); + + crc = sbgCrc16Compute(crcDataStart, crcDataEnd - crcDataStart); + + sbgStreamBufferWriteUint16LE(&streamBuffer, crc); + + sbgStreamBufferWriteUint8(&streamBuffer, SBG_ECOM_ETX); + + assert(sbgStreamBufferGetLastError(&streamBuffer) == SBG_NO_ERROR); + + for (;;) + { + errorCode = sbgInterfaceWrite(pProtocol->pLinkedInterface, sbgStreamBufferGetLinkedBuffer(&streamBuffer), sbgStreamBufferGetLength(&streamBuffer)); + + if (errorCode != SBG_BUFFER_OVERFLOW) + { + break; + } + + sbgSleep(SBG_ECOM_PROTOCOL_EXT_SEND_DELAY); + } + + return errorCode; +} + +/*! + * Get a transfer ID for the next large send. + * + * This function returns a different ID every time it's called. + * + * \param[in] pProtocol Protocol. + * \return Transfer ID of the next large send. + */ +static SbgErrorCode sbgEComProtocolGetTxId(SbgEComProtocol *pProtocol) +{ + uint8_t transferId; + + assert(pProtocol); + assert((pProtocol->nextLargeTxId & 0xf0) == 0); + + transferId = pProtocol->nextLargeTxId; + pProtocol->nextLargeTxId = (pProtocol->nextLargeTxId + 1) & 0xf0; + + return transferId; +} + +/*! + * Check if a large transfer is in progress. + * + * \param[in] pProtocol Protocol. + * \return True if a large transfer is in progress. + */ +static bool sbgEComProtocolLargeTransferInProgress(const SbgEComProtocol *pProtocol) +{ + assert(pProtocol); + + return pProtocol->pLargeBuffer; +} + +/*! + * Reset The large transfer member variables of a protocol. + * + * \param[in] pProtocol Protocol. + */ +static void sbgEComProtocolResetLargeTransfer(SbgEComProtocol *pProtocol) +{ + assert(pProtocol); + + pProtocol->pLargeBuffer = NULL; + pProtocol->largeBufferSize = 0; + pProtocol->transferId = 0; + pProtocol->pageIndex = 0; + pProtocol->nrPages = 0; +} + +/*! + * Clear any large transfer in progress. + * + * \param[in] pProtocol Protocol. + */ +static void sbgEComProtocolClearLargeTransfer(SbgEComProtocol *pProtocol) +{ + assert(pProtocol); + + free(pProtocol->pLargeBuffer); + + sbgEComProtocolResetLargeTransfer(pProtocol); +} + +/*! + * Process an extended frame. + * + * \param[in] pProtocol Protocol. + * \param[in] msgClass Message class. + * \param[in] msgId Message ID. + * \param[in] transferId Transfer ID. + * \param[in] pageIndex Page index. + * \param[in] nrPages Number of pages. + * \param[in] pBuffer Buffer. + * \param[in] size Buffer size, in bytes. + * \return SBG_NO_ERROR if a large transfer is complete, + * SBG_NOT_READY otherwise. + */ +static SbgErrorCode sbgEComProtocolProcessExtendedFrame(SbgEComProtocol *pProtocol, uint8_t msgClass, uint8_t msgId, uint8_t transferId, uint16_t pageIndex, uint16_t nrPages, const void *pBuffer, size_t size) +{ + SbgErrorCode errorCode; + + assert(pProtocol); + assert((transferId & 0xf0) == 0); + assert(pageIndex < nrPages); + assert(pBuffer || (size == 0)); + assert(size <= SBG_ECOM_MAX_EXTENDED_PAYLOAD_SIZE); + + if (pageIndex == 0) + { + size_t capacity; + + if (sbgEComProtocolLargeTransferInProgress(pProtocol)) + { + SBG_LOG_ERROR(SBG_ERROR, "large transfer started while a large transfer is in progress"); + SBG_LOG_ERROR(SBG_ERROR, "terminating large transfer"); + + sbgEComProtocolClearLargeTransfer(pProtocol); + } + + capacity = nrPages * SBG_ECOM_MAX_EXTENDED_PAYLOAD_SIZE; + + pProtocol->pLargeBuffer = malloc(capacity); + + if (pProtocol->pLargeBuffer) + { + pProtocol->largeBufferSize = 0; + pProtocol->msgClass = msgClass; + pProtocol->msgId = msgId; + pProtocol->transferId = transferId; + pProtocol->pageIndex = 0; + pProtocol->nrPages = nrPages; + + errorCode = SBG_NO_ERROR; + } + else + { + SBG_LOG_ERROR(SBG_MALLOC_FAILED, "unable to allocate buffer"); + + sbgEComProtocolResetLargeTransfer(pProtocol); + + errorCode = SBG_NOT_READY; + } + } + else + { + if (sbgEComProtocolLargeTransferInProgress(pProtocol)) + { + errorCode = SBG_NO_ERROR; + } + else + { + SBG_LOG_ERROR(SBG_ERROR, "extended frame received while no large transfer in progress"); + + errorCode = SBG_NOT_READY; + } + } + + if (errorCode == SBG_NO_ERROR) + { + if (msgClass == pProtocol->msgClass) + { + errorCode = SBG_NO_ERROR; + } + else + { + SBG_LOG_ERROR(SBG_ERROR, "message class mismatch in extended frame"); + SBG_LOG_ERROR(SBG_ERROR, "terminating large transfer"); + + sbgEComProtocolClearLargeTransfer(pProtocol); + + errorCode = SBG_NOT_READY; + } + + if (msgId == pProtocol->msgId) + { + errorCode = SBG_NO_ERROR; + } + else + { + SBG_LOG_ERROR(SBG_ERROR, "message ID mismatch in extended frame"); + SBG_LOG_ERROR(SBG_ERROR, "terminating large transfer"); + + sbgEComProtocolClearLargeTransfer(pProtocol); + + errorCode = SBG_NOT_READY; + } + + if (transferId == pProtocol->transferId) + { + errorCode = SBG_NO_ERROR; + } + else + { + SBG_LOG_ERROR(SBG_ERROR, "transfer ID mismatch in extended frame"); + SBG_LOG_ERROR(SBG_ERROR, "terminating large transfer"); + + sbgEComProtocolClearLargeTransfer(pProtocol); + + errorCode = SBG_NOT_READY; + } + + if (errorCode == SBG_NO_ERROR) + { + if (nrPages == pProtocol->nrPages) + { + if (pageIndex == pProtocol->pageIndex) + { + size_t offset; + + offset = pageIndex * SBG_ECOM_MAX_EXTENDED_PAYLOAD_SIZE; + memcpy(&pProtocol->pLargeBuffer[offset], pBuffer, size); + + pProtocol->largeBufferSize += size; + pProtocol->pageIndex++; + + if (pProtocol->pageIndex != pProtocol->nrPages) + { + errorCode = SBG_NOT_READY; + } + } + else + { + SBG_LOG_ERROR(SBG_ERROR, "extended frame received out of sequence"); + SBG_LOG_ERROR(SBG_ERROR, "terminating large transfer"); + + sbgEComProtocolClearLargeTransfer(pProtocol); + + errorCode = SBG_NOT_READY; + } + } + else + { + SBG_LOG_ERROR(SBG_ERROR, "page count mismatch in extended frame"); + SBG_LOG_ERROR(SBG_ERROR, "terminating large transfer"); + + sbgEComProtocolClearLargeTransfer(pProtocol); + + errorCode = SBG_NOT_READY; + } + } + } + + return errorCode; +} + +//----------------------------------------------------------------------// +//- Public methods (SbgEComProtocolPayload) -// +//----------------------------------------------------------------------// + +void sbgEComProtocolPayloadConstruct(SbgEComProtocolPayload *pPayload) +{ + assert(pPayload); + + pPayload->allocated = false; + pPayload->pBuffer = NULL; + pPayload->size = 0; +} + +void sbgEComProtocolPayloadDestroy(SbgEComProtocolPayload *pPayload) +{ + assert(pPayload); + + if (pPayload->allocated) + { + free(pPayload->pBuffer); + } +} + +const void *sbgEComProtocolPayloadGetBuffer(const SbgEComProtocolPayload *pPayload) +{ + assert(pPayload); + + return pPayload->pBuffer; +} + +size_t sbgEComProtocolPayloadGetSize(const SbgEComProtocolPayload *pPayload) +{ + assert(pPayload); + + return pPayload->size; +} + +void *sbgEComProtocolPayloadMoveBuffer(SbgEComProtocolPayload *pPayload) +{ + void *pBuffer; + + assert(pPayload); + + if (pPayload->pBuffer) + { + if (pPayload->allocated) + { + pBuffer = pPayload->pBuffer; + + sbgEComProtocolPayloadConstruct(pPayload); + } + else + { + pBuffer = malloc(pPayload->size); + + if (pBuffer) + { + memcpy(pBuffer, pPayload->pBuffer, pPayload->size); + + sbgEComProtocolPayloadConstruct(pPayload); + } + else + { + SBG_LOG_ERROR(SBG_MALLOC_FAILED, "unable to allocate buffer"); + } + } + } + else + { + pBuffer = NULL; + } + + return pBuffer; +} + +//----------------------------------------------------------------------// +//- Public methods (SbgEComProtocol) -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComProtocolInit(SbgEComProtocol *pProtocol, SbgInterface *pInterface) +{ + assert(pProtocol); + assert(pInterface); + + pProtocol->pLinkedInterface = pInterface; + pProtocol->rxBufferSize = 0; + pProtocol->discardSize = 0; + pProtocol->nextLargeTxId = 0; + + sbgEComProtocolResetLargeTransfer(pProtocol); + + return SBG_NO_ERROR; +} + +SbgErrorCode sbgEComProtocolClose(SbgEComProtocol *pProtocol) +{ + assert(pProtocol); + + pProtocol->pLinkedInterface = NULL; + pProtocol->rxBufferSize = 0; + pProtocol->discardSize = 0; + pProtocol->nextLargeTxId = 0; + + sbgEComProtocolClearLargeTransfer(pProtocol); + + return SBG_NO_ERROR; +} + +SbgErrorCode sbgEComProtocolPurgeIncoming(SbgEComProtocol *pProtocol) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + size_t numBytesRead; + uint32_t timeStamp; + + // + // Reset the work buffer + // + pProtocol->rxBufferSize = 0; + pProtocol->discardSize = 0; + pProtocol->nextLargeTxId = 0; + + sbgEComProtocolClearLargeTransfer(pProtocol); + + // + // Try to read all iconming data for at least 100 ms and trash them + /// + timeStamp = sbgGetTime(); + + do + { + errorCode = sbgInterfaceRead(pProtocol->pLinkedInterface, pProtocol->rxBuffer, &numBytesRead, sizeof(pProtocol->rxBuffer)); + + if (errorCode != SBG_NO_ERROR) + { + SBG_LOG_ERROR(errorCode, "Unable to read data from interface"); + break; + } + } while ((sbgGetTime() - timeStamp) < 100); + + // + // If we still have read some bytes it means we were not able to purge successfully the rx buffer + // + if ( (errorCode == SBG_NO_ERROR) && (numBytesRead > 0) ) + { + errorCode = SBG_ERROR; + SBG_LOG_ERROR(errorCode, "Unable to purge the rx buffer, %zu bytes remaining", numBytesRead); + } + + return errorCode; +} + +SbgErrorCode sbgEComProtocolSend(SbgEComProtocol *pProtocol, uint8_t msgClass, uint8_t msgId, const void *pData, size_t size) +{ + SbgErrorCode errorCode; + + if (size <= SBG_ECOM_MAX_PAYLOAD_SIZE) + { + errorCode = sbgEComProtocolSendStandardFrame(pProtocol, msgClass, msgId, pData, size); + } + else + { + size_t nrPages; + + nrPages = sbgDivCeil(size, SBG_ECOM_MAX_EXTENDED_PAYLOAD_SIZE); + + if (nrPages <= UINT16_MAX) + { + const uint8_t *pBuffer; + size_t offset; + uint8_t transferId; + + pBuffer = pData; + offset = 0; + transferId = sbgEComProtocolGetTxId(pProtocol); + errorCode = SBG_INVALID_PARAMETER; + + for (uint16_t pageIndex = 0; pageIndex < nrPages; pageIndex++) + { + size_t transferSize; + + if ((size - offset) < SBG_ECOM_MAX_EXTENDED_PAYLOAD_SIZE) + { + transferSize = size - offset; + } + else + { + transferSize = SBG_ECOM_MAX_EXTENDED_PAYLOAD_SIZE; + } + + errorCode = sbgEComProtocolSendExtendedFrame(pProtocol, msgClass, msgId, transferId, pageIndex, nrPages, &pBuffer[offset], transferSize); + + if (errorCode != SBG_NO_ERROR) + { + break; + } + + offset += transferSize; + } + } + else + { + errorCode = SBG_INVALID_PARAMETER; + SBG_LOG_ERROR(errorCode, "payload size too large: %zu", size); + } + } + + return errorCode; +} + +SbgErrorCode sbgEComProtocolReceive(SbgEComProtocol *pProtocol, uint8_t *pMsgClass, uint8_t *pMsgId, void *pData, size_t *pSize, size_t maxSize) +{ + SbgErrorCode errorCode; + SbgEComProtocolPayload payload; + + sbgEComProtocolPayloadConstruct(&payload); + + errorCode = sbgEComProtocolReceive2(pProtocol, pMsgClass, pMsgId, &payload); + + if (errorCode == SBG_NO_ERROR) + { + size_t size; + + size = sbgEComProtocolPayloadGetSize(&payload); + + if (size <= maxSize) + { + if (pData) + { + const void *pBuffer; + + pBuffer = sbgEComProtocolPayloadGetBuffer(&payload); + + memcpy(pData, pBuffer, size); + } + + if (pSize) + { + *pSize = size; + } + } + else + { + errorCode = SBG_BUFFER_OVERFLOW; + } + } + + sbgEComProtocolPayloadDestroy(&payload); + + return errorCode; +} + +SbgErrorCode sbgEComProtocolReceive2(SbgEComProtocol *pProtocol, uint8_t *pMsgClass, uint8_t *pMsgId, SbgEComProtocolPayload *pPayload) +{ + SbgErrorCode errorCode; + uint8_t msgClass; + uint8_t msgId; + uint8_t transferId; + uint16_t pageIndex; + uint16_t nrPages; + void *pBuffer; + size_t size; + + assert(pProtocol); + assert(pProtocol->discardSize <= pProtocol->rxBufferSize); + + sbgEComProtocolPayloadClear(pPayload); + + sbgEComProtocolDiscardUnusedBytes(pProtocol); + + sbgEComProtocolRead(pProtocol); + + errorCode = sbgEComProtocolFindFrame(pProtocol, &msgClass, &msgId, &transferId, &pageIndex, &nrPages, &pBuffer, &size); + + if (errorCode == SBG_NO_ERROR) + { + if (nrPages == 0) + { + if (sbgEComProtocolLargeTransferInProgress(pProtocol)) + { + SBG_LOG_ERROR(SBG_ERROR, "standard frame received while a large transfer is in progress"); + SBG_LOG_ERROR(SBG_ERROR, "terminating large transfer"); + + sbgEComProtocolClearLargeTransfer(pProtocol); + } + + if (pMsgClass) + { + *pMsgClass = msgClass; + } + + if (pMsgId) + { + *pMsgId = msgId; + } + + sbgEComProtocolPayloadSet(pPayload, false, pBuffer, size); + } + else + { + errorCode = sbgEComProtocolProcessExtendedFrame(pProtocol, msgClass, msgId, transferId, pageIndex, nrPages, pBuffer, size); + + if (errorCode == SBG_NO_ERROR) + { + if (pMsgClass) + { + *pMsgClass = msgClass; + } + + if (pMsgId) + { + *pMsgId = msgId; + } + + sbgEComProtocolPayloadSet(pPayload, true, pProtocol->pLargeBuffer, pProtocol->largeBufferSize); + sbgEComProtocolResetLargeTransfer(pProtocol); + } + } + } + + return errorCode; +} + +SbgErrorCode sbgEComStartFrameGeneration(SbgStreamBuffer *pOutputStream, uint8_t msgClass, uint8_t msg, size_t *pStreamCursor) +{ + assert(pOutputStream); + assert((msgClass & 0x80) == 0); + assert(pStreamCursor); + + // + // Backup the current position in the stream buffer + // + *pStreamCursor = sbgStreamBufferTell(pOutputStream); + + // + // Write the header + // + sbgStreamBufferWriteUint8LE(pOutputStream, SBG_ECOM_SYNC_1); + sbgStreamBufferWriteUint8LE(pOutputStream, SBG_ECOM_SYNC_2); + + // + // Write the message ID and class + // + sbgStreamBufferWriteUint8LE(pOutputStream, msg); + sbgStreamBufferWriteUint8LE(pOutputStream, msgClass); + + // + // For now, we don't know the payload size so skip it + // + return sbgStreamBufferSeek(pOutputStream, sizeof(uint16_t), SB_SEEK_CUR_INC); +} + +SbgErrorCode sbgEComFinalizeFrameGeneration(SbgStreamBuffer *pOutputStream, size_t streamCursor) +{ + SbgErrorCode errorCode; + size_t payloadSize; + size_t currentPos; + uint16_t frameCrc; + + assert(pOutputStream); + + // + // Test if any error has occurred on the stream first + // + errorCode = sbgStreamBufferGetLastError(pOutputStream); + + // + // Is the stream buffer error free ? + // + if (errorCode == SBG_NO_ERROR) + { + // + // Compute the payload size (written data minus the header) + // + payloadSize = sbgStreamBufferGetLength(pOutputStream) - streamCursor - 6; + + // + // Test that the payload size is valid + // + if (payloadSize <= SBG_ECOM_MAX_PAYLOAD_SIZE) + { + // + // Backup the current cursor position + // + currentPos = sbgStreamBufferTell(pOutputStream); + + // + // Goto the payload size field (4th byte in the frame) + // + sbgStreamBufferSeek(pOutputStream, streamCursor+4, SB_SEEK_SET); + + // + // Write the payload size + // + sbgStreamBufferWriteUint16LE(pOutputStream, (uint16_t)payloadSize); + + // + // Go back to the previous position + // + sbgStreamBufferSeek(pOutputStream, currentPos, SB_SEEK_SET); + + // + // Compute the 16 bits CRC on the whole frame except Sync 1 and Sync 2 + // + frameCrc = sbgCrc16Compute((uint8_t*)sbgStreamBufferGetLinkedBuffer(pOutputStream) + streamCursor + 2, payloadSize + 4); + + // + // Append the CRC + // + sbgStreamBufferWriteUint16LE(pOutputStream, frameCrc); + + // + // Append the ETX + // + errorCode = sbgStreamBufferWriteUint8LE(pOutputStream, SBG_ECOM_ETX); + } + else + { + // + // Invalid payload size + // + errorCode = SBG_BUFFER_OVERFLOW; + SBG_LOG_ERROR(errorCode, "Payload of %zu bytes is too big for a valid sbgECom log", payloadSize); + } + } + else + { + // + // Notify error + // + SBG_LOG_ERROR(errorCode, "Unable to finalize frame because of an error on Stream Buffer"); + } + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/protocol/sbgEComProtocol.h b/crates/sbg-rs/sbgECom/src/protocol/sbgEComProtocol.h new file mode 100644 index 0000000..bf251d1 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/protocol/sbgEComProtocol.h @@ -0,0 +1,284 @@ +/*! + * \file sbgEComProtocol.h + * \ingroup protocol + * \author SBG Systems + * \date 06 February 2013 + * + * \brief Implementation of the sbgECom binary communication protocol. + * + * You will find below, the frame definition used by Ekinox devices.
+ *
+ * + * + * + * + * + *
Frame structure
Fields SYNC 1 SYNC 2 CMD LEN DATA CRC ETX
Size in bytes 1 1 2 2 (0-4086) 2 1
Value 0xFF 0x5A ? ? ? ? 0x33
+ *
+ * Size in bytes indicates the size of the data field.
+ * The minimum frame size is 9 bytes and the maximum is 512 bytes.
+ *
+ * The CRC is calculated on the whole frame without:
+ * SYNC STX CRC and ETX fields.
+ * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +/*! + * \defgroup protocol Low Level Protocol + * \brief Defines the low level protocol method to receive and send frames. + */ + +#ifndef SBG_ECOM_PROTOCOL_H +#define SBG_ECOM_PROTOCOL_H + +// sbgCommonLib headers +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +#define SBG_ECOM_MAX_BUFFER_SIZE (4096) /*!< Maximum reception buffer size in bytes. */ +#define SBG_ECOM_MAX_PAYLOAD_SIZE (4086) /*!< Maximum payload size in bytes. */ +#define SBG_ECOM_MAX_EXTENDED_PAYLOAD_SIZE (4081) /*!< Maximum payload size in an extended frame, in bytes. */ +#define SBG_ECOM_SYNC_1 (0xFF) /*!< First synchronization char of the frame. */ +#define SBG_ECOM_SYNC_2 (0x5A) /*!< Second synchronization char of the frame. */ +#define SBG_ECOM_ETX (0x33) /*!< End of frame byte. */ + +#define SBG_ECOM_RX_TIME_OUT (450) /*!< Default time out for new frame reception. */ + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Payload. + * + * This class is used to abstract whether some payload is received from a single + * or multiple frames. + */ +typedef struct _SbgEComProtocolPayload +{ + bool allocated; /*!< True if the buffer is allocated with malloc(). */ + void *pBuffer; /*!< Buffer. */ + size_t size; /*!< Buffer size, in bytes. */ +} SbgEComProtocolPayload; + +/*! + * Struct containing all protocol related data. + * + * The member variables related to large transfers are valid if and only if the large buffer is valid. + */ +typedef struct _SbgEComProtocol +{ + SbgInterface *pLinkedInterface; /*!< Associated interface used by the protocol to read/write bytes. */ + uint8_t rxBuffer[SBG_ECOM_MAX_BUFFER_SIZE]; /*!< The reception buffer. */ + size_t rxBufferSize; /*!< The current reception buffer size in bytes. */ + size_t discardSize; /*!< Number of bytes to discard on the next receive attempt. */ + uint8_t nextLargeTxId; /*!< Transfer ID of the next large send. */ + + // + // Member variables related to large transfer reception. + // + uint8_t *pLargeBuffer; /*!< Buffer for large transfers, allocated with malloc() if valid. */ + size_t largeBufferSize; /*!< Size of the large transfer buffer, in bytes. */ + uint8_t msgClass; /*!< Message class for the current large transfer. */ + uint8_t msgId; /*!< Message ID for the current large transfer. */ + uint8_t transferId; /*!< ID of the current large transfer. */ + uint16_t pageIndex; /*!< Expected page index of the next frame. */ + uint16_t nrPages; /*!< Number of pages in the current transfer. */ +} SbgEComProtocol; + +//----------------------------------------------------------------------// +//- Public methods (SbgEComProtocolPayload) -// +//----------------------------------------------------------------------// + +/*! + * Payload constructor. + * + * \param[in] pPayload Payload. + */ +void sbgEComProtocolPayloadConstruct(SbgEComProtocolPayload *pPayload); + +/*! + * Payload destructor. + * + * \param[in] pPayload Payload. + */ +void sbgEComProtocolPayloadDestroy(SbgEComProtocolPayload *pPayload); + +/*! + * Get the buffer of a payload. + * + * \param[in] pPayload Payload. + * \return Payload buffer. + */ +const void *sbgEComProtocolPayloadGetBuffer(const SbgEComProtocolPayload *pPayload); + +/*! + * Get the size of a payload buffer. + * + * \param[in] pPayload Payload. + * \return Size of the payload buffer, in bytes. + */ +size_t sbgEComProtocolPayloadGetSize(const SbgEComProtocolPayload *pPayload); + +/*! + * Move the buffer of a payload. + * + * If successful, the ownership of the buffer is passed to the caller. Otherwise, the payload + * is unchanged. + * + * The buffer must be released with free() once unused. + * + * \param[in] pPayload Payload. + * \return Payload buffer if successful, NULL otherwise. + */ +void *sbgEComProtocolPayloadMoveBuffer(SbgEComProtocolPayload *pPayload); + +//----------------------------------------------------------------------// +//- Public methods (SbgEComProtocol) -// +//----------------------------------------------------------------------// + +/*! + * Initialize the protocol system used to communicate with the product and return the created handle. + * + * \param[in] pProtocol Pointer on an allocated protocol structure to initialize. + * \param[in] pInterface Interface to use for read/write operations. + * \return SBG_NO_ERROR if we have initialised the protocol system. + */ +SbgErrorCode sbgEComProtocolInit(SbgEComProtocol *pProtocol, SbgInterface *pInterface); + +/*! + * Close the protocol system. + * + * \param[in] pProtocol A valid protocol handle to close. + * \return SBG_NO_ERROR if we have closed and released the protocol system. + */ +SbgErrorCode sbgEComProtocolClose(SbgEComProtocol *pProtocol); + +/*! + * Purge the interface rx buffer as well as the sbgECom rx work buffer. + * + * For example, if the program flow has been interrupted, this method can be helpful to discard all trash received data. + * + * WARNING: This method is blocking for 100ms and actively tries to read incoming data. + * + * \param[in] pProtocol A valid SbgEComProtocol handle. + * \return SBG_NO_ERROR if the incoming data has been purged successfully. + */ +SbgErrorCode sbgEComProtocolPurgeIncoming(SbgEComProtocol *pProtocol); + +/*! + * Send data. + * + * If the size is SBG_ECOM_MAX_PAYLOAD_SIZE or less, the data is sent in a single frame. Otherwise, + * is it fragmented into multiple extended frames, each sent in order, which may block. + * + * \param[in] pProtocol A valid protocol handle. + * \param[in] msgClass Message class. + * \param[in] msg Message ID. + * \param[in] pData Data buffer. + * \param[in] size Data buffer size, in bytes. + * \return SBG_NO_ERROR if the frame has been sent. + */ +SbgErrorCode sbgEComProtocolSend(SbgEComProtocol *pProtocol, uint8_t msgClass, uint8_t msg, const void *pData, size_t size); + +/*! + * Receive a frame. + * + * \param[in] pProtocol A valid protocol handle. + * \param[out] pMsgClass Message class, may be NULL. + * \param[out] pMsgId Message ID, may be NULL. + * \param[out] pData Data buffer. + * \param[out] pSize Number of bytes received. + * \param[in] maxSize Data buffer size, in bytes. + * \return SBG_NO_ERROR if successful, + * SBG_NOT_READY if no complete frame has been received, + * SBG_BUFFER_OVERFLOW if the payload of the received frame couldn't fit into the data buffer. + */ +SbgErrorCode sbgEComProtocolReceive(SbgEComProtocol *pProtocol, uint8_t *pMsgClass, uint8_t *pMsgId, void *pData, size_t *pSize, size_t maxSize); + +/*! + * Receive a frame. + * + * This function is equivalent to sbgEComProtocolReceive() with two exceptions : + * - the use of a payload object allows handling payloads not limited by the size of a user-provided buffer + * - the payload object allows direct access to the protocol work buffer to avoid an extra copy per call + * + * Any allocated resource associated with the given payload is released when calling this function. + * + * Because the payload buffer may directly refer to the protocol work buffer on return, it is only valid until + * the next attempt to receive a frame, with any of the receive functions. + * + * \param[in] pProtocol A valid protocol handle. + * \param[out] pMsgClass Message class, may be NULL. + * \param[out] pMsgId Message ID, may be NULL. + * \param[out] pPayload Payload. + * \return SBG_NO_ERROR if successful, + * SBG_NOT_READY if no complete frame has been received. + */ +SbgErrorCode sbgEComProtocolReceive2(SbgEComProtocol *pProtocol, uint8_t *pMsgClass, uint8_t *pMsgId, SbgEComProtocolPayload *pPayload); + +/*! + * Initialize an output stream for an sbgECom frame generation. + * + * This function is helpful to avoid memory copy compared to sbgEComProtocolSend one. + * + * Only standard frames may be sent with this function. + * + * \param[in] pOutputStream Pointer to an allocated and initialized output stream. + * \param[in] msgClass Message class. + * \param[in] msg Message ID. + * \param[out] pStreamCursor The initial output stream cursor that thus points to the begining of the generated message. + * This value should be passed to sbgEComFinalizeFrameGeneration for correct operations. + * \return SBG_NO_ERROR in case of good operation. + */ +SbgErrorCode sbgEComStartFrameGeneration(SbgStreamBuffer *pOutputStream, uint8_t msgClass, uint8_t msg, size_t *pStreamCursor); + +/*! + * Finalize an output stream that has been initialized with sbgEComStartFrameGeneration. + * + * At return, the output stream buffer should point at the end of the generated message. + * You can thus easily create consecutive SBG_ECOM_LOGS with these methods. + * + * \param[in] pOutputStream Pointer to an allocated and initialized output stream. + * \param[in] streamCursor Position in the stream buffer of the generated message first byte. + * This value is returned by sbgEComStartFrameGeneration and is mandatory for correct operations. + * \return SBG_NO_ERROR in case of good operation. + */ +SbgErrorCode sbgEComFinalizeFrameGeneration(SbgStreamBuffer *pOutputStream, size_t streamCursor); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_PROTOCOL_H diff --git a/crates/sbg-rs/sbgECom/src/sbgECanId.h b/crates/sbg-rs/sbgECom/src/sbgECanId.h new file mode 100644 index 0000000..e4790a3 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/sbgECanId.h @@ -0,0 +1,162 @@ +/*! + * \file sbgECanId.h + * \ingroup main + * \author SBG Systems + * \date 10 October 2014 + * + * \brief Defines all sbgECom commands identifiers. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECAN_ID_H +#define SBG_ECAN_ID_H + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Definition of all messages id for sbgECan -// +//----------------------------------------------------------------------// + +/*! + * Enum containing the list of messages that can be output on the can interface. + */ +typedef enum _SbgECanMessageId +{ + // + // Output Messages + // + SBG_ECAN_MSG_STATUS_01 = 0x100, + SBG_ECAN_MSG_STATUS_02 = 0x101, + SBG_ECAN_MSG_STATUS_03 = 0x102, + + SBG_ECAN_MSG_UTC_0 = 0x110, + SBG_ECAN_MSG_UTC_1 = 0x111, + + SBG_ECAN_MSG_IMU_INFO = 0x120, + SBG_ECAN_MSG_IMU_ACCEL = 0x121, + SBG_ECAN_MSG_IMU_GYRO = 0x122, + SBG_ECAN_MSG_IMU_DELTA_VEL = 0x123, + SBG_ECAN_MSG_IMU_DELTA_ANGLE = 0x124, + + SBG_ECAN_MSG_EKF_INFO = 0x130, + SBG_ECAN_MSG_EKF_QUAT = 0x131, + SBG_ECAN_MSG_EKF_EULER = 0x132, + SBG_ECAN_MSG_EKF_ORIENTATION_ACC = 0x133, + SBG_ECAN_MSG_EKF_POS = 0x134, + SBG_ECAN_MSG_EKF_ALTITUDE = 0x135, + SBG_ECAN_MSG_EKF_POS_ACC = 0x136, + SBG_ECAN_MSG_EKF_VEL_NED = 0x137, + SBG_ECAN_MSG_EKF_VEL_NED_ACC = 0x138, + SBG_ECAN_MSG_EKF_VEL_BODY = 0x139, + + SBG_ECAN_MSG_SHIP_MOTION_INFO = 0x140, + SBG_ECAN_MSG_SHIP_MOTION_0 = 0x141, + SBG_ECAN_MSG_SHIP_MOTION_1 = 0x145, + SBG_ECAN_MSG_SHIP_MOTION_2 = 0x149, + + SBG_ECAN_MSG_SHIP_MOTION_HP_INFO = 0x14A, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_SHIP_MOTION_HP_0 = 0x14B, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_SHIP_MOTION_HP_1 = 0x14C, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_SHIP_MOTION_HP_2 = 0x14D, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + + SBG_ECAN_MSG_MAG_0 = 0x150, + SBG_ECAN_MSG_MAG_1 = 0x151, + SBG_ECAN_MSG_MAG_2 = 0x152, + + SBG_ECAN_MSG_ODO_INFO = 0x160, + SBG_ECAN_MSG_ODO_VEL = 0x161, + + SBG_ECAN_MSG_AIR_DATA_INFO = 0x162, + SBG_ECAN_MSG_AIR_DATA_ALTITUDE = 0x163, + SBG_ECAN_MSG_AIR_DATA_AIRSPEED = 0x164, + + SBG_ECAN_MSG_DEPTH_INFO = 0x166, + SBG_ECAN_MSG_DEPTH_ALTITUDE = 0x167, + + SBG_ECAN_MSG_GPS1_VEL_INFO = 0x170, + SBG_ECAN_MSG_GPS1_VEL = 0x171, + SBG_ECAN_MSG_GPS1_VEL_ACC = 0x172, + SBG_ECAN_MSG_GPS1_VEL_COURSE = 0x173, + SBG_ECAN_MSG_GPS1_POS_INFO = 0x174, + SBG_ECAN_MSG_GPS1_POS = 0x175, + SBG_ECAN_MSG_GPS1_POS_ALT = 0x176, + SBG_ECAN_MSG_GPS1_POS_ACC = 0x177, + SBG_ECAN_MSG_GPS1_HDT_INFO = 0x178, + SBG_ECAN_MSG_GPS1_HDT = 0x179, + + SBG_ECAN_MSG_GPS2_VEL_INFO = 0x180, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_GPS2_VEL = 0x181, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_GPS2_VEL_ACC = 0x182, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_GPS2_VEL_COURSE = 0x183, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_GPS2_POS_INFO = 0x184, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_GPS2_POS = 0x185, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_GPS2_POS_ALT = 0x186, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_GPS2_POS_ACC = 0x187, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_GPS2_HDT_INFO = 0x188, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_GPS2_HDT = 0x189, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + + SBG_ECAN_MSG_EVENT_INFO_A = 0x200, + SBG_ECAN_MSG_EVENT_TIME_A = 0x201, + SBG_ECAN_MSG_EVENT_INFO_B = 0x202, + SBG_ECAN_MSG_EVENT_TIME_B = 0x203, + SBG_ECAN_MSG_EVENT_INFO_C = 0x204, + SBG_ECAN_MSG_EVENT_TIME_C = 0x205, + SBG_ECAN_MSG_EVENT_INFO_D = 0x206, + SBG_ECAN_MSG_EVENT_TIME_D = 0x207, + SBG_ECAN_MSG_EVENT_INFO_E = 0x208, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + SBG_ECAN_MSG_EVENT_TIME_E = 0x209, /*!< Only for Ekinox, Apogee, Navsight & Quanta */ + + // + // Proprietary CASS logs + // + SBG_ECAN_MSG_CASS_DATINF = 0x210, + SBG_ECAN_MSG_CASS_ACCS = 0x211, + SBG_ECAN_MSG_CASS_OMGS = 0x212, + SBG_ECAN_MSG_CASS_NRPY = 0x213, + SBG_ECAN_MSG_CASS_VEL = 0x214, + SBG_ECAN_MSG_CASS_TIME = 0x215, + SBG_ECAN_MSG_CASS_GPS_INF = 0x216, + SBG_ECAN_MSG_CASS_GPS_COG = 0x217, + SBG_ECAN_MSG_CASS_ADDINF = 0x218, + SBG_ECAN_MSG_CASS_POS1 = 0x219, + SBG_ECAN_MSG_CASS_POS2 = 0x21A, + SBG_ECAN_MSG_CASS_SAT_INF = 0x21B, + SBG_ECAN_MSG_CASS_IACCS = 0x21C, + SBG_ECAN_MSG_CASS_IOMG = 0x21D, + SBG_ECAN_MSG_CASS_RR = 0x21E, + + // + // Automotive specific CAN output + // + SBG_ECAN_MSG_AUTO_TRACK_SLIP_CURV = 0x220, +} SbgECanMessageId; + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECAN_ID_H diff --git a/crates/sbg-rs/sbgECom/src/sbgECom.c b/crates/sbg-rs/sbgECom/src/sbgECom.c new file mode 100644 index 0000000..ec29ecb --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/sbgECom.c @@ -0,0 +1,256 @@ +#include "sbgECom.h" +#include +#include "commands/sbgEComCmdCommon.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComInit(SbgEComHandle *pHandle, SbgInterface *pInterface) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + + assert(pHandle); + assert(pInterface); + + // + // Initialize the sbgECom handle + // + pHandle->pReceiveLogCallback = NULL; + pHandle->pUserArg = NULL; + + // + // Initialize the default number of trials and time out + // + pHandle->numTrials = 3; + pHandle->cmdDefaultTimeOut = SBG_ECOM_DEFAULT_CMD_TIME_OUT; + + // + // Initialize the protocol + // + errorCode = sbgEComProtocolInit(&pHandle->protocolHandle, pInterface); + + return errorCode; +} + +SbgErrorCode sbgEComClose(SbgEComHandle *pHandle) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + + assert(pHandle); + + // + // Close the protocol + // + errorCode = sbgEComProtocolClose(&pHandle->protocolHandle); + + return errorCode; +} + +SbgErrorCode sbgEComHandleOneLog(SbgEComHandle *pHandle) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgBinaryLogData logData; + uint8_t receivedMsg; + uint8_t receivedMsgClass; + size_t payloadSize; + uint8_t payloadData[SBG_ECOM_MAX_PAYLOAD_SIZE]; + + assert(pHandle); + + // + // Try to read a received frame + // + errorCode = sbgEComProtocolReceive(&pHandle->protocolHandle, &receivedMsgClass, &receivedMsg, payloadData, &payloadSize, sizeof(payloadData)); + + // + // Test if we have received a valid frame + // + if (errorCode == SBG_NO_ERROR) + { + // + // Test if the received frame is a binary log + // + if (sbgEComMsgClassIsALog((SbgEComClass)receivedMsgClass)) + { + // + // The received frame is a binary log one + // + errorCode = sbgEComBinaryLogParse((SbgEComClass)receivedMsgClass, (SbgEComMsgId)receivedMsg, payloadData, payloadSize, &logData); + + // + // Test if the incoming log has been parsed successfully + // + if (errorCode == SBG_NO_ERROR) + { + // + // Test if we have a valid callback to handle received logs + // + if (pHandle->pReceiveLogCallback) + { + // + // Call the binary log callback using the new method + // + errorCode = pHandle->pReceiveLogCallback(pHandle, (SbgEComClass)receivedMsgClass, receivedMsg, &logData, pHandle->pUserArg); + } + + // + // Clean up resources allocated during parsing, if any. + // + sbgEComBinaryLogCleanup(&logData, (SbgEComClass)receivedMsgClass, (SbgEComMsgId)receivedMsg); + } + else + { + // + // Call the on error callback + // + } + } + else + { + // + // We have received a command, it shouldn't happen + // + } + } + else if (errorCode != SBG_NOT_READY) + { + // + // We have received an invalid frame + // + SBG_LOG_WARNING(errorCode, "Invalid frame received"); + } + + return errorCode; +} + +SbgErrorCode sbgEComHandle(SbgEComHandle *pHandle) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + + assert(pHandle); + + // + // Try to read all received frames, we thus loop until we get an SBG_NOT_READY error + // + do + { + // + // Try to read and parse one frame + // + errorCode = sbgEComHandleOneLog(pHandle); + } while (errorCode != SBG_NOT_READY); + + return errorCode; +} + +SbgErrorCode sbgEComPurgeIncoming(SbgEComHandle *pHandle) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + + assert(pHandle); + + errorCode = sbgEComProtocolPurgeIncoming(&pHandle->protocolHandle); + + return errorCode; +} + +void sbgEComSetReceiveLogCallback(SbgEComHandle *pHandle, SbgEComReceiveLogFunc pReceiveLogCallback, void *pUserArg) +{ + assert(pHandle); + + // + // Define the callback and the user argument + // + pHandle->pReceiveLogCallback = pReceiveLogCallback; + pHandle->pUserArg = pUserArg; +} + +void sbgEComSetCmdTrialsAndTimeOut(SbgEComHandle *pHandle, uint32_t numTrials, uint32_t cmdDefaultTimeOut) +{ + assert(pHandle); + assert(numTrials > 0); + assert(cmdDefaultTimeOut > 0); + + // + // Define the new settings + // + pHandle->numTrials = numTrials; + pHandle->cmdDefaultTimeOut = cmdDefaultTimeOut; +} + +void sbgEComErrorToString(SbgErrorCode errorCode, char errorMsg[256]) +{ + if (errorMsg) + { + // + // For each error code, copy the error msg + // + switch (errorCode) + { + case SBG_NO_ERROR: + strcpy(errorMsg, "SBG_NO_ERROR: No error."); + break; + case SBG_ERROR: + strcpy(errorMsg, "SBG_ERROR: Generic error."); + break; + case SBG_NULL_POINTER: + strcpy(errorMsg, "SBG_NULL_POINTER: A pointer is null."); + break; + case SBG_INVALID_CRC: + strcpy(errorMsg, "SBG_INVALID_CRC: The received frame has an invalid CRC."); + break; + case SBG_INVALID_FRAME: + strcpy(errorMsg, "SBG_INVALID_FRAME: The received frame is invalid."); + break; + case SBG_TIME_OUT: + strcpy(errorMsg, "SBG_TIME_OUT: We have a time out during frame reception."); + break; + case SBG_WRITE_ERROR: + strcpy(errorMsg, "SBG_WRITE_ERROR: All bytes hasn't been written."); + break; + case SBG_READ_ERROR: + strcpy(errorMsg, "SBG_READ_ERROR: All bytes hasn't been read."); + break; + case SBG_BUFFER_OVERFLOW: + strcpy(errorMsg, "SBG_BUFFER_OVERFLOW: A buffer is too small to contain so much data."); + break; + case SBG_INVALID_PARAMETER: + strcpy(errorMsg, "SBG_INVALID_PARAMETER: An invalid parameter has been founded."); + break; + case SBG_NOT_READY: + strcpy(errorMsg, "SBG_NOT_READY: A device isn't ready (Rx isn't ready for example)."); + break; + case SBG_MALLOC_FAILED: + strcpy(errorMsg, "SBG_MALLOC_FAILED: Failed to allocate a buffer."); + break; + case SGB_CALIB_MAG_NOT_ENOUGH_POINTS: + strcpy(errorMsg, "SGB_CALIB_MAG_NOT_ENOUGH_POINTS: Not enough points were available to perform magnetometers calibration."); + break; + case SBG_CALIB_MAG_INVALID_TAKE: + strcpy(errorMsg, "SBG_CALIB_MAG_INVALID_TAKE: The calibration procedure could not be properly executed due to insufficient precision."); + break; + case SBG_CALIB_MAG_SATURATION: + strcpy(errorMsg, "SBG_CALIB_MAG_SATURATION: Saturation were detected when attempt to calibrate magnetos."); + break; + case SBG_CALIB_MAG_POINTS_NOT_IN_A_PLANE: + strcpy(errorMsg, "SBG_CALIB_MAG_POINTS_NOT_IN_A_PLANE: 2D calibration procedure could not be performed."); + break; + case SBG_DEVICE_NOT_FOUND: + strcpy(errorMsg, "SBG_DEVICE_NOT_FOUND: A device couldn't be founded or opened."); + break; + case SBG_OPERATION_CANCELLED: + strcpy(errorMsg, "SBG_OPERATION_CANCELLED: An operation has been cancelled by a user."); + break; + case SBG_NOT_CONTINUOUS_FRAME: + strcpy(errorMsg, "SBG_NOT_CONTINUOUS_FRAME: We have received a frame that isn't a continuous one."); + break; + case SBG_INCOMPATIBLE_HARDWARE: + strcpy(errorMsg, "SBG_INCOMPATIBLE_HARDWARE: Hence valid, the configuration cannot be executed because of incompatible hardware."); + break; + default: + sprintf(errorMsg, "Undefined error code: %u", errorCode); + break; + } + } +} diff --git a/crates/sbg-rs/sbgECom/src/sbgECom.h b/crates/sbg-rs/sbgECom/src/sbgECom.h new file mode 100644 index 0000000..17a7689 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/sbgECom.h @@ -0,0 +1,177 @@ +/*! + * \file sbgECom.h + * \ingroup main + * \author SBG Systems + * \date 05 February 2013 + * + * \brief Contains main sbgECom methods. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +/*! + * \defgroup main Main Library + * \brief Main sbgECom library initialization and parsing methods. + */ + +#ifndef SBG_ECOM_H +#define SBG_ECOM_H + +#ifdef __cplusplus +extern "C" { +#endif + +// sbgCommonLib headers +#include + +// Local headers +#include "sbgECanId.h" +#include "sbgEComIds.h" +#include "protocol/sbgEComProtocol.h" +#include "binaryLogs/sbgEComBinaryLogs.h" + +//----------------------------------------------------------------------// +//- Predefinitions -// +//----------------------------------------------------------------------// + +/*! + * Interface structure pre-definition. + */ +typedef struct _SbgEComHandle SbgEComHandle; + +//----------------------------------------------------------------------// +//- Callbacks definitions -// +//----------------------------------------------------------------------// + +/*! + * Callback definition called each time a new log is received. + * + * \param[in] pHandle Valid handle on the sbgECom instance that has called this callback. + * \param[in] msgClass Class of the message we have received + * \param[in] msg Message ID of the log received. + * \param[in] pLogData Contains the received log data as an union. + * \param[in] pUserArg Optional user supplied argument. + * \return SBG_NO_ERROR if the received log has been used successfully. + */ +typedef SbgErrorCode (*SbgEComReceiveLogFunc)(SbgEComHandle *pHandle, SbgEComClass msgClass, SbgEComMsgId msg, const SbgBinaryLogData *pLogData, void *pUserArg); + +//----------------------------------------------------------------------// +//- Structures definitions -// +//----------------------------------------------------------------------// + +/*! + * Interface definition that stores methods used to communicate on the interface. + */ +struct _SbgEComHandle +{ + SbgEComProtocol protocolHandle; /*!< Handle on the protocol system. */ + + SbgEComReceiveLogFunc pReceiveLogCallback; /*!< Pointer on the method called each time a new binary log is received. */ + void *pUserArg; /*!< Optional user supplied argument for callbacks. */ + + uint32_t numTrials; /*!< Number of trials when a command is sent (default is 3). */ + uint32_t cmdDefaultTimeOut; /*!< Default time out in ms to get an answer from the device (default 500 ms). */ +}; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Initialize the protocol system used to communicate with the product and return the created handle. + * + * \param[out] pHandle Pointer used to store the allocated and initialized sbgECom handle. + * \param[in] pInterface Interface to use for read/write operations. + * \return SBG_NO_ERROR if we have initialized the protocol system. + */ +SbgErrorCode sbgEComInit(SbgEComHandle *pHandle, SbgInterface *pInterface); + +/*! + * Close the protocol system and release associated memory. + * + * \param[in] pHandle A valid sbgECom handle to close. + * \return SBG_NO_ERROR if we have closed and released the sbgECom system. + */ +SbgErrorCode sbgEComClose(SbgEComHandle *pHandle); + +/*! + * Try to parse one log from the input interface and then return. + * + * \param[in] pHandle A valid sbgECom handle. + * \return SBG_NO_ERROR if no error occurs during incoming log parsing. + */ +SbgErrorCode sbgEComHandleOneLog(SbgEComHandle *pHandle); + +/*! + * Handle all incoming logs until no more log are available in the input interface. + * + * \param[in] pHandle A valid sbgECom handle. + * \return SBG_NO_ERROR if no error occurs during incoming logs parsing. + */ +SbgErrorCode sbgEComHandle(SbgEComHandle *pHandle); + +/*! + * Purge the interface rx buffer as well as the sbgECom rx work buffer. + * + * For example, if the program flow has been interrupted, this method can be helpful to discard all trash received data. + * + * WARNING: This method is blocking for 100ms and actively tries to read incoming data. + * + * \param[in] pHandle A valid sbgECom handle. + * \return SBG_NO_ERROR if the incoming data has been purged successfully. + */ +SbgErrorCode sbgEComPurgeIncoming(SbgEComHandle *pHandle); + +/*! + * Define the callback that should be called each time a new binary log is received. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] pReceiveLogCallback Pointer on the callback to call when a new log is received. + * \param[in] pUserArg Optional user argument that will be passed to the callback method. + */ +void sbgEComSetReceiveLogCallback(SbgEComHandle *pHandle, SbgEComReceiveLogFunc pReceiveLogCallback, void *pUserArg); + +/*! + * Define the default number of trials that should be done when a command is send to the device as well as the time out. + * + * \param[in] pHandle A valid sbgECom handle. + * \param[in] numTrials Number of trials when a command is sent (starting at 1). + * \param[in] cmdDefaultTimeOut Default time out in milliseconds to wait to receive an answer from the device. + */ +void sbgEComSetCmdTrialsAndTimeOut(SbgEComHandle *pHandle, uint32_t numTrials, uint32_t cmdDefaultTimeOut); + +/*! + * Convert an error code into a human readable string. + * + * \param[in] errorCode The errorCode to convert into a string. + * \param[out] errorMsg String buffer used to hold the error string. + */ +void sbgEComErrorToString(SbgErrorCode errorCode, char errorMsg[256]); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_H + diff --git a/crates/sbg-rs/sbgECom/src/sbgEComGetVersion.c b/crates/sbg-rs/sbgECom/src/sbgEComGetVersion.c new file mode 100644 index 0000000..8c2f207 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/sbgEComGetVersion.c @@ -0,0 +1,23 @@ +// sbgCommonLib headers +#include +#include + +// Project headers +#include "sbgEComVersion.h" + +// Local headers +#include "sbgEComGetVersion.h" + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +uint32_t sbgEComGetVersion(void) +{ + return SBG_E_COM_VERSION; +} + +const char *sbgEComGetVersionAsString(void) +{ + return SBG_E_COM_VERSION_STR; +} diff --git a/crates/sbg-rs/sbgECom/src/sbgEComGetVersion.h b/crates/sbg-rs/sbgECom/src/sbgEComGetVersion.h new file mode 100644 index 0000000..6f628b7 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/sbgEComGetVersion.h @@ -0,0 +1,64 @@ +/*! + * \file sbgEComGetVersion.h + * \ingroup main + * \author SBG Systems + * \date 05 February 2013 + * \brief Version information. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_GET_VERSION_H +#define SBG_ECOM_GET_VERSION_H + +// sbgCommonLib headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Returns an integer representing the version of the sbgECom library. + * + * \return An integer representing the version of the sbgECom library.
+ */ +uint32_t sbgEComGetVersion(void); + +/*! + * Retrieve the sbgECom library version as a string (1.0.443-stable). + * + * \return Null terminated string that contains the sbgECom library version. + */ +const char *sbgEComGetVersionAsString(void); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_GET_VERSION_H diff --git a/crates/sbg-rs/sbgECom/src/sbgEComIds.h b/crates/sbg-rs/sbgECom/src/sbgEComIds.h new file mode 100644 index 0000000..dfe39f8 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/sbgEComIds.h @@ -0,0 +1,341 @@ +/*! + * \file sbgEComIds.h + * \ingroup main + * \author SBG Systems + * \date 25 February 2013 + * + * \brief Defines all sbgECom commands identifiers. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_IDS_H +#define SBG_ECOM_IDS_H + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Definition of all class id for sbgECom -// +//----------------------------------------------------------------------// + +/*! + * Enum that defines all the message classes available. + * + * Keep in mind that message classes are encoded on 7 bits. + */ +typedef enum _SbgEComClass +{ + SBG_ECOM_CLASS_LOG_ECOM_0 = 0x00, /*!< Class that contains sbgECom protocol input/output log messages. */ + + SBG_ECOM_CLASS_LOG_ECOM_1 = 0x01, /*!< Class that contains special sbgECom output messages that handle high frequency output. */ + + SBG_ECOM_CLASS_LOG_NMEA_0 = 0x02, /*!< Class that contains NMEA (and NMEA like) output logs.
+ Note: This class is only used for identification purpose and does not contain any sbgECom message. */ + SBG_ECOM_CLASS_LOG_NMEA_1 = 0x03, /*!< Class that contains proprietary NMEA (and NMEA like) output logs.
+ Note: This class is only used for identification purpose and does not contain any sbgECom message. */ + SBG_ECOM_CLASS_LOG_THIRD_PARTY_0 = 0x04, /*!< Class that contains third party output logs. + Note: This class is only used for identification purpose and does not contain any sbgECom message. */ + + SBG_ECOM_CLASS_LOG_CMD_0 = 0x10, /*!< Class that contains sbgECom protocol commands. */ + +} SbgEComClass; + +//----------------------------------------------------------------------// +//- Definition of all messages id for sbgECom -// +//----------------------------------------------------------------------// + +/*! + * Enum that defines all the available ECom output logs from the sbgECom library. + */ +typedef enum _SbgEComLog +{ + SBG_ECOM_LOG_STATUS = 1, /*!< Status general, clock, com aiding, solution, heave */ + + SBG_ECOM_LOG_UTC_TIME = 2, /*!< Provides UTC time reference */ + + SBG_ECOM_LOG_IMU_DATA = 3, /*!< Includes IMU status, acc., gyro, temp delta speeds and delta angles values */ + + SBG_ECOM_LOG_MAG = 4, /*!< Magnetic data with associated accelerometer on each axis */ + SBG_ECOM_LOG_MAG_CALIB = 5, /*!< Magnetometer calibration data (raw buffer) */ + + SBG_ECOM_LOG_EKF_EULER = 6, /*!< Includes roll, pitch, yaw and their accuracies on each axis */ + SBG_ECOM_LOG_EKF_QUAT = 7, /*!< Includes the 4 quaternions values */ + SBG_ECOM_LOG_EKF_NAV = 8, /*!< Position and velocities in NED coordinates with the accuracies on each axis */ + + SBG_ECOM_LOG_SHIP_MOTION = 9, /*!< Heave, surge and sway and accelerations on each axis. */ + + SBG_ECOM_LOG_GPS1_VEL = 13, /*!< GPS velocities from primary or secondary GPS receiver */ + SBG_ECOM_LOG_GPS1_POS = 14, /*!< GPS positions from primary or secondary GPS receiver */ + SBG_ECOM_LOG_GPS1_HDT = 15, /*!< GPS true heading from dual antenna system */ + SBG_ECOM_LOG_GPS1_RAW = 31, /*!< GPS 1 raw data for post processing. */ + SBG_ECOM_LOG_GPS1_SAT = 50, /*!< GPS 1 Satellite data. */ + + SBG_ECOM_LOG_GPS2_VEL = 16, /*!< GPS 2 velocity log data. */ + SBG_ECOM_LOG_GPS2_POS = 17, /*!< GPS 2 position log data. */ + SBG_ECOM_LOG_GPS2_HDT = 18, /*!< GPS 2 true heading log data. */ + SBG_ECOM_LOG_GPS2_RAW = 38, /*!< GPS 2 raw data for post processing. */ + SBG_ECOM_LOG_GPS2_SAT = 51, /*!< GNSS2 Satellite data. */ + + SBG_ECOM_LOG_ODO_VEL = 19, /*!< Provides odometer velocity */ + + SBG_ECOM_LOG_EVENT_A = 24, /*!< Event markers sent when events are detected on sync in A pin */ + SBG_ECOM_LOG_EVENT_B = 25, /*!< Event markers sent when events are detected on sync in B pin */ + SBG_ECOM_LOG_EVENT_C = 26, /*!< Event markers sent when events are detected on sync in C pin */ + SBG_ECOM_LOG_EVENT_D = 27, /*!< Event markers sent when events are detected on sync in D pin */ + SBG_ECOM_LOG_EVENT_E = 28, /*!< Event markers sent when events are detected on sync in E pin */ + + SBG_ECOM_LOG_DVL_BOTTOM_TRACK = 29, /*!< Doppler Velocity Log for bottom tracking data. */ + SBG_ECOM_LOG_DVL_WATER_TRACK = 30, /*!< Doppler Velocity log for water layer data. */ + + SBG_ECOM_LOG_SHIP_MOTION_HP = 32, /*!< Return delayed ship motion such as surge, sway, heave. */ + + SBG_ECOM_LOG_AIR_DATA = 36, /*!< Air Data aiding such as barometric altimeter and true air speed. */ + + SBG_ECOM_LOG_USBL = 37, /*!< Raw USBL position data for subsea navigation. */ + + + SBG_ECOM_LOG_IMU_SHORT = 44, /*!< Short IMU message recommended for post processing usages. */ + + SBG_ECOM_LOG_EVENT_OUT_A = 45, /*!< Event marker used to time stamp each generated Sync Out A signal. */ + SBG_ECOM_LOG_EVENT_OUT_B = 46, /*!< Event marker used to time stamp each generated Sync Out B signal. */ + + SBG_ECOM_LOG_DEPTH = 47, /*!< Depth sensor measurement log used for subsea navigation. */ + SBG_ECOM_LOG_DIAG = 48, /*!< Diagnostic log. */ + + SBG_ECOM_LOG_RTCM_RAW = 49, /*!< RTCM raw data. */ + + SBG_ECOM_LOG_ECOM_NUM_MESSAGES /*!< Helper definition to know the number of ECom messages */ +} SbgEComLog; + +/*! + * Enum that defines all the available ECom output logs in the class SBG_ECOM_CLASS_LOG_ECOM_1 + */ +typedef enum _SbgEComLog1MsgId +{ + SBG_ECOM_LOG_FAST_IMU_DATA = 0, /*!< Provides accelerometers, gyroscopes, time and status at 1KHz rate. */ + SBG_ECOM_LOG_ECOM_1_NUM_MESSAGES /*!< Helper definition to know the number of ECom messages */ +} SbgEComLog1; + +/*! + * Enum that defines all the available Nmea output logs from the sbgECom library. + */ +typedef enum _SbgEComNmeaLog +{ + SBG_ECOM_LOG_NMEA_GGA = 0, /*!< Latitude, Longitude, Altitude, Quality indicator. */ + SBG_ECOM_LOG_NMEA_RMC = 1, /*!< Latitude, Longitude, velocity, course over ground. */ + SBG_ECOM_LOG_NMEA_ZDA = 2, /*!< UTC Time. */ + SBG_ECOM_LOG_NMEA_HDT = 3, /*!< Heading (True). */ + SBG_ECOM_LOG_NMEA_GST = 4, /*!< GPS Pseudorange Noise Statistics. */ + SBG_ECOM_LOG_NMEA_VBW = 5, /*!< Water referenced and ground referenced speed data. */ + SBG_ECOM_LOG_NMEA_DPT = 7, /*!< Depth sensor output. */ + SBG_ECOM_LOG_NMEA_VTG = 8, /*!< Track an Speed over the ground. */ + SBG_ECOM_LOG_NMEA_RTO = 9, /*!< Rate and direction of turn. */ + SBG_ECOM_LOG_NMEA_GSV = 10, /*!< GNSS Satellites in View with azimuth, elevation and SNR information */ + SBG_ECOM_LOG_NMEA_NUM_MESSAGES /*!< Helper definition to know the number of NMEA messages */ +} SbgEComNmeaLog; + +/*! + * Enum that defines all the available Proprietary Nmea output logs from the sbgECom library. + */ +typedef enum _SbgEComIdNmea1Log +{ + SBG_ECOM_LOG_NMEA_1_PRDID = 0, /*!< RDI proprietary sentence. Pitch, Roll, Heading */ + SBG_ECOM_LOG_NMEA_1_PSBGI = 1, /*!< SBG Systems proprietary sentence. Rotation rates, accelerations. */ + SBG_ECOM_LOG_NMEA_1_PASHR = 2, /*!< Proprietary sentence. Roll, Pitch, Heading, Heave. */ + SBG_ECOM_LOG_NMEA_1_PSBGB = 3, /*!< SBG Systems proprietary sentence. Attitude, heading, heave, angular rates, velocity. */ + + SBG_ECOM_LOG_NMEA_1_PHINF = 5, /*!< Ixblue NMEA like log used to output Status information. */ + SBG_ECOM_LOG_NMEA_1_PHTRO = 6, /*!< Ixblue NMEA like log used to output Roll and Pitch. */ + SBG_ECOM_LOG_NMEA_1_PHLIN = 7, /*!< Ixblue NMEA like log used to output Surge, Sway and Heave. */ + SBG_ECOM_LOG_NMEA_1_PHOCT = 8, /*!< Ixblue NMEA like log used to output attitude and ship motion. */ + SBG_ECOM_LOG_NMEA_1_INDYN = 9, /*!< Ixblue NMEA like log used to output position, heading, attitude, attitude rate and speed. */ + + SBG_ECOM_LOG_NMEA_1_GGK = 10, /*!< Trimble NMEA like log with Time, Latitude, Longitude, Ellipsoidal height */ + SBG_ECOM_LOG_NMEA_1_PPS = 11, /*!< Trimble (Applanix) NMEA like log with UTC and PPS information. */ + + SBG_ECOM_LOG_NMEA_1_WASSP = 12, /*!< WASSP NMEA like log similar to PASHR one. */ + + SBG_ECOM_LOG_NMEA_1_PSBGA = 13, /*!< SBG Systems proprietary sentence that reports EKF attitude and status. */ + + SBG_ECOM_LOG_NMEA_1_NUM_MESSAGES /*!< Helper definition to know the number of NMEA messages */ +} SbgEComIdNmea1Log; + +/*! + * Enum that defines all the available Proprietary output logs from the sbgECom library. + */ +typedef enum _SbgEComIdThirdParty +{ + SBG_ECOM_THIRD_PARTY_TSS1 = 0, /*!< Roll, Pitch, Heave, heave accelerations */ + SBG_ECOM_THIRD_PARTY_KVH = 1, /*!< Roll, Pitch, Yaw */ + + SBG_ECOM_THIRD_PARTY_PD0 = 2, /*!< Teledyne PD0 DVL proprietary frame. */ + SBG_ECOM_THIRD_PARTY_SIMRAD_1000 = 3, /*!< Konsberg SimRad 1000 proprietary frame that outputs Roll, Pitch and Heading. */ + SBG_ECOM_THIRD_PARTY_SIMRAD_3000 = 4, /*!< Konsberg SimRad 3000 proprietary frame that outputs Roll, Pitch and Heading. */ + + SBG_ECOM_THIRD_PARTY_SEAPATH_B26 = 5, /*!< Konsberg Seapth Binary Log 26 used for MBES FM mode. */ + SBG_ECOM_THIRD_PARTY_DOLOG_HRP = 6, /*!< DOLOG Heading, Roll, Pitch proprietary and binary message. */ + SBG_ECOM_THIRD_PARTY_AHRS_500 = 7, /*!< Crossbow AHRS-500 Data Packet output with attitude, rate, acceleration and status. */ + SBG_ECOM_THIRD_PARTY_ADA_01 = 8, /*!< ADA specific Data Packet with IMU/INS/Status data */ + + SBG_ECOM_THIRD_PARTY_AT_ITINS = 9, /*!< Cobham Aviator UAV 200 navigation (orientation & position) data */ + + SBG_ECOM_THIRD_PARTY_KONGSBERG_MB = 10, /*!< Kongsberg multibeam binary log. */ + + SBG_ECOM_LOG_THIRD_PARTY_NUM_MESSAGES /*!< Helper definition to know the number of third party messages */ +} SbgEComIdThirdParty; + + +/*! + * Enum that defines all the available commands for the sbgECom library. + */ +typedef enum _SbgEComCmd +{ + /* Acknowledge */ + SBG_ECOM_CMD_ACK = 0, /*!< Acknowledge */ + + /* Special settings commands */ + SBG_ECOM_CMD_SETTINGS_ACTION = 1, /*!< Performs various settings actions */ + SBG_ECOM_CMD_IMPORT_SETTINGS = 2, /*!< Imports a new settings structure to the sensor */ + SBG_ECOM_CMD_EXPORT_SETTINGS = 3, /*!< Export the whole configuration from the sensor */ + + /* Device info */ + SBG_ECOM_CMD_INFO = 4, /*!< Get basic device information */ + + /* Sensor parameters */ + SBG_ECOM_CMD_INIT_PARAMETERS = 5, /*!< Initial configuration */ + SBG_ECOM_CMD_MOTION_PROFILE_ID = 7, /*!< Set/get motion profile information */ + SBG_ECOM_CMD_IMU_ALIGNMENT_LEVER_ARM = 8, /*!< Sensor alignment and lever arm on vehicle configuration */ + SBG_ECOM_CMD_AIDING_ASSIGNMENT = 9, /*!< Aiding assignments such as RTCM / GPS / Odometer configuration */ + + /* Magnetometer configuration */ + SBG_ECOM_CMD_MAGNETOMETER_MODEL_ID = 11, /*!< Set/get magnetometer error model information */ + SBG_ECOM_CMD_MAGNETOMETER_REJECT_MODE = 12, /*!< Magnetometer aiding rejection mode */ + SBG_ECOM_CMD_SET_MAG_CALIB = 13, /*!< Set magnetic soft and hard Iron calibration data */ + + /* Magnetometer on-board calibration */ + SBG_ECOM_CMD_START_MAG_CALIB = 14, /*!< Start / reset internal magnetic field logging for calibration. */ + SBG_ECOM_CMD_COMPUTE_MAG_CALIB = 15, /*!< Compute a magnetic calibration based on previously logged data. */ + + /* GNSS configuration */ + SBG_ECOM_CMD_GNSS_1_MODEL_ID = 17, /*!< Set/get GNSS model information */ + SBG_ECOM_CMD_GNSS_1_LEVER_ARM_ALIGNMENT = 18, /*!< DEPRECATED: GNSS installation configuration (lever arm, antenna alignments) */ + SBG_ECOM_CMD_GNSS_1_INSTALLATION = 46, /*!< Define or retrieve the GNSS 1 main and secondary lever arms configuration. */ + SBG_ECOM_CMD_GNSS_1_REJECT_MODES = 19, /*!< GNSS aiding rejection modes configuration. */ + + /* Odometer configuration */ + SBG_ECOM_CMD_ODO_CONF = 20, /*!< Odometer gain, direction configuration */ + SBG_ECOM_CMD_ODO_LEVER_ARM = 21, /*!< Odometer installation configuration (lever arm) */ + SBG_ECOM_CMD_ODO_REJECT_MODE = 22, /*!< Odometer aiding rejection mode configuration. */ + + /* Interfaces configuration */ + SBG_ECOM_CMD_UART_CONF = 23, /*!< UART interfaces configuration */ + SBG_ECOM_CMD_CAN_BUS_CONF = 24, /*!< CAN bus interface configuration */ + SBG_ECOM_CMD_CAN_OUTPUT_CONF = 25, /*!< CAN identifiers configuration */ + + /* Events configuration */ + SBG_ECOM_CMD_SYNC_IN_CONF = 26, /*!< Synchronization inputs configuration */ + SBG_ECOM_CMD_SYNC_OUT_CONF = 27, /*!< Synchronization outputs configuration */ + + /* Output configuration */ + SBG_ECOM_CMD_NMEA_TALKER_ID = 29, /*!< NMEA talker ID configuration */ + SBG_ECOM_CMD_OUTPUT_CONF = 30, /*!< Output configuration */ + + /* Advanced configuration */ + SBG_ECOM_CMD_ADVANCED_CONF = 32, /*!< Advanced settings configuration */ + + /* Features related commands */ + SBG_ECOM_CMD_FEATURES = 33, /*!< Retrieve device features */ + + /* Licenses related commands */ + SBG_ECOM_CMD_LICENSE_APPLY = 34, /*!< Upload and apply a new license */ + + /* Message class output switch */ + SBG_ECOM_CMD_OUTPUT_CLASS_ENABLE = 35, /*!< Enable/disable the output of an entire class */ + + /* Ethernet configuration */ + SBG_ECOM_CMD_ETHERNET_CONF = 36, /*!< Set/get Ethernet configuration such as DHCP mode and IP address. */ + SBG_ECOM_CMD_ETHERNET_INFO = 37, /*!< Return the current IP used by the device. */ + + /* Validity thresholds */ + SBG_ECOM_CMD_VALIDITY_THRESHOLDS = 38, /*!< Set/get Validity flag thresholds for position, velocity, attitude and heading */ + + /* DVL configuration */ + SBG_ECOM_CMD_DVL_MODEL_ID = 39, /*!< Set/get DVL model id to use */ + SBG_ECOM_CMD_DVL_INSTALLATION = 40, /*!< DVL installation configuration (lever arm, alignments) */ + SBG_ECOM_CMD_DVL_REJECT_MODES = 41, /*!< DVL aiding rejection modes configuration. */ + + /* AirData configuration */ + SBG_ECOM_CMD_AIRDATA_MODEL_ID = 42, /*!< Set/get AirData model id and protocol to use. */ + SBG_ECOM_CMD_AIRDATA_LEVER_ARM = 43, /*!< AirData installation configuration (lever arm, offsets) */ + SBG_ECOM_CMD_AIRDATA_REJECT_MODES = 44, /*!< AirData aiding rejection modes configuration. */ + + /* Odometer configuration (using CAN) */ + SBG_ECOM_CMD_ODO_CAN_CONF = 45, /*!< Configuration for CAN based odometer (CAN ID & DBC) */ + + /* REST API related commands */ + SBG_ECOM_CMD_API_GET = 46, /*!< Command equivalent to the HTTP GET method for a REST API. */ + SBG_ECOM_CMD_API_POST = 47, /*!< Command equivalent to the HTTP POST method for a REST API. */ + + /* Misc. */ + SBG_ECOM_LOG_ECOM_NUM_CMDS /*!< Helper definition to know the number of commands */ +} SbgEComCmd; + +/*! + * This type defines any message identifier. + * Because message identifiers enum will be different with each class id, we use a generic uint8_t rather than an enum. + */ +typedef uint8_t SbgEComMsgId; + +//----------------------------------------------------------------------// +//- Inline helpers for log IDs -// +//----------------------------------------------------------------------// + +/*! + * Test if the message class is a binary log one. + * + * \param[in] msgClass Message class. + * \return TRUE if the message class corresponds to a binary log. + */ +SBG_INLINE bool sbgEComMsgClassIsALog(SbgEComClass msgClass) +{ + // + // Test if this class id is part of the enum + // + if ((msgClass == SBG_ECOM_CLASS_LOG_ECOM_0) || (msgClass == SBG_ECOM_CLASS_LOG_ECOM_1) ) + { + return true; + } + else + { + return false; + } +} + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_IDS_H diff --git a/crates/sbg-rs/sbgECom/src/sbgEComLib.h b/crates/sbg-rs/sbgECom/src/sbgEComLib.h new file mode 100644 index 0000000..714f72c --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/sbgEComLib.h @@ -0,0 +1,69 @@ +/*! + * \file sbgEComLib.h + * \ingroup main + * \author SBG Systems + * \date 05 February 2013 + * + * \brief Main header file for the SBG Systems Enhanced Communication Library. + * + * Only this main header file should be included to use the library. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_LIB_H +#define SBG_ECOM_LIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +// sbgCommonLib headers +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local headers +#include "sbgECanId.h" +#include "sbgEComIds.h" +#include "commands/sbgEComCmd.h" +#include "protocol/sbgEComProtocol.h" +#include "binaryLogs/sbgEComBinaryLogs.h" +#include "sbgEComVersion.h" +#include "sbgEComGetVersion.h" + +//----------------------------------------------------------------------// +//- Footer (close extern C block) -// +//----------------------------------------------------------------------// +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_LIB_H diff --git a/crates/sbg-rs/sbgECom/src/sbgEComVersion.h b/crates/sbg-rs/sbgECom/src/sbgEComVersion.h new file mode 100644 index 0000000..2fe6083 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/sbgEComVersion.h @@ -0,0 +1,70 @@ +/*! + * \file sbgEComVersion.h + * \ingroup main + * \author SBG Systems + * \date 05 February 2013 + * + * \brief Header file that contains all versions related information such as change log. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_E_COM_VERSION_H +#define SBG_E_COM_VERSION_H + +// sbgCommonLib headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +//----------------------------------------------------------------------// +//- Version definitions -// +//----------------------------------------------------------------------// + +#define SBG_E_COM_VERSION_MAJOR 3 +#define SBG_E_COM_VERSION_MINOR 2 +#define SBG_E_COM_VERSION_REV 4011 +#define SBG_E_COM_VERSION_BUILD SBG_VERSION_QUALIFIER_STABLE + +#define SBG_E_COM_VERSION SBG_VERSION_SOFTWARE(SBG_E_COM_VERSION_MAJOR,SBG_E_COM_VERSION_MINOR,SBG_E_COM_VERSION_REV,SBG_E_COM_VERSION_BUILD) + +/* + * Backward compatibility macro definitions. + */ + #ifndef SBG_STR + #define SBG_STR(X) #X +#endif +#ifndef SBG_ASSTR + #define SBG_ASSTR(X) SBG_STR(X) +#endif +#define SBG_E_COM_VERSION_STR SBG_ASSTR(SBG_E_COM_VERSION_MAJOR) "." SBG_ASSTR(SBG_E_COM_VERSION_MINOR) "." SBG_ASSTR(SBG_E_COM_VERSION_REV) "-stable\0" + +#ifdef __cplusplus +} +#endif + +#endif // SBG_E_COM_VERSION_H diff --git a/crates/sbg-rs/sbgECom/src/transfer/sbgEComTransfer.c b/crates/sbg-rs/sbgECom/src/transfer/sbgEComTransfer.c new file mode 100644 index 0000000..4096908 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/transfer/sbgEComTransfer.c @@ -0,0 +1,620 @@ +// sbgCommonLib headers +#include +#include +#include + +// Project headers +#include + +// Local headers +#include "sbgEComTransfer.h" + +//----------------------------------------------------------------------// +//- Private methods -// +//----------------------------------------------------------------------// +/*! + * Initiates an upload transfer sequence with a device. + * + * \param[in] pHandle Pointer to a valid SbgEComHandle. + * \param[in] msgClass Original protocol class asking for transfer. + * \param[in] msg Original protocol message id asking for transfer. + * \param[in] size Total size of the upload. + * \return SBG_NO_ERROR when the transfer was initiated successfully. + */ +static SbgErrorCode sbgEComTransferSendInit(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, size_t size) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgStreamBuffer streamBuffer; + uint8_t outputBuffer[6]; + uint32_t trial; + + assert(pHandle); + + // + // Initialize stream buffer that will contain payload + // + sbgStreamBufferInitForWrite(&streamBuffer, outputBuffer, sizeof(outputBuffer)); + + // + // Build transfer payload (a SBG_ECOM_TRANSFER_START command and the total size of the upload) + // + sbgStreamBufferWriteUint16LE(&streamBuffer, SBG_ECOM_TRANSFER_START); + sbgStreamBufferWriteSizeT32LE(&streamBuffer, size); + + // + // Send command (multiple times in case of failures) + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send transfer payload encapsulated in ECom protocol + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, msgClass, msg, sbgStreamBufferGetLinkedBuffer(&streamBuffer), sbgStreamBufferGetLength(&streamBuffer)); + + if (errorCode == SBG_NO_ERROR) + { + // + // If the device accepts the transfer, it returns an ack, wait for the answer. + // + errorCode = sbgEComWaitForAck(pHandle, msgClass, msg, pHandle->cmdDefaultTimeOut); + + // + // Test if the response is positive from device + // + if (errorCode == SBG_NO_ERROR) + { + // + // Ack received, no need for other trial. + // + break; + } + } + } + + return errorCode; +} + +/*! + * Send one packet of data on a initiated upload transfer. + * + * \param[in] pHandle Pointer to a valid SbgEComHandle. + * \param[in] msgClass Original protocol class asking for transfer. + * \param[in] msg Original protocol message id asking for transfer. + * \param[in] pBuffer Pointer to the buffer containing the data to send. + * \param[in] offset The offset from the start of the transfer. + * \param[in] packetSize The size of this packet. + * \return SBG_NO_ERROR if the packet was sent and acknowledged by the device. + */ +static SbgErrorCode sbgEComTransferSendData(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, const void *pBuffer, size_t offset, size_t packetSize) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgStreamBuffer streamBuffer; + uint8_t outputBuffer[SBG_ECOM_TRANSFER_PACKET_SIZE+6]; + uint32_t trial; + + assert(pHandle); + assert(pBuffer); + assert(packetSize > 0); + + // + // Initialize stream buffer for output + // + sbgStreamBufferInitForWrite(&streamBuffer, outputBuffer, sizeof(outputBuffer)); + + // + // Build payload: a SBG_ECOM_TRANSFER_DATA command, the offset from the start of the transfer, and the data + // + sbgStreamBufferWriteUint16LE(&streamBuffer, SBG_ECOM_TRANSFER_DATA); + sbgStreamBufferWriteSizeT32LE(&streamBuffer, offset); + sbgStreamBufferWriteBuffer(&streamBuffer, pBuffer, packetSize); + + // + // Send command (multiple times in case of failures) + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send transfer payload encapsulated in a ECom protocol frame + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, msgClass, msg, sbgStreamBufferGetLinkedBuffer(&streamBuffer), sbgStreamBufferGetLength(&streamBuffer)); + + if (errorCode == SBG_NO_ERROR) + { + // + // If the device receives the frame successfully received, it responds with an ACK, wait for the answer + // + errorCode = sbgEComWaitForAck(pHandle, msgClass, msg, pHandle->cmdDefaultTimeOut); + + // + // Test if the response is positive from device + // + if (errorCode == SBG_NO_ERROR) + { + // + // Ack received, no need for other trial + // + break; + } + } + } + + return errorCode; +} + +/*! + * Ends ongoing upload transfer sequence with a device. + * + * \param[in] pHandle Pointer to a valid SbgEComHandle. + * \param[in] msgClass Original protocol class asking for transfer. + * \param[in] msg Original protocol message id asking for transfer. + * \return SBG_NO_ERROR when the transfer ended successfully. + */ +static SbgErrorCode sbgEComTransferSendEnd(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgStreamBuffer outputStream; + uint8_t outputBuffer[2]; + uint32_t trial; + + assert(pHandle); + + // + // Build payload, only a SBG_ECOM_TRANSFER_END cmd + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + sbgStreamBufferWriteUint16LE(&outputStream, SBG_ECOM_TRANSFER_END); + + // + // Send command (multiple times in case of failures) + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send upload end payload encapsulated in a ECom protocol frame + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, msgClass, msg, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + if (errorCode == SBG_NO_ERROR) + { + // + // If the device finishes the sequence successfully, it responds with an ACK, wait for answer + // + errorCode = sbgEComWaitForAck(pHandle, msgClass, msg, pHandle->cmdDefaultTimeOut); + + // + // Test if the response is positive from device + // + if (errorCode == SBG_NO_ERROR) + { + // + // ACK received, no need for other trial + // + break; + } + } + } + + return errorCode; +} + +/*! + * Initiates a download sequences with a device. + * + * \param[in] pHandle Pointer to a valid SbgEComHandle. + * \param[in] msgClass Original protocol class asking for transfer. + * \param[in] msg Original protocol message id asking for transfer. + * \param[out] pSize Size of the transfer initiated, returned from the device. + * \return SBG_NO_ERROR when the transfer initiated successfully. + */ +static SbgErrorCode sbgEComTransferReceiveInit(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, size_t *pSize) +{ + SbgErrorCode errorCode = SBG_ERROR; + SbgEComProtocolPayload receivedPayload; + SbgStreamBuffer outputStream; + uint8_t outputBuffer[2]; + uint16_t transferCmd; + size_t transferSize; + uint32_t trial; + + assert(pHandle); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Build payload, only a SBG_ECOM_TRANSFER_START cmd + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + sbgStreamBufferWriteUint16LE(&outputStream, SBG_ECOM_TRANSFER_START); + + // + // Send command (multiple times in case of failures) + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send transfer payload encapsulated in an ECom protocol frame + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, msgClass, msg, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + if (errorCode == SBG_NO_ERROR) + { + // + // Wait for reponse, the device should respond with a ECOM_TRANSFER_START command and the transfer size + // If it can not initiate the transfer, it will respond with a NACK + // + errorCode = sbgEComReceiveCmd2(pHandle, msgClass, msg, &receivedPayload, pHandle->cmdDefaultTimeOut); + + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + + // + // Init stream buffer on received payload to process it + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Retrieve parameters, the first one is the transfer command + // The second one is the total transfer size + // + transferCmd = sbgStreamBufferReadUint16LE(&inputStream); + transferSize = sbgStreamBufferReadSizeT32LE(&inputStream); + + // + // The device should have answered with SBG_ECOM_TRANSFER_START transfer command + // + if (transferCmd == SBG_ECOM_TRANSFER_START) + { + // + // Update output variable with the transfer size + // + *pSize = transferSize; + + // + // No need for other trials, exit loop/ + // + break; + } + else + { + // + // Invalid transfer command response + // + errorCode = SBG_ERROR; + } + } + else if (errorCode != SBG_TIME_OUT) + { + SBG_LOG_ERROR(errorCode, "Invalid answer received"); + } + else + { + SBG_LOG_ERROR(errorCode, "No response received"); + } + } + else + { + SBG_LOG_ERROR(errorCode, "Unable to send the command"); + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +/*! + * Receive one packet of data on a initiated download transfer. + * + * \param[in] pHandle Pointer to a valid SbgEComHandle. + * \param[in] msgClass Original protocol class asking for transfer. + * \param[in] msg Original protocol message id asking for transfer. + * \param[in] pBuffer Pointer to the buffer where to write the packet. + * \param[in] offset The offset from the start of the buffer. + * \param[in] packetSize The size of the data asked to the device. + * \return SBG_NO_ERROR if the packet was successfully received. + */ +static SbgErrorCode sbgEComTransferReceiveData(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, void *pBuffer, size_t offset, size_t packetSize) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgEComProtocolPayload receivedPayload; + SbgStreamBuffer outputStream; + uint8_t outputBuffer[10]; + uint32_t trial; + + assert(pHandle); + assert(pBuffer); + assert(packetSize > 0); + + sbgEComProtocolPayloadConstruct(&receivedPayload); + + // + // Build payload: an SBG_ECOM_TRANSFER_DATA transfer command, the offset from the start of the transfer, the size of the packet the device must send + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + sbgStreamBufferWriteUint16LE(&outputStream, SBG_ECOM_TRANSFER_DATA); + sbgStreamBufferWriteSizeT32LE(&outputStream, offset); + sbgStreamBufferWriteSizeT32LE(&outputStream, packetSize); + + // + // Send command (multiple times in case of failures) + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send transfer payload encapsulated in an ECom protocol frame + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, msgClass, msg, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + if (errorCode == SBG_NO_ERROR) + { + // + // Wait for reponse, the device should respond with a ECOM_TRANSFER_DATA, the offset from the start of the transfer and the data payload + // If it can not provide the data, it will respond with a NACK + // + errorCode = sbgEComReceiveCmd2(pHandle, msgClass, msg, &receivedPayload, pHandle->cmdDefaultTimeOut); + + if (errorCode == SBG_NO_ERROR) + { + SbgStreamBuffer inputStream; + uint16_t transferCmd; + size_t rcvdOffset; + + // + // Initialize stream buffer for read on input buffer + // + sbgStreamBufferInitForRead(&inputStream, sbgEComProtocolPayloadGetBuffer(&receivedPayload), sbgEComProtocolPayloadGetSize(&receivedPayload)); + + // + // Read response fields, first is the transfer command, second is the offset + // + transferCmd = sbgStreamBufferReadUint16LE(&inputStream); + rcvdOffset = sbgStreamBufferReadSizeT32LE(&inputStream); + + // + // Test that it's a SBG_ECOM_TRANSFER_DATA command + // The data is at the offset asked and the size corresponds + // + if ( (transferCmd == SBG_ECOM_TRANSFER_DATA) && (offset == rcvdOffset) && (packetSize == (sbgEComProtocolPayloadGetSize(&receivedPayload) - (sizeof(uint16_t) + sizeof(uint32_t)))) ) + { + // + // Read all the buffer + // + sbgStreamBufferReadBuffer(&inputStream, pBuffer, sbgEComProtocolPayloadGetSize(&receivedPayload) - (sizeof(uint16_t) + sizeof(uint32_t))); + + // + // No need for other trials, exit loop + // + break; + } + } + } + } + + sbgEComProtocolPayloadDestroy(&receivedPayload); + + return errorCode; +} + +/*! + * Function that ends a download sequence with a device. + * + * \param[in] pHandle Pointer to a valid SbgEComHandle. + * \param[in] msgClass Original protocol class asking for transfer. + * \param[in] msg Original protocol message id asking for transfer. + * \return SBG_NO_ERROR when the transfer ended successfully. + */ +static SbgErrorCode sbgEComTransferReceiveEnd(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgStreamBuffer outputStream; + uint8_t outputBuffer[2]; + uint32_t trial; + + assert(pHandle); + + // + // Build payload, only a SBG_ECOM_TRANSFER_END cmd + // + sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer)); + sbgStreamBufferWriteUint16LE(&outputStream, SBG_ECOM_TRANSFER_END); + + // + // Send command (multiple times in case of failures) + // + for (trial = 0; trial < pHandle->numTrials; trial++) + { + // + // Send upload end payload encapsulated in a ECom protocol frame + // + errorCode = sbgEComProtocolSend(&pHandle->protocolHandle, msgClass, msg, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream)); + + if (errorCode == SBG_NO_ERROR) + { + // + // If the device is able to finish transfer sequence, it responds with an ACK + // + errorCode = sbgEComWaitForAck(pHandle, msgClass, msg, pHandle->cmdDefaultTimeOut); + + // + // Test if the response is positive from device + // + if (errorCode == SBG_NO_ERROR) + { + // + // No need for other trial, exit loop + // + break; + } + } + } + + return errorCode; +} + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +SbgErrorCode sbgEComTransferSend(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, const void *pBuffer, size_t size) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgSplitBuffer splitBuffer; + size_t i; + + assert(pHandle); + assert(pBuffer); + assert(size > 0); + + // + // Make sure we are not trying to send a buffer that is too large + // + if (size <= SBG_ECOM_TRANSFER_MAX_SIZE) + { + // + // Initiate data transfer + // + errorCode = sbgEComTransferSendInit(pHandle, msgClass, msg, size); + + // + // Check that the transfer was correctly initialized + // + if (errorCode == SBG_NO_ERROR) + { + // + // Initialize split buffer that will help with splitting up provided buffer + // + sbgSplitBufferInitForRead(&splitBuffer, pBuffer, size, SBG_ECOM_TRANSFER_PACKET_SIZE); + + // + // Transfer sub buffer one by one + // + for (i = 0; i < sbgSplitBufferGetSubBufferNbr(&splitBuffer); i++) + { + // + // Send a sub buffer + // + errorCode = sbgEComTransferSendData(pHandle, msgClass, msg, sbgSplitBufferGetSubBuffer(&splitBuffer, i), sbgSplitBufferGetSubBufferOffset(&splitBuffer, i), sbgSplitBufferGetSubBufferSize(&splitBuffer, i)); + + // + // Test if the sub buffer has been sent + // + if (errorCode != SBG_NO_ERROR) + { + // + // Unable to send a sub buffer, abort send operation. + // + break; + } + } + + // + // Test if any error occurred during data transfer + // + if (errorCode == SBG_NO_ERROR) + { + // + // End data transfer + // + errorCode = sbgEComTransferSendEnd(pHandle, msgClass, msg); + } + } + } + else + { + // + // Trying to send a buffer that is too large + // + errorCode = SBG_INVALID_PARAMETER; + } + + return errorCode; +} + +SbgErrorCode sbgEComTransferReceive(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, void *pBuffer, size_t *pActualSize, size_t bufferSize) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + SbgSplitBuffer splitBuffer; + size_t transferSize; + size_t i; + + assert(pHandle); + assert(pBuffer); + assert(pActualSize); + assert(bufferSize > 0); + + // + // initiate data transfer + // + errorCode = sbgEComTransferReceiveInit(pHandle, msgClass, msg, &transferSize); + + // + // Make sure the receive transfer has been correctly initialized + // + if (errorCode == SBG_NO_ERROR) + { + // + // Test that the provided buffer is large enough to receive all data + // + if (transferSize <= bufferSize) + { + // + // Initialize Split buffer to help with sub buffer receive + // + sbgSplitBufferInitForWrite(&splitBuffer, pBuffer, transferSize, SBG_ECOM_TRANSFER_PACKET_SIZE); + + // + // Receive buffers one by one + // + for (i = 0; i < sbgSplitBufferGetSubBufferNbr(&splitBuffer); i++) + { + // + // Receive a sub buffer + // + errorCode = sbgEComTransferReceiveData(pHandle, msgClass, msg, sbgSplitBufferGetSubBuffer(&splitBuffer, i), sbgSplitBufferGetSubBufferOffset(&splitBuffer, i), sbgSplitBufferGetSubBufferSize(&splitBuffer, i)); + + // + // Make sure that the sub buffer has been correctly received + // + if (errorCode != SBG_NO_ERROR) + { + // + // An error occurred, abort data transfer + // + break; + } + } + + // + // Test if any error occurred during transfer + // + if (errorCode == SBG_NO_ERROR) + { + // + // End data transfer + // + errorCode = sbgEComTransferReceiveEnd(pHandle, msgClass, msg); + + // + // Make sure that the transfer has been correctly ended + // + if (errorCode == SBG_NO_ERROR) + { + // + // Since the transfer was successful update output variable pActualSize + // + *pActualSize = transferSize; + } + } + } + else + { + // + // Provided buffer is too small + // + errorCode = SBG_INVALID_PARAMETER; + } + } + + return errorCode; +} diff --git a/crates/sbg-rs/sbgECom/src/transfer/sbgEComTransfer.h b/crates/sbg-rs/sbgECom/src/transfer/sbgEComTransfer.h new file mode 100644 index 0000000..1a22700 --- /dev/null +++ b/crates/sbg-rs/sbgECom/src/transfer/sbgEComTransfer.h @@ -0,0 +1,100 @@ +/*! + * \file sbgEComTransfer.h + * \ingroup protocol + * \author SBG Systems + * \date 19 November 2013 + * + * \brief Handle large send/receive transfer for specific ECom Protocol commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense The MIT license + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * \endlicense + */ + +#ifndef SBG_ECOM_TRANSFER_H +#define SBG_ECOM_TRANSFER_H + +// sbgCommonLib headers +#include + +// Project headers +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------// +//- Global definitions -// +//----------------------------------------------------------------------// + +#define SBG_ECOM_TRANSFER_MAX_SIZE (8192u) /*!< Maximum buffer that can be transmitted using the sbgECom transfer protocol. */ +#define SBG_ECOM_TRANSFER_PACKET_SIZE (512u) /*!< Max packet size transmitted in a single frame */ + +//----------------------------------------------------------------------// +//- Communication protocol structs and definitions -// +//----------------------------------------------------------------------// + +/*! + * Defines the ECom transfer commands + */ +typedef enum _SbgEComTransferCmd +{ + SBG_ECOM_TRANSFER_START = 0, /*!< Command to initiate a transfer. */ + SBG_ECOM_TRANSFER_DATA = 1, /*!< Command to transmit/receive data. */ + SBG_ECOM_TRANSFER_END = 2 /*!< Command to end a transfer. */ +} SbgEComTransferCmd; + +//----------------------------------------------------------------------// +//- Public methods -// +//----------------------------------------------------------------------// + +/*! + * Specific method to handle a large send into multiple frames. + * + * \param[in] pHandle Pointer to a valid SbgEComHandle. + * \param[in] msgClass Original protocol class asking for transfer. + * \param[in] msg Original protocol message id asking for transfer. + * \param[in] pBuffer Pointer to the buffer containing the data to send. + * \param[in] size The size of the buffer. + * \return SBG_NO_ERROR in case of a successful upload. + */ +SbgErrorCode sbgEComTransferSend(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, const void *pBuffer, size_t size); + +/*! + * Specific method to handle a large receive from the device. + * + * \param[in] pHandle Pointer to a valid SbgEComHandle. + * \param[in] msgClass Original protocol class asking for transfer. + * \param[in] msg Original protocol message id asking for transfer. + * \param[in] pBuffer Pointer to the buffer where to write data. + * \param[out] pActualSize The final size written into the buffer. + * \param[in] bufferSize The size of the buffer. + * \return SBG_NO_ERROR in case of a successful download. + */ +SbgErrorCode sbgEComTransferReceive(SbgEComHandle *pHandle, uint8_t msgClass, uint8_t msg, void *pBuffer, size_t *pActualSize, size_t bufferSize); + +#ifdef __cplusplus +} +#endif + +#endif // SBG_ECOM_TRANSFER_H diff --git a/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/README.md b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/README.md new file mode 100644 index 0000000..0ee1616 --- /dev/null +++ b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/README.md @@ -0,0 +1,70 @@ +# sbgBasicLogger + +The sbgBasicLogger let you log and display sbgECom binary messages into CSV like text files. + +## Output +The output is as close as possible as the sbgECom message definition. +You can both output incoming messages in text files and/or display the data in the terminal. + +## Decimation +The tool can also decimate incoming IMU data using a simple moving average filter. +You can specify decimation to apply before displayed the data to the terminal and also one before writing the data to text files. + +Only the following logs are decimated: + - IMU short + - IMU fast + - IMU data + +## Interfaces +The sbgBasicLogger can be used to parse incoming data from a serial or an Ethernet UDP interface. +You can also select an binary file containing raw sbgECom dump. This tool can thus be used to easily export sbgECom data to CVS like text files. + +# Usage + +The sbgBasicLogger implements a simple to use command line interface (CLI): + +```sh +sbgBasicLogger [-hvwpH] [-a IP address] [-I UDP port in] [-O UDP port out] [-s SERIAL_DEVICE] [-r SERIAL_BAUDRATE] [-i INPUT-FILE] [--dir=DIRECTORY] [-d FILE DECIMATION] [-c CONSOLE DECIMATION] +``` + +## Serial example and only print on console + +```sh +sbgBasicLogger -s -r -p +``` + +## Serial example, print on console and write files into + +```sh +sbgBasicLogger -s -r -p -w --dir=directory/ +``` + +## UDP example and only print on console + +```sh +sbgBasicLogger -a -I -O -p +``` + +## Input file example and only print on console + +```sh +sbgBasicLogger -i -p +``` + +## Options +``` + -h, --help display this help and exit + -v, --version display sbgECom version and exit + -a, --addr-ip=IP address open an UDP interface + -I, --udp-port-in=UDP port in UDP port in + -O, --udp-port-out=UDP port out UDP port out + -s, --serial-device=SERIAL_DEVICE open a serial interface + -r, --serial-baudrate=SERIAL_BAUDRATE serial baudrate + -i, --input-file=INPUT-FILE input file + -w, --write-logs write logs in different files + --dir=DIRECTORY directory to write logs into + -d, --file-decimation=FILE DECIMATION file decimation + -c, --console-decimation=CONSOLE DECIMATION output stream decimation + -p, --print-logs print the logs on the output stream + -H, --disable-header disable header for files +``` \ No newline at end of file diff --git a/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/main.c b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/main.c new file mode 100644 index 0000000..a59a1a9 --- /dev/null +++ b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/main.c @@ -0,0 +1,1046 @@ +/*! + * \file main.c + * \author SBG Systems + * \date July 29, 2021 + * + * \brief Tool to manage SBG logs in text format. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense Proprietary license + * + * This source code is intended for use only by SBG Systems SAS and + * those that have explicit written permission to use it from + * SBG Systems SAS. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + * PARTICULAR PURPOSE. + * + * \endlicense + */ + +// sbgCommonLib headers +#include +#include +#include +#include +#include +#include + +// sbgECom headers +#include +#include +#include + +// Argtable3 headers +#include + +// Local headers +#include "sbgBasicLoggerHandler.h" + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +/*! + * Program name. + */ +#define PROGRAM_NAME "sbgBasicLogger" + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * User arguments. + */ +typedef struct _UserArgs +{ + bool writeHeader; /*!< True to write data header. */ + bool writingFiles; /*!< True to write data into files. */ + size_t fileDecimation; /*!< File decimation. */ + bool consoleEnabled; /*!< True to enable console. */ + size_t consoleDecimation; /*!< Console decimation. */ + SbgString path; /*!< Output path string to write log files into. */ + const char *pPathStr; /*!< Output path string shortcut. */ +} UserArgs; + +/*! + * SbgBasicLoggerManager. + */ +typedef struct _SbgBasicLoggerManager +{ + UserArgs userArgs; /*!< User arguments. */ + + SbgEComHandle ecomHandle; /*!< ECom handler. */ + SbgInterface ecomInterface; /*!< SBG interface. */ + + SbgLogUtcData lastUtcData; /*!< Latest UTC time reference used to time stamp messages. */ + + SbgBasicLoggerImuHandler imuShort; /*!< IMU short logs handler. */ + SbgBasicLoggerImuHandler imu; /*!< IMU logs handler. */ + SbgBasicLoggerImuHandler imuFast; /*!< IMU fast logs handler. */ + SbgBasicLoggerStatusHandler status; /*!< Status logs handler. */ + SbgBasicLoggerDiagHandler diag; /*!< Diagnostic logs handler. */ + SbgBasicLoggerUtcHandler utc; /*!< Diagnostic logs handler. */ + + SbgBasicLoggerEkfEulerHandler ekfEuler; /*!< EKF Euler logs handler. */ + SbgBasicLoggerEkfQuatHandler ekfQuat; /*!< EKF quat logs handler. */ + SbgBasicLoggerEkfNavHandler ekfNav; /*!< EKF nav logs handler. */ + + SbgBasicLoggerShipMotionHandler shipMotion; /*!< Ship motion logs handler. */ + SbgBasicLoggerShipMotionHpHandler shipMotionHp; /*!< Ship motion HP logs handler. */ + + SbgBasicLoggerGpsHdtHandler gps1Hdt; /*!< GPS 1 hdt logs handler. */ + SbgBasicLoggerGpsPosHandler gps1Pos; /*!< GPS 1 pos logs handler. */ + SbgBasicLoggerGpsVelHandler gps1Vel; /*!< GPS 1 vel logs handler. */ + SbgBasicLoggerGpsRawHandler gps1Raw; /*!< GPS 1 raw logs handler. */ + SbgBasicLoggerGpsSatHandler gps1Sat; /*!< GPS 1 Satellite in View logs handler. */ + + SbgBasicLoggerGpsHdtHandler gps2Hdt; /*!< GPS 2 hdt logs handler. */ + SbgBasicLoggerGpsPosHandler gps2Pos; /*!< GPS 2 pos logs handler. */ + SbgBasicLoggerGpsVelHandler gps2Vel; /*!< GPS 2 vel logs handler. */ + SbgBasicLoggerGpsRawHandler gps2Raw; /*!< GPS 2 raw logs handler. */ + SbgBasicLoggerGpsSatHandler gps2Sat; /*!< GPS 2 Satellite in View logs handler. */ + + SbgBasicLoggerOdometerHandler odometer; /*!< Odometer logs handler. */ + SbgBasicLoggerDvlHandler dvlBottom; /*!< DVL bottom logs handler. */ + SbgBasicLoggerDvlHandler dvlWater; /*!< DVL water logs handler. */ + SbgBasicLoggerAirHandler air; /*!< Air logs handler. */ + SbgBasicLoggerUsblHandler usbl; /*!< USBL logs handler. */ + SbgBasicLoggerDepthHandler depth; /*!< Depth logs handler. */ + SbgBasicLoggerRawRtcmHandler rawRtcm; /*!< Raw RTCM logs handler. */ + + SbgBasicLoggerEventHandler eventInA; /*!< Event in A logs handler. */ + SbgBasicLoggerEventHandler eventInB; /*!< Event in B logs handler. */ + SbgBasicLoggerEventHandler eventInC; /*!< Event in C logs handler. */ + SbgBasicLoggerEventHandler eventInD; /*!< Event in D logs handler. */ + SbgBasicLoggerEventHandler eventInE; /*!< Event in E logs handler. */ + + SbgBasicLoggerEventHandler eventOutA; /*!< Event out A logs handler. */ + SbgBasicLoggerEventHandler eventOutB; /*!< Event out B logs handler. */ + + SbgBasicLoggerMagHandler mag; /*!< Mag logs handler. */ +} SbgBasicLoggerManager; + +//----------------------------------------------------------------------// +//- Private variables -// +//----------------------------------------------------------------------// + +/*! + * SBG basic logger singleton. + */ +static SbgBasicLoggerManager gSbgBasicLogger; + +//----------------------------------------------------------------------// +//- Private functions -// +//----------------------------------------------------------------------// + +/*! + * Callback definition used to route log error messages. + * + * \param[in] pFileName The file in which the log was triggered. + * \param[in] pFunctionName The function where the log was triggered. + * \param[in] line The line in the file where the log was triggered. + * \param[in] pCategory Category for this log or "None" if no category has been specified. + * \param[in] type Associated log message type. + * \param[in] errorCode Associated error code or SBG_NO_ERROR for INFO & DEBUG level logs. + * \param[in] pMessage The message to log. + */ +static void onLogCallback(const char *pFileName, const char *pFunctionName, uint32_t line, const char *pCategory, SbgDebugLogType logType, SbgErrorCode errorCode, const char *pMessage) +{ + assert(pFunctionName); + assert(pCategory); + assert(pMessage); + + SBG_UNUSED_PARAMETER(pFileName); + SBG_UNUSED_PARAMETER(pCategory); + + switch (logType) + { + case SBG_DEBUG_LOG_TYPE_ERROR: + fprintf(stderr, "*ERR * %10s %s(%"PRIu32"): %s\n\r", sbgErrorCodeToString(errorCode), pFunctionName, line, pMessage); + break; + case SBG_DEBUG_LOG_TYPE_WARNING: + fprintf(stderr, "*WARN* %10s %s(%"PRIu32"): %s\n\r", sbgErrorCodeToString(errorCode), pFunctionName, line, pMessage); + break; + case SBG_DEBUG_LOG_TYPE_INFO: + fprintf(stderr, "*INFO* %s(%"PRIu32"): %s\n\r", pFunctionName, line, pMessage); + break; + case SBG_DEBUG_LOG_TYPE_DEBUG: + fprintf(stderr, "*DBG * %s(%"PRIu32") : % s\n\r", pFunctionName, line, pMessage); + break; + default: + fprintf(stderr, "error: unexpected logType (0x%x)\n\r", logType); + break; + } +} + +//----------------------------------------------------------------------// +//- SbgBasicLoggerManager methods -// +//----------------------------------------------------------------------// + +/*! + * Process an UTC data. + * + * \param[in] pManager SBG basic logger. + * \param[in] pUtc UTC data. + */ +static void sbgBasicLoggerManagerProcessUtc(SbgBasicLoggerManager *pManager, const SbgLogUtcData *pUtcData) +{ + assert(pManager); + assert(pUtcData); + + pManager->lastUtcData = *pUtcData; + sbgBasicLoggerUtcHandlerProcess(&pManager->utc, pUtcData); +} + +/*! + * Process a new IMU short data. + * + * \param[in] pManager SBG basic logger. + * \param[in] pImuShort New IMU short data. + */ +static void sbgBasicLoggerManagerProcessImuShort(SbgBasicLoggerManager *pManager, const SbgLogImuShort *pImuShort) +{ + SbgBasicLoggerImu newData; + + assert(pManager); + assert(pImuShort); + + newData.timestamp = pImuShort->timeStamp; + newData.status = pImuShort->status; + newData.temperature = sbgLogImuShortGetTemperature(pImuShort); + + for (size_t i = 0; i < 3; i++) + { + newData.deltaAngle[i] = sbgLogImuShortGetDeltaAngle(pImuShort, i); + newData.deltaVelocity[i] = sbgLogImuShortGetDeltaVelocity(pImuShort, i); + } + + sbgBasicLoggerImuHandlerProcess(&pManager->imuShort, &newData); +} + +/*! + * Process a new IMU data. + * + * \param[in] pManager SBG basic logger. + * \param[in] pImu New IMU data. + */ +static void sbgBasicLoggerManagerProcessImu(SbgBasicLoggerManager *pManager, const SbgLogImuData *pImu) +{ + SbgBasicLoggerImu newData; + + assert(pManager); + assert(pImu); + + newData.timestamp = pImu->timeStamp; + newData.status = pImu->status; + newData.temperature = pImu->temperature; + + for (size_t i = 0; i < 3; i++) + { + newData.deltaAngle[i] = pImu->deltaAngle[i]; + newData.deltaVelocity[i] = pImu->deltaVelocity[i]; + } + + sbgBasicLoggerImuHandlerProcess(&pManager->imu, &newData); +} + +/*! + * Process a new IMU fast data. + * + * \param[in] pManager SBG basic logger. + * \param[in] pImuShort New IMU fast data. + */ +static void sbgBasicLoggerManagerProcessImuFast(SbgBasicLoggerManager *pManager, const SbgLogFastImuData *pFast) +{ + SbgBasicLoggerImu newData; + + assert(pManager); + assert(pFast); + + newData.timestamp = pFast->timeStamp; + newData.status = pFast->status; + newData.temperature = 0.0f; + + for (size_t i = 0; i < 3; i++) + { + newData.deltaAngle[i] = pFast->gyroscopes[i]; + newData.deltaVelocity[i] = pFast->accelerometers[i]; + } + + sbgBasicLoggerImuHandlerProcess(&pManager->imuFast, &newData); +} + +/*! + * Callback used to handle received logs. + * + * \param[in] pECom SbgECom instance. + * \param[in] msgClass Class of the received message. + * \param[in] msg Received message ID. + * \param[in] pLogData Received data. + * \param[in] pUserArg Optional user argument. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode onLogReceived(SbgEComHandle *pECom, SbgEComClass msgClass, SbgEComMsgId msg, const SbgBinaryLogData *pLogData, void *pUserArg) +{ + SbgBasicLoggerManager *pManager; + + assert(pLogData); + assert(pUserArg); + + SBG_UNUSED_PARAMETER(pECom); + + pManager = (SbgBasicLoggerManager*)pUserArg; + + if (msgClass == SBG_ECOM_CLASS_LOG_ECOM_0) + { + switch (msg) + { + case SBG_ECOM_LOG_STATUS: + sbgBasicLoggerStatusHandlerProcess(&pManager->status, &pLogData->statusData); + break; + + case SBG_ECOM_LOG_UTC_TIME: + sbgBasicLoggerManagerProcessUtc(pManager, &pLogData->utcData); + break; + + case SBG_ECOM_LOG_IMU_DATA: + sbgBasicLoggerManagerProcessImu(pManager, &pLogData->imuData); + break; + + case SBG_ECOM_LOG_MAG: + sbgBasicLoggerMagHandlerProcess(&pManager->mag, &pLogData->magData); + break; + + case SBG_ECOM_LOG_MAG_CALIB: + // + // Known but not sbgBasicLoggerManagerProcessed. + // + break; + + case SBG_ECOM_LOG_EKF_EULER: + sbgBasicLoggerEkfEulerHandlerProcess(&pManager->ekfEuler, &pLogData->ekfEulerData); + break; + + case SBG_ECOM_LOG_EKF_QUAT: + sbgBasicLoggerEkfQuatHandlerProcess(&pManager->ekfQuat, &pLogData->ekfQuatData); + break; + + case SBG_ECOM_LOG_EKF_NAV: + sbgBasicLoggerEkfNavHandlerProcess(&pManager->ekfNav, &pLogData->ekfNavData); + break; + + case SBG_ECOM_LOG_SHIP_MOTION: + sbgBasicLoggerShipMotionHandlerProcess(&pManager->shipMotion, &pLogData->shipMotionData); + break; + + case SBG_ECOM_LOG_GPS1_VEL: + sbgBasicLoggerGpsVelHandlerProcess(&pManager->gps1Vel, &pLogData->gpsVelData); + break; + + case SBG_ECOM_LOG_GPS1_POS: + sbgBasicLoggerGpsPosHandlerProcess(&pManager->gps1Pos, &pLogData->gpsPosData); + break; + + case SBG_ECOM_LOG_GPS1_HDT: + sbgBasicLoggerGpsHdtHandlerProcess(&pManager->gps1Hdt, &pLogData->gpsHdtData); + break; + + case SBG_ECOM_LOG_GPS1_RAW: + sbgBasicLoggerGpsRawHandlerProcess(&pManager->gps1Raw, &pLogData->gpsRawData); + break; + + case SBG_ECOM_LOG_GPS1_SAT: + sbgBasicLoggerGpsSatHandlerProcess(&pManager->gps1Sat, &pLogData->satGroupData); + break; + + case SBG_ECOM_LOG_GPS2_VEL: + sbgBasicLoggerGpsVelHandlerProcess(&pManager->gps2Vel, &pLogData->gpsVelData); + break; + + case SBG_ECOM_LOG_GPS2_POS: + sbgBasicLoggerGpsPosHandlerProcess(&pManager->gps2Pos, &pLogData->gpsPosData); + break; + + case SBG_ECOM_LOG_GPS2_HDT: + sbgBasicLoggerGpsHdtHandlerProcess(&pManager->gps2Hdt, &pLogData->gpsHdtData); + break; + + case SBG_ECOM_LOG_GPS2_RAW: + sbgBasicLoggerGpsRawHandlerProcess(&pManager->gps2Raw, &pLogData->gpsRawData); + break; + + case SBG_ECOM_LOG_GPS2_SAT: + sbgBasicLoggerGpsSatHandlerProcess(&pManager->gps2Sat, &pLogData->satGroupData); + break; + + case SBG_ECOM_LOG_ODO_VEL: + sbgBasicLoggerOdometerHandlerProcess(&pManager->odometer, &pLogData->odometerData); + break; + + case SBG_ECOM_LOG_EVENT_A: + sbgBasicLoggerEventHandlerProcess(&pManager->eventInA, &pLogData->eventMarker); + break; + + case SBG_ECOM_LOG_EVENT_B: + sbgBasicLoggerEventHandlerProcess(&pManager->eventInB, &pLogData->eventMarker); + break; + + case SBG_ECOM_LOG_EVENT_C: + sbgBasicLoggerEventHandlerProcess(&pManager->eventInC, &pLogData->eventMarker); + break; + + case SBG_ECOM_LOG_EVENT_D: + sbgBasicLoggerEventHandlerProcess(&pManager->eventInD, &pLogData->eventMarker); + break; + + case SBG_ECOM_LOG_EVENT_E: + sbgBasicLoggerEventHandlerProcess(&pManager->eventInE, &pLogData->eventMarker); + break; + + case SBG_ECOM_LOG_DVL_BOTTOM_TRACK: + sbgBasicLoggerDvlHandlerProcess(&pManager->dvlBottom, &pLogData->dvlData); + break; + + case SBG_ECOM_LOG_DVL_WATER_TRACK: + sbgBasicLoggerDvlHandlerProcess(&pManager->dvlWater, &pLogData->dvlData); + break; + + case SBG_ECOM_LOG_SHIP_MOTION_HP: + sbgBasicLoggerShipMotionHpHandlerProcess(&pManager->shipMotionHp, &pLogData->shipMotionData); + break; + + case SBG_ECOM_LOG_AIR_DATA: + sbgBasicLoggerAirHandlerProcess(&pManager->air, &pLogData->airData); + break; + + case SBG_ECOM_LOG_USBL: + sbgBasicLoggerUsblHandlerProcess(&pManager->usbl, &pLogData->usblData); + break; + + case SBG_ECOM_LOG_IMU_SHORT: + sbgBasicLoggerManagerProcessImuShort(pUserArg, &pLogData->imuShort); + break; + + case SBG_ECOM_LOG_EVENT_OUT_A: + sbgBasicLoggerEventHandlerProcess(&pManager->eventOutA, &pLogData->eventMarker); + break; + + case SBG_ECOM_LOG_EVENT_OUT_B: + sbgBasicLoggerEventHandlerProcess(&pManager->eventOutB, &pLogData->eventMarker); + break; + + case SBG_ECOM_LOG_DEPTH: + sbgBasicLoggerDepthHandlerProcess(&pManager->depth, &pLogData->depthData); + break; + + case SBG_ECOM_LOG_DIAG: + sbgBasicLoggerDiagHandlerProcess(&pManager->diag, &pManager->lastUtcData, &pLogData->diagData); + break; + + case SBG_ECOM_LOG_RTCM_RAW: + sbgBasicLoggerRawRtcmHandlerProcess(&pManager->rawRtcm, &pLogData->rtcmRawData); + break; + + default: + fprintf(stdout, "unkwown log: %u", msg); + break; + } + } + else if (msgClass == SBG_ECOM_CLASS_LOG_ECOM_1) + { + switch (msg) + { + case SBG_ECOM_LOG_FAST_IMU_DATA: + sbgBasicLoggerManagerProcessImuFast(pUserArg, &pLogData->fastImuData); + break; + + default: + fprintf(stdout, "unkwown log1: %u", msg); + break; + } + } + else if (msgClass == SBG_ECOM_CLASS_LOG_NMEA_0) + { + // + // Known but not sbgBasicLoggerManagerProcessed. + // + } + else if (msgClass == SBG_ECOM_CLASS_LOG_NMEA_1) + { + // + // Known but not sbgBasicLoggerManagerProcessed. + // + } + else if (msgClass == SBG_ECOM_CLASS_LOG_THIRD_PARTY_0) + { + // + // Known but not sbgBasicLoggerManagerProcessed. + // + } + else if (msgClass == SBG_ECOM_CLASS_LOG_CMD_0) + { + // + // Known but not sbgBasicLoggerManagerProcessed. + // + } + else + { + fprintf(stdout, "unkwown class: %u", msgClass); + } + + return SBG_NO_ERROR; +} + +/*! + * Construct all log handlers. + * + * \param[in] pManager SBG basic logger. + */ +static void sbgBasicLoggerConstructLogHandlers(SbgBasicLoggerManager *pManager) +{ + assert(pManager); + + sbgBasicLoggerImuShortHandlerConstruct(&pManager->imuShort, + pManager->userArgs.consoleEnabled, + pManager->userArgs.consoleDecimation, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.fileDecimation, + pManager->userArgs.writeHeader); + + sbgBasicLoggerImuHandlerConstruct(&pManager->imu, + pManager->userArgs.consoleEnabled, + pManager->userArgs.consoleDecimation, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.fileDecimation, + pManager->userArgs.writeHeader); + + sbgBasicLoggerImuFastHandlerConstruct(&pManager->imuFast, + pManager->userArgs.consoleEnabled, + pManager->userArgs.consoleDecimation, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.fileDecimation, + pManager->userArgs.writeHeader); + + + sbgBasicLoggerDiagHandlerConstruct(&pManager->diag, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr); + + sbgBasicLoggerUtcHandlerConstruct(&pManager->utc, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerStatusHandlerConstruct(&pManager->status, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerEkfEulerHandlerConstruct(&pManager->ekfEuler, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerEkfQuatHandlerConstruct(&pManager->ekfQuat, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerEkfNavHandlerConstruct(&pManager->ekfNav, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerShipMotionHandlerConstruct(&pManager->shipMotion, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerShipMotionHpHandlerConstruct(&pManager->shipMotionHp, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerGpsHdt1HandlerConstruct(&pManager->gps1Hdt, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerGpsPos1HandlerConstruct(&pManager->gps1Pos, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerGpsVel1HandlerConstruct(&pManager->gps1Vel, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerGps1RawHandlerConstruct(&pManager->gps1Raw, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr); + + sbgBasicLoggerGps1SatHandlerConstruct(&pManager->gps1Sat, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr); + + sbgBasicLoggerGpsHdt2HandlerConstruct(&pManager->gps2Hdt, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerGpsPos2HandlerConstruct(&pManager->gps2Pos, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerGpsVel2HandlerConstruct(&pManager->gps2Vel, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerGps2RawHandlerConstruct(&pManager->gps2Raw, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr); + + sbgBasicLoggerGps2SatHandlerConstruct(&pManager->gps2Sat, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr); + + sbgBasicLoggerOdometerHandlerConstruct(&pManager->odometer, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerDvlBottomHandlerConstruct(&pManager->dvlBottom, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerDvlWaterHandlerConstruct(&pManager->dvlWater, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerAirHandlerConstruct(&pManager->air, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerUsblHandlerConstruct(&pManager->usbl, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerDepthHandlerConstruct(&pManager->depth, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerRawRtcmHandlerConstruct(&pManager->rawRtcm, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr); + + sbgBasicLoggerEventInAHandlerConstruct(&pManager->eventInA, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerEventInBHandlerConstruct(&pManager->eventInB, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerEventInCHandlerConstruct(&pManager->eventInC, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerEventInDHandlerConstruct(&pManager->eventInD, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerEventInEHandlerConstruct(&pManager->eventInE, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerEventOutAHandlerConstruct(&pManager->eventOutA, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerEventOutBHandlerConstruct(&pManager->eventOutB, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); + + sbgBasicLoggerMagHandlerConstruct(&pManager->mag, + pManager->userArgs.consoleEnabled, + pManager->userArgs.writingFiles, + pManager->userArgs.pPathStr, + pManager->userArgs.writeHeader); +} + +/*! + * Receive logs. + * + * \param[in] pManager Sbg Basic logger. + */ +static SbgErrorCode sbgBasicLoggerManagerReceiveLogs(SbgBasicLoggerManager *pManager) +{ + SbgErrorCode errorCode; + + assert(pManager); + + errorCode = sbgEComInit(&pManager->ecomHandle, &pManager->ecomInterface); + + if (errorCode == SBG_NO_ERROR) + { + sbgBasicLoggerConstructLogHandlers(pManager); + + sbgEComSetReceiveLogCallback(&pManager->ecomHandle, onLogReceived, pManager); + + while (1) + { + errorCode = sbgEComHandle(&pManager->ecomHandle); + + if (errorCode == SBG_NOT_READY) + { + if (pManager->ecomInterface.type == SBG_IF_TYPE_FILE) + { + break; + } + + // + // Save CPU time. + // + sbgSleep(1); + } + } + + sbgEComClose(&pManager->ecomHandle); + } + + return errorCode; +} + +//----------------------------------------------------------------------// +// Public functions // +//----------------------------------------------------------------------// + +/*! + * Program entry point. + * + * \param[in] argc Number of input arguments. + * \param[in] argv Input arguments as an array of strings. + * \return EXIT_SUCCESS if successful. + */ +int main(int argc, char **argv) +{ + SbgBasicLoggerManager *pManager; + int exitCode = EXIT_SUCCESS; + bool printHelp = false; + + struct arg_lit *pHelpArg; + struct arg_lit *pVersionArg; + struct arg_str *pUdpAddrArg; + struct arg_int *pUdpPortInArg; + struct arg_int *pUdpPortOutArg; + struct arg_str *pSerialDeviceArg; + struct arg_int *pSerialBaudrateArg; + struct arg_file *pInputFileArg; + struct arg_lit *pWriteLogs; + struct arg_str *pWriteLogsDirArg; + struct arg_int *pFileDecimationArg; + struct arg_int *pScreenDecimationArg; + struct arg_lit *pPrintLogs; + struct arg_lit *pLogsHeader; + struct arg_end *pEndArg; + + void *argTable[] = + { + pHelpArg = arg_lit0( "h", "help", "display this help and exit"), + pVersionArg = arg_lit0( "v", "version", "display sbgECom version and exit"), + + pUdpAddrArg = arg_str0( "a", "addr-ip", "IP address", "open an UDP interface"), + pUdpPortInArg = arg_int0( "I", "udp-port-in", "UDP port in", "UDP port in"), + pUdpPortOutArg = arg_int0( "O", "udp-port-out", "UDP port out", "UDP port out"), + + pSerialDeviceArg = arg_str0( "s", "serial-device", "SERIAL_DEVICE", "open a serial interface"), + pSerialBaudrateArg = arg_int0( "r", "serial-baudrate", "SERIAL_BAUDRATE", "serial baudrate"), + + pInputFileArg = arg_file0( "i", "input-file", "INPUT-FILE", "input file"), + + pWriteLogs = arg_lit0( "w", "write-logs", "write logs in different files"), + pWriteLogsDirArg = arg_str0( NULL, "dir", "DIRECTORY", "directory to write logs into"), + + pFileDecimationArg = arg_int0( "d", "file-decimation", "FILE DECIMATION", "file decimation"), + pScreenDecimationArg = arg_int0( "c", "console-decimation", "CONSOLE DECIMATION", "output stream decimation"), + + pPrintLogs = arg_lit0( "p", "print-logs", "print the logs on the output stream"), + + pLogsHeader = arg_lit0( "H", "disable-header", "disable header for files"), + + pEndArg = arg_end(20), + }; + + memset(&gSbgBasicLogger, 0, sizeof(gSbgBasicLogger)); + + pManager = &gSbgBasicLogger; + + sbgCommonLibSetLogCallback(onLogCallback); + + if (arg_nullcheck(argTable) == 0) + { + int argError; + + argError = arg_parse(argc, argv, argTable); + + if (pHelpArg->count != 0) + { + printf("Usage: %s", PROGRAM_NAME); + arg_print_syntax(stdout, argTable, "\n\n"); + printf("Manage sbgECom logs in text format.\n\n"); + + printf("Serial example: %s -s -r -p\n", PROGRAM_NAME); + printf(" UDP example: %s -a -I -O -p\n", PROGRAM_NAME); + printf(" File example: %s -i -p\n\n", PROGRAM_NAME); + + printf("Logs affected by decimation:\n\t- IMU short\n\t- IMU fast\n\t- IMU data\n\n"); + + arg_print_glossary(stdout, argTable, " %-50s %s\n"); + } + else if (pVersionArg->count != 0) + { + printf("%s\n", sbgEComGetVersionAsString()); + } + else if (argError == 0) + { + if (pLogsHeader->count != 0) + { + pManager->userArgs.writeHeader = false; + } + else + { + pManager->userArgs.writeHeader = true; + } + + if (pWriteLogs->count != 0) + { + pManager->userArgs.writingFiles = true; + pManager->userArgs.fileDecimation = 0; + + if (pWriteLogsDirArg->count != 0) + { + SbgErrorCode errorCode; + + errorCode = sbgStringConstructCString(&pManager->userArgs.path, pWriteLogsDirArg->sval[0]); + + if (errorCode == SBG_NO_ERROR) + { + if ((errorCode == SBG_NO_ERROR) && !sbgStringEndsWith(&pManager->userArgs.path, "/")) + { + sbgStringAppendCString(&pManager->userArgs.path, "/"); + } + } + else + { + fprintf(stderr, "Invalid path format.\n"); + exitCode = EXIT_FAILURE; + printHelp = true; + } + } + else + { + sbgStringConstructCString(&pManager->userArgs.path, ""); + } + + pManager->userArgs.pPathStr = sbgStringGetCString(&pManager->userArgs.path); + } + + if (pFileDecimationArg->count != 0) + { + pManager->userArgs.fileDecimation = pFileDecimationArg->ival[0]; + } + else + { + pManager->userArgs.fileDecimation = 1; + } + + if (pPrintLogs->count != 0) + { + pManager->userArgs.consoleEnabled = true; + pManager->userArgs.consoleDecimation = 0; + } + + if (pScreenDecimationArg->count != 0) + { + pManager->userArgs.consoleDecimation = pScreenDecimationArg->ival[0]; + } + else + { + pManager->userArgs.consoleDecimation = 1; + } + + if ((pSerialDeviceArg->count != 0) && (pSerialBaudrateArg->count != 0) && + ((pInputFileArg->count != 0) || + (pUdpAddrArg->count != 0) || + (pUdpPortInArg->count != 0) || + (pUdpPortOutArg->count != 0))) + { + fprintf(stderr, "Too many arguments.\n"); + exitCode = EXIT_FAILURE; + printHelp = true; + } + + if ((pInputFileArg->count != 0) && + ((pSerialDeviceArg->count != 0) || + (pSerialBaudrateArg->count != 0) || + (pUdpAddrArg->count != 0) || + (pUdpPortInArg->count != 0) || + (pUdpPortOutArg->count != 0))) + { + fprintf(stderr, "Too many arguments.\n"); + exitCode = EXIT_FAILURE; + printHelp = true; + } + + if ((pUdpAddrArg->count != 0) && (pUdpPortInArg->count != 0) && (pUdpPortOutArg->count != 0) && + ((pInputFileArg->count != 0) || + (pSerialDeviceArg->count != 0) || + (pSerialBaudrateArg->count != 0))) + { + fprintf(stderr, "Too many arguments.\n"); + exitCode = EXIT_FAILURE; + printHelp = true; + } + + if (!pManager->userArgs.consoleEnabled && !pManager->userArgs.writingFiles) + { + fprintf(stderr, "Specify if you want to print (-p) logs on console or write (-w) into files.\n"); + exitCode = EXIT_FAILURE; + printHelp = true; + } + + if (exitCode == EXIT_SUCCESS) + { + if ((pSerialDeviceArg->count != 0) && (pSerialBaudrateArg->count != 0)) + { + SbgErrorCode errorCode; + + errorCode = sbgInterfaceSerialCreate(&pManager->ecomInterface, pSerialDeviceArg->sval[0], pSerialBaudrateArg->ival[0]); + + if (errorCode != SBG_NO_ERROR) + { + SBG_LOG_ERROR(errorCode, "unable to open serial interface"); + exitCode = EXIT_FAILURE; + } + } + else if (pInputFileArg->count != 0) + { + SbgErrorCode errorCode; + + errorCode = sbgInterfaceFileOpen(&pManager->ecomInterface, pInputFileArg->filename[0]); + + if (errorCode != SBG_NO_ERROR) + { + SBG_LOG_ERROR(errorCode, "unable to open file interface"); + exitCode = EXIT_FAILURE; + } + } + else if ((pUdpAddrArg->count != 0) && (pUdpPortInArg->count != 0) && (pUdpPortOutArg->count != 0)) + { + SbgErrorCode errorCode; + + errorCode = sbgInterfaceUdpCreate(&pManager->ecomInterface, sbgNetworkIpFromString(pUdpAddrArg->sval[0]), pUdpPortOutArg->ival[0], pUdpPortInArg->ival[0]); + + if (errorCode != SBG_NO_ERROR) + { + SBG_LOG_ERROR(errorCode, "unable to open file interface"); + exitCode = EXIT_FAILURE; + } + } + else + { + exitCode = EXIT_FAILURE; + printHelp = true; + } + } + + if (exitCode == EXIT_SUCCESS) + { + SbgErrorCode errorCode; + + errorCode = sbgBasicLoggerManagerReceiveLogs(pManager); + + if (errorCode != SBG_NO_ERROR) + { + exitCode = EXIT_FAILURE; + } + + sbgInterfaceDestroy(&pManager->ecomInterface); + } + } + else + { + printHelp = true; + } + + if (printHelp) + { + arg_print_errors(stderr, pEndArg, PROGRAM_NAME); + fprintf(stderr, "Try '%s --help' for more information.\n", PROGRAM_NAME); + exitCode = EXIT_FAILURE; + } + + arg_freetable(argTable, SBG_ARRAY_SIZE(argTable)); + } + else + { + SBG_LOG_ERROR(SBG_MALLOC_FAILED, "unable to allocate memory"); + exitCode = EXIT_FAILURE; + } + + return exitCode; +} diff --git a/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerAccumulators.c b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerAccumulators.c new file mode 100644 index 0000000..b127303 --- /dev/null +++ b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerAccumulators.c @@ -0,0 +1,58 @@ +// sbgCommonLib +#include + +// sbgECom headers +#include + +// Local header +#include "sbgBasicLoggerAccumulators.h" + +//----------------------------------------------------------------------// +//- Private methods for SbgEComBasicLoggerAcc -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerImuAccZeroInit(SbgBasicLoggerImuAcc *pAccumulator) +{ + assert(pAccumulator); + + memset(pAccumulator, 0x00, sizeof(*pAccumulator)); +} + +void sbgBasicLoggerImuAccAdd(SbgBasicLoggerImuAcc *pAccumulator, const SbgBasicLoggerImu *pNewImuData) +{ + assert(pAccumulator); + assert(pNewImuData); + + pAccumulator->imuAccumulated.timestamp = pNewImuData->timestamp; + pAccumulator->imuAccumulated.status |= pNewImuData->status; + + for (size_t i = 0; i < 3; i++) + { + pAccumulator->imuAccumulated.deltaAngle[i] += pNewImuData->deltaAngle[i]; + pAccumulator->imuAccumulated.deltaVelocity[i] += pNewImuData->deltaVelocity[i]; + } + + pAccumulator->imuAccumulated.temperature += pNewImuData->temperature; + + pAccumulator->nrAcc++; +} + +void sbgBasicLoggerImuAccGet(SbgBasicLoggerImuAcc *pAccumulator, SbgBasicLoggerImu *pDecimatedImu) +{ + assert(pAccumulator); + assert(pDecimatedImu); + + pDecimatedImu->timestamp = pAccumulator->imuAccumulated.timestamp; + pDecimatedImu->status = pAccumulator->imuAccumulated.status; + + for (size_t i = 0; i < 3; i++) + { + pDecimatedImu->deltaAngle[i] = pAccumulator->imuAccumulated.deltaAngle[i] / (double)pAccumulator->nrAcc; + pDecimatedImu->deltaVelocity[i] = pAccumulator->imuAccumulated.deltaVelocity[i] / (double)pAccumulator->nrAcc; + } + + pDecimatedImu->temperature = pAccumulator->imuAccumulated.temperature / (double)pAccumulator->nrAcc; + + sbgBasicLoggerImuAccZeroInit(pAccumulator); +} + diff --git a/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerAccumulators.h b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerAccumulators.h new file mode 100644 index 0000000..f636fd5 --- /dev/null +++ b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerAccumulators.h @@ -0,0 +1,115 @@ +/*! + * \file sbgBasicLoggerAccumulators.h + * \author SBG Systems + * \date July 29, 2021 + * + * \brief Helper accumulators for IMU data. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense Proprietary license + * + * This source code is intended for use only by SBG Systems SAS and + * those that have explicit written permission to use it from + * SBG Systems SAS. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + * PARTICULAR PURPOSE. + * + * \endlicense + */ + +#ifndef SBG_BASIC_LOGGER_ACCUMULATORS_H +#define SBG_BASIC_LOGGER_ACCUMULATORS_H + +// sbgCommonLib headers +#include + +// sbgECom headers +#include + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Define a set of IMU data + */ +typedef struct _SbgBasicLoggerImu +{ + uint32_t timestamp; /*!< The data time stamp in us */ + uint16_t status; /*!< IMU data status as defined in sbgECom logs */ + double deltaAngle[3]; /*!< X, Y, Z delta angles values in rad.s^-1 */ + double deltaVelocity[3]; /*!< X, Y, Z delta velocities values in m.s^-2 */ + double temperature; /*!< IMU temperature in °C. */ +} SbgBasicLoggerImu; + +/*! + * Used to accumulate and decimate gyros / accels values. + */ +typedef struct _SbgBasicLoggerImuAcc +{ + size_t nrAcc; /*!< Number of accumulated samples. */ + SbgBasicLoggerImu imuAccumulated; /*!< Accumulated IMU data. */ +} SbgBasicLoggerImuAcc; + + +/*! + * Define a set of raw IMU data. + */ +typedef struct _SbgBasicLoggerImuRaw +{ + uint32_t timestamp; /*!< Time in us since the sensor power up. */ + uint16_t status; /*!< IMU status bitmask. */ + + int64_t rawAccelerometers[3]; /*!< X,Y,Z raw accelerometers signed data. No scale factor defined. */ + int64_t rawGyroscopes[3]; /*!< X,Y,Z raw gyroscopes signed data. No scale factor defined. */ + int64_t rawMagnetometers[3]; /*!< X,Y,Z raw magnetometers signed data. No scale factor defined. */ + + int64_t rawTempAccels[3]; /*!< X,Y,Z raw accelerometers temperature signed data. No scale factor defined. */ + int64_t rawTempGyros[3]; /*!< X,Y,Z raw gyroscopes temperature signed data. No scale factor defined. */ + int64_t rawTempMags[3]; /*!< X,Y,Z raw magnetometers temperature signed data. No scale factor defined. */ + + int64_t rawAuxValues[3]; /*!< Spare raw sensor values for specifics needs. */ + int64_t rawTempAuxValues[3]; /*!< Spare raw sensor temperature values for specifics needs. */ +} SbgBasicLoggerImuRaw; + +/*! + * Used to accumulate and decimate raw IMU values. + */ +typedef struct _SbgBasicLoggerRawImuAcc +{ + size_t nrAcc; /*!< Number of accumulated samples. */ + SbgBasicLoggerImuRaw rawImuAcc; /*!< Accumulated raw IMU data. */ +} SbgBasicLoggerRawImuAcc; + +//----------------------------------------------------------------------// +//- Private methods for SbgEComBasicLoggerAcc -// +//----------------------------------------------------------------------// + +/*! + * Zero initialize / reset an IMU accumulator instance. + * + * \param[in] pAccumulator Instance on the IMU accumulator to reset. + */ +void sbgBasicLoggerImuAccZeroInit(SbgBasicLoggerImuAcc *pAccumulator); + +/*! + * Accumulate a new set of IMU data + * + * \param[in] pAccumulator Instance on the IMU accumulator. + * \param[in] pNewImuData New set of IMU data to accumulate + */ +void sbgBasicLoggerImuAccAdd(SbgBasicLoggerImuAcc *pAccumulator, const SbgBasicLoggerImu *pNewImuData); + +/*! + * Compute the decimated IMU values and reset the accumulator for next iteration. + * + * \param[in] pAccumulator Instance on the IMU accumulator. + * \param[out] pDecimatedImu The decimated IMU values. + */ +void sbgBasicLoggerImuAccGet(SbgBasicLoggerImuAcc *pAccumulator, SbgBasicLoggerImu *pDecimatedImu); + + +#endif // SBG_BASIC_LOGGER_ACCUMULATORS_H diff --git a/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerFile.c b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerFile.c new file mode 100644 index 0000000..89a958f --- /dev/null +++ b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerFile.c @@ -0,0 +1,88 @@ +// sbgCommonLib headers +#include + +// sbgECom headers +#include +#include + +// Local headers +#include "sbgBasicLoggerFile.h" + +//----------------------------------------------------------------------// +//- Private variables -// +//----------------------------------------------------------------------// + +static SbgBasicLoggerFileDesc gSbgBasicLoggerFileDescs[] = +{ + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_STATUS, .pName = "STATUS", .pFileName = "log_status.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_UTC_TIME, .pName = "UTC", .pFileName = "log_utc.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_DIAG, .pName = "DIAG", .pFileName = "log_diag.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_IMU_DATA, .pName = "IMU_DATA", .pFileName = "log_imu.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_IMU_SHORT, .pName = "IMU_SHORT", .pFileName = "log_imuShort.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_MAG, .pName = "MAG", .pFileName = "log_mag.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_MAG_CALIB, .pName = "MAG_CALIB", .pFileName = "log_magCalib.txt" }, + + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_EKF_EULER, .pName = "EULER", .pFileName = "log_euler.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_EKF_QUAT, .pName = "QUAT", .pFileName = "log_quat.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_EKF_NAV, .pName = "NAV", .pFileName = "log_nav.txt" }, + + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_SHIP_MOTION, .pName = "SHIP_MOTION", .pFileName = "log_shipMotion.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_SHIP_MOTION_HP, .pName = "SHIP_MOTION_HP", .pFileName = "log_shipMotionHP.txt" }, + + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_GPS1_VEL, .pName = "GPS1_VEL", .pFileName = "log_gps1Vel.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_GPS1_POS, .pName = "GPS1_POS", .pFileName = "log_gps1Pos.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_GPS1_HDT, .pName = "GPS1_HDT", .pFileName = "log_gps1Hdt.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_GPS1_RAW, .pName = "GPS1_RAW", .pFileName = "log_gps1Raw.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_GPS1_SAT, .pName = "GPS1_SAT", .pFileName = "log_gps1Sat.txt" }, + + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_GPS2_VEL, .pName = "GPS2_VEL", .pFileName = "log_gps2Vel.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_GPS2_POS, .pName = "GPS2_POS", .pFileName = "log_gps2Pos.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_GPS2_HDT, .pName = "GPS2_HDT", .pFileName = "log_gps2Hdt.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_GPS2_RAW, .pName = "GPS2_RAW", .pFileName = "log_gps2Raw.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_GPS2_SAT, .pName = "GPS2_SAT", .pFileName = "log_gps2Sat.txt" }, + + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_RTCM_RAW, .pName = "RTCM_RAW", .pFileName = "log_rtcmRaw.txt" }, + + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_ODO_VEL, .pName = "ODO_VEL", .pFileName = "log_odo.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_DVL_BOTTOM_TRACK, .pName = "DVL_BOTTOM", .pFileName = "log_dvl_bottom.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_DVL_WATER_TRACK, .pName = "DVL_WATER", .pFileName = "log_dvl_water.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_AIR_DATA, .pName = "AIR_DATA", .pFileName = "log_air.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_USBL, .pName = "USBL", .pFileName = "log_usbl.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_DEPTH, .pName = "DEPTH", .pFileName = "log_depth.txt" }, + + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_EVENT_A, .pName = "EVENT_IN_A", .pFileName = "log_eventInA.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_EVENT_B, .pName = "EVENT_IN_B", .pFileName = "log_eventInB.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_EVENT_C, .pName = "EVENT_IN_C", .pFileName = "log_eventInC.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_EVENT_D, .pName = "EVENT_IN_D", .pFileName = "log_eventInD.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_EVENT_E, .pName = "EVENT_IN_E", .pFileName = "log_eventInE.txt" }, + + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_EVENT_OUT_A, .pName = "EVENT_OUT_A", .pFileName = "log_eventOutA.txt" }, + { .class = SBG_ECOM_CLASS_LOG_ECOM_0, .id = SBG_ECOM_LOG_EVENT_OUT_B, .pName = "EVENT_OUT_B", .pFileName = "log_eventOutB.txt" }, + + { .class = SBG_ECOM_CLASS_LOG_ECOM_1, .id = SBG_ECOM_LOG_FAST_IMU_DATA, .pName = "IMU_FAST", .pFileName = "log_imuFast.txt" }, + +}; + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +const SbgBasicLoggerFileDesc *sbgBasicLoggerFileGetDesc(SbgEComClass msgClass, SbgEComMsgId msgId) +{ + const SbgBasicLoggerFileDesc *pDesc = NULL; + + for (size_t i = 0; i < SBG_ARRAY_SIZE(gSbgBasicLoggerFileDescs); i++) + { + const SbgBasicLoggerFileDesc *pTmpDesc; + + pTmpDesc = &gSbgBasicLoggerFileDescs[i]; + + if ((pTmpDesc->class == msgClass) && (pTmpDesc->id == msgId)) + { + pDesc = pTmpDesc; + break; + } + } + + return pDesc; +} diff --git a/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerFile.h b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerFile.h new file mode 100644 index 0000000..c92badc --- /dev/null +++ b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerFile.h @@ -0,0 +1,60 @@ +/*! + * \file sbgBasicLoggerAccumulators.h + * \author SBG Systems + * \date July 29, 2021 + * + * \brief Ease output log files management. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense Proprietary license + * + * This source code is intended for use only by SBG Systems SAS and + * those that have explicit written permission to use it from + * SBG Systems SAS. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + * PARTICULAR PURPOSE. + * + * \endlicense + */ + +#ifndef SBG_BASIC_LOGGER_FILE_H +#define SBG_BASIC_LOGGER_FILE_H + +// sbgCommonLib headers +#include + +// sbgECom headers +#include + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * SBG basic logger file descriptor. + */ +typedef struct _SbgBasicLoggerFileDesc +{ + SbgEComClass class; /*!< Message class. */ + SbgEComMsgId id; /*!< Message ID. */ + const char *pName; /*!< The log name. */ + const char *pFileName; /*!< File name suffix. */ +} SbgBasicLoggerFileDesc; + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +/*! + * Return the file descriptor. + * + * \param[in] msgClass Message class. + * \param[in] msgId Message ID. + * \return File descriptor. + */ +const SbgBasicLoggerFileDesc *sbgBasicLoggerFileGetDesc(SbgEComClass msgClass, SbgEComMsgId msgId); + +#endif // SBG_BASIC_LOGGER_FILE_H diff --git a/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerHandler.c b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerHandler.c new file mode 100644 index 0000000..64bea96 --- /dev/null +++ b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerHandler.c @@ -0,0 +1,2064 @@ +// sbgCommonLib headers +#include +#include + +// sbgECom headers +#include + +// Local headers +#include "sbgBasicLoggerAccumulators.h" +#include "sbgBasicLoggerHandler.h" + +//----------------------------------------------------------------------// +//- Private functions -// +//----------------------------------------------------------------------// + +/*! + * Write IMU short data into an output stream. + * + * \param[in] pImuShort IMU short data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteImu(const SbgBasicLoggerImu *pImuShort, void *pStream) +{ + assert(pImuShort); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu32"\t%0.12lf\t%0.12lf\t%0.12lf\t%0.12lf\t%0.12lf\t%0.12lf\t%0.3lf\n", + pImuShort->timestamp, pImuShort->status, + pImuShort->deltaVelocity[0], pImuShort->deltaVelocity[1], pImuShort->deltaVelocity[2], + sbgRadToDegd(pImuShort->deltaAngle[0]), sbgRadToDegd(pImuShort->deltaAngle[1]), sbgRadToDegd(pImuShort->deltaAngle[2]), + pImuShort->temperature); + + fflush(pStream); +} + +/*! + * Write IMU data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteImuHeader(void *pStream) +{ + assert(pStream); + + fprintf(pStream, "timestamp\tstatus\tdeltaVelX\tdeltaVelY\tdeltaVelZ\tdeltaAngleX\tdeltaAngleY\tdeltaAngleZ\ttemperature\n"); + fprintf(pStream, "(us)\t(N/A)\t(m.s^-2)\t(m.s^-2)\t(m.s^-2)\t(deg.s^-1)\t(deg.s^-1)\t(deg.s^-1)\t(°C)\n"); + fflush(pStream); +} + + +/*! + * Write a diag data into an output stream. + * + * \param[in] pDiag Diag data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteDiag(const SbgLogDiagData *pDiag, const char *pUtcTimeStr, void *pStream) +{ + assert(pDiag); + assert(pUtcTimeStr); + assert(pStream); + + switch (pDiag->type) + { + case SBG_DEBUG_LOG_TYPE_ERROR: + fprintf(pStream, "%s *ERR * [%s]: %s\n", pUtcTimeStr, sbgErrorCodeToString(pDiag->errorCode), pDiag->string); + break; + case SBG_DEBUG_LOG_TYPE_WARNING: + fprintf(pStream, "%s *WARN* [%s]: %s\n", pUtcTimeStr, sbgErrorCodeToString(pDiag->errorCode), pDiag->string); + break; + case SBG_DEBUG_LOG_TYPE_INFO: + fprintf(pStream, "%s *INFO* %s\n", pUtcTimeStr, pDiag->string); + break; + case SBG_DEBUG_LOG_TYPE_DEBUG: + fprintf(pStream, "%s *DBG * %s\n", pUtcTimeStr, pDiag->string); + break; + default: + fprintf(pStream, "%s *UKN * [%s]: %s\n", pUtcTimeStr, sbgErrorCodeToString(pDiag->errorCode), pDiag->string); + } + + fflush(pStream); +} + +/*! + * Write an UTC data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteUtcHeader(void *pStream) +{ + assert(pStream); + + fprintf(pStream, "timestamp\tstatus\tgpsTimeOfWeek\tyear\tmonth\tday\thour\tminute\tsecond\tnanosecond\n"); + fprintf(pStream, "(us)\t(NA)\t(ms)\t(yyyy)\t(mm)\t(dd)\t(hh)\t(mm)\t(ss)\t(ns)\n"); + fflush(pStream); +} + +/*! + * Write an UTC data into an output stream. + * + * \param[in] pUtc UTC data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteUtc(const SbgLogUtcData *pUtc, void *pStream) +{ + assert(pUtc); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu16"\t%"PRIu32"\t%"PRIu16"\t%0.2"PRId8"\t%0.2"PRId8"\t%0.2"PRId8"\t%0.2"PRId8"\t%0.2"PRId8"\t%"PRId32"\n", + pUtc->timeStamp, + pUtc->status, + pUtc->gpsTimeOfWeek, + pUtc->year, + pUtc->month, + pUtc->day, + pUtc->hour, + pUtc->minute, + pUtc->second, + pUtc->nanoSecond + ); + fflush(pStream); +} + +/*! + * Write a status data into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteStatusHeader(void *pStream) +{ + assert(pStream); + + fprintf(pStream, "timestamp\tgeneral\tcom2\tcom\taiding\n"); + fprintf(pStream, "(us)\t(NA)\t(NA)\t(NA)\t(NA)\n"); + fflush(pStream); +} + +/*! + * Write a status data into an output stream. + * + * \param[in] pStatus Status data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteStatus(const SbgLogStatusData *pStatus, void *pStream) +{ + assert(pStatus); + assert(pStream); + + fprintf(pStream, "%" PRIu32 "\t%" PRIu16 "\t%" PRIu16 "\t%" PRIu32 "\t%" PRIu32 "\n", + pStatus->timeStamp, + pStatus->generalStatus, + pStatus->comStatus2, + pStatus->comStatus, + pStatus->aidingStatus + ); + + fflush(pStream); +} + +/*! + * Write an EKF Euler data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteEkfEulerHeader(void *pStream) +{ + assert(pStream); + + fprintf(pStream, "timestamp\tstatus\troll\tpitch\tyaw\trollStd\tpitchStd\tyawStd\n"); + fprintf(pStream, "(us)\t(NA)\t(deg)\t(deg)\t(deg)\t(deg)\t(deg)\t(deg)\n"); + fflush(pStream); +} + +/*! + * Write an EKF Euler data into an output stream. + * + * \param[in] pData EKF Euler data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteEkfEuler(const SbgLogEkfEulerData *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu32"\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\n", + pData->timeStamp, + pData->status, + sbgRadToDegf(pData->euler[0]), + sbgRadToDegf(pData->euler[1]), + sbgRadToDegf(pData->euler[2]), + sbgRadToDegf(pData->eulerStdDev[0]), + sbgRadToDegf(pData->eulerStdDev[1]), + sbgRadToDegf(pData->eulerStdDev[2]) + ); + fflush(pStream); +} + +/*! + * Write an EKF Euler data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteEkfQuatHeader(void *pStream) +{ + assert(pStream); + + fprintf(pStream, "timestamp\tstatus\tW\tX\tY\tZ\trollStd\tpitchStd\tyawStd\n"); + fprintf(pStream, "(us)\t(NA)\t(NA)\t(NA)\t(NA)\t(NA)\t(deg)\t(deg)\t(deg)\n"); + fflush(pStream); +} + +/*! + * Write an EKF quat data into an output stream. + * + * \param[in] pData EKF quat data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteEkfQuat(const SbgLogEkfQuatData *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu32"\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\n", + pData->timeStamp, + pData->status, + pData->quaternion[0], + pData->quaternion[1], + pData->quaternion[2], + pData->quaternion[3], + sbgRadToDegf(pData->eulerStdDev[0]), + sbgRadToDegf(pData->eulerStdDev[1]), + sbgRadToDegf(pData->eulerStdDev[2]) + ); + fflush(pStream); +} + +/*! + * Write an EKF nav data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteEkfNavHeader(void *pStream) +{ + assert(pStream); + + fprintf(pStream, "timestamp\tstatus\tvelN\tvelE\tvelD\tvelStdN\tvelStdE\tvelStdD\tlatitude\tlongitude\taltitude\tlatitudeStd\tlongitudeStd\taltitudeStd\tundulation\n"); + fprintf(pStream, "(us)\t(NA)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(deg)\t(deg)\t(m)\t(m)\t(m)\t(m)\t(m)\n"); + fflush(pStream); +} + +/*! + * Write an EKF nav data into an output stream. + * + * \param[in] pData EKF nav data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteEkfNav(const SbgLogEkfNavData *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu32"\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\n", + pData->timeStamp, + pData->status, + pData->velocity[0], + pData->velocity[1], + pData->velocity[2], + pData->velocityStdDev[0], + pData->velocityStdDev[1], + pData->velocityStdDev[2], + pData->position[0], + pData->position[1], + pData->position[2], + pData->positionStdDev[0], + pData->positionStdDev[1], + pData->positionStdDev[2], + pData->undulation + ); + fflush(pStream); +} + +/*! + * Write a ship motion data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteShipMotionHeader(void *pStream) +{ + assert(pStream); + fprintf(pStream, "timestamp\tstatus\tsurge\tsway\theave\tsurgeVel\tswayVel\theaveVel\tsurgeAccel\tswayAccel\theaveAccel\theavePeriod\n"); + fprintf(pStream, "(us)\t(NA)\t(m)\t(m)\t(m)\t(m)\t(m)\t(m)\t(m)\t(m)\t(m)\t(s)\n"); + fflush(pStream); +} + +/*! + * Write a ship motion data into an output stream. + * + * \param[in] pData Ship motion data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteShipMotion(const SbgLogShipMotionData *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu16"\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n", + pData->timeStamp, + pData->status, + pData->shipMotion[0], + pData->shipMotion[1], + pData->shipMotion[2], + pData->shipVel[0], + pData->shipVel[1], + pData->shipVel[2], + pData->shipAccel[0], + pData->shipAccel[1], + pData->shipAccel[2], + pData->mainHeavePeriod + ); + fflush(pStream); +} + +/*! + * Write a GPS vel data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteGpsVelHeader(void *pStream) +{ + assert(pStream); + fprintf(pStream, "timestamp\tstatus\ttimeOfWeek\tvelN\tvelE\tvelD\tvelNStd\tvelEStd\tvelDStd\tcourse\tcourseStd\n"); + fprintf(pStream, "(us)\t(NA)\t(ms)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(degrees)\t(degrees)\n"); + fflush(pStream); +} + +/*! + * Write a GPS vel data into an output stream. + * + * \param[in] pData GPS vel data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteGpsVel(const SbgLogGpsVel *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu32"\t%"PRIu32"\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\n", + pData->timeStamp, + pData->status, + pData->timeOfWeek, + pData->velocity[0], + pData->velocity[1], + pData->velocity[2], + pData->velocityAcc[0], + pData->velocityAcc[1], + pData->velocityAcc[2], + pData->course, + pData->courseAcc + ); + fflush(pStream); +} + +/*! + * Write a GPS data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteGpsHeader(void *pStream) +{ + assert(pStream); + fprintf(pStream, "timestamp\ttimeOfWeek\tstatus\taltitude\n"); + fprintf(pStream, "(us)\t(ms)\t(NA)\t(m)\n"); + fflush(pStream); +} + +/*! + * Write a GPS data into an output stream. + * + * \param[in] pData GPS data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteGps(const SbgLogGpsPos *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu32"\t%"PRIu32"\t%lf\n", + pData->timeStamp, + pData->timeOfWeek, + pData->status, + pData->altitude); + fflush(pStream); +} + +/*! + * Write a GPS hdt data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteGpsHdtHeader(void *pStream) +{ + assert(pStream); + fprintf(pStream, "timestamp\tstatus\ttimeOfWeek\theading\theadingStd\tpitch\tpitchStd\tbaseline\n"); + fprintf(pStream, "(us)\t(NA)\t(ms)\t(degrees)\t(degrees)\t(degrees)\t(degrees)\t(m)\n"); + fflush(pStream); +} + +/*! + * Write a GPS hdt data into an output stream. + * + * \param[in] pData GPS hdt data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteGpsHdt(const SbgLogGpsHdt *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu16"\t%"PRIu32"\t%lf\t%lf\t%lf\t%lf\t%lf\n", + pData->timeStamp, + pData->status, + pData->timeOfWeek, + pData->heading, + pData->headingAccuracy, + pData->pitch, + pData->pitchAccuracy, + pData->baseline + ); + fflush(pStream); +} + +/*! + * Write a GPS Satellite data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteGpsSatHeader(void *pStream) +{ + assert(pStream); +} + +/*! + * Write a GPS Satellite data into an output stream. + * + * \param[in] pData GPS satellite data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteGpsSat(const SbgLogSatGroupData *pData, void *pStream) +{ + size_t satelliteIdx; + size_t signalIdx; + + assert(pData); + assert(pStream); + + fprintf(pStream, "%10"PRIu32" us | Satellites: %3zu ====================================================================\n", + pData->timeStamp, + pData->nrSatellites); + + for (satelliteIdx = 0; satelliteIdx < pData->nrSatellites; satelliteIdx++) + { + const SbgLogSatData *pSatEntry = &pData->pSatData[satelliteIdx]; + SbgEComSatElevationStatus elevationStatus; + char elevationStatusChr; + + elevationStatus = sbgLogSatDataGetElevationStatus(pSatEntry); + + if (elevationStatus == SBG_ECOM_SAT_ELEVATION_STATUS_SETTING) + { + elevationStatusChr = 's'; + } + else if (elevationStatus == SBG_ECOM_SAT_ELEVATION_STATUS_RISING) + { + elevationStatusChr = 'r'; + } + else + { + elevationStatusChr = '*'; + } + + fprintf(pStream, " [ID: %2"PRIu8" %-8s] Elevation: %3"PRIi8"%c Azimuth: %3"PRIi16" nrSignals: %2zu %-10s%-10s\n", + pSatEntry->id, + sbgLogSatDataGetConstellationIdAsStr(pSatEntry), + pSatEntry->elevation, + elevationStatusChr, + pSatEntry->azimuth, + pSatEntry->nrSignals, + sbgLogSatDataGetHealthStatusAsStr(pSatEntry), + sbgLogSatDataGetTrackingStatusAsStr(pSatEntry)); + + for (signalIdx = 0; signalIdx < pSatEntry->nrSignals; signalIdx++) + { + const SbgLogSatSignalData *pSignalEntry = &pSatEntry->pSignalData[signalIdx]; + char snrStr[16]; + + if (sbgLogSatSignalDataSnrIsValid(pSignalEntry)) + { + sprintf(snrStr, "%-3"PRIu8, pSignalEntry->snr); + } + else + { + strcpy(snrStr, " -"); + } + + fprintf(pStream, " %-14s SNR: %3s %-10s %-10s\n", + sbgLogSatSignalDataGetSignalIdAsStr(pSignalEntry), + snrStr, + sbgLogSatSignalDataGetHealthStatusAsStr(pSignalEntry), + sbgLogSatSignalDataGetTrackingStatusAsStr(pSignalEntry)); + } + } + + fflush(pStream); +} + +/*! + * Write an odometer data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteOdometerHeader(void *pStream) +{ + assert(pStream); + fprintf(pStream, "timestamp\tstatus\tvelocity\n"); + fprintf(pStream, "(us)\t(NA)\t(m.s-1)\n"); + fflush(pStream); +} + +/*! + * Write an odometer data into an output stream. + * + * \param[in] pData Odometer data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteOdometer(const SbgLogOdometerData *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu16"\t%lf\n", + pData->timeStamp, + pData->status, + pData->velocity + ); + fflush(pStream); +} + +/*! + * Write a DVL data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteDvlHeader(void *pStream) +{ + assert(pStream); + fprintf(pStream, "timestamp\tstatus\tvelX\tvelY\tvelZ\tvelQualityX\tvelQualityY\tvelQualityZ\n"); + fprintf(pStream, "(us)\t(NA)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(m.s-1)\t(m.s-1)\n"); + fflush(pStream); +} + +/*! + * Write an DVL data into an output stream. + * + * \param[in] pData DVL data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteDvl(const SbgLogDvlData *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu16"\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\n", + pData->timeStamp, + pData->status, + pData->velocity[0], + pData->velocity[1], + pData->velocity[2], + pData->velocityQuality[0], + pData->velocityQuality[1], + pData->velocityQuality[2] + ); + fflush(pStream); +} + +/*! + * Write an air data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteAirHeader(void *pStream) +{ + assert(pStream); + fprintf(pStream, "timestamp\tstatus\tpressure\taltitude\tpressureDiff\tairSpeed\tairTemp\n"); + fprintf(pStream, "(us)\t(NA)\t(pascal)\t(meters)\t(pascal)\t(m.s-1)\t(celcius degrees)\n"); + fflush(pStream); +} + +/*! + * Write an air data into an output stream. + * + * \param[in] pData Air data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteAir(const SbgLogAirData *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu16"\t%lf\t%lf\t%lf\t%lf\t%lf\n", + pData->timeStamp, + pData->status, + pData->pressureAbs, + pData->altitude, + pData->pressureDiff, + pData->trueAirspeed, + pData->airTemperature + ); + fflush(pStream); +} + +/*! + * Write an USBL data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteUsblHeader(void *pStream) +{ + assert(pStream); + fprintf(pStream, "timestamp\tstatus\tlatitude\tlongitude\tdepth\tlatitudeStd\tlongitudeStd\tdepthStd\n"); + fprintf(pStream, "(us)\t(NA)\t(degrees)\t(degrees)\t(meters)\t(meters)\t(meters)\t(meters)\n"); + fflush(pStream); +} + +/*! + * Write an USBL data into an output stream. + * + * \param[in] pData Air data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteUsbl(const SbgLogUsblData *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu16"\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\n", + pData->timeStamp, + pData->status, + pData->latitude, + pData->longitude, + pData->depth, + pData->latitudeAccuracy, + pData->longitudeAccuracy, + pData->depthAccuracy + ); + fflush(pStream); +} + +/*! + * Write a depth data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteDepthHeader(void *pStream) +{ + assert(pStream); + fprintf(pStream, "timestamp\tstatus\tpressure\tdepth\n"); + fprintf(pStream, "(us)\t(NA)\t(pascal)\t(meters)\n"); + fflush(pStream); +} + +/*! + * Write an depth data into an output stream. + * + * \param[in] pData Depth data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteDepth(const SbgLogDepth *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu16"\t%lf\t%lf\n", + pData->timeStamp, + pData->status, + pData->pressureAbs, + pData->altitude + ); + fflush(pStream); +} + +/*! + * Write a GPS raw data into an output stream. + * + * \param[in] pData GPS raw data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteRawRtcm(const SbgLogRawData *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%zu\n", + pData->bufferSize); + fflush(pStream); +} + +/*! + * Write a GPS raw data into an output stream. + * + * \param[in] pData GPS raw data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteGpsRaw(const SbgLogRawData *pData, void *pStream) +{ + assert(pData); + assert(pStream); + + fprintf(pStream, "%zu\n", + pData->bufferSize); + fflush(pStream); +} + +/*! + * Write event data header into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteEventHeader(void *pStream) +{ + assert(pStream); + + fprintf(pStream, "timestamp\tstatus\ttimeOffset0\ttimeOffset1\ttimeOffset2\ttimeOffset3\n"); + fflush(pStream); +} + +/*! + * Write event data into an output stream. + * + * \param[in] pEvent Event data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteEvent(const SbgLogEvent *pEvent, void *pStream) +{ + assert(pEvent); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu16"\t%"PRIu16"\t%"PRIu16"\t%"PRIu16"\t%"PRIu16"\n", + pEvent->timeStamp, + pEvent->status, + pEvent->timeOffset0, + pEvent->timeOffset1, + pEvent->timeOffset2, + pEvent->timeOffset3); + fflush(pStream); +} + +/*! + * Write mag data into an output stream. + * + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteMagHeader(void *pStream) +{ + assert(pStream); + + fprintf(pStream, "timestamp\tstatus\tmagX\tmagY\tmagZ\taccelX\taccelY\taccelZ\n"); + fprintf(pStream, "(us)\t(NA)\t(A.U)\t(A.U)\t(A.U)\t(m.s^-2)\t(m.s^-2)\t(m.s^-2)\n"); + fflush(pStream); +} + +/*! + * Write mag data into an output stream. + * + * \param[in] pMag Mag data. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerHandlerWriteMag(const SbgLogMag *pMag, void *pStream) +{ + assert(pMag); + assert(pStream); + + fprintf(pStream, "%"PRIu32"\t%"PRIu16"\t%f\t%f\t%f\t%f\t%f\t%f\n", + pMag->timeStamp, + pMag->status, + pMag->magnetometers[0], pMag->magnetometers[1], pMag->magnetometers[2], + pMag->accelerometers[0], pMag->accelerometers[1], pMag->accelerometers[2]); + fflush(pStream); +} + +static SbgErrorCode sbgBasicLoggerHandlerGetUtcTimeFromTimeStamp(uint32_t timeStamp, SbgLogUtcData *pLastUtcData, struct tm *pRefUtcTimestamp, uint32_t *pUs) +{ + SbgErrorCode errorCode = SBG_NO_ERROR; + + assert(pLastUtcData); + assert(pRefUtcTimestamp); + assert(pUs); + + if (sbgEComLogUtcGetClockUtcStatus(pLastUtcData->status) != SBG_ECOM_UTC_INVALID) + { + time_t nrSeconds; + int64_t nrMicroseconds; + int32_t elapsedTime; + + pRefUtcTimestamp->tm_sec = pLastUtcData->second; + pRefUtcTimestamp->tm_min = pLastUtcData->minute; + pRefUtcTimestamp->tm_hour = pLastUtcData->hour; + pRefUtcTimestamp->tm_mday = pLastUtcData->day; + pRefUtcTimestamp->tm_mon = pLastUtcData->month - 1; + pRefUtcTimestamp->tm_year = pLastUtcData->year - 1900; + pRefUtcTimestamp->tm_isdst = -1; + + nrSeconds = mktime(pRefUtcTimestamp); + nrMicroseconds = (int64_t)nrSeconds * 1000000; + elapsedTime = timeStamp - pLastUtcData->timeStamp; + nrMicroseconds += elapsedTime; + + nrSeconds = nrMicroseconds / 1000000; + nrMicroseconds %= 1000000; + + *pRefUtcTimestamp = *localtime(&nrSeconds); + *pUs = (uint32_t)nrMicroseconds; + } + else + { + errorCode = SBG_ERROR; + } + + return errorCode; +} + +//----------------------------------------------------------------------// +//- sbgBasicLoggerCommonHandler methods -// +//----------------------------------------------------------------------// + +/*! + * Check if a handler is initialized. + * + * \param[in] pHandler Common handler. + * \return True if initialized. + */ +static bool sbgBasicLoggerCommonHandlerInitialized(SbgBasicLoggerCommonHandler *pHandler) +{ + assert(pHandler); + + if (pHandler->pDesc) + { + return true; + } + else + { + return false; + } +} + +/*! + * Common handler constructor. + * + * \param[in] pHandler IMU short handler. + * \param[in] consoleEnabled True to print IMU short data on console. + * \param[in] writingFile True to write IMU short data into a file. + */ +static void sbgBasicLoggerCommonHandlerConstruct(SbgBasicLoggerCommonHandler *pHandler, bool consoleEnabled, size_t consoleDecimation, bool writingFile, const char *pPathStr, size_t fileDecimation, bool writeHeader, SbgEComClass class, SbgEComMsgId id) +{ + assert(pHandler); + + pHandler->consoleEnabled = consoleEnabled; + pHandler->writingFile = writingFile; + pHandler->pDesc = sbgBasicLoggerFileGetDesc(class, id); + pHandler->pFILE = NULL; + + pHandler->consoleDecimation = consoleDecimation; + pHandler->fileDecimation = fileDecimation; + pHandler->writeHeader = writeHeader; + pHandler->headerWritten = false; + + pHandler->pPathStr = pPathStr; + pHandler->class = class; + pHandler->id = id; +} + +/*! + * Check if a file is opened. + * + * \param[in] pHandler Common handler. + * \return True if opened. + */ +static bool sbgBasicLoggerCommonHandlerFileOpened(SbgBasicLoggerCommonHandler *pHandler) +{ + assert(sbgBasicLoggerCommonHandlerInitialized(pHandler)); + return pHandler->pFILE; +} + +/*! + * Check if writing file is enabled. + * + * \param[in] pHandler Common handler. + * \return True if enabled. + */ +static bool sbgBasicLoggerCommonHandlerWritingFile(SbgBasicLoggerCommonHandler *pHandler) +{ + assert(sbgBasicLoggerCommonHandlerInitialized(pHandler)); + return pHandler->writingFile; +} + +/*! + * Check if console is enabled. + * + * \param[in] pHandler Common handler. + * \return True if enabled. + */ +static bool sbgBasicLoggerCommonHandlerConsoleEnabled(SbgBasicLoggerCommonHandler *pHandler) +{ + assert(sbgBasicLoggerCommonHandlerInitialized(pHandler)); + return pHandler->consoleEnabled; +} + +/*! + * Check if header writing is enabled. + * + * \param[in] pHandler Common handler. + * \return True if enabled. + */ +static bool sbgBasicLoggerCommonHandlerHeaderWriting(SbgBasicLoggerCommonHandler *pHandler) +{ + assert(sbgBasicLoggerCommonHandlerInitialized(pHandler)); + return pHandler->writeHeader; +} + +/*! + * Check if header have been written. + * + * \param[in] pHandler Common handler. + * \return True if written. + */ +static bool sbgBasicLoggerCommonHandlerHeaderWritten(SbgBasicLoggerCommonHandler *pHandler) +{ + assert(sbgBasicLoggerCommonHandlerInitialized(pHandler)); + return pHandler->headerWritten; +} + +/*! + * Get the path of the handler. + * + * \param[in] pHandler Common handler. + * \return File path. + */ +static FILE *sbgBasicLoggerCommonHandlerGetPath(SbgBasicLoggerCommonHandler *pHandler) +{ + if (!sbgBasicLoggerCommonHandlerFileOpened(pHandler)) + { + if (pHandler->pDesc) + { + SbgErrorCode errorCode; + SbgString fileStr; + SbgString pathStr; + + errorCode = sbgStringConstructCString(&pathStr, pHandler->pPathStr); + + if (errorCode == SBG_NO_ERROR) + { + errorCode = sbgStringConstructCString(&fileStr, pHandler->pDesc->pFileName); + + if (errorCode == SBG_NO_ERROR) + { + errorCode = sbgStringAppend(&pathStr, &fileStr); + + if (errorCode == SBG_NO_ERROR) + { + pHandler->pFILE = fopen(sbgStringGetCString(&pathStr), "wt"); + } + + sbgStringDestroy(&fileStr); + } + + sbgStringDestroy(&pathStr); + } + } + } + + return pHandler->pFILE; +} + +/*! + * Write log info on an output stream. + * + * \param[in] pHandler Common handler. + * \param[in] pStream Output stream. + */ +static void sbgBasicLoggerCommonHandlerWriteLogInfo(SbgBasicLoggerCommonHandler *pHandler, void *pStream) +{ + const SbgBasicLoggerFileDesc *pMsgDesc; + + assert(sbgBasicLoggerCommonHandlerInitialized(pHandler)); + assert(pStream); + + pMsgDesc = sbgBasicLoggerFileGetDesc(pHandler->class, pHandler->id); + + if (pMsgDesc) + { + fprintf(pStream, "%14s: ", pMsgDesc->pName); + } + else + { + fprintf(pStream, "class:%0.2u id:%0.2u: ", pHandler->class, pHandler->id); + } +} + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +//----------------------------------------------------------------------// +//- IMU short handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerImuShortHandlerConstruct(SbgBasicLoggerImuHandler *pHandler, bool consoleEnabled, size_t consoleDecimation, bool writingFile, const char *pPathStr, size_t fileDecimation, bool writeHeader) +{ + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, consoleDecimation, writingFile, pPathStr, fileDecimation, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_IMU_SHORT); + + sbgBasicLoggerImuAccZeroInit(&pHandler->consoleAcc); + sbgBasicLoggerImuAccZeroInit(&pHandler->fileAcc); +} + +void sbgBasicLoggerImuHandlerConstruct(SbgBasicLoggerImuHandler *pHandler, bool consoleEnabled, size_t consoleDecimation, bool writingFile, const char *pPathStr, size_t fileDecimation, bool writeHeader) +{ + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, consoleDecimation, writingFile, pPathStr, fileDecimation, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_IMU_DATA); + + sbgBasicLoggerImuAccZeroInit(&pHandler->consoleAcc); + sbgBasicLoggerImuAccZeroInit(&pHandler->fileAcc); +} + +void sbgBasicLoggerImuFastHandlerConstruct(SbgBasicLoggerImuHandler *pHandler, bool consoleEnabled, size_t consoleDecimation, bool writingFile, const char *pPathStr, size_t fileDecimation, bool writeHeader) +{ + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, consoleDecimation, writingFile, pPathStr, fileDecimation, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_1, SBG_ECOM_LOG_FAST_IMU_DATA); + + sbgBasicLoggerImuAccZeroInit(&pHandler->consoleAcc); + sbgBasicLoggerImuAccZeroInit(&pHandler->fileAcc); +} + +void sbgBasicLoggerImuHandlerProcess(SbgBasicLoggerImuHandler *pHandler, const SbgBasicLoggerImu *pNewData) +{ + assert(pNewData); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if ((sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler)) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteImuHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerImuAccAdd(&pHandler->fileAcc, pNewData); + + if (pHandler->fileAcc.nrAcc >= pHandler->commonHandler.fileDecimation) + { + SbgBasicLoggerImu decimated; + + sbgBasicLoggerImuAccGet(&pHandler->fileAcc, &decimated); + + sbgBasicLoggerHandlerWriteImu(&decimated, pOutputFile); + } + } + else + { + SBG_LOG_ERROR(SBG_NULL_POINTER, "no file found for IMU short log"); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerImuAccAdd(&pHandler->consoleAcc, pNewData); + + if (pHandler->consoleAcc.nrAcc >= pHandler->commonHandler.consoleDecimation) + { + SbgBasicLoggerImu decimated; + + sbgBasicLoggerImuAccGet(&pHandler->consoleAcc, &decimated); + + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteImu(&decimated, stdout); + } + } +} + +//----------------------------------------------------------------------// +//- IMU cluster handler methods -// +//----------------------------------------------------------------------// + + +//----------------------------------------------------------------------// +//- Diagnostic handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerDiagHandlerConstruct(SbgBasicLoggerDiagHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, 0, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_DIAG); +} + +void sbgBasicLoggerDiagHandlerProcess(SbgBasicLoggerDiagHandler *pHandler, SbgLogUtcData *pLastUtcData, const SbgLogDiagData *pDiag) +{ + struct tm utcTime; + char utcTimeStr[128]; + uint32_t us; + + assert(pHandler); + assert(pDiag); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + + if (sbgBasicLoggerHandlerGetUtcTimeFromTimeStamp(pDiag->timestamp, pLastUtcData, &utcTime, &us) == SBG_NO_ERROR) + { + char dateStr[64]; + + strftime(dateStr, sizeof(dateStr), "%Y-%m-%dT%H:%M:%S", &utcTime); + snprintf(utcTimeStr, sizeof(utcTimeStr), "%s:%.3" PRIu32 "Z", dateStr, us / 1000); + } + else + { + snprintf(utcTimeStr, sizeof(utcTimeStr), "%10u", pDiag->timestamp); + } + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + sbgBasicLoggerHandlerWriteDiag(pDiag, utcTimeStr, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerHandlerWriteDiag(pDiag, utcTimeStr, stdout); + } +} + +//----------------------------------------------------------------------// +//- UTC handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerUtcHandlerConstruct(SbgBasicLoggerUtcHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_UTC_TIME); +} + +void sbgBasicLoggerUtcHandlerProcess(SbgBasicLoggerUtcHandler *pHandler, const SbgLogUtcData *pUtc) +{ + assert(pHandler); + assert(pUtc); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteUtcHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteUtc(pUtc, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteUtc(pUtc, stdout); + } +} + +//----------------------------------------------------------------------// +//- Status handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerStatusHandlerConstruct(SbgBasicLoggerStatusHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_STATUS); +} + +void sbgBasicLoggerStatusHandlerProcess(SbgBasicLoggerStatusHandler *pHandler, const SbgLogStatusData *pStatus) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pStatus); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteStatusHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteStatus(pStatus, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteStatus(pStatus, stdout); + } +} + +//----------------------------------------------------------------------// +//- EKF Euler handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerEkfEulerHandlerConstruct(SbgBasicLoggerEkfEulerHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_EKF_EULER); +} + +void sbgBasicLoggerEkfEulerHandlerProcess(SbgBasicLoggerEkfEulerHandler *pHandler, const SbgLogEkfEulerData *pEkfEuler) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pEkfEuler); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteEkfEulerHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteEkfEuler(pEkfEuler, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteEkfEuler(pEkfEuler, stdout); + } +} + +//----------------------------------------------------------------------// +//- EKF quat handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerEkfQuatHandlerConstruct(SbgBasicLoggerEkfQuatHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_EKF_QUAT); +} + +void sbgBasicLoggerEkfQuatHandlerProcess(SbgBasicLoggerEkfQuatHandler *pHandler, const SbgLogEkfQuatData *pEkfQuat) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pEkfQuat); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteEkfQuatHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteEkfQuat(pEkfQuat, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteEkfQuat(pEkfQuat, stdout); + } +} + +//----------------------------------------------------------------------// +//- EKF nav handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerEkfNavHandlerConstruct(SbgBasicLoggerEkfNavHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_EKF_NAV); +} + +void sbgBasicLoggerEkfNavHandlerProcess(SbgBasicLoggerEkfNavHandler *pHandler, const SbgLogEkfNavData *pEkfNav) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pEkfNav); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteEkfNavHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteEkfNav(pEkfNav, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteEkfNav(pEkfNav, stdout); + } +} + +//----------------------------------------------------------------------// +//- Ship motion methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerShipMotionHandlerConstruct(SbgBasicLoggerShipMotionHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_SHIP_MOTION); +} + +void sbgBasicLoggerShipMotionHandlerProcess(SbgBasicLoggerShipMotionHandler *pHandler, const SbgLogShipMotionData *pShipMotion) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pShipMotion); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteShipMotionHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteShipMotion(pShipMotion, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteShipMotion(pShipMotion, stdout); + } +} + +//----------------------------------------------------------------------// +//- Ship motion HP methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerShipMotionHpHandlerConstruct(SbgBasicLoggerShipMotionHpHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_SHIP_MOTION_HP); +} + +void sbgBasicLoggerShipMotionHpHandlerProcess(SbgBasicLoggerShipMotionHpHandler *pHandler, const SbgLogShipMotionData *pShipMotion) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pShipMotion); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteShipMotionHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteShipMotion(pShipMotion, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteShipMotion(pShipMotion, stdout); + } +} + +//----------------------------------------------------------------------// +//- GPS vel handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerGpsVel1HandlerConstruct(SbgBasicLoggerGpsVelHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_GPS1_VEL); +} + +void sbgBasicLoggerGpsVel2HandlerConstruct(SbgBasicLoggerGpsVelHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_GPS2_VEL); +} + +void sbgBasicLoggerGpsVelHandlerProcess(SbgBasicLoggerGpsVelHandler *pHandler, const SbgLogGpsVel *pGps) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pGps); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteGpsVelHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteGpsVel(pGps, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteGpsVel(pGps, stdout); + } +} + +//----------------------------------------------------------------------// +//- GPS pos handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerGpsPos1HandlerConstruct(SbgBasicLoggerGpsPosHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_GPS1_POS); +} + +void sbgBasicLoggerGpsPos2HandlerConstruct(SbgBasicLoggerGpsPosHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_GPS2_POS); +} + +void sbgBasicLoggerGpsPosHandlerProcess(SbgBasicLoggerGpsPosHandler *pHandler, const SbgLogGpsPos *pGps) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pGps); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteGpsHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteGps(pGps, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteGps(pGps, stdout); + } +} + +//----------------------------------------------------------------------// +//- GPS hdt handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerGpsHdt1HandlerConstruct(SbgBasicLoggerGpsHdtHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_GPS1_HDT); +} + +void sbgBasicLoggerGpsHdt2HandlerConstruct(SbgBasicLoggerGpsHdtHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_GPS2_HDT); +} + +void sbgBasicLoggerGpsHdtHandlerProcess(SbgBasicLoggerGpsHdtHandler *pHandler, const SbgLogGpsHdt *pGps) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pGps); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteGpsHdtHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteGpsHdt(pGps, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteGpsHdt(pGps, stdout); + } +} + +//----------------------------------------------------------------------// +//- Raw GPS handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerGps1RawHandlerConstruct(SbgBasicLoggerGpsRawHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, 0, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_GPS1_RAW); +} + +void sbgBasicLoggerGps2RawHandlerConstruct(SbgBasicLoggerGpsRawHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, 0, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_GPS2_RAW); +} + +void sbgBasicLoggerGpsRawHandlerProcess(SbgBasicLoggerGpsRawHandler *pHandler, const SbgLogRawData *pRawGps) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pRawGps); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + sbgBasicLoggerHandlerWriteGpsRaw(pRawGps, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteGpsRaw(pRawGps, stdout); + } +} + +//----------------------------------------------------------------------// +//- GNSS Satellite in View handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerGps1SatHandlerConstruct(SbgBasicLoggerGpsSatHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, 0, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_GPS1_SAT); +} + +void sbgBasicLoggerGps2SatHandlerConstruct(SbgBasicLoggerGpsSatHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, 0, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_GPS2_SAT); +} + +void sbgBasicLoggerGpsSatHandlerProcess(SbgBasicLoggerGpsSatHandler *pHandler, const SbgLogSatGroupData *pData) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pData); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteGpsSatHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteGpsSat(pData, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteGpsSat(pData, stdout); + } +} +//----------------------------------------------------------------------// +//- Odometer handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerOdometerHandlerConstruct(SbgBasicLoggerOdometerHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_ODO_VEL); +} + +void sbgBasicLoggerOdometerHandlerProcess(SbgBasicLoggerOdometerHandler *pHandler, const SbgLogOdometerData *pData) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pData); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteOdometerHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteOdometer(pData, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteOdometer(pData, stdout); + } +} + +//----------------------------------------------------------------------// +//- DVL handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerDvlBottomHandlerConstruct(SbgBasicLoggerDvlHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_DVL_BOTTOM_TRACK); +} + +void sbgBasicLoggerDvlWaterHandlerConstruct(SbgBasicLoggerDvlHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_DVL_WATER_TRACK); +} + +void sbgBasicLoggerDvlHandlerProcess(SbgBasicLoggerDvlHandler *pHandler, const SbgLogDvlData *pData) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pData); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteDvlHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteDvl(pData, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteDvl(pData, stdout); + } +} + +//----------------------------------------------------------------------// +//- Air handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerAirHandlerConstruct(SbgBasicLoggerAirHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_AIR_DATA); +} + +void sbgBasicLoggerAirHandlerProcess(SbgBasicLoggerAirHandler *pHandler, const SbgLogAirData *pData) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pData); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteAirHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteAir(pData, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteAir(pData, stdout); + } +} + +//----------------------------------------------------------------------// +//- USBL handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerUsblHandlerConstruct(SbgBasicLoggerUsblHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_USBL); +} + +void sbgBasicLoggerUsblHandlerProcess(SbgBasicLoggerUsblHandler *pHandler, const SbgLogUsblData *pData) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pData); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteUsblHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteUsbl(pData, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteUsbl(pData, stdout); + } +} + +//----------------------------------------------------------------------// +//- Depth handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerDepthHandlerConstruct(SbgBasicLoggerDepthHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_DEPTH); +} + +void sbgBasicLoggerDepthHandlerProcess(SbgBasicLoggerDepthHandler *pHandler, const SbgLogDepth *pData) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pData); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteDepthHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteDepth(pData, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerHandlerWriteDepth(pData, stdout); + } +} + +//----------------------------------------------------------------------// +//- Raw RTCM handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerRawRtcmHandlerConstruct(SbgBasicLoggerRawRtcmHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, 0, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_RTCM_RAW); +} + +void sbgBasicLoggerRawRtcmHandlerProcess(SbgBasicLoggerRawRtcmHandler *pHandler, const SbgLogRawData *pData) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pData); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + sbgBasicLoggerHandlerWriteRawRtcm(pData, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteRawRtcm(pData, stdout); + } +} + +//----------------------------------------------------------------------// +//- Events handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerEventInAHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_EVENT_A); +} + +void sbgBasicLoggerEventInBHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_EVENT_B); +} + +void sbgBasicLoggerEventInCHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_EVENT_C); +} + +void sbgBasicLoggerEventInDHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_EVENT_D); +} + +void sbgBasicLoggerEventInEHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_EVENT_E); +} + +void sbgBasicLoggerEventOutAHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_EVENT_OUT_A); +} + +void sbgBasicLoggerEventOutBHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_EVENT_OUT_B); +} + +void sbgBasicLoggerEventHandlerProcess(SbgBasicLoggerEventHandler *pHandler, const SbgLogEvent *pEvent) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pEvent); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteEventHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteEvent(pEvent, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteEvent(pEvent, stdout); + } +} + +//----------------------------------------------------------------------// +//- Mag handler methods -// +//----------------------------------------------------------------------// + +void sbgBasicLoggerMagHandlerConstruct(SbgBasicLoggerMagHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader) +{ + assert(pHandler); + assert(!sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + sbgBasicLoggerCommonHandlerConstruct(&pHandler->commonHandler, consoleEnabled, 0, writingFile, pPathStr, 0, writeHeader, SBG_ECOM_CLASS_LOG_ECOM_0, SBG_ECOM_LOG_MAG); +} + +void sbgBasicLoggerMagHandlerProcess(SbgBasicLoggerMagHandler *pHandler, const SbgLogMag *pMag) +{ + assert(pHandler); + assert(sbgBasicLoggerCommonHandlerInitialized(&pHandler->commonHandler)); + assert(pMag); + + if (sbgBasicLoggerCommonHandlerWritingFile(&pHandler->commonHandler)) + { + FILE *pOutputFile; + + pOutputFile = sbgBasicLoggerCommonHandlerGetPath(&pHandler->commonHandler); + + if (pOutputFile) + { + if (sbgBasicLoggerCommonHandlerHeaderWriting(&pHandler->commonHandler) && (!sbgBasicLoggerCommonHandlerHeaderWritten(&pHandler->commonHandler))) + { + sbgBasicLoggerHandlerWriteMagHeader(pHandler->commonHandler.pFILE); + pHandler->commonHandler.headerWritten = true; + } + + sbgBasicLoggerHandlerWriteMag(pMag, pOutputFile); + } + } + + if (sbgBasicLoggerCommonHandlerConsoleEnabled(&pHandler->commonHandler)) + { + sbgBasicLoggerCommonHandlerWriteLogInfo(&pHandler->commonHandler, stdout); + sbgBasicLoggerHandlerWriteMag(pMag, stdout); + } +} diff --git a/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerHandler.h b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerHandler.h new file mode 100644 index 0000000..6b93367 --- /dev/null +++ b/crates/sbg-rs/sbgECom/tools/sbgBasicLogger/src/sbgBasicLoggerHandler.h @@ -0,0 +1,823 @@ +/*! + * \file sbgBasicLoggerHandler.h + * \author SBG Systems + * \date July 30, 2021 + * + * \brief Helper to handle logs. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense Proprietary license + * + * This source code is intended for use only by SBG Systems SAS and + * those that have explicit written permission to use it from + * SBG Systems SAS. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + * PARTICULAR PURPOSE. + * + * \endlicense + */ + +#ifndef SBG_BASIC_LOGGER_HANDLER_H +#define SBG_BASIC_LOGGER_HANDLER_H + +// sbgCommonLib headers +#include + +// sbgECom headers +#include + +// Local headers +#include "sbgBasicLoggerAccumulators.h" +#include "sbgBasicLoggerFile.h" + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Common log handler. + */ +typedef struct _SbgBasicLoggerCommonHandler +{ + bool consoleEnabled; /*!< True to print data on the console. */ + size_t consoleDecimation; /*!< Console decimation. */ + size_t fileDecimation; /*!< File decimation. */ + bool writingFile; /*!< True to save data into a file. */ + bool writeHeader; /*!< True to write header. */ + bool headerWritten; /*!< True if headers have been written. */ + const SbgBasicLoggerFileDesc *pDesc; /*!< File descriptor. */ + FILE *pFILE; /*!< File. */ + + const char *pPathStr; /*!< String path directory. */ + SbgEComClass class; /*!< Handler class. */ + SbgEComMsgId id; /*!< Handler message ID. */ +} SbgBasicLoggerCommonHandler; + +/*! + * IMU short log handler. + */ +typedef struct _SbgBasicLoggerImuHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ + + SbgBasicLoggerImuAcc consoleAcc; /*!< Decimated IMU data for the console. */ + SbgBasicLoggerImuAcc fileAcc; /*!< Decimated IMU data for the file. */ +} SbgBasicLoggerImuHandler; + + +/*! + * Diag log handler. + */ +typedef struct _SbgBasicLoggerDiagHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerDiagHandler; + +/*! + * UTC log handler. + */ +typedef struct _SbgBasicLoggerUtcHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerUtcHandler; + +/*! + * Status log handler. + */ +typedef struct _SbgBasicLoggerStatusHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerStatusHandler; + +/*! + * EKF Euler log handler. + */ +typedef struct _SbgBasicLoggerEkfEulerHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerEkfEulerHandler; + +/*! + * EKF quat log handler. + */ +typedef struct _SbgBasicLoggerEkfQuatHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerEkfQuatHandler; + +/*! + * EKF nav log handler. + */ +typedef struct _SbgBasicLoggerEkfNavHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerEkfNavHandler; + +/*! + * Ship motion log handler. + */ +typedef struct _SbgBasicLoggerShipMotionHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerShipMotionHandler; + +/*! + * Ship motion HP log handler. + */ +typedef struct _SbgBasicLoggerShipMotionHpHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerShipMotionHpHandler; + +/*! + * GPS vel log handler. + */ +typedef struct _SbgBasicLoggerGpsVelHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerGpsVelHandler; + +/*! + * GPS pos log handler. + */ +typedef struct _SbgBasicLoggerGpsPosHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerGpsPosHandler; + +/*! + * GPS hdt log handler. + */ +typedef struct _SbgBasicLoggerGpsHdtHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerGpsHdtHandler; + +/*! + * GPS RAW log handler. + */ +typedef struct _SbgBasicLoggerGpsRawHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerGpsRawHandler; + +/*! + * GPS Satellite in View log handler. + */ +typedef struct _SbgBasicLoggerGpsSatHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerGpsSatHandler; + +/*! + * Odometer log handler. + */ +typedef struct _SbgBasicLoggerOdometerHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerOdometerHandler; + +/*! + * DVL log handler. + */ +typedef struct _SbgBasicLoggerDvlHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerDvlHandler; + +/*! + * Air log handler. + */ +typedef struct _SbgBasicLoggerAirHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerAirHandler; + +/*! + * USBL log handler. + */ +typedef struct _SbgBasicLoggerUsblHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerUsblHandler; + +/*! + * Depth log handler. + */ +typedef struct _SbgBasicLoggerDepthHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerDepthHandler; + +/*! + * RTCM log handler. + */ +typedef struct _SbgBasicLoggerRawRtcmHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerRawRtcmHandler; + +/*! + * Event log handler. + */ +typedef struct _SbgBasicLoggerEventHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerEventHandler; + +/*! + * Magnetometer log handler. + */ +typedef struct _SbgBasicLoggerMagHandler +{ + SbgBasicLoggerCommonHandler commonHandler; /*!< Common with all handler logs. */ +} SbgBasicLoggerMagHandler; + +//----------------------------------------------------------------------// +//- Public functions -// +//----------------------------------------------------------------------// + +/*! + * IMU short handler constructor. + * + * \param[in] pHandler IMU short handler. + * \param[in] consoleEnabled True to print IMU short data on console. + * \param[in] consoleDecimation Console decimation. + * \param[in] writingFile True to write IMU short data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] fileDecimation File decimation. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerImuShortHandlerConstruct(SbgBasicLoggerImuHandler *pHandler, bool consoleEnabled, size_t consoleDecimation, bool writingFile, const char *pPathStr, size_t fileDecimation, bool writeHeader); + +/*! + * IMU data handler constructor. + * + * \param[in] pHandler IMU data handler. + * \param[in] consoleEnabled True to print IMU short data on console. + * \param[in] consoleDecimation Console decimation. + * \param[in] writingFile True to write IMU short data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] fileDecimation File decimation. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerImuHandlerConstruct(SbgBasicLoggerImuHandler *pHandler, bool consoleEnabled, size_t consoleDecimation, bool writingFile, const char *pPathStr, size_t fileDecimation, bool writeHeader); + +/*! + * IMU fast handler constructor. + * + * \param[in] pHandler IMU fast data handler. + * \param[in] consoleEnabled True to print IMU short data on console. + * \param[in] consoleDecimation Console decimation. + * \param[in] writingFile True to write IMU short data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] fileDecimation File decimation. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerImuFastHandlerConstruct(SbgBasicLoggerImuHandler *pHandler, bool consoleEnabled, size_t consoleDecimation, bool writingFile, const char *pPathStr, size_t fileDecimation, bool writeHeader); + +/*! + * Process an IMU short handler with a new data. + * + * \param[in] pHandler IMU short handler. + * \param[in] pNewData New IMU short data. + */ +void sbgBasicLoggerImuHandlerProcess(SbgBasicLoggerImuHandler *pHandler, const SbgBasicLoggerImu *pNewData); + + +/*! + * Diagnostic handler constructor. + * + * \param[in] pHandler Diag handler. + * \param[in] consoleEnabled True to print diag data on console. + * \param[in] writingFile True to write diag data into a file. + * \param[in] pPathStr Path to write file logs. + */ +void sbgBasicLoggerDiagHandlerConstruct(SbgBasicLoggerDiagHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr); + +/*! + * Process a diagnostic data. + * + * \param[in] pHandler Diag log handler. + * \param[in] pLastUtcData Last UTC data, used of timestamp. + * \param[in] pDiag Diagnostic data. + */ +void sbgBasicLoggerDiagHandlerProcess(SbgBasicLoggerDiagHandler *pHandler, SbgLogUtcData *pLastUtcData, const SbgLogDiagData *pDiag); + +/*! + * UTC handler constructor. + * + * \param[in] pHandler UTC handler. + * \param[in] consoleEnabled True to print UTC data on console. + * \param[in] writingFile True to write UTC data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerUtcHandlerConstruct(SbgBasicLoggerUtcHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process an UTC data. + * + * \param[in] pHandler UTC log handler. + * \param[in] pLastUtcData Last UTC data, used of timestamp. + * \param[in] pDiag Diagnostic data. + */ +void sbgBasicLoggerUtcHandlerProcess(SbgBasicLoggerUtcHandler *pHandler, const SbgLogUtcData *pUtc); + +/*! + * Status handler constructor. + * + * \param[in] pHandler Status handler. + * \param[in] consoleEnabled True to print status data on console. + * \param[in] writingFile True to write status data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerStatusHandlerConstruct(SbgBasicLoggerStatusHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a status data. + * + * \param[in] pHandler Status log handler. + * \param[in] pDiag Status data. + */ +void sbgBasicLoggerStatusHandlerProcess(SbgBasicLoggerStatusHandler *pHandler, const SbgLogStatusData *pStatus); + +/*! + * EKF Euler handler constructor. + * + * \param[in] pHandler EKF Euler handler. + * \param[in] consoleEnabled True to print EKF Euler data on console. + * \param[in] writingFile True to write EKF Euler data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerEkfEulerHandlerConstruct(SbgBasicLoggerEkfEulerHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a EKF Euler data. + * + * \param[in] pHandler EKF Euler handler. + * \param[in] pEkfEuler EKF Euler data. + */ +void sbgBasicLoggerEkfEulerHandlerProcess(SbgBasicLoggerEkfEulerHandler *pHandler, const SbgLogEkfEulerData *pEkfEuler); + +/*! + * EKF quat handler constructor. + * + * \param[in] pHandler EKF quat handler. + * \param[in] consoleEnabled True to print EKF quat data on console. + * \param[in] writingFile True to write EKF quat data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerEkfQuatHandlerConstruct(SbgBasicLoggerEkfQuatHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a EKF quat data. + * + * \param[in] pHandler EKF quat handler. + * \param[in] pEkfQuat EKF quat data. + */ +void sbgBasicLoggerEkfQuatHandlerProcess(SbgBasicLoggerEkfQuatHandler *pHandler, const SbgLogEkfQuatData *pEkfEuler); + +/*! + * EKF nav handler constructor. + * + * \param[in] pHandler EKF nav handler. + * \param[in] consoleEnabled True to print EKF nav data on console. + * \param[in] writingFile True to write EKF nav data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerEkfNavHandlerConstruct(SbgBasicLoggerEkfNavHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a EKF nav data. + * + * \param[in] pHandler EKF nav handler. + * \param[in] pEkfEuler EKF nav data. + */ +void sbgBasicLoggerEkfNavHandlerProcess(SbgBasicLoggerEkfNavHandler *pHandler, const SbgLogEkfNavData *pEkfEuler); + +/*! + * Ship motion handler constructor. + * + * \param[in] pHandler Ship motion handler. + * \param[in] consoleEnabled True to print ship motion data on console. + * \param[in] writingFile True to write ship motion data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerShipMotionHandlerConstruct(SbgBasicLoggerShipMotionHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a ship motion data. + * + * \param[in] pHandler SHip motion handler. + * \param[in] pShipMotion Ship motion data. + */ +void sbgBasicLoggerShipMotionHandlerProcess(SbgBasicLoggerShipMotionHandler *pHandler, const SbgLogShipMotionData *pShipMotion); + +/*! + * Ship motion HP handler constructor. + * + * \param[in] pHandler Ship motion HP handler. + * \param[in] consoleEnabled True to print ship motion HP data on console. + * \param[in] writingFile True to write ship motion HP data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerShipMotionHpHandlerConstruct(SbgBasicLoggerShipMotionHpHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a ship motion HP data. + * + * \param[in] pHandler Ship motion HP handler. + * \param[in] pShipMotion Ship motion HP data. + */ +void sbgBasicLoggerShipMotionHpHandlerProcess(SbgBasicLoggerShipMotionHpHandler *pHandler, const SbgLogShipMotionData *pShipMotion); + +/*! + * GPS 1 vel handler constructor. + * + * \param[in] pHandler GPS vel handler. + * \param[in] consoleEnabled True to print GPS vel data on console. + * \param[in] writingFile True to write GPS vel data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerGpsVel1HandlerConstruct(SbgBasicLoggerGpsVelHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * GPS 2 vel handler constructor. + * + * \param[in] pHandler GPS vel handler. + * \param[in] consoleEnabled True to print GPS vel data on console. + * \param[in] writingFile True to write GPS vel data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerGpsVel2HandlerConstruct(SbgBasicLoggerGpsVelHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a GPS vel data. + * + * \param[in] pHandler GPS vel handler. + * \param[in] pGps GPS vel data. + */ +void sbgBasicLoggerGpsVelHandlerProcess(SbgBasicLoggerGpsVelHandler *pHandler, const SbgLogGpsVel *pGps); + +/*! + * GPS handler constructor. + * + * \param[in] pHandler GPS handler. + * \param[in] consoleEnabled True to print GPS data on console. + * \param[in] writingFile True to write GPS data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerGpsPos1HandlerConstruct(SbgBasicLoggerGpsPosHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * GPS 2 handler constructor. + * + * \param[in] pHandler GPS handler. + * \param[in] consoleEnabled True to print GPS data on console. + * \param[in] writingFile True to write GPS data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerGpsPos2HandlerConstruct(SbgBasicLoggerGpsPosHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a GPS data. + * + * \param[in] pHandler GPS handler. + * \param[in] pGps GPS data. + */ +void sbgBasicLoggerGpsPosHandlerProcess(SbgBasicLoggerGpsPosHandler *pHandler, const SbgLogGpsPos *pGps); + +/*! + * GPS 1 hdt handler constructor. + * + * \param[in] pHandler GPS hdt handler. + * \param[in] consoleEnabled True to print GPS vel data on console. + * \param[in] writingFile True to write GPS vel data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerGpsHdt1HandlerConstruct(SbgBasicLoggerGpsHdtHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * GPS 2 hdt handler constructor. + * + * \param[in] pHandler GPS vel handler. + * \param[in] consoleEnabled True to print GPS hdt data on console. + * \param[in] writingFile True to write GPS hdt data into a file. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerGpsHdt2HandlerConstruct(SbgBasicLoggerGpsHdtHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a GPS hdt data. + * + * \param[in] pHandler GPS vel handler. + * \param[in] pGps GPS vel data. + */ +void sbgBasicLoggerGpsHdtHandlerProcess(SbgBasicLoggerGpsHdtHandler *pHandler, const SbgLogGpsHdt *pGps); + +/*! + * GPS raw handler constructor. + * + * \param[in] pHandler GPS raw handler. + * \param[in] consoleEnabled True to print GPS data on console. + * \param[in] writingFile True to write GPS data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerGps1RawHandlerConstruct(SbgBasicLoggerGpsRawHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr); + +/*! + * GPS raw handler constructor. + * + * \param[in] pHandler GPS raw handler. + * \param[in] consoleEnabled True to print GPS data on console. + * \param[in] writingFile True to write GPS data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerGps2RawHandlerConstruct(SbgBasicLoggerGpsRawHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr); + +/*! + * Process a GPS raw data. + * + * \param[in] pHandler GPS raw handler. + * \param[in] pGps GPS raw data. + */ +void sbgBasicLoggerGpsRawHandlerProcess(SbgBasicLoggerGpsRawHandler *pHandler, const SbgLogRawData *pRawGps); + +/*! + * GPS 1 Satellite in View handler constructor. + * + * \param[in] pHandler GPS Sat handler. + * \param[in] consoleEnabled True to print GPS data on console. + * \param[in] writingFile True to write GPS data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerGps1SatHandlerConstruct(SbgBasicLoggerGpsSatHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr); + +/*! + * GPS 2 Satellite in View handler constructor. + * + * \param[in] pHandler GPS Sat handler. + * \param[in] consoleEnabled True to print GPS data on console. + * \param[in] writingFile True to write GPS data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerGps2SatHandlerConstruct(SbgBasicLoggerGpsSatHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr); + +/*! + * Process a GPS Satellite in View data. + * + * \param[in] pHandler GPS Sat handler. + * \param[in] pData GPS Sat data. + */ +void sbgBasicLoggerGpsSatHandlerProcess(SbgBasicLoggerGpsSatHandler *pHandler, const SbgLogSatGroupData *pData); + +/*! + * Odometer handler constructor. + * + * \param[in] pHandler Odometer handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerOdometerHandlerConstruct(SbgBasicLoggerOdometerHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process an odometer data. + * + * \param[in] pHandler Odometer handler. + * \param[in] pData Odometer data. + */ +void sbgBasicLoggerOdometerHandlerProcess(SbgBasicLoggerOdometerHandler *pHandler, const SbgLogOdometerData *pData); + +/*! + * DVL bottom handler constructor. + * + * \param[in] pHandler DVL bottom handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerDvlBottomHandlerConstruct(SbgBasicLoggerDvlHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * DVL water handler constructor. + * + * \param[in] pHandler DVL water handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerDvlWaterHandlerConstruct(SbgBasicLoggerDvlHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a DVL data. + * + * \param[in] pHandler DVL handler. + * \param[in] pData DVL data. + */ +void sbgBasicLoggerDvlHandlerProcess(SbgBasicLoggerDvlHandler *pHandler, const SbgLogDvlData *pData); + +/*! + * Air handler constructor. + * + * \param[in] pHandler Air handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerAirHandlerConstruct(SbgBasicLoggerAirHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process an air data. + * + * \param[in] pHandler Air handler. + * \param[in] pData Air data. + */ +void sbgBasicLoggerAirHandlerProcess(SbgBasicLoggerAirHandler *pHandler, const SbgLogAirData *pData); + +/*! + * USBL handler constructor. + * + * \param[in] pHandler USBL handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerUsblHandlerConstruct(SbgBasicLoggerUsblHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a USBL data. + * + * \param[in] pHandler USBL handler. + * \param[in] pData USBL data. + */ +void sbgBasicLoggerUsblHandlerProcess(SbgBasicLoggerUsblHandler *pHandler, const SbgLogUsblData *pData); + +/*! + * Depth handler constructor. + * + * \param[in] pHandler Depth handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerDepthHandlerConstruct(SbgBasicLoggerDepthHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a depth data. + * + * \param[in] pHandler Depth handler. + * \param[in] pData Depth data. + */ +void sbgBasicLoggerDepthHandlerProcess(SbgBasicLoggerDepthHandler *pHandler, const SbgLogDepth *pData); + +/*! + * Raw RTCM handler constructor. + * + * \param[in] pHandler Raw RTCM handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerRawRtcmHandlerConstruct(SbgBasicLoggerRawRtcmHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr); + +/*! + * Process a raw RTCM data. + * + * \param[in] pHandler Raw RTCM handler. + * \param[in] pData Raw RTCM data. + */ +void sbgBasicLoggerRawRtcmHandlerProcess(SbgBasicLoggerRawRtcmHandler *pHandler, const SbgLogRawData *pData); + + +/*! + * Event in A handler constructor. + * + * \param[in] pHandler Event handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerEventInAHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Event in B handler constructor. + * + * \param[in] pHandler Event handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerEventInBHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Event in C handler constructor. + * + * \param[in] pHandler Event handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerEventInCHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Event in D handler constructor. + * + * \param[in] pHandler Event handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerEventInDHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Event in E handler constructor. + * + * \param[in] pHandler Event handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerEventInEHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Event out A handler constructor. + * + * \param[in] pHandler Event handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerEventOutAHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Event out B handler constructor. + * + * \param[in] pHandler Event handler. + * \param[in] consoleEnabled True to print data on console. + * \param[in] writingFile True to write data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerEventOutBHandlerConstruct(SbgBasicLoggerEventHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process an event data. + * + * \param[in] pHandler Event handler. + * \param[in] pEvent Event data. + */ +void sbgBasicLoggerEventHandlerProcess(SbgBasicLoggerEventHandler *pHandler, const SbgLogEvent *pEvent); + +/*! + * Mag handler constructor. + * + * \param[in] pHandler Mag handler. + * \param[in] consoleEnabled True to print mag data on console. + * \param[in] writingFile True to write mag data into a file. + * \param[in] pPathStr Path to write file logs. + * \param[in] writeHeader True to print and write header. + */ +void sbgBasicLoggerMagHandlerConstruct(SbgBasicLoggerMagHandler *pHandler, bool consoleEnabled, bool writingFile, const char *pPathStr, bool writeHeader); + +/*! + * Process a mag data. + * + * \param[in] pHandler Mag handler. + * \param[in] pMag Mag data. + */ +void sbgBasicLoggerMagHandlerProcess(SbgBasicLoggerMagHandler *pHandler, const SbgLogMag *pMag); + +#endif // SBG_BASIC_LOGGER_HANDLER_H diff --git a/crates/sbg-rs/sbgECom/tools/sbgEComApi/README.md b/crates/sbg-rs/sbgECom/tools/sbgEComApi/README.md new file mode 100644 index 0000000..cccc961 --- /dev/null +++ b/crates/sbg-rs/sbgECom/tools/sbgEComApi/README.md @@ -0,0 +1,80 @@ +# sbgEComApi + +The sbgEComApi command line tool let you read/update your product configuration through the JSON REST API. +A typical REST API works using GET / POST requests other HTTP protocols. + +The sbgEComApi tool encapsulate GET/POST requests so it can be used over a serial interface. +This tool is perfect to create complex and automated configuration scripts with no code. + +# Usage + +The sbgEComApi implements a simple to use command line interface (CLI) with two main operations. + +## Read Configuration (GET) + +You can read the whole product configuration or a specific configuration node. +The following example, reads the Port A configuration. +It uses the COM5 at 921600 bps to communicate with the device: + +```sh +sbgEComApi.exe -s COM5 -r 921600 /api/v1/settings/ports/comA -g +``` + +You should get the following response: +```js +{"mode":"rs232", "parity":"none", "baudrate":921600} +``` + +## Update Configuration (POST) + +You can update the whole product configuration at once or each setting one by one. +In the following example, we just update the Port A baudrate to 230400 bps. +The tool uses the computer COM5 at 921600 bps to communicate with the device: + +```sh +sbgEComApi.exe -s COM5 -r 921600 /api/v1/settings/ports/comA/baudrate -p -b 230400 +``` + +You should get the following response: +```js +{"title":"request successful","needReboot":false} +``` + +# Options +You can access the tool help using the --help argument. + +``` +Usage: sbgEComApi [-gpS] [--help] [--version] -s SERIAL_DEVICE -r SERIAL_BAUDRATE [-q QUERY] [-b BODY] [-B BODY_FILE] [-o OUTPUT_FILE] PATH +Access a RESTful SBG ECom server. + + --help display this help and exit + --version display version info and exit + -s, --serial-device=SERIAL_DEVICE open a serial interface + -r, --serial-baudrate=SERIAL_BAUDRATE serial baudrate + -g, --method-get use the GET method (default) + -p, --method-post use the POST method + -q, --query=QUERY query string + -b, --body=BODY body (POST method only) + -B, --body-file=BODY_FILE file containing the body (POST method only) + -S, --print-status print the status code on the output stream + -o, --output-file=OUTPUT_FILE output file + PATH path + +BODY or BODY_FILE may only be provided when using the POST method. + +If provided, BODY_FILE may not contain binary data. + +PATH is a URI path component. + +Exit codes : + 0: 200 OK + 60: 400 BAD REQUEST + 61: 401 UNAUTHORIZED + 63: 403 FORBIDDEN + 64: 404 NOT FOUND + 69: 409 CONFLICT + 82: 422 UNPROCESSABLE ENTITY + 100: 200 INTERNAL SERVER ERROR +If an error occurs and is unrelated to the status code, or if the status code is unknown, +return EXIT_FAILURE (1). +``` \ No newline at end of file diff --git a/crates/sbg-rs/sbgECom/tools/sbgEComApi/src/main.c b/crates/sbg-rs/sbgECom/tools/sbgEComApi/src/main.c new file mode 100644 index 0000000..d6ff9d6 --- /dev/null +++ b/crates/sbg-rs/sbgECom/tools/sbgEComApi/src/main.c @@ -0,0 +1,716 @@ +/*! + * \file main.c + * \author SBG Systems + * \date October 27, 2020 + * + * \brief Tool to perform REST GET/POST queries through sbgECom commands. + * + * \copyright Copyright (C) 2022, SBG Systems SAS. All rights reserved. + * \beginlicense Proprietary license + * + * This source code is intended for use only by SBG Systems SAS and + * those that have explicit written permission to use it from + * SBG Systems SAS. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + * PARTICULAR PURPOSE. + * + * \endlicense + */ + +// sbgCommonLib headers +#include +#include +#include +#include + +// sbgECom headers +#include +#include +#include + +// Argtable3 headers +#include + +//----------------------------------------------------------------------// +//- Constant definitions -// +//----------------------------------------------------------------------// + +/*! + * Program name. + */ +#define PROGRAM_NAME "sbgEComApi" + +/*! + * Default number of attempts per command execution. + */ +#define DEFAULT_CMD_NR_ATTEMPTS (3) + +/*! + * Default time-out per command execution attempt, in seconds. + */ +#define DEFAULT_CMD_TIMEOUT (5) + +//----------------------------------------------------------------------// +//- Structure definitions -// +//----------------------------------------------------------------------// + +/*! + * Exit code descriptor. + */ +typedef struct _ExitCodeDesc +{ + int exitCode; /*!< Exit code, on 7 bits. */ + uint16_t statusCode; /*!< Status code. */ + const char *pMessage; /*!< Message. */ +} ExitCodeDesc; + +//----------------------------------------------------------------------// +//- Private variables -// +//----------------------------------------------------------------------// + +/*! + * Table of exit code descriptors. + */ +static const ExitCodeDesc gExitCodeDescs[] = +{ + { .exitCode = 0, .statusCode = 200, .pMessage = "OK" }, + { .exitCode = 60, .statusCode = 400, .pMessage = "BAD REQUEST" }, + { .exitCode = 61, .statusCode = 401, .pMessage = "UNAUTHORIZED" }, + { .exitCode = 63, .statusCode = 403, .pMessage = "FORBIDDEN" }, + { .exitCode = 64, .statusCode = 404, .pMessage = "NOT FOUND" }, + { .exitCode = 69, .statusCode = 409, .pMessage = "CONFLICT" }, + { .exitCode = 82, .statusCode = 422, .pMessage = "UNPROCESSABLE ENTITY" }, + { .exitCode = 100, .statusCode = 200, .pMessage = "INTERNAL SERVER ERROR" }, +}; + +//----------------------------------------------------------------------// +//- Private functions -// +//----------------------------------------------------------------------// + +/*! + * Look up the exit code descriptor matching the given status code. + * + * \param[in] statusCode Status code. + * \return Exit code descriptor. + */ +static const ExitCodeDesc *lookupExitCodeDesc(uint16_t statusCode) +{ + const ExitCodeDesc *pDesc = NULL; + + for (size_t i = 0; i < SBG_ARRAY_SIZE(gExitCodeDescs); i++) + { + const ExitCodeDesc *pTmpDesc; + + pTmpDesc = &gExitCodeDescs[i]; + + if (pTmpDesc->statusCode == statusCode) + { + pDesc = pTmpDesc; + break; + } + } + + return pDesc; +} + +/*! + * Convert a status code into an exit code. + * + * \param[in] statusCode Status code. + * \return Exit code. + */ +static int convertStatusCodeToExitCode(uint16_t statusCode) +{ + const ExitCodeDesc *pDesc; + int exitCode; + + pDesc = lookupExitCodeDesc(statusCode); + + if (pDesc) + { + exitCode = pDesc->exitCode; + } + else + { + exitCode = EXIT_FAILURE; + } + + return exitCode; +} + +/*! + * Print help about a single exit code / status code mapping. + * + * \param[in] pDesc Exit code descriptor. + */ +static void print_exit_code_mapping(const ExitCodeDesc *pDesc) +{ + printf(" %3u: %3u %s\n", pDesc->exitCode, pDesc->statusCode, pDesc->pMessage); +} + +/*! + * Print help about exit codes. + */ +static void print_exit_code_help(void) +{ + printf("Exit codes :\n"); + + for (size_t i = 0; i < SBG_ARRAY_SIZE(gExitCodeDescs); i++) + { + print_exit_code_mapping(&gExitCodeDescs[i]); + } + + printf("If an error occurs and is unrelated to the status code, or if the status code is unknown,\n"); + printf("return EXIT_FAILURE.\n"); +} + +/*! + * Callback definition used to route log error messages. + * + * \param[in] pFileName The file in which the log was triggered. + * \param[in] pFunctionName The function where the log was triggered. + * \param[in] line The line in the file where the log was triggered. + * \param[in] pCategory Category for this log or "None" if no category has been specified. + * \param[in] logType Associated log message level. + * \param[in] errorCode Associated error code or SBG_NO_ERROR for INFO & DEBUG level logs. + * \param[in] pMessage The message to log. + */ +static void onLogCallback(const char *pFileName, const char *pFunctionName, uint32_t line, const char *pCategory, SbgDebugLogType type, SbgErrorCode errorCode, const char *pMessage) +{ + const char *pTypeStr; + const char *pBaseName; + + assert(pFileName); + assert(pFunctionName); + assert(pCategory); + assert(pMessage); + + pTypeStr = sbgDebugLogTypeToStr(type); + pBaseName = strrchr(pFileName, '/'); + + if (!pBaseName) + { + pBaseName = pFileName; + } + else + { + // + // Skip the slash. + // + pBaseName++; + } + + if (errorCode == SBG_NO_ERROR) + { + fprintf(stderr, "%-7s %s (%s:%" PRIu32 ") %s\n", pTypeStr, pFunctionName, pBaseName, line, pMessage); + } + else + { + fprintf(stderr, "%-7s err:%s %s (%s:%" PRIu32 ") %s\n", pTypeStr, sbgErrorCodeToString(errorCode), pFunctionName, pBaseName, line, pMessage); + } +} + +/*! + * Read a string from a file. + * + * \param[out] pString String. + * \param[in] pPath File path. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode readStringFromFile(SbgString *pString, const char *pPath) +{ + SbgErrorCode errorCode; + FILE *pFile; + + assert(pString); + assert(pPath); + + pFile = fopen(pPath, "r"); + + if (pFile) + { + for (;;) + { + size_t size; + char buffer[4096]; + + size = fread(buffer, 1, sizeof(buffer) - 1, pFile); + + if (size != 0) + { + assert(size < sizeof(buffer)); + buffer[size] = '\0'; + + errorCode = sbgStringAppendCString(pString, buffer); + + if (errorCode == SBG_NO_ERROR) + { + char *pPtr; + + pPtr = memchr(buffer, '\0', size); + + if (pPtr) + { + break; + } + } + else + { + break; + } + } + else + { + if (ferror(pFile)) + { + errorCode = SBG_READ_ERROR; + SBG_LOG_ERROR(errorCode, "unable to read file %s", pPath); + } + else + { + errorCode = SBG_NO_ERROR; + } + + break; + } + } + + fclose(pFile); + } + else + { + errorCode = SBG_INVALID_PARAMETER; + SBG_LOG_ERROR(errorCode, "unable to open file %s", pPath); + } + + return errorCode; +} + +/*! + * Write a reply to an output file. + * + * \param[in] pReply Reply. + * \param[in] writeStatus If true, print the status to the output file. + * \param[out] pOutputFile Output file. + */ +static SbgErrorCode writeReply(const SbgEComCmdApiReply *pReply, bool writeStatus, FILE *pOutputFile) +{ + SbgErrorCode errorCode; + + if (writeStatus) + { + int nrChars; + + nrChars = fprintf(pOutputFile, "%"PRIu16"\n", pReply->statusCode); + + if (nrChars >= 0) + { + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_WRITE_ERROR; + SBG_LOG_ERROR(errorCode, "unable to write status code"); + } + } + else + { + errorCode = SBG_NO_ERROR; + } + + if (errorCode == SBG_NO_ERROR) + { + int nrChars; + + nrChars = fprintf(pOutputFile, "%s", pReply->pContent); + + if (nrChars >= 0) + { + errorCode = SBG_NO_ERROR; + } + else + { + errorCode = SBG_WRITE_ERROR; + SBG_LOG_ERROR(errorCode, "unable to write content"); + } + } + + return errorCode; +} + +/*! + * Execute a GET or POST ECom command. + * + * \param[in] pInterface Interface. + * \param[in] methodIsGet The GET command is executed if true, the POST command otherwise. + * \param[in] pPath URI path component. + * \param[in] nrAttempts Number of attempts. + * \param[in] timeout Time-out per attempt, in seconds. + * \param[in] pQuery Query string, may be NULL. + * \param[in] pBody Body, may be NULL. + * \param[in] writeStatus If true, print the status to the output file. + * \param[out] pStatusCode Status code. + * \param[in] pOutputFile Output file. + * \return SBG_NO_ERROR if successful. + */ +static SbgErrorCode execute(SbgInterface *pInterface, bool methodIsGet, const char *pPath, uint32_t nrAttempts, uint32_t timeout, + const char *pQuery, const char *pBody, bool writeStatus, uint16_t *pStatusCode, FILE *pOutputFile) +{ + SbgErrorCode errorCode; + SbgEComHandle ecomHandle; + + assert(pPath); + assert(pOutputFile); + + errorCode = sbgEComInit(&ecomHandle, pInterface); + + if (errorCode == SBG_NO_ERROR) + { + SbgEComCmdApiReply reply; + + sbgEComSetCmdTrialsAndTimeOut(&ecomHandle, nrAttempts, timeout * 1000); + + sbgEComCmdApiReplyConstruct(&reply); + + if (methodIsGet) + { + errorCode = sbgEComCmdApiGet(&ecomHandle, pPath, pQuery, &reply); + } + else + { + errorCode = sbgEComCmdApiPost(&ecomHandle, pPath, pQuery, pBody, &reply); + } + + if (errorCode == SBG_NO_ERROR) + { + errorCode = writeReply(&reply, writeStatus, pOutputFile); + + if (errorCode == SBG_NO_ERROR) + { + *pStatusCode = reply.statusCode; + } + } + else + { + SBG_LOG_ERROR(errorCode, "unable to execute command"); + } + + sbgEComCmdApiReplyDestroy(&reply); + + if (errorCode == SBG_NO_ERROR) + { + errorCode = sbgEComClose(&ecomHandle); + } + else + { + sbgEComClose(&ecomHandle); + } + } + + return errorCode; +} + +//----------------------------------------------------------------------// +// Public functions // +//----------------------------------------------------------------------// + +/*! + * Program entry point. + * + * \param[in] argc Number of input arguments. + * \param[in] argv Input arguments as an array of strings. + * \return EXIT_SUCCESS if successful. + */ +int main(int argc, char **argv) +{ + int exitCode = EXIT_SUCCESS; + bool printHelp = false; + + struct arg_lit *pHelpArg; + struct arg_lit *pVersionArg; + struct arg_str *pSerialDeviceArg; + struct arg_int *pSerialBaudrateArg; + struct arg_int *pNrAttemptsArg; + struct arg_int *pTimeoutArg; + struct arg_lit *pGetMethodArg; + struct arg_lit *pPostMethodArg; + struct arg_str *pPathArg; + struct arg_str *pQueryArg; + struct arg_str *pBodyArg; + struct arg_file *pBodyFileArg; + struct arg_lit *pPrintStatus; + struct arg_file *pOutputFileArg; + struct arg_end *pEndArg; + + // + // TODO: add support for network interfaces. + // + void *argTable[] = + { + pHelpArg = arg_lit0( NULL, "help", "display this help and exit"), + pVersionArg = arg_lit0( NULL, "version", "display version info and exit"), + pSerialDeviceArg = arg_str1( "s", "serial-device", "SERIAL_DEVICE", "open a serial interface"), + pSerialBaudrateArg = arg_int1( "r", "serial-baudrate", "SERIAL_BAUDRATE", "serial baudrate"), + pNrAttemptsArg = arg_int0( "n", "nr-attempts", "NR_ATTEMPTS", "number of transaction attempts"), + pTimeoutArg = arg_int0( "t", "timeout", "TIMEOUT", "reply time-out, in seconds"), + pGetMethodArg = arg_lit0( "g", "method-get", "use the GET method (default)"), + pPostMethodArg = arg_lit0( "p", "method-post", "use the POST method"), + pQueryArg = arg_str0( "q", "query", "QUERY", "query string, format=pretty&delta=true, format and delta options are optionnal"), + pBodyArg = arg_str0( "b", "body", "BODY", "body (POST method only)"), + pBodyFileArg = arg_file0( "B", "body-file", "BODY_FILE", "file containing the body (POST method only)"), + pPrintStatus = arg_lit0( "S", "print-status", "print the status code on the output stream"), + pOutputFileArg = arg_file0( "o", "output-file", "OUTPUT_FILE", "output file"), + pPathArg = arg_str1( NULL, NULL, "PATH", "path"), + + pEndArg = arg_end(20), + }; + + sbgCommonLibSetLogCallback(onLogCallback); + + if (arg_nullcheck(argTable) == 0) + { + int argError; + + argError = arg_parse(argc, argv, argTable); + + if (pHelpArg->count != 0) + { + printf("Usage: %s", PROGRAM_NAME); + arg_print_syntax(stdout, argTable, "\n"); + printf("Access a RESTful SBG ECom server.\n\n"); + arg_print_glossary(stdout, argTable, " %-25s %s\n"); + + puts(""); + printf("BODY or BODY_FILE may only be provided when using the POST method.\n"); + + puts(""); + printf("If provided, BODY_FILE may not contain binary data.\n"); + + puts(""); + printf("PATH is a URI path component.\n"); + + puts(""); + print_exit_code_help(); + } + else if (pVersionArg->count != 0) + { + printf("%s\n", sbgEComGetVersionAsString()); + } + else if (argError == 0) + { + SbgInterface ecomInterface; + bool methodIsGet = true; + int nrAttempts = DEFAULT_CMD_NR_ATTEMPTS; + int timeout = DEFAULT_CMD_TIMEOUT; + bool writeStatus = false; + SbgString bodyStorage; + SbgString *pBody = NULL; + const char *pQuery = NULL; + const char *pPath = NULL; + + if (exitCode == EXIT_SUCCESS) + { + sbgStringConstructEmpty(&bodyStorage); + pBody = &bodyStorage; + } + + if (exitCode == EXIT_SUCCESS) + { + if ((pSerialDeviceArg->count != 0) && (pSerialBaudrateArg->count != 0)) + { + SbgErrorCode errorCode; + + errorCode = sbgInterfaceSerialCreate(&ecomInterface, pSerialDeviceArg->sval[0], pSerialBaudrateArg->ival[0]); + + if (errorCode == SBG_NO_ERROR) + { + FILE *pOutputFile = NULL; + + if ((pGetMethodArg->count != 0) && (pPostMethodArg->count == 0)) + { + methodIsGet = true; + } + else if ((pGetMethodArg->count == 0) && (pPostMethodArg->count != 0)) + { + methodIsGet = false; + } + else if ((pGetMethodArg->count != 0) && (pPostMethodArg->count != 0)) + { + exitCode = EXIT_FAILURE; + printHelp = true; + } + + if (exitCode == EXIT_SUCCESS) + { + if (pNrAttemptsArg->count != 0) + { + nrAttempts = pNrAttemptsArg->ival[0]; + + if (nrAttempts <= 0) + { + exitCode = EXIT_FAILURE; + printHelp = true; + } + } + + if (pTimeoutArg->count != 0) + { + timeout = pTimeoutArg->ival[0]; + + if (timeout <= 0) + { + exitCode = EXIT_FAILURE; + printHelp = true; + } + } + + if (pQueryArg->count != 0) + { + pQuery = pQueryArg->sval[0]; + } + } + + if (exitCode == EXIT_SUCCESS) + { + if (!methodIsGet && (pBodyArg->count != 0) && (pBodyFileArg->count == 0)) + { + errorCode = sbgStringAssignCString(pBody, pBodyArg->sval[0]); + + if (errorCode != SBG_NO_ERROR) + { + exitCode = EXIT_FAILURE; + } + } + else if (!methodIsGet && (pBodyArg->count == 0) && (pBodyFileArg->count != 0)) + { + errorCode = readStringFromFile(&bodyStorage, pBodyFileArg->filename[0]); + + if (errorCode != SBG_NO_ERROR) + { + exitCode = EXIT_FAILURE; + } + } + else if ((pBodyArg->count != 0) && (pBodyFileArg->count != 0)) + { + exitCode = EXIT_FAILURE; + printHelp = true; + } + } + + if (exitCode == EXIT_SUCCESS) + { + if (pPrintStatus->count != 0) + { + writeStatus = true; + } + } + + if (exitCode == EXIT_SUCCESS) + { + if (pOutputFileArg->count == 0) + { + pOutputFile = stdout; + } + else + { + pOutputFile = fopen(pOutputFileArg->filename[0], "w"); + + if (!pOutputFile) + { + SBG_LOG_ERROR(SBG_ERROR, "unable to open %s", pOutputFileArg->filename[0]); + exitCode = EXIT_FAILURE; + } + } + } + + if (exitCode == EXIT_SUCCESS) + { + assert(pPathArg->count != 0); + + pPath = pPathArg->sval[0]; + } + + if (exitCode == EXIT_SUCCESS) + { + const char *pBodyCString; + uint16_t statusCode; + + if (pBody) + { + pBodyCString = sbgStringGetCString(pBody); + } + else + { + pBodyCString = NULL; + } + + errorCode = execute(&ecomInterface, methodIsGet, pPath, nrAttempts, timeout, pQuery, pBodyCString, writeStatus, &statusCode, pOutputFile); + + if (errorCode == SBG_NO_ERROR) + { + exitCode = convertStatusCodeToExitCode(statusCode); + } + else + { + exitCode = EXIT_FAILURE; + } + } + + if (pOutputFile && (pOutputFile != stdout)) + { + int result; + + result = fclose(pOutputFile); + + if (result != 0) + { + SBG_LOG_ERROR(SBG_WRITE_ERROR, "unable to close %s", pOutputFileArg->filename[0]); + exitCode = EXIT_FAILURE; + } + } + + sbgInterfaceDestroy(&ecomInterface); + } + else + { + SBG_LOG_ERROR(errorCode, "unable to open serial interface"); + exitCode = EXIT_FAILURE; + } + } + else + { + exitCode = EXIT_FAILURE; + printHelp = true; + } + } + + if (pBody) + { + sbgStringDestroy(pBody); + } + } + else + { + printHelp = true; + } + + if (printHelp) + { + arg_print_errors(stderr, pEndArg, PROGRAM_NAME); + fprintf(stderr, "Try '%s --help' for more information.\n", PROGRAM_NAME); + exitCode = EXIT_FAILURE; + } + + arg_freetable(argTable, SBG_ARRAY_SIZE(argTable)); + } + else + { + SBG_LOG_ERROR(SBG_MALLOC_FAILED, "unable to allocate memory"); + exitCode = EXIT_FAILURE; + } + + return exitCode; +} diff --git a/crates/sbg-rs/src/bindings.rs b/crates/sbg-rs/src/bindings.rs new file mode 100644 index 0000000..7e46bdd --- /dev/null +++ b/crates/sbg-rs/src/bindings.rs @@ -0,0 +1,14025 @@ +/* automatically generated by rust-bindgen 0.63.0 */ + +pub const __NEWLIB_H__: u32 = 1; +pub const _NEWLIB_VERSION_H__: u32 = 1; +pub const _NEWLIB_VERSION: &[u8; 6usize] = b"4.2.0\0"; +pub const __NEWLIB__: u32 = 4; +pub const __NEWLIB_MINOR__: u32 = 2; +pub const __NEWLIB_PATCHLEVEL__: u32 = 0; +pub const _WANT_IO_C99_FORMATS: u32 = 1; +pub const _WANT_IO_LONG_LONG: u32 = 1; +pub const _WANT_REGISTER_FINI: u32 = 1; +pub const _REENT_CHECK_VERIFY: u32 = 1; +pub const _MB_LEN_MAX: u32 = 1; +pub const HAVE_INITFINI_ARRAY: u32 = 1; +pub const _ATEXIT_DYNAMIC_ALLOC: u32 = 1; +pub const _HAVE_LONG_DOUBLE: u32 = 1; +pub const _HAVE_CC_INHIBIT_LOOP_TO_LIBCALL: u32 = 1; +pub const _LDBL_EQ_DBL: u32 = 1; +pub const _FVWRITE_IN_STREAMIO: u32 = 1; +pub const _FSEEK_OPTIMIZATION: u32 = 1; +pub const _WIDE_ORIENT: u32 = 1; +pub const _UNBUF_STREAM_OPT: u32 = 1; +pub const _RETARGETABLE_LOCKING: u32 = 1; +pub const _WANT_USE_GDTOA: u32 = 1; +pub const __OBSOLETE_MATH_DEFAULT: u32 = 1; +pub const __OBSOLETE_MATH: u32 = 1; +pub const _DEFAULT_SOURCE: u32 = 1; +pub const _POSIX_SOURCE: u32 = 1; +pub const _POSIX_C_SOURCE: u32 = 200809; +pub const _ATFILE_SOURCE: u32 = 1; +pub const __ATFILE_VISIBLE: u32 = 1; +pub const __BSD_VISIBLE: u32 = 1; +pub const __GNU_VISIBLE: u32 = 0; +pub const __ISO_C_VISIBLE: u32 = 2011; +pub const __LARGEFILE_VISIBLE: u32 = 0; +pub const __MISC_VISIBLE: u32 = 1; +pub const __POSIX_VISIBLE: u32 = 200809; +pub const __SVID_VISIBLE: u32 = 1; +pub const __XSI_VISIBLE: u32 = 0; +pub const __SSP_FORTIFY_LEVEL: u32 = 0; +pub const __RAND_MAX: u32 = 2147483647; +pub const __error_t_defined: u32 = 1; +pub const __have_longlong64: u32 = 1; +pub const __have_long32: u32 = 1; +pub const ___int8_t_defined: u32 = 1; +pub const ___int16_t_defined: u32 = 1; +pub const ___int32_t_defined: u32 = 1; +pub const ___int64_t_defined: u32 = 1; +pub const ___int_least8_t_defined: u32 = 1; +pub const ___int_least16_t_defined: u32 = 1; +pub const ___int_least32_t_defined: u32 = 1; +pub const ___int_least64_t_defined: u32 = 1; +pub const _NULL: u32 = 0; +pub const _ATEXIT_SIZE: u32 = 32; +pub const _RAND48_SEED_0: u32 = 13070; +pub const _RAND48_SEED_1: u32 = 43981; +pub const _RAND48_SEED_2: u32 = 4660; +pub const _RAND48_MULT_0: u32 = 58989; +pub const _RAND48_MULT_1: u32 = 57068; +pub const _RAND48_MULT_2: u32 = 5; +pub const _RAND48_ADD: u32 = 11; +pub const _REENT_EMERGENCY_SIZE: u32 = 25; +pub const _REENT_ASCTIME_SIZE: u32 = 26; +pub const _REENT_SIGNAL_SIZE: u32 = 24; +pub const _N_LISTS: u32 = 30; +pub const EPERM: u32 = 1; +pub const ENOENT: u32 = 2; +pub const ESRCH: u32 = 3; +pub const EINTR: u32 = 4; +pub const EIO: u32 = 5; +pub const ENXIO: u32 = 6; +pub const E2BIG: u32 = 7; +pub const ENOEXEC: u32 = 8; +pub const EBADF: u32 = 9; +pub const ECHILD: u32 = 10; +pub const EAGAIN: u32 = 11; +pub const ENOMEM: u32 = 12; +pub const EACCES: u32 = 13; +pub const EFAULT: u32 = 14; +pub const EBUSY: u32 = 16; +pub const EEXIST: u32 = 17; +pub const EXDEV: u32 = 18; +pub const ENODEV: u32 = 19; +pub const ENOTDIR: u32 = 20; +pub const EISDIR: u32 = 21; +pub const EINVAL: u32 = 22; +pub const ENFILE: u32 = 23; +pub const EMFILE: u32 = 24; +pub const ENOTTY: u32 = 25; +pub const ETXTBSY: u32 = 26; +pub const EFBIG: u32 = 27; +pub const ENOSPC: u32 = 28; +pub const ESPIPE: u32 = 29; +pub const EROFS: u32 = 30; +pub const EMLINK: u32 = 31; +pub const EPIPE: u32 = 32; +pub const EDOM: u32 = 33; +pub const ERANGE: u32 = 34; +pub const ENOMSG: u32 = 35; +pub const EIDRM: u32 = 36; +pub const EDEADLK: u32 = 45; +pub const ENOLCK: u32 = 46; +pub const ENOSTR: u32 = 60; +pub const ENODATA: u32 = 61; +pub const ETIME: u32 = 62; +pub const ENOSR: u32 = 63; +pub const ENOLINK: u32 = 67; +pub const EPROTO: u32 = 71; +pub const EMULTIHOP: u32 = 74; +pub const EBADMSG: u32 = 77; +pub const EFTYPE: u32 = 79; +pub const ENOSYS: u32 = 88; +pub const ENOTEMPTY: u32 = 90; +pub const ENAMETOOLONG: u32 = 91; +pub const ELOOP: u32 = 92; +pub const EOPNOTSUPP: u32 = 95; +pub const EPFNOSUPPORT: u32 = 96; +pub const ECONNRESET: u32 = 104; +pub const ENOBUFS: u32 = 105; +pub const EAFNOSUPPORT: u32 = 106; +pub const EPROTOTYPE: u32 = 107; +pub const ENOTSOCK: u32 = 108; +pub const ENOPROTOOPT: u32 = 109; +pub const ECONNREFUSED: u32 = 111; +pub const EADDRINUSE: u32 = 112; +pub const ECONNABORTED: u32 = 113; +pub const ENETUNREACH: u32 = 114; +pub const ENETDOWN: u32 = 115; +pub const ETIMEDOUT: u32 = 116; +pub const EHOSTDOWN: u32 = 117; +pub const EHOSTUNREACH: u32 = 118; +pub const EINPROGRESS: u32 = 119; +pub const EALREADY: u32 = 120; +pub const EDESTADDRREQ: u32 = 121; +pub const EMSGSIZE: u32 = 122; +pub const EPROTONOSUPPORT: u32 = 123; +pub const EADDRNOTAVAIL: u32 = 125; +pub const ENETRESET: u32 = 126; +pub const EISCONN: u32 = 127; +pub const ENOTCONN: u32 = 128; +pub const ETOOMANYREFS: u32 = 129; +pub const EDQUOT: u32 = 132; +pub const ESTALE: u32 = 133; +pub const ENOTSUP: u32 = 134; +pub const EILSEQ: u32 = 138; +pub const EOVERFLOW: u32 = 139; +pub const ECANCELED: u32 = 140; +pub const ENOTRECOVERABLE: u32 = 141; +pub const EOWNERDEAD: u32 = 142; +pub const EWOULDBLOCK: u32 = 11; +pub const __ELASTERROR: u32 = 2000; +pub const __int20: u32 = 2; +pub const __int20__: u32 = 2; +pub const __INT8: &[u8; 3usize] = b"hh\0"; +pub const __INT16: &[u8; 2usize] = b"h\0"; +pub const __INT64: &[u8; 3usize] = b"ll\0"; +pub const __FAST8: &[u8; 3usize] = b"hh\0"; +pub const __FAST16: &[u8; 2usize] = b"h\0"; +pub const __FAST64: &[u8; 3usize] = b"ll\0"; +pub const __LEAST8: &[u8; 3usize] = b"hh\0"; +pub const __LEAST16: &[u8; 2usize] = b"h\0"; +pub const __LEAST64: &[u8; 3usize] = b"ll\0"; +pub const __int8_t_defined: u32 = 1; +pub const __int16_t_defined: u32 = 1; +pub const __int32_t_defined: u32 = 1; +pub const __int64_t_defined: u32 = 1; +pub const __int_least8_t_defined: u32 = 1; +pub const __int_least16_t_defined: u32 = 1; +pub const __int_least32_t_defined: u32 = 1; +pub const __int_least64_t_defined: u32 = 1; +pub const __int_fast8_t_defined: u32 = 1; +pub const __int_fast16_t_defined: u32 = 1; +pub const __int_fast32_t_defined: u32 = 1; +pub const __int_fast64_t_defined: u32 = 1; +pub const WINT_MIN: u32 = 0; +pub const _LIBC_LIMITS_H_: u32 = 1; +pub const __GNUCLIKE_ASM: u32 = 3; +pub const __GNUCLIKE___TYPEOF: u32 = 1; +pub const __GNUCLIKE___OFFSETOF: u32 = 1; +pub const __GNUCLIKE___SECTION: u32 = 1; +pub const __GNUCLIKE_CTOR_SECTION_HANDLING: u32 = 1; +pub const __GNUCLIKE_BUILTIN_CONSTANT_P: u32 = 1; +pub const __GNUCLIKE_BUILTIN_VARARGS: u32 = 1; +pub const __GNUCLIKE_BUILTIN_STDARG: u32 = 1; +pub const __GNUCLIKE_BUILTIN_VAALIST: u32 = 1; +pub const __GNUC_VA_LIST_COMPATIBILITY: u32 = 1; +pub const __GNUCLIKE_BUILTIN_NEXT_ARG: u32 = 1; +pub const __GNUCLIKE_BUILTIN_MEMCPY: u32 = 1; +pub const __CC_SUPPORTS_INLINE: u32 = 1; +pub const __CC_SUPPORTS___INLINE: u32 = 1; +pub const __CC_SUPPORTS___INLINE__: u32 = 1; +pub const __CC_SUPPORTS___FUNC__: u32 = 1; +pub const __CC_SUPPORTS_WARNING: u32 = 1; +pub const __CC_SUPPORTS_VARADIC_XXX: u32 = 1; +pub const __CC_SUPPORTS_DYNAMIC_ARRAY_INIT: u32 = 1; +pub const ARG_MAX: u32 = 65536; +pub const CHILD_MAX: u32 = 40; +pub const LINK_MAX: u32 = 32767; +pub const MAX_CANON: u32 = 255; +pub const MAX_INPUT: u32 = 255; +pub const NAME_MAX: u32 = 255; +pub const NGROUPS_MAX: u32 = 16; +pub const OPEN_MAX: u32 = 64; +pub const PATH_MAX: u32 = 1024; +pub const PIPE_BUF: u32 = 512; +pub const IOV_MAX: u32 = 1024; +pub const BC_BASE_MAX: u32 = 99; +pub const BC_DIM_MAX: u32 = 2048; +pub const BC_SCALE_MAX: u32 = 99; +pub const BC_STRING_MAX: u32 = 1000; +pub const COLL_WEIGHTS_MAX: u32 = 0; +pub const EXPR_NEST_MAX: u32 = 32; +pub const LINE_MAX: u32 = 2048; +pub const RE_DUP_MAX: u32 = 255; +pub const MB_LEN_MAX: u32 = 1; +pub const NL_ARGMAX: u32 = 32; +pub const _POSIX2_RE_DUP_MAX: u32 = 255; +pub const CHAR_MIN: u32 = 0; +pub const _M_LN2: f64 = 0.6931471805599453; +pub const FP_NAN: u32 = 0; +pub const FP_INFINITE: u32 = 1; +pub const FP_ZERO: u32 = 2; +pub const FP_SUBNORMAL: u32 = 3; +pub const FP_NORMAL: u32 = 4; +pub const MATH_ERRNO: u32 = 1; +pub const MATH_ERREXCEPT: u32 = 2; +pub const _MATH_ERRHANDLING_ERRNO: u32 = 1; +pub const _MATH_ERRHANDLING_ERREXCEPT: u32 = 2; +pub const math_errhandling: u32 = 3; +pub const M_E: f64 = 2.718281828459045; +pub const M_LOG2E: f64 = 1.4426950408889634; +pub const M_LOG10E: f64 = 0.4342944819032518; +pub const M_LN2: f64 = 0.6931471805599453; +pub const M_LN10: f64 = 2.302585092994046; +pub const M_PI: f64 = 3.141592653589793; +pub const M_PI_2: f64 = 1.5707963267948966; +pub const M_PI_4: f64 = 0.7853981633974483; +pub const M_1_PI: f64 = 0.3183098861837907; +pub const M_2_PI: f64 = 0.6366197723675814; +pub const M_2_SQRTPI: f64 = 1.1283791670955126; +pub const M_SQRT2: f64 = 1.4142135623730951; +pub const M_SQRT1_2: f64 = 0.7071067811865476; +pub const M_TWOPI: f64 = 6.283185307179586; +pub const M_SQRTPI: f64 = 1.772453850905516; +pub const M_SQRT3: f64 = 1.7320508075688772; +pub const M_IVLN10: f64 = 0.4342944819032518; +pub const M_LOG2_E: f64 = 0.6931471805599453; +pub const __GNUC_VA_LIST: u32 = 1; +pub const __bool_true_false_are_defined: u32 = 1; +pub const true_: u32 = 1; +pub const false_: u32 = 0; +pub const EXIT_FAILURE: u32 = 1; +pub const EXIT_SUCCESS: u32 = 0; +pub const RAND_MAX: u32 = 2147483647; +pub const __BIT_TYPES_DEFINED__: u32 = 1; +pub const _LITTLE_ENDIAN: u32 = 1234; +pub const _BIG_ENDIAN: u32 = 4321; +pub const _PDP_ENDIAN: u32 = 3412; +pub const _BYTE_ORDER: u32 = 1234; +pub const _QUAD_HIGHWORD: u32 = 1; +pub const _QUAD_LOWWORD: u32 = 0; +pub const LITTLE_ENDIAN: u32 = 1234; +pub const BIG_ENDIAN: u32 = 4321; +pub const PDP_ENDIAN: u32 = 3412; +pub const BYTE_ORDER: u32 = 1234; +pub const FD_SETSIZE: u32 = 64; +pub const SCHED_OTHER: u32 = 0; +pub const SCHED_FIFO: u32 = 1; +pub const SCHED_RR: u32 = 2; +pub const PTHREAD_SCOPE_PROCESS: u32 = 0; +pub const PTHREAD_SCOPE_SYSTEM: u32 = 1; +pub const PTHREAD_INHERIT_SCHED: u32 = 1; +pub const PTHREAD_EXPLICIT_SCHED: u32 = 2; +pub const PTHREAD_CREATE_DETACHED: u32 = 0; +pub const PTHREAD_CREATE_JOINABLE: u32 = 1; +pub const __SLBF: u32 = 1; +pub const __SNBF: u32 = 2; +pub const __SRD: u32 = 4; +pub const __SWR: u32 = 8; +pub const __SRW: u32 = 16; +pub const __SEOF: u32 = 32; +pub const __SERR: u32 = 64; +pub const __SMBF: u32 = 128; +pub const __SAPP: u32 = 256; +pub const __SSTR: u32 = 512; +pub const __SOPT: u32 = 1024; +pub const __SNPT: u32 = 2048; +pub const __SOFF: u32 = 4096; +pub const __SORD: u32 = 8192; +pub const __SL64: u32 = 32768; +pub const __SNLK: u32 = 1; +pub const __SWID: u32 = 8192; +pub const _IOFBF: u32 = 0; +pub const _IOLBF: u32 = 1; +pub const _IONBF: u32 = 2; +pub const EOF: i32 = -1; +pub const BUFSIZ: u32 = 1024; +pub const FOPEN_MAX: u32 = 20; +pub const FILENAME_MAX: u32 = 1024; +pub const L_tmpnam: u32 = 1024; +pub const P_tmpdir: &[u8; 5usize] = b"/tmp\0"; +pub const SEEK_SET: u32 = 0; +pub const SEEK_CUR: u32 = 1; +pub const SEEK_END: u32 = 2; +pub const TMP_MAX: u32 = 26; +pub const L_ctermid: u32 = 16; +pub const _CLOCKS_PER_SEC_: u32 = 100; +pub const CLOCKS_PER_SEC: u32 = 100; +pub const CLK_TCK: u32 = 100; +pub const CLOCK_ENABLED: u32 = 1; +pub const CLOCK_DISABLED: u32 = 0; +pub const CLOCK_ALLOWED: u32 = 1; +pub const CLOCK_DISALLOWED: u32 = 0; +pub const TIMER_ABSTIME: u32 = 4; +pub const SBG_CONFIG_UNALIGNED_ACCESS_AUTH: u32 = 0; +pub const SBG_CONFIG_BIG_ENDIAN: u32 = 0; +pub const SBG_CONFIG_ENABLE_LOG_ERROR: u32 = 1; +pub const SBG_CONFIG_ENABLE_LOG_WARNING: u32 = 1; +pub const SBG_CONFIG_ENABLE_LOG_INFO: u32 = 1; +pub const SBG_CONFIG_ENABLE_LOG_DEBUG: u32 = 1; +pub const SBG_DISABLE: u32 = 0; +pub const SBG_ENABLE: u32 = 1; +pub const FALSE: u32 = 0; +pub const TRUE: u32 = 1; +pub const SBG_CONFIG_WARN_ABOUT_DEPRECATED_TYPES: u32 = 1; +pub const SBG_PI: f64 = 3.141592653589793; +pub const SBG_PI_F: f64 = 3.141592653589793; +pub const SBG_MIN_INT_24: i32 = -8388608; +pub const SBG_MAX_INT_24: u32 = 8388607; +pub const SBG_MAX_UINT_24: u32 = 16777215; +pub const SBG_MIN_INT_40: i64 = -549755813888; +pub const SBG_MAX_INT_40: u64 = 549755813887; +pub const SBG_MAX_UINT_40: u64 = 1099511627775; +pub const SBG_MIN_INT_48: i64 = -140737488355328; +pub const SBG_MAX_INT_48: u64 = 140737488355327; +pub const SBG_MAX_UINT_48: u64 = 281474976710655; +pub const SBG_MIN_INT_56: i64 = -36028797018963968; +pub const SBG_MAX_INT_56: u64 = 36028797018963967; +pub const SBG_MAX_UINT_56: u64 = 72057594037927935; +pub const SBG_DEBUG_LOG_CATEGORY: &[u8; 5usize] = b"None\0"; +pub const SBG_IF_NAME_MAX_SIZE: u32 = 48; +pub const SBG_IF_TYPE_UNKNOW: u32 = 0; +pub const SBG_IF_TYPE_SERIAL: u32 = 1; +pub const SBG_IF_TYPE_ETH_UDP: u32 = 2; +pub const SBG_IF_TYPE_ETH_TCP_IP: u32 = 3; +pub const SBG_IF_TYPE_FILE: u32 = 4; +pub const SBG_IF_TYPE_LAST_RESERVED: u32 = 999; +pub const SBG_NETWORK_IPV4_STRING_SIZE: u32 = 16; +pub const SBG_ECOM_MAX_BUFFER_SIZE: u32 = 4096; +pub const SBG_ECOM_MAX_PAYLOAD_SIZE: u32 = 4086; +pub const SBG_ECOM_MAX_EXTENDED_PAYLOAD_SIZE: u32 = 4081; +pub const SBG_ECOM_SYNC_1: u32 = 255; +pub const SBG_ECOM_SYNC_2: u32 = 90; +pub const SBG_ECOM_ETX: u32 = 51; +pub const SBG_ECOM_RX_TIME_OUT: u32 = 450; +pub const SBG_ECOM_AIR_DATA_TIME_IS_DELAY: u32 = 1; +pub const SBG_ECOM_AIR_DATA_PRESSURE_ABS_VALID: u32 = 2; +pub const SBG_ECOM_AIR_DATA_ALTITUDE_VALID: u32 = 4; +pub const SBG_ECOM_AIR_DATA_PRESSURE_DIFF_VALID: u32 = 8; +pub const SBG_ECOM_AIR_DATA_AIRPSEED_VALID: u32 = 16; +pub const SBG_ECOM_AIR_DATA_TEMPERATURE_VALID: u32 = 32; +pub const SBG_ECOM_DEPTH_TIME_IS_DELAY: u32 = 1; +pub const SBG_ECOM_DEPTH_PRESSURE_ABS_VALID: u32 = 2; +pub const SBG_ECOM_DEPTH_ALTITUDE_VALID: u32 = 4; +pub const SBG_ECOM_LOG_DIAG_MAX_STRING_SIZE: u32 = 4080; +pub const SBG_ECOM_DVL_VELOCITY_VALID: u32 = 1; +pub const SBG_ECOM_DVL_TIME_SYNC: u32 = 2; +pub const SBG_ECOM_SOLUTION_MODE_SHIFT: u32 = 0; +pub const SBG_ECOM_SOLUTION_MODE_MASK: u32 = 15; +pub const SBG_ECOM_SOL_ATTITUDE_VALID: u32 = 16; +pub const SBG_ECOM_SOL_HEADING_VALID: u32 = 32; +pub const SBG_ECOM_SOL_VELOCITY_VALID: u32 = 64; +pub const SBG_ECOM_SOL_POSITION_VALID: u32 = 128; +pub const SBG_ECOM_SOL_VERT_REF_USED: u32 = 256; +pub const SBG_ECOM_SOL_MAG_REF_USED: u32 = 512; +pub const SBG_ECOM_SOL_GPS1_VEL_USED: u32 = 1024; +pub const SBG_ECOM_SOL_GPS1_POS_USED: u32 = 2048; +pub const SBG_ECOM_SOL_GPS1_HDT_USED: u32 = 8192; +pub const SBG_ECOM_SOL_GPS2_VEL_USED: u32 = 16384; +pub const SBG_ECOM_SOL_GPS2_POS_USED: u32 = 32768; +pub const SBG_ECOM_SOL_GPS2_HDT_USED: u32 = 131072; +pub const SBG_ECOM_SOL_ODO_USED: u32 = 262144; +pub const SBG_ECOM_SOL_DVL_BT_USED: u32 = 524288; +pub const SBG_ECOM_SOL_DVL_WT_USED: u32 = 1048576; +pub const SBG_ECOM_SOL_USER_POS_USED: u32 = 2097152; +pub const SBG_ECOM_SOL_USER_VEL_USED: u32 = 4194304; +pub const SBG_ECOM_SOL_USER_HEADING_USED: u32 = 8388608; +pub const SBG_ECOM_SOL_USBL_USED: u32 = 16777216; +pub const SBG_ECOM_SOL_AIR_DATA_USED: u32 = 33554432; +pub const SBG_ECOM_SOL_ZUPT_USED: u32 = 67108864; +pub const SBG_ECOM_SOL_ALIGN_VALID: u32 = 134217728; +pub const SBG_ECOM_SOL_DEPTH_USED: u32 = 268435456; +pub const SBG_ECOM_EVENT_OVERFLOW: u32 = 1; +pub const SBG_ECOM_EVENT_OFFSET_0_VALID: u32 = 2; +pub const SBG_ECOM_EVENT_OFFSET_1_VALID: u32 = 4; +pub const SBG_ECOM_EVENT_OFFSET_2_VALID: u32 = 8; +pub const SBG_ECOM_EVENT_OFFSET_3_VALID: u32 = 16; +pub const SBG_ECOM_RAW_DATA_MAX_BUFFER_SIZE: u32 = 4086; +pub const SBG_ECOM_GPS_VEL_STATUS_SHIFT: u32 = 0; +pub const SBG_ECOM_GPS_VEL_STATUS_MASK: u32 = 63; +pub const SBG_ECOM_GPS_VEL_TYPE_SHIFT: u32 = 6; +pub const SBG_ECOM_GPS_VEL_TYPE_MASK: u32 = 63; +pub const SBG_ECOM_GPS_POS_STATUS_SHIFT: u32 = 0; +pub const SBG_ECOM_GPS_POS_STATUS_MASK: u32 = 63; +pub const SBG_ECOM_GPS_POS_TYPE_SHIFT: u32 = 6; +pub const SBG_ECOM_GPS_POS_TYPE_MASK: u32 = 63; +pub const SBG_ECOM_GPS_POS_GPS_L1_USED: u32 = 4096; +pub const SBG_ECOM_GPS_POS_GPS_L2_USED: u32 = 8192; +pub const SBG_ECOM_GPS_POS_GPS_L5_USED: u32 = 16384; +pub const SBG_ECOM_GPS_POS_GLO_L1_USED: u32 = 32768; +pub const SBG_ECOM_GPS_POS_GLO_L2_USED: u32 = 65536; +pub const SBG_ECOM_GPS_POS_GLO_L3_USED: u32 = 131072; +pub const SBG_ECOM_GPS_POS_GAL_E1_USED: u32 = 262144; +pub const SBG_ECOM_GPS_POS_GAL_E5A_USED: u32 = 524288; +pub const SBG_ECOM_GPS_POS_GAL_E5B_USED: u32 = 1048576; +pub const SBG_ECOM_GPS_POS_GAL_E5ALT_USED: u32 = 2097152; +pub const SBG_ECOM_GPS_POS_GAL_E6_USED: u32 = 4194304; +pub const SBG_ECOM_GPS_POS_BDS_B1_USED: u32 = 8388608; +pub const SBG_ECOM_GPS_POS_BDS_B2_USED: u32 = 16777216; +pub const SBG_ECOM_GPS_POS_BDS_B3_USED: u32 = 33554432; +pub const SBG_ECOM_GPS_POS_QZSS_L1_USED: u32 = 67108864; +pub const SBG_ECOM_GPS_POS_QZSS_L2_USED: u32 = 134217728; +pub const SBG_ECOM_GPS_POS_QZSS_L5_USED: u32 = 268435456; +pub const SBG_ECOM_GPS_HDT_STATUS_SHIFT: u32 = 0; +pub const SBG_ECOM_GPS_HDT_STATUS_MASK: u32 = 63; +pub const SBG_ECOM_GPS_HDT_BASELINE_VALID: u32 = 64; +pub const SBG_ECOM_IMU_COM_OK: u32 = 1; +pub const SBG_ECOM_IMU_STATUS_BIT: u32 = 2; +pub const SBG_ECOM_IMU_ACCEL_X_BIT: u32 = 4; +pub const SBG_ECOM_IMU_ACCEL_Y_BIT: u32 = 8; +pub const SBG_ECOM_IMU_ACCEL_Z_BIT: u32 = 16; +pub const SBG_ECOM_IMU_GYRO_X_BIT: u32 = 32; +pub const SBG_ECOM_IMU_GYRO_Y_BIT: u32 = 64; +pub const SBG_ECOM_IMU_GYRO_Z_BIT: u32 = 128; +pub const SBG_ECOM_IMU_ACCELS_IN_RANGE: u32 = 256; +pub const SBG_ECOM_IMU_GYROS_IN_RANGE: u32 = 512; +pub const SBG_ECOM_MAG_MAG_X_BIT: u32 = 1; +pub const SBG_ECOM_MAG_MAG_Y_BIT: u32 = 2; +pub const SBG_ECOM_MAG_MAG_Z_BIT: u32 = 4; +pub const SBG_ECOM_MAG_ACCEL_X_BIT: u32 = 8; +pub const SBG_ECOM_MAG_ACCEL_Y_BIT: u32 = 16; +pub const SBG_ECOM_MAG_ACCEL_Z_BIT: u32 = 32; +pub const SBG_ECOM_MAG_MAGS_IN_RANGE: u32 = 64; +pub const SBG_ECOM_MAG_ACCELS_IN_RANGE: u32 = 128; +pub const SBG_ECOM_MAG_CALIBRATION_OK: u32 = 256; +pub const SBG_ECOM_ODO_REAL_MEAS: u32 = 1; +pub const SBG_ECOM_ODO_TIME_SYNC: u32 = 2; +pub const SBG_ECOM_SAT_MAX_NR_SATELLITES: u32 = 64; +pub const SBG_ECOM_SAT_MAX_NR_SIGNALS: u32 = 8; +pub const SBG_ECOM_HEAVE_VALID: u32 = 1; +pub const SBG_ECOM_HEAVE_VEL_AIDED: u32 = 2; +pub const SBG_ECOM_HEAVE_SURGE_SWAY_INCLUDED: u32 = 4; +pub const SBG_ECOM_HEAVE_PERIOD_INCLUDED: u32 = 8; +pub const SBG_ECOM_HEAVE_PERIOD_VALID: u32 = 16; +pub const SBG_ECOM_HEAVE_SWELL_MODE: u32 = 32; +pub const SBG_ECOM_GENERAL_MAIN_POWER_OK: u32 = 1; +pub const SBG_ECOM_GENERAL_IMU_POWER_OK: u32 = 2; +pub const SBG_ECOM_GENERAL_GPS_POWER_OK: u32 = 4; +pub const SBG_ECOM_GENERAL_SETTINGS_OK: u32 = 8; +pub const SBG_ECOM_GENERAL_TEMPERATURE_OK: u32 = 16; +pub const SBG_ECOM_GENERAL_DATALOGGER_OK: u32 = 32; +pub const SBG_ECOM_GENERAL_CPU_OK: u32 = 64; +pub const SBG_ECOM_CAN_STATUS_SHIFT: u32 = 28; +pub const SBG_ECOM_CAN_STATUS_MASK: u32 = 7; +pub const SBG_ECOM_PORTA_VALID: u32 = 1; +pub const SBG_ECOM_PORTB_VALID: u32 = 2; +pub const SBG_ECOM_PORTC_VALID: u32 = 4; +pub const SBG_ECOM_PORTD_VALID: u32 = 8; +pub const SBG_ECOM_PORTE_VALID: u32 = 16; +pub const SBG_ECOM_PORTA_RX_OK: u32 = 32; +pub const SBG_ECOM_PORTA_TX_OK: u32 = 64; +pub const SBG_ECOM_PORTB_RX_OK: u32 = 128; +pub const SBG_ECOM_PORTB_TX_OK: u32 = 256; +pub const SBG_ECOM_PORTC_RX_OK: u32 = 512; +pub const SBG_ECOM_PORTC_TX_OK: u32 = 1024; +pub const SBG_ECOM_PORTD_RX_OK: u32 = 2048; +pub const SBG_ECOM_PORTD_TX_OK: u32 = 4096; +pub const SBG_ECOM_PORTE_RX_OK: u32 = 8192; +pub const SBG_ECOM_PORTE_TX_OK: u32 = 16384; +pub const SBG_ECOM_ETH0_VALID: u32 = 32768; +pub const SBG_ECOM_ETH1_VALID: u32 = 65536; +pub const SBG_ECOM_ETH2_VALID: u32 = 131072; +pub const SBG_ECOM_ETH3_VALID: u32 = 262144; +pub const SBG_ECOM_ETH4_VALID: u32 = 524288; +pub const SBG_ECOM_CAN_VALID: u32 = 33554432; +pub const SBG_ECOM_CAN_RX_OK: u32 = 67108864; +pub const SBG_ECOM_CAN_TX_OK: u32 = 134217728; +pub const SBG_ECOM_COM2_ETH0_RX_OK: u32 = 1; +pub const SBG_ECOM_COM2_ETH0_TX_OK: u32 = 2; +pub const SBG_ECOM_COM2_ETH1_RX_OK: u32 = 4; +pub const SBG_ECOM_COM2_ETH1_TX_OK: u32 = 8; +pub const SBG_ECOM_COM2_ETH2_RX_OK: u32 = 16; +pub const SBG_ECOM_COM2_ETH2_TX_OK: u32 = 32; +pub const SBG_ECOM_COM2_ETH3_RX_OK: u32 = 64; +pub const SBG_ECOM_COM2_ETH3_TX_OK: u32 = 128; +pub const SBG_ECOM_COM2_ETH4_RX_OK: u32 = 256; +pub const SBG_ECOM_COM2_ETH4_TX_OK: u32 = 512; +pub const SBG_ECOM_AIDING_GPS1_POS_RECV: u32 = 1; +pub const SBG_ECOM_AIDING_GPS1_VEL_RECV: u32 = 2; +pub const SBG_ECOM_AIDING_GPS1_HDT_RECV: u32 = 4; +pub const SBG_ECOM_AIDING_GPS1_UTC_RECV: u32 = 8; +pub const SBG_ECOM_AIDING_GPS2_POS_RECV: u32 = 16; +pub const SBG_ECOM_AIDING_GPS2_VEL_RECV: u32 = 32; +pub const SBG_ECOM_AIDING_GPS2_HDT_RECV: u32 = 64; +pub const SBG_ECOM_AIDING_GPS2_UTC_RECV: u32 = 128; +pub const SBG_ECOM_AIDING_MAG_RECV: u32 = 256; +pub const SBG_ECOM_AIDING_ODO_RECV: u32 = 512; +pub const SBG_ECOM_AIDING_DVL_RECV: u32 = 1024; +pub const SBG_ECOM_AIDING_USBL_RECV: u32 = 2048; +pub const SBG_ECOM_AIDING_DEPTH_RECV: u32 = 4096; +pub const SBG_ECOM_AIDING_AIR_DATA_RECV: u32 = 8192; +pub const SBG_ECOM_AIDING_USER_POS_RECV: u32 = 16384; +pub const SBG_ECOM_AIDING_USER_VEL_RECV: u32 = 32768; +pub const SBG_ECOM_AIDING_USER_HEADING_RECV: u32 = 65536; +pub const SBG_ECOM_USBL_TIME_SYNC: u32 = 1; +pub const SBG_ECOM_USBL_POSITION_VALID: u32 = 2; +pub const SBG_ECOM_USBL_DEPTH_VALID: u32 = 4; +pub const SBG_ECOM_CLOCK_STATUS_SHIFT: u32 = 1; +pub const SBG_ECOM_CLOCK_STATUS_MASK: u32 = 15; +pub const SBG_ECOM_CLOCK_UTC_STATUS_SHIFT: u32 = 6; +pub const SBG_ECOM_CLOCK_UTC_STATUS_MASK: u32 = 15; +pub const SBG_ECOM_CLOCK_STABLE_INPUT: u32 = 1; +pub const SBG_ECOM_CLOCK_UTC_SYNC: u32 = 32; +pub const SBG_ECOM_DEFAULT_CMD_TIME_OUT: u32 = 500; +pub const SBG_ECOM_SENSOR_FEATURE_IMU: u32 = 1; +pub const SBG_ECOM_SENSOR_FEATURE_AHRS: u32 = 2; +pub const SBG_ECOM_SENSOR_FEATURE_NAVIGATION: u32 = 4; +pub const SBG_ECOM_SENSOR_FEATURE_SHIP_MOTION: u32 = 8; +pub const SBG_ECOM_GNSS_SIGNAL_GPS_L1: u32 = 1; +pub const SBG_ECOM_GNSS_SIGNAL_GPS_L2: u32 = 2; +pub const SBG_ECOM_GNSS_SIGNAL_GPS_L5: u32 = 4; +pub const SBG_ECOM_GNSS_SIGNAL_GLONASS_L1: u32 = 8; +pub const SBG_ECOM_GNSS_SIGNAL_GLONASS_L2: u32 = 16; +pub const SBG_ECOM_GNSS_SIGNAL_BEIDOU_B1: u32 = 32; +pub const SBG_ECOM_GNSS_SIGNAL_BEIDOU_B2: u32 = 64; +pub const SBG_ECOM_GNSS_SIGNAL_BEIDOU_B3: u32 = 128; +pub const SBG_ECOM_GNSS_SIGNAL_GALILEO_E1: u32 = 256; +pub const SBG_ECOM_GNSS_SIGNAL_GALILEO_E5: u32 = 512; +pub const SBG_ECOM_GNSS_SIGNAL_GALILEO_E6: u32 = 1024; +pub const SBG_ECOM_GNSS_SIGNAL_QZSS: u32 = 2048; +pub const SBG_ECOM_GNSS_SIGNAL_SBAS: u32 = 4096; +pub const SBG_ECOM_GNSS_SIGNAL_L_BAND: u32 = 8192; +pub const SBG_ECOM_GNSS_FEATURE_DUAL_ANT: u32 = 1; +pub const SBG_ECOM_GNSS_FEATURE_RTK_LIMITED: u32 = 2; +pub const SBG_ECOM_GNSS_FEATURE_RTK: u32 = 4; +pub const SBG_ECOM_GNSS_FEATURE_PPP: u32 = 8; +pub const SBG_ECOM_GNSS_FEATURE_RAW_DATA: u32 = 16; +pub const SBG_ECOM_GNSS_FEATURE_RAIM: u32 = 32; +pub const SBG_ECOM_GNSS_FEATURE_HIGH_SPEED: u32 = 64; +pub const SBG_ECOM_INFO_PRODUCT_CODE_LENGTH: u32 = 32; +pub const SBG_ECOM_MAG_CALIB_NOT_ENOUGH_POINTS: u32 = 1; +pub const SBG_ECOM_MAG_CALIB_TOO_MUCH_DISTORTIONS: u32 = 2; +pub const SBG_ECOM_MAG_CALIB_X_MOTION_ISSUE: u32 = 4; +pub const SBG_ECOM_MAG_CALIB_Y_MOTION_ISSUE: u32 = 8; +pub const SBG_ECOM_MAG_CALIB_Z_MOTION_ISSUE: u32 = 16; +pub const SBG_ECOM_MAG_CALIB_ALIGNMENT_ISSUE: u32 = 32; +pub const SBG_E_COM_VERSION_MAJOR: u32 = 3; +pub const SBG_E_COM_VERSION_MINOR: u32 = 2; +pub const SBG_E_COM_VERSION_REV: u32 = 4011; +extern "C" { + pub fn __assert( + arg1: *const ::core::ffi::c_char, + arg2: ::core::ffi::c_int, + arg3: *const ::core::ffi::c_char, + ) -> !; +} +extern "C" { + pub fn __assert_func( + arg1: *const ::core::ffi::c_char, + arg2: ::core::ffi::c_int, + arg3: *const ::core::ffi::c_char, + arg4: *const ::core::ffi::c_char, + ) -> !; +} +pub type error_t = ::core::ffi::c_int; +pub type wchar_t = ::core::ffi::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct max_align_t { + pub __clang_max_align_nonce1: ::core::ffi::c_longlong, + pub __clang_max_align_nonce2: f64, +} +#[test] +fn bindgen_test_layout_max_align_t() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(max_align_t)) + ); + assert_eq!( + ::core::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(max_align_t)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__clang_max_align_nonce1) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(max_align_t), + "::", + stringify!(__clang_max_align_nonce1) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__clang_max_align_nonce2) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(max_align_t), + "::", + stringify!(__clang_max_align_nonce2) + ) + ); +} +pub type wint_t = ::core::ffi::c_int; +pub type __int8_t = ::core::ffi::c_schar; +pub type __uint8_t = ::core::ffi::c_uchar; +pub type __int16_t = ::core::ffi::c_short; +pub type __uint16_t = ::core::ffi::c_ushort; +pub type __int32_t = ::core::ffi::c_int; +pub type __uint32_t = ::core::ffi::c_uint; +pub type __int64_t = ::core::ffi::c_longlong; +pub type __uint64_t = ::core::ffi::c_ulonglong; +pub type __int_least8_t = ::core::ffi::c_schar; +pub type __uint_least8_t = ::core::ffi::c_uchar; +pub type __int_least16_t = ::core::ffi::c_short; +pub type __uint_least16_t = ::core::ffi::c_ushort; +pub type __int_least32_t = ::core::ffi::c_int; +pub type __uint_least32_t = ::core::ffi::c_uint; +pub type __int_least64_t = ::core::ffi::c_longlong; +pub type __uint_least64_t = ::core::ffi::c_ulonglong; +pub type __intmax_t = ::core::ffi::c_longlong; +pub type __uintmax_t = ::core::ffi::c_ulonglong; +pub type __intptr_t = ::core::ffi::c_int; +pub type __uintptr_t = ::core::ffi::c_uint; +pub type __blkcnt_t = ::core::ffi::c_long; +pub type __blksize_t = ::core::ffi::c_long; +pub type __fsblkcnt_t = __uint64_t; +pub type __fsfilcnt_t = __uint32_t; +pub type _off_t = ::core::ffi::c_long; +pub type __pid_t = ::core::ffi::c_int; +pub type __dev_t = ::core::ffi::c_short; +pub type __uid_t = ::core::ffi::c_ushort; +pub type __gid_t = ::core::ffi::c_ushort; +pub type __id_t = __uint32_t; +pub type __ino_t = ::core::ffi::c_ushort; +pub type __mode_t = __uint32_t; +pub type _off64_t = ::core::ffi::c_longlong; +pub type __off_t = _off_t; +pub type __loff_t = _off64_t; +pub type __key_t = ::core::ffi::c_long; +pub type _fpos_t = ::core::ffi::c_long; +pub type __size_t = ::core::ffi::c_uint; +pub type _ssize_t = ::core::ffi::c_int; +pub type __ssize_t = _ssize_t; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct _mbstate_t { + pub __count: ::core::ffi::c_int, + pub __value: _mbstate_t__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union _mbstate_t__bindgen_ty_1 { + pub __wch: wint_t, + pub __wchb: [::core::ffi::c_uchar; 4usize], +} +#[test] +fn bindgen_test_layout__mbstate_t__bindgen_ty_1() { + const UNINIT: ::core::mem::MaybeUninit<_mbstate_t__bindgen_ty_1> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_mbstate_t__bindgen_ty_1>(), + 4usize, + concat!("Size of: ", stringify!(_mbstate_t__bindgen_ty_1)) + ); + assert_eq!( + ::core::mem::align_of::<_mbstate_t__bindgen_ty_1>(), + 4usize, + concat!("Alignment of ", stringify!(_mbstate_t__bindgen_ty_1)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__wch) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_mbstate_t__bindgen_ty_1), + "::", + stringify!(__wch) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__wchb) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_mbstate_t__bindgen_ty_1), + "::", + stringify!(__wchb) + ) + ); +} +#[test] +fn bindgen_test_layout__mbstate_t() { + const UNINIT: ::core::mem::MaybeUninit<_mbstate_t> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_mbstate_t>(), + 8usize, + concat!("Size of: ", stringify!(_mbstate_t)) + ); + assert_eq!( + ::core::mem::align_of::<_mbstate_t>(), + 4usize, + concat!("Alignment of ", stringify!(_mbstate_t)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__count) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_mbstate_t), + "::", + stringify!(__count) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__value) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_mbstate_t), + "::", + stringify!(__value) + ) + ); +} +pub type _iconv_t = *mut ::core::ffi::c_void; +pub type __clock_t = ::core::ffi::c_ulong; +pub type __time_t = __int_least64_t; +pub type __clockid_t = ::core::ffi::c_ulong; +pub type __timer_t = ::core::ffi::c_ulong; +pub type __sa_family_t = __uint8_t; +pub type __socklen_t = __uint32_t; +pub type __nl_item = ::core::ffi::c_int; +pub type __nlink_t = ::core::ffi::c_ushort; +pub type __suseconds_t = ::core::ffi::c_long; +pub type __useconds_t = ::core::ffi::c_ulong; +pub type __va_list = u32; +pub type __ULong = ::core::ffi::c_ulong; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __lock { + _unused: [u8; 0], +} +pub type _LOCK_T = *mut __lock; +extern "C" { + pub fn __retarget_lock_init(lock: *mut _LOCK_T); +} +extern "C" { + pub fn __retarget_lock_init_recursive(lock: *mut _LOCK_T); +} +extern "C" { + pub fn __retarget_lock_close(lock: _LOCK_T); +} +extern "C" { + pub fn __retarget_lock_close_recursive(lock: _LOCK_T); +} +extern "C" { + pub fn __retarget_lock_acquire(lock: _LOCK_T); +} +extern "C" { + pub fn __retarget_lock_acquire_recursive(lock: _LOCK_T); +} +extern "C" { + pub fn __retarget_lock_try_acquire(lock: _LOCK_T) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __retarget_lock_try_acquire_recursive(lock: _LOCK_T) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __retarget_lock_release(lock: _LOCK_T); +} +extern "C" { + pub fn __retarget_lock_release_recursive(lock: _LOCK_T); +} +pub type _flock_t = _LOCK_T; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __locale_t { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _Bigint { + pub _next: *mut _Bigint, + pub _k: ::core::ffi::c_int, + pub _maxwds: ::core::ffi::c_int, + pub _sign: ::core::ffi::c_int, + pub _wds: ::core::ffi::c_int, + pub _x: [__ULong; 1usize], +} +#[test] +fn bindgen_test_layout__Bigint() { + const UNINIT: ::core::mem::MaybeUninit<_Bigint> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_Bigint>(), + 24usize, + concat!("Size of: ", stringify!(_Bigint)) + ); + assert_eq!( + ::core::mem::align_of::<_Bigint>(), + 4usize, + concat!("Alignment of ", stringify!(_Bigint)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._next) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Bigint), + "::", + stringify!(_next) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._k) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_Bigint), + "::", + stringify!(_k) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._maxwds) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_Bigint), + "::", + stringify!(_maxwds) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._sign) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_Bigint), + "::", + stringify!(_sign) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._wds) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_Bigint), + "::", + stringify!(_wds) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._x) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_Bigint), + "::", + stringify!(_x) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __tm { + pub __tm_sec: ::core::ffi::c_int, + pub __tm_min: ::core::ffi::c_int, + pub __tm_hour: ::core::ffi::c_int, + pub __tm_mday: ::core::ffi::c_int, + pub __tm_mon: ::core::ffi::c_int, + pub __tm_year: ::core::ffi::c_int, + pub __tm_wday: ::core::ffi::c_int, + pub __tm_yday: ::core::ffi::c_int, + pub __tm_isdst: ::core::ffi::c_int, +} +#[test] +fn bindgen_test_layout___tm() { + const UNINIT: ::core::mem::MaybeUninit<__tm> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<__tm>(), + 36usize, + concat!("Size of: ", stringify!(__tm)) + ); + assert_eq!( + ::core::mem::align_of::<__tm>(), + 4usize, + concat!("Alignment of ", stringify!(__tm)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__tm_sec) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__tm), + "::", + stringify!(__tm_sec) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__tm_min) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(__tm), + "::", + stringify!(__tm_min) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__tm_hour) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__tm), + "::", + stringify!(__tm_hour) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__tm_mday) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(__tm), + "::", + stringify!(__tm_mday) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__tm_mon) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__tm), + "::", + stringify!(__tm_mon) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__tm_year) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(__tm), + "::", + stringify!(__tm_year) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__tm_wday) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(__tm), + "::", + stringify!(__tm_wday) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__tm_yday) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(__tm), + "::", + stringify!(__tm_yday) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__tm_isdst) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(__tm), + "::", + stringify!(__tm_isdst) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _on_exit_args { + pub _fnargs: [*mut ::core::ffi::c_void; 32usize], + pub _dso_handle: [*mut ::core::ffi::c_void; 32usize], + pub _fntypes: __ULong, + pub _is_cxa: __ULong, +} +#[test] +fn bindgen_test_layout__on_exit_args() { + const UNINIT: ::core::mem::MaybeUninit<_on_exit_args> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_on_exit_args>(), + 264usize, + concat!("Size of: ", stringify!(_on_exit_args)) + ); + assert_eq!( + ::core::mem::align_of::<_on_exit_args>(), + 4usize, + concat!("Alignment of ", stringify!(_on_exit_args)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._fnargs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_on_exit_args), + "::", + stringify!(_fnargs) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._dso_handle) as usize - ptr as usize }, + 128usize, + concat!( + "Offset of field: ", + stringify!(_on_exit_args), + "::", + stringify!(_dso_handle) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._fntypes) as usize - ptr as usize }, + 256usize, + concat!( + "Offset of field: ", + stringify!(_on_exit_args), + "::", + stringify!(_fntypes) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._is_cxa) as usize - ptr as usize }, + 260usize, + concat!( + "Offset of field: ", + stringify!(_on_exit_args), + "::", + stringify!(_is_cxa) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _atexit { + pub _next: *mut _atexit, + pub _ind: ::core::ffi::c_int, + pub _fns: [::core::option::Option; 32usize], + pub _on_exit_args: _on_exit_args, +} +#[test] +fn bindgen_test_layout__atexit() { + const UNINIT: ::core::mem::MaybeUninit<_atexit> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_atexit>(), + 400usize, + concat!("Size of: ", stringify!(_atexit)) + ); + assert_eq!( + ::core::mem::align_of::<_atexit>(), + 4usize, + concat!("Alignment of ", stringify!(_atexit)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._next) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_atexit), + "::", + stringify!(_next) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._ind) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_atexit), + "::", + stringify!(_ind) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._fns) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_atexit), + "::", + stringify!(_fns) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._on_exit_args) as usize - ptr as usize }, + 136usize, + concat!( + "Offset of field: ", + stringify!(_atexit), + "::", + stringify!(_on_exit_args) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __sbuf { + pub _base: *mut ::core::ffi::c_uchar, + pub _size: ::core::ffi::c_int, +} +#[test] +fn bindgen_test_layout___sbuf() { + const UNINIT: ::core::mem::MaybeUninit<__sbuf> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<__sbuf>(), + 8usize, + concat!("Size of: ", stringify!(__sbuf)) + ); + assert_eq!( + ::core::mem::align_of::<__sbuf>(), + 4usize, + concat!("Alignment of ", stringify!(__sbuf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._base) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__sbuf), + "::", + stringify!(_base) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._size) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(__sbuf), + "::", + stringify!(_size) + ) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct __sFILE { + pub _p: *mut ::core::ffi::c_uchar, + pub _r: ::core::ffi::c_int, + pub _w: ::core::ffi::c_int, + pub _flags: ::core::ffi::c_short, + pub _file: ::core::ffi::c_short, + pub _bf: __sbuf, + pub _lbfsize: ::core::ffi::c_int, + pub _cookie: *mut ::core::ffi::c_void, + pub _read: ::core::option::Option< + unsafe extern "C" fn( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_void, + arg3: *mut ::core::ffi::c_char, + arg4: ::core::ffi::c_int, + ) -> ::core::ffi::c_int, + >, + pub _write: ::core::option::Option< + unsafe extern "C" fn( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_void, + arg3: *const ::core::ffi::c_char, + arg4: ::core::ffi::c_int, + ) -> ::core::ffi::c_int, + >, + pub _seek: ::core::option::Option< + unsafe extern "C" fn( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_void, + arg3: _fpos_t, + arg4: ::core::ffi::c_int, + ) -> _fpos_t, + >, + pub _close: ::core::option::Option< + unsafe extern "C" fn( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_void, + ) -> ::core::ffi::c_int, + >, + pub _ub: __sbuf, + pub _up: *mut ::core::ffi::c_uchar, + pub _ur: ::core::ffi::c_int, + pub _ubuf: [::core::ffi::c_uchar; 3usize], + pub _nbuf: [::core::ffi::c_uchar; 1usize], + pub _lb: __sbuf, + pub _blksize: ::core::ffi::c_int, + pub _offset: _off_t, + pub _data: *mut _reent, + pub _lock: _flock_t, + pub _mbstate: _mbstate_t, + pub _flags2: ::core::ffi::c_int, +} +#[test] +fn bindgen_test_layout___sFILE() { + const UNINIT: ::core::mem::MaybeUninit<__sFILE> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<__sFILE>(), + 104usize, + concat!("Size of: ", stringify!(__sFILE)) + ); + assert_eq!( + ::core::mem::align_of::<__sFILE>(), + 4usize, + concat!("Alignment of ", stringify!(__sFILE)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._p) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_p) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._r) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_r) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._w) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_w) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._flags) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_flags) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._file) as usize - ptr as usize }, + 14usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_file) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._bf) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_bf) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._lbfsize) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_lbfsize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._cookie) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_cookie) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._read) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_read) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._write) as usize - ptr as usize }, + 36usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_write) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._seek) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_seek) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._close) as usize - ptr as usize }, + 44usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_close) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._ub) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_ub) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._up) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_up) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._ur) as usize - ptr as usize }, + 60usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_ur) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._ubuf) as usize - ptr as usize }, + 64usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_ubuf) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._nbuf) as usize - ptr as usize }, + 67usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_nbuf) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._lb) as usize - ptr as usize }, + 68usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_lb) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._blksize) as usize - ptr as usize }, + 76usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_blksize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._offset) as usize - ptr as usize }, + 80usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_offset) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._data) as usize - ptr as usize }, + 84usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_data) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._lock) as usize - ptr as usize }, + 88usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_lock) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._mbstate) as usize - ptr as usize }, + 92usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_mbstate) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._flags2) as usize - ptr as usize }, + 100usize, + concat!( + "Offset of field: ", + stringify!(__sFILE), + "::", + stringify!(_flags2) + ) + ); +} +pub type __FILE = __sFILE; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _glue { + pub _next: *mut _glue, + pub _niobs: ::core::ffi::c_int, + pub _iobs: *mut __FILE, +} +#[test] +fn bindgen_test_layout__glue() { + const UNINIT: ::core::mem::MaybeUninit<_glue> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_glue>(), + 12usize, + concat!("Size of: ", stringify!(_glue)) + ); + assert_eq!( + ::core::mem::align_of::<_glue>(), + 4usize, + concat!("Alignment of ", stringify!(_glue)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._next) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_glue), + "::", + stringify!(_next) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._niobs) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_glue), + "::", + stringify!(_niobs) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._iobs) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_glue), + "::", + stringify!(_iobs) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _rand48 { + pub _seed: [::core::ffi::c_ushort; 3usize], + pub _mult: [::core::ffi::c_ushort; 3usize], + pub _add: ::core::ffi::c_ushort, +} +#[test] +fn bindgen_test_layout__rand48() { + const UNINIT: ::core::mem::MaybeUninit<_rand48> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_rand48>(), + 14usize, + concat!("Size of: ", stringify!(_rand48)) + ); + assert_eq!( + ::core::mem::align_of::<_rand48>(), + 2usize, + concat!("Alignment of ", stringify!(_rand48)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._seed) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_rand48), + "::", + stringify!(_seed) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._mult) as usize - ptr as usize }, + 6usize, + concat!( + "Offset of field: ", + stringify!(_rand48), + "::", + stringify!(_mult) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._add) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_rand48), + "::", + stringify!(_add) + ) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct _reent { + pub _errno: ::core::ffi::c_int, + pub _stdin: *mut __FILE, + pub _stdout: *mut __FILE, + pub _stderr: *mut __FILE, + pub _inc: ::core::ffi::c_int, + pub _emergency: [::core::ffi::c_char; 25usize], + pub _unspecified_locale_info: ::core::ffi::c_int, + pub _locale: *mut __locale_t, + pub __sdidinit: ::core::ffi::c_int, + pub __cleanup: ::core::option::Option, + pub _result: *mut _Bigint, + pub _result_k: ::core::ffi::c_int, + pub _p5s: *mut _Bigint, + pub _freelist: *mut *mut _Bigint, + pub _cvtlen: ::core::ffi::c_int, + pub _cvtbuf: *mut ::core::ffi::c_char, + pub _new: _reent__bindgen_ty_1, + pub _atexit: *mut _atexit, + pub _atexit0: _atexit, + pub _sig_func: *mut ::core::option::Option, + pub __sglue: _glue, + pub __sf: [__FILE; 3usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union _reent__bindgen_ty_1 { + pub _reent: _reent__bindgen_ty_1__bindgen_ty_1, + pub _unused: _reent__bindgen_ty_1__bindgen_ty_2, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct _reent__bindgen_ty_1__bindgen_ty_1 { + pub _unused_rand: ::core::ffi::c_uint, + pub _strtok_last: *mut ::core::ffi::c_char, + pub _asctime_buf: [::core::ffi::c_char; 26usize], + pub _localtime_buf: __tm, + pub _gamma_signgam: ::core::ffi::c_int, + pub _rand_next: ::core::ffi::c_ulonglong, + pub _r48: _rand48, + pub _mblen_state: _mbstate_t, + pub _mbtowc_state: _mbstate_t, + pub _wctomb_state: _mbstate_t, + pub _l64a_buf: [::core::ffi::c_char; 8usize], + pub _signal_buf: [::core::ffi::c_char; 24usize], + pub _getdate_err: ::core::ffi::c_int, + pub _mbrlen_state: _mbstate_t, + pub _mbrtowc_state: _mbstate_t, + pub _mbsrtowcs_state: _mbstate_t, + pub _wcrtomb_state: _mbstate_t, + pub _wcsrtombs_state: _mbstate_t, + pub _h_errno: ::core::ffi::c_int, +} +#[test] +fn bindgen_test_layout__reent__bindgen_ty_1__bindgen_ty_1() { + const UNINIT: ::core::mem::MaybeUninit<_reent__bindgen_ty_1__bindgen_ty_1> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_reent__bindgen_ty_1__bindgen_ty_1>(), + 208usize, + concat!("Size of: ", stringify!(_reent__bindgen_ty_1__bindgen_ty_1)) + ); + assert_eq!( + ::core::mem::align_of::<_reent__bindgen_ty_1__bindgen_ty_1>(), + 8usize, + concat!( + "Alignment of ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._unused_rand) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_unused_rand) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._strtok_last) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_strtok_last) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._asctime_buf) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_asctime_buf) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._localtime_buf) as usize - ptr as usize }, + 36usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_localtime_buf) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._gamma_signgam) as usize - ptr as usize }, + 72usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_gamma_signgam) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._rand_next) as usize - ptr as usize }, + 80usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_rand_next) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._r48) as usize - ptr as usize }, + 88usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_r48) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._mblen_state) as usize - ptr as usize }, + 104usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_mblen_state) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._mbtowc_state) as usize - ptr as usize }, + 112usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_mbtowc_state) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._wctomb_state) as usize - ptr as usize }, + 120usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_wctomb_state) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._l64a_buf) as usize - ptr as usize }, + 128usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_l64a_buf) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._signal_buf) as usize - ptr as usize }, + 136usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_signal_buf) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._getdate_err) as usize - ptr as usize }, + 160usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_getdate_err) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._mbrlen_state) as usize - ptr as usize }, + 164usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_mbrlen_state) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._mbrtowc_state) as usize - ptr as usize }, + 172usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_mbrtowc_state) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._mbsrtowcs_state) as usize - ptr as usize }, + 180usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_mbsrtowcs_state) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._wcrtomb_state) as usize - ptr as usize }, + 188usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_wcrtomb_state) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._wcsrtombs_state) as usize - ptr as usize }, + 196usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_wcsrtombs_state) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._h_errno) as usize - ptr as usize }, + 204usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(_h_errno) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _reent__bindgen_ty_1__bindgen_ty_2 { + pub _nextf: [*mut ::core::ffi::c_uchar; 30usize], + pub _nmalloc: [::core::ffi::c_uint; 30usize], +} +#[test] +fn bindgen_test_layout__reent__bindgen_ty_1__bindgen_ty_2() { + const UNINIT: ::core::mem::MaybeUninit<_reent__bindgen_ty_1__bindgen_ty_2> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_reent__bindgen_ty_1__bindgen_ty_2>(), + 240usize, + concat!("Size of: ", stringify!(_reent__bindgen_ty_1__bindgen_ty_2)) + ); + assert_eq!( + ::core::mem::align_of::<_reent__bindgen_ty_1__bindgen_ty_2>(), + 4usize, + concat!( + "Alignment of ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_2) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._nextf) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_2), + "::", + stringify!(_nextf) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._nmalloc) as usize - ptr as usize }, + 120usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1__bindgen_ty_2), + "::", + stringify!(_nmalloc) + ) + ); +} +#[test] +fn bindgen_test_layout__reent__bindgen_ty_1() { + const UNINIT: ::core::mem::MaybeUninit<_reent__bindgen_ty_1> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_reent__bindgen_ty_1>(), + 240usize, + concat!("Size of: ", stringify!(_reent__bindgen_ty_1)) + ); + assert_eq!( + ::core::mem::align_of::<_reent__bindgen_ty_1>(), + 8usize, + concat!("Alignment of ", stringify!(_reent__bindgen_ty_1)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._reent) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1), + "::", + stringify!(_reent) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._unused) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_reent__bindgen_ty_1), + "::", + stringify!(_unused) + ) + ); +} +#[test] +fn bindgen_test_layout__reent() { + const UNINIT: ::core::mem::MaybeUninit<_reent> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_reent>(), + 1064usize, + concat!("Size of: ", stringify!(_reent)) + ); + assert_eq!( + ::core::mem::align_of::<_reent>(), + 8usize, + concat!("Alignment of ", stringify!(_reent)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._errno) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_errno) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._stdin) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_stdin) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._stdout) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_stdout) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._stderr) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_stderr) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._inc) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_inc) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._emergency) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_emergency) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._unspecified_locale_info) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_unspecified_locale_info) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._locale) as usize - ptr as usize }, + 52usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_locale) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__sdidinit) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(__sdidinit) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__cleanup) as usize - ptr as usize }, + 60usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(__cleanup) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._result) as usize - ptr as usize }, + 64usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_result) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._result_k) as usize - ptr as usize }, + 68usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_result_k) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._p5s) as usize - ptr as usize }, + 72usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_p5s) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._freelist) as usize - ptr as usize }, + 76usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_freelist) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._cvtlen) as usize - ptr as usize }, + 80usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_cvtlen) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._cvtbuf) as usize - ptr as usize }, + 84usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_cvtbuf) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._new) as usize - ptr as usize }, + 88usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_new) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._atexit) as usize - ptr as usize }, + 328usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_atexit) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._atexit0) as usize - ptr as usize }, + 332usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_atexit0) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr)._sig_func) as usize - ptr as usize }, + 732usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(_sig_func) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__sglue) as usize - ptr as usize }, + 736usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(__sglue) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__sf) as usize - ptr as usize }, + 748usize, + concat!( + "Offset of field: ", + stringify!(_reent), + "::", + stringify!(__sf) + ) + ); +} +extern "C" { + pub static mut _impure_ptr: *mut _reent; +} +extern "C" { + pub static _global_impure_ptr: *mut _reent; +} +extern "C" { + pub fn _reclaim_reent(arg1: *mut _reent); +} +extern "C" { + pub fn __errno() -> *mut ::core::ffi::c_int; +} +extern "C" { + pub static _sys_errlist: [*const ::core::ffi::c_char; 0usize]; +} +extern "C" { + pub static mut _sys_nerr: ::core::ffi::c_int; +} +pub type intmax_t = __intmax_t; +pub type uintmax_t = __uintmax_t; +pub type int_least8_t = __int_least8_t; +pub type uint_least8_t = __uint_least8_t; +pub type int_least16_t = __int_least16_t; +pub type uint_least16_t = __uint_least16_t; +pub type int_least32_t = __int_least32_t; +pub type uint_least32_t = __uint_least32_t; +pub type int_least64_t = __int_least64_t; +pub type uint_least64_t = __uint_least64_t; +pub type int_fast8_t = ::core::ffi::c_schar; +pub type uint_fast8_t = ::core::ffi::c_uchar; +pub type int_fast16_t = ::core::ffi::c_short; +pub type uint_fast16_t = ::core::ffi::c_ushort; +pub type int_fast32_t = ::core::ffi::c_int; +pub type uint_fast32_t = ::core::ffi::c_uint; +pub type int_fast64_t = ::core::ffi::c_longlong; +pub type uint_fast64_t = ::core::ffi::c_ulonglong; +pub type locale_t = *mut __locale_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct imaxdiv_t { + pub quot: intmax_t, + pub rem: intmax_t, +} +#[test] +fn bindgen_test_layout_imaxdiv_t() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(imaxdiv_t)) + ); + assert_eq!( + ::core::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(imaxdiv_t)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).quot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(imaxdiv_t), + "::", + stringify!(quot) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).rem) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(imaxdiv_t), + "::", + stringify!(rem) + ) + ); +} +extern "C" { + pub fn imaxabs(arg1: intmax_t) -> intmax_t; +} +extern "C" { + pub fn imaxdiv(__numer: intmax_t, __denomer: intmax_t) -> imaxdiv_t; +} +extern "C" { + pub fn strtoimax( + arg1: *const ::core::ffi::c_char, + arg2: *mut *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + ) -> intmax_t; +} +extern "C" { + pub fn _strtoimax_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *mut *mut ::core::ffi::c_char, + arg4: ::core::ffi::c_int, + ) -> intmax_t; +} +extern "C" { + pub fn strtoumax( + arg1: *const ::core::ffi::c_char, + arg2: *mut *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + ) -> uintmax_t; +} +extern "C" { + pub fn _strtoumax_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *mut *mut ::core::ffi::c_char, + arg4: ::core::ffi::c_int, + ) -> uintmax_t; +} +extern "C" { + pub fn wcstoimax( + arg1: *const wchar_t, + arg2: *mut *mut wchar_t, + arg3: ::core::ffi::c_int, + ) -> intmax_t; +} +extern "C" { + pub fn _wcstoimax_r( + arg1: *mut _reent, + arg2: *const wchar_t, + arg3: *mut *mut wchar_t, + arg4: ::core::ffi::c_int, + ) -> intmax_t; +} +extern "C" { + pub fn wcstoumax( + arg1: *const wchar_t, + arg2: *mut *mut wchar_t, + arg3: ::core::ffi::c_int, + ) -> uintmax_t; +} +extern "C" { + pub fn _wcstoumax_r( + arg1: *mut _reent, + arg2: *const wchar_t, + arg3: *mut *mut wchar_t, + arg4: ::core::ffi::c_int, + ) -> uintmax_t; +} +extern "C" { + pub fn strtoimax_l( + arg1: *const ::core::ffi::c_char, + _restrict: *mut *mut ::core::ffi::c_char, + arg2: ::core::ffi::c_int, + arg3: locale_t, + ) -> intmax_t; +} +extern "C" { + pub fn strtoumax_l( + arg1: *const ::core::ffi::c_char, + _restrict: *mut *mut ::core::ffi::c_char, + arg2: ::core::ffi::c_int, + arg3: locale_t, + ) -> uintmax_t; +} +extern "C" { + pub fn wcstoimax_l( + arg1: *const wchar_t, + _restrict: *mut *mut wchar_t, + arg2: ::core::ffi::c_int, + arg3: locale_t, + ) -> intmax_t; +} +extern "C" { + pub fn wcstoumax_l( + arg1: *const wchar_t, + _restrict: *mut *mut wchar_t, + arg2: ::core::ffi::c_int, + arg3: locale_t, + ) -> uintmax_t; +} +extern "C" { + pub fn atan(arg1: f64) -> f64; +} +extern "C" { + pub fn cos(arg1: f64) -> f64; +} +extern "C" { + pub fn sin(arg1: f64) -> f64; +} +extern "C" { + pub fn tan(arg1: f64) -> f64; +} +extern "C" { + pub fn tanh(arg1: f64) -> f64; +} +extern "C" { + pub fn frexp(arg1: f64, arg2: *mut ::core::ffi::c_int) -> f64; +} +extern "C" { + pub fn modf(arg1: f64, arg2: *mut f64) -> f64; +} +extern "C" { + pub fn ceil(arg1: f64) -> f64; +} +extern "C" { + pub fn fabs(arg1: f64) -> f64; +} +extern "C" { + pub fn floor(arg1: f64) -> f64; +} +extern "C" { + pub fn acos(arg1: f64) -> f64; +} +extern "C" { + pub fn asin(arg1: f64) -> f64; +} +extern "C" { + pub fn atan2(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn cosh(arg1: f64) -> f64; +} +extern "C" { + pub fn sinh(arg1: f64) -> f64; +} +extern "C" { + pub fn exp(arg1: f64) -> f64; +} +extern "C" { + pub fn ldexp(arg1: f64, arg2: ::core::ffi::c_int) -> f64; +} +extern "C" { + pub fn log(arg1: f64) -> f64; +} +extern "C" { + pub fn log10(arg1: f64) -> f64; +} +extern "C" { + pub fn pow(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn sqrt(arg1: f64) -> f64; +} +extern "C" { + pub fn fmod(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn finite(arg1: f64) -> ::core::ffi::c_int; +} +extern "C" { + pub fn finitef(arg1: f32) -> ::core::ffi::c_int; +} +extern "C" { + pub fn finitel(arg1: f64) -> ::core::ffi::c_int; +} +extern "C" { + pub fn isinff(arg1: f32) -> ::core::ffi::c_int; +} +extern "C" { + pub fn isnanf(arg1: f32) -> ::core::ffi::c_int; +} +extern "C" { + pub fn isinf(arg1: f64) -> ::core::ffi::c_int; +} +extern "C" { + pub fn isnan(arg1: f64) -> ::core::ffi::c_int; +} +pub type float_t = f32; +pub type double_t = f64; +extern "C" { + pub fn __isinff(arg1: f32) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __isinfd(arg1: f64) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __isnanf(arg1: f32) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __isnand(arg1: f64) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __fpclassifyf(arg1: f32) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __fpclassifyd(arg1: f64) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __signbitf(arg1: f32) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __signbitd(arg1: f64) -> ::core::ffi::c_int; +} +extern "C" { + pub fn infinity() -> f64; +} +extern "C" { + pub fn nan(arg1: *const ::core::ffi::c_char) -> f64; +} +extern "C" { + pub fn copysign(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn logb(arg1: f64) -> f64; +} +extern "C" { + pub fn ilogb(arg1: f64) -> ::core::ffi::c_int; +} +extern "C" { + pub fn asinh(arg1: f64) -> f64; +} +extern "C" { + pub fn cbrt(arg1: f64) -> f64; +} +extern "C" { + pub fn nextafter(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn rint(arg1: f64) -> f64; +} +extern "C" { + pub fn scalbn(arg1: f64, arg2: ::core::ffi::c_int) -> f64; +} +extern "C" { + pub fn exp2(arg1: f64) -> f64; +} +extern "C" { + pub fn scalbln(arg1: f64, arg2: ::core::ffi::c_long) -> f64; +} +extern "C" { + pub fn tgamma(arg1: f64) -> f64; +} +extern "C" { + pub fn nearbyint(arg1: f64) -> f64; +} +extern "C" { + pub fn lrint(arg1: f64) -> ::core::ffi::c_long; +} +extern "C" { + pub fn llrint(arg1: f64) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn round(arg1: f64) -> f64; +} +extern "C" { + pub fn lround(arg1: f64) -> ::core::ffi::c_long; +} +extern "C" { + pub fn llround(arg1: f64) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn trunc(arg1: f64) -> f64; +} +extern "C" { + pub fn remquo(arg1: f64, arg2: f64, arg3: *mut ::core::ffi::c_int) -> f64; +} +extern "C" { + pub fn fdim(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn fmax(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn fmin(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn fma(arg1: f64, arg2: f64, arg3: f64) -> f64; +} +extern "C" { + pub fn log1p(arg1: f64) -> f64; +} +extern "C" { + pub fn expm1(arg1: f64) -> f64; +} +extern "C" { + pub fn acosh(arg1: f64) -> f64; +} +extern "C" { + pub fn atanh(arg1: f64) -> f64; +} +extern "C" { + pub fn remainder(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn gamma(arg1: f64) -> f64; +} +extern "C" { + pub fn lgamma(arg1: f64) -> f64; +} +extern "C" { + pub fn erf(arg1: f64) -> f64; +} +extern "C" { + pub fn erfc(arg1: f64) -> f64; +} +extern "C" { + pub fn log2(arg1: f64) -> f64; +} +extern "C" { + pub fn hypot(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn atanf(arg1: f32) -> f32; +} +extern "C" { + pub fn cosf(arg1: f32) -> f32; +} +extern "C" { + pub fn sinf(arg1: f32) -> f32; +} +extern "C" { + pub fn tanf(arg1: f32) -> f32; +} +extern "C" { + pub fn tanhf(arg1: f32) -> f32; +} +extern "C" { + pub fn frexpf(arg1: f32, arg2: *mut ::core::ffi::c_int) -> f32; +} +extern "C" { + pub fn modff(arg1: f32, arg2: *mut f32) -> f32; +} +extern "C" { + pub fn ceilf(arg1: f32) -> f32; +} +extern "C" { + pub fn fabsf(arg1: f32) -> f32; +} +extern "C" { + pub fn floorf(arg1: f32) -> f32; +} +extern "C" { + pub fn acosf(arg1: f32) -> f32; +} +extern "C" { + pub fn asinf(arg1: f32) -> f32; +} +extern "C" { + pub fn atan2f(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn coshf(arg1: f32) -> f32; +} +extern "C" { + pub fn sinhf(arg1: f32) -> f32; +} +extern "C" { + pub fn expf(arg1: f32) -> f32; +} +extern "C" { + pub fn ldexpf(arg1: f32, arg2: ::core::ffi::c_int) -> f32; +} +extern "C" { + pub fn logf(arg1: f32) -> f32; +} +extern "C" { + pub fn log10f(arg1: f32) -> f32; +} +extern "C" { + pub fn powf(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn sqrtf(arg1: f32) -> f32; +} +extern "C" { + pub fn fmodf(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn exp2f(arg1: f32) -> f32; +} +extern "C" { + pub fn scalblnf(arg1: f32, arg2: ::core::ffi::c_long) -> f32; +} +extern "C" { + pub fn tgammaf(arg1: f32) -> f32; +} +extern "C" { + pub fn nearbyintf(arg1: f32) -> f32; +} +extern "C" { + pub fn lrintf(arg1: f32) -> ::core::ffi::c_long; +} +extern "C" { + pub fn llrintf(arg1: f32) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn roundf(arg1: f32) -> f32; +} +extern "C" { + pub fn lroundf(arg1: f32) -> ::core::ffi::c_long; +} +extern "C" { + pub fn llroundf(arg1: f32) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn truncf(arg1: f32) -> f32; +} +extern "C" { + pub fn remquof(arg1: f32, arg2: f32, arg3: *mut ::core::ffi::c_int) -> f32; +} +extern "C" { + pub fn fdimf(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn fmaxf(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn fminf(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn fmaf(arg1: f32, arg2: f32, arg3: f32) -> f32; +} +extern "C" { + pub fn infinityf() -> f32; +} +extern "C" { + pub fn nanf(arg1: *const ::core::ffi::c_char) -> f32; +} +extern "C" { + pub fn copysignf(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn logbf(arg1: f32) -> f32; +} +extern "C" { + pub fn ilogbf(arg1: f32) -> ::core::ffi::c_int; +} +extern "C" { + pub fn asinhf(arg1: f32) -> f32; +} +extern "C" { + pub fn cbrtf(arg1: f32) -> f32; +} +extern "C" { + pub fn nextafterf(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn rintf(arg1: f32) -> f32; +} +extern "C" { + pub fn scalbnf(arg1: f32, arg2: ::core::ffi::c_int) -> f32; +} +extern "C" { + pub fn log1pf(arg1: f32) -> f32; +} +extern "C" { + pub fn expm1f(arg1: f32) -> f32; +} +extern "C" { + pub fn acoshf(arg1: f32) -> f32; +} +extern "C" { + pub fn atanhf(arg1: f32) -> f32; +} +extern "C" { + pub fn remainderf(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn gammaf(arg1: f32) -> f32; +} +extern "C" { + pub fn lgammaf(arg1: f32) -> f32; +} +extern "C" { + pub fn erff(arg1: f32) -> f32; +} +extern "C" { + pub fn erfcf(arg1: f32) -> f32; +} +extern "C" { + pub fn log2f(arg1: f32) -> f32; +} +extern "C" { + pub fn hypotf(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn atanl(arg1: f64) -> f64; +} +extern "C" { + pub fn cosl(arg1: f64) -> f64; +} +extern "C" { + pub fn sinl(arg1: f64) -> f64; +} +extern "C" { + pub fn tanl(arg1: f64) -> f64; +} +extern "C" { + pub fn tanhl(arg1: f64) -> f64; +} +extern "C" { + pub fn frexpl(arg1: f64, arg2: *mut ::core::ffi::c_int) -> f64; +} +extern "C" { + pub fn modfl(arg1: f64, arg2: *mut f64) -> f64; +} +extern "C" { + pub fn ceill(arg1: f64) -> f64; +} +extern "C" { + pub fn fabsl(arg1: f64) -> f64; +} +extern "C" { + pub fn floorl(arg1: f64) -> f64; +} +extern "C" { + pub fn log1pl(arg1: f64) -> f64; +} +extern "C" { + pub fn expm1l(arg1: f64) -> f64; +} +extern "C" { + pub fn acosl(arg1: f64) -> f64; +} +extern "C" { + pub fn asinl(arg1: f64) -> f64; +} +extern "C" { + pub fn atan2l(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn coshl(arg1: f64) -> f64; +} +extern "C" { + pub fn sinhl(arg1: f64) -> f64; +} +extern "C" { + pub fn expl(arg1: f64) -> f64; +} +extern "C" { + pub fn ldexpl(arg1: f64, arg2: ::core::ffi::c_int) -> f64; +} +extern "C" { + pub fn logl(arg1: f64) -> f64; +} +extern "C" { + pub fn log10l(arg1: f64) -> f64; +} +extern "C" { + pub fn powl(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn sqrtl(arg1: f64) -> f64; +} +extern "C" { + pub fn fmodl(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn hypotl(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn copysignl(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn nanl(arg1: *const ::core::ffi::c_char) -> f64; +} +extern "C" { + pub fn ilogbl(arg1: f64) -> ::core::ffi::c_int; +} +extern "C" { + pub fn asinhl(arg1: f64) -> f64; +} +extern "C" { + pub fn cbrtl(arg1: f64) -> f64; +} +extern "C" { + pub fn nextafterl(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn nexttowardf(arg1: f32, arg2: f64) -> f32; +} +extern "C" { + pub fn nexttoward(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn nexttowardl(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn logbl(arg1: f64) -> f64; +} +extern "C" { + pub fn log2l(arg1: f64) -> f64; +} +extern "C" { + pub fn rintl(arg1: f64) -> f64; +} +extern "C" { + pub fn scalbnl(arg1: f64, arg2: ::core::ffi::c_int) -> f64; +} +extern "C" { + pub fn exp2l(arg1: f64) -> f64; +} +extern "C" { + pub fn scalblnl(arg1: f64, arg2: ::core::ffi::c_long) -> f64; +} +extern "C" { + pub fn tgammal(arg1: f64) -> f64; +} +extern "C" { + pub fn nearbyintl(arg1: f64) -> f64; +} +extern "C" { + pub fn lrintl(arg1: f64) -> ::core::ffi::c_long; +} +extern "C" { + pub fn llrintl(arg1: f64) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn roundl(arg1: f64) -> f64; +} +extern "C" { + pub fn lroundl(arg1: f64) -> ::core::ffi::c_long; +} +extern "C" { + pub fn llroundl(arg1: f64) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn truncl(arg1: f64) -> f64; +} +extern "C" { + pub fn remquol(arg1: f64, arg2: f64, arg3: *mut ::core::ffi::c_int) -> f64; +} +extern "C" { + pub fn fdiml(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn fmaxl(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn fminl(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn fmal(arg1: f64, arg2: f64, arg3: f64) -> f64; +} +extern "C" { + pub fn acoshl(arg1: f64) -> f64; +} +extern "C" { + pub fn atanhl(arg1: f64) -> f64; +} +extern "C" { + pub fn remainderl(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn lgammal(arg1: f64) -> f64; +} +extern "C" { + pub fn erfl(arg1: f64) -> f64; +} +extern "C" { + pub fn erfcl(arg1: f64) -> f64; +} +extern "C" { + pub fn drem(arg1: f64, arg2: f64) -> f64; +} +extern "C" { + pub fn dremf(arg1: f32, arg2: f32) -> f32; +} +extern "C" { + pub fn gamma_r(arg1: f64, arg2: *mut ::core::ffi::c_int) -> f64; +} +extern "C" { + pub fn lgamma_r(arg1: f64, arg2: *mut ::core::ffi::c_int) -> f64; +} +extern "C" { + pub fn gammaf_r(arg1: f32, arg2: *mut ::core::ffi::c_int) -> f32; +} +extern "C" { + pub fn lgammaf_r(arg1: f32, arg2: *mut ::core::ffi::c_int) -> f32; +} +extern "C" { + pub fn y0(arg1: f64) -> f64; +} +extern "C" { + pub fn y1(arg1: f64) -> f64; +} +extern "C" { + pub fn yn(arg1: ::core::ffi::c_int, arg2: f64) -> f64; +} +extern "C" { + pub fn j0(arg1: f64) -> f64; +} +extern "C" { + pub fn j1(arg1: f64) -> f64; +} +extern "C" { + pub fn jn(arg1: ::core::ffi::c_int, arg2: f64) -> f64; +} +extern "C" { + pub fn y0f(arg1: f32) -> f32; +} +extern "C" { + pub fn y1f(arg1: f32) -> f32; +} +extern "C" { + pub fn ynf(arg1: ::core::ffi::c_int, arg2: f32) -> f32; +} +extern "C" { + pub fn j0f(arg1: f32) -> f32; +} +extern "C" { + pub fn j1f(arg1: f32) -> f32; +} +extern "C" { + pub fn jnf(arg1: ::core::ffi::c_int, arg2: f32) -> f32; +} +extern "C" { + pub fn __signgam() -> *mut ::core::ffi::c_int; +} +pub type va_list = u32; +pub type __gnuc_va_list = u32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct div_t { + pub quot: ::core::ffi::c_int, + pub rem: ::core::ffi::c_int, +} +#[test] +fn bindgen_test_layout_div_t() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(div_t)) + ); + assert_eq!( + ::core::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(div_t)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).quot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(div_t), + "::", + stringify!(quot) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).rem) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(div_t), + "::", + stringify!(rem) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ldiv_t { + pub quot: ::core::ffi::c_long, + pub rem: ::core::ffi::c_long, +} +#[test] +fn bindgen_test_layout_ldiv_t() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(ldiv_t)) + ); + assert_eq!( + ::core::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(ldiv_t)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).quot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(ldiv_t), + "::", + stringify!(quot) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).rem) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(ldiv_t), + "::", + stringify!(rem) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct lldiv_t { + pub quot: ::core::ffi::c_longlong, + pub rem: ::core::ffi::c_longlong, +} +#[test] +fn bindgen_test_layout_lldiv_t() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(lldiv_t)) + ); + assert_eq!( + ::core::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(lldiv_t)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).quot) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(lldiv_t), + "::", + stringify!(quot) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).rem) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(lldiv_t), + "::", + stringify!(rem) + ) + ); +} +pub type __compar_fn_t = ::core::option::Option< + unsafe extern "C" fn( + arg1: *const ::core::ffi::c_void, + arg2: *const ::core::ffi::c_void, + ) -> ::core::ffi::c_int, +>; +extern "C" { + pub fn __locale_mb_cur_max() -> ::core::ffi::c_int; +} +extern "C" { + pub fn abort() -> !; +} +extern "C" { + pub fn abs(arg1: ::core::ffi::c_int) -> ::core::ffi::c_int; +} +extern "C" { + pub fn arc4random() -> __uint32_t; +} +extern "C" { + pub fn arc4random_uniform(arg1: __uint32_t) -> __uint32_t; +} +extern "C" { + pub fn arc4random_buf(arg1: *mut ::core::ffi::c_void, arg2: usize); +} +extern "C" { + pub fn atexit(__func: ::core::option::Option) -> ::core::ffi::c_int; +} +extern "C" { + pub fn atof(__nptr: *const ::core::ffi::c_char) -> f64; +} +extern "C" { + pub fn atoff(__nptr: *const ::core::ffi::c_char) -> f32; +} +extern "C" { + pub fn atoi(__nptr: *const ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _atoi_r(arg1: *mut _reent, __nptr: *const ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn atol(__nptr: *const ::core::ffi::c_char) -> ::core::ffi::c_long; +} +extern "C" { + pub fn _atol_r(arg1: *mut _reent, __nptr: *const ::core::ffi::c_char) -> ::core::ffi::c_long; +} +extern "C" { + pub fn bsearch( + __key: *const ::core::ffi::c_void, + __base: *const ::core::ffi::c_void, + __nmemb: usize, + __size: usize, + _compar: __compar_fn_t, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn calloc(arg1: ::core::ffi::c_uint, arg2: ::core::ffi::c_uint) + -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn div(__numer: ::core::ffi::c_int, __denom: ::core::ffi::c_int) -> div_t; +} +extern "C" { + pub fn exit(__status: ::core::ffi::c_int) -> !; +} +extern "C" { + pub fn free(arg1: *mut ::core::ffi::c_void); +} +extern "C" { + pub fn getenv(__string: *const ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _getenv_r( + arg1: *mut _reent, + __string: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _findenv( + arg1: *const ::core::ffi::c_char, + arg2: *mut ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _findenv_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *mut ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub static mut suboptarg: *mut ::core::ffi::c_char; +} +extern "C" { + pub fn getsubopt( + arg1: *mut *mut ::core::ffi::c_char, + arg2: *const *mut ::core::ffi::c_char, + arg3: *mut *mut ::core::ffi::c_char, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn labs(arg1: ::core::ffi::c_long) -> ::core::ffi::c_long; +} +extern "C" { + pub fn ldiv(__numer: ::core::ffi::c_long, __denom: ::core::ffi::c_long) -> ldiv_t; +} +extern "C" { + pub fn malloc(arg1: ::core::ffi::c_uint) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn mblen(arg1: *const ::core::ffi::c_char, arg2: usize) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _mblen_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: usize, + arg4: *mut _mbstate_t, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn mbtowc( + arg1: *mut wchar_t, + arg2: *const ::core::ffi::c_char, + arg3: usize, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _mbtowc_r( + arg1: *mut _reent, + arg2: *mut wchar_t, + arg3: *const ::core::ffi::c_char, + arg4: usize, + arg5: *mut _mbstate_t, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn wctomb(arg1: *mut ::core::ffi::c_char, arg2: wchar_t) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _wctomb_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: wchar_t, + arg4: *mut _mbstate_t, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn mbstowcs(arg1: *mut wchar_t, arg2: *const ::core::ffi::c_char, arg3: usize) -> usize; +} +extern "C" { + pub fn _mbstowcs_r( + arg1: *mut _reent, + arg2: *mut wchar_t, + arg3: *const ::core::ffi::c_char, + arg4: usize, + arg5: *mut _mbstate_t, + ) -> usize; +} +extern "C" { + pub fn wcstombs(arg1: *mut ::core::ffi::c_char, arg2: *const wchar_t, arg3: usize) -> usize; +} +extern "C" { + pub fn _wcstombs_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: *const wchar_t, + arg4: usize, + arg5: *mut _mbstate_t, + ) -> usize; +} +extern "C" { + pub fn mkdtemp(arg1: *mut ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn mkstemp(arg1: *mut ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn mkstemps(arg1: *mut ::core::ffi::c_char, arg2: ::core::ffi::c_int) + -> ::core::ffi::c_int; +} +extern "C" { + pub fn mktemp(arg1: *mut ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _mkdtemp_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _mkostemp_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _mkostemps_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + arg4: ::core::ffi::c_int, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _mkstemp_r(arg1: *mut _reent, arg2: *mut ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _mkstemps_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _mktemp_r(arg1: *mut _reent, arg2: *mut ::core::ffi::c_char) + -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn qsort( + __base: *mut ::core::ffi::c_void, + __nmemb: usize, + __size: usize, + _compar: __compar_fn_t, + ); +} +extern "C" { + pub fn rand() -> ::core::ffi::c_int; +} +extern "C" { + pub fn realloc( + arg1: *mut ::core::ffi::c_void, + arg2: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn reallocarray( + arg1: *mut ::core::ffi::c_void, + arg2: usize, + arg3: usize, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn reallocf(arg1: *mut ::core::ffi::c_void, arg2: usize) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn realpath( + path: *const ::core::ffi::c_char, + resolved_path: *mut ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn rpmatch(response: *const ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn srand(__seed: ::core::ffi::c_uint); +} +extern "C" { + pub fn strtod(__n: *const ::core::ffi::c_char, __end_PTR: *mut *mut ::core::ffi::c_char) + -> f64; +} +extern "C" { + pub fn _strtod_r( + arg1: *mut _reent, + __n: *const ::core::ffi::c_char, + __end_PTR: *mut *mut ::core::ffi::c_char, + ) -> f64; +} +extern "C" { + pub fn strtof(__n: *const ::core::ffi::c_char, __end_PTR: *mut *mut ::core::ffi::c_char) + -> f32; +} +extern "C" { + pub fn strtol( + __n: *const ::core::ffi::c_char, + __end_PTR: *mut *mut ::core::ffi::c_char, + __base: ::core::ffi::c_int, + ) -> ::core::ffi::c_long; +} +extern "C" { + pub fn _strtol_r( + arg1: *mut _reent, + __n: *const ::core::ffi::c_char, + __end_PTR: *mut *mut ::core::ffi::c_char, + __base: ::core::ffi::c_int, + ) -> ::core::ffi::c_long; +} +extern "C" { + pub fn strtoul( + __n: *const ::core::ffi::c_char, + __end_PTR: *mut *mut ::core::ffi::c_char, + __base: ::core::ffi::c_int, + ) -> ::core::ffi::c_ulong; +} +extern "C" { + pub fn _strtoul_r( + arg1: *mut _reent, + __n: *const ::core::ffi::c_char, + __end_PTR: *mut *mut ::core::ffi::c_char, + __base: ::core::ffi::c_int, + ) -> ::core::ffi::c_ulong; +} +extern "C" { + pub fn system(__string: *const ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn a64l(__input: *const ::core::ffi::c_char) -> ::core::ffi::c_long; +} +extern "C" { + pub fn l64a(__input: ::core::ffi::c_long) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _l64a_r(arg1: *mut _reent, __input: ::core::ffi::c_long) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn on_exit( + __func: ::core::option::Option< + unsafe extern "C" fn(arg1: ::core::ffi::c_int, arg2: *mut ::core::ffi::c_void), + >, + __arg: *mut ::core::ffi::c_void, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _Exit(__status: ::core::ffi::c_int) -> !; +} +extern "C" { + pub fn putenv(__string: *mut ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _putenv_r(arg1: *mut _reent, __string: *mut ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _reallocf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_void, + arg3: usize, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn setenv( + __string: *const ::core::ffi::c_char, + __value: *const ::core::ffi::c_char, + __overwrite: ::core::ffi::c_int, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _setenv_r( + arg1: *mut _reent, + __string: *const ::core::ffi::c_char, + __value: *const ::core::ffi::c_char, + __overwrite: ::core::ffi::c_int, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __itoa( + arg1: ::core::ffi::c_int, + arg2: *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn __utoa( + arg1: ::core::ffi::c_uint, + arg2: *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn itoa( + arg1: ::core::ffi::c_int, + arg2: *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn utoa( + arg1: ::core::ffi::c_uint, + arg2: *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn rand_r(__seed: *mut ::core::ffi::c_uint) -> ::core::ffi::c_int; +} +extern "C" { + pub fn drand48() -> f64; +} +extern "C" { + pub fn _drand48_r(arg1: *mut _reent) -> f64; +} +extern "C" { + pub fn erand48(arg1: *mut ::core::ffi::c_ushort) -> f64; +} +extern "C" { + pub fn _erand48_r(arg1: *mut _reent, arg2: *mut ::core::ffi::c_ushort) -> f64; +} +extern "C" { + pub fn jrand48(arg1: *mut ::core::ffi::c_ushort) -> ::core::ffi::c_long; +} +extern "C" { + pub fn _jrand48_r(arg1: *mut _reent, arg2: *mut ::core::ffi::c_ushort) -> ::core::ffi::c_long; +} +extern "C" { + pub fn lcong48(arg1: *mut ::core::ffi::c_ushort); +} +extern "C" { + pub fn _lcong48_r(arg1: *mut _reent, arg2: *mut ::core::ffi::c_ushort); +} +extern "C" { + pub fn lrand48() -> ::core::ffi::c_long; +} +extern "C" { + pub fn _lrand48_r(arg1: *mut _reent) -> ::core::ffi::c_long; +} +extern "C" { + pub fn mrand48() -> ::core::ffi::c_long; +} +extern "C" { + pub fn _mrand48_r(arg1: *mut _reent) -> ::core::ffi::c_long; +} +extern "C" { + pub fn nrand48(arg1: *mut ::core::ffi::c_ushort) -> ::core::ffi::c_long; +} +extern "C" { + pub fn _nrand48_r(arg1: *mut _reent, arg2: *mut ::core::ffi::c_ushort) -> ::core::ffi::c_long; +} +extern "C" { + pub fn seed48(arg1: *mut ::core::ffi::c_ushort) -> *mut ::core::ffi::c_ushort; +} +extern "C" { + pub fn _seed48_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_ushort, + ) -> *mut ::core::ffi::c_ushort; +} +extern "C" { + pub fn srand48(arg1: ::core::ffi::c_long); +} +extern "C" { + pub fn _srand48_r(arg1: *mut _reent, arg2: ::core::ffi::c_long); +} +extern "C" { + pub fn initstate( + arg1: ::core::ffi::c_uint, + arg2: *mut ::core::ffi::c_char, + arg3: usize, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn random() -> ::core::ffi::c_long; +} +extern "C" { + pub fn setstate(arg1: *mut ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn srandom(arg1: ::core::ffi::c_uint); +} +extern "C" { + pub fn atoll(__nptr: *const ::core::ffi::c_char) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn _atoll_r( + arg1: *mut _reent, + __nptr: *const ::core::ffi::c_char, + ) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn llabs(arg1: ::core::ffi::c_longlong) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn lldiv(__numer: ::core::ffi::c_longlong, __denom: ::core::ffi::c_longlong) -> lldiv_t; +} +extern "C" { + pub fn strtoll( + __n: *const ::core::ffi::c_char, + __end_PTR: *mut *mut ::core::ffi::c_char, + __base: ::core::ffi::c_int, + ) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn _strtoll_r( + arg1: *mut _reent, + __n: *const ::core::ffi::c_char, + __end_PTR: *mut *mut ::core::ffi::c_char, + __base: ::core::ffi::c_int, + ) -> ::core::ffi::c_longlong; +} +extern "C" { + pub fn strtoull( + __n: *const ::core::ffi::c_char, + __end_PTR: *mut *mut ::core::ffi::c_char, + __base: ::core::ffi::c_int, + ) -> ::core::ffi::c_ulonglong; +} +extern "C" { + pub fn _strtoull_r( + arg1: *mut _reent, + __n: *const ::core::ffi::c_char, + __end_PTR: *mut *mut ::core::ffi::c_char, + __base: ::core::ffi::c_int, + ) -> ::core::ffi::c_ulonglong; +} +extern "C" { + pub fn cfree(arg1: *mut ::core::ffi::c_void); +} +extern "C" { + pub fn unsetenv(__string: *const ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _unsetenv_r( + arg1: *mut _reent, + __string: *const ::core::ffi::c_char, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn posix_memalign( + arg1: *mut *mut ::core::ffi::c_void, + arg2: usize, + arg3: usize, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _dtoa_r( + arg1: *mut _reent, + arg2: f64, + arg3: ::core::ffi::c_int, + arg4: ::core::ffi::c_int, + arg5: *mut ::core::ffi::c_int, + arg6: *mut ::core::ffi::c_int, + arg7: *mut *mut ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _malloc_r(arg1: *mut _reent, arg2: usize) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn _calloc_r(arg1: *mut _reent, arg2: usize, arg3: usize) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn _free_r(arg1: *mut _reent, arg2: *mut ::core::ffi::c_void); +} +extern "C" { + pub fn _realloc_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_void, + arg3: usize, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn _mstats_r(arg1: *mut _reent, arg2: *mut ::core::ffi::c_char); +} +extern "C" { + pub fn _system_r(arg1: *mut _reent, arg2: *const ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __eprintf( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: ::core::ffi::c_uint, + arg4: *const ::core::ffi::c_char, + ); +} +extern "C" { + #[link_name = "\u{1}__bsd_qsort_r"] + pub fn qsort_r( + __base: *mut ::core::ffi::c_void, + __nmemb: usize, + __size: usize, + __thunk: *mut ::core::ffi::c_void, + _compar: ::core::option::Option< + unsafe extern "C" fn( + arg1: *mut ::core::ffi::c_void, + arg2: *const ::core::ffi::c_void, + arg3: *const ::core::ffi::c_void, + ) -> ::core::ffi::c_int, + >, + ); +} +extern "C" { + pub fn _strtold_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *mut *mut ::core::ffi::c_char, + ) -> f64; +} +extern "C" { + pub fn strtold(arg1: *const ::core::ffi::c_char, arg2: *mut *mut ::core::ffi::c_char) -> f64; +} +extern "C" { + pub fn aligned_alloc( + arg1: ::core::ffi::c_uint, + arg2: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn at_quick_exit( + arg1: ::core::option::Option, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn quick_exit(arg1: ::core::ffi::c_int); +} +pub type u_int8_t = __uint8_t; +pub type u_int16_t = __uint16_t; +pub type u_int32_t = __uint32_t; +pub type u_int64_t = __uint64_t; +pub type register_t = __intptr_t; +pub type __sigset_t = ::core::ffi::c_ulong; +pub type suseconds_t = __suseconds_t; +pub type time_t = __int_least64_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct timeval { + pub tv_sec: time_t, + pub tv_usec: suseconds_t, +} +#[test] +fn bindgen_test_layout_timeval() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(timeval)) + ); + assert_eq!( + ::core::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(timeval)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tv_sec) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(timeval), + "::", + stringify!(tv_sec) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tv_usec) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(timeval), + "::", + stringify!(tv_usec) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: ::core::ffi::c_long, +} +#[test] +fn bindgen_test_layout_timespec() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(timespec)) + ); + assert_eq!( + ::core::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(timespec)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tv_sec) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(timespec), + "::", + stringify!(tv_sec) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tv_nsec) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(timespec), + "::", + stringify!(tv_nsec) + ) + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct itimerspec { + pub it_interval: timespec, + pub it_value: timespec, +} +#[test] +fn bindgen_test_layout_itimerspec() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(itimerspec)) + ); + assert_eq!( + ::core::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(itimerspec)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).it_interval) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(itimerspec), + "::", + stringify!(it_interval) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).it_value) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(itimerspec), + "::", + stringify!(it_value) + ) + ); +} +pub type sigset_t = __sigset_t; +pub type __fd_mask = ::core::ffi::c_ulong; +pub type fd_mask = __fd_mask; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct fd_set { + pub __fds_bits: [__fd_mask; 2usize], +} +#[test] +fn bindgen_test_layout_fd_set() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(fd_set)) + ); + assert_eq!( + ::core::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(fd_set)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).__fds_bits) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(fd_set), + "::", + stringify!(__fds_bits) + ) + ); +} +extern "C" { + pub fn select( + __n: ::core::ffi::c_int, + __readfds: *mut fd_set, + __writefds: *mut fd_set, + __exceptfds: *mut fd_set, + __timeout: *mut timeval, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn pselect( + __n: ::core::ffi::c_int, + __readfds: *mut fd_set, + __writefds: *mut fd_set, + __exceptfds: *mut fd_set, + __timeout: *const timespec, + __set: *const sigset_t, + ) -> ::core::ffi::c_int; +} +pub type in_addr_t = __uint32_t; +pub type in_port_t = __uint16_t; +pub type u_register_t = __uintptr_t; +pub type u_char = ::core::ffi::c_uchar; +pub type u_short = ::core::ffi::c_ushort; +pub type u_int = ::core::ffi::c_uint; +pub type u_long = ::core::ffi::c_ulong; +pub type ushort = ::core::ffi::c_ushort; +pub type uint = ::core::ffi::c_uint; +pub type ulong = ::core::ffi::c_ulong; +pub type blkcnt_t = __blkcnt_t; +pub type blksize_t = __blksize_t; +pub type clock_t = ::core::ffi::c_ulong; +pub type daddr_t = ::core::ffi::c_long; +pub type caddr_t = *mut ::core::ffi::c_char; +pub type fsblkcnt_t = __fsblkcnt_t; +pub type fsfilcnt_t = __fsfilcnt_t; +pub type id_t = __id_t; +pub type ino_t = __ino_t; +pub type off_t = __off_t; +pub type dev_t = __dev_t; +pub type uid_t = __uid_t; +pub type gid_t = __gid_t; +pub type pid_t = __pid_t; +pub type key_t = __key_t; +pub type mode_t = __mode_t; +pub type nlink_t = __nlink_t; +pub type clockid_t = __clockid_t; +pub type timer_t = __timer_t; +pub type useconds_t = __useconds_t; +pub type sbintime_t = __int64_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sched_param { + pub sched_priority: ::core::ffi::c_int, +} +#[test] +fn bindgen_test_layout_sched_param() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(sched_param)) + ); + assert_eq!( + ::core::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(sched_param)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).sched_priority) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(sched_param), + "::", + stringify!(sched_priority) + ) + ); +} +pub type pthread_t = __uint32_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct pthread_attr_t { + pub is_initialized: ::core::ffi::c_int, + pub stackaddr: *mut ::core::ffi::c_void, + pub stacksize: ::core::ffi::c_int, + pub contentionscope: ::core::ffi::c_int, + pub inheritsched: ::core::ffi::c_int, + pub schedpolicy: ::core::ffi::c_int, + pub schedparam: sched_param, + pub detachstate: ::core::ffi::c_int, +} +#[test] +fn bindgen_test_layout_pthread_attr_t() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(pthread_attr_t)) + ); + assert_eq!( + ::core::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(pthread_attr_t)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).is_initialized) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(pthread_attr_t), + "::", + stringify!(is_initialized) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).stackaddr) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(pthread_attr_t), + "::", + stringify!(stackaddr) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).stacksize) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(pthread_attr_t), + "::", + stringify!(stacksize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).contentionscope) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(pthread_attr_t), + "::", + stringify!(contentionscope) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).inheritsched) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(pthread_attr_t), + "::", + stringify!(inheritsched) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).schedpolicy) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(pthread_attr_t), + "::", + stringify!(schedpolicy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).schedparam) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(pthread_attr_t), + "::", + stringify!(schedparam) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).detachstate) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(pthread_attr_t), + "::", + stringify!(detachstate) + ) + ); +} +pub type pthread_mutex_t = __uint32_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct pthread_mutexattr_t { + pub is_initialized: ::core::ffi::c_int, + pub recursive: ::core::ffi::c_int, +} +#[test] +fn bindgen_test_layout_pthread_mutexattr_t() { + const UNINIT: ::core::mem::MaybeUninit = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(pthread_mutexattr_t)) + ); + assert_eq!( + ::core::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(pthread_mutexattr_t)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).is_initialized) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(pthread_mutexattr_t), + "::", + stringify!(is_initialized) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).recursive) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(pthread_mutexattr_t), + "::", + stringify!(recursive) + ) + ); +} +pub type pthread_cond_t = __uint32_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct pthread_condattr_t { + pub is_initialized: ::core::ffi::c_int, + pub clock: clock_t, +} +#[test] +fn bindgen_test_layout_pthread_condattr_t() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(pthread_condattr_t)) + ); + assert_eq!( + ::core::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(pthread_condattr_t)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).is_initialized) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(pthread_condattr_t), + "::", + stringify!(is_initialized) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).clock) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(pthread_condattr_t), + "::", + stringify!(clock) + ) + ); +} +pub type pthread_key_t = __uint32_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct pthread_once_t { + pub is_initialized: ::core::ffi::c_int, + pub init_executed: ::core::ffi::c_int, +} +#[test] +fn bindgen_test_layout_pthread_once_t() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(pthread_once_t)) + ); + assert_eq!( + ::core::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(pthread_once_t)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).is_initialized) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(pthread_once_t), + "::", + stringify!(is_initialized) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).init_executed) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(pthread_once_t), + "::", + stringify!(init_executed) + ) + ); +} +pub type FILE = __FILE; +pub type fpos_t = _fpos_t; +extern "C" { + pub fn ctermid(arg1: *mut ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn tmpfile() -> *mut FILE; +} +extern "C" { + pub fn tmpnam(arg1: *mut ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn tempnam( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn fclose(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fflush(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn freopen( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: *mut FILE, + ) -> *mut FILE; +} +extern "C" { + pub fn setbuf(arg1: *mut FILE, arg2: *mut ::core::ffi::c_char); +} +extern "C" { + pub fn setvbuf( + arg1: *mut FILE, + arg2: *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + arg4: usize, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fprintf(arg1: *mut FILE, arg2: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fscanf(arg1: *mut FILE, arg2: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +extern "C" { + pub fn printf(arg1: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +extern "C" { + pub fn scanf(arg1: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +extern "C" { + pub fn sscanf( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vfprintf( + arg1: *mut FILE, + arg2: *const ::core::ffi::c_char, + arg3: u32, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vprintf(arg1: *const ::core::ffi::c_char, arg2: u32) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vsprintf( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: u32, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fgetc(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fgets( + arg1: *mut ::core::ffi::c_char, + arg2: ::core::ffi::c_int, + arg3: *mut FILE, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn fputc(arg1: ::core::ffi::c_int, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fputs(arg1: *const ::core::ffi::c_char, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn getc(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn getchar() -> ::core::ffi::c_int; +} +extern "C" { + pub fn gets(arg1: *mut ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn putc(arg1: ::core::ffi::c_int, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn putchar(arg1: ::core::ffi::c_int) -> ::core::ffi::c_int; +} +extern "C" { + pub fn puts(arg1: *const ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn ungetc(arg1: ::core::ffi::c_int, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fread( + arg1: *mut ::core::ffi::c_void, + _size: ::core::ffi::c_uint, + _n: ::core::ffi::c_uint, + arg2: *mut FILE, + ) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn fwrite( + arg1: *const ::core::ffi::c_void, + _size: ::core::ffi::c_uint, + _n: ::core::ffi::c_uint, + arg2: *mut FILE, + ) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn fgetpos(arg1: *mut FILE, arg2: *mut fpos_t) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fseek( + arg1: *mut FILE, + arg2: ::core::ffi::c_long, + arg3: ::core::ffi::c_int, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fsetpos(arg1: *mut FILE, arg2: *const fpos_t) -> ::core::ffi::c_int; +} +extern "C" { + pub fn ftell(arg1: *mut FILE) -> ::core::ffi::c_long; +} +extern "C" { + pub fn rewind(arg1: *mut FILE); +} +extern "C" { + pub fn clearerr(arg1: *mut FILE); +} +extern "C" { + pub fn feof(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn ferror(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn perror(arg1: *const ::core::ffi::c_char); +} +extern "C" { + pub fn fopen(_name: *const ::core::ffi::c_char, _type: *const ::core::ffi::c_char) + -> *mut FILE; +} +extern "C" { + pub fn sprintf( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn remove(arg1: *const ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn rename( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fseeko(arg1: *mut FILE, arg2: off_t, arg3: ::core::ffi::c_int) -> ::core::ffi::c_int; +} +extern "C" { + pub fn ftello(arg1: *mut FILE) -> off_t; +} +extern "C" { + pub fn snprintf( + arg1: *mut ::core::ffi::c_char, + arg2: ::core::ffi::c_uint, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vsnprintf( + arg1: *mut ::core::ffi::c_char, + arg2: ::core::ffi::c_uint, + arg3: *const ::core::ffi::c_char, + arg4: u32, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vfscanf( + arg1: *mut FILE, + arg2: *const ::core::ffi::c_char, + arg3: u32, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vscanf(arg1: *const ::core::ffi::c_char, arg2: u32) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vsscanf( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: u32, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn asiprintf( + arg1: *mut *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn asniprintf( + arg1: *mut ::core::ffi::c_char, + arg2: *mut usize, + arg3: *const ::core::ffi::c_char, + ... + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn asnprintf( + arg1: *mut ::core::ffi::c_char, + arg2: *mut usize, + arg3: *const ::core::ffi::c_char, + ... + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn diprintf( + arg1: ::core::ffi::c_int, + arg2: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fiprintf(arg1: *mut FILE, arg2: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fiscanf(arg1: *mut FILE, arg2: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +extern "C" { + pub fn iprintf(arg1: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +extern "C" { + pub fn iscanf(arg1: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +extern "C" { + pub fn siprintf( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn siscanf( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn sniprintf( + arg1: *mut ::core::ffi::c_char, + arg2: usize, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vasiprintf( + arg1: *mut *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vasniprintf( + arg1: *mut ::core::ffi::c_char, + arg2: *mut usize, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn vasnprintf( + arg1: *mut ::core::ffi::c_char, + arg2: *mut usize, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn vdiprintf( + arg1: ::core::ffi::c_int, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vfiprintf( + arg1: *mut FILE, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vfiscanf( + arg1: *mut FILE, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn viprintf(arg1: *const ::core::ffi::c_char, arg2: __gnuc_va_list) -> ::core::ffi::c_int; +} +extern "C" { + pub fn viscanf(arg1: *const ::core::ffi::c_char, arg2: __gnuc_va_list) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vsiprintf( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vsiscanf( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn vsniprintf( + arg1: *mut ::core::ffi::c_char, + arg2: usize, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fdopen(arg1: ::core::ffi::c_int, arg2: *const ::core::ffi::c_char) -> *mut FILE; +} +extern "C" { + pub fn fileno(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn pclose(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn popen(arg1: *const ::core::ffi::c_char, arg2: *const ::core::ffi::c_char) -> *mut FILE; +} +extern "C" { + pub fn setbuffer(arg1: *mut FILE, arg2: *mut ::core::ffi::c_char, arg3: ::core::ffi::c_int); +} +extern "C" { + pub fn setlinebuf(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn getw(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn putw(arg1: ::core::ffi::c_int, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn getc_unlocked(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn getchar_unlocked() -> ::core::ffi::c_int; +} +extern "C" { + pub fn flockfile(arg1: *mut FILE); +} +extern "C" { + pub fn ftrylockfile(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn funlockfile(arg1: *mut FILE); +} +extern "C" { + pub fn putc_unlocked(arg1: ::core::ffi::c_int, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn putchar_unlocked(arg1: ::core::ffi::c_int) -> ::core::ffi::c_int; +} +extern "C" { + pub fn dprintf( + arg1: ::core::ffi::c_int, + arg2: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fmemopen( + arg1: *mut ::core::ffi::c_void, + arg2: usize, + arg3: *const ::core::ffi::c_char, + ) -> *mut FILE; +} +extern "C" { + pub fn open_memstream(arg1: *mut *mut ::core::ffi::c_char, arg2: *mut usize) -> *mut FILE; +} +extern "C" { + pub fn vdprintf( + arg1: ::core::ffi::c_int, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn renameat( + arg1: ::core::ffi::c_int, + arg2: *const ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + arg4: *const ::core::ffi::c_char, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _asiprintf_r( + arg1: *mut _reent, + arg2: *mut *mut ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _asniprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: *mut usize, + arg4: *const ::core::ffi::c_char, + ... + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _asnprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: *mut usize, + arg4: *const ::core::ffi::c_char, + ... + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _asprintf_r( + arg1: *mut _reent, + arg2: *mut *mut ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _diprintf_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _dprintf_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fclose_r(arg1: *mut _reent, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fcloseall_r(arg1: *mut _reent) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fdopen_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *const ::core::ffi::c_char, + ) -> *mut FILE; +} +extern "C" { + pub fn _fflush_r(arg1: *mut _reent, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fgetc_r(arg1: *mut _reent, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fgetc_unlocked_r(arg1: *mut _reent, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fgets_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + arg4: *mut FILE, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _fgets_unlocked_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: ::core::ffi::c_int, + arg4: *mut FILE, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _fgetpos_r(arg1: *mut _reent, arg2: *mut FILE, arg3: *mut fpos_t) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fsetpos_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: *const fpos_t, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fiprintf_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fiscanf_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fmemopen_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_void, + arg3: usize, + arg4: *const ::core::ffi::c_char, + ) -> *mut FILE; +} +extern "C" { + pub fn _fopen_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + ) -> *mut FILE; +} +extern "C" { + pub fn _freopen_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + arg4: *mut FILE, + ) -> *mut FILE; +} +extern "C" { + pub fn _fprintf_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fpurge_r(arg1: *mut _reent, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fputc_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *mut FILE, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fputc_unlocked_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *mut FILE, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fputs_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *mut FILE, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fputs_unlocked_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *mut FILE, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fread_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_void, + _size: usize, + _n: usize, + arg3: *mut FILE, + ) -> usize; +} +extern "C" { + pub fn _fread_unlocked_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_void, + _size: usize, + _n: usize, + arg3: *mut FILE, + ) -> usize; +} +extern "C" { + pub fn _fscanf_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fseek_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: ::core::ffi::c_long, + arg4: ::core::ffi::c_int, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _fseeko_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: _off_t, + arg4: ::core::ffi::c_int, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _ftell_r(arg1: *mut _reent, arg2: *mut FILE) -> ::core::ffi::c_long; +} +extern "C" { + pub fn _ftello_r(arg1: *mut _reent, arg2: *mut FILE) -> _off_t; +} +extern "C" { + pub fn _rewind_r(arg1: *mut _reent, arg2: *mut FILE); +} +extern "C" { + pub fn _fwrite_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_void, + _size: usize, + _n: usize, + arg3: *mut FILE, + ) -> usize; +} +extern "C" { + pub fn _fwrite_unlocked_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_void, + _size: usize, + _n: usize, + arg3: *mut FILE, + ) -> usize; +} +extern "C" { + pub fn _getc_r(arg1: *mut _reent, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _getc_unlocked_r(arg1: *mut _reent, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _getchar_r(arg1: *mut _reent) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _getchar_unlocked_r(arg1: *mut _reent) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _gets_r(arg1: *mut _reent, arg2: *mut ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _iprintf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _iscanf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _open_memstream_r( + arg1: *mut _reent, + arg2: *mut *mut ::core::ffi::c_char, + arg3: *mut usize, + ) -> *mut FILE; +} +extern "C" { + pub fn _perror_r(arg1: *mut _reent, arg2: *const ::core::ffi::c_char); +} +extern "C" { + pub fn _printf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _putc_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *mut FILE, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _putc_unlocked_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *mut FILE, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _putchar_unlocked_r(arg1: *mut _reent, arg2: ::core::ffi::c_int) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _putchar_r(arg1: *mut _reent, arg2: ::core::ffi::c_int) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _puts_r(arg1: *mut _reent, arg2: *const ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _remove_r(arg1: *mut _reent, arg2: *const ::core::ffi::c_char) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _rename_r( + arg1: *mut _reent, + _old: *const ::core::ffi::c_char, + _new: *const ::core::ffi::c_char, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _scanf_r(arg1: *mut _reent, arg2: *const ::core::ffi::c_char, ...) + -> ::core::ffi::c_int; +} +extern "C" { + pub fn _siprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _siscanf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _sniprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: usize, + arg4: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _snprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: usize, + arg4: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _sprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _sscanf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + ... + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _tempnam_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _tmpfile_r(arg1: *mut _reent) -> *mut FILE; +} +extern "C" { + pub fn _tmpnam_r(arg1: *mut _reent, arg2: *mut ::core::ffi::c_char) + -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _ungetc_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *mut FILE, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vasiprintf_r( + arg1: *mut _reent, + arg2: *mut *mut ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vasniprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: *mut usize, + arg4: *const ::core::ffi::c_char, + arg5: __gnuc_va_list, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _vasnprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: *mut usize, + arg4: *const ::core::ffi::c_char, + arg5: __gnuc_va_list, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _vasprintf_r( + arg1: *mut _reent, + arg2: *mut *mut ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vdiprintf_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vdprintf_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vfiprintf_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vfiscanf_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vfprintf_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vfscanf_r( + arg1: *mut _reent, + arg2: *mut FILE, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _viprintf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _viscanf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vprintf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vscanf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vsiprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vsiscanf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vsniprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: usize, + arg4: *const ::core::ffi::c_char, + arg5: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vsnprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: usize, + arg4: *const ::core::ffi::c_char, + arg5: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vsprintf_r( + arg1: *mut _reent, + arg2: *mut ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _vsscanf_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: *const ::core::ffi::c_char, + arg4: __gnuc_va_list, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fpurge(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __getdelim( + arg1: *mut *mut ::core::ffi::c_char, + arg2: *mut usize, + arg3: ::core::ffi::c_int, + arg4: *mut FILE, + ) -> isize; +} +extern "C" { + pub fn __getline( + arg1: *mut *mut ::core::ffi::c_char, + arg2: *mut usize, + arg3: *mut FILE, + ) -> isize; +} +extern "C" { + pub fn clearerr_unlocked(arg1: *mut FILE); +} +extern "C" { + pub fn feof_unlocked(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn ferror_unlocked(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fileno_unlocked(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fflush_unlocked(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fgetc_unlocked(arg1: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fputc_unlocked(arg1: ::core::ffi::c_int, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fread_unlocked( + arg1: *mut ::core::ffi::c_void, + _size: usize, + _n: usize, + arg2: *mut FILE, + ) -> usize; +} +extern "C" { + pub fn fwrite_unlocked( + arg1: *const ::core::ffi::c_void, + _size: usize, + _n: usize, + arg2: *mut FILE, + ) -> usize; +} +extern "C" { + pub fn __srget_r(arg1: *mut _reent, arg2: *mut FILE) -> ::core::ffi::c_int; +} +extern "C" { + pub fn __swbuf_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: *mut FILE, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn funopen( + __cookie: *const ::core::ffi::c_void, + __readfn: ::core::option::Option< + unsafe extern "C" fn( + __cookie: *mut ::core::ffi::c_void, + __buf: *mut ::core::ffi::c_char, + __n: ::core::ffi::c_int, + ) -> ::core::ffi::c_int, + >, + __writefn: ::core::option::Option< + unsafe extern "C" fn( + __cookie: *mut ::core::ffi::c_void, + __buf: *const ::core::ffi::c_char, + __n: ::core::ffi::c_int, + ) -> ::core::ffi::c_int, + >, + __seekfn: ::core::option::Option< + unsafe extern "C" fn( + __cookie: *mut ::core::ffi::c_void, + __off: fpos_t, + __whence: ::core::ffi::c_int, + ) -> fpos_t, + >, + __closefn: ::core::option::Option< + unsafe extern "C" fn(__cookie: *mut ::core::ffi::c_void) -> ::core::ffi::c_int, + >, + ) -> *mut FILE; +} +extern "C" { + pub fn _funopen_r( + arg1: *mut _reent, + __cookie: *const ::core::ffi::c_void, + __readfn: ::core::option::Option< + unsafe extern "C" fn( + __cookie: *mut ::core::ffi::c_void, + __buf: *mut ::core::ffi::c_char, + __n: ::core::ffi::c_int, + ) -> ::core::ffi::c_int, + >, + __writefn: ::core::option::Option< + unsafe extern "C" fn( + __cookie: *mut ::core::ffi::c_void, + __buf: *const ::core::ffi::c_char, + __n: ::core::ffi::c_int, + ) -> ::core::ffi::c_int, + >, + __seekfn: ::core::option::Option< + unsafe extern "C" fn( + __cookie: *mut ::core::ffi::c_void, + __off: fpos_t, + __whence: ::core::ffi::c_int, + ) -> fpos_t, + >, + __closefn: ::core::option::Option< + unsafe extern "C" fn(__cookie: *mut ::core::ffi::c_void) -> ::core::ffi::c_int, + >, + ) -> *mut FILE; +} +extern "C" { + pub fn bcmp( + arg1: *const ::core::ffi::c_void, + arg2: *const ::core::ffi::c_void, + arg3: ::core::ffi::c_uint, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn bcopy(arg1: *const ::core::ffi::c_void, arg2: *mut ::core::ffi::c_void, arg3: usize); +} +extern "C" { + pub fn bzero(arg1: *mut ::core::ffi::c_void, arg2: ::core::ffi::c_uint); +} +extern "C" { + pub fn explicit_bzero(arg1: *mut ::core::ffi::c_void, arg2: usize); +} +extern "C" { + pub fn ffs(arg1: ::core::ffi::c_int) -> ::core::ffi::c_int; +} +extern "C" { + pub fn ffsl(arg1: ::core::ffi::c_long) -> ::core::ffi::c_int; +} +extern "C" { + pub fn ffsll(arg1: ::core::ffi::c_longlong) -> ::core::ffi::c_int; +} +extern "C" { + pub fn fls(arg1: ::core::ffi::c_int) -> ::core::ffi::c_int; +} +extern "C" { + pub fn flsl(arg1: ::core::ffi::c_long) -> ::core::ffi::c_int; +} +extern "C" { + pub fn flsll(arg1: ::core::ffi::c_longlong) -> ::core::ffi::c_int; +} +extern "C" { + pub fn index( + arg1: *const ::core::ffi::c_char, + arg2: ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn rindex( + arg1: *const ::core::ffi::c_char, + arg2: ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strcasecmp( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn strncasecmp( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: ::core::ffi::c_uint, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn strcasecmp_l( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: locale_t, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn strncasecmp_l( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: usize, + arg4: locale_t, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn memchr( + arg1: *const ::core::ffi::c_void, + arg2: ::core::ffi::c_int, + arg3: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn memcmp( + arg1: *const ::core::ffi::c_void, + arg2: *const ::core::ffi::c_void, + arg3: ::core::ffi::c_uint, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn memcpy( + arg1: *mut ::core::ffi::c_void, + arg2: *const ::core::ffi::c_void, + arg3: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn memmove( + arg1: *mut ::core::ffi::c_void, + arg2: *const ::core::ffi::c_void, + arg3: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn memset( + arg1: *mut ::core::ffi::c_void, + arg2: ::core::ffi::c_int, + arg3: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn strcat( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strchr( + arg1: *const ::core::ffi::c_char, + arg2: ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strcmp( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn strcoll( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn strcpy( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strcspn( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn strerror(arg1: ::core::ffi::c_int) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strlen(arg1: *const ::core::ffi::c_char) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn strncat( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strncmp( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: ::core::ffi::c_uint, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn strncpy( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strpbrk( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strrchr( + arg1: *const ::core::ffi::c_char, + arg2: ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strspn( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn strstr( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strtok( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strxfrm( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: ::core::ffi::c_uint, + ) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn strcoll_l( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: locale_t, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn strerror_l(arg1: ::core::ffi::c_int, arg2: locale_t) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strxfrm_l( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: usize, + arg4: locale_t, + ) -> usize; +} +extern "C" { + pub fn strtok_r( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: *mut *mut ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn timingsafe_bcmp( + arg1: *const ::core::ffi::c_void, + arg2: *const ::core::ffi::c_void, + arg3: usize, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn timingsafe_memcmp( + arg1: *const ::core::ffi::c_void, + arg2: *const ::core::ffi::c_void, + arg3: usize, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn memccpy( + arg1: *mut ::core::ffi::c_void, + arg2: *const ::core::ffi::c_void, + arg3: ::core::ffi::c_int, + arg4: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + pub fn stpcpy( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn stpncpy( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strdup(arg1: *const ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _strdup_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strndup( + arg1: *const ::core::ffi::c_char, + arg2: ::core::ffi::c_uint, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn _strndup_r( + arg1: *mut _reent, + arg2: *const ::core::ffi::c_char, + arg3: usize, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + #[link_name = "\u{1}__xpg_strerror_r"] + pub fn strerror_r( + arg1: ::core::ffi::c_int, + arg2: *mut ::core::ffi::c_char, + arg3: usize, + ) -> ::core::ffi::c_int; +} +extern "C" { + pub fn _strerror_r( + arg1: *mut _reent, + arg2: ::core::ffi::c_int, + arg3: ::core::ffi::c_int, + arg4: *mut ::core::ffi::c_int, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strlcat( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: ::core::ffi::c_uint, + ) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn strlcpy( + arg1: *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: ::core::ffi::c_uint, + ) -> ::core::ffi::c_uint; +} +extern "C" { + pub fn strnlen(arg1: *const ::core::ffi::c_char, arg2: usize) -> usize; +} +extern "C" { + pub fn strsep( + arg1: *mut *mut ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strnstr( + arg1: *const ::core::ffi::c_char, + arg2: *const ::core::ffi::c_char, + arg3: usize, + ) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strlwr(arg1: *mut ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strupr(arg1: *mut ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn strsignal(__signo: ::core::ffi::c_int) -> *mut ::core::ffi::c_char; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct tm { + pub tm_sec: ::core::ffi::c_int, + pub tm_min: ::core::ffi::c_int, + pub tm_hour: ::core::ffi::c_int, + pub tm_mday: ::core::ffi::c_int, + pub tm_mon: ::core::ffi::c_int, + pub tm_year: ::core::ffi::c_int, + pub tm_wday: ::core::ffi::c_int, + pub tm_yday: ::core::ffi::c_int, + pub tm_isdst: ::core::ffi::c_int, +} +#[test] +fn bindgen_test_layout_tm() { + const UNINIT: ::core::mem::MaybeUninit = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::(), + 36usize, + concat!("Size of: ", stringify!(tm)) + ); + assert_eq!( + ::core::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(tm)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tm_sec) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_sec) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tm_min) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_min) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tm_hour) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_hour) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tm_mday) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_mday) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tm_mon) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_mon) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tm_year) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_year) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tm_wday) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_wday) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tm_yday) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_yday) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).tm_isdst) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(tm), + "::", + stringify!(tm_isdst) + ) + ); +} +extern "C" { + pub fn clock() -> clock_t; +} +extern "C" { + pub fn difftime(_time2: time_t, _time1: time_t) -> f64; +} +extern "C" { + pub fn mktime(_timeptr: *mut tm) -> time_t; +} +extern "C" { + pub fn time(_timer: *mut time_t) -> time_t; +} +extern "C" { + pub fn asctime(_tblock: *const tm) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn ctime(_time: *const time_t) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn gmtime(_timer: *const time_t) -> *mut tm; +} +extern "C" { + pub fn localtime(_timer: *const time_t) -> *mut tm; +} +extern "C" { + pub fn strftime( + _s: *mut ::core::ffi::c_char, + _maxsize: usize, + _fmt: *const ::core::ffi::c_char, + _t: *const tm, + ) -> usize; +} +extern "C" { + pub fn strftime_l( + _s: *mut ::core::ffi::c_char, + _maxsize: usize, + _fmt: *const ::core::ffi::c_char, + _t: *const tm, + _l: locale_t, + ) -> usize; +} +extern "C" { + pub fn asctime_r(arg1: *const tm, arg2: *mut ::core::ffi::c_char) -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn ctime_r(arg1: *const time_t, arg2: *mut ::core::ffi::c_char) + -> *mut ::core::ffi::c_char; +} +extern "C" { + pub fn gmtime_r(arg1: *const time_t, arg2: *mut tm) -> *mut tm; +} +extern "C" { + pub fn localtime_r(arg1: *const time_t, arg2: *mut tm) -> *mut tm; +} +extern "C" { + pub fn tzset(); +} +extern "C" { + pub fn _tzset_r(arg1: *mut _reent); +} +extern "C" { + pub static mut _timezone: ::core::ffi::c_long; +} +extern "C" { + pub static mut _daylight: ::core::ffi::c_int; +} +extern "C" { + pub static mut _tzname: [*mut ::core::ffi::c_char; 2usize]; +} +#[doc = "< The operation was successfully executed."] +pub const _SbgErrorCode_SBG_NO_ERROR: _SbgErrorCode = 0; +#[doc = "< We have a generic error."] +pub const _SbgErrorCode_SBG_ERROR: _SbgErrorCode = 1; +#[doc = "< A pointer is null."] +pub const _SbgErrorCode_SBG_NULL_POINTER: _SbgErrorCode = 2; +#[doc = "< The received frame has an invalid CRC."] +pub const _SbgErrorCode_SBG_INVALID_CRC: _SbgErrorCode = 3; +#[doc = "< The received frame is invalid
*/\n/*!<\tWe have received an unexpected frame (not the cmd we are waiting for or with an invalid data size.
*/\n/*!<\tThis could be caused by a desync between questions and answers.
*/\n/*!<\tYou should flush the serial port to fix this."] +pub const _SbgErrorCode_SBG_INVALID_FRAME: _SbgErrorCode = 4; +#[doc = "< We have started to receive a frame but not the end."] +pub const _SbgErrorCode_SBG_TIME_OUT: _SbgErrorCode = 5; +#[doc = "< All bytes hasn't been written."] +pub const _SbgErrorCode_SBG_WRITE_ERROR: _SbgErrorCode = 6; +#[doc = "< All bytes hasn't been read."] +pub const _SbgErrorCode_SBG_READ_ERROR: _SbgErrorCode = 7; +#[doc = "< A buffer is too small to contain so much data."] +pub const _SbgErrorCode_SBG_BUFFER_OVERFLOW: _SbgErrorCode = 8; +#[doc = "< An invalid parameter has been found."] +pub const _SbgErrorCode_SBG_INVALID_PARAMETER: _SbgErrorCode = 9; +#[doc = "< A device isn't ready (Rx isn't ready for example)."] +pub const _SbgErrorCode_SBG_NOT_READY: _SbgErrorCode = 10; +#[doc = "< Failed to allocate a buffer."] +pub const _SbgErrorCode_SBG_MALLOC_FAILED: _SbgErrorCode = 11; +#[doc = "< Not enough points were available to perform magnetometers calibration."] +pub const _SbgErrorCode_SGB_CALIB_MAG_NOT_ENOUGH_POINTS: _SbgErrorCode = 12; +#[doc = "< The calibration procedure could not be properly executed due to insufficient precision."] +pub const _SbgErrorCode_SBG_CALIB_MAG_INVALID_TAKE: _SbgErrorCode = 13; +#[doc = "< Saturation were detected when attempt to calibrate magnetos."] +pub const _SbgErrorCode_SBG_CALIB_MAG_SATURATION: _SbgErrorCode = 14; +#[doc = "< 2D calibration procedure could not be performed."] +pub const _SbgErrorCode_SBG_CALIB_MAG_POINTS_NOT_IN_A_PLANE: _SbgErrorCode = 15; +#[doc = "< A device couldn't be founded or opened PC only error code"] +pub const _SbgErrorCode_SBG_DEVICE_NOT_FOUND: _SbgErrorCode = 16; +#[doc = "< An operation was canceled. PC only error code"] +pub const _SbgErrorCode_SBG_OPERATION_CANCELLED: _SbgErrorCode = 17; +#[doc = "< We have received a frame that isn't a continuous one. PC only error code"] +pub const _SbgErrorCode_SBG_NOT_CONTINUOUS_FRAME: _SbgErrorCode = 18; +#[doc = "< Hence valid; the command cannot be executed because of hardware incompatibility"] +pub const _SbgErrorCode_SBG_INCOMPATIBLE_HARDWARE: _SbgErrorCode = 19; +#[doc = "< Incompatible version"] +pub const _SbgErrorCode_SBG_INVALID_VERSION: _SbgErrorCode = 20; +#[doc = "\tGeneric errors definitions for SBG Systems projects."] +pub type _SbgErrorCode = ::core::ffi::c_uint; +#[doc = "\tGeneric errors definitions for SBG Systems projects."] +pub use self::_SbgErrorCode as SbgErrorCode; +pub type uint8 = ::core::ffi::c_uchar; +pub type uint16 = ::core::ffi::c_ushort; +pub type uint32 = ::core::ffi::c_uint; +pub type uint64 = ::core::ffi::c_ulonglong; +pub type int8 = ::core::ffi::c_schar; +pub type int16 = ::core::ffi::c_short; +pub type int32 = ::core::ffi::c_int; +pub type int64 = ::core::ffi::c_longlong; +pub type sbgIpAddress = u32; +#[doc = " Used to get a uint32_t from a uint8_t array."] +#[repr(C)] +#[derive(Copy, Clone)] +pub union _Uint8PtrToUint32Ptr { + #[doc = "< Set the address used to access the uint32_t."] + pub m_pointerUint8: *mut u8, + #[doc = "< Store the unint32 value."] + pub m_pointerUint32: *mut u32, +} +#[test] +fn bindgen_test_layout__Uint8PtrToUint32Ptr() { + const UNINIT: ::core::mem::MaybeUninit<_Uint8PtrToUint32Ptr> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_Uint8PtrToUint32Ptr>(), + 4usize, + concat!("Size of: ", stringify!(_Uint8PtrToUint32Ptr)) + ); + assert_eq!( + ::core::mem::align_of::<_Uint8PtrToUint32Ptr>(), + 4usize, + concat!("Alignment of ", stringify!(_Uint8PtrToUint32Ptr)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).m_pointerUint8) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8PtrToUint32Ptr), + "::", + stringify!(m_pointerUint8) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).m_pointerUint32) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8PtrToUint32Ptr), + "::", + stringify!(m_pointerUint32) + ) + ); +} +#[doc = " Used to get a uint32_t from a uint8_t array."] +pub type Uint8PtrToUint32Ptr = _Uint8PtrToUint32Ptr; +#[doc = " Union used to convert a buffer or 2 unit8 two's complement values to a int16_t"] +#[repr(C)] +#[derive(Copy, Clone)] +pub union _Uint8ToInt16 { + pub value: i16, + pub buffer: [u8; 2usize], +} +#[test] +fn bindgen_test_layout__Uint8ToInt16() { + const UNINIT: ::core::mem::MaybeUninit<_Uint8ToInt16> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_Uint8ToInt16>(), + 2usize, + concat!("Size of: ", stringify!(_Uint8ToInt16)) + ); + assert_eq!( + ::core::mem::align_of::<_Uint8ToInt16>(), + 2usize, + concat!("Alignment of ", stringify!(_Uint8ToInt16)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).value) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToInt16), + "::", + stringify!(value) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).buffer) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToInt16), + "::", + stringify!(buffer) + ) + ); +} +#[doc = " Union used to convert a buffer or 2 unit8 two's complement values to a int16_t"] +pub type Uint8ToInt16 = _Uint8ToInt16; +#[doc = " Union used to convert a buffer or 2 unit8 values to a uint16_t"] +#[repr(C)] +#[derive(Copy, Clone)] +pub union _Uint8ToUint16 { + pub value: u16, + pub buffer: [u8; 2usize], +} +#[test] +fn bindgen_test_layout__Uint8ToUint16() { + const UNINIT: ::core::mem::MaybeUninit<_Uint8ToUint16> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_Uint8ToUint16>(), + 2usize, + concat!("Size of: ", stringify!(_Uint8ToUint16)) + ); + assert_eq!( + ::core::mem::align_of::<_Uint8ToUint16>(), + 2usize, + concat!("Alignment of ", stringify!(_Uint8ToUint16)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).value) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToUint16), + "::", + stringify!(value) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).buffer) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToUint16), + "::", + stringify!(buffer) + ) + ); +} +#[doc = " Union used to convert a buffer or 2 unit8 values to a uint16_t"] +pub type Uint8ToUint16 = _Uint8ToUint16; +#[doc = " Union used to convert a buffer or 4 unit8 two's complement values to a int32_t"] +#[repr(C)] +#[derive(Copy, Clone)] +pub union _Uint8ToInt32 { + pub value: i32, + pub buffer: [u8; 4usize], +} +#[test] +fn bindgen_test_layout__Uint8ToInt32() { + const UNINIT: ::core::mem::MaybeUninit<_Uint8ToInt32> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_Uint8ToInt32>(), + 4usize, + concat!("Size of: ", stringify!(_Uint8ToInt32)) + ); + assert_eq!( + ::core::mem::align_of::<_Uint8ToInt32>(), + 4usize, + concat!("Alignment of ", stringify!(_Uint8ToInt32)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).value) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToInt32), + "::", + stringify!(value) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).buffer) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToInt32), + "::", + stringify!(buffer) + ) + ); +} +#[doc = " Union used to convert a buffer or 4 unit8 two's complement values to a int32_t"] +pub type Uint8ToInt32 = _Uint8ToInt32; +#[doc = " Union used to convert a buffer or 4 unit8 values to a uint32_t"] +#[repr(C)] +#[derive(Copy, Clone)] +pub union _Uint8ToUint32 { + pub value: u32, + pub buffer: [u8; 4usize], +} +#[test] +fn bindgen_test_layout__Uint8ToUint32() { + const UNINIT: ::core::mem::MaybeUninit<_Uint8ToUint32> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_Uint8ToUint32>(), + 4usize, + concat!("Size of: ", stringify!(_Uint8ToUint32)) + ); + assert_eq!( + ::core::mem::align_of::<_Uint8ToUint32>(), + 4usize, + concat!("Alignment of ", stringify!(_Uint8ToUint32)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).value) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToUint32), + "::", + stringify!(value) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).buffer) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToUint32), + "::", + stringify!(buffer) + ) + ); +} +#[doc = " Union used to convert a buffer or 4 unit8 values to a uint32_t"] +pub type Uint8ToUint32 = _Uint8ToUint32; +#[doc = " Union used to convert a buffer or 8 unit8 two's complement values to a int64_t"] +#[repr(C)] +#[derive(Copy, Clone)] +pub union _Uint8ToInt64 { + pub value: i64, + pub buffer: [u8; 8usize], +} +#[test] +fn bindgen_test_layout__Uint8ToInt64() { + const UNINIT: ::core::mem::MaybeUninit<_Uint8ToInt64> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_Uint8ToInt64>(), + 8usize, + concat!("Size of: ", stringify!(_Uint8ToInt64)) + ); + assert_eq!( + ::core::mem::align_of::<_Uint8ToInt64>(), + 8usize, + concat!("Alignment of ", stringify!(_Uint8ToInt64)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).value) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToInt64), + "::", + stringify!(value) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).buffer) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToInt64), + "::", + stringify!(buffer) + ) + ); +} +#[doc = " Union used to convert a buffer or 8 unit8 two's complement values to a int64_t"] +pub type Uint8ToInt64 = _Uint8ToInt64; +#[doc = " Union used to convert a buffer or 8 unit8 values to a uint64_t"] +#[repr(C)] +#[derive(Copy, Clone)] +pub union _Uint8ToUint64 { + pub value: u64, + pub buffer: [u8; 8usize], +} +#[test] +fn bindgen_test_layout__Uint8ToUint64() { + const UNINIT: ::core::mem::MaybeUninit<_Uint8ToUint64> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_Uint8ToUint64>(), + 8usize, + concat!("Size of: ", stringify!(_Uint8ToUint64)) + ); + assert_eq!( + ::core::mem::align_of::<_Uint8ToUint64>(), + 8usize, + concat!("Alignment of ", stringify!(_Uint8ToUint64)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).value) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToUint64), + "::", + stringify!(value) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).buffer) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Uint8ToUint64), + "::", + stringify!(buffer) + ) + ); +} +#[doc = " Union used to convert a buffer or 8 unit8 values to a uint64_t"] +pub type Uint8ToUint64 = _Uint8ToUint64; +#[doc = " Union that allows type punning (access to a floating point number bits)"] +#[repr(C)] +#[derive(Copy, Clone)] +pub union _FloatNint { + pub valF: f32, + pub valI: i32, + pub valU: u32, +} +#[test] +fn bindgen_test_layout__FloatNint() { + const UNINIT: ::core::mem::MaybeUninit<_FloatNint> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_FloatNint>(), + 4usize, + concat!("Size of: ", stringify!(_FloatNint)) + ); + assert_eq!( + ::core::mem::align_of::<_FloatNint>(), + 4usize, + concat!("Alignment of ", stringify!(_FloatNint)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).valF) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_FloatNint), + "::", + stringify!(valF) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).valI) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_FloatNint), + "::", + stringify!(valI) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).valU) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_FloatNint), + "::", + stringify!(valU) + ) + ); +} +#[doc = " Union that allows type punning (access to a floating point number bits)"] +pub type FloatNint = _FloatNint; +#[doc = " Union that allows type punning (access to a double number bits)"] +#[repr(C)] +#[derive(Copy, Clone)] +pub union _DoubleNint { + pub valF: f64, + pub valU: u64, + pub valI: i64, +} +#[test] +fn bindgen_test_layout__DoubleNint() { + const UNINIT: ::core::mem::MaybeUninit<_DoubleNint> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_DoubleNint>(), + 8usize, + concat!("Size of: ", stringify!(_DoubleNint)) + ); + assert_eq!( + ::core::mem::align_of::<_DoubleNint>(), + 8usize, + concat!("Alignment of ", stringify!(_DoubleNint)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).valF) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_DoubleNint), + "::", + stringify!(valF) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).valU) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_DoubleNint), + "::", + stringify!(valU) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).valI) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_DoubleNint), + "::", + stringify!(valI) + ) + ); +} +#[doc = " Union that allows type punning (access to a double number bits)"] +pub type DoubleNint = _DoubleNint; +#[doc = " Structure that splits a 64bits"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _Split64 { + pub high: u32, + pub low: u32, +} +#[test] +fn bindgen_test_layout__Split64() { + const UNINIT: ::core::mem::MaybeUninit<_Split64> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_Split64>(), + 8usize, + concat!("Size of: ", stringify!(_Split64)) + ); + assert_eq!( + ::core::mem::align_of::<_Split64>(), + 4usize, + concat!("Alignment of ", stringify!(_Split64)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).high) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_Split64), + "::", + stringify!(high) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).low) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_Split64), + "::", + stringify!(low) + ) + ); +} +#[doc = " Structure that splits a 64bits"] +pub type Split64 = _Split64; +#[doc = " Set of 3 int32_t"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgVector3i { + pub v: [i32; 3usize], +} +#[test] +fn bindgen_test_layout__SbgVector3i() { + const UNINIT: ::core::mem::MaybeUninit<_SbgVector3i> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgVector3i>(), + 12usize, + concat!("Size of: ", stringify!(_SbgVector3i)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgVector3i>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgVector3i)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).v) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgVector3i), + "::", + stringify!(v) + ) + ); +} +#[doc = " Set of 3 int32_t"] +pub type SbgVector3i = _SbgVector3i; +#[doc = " Set of 3 int64_t"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgVector3ll { + pub v: [i64; 3usize], +} +#[test] +fn bindgen_test_layout__SbgVector3ll() { + const UNINIT: ::core::mem::MaybeUninit<_SbgVector3ll> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgVector3ll>(), + 24usize, + concat!("Size of: ", stringify!(_SbgVector3ll)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgVector3ll>(), + 8usize, + concat!("Alignment of ", stringify!(_SbgVector3ll)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).v) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgVector3ll), + "::", + stringify!(v) + ) + ); +} +#[doc = " Set of 3 int64_t"] +pub type SbgVector3ll = _SbgVector3ll; +#[doc = "< The message to log is an error."] +pub const _SbgDebugLogType_SBG_DEBUG_LOG_TYPE_ERROR: _SbgDebugLogType = 0; +#[doc = "< The message to log is a warning."] +pub const _SbgDebugLogType_SBG_DEBUG_LOG_TYPE_WARNING: _SbgDebugLogType = 1; +#[doc = "< The message to log is an information."] +pub const _SbgDebugLogType_SBG_DEBUG_LOG_TYPE_INFO: _SbgDebugLogType = 2; +#[doc = "< The message to log is a debug information."] +pub const _SbgDebugLogType_SBG_DEBUG_LOG_TYPE_DEBUG: _SbgDebugLogType = 3; +#[doc = "\tEnum that identify the type of error / warning that has been thrown."] +pub type _SbgDebugLogType = ::core::ffi::c_uint; +#[doc = "\tEnum that identify the type of error / warning that has been thrown."] +pub use self::_SbgDebugLogType as SbgDebugLogType; +extern "C" { + #[doc = " Produce a text dump of a buffer.\n\n \\param[in]\tpPrefix\t\t\t\t\t\tPrefix string before each line.\n \\param[in]\tpBuffer\t\t\t\t\t\tData buffer, may be NULL.\n \\param[in]\tsize\t\t\t\t\t\tData size, in bytes."] + pub fn sbgDebugHexDump( + pPrefix: *const ::core::ffi::c_char, + pBuffer: *const ::core::ffi::c_void, + size: usize, + ); +} +#[doc = " Type for logging functions.\n\n \\param[in]\tpFileName\t\t\t\t\tFile name where the error occurred.\n \\param[in]\tpFunctionName\t\t\t\tFunction name where the error occurred.\n \\param[in]\tline\t\t\t\t\t\tLine number where the error occurred.\n \\param[in]\tpCategory\t\t\t\t\tCategory for this log or \"None\" if no category has been specified.\n \\param[in]\tlogType\t\t\t\t\t\tDefine if we have an error, a warning, an info or a debug log.\n \\param[in]\terrorCode\t\t\t\t\tThe error code associated with the message.\n \\param[in]\tpMessage\t\t\t\t\tThe message to log."] +pub type SbgCommonLibOnLogFunc = ::core::option::Option< + unsafe extern "C" fn( + pFileName: *const ::core::ffi::c_char, + pFunctionName: *const ::core::ffi::c_char, + line: u32, + pCategory: *const ::core::ffi::c_char, + logType: SbgDebugLogType, + errorCode: SbgErrorCode, + pMessage: *const ::core::ffi::c_char, + ), +>; +extern "C" { + #[doc = " Get the current time.\n\n \\return\t\t\t\t\t\t\t\t\tThe current time, in ms."] + pub fn sbgGetTime() -> u32; +} +extern "C" { + #[doc = " Sleep.\n\n \\param[in]\tms\t\t\t\t\t\t\tTime to wait, in ms."] + pub fn sbgSleep(ms: u32); +} +extern "C" { + #[doc = " Set the log function.\n\n Some platforms may not provide the ability to set a user-provided log function, in which\n case this function does nothing.\n\n \\param[in]\tlogCallback\t\t\t\t\tLog function."] + pub fn sbgCommonLibSetLogCallback(logCallback: SbgCommonLibOnLogFunc); +} +extern "C" { + #[doc = " Log a message.\n\n \\param[in]\tpFileName\t\t\t\t\tFile name where the error occurred.\n \\param[in]\tpFunctionName\t\t\t\tFunction name where the error occurred.\n \\param[in]\tline\t\t\t\t\t\tLine number where the error occurred.\n \\param[in]\tpCategory\t\t\t\t\tCategory for this log or \"None\" if no category has been specified.\n \\param[in]\tlogType\t\t\t\t\t\tDefine if we have an error, a warning, an info or a debug log.\n \\param[in]\terrorCode\t\t\t\t\tThe error code associated with the message.\n \\param[in]\tpFormat\t\t\t\t\t\tThe error message that will be used with the variable list of arguments."] + pub fn sbgPlatformDebugLogMsg( + pFileName: *const ::core::ffi::c_char, + pFunctionName: *const ::core::ffi::c_char, + line: u32, + pCategory: *const ::core::ffi::c_char, + logType: SbgDebugLogType, + errorCode: SbgErrorCode, + pFormat: *const ::core::ffi::c_char, + ... + ); +} +extern "C" { + #[doc = " Retreive the current sbgCommonLib encoded version.\n \\return\t\t\t\t\t\t\t\t\t\t\t\tThe current sbgCommonLib version"] + pub fn sbgCommonLibGetVersion() -> u32; +} +extern "C" { + #[doc = "\tTell if the library is compiled in debug mode or not\n\t\\return\t\t\t\t\t\tTrue if it's compiled in debug, False otherwise"] + pub fn sbgCommonLibIsDebug() -> bool; +} +pub type SbgCrc32 = u32; +pub type SbgCrc16 = u16; +extern "C" { + #[doc = "\tInitialize the 32 bit CRC computation system.\n\t\\param[in]\tpInstance\t\t\t\tPointer on an allocated but non initialized Crc32 object."] + pub fn sbgCrc32Initialize(pInstance: *mut SbgCrc32); +} +extern "C" { + #[doc = "\tCompute a 32 bit CRC using an Ethernet polynome.\n\tWarning: the buffer size should be at least 4 bytes long.\n\t\\param[in]\tpInstance\t\t\t\tRead only pointer on a valid Crc32 object.\n\t\\param[in]\tpData\t\t\t\t\tRead only pointer on the data buffer to compute CRC on.\n\t\\param[in]\tdataSize\t\t\t\tData size in bytes of the buffer, has to be greater or equals to 4."] + pub fn sbgCrc32Update( + pInstance: *mut SbgCrc32, + pData: *const ::core::ffi::c_void, + dataSize: usize, + ); +} +extern "C" { + #[doc = "\tCompute a 32 Bit CRC using an Ethernet polynome.\n\tWarning: the buffer size should be at least 4 bytes long.\n\t\\param[in]\tpData\t\t\t\t\tRead only pointer on the data buffer to compute CRC on.\n\t\\param[in]\tdataSize\t\t\t\tData size in bytes of the buffer, has to be greater or equals to 4.\n\t\\return\t\t\t\t\t\t\t\tThe computed CRC."] + pub fn sbgCrc32Compute(pData: *const ::core::ffi::c_void, dataSize: usize) -> u32; +} +extern "C" { + #[doc = "\tInitialize the 16 bit CRC computation system.\n\t\\param[in]\tpInstance\t\t\t\tPointer on an allocated but non initialized Crc16 object."] + pub fn sbgCrc16Initialize(pInstance: *mut SbgCrc16); +} +extern "C" { + #[doc = "\tCompute a 16 bit CRC using an the polynome 0x8408.\n\t\\param[in]\tpInstance\t\t\t\tRead only pointer on a valid Crc16 object.\n\t\\param[in]\tpData\t\t\t\t\tRead only pointer on the data buffer to compute CRC on.\n\t\\param[in]\tdataSize\t\t\t\tData size in bytes of the buffer."] + pub fn sbgCrc16Update( + pInstance: *mut SbgCrc16, + pData: *const ::core::ffi::c_void, + dataSize: usize, + ); +} +extern "C" { + #[doc = "\tCompute a 32 Bit CRC using an the polynome 0x8408.\n\t\\param[in]\tpData\t\t\t\t\tRead only pointer on the data buffer to compute CRC on.\n\t\\param[in]\tdataSize\t\t\t\tData size in bytes of the buffer.\n\t\\return\t\t\t\t\t\t\t\tThe computed CRC."] + pub fn sbgCrc16Compute(pData: *const ::core::ffi::c_void, dataSize: usize) -> u16; +} +#[doc = " Interface definition that stores methods used to communicate on the interface.\n\n The interface class is designed to allow custom user implementations. The type member stores\n a type identifier allowing the identification of the underlying type, including custom\n implementations. Standard interfaces provided by this library use types from 1 up to\n and including SBG_IF_TYPE_LAST_RESERVED. Greater values are intended to identify custom\n types that are normally specific to the project using this library. The value 0 identifies\n an unknown interface type, usually indicating that the interface was not correctly initialized."] +pub type SbgInterface = _SbgInterface; +#[doc = " Handle that stores the internal interface handle (ie Serial or Ethernet)"] +pub type SbgInterfaceHandle = *mut ::core::ffi::c_void; +#[doc = " Method to implement that close and destroy an interface.\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tInterface instance.\n \\return\t\t\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the interface has been closed successfully."] +pub type SbgInterfaceDestroyFunc = + ::core::option::Option SbgErrorCode>; +#[doc = " Method to implement to write a buffer to an interface.\n\n This method should return an error only if all bytes were not written successfully.\n If you try to write zero byte, the method shouldn't return any error.\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tInterface instance.\n \\param[in]\tpBuffer\t\t\t\t\t\t\t\t\tPointer on an allocated buffer that contains the data to write\n \\param[in]\tbytesToWrite\t\t\t\t\t\t\tNumber of bytes we would like to write (can be zero).\n \\return\t\t\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if exactly bytesToWrite have been written successfully."] +pub type SbgInterfaceWriteFunc = ::core::option::Option< + unsafe extern "C" fn( + pInterface: *mut SbgInterface, + pBuffer: *const ::core::ffi::c_void, + bytesToWrite: usize, + ) -> SbgErrorCode, +>; +#[doc = " Method to implement to read data from an interface.\n\n This method returns an error only if there is a 'low level' error on the interface.\n If no byte is read at all or less bytes than bytesToRead, this method returns SBG_NO_ERROR.\n You have to check pReadBytes field to know the number of bytes actually read.\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tInterface instance.\n \\param[in]\tpBuffer\t\t\t\t\t\t\t\t\tPointer on an allocated buffer that can hold at least bytesToRead bytes of data.\n \\param[out]\tpReadBytes\t\t\t\t\t\t\t\tReturns the number of bytes actually read (can be zero and up to bytesToRead).\n \\param[in]\tbytesToRead\t\t\t\t\t\t\t\tMaximum number of bytes to try to read on the interface.\n \\return\t\t\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if zero or some bytes have been read successfully."] +pub type SbgInterfaceReadFunc = ::core::option::Option< + unsafe extern "C" fn( + pInterface: *mut SbgInterface, + pBuffer: *mut ::core::ffi::c_void, + pReadBytes: *mut usize, + bytesToRead: usize, + ) -> SbgErrorCode, +>; +#[doc = " Make an interface flush pending input and/or output data.\n\n If flags include SBG_IF_FLUSH_INPUT, all pending input data is discarded.\n If flags include SBG_IF_FLUSH_OUTPUT, the function blocks until all output data has been written out.\n\n WARNING: The method has no action if not applicable for a type of interface\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tInterface instance.\n \\param[in]\tflags\t\t\t\t\t\t\t\t\tCombination of the SBG_IF_FLUSH_INPUT and SBG_IF_FLUSH_OUTPUT flags.\n \\return\t\t\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful."] +pub type SbgInterfaceFlushFunc = ::core::option::Option< + unsafe extern "C" fn(pInterface: *mut SbgInterface, flags: u32) -> SbgErrorCode, +>; +#[doc = " Change an interface input and output speed in bps (bit per second)\n\n This method will try to change the speed immediately even if there are\n pending bytes in the send buffer.\n\n If you would like to make sure that all bytes in the Tx buffer have been\n sent before changing the speed, please flush the interface before.\n\n WARNING: The method has no action if not applicable for a type of interface\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tInterface instance.\n \\param[in]\tspeed\t\t\t\t\t\t\t\t\tThe new interface speed to set in bps.\n \\return\t\t\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful."] +pub type SbgInterfaceSetSpeed = ::core::option::Option< + unsafe extern "C" fn(pInterface: *mut SbgInterface, speed: u32) -> SbgErrorCode, +>; +#[doc = " Returns the current interface baud rate in bps (bit per second)\n\n WARNING: The method will returns zero if not applicable for a type of interface\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tInterface instance.\n \\return\t\t\t\t\t\t\t\t\t\t\t\tThe current interface baud rate in bps or zero if not applicable."] +pub type SbgInterfaceGetSpeed = + ::core::option::Option u32>; +#[doc = " Compute and return the delay needed by the interface to transmit / receive X number of bytes.\n\n WARNING: The method will returns zero if not applicable for a type of interface.\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tInterface instance.\n \\param[in]\tnumBytes\t\t\t\t\t\t\t\tThe number of bytes to transmit / receive to evaluate the needed delay.\n \\return\t\t\t\t\t\t\t\t\t\t\t\tThe expected delay in us needed to transmit / receive the specified number of bytes or 0 if not applicable."] +pub type SbgInterfaceGetDelayFunc = ::core::option::Option< + unsafe extern "C" fn(pInterface: *const SbgInterface, numBytes: usize) -> u32, +>; +#[doc = " Interface definition that stores methods used to communicate on the interface.\n\n The interface class is designed to allow custom user implementations. The type member stores\n a type identifier allowing the identification of the underlying type, including custom\n implementations. Standard interfaces provided by this library use types from 1 up to\n and including SBG_IF_TYPE_LAST_RESERVED. Greater values are intended to identify custom\n types that are normally specific to the project using this library. The value 0 identifies\n an unknown interface type, usually indicating that the interface was not correctly initialized."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgInterface { + #[doc = "< Internal interface handle used to access the media."] + pub handle: SbgInterfaceHandle, + #[doc = "< Opaque interface type."] + pub type_: u32, + #[doc = "< The interface name as passed during the creation"] + pub name: [::core::ffi::c_char; 48usize], + #[doc = "< Optional method used to destroy an interface."] + pub pDestroyFunc: SbgInterfaceDestroyFunc, + #[doc = "< Optional method used to write some data to this interface."] + pub pWriteFunc: SbgInterfaceWriteFunc, + #[doc = "< Optional method used to read some data to this interface."] + pub pReadFunc: SbgInterfaceReadFunc, + #[doc = "< Optional method used to make this interface flush all pending data."] + pub pFlushFunc: SbgInterfaceFlushFunc, + #[doc = "< Optional method used to set the interface speed in bps."] + pub pSetSpeedFunc: SbgInterfaceSetSpeed, + #[doc = "< Optional method used to retrieve the interface speed in bps."] + pub pGetSpeedFunc: SbgInterfaceGetSpeed, + #[doc = "< Optional method used to compute an expected delay to transmit/receive X bytes"] + pub pDelayFunc: SbgInterfaceGetDelayFunc, +} +#[test] +fn bindgen_test_layout__SbgInterface() { + const UNINIT: ::core::mem::MaybeUninit<_SbgInterface> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgInterface>(), + 84usize, + concat!("Size of: ", stringify!(_SbgInterface)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgInterface>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgInterface)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).handle) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgInterface), + "::", + stringify!(handle) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgInterface), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).name) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgInterface), + "::", + stringify!(name) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pDestroyFunc) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(_SbgInterface), + "::", + stringify!(pDestroyFunc) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pWriteFunc) as usize - ptr as usize }, + 60usize, + concat!( + "Offset of field: ", + stringify!(_SbgInterface), + "::", + stringify!(pWriteFunc) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pReadFunc) as usize - ptr as usize }, + 64usize, + concat!( + "Offset of field: ", + stringify!(_SbgInterface), + "::", + stringify!(pReadFunc) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pFlushFunc) as usize - ptr as usize }, + 68usize, + concat!( + "Offset of field: ", + stringify!(_SbgInterface), + "::", + stringify!(pFlushFunc) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pSetSpeedFunc) as usize - ptr as usize }, + 72usize, + concat!( + "Offset of field: ", + stringify!(_SbgInterface), + "::", + stringify!(pSetSpeedFunc) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pGetSpeedFunc) as usize - ptr as usize }, + 76usize, + concat!( + "Offset of field: ", + stringify!(_SbgInterface), + "::", + stringify!(pGetSpeedFunc) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pDelayFunc) as usize - ptr as usize }, + 80usize, + concat!( + "Offset of field: ", + stringify!(_SbgInterface), + "::", + stringify!(pDelayFunc) + ) + ); +} +extern "C" { + #[doc = " Initialize an interface instance to zero.\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tThe interface instance."] + pub fn sbgInterfaceZeroInit(pInterface: *mut SbgInterface); +} +extern "C" { + #[doc = " Close and destroy the interface gracefully.\n\n This method will call the specialized interface destructor if any.\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tThe interface instance.\n \\return\t\t\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the interface has been destroyed successfully."] + pub fn sbgInterfaceDestroy(pInterface: *mut SbgInterface) -> SbgErrorCode; +} +extern "C" { + #[doc = " Returns the interface as string.\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tInterface instance\n \\return\t\t\t\t\t\t\t\t\t\t\t\tThe interface type."] + pub fn sbgInterfaceTypeGetAsString( + pInterface: *const SbgInterface, + ) -> *const ::core::ffi::c_char; +} +extern "C" { + #[doc = " Define the interface name as a NULL terminated C string.\n\n This method make sure that the provided string will always fit within\n the allocated name buffer.\n\n If the interface name you would like to set is too long, only the end\n of the string will be kept.\n\n \\param[in]\tpInterface\t\t\t\t\t\t\t\tInterface instance\n \\param[in]\tpName\t\t\t\t\t\t\t\t\tThe interface name to set as a NULL terminated C string"] + pub fn sbgInterfaceNameSet(pInterface: *mut SbgInterface, pName: *const ::core::ffi::c_char); +} +extern "C" { + #[doc = "\tInitialize a serial interface for read and write operations.\n\n\t\\param[in]\tpInterface\t\t\t\t\t\tPointer on an allocated interface instance to initialize.\n\t\\param[in]\tdeviceName\t\t\t\t\t\tSerial interface location (COM21 , /dev/ttys0, depending on platform).\n\t\\param[in]\tbaudRate\t\t\t\t\t\tSerial interface baud rate in bps.\n\t\\return\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the interface has been created."] + pub fn sbgInterfaceSerialCreate( + pInterface: *mut SbgInterface, + deviceName: *const ::core::ffi::c_char, + baudRate: u32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = "\tOpen a file as an interface for read only operations.\n\n\t\\param[in]\tpInterface\t\t\t\t\t\tPointer on an allocated interface instance to initialize.\n\t\\param[in]\tfilePath\t\t\t\t\t\tFile path to open.\n\t\\return\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the interface has been created."] + pub fn sbgInterfaceFileOpen( + pInterface: *mut SbgInterface, + filePath: *const ::core::ffi::c_char, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = "\tOpen a file as an interface for write only operations.\n\n\t\\param[in]\tpInterface\t\t\t\t\t\tPointer on an allocated interface instance to initialize.\n\t\\param[in]\tfilePath\t\t\t\t\t\tFile path to open.\n\t\\return\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the interface has been created."] + pub fn sbgInterfaceFileWriteOpen( + pInterface: *mut SbgInterface, + filePath: *const ::core::ffi::c_char, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = "\tReturns the file size in bytes.\n\n\t\\param[in]\tpInterface\t\t\t\t\t\tValid handle on an initialized interface.\n\t\\return\t\t\t\t\t\t\t\t\t\tThe file size in bytes."] + pub fn sbgInterfaceFileGetSize(pInterface: *mut SbgInterface) -> usize; +} +extern "C" { + #[doc = "\tReturns the current cursor position in the file in bytes.\n\n\t\\param[in]\tpInterface\t\t\t\t\t\tValid handle on an initialized interface.\n\t\\return\t\t\t\t\t\t\t\t\t\tThe current cursor position in bytes."] + pub fn sbgInterfaceFileGetCursor(pInterface: *const SbgInterface) -> usize; +} +#[doc = " Defines the ECom transfer states"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgSplitBuffer { + #[doc = "< Pointer on the buffer that needs to be split"] + pub pLinkedBuffer: *mut u8, + #[doc = "< Size of the original buffer"] + pub linkedBufferSize: usize, + #[doc = "< The size of the sub buffers"] + pub subBufferSize: usize, + #[doc = "< The number of sub buffers in this split buffer"] + pub subBufferNbr: usize, +} +#[test] +fn bindgen_test_layout__SbgSplitBuffer() { + const UNINIT: ::core::mem::MaybeUninit<_SbgSplitBuffer> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgSplitBuffer>(), + 16usize, + concat!("Size of: ", stringify!(_SbgSplitBuffer)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgSplitBuffer>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgSplitBuffer)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pLinkedBuffer) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgSplitBuffer), + "::", + stringify!(pLinkedBuffer) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).linkedBufferSize) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgSplitBuffer), + "::", + stringify!(linkedBufferSize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).subBufferSize) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgSplitBuffer), + "::", + stringify!(subBufferSize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).subBufferNbr) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgSplitBuffer), + "::", + stringify!(subBufferNbr) + ) + ); +} +#[doc = " Defines the ECom transfer states"] +pub type SbgSplitBuffer = _SbgSplitBuffer; +#[doc = "< This stream buffer can perform read operations."] +pub const _SbgSBMode_SB_MODE_READ: _SbgSBMode = 0; +#[doc = "< This stream buffer can perform write operations."] +pub const _SbgSBMode_SB_MODE_WRITE: _SbgSBMode = 1; +#[doc = " Stream buffer modes."] +pub type _SbgSBMode = ::core::ffi::c_uint; +#[doc = " Stream buffer modes."] +pub use self::_SbgSBMode as SbgSBMode; +#[doc = "< The offset is referenced to the begining of the stream."] +pub const _SbgSBSeekOrigin_SB_SEEK_SET: _SbgSBSeekOrigin = 0; +#[doc = "< The offset is referenced to the current cursor position and increment the current cursor."] +pub const _SbgSBSeekOrigin_SB_SEEK_CUR_INC: _SbgSBSeekOrigin = 1; +#[doc = "< The offset is referenced to the current cursor position and decrement the current cursor."] +pub const _SbgSBSeekOrigin_SB_SEEK_CUR_DEC: _SbgSBSeekOrigin = 2; +#[doc = "< The offset is referenced to the end of the stream."] +pub const _SbgSBSeekOrigin_SB_SEEK_END: _SbgSBSeekOrigin = 3; +#[doc = " Enum used to define all seek modes"] +pub type _SbgSBSeekOrigin = ::core::ffi::c_uint; +#[doc = " Enum used to define all seek modes"] +pub use self::_SbgSBSeekOrigin as SbgSBSeekOrigin; +#[doc = " Defines a stream buffer."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgStreamBuffer { + #[doc = "< Defines the stream buffer modes (read/write)."] + pub modes: SbgSBMode, + #[doc = "< Size in bytes of the linked buffer."] + pub bufferSize: usize, + #[doc = "< Pointer to the buffer linked with this stream."] + pub pBufferPtr: *mut u8, + #[doc = "< Current pointer within the buffer."] + pub pCurrentPtr: *mut u8, + #[doc = "< Current error code on stream buffer."] + pub errorCode: SbgErrorCode, +} +#[test] +fn bindgen_test_layout__SbgStreamBuffer() { + const UNINIT: ::core::mem::MaybeUninit<_SbgStreamBuffer> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgStreamBuffer>(), + 20usize, + concat!("Size of: ", stringify!(_SbgStreamBuffer)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgStreamBuffer>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgStreamBuffer)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).modes) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgStreamBuffer), + "::", + stringify!(modes) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).bufferSize) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgStreamBuffer), + "::", + stringify!(bufferSize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pBufferPtr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgStreamBuffer), + "::", + stringify!(pBufferPtr) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pCurrentPtr) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgStreamBuffer), + "::", + stringify!(pCurrentPtr) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).errorCode) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgStreamBuffer), + "::", + stringify!(errorCode) + ) + ); +} +#[doc = " Defines a stream buffer."] +pub type SbgStreamBuffer = _SbgStreamBuffer; +extern "C" { + #[doc = " Convert an ip to a string of the form A.B.C.D\n \\param[in]\tipAddr\t\t\t\t\t\tIP address to convert to a string.\n \\param[out]\tpBuffer\t\t\t\t\t\tPointer on an allocated buffer than can hold ip address as a string.\n \\param[in]\tmaxSize\t\t\t\t\t\tMaximum number of chars that can be stored in pBuffer including the NULL char."] + pub fn sbgNetworkIpToString( + ipAddr: sbgIpAddress, + pBuffer: *mut ::core::ffi::c_char, + maxSize: usize, + ); +} +extern "C" { + #[doc = " Convert an ip address stored in a string of the form A.B.C.D to an sbgIpAddress object.\n \\param[in]\tpBuffer\t\t\t\t\t\tIP address as a string of the form A.B.C.D\n \\return\t\t\t\t\t\t\t\t\tIP address parsed from the string or 0.0.0.0 if the IP is invalid."] + pub fn sbgNetworkIpFromString(pBuffer: *const ::core::ffi::c_char) -> sbgIpAddress; +} +extern "C" { + #[doc = " Check if an IpV4 netmask is valid, the mask should be contiguous (1111 followed by 0)\n \\param[in]\tnetmask\t\t\t\t\t\t\tThe netmask stored in an uint32_t (host endianness).\n \\return\t\t\t\t\t\t\t\t\t\ttrue if the netmask is valid ie contiguous."] + pub fn sbgIpNetMaskValid(netmask: sbgIpAddress) -> bool; +} +pub const _SbgECanMessageId_SBG_ECAN_MSG_STATUS_01: _SbgECanMessageId = 256; +pub const _SbgECanMessageId_SBG_ECAN_MSG_STATUS_02: _SbgECanMessageId = 257; +pub const _SbgECanMessageId_SBG_ECAN_MSG_STATUS_03: _SbgECanMessageId = 258; +pub const _SbgECanMessageId_SBG_ECAN_MSG_UTC_0: _SbgECanMessageId = 272; +pub const _SbgECanMessageId_SBG_ECAN_MSG_UTC_1: _SbgECanMessageId = 273; +pub const _SbgECanMessageId_SBG_ECAN_MSG_IMU_INFO: _SbgECanMessageId = 288; +pub const _SbgECanMessageId_SBG_ECAN_MSG_IMU_ACCEL: _SbgECanMessageId = 289; +pub const _SbgECanMessageId_SBG_ECAN_MSG_IMU_GYRO: _SbgECanMessageId = 290; +pub const _SbgECanMessageId_SBG_ECAN_MSG_IMU_DELTA_VEL: _SbgECanMessageId = 291; +pub const _SbgECanMessageId_SBG_ECAN_MSG_IMU_DELTA_ANGLE: _SbgECanMessageId = 292; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EKF_INFO: _SbgECanMessageId = 304; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EKF_QUAT: _SbgECanMessageId = 305; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EKF_EULER: _SbgECanMessageId = 306; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EKF_ORIENTATION_ACC: _SbgECanMessageId = 307; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EKF_POS: _SbgECanMessageId = 308; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EKF_ALTITUDE: _SbgECanMessageId = 309; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EKF_POS_ACC: _SbgECanMessageId = 310; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EKF_VEL_NED: _SbgECanMessageId = 311; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EKF_VEL_NED_ACC: _SbgECanMessageId = 312; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EKF_VEL_BODY: _SbgECanMessageId = 313; +pub const _SbgECanMessageId_SBG_ECAN_MSG_SHIP_MOTION_INFO: _SbgECanMessageId = 320; +pub const _SbgECanMessageId_SBG_ECAN_MSG_SHIP_MOTION_0: _SbgECanMessageId = 321; +pub const _SbgECanMessageId_SBG_ECAN_MSG_SHIP_MOTION_1: _SbgECanMessageId = 325; +pub const _SbgECanMessageId_SBG_ECAN_MSG_SHIP_MOTION_2: _SbgECanMessageId = 329; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_SHIP_MOTION_HP_INFO: _SbgECanMessageId = 330; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_SHIP_MOTION_HP_0: _SbgECanMessageId = 331; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_SHIP_MOTION_HP_1: _SbgECanMessageId = 332; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_SHIP_MOTION_HP_2: _SbgECanMessageId = 333; +pub const _SbgECanMessageId_SBG_ECAN_MSG_MAG_0: _SbgECanMessageId = 336; +pub const _SbgECanMessageId_SBG_ECAN_MSG_MAG_1: _SbgECanMessageId = 337; +pub const _SbgECanMessageId_SBG_ECAN_MSG_MAG_2: _SbgECanMessageId = 338; +pub const _SbgECanMessageId_SBG_ECAN_MSG_ODO_INFO: _SbgECanMessageId = 352; +pub const _SbgECanMessageId_SBG_ECAN_MSG_ODO_VEL: _SbgECanMessageId = 353; +pub const _SbgECanMessageId_SBG_ECAN_MSG_AIR_DATA_INFO: _SbgECanMessageId = 354; +pub const _SbgECanMessageId_SBG_ECAN_MSG_AIR_DATA_ALTITUDE: _SbgECanMessageId = 355; +pub const _SbgECanMessageId_SBG_ECAN_MSG_AIR_DATA_AIRSPEED: _SbgECanMessageId = 356; +pub const _SbgECanMessageId_SBG_ECAN_MSG_DEPTH_INFO: _SbgECanMessageId = 358; +pub const _SbgECanMessageId_SBG_ECAN_MSG_DEPTH_ALTITUDE: _SbgECanMessageId = 359; +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS1_VEL_INFO: _SbgECanMessageId = 368; +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS1_VEL: _SbgECanMessageId = 369; +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS1_VEL_ACC: _SbgECanMessageId = 370; +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS1_VEL_COURSE: _SbgECanMessageId = 371; +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS1_POS_INFO: _SbgECanMessageId = 372; +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS1_POS: _SbgECanMessageId = 373; +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS1_POS_ALT: _SbgECanMessageId = 374; +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS1_POS_ACC: _SbgECanMessageId = 375; +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS1_HDT_INFO: _SbgECanMessageId = 376; +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS1_HDT: _SbgECanMessageId = 377; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS2_VEL_INFO: _SbgECanMessageId = 384; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS2_VEL: _SbgECanMessageId = 385; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS2_VEL_ACC: _SbgECanMessageId = 386; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS2_VEL_COURSE: _SbgECanMessageId = 387; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS2_POS_INFO: _SbgECanMessageId = 388; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS2_POS: _SbgECanMessageId = 389; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS2_POS_ALT: _SbgECanMessageId = 390; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS2_POS_ACC: _SbgECanMessageId = 391; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS2_HDT_INFO: _SbgECanMessageId = 392; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_GPS2_HDT: _SbgECanMessageId = 393; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EVENT_INFO_A: _SbgECanMessageId = 512; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EVENT_TIME_A: _SbgECanMessageId = 513; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EVENT_INFO_B: _SbgECanMessageId = 514; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EVENT_TIME_B: _SbgECanMessageId = 515; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EVENT_INFO_C: _SbgECanMessageId = 516; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EVENT_TIME_C: _SbgECanMessageId = 517; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EVENT_INFO_D: _SbgECanMessageId = 518; +pub const _SbgECanMessageId_SBG_ECAN_MSG_EVENT_TIME_D: _SbgECanMessageId = 519; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_EVENT_INFO_E: _SbgECanMessageId = 520; +#[doc = "< Only for Ekinox, Apogee, Navsight & Quanta"] +pub const _SbgECanMessageId_SBG_ECAN_MSG_EVENT_TIME_E: _SbgECanMessageId = 521; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_DATINF: _SbgECanMessageId = 528; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_ACCS: _SbgECanMessageId = 529; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_OMGS: _SbgECanMessageId = 530; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_NRPY: _SbgECanMessageId = 531; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_VEL: _SbgECanMessageId = 532; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_TIME: _SbgECanMessageId = 533; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_GPS_INF: _SbgECanMessageId = 534; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_GPS_COG: _SbgECanMessageId = 535; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_ADDINF: _SbgECanMessageId = 536; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_POS1: _SbgECanMessageId = 537; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_POS2: _SbgECanMessageId = 538; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_SAT_INF: _SbgECanMessageId = 539; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_IACCS: _SbgECanMessageId = 540; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_IOMG: _SbgECanMessageId = 541; +pub const _SbgECanMessageId_SBG_ECAN_MSG_CASS_RR: _SbgECanMessageId = 542; +pub const _SbgECanMessageId_SBG_ECAN_MSG_AUTO_TRACK_SLIP_CURV: _SbgECanMessageId = 544; +#[doc = " Enum containing the list of messages that can be output on the can interface."] +pub type _SbgECanMessageId = ::core::ffi::c_uint; +#[doc = " Enum containing the list of messages that can be output on the can interface."] +pub use self::_SbgECanMessageId as SbgECanMessageId; +#[doc = "< Class that contains sbgECom protocol input/output log messages."] +pub const _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_0: _SbgEComClass = 0; +#[doc = "< Class that contains special sbgECom output messages that handle high frequency output."] +pub const _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_1: _SbgEComClass = 1; +#[doc = "< Class that contains NMEA (and NMEA like) output logs.
\nNote: This class is only used for identification purpose and does not contain any sbgECom message."] +pub const _SbgEComClass_SBG_ECOM_CLASS_LOG_NMEA_0: _SbgEComClass = 2; +#[doc = "< Class that contains proprietary NMEA (and NMEA like) output logs.
\nNote: This class is only used for identification purpose and does not contain any sbgECom message."] +pub const _SbgEComClass_SBG_ECOM_CLASS_LOG_NMEA_1: _SbgEComClass = 3; +#[doc = "< Class that contains third party output logs.\nNote: This class is only used for identification purpose and does not contain any sbgECom message."] +pub const _SbgEComClass_SBG_ECOM_CLASS_LOG_THIRD_PARTY_0: _SbgEComClass = 4; +#[doc = "< Class that contains sbgECom protocol commands."] +pub const _SbgEComClass_SBG_ECOM_CLASS_LOG_CMD_0: _SbgEComClass = 16; +#[doc = " Enum that defines all the message classes available.\n\n Keep in mind that message classes are encoded on 7 bits."] +pub type _SbgEComClass = ::core::ffi::c_uint; +#[doc = " Enum that defines all the message classes available.\n\n Keep in mind that message classes are encoded on 7 bits."] +pub use self::_SbgEComClass as SbgEComClass; +#[doc = "< Status general, clock, com aiding, solution, heave"] +pub const _SbgEComLog_SBG_ECOM_LOG_STATUS: _SbgEComLog = 1; +#[doc = "< Provides UTC time reference"] +pub const _SbgEComLog_SBG_ECOM_LOG_UTC_TIME: _SbgEComLog = 2; +#[doc = "< Includes IMU status, acc., gyro, temp delta speeds and delta angles values"] +pub const _SbgEComLog_SBG_ECOM_LOG_IMU_DATA: _SbgEComLog = 3; +#[doc = "< Magnetic data with associated accelerometer on each axis"] +pub const _SbgEComLog_SBG_ECOM_LOG_MAG: _SbgEComLog = 4; +#[doc = "< Magnetometer calibration data (raw buffer)"] +pub const _SbgEComLog_SBG_ECOM_LOG_MAG_CALIB: _SbgEComLog = 5; +#[doc = "< Includes roll, pitch, yaw and their accuracies on each axis"] +pub const _SbgEComLog_SBG_ECOM_LOG_EKF_EULER: _SbgEComLog = 6; +#[doc = "< Includes the 4 quaternions values"] +pub const _SbgEComLog_SBG_ECOM_LOG_EKF_QUAT: _SbgEComLog = 7; +#[doc = "< Position and velocities in NED coordinates with the accuracies on each axis"] +pub const _SbgEComLog_SBG_ECOM_LOG_EKF_NAV: _SbgEComLog = 8; +#[doc = "< Heave, surge and sway and accelerations on each axis."] +pub const _SbgEComLog_SBG_ECOM_LOG_SHIP_MOTION: _SbgEComLog = 9; +#[doc = "< GPS velocities from primary or secondary GPS receiver"] +pub const _SbgEComLog_SBG_ECOM_LOG_GPS1_VEL: _SbgEComLog = 13; +#[doc = "< GPS positions from primary or secondary GPS receiver"] +pub const _SbgEComLog_SBG_ECOM_LOG_GPS1_POS: _SbgEComLog = 14; +#[doc = "< GPS true heading from dual antenna system"] +pub const _SbgEComLog_SBG_ECOM_LOG_GPS1_HDT: _SbgEComLog = 15; +#[doc = "< GPS 1 raw data for post processing."] +pub const _SbgEComLog_SBG_ECOM_LOG_GPS1_RAW: _SbgEComLog = 31; +#[doc = "< GPS 1 Satellite data."] +pub const _SbgEComLog_SBG_ECOM_LOG_GPS1_SAT: _SbgEComLog = 50; +#[doc = "< GPS 2 velocity log data."] +pub const _SbgEComLog_SBG_ECOM_LOG_GPS2_VEL: _SbgEComLog = 16; +#[doc = "< GPS 2 position log data."] +pub const _SbgEComLog_SBG_ECOM_LOG_GPS2_POS: _SbgEComLog = 17; +#[doc = "< GPS 2 true heading log data."] +pub const _SbgEComLog_SBG_ECOM_LOG_GPS2_HDT: _SbgEComLog = 18; +#[doc = "< GPS 2 raw data for post processing."] +pub const _SbgEComLog_SBG_ECOM_LOG_GPS2_RAW: _SbgEComLog = 38; +#[doc = "< GNSS2 Satellite data."] +pub const _SbgEComLog_SBG_ECOM_LOG_GPS2_SAT: _SbgEComLog = 51; +#[doc = "< Provides odometer velocity"] +pub const _SbgEComLog_SBG_ECOM_LOG_ODO_VEL: _SbgEComLog = 19; +#[doc = "< Event markers sent when events are detected on sync in A pin"] +pub const _SbgEComLog_SBG_ECOM_LOG_EVENT_A: _SbgEComLog = 24; +#[doc = "< Event markers sent when events are detected on sync in B pin"] +pub const _SbgEComLog_SBG_ECOM_LOG_EVENT_B: _SbgEComLog = 25; +#[doc = "< Event markers sent when events are detected on sync in C pin"] +pub const _SbgEComLog_SBG_ECOM_LOG_EVENT_C: _SbgEComLog = 26; +#[doc = "< Event markers sent when events are detected on sync in D pin"] +pub const _SbgEComLog_SBG_ECOM_LOG_EVENT_D: _SbgEComLog = 27; +#[doc = "< Event markers sent when events are detected on sync in E pin"] +pub const _SbgEComLog_SBG_ECOM_LOG_EVENT_E: _SbgEComLog = 28; +#[doc = "< Doppler Velocity Log for bottom tracking data."] +pub const _SbgEComLog_SBG_ECOM_LOG_DVL_BOTTOM_TRACK: _SbgEComLog = 29; +#[doc = "< Doppler Velocity log for water layer data."] +pub const _SbgEComLog_SBG_ECOM_LOG_DVL_WATER_TRACK: _SbgEComLog = 30; +#[doc = "< Return delayed ship motion such as surge, sway, heave."] +pub const _SbgEComLog_SBG_ECOM_LOG_SHIP_MOTION_HP: _SbgEComLog = 32; +#[doc = "< Air Data aiding such as barometric altimeter and true air speed."] +pub const _SbgEComLog_SBG_ECOM_LOG_AIR_DATA: _SbgEComLog = 36; +#[doc = "< Raw USBL position data for subsea navigation."] +pub const _SbgEComLog_SBG_ECOM_LOG_USBL: _SbgEComLog = 37; +#[doc = "< Short IMU message recommended for post processing usages."] +pub const _SbgEComLog_SBG_ECOM_LOG_IMU_SHORT: _SbgEComLog = 44; +#[doc = "< Event marker used to time stamp each generated Sync Out A signal."] +pub const _SbgEComLog_SBG_ECOM_LOG_EVENT_OUT_A: _SbgEComLog = 45; +#[doc = "< Event marker used to time stamp each generated Sync Out B signal."] +pub const _SbgEComLog_SBG_ECOM_LOG_EVENT_OUT_B: _SbgEComLog = 46; +#[doc = "< Depth sensor measurement log used for subsea navigation."] +pub const _SbgEComLog_SBG_ECOM_LOG_DEPTH: _SbgEComLog = 47; +#[doc = "< Diagnostic log."] +pub const _SbgEComLog_SBG_ECOM_LOG_DIAG: _SbgEComLog = 48; +#[doc = "< RTCM raw data."] +pub const _SbgEComLog_SBG_ECOM_LOG_RTCM_RAW: _SbgEComLog = 49; +#[doc = "< Helper definition to know the number of ECom messages"] +pub const _SbgEComLog_SBG_ECOM_LOG_ECOM_NUM_MESSAGES: _SbgEComLog = 50; +#[doc = " Enum that defines all the available ECom output logs from the sbgECom library."] +pub type _SbgEComLog = ::core::ffi::c_uint; +#[doc = " Enum that defines all the available ECom output logs from the sbgECom library."] +pub use self::_SbgEComLog as SbgEComLog; +#[doc = "< Provides accelerometers, gyroscopes, time and status at 1KHz rate."] +pub const _SbgEComLog1MsgId_SBG_ECOM_LOG_FAST_IMU_DATA: _SbgEComLog1MsgId = 0; +#[doc = "< Helper definition to know the number of ECom messages"] +pub const _SbgEComLog1MsgId_SBG_ECOM_LOG_ECOM_1_NUM_MESSAGES: _SbgEComLog1MsgId = 1; +#[doc = " Enum that defines all the available ECom output logs in the class SBG_ECOM_CLASS_LOG_ECOM_1"] +pub type _SbgEComLog1MsgId = ::core::ffi::c_uint; +#[doc = " Enum that defines all the available ECom output logs in the class SBG_ECOM_CLASS_LOG_ECOM_1"] +pub use self::_SbgEComLog1MsgId as SbgEComLog1; +#[doc = "< Latitude, Longitude, Altitude, Quality indicator."] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_GGA: _SbgEComNmeaLog = 0; +#[doc = "< Latitude, Longitude, velocity, course over ground."] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_RMC: _SbgEComNmeaLog = 1; +#[doc = "< UTC Time."] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_ZDA: _SbgEComNmeaLog = 2; +#[doc = "< Heading (True)."] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_HDT: _SbgEComNmeaLog = 3; +#[doc = "< GPS Pseudorange Noise Statistics."] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_GST: _SbgEComNmeaLog = 4; +#[doc = "< Water referenced and ground referenced speed data."] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_VBW: _SbgEComNmeaLog = 5; +#[doc = "< Depth sensor output."] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_DPT: _SbgEComNmeaLog = 7; +#[doc = "< Track an Speed over the ground."] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_VTG: _SbgEComNmeaLog = 8; +#[doc = "< Rate and direction of turn."] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_RTO: _SbgEComNmeaLog = 9; +#[doc = "< GNSS Satellites in View with azimuth, elevation and SNR information"] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_GSV: _SbgEComNmeaLog = 10; +#[doc = "< Helper definition to know the number of NMEA messages"] +pub const _SbgEComNmeaLog_SBG_ECOM_LOG_NMEA_NUM_MESSAGES: _SbgEComNmeaLog = 11; +#[doc = " Enum that defines all the available Nmea output logs from the sbgECom library."] +pub type _SbgEComNmeaLog = ::core::ffi::c_uint; +#[doc = " Enum that defines all the available Nmea output logs from the sbgECom library."] +pub use self::_SbgEComNmeaLog as SbgEComNmeaLog; +#[doc = "< RDI proprietary sentence. Pitch, Roll, Heading"] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_PRDID: _SbgEComIdNmea1Log = 0; +#[doc = "< SBG Systems proprietary sentence. Rotation rates, accelerations."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_PSBGI: _SbgEComIdNmea1Log = 1; +#[doc = "< Proprietary sentence. Roll, Pitch, Heading, Heave."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_PASHR: _SbgEComIdNmea1Log = 2; +#[doc = "< SBG Systems proprietary sentence. Attitude, heading, heave, angular rates, velocity."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_PSBGB: _SbgEComIdNmea1Log = 3; +#[doc = "< Ixblue NMEA like log used to output Status information."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_PHINF: _SbgEComIdNmea1Log = 5; +#[doc = "< Ixblue NMEA like log used to output Roll and Pitch."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_PHTRO: _SbgEComIdNmea1Log = 6; +#[doc = "< Ixblue NMEA like log used to output Surge, Sway and Heave."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_PHLIN: _SbgEComIdNmea1Log = 7; +#[doc = "< Ixblue NMEA like log used to output attitude and ship motion."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_PHOCT: _SbgEComIdNmea1Log = 8; +#[doc = "< Ixblue NMEA like log used to output position, heading, attitude, attitude rate and speed."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_INDYN: _SbgEComIdNmea1Log = 9; +#[doc = "< Trimble NMEA like log with Time, Latitude, Longitude, Ellipsoidal height"] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_GGK: _SbgEComIdNmea1Log = 10; +#[doc = "< Trimble (Applanix) NMEA like log with UTC and PPS information."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_PPS: _SbgEComIdNmea1Log = 11; +#[doc = "< WASSP NMEA like log similar to PASHR one."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_WASSP: _SbgEComIdNmea1Log = 12; +#[doc = "< SBG Systems proprietary sentence that reports EKF attitude and status."] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_PSBGA: _SbgEComIdNmea1Log = 13; +#[doc = "< Helper definition to know the number of NMEA messages"] +pub const _SbgEComIdNmea1Log_SBG_ECOM_LOG_NMEA_1_NUM_MESSAGES: _SbgEComIdNmea1Log = 14; +#[doc = " Enum that defines all the available Proprietary Nmea output logs from the sbgECom library."] +pub type _SbgEComIdNmea1Log = ::core::ffi::c_uint; +#[doc = " Enum that defines all the available Proprietary Nmea output logs from the sbgECom library."] +pub use self::_SbgEComIdNmea1Log as SbgEComIdNmea1Log; +#[doc = "< Roll, Pitch, Heave, heave accelerations"] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_TSS1: _SbgEComIdThirdParty = 0; +#[doc = "< Roll, Pitch, Yaw"] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_KVH: _SbgEComIdThirdParty = 1; +#[doc = "< Teledyne PD0 DVL proprietary frame."] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_PD0: _SbgEComIdThirdParty = 2; +#[doc = "< Konsberg SimRad 1000 proprietary frame that outputs Roll, Pitch and Heading."] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_SIMRAD_1000: _SbgEComIdThirdParty = 3; +#[doc = "< Konsberg SimRad 3000 proprietary frame that outputs Roll, Pitch and Heading."] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_SIMRAD_3000: _SbgEComIdThirdParty = 4; +#[doc = "< Konsberg Seapth Binary Log 26 used for MBES FM mode."] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_SEAPATH_B26: _SbgEComIdThirdParty = 5; +#[doc = "< DOLOG Heading, Roll, Pitch proprietary and binary message."] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_DOLOG_HRP: _SbgEComIdThirdParty = 6; +#[doc = "< Crossbow AHRS-500 Data Packet output with attitude, rate, acceleration and status."] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_AHRS_500: _SbgEComIdThirdParty = 7; +#[doc = "< ADA specific Data Packet with IMU/INS/Status data"] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_ADA_01: _SbgEComIdThirdParty = 8; +#[doc = "< Cobham Aviator UAV 200 navigation (orientation & position) data"] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_AT_ITINS: _SbgEComIdThirdParty = 9; +#[doc = "< Kongsberg multibeam binary log."] +pub const _SbgEComIdThirdParty_SBG_ECOM_THIRD_PARTY_KONGSBERG_MB: _SbgEComIdThirdParty = 10; +#[doc = "< Helper definition to know the number of third party messages"] +pub const _SbgEComIdThirdParty_SBG_ECOM_LOG_THIRD_PARTY_NUM_MESSAGES: _SbgEComIdThirdParty = 11; +#[doc = " Enum that defines all the available Proprietary output logs from the sbgECom library."] +pub type _SbgEComIdThirdParty = ::core::ffi::c_uint; +#[doc = " Enum that defines all the available Proprietary output logs from the sbgECom library."] +pub use self::_SbgEComIdThirdParty as SbgEComIdThirdParty; +#[doc = "< Acknowledge"] +pub const _SbgEComCmd_SBG_ECOM_CMD_ACK: _SbgEComCmd = 0; +#[doc = "< Performs various settings actions"] +pub const _SbgEComCmd_SBG_ECOM_CMD_SETTINGS_ACTION: _SbgEComCmd = 1; +#[doc = "< Imports a new settings structure to the sensor"] +pub const _SbgEComCmd_SBG_ECOM_CMD_IMPORT_SETTINGS: _SbgEComCmd = 2; +#[doc = "< Export the whole configuration from the sensor"] +pub const _SbgEComCmd_SBG_ECOM_CMD_EXPORT_SETTINGS: _SbgEComCmd = 3; +#[doc = "< Get basic device information"] +pub const _SbgEComCmd_SBG_ECOM_CMD_INFO: _SbgEComCmd = 4; +#[doc = "< Initial configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_INIT_PARAMETERS: _SbgEComCmd = 5; +#[doc = "< Set/get motion profile information"] +pub const _SbgEComCmd_SBG_ECOM_CMD_MOTION_PROFILE_ID: _SbgEComCmd = 7; +#[doc = "< Sensor alignment and lever arm on vehicle configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_IMU_ALIGNMENT_LEVER_ARM: _SbgEComCmd = 8; +#[doc = "< Aiding assignments such as RTCM / GPS / Odometer configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_AIDING_ASSIGNMENT: _SbgEComCmd = 9; +#[doc = "< Set/get magnetometer error model information"] +pub const _SbgEComCmd_SBG_ECOM_CMD_MAGNETOMETER_MODEL_ID: _SbgEComCmd = 11; +#[doc = "< Magnetometer aiding rejection mode"] +pub const _SbgEComCmd_SBG_ECOM_CMD_MAGNETOMETER_REJECT_MODE: _SbgEComCmd = 12; +#[doc = "< Set magnetic soft and hard Iron calibration data"] +pub const _SbgEComCmd_SBG_ECOM_CMD_SET_MAG_CALIB: _SbgEComCmd = 13; +#[doc = "< Start / reset internal magnetic field logging for calibration."] +pub const _SbgEComCmd_SBG_ECOM_CMD_START_MAG_CALIB: _SbgEComCmd = 14; +#[doc = "< Compute a magnetic calibration based on previously logged data."] +pub const _SbgEComCmd_SBG_ECOM_CMD_COMPUTE_MAG_CALIB: _SbgEComCmd = 15; +#[doc = "< Set/get GNSS model information"] +pub const _SbgEComCmd_SBG_ECOM_CMD_GNSS_1_MODEL_ID: _SbgEComCmd = 17; +#[doc = "< DEPRECATED: GNSS installation configuration (lever arm, antenna alignments)"] +pub const _SbgEComCmd_SBG_ECOM_CMD_GNSS_1_LEVER_ARM_ALIGNMENT: _SbgEComCmd = 18; +#[doc = "< Define or retrieve the GNSS 1 main and secondary lever arms configuration."] +pub const _SbgEComCmd_SBG_ECOM_CMD_GNSS_1_INSTALLATION: _SbgEComCmd = 46; +#[doc = "< GNSS aiding rejection modes configuration."] +pub const _SbgEComCmd_SBG_ECOM_CMD_GNSS_1_REJECT_MODES: _SbgEComCmd = 19; +#[doc = "< Odometer gain, direction configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_ODO_CONF: _SbgEComCmd = 20; +#[doc = "< Odometer installation configuration (lever arm)"] +pub const _SbgEComCmd_SBG_ECOM_CMD_ODO_LEVER_ARM: _SbgEComCmd = 21; +#[doc = "< Odometer aiding rejection mode configuration."] +pub const _SbgEComCmd_SBG_ECOM_CMD_ODO_REJECT_MODE: _SbgEComCmd = 22; +#[doc = "< UART interfaces configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_UART_CONF: _SbgEComCmd = 23; +#[doc = "< CAN bus interface configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_CAN_BUS_CONF: _SbgEComCmd = 24; +#[doc = "< CAN identifiers configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_CAN_OUTPUT_CONF: _SbgEComCmd = 25; +#[doc = "< Synchronization inputs configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_SYNC_IN_CONF: _SbgEComCmd = 26; +#[doc = "< Synchronization outputs configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_SYNC_OUT_CONF: _SbgEComCmd = 27; +#[doc = "< NMEA talker ID configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_NMEA_TALKER_ID: _SbgEComCmd = 29; +#[doc = "< Output configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_OUTPUT_CONF: _SbgEComCmd = 30; +#[doc = "< Advanced settings configuration"] +pub const _SbgEComCmd_SBG_ECOM_CMD_ADVANCED_CONF: _SbgEComCmd = 32; +#[doc = "< Retrieve device features"] +pub const _SbgEComCmd_SBG_ECOM_CMD_FEATURES: _SbgEComCmd = 33; +#[doc = "< Upload and apply a new license"] +pub const _SbgEComCmd_SBG_ECOM_CMD_LICENSE_APPLY: _SbgEComCmd = 34; +#[doc = "< Enable/disable the output of an entire class"] +pub const _SbgEComCmd_SBG_ECOM_CMD_OUTPUT_CLASS_ENABLE: _SbgEComCmd = 35; +#[doc = "< Set/get Ethernet configuration such as DHCP mode and IP address."] +pub const _SbgEComCmd_SBG_ECOM_CMD_ETHERNET_CONF: _SbgEComCmd = 36; +#[doc = "< Return the current IP used by the device."] +pub const _SbgEComCmd_SBG_ECOM_CMD_ETHERNET_INFO: _SbgEComCmd = 37; +#[doc = "< Set/get Validity flag thresholds for position, velocity, attitude and heading"] +pub const _SbgEComCmd_SBG_ECOM_CMD_VALIDITY_THRESHOLDS: _SbgEComCmd = 38; +#[doc = "< Set/get DVL model id to use"] +pub const _SbgEComCmd_SBG_ECOM_CMD_DVL_MODEL_ID: _SbgEComCmd = 39; +#[doc = "< DVL installation configuration (lever arm, alignments)"] +pub const _SbgEComCmd_SBG_ECOM_CMD_DVL_INSTALLATION: _SbgEComCmd = 40; +#[doc = "< DVL aiding rejection modes configuration."] +pub const _SbgEComCmd_SBG_ECOM_CMD_DVL_REJECT_MODES: _SbgEComCmd = 41; +#[doc = "< Set/get AirData model id and protocol to use."] +pub const _SbgEComCmd_SBG_ECOM_CMD_AIRDATA_MODEL_ID: _SbgEComCmd = 42; +#[doc = "< AirData installation configuration (lever arm, offsets)"] +pub const _SbgEComCmd_SBG_ECOM_CMD_AIRDATA_LEVER_ARM: _SbgEComCmd = 43; +#[doc = "< AirData aiding rejection modes configuration."] +pub const _SbgEComCmd_SBG_ECOM_CMD_AIRDATA_REJECT_MODES: _SbgEComCmd = 44; +#[doc = "< Configuration for CAN based odometer (CAN ID & DBC)"] +pub const _SbgEComCmd_SBG_ECOM_CMD_ODO_CAN_CONF: _SbgEComCmd = 45; +#[doc = "< Command equivalent to the HTTP GET method for a REST API."] +pub const _SbgEComCmd_SBG_ECOM_CMD_API_GET: _SbgEComCmd = 46; +#[doc = "< Command equivalent to the HTTP POST method for a REST API."] +pub const _SbgEComCmd_SBG_ECOM_CMD_API_POST: _SbgEComCmd = 47; +#[doc = "< Helper definition to know the number of commands"] +pub const _SbgEComCmd_SBG_ECOM_LOG_ECOM_NUM_CMDS: _SbgEComCmd = 48; +#[doc = " Enum that defines all the available commands for the sbgECom library."] +pub type _SbgEComCmd = ::core::ffi::c_uint; +#[doc = " Enum that defines all the available commands for the sbgECom library."] +pub use self::_SbgEComCmd as SbgEComCmd; +#[doc = "\tThis type defines any message identifier.\n\tBecause message identifiers enum will be different with each class id, we use a generic uint8_t rather than an enum."] +pub type SbgEComMsgId = ::core::ffi::c_uint; +#[doc = " Payload.\n\n This class is used to abstract whether some payload is received from a single\n or multiple frames."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComProtocolPayload { + #[doc = "< True if the buffer is allocated with malloc()."] + pub allocated: bool, + #[doc = "< Buffer."] + pub pBuffer: *mut ::core::ffi::c_void, + #[doc = "< Buffer size, in bytes."] + pub size: usize, +} +#[test] +fn bindgen_test_layout__SbgEComProtocolPayload() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComProtocolPayload> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComProtocolPayload>(), + 12usize, + concat!("Size of: ", stringify!(_SbgEComProtocolPayload)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComProtocolPayload>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComProtocolPayload)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).allocated) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocolPayload), + "::", + stringify!(allocated) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pBuffer) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocolPayload), + "::", + stringify!(pBuffer) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocolPayload), + "::", + stringify!(size) + ) + ); +} +#[doc = " Payload.\n\n This class is used to abstract whether some payload is received from a single\n or multiple frames."] +pub type SbgEComProtocolPayload = _SbgEComProtocolPayload; +#[doc = " Struct containing all protocol related data.\n\n The member variables related to large transfers are valid if and only if the large buffer is valid."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComProtocol { + #[doc = "< Associated interface used by the protocol to read/write bytes."] + pub pLinkedInterface: *mut SbgInterface, + #[doc = "< The reception buffer."] + pub rxBuffer: [u8; 4096usize], + #[doc = "< The current reception buffer size in bytes."] + pub rxBufferSize: usize, + #[doc = "< Number of bytes to discard on the next receive attempt."] + pub discardSize: usize, + #[doc = "< Transfer ID of the next large send."] + pub nextLargeTxId: u8, + #[doc = "< Buffer for large transfers, allocated with malloc() if valid."] + pub pLargeBuffer: *mut u8, + #[doc = "< Size of the large transfer buffer, in bytes."] + pub largeBufferSize: usize, + #[doc = "< Message class for the current large transfer."] + pub msgClass: u8, + #[doc = "< Message ID for the current large transfer."] + pub msgId: u8, + #[doc = "< ID of the current large transfer."] + pub transferId: u8, + #[doc = "< Expected page index of the next frame."] + pub pageIndex: u16, + #[doc = "< Number of pages in the current transfer."] + pub nrPages: u16, +} +#[test] +fn bindgen_test_layout__SbgEComProtocol() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComProtocol> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComProtocol>(), + 4128usize, + concat!("Size of: ", stringify!(_SbgEComProtocol)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComProtocol>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComProtocol)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pLinkedInterface) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(pLinkedInterface) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).rxBuffer) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(rxBuffer) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).rxBufferSize) as usize - ptr as usize }, + 4100usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(rxBufferSize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).discardSize) as usize - ptr as usize }, + 4104usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(discardSize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).nextLargeTxId) as usize - ptr as usize }, + 4108usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(nextLargeTxId) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pLargeBuffer) as usize - ptr as usize }, + 4112usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(pLargeBuffer) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).largeBufferSize) as usize - ptr as usize }, + 4116usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(largeBufferSize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).msgClass) as usize - ptr as usize }, + 4120usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(msgClass) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).msgId) as usize - ptr as usize }, + 4121usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(msgId) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).transferId) as usize - ptr as usize }, + 4122usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(transferId) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pageIndex) as usize - ptr as usize }, + 4124usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(pageIndex) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).nrPages) as usize - ptr as usize }, + 4126usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComProtocol), + "::", + stringify!(nrPages) + ) + ); +} +#[doc = " Struct containing all protocol related data.\n\n The member variables related to large transfers are valid if and only if the large buffer is valid."] +pub type SbgEComProtocol = _SbgEComProtocol; +extern "C" { + #[doc = " Payload constructor.\n\n \\param[in]\tpPayload\t\t\t\tPayload."] + pub fn sbgEComProtocolPayloadConstruct(pPayload: *mut SbgEComProtocolPayload); +} +extern "C" { + #[doc = " Payload destructor.\n\n \\param[in]\tpPayload\t\t\t\tPayload."] + pub fn sbgEComProtocolPayloadDestroy(pPayload: *mut SbgEComProtocolPayload); +} +extern "C" { + #[doc = " Get the buffer of a payload.\n\n \\param[in]\tpPayload\t\t\t\tPayload.\n \\return\t\t\t\t\t\t\t\tPayload buffer."] + pub fn sbgEComProtocolPayloadGetBuffer( + pPayload: *const SbgEComProtocolPayload, + ) -> *const ::core::ffi::c_void; +} +extern "C" { + #[doc = " Get the size of a payload buffer.\n\n \\param[in]\tpPayload\t\t\t\tPayload.\n \\return\t\t\t\t\t\t\t\tSize of the payload buffer, in bytes."] + pub fn sbgEComProtocolPayloadGetSize(pPayload: *const SbgEComProtocolPayload) -> usize; +} +extern "C" { + #[doc = " Move the buffer of a payload.\n\n If successful, the ownership of the buffer is passed to the caller. Otherwise, the payload\n is unchanged.\n\n The buffer must be released with free() once unused.\n\n \\param[in]\tpPayload\t\t\t\tPayload.\n \\return\t\t\t\t\t\t\t\tPayload buffer if successful, NULL otherwise."] + pub fn sbgEComProtocolPayloadMoveBuffer( + pPayload: *mut SbgEComProtocolPayload, + ) -> *mut ::core::ffi::c_void; +} +extern "C" { + #[doc = " Initialize the protocol system used to communicate with the product and return the created handle.\n\n \\param[in]\tpProtocol\t\t\t\tPointer on an allocated protocol structure to initialize.\n \\param[in]\tpInterface\t\t\t\tInterface to use for read/write operations.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR if we have initialised the protocol system."] + pub fn sbgEComProtocolInit( + pProtocol: *mut SbgEComProtocol, + pInterface: *mut SbgInterface, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Close the protocol system.\n\n \\param[in]\tpProtocol\t\t\t\tA valid protocol handle to close.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR if we have closed and released the protocol system."] + pub fn sbgEComProtocolClose(pProtocol: *mut SbgEComProtocol) -> SbgErrorCode; +} +extern "C" { + #[doc = " Purge the interface rx buffer as well as the sbgECom rx work buffer.\n\n For example, if the program flow has been interrupted, this method can be helpful to discard all trash received data.\n\n WARNING: This method is blocking for 100ms and actively tries to read incoming data.\n\n \\param[in]\tpProtocol\t\t\t\t\t\tA valid SbgEComProtocol handle.\n \\return\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the incoming data has been purged successfully."] + pub fn sbgEComProtocolPurgeIncoming(pProtocol: *mut SbgEComProtocol) -> SbgErrorCode; +} +extern "C" { + #[doc = " Send data.\n\n If the size is SBG_ECOM_MAX_PAYLOAD_SIZE or less, the data is sent in a single frame. Otherwise,\n is it fragmented into multiple extended frames, each sent in order, which may block.\n\n \\param[in]\tpProtocol\t\t\t\tA valid protocol handle.\n \\param[in]\tmsgClass\t\t\t\tMessage class.\n \\param[in]\tmsg\t\t\t\t\t\tMessage ID.\n \\param[in]\tpData\t\t\t\t\tData buffer.\n \\param[in]\tsize\t\t\t\t\tData buffer size, in bytes.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR if the frame has been sent."] + pub fn sbgEComProtocolSend( + pProtocol: *mut SbgEComProtocol, + msgClass: u8, + msg: u8, + pData: *const ::core::ffi::c_void, + size: usize, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Receive a frame.\n\n \\param[in]\tpProtocol\t\t\t\tA valid protocol handle.\n \\param[out]\tpMsgClass\t\t\t\tMessage class, may be NULL.\n \\param[out]\tpMsgId\t\t\t\t\tMessage ID, may be NULL.\n \\param[out]\tpData\t\t\t\t\tData buffer.\n \\param[out]\tpSize\t\t\t\t\tNumber of bytes received.\n \\param[in]\tmaxSize\t\t\t\t\tData buffer size, in bytes.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful,\n\t\t\t\t\t\t\t\t\t\tSBG_NOT_READY if no complete frame has been received,\n\t\t\t\t\t\t\t\t\t\tSBG_BUFFER_OVERFLOW if the payload of the received frame couldn't fit into the data buffer."] + pub fn sbgEComProtocolReceive( + pProtocol: *mut SbgEComProtocol, + pMsgClass: *mut u8, + pMsgId: *mut u8, + pData: *mut ::core::ffi::c_void, + pSize: *mut usize, + maxSize: usize, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Receive a frame.\n\n This function is equivalent to sbgEComProtocolReceive() with two exceptions :\n - the use of a payload object allows handling payloads not limited by the size of a user-provided buffer\n - the payload object allows direct access to the protocol work buffer to avoid an extra copy per call\n\n Any allocated resource associated with the given payload is released when calling this function.\n\n Because the payload buffer may directly refer to the protocol work buffer on return, it is only valid until\n the next attempt to receive a frame, with any of the receive functions.\n\n \\param[in]\tpProtocol\t\t\t\tA valid protocol handle.\n \\param[out]\tpMsgClass\t\t\t\tMessage class, may be NULL.\n \\param[out]\tpMsgId\t\t\t\t\tMessage ID, may be NULL.\n \\param[out]\tpPayload\t\t\t\tPayload.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful,\n\t\t\t\t\t\t\t\t\t\tSBG_NOT_READY if no complete frame has been received."] + pub fn sbgEComProtocolReceive2( + pProtocol: *mut SbgEComProtocol, + pMsgClass: *mut u8, + pMsgId: *mut u8, + pPayload: *mut SbgEComProtocolPayload, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Initialize an output stream for an sbgECom frame generation.\n\n This function is helpful to avoid memory copy compared to sbgEComProtocolSend one.\n\n Only standard frames may be sent with this function.\n\n \\param[in]\tpOutputStream\t\t\tPointer to an allocated and initialized output stream.\n \\param[in]\tmsgClass\t\t\t\tMessage class.\n \\param[in]\tmsg\t\t\t\t\t\tMessage ID.\n \\param[out]\tpStreamCursor\t\t\tThe initial output stream cursor that thus points to the begining of the generated message.\n\t\t\t\t\t\t\t\t\t\tThis value should be passed to sbgEComFinalizeFrameGeneration for correct operations.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR in case of good operation."] + pub fn sbgEComStartFrameGeneration( + pOutputStream: *mut SbgStreamBuffer, + msgClass: u8, + msg: u8, + pStreamCursor: *mut usize, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Finalize an output stream that has been initialized with sbgEComStartFrameGeneration.\n\n At return, the output stream buffer should point at the end of the generated message.\n You can thus easily create consecutive SBG_ECOM_LOGS with these methods.\n\n \\param[in]\tpOutputStream\t\t\tPointer to an allocated and initialized output stream.\n \\param[in]\tstreamCursor\t\t\tPosition in the stream buffer of the generated message first byte.\n\t\t\t\t\t\t\t\t\t\tThis value is returned by sbgEComStartFrameGeneration and is mandatory for correct operations.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR in case of good operation."] + pub fn sbgEComFinalizeFrameGeneration( + pOutputStream: *mut SbgStreamBuffer, + streamCursor: usize, + ) -> SbgErrorCode; +} +#[doc = " Log structure for AirData."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogAirData { + #[doc = "< Time in us since the sensor power up OR measurement delay in us."] + pub timeStamp: u32, + #[doc = "< Airdata sensor status bitmask."] + pub status: u16, + #[doc = "< Raw absolute pressure measured by the barometer sensor in Pascals."] + pub pressureAbs: f32, + #[doc = "< Altitude computed from barometric altimeter in meters and positive upward."] + pub altitude: f32, + #[doc = "< Raw differential pressure measured by the pitot tube in Pascal."] + pub pressureDiff: f32, + #[doc = "< True airspeed measured by a pitot tube in m.s^-1 and positive forward."] + pub trueAirspeed: f32, + #[doc = "< Outside air temperature in °C that could be used to compute true airspeed from differential pressure."] + pub airTemperature: f32, +} +#[test] +fn bindgen_test_layout__SbgLogAirData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogAirData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogAirData>(), + 28usize, + concat!("Size of: ", stringify!(_SbgLogAirData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogAirData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogAirData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogAirData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogAirData), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pressureAbs) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogAirData), + "::", + stringify!(pressureAbs) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).altitude) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogAirData), + "::", + stringify!(altitude) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pressureDiff) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogAirData), + "::", + stringify!(pressureDiff) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).trueAirspeed) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogAirData), + "::", + stringify!(trueAirspeed) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).airTemperature) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogAirData), + "::", + stringify!(airTemperature) + ) + ); +} +#[doc = " Log structure for AirData."] +pub type SbgLogAirData = _SbgLogAirData; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_AIR_DATA message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseAirData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogAirData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_AIR_DATA message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteAirData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogAirData, + ) -> SbgErrorCode; +} +#[doc = " Log structure for Depth sensor measurement (subsea)."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogDepth { + #[doc = "< Time in us since the sensor power up OR measurement delay in us."] + pub timeStamp: u32, + #[doc = "< Airdata sensor status bitmask."] + pub status: u16, + #[doc = "< Raw absolute pressure measured by the depth sensor in Pascals."] + pub pressureAbs: f32, + #[doc = "< Altitude computed from depth sensor in meters and positive upward."] + pub altitude: f32, +} +#[test] +fn bindgen_test_layout__SbgLogDepth() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogDepth> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogDepth>(), + 16usize, + concat!("Size of: ", stringify!(_SbgLogDepth)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogDepth>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogDepth)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDepth), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDepth), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pressureAbs) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDepth), + "::", + stringify!(pressureAbs) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).altitude) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDepth), + "::", + stringify!(altitude) + ) + ); +} +#[doc = " Log structure for Depth sensor measurement (subsea)."] +pub type SbgLogDepth = _SbgLogDepth; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_DEPTH message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseDepth( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogDepth, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_DEPTH message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteDepth( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogDepth, + ) -> SbgErrorCode; +} +#[doc = " Diagnostic log structure."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogDiagData { + #[doc = "< Timestamp, in microseconds."] + pub timestamp: u32, + #[doc = "< Log type."] + pub type_: SbgDebugLogType, + #[doc = "< Error code."] + pub errorCode: SbgErrorCode, + #[doc = "< Log string, null-terminated."] + pub string: [::core::ffi::c_char; 4080usize], +} +#[test] +fn bindgen_test_layout__SbgLogDiagData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogDiagData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogDiagData>(), + 4092usize, + concat!("Size of: ", stringify!(_SbgLogDiagData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogDiagData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogDiagData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timestamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDiagData), + "::", + stringify!(timestamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).type_) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDiagData), + "::", + stringify!(type_) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).errorCode) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDiagData), + "::", + stringify!(errorCode) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).string) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDiagData), + "::", + stringify!(string) + ) + ); +} +#[doc = " Diagnostic log structure."] +pub type SbgLogDiagData = _SbgLogDiagData; +extern "C" { + #[doc = "\tParse data for SBG_ECOM_LOG_DIAG messages and fill the corresponding structure.\n\n\t\\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n\t\\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n\t\\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseDiagData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogDiagData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for SBG_ECOM_LOG_DIAG messages to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteDiagData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogDiagData, + ) -> SbgErrorCode; +} +#[doc = " Log structure for DVL data."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogDvlData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< DVL status bitmask."] + pub status: u16, + #[doc = "< X, Y, Z velocities in m.s^-1 expressed in the DVL instrument frame."] + pub velocity: [f32; 3usize], + #[doc = "< X, Y, Z velocities quality indicators as provided by the DVL sensor and expressed in m.s^-1.\nWARNING: This is typically just a residual information and not a real standard deviation."] + pub velocityQuality: [f32; 3usize], +} +#[test] +fn bindgen_test_layout__SbgLogDvlData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogDvlData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogDvlData>(), + 32usize, + concat!("Size of: ", stringify!(_SbgLogDvlData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogDvlData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogDvlData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDvlData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDvlData), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).velocity) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDvlData), + "::", + stringify!(velocity) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).velocityQuality) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogDvlData), + "::", + stringify!(velocityQuality) + ) + ); +} +#[doc = " Log structure for DVL data."] +pub type SbgLogDvlData = _SbgLogDvlData; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_DVL_BOTTOM_TRACK / SBG_ECOM_LOG_DVL_WATER_TRACK message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseDvlData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogDvlData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_DVL_BOTTOM_TRACK / SBG_ECOM_LOG_DVL_WATER_TRACK message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteDvlData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogDvlData, + ) -> SbgErrorCode; +} +#[doc = "< The Kalman filter is not initialized and the returned data are all invalid."] +pub const _SbgEComSolutionMode_SBG_ECOM_SOL_MODE_UNINITIALIZED: _SbgEComSolutionMode = 0; +#[doc = "< The Kalman filter only rely on a vertical reference to compute roll and pitch angles. Heading and navigation data drift freely."] +pub const _SbgEComSolutionMode_SBG_ECOM_SOL_MODE_VERTICAL_GYRO: _SbgEComSolutionMode = 1; +#[doc = "< A heading reference is available, the Kalman filter provides full orientation but navigation data drift freely."] +pub const _SbgEComSolutionMode_SBG_ECOM_SOL_MODE_AHRS: _SbgEComSolutionMode = 2; +#[doc = "< The Kalman filter computes orientation and velocity. Position is freely integrated from velocity estimation."] +pub const _SbgEComSolutionMode_SBG_ECOM_SOL_MODE_NAV_VELOCITY: _SbgEComSolutionMode = 3; +#[doc = "< Nominal mode, the Kalman filter computes all parameters (attitude, velocity, position). Absolute position is provided."] +pub const _SbgEComSolutionMode_SBG_ECOM_SOL_MODE_NAV_POSITION: _SbgEComSolutionMode = 4; +#[doc = " Solution filter mode enum."] +pub type _SbgEComSolutionMode = ::core::ffi::c_uint; +#[doc = " Solution filter mode enum."] +pub use self::_SbgEComSolutionMode as SbgEComSolutionMode; +#[doc = " EKF computed orientation using euler angles."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogEkfEulerData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< Roll, Pitch and Yaw angles in rad."] + pub euler: [f32; 3usize], + #[doc = "< Roll, Pitch and Yaw angles 1 sigma standard deviation in rad."] + pub eulerStdDev: [f32; 3usize], + #[doc = "< EKF solution status bitmask and enum."] + pub status: u32, +} +#[test] +fn bindgen_test_layout__SbgLogEkfEulerData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogEkfEulerData> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogEkfEulerData>(), + 32usize, + concat!("Size of: ", stringify!(_SbgLogEkfEulerData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogEkfEulerData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogEkfEulerData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfEulerData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).euler) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfEulerData), + "::", + stringify!(euler) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).eulerStdDev) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfEulerData), + "::", + stringify!(eulerStdDev) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfEulerData), + "::", + stringify!(status) + ) + ); +} +#[doc = " EKF computed orientation using euler angles."] +pub type SbgLogEkfEulerData = _SbgLogEkfEulerData; +#[doc = " EFK computed orientation using quaternion."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogEkfQuatData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< Orientation quaternion stored in W, X, Y, Z form."] + pub quaternion: [f32; 4usize], + #[doc = "< Roll, Pitch and Yaw angles 1 sigma standard deviation in rad."] + pub eulerStdDev: [f32; 3usize], + #[doc = "< EKF solution status bitmask and enum."] + pub status: u32, +} +#[test] +fn bindgen_test_layout__SbgLogEkfQuatData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogEkfQuatData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogEkfQuatData>(), + 36usize, + concat!("Size of: ", stringify!(_SbgLogEkfQuatData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogEkfQuatData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogEkfQuatData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfQuatData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).quaternion) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfQuatData), + "::", + stringify!(quaternion) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).eulerStdDev) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfQuatData), + "::", + stringify!(eulerStdDev) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfQuatData), + "::", + stringify!(status) + ) + ); +} +#[doc = " EFK computed orientation using quaternion."] +pub type SbgLogEkfQuatData = _SbgLogEkfQuatData; +#[doc = " EFK computed navigation data."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogEkfNavData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< North, East, Down velocity in m.s^-1."] + pub velocity: [f32; 3usize], + #[doc = "< North, East, Down velocity 1 sigma standard deviation in m.s^-1."] + pub velocityStdDev: [f32; 3usize], + #[doc = "< Latitude, Longitude in degrees positive North and East.\nAltitude above Mean Sea Level in meters."] + pub position: [f64; 3usize], + #[doc = "< Altitude difference between the geoid and the Ellipsoid in meters (Height above Ellipsoid = altitude + undulation)."] + pub undulation: f32, + #[doc = "< Latitude, longitude and altitude 1 sigma standard deviation in meters."] + pub positionStdDev: [f32; 3usize], + #[doc = "< EKF solution status bitmask and enum."] + pub status: u32, +} +#[test] +fn bindgen_test_layout__SbgLogEkfNavData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogEkfNavData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogEkfNavData>(), + 80usize, + concat!("Size of: ", stringify!(_SbgLogEkfNavData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogEkfNavData>(), + 8usize, + concat!("Alignment of ", stringify!(_SbgLogEkfNavData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfNavData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).velocity) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfNavData), + "::", + stringify!(velocity) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).velocityStdDev) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfNavData), + "::", + stringify!(velocityStdDev) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).position) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfNavData), + "::", + stringify!(position) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).undulation) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfNavData), + "::", + stringify!(undulation) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).positionStdDev) as usize - ptr as usize }, + 60usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfNavData), + "::", + stringify!(positionStdDev) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 72usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEkfNavData), + "::", + stringify!(status) + ) + ); +} +#[doc = " EFK computed navigation data."] +pub type SbgLogEkfNavData = _SbgLogEkfNavData; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_EKF_EULER message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseEkfEulerData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogEkfEulerData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_EKF_EULER message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteEkfEulerData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogEkfEulerData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_EKF_QUAT message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseEkfQuatData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogEkfQuatData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_EKF_QUAT message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteEkfQuatData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogEkfQuatData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_EKF_NAV message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseEkfNavData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogEkfNavData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_EKF_NAV message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteEkfNavData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogEkfNavData, + ) -> SbgErrorCode; +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_EVENT_# message."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogEvent { + #[doc = "< Measurement time since the sensor power up."] + pub timeStamp: u32, + #[doc = "< Events status bitmask."] + pub status: u16, + #[doc = "< Time offset for the second received event."] + pub timeOffset0: u16, + #[doc = "< Time offset for the third received event."] + pub timeOffset1: u16, + #[doc = "< Time offset for the fourth received event."] + pub timeOffset2: u16, + #[doc = "< Time offset for the fifth received event."] + pub timeOffset3: u16, +} +#[test] +fn bindgen_test_layout__SbgLogEvent() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogEvent> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogEvent>(), + 16usize, + concat!("Size of: ", stringify!(_SbgLogEvent)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogEvent>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogEvent)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEvent), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEvent), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeOffset0) as usize - ptr as usize }, + 6usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEvent), + "::", + stringify!(timeOffset0) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeOffset1) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEvent), + "::", + stringify!(timeOffset1) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeOffset2) as usize - ptr as usize }, + 10usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEvent), + "::", + stringify!(timeOffset2) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeOffset3) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogEvent), + "::", + stringify!(timeOffset3) + ) + ); +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_EVENT_# message."] +pub type SbgLogEvent = _SbgLogEvent; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_EVENT_# message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseEvent( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogEvent, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_EVENT_# message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteEvent( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogEvent, + ) -> SbgErrorCode; +} +#[doc = " Structure that stores raw data message."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogRawData { + #[doc = "< Buffer that contains raw data."] + pub rawBuffer: [u8; 4086usize], + #[doc = "< Raw buffer size in bytes."] + pub bufferSize: usize, +} +#[test] +fn bindgen_test_layout__SbgLogRawData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogRawData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogRawData>(), + 4092usize, + concat!("Size of: ", stringify!(_SbgLogRawData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogRawData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogRawData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).rawBuffer) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogRawData), + "::", + stringify!(rawBuffer) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).bufferSize) as usize - ptr as usize }, + 4088usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogRawData), + "::", + stringify!(bufferSize) + ) + ); +} +#[doc = " Structure that stores raw data message."] +pub type SbgLogRawData = _SbgLogRawData; +extern "C" { + #[doc = " Parse raw data message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseRawData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogRawData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write raw data message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteRawData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogRawData, + ) -> SbgErrorCode; +} +#[doc = "< A valid solution has been computed."] +pub const _SbgEComGpsVelStatus_SBG_ECOM_VEL_SOL_COMPUTED: _SbgEComGpsVelStatus = 0; +#[doc = "< Not enough valid SV to compute a solution."] +pub const _SbgEComGpsVelStatus_SBG_ECOM_VEL_INSUFFICIENT_OBS: _SbgEComGpsVelStatus = 1; +#[doc = "< An internal error has occurred."] +pub const _SbgEComGpsVelStatus_SBG_ECOM_VEL_INTERNAL_ERROR: _SbgEComGpsVelStatus = 2; +#[doc = "< Velocity limit exceeded."] +pub const _SbgEComGpsVelStatus_SBG_ECOM_VEL_LIMIT: _SbgEComGpsVelStatus = 3; +#[doc = " GPS velocity status definitions."] +pub type _SbgEComGpsVelStatus = ::core::ffi::c_uint; +#[doc = " GPS velocity status definitions."] +pub use self::_SbgEComGpsVelStatus as SbgEComGpsVelStatus; +#[doc = "< No valid velocity solution available."] +pub const _SbgEComGpsVelType_SBG_ECOM_VEL_NO_SOLUTION: _SbgEComGpsVelType = 0; +#[doc = "< An unknown solution type has been computed."] +pub const _SbgEComGpsVelType_SBG_ECOM_VEL_UNKNOWN_TYPE: _SbgEComGpsVelType = 1; +#[doc = "< A Doppler velocity has been computed."] +pub const _SbgEComGpsVelType_SBG_ECOM_VEL_DOPPLER: _SbgEComGpsVelType = 2; +#[doc = "< A differential velocity has been computed between two positions."] +pub const _SbgEComGpsVelType_SBG_ECOM_VEL_DIFFERENTIAL: _SbgEComGpsVelType = 3; +#[doc = " GPS velocity types definitions."] +pub type _SbgEComGpsVelType = ::core::ffi::c_uint; +#[doc = " GPS velocity types definitions."] +pub use self::_SbgEComGpsVelType as SbgEComGpsVelType; +#[doc = "< A valid solution has been computed."] +pub const _SbgEComGpsPosStatus_SBG_ECOM_POS_SOL_COMPUTED: _SbgEComGpsPosStatus = 0; +#[doc = "< Not enough valid SV to compute a solution."] +pub const _SbgEComGpsPosStatus_SBG_ECOM_POS_INSUFFICIENT_OBS: _SbgEComGpsPosStatus = 1; +#[doc = "< An internal error has occurred."] +pub const _SbgEComGpsPosStatus_SBG_ECOM_POS_INTERNAL_ERROR: _SbgEComGpsPosStatus = 2; +#[doc = "< The height limit has been exceeded."] +pub const _SbgEComGpsPosStatus_SBG_ECOM_POS_HEIGHT_LIMIT: _SbgEComGpsPosStatus = 3; +#[doc = " GPS position status definitions."] +pub type _SbgEComGpsPosStatus = ::core::ffi::c_uint; +#[doc = " GPS position status definitions."] +pub use self::_SbgEComGpsPosStatus as SbgEComGpsPosStatus; +#[doc = "< No valid solution available."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_NO_SOLUTION: _SbgEComGpsPosType = 0; +#[doc = "< An unknown solution type has been computed."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_UNKNOWN_TYPE: _SbgEComGpsPosType = 1; +#[doc = "< Single point solution position."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_SINGLE: _SbgEComGpsPosType = 2; +#[doc = "< Standard Pseudorange Differential Solution (DGPS)."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_PSRDIFF: _SbgEComGpsPosType = 3; +#[doc = "< SBAS satellite used for differential corrections."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_SBAS: _SbgEComGpsPosType = 4; +#[doc = "< Omnistar VBS Position (L1 sub-meter)."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_OMNISTAR: _SbgEComGpsPosType = 5; +#[doc = "< Floating RTK ambiguity solution (20 cms RTK)."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_RTK_FLOAT: _SbgEComGpsPosType = 6; +#[doc = "< Integer RTK ambiguity solution (2 cms RTK)."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_RTK_INT: _SbgEComGpsPosType = 7; +#[doc = "< Precise Point Positioning with float ambiguities."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_PPP_FLOAT: _SbgEComGpsPosType = 8; +#[doc = "< Precise Point Positioning with fixed ambiguities."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_PPP_INT: _SbgEComGpsPosType = 9; +#[doc = "< Fixed location solution position."] +pub const _SbgEComGpsPosType_SBG_ECOM_POS_FIXED: _SbgEComGpsPosType = 10; +#[doc = " GPS position types definitions."] +pub type _SbgEComGpsPosType = ::core::ffi::c_uint; +#[doc = " GPS position types definitions."] +pub use self::_SbgEComGpsPosType as SbgEComGpsPosType; +#[doc = "< A valid solution has been computed."] +pub const _SbgEComGpsHdtStatus_SBG_ECOM_HDT_SOL_COMPUTED: _SbgEComGpsHdtStatus = 0; +#[doc = "< Not enough valid SV to compute a solution."] +pub const _SbgEComGpsHdtStatus_SBG_ECOM_HDT_INSUFFICIENT_OBS: _SbgEComGpsHdtStatus = 1; +#[doc = "< An internal error has occurred."] +pub const _SbgEComGpsHdtStatus_SBG_ECOM_HDT_INTERNAL_ERROR: _SbgEComGpsHdtStatus = 2; +#[doc = "< The height limit has been exceeded."] +pub const _SbgEComGpsHdtStatus_SBG_ECOM_HDT_HEIGHT_LIMIT: _SbgEComGpsHdtStatus = 3; +#[doc = " GPS HDT status definitions."] +pub type _SbgEComGpsHdtStatus = ::core::ffi::c_uint; +#[doc = " GPS HDT status definitions."] +pub use self::_SbgEComGpsHdtStatus as SbgEComGpsHdtStatus; +#[doc = " Structure that stores data for the SBG_ECOM_LOG_GPS#_VEL message."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogGpsVel { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< GPS velocity status, type and bitmask."] + pub status: u32, + #[doc = "< GPS time of week in ms."] + pub timeOfWeek: u32, + #[doc = "< GPS North, East, Down velocity in m.s^-1."] + pub velocity: [f32; 3usize], + #[doc = "< GPS North, East, Down velocity 1 sigma accuracy in m.s^-1."] + pub velocityAcc: [f32; 3usize], + #[doc = "< Track ground course in degrees."] + pub course: f32, + #[doc = "< Course accuracy in degrees."] + pub courseAcc: f32, +} +#[test] +fn bindgen_test_layout__SbgLogGpsVel() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogGpsVel> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogGpsVel>(), + 44usize, + concat!("Size of: ", stringify!(_SbgLogGpsVel)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogGpsVel>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogGpsVel)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsVel), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsVel), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeOfWeek) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsVel), + "::", + stringify!(timeOfWeek) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).velocity) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsVel), + "::", + stringify!(velocity) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).velocityAcc) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsVel), + "::", + stringify!(velocityAcc) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).course) as usize - ptr as usize }, + 36usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsVel), + "::", + stringify!(course) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).courseAcc) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsVel), + "::", + stringify!(courseAcc) + ) + ); +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_GPS#_VEL message."] +pub type SbgLogGpsVel = _SbgLogGpsVel; +#[doc = " Structure that stores data for the SBG_ECOM_LOG_GPS#_POS message."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogGpsPos { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< GPS position status, type and bitmask."] + pub status: u32, + #[doc = "< GPS time of week in ms."] + pub timeOfWeek: u32, + #[doc = "< Latitude in degrees, positive north."] + pub latitude: f64, + #[doc = "< Longitude in degrees, positive east."] + pub longitude: f64, + #[doc = "< Altitude above Mean Sea Level in meters."] + pub altitude: f64, + #[doc = "< Altitude difference between the geoid and the Ellipsoid in meters (Height above Ellipsoid = altitude + undulation)."] + pub undulation: f32, + #[doc = "< 1 sigma latitude accuracy in meters."] + pub latitudeAccuracy: f32, + #[doc = "< 1 sigma longitude accuracy in meters."] + pub longitudeAccuracy: f32, + #[doc = "< 1 sigma altitude accuracy in meters."] + pub altitudeAccuracy: f32, + #[doc = "< Number of space vehicles used to compute the solution (since version 1.4)."] + pub numSvUsed: u8, + #[doc = "< Base station id for differential corrections (0-4095). Set to 0xFFFF if differential corrections are not used (since version 1.4)."] + pub baseStationId: u16, + #[doc = "< Differential correction age in 0.01 seconds. Set to 0XFFFF if differential corrections are not used (since version 1.4)."] + pub differentialAge: u16, +} +#[test] +fn bindgen_test_layout__SbgLogGpsPos() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogGpsPos> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogGpsPos>(), + 64usize, + concat!("Size of: ", stringify!(_SbgLogGpsPos)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogGpsPos>(), + 8usize, + concat!("Alignment of ", stringify!(_SbgLogGpsPos)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeOfWeek) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(timeOfWeek) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).latitude) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(latitude) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).longitude) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(longitude) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).altitude) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(altitude) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).undulation) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(undulation) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).latitudeAccuracy) as usize - ptr as usize }, + 44usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(latitudeAccuracy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).longitudeAccuracy) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(longitudeAccuracy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).altitudeAccuracy) as usize - ptr as usize }, + 52usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(altitudeAccuracy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).numSvUsed) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(numSvUsed) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).baseStationId) as usize - ptr as usize }, + 58usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(baseStationId) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).differentialAge) as usize - ptr as usize }, + 60usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsPos), + "::", + stringify!(differentialAge) + ) + ); +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_GPS#_POS message."] +pub type SbgLogGpsPos = _SbgLogGpsPos; +#[doc = " Structure that stores data for the SBG_ECOM_LOG_GPS#_HDT message."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogGpsHdt { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< GPS HDT status, type and bitmask."] + pub status: u16, + #[doc = "< GPS time of week in ms."] + pub timeOfWeek: u32, + #[doc = "< GPS true heading in degrees."] + pub heading: f32, + #[doc = "< 1 sigma GPS true heading accuracy in degrees."] + pub headingAccuracy: f32, + #[doc = "< GPS pitch angle measured from the master to the rover in degrees."] + pub pitch: f32, + #[doc = "< 1 signa GPS pitch angle accuarcy in degrees."] + pub pitchAccuracy: f32, + #[doc = "< The distance between the main and aux antenna in meters."] + pub baseline: f32, +} +#[test] +fn bindgen_test_layout__SbgLogGpsHdt() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogGpsHdt> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogGpsHdt>(), + 32usize, + concat!("Size of: ", stringify!(_SbgLogGpsHdt)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogGpsHdt>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogGpsHdt)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsHdt), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsHdt), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeOfWeek) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsHdt), + "::", + stringify!(timeOfWeek) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).heading) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsHdt), + "::", + stringify!(heading) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).headingAccuracy) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsHdt), + "::", + stringify!(headingAccuracy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pitch) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsHdt), + "::", + stringify!(pitch) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pitchAccuracy) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsHdt), + "::", + stringify!(pitchAccuracy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).baseline) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogGpsHdt), + "::", + stringify!(baseline) + ) + ); +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_GPS#_HDT message."] +pub type SbgLogGpsHdt = _SbgLogGpsHdt; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_GPS#_VEL message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseGpsVelData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogGpsVel, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_GPS#_VEL message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteGpsVelData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogGpsVel, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_GPS#_POS message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseGpsPosData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogGpsPos, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_GPS#_POS message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteGpsPosData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogGpsPos, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_GPS#_HDT message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseGpsHdtData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogGpsHdt, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_GPS#_HDT message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteGpsHdtData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogGpsHdt, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_GPS#_RAW message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseGpsRawData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogRawData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_GPS#_RAW message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteGpsRawData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogRawData, + ) -> SbgErrorCode; +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_IMU_DATA message."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogImuData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< IMU status bitmask."] + pub status: u16, + #[doc = "< X, Y, Z accelerometers in m.s^-2."] + pub accelerometers: [f32; 3usize], + #[doc = "< X, Y, Z gyroscopes in rad.s^-1."] + pub gyroscopes: [f32; 3usize], + #[doc = "< Internal temperature in °C."] + pub temperature: f32, + #[doc = "< X, Y, Z delta velocity in m.s^-2."] + pub deltaVelocity: [f32; 3usize], + #[doc = "< X, Y, Z delta angle in rad.s^-1."] + pub deltaAngle: [f32; 3usize], +} +#[test] +fn bindgen_test_layout__SbgLogImuData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogImuData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogImuData>(), + 60usize, + concat!("Size of: ", stringify!(_SbgLogImuData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogImuData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogImuData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuData), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).accelerometers) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuData), + "::", + stringify!(accelerometers) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gyroscopes) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuData), + "::", + stringify!(gyroscopes) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).temperature) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuData), + "::", + stringify!(temperature) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).deltaVelocity) as usize - ptr as usize }, + 36usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuData), + "::", + stringify!(deltaVelocity) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).deltaAngle) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuData), + "::", + stringify!(deltaAngle) + ) + ); +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_IMU_DATA message."] +pub type SbgLogImuData = _SbgLogImuData; +#[doc = " Structure that stores data for the SBG_ECOM_LOG_IMU_SHORT message.\n This message is only sent asynchronously and is the preferred log for post processing."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogImuShort { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< IMU status bitmask."] + pub status: u16, + #[doc = "< X, Y, Z delta velocity. Unit is 1048576 LSB for 1 m.s^-2."] + pub deltaVelocity: [i32; 3usize], + #[doc = "< X, Y, Z delta angle. Unit is 67108864 LSB for 1 rad.s^-1."] + pub deltaAngle: [i32; 3usize], + #[doc = "< IMU average temperature. Unit is 256 LSB for 1°C."] + pub temperature: i16, +} +#[test] +fn bindgen_test_layout__SbgLogImuShort() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogImuShort> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogImuShort>(), + 36usize, + concat!("Size of: ", stringify!(_SbgLogImuShort)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogImuShort>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogImuShort)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuShort), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuShort), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).deltaVelocity) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuShort), + "::", + stringify!(deltaVelocity) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).deltaAngle) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuShort), + "::", + stringify!(deltaAngle) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).temperature) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogImuShort), + "::", + stringify!(temperature) + ) + ); +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_IMU_SHORT message.\n This message is only sent asynchronously and is the preferred log for post processing."] +pub type SbgLogImuShort = _SbgLogImuShort; +#[doc = " Structure that stores the data for SBG_ECOM_LOG_FAST_IMU_DATA message"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogFastImuData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< IMU status bitmask."] + pub status: u16, + #[doc = "< X, Y, Z accelerometers in m.s^-2."] + pub accelerometers: [f32; 3usize], + #[doc = "< X, Y, Z gyroscopes in rad.s^-1."] + pub gyroscopes: [f32; 3usize], +} +#[test] +fn bindgen_test_layout__SbgLogFastImuData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogFastImuData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogFastImuData>(), + 32usize, + concat!("Size of: ", stringify!(_SbgLogFastImuData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogFastImuData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogFastImuData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogFastImuData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogFastImuData), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).accelerometers) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogFastImuData), + "::", + stringify!(accelerometers) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gyroscopes) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogFastImuData), + "::", + stringify!(gyroscopes) + ) + ); +} +#[doc = " Structure that stores the data for SBG_ECOM_LOG_FAST_IMU_DATA message"] +pub type SbgLogFastImuData = _SbgLogFastImuData; +extern "C" { + #[doc = " Return from an IMU Short log, the X, Y or Z delta angle value in rad.s^-1\n\n \\param[in]\tpImuShort\t\t\t\t\tInput IMU short message instance.\n \\param[in]\tidx\t\t\t\t\t\t\tThe component to return from 0 to 2.\n \\return\t\t\t\t\t\t\t\t\tThe delta angle value converted in rad.s^-1."] + pub fn sbgLogImuShortGetDeltaAngle(pImuShort: *const SbgLogImuShort, idx: usize) -> f32; +} +extern "C" { + #[doc = " Return from an IMU Short log, the X, Y or Z delta velocity value in m.s^-2\n\n \\param[in]\tpImuShort\t\t\t\t\tInput IMU short message instance.\n \\param[in]\tidx\t\t\t\t\t\t\tThe component to return from 0 to 2.\n \\return\t\t\t\t\t\t\t\t\tThe delta velocity value converted in m.s^-2."] + pub fn sbgLogImuShortGetDeltaVelocity(pImuShort: *const SbgLogImuShort, idx: usize) -> f32; +} +extern "C" { + #[doc = " Return from an IMU Short log, the temperature in °C\n\n \\param[in]\tpImuShort\t\t\t\t\tInput IMU short message instance.\n \\return\t\t\t\t\t\t\t\t\tThe converted temperature in °C"] + pub fn sbgLogImuShortGetTemperature(pImuShort: *const SbgLogImuShort) -> f32; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_IMU_DATA message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseImuData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogImuData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_IMU_DATA message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteImuData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogImuData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_IMU_SHORT message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseImuShort( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogImuShort, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_IMU_SHORT message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteImuShort( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogImuShort, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_FAST_IMU_DATA message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseFastImuData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogFastImuData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_FAST_IMU_DATA message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteFastImuData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogFastImuData, + ) -> SbgErrorCode; +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_MAG message."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogMag { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< Magnetometer status bitmask."] + pub status: u16, + #[doc = "< X, Y, Z magnetometer data in A.U."] + pub magnetometers: [f32; 3usize], + #[doc = "< X, Y, Z accelerometers in m.s^-2."] + pub accelerometers: [f32; 3usize], +} +#[test] +fn bindgen_test_layout__SbgLogMag() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogMag> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogMag>(), + 32usize, + concat!("Size of: ", stringify!(_SbgLogMag)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogMag>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogMag)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogMag), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogMag), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).magnetometers) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogMag), + "::", + stringify!(magnetometers) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).accelerometers) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogMag), + "::", + stringify!(accelerometers) + ) + ); +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_MAG message."] +pub type SbgLogMag = _SbgLogMag; +#[doc = " Structure that stores data for the SBG_ECOM_LOG_MAG_CALIB message."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogMagCalib { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< Reserved for future use."] + pub reserved: u16, + #[doc = "< Magnetometers calibration data."] + pub magData: [u8; 16usize], +} +#[test] +fn bindgen_test_layout__SbgLogMagCalib() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogMagCalib> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogMagCalib>(), + 24usize, + concat!("Size of: ", stringify!(_SbgLogMagCalib)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogMagCalib>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogMagCalib)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogMagCalib), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogMagCalib), + "::", + stringify!(reserved) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).magData) as usize - ptr as usize }, + 6usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogMagCalib), + "::", + stringify!(magData) + ) + ); +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_MAG_CALIB message."] +pub type SbgLogMagCalib = _SbgLogMagCalib; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_MAG message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseMagData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogMag, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_MAG message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteMagData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogMag, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_MAG_CALIB message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseMagCalibData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogMagCalib, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_MAG_CALIB message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteMagCalibData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogMagCalib, + ) -> SbgErrorCode; +} +#[doc = " Log structure for odometer data."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogOdometerData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< Odometer velocity status bitmask."] + pub status: u16, + #[doc = "< Velocity in m.s^-1 in the odometer direction."] + pub velocity: f32, +} +#[test] +fn bindgen_test_layout__SbgLogOdometerData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogOdometerData> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogOdometerData>(), + 12usize, + concat!("Size of: ", stringify!(_SbgLogOdometerData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogOdometerData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogOdometerData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogOdometerData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogOdometerData), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).velocity) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogOdometerData), + "::", + stringify!(velocity) + ) + ); +} +#[doc = " Log structure for odometer data."] +pub type SbgLogOdometerData = _SbgLogOdometerData; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_ODO_VEL message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseOdometerData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogOdometerData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_ODO_VEL message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteOdometerData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogOdometerData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_RTCM_RAW message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseRtcmRawData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogRawData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_RTCM_RAW message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteRtcmRawData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogRawData, + ) -> SbgErrorCode; +} +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_UNKNOWN: _SbgEComSignalId = 0; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L1C_DP: _SbgEComSignalId = 10; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L1C_D: _SbgEComSignalId = 11; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L1C_P: _SbgEComSignalId = 12; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L1_W: _SbgEComSignalId = 13; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L1_CA: _SbgEComSignalId = 14; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L1P: _SbgEComSignalId = 15; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L1_PY: _SbgEComSignalId = 16; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L1M: _SbgEComSignalId = 17; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L2C_ML: _SbgEComSignalId = 18; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L2C_L: _SbgEComSignalId = 19; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L2_SEMICL: _SbgEComSignalId = 20; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L2_W: _SbgEComSignalId = 21; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L2_CA: _SbgEComSignalId = 22; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L2C_M: _SbgEComSignalId = 23; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L2_PY: _SbgEComSignalId = 24; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L2M: _SbgEComSignalId = 25; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L2P: _SbgEComSignalId = 26; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L5_IQ: _SbgEComSignalId = 27; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L5_I: _SbgEComSignalId = 28; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GPS_L5_Q: _SbgEComSignalId = 29; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GLONASS_G1_P: _SbgEComSignalId = 40; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GLONASS_G1_CA: _SbgEComSignalId = 41; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GLONASS_G2_P: _SbgEComSignalId = 42; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GLONASS_G2_CA: _SbgEComSignalId = 43; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GLONASS_G3_I: _SbgEComSignalId = 44; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GLONASS_G3_Q: _SbgEComSignalId = 45; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GLONASS_G3_IQ: _SbgEComSignalId = 46; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E1_BC: _SbgEComSignalId = 60; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E1_C: _SbgEComSignalId = 61; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E1_B: _SbgEComSignalId = 62; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E1_A: _SbgEComSignalId = 63; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E1_ABC: _SbgEComSignalId = 64; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E5B_IQ: _SbgEComSignalId = 65; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E5B_I: _SbgEComSignalId = 66; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E5B_Q: _SbgEComSignalId = 67; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E5A_IQ: _SbgEComSignalId = 68; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E5A_I: _SbgEComSignalId = 69; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E5A_Q: _SbgEComSignalId = 70; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E5_IQ: _SbgEComSignalId = 71; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E5_I: _SbgEComSignalId = 72; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E5_Q: _SbgEComSignalId = 73; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E6_BC: _SbgEComSignalId = 74; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E6_C: _SbgEComSignalId = 75; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E6_B: _SbgEComSignalId = 76; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E6_ABC: _SbgEComSignalId = 77; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_GALILEO_E6_A: _SbgEComSignalId = 78; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B1IQ: _SbgEComSignalId = 100; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B1I: _SbgEComSignalId = 101; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B1Q: _SbgEComSignalId = 102; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_P: _SbgEComSignalId = 103; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_DP: _SbgEComSignalId = 104; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B1C_D: _SbgEComSignalId = 105; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_P: _SbgEComSignalId = 106; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_DP: _SbgEComSignalId = 107; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B1A_D: _SbgEComSignalId = 108; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2IQ: _SbgEComSignalId = 109; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2I: _SbgEComSignalId = 110; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_P: _SbgEComSignalId = 111; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_DP: _SbgEComSignalId = 112; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2A_D: _SbgEComSignalId = 113; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2Q: _SbgEComSignalId = 114; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_P: _SbgEComSignalId = 115; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_DP: _SbgEComSignalId = 116; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2B_D: _SbgEComSignalId = 117; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_P: _SbgEComSignalId = 118; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_DP: _SbgEComSignalId = 119; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B2AB_D: _SbgEComSignalId = 120; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B3IQ: _SbgEComSignalId = 121; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B3I: _SbgEComSignalId = 122; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B3Q: _SbgEComSignalId = 123; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_D: _SbgEComSignalId = 124; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_P: _SbgEComSignalId = 125; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_BEIDOU_B3A_DP: _SbgEComSignalId = 126; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L1C_DP: _SbgEComSignalId = 150; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L1C_D: _SbgEComSignalId = 151; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L1C_P: _SbgEComSignalId = 152; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L1_CA: _SbgEComSignalId = 153; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L1_SAIF: _SbgEComSignalId = 154; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L1_SB: _SbgEComSignalId = 155; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L2C_ML: _SbgEComSignalId = 156; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L2C_L: _SbgEComSignalId = 157; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L2C_M: _SbgEComSignalId = 158; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L5_IQ: _SbgEComSignalId = 159; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L5_I: _SbgEComSignalId = 160; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L5_Q: _SbgEComSignalId = 161; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L5S_IQ: _SbgEComSignalId = 162; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L5S_I: _SbgEComSignalId = 163; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L5S_Q: _SbgEComSignalId = 164; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L6_P: _SbgEComSignalId = 165; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L6_DP: _SbgEComSignalId = 166; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L6_D: _SbgEComSignalId = 167; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L6_E: _SbgEComSignalId = 168; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_QZSS_L6_DE: _SbgEComSignalId = 169; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_SBAS_L1_CA: _SbgEComSignalId = 180; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_SBAS_L5_I: _SbgEComSignalId = 181; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_SBAS_L5_Q: _SbgEComSignalId = 182; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_SBAS_L5_IQ: _SbgEComSignalId = 183; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_IRNSS_L5_A: _SbgEComSignalId = 200; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_IRNSS_L5_B: _SbgEComSignalId = 201; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_IRNSS_L5_C: _SbgEComSignalId = 202; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_IRNSS_L5_BC: _SbgEComSignalId = 203; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_IRNSS_S9_A: _SbgEComSignalId = 204; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_IRNSS_S9_B: _SbgEComSignalId = 205; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_IRNSS_S9_C: _SbgEComSignalId = 206; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_IRNSS_S9_BC: _SbgEComSignalId = 207; +pub const _SbgEComSignalId_SBG_ECOM_SIGNAL_ID_LBAND: _SbgEComSignalId = 220; +#[doc = " Signal IDs.\n\n These are on-the-wire values."] +pub type _SbgEComSignalId = ::core::ffi::c_uint; +#[doc = " Signal IDs.\n\n These are on-the-wire values."] +pub use self::_SbgEComSignalId as SbgEComSignalId; +pub const _SbgEComConstellationId_SBG_ECOM_CONSTELLATION_ID_UNKNOWN: _SbgEComConstellationId = 0; +pub const _SbgEComConstellationId_SBG_ECOM_CONSTELLATION_ID_GPS: _SbgEComConstellationId = 1; +pub const _SbgEComConstellationId_SBG_ECOM_CONSTELLATION_ID_GLONASS: _SbgEComConstellationId = 2; +pub const _SbgEComConstellationId_SBG_ECOM_CONSTELLATION_ID_GALILEO: _SbgEComConstellationId = 3; +pub const _SbgEComConstellationId_SBG_ECOM_CONSTELLATION_ID_BEIDOU: _SbgEComConstellationId = 4; +pub const _SbgEComConstellationId_SBG_ECOM_CONSTELLATION_ID_QZSS: _SbgEComConstellationId = 5; +pub const _SbgEComConstellationId_SBG_ECOM_CONSTELLATION_ID_SBAS: _SbgEComConstellationId = 6; +pub const _SbgEComConstellationId_SBG_ECOM_CONSTELLATION_ID_IRNSS: _SbgEComConstellationId = 7; +pub const _SbgEComConstellationId_SBG_ECOM_CONSTELLATION_ID_LBAND: _SbgEComConstellationId = 8; +#[doc = " Constellation IDs.\n\n All values must be strictly lower than 16.\n\n These are on-the-wire values."] +pub type _SbgEComConstellationId = ::core::ffi::c_uint; +#[doc = " Constellation IDs.\n\n All values must be strictly lower than 16.\n\n These are on-the-wire values."] +pub use self::_SbgEComConstellationId as SbgEComConstellationId; +extern "C" { + #[doc = " Returns a constellation given a signal ID\n\n \\param[in]\tsignalId\t\t\t\t\tSignal ID value.\n \\return\t\t\t\t\t\t\t\t\tConstellation this signal belongs to."] + pub fn sbgEComGetConstellationFromSignalId(signalId: SbgEComSignalId) + -> SbgEComConstellationId; +} +extern "C" { + #[doc = " Check if a value belongs to SbgEComSignalId enum.\n\n WARNING: SBG_ECOM_SIGNAL_ID_UNKNOWN is considered to be a valid enum value.\n\n \\param[in]\tsignalId\t\t\t\t\tSignal ID value.\n \\return\t\t\t\t\t\t\t\t\ttrue if the value is valid"] + pub fn sbgEComSignalIdIsValid(signalId: u8) -> bool; +} +extern "C" { + #[doc = " Get a signal ID as a read only C string.\n\n \\param[in]\tsignalId\t\t\t\t\tSignal ID value.\n \\return\t\t\t\t\t\t\t\t\tSignal ID as a read only C string."] + pub fn sbgEComSignalToStr(signalId: SbgEComSignalId) -> *const ::core::ffi::c_char; +} +extern "C" { + #[doc = " Check if a value belongs to SbgEComConstellationId enum.\n\n \\param[in]\tconstellationId\t\t\t\tconstellation ID value.\n \\return\t\t\t\t\t\t\t\t\ttrue if the value is valid"] + pub fn sbgEComConstellationIdIsValid(constellationId: u8) -> bool; +} +extern "C" { + #[doc = " Get a constellation ID as a read only C string.\n\n \\param[in]\tconstellationId\t\t\t\tConstellation ID value.\n \\return\t\t\t\t\t\t\t\t\tConstellation ID as a read only C string."] + pub fn sbgEComConstellationToStr( + constellationId: SbgEComConstellationId, + ) -> *const ::core::ffi::c_char; +} +#[doc = "< Unknown tracking status such as no signal / idle."] +pub const _SbgEComSatTrackingStatus_SBG_ECOM_SAT_TRACKING_STATUS_UNKNOWN: + _SbgEComSatTrackingStatus = 0; +#[doc = "< Signal is beeing searched and can't be used yet."] +pub const _SbgEComSatTrackingStatus_SBG_ECOM_SAT_TRACKING_STATUS_SEARCHING: + _SbgEComSatTrackingStatus = 1; +#[doc = "< Signal is tracked but don't know if used or not in the solution."] +pub const _SbgEComSatTrackingStatus_SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_UNKNOWN: + _SbgEComSatTrackingStatus = 2; +#[doc = "< Signal is tracked and is not used in the solution."] +pub const _SbgEComSatTrackingStatus_SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_NOT_USED: + _SbgEComSatTrackingStatus = 3; +#[doc = "< Signal is tracjed and is rejected from the solution."] +pub const _SbgEComSatTrackingStatus_SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_REJECTED: + _SbgEComSatTrackingStatus = 4; +#[doc = "< Signal is tracked and used in the solution."] +pub const _SbgEComSatTrackingStatus_SBG_ECOM_SAT_TRACKING_STATUS_TRACKING_USED: + _SbgEComSatTrackingStatus = 5; +#[doc = " Tracking status.\n\n The tracking status embeds the solution status when the latter is known.\n\n All values must be strictly lower than 8.\n\n These are on-the-wire values."] +pub type _SbgEComSatTrackingStatus = ::core::ffi::c_uint; +#[doc = " Tracking status.\n\n The tracking status embeds the solution status when the latter is known.\n\n All values must be strictly lower than 8.\n\n These are on-the-wire values."] +pub use self::_SbgEComSatTrackingStatus as SbgEComSatTrackingStatus; +#[doc = "< Don't know the satellite or the signal health status."] +pub const _SbgEComSatHealthStatus_SBG_ECOM_SAT_HEALTH_STATUS_UNKNOWN: _SbgEComSatHealthStatus = 0; +#[doc = "< The satellite or the signal is healthy and can be used."] +pub const _SbgEComSatHealthStatus_SBG_ECOM_SAT_HEALTH_STATUS_HEALTHY: _SbgEComSatHealthStatus = 1; +#[doc = "< The satellite or the signal is not healthy and can't be used."] +pub const _SbgEComSatHealthStatus_SBG_ECOM_SAT_HEALTH_STATUS_UNHEALTHY: _SbgEComSatHealthStatus = 2; +#[doc = " Health status.\n\n All values must be strictly lower than 4.\n\n These are on-the-wire values."] +pub type _SbgEComSatHealthStatus = ::core::ffi::c_uint; +#[doc = " Health status.\n\n All values must be strictly lower than 4.\n\n These are on-the-wire values."] +pub use self::_SbgEComSatHealthStatus as SbgEComSatHealthStatus; +#[doc = "< Don't know if the satellite elevation is setting or rising."] +pub const _SbgEComSatElevationStatus_SBG_ECOM_SAT_ELEVATION_STATUS_UNKNOWN: + _SbgEComSatElevationStatus = 0; +#[doc = "< The satellite elevation is setting."] +pub const _SbgEComSatElevationStatus_SBG_ECOM_SAT_ELEVATION_STATUS_SETTING: + _SbgEComSatElevationStatus = 1; +#[doc = "< The satellite elevation is rising"] +pub const _SbgEComSatElevationStatus_SBG_ECOM_SAT_ELEVATION_STATUS_RISING: + _SbgEComSatElevationStatus = 2; +#[doc = " Elevation status.\n\n All values must be strictly lower than 4.\n\n These are on-the-wire values."] +pub type _SbgEComSatElevationStatus = ::core::ffi::c_uint; +#[doc = " Elevation status.\n\n All values must be strictly lower than 4.\n\n These are on-the-wire values."] +pub use self::_SbgEComSatElevationStatus as SbgEComSatElevationStatus; +#[doc = " Satellite signal data.\n\n The flags include the snr available, health and tracking statuses."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogSatSignalData { + #[doc = "< Signal ID."] + pub id: SbgEComSignalId, + #[doc = "< Flags."] + pub flags: u8, + #[doc = "< Signal-to-noise ratio, in dB."] + pub snr: u8, +} +#[test] +fn bindgen_test_layout__SbgLogSatSignalData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogSatSignalData> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogSatSignalData>(), + 8usize, + concat!("Size of: ", stringify!(_SbgLogSatSignalData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogSatSignalData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogSatSignalData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatSignalData), + "::", + stringify!(id) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatSignalData), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).snr) as usize - ptr as usize }, + 5usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatSignalData), + "::", + stringify!(snr) + ) + ); +} +#[doc = " Satellite signal data.\n\n The flags include the snr available, health and tracking statuses."] +pub type SbgLogSatSignalData = _SbgLogSatSignalData; +#[doc = " Satellite data.\n\n The flags include the constellation ID, the elevation status, the health status, and the tracking status.\n\n Satellite data and signal data each have their own health and tracking statuses. The statuses of satellite\n data may be a priority-based summary of the statuses of signal data, or they may reflect information that\n is limited to a satellite and unavailable for its signals.\n\n The priority rules are :\n - health status : unhealthy -> healthy -> unknown\n - tracking status : tracking and used -> tracking and not used -> tracking (solution status unknown) -> searching -> unknown\n\n For example, if satellite data have an unknown tracking status, and have three signals, one with the\n searching status, another with the tracking and not used status, and the last with the tracking and used status,\n the satellite data tracking status will be tracking and used.\n But if those satellite data are initially set with a healthy health status, and all three signals added have the\n unknown health status, the satellite data health status remains healthy."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogSatData { + #[doc = "< Satellite ID."] + pub id: u8, + #[doc = "< Elevation, in degrees [-90; +90], valid if and only if the elevation is known."] + pub elevation: i8, + #[doc = "< Azimuth, in degrees [0; 359], valid if and only if the elevation is known."] + pub azimuth: u16, + #[doc = "< Flags."] + pub flags: u16, + #[doc = "< Number of signals."] + pub nrSignals: usize, + #[doc = "< Size of the signal data array."] + pub signalDataArraySize: usize, + #[doc = "< Signal data array."] + pub pSignalData: *mut SbgLogSatSignalData, +} +#[test] +fn bindgen_test_layout__SbgLogSatData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogSatData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogSatData>(), + 20usize, + concat!("Size of: ", stringify!(_SbgLogSatData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogSatData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogSatData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).id) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatData), + "::", + stringify!(id) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).elevation) as usize - ptr as usize }, + 1usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatData), + "::", + stringify!(elevation) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).azimuth) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatData), + "::", + stringify!(azimuth) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatData), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).nrSignals) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatData), + "::", + stringify!(nrSignals) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).signalDataArraySize) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatData), + "::", + stringify!(signalDataArraySize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pSignalData) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatData), + "::", + stringify!(pSignalData) + ) + ); +} +#[doc = " Satellite data.\n\n The flags include the constellation ID, the elevation status, the health status, and the tracking status.\n\n Satellite data and signal data each have their own health and tracking statuses. The statuses of satellite\n data may be a priority-based summary of the statuses of signal data, or they may reflect information that\n is limited to a satellite and unavailable for its signals.\n\n The priority rules are :\n - health status : unhealthy -> healthy -> unknown\n - tracking status : tracking and used -> tracking and not used -> tracking (solution status unknown) -> searching -> unknown\n\n For example, if satellite data have an unknown tracking status, and have three signals, one with the\n searching status, another with the tracking and not used status, and the last with the tracking and used status,\n the satellite data tracking status will be tracking and used.\n But if those satellite data are initially set with a healthy health status, and all three signals added have the\n unknown health status, the satellite data health status remains healthy."] +pub type SbgLogSatData = _SbgLogSatData; +#[doc = " Satellite group data."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogSatGroupData { + #[doc = "< Time since the sensor power up, in us."] + pub timeStamp: u32, + #[doc = "< Reserved for future use."] + pub reserved: u32, + #[doc = "< Number of satellites."] + pub nrSatellites: usize, + #[doc = "< Size of the satellite data array."] + pub satDataArraySize: usize, + #[doc = "< Satellite data array."] + pub pSatData: *mut SbgLogSatData, +} +#[test] +fn bindgen_test_layout__SbgLogSatGroupData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogSatGroupData> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogSatGroupData>(), + 20usize, + concat!("Size of: ", stringify!(_SbgLogSatGroupData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogSatGroupData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogSatGroupData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatGroupData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).reserved) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatGroupData), + "::", + stringify!(reserved) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).nrSatellites) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatGroupData), + "::", + stringify!(nrSatellites) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).satDataArraySize) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatGroupData), + "::", + stringify!(satDataArraySize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pSatData) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogSatGroupData), + "::", + stringify!(pSatData) + ) + ); +} +#[doc = " Satellite group data."] +pub type SbgLogSatGroupData = _SbgLogSatGroupData; +extern "C" { + #[doc = " Parse satellite group data from a stream buffer.\n\n This function constructs the satellite group data, which must be destroyed once not needed any more.\n\n \\param[in]\tpStreamBuffer\t\t\t\tStream buffer.\n \\param[out]\tpSatGroupData\t\t\t\tSatellite group data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful."] + pub fn sbgEComBinaryLogParseSatGroupData( + pStreamBuffer: *mut SbgStreamBuffer, + pSatGroupData: *mut SbgLogSatGroupData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write satellite group data to a stream buffer.\n\n \\param[out]\tpStreamBuffer\t\t\t\tStream buffer.\n \\param[in]\tpSatGroupData\t\t\t\tSatellite group data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful."] + pub fn sbgEComBinaryLogWriteSatGroupData( + pStreamBuffer: *mut SbgStreamBuffer, + pSatGroupData: *const SbgLogSatGroupData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Satellite group data constructor.\n\n \\param[in]\tpSatGroupData\t\t\t\tSatellite group data.\n \\param[in]\tnrSatellites\t\t\t\tNumber of satellites.\n \\param[in]\ttimeStamp\t\t\t\t\tTime stamp, in us.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful."] + pub fn sbgLogSatGroupDataConstruct( + pSatGroupData: *mut SbgLogSatGroupData, + nrSatellites: usize, + timeStamp: u32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Satellite group data destructor.\n\n \\param[in]\tpSatGroupData\t\t\t\tSatellite group data."] + pub fn sbgLogSatGroupDataDestroy(pSatGroupData: *mut SbgLogSatGroupData); +} +extern "C" { + #[doc = " Add satellite data to satellite group data.\n\n \\param[in]\tpSatGroupData\t\t\t\tSatellite group data.\n \\param[in]\tnrSignals\t\t\t\t\tNumber of signals.\n \\param[in]\tid\t\t\t\t\t\t\tSatellite ID.\n \\param[in]\televation\t\t\t\t\tElevation, in degrees.\n \\param[in]\tazimuth\t\t\t\t\t\tAzimuth, in degrees.\n \\param[in]\tconstellationId\t\t\t\tConstellation ID.\n \\param[in]\televationStatus\t\t\t\tElevation status.\n \\param[in]\thealthStatus\t\t\t\tHealth status.\n \\param[in]\ttrackingStatus\t\t\t\tTracking status.\n \\return\t\t\t\t\t\t\t\t\tSatellite data, NULL if an error occurs."] + pub fn sbgLogSatGroupDataAdd( + pSatGroupData: *mut SbgLogSatGroupData, + nrSignals: usize, + id: u8, + elevation: i8, + azimuth: u16, + constellationId: SbgEComConstellationId, + elevationStatus: SbgEComSatElevationStatus, + healthStatus: SbgEComSatHealthStatus, + trackingStatus: SbgEComSatTrackingStatus, + ) -> *mut SbgLogSatData; +} +extern "C" { + #[doc = " Get satellite data from satellite group data.\n\n \\param[in]\tpSatGroupData\t\t\t\tSatellite group data.\n \\param[in]\tid\t\t\t\t\t\t\tSatellite ID.\n \\return\t\t\t\t\t\t\t\t\tSatellite data, NULL if not found."] + pub fn sbgLogSatGroupGet(pSatGroupData: *mut SbgLogSatGroupData, id: u8) -> *mut SbgLogSatData; +} +extern "C" { + #[doc = " Get the constellation ID of satellite data.\n\n \\param[in]\tpSatData\t\t\t\t\tSatellite data.\n \\return\t\t\t\t\t\t\t\t\tConstellation ID."] + pub fn sbgLogSatDataGetConstellationId( + pSatData: *const SbgLogSatData, + ) -> SbgEComConstellationId; +} +extern "C" { + #[doc = " Get the constellation ID of satellite data as a read only C string.\n\n \\param[in]\tpSatData\t\t\t\t\tSatellite data.\n \\return\t\t\t\t\t\t\t\t\tConstellation ID as a read only C string."] + pub fn sbgLogSatDataGetConstellationIdAsStr( + pSatData: *const SbgLogSatData, + ) -> *const ::core::ffi::c_char; +} +extern "C" { + #[doc = " Get the elevation status of satellite data.\n\n \\param[in]\tpSatData\t\t\t\t\tSatellite data.\n \\return\t\t\t\t\t\t\t\t\tElevation status."] + pub fn sbgLogSatDataGetElevationStatus( + pSatData: *const SbgLogSatData, + ) -> SbgEComSatElevationStatus; +} +extern "C" { + #[doc = " Get the elevation status of satellite data as a read only C string.\n\n \\param[in]\tpSatData\t\t\t\t\tSatellite data.\n \\return\t\t\t\t\t\t\t\t\tElevation status as a read only C string."] + pub fn sbgLogSatDataGetElevationStatusAsStr( + pSatData: *const SbgLogSatData, + ) -> *const ::core::ffi::c_char; +} +extern "C" { + #[doc = " Get the health status of satellite data.\n\n \\param[in]\tpSatData\t\t\t\t\tSatellite data.\n \\return\t\t\t\t\t\t\t\t\tHealth status."] + pub fn sbgLogSatDataGetHealthStatus(pSatData: *const SbgLogSatData) -> SbgEComSatHealthStatus; +} +extern "C" { + #[doc = " Get the health status of satellite data as a read only C string.\n\n \\param[in]\tpSatData\t\t\t\t\tSatellite data.\n \\return\t\t\t\t\t\t\t\t\tHealth status as a read only C string."] + pub fn sbgLogSatDataGetHealthStatusAsStr( + pSatData: *const SbgLogSatData, + ) -> *const ::core::ffi::c_char; +} +extern "C" { + #[doc = " Get the tracking status of satellite data.\n\n \\param[in]\tpSatData\t\t\t\t\tSatellite data.\n \\return\t\t\t\t\t\t\t\t\tTracking status."] + pub fn sbgLogSatDataGetTrackingStatus( + pSatData: *const SbgLogSatData, + ) -> SbgEComSatTrackingStatus; +} +extern "C" { + #[doc = " Get the tracking status of satellite data as a read only C string.\n\n \\param[in]\tpSatData\t\t\t\t\tSatellite data.\n \\return\t\t\t\t\t\t\t\t\tTracking status as a read only C string."] + pub fn sbgLogSatDataGetTrackingStatusAsStr( + pSatData: *const SbgLogSatData, + ) -> *const ::core::ffi::c_char; +} +extern "C" { + #[doc = " Add signal data to satellite data.\n\n The health and tracking statuses of the satellite data are updated according to their respective\n priority rules.\n\n \\param[in]\tpSatData\t\t\t\t\tSatellite data.\n \\param[in]\tid\t\t\t\t\t\t\tSignal ID.\n \\param[in]\thealthStatus\t\t\t\tHealth status.\n \\param[in]\ttrackingStatus\t\t\t\tTracking status.\n \\param[in]\tsnrValid\t\t\t\t\tSet to true if the SNR value is valid.\n \\param[in]\tsnr\t\t\t\t\t\t\tSignal-to-noise ratio, in dB.\n \\return\t\t\t\t\t\t\t\t\tSignal data, NULL if an error occurs."] + pub fn sbgLogSatDataAdd( + pSatData: *mut SbgLogSatData, + id: SbgEComSignalId, + healthStatus: SbgEComSatHealthStatus, + trackingStatus: SbgEComSatTrackingStatus, + snrValid: bool, + snr: u8, + ) -> *mut SbgLogSatSignalData; +} +extern "C" { + #[doc = " Get signal data from satellite data.\n\n \\param[in]\tpSatData\t\t\t\t\tSatellite data.\n \\param[in]\tid\t\t\t\t\t\t\tSignal ID.\n \\return\t\t\t\t\t\t\t\t\tSignal data, NULL if not found."] + pub fn sbgLogSatDataGet( + pSatData: *mut SbgLogSatData, + id: SbgEComSignalId, + ) -> *mut SbgLogSatSignalData; +} +extern "C" { + #[doc = " Get a signal id as a read only C string.\n\n \\param[in]\tpSignalData\t\t\t\t\tSignal data.\n \\return\t\t\t\t\t\t\t\t\tSignal id as a read only C string."] + pub fn sbgLogSatSignalDataGetSignalIdAsStr( + pSignalData: *const SbgLogSatSignalData, + ) -> *const ::core::ffi::c_char; +} +extern "C" { + #[doc = " Returns true if the SNR value is valid.\n\n \\param[in]\tpSignalData\t\t\t\t\tSignal data.\n \\return\t\t\t\t\t\t\t\t\ttrue if the SNR value is valid."] + pub fn sbgLogSatSignalDataSnrIsValid(pSignalData: *const SbgLogSatSignalData) -> bool; +} +extern "C" { + #[doc = " Get the health status of signal data.\n\n \\param[in]\tpSignalData\t\t\t\t\tSignal data.\n \\return\t\t\t\t\t\t\t\t\tHealth status."] + pub fn sbgLogSatSignalDataGetHealthStatus( + pSignalData: *const SbgLogSatSignalData, + ) -> SbgEComSatHealthStatus; +} +extern "C" { + #[doc = " Get the health status of signal data as a read only C string.\n\n \\param[in]\tpSignalData\t\t\t\t\tSignal data.\n \\return\t\t\t\t\t\t\t\t\tHealth status as a read only C string."] + pub fn sbgLogSatSignalDataGetHealthStatusAsStr( + pSignalData: *const SbgLogSatSignalData, + ) -> *const ::core::ffi::c_char; +} +extern "C" { + #[doc = " Get the tracking status of signal data.\n\n \\param[in]\tpSignalData\t\t\t\t\tSignal data.\n \\return\t\t\t\t\t\t\t\t\tTracking status."] + pub fn sbgLogSatSignalDataGetTrackingStatus( + pSignalData: *const SbgLogSatSignalData, + ) -> SbgEComSatTrackingStatus; +} +extern "C" { + #[doc = " Get the tracking status of signal data as a read only C string.\n\n \\param[in]\tpSignalData\t\t\t\t\tSignal data.\n \\return\t\t\t\t\t\t\t\t\tTracking status as a read only C string."] + pub fn sbgLogSatSignalDataGetTrackingStatusAsStr( + pSignalData: *const SbgLogSatSignalData, + ) -> *const ::core::ffi::c_char; +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_SHIP_MOTION or SBG_ECOM_LOG_SHIP_MOTION_HP message.
\n The data are expressed in the standard NED Ekinox coordiante frame.\n Surge is positive forward, sway is positive right and heave is positive down.
\n Note that status flag should be read before using the different parameters because it will provide validity information\n about all included outputs. Some frames may not provide the heave period or surge/sway axes for example"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogShipMotionData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< Ship Motion data status bitmask"] + pub status: u16, + #[doc = "< Main heave period in seconds."] + pub mainHeavePeriod: f32, + #[doc = "< Surge, sway and heave in meters."] + pub shipMotion: [f32; 3usize], + #[doc = "< Surge, sway and heave ship Acceleration in m.s^-2."] + pub shipAccel: [f32; 3usize], + #[doc = "< Surge, sway and heave velocities"] + pub shipVel: [f32; 3usize], +} +#[test] +fn bindgen_test_layout__SbgLogShipMotionData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogShipMotionData> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogShipMotionData>(), + 48usize, + concat!("Size of: ", stringify!(_SbgLogShipMotionData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogShipMotionData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogShipMotionData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogShipMotionData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogShipMotionData), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).mainHeavePeriod) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogShipMotionData), + "::", + stringify!(mainHeavePeriod) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).shipMotion) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogShipMotionData), + "::", + stringify!(shipMotion) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).shipAccel) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogShipMotionData), + "::", + stringify!(shipAccel) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).shipVel) as usize - ptr as usize }, + 36usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogShipMotionData), + "::", + stringify!(shipVel) + ) + ); +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_SHIP_MOTION or SBG_ECOM_LOG_SHIP_MOTION_HP message.
\n The data are expressed in the standard NED Ekinox coordiante frame.\n Surge is positive forward, sway is positive right and heave is positive down.
\n Note that status flag should be read before using the different parameters because it will provide validity information\n about all included outputs. Some frames may not provide the heave period or surge/sway axes for example"] +pub type SbgLogShipMotionData = _SbgLogShipMotionData; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_SHIP_MOTION or SBG_ECOM_LOG_SHIP_MOTION_HP message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseShipMotionData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogShipMotionData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_SHIP_MOTION or SBG_ECOM_LOG_SHIP_MOTION_HP message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteShipMotionData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogShipMotionData, + ) -> SbgErrorCode; +} +#[doc = "< Bus OFF operation due to too much errors."] +pub const _SbgEComCanBusStatus_SBG_ECOM_CAN_BUS_OFF: _SbgEComCanBusStatus = 0; +#[doc = "< Errors on Tx or Rx."] +pub const _SbgEComCanBusStatus_SBG_ECOM_CAN_BUS_TX_RX_ERR: _SbgEComCanBusStatus = 1; +#[doc = "< Bus OK."] +pub const _SbgEComCanBusStatus_SBG_ECOM_CAN_BUS_OK: _SbgEComCanBusStatus = 2; +#[doc = "< Bus error."] +pub const _SbgEComCanBusStatus_SBG_ECOM_CAN_BUS_ERROR: _SbgEComCanBusStatus = 3; +#[doc = " Communication status for the CAN Bus."] +pub type _SbgEComCanBusStatus = ::core::ffi::c_uint; +#[doc = " Communication status for the CAN Bus."] +pub use self::_SbgEComCanBusStatus as SbgEComCanBusStatus; +#[doc = " Stores global status data."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogStatusData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< General status bitmask and enums."] + pub generalStatus: u16, + #[doc = "< Communication status bitmask and enums."] + pub comStatus: u32, + #[doc = "< Second communication status bitmask and enums."] + pub comStatus2: u16, + #[doc = "< Aiding equipments status bitmask and enums."] + pub aidingStatus: u32, + #[doc = "< Reserved status field for future use."] + pub reserved2: u32, + #[doc = "< Reserved status field for future use."] + pub reserved3: u16, + #[doc = "< System uptime in seconds."] + pub uptime: u32, +} +#[test] +fn bindgen_test_layout__SbgLogStatusData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogStatusData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogStatusData>(), + 32usize, + concat!("Size of: ", stringify!(_SbgLogStatusData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogStatusData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogStatusData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogStatusData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).generalStatus) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogStatusData), + "::", + stringify!(generalStatus) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).comStatus) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogStatusData), + "::", + stringify!(comStatus) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).comStatus2) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogStatusData), + "::", + stringify!(comStatus2) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).aidingStatus) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogStatusData), + "::", + stringify!(aidingStatus) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).reserved2) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogStatusData), + "::", + stringify!(reserved2) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).reserved3) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogStatusData), + "::", + stringify!(reserved3) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).uptime) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogStatusData), + "::", + stringify!(uptime) + ) + ); +} +#[doc = " Stores global status data."] +pub type SbgLogStatusData = _SbgLogStatusData; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_STATUS message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseStatusData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogStatusData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_STATUS message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteStatusData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogStatusData, + ) -> SbgErrorCode; +} +#[doc = " Log structure for USBL data."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogUsblData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< USBL system status bitmask."] + pub status: u16, + #[doc = "< Latitude in degrees, positive north."] + pub latitude: f64, + #[doc = "< Longitude in degrees, positive east."] + pub longitude: f64, + #[doc = "< Depth in meters below mean sea level (positive down)."] + pub depth: f32, + #[doc = "< 1 sigma latitude accuracy in meters."] + pub latitudeAccuracy: f32, + #[doc = "< 1 sigma longitude accuracy in meters."] + pub longitudeAccuracy: f32, + #[doc = "< 1 sigma depth accuracy in meters."] + pub depthAccuracy: f32, +} +#[test] +fn bindgen_test_layout__SbgLogUsblData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogUsblData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogUsblData>(), + 40usize, + concat!("Size of: ", stringify!(_SbgLogUsblData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogUsblData>(), + 8usize, + concat!("Alignment of ", stringify!(_SbgLogUsblData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUsblData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUsblData), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).latitude) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUsblData), + "::", + stringify!(latitude) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).longitude) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUsblData), + "::", + stringify!(longitude) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).depth) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUsblData), + "::", + stringify!(depth) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).latitudeAccuracy) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUsblData), + "::", + stringify!(latitudeAccuracy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).longitudeAccuracy) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUsblData), + "::", + stringify!(longitudeAccuracy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).depthAccuracy) as usize - ptr as usize }, + 36usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUsblData), + "::", + stringify!(depthAccuracy) + ) + ); +} +#[doc = " Log structure for USBL data."] +pub type SbgLogUsblData = _SbgLogUsblData; +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_USBL message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseUsblData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogUsblData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_USBL message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteUsblData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogUsblData, + ) -> SbgErrorCode; +} +#[doc = "< An error has occurred on the clock estimation."] +pub const _SbgEComClockStatus_SBG_ECOM_CLOCK_ERROR: _SbgEComClockStatus = 0; +#[doc = "< The clock is only based on the internal crystal."] +pub const _SbgEComClockStatus_SBG_ECOM_CLOCK_FREE_RUNNING: _SbgEComClockStatus = 1; +#[doc = "< A PPS has been detected and the clock is converging to it."] +pub const _SbgEComClockStatus_SBG_ECOM_CLOCK_STEERING: _SbgEComClockStatus = 2; +#[doc = "< The clock has converged to the PPS and is within 500ns."] +pub const _SbgEComClockStatus_SBG_ECOM_CLOCK_VALID: _SbgEComClockStatus = 3; +#[doc = " Clock status enum."] +pub type _SbgEComClockStatus = ::core::ffi::c_uint; +#[doc = " Clock status enum."] +pub use self::_SbgEComClockStatus as SbgEComClockStatus; +#[doc = "< The UTC time is not known, we are just propagating the UTC time internally."] +pub const _SbgEComClockUtcStatus_SBG_ECOM_UTC_INVALID: _SbgEComClockUtcStatus = 0; +#[doc = "< We have received valid UTC time information but we don't have the leap seconds information."] +pub const _SbgEComClockUtcStatus_SBG_ECOM_UTC_NO_LEAP_SEC: _SbgEComClockUtcStatus = 1; +#[doc = "< We have received valid UTC time data with valid leap seconds."] +pub const _SbgEComClockUtcStatus_SBG_ECOM_UTC_VALID: _SbgEComClockUtcStatus = 2; +#[doc = " Status for the UTC time data."] +pub type _SbgEComClockUtcStatus = ::core::ffi::c_uint; +#[doc = " Status for the UTC time data."] +pub use self::_SbgEComClockUtcStatus as SbgEComClockUtcStatus; +#[doc = " Structure that stores data for the SBG_ECOM_LOG_UTC_TIME message."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgLogUtcData { + #[doc = "< Time in us since the sensor power up."] + pub timeStamp: u32, + #[doc = "< UTC time and clock status information"] + pub status: u16, + #[doc = "< Year for example: 2013."] + pub year: u16, + #[doc = "< Month in year [1 .. 12]."] + pub month: i8, + #[doc = "< Day in month [1 .. 31]."] + pub day: i8, + #[doc = "< Hour in day [0 .. 23]."] + pub hour: i8, + #[doc = "< Minute in hour [0 .. 59]."] + pub minute: i8, + #[doc = "< Second in minute [0 .. 60]. (60 is used only when a leap second is added)"] + pub second: i8, + #[doc = "< Nanosecond of current second in ns."] + pub nanoSecond: i32, + #[doc = "< GPS time of week in ms."] + pub gpsTimeOfWeek: u32, +} +#[test] +fn bindgen_test_layout__SbgLogUtcData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgLogUtcData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgLogUtcData>(), + 24usize, + concat!("Size of: ", stringify!(_SbgLogUtcData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgLogUtcData>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgLogUtcData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeStamp) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUtcData), + "::", + stringify!(timeStamp) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).status) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUtcData), + "::", + stringify!(status) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).year) as usize - ptr as usize }, + 6usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUtcData), + "::", + stringify!(year) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).month) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUtcData), + "::", + stringify!(month) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).day) as usize - ptr as usize }, + 9usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUtcData), + "::", + stringify!(day) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).hour) as usize - ptr as usize }, + 10usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUtcData), + "::", + stringify!(hour) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).minute) as usize - ptr as usize }, + 11usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUtcData), + "::", + stringify!(minute) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).second) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUtcData), + "::", + stringify!(second) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).nanoSecond) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUtcData), + "::", + stringify!(nanoSecond) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gpsTimeOfWeek) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgLogUtcData), + "::", + stringify!(gpsTimeOfWeek) + ) + ); +} +#[doc = " Structure that stores data for the SBG_ECOM_LOG_UTC_TIME message."] +pub type SbgLogUtcData = _SbgLogUtcData; +extern "C" { + #[doc = " Returns the clock status as a NULL terminated C string.\n\n \\param[in]\tpLogUtc\t\t\t\tUTC log instance.\n \\return\t\t\t\t\t\t\tThe clock status as a C string."] + pub fn sbgEcomLogUtcGetClockStatusAsString( + pLogUtc: *const SbgLogUtcData, + ) -> *const ::core::ffi::c_char; +} +extern "C" { + #[doc = " Returns the UTC status as a NULL terminated C string.\n\n \\param[in]\tpLogUtc\t\t\t\tUTC log instance.\n \\return\t\t\t\t\t\t\tThe UTC status as a C string."] + pub fn sbgEcomLogUtcGetUtcStatusAsString( + pLogUtc: *const SbgLogUtcData, + ) -> *const ::core::ffi::c_char; +} +extern "C" { + #[doc = " Parse data for the SBG_ECOM_LOG_UTC_DATA message and fill the corresponding structure.\n\n \\param[in]\tpInputStream\t\t\t\tInput stream buffer to read the payload from.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output structure that stores parsed data.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the payload has been parsed."] + pub fn sbgEComBinaryLogParseUtcData( + pInputStream: *mut SbgStreamBuffer, + pOutputData: *mut SbgLogUtcData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Write data for the SBG_ECOM_LOG_UTC_DATA message to the output stream buffer from the provided structure.\n\n \\param[out]\tpOutputStream\t\t\t\tOutput stream buffer to write the payload to.\n \\param[in]\tpInputData\t\t\t\t\tPointer on the input structure that stores data to write.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the message has been generated in the provided buffer."] + pub fn sbgEComBinaryLogWriteUtcData( + pOutputStream: *mut SbgStreamBuffer, + pInputData: *const SbgLogUtcData, + ) -> SbgErrorCode; +} +#[doc = "\tUnion used to store received logs data."] +#[repr(C)] +#[derive(Copy, Clone)] +pub union _SbgBinaryLogData { + #[doc = "< Stores data for the SBG_ECOM_LOG_STATUS message."] + pub statusData: SbgLogStatusData, + #[doc = "< Stores data for the SBG_ECOM_LOG_IMU_DATA message."] + pub imuData: SbgLogImuData, + #[doc = "< Stores data for the SBG_ECOM_LOG_IMU_SHORT message."] + pub imuShort: SbgLogImuShort, + #[doc = "< Stores data for the SBG_ECOM_LOG_EKF_EULER message."] + pub ekfEulerData: SbgLogEkfEulerData, + #[doc = "< Stores data for the SBG_ECOM_LOG_EKF_QUAT message."] + pub ekfQuatData: SbgLogEkfQuatData, + #[doc = "< Stores data for the SBG_ECOM_LOG_EKF_NAV message."] + pub ekfNavData: SbgLogEkfNavData, + #[doc = "< Stores data for the SBG_ECOM_LOG_SHIP_MOTION or SBG_ECOM_LOG_SHIP_MOTION_HP message."] + pub shipMotionData: SbgLogShipMotionData, + #[doc = "< Stores data for the SBG_ECOM_LOG_ODO_VEL message."] + pub odometerData: SbgLogOdometerData, + #[doc = "< Stores data for the SBG_ECOM_LOG_UTC_TIME message."] + pub utcData: SbgLogUtcData, + #[doc = "< Stores data for the SBG_ECOM_LOG_GPS_POS message."] + pub gpsPosData: SbgLogGpsPos, + #[doc = "< Stores data for the SBG_ECOM_LOG_GPS#_VEL message."] + pub gpsVelData: SbgLogGpsVel, + #[doc = "< Stores data for the SBG_ECOM_LOG_GPS#_HDT message."] + pub gpsHdtData: SbgLogGpsHdt, + #[doc = "< Stores data for the SBG_ECOM_LOG_GPS#_RAW message."] + pub gpsRawData: SbgLogRawData, + #[doc = "< Stores data for the SBG_ECOM_LOG_RTCM_RAW message."] + pub rtcmRawData: SbgLogRawData, + #[doc = "< Stores data for the SBG_ECOM_LOG_MAG message."] + pub magData: SbgLogMag, + #[doc = "< Stores data for the SBG_ECOM_LOG_MAG_CALIB message."] + pub magCalibData: SbgLogMagCalib, + #[doc = "< Stores data for the SBG_ECOM_LOG_DVL_BOTTOM_TRACK message."] + pub dvlData: SbgLogDvlData, + #[doc = "< Stores data for the SBG_ECOM_LOG_AIR_DATA message."] + pub airData: SbgLogAirData, + #[doc = "< Stores data for the SBG_ECOM_LOG_USBL message."] + pub usblData: SbgLogUsblData, + #[doc = "< Stores data for the SBG_ECOM_LOG_DEPTH message"] + pub depthData: SbgLogDepth, + #[doc = "< Stores data for the SBG_ECOM_LOG_EVENT_# message."] + pub eventMarker: SbgLogEvent, + #[doc = "< Stores data for the SBG_ECOM_LOG_DIAG message."] + pub diagData: SbgLogDiagData, + #[doc = "< Stores data for the SBG_ECOM_LOG_SAT message."] + pub satGroupData: SbgLogSatGroupData, + #[doc = "< Stores Fast Imu Data for 1KHz output"] + pub fastImuData: SbgLogFastImuData, +} +#[test] +fn bindgen_test_layout__SbgBinaryLogData() { + const UNINIT: ::core::mem::MaybeUninit<_SbgBinaryLogData> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgBinaryLogData>(), + 4096usize, + concat!("Size of: ", stringify!(_SbgBinaryLogData)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgBinaryLogData>(), + 8usize, + concat!("Alignment of ", stringify!(_SbgBinaryLogData)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).statusData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(statusData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).imuData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(imuData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).imuShort) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(imuShort) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).ekfEulerData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(ekfEulerData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).ekfQuatData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(ekfQuatData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).ekfNavData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(ekfNavData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).shipMotionData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(shipMotionData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).odometerData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(odometerData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).utcData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(utcData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gpsPosData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(gpsPosData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gpsVelData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(gpsVelData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gpsHdtData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(gpsHdtData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gpsRawData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(gpsRawData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).rtcmRawData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(rtcmRawData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).magData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(magData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).magCalibData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(magCalibData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).dvlData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(dvlData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).airData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(airData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).usblData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(usblData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).depthData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(depthData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).eventMarker) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(eventMarker) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).diagData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(diagData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).satGroupData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(satGroupData) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).fastImuData) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgBinaryLogData), + "::", + stringify!(fastImuData) + ) + ); +} +#[doc = "\tUnion used to store received logs data."] +pub type SbgBinaryLogData = _SbgBinaryLogData; +extern "C" { + #[doc = " Parse an incoming log and fill the output union.\n\n \\param[in]\tmsgClass\t\t\t\t\tReceived message class\n \\param[in]\tmsg\t\t\t\t\t\t\tReceived message ID\n \\param[in]\tpPayload\t\t\t\t\tRead only pointer on the payload buffer.\n \\param[in]\tpayloadSize\t\t\t\t\tPayload size in bytes.\n \\param[out]\tpOutputData\t\t\t\t\tPointer on the output union that stores parsed data."] + pub fn sbgEComBinaryLogParse( + msgClass: SbgEComClass, + msg: SbgEComMsgId, + pPayload: *const ::core::ffi::c_void, + payloadSize: usize, + pOutputData: *mut SbgBinaryLogData, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Clean up resources allocated during parsing, if any.\n\n \\param[in]\tpLogData\t\t\t\t\tLog data.\n \\param[in]\tmsgClass\t\t\t\t\tMessage class.\n \\param[in]\tmsgId\t\t\t\t\t\tMessage ID."] + pub fn sbgEComBinaryLogCleanup( + pLogData: *mut SbgBinaryLogData, + msgClass: SbgEComClass, + msgId: SbgEComMsgId, + ); +} +#[doc = " Interface definition that stores methods used to communicate on the interface."] +pub type SbgEComHandle = _SbgEComHandle; +#[doc = " Callback definition called each time a new log is received.\n\n \\param[in]\tpHandle\t\t\t\t\t\t\t\t\tValid handle on the sbgECom instance that has called this callback.\n \\param[in]\tmsgClass\t\t\t\t\t\t\t\tClass of the message we have received\n \\param[in]\tmsg\t\t\t\t\t\t\t\t\t\tMessage ID of the log received.\n \\param[in]\tpLogData\t\t\t\t\t\t\t\tContains the received log data as an union.\n \\param[in]\tpUserArg\t\t\t\t\t\t\t\tOptional user supplied argument.\n \\return\t\t\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the received log has been used successfully."] +pub type SbgEComReceiveLogFunc = ::core::option::Option< + unsafe extern "C" fn( + pHandle: *mut SbgEComHandle, + msgClass: SbgEComClass, + msg: SbgEComMsgId, + pLogData: *const SbgBinaryLogData, + pUserArg: *mut ::core::ffi::c_void, + ) -> SbgErrorCode, +>; +#[doc = " Interface definition that stores methods used to communicate on the interface."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComHandle { + #[doc = "< Handle on the protocol system."] + pub protocolHandle: SbgEComProtocol, + #[doc = "< Pointer on the method called each time a new binary log is received."] + pub pReceiveLogCallback: SbgEComReceiveLogFunc, + #[doc = "< Optional user supplied argument for callbacks."] + pub pUserArg: *mut ::core::ffi::c_void, + #[doc = "< Number of trials when a command is sent (default is 3)."] + pub numTrials: u32, + #[doc = "< Default time out in ms to get an answer from the device (default 500 ms)."] + pub cmdDefaultTimeOut: u32, +} +#[test] +fn bindgen_test_layout__SbgEComHandle() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComHandle> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComHandle>(), + 4144usize, + concat!("Size of: ", stringify!(_SbgEComHandle)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComHandle>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComHandle)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).protocolHandle) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComHandle), + "::", + stringify!(protocolHandle) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pReceiveLogCallback) as usize - ptr as usize }, + 4128usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComHandle), + "::", + stringify!(pReceiveLogCallback) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pUserArg) as usize - ptr as usize }, + 4132usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComHandle), + "::", + stringify!(pUserArg) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).numTrials) as usize - ptr as usize }, + 4136usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComHandle), + "::", + stringify!(numTrials) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).cmdDefaultTimeOut) as usize - ptr as usize }, + 4140usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComHandle), + "::", + stringify!(cmdDefaultTimeOut) + ) + ); +} +extern "C" { + #[doc = " Initialize the protocol system used to communicate with the product and return the created handle.\n\n \\param[out]\tpHandle\t\t\t\t\t\t\tPointer used to store the allocated and initialized sbgECom handle.\n \\param[in]\tpInterface\t\t\t\t\t\tInterface to use for read/write operations.\n \\return\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if we have initialized the protocol system."] + pub fn sbgEComInit(pHandle: *mut SbgEComHandle, pInterface: *mut SbgInterface) -> SbgErrorCode; +} +extern "C" { + #[doc = " Close the protocol system and release associated memory.\n\n \\param[in]\tpHandle\t\t\t\t\t\t\tA valid sbgECom handle to close.\n \\return\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if we have closed and released the sbgECom system."] + pub fn sbgEComClose(pHandle: *mut SbgEComHandle) -> SbgErrorCode; +} +extern "C" { + #[doc = " Try to parse one log from the input interface and then return.\n\n \\param[in]\tpHandle\t\t\t\t\t\t\tA valid sbgECom handle.\n \\return\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if no error occurs during incoming log parsing."] + pub fn sbgEComHandleOneLog(pHandle: *mut SbgEComHandle) -> SbgErrorCode; +} +extern "C" { + #[doc = " Handle all incoming logs until no more log are available in the input interface.\n\n \\param[in]\tpHandle\t\t\t\t\t\t\tA valid sbgECom handle.\n \\return\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if no error occurs during incoming logs parsing."] + pub fn sbgEComHandle(pHandle: *mut SbgEComHandle) -> SbgErrorCode; +} +extern "C" { + #[doc = " Purge the interface rx buffer as well as the sbgECom rx work buffer.\n\n For example, if the program flow has been interrupted, this method can be helpful to discard all trash received data.\n\n WARNING: This method is blocking for 100ms and actively tries to read incoming data.\n\n \\param[in]\tpHandle\t\t\t\t\t\t\tA valid sbgECom handle.\n \\return\t\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the incoming data has been purged successfully."] + pub fn sbgEComPurgeIncoming(pHandle: *mut SbgEComHandle) -> SbgErrorCode; +} +extern "C" { + #[doc = " Define the callback that should be called each time a new binary log is received.\n\n \\param[in]\tpHandle\t\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpReceiveLogCallback\t\t\t\tPointer on the callback to call when a new log is received.\n \\param[in]\tpUserArg\t\t\t\t\t\tOptional user argument that will be passed to the callback method."] + pub fn sbgEComSetReceiveLogCallback( + pHandle: *mut SbgEComHandle, + pReceiveLogCallback: SbgEComReceiveLogFunc, + pUserArg: *mut ::core::ffi::c_void, + ); +} +extern "C" { + #[doc = " Define the default number of trials that should be done when a command is send to the device as well as the time out.\n\n \\param[in]\tpHandle\t\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tnumTrials\t\t\t\t\t\tNumber of trials when a command is sent (starting at 1).\n \\param[in]\tcmdDefaultTimeOut\t\t\t\tDefault time out in milliseconds to wait to receive an answer from the device."] + pub fn sbgEComSetCmdTrialsAndTimeOut( + pHandle: *mut SbgEComHandle, + numTrials: u32, + cmdDefaultTimeOut: u32, + ); +} +extern "C" { + #[doc = "\tConvert an error code into a human readable string.\n\n\t\\param[in]\terrorCode\t\t\t\t\t\tThe errorCode to convert into a string.\n\t\\param[out]\terrorMsg\t\t\t\t\t\tString buffer used to hold the error string."] + pub fn sbgEComErrorToString(errorCode: SbgErrorCode, errorMsg: *mut ::core::ffi::c_char); +} +#[doc = "< The device is running it's internal clock without any time reference."] +pub const _SbgEComTimeReferenceSrc_SBG_ECOM_TIME_REF_DISABLED: _SbgEComTimeReferenceSrc = 0; +#[doc = "< The main port sync in A is used as a time reference."] +pub const _SbgEComTimeReferenceSrc_SBG_ECOM_TIME_REF_SYNC_IN_A: _SbgEComTimeReferenceSrc = 1; +#[doc = "< The GPS 1 module is used to provide both time reference and UTC data."] +pub const _SbgEComTimeReferenceSrc_SBG_ECOM_TIME_REF_UTC_GPS_1: _SbgEComTimeReferenceSrc = 2; +#[doc = " List of available time reference source."] +pub type _SbgEComTimeReferenceSrc = ::core::ffi::c_uint; +#[doc = " List of available time reference source."] +pub use self::_SbgEComTimeReferenceSrc as SbgEComTimeReferenceSrc; +#[doc = " Structure containing all the info for advanced configuration."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComAdvancedConf { + #[doc = "< Time reference source for clock alignment."] + pub timeReference: SbgEComTimeReferenceSrc, + #[doc = "< Advanced GNSS options - contact SBG Systems."] + pub gnssOptions: u32, + #[doc = "< Advanced NMEA output options."] + pub nmeaOptions: u32, +} +#[test] +fn bindgen_test_layout__SbgEComAdvancedConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComAdvancedConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComAdvancedConf>(), + 12usize, + concat!("Size of: ", stringify!(_SbgEComAdvancedConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComAdvancedConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComAdvancedConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).timeReference) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAdvancedConf), + "::", + stringify!(timeReference) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gnssOptions) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAdvancedConf), + "::", + stringify!(gnssOptions) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).nmeaOptions) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAdvancedConf), + "::", + stringify!(nmeaOptions) + ) + ); +} +#[doc = " Structure containing all the info for advanced configuration."] +pub type SbgEComAdvancedConf = _SbgEComAdvancedConf; +#[doc = " Structure containing all validity thresholds (status outputs)\n Setting these thresholds to 0.0 will keep default configuration"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComValidityThresholds { + #[doc = "< Norm of the position standard deviation threshold to raise position valid flag (m)"] + pub positionThreshold: f32, + #[doc = "< Norm of the velocity standard deviation threshold to raise velocity valid flag (m/s)"] + pub velocityThreshold: f32, + #[doc = "< Max of the roll/pitch standard deviations threshold to raise attitude valid flag (rad)"] + pub attitudeThreshold: f32, + #[doc = "< Heading standard deviations threshold to raise heading valid flag (rad)"] + pub headingThreshold: f32, +} +#[test] +fn bindgen_test_layout__SbgEComValidityThresholds() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComValidityThresholds> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComValidityThresholds>(), + 16usize, + concat!("Size of: ", stringify!(_SbgEComValidityThresholds)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComValidityThresholds>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComValidityThresholds)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).positionThreshold) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComValidityThresholds), + "::", + stringify!(positionThreshold) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).velocityThreshold) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComValidityThresholds), + "::", + stringify!(velocityThreshold) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).attitudeThreshold) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComValidityThresholds), + "::", + stringify!(attitudeThreshold) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).headingThreshold) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComValidityThresholds), + "::", + stringify!(headingThreshold) + ) + ); +} +#[doc = " Structure containing all validity thresholds (status outputs)\n Setting these thresholds to 0.0 will keep default configuration"] +pub type SbgEComValidityThresholds = _SbgEComValidityThresholds; +extern "C" { + #[doc = " Retrieve the advanced configurations.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpConf\t\t\t\t\t\tPointer to a SbgEComAdvancedConf to contain the current configuration.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdAdvancedGetConf( + pHandle: *mut SbgEComHandle, + pConf: *mut SbgEComAdvancedConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the advanced configurations.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpConf\t\t\t\t\t\tPointer to a SbgEComAdvancedConf that contains the new configuration.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdAdvancedSetConf( + pHandle: *mut SbgEComHandle, + pConf: *const SbgEComAdvancedConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the current validity thresholds\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpConf\t\t\t\t\t\tPointer to a SbgEComValidityThresholds to contain the current configuration.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdAdvancedGetThresholds( + pHandle: *mut SbgEComHandle, + pConf: *mut SbgEComValidityThresholds, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the validity thresholds\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpConf\t\t\t\t\t\tPointer to a SbgEComValidityThresholds that contains the new configuration.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdAdvancedSetThresholds( + pHandle: *mut SbgEComHandle, + pConf: *const SbgEComValidityThresholds, + ) -> SbgErrorCode; +} +#[doc = "< Measurement is not taken into account."] +pub const _SbgEComRejectionMode_SBG_ECOM_NEVER_ACCEPT_MODE: _SbgEComRejectionMode = 0; +#[doc = "< Measurement is accepted and rejected automatically depending on consistency checks"] +pub const _SbgEComRejectionMode_SBG_ECOM_AUTOMATIC_MODE: _SbgEComRejectionMode = 1; +#[doc = "< Measurement is always accepted. Should be used with caution"] +pub const _SbgEComRejectionMode_SBG_ECOM_ALWAYS_ACCEPT_MODE: _SbgEComRejectionMode = 2; +#[doc = " List of all rejection modes for aiding inputs."] +pub type _SbgEComRejectionMode = ::core::ffi::c_uint; +#[doc = " List of all rejection modes for aiding inputs."] +pub use self::_SbgEComRejectionMode as SbgEComRejectionMode; +#[doc = "< IMU/module Axis is turned in vehicle's forward direction."] +pub const _SbgEComAxisDirection_SBG_ECOM_ALIGNMENT_FORWARD: _SbgEComAxisDirection = 0; +#[doc = "< IMU/module Axis is turned in vehicle's backward direction."] +pub const _SbgEComAxisDirection_SBG_ECOM_ALIGNMENT_BACKWARD: _SbgEComAxisDirection = 1; +#[doc = "< IMU/module Axis is turned in vehicle's left direction."] +pub const _SbgEComAxisDirection_SBG_ECOM_ALIGNMENT_LEFT: _SbgEComAxisDirection = 2; +#[doc = "< IMU/module Axis is turned in vehicle's right direction."] +pub const _SbgEComAxisDirection_SBG_ECOM_ALIGNMENT_RIGHT: _SbgEComAxisDirection = 3; +#[doc = "< IMU/module Axis is turned in vehicle's up direction."] +pub const _SbgEComAxisDirection_SBG_ECOM_ALIGNMENT_UP: _SbgEComAxisDirection = 4; +#[doc = "< IMU/module Axis is turned in vehicle's down direction."] +pub const _SbgEComAxisDirection_SBG_ECOM_ALIGNMENT_DOWN: _SbgEComAxisDirection = 5; +#[doc = " List of all axis directions for modules/sensor alignment."] +pub type _SbgEComAxisDirection = ::core::ffi::c_uint; +#[doc = " List of all axis directions for modules/sensor alignment."] +pub use self::_SbgEComAxisDirection as SbgEComAxisDirection; +extern "C" { + #[doc = " Receive a command message.\n\n All binary logs received are handled trough the standard callback system.\n\n \\param[in]\tpHandle\t\t\t\t\tSbgECom handle.\n \\param[out]\tpMsgClass\t\t\t\tMessage class.\n \\param[out]\tpMsgId\t\t\t\t\tMessage ID.\n \\param[out]\tpData\t\t\t\t\tData buffer, may be NULL.\n \\param[out]\tpSize\t\t\t\t\tNumber of bytes received, in bytes, may be NULL.\n \\param[in]\tmaxSize\t\t\t\t\tData buffer size, in bytes.\n \\param[in]\ttimeOut\t\t\t\t\tTime-out, in ms.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful,\n\t\t\t\t\t\t\t\t\t\tSBG_NOT_READY if no command message has been received,\n\t\t\t\t\t\t\t\t\t\tSBG_BUFFER_OVERFLOW if the payload of the received frame couldn't fit into the buffer,\n\t\t\t\t\t\t\t\t\t\tSBG_TIME_OUT if no command message was received within the specified time out."] + pub fn sbgEComReceiveAnyCmd( + pHandle: *mut SbgEComHandle, + pMsgClass: *mut u8, + pMsgId: *mut u8, + pData: *mut ::core::ffi::c_void, + pSize: *mut usize, + maxSize: usize, + timeOut: u32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Receive a command message.\n\n All binary logs received are handled trough the standard callback system.\n\n This function is equivalent to sbgEComReceiveAnyCmd() with two exceptions :\n - the use of a payload object allows handling payloads not limited by the size of a user-provided buffer\n - the payload object allows direct access to the protocol work buffer to avoid an extra copy per call\n\n Any allocated resource associated with the given payload is released when calling this function.\n\n Because the payload buffer may directly refer to the protocol work buffer on return, it is only valid until\n the next attempt to receive a frame, with any of the receive functions.\n\n \\param[in]\tpHandle\t\t\t\t\tSbgECom handle.\n \\param[out]\tpMsgClass\t\t\t\tMessage class.\n \\param[out]\tpMsgId\t\t\t\t\tMessage ID.\n \\param[out]\tpPayload\t\t\t\tPayload.\n \\param[in]\ttimeOut\t\t\t\t\tTime-out, in ms.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful,\n\t\t\t\t\t\t\t\t\t\tSBG_NOT_READY if no command message has been received,\n\t\t\t\t\t\t\t\t\t\tSBG_TIME_OUT if no command message was received within the specified time out."] + pub fn sbgEComReceiveAnyCmd2( + pHandle: *mut SbgEComHandle, + pMsgClass: *mut u8, + pMsgId: *mut u8, + pPayload: *mut SbgEComProtocolPayload, + timeOut: u32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Receive a specific command message.\n\n This function also processes ACK messages for the given class and ID.\n\n All binary logs received during this time are handled trough the standard callback system.\n\n \\param[in]\tpHandle\t\t\t\t\tSbgECom handle.\n \\param[in]\tmsgClass\t\t\t\tMessage class.\n \\param[in]\tmsgId\t\t\t\t\tMessage ID.\n \\param[out]\tpData\t\t\t\t\tData buffer.\n \\param[out]\tpSize\t\t\t\t\tNumber of bytes received, in bytes.\n \\param[in]\tmaxSize\t\t\t\t\tData buffer size, in bytes.\n \\param[in]\ttimeOut\t\t\t\t\tTime-out, in ms.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful,\n\t\t\t\t\t\t\t\t\t\tSBG_NOT_READY if no command message has been received,\n\t\t\t\t\t\t\t\t\t\tSBG_BUFFER_OVERFLOW if the payload of the received frame couldn't fit into the buffer,\n\t\t\t\t\t\t\t\t\t\tSBG_TIME_OUT if no command message was received within the specified time out,\n\t\t\t\t\t\t\t\t\t\tany error code reported by an ACK message for the given class and ID."] + pub fn sbgEComReceiveCmd( + pHandle: *mut SbgEComHandle, + msgClass: u8, + msgId: u8, + pData: *mut ::core::ffi::c_void, + pSize: *mut usize, + maxSize: usize, + timeOut: u32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Receive a specific command message.\n\n This function also processes ACK messages for the given class and ID.\n\n All binary logs received during this time are handled trough the standard callback system.\n\n This function is equivalent to sbgEComReceiveCmd() with two exceptions :\n - the use of a payload object allows handling payloads not limited by the size of a user-provided buffer\n - the payload object allows direct access to the protocol work buffer to avoid an extra copy per call\n\n Any allocated resource associated with the given payload is released when calling this function.\n\n Because the payload buffer may directly refer to the protocol work buffer on return, it is only valid until\n the next attempt to receive a frame, with any of the receive functions.\n\n \\param[in]\tpHandle\t\t\t\t\tSbgECom handle.\n \\param[in]\tmsgClass\t\t\t\tMessage class.\n \\param[in]\tmsgId\t\t\t\t\tMessage ID.\n \\param[out]\tpPayload\t\t\t\tPayload.\n \\param[in]\ttimeOut\t\t\t\t\tTime-out, in ms.\n \\return\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful,\n\t\t\t\t\t\t\t\t\t\tSBG_NOT_READY if no command message has been received,\n\t\t\t\t\t\t\t\t\t\tSBG_TIME_OUT if no command message was received within the specified time out,\n\t\t\t\t\t\t\t\t\t\tany error code reported by an ACK message for the given class and ID."] + pub fn sbgEComReceiveCmd2( + pHandle: *mut SbgEComHandle, + msgClass: u8, + msgId: u8, + pPayload: *mut SbgEComProtocolPayload, + timeOut: u32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Wait for an ACK for a specified amount of time.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tmsgClass\t\t\t\t\tThe message class that we want to check\n \\param[in]\tmsg\t\t\t\t\t\t\tThe message ID that we want to check\n \\param[in]\ttimeOut\t\t\t\t\t\tTime out in ms during which we can receive the ACK.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the ACK has been received."] + pub fn sbgEComWaitForAck( + pHandle: *mut SbgEComHandle, + msgClass: u8, + msg: u8, + timeOut: u32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Send an ACK for a specific command with an associated error code.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tmsgClass\t\t\t\t\tThe message class that we want to send\n \\param[in]\tmsg\t\t\t\t\t\t\tThe message ID that we want to send.\n \\param[in]\tcmdError\t\t\t\t\tThe associated error code.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the ACK has been sent."] + pub fn sbgEComSendAck( + pHandle: *mut SbgEComHandle, + msgClass: u8, + msg: u8, + cmdError: SbgErrorCode, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Generic function to set an error model ID\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tmsgClass\t\t\t\t\tOriginal message class\n \\param[in]\tmsg\t\t\t\t\t\t\tOriginal message ID\n \\param[in]\tmodelId\t\t\t\t\t\tModel ID to set\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdGenericSetModelId( + pHandle: *mut SbgEComHandle, + msgClass: u8, + msg: u8, + modelId: u32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Generic function to get an error model ID\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tmsgClass\t\t\t\t\tOriginal message class\n \\param[in]\tmsg\t\t\t\t\t\t\tOriginal message ID\n \\param[out]\tpModelId\t\t\t\t\tReturns the currently used model ID.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdGenericGetModelId( + pHandle: *mut SbgEComHandle, + msgClass: u8, + msg: u8, + pModelId: *mut u32, + ) -> SbgErrorCode; +} +#[doc = "< Use the internal barometer sensor if available."] +pub const _SbgEComAirDataModelsIds_SBG_ECOM_AIR_DATA_MODEL_INTERNAL: _SbgEComAirDataModelsIds = 1; +#[doc = "< Generic AirData model using sbgECom input protocol format."] +pub const _SbgEComAirDataModelsIds_SBG_ECOM_AIR_DATA_MODEL_GENERIC_ECOM: _SbgEComAirDataModelsIds = + 2; +#[doc = "< Crossbow AHRS-500 compatible input for barometric altitude and airspeed."] +pub const _SbgEComAirDataModelsIds_SBG_ECOM_AIR_DATA_MODEL_AHRS_500: _SbgEComAirDataModelsIds = 3; +#[doc = " This enum defines the different AirData model IDs available in standard"] +pub type _SbgEComAirDataModelsIds = ::core::ffi::c_uint; +#[doc = " This enum defines the different AirData model IDs available in standard"] +pub use self::_SbgEComAirDataModelsIds as SbgEComAirDataModelsIds; +#[doc = " Holds all necessary information for AirData module data rejection."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComAirDataRejectionConf { + #[doc = "< Rejection mode for the true air speed measurement."] + pub airspeed: SbgEComRejectionMode, + #[doc = "< Rejection mode for the barometric altitude measurement."] + pub altitude: SbgEComRejectionMode, +} +#[test] +fn bindgen_test_layout__SbgEComAirDataRejectionConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComAirDataRejectionConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComAirDataRejectionConf>(), + 8usize, + concat!("Size of: ", stringify!(_SbgEComAirDataRejectionConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComAirDataRejectionConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComAirDataRejectionConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).airspeed) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAirDataRejectionConf), + "::", + stringify!(airspeed) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).altitude) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAirDataRejectionConf), + "::", + stringify!(altitude) + ) + ); +} +#[doc = " Holds all necessary information for AirData module data rejection."] +pub type SbgEComAirDataRejectionConf = _SbgEComAirDataRejectionConf; +extern "C" { + #[doc = " Set the AirData model to use that both defines the protocol as well as the associated error model.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tmodelId\t\t\t\t\t\tAirData model ID to set\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdAirDataSetModelId( + pHandle: *mut SbgEComHandle, + modelId: SbgEComAirDataModelsIds, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the AirData model id currently in use by the device.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpModelId\t\t\t\t\tReturns the AirData model ID currently in use by the device.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdAirDataGetModelId( + pHandle: *mut SbgEComHandle, + pModelId: *mut SbgEComAirDataModelsIds, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the lever arm configuration of the AirData module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpLeverArm\t\t\t\t\tThe X, Y, Z airspeed sensor lever arm in meters from the pitot sensor to the IMU.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdAirDataSetLeverArm( + pHandle: *mut SbgEComHandle, + pLeverArm: *const f32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the lever arm configuration of the AirData module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpLeverArm\t\t\t\t\tReturns the airspeed sensor X,Y,Z lever arm in meters from the pitot sensor to the IMU.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdAirDataGetLeverArm( + pHandle: *mut SbgEComHandle, + pLeverArm: *mut f32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the rejection configuration of the AirData module (this command doesn't need a reboot to be applied)\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpRejectConf\t\t\t\t\tThe new rejection configuration to set.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdAirDataSetRejection( + pHandle: *mut SbgEComHandle, + pRejectConf: *const SbgEComAirDataRejectionConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the current rejection configuration of the AirData module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpRejectConf\t\t\t\t\tReturn the rejection configuration currently in use.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdAirDataGetRejection( + pHandle: *mut SbgEComHandle, + pRejectConf: *mut SbgEComAirDataRejectionConf, + ) -> SbgErrorCode; +} +#[doc = " Reply to REST API commands.\n\n The reply content is a null-terminated string, normally in JSON format.\n\n The content directly refers to data inside the payload."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComCmdApiReply { + #[doc = "< Payload."] + pub payload: SbgEComProtocolPayload, + #[doc = "< Status code."] + pub statusCode: u16, + #[doc = "< Content."] + pub pContent: *const ::core::ffi::c_char, +} +#[test] +fn bindgen_test_layout__SbgEComCmdApiReply() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComCmdApiReply> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComCmdApiReply>(), + 20usize, + concat!("Size of: ", stringify!(_SbgEComCmdApiReply)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComCmdApiReply>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComCmdApiReply)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).payload) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdApiReply), + "::", + stringify!(payload) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).statusCode) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdApiReply), + "::", + stringify!(statusCode) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).pContent) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdApiReply), + "::", + stringify!(pContent) + ) + ); +} +#[doc = " Reply to REST API commands.\n\n The reply content is a null-terminated string, normally in JSON format.\n\n The content directly refers to data inside the payload."] +pub type SbgEComCmdApiReply = _SbgEComCmdApiReply; +extern "C" { + #[doc = " REST API reply constructor.\n\n \\param[in]\tpReply\t\t\t\t\t\tREST API reply."] + pub fn sbgEComCmdApiReplyConstruct(pReply: *mut SbgEComCmdApiReply); +} +extern "C" { + #[doc = " REST API reply destructor.\n\n \\param[in]\tpReply\t\t\t\t\t\tREST API reply."] + pub fn sbgEComCmdApiReplyDestroy(pReply: *mut SbgEComCmdApiReply); +} +extern "C" { + #[doc = " Check if a reply indicates successful command execution.\n\n \\param[in]\tpReply\t\t\t\t\t\tREST API reply.\n \\return\t\t\t\t\t\t\t\t\tTrue if the reply indicates successful command execution."] + pub fn sbgEComCmdApiReplySuccessful(pReply: *const SbgEComCmdApiReply) -> bool; +} +extern "C" { + #[doc = " Send a GET command.\n\n The reply must be destroyed before the next attempt to receive data, either logs or command replies.\n\n \\param[in]\tpHandle\t\t\t\t\t\tECom handle.\n \\param[in]\tpPath\t\t\t\t\t\tURI path component.\n \\param[in]\tpQuery\t\t\t\t\t\tQuery string, may be NULL.\n \\param[out]\tpReply\t\t\t\t\t\tReply.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful."] + pub fn sbgEComCmdApiGet( + pHandle: *mut SbgEComHandle, + pPath: *const ::core::ffi::c_char, + pQuery: *const ::core::ffi::c_char, + pReply: *mut SbgEComCmdApiReply, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Send a POST command.\n\n The reply must be destroyed before the next attempt to receive data, either logs or command replies.\n\n \\param[in]\tpHandle\t\t\t\t\t\tECom handle.\n \\param[in]\tpPath\t\t\t\t\t\tURI path component.\n \\param[in]\tpQuery\t\t\t\t\t\tQuery string, may be NULL.\n \\param[in]\tpBody\t\t\t\t\t\tBody, may be NULL.\n \\param[out]\tpReply\t\t\t\t\t\tReply.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if successful."] + pub fn sbgEComCmdApiPost( + pHandle: *mut SbgEComHandle, + pPath: *const ::core::ffi::c_char, + pQuery: *const ::core::ffi::c_char, + pBody: *const ::core::ffi::c_char, + pReply: *mut SbgEComCmdApiReply, + ) -> SbgErrorCode; +} +#[doc = "< Generic DVL using PD6 protocol format."] +pub const _SbgEComDvlModelsIds_SBG_ECOM_DVL_MODEL_GENERIC_PD6: _SbgEComDvlModelsIds = 202; +#[doc = "< Teledyne Wayfinder DVL using proprietary protocol."] +pub const _SbgEComDvlModelsIds_SBG_ECOM_DVL_MODEL_WAYFINDER: _SbgEComDvlModelsIds = 203; +#[doc = " This enum defines the different DVL model IDs available in standard"] +pub type _SbgEComDvlModelsIds = ::core::ffi::c_uint; +#[doc = " This enum defines the different DVL model IDs available in standard"] +pub use self::_SbgEComDvlModelsIds as SbgEComDvlModelsIds; +#[doc = " DVL mechanical installation parameters such as lever arm and alignment"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComDvlInstallation { + #[doc = "< X, Y, Z DVL lever arm in meters expressed from the DVL to the IMU."] + pub leverArm: [f32; 3usize], + #[doc = "< Roll, pitch, yaw DVL alignment expressed in radians."] + pub alignment: [f32; 3usize], + #[doc = "< Set to true if both the DVL lever arm and DVL alignment are precise and don't require in-run estimation."] + pub preciseInstallation: bool, +} +#[test] +fn bindgen_test_layout__SbgEComDvlInstallation() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComDvlInstallation> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComDvlInstallation>(), + 28usize, + concat!("Size of: ", stringify!(_SbgEComDvlInstallation)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComDvlInstallation>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComDvlInstallation)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).leverArm) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDvlInstallation), + "::", + stringify!(leverArm) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).alignment) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDvlInstallation), + "::", + stringify!(alignment) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).preciseInstallation) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDvlInstallation), + "::", + stringify!(preciseInstallation) + ) + ); +} +#[doc = " DVL mechanical installation parameters such as lever arm and alignment"] +pub type SbgEComDvlInstallation = _SbgEComDvlInstallation; +#[doc = " Holds all necessary information for DVL module data rejection."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComDvlRejectionConf { + #[doc = "< Rejection mode for the bottom tracking (ie when the velocity measurement is in respect to the seabed)."] + pub bottomLayer: SbgEComRejectionMode, + #[doc = "< Rejection mode for the water tracking (ie when the velocity measurement is relative to a water layer)."] + pub waterLayer: SbgEComRejectionMode, +} +#[test] +fn bindgen_test_layout__SbgEComDvlRejectionConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComDvlRejectionConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComDvlRejectionConf>(), + 8usize, + concat!("Size of: ", stringify!(_SbgEComDvlRejectionConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComDvlRejectionConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComDvlRejectionConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).bottomLayer) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDvlRejectionConf), + "::", + stringify!(bottomLayer) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).waterLayer) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDvlRejectionConf), + "::", + stringify!(waterLayer) + ) + ); +} +#[doc = " Holds all necessary information for DVL module data rejection."] +pub type SbgEComDvlRejectionConf = _SbgEComDvlRejectionConf; +extern "C" { + #[doc = " Set the DVL model to use that both defines the protocol as well as the associated error model.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tmodelId\t\t\t\t\t\tDVL model ID to set\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdDvlSetModelId( + pHandle: *mut SbgEComHandle, + modelId: SbgEComDvlModelsIds, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the DVL model id currently in use by the device.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpModelId\t\t\t\t\tReturns the DVL model ID currently in use by the device.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdDvlGetModelId( + pHandle: *mut SbgEComHandle, + pModelId: *mut SbgEComDvlModelsIds, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the lever arm and alignment configuration of the DVL module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpDvlInstallation\t\t\tThe DVL lever arm and alignment configuration to apply.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdDvlInstallationSet( + pHandle: *mut SbgEComHandle, + pDvlInstallation: *const SbgEComDvlInstallation, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the lever arm and alignment configuration of the DVL module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpDvlInstallation\t\t\tReturns the DVL lever arm and alignment configuration currently in use.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdDvlInstallationGet( + pHandle: *mut SbgEComHandle, + pDvlInstallation: *mut SbgEComDvlInstallation, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the rejection configuration of the DVL module (this command doesn't need a reboot to be applied)\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpRejectConf\t\t\t\t\tThe new DVL rejection configuration to set.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdDvlSetRejection( + pHandle: *mut SbgEComHandle, + pRejectConf: *const SbgEComDvlRejectionConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the current rejection configuration of the DVL module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpRejectConf\t\t\t\t\tReturn the DVL rejection configuration currently in use.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdDvlGetRejection( + pHandle: *mut SbgEComHandle, + pRejectConf: *mut SbgEComDvlRejectionConf, + ) -> SbgErrorCode; +} +#[doc = "< The TCP/IP configuration should be acquired from a DHCP server."] +pub const _SbgEComEthernetMode_SBG_ECOM_ETHERNET_DHCP: _SbgEComEthernetMode = 0; +#[doc = "< The TCP/IP configuration is manually defined."] +pub const _SbgEComEthernetMode_SBG_ECOM_ETHERNET_STATIC: _SbgEComEthernetMode = 1; +#[doc = " Enum that defines the different type of IP acquisition method."] +pub type _SbgEComEthernetMode = ::core::ffi::c_uint; +#[doc = " Enum that defines the different type of IP acquisition method."] +pub use self::_SbgEComEthernetMode as SbgEComEthernetMode; +#[doc = " Structure that contains all Ethernet configuration or settings."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComEthernetConf { + #[doc = "< Define how the device will acquiere its IP address, either DHCP or Static."] + pub mode: SbgEComEthernetMode, + #[doc = "< For static mode, defines the device IP address."] + pub ipAddress: sbgIpAddress, + #[doc = "< For static mode, defines the device net mask."] + pub netmask: sbgIpAddress, + #[doc = "< For static mode, defines the gateway to use."] + pub gateway: sbgIpAddress, + #[doc = "< For static mode, defines the primary DNS to use."] + pub dns1: sbgIpAddress, + #[doc = "< For static mode, defines the secondary DNS to use."] + pub dns2: sbgIpAddress, +} +#[test] +fn bindgen_test_layout__SbgEComEthernetConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComEthernetConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComEthernetConf>(), + 24usize, + concat!("Size of: ", stringify!(_SbgEComEthernetConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComEthernetConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComEthernetConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).mode) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComEthernetConf), + "::", + stringify!(mode) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).ipAddress) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComEthernetConf), + "::", + stringify!(ipAddress) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).netmask) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComEthernetConf), + "::", + stringify!(netmask) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gateway) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComEthernetConf), + "::", + stringify!(gateway) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).dns1) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComEthernetConf), + "::", + stringify!(dns1) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).dns2) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComEthernetConf), + "::", + stringify!(dns2) + ) + ); +} +#[doc = " Structure that contains all Ethernet configuration or settings."] +pub type SbgEComEthernetConf = _SbgEComEthernetConf; +extern "C" { + #[doc = " Get the configuration for the Ethernet interface.\n\n Warning: this method only returns the Ethernet configuration and NOT the ip address currently used by the device.\n You should rather use sbgEComEthernetInfo to retreive the current assigned IP.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpEthernetConf\t\t\t\tPoiner to a SbgEComEthernetConf struct that holds the read configuration from the device.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComEthernetGetConf( + pHandle: *mut SbgEComHandle, + pEthernetConf: *mut SbgEComEthernetConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the configuration for the Ethernet interface.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpEthernetConf\t\t\t\tPoiner to a SbgEComEthernetConf struct that holds the new configuration to apply.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComEthernetSetConf( + pHandle: *mut SbgEComHandle, + pEthernetConf: *const SbgEComEthernetConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Get the current assigned and used IP address as well as network inforamtion.\n\n In opposition to sbgEComEthernetGetConf, this method will not return the Ethernet configuration.\n It will rather return the IP address currently used by the device.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpEthernetConf\t\t\t\tPoiner to a SbgEComEthernetConf struct that holds the read IP settings from the device.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComEthernetInfo( + pHandle: *mut SbgEComHandle, + pEthernetConf: *mut SbgEComEthernetConf, + ) -> SbgErrorCode; +} +#[doc = "< Sync IN A"] +pub const _SbgEComSyncInId_SBG_ECOM_SYNC_IN_A: _SbgEComSyncInId = 0; +#[doc = "< Sync IN B"] +pub const _SbgEComSyncInId_SBG_ECOM_SYNC_IN_B: _SbgEComSyncInId = 1; +#[doc = "< Sync IN C"] +pub const _SbgEComSyncInId_SBG_ECOM_SYNC_IN_C: _SbgEComSyncInId = 2; +#[doc = "< Sync IN D"] +pub const _SbgEComSyncInId_SBG_ECOM_SYNC_IN_D: _SbgEComSyncInId = 3; +#[doc = " List of sync in signals available."] +pub type _SbgEComSyncInId = ::core::ffi::c_uint; +#[doc = " List of sync in signals available."] +pub use self::_SbgEComSyncInId as SbgEComSyncInId; +#[doc = "< This trigger is turned OFF."] +pub const _SbgEComSyncInSensitivity_SBG_ECOM_SYNC_IN_DISABLED: _SbgEComSyncInSensitivity = 0; +#[doc = "< The trigger will be activated by a falling edge."] +pub const _SbgEComSyncInSensitivity_SBG_ECOM_SYNC_IN_FALLING_EDGE: _SbgEComSyncInSensitivity = 1; +#[doc = "< The trigger will be activated by a rising edge."] +pub const _SbgEComSyncInSensitivity_SBG_ECOM_SYNC_IN_RISING_EDGE: _SbgEComSyncInSensitivity = 2; +#[doc = "< The trigger is activated by a level change (rising or falling edge)."] +pub const _SbgEComSyncInSensitivity_SBG_ECOM_SYNC_IN_BOTH_EDGES: _SbgEComSyncInSensitivity = 3; +#[doc = " List of available sensitivities for sync in signals."] +pub type _SbgEComSyncInSensitivity = ::core::ffi::c_uint; +#[doc = " List of available sensitivities for sync in signals."] +pub use self::_SbgEComSyncInSensitivity as SbgEComSyncInSensitivity; +#[doc = "< Synchronization output A"] +pub const _SbgEComSyncOutId_SBG_ECOM_SYNC_OUT_A: _SbgEComSyncOutId = 0; +#[doc = "< Synchronization output B"] +pub const _SbgEComSyncOutId_SBG_ECOM_SYNC_OUT_B: _SbgEComSyncOutId = 1; +#[doc = " List of sync out signals available."] +pub type _SbgEComSyncOutId = ::core::ffi::c_uint; +#[doc = " List of sync out signals available."] +pub use self::_SbgEComSyncOutId as SbgEComSyncOutId; +#[doc = "< Output is disabled."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_DISABLED: _SbgEComSyncOutFunction = 0; +#[doc = "< Output is generated at 200Hz."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_MAIN_LOOP: _SbgEComSyncOutFunction = 1; +#[doc = "< Output is generated at 100Hz."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_DIV_2: _SbgEComSyncOutFunction = 2; +#[doc = "< Output is generated at 50Hz."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_DIV_4: _SbgEComSyncOutFunction = 4; +#[doc = "< Output is generated at 25Hz."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_DIV_8: _SbgEComSyncOutFunction = 8; +#[doc = "< Output is generated at 20Hz."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_DIV_10: _SbgEComSyncOutFunction = 10; +#[doc = "< Output is generated at 10Hz."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_DIV_20: _SbgEComSyncOutFunction = 20; +#[doc = "< Output is generated at 5Hz."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_DIV_40: _SbgEComSyncOutFunction = 40; +#[doc = "< Output is generated at 1Hz."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_DIV_200: _SbgEComSyncOutFunction = 200; +#[doc = "< Pulse Per Second. Same mode as above."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_PPS: _SbgEComSyncOutFunction = 10000; +#[doc = "< Output is generated on a Sync In A event."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_EVENT_IN_A: _SbgEComSyncOutFunction = + 10003; +#[doc = "< Output is generated on a Sync In B event."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_EVENT_IN_B: _SbgEComSyncOutFunction = + 10004; +#[doc = "< Output is generated on a Sync In C event."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_EVENT_IN_C: _SbgEComSyncOutFunction = + 10005; +#[doc = "< Output is generated on a Sync In D event."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_EVENT_IN_D: _SbgEComSyncOutFunction = + 10006; +#[doc = "< The internal GNSS PPS signal is directly routed to the Sync Out.\nThis mode is only valid for ELLIPSE-N with hardware revisions above 1.2.1.0.\nPolarity and duration parameters are ignored with this specific mode."] +pub const _SbgEComSyncOutFunction_SBG_ECOM_SYNC_OUT_MODE_DIRECT_PPS: _SbgEComSyncOutFunction = + 10100; +#[doc = " Logic and synchronization output types"] +pub type _SbgEComSyncOutFunction = ::core::ffi::c_uint; +#[doc = " Logic and synchronization output types"] +pub use self::_SbgEComSyncOutFunction as SbgEComSyncOutFunction; +#[doc = "< The output pin will generate a falling edge"] +pub const _SbgEComSyncOutPolarity_SBG_ECOM_SYNC_OUT_FALLING_EDGE: _SbgEComSyncOutPolarity = 0; +#[doc = "< The output pin will generate a rising edge"] +pub const _SbgEComSyncOutPolarity_SBG_ECOM_SYNC_OUT_RISING_EDGE: _SbgEComSyncOutPolarity = 1; +#[doc = "< The pulse is a level change"] +pub const _SbgEComSyncOutPolarity_SBG_ECOM_SYNC_OUT_TOGGLE: _SbgEComSyncOutPolarity = 2; +#[doc = " Logic output polarity"] +pub type _SbgEComSyncOutPolarity = ::core::ffi::c_uint; +#[doc = " Logic output polarity"] +pub use self::_SbgEComSyncOutPolarity as SbgEComSyncOutPolarity; +#[doc = " Helper structure for sync in configuration."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComSyncInConf { + #[doc = "< Sensitivity of the sync in."] + pub sensitivity: SbgEComSyncInSensitivity, + #[doc = "< Delay to take into account for the sync in. (in us)"] + pub delay: i32, +} +#[test] +fn bindgen_test_layout__SbgEComSyncInConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComSyncInConf> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComSyncInConf>(), + 8usize, + concat!("Size of: ", stringify!(_SbgEComSyncInConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComSyncInConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComSyncInConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).sensitivity) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComSyncInConf), + "::", + stringify!(sensitivity) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).delay) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComSyncInConf), + "::", + stringify!(delay) + ) + ); +} +#[doc = " Helper structure for sync in configuration."] +pub type SbgEComSyncInConf = _SbgEComSyncInConf; +#[doc = " Helper structure for sync out configuration."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComSyncOutConf { + #[doc = "< Output function of the sync out pin"] + pub outputFunction: SbgEComSyncOutFunction, + #[doc = "< Polarity of the sync out."] + pub polarity: SbgEComSyncOutPolarity, + #[doc = "< Pulse width for the sync out (in ns)."] + pub duration: u32, +} +#[test] +fn bindgen_test_layout__SbgEComSyncOutConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComSyncOutConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComSyncOutConf>(), + 12usize, + concat!("Size of: ", stringify!(_SbgEComSyncOutConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComSyncOutConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComSyncOutConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).outputFunction) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComSyncOutConf), + "::", + stringify!(outputFunction) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).polarity) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComSyncOutConf), + "::", + stringify!(polarity) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).duration) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComSyncOutConf), + "::", + stringify!(duration) + ) + ); +} +#[doc = " Helper structure for sync out configuration."] +pub type SbgEComSyncOutConf = _SbgEComSyncOutConf; +extern "C" { + #[doc = "\tRetrieve the configuration of a Sync In.\n\n\t\\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n\t\\param[in]\tsyncInId\t\t\t\t\tThe id of the sync whose configuration is to be retrieved.\n\t\\param[out]\tpConf\t\t\t\t\t\tPointer to a SbgEComSyncInConf to contain the current configuration of the sync in.\n\t\\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSyncInGetConf( + pHandle: *mut SbgEComHandle, + syncInId: SbgEComSyncInId, + pConf: *mut SbgEComSyncInConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = "\tSet the configuration of a Sync In.\n\n\t\\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n\t\\param[in]\tsyncInId\t\t\t\t\tThe id of the sync whose configuration is to be set.\n\t\\param[in]\tpConf\t\t\t\t\t\tPointer to a SbgEComSyncInConf that contains the new configuration for the sync in.\n\t\\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSyncInSetConf( + pHandle: *mut SbgEComHandle, + syncInId: SbgEComSyncInId, + pConf: *const SbgEComSyncInConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = "\tRetrieve the configuration of a Sync Out.\n\n\t\\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n\t\\param[in]\tsyncOutId\t\t\t\t\tThe id of the sync whose configuration is to be retrieved.\n\t\\param[out]\tpConf\t\t\t\t\t\tPointer to a SbgEComSyncOutConf to contain the current configuration of the sync out.\n\t\\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSyncOutGetConf( + pHandle: *mut SbgEComHandle, + syncOutId: SbgEComSyncOutId, + pConf: *mut SbgEComSyncOutConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = "\tSet the configuration of a Sync Out.\n\n\t\\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n\t\\param[in]\tsyncOutId\t\t\t\t\tThe id of the sync whose configuration is to be set.\n\t\\param[in]\tpConf\t\t\t\t\t\tPointer to a SbgEComSyncOutConf that contains the new configuration for the sync Out.\n\t\\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSyncOutSetConf( + pHandle: *mut SbgEComHandle, + syncOutId: SbgEComSyncOutId, + pConf: *const SbgEComSyncOutConf, + ) -> SbgErrorCode; +} +#[doc = "< GNSS module disabled"] +pub const _SbgEComGnssType_SBG_ECOM_GNSS_TYPE_DISABLED: _SbgEComGnssType = 0; +#[doc = "< External GNSS module (all features are unknown)"] +pub const _SbgEComGnssType_SBG_ECOM_GNSS_TYPE_EXTERNAL: _SbgEComGnssType = 1; +#[doc = "< Ublox MAX-M8 module"] +pub const _SbgEComGnssType_SBG_ECOM_GNSS_TYPE_UBX_MAX_M8: _SbgEComGnssType = 2; +#[doc = "< Novatel OEM615 device"] +pub const _SbgEComGnssType_SBG_ECOM_GNSS_TYPE_NOV_OEM615: _SbgEComGnssType = 3; +#[doc = "< Two Novatel OEM615 devices for dual antenna"] +pub const _SbgEComGnssType_SBG_ECOM_GNSS_TYPE_NOV_OEM615_DUAL: _SbgEComGnssType = 4; +#[doc = "< Novatel OEM617D device"] +pub const _SbgEComGnssType_SBG_ECOM_GNSS_TYPE_NOV_OEM617D: _SbgEComGnssType = 5; +#[doc = "< Septentrio Asterx m4"] +pub const _SbgEComGnssType_SBG_ECOM_GNSS_TYPE_SEP_AX4: _SbgEComGnssType = 6; +#[doc = "< Septentrio Asterx m2a"] +pub const _SbgEComGnssType_SBG_ECOM_GNSS_TYPE_SEP_AXM2A: _SbgEComGnssType = 7; +#[doc = "< Ublox ZED-F9P module"] +pub const _SbgEComGnssType_SBG_ECOM_GNSS_TYPE_UBX_F9P: _SbgEComGnssType = 8; +#[doc = " This enum defines the different types of internal GNSS receiver that can provide specific features.\n Note External type is considered as not handled by the feature system"] +pub type _SbgEComGnssType = ::core::ffi::c_uint; +#[doc = " This enum defines the different types of internal GNSS receiver that can provide specific features.\n Note External type is considered as not handled by the feature system"] +pub use self::_SbgEComGnssType as SbgEComGnssType; +#[doc = " This structure contains all the information provided by the SBG_ECOM_CMD_GET_FEATURES command"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComFeatures { + #[doc = "< The different measurement capabilities of this unit"] + pub sensorFeaturesMask: u32, + #[doc = "< The type of GNSS receiver used (brand and model)"] + pub gnssType: SbgEComGnssType, + #[doc = "< The actual GNSS update rate"] + pub gnssUpdateRate: u8, + #[doc = "< GNSS receiver signals tracking"] + pub gnssSignalsMask: u32, + #[doc = "< GNSS receiver computation and output features"] + pub gnssFeaturesMask: u32, + #[doc = "< String containing the GNSS receiver product code (\"\\0\" if unknown)"] + pub gnssProductCode: [::core::ffi::c_char; 32usize], + #[doc = "< String containing the GNSS receiver serial number (\"\\0\" if unknown)"] + pub gnssSerialNumber: [::core::ffi::c_char; 32usize], + #[doc = "< String containing the GNSS receiver firmware version (\"\\0\" if unknown)"] + pub gnssFirmwareVersion: [::core::ffi::c_char; 32usize], +} +#[test] +fn bindgen_test_layout__SbgEComFeatures() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComFeatures> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComFeatures>(), + 116usize, + concat!("Size of: ", stringify!(_SbgEComFeatures)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComFeatures>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComFeatures)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).sensorFeaturesMask) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComFeatures), + "::", + stringify!(sensorFeaturesMask) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gnssType) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComFeatures), + "::", + stringify!(gnssType) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gnssUpdateRate) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComFeatures), + "::", + stringify!(gnssUpdateRate) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gnssSignalsMask) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComFeatures), + "::", + stringify!(gnssSignalsMask) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gnssFeaturesMask) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComFeatures), + "::", + stringify!(gnssFeaturesMask) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gnssProductCode) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComFeatures), + "::", + stringify!(gnssProductCode) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gnssSerialNumber) as usize - ptr as usize }, + 52usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComFeatures), + "::", + stringify!(gnssSerialNumber) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gnssFirmwareVersion) as usize - ptr as usize }, + 84usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComFeatures), + "::", + stringify!(gnssFirmwareVersion) + ) + ); +} +#[doc = " This structure contains all the information provided by the SBG_ECOM_CMD_GET_FEATURES command"] +pub type SbgEComFeatures = _SbgEComFeatures; +extern "C" { + #[doc = " Retrieve the device and embedded GPS receiver features.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpFeatures\t\t\t\t\tA pointer to a structure to hold features.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdGetFeatures( + pHandle: *mut SbgEComHandle, + pFeatures: *mut SbgEComFeatures, + ) -> SbgErrorCode; +} +#[doc = "< Default internal GNSS for ELLIPSE-N and ELLIPSE-D"] +pub const _SbgEComGnssModelsStdIds_SBG_ECOM_GNSS_MODEL_INTERNAL: _SbgEComGnssModelsStdIds = 101; +#[doc = "< ELLIPSE-E to accept an external GNSS using NMEA protocol"] +pub const _SbgEComGnssModelsStdIds_SBG_ECOM_GNSS_MODEL_NMEA: _SbgEComGnssModelsStdIds = 102; +#[doc = "< Only for ELLIPSE-N hardware 1 & 2 to select GPS+BEIDOU instead of the default GPS+GLONASS"] +pub const _SbgEComGnssModelsStdIds_SBG_ECOM_GNSS_MODEL_UBLOX_GPS_BEIDOU: _SbgEComGnssModelsStdIds = + 103; +#[doc = "< ELLIPSE-E to accept an external Ublox GNSS (receive only - passive)"] +pub const _SbgEComGnssModelsStdIds_SBG_ECOM_GNSS_MODEL_UBLOX_EXTERNAL: _SbgEComGnssModelsStdIds = + 104; +#[doc = "< Reserved, do not use"] +pub const _SbgEComGnssModelsStdIds_SBG_ECOM_GNSS_MODEL_RESERVED_01: _SbgEComGnssModelsStdIds = 105; +#[doc = "< ELLIPSE-E to accept an external Novatel GNSS (receive only - passive)"] +pub const _SbgEComGnssModelsStdIds_SBG_ECOM_GNSS_MODEL_NOVATEL_EXTERNAL: _SbgEComGnssModelsStdIds = + 106; +#[doc = "< Reserved, do not use"] +pub const _SbgEComGnssModelsStdIds_SBG_ECOM_GNSS_MODEL_RESERVED_02: _SbgEComGnssModelsStdIds = 107; +#[doc = "< Reserved, do not use"] +pub const _SbgEComGnssModelsStdIds_SBG_ECOM_GNSS_MODEL_RESERVED_03: _SbgEComGnssModelsStdIds = 108; +#[doc = "< ELLIPSE-E to accept an external Septentrio GNSS(receive only - passive)"] +pub const _SbgEComGnssModelsStdIds_SBG_ECOM_GNSS_MODEL_SEPTENTRIO_EXTERNAL: + _SbgEComGnssModelsStdIds = 109; +#[doc = "< Reserved, do not use"] +pub const _SbgEComGnssModelsStdIds_SBG_ECOM_GNSS_MODEL_RESERVED_04: _SbgEComGnssModelsStdIds = 110; +#[doc = " This enum defines the different GNSS model IDs available in standard"] +pub type _SbgEComGnssModelsStdIds = ::core::ffi::c_uint; +#[doc = " This enum defines the different GNSS model IDs available in standard"] +pub use self::_SbgEComGnssModelsStdIds as SbgEComGnssModelsStdIds; +#[doc = "< The GNSS will be used in single antenna mode only and the secondary lever arm is not used."] +pub const _SbgEComGnssInstallationMode_SBG_ECOM_GNSS_INSTALLATION_MODE_SINGLE: + _SbgEComGnssInstallationMode = 1; +#[doc = "< [Reserved] The GNSS dual antenna information will be used but the secondary lever arm is not known."] +pub const _SbgEComGnssInstallationMode_SBG_ECOM_GNSS_INSTALLATION_MODE_DUAL_AUTO: + _SbgEComGnssInstallationMode = 2; +#[doc = "< The GNSS dual antenna information will be used and we have a rough guess for the secondary lever arm."] +pub const _SbgEComGnssInstallationMode_SBG_ECOM_GNSS_INSTALLATION_MODE_DUAL_ROUGH: + _SbgEComGnssInstallationMode = 3; +#[doc = "< The GNSS dual antenna information will be used and the secondary lever arm is accurately entered and doesn't need online re-estimation."] +pub const _SbgEComGnssInstallationMode_SBG_ECOM_GNSS_INSTALLATION_MODE_DUAL_PRECISE: + _SbgEComGnssInstallationMode = 4; +#[doc = " GNSS mechanical installation modes for the dual antenna mode."] +pub type _SbgEComGnssInstallationMode = ::core::ffi::c_uint; +#[doc = " GNSS mechanical installation modes for the dual antenna mode."] +pub use self::_SbgEComGnssInstallationMode as SbgEComGnssInstallationMode; +#[doc = " GNSS mechanical installation parameters to be used with command SBG_ECOM_CMD_GNSS_#_INSTALLATION"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComGnssInstallation { + #[doc = "< GNSS primary antenna lever arm in IMU X, Y, Z axis in meters"] + pub leverArmPrimary: [f32; 3usize], + #[doc = "< If set to true, the primary lever arm has been accurately entered and doesn't need online re-estimation."] + pub leverArmPrimaryPrecise: bool, + #[doc = "< GNSS secondary antenna lever arm in IMU X, Y, Z axis in meters"] + pub leverArmSecondary: [f32; 3usize], + #[doc = "< Define the secondary antenna (dual antenna) operating mode."] + pub leverArmSecondaryMode: SbgEComGnssInstallationMode, +} +#[test] +fn bindgen_test_layout__SbgEComGnssInstallation() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComGnssInstallation> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComGnssInstallation>(), + 32usize, + concat!("Size of: ", stringify!(_SbgEComGnssInstallation)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComGnssInstallation>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComGnssInstallation)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).leverArmPrimary) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComGnssInstallation), + "::", + stringify!(leverArmPrimary) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).leverArmPrimaryPrecise) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComGnssInstallation), + "::", + stringify!(leverArmPrimaryPrecise) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).leverArmSecondary) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComGnssInstallation), + "::", + stringify!(leverArmSecondary) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).leverArmSecondaryMode) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComGnssInstallation), + "::", + stringify!(leverArmSecondaryMode) + ) + ); +} +#[doc = " GNSS mechanical installation parameters to be used with command SBG_ECOM_CMD_GNSS_#_INSTALLATION"] +pub type SbgEComGnssInstallation = _SbgEComGnssInstallation; +#[doc = " Holds all necessary information for GNSS module data rejection."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComGnssRejectionConf { + #[doc = "< Rejection mode for position."] + pub position: SbgEComRejectionMode, + #[doc = "< Rejection mode for velocity."] + pub velocity: SbgEComRejectionMode, + #[doc = "< Rejection mode for true heading."] + pub hdt: SbgEComRejectionMode, +} +#[test] +fn bindgen_test_layout__SbgEComGnssRejectionConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComGnssRejectionConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComGnssRejectionConf>(), + 12usize, + concat!("Size of: ", stringify!(_SbgEComGnssRejectionConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComGnssRejectionConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComGnssRejectionConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).position) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComGnssRejectionConf), + "::", + stringify!(position) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).velocity) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComGnssRejectionConf), + "::", + stringify!(velocity) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).hdt) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComGnssRejectionConf), + "::", + stringify!(hdt) + ) + ); +} +#[doc = " Holds all necessary information for GNSS module data rejection."] +pub type SbgEComGnssRejectionConf = _SbgEComGnssRejectionConf; +extern "C" { + #[doc = " Set GNSS error model id.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tmodelId\t\t\t\t\t\tModel ID to set\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdGnss1SetModelId( + pHandle: *mut SbgEComHandle, + modelId: SbgEComGnssModelsStdIds, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve GNSS error model id.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpModelId\t\t\t\t\tRetrieved model id.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdGnss1GetModelId( + pHandle: *mut SbgEComHandle, + pModelId: *mut SbgEComGnssModelsStdIds, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the mechanical installation parameters for the GNSS 1 module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpGnssInstallation\t\t\tUsed to store the retrieved the GNSS installation parameters.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdGnss1InstallationGet( + pHandle: *mut SbgEComHandle, + pGnssInstallation: *mut SbgEComGnssInstallation, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the mechanical installation parameters for the GNSS 1 module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpGnssInstallation\t\t\t\tThe GNSS installation parameters to set.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdGnss1InstallationSet( + pHandle: *mut SbgEComHandle, + pGnssInstallation: *const SbgEComGnssInstallation, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the rejection configuration of the gnss module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpRejectConf\t\t\t\t\tPointer to a SbgEComGnssRejectionConf struct to hold rejection configuration of the gnss module.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdGnss1GetRejection( + pHandle: *mut SbgEComHandle, + pRejectConf: *mut SbgEComGnssRejectionConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the rejection configuration of the gnss module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpRejectConf\t\t\t\t\tPointer to a SbgEComGnssRejectionConf struct holding rejection configuration for the gnss module.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdGnss1SetRejection( + pHandle: *mut SbgEComHandle, + pRejectConf: *const SbgEComGnssRejectionConf, + ) -> SbgErrorCode; +} +#[doc = " Helper structure to retrieve device info."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComDeviceInfo { + #[doc = "< Human readable Product Code."] + pub productCode: [u8; 32usize], + #[doc = "< Device serial number"] + pub serialNumber: u32, + #[doc = "< Calibration data revision"] + pub calibationRev: u32, + #[doc = "< Device Calibration Year"] + pub calibrationYear: u16, + #[doc = "< Device Calibration Month"] + pub calibrationMonth: u8, + #[doc = "< Device Calibration Day"] + pub calibrationDay: u8, + #[doc = "< Device hardware revision"] + pub hardwareRev: u32, + #[doc = "< Firmware revision"] + pub firmwareRev: u32, +} +#[test] +fn bindgen_test_layout__SbgEComDeviceInfo() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComDeviceInfo> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComDeviceInfo>(), + 52usize, + concat!("Size of: ", stringify!(_SbgEComDeviceInfo)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComDeviceInfo>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComDeviceInfo)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).productCode) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDeviceInfo), + "::", + stringify!(productCode) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).serialNumber) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDeviceInfo), + "::", + stringify!(serialNumber) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).calibationRev) as usize - ptr as usize }, + 36usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDeviceInfo), + "::", + stringify!(calibationRev) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).calibrationYear) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDeviceInfo), + "::", + stringify!(calibrationYear) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).calibrationMonth) as usize - ptr as usize }, + 42usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDeviceInfo), + "::", + stringify!(calibrationMonth) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).calibrationDay) as usize - ptr as usize }, + 43usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDeviceInfo), + "::", + stringify!(calibrationDay) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).hardwareRev) as usize - ptr as usize }, + 44usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDeviceInfo), + "::", + stringify!(hardwareRev) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).firmwareRev) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComDeviceInfo), + "::", + stringify!(firmwareRev) + ) + ); +} +#[doc = " Helper structure to retrieve device info."] +pub type SbgEComDeviceInfo = _SbgEComDeviceInfo; +extern "C" { + #[doc = " Retrieve the device information.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpInfo\t\t\t\t\t\tA pointer to a structure to hold device information.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdGetInfo( + pHandle: *mut SbgEComHandle, + pInfo: *mut SbgEComDeviceInfo, + ) -> SbgErrorCode; +} +#[doc = "< Main communication interface. Full duplex."] +pub const _SbgEComPortId_SBG_ECOM_IF_COM_A: _SbgEComPortId = 0; +#[doc = "< Auxiliary input interface for RTCM."] +pub const _SbgEComPortId_SBG_ECOM_IF_COM_B: _SbgEComPortId = 1; +#[doc = "< Auxiliary communication interface. Full duplex."] +pub const _SbgEComPortId_SBG_ECOM_IF_COM_C: _SbgEComPortId = 2; +#[doc = "< Auxiliary input interface."] +pub const _SbgEComPortId_SBG_ECOM_IF_COM_D: _SbgEComPortId = 3; +#[doc = "< Auxiliary output interface."] +pub const _SbgEComPortId_SBG_ECOM_IF_COM_E: _SbgEComPortId = 4; +#[doc = "< Ethernet interface 0."] +pub const _SbgEComPortId_SBG_ECOM_IF_ETH_0: _SbgEComPortId = 10; +#[doc = "< Ethernet interface 1."] +pub const _SbgEComPortId_SBG_ECOM_IF_ETH_1: _SbgEComPortId = 11; +#[doc = "< Ethernet interface 2."] +pub const _SbgEComPortId_SBG_ECOM_IF_ETH_2: _SbgEComPortId = 12; +#[doc = "< Ethernet interface 3."] +pub const _SbgEComPortId_SBG_ECOM_IF_ETH_3: _SbgEComPortId = 13; +#[doc = "< Ethernet interface 4."] +pub const _SbgEComPortId_SBG_ECOM_IF_ETH_4: _SbgEComPortId = 14; +#[doc = "< Data logger interface."] +pub const _SbgEComPortId_SBG_ECOM_IF_DATA_LOGGER: _SbgEComPortId = 20; +#[doc = " List of serial interfaces available."] +pub type _SbgEComPortId = ::core::ffi::c_uint; +#[doc = " List of serial interfaces available."] +pub use self::_SbgEComPortId as SbgEComPortId; +#[doc = "< This interface is turned OFF."] +pub const _SbgEComPortMode_SBG_ECOM_UART_MODE_OFF: _SbgEComPortMode = 0; +#[doc = "< This interface is using RS-232 communications."] +pub const _SbgEComPortMode_SBG_ECOM_UART_MODE_232: _SbgEComPortMode = 1; +#[doc = "< This interface is using RS-422 communications."] +pub const _SbgEComPortMode_SBG_ECOM_UART_MODE_422: _SbgEComPortMode = 2; +#[doc = " List of serial modes available."] +pub type _SbgEComPortMode = ::core::ffi::c_uint; +#[doc = " List of serial modes available."] +pub use self::_SbgEComPortMode as SbgEComPortMode; +#[doc = " Helper structure to configure a serial interface"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComInterfaceConf { + #[doc = "< The baud rate of the interface."] + pub baudRate: u32, + #[doc = "< The mode of the interface."] + pub mode: SbgEComPortMode, +} +#[test] +fn bindgen_test_layout__SbgEComInterfaceConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComInterfaceConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComInterfaceConf>(), + 8usize, + concat!("Size of: ", stringify!(_SbgEComInterfaceConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComInterfaceConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComInterfaceConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).baudRate) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComInterfaceConf), + "::", + stringify!(baudRate) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).mode) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComInterfaceConf), + "::", + stringify!(mode) + ) + ); +} +#[doc = " Helper structure to configure a serial interface"] +pub type SbgEComInterfaceConf = _SbgEComInterfaceConf; +#[doc = "< The CAN interface is disabled."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_DISABLED: _SbgEComCanBitRate = 0; +#[doc = "< 10Kb/s."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_10: _SbgEComCanBitRate = 10; +#[doc = "< 20Kb/s."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_20: _SbgEComCanBitRate = 20; +#[doc = "< 25Kb/s."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_25: _SbgEComCanBitRate = 25; +#[doc = "< 50Kb/s."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_50: _SbgEComCanBitRate = 50; +#[doc = "< 100Kb/s."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_100: _SbgEComCanBitRate = 100; +#[doc = "< 125Kb/s."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_125: _SbgEComCanBitRate = 125; +#[doc = "< 250Kb/s."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_250: _SbgEComCanBitRate = 250; +#[doc = "< 500Kb/s."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_500: _SbgEComCanBitRate = 500; +#[doc = "< 750Kb/s."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_750: _SbgEComCanBitRate = 750; +#[doc = "< 1Mb/s."] +pub const _SbgEComCanBitRate_SBG_ECOM_CAN_BITRATE_1000: _SbgEComCanBitRate = 1000; +#[doc = " Enum containing the list of all available bit rates (in KB/s)."] +pub type _SbgEComCanBitRate = ::core::ffi::c_uint; +#[doc = " Enum containing the list of all available bit rates (in KB/s)."] +pub use self::_SbgEComCanBitRate as SbgEComCanBitRate; +#[doc = "< CAN Mode undefined."] +pub const _SbgEComCanMode_SBG_ECOM_CAN_MODE_UNDEFINED: _SbgEComCanMode = 0; +#[doc = "< Only listening on the CAN bus and doesn't sent anything (even RX ACK bit)."] +pub const _SbgEComCanMode_SBG_ECOM_CAN_MODE_SPY: _SbgEComCanMode = 1; +#[doc = "< The device is allowed to both send and receive over the CAN bus."] +pub const _SbgEComCanMode_SBG_ECOM_CAN_MODE_NORMAL: _SbgEComCanMode = 2; +pub const _SbgEComCanMode_SBG_ECOM_CAN_NR_MODE: _SbgEComCanMode = 3; +#[doc = " Enum containing the list of different CAN modes"] +pub type _SbgEComCanMode = ::core::ffi::c_uint; +#[doc = " Enum containing the list of different CAN modes"] +pub use self::_SbgEComCanMode as SbgEComCanMode; +extern "C" { + #[doc = " Retrieve the configuration of one of the interfaces.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tinterfaceId\t\t\t\t\tThe interface from which the configuration is to be retrieved.\n \\param[out]\tpConf\t\t\t\t\t\tPointer to a SbgEComInterfaceConf struct to hold configuration of the interface.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdInterfaceGetUartConf( + pHandle: *mut SbgEComHandle, + interfaceId: SbgEComPortId, + pConf: *mut SbgEComInterfaceConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the configuration of one of the interfaces.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tinterfaceId\t\t\t\t\tThe interface from which the configuration is to be retrieved.\n \\param[in]\tpConf\t\t\t\t\t\tPointer to a SbgEComInterfaceConf struct that holds the new configuration for the interface.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdInterfaceSetUartConf( + pHandle: *mut SbgEComHandle, + interfaceId: SbgEComPortId, + pConf: *const SbgEComInterfaceConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the configuration of the CAN interface.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpBitrate\t\t\t\t\tThe bitrate of the CAN interface.\n \\param[out]\tpMode\t Mode of the CAN interface.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdInterfaceGetCanConf( + pHandle: *mut SbgEComHandle, + pBitrate: *mut SbgEComCanBitRate, + pMode: *mut SbgEComCanMode, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the configuration of the CAN interface.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tbitRate\t\t\t\t\t\tThe bitrate of the CAN interface.\n \\param[in]\tmode\t Mode of the CAN interface.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdInterfaceSetCanConf( + pHandle: *mut SbgEComHandle, + bitRate: SbgEComCanBitRate, + mode: SbgEComCanMode, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Upload and apply a new license to a device.\n\n The device will reboot automatically to use the new license.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpBuffer\t\t\t\t\t\tRead only buffer containing the license.\n \\param[in]\tsize\t\t\t\t\t\tSize of the buffer.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdLicenseApply( + pHandle: *mut SbgEComHandle, + pBuffer: *const ::core::ffi::c_void, + size: usize, + ) -> SbgErrorCode; +} +#[doc = "< Tell the device that the magnetic calibration will be performed with limited motions.\nThis calibration mode is only designed to be used when roll and pitch motions are less than ± 5°.\nTo work correctly, the device should be rotated through at least a full circle."] +pub const _SbgEComMagCalibMode_SBG_ECOM_MAG_CALIB_MODE_2D: _SbgEComMagCalibMode = 1; +#[doc = "< Tell the device to start a full 3D magnetic calibration procedure.\nThe 3D magnetic calibration offers the best accuracy but needs at least motion of ± 30° on the roll and pitch angles."] +pub const _SbgEComMagCalibMode_SBG_ECOM_MAG_CALIB_MODE_3D: _SbgEComMagCalibMode = 2; +#[doc = "\tDefine if the onboard magnetic calibration should acquiere points for a 3D or 2D calibration."] +pub type _SbgEComMagCalibMode = ::core::ffi::c_uint; +#[doc = "\tDefine if the onboard magnetic calibration should acquiere points for a 3D or 2D calibration."] +pub use self::_SbgEComMagCalibMode as SbgEComMagCalibMode; +#[doc = "< Tell the device that low dynamics will be observed during the magnetic calibration process."] +pub const _SbgEComMagCalibBandwidth_SBG_ECOM_MAG_CALIB_LOW_BW: _SbgEComMagCalibBandwidth = 0; +#[doc = "< Tell the device that normal dynamics will be observed during the magnetic calibration process."] +pub const _SbgEComMagCalibBandwidth_SBG_ECOM_MAG_CALIB_MEDIUM_BW: _SbgEComMagCalibBandwidth = 1; +#[doc = "< Tell the device that high dynamics will be observed during the magnetic calibration process."] +pub const _SbgEComMagCalibBandwidth_SBG_ECOM_MAG_CALIB_HIGH_BW: _SbgEComMagCalibBandwidth = 2; +#[doc = "\tUsed to select the expected dynamics during the magnetic calibration."] +pub type _SbgEComMagCalibBandwidth = ::core::ffi::c_uint; +#[doc = "\tUsed to select the expected dynamics during the magnetic calibration."] +pub use self::_SbgEComMagCalibBandwidth as SbgEComMagCalibBandwidth; +#[doc = "< All acquired points fit very well on a unit sphere after the calibration."] +pub const _SbgEComMagCalibQuality_SBG_ECOM_MAG_CALIB_QUAL_OPTIMAL: _SbgEComMagCalibQuality = 0; +#[doc = "< Small deviations of the magnetic field norm have been detected. The magnetic calibration should although provide accurate heading."] +pub const _SbgEComMagCalibQuality_SBG_ECOM_MAG_CALIB_QUAL_GOOD: _SbgEComMagCalibQuality = 1; +#[doc = "< Large deviations of the magnetic field norm have been detected. It may come from external magnetic distortions during the calibration."] +pub const _SbgEComMagCalibQuality_SBG_ECOM_MAG_CALIB_QUAL_POOR: _SbgEComMagCalibQuality = 2; +#[doc = "< No valid magnetic calibration has been computed. It could comes from too much magnetic disturbances, insufficient or invalid motions."] +pub const _SbgEComMagCalibQuality_SBG_ECOM_MAG_CALIB_QUAL_INVALID: _SbgEComMagCalibQuality = 3; +#[doc = "\tGeneral quality indicator of an onboard magnetic calibration."] +pub type _SbgEComMagCalibQuality = ::core::ffi::c_uint; +#[doc = "\tGeneral quality indicator of an onboard magnetic calibration."] +pub use self::_SbgEComMagCalibQuality as SbgEComMagCalibQuality; +#[doc = "< Reported quality indicator can be trusted as enough remarkable magnetic field points have been acquired."] +pub const _SbgEComMagCalibConfidence_SBG_ECOM_MAG_CALIB_TRUST_HIGH: _SbgEComMagCalibConfidence = 0; +#[doc = "< Few remarkable magnetic field points have been used to compute the magnetic calibration leading to a medium confidence in reported quality indicators."] +pub const _SbgEComMagCalibConfidence_SBG_ECOM_MAG_CALIB_TRUST_MEDIUM: _SbgEComMagCalibConfidence = + 1; +#[doc = "< Even if the quality indicator could report an excellent calibration,\nThe data set used to compute the magnetic calibration was not meaningful enough to compute meaningful quality indicators.\nThis calibration should be used carefully."] +pub const _SbgEComMagCalibConfidence_SBG_ECOM_MAG_CALIB_TRUST_LOW: _SbgEComMagCalibConfidence = 2; +#[doc = "\tConfidence indicator on results of an onbard magnetic calibration."] +pub type _SbgEComMagCalibConfidence = ::core::ffi::c_uint; +#[doc = "\tConfidence indicator on results of an onbard magnetic calibration."] +pub use self::_SbgEComMagCalibConfidence as SbgEComMagCalibConfidence; +#[doc = "< Should be used in most applications"] +pub const _SbgEComMagModelsStdIds_SBG_ECOM_MAG_MODEL_NORMAL: _SbgEComMagModelsStdIds = 201; +#[doc = "< Should be used in disturbed magnetic environment"] +pub const _SbgEComMagModelsStdIds_SBG_ECOM_MAG_MODEL_NOISY_MAG_TOLERANT: _SbgEComMagModelsStdIds = + 202; +#[doc = " This enum defines the different magnetometer model IDs available in standard"] +pub type _SbgEComMagModelsStdIds = ::core::ffi::c_uint; +#[doc = " This enum defines the different magnetometer model IDs available in standard"] +pub use self::_SbgEComMagModelsStdIds as SbgEComMagModelsStdId; +#[doc = " Holds all necessary information for Magnetometer module data rejection."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComMagRejectionConf { + #[doc = "< Rejection mode for magnetic field."] + pub magneticField: SbgEComRejectionMode, +} +#[test] +fn bindgen_test_layout__SbgEComMagRejectionConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComMagRejectionConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComMagRejectionConf>(), + 4usize, + concat!("Size of: ", stringify!(_SbgEComMagRejectionConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComMagRejectionConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComMagRejectionConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).magneticField) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagRejectionConf), + "::", + stringify!(magneticField) + ) + ); +} +#[doc = " Holds all necessary information for Magnetometer module data rejection."] +pub type SbgEComMagRejectionConf = _SbgEComMagRejectionConf; +#[doc = " Helper structure to retrieve onboard magnetic calibration results."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComMagCalibResults { + #[doc = "< General magnetic calibration quality indicator."] + pub quality: SbgEComMagCalibQuality, + #[doc = "< Confidence indicator that should be read to interpret the quality indicator."] + pub confidence: SbgEComMagCalibConfidence, + #[doc = "< Set of bit masks used to report advanced information on the magnetic calibration status."] + pub advancedStatus: u16, + #[doc = "< Mean magnetic field norm error observed before calibration."] + pub beforeMeanError: f32, + #[doc = "< Standard deviation of the magnetic field norm error observed before calibration."] + pub beforeStdError: f32, + #[doc = "< Maximum magnetic field norm error observed before calibration."] + pub beforeMaxError: f32, + #[doc = "< Mean magnetic field norm error observed after calibration."] + pub afterMeanError: f32, + #[doc = "< Standard deviation of the magnetic field norm error observed after calibration."] + pub afterStdError: f32, + #[doc = "< Maximum magnetic field norm error observed after calibration."] + pub afterMaxError: f32, + #[doc = "< Mean expected heading accuracy in radians."] + pub meanAccuracy: f32, + #[doc = "< Standard deviation of the expected heading accuracy in radians."] + pub stdAccuracy: f32, + #[doc = "< Maximum expected heading accuracy in radians."] + pub maxAccuracy: f32, + #[doc = "< Number of magnetic field points stored internally and used to compute the magnetic calibration."] + pub numPoints: u16, + #[doc = "< Maximum number of magnetic field points that can be stored internally."] + pub maxNumPoints: u16, + #[doc = "< Computed Hard Iron correction vector offset."] + pub offset: [f32; 3usize], + #[doc = "< Computed Hard & Soft Iron correction matrix."] + pub matrix: [f32; 9usize], +} +#[test] +fn bindgen_test_layout__SbgEComMagCalibResults() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComMagCalibResults> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComMagCalibResults>(), + 100usize, + concat!("Size of: ", stringify!(_SbgEComMagCalibResults)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComMagCalibResults>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComMagCalibResults)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).quality) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(quality) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).confidence) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(confidence) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).advancedStatus) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(advancedStatus) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).beforeMeanError) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(beforeMeanError) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).beforeStdError) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(beforeStdError) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).beforeMaxError) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(beforeMaxError) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).afterMeanError) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(afterMeanError) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).afterStdError) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(afterStdError) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).afterMaxError) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(afterMaxError) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).meanAccuracy) as usize - ptr as usize }, + 36usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(meanAccuracy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).stdAccuracy) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(stdAccuracy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).maxAccuracy) as usize - ptr as usize }, + 44usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(maxAccuracy) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).numPoints) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(numPoints) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).maxNumPoints) as usize - ptr as usize }, + 50usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(maxNumPoints) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, + 52usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(offset) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).matrix) as usize - ptr as usize }, + 64usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComMagCalibResults), + "::", + stringify!(matrix) + ) + ); +} +#[doc = " Helper structure to retrieve onboard magnetic calibration results."] +pub type SbgEComMagCalibResults = _SbgEComMagCalibResults; +extern "C" { + #[doc = " Set magnetometer error model id.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle\n \\param[in]\tmodelId\t\t\t\t\t\tMagnetometer model id to set\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully"] + pub fn sbgEComCmdMagSetModelId( + pHandle: *mut SbgEComHandle, + modelId: SbgEComMagModelsStdId, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve magnetometer error model id\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle\n \\param[out]\tpModelId\t\t\t\t\tRetrieved magnetometer model id\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully"] + pub fn sbgEComCmdMagGetModelId( + pHandle: *mut SbgEComHandle, + pModelId: *mut SbgEComMagModelsStdId, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the rejection configuration of the magnetometer module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpRejectConf\t\t\t\t\tPointer to a SbgEComMagRejectionConf struct to hold rejection configuration of the magnetometer module.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdMagGetRejection( + pHandle: *mut SbgEComHandle, + pRejectConf: *mut SbgEComMagRejectionConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the rejection configuration of the magnetometer module.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpRejectConf\t\t\t\t\tPointer to a SbgEComMagRejectionConf struct holding rejection configuration for the magnetometer module.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdMagSetRejection( + pHandle: *mut SbgEComHandle, + pRejectConf: *const SbgEComMagRejectionConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Send a command that set the magnetometers calibration parameters.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpOffset\t\t\t\t\t\tMagnetometers calibration offset vector.\n \\param[in]\tpMatrix\t\t\t\t\t\tMagnetometers calibration 3x3 matrix.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdMagSetCalibData( + pHandle: *mut SbgEComHandle, + pOffset: *const f32, + pMatrix: *const f32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Start the magnetic calibration process.\n\n As soon as this command is sent, the device will start logging magnetic field data internally.\n This set of data will be used later by the magnetic calibration algorithms to map the surrounding magnetic field.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tmode\t\t\t\t\t\tDefine which magnetic calibration type to perform. It could be 3D or 2D.\n \\param[in]\tbandwidth\t\t\t\t\tTell the device that we should have low, medium or high dynamics during the magnetic calibration process.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdMagStartCalib( + pHandle: *mut SbgEComHandle, + mode: SbgEComMagCalibMode, + bandwidth: SbgEComMagCalibBandwidth, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " This command computes a magnetic calibration solution based on the magnetic field logged since the last call to the command SBG_ECOM_CMD_START_MAG_CALIB (15).\n\n As soon as the computations are done, the device will answer with quality indicators, status flags and if possible a valid magnetic calibration matrix and offset.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpCalibResults\t\t\t\tPointer on a SbgEComMagCalibResults structure that can hold onboard magnetic calibration results and status.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdMagComputeCalib( + pHandle: *mut SbgEComHandle, + pCalibResults: *mut SbgEComMagCalibResults, + ) -> SbgErrorCode; +} +#[doc = " Holds all necessary information for Odometer module parameter configuration."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComOdoConf { + #[doc = "< Odometer's gain in pulses / meter."] + pub gain: f32, + #[doc = "< User gain average error in %"] + pub gainError: u8, + #[doc = "< Whether the odometer is in reverse mode or not."] + pub reverseMode: bool, +} +#[test] +fn bindgen_test_layout__SbgEComOdoConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComOdoConf> = ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComOdoConf>(), + 8usize, + concat!("Size of: ", stringify!(_SbgEComOdoConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComOdoConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComOdoConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gain) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComOdoConf), + "::", + stringify!(gain) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gainError) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComOdoConf), + "::", + stringify!(gainError) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).reverseMode) as usize - ptr as usize }, + 5usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComOdoConf), + "::", + stringify!(reverseMode) + ) + ); +} +#[doc = " Holds all necessary information for Odometer module parameter configuration."] +pub type SbgEComOdoConf = _SbgEComOdoConf; +#[doc = " Holds all necessary information for Odometer module data rejection."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComOdoRejectionConf { + #[doc = "< Rejection mode for velocity."] + pub velocity: SbgEComRejectionMode, +} +#[test] +fn bindgen_test_layout__SbgEComOdoRejectionConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComOdoRejectionConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComOdoRejectionConf>(), + 4usize, + concat!("Size of: ", stringify!(_SbgEComOdoRejectionConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComOdoRejectionConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComOdoRejectionConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).velocity) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComOdoRejectionConf), + "::", + stringify!(velocity) + ) + ); +} +#[doc = " Holds all necessary information for Odometer module data rejection."] +pub type SbgEComOdoRejectionConf = _SbgEComOdoRejectionConf; +#[doc = "< Channel used to decode the vehicle velocity information"] +pub const _SbgEComCmdOdoCanChannel_SBG_ECOM_CMD_ODO_CAN_CH_VELOCITY: _SbgEComCmdOdoCanChannel = 0; +#[doc = "< Channel used to decode the vehicle velocity reverse info (if available)."] +pub const _SbgEComCmdOdoCanChannel_SBG_ECOM_CMD_ODO_CAN_CH_REVERSE: _SbgEComCmdOdoCanChannel = 1; +#[doc = " CAN odometer channels definition\n A channel is an inforamtion that can be decoded / used by the device."] +pub type _SbgEComCmdOdoCanChannel = ::core::ffi::c_uint; +#[doc = " CAN odometer channels definition\n A channel is an inforamtion that can be decoded / used by the device."] +pub use self::_SbgEComCmdOdoCanChannel as SbgEComCmdOdoCanChannel; +#[doc = " Holds all necessary information for CAN Odometer parameter configuration.\n This format is very similar to info contained in a DBC file."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComCmdOdoCanConf { + #[doc = "< Set of options bit masks such as CAN extended."] + pub options: u16, + #[doc = "< CAN message ID from which the odometer velocity will be parsed."] + pub canId: u32, + #[doc = "< Index of field MSB in big endian or LSB in little endian within the payload (any value from 0 to 63)."] + pub startBit: usize, + #[doc = "< Length in bits of the odometer velocity field (any value from 1 to 64 minus dataOffset)."] + pub dataSize: usize, + #[doc = "< Value to multiply the parsed field with to get physical unit^in m.s-1."] + pub scale: f32, + #[doc = "< Offset to add on the scaled velocity information in m.s-1 (after applying scale factor)."] + pub offset: f32, + #[doc = "< The minimum velocity to consider the message valid in m.s-1"] + pub minValue: f32, + #[doc = "< The maximum velocity to consider the message valid in m.s-1"] + pub maxValue: f32, +} +#[test] +fn bindgen_test_layout__SbgEComCmdOdoCanConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComCmdOdoCanConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComCmdOdoCanConf>(), + 32usize, + concat!("Size of: ", stringify!(_SbgEComCmdOdoCanConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComCmdOdoCanConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComCmdOdoCanConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).options) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdOdoCanConf), + "::", + stringify!(options) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).canId) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdOdoCanConf), + "::", + stringify!(canId) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).startBit) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdOdoCanConf), + "::", + stringify!(startBit) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).dataSize) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdOdoCanConf), + "::", + stringify!(dataSize) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).scale) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdOdoCanConf), + "::", + stringify!(scale) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdOdoCanConf), + "::", + stringify!(offset) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).minValue) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdOdoCanConf), + "::", + stringify!(minValue) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).maxValue) as usize - ptr as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComCmdOdoCanConf), + "::", + stringify!(maxValue) + ) + ); +} +#[doc = " Holds all necessary information for CAN Odometer parameter configuration.\n This format is very similar to info contained in a DBC file."] +pub type SbgEComCmdOdoCanConf = _SbgEComCmdOdoCanConf; +extern "C" { + #[doc = " For quadrature and/or pulse based odometer, retrieve the configuration.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpOdometerConf\t\t\t\tPointer to a SbgEComOdoConf struct to hold configuration of the odometer module.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOdoGetConf( + pHandle: *mut SbgEComHandle, + pOdometerConf: *mut SbgEComOdoConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " For quadrature and/or pulse base odometer, define the configuration.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpOdometerConf\t\t\t\tPointer to a SbgEComOdoConf struct holding configuration for the odometer module.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOdoSetConf( + pHandle: *mut SbgEComHandle, + pOdometerConf: *const SbgEComOdoConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the lever arm applicable for both quadrature or CAN based odometer.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpLeverArm\t\t\t\t\tArray of three values, one for each axis.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOdoGetLeverArm( + pHandle: *mut SbgEComHandle, + pLeverArm: *mut f32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the lever arm applicable for both quadrature or CAN based odometer.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpLeverArm\t\t\t\t\tArray of three values, one for each axis.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOdoSetLeverArm( + pHandle: *mut SbgEComHandle, + pLeverArm: *const f32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the velocity rejection configuration for both quadrature or CAN based odometer.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpRejectConf\t\t\t\t\tPointer to a SbgEComOdoRejectionConf struct to hold rejection configuration of the odometer module.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOdoGetRejection( + pHandle: *mut SbgEComHandle, + pRejectConf: *mut SbgEComOdoRejectionConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the velocity rejection configuration for both quadrature or CAN based odometer.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpRejectConf\t\t\t\t\tPointer to a SbgEComOdoRejectionConf struct holding rejection configuration for the odometer module.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOdoSetRejection( + pHandle: *mut SbgEComHandle, + pRejectConf: *const SbgEComOdoRejectionConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the CAN odometer configuration for a specific CAN information channel\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tcanChannel\t\t\t\t\tThe CAN channel to retreive associated DBC configuration.\n \\param[out]\tpOdoCanConf\t\t\t\t\tStruct to hold configuration of the CAN odometer.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOdoCanGetConf( + pHandle: *mut SbgEComHandle, + canChannel: SbgEComCmdOdoCanChannel, + pOdoCanConf: *mut SbgEComCmdOdoCanConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the CAN odometer configuration for a specific CAN information channel\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tcanChannel\t\t\t\t\tThe CAN channel to define associated DBC configuration.\n \\param[in]\tpOdoCanConf\t\t\t\t\tStruct holding configuration for the CAN odometer.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOdoCanSetConf( + pHandle: *mut SbgEComHandle, + canChannel: SbgEComCmdOdoCanChannel, + pOdoCanConf: *const SbgEComCmdOdoCanConf, + ) -> SbgErrorCode; +} +#[doc = "< Main output port."] +pub const _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_A: _SbgEComOutputPort = 0; +#[doc = "< Secondary output port only available on Ellipse-E devices"] +pub const _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_C: _SbgEComOutputPort = 2; +#[doc = "< Secondary output port only available on B1 devices"] +pub const _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_E: _SbgEComOutputPort = 4; +#[doc = " List of ouput ports available."] +pub type _SbgEComOutputPort = ::core::ffi::c_uint; +#[doc = " List of ouput ports available."] +pub use self::_SbgEComOutputPort as SbgEComOutputPort; +#[doc = "< This output is disabled."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DISABLED: _SbgEComOutputMode = 0; +#[doc = "< Output the message every main loop (ie 200 Hz)."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_MAIN_LOOP: _SbgEComOutputMode = 1; +#[doc = "< Output the message every 2 main loops (ie 100 Hz)."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_2: _SbgEComOutputMode = 2; +#[doc = "< Output the message every 4 main loops (ie 50 Hz)."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_4: _SbgEComOutputMode = 4; +#[doc = "< Output the message every 4 main loops (ie 40 Hz)."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_5: _SbgEComOutputMode = 5; +#[doc = "< Output the message every 8 main loops (ie 25 Hz)."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_8: _SbgEComOutputMode = 8; +#[doc = "< Output the message every 10 main loops (ie 20 Hz)."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_10: _SbgEComOutputMode = 10; +#[doc = "< Output the message every 20 main loops (ie 10 Hz)."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_20: _SbgEComOutputMode = 20; +#[doc = "< Output the message every 40 main loops (ie 5 Hz)."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_40: _SbgEComOutputMode = 40; +#[doc = "< Output the message every 200 main loops (ie 1 Hz)."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_200: _SbgEComOutputMode = 200; +#[doc = "< Output the message on a Pulse Per Second event."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_PPS: _SbgEComOutputMode = 10000; +#[doc = "< Output sent when a new data is available."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_NEW_DATA: _SbgEComOutputMode = 10001; +#[doc = "< Output the message when a Sync A is received."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_EVENT_IN_A: _SbgEComOutputMode = 10003; +#[doc = "< Output the message when a Sync B is received."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_EVENT_IN_B: _SbgEComOutputMode = 10004; +#[doc = "< Output the message when a Sync C is received."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_EVENT_IN_C: _SbgEComOutputMode = 10005; +#[doc = "< Output the message when a Sync D is received."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_EVENT_IN_D: _SbgEComOutputMode = 10006; +#[doc = "< Output the message when a Sync E is received."] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_EVENT_IN_E: _SbgEComOutputMode = 10007; +#[doc = "< Output the message in the 1KHz IMU loop"] +pub const _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_HIGH_FREQ_LOOP: _SbgEComOutputMode = 20001; +#[doc = " List of output modes available."] +pub type _SbgEComOutputMode = ::core::ffi::c_uint; +#[doc = " List of output modes available."] +pub use self::_SbgEComOutputMode as SbgEComOutputMode; +#[doc = "< Output measurements at the IMU location."] +pub const _SbgEComOutputMonitoringPoint_SBG_ECOM_OUTPUT_MONITORING_POINT_IMU: + _SbgEComOutputMonitoringPoint = 0; +#[doc = "< Output measurements at the center of rotation."] +pub const _SbgEComOutputMonitoringPoint_SBG_ECOM_OUTPUT_MONITORING_POINT_COG: + _SbgEComOutputMonitoringPoint = 1; +#[doc = "< Output measurements at the user deported location 1 (only for Ekinox and Apogee)."] +pub const _SbgEComOutputMonitoringPoint_SBG_ECOM_OUTPUT_MONITORING_POINT_1: + _SbgEComOutputMonitoringPoint = 2; +#[doc = "< Output measurements at the user deported location 2 (only for Ekinox and Apogee)."] +pub const _SbgEComOutputMonitoringPoint_SBG_ECOM_OUTPUT_MONITORING_POINT_2: + _SbgEComOutputMonitoringPoint = 3; +#[doc = "< Output measurements at the user deported location 3 (only for Ekinox and Apogee)."] +pub const _SbgEComOutputMonitoringPoint_SBG_ECOM_OUTPUT_MONITORING_POINT_3: + _SbgEComOutputMonitoringPoint = 4; +#[doc = "< Number of output monitoring points."] +pub const _SbgEComOutputMonitoringPoint_SBG_ECOM_OUTPUT_MONITORING_NUM: + _SbgEComOutputMonitoringPoint = 5; +#[doc = " Defines which monitoring point to use for an output port.\n This feature enabled deporting measurements at a specific monitoring point."] +pub type _SbgEComOutputMonitoringPoint = ::core::ffi::c_uint; +#[doc = " Defines which monitoring point to use for an output port.\n This feature enabled deporting measurements at a specific monitoring point."] +pub use self::_SbgEComOutputMonitoringPoint as SbgEComOutputMonitoringPoint; +extern "C" { + #[doc = " Retrieve the configuration of one the message on one of the output interfaces.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\toutputPort\t\t\t\t\tThe output port of the device for the log concerned.\n \\param[in]\tclassId\t\t\t\t\t\tThe class of the concerned log.\n \\param[in]\tmsgId\t\t\t\t\t\tThe id of the concerned log.\n \\param[out]\tpMode\t\t\t\t\t\tPointer to a SbgEComOutputMode to contain the current output mode of the message.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOutputGetConf( + pHandle: *mut SbgEComHandle, + outputPort: SbgEComOutputPort, + classId: SbgEComClass, + msgId: SbgEComMsgId, + pMode: *mut SbgEComOutputMode, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the configuration of one the message on one of the output interfaces.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\toutputPort\t\t\t\t\tThe output port of the device for the log concerned.\n \\param[in]\tclassId\t\t\t\t\t\tThe class of the concerned log.\n \\param[in]\tmsgId\t\t\t\t\t\tThe id of the concerned log.\n \\param[in]\tmode\t\t\t\t\t\tNew output mode to set.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOutputSetConf( + pHandle: *mut SbgEComHandle, + outputPort: SbgEComOutputPort, + classId: SbgEComClass, + msgId: SbgEComMsgId, + mode: SbgEComOutputMode, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the enable of one of the output class message on one of the output interfaces.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\toutputPort\t\t\t\t\tThe output port.\n \\param[in]\tclassId\t\t\t\t\t\tThe class to enable or disable.\n \\param[out]\tpEnable\t\t\t\t\t\tTRUE to enable message output of this class, FALSE to disable it.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOutputClassGetEnable( + pHandle: *mut SbgEComHandle, + outputPort: SbgEComOutputPort, + classId: SbgEComClass, + pEnable: *mut bool, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the enable of one of the output class message on one of the output interfaces.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\toutputPort\t\t\t\t\tThe output port.\n \\param[in]\tclassId\t\t\t\t\t\tThe class to enable or disable.\n \\param[in]\tenable\t\t\t\t\t\tTRUE to enable message output of this class, FALSE to disable it.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOutputClassSetEnable( + pHandle: *mut SbgEComHandle, + outputPort: SbgEComOutputPort, + classId: SbgEComClass, + enable: bool, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the configuration of one the message on the CAN interface.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tinternalId\t\t\t\t\tThe internal message id.\n \\param[out]\tpMode\t\t\t\t\t\tPointer to a SbgEComOutputMode to contain the current output mode of the message.\n \\param[out]\tpUserId\t\t\t\t\t\tThe user defined message id.\n \\param[out]\tpExtended\t\t\t\t\tTRUE if the user id uses the extended format.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdCanOutputGetConf( + pHandle: *mut SbgEComHandle, + internalId: SbgECanMessageId, + pMode: *mut SbgEComOutputMode, + pUserId: *mut u32, + pExtended: *mut bool, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the configuration of one the message on the CAN interface\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tinternalId\t\t\t\t\tThe internal message id.\n \\param[in]\tmode\t\t\t\t\t\tPointer to a SbgEComOutputMode containing the new output mode of the message.\n \\param[in]\tuserId\t\t\t\t\t\tThe user defined message id.\n \\param[in]\textended\t\t\t\t\tTRUE if the user id uses the extended format.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdCanOutputSetConf( + pHandle: *mut SbgEComHandle, + internalId: SbgECanMessageId, + mode: SbgEComOutputMode, + userId: u32, + extended: bool, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the NMEA talker id of one of the output interfaces.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\toutputPort\t\t\t\t\tThe output port of the device for the log concerned.\n \\param[out]\tpNmeaTalkerId\t\t\t\tA 2-char array to contain the nmea talker id.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOutputGetNmeaTalkerId( + pHandle: *mut SbgEComHandle, + outputPort: SbgEComOutputPort, + pNmeaTalkerId: *mut ::core::ffi::c_char, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the NMEA talker id of one of the output interfaces.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\toutputPort\t\t\t\t\tThe output port of the device for the log concerned.\n \\param[out]\tpNmeaTalkerId\t\t\t\tA 2-char array containint the new nmea talker id.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdOutputSetNmeaTalkerId( + pHandle: *mut SbgEComHandle, + outputPort: SbgEComOutputPort, + pNmeaTalkerId: *const ::core::ffi::c_char, + ) -> SbgErrorCode; +} +#[doc = "< Module connected on PORT_A."] +pub const _SbgEComModulePortAssignment_SBG_ECOM_MODULE_PORT_A: _SbgEComModulePortAssignment = 0; +#[doc = "< Module connected on PORT_B."] +pub const _SbgEComModulePortAssignment_SBG_ECOM_MODULE_PORT_B: _SbgEComModulePortAssignment = 1; +#[doc = "< Module connected on PORT_C."] +pub const _SbgEComModulePortAssignment_SBG_ECOM_MODULE_PORT_C: _SbgEComModulePortAssignment = 2; +#[doc = "< Module connected on PORT_D."] +pub const _SbgEComModulePortAssignment_SBG_ECOM_MODULE_PORT_D: _SbgEComModulePortAssignment = 3; +#[doc = "< Module connected on PORT_E."] +pub const _SbgEComModulePortAssignment_SBG_ECOM_MODULE_PORT_E: _SbgEComModulePortAssignment = 4; +#[doc = "< Module is connected internally."] +pub const _SbgEComModulePortAssignment_SBG_ECOM_MODULE_INTERNAL: _SbgEComModulePortAssignment = 5; +#[doc = "< Module is disabled."] +pub const _SbgEComModulePortAssignment_SBG_ECOM_MODULE_DISABLED: _SbgEComModulePortAssignment = 255; +#[doc = " Ports available for the modules."] +pub type _SbgEComModulePortAssignment = ::core::ffi::c_uint; +#[doc = " Ports available for the modules."] +pub use self::_SbgEComModulePortAssignment as SbgEComModulePortAssignment; +#[doc = "< Module is disabled."] +pub const _SbgEComModuleSyncAssignment_SBG_ECOM_MODULE_SYNC_DISABLED: _SbgEComModuleSyncAssignment = + 0; +#[doc = "< Synchronization is done using SYNC_IN_A pin."] +pub const _SbgEComModuleSyncAssignment_SBG_ECOM_MODULE_SYNC_IN_A: _SbgEComModuleSyncAssignment = 1; +#[doc = "< Synchronization is done using SYNC_IN_B pin."] +pub const _SbgEComModuleSyncAssignment_SBG_ECOM_MODULE_SYNC_IN_B: _SbgEComModuleSyncAssignment = 2; +#[doc = "< Synchronization is done using SYNC_IN_C pin."] +pub const _SbgEComModuleSyncAssignment_SBG_ECOM_MODULE_SYNC_IN_C: _SbgEComModuleSyncAssignment = 3; +#[doc = "< Synchronization is done using SYNC_IN_D pin."] +pub const _SbgEComModuleSyncAssignment_SBG_ECOM_MODULE_SYNC_IN_D: _SbgEComModuleSyncAssignment = 4; +#[doc = "< Synchronization is internal."] +pub const _SbgEComModuleSyncAssignment_SBG_ECOM_MODULE_SYNC_INTERNAL: _SbgEComModuleSyncAssignment = + 5; +#[doc = "< Synchronization signal is output on SYNC_OUT_A."] +pub const _SbgEComModuleSyncAssignment_SBG_ECOM_MODULE_SYNC_OUT_A: _SbgEComModuleSyncAssignment = 6; +#[doc = "< Synchronization signal is output on SYNC_OUT_B."] +pub const _SbgEComModuleSyncAssignment_SBG_ECOM_MODULE_SYNC_OUT_B: _SbgEComModuleSyncAssignment = 7; +#[doc = " Synchronization signals available for the modules."] +pub type _SbgEComModuleSyncAssignment = ::core::ffi::c_uint; +#[doc = " Synchronization signals available for the modules."] +pub use self::_SbgEComModuleSyncAssignment as SbgEComModuleSyncAssignment; +#[doc = "< Odometer is disabled."] +pub const _SbgEComOdometerPinAssignment_SBG_ECOM_MODULE_ODO_DISABLED: + _SbgEComOdometerPinAssignment = 0; +#[doc = "< Odometer connected only to ODO_A (unidirectional).."] +pub const _SbgEComOdometerPinAssignment_SBG_ECOM_MODULE_ODO_A: _SbgEComOdometerPinAssignment = 1; +#[doc = "< Odometer connected to both ODO_A (signal A) and ODO_B (Signal B or direction) for bidirectional odometer.."] +pub const _SbgEComOdometerPinAssignment_SBG_ECOM_MODULE_ODO_A_B: _SbgEComOdometerPinAssignment = 2; +#[doc = "< Vehicle odometer using CAN (OBD-II)."] +pub const _SbgEComOdometerPinAssignment_SBG_ECOM_MODULE_ODO_CAN: _SbgEComOdometerPinAssignment = 3; +#[doc = " List of configurations available for the odometer."] +pub type _SbgEComOdometerPinAssignment = ::core::ffi::c_uint; +#[doc = " List of configurations available for the odometer."] +pub use self::_SbgEComOdometerPinAssignment as SbgEComOdometerPinAssignment; +#[doc = "< Should be used as a default when other profiles do not apply"] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_GENERAL_PURPOSE: + _SbgEComMotionProfileStdIds = 1; +#[doc = "< Dedicated to car applications with strict lateral velocity constraints."] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_AUTOMOTIVE: + _SbgEComMotionProfileStdIds = 2; +#[doc = "< Used in marine and underwater applications"] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_MARINE: _SbgEComMotionProfileStdIds = + 3; +#[doc = "< For fixed wings aircraft"] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_AIRPLANE: + _SbgEComMotionProfileStdIds = 4; +#[doc = "< For rotary wing aircraft"] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_HELICOPTER: + _SbgEComMotionProfileStdIds = 5; +#[doc = "< Pedestrian applications using foot odometry"] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_PEDESTRIAN: + _SbgEComMotionProfileStdIds = 6; +#[doc = "< For rotary wing UAVs that have low dynamics"] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_UAV_ROTARY_WING: + _SbgEComMotionProfileStdIds = 7; +#[doc = "< For vibrating applications with low dynamics and no specific travel direction"] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_HEAVY_MACHINERY: + _SbgEComMotionProfileStdIds = 8; +#[doc = "< Static motion profile that delivers stable results for 27/7 operations."] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_STATIC: _SbgEComMotionProfileStdIds = + 9; +#[doc = "< Truck applications with medium lateral velocity constraints."] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_TRUCK: _SbgEComMotionProfileStdIds = + 10; +#[doc = "< Train applications with relaxed lateral velocity constraints."] +pub const _SbgEComMotionProfileStdIds_SBG_ECOM_MOTION_PROFILE_RAILWAY: _SbgEComMotionProfileStdIds = + 11; +#[doc = " This enum defines the different motion profile IDs available in standard"] +pub type _SbgEComMotionProfileStdIds = ::core::ffi::c_uint; +#[doc = " This enum defines the different motion profile IDs available in standard"] +pub use self::_SbgEComMotionProfileStdIds as SbgEComMotionProfileStdIds; +#[doc = " Helper structure for module assignments"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComAidingAssignConf { + #[doc = "< GNSS module port assignment."] + pub gps1Port: SbgEComModulePortAssignment, + #[doc = "< GNSS module sync assignment."] + pub gps1Sync: SbgEComModuleSyncAssignment, + #[doc = "< Port on which the DVL is connected"] + pub dvlPort: SbgEComModulePortAssignment, + #[doc = "< Optional sync signal that could be used to time stamp the DVL data."] + pub dvlSync: SbgEComModuleSyncAssignment, + #[doc = "< RTCM input port assignment for IGNG-N DGPS."] + pub rtcmPort: SbgEComModulePortAssignment, + #[doc = "< Port on which Air Data aiding is connected."] + pub airDataPort: SbgEComModulePortAssignment, + #[doc = "< Odometer module pin assignment."] + pub odometerPinsConf: SbgEComOdometerPinAssignment, +} +#[test] +fn bindgen_test_layout__SbgEComAidingAssignConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComAidingAssignConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComAidingAssignConf>(), + 28usize, + concat!("Size of: ", stringify!(_SbgEComAidingAssignConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComAidingAssignConf>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComAidingAssignConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gps1Port) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAidingAssignConf), + "::", + stringify!(gps1Port) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).gps1Sync) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAidingAssignConf), + "::", + stringify!(gps1Sync) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).dvlPort) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAidingAssignConf), + "::", + stringify!(dvlPort) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).dvlSync) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAidingAssignConf), + "::", + stringify!(dvlSync) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).rtcmPort) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAidingAssignConf), + "::", + stringify!(rtcmPort) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).airDataPort) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAidingAssignConf), + "::", + stringify!(airDataPort) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).odometerPinsConf) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComAidingAssignConf), + "::", + stringify!(odometerPinsConf) + ) + ); +} +#[doc = " Helper structure for module assignments"] +pub type SbgEComAidingAssignConf = _SbgEComAidingAssignConf; +#[doc = " Helper structure for sensor alignment details"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComSensorAlignmentInfo { + #[doc = "< Sensor X axis direction in vehicle"] + pub axisDirectionX: SbgEComAxisDirection, + #[doc = "< Sensor Y axis direction in vehicle"] + pub axisDirectionY: SbgEComAxisDirection, + #[doc = "< Roll angle fine misalignment in rad"] + pub misRoll: f32, + #[doc = "< Pitch angle fine misalignment in rad"] + pub misPitch: f32, + #[doc = "< Yaw angle fine misalignment in rad"] + pub misYaw: f32, +} +#[test] +fn bindgen_test_layout__SbgEComSensorAlignmentInfo() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComSensorAlignmentInfo> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComSensorAlignmentInfo>(), + 20usize, + concat!("Size of: ", stringify!(_SbgEComSensorAlignmentInfo)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComSensorAlignmentInfo>(), + 4usize, + concat!("Alignment of ", stringify!(_SbgEComSensorAlignmentInfo)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).axisDirectionX) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComSensorAlignmentInfo), + "::", + stringify!(axisDirectionX) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).axisDirectionY) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComSensorAlignmentInfo), + "::", + stringify!(axisDirectionY) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).misRoll) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComSensorAlignmentInfo), + "::", + stringify!(misRoll) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).misPitch) as usize - ptr as usize }, + 12usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComSensorAlignmentInfo), + "::", + stringify!(misPitch) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).misYaw) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComSensorAlignmentInfo), + "::", + stringify!(misYaw) + ) + ); +} +#[doc = " Helper structure for sensor alignment details"] +pub type SbgEComSensorAlignmentInfo = _SbgEComSensorAlignmentInfo; +#[doc = " Helper structure for sensor Initial condition details"] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _SbgEComInitConditionConf { + #[doc = "< Initial latitude in °"] + pub latitude: f64, + #[doc = "< Initial longitude in °"] + pub longitude: f64, + #[doc = "< Initial altitude above MSL in meters"] + pub altitude: f64, + #[doc = "< Initial Year"] + pub year: u16, + #[doc = "< Initial month"] + pub month: u8, + #[doc = "< Initial day"] + pub day: u8, +} +#[test] +fn bindgen_test_layout__SbgEComInitConditionConf() { + const UNINIT: ::core::mem::MaybeUninit<_SbgEComInitConditionConf> = + ::core::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::core::mem::size_of::<_SbgEComInitConditionConf>(), + 32usize, + concat!("Size of: ", stringify!(_SbgEComInitConditionConf)) + ); + assert_eq!( + ::core::mem::align_of::<_SbgEComInitConditionConf>(), + 8usize, + concat!("Alignment of ", stringify!(_SbgEComInitConditionConf)) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).latitude) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComInitConditionConf), + "::", + stringify!(latitude) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).longitude) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComInitConditionConf), + "::", + stringify!(longitude) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).altitude) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComInitConditionConf), + "::", + stringify!(altitude) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).year) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComInitConditionConf), + "::", + stringify!(year) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).month) as usize - ptr as usize }, + 26usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComInitConditionConf), + "::", + stringify!(month) + ) + ); + assert_eq!( + unsafe { ::core::ptr::addr_of!((*ptr).day) as usize - ptr as usize }, + 27usize, + concat!( + "Offset of field: ", + stringify!(_SbgEComInitConditionConf), + "::", + stringify!(day) + ) + ); +} +#[doc = " Helper structure for sensor Initial condition details"] +pub type SbgEComInitConditionConf = _SbgEComInitConditionConf; +extern "C" { + #[doc = " Set the motion profile id used to tune the Kalman Filter to a specific application\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tmodelId\t\t\t\t\t\tMotion profile id to set\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSensorSetMotionProfileId( + pHandle: *mut SbgEComHandle, + modelId: SbgEComMotionProfileStdIds, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the motion profile id.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpModelId\t\t\t\t\tRetrieved motion profile id\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSensorGetMotionProfileId( + pHandle: *mut SbgEComHandle, + pModelId: *mut SbgEComMotionProfileStdIds, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the initial conditions settings.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpConf\t\t\t\t\t\tPointer to a SbgEComInitConditionConf to contain the current initial conditions settings.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSensorGetInitCondition( + pHandle: *mut SbgEComHandle, + pConf: *mut SbgEComInitConditionConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the initial condition configuration.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpConf\t\t\t\t\t\tPointer to a SbgEComInitConditionConf containing the new initial condition configuration.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSensorSetInitCondition( + pHandle: *mut SbgEComHandle, + pConf: *const SbgEComInitConditionConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the assignment of the aiding sensors.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpConf\t\t\t\t\t\tPointer to a SbgEComAidingAssignConf to contain the current assignment of the aiding sensors.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSensorGetAidingAssignment( + pHandle: *mut SbgEComHandle, + pConf: *mut SbgEComAidingAssignConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the assignment of the aiding sensors.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpConf\t\t\t\t\t\tPointer to a SbgEComAidingAssignConf containing the new assignment of the aiding sensors.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSensorSetAidingAssignment( + pHandle: *mut SbgEComHandle, + pConf: *const SbgEComAidingAssignConf, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve the alignment and lever arm configuration of the sensor.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[out]\tpAlignConf\t\t\t\t\tPointer to a SbgEComSensorAlignmentInfo struct to hold alignment configuration of the sensor.\n \\param[out]\tpLeverArm\t\t\t\t\tPointer to a table to contain lever arm X, Y, Z components in meters.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSensorGetAlignmentAndLeverArm( + pHandle: *mut SbgEComHandle, + pAlignConf: *mut SbgEComSensorAlignmentInfo, + pLeverArm: *mut f32, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Set the alignment and lever arm configuration of the sensor.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpAlignConf\t\t\t\t\tPointer to a SbgEComSensorAlignmentInfo struct holding alignment configuration for the sensor.\n \\param[in]\tpLeverArm\t\t\t\t\tPointer to a table containing lever arm X, Y, Z components in meters.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSensorSetAlignmentAndLeverArm( + pHandle: *mut SbgEComHandle, + pAlignConf: *const SbgEComSensorAlignmentInfo, + pLeverArm: *const f32, + ) -> SbgErrorCode; +} +#[doc = "< Only reboot the device."] +pub const _SbgEComSettingsAction_SBG_ECOM_REBOOT_ONLY: _SbgEComSettingsAction = 0; +#[doc = "< Save the settings to non-volatile memory and then reboot the device."] +pub const _SbgEComSettingsAction_SBG_ECOM_SAVE_SETTINGS: _SbgEComSettingsAction = 1; +#[doc = "< Restore default settings, save them to non-volatile memory and reboot the device."] +pub const _SbgEComSettingsAction_SBG_ECOM_RESTORE_DEFAULT_SETTINGS: _SbgEComSettingsAction = 2; +#[doc = " Defintion of all the settings actions available."] +pub type _SbgEComSettingsAction = ::core::ffi::c_uint; +#[doc = " Defintion of all the settings actions available."] +pub use self::_SbgEComSettingsAction as SbgEComSettingsAction; +extern "C" { + #[doc = " Send a command to execute a specific system action to reboot/save/restore default settings.\n\n Execute one of the available settings action:\n\t- SBG_ECOM_REBOOT_ONLY : Only reboot the device.\n\t- SBG_ECOM_SAVE_SETTINGS : Save the settings to non-volatile memory and then reboot the device.\n\t- SBG_ECOM_RESTORE_DEFAULT_SETTINGS : Restore default settings, save them to non-volatile memory and reboot the device.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\taction\t\t\t\t\t\tOne of the available SbgEComSettingsAction.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdSettingsAction( + pHandle: *mut SbgEComHandle, + action: SbgEComSettingsAction, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Send a complete set of settings to the device and store them into the FLASH memory.\n\n The device will reboot automatically to use the new settings.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpBuffer\t\t\t\t\t\tRead only buffer containing the settings.\n \\param[in]\tsize\t\t\t\t\t\tSize of the buffer.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdImportSettings( + pHandle: *mut SbgEComHandle, + pBuffer: *const ::core::ffi::c_void, + size: usize, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Retrieve a complete set of settings from the device as a buffer.\n\n \\param[in]\tpHandle\t\t\t\t\t\tA valid sbgECom handle.\n \\param[in]\tpBuffer\t\t\t\t\t\tAllocated buffer that can hold the received settings.\n \\param[out]\tpSize\t\t\t\t\t\tThe number of bytes that have been stored into pBuffer.\n \\param[in]\tmaxSize\t\t\t\t\t\tThe maximum buffer size in bytes that can be stored into pBuffer.\n \\return\t\t\t\t\t\t\t\t\tSBG_NO_ERROR if the command has been executed successfully."] + pub fn sbgEComCmdExportSettings( + pHandle: *mut SbgEComHandle, + pBuffer: *mut ::core::ffi::c_void, + pSize: *mut usize, + maxSize: usize, + ) -> SbgErrorCode; +} +extern "C" { + #[doc = " Returns an integer representing the version of the sbgECom library.\n\n \\return\t\t\t\t\t\t\t\t\t\tAn integer representing the version of the sbgECom library.
"] + pub fn sbgEComGetVersion() -> u32; +} +extern "C" { + #[doc = " Retrieve the sbgECom library version as a string (1.0.443-stable).\n\n \\return\t\t\t\t\t\t\t\t\t\tNull terminated string that contains the sbgECom library version."] + pub fn sbgEComGetVersionAsString() -> *const ::core::ffi::c_char; +} diff --git a/crates/sbg-rs/src/data_conversion.rs b/crates/sbg-rs/src/data_conversion.rs new file mode 100644 index 0000000..b960702 --- /dev/null +++ b/crates/sbg-rs/src/data_conversion.rs @@ -0,0 +1,277 @@ +use crate::bindings::{ + SbgLogAirData, SbgLogEkfNavData, SbgLogEkfQuatData, SbgLogGpsPos, SbgLogGpsVel, SbgLogImuData, + SbgLogUtcData, +}; +use defmt::info; +use messages_prost::sensor::sbg::{ + Air, AirData, AirStatus, AirStatusFlag, EkfNav, EkfPositionData, EkfQuat, EkfStatus, + EkfStatusFlag, EkfVelocityData, GpsPos, GpsPosData, GpsPositionStatus, GpsPositionStatusE, + GpsPositionType, GpsVel, GpsVelData, GpsVelStatus, GpsVelStatusE, GpsVelType, Imu, + ImuAccelData, ImuGyroData, ImuStatus, ImuStatusFlag, Quaternion, QuaternionData, UtcStatus, + UtcTime, UtcTimeData, UtcTimeStatus, Vector3, +}; + +/// Simple helper function to work with boolean flags and set the fields as needed. +#[inline] +fn check(flag: bool, value: T) -> Option { + if flag { + Some(value) + } else { + None + } +} + +/// Convert array to Vector3 +fn array_to_vector3(arr: [f32; 3]) -> Vector3 { + Vector3 { + x: arr[0] as f64, + y: arr[1] as f64, + z: arr[2] as f64, + } +} + +/// Convert array to Quaternion +fn array_to_quaternion(arr: [f32; 4]) -> Quaternion { + Quaternion { + w: arr[0] as f64, + x: arr[1] as f64, + y: arr[2] as f64, + z: arr[3] as f64, + } +} + +/// Convert array to Vector3 for f64 arrays (position data) +fn array_to_vector3_f64(arr: [f64; 3]) -> Vector3 { + Vector3 { + x: arr[0], + y: arr[1], + z: arr[2], + } +} + +impl From for GpsPos { + fn from(value: SbgLogGpsPos) -> Self { + let status = GpsPositionStatus { + status: value.status as i32, + r#type: GpsPositionType::Unspecified as i32, // Adjust as needed + }; + let valid = status.status == GpsPositionStatusE::SolComputed as i32; + // info!("Gps message sbg {}, {}", value.latitude, value.longitude); + + let data = Some(GpsPosData { + latitude: value.latitude, + longitude: value.longitude, + time_of_week: value.timeOfWeek, + undulation: value.undulation, + altitude: value.altitude, + latitude_accuracy: value.latitudeAccuracy, + longitude_accuracy: value.longitudeAccuracy, + altitude_accuracy: value.altitudeAccuracy, + num_sv_used: value.numSvUsed as u32, + base_station_id: value.baseStationId as u32, + differential_age: value.differentialAge as u32, + }); + // if valid { + + // } else { + // None + // }; + GpsPos { + time_stamp: value.timeStamp, + status: Some(status), + data, + } + } +} + +impl From for UtcTime { + fn from(value: SbgLogUtcData) -> Self { + let status = UtcTimeStatus { + clock_status: 0, // Default value + utc_status: value.status as i32, + }; + let valid = status.utc_status == UtcStatus::NoLeapSec as i32 + || status.utc_status == UtcStatus::UtcValid as i32; + let data = if valid { + Some(UtcTimeData { + year: value.year as u32, + month: value.month as i32, + day: value.day as i32, + hour: value.hour as i32, + minute: value.minute as i32, + second: value.second as i32, + nano_second: value.nanoSecond, + gps_time_of_week: value.gpsTimeOfWeek, + }) + } else { + None + }; + UtcTime { + time_stamp: value.timeStamp, + status: Some(status), + data, + } + } +} + +impl From for Air { + fn from(value: SbgLogAirData) -> Self { + let status = AirStatus { + flags: value.status as u32, + }; + let data = Some(AirData { + pressure_abs: if (status.flags & AirStatusFlag::AirStatusPressureAbsValid as u32) != 0 { + value.pressureAbs + } else { + 0.0 + }, + altitude: if (status.flags & AirStatusFlag::AirStatusAltitudeValid as u32) != 0 { + value.altitude + } else { + 0.0 + }, + pressure_diff: if (status.flags & AirStatusFlag::AirStatusPressureDiffValid as u32) != 0 + { + value.pressureDiff + } else { + 0.0 + }, + true_airspeed: if (status.flags & AirStatusFlag::AirStatusAirspeedValid as u32) != 0 { + value.trueAirspeed + } else { + 0.0 + }, + air_temperature: if (status.flags & AirStatusFlag::AirStatusTemperatureValid as u32) + != 0 + { + value.airTemperature + } else { + 0.0 + }, + }); + Air { + time_stamp: value.timeStamp, + status: Some(status), + data, + } + } +} + +impl From for EkfQuat { + fn from(value: SbgLogEkfQuatData) -> Self { + let heading_valid = (value.status & EkfStatusFlag::EkfStatusHeadingValid as u32) != 0; + let status = EkfStatus { + flags: value.status, + }; + let data = if heading_valid { + Some(QuaternionData { + quaternion: Some(array_to_quaternion(value.quaternion)), + euler_std_dev: Some(array_to_vector3(value.eulerStdDev)), + }) + } else { + None + }; + EkfQuat { + time_stamp: value.timeStamp, + status: Some(status), + data, + } + } +} + +impl From for EkfNav { + fn from(value: SbgLogEkfNavData) -> Self { + let status = EkfStatus { + flags: value.status as u32, + }; + let velocity_valid = (status.flags & EkfStatusFlag::EkfStatusVelocityValid as u32) != 0; + let position_valid = (status.flags & EkfStatusFlag::EkfStatusPositionValid as u32) != 0; + let attitude_valid = (status.flags & EkfStatusFlag::EkfStatusAttitudeValid as u32) != 0; + let velocity = if velocity_valid { + Some(EkfVelocityData { + velocity: Some(array_to_vector3(value.velocity)), + velocity_std_dev: Some(array_to_vector3(value.velocityStdDev)), + }) + } else { + None + }; + let position = if position_valid { + Some(EkfPositionData { + position: Some(array_to_vector3_f64(value.position)), + position_std_dev: Some(array_to_vector3(value.positionStdDev)), + }) + } else { + None + }; + EkfNav { + time_stamp: value.timeStamp, + status: Some(status), + velocity, + position, + undulation: if attitude_valid { + Some(value.undulation) + } else { + None + }, + } + } +} + +impl From for Imu { + fn from(value: SbgLogImuData) -> Self { + let status = ImuStatus { + flags: value.status as u32, + }; + let gyros_in_range = (status.flags & ImuStatusFlag::ImuStatusGyrosInRange as u32) != 0; + let accels_in_range = (status.flags & ImuStatusFlag::ImuStatusAccelsInRange as u32) != 0; + let gyroscopes = if gyros_in_range { + Some(ImuGyroData { + gyroscopes: Some(array_to_vector3(value.gyroscopes)), + delta_angle: Some(array_to_vector3(value.deltaAngle)), + }) + } else { + None + }; + let accelerometers = if accels_in_range { + Some(ImuAccelData { + accelerometers: Some(array_to_vector3(value.accelerometers)), + delta_velocity: Some(array_to_vector3(value.deltaVelocity)), + }) + } else { + None + }; + Imu { + time_stamp: value.timeStamp, + status: Some(status), + gyroscopes, + accelerometers, + temperature: Some(value.temperature), + } + } +} + +impl From for GpsVel { + fn from(value: SbgLogGpsVel) -> Self { + let status = GpsVelStatus { + status: value.status as i32, + r#type: GpsVelType::Unspecified as i32, // Adjust as needed + }; + let valid = status.status == GpsVelStatusE::VelSolComputed as i32; + let data = if valid { + Some(GpsVelData { + velocity: Some(array_to_vector3(value.velocity)), + velocity_acc: Some(array_to_vector3(value.velocityAcc)), + course: value.course, + course_acc: value.courseAcc, + time_of_week: value.timeOfWeek, + }) + } else { + None + }; + GpsVel { + time_stamp: value.timeStamp, + status: Some(status), + data, + } + } +} diff --git a/crates/sbg-rs/src/lib.rs b/crates/sbg-rs/src/lib.rs new file mode 100644 index 0000000..4a161aa --- /dev/null +++ b/crates/sbg-rs/src/lib.rs @@ -0,0 +1,13 @@ +#![no_std] +#![allow(dead_code)] +#![allow(non_snake_case)] +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +/// Required bindings for the SBGECom C library. +#[allow(clippy::all)] +mod bindings; +mod data_conversion; +/// This modules contains the Rust API for the SBGECom C library. +/// Covers the implementation of the SBGECom struct and its related functions. +pub mod sbg; diff --git a/crates/sbg-rs/src/sbg.rs b/crates/sbg-rs/src/sbg.rs new file mode 100644 index 0000000..a1d23b8 --- /dev/null +++ b/crates/sbg-rs/src/sbg.rs @@ -0,0 +1,519 @@ +use crate::bindings::{ + self, _SbgDebugLogType_SBG_DEBUG_LOG_TYPE_WARNING, _SbgEComLog_SBG_ECOM_LOG_AIR_DATA, + _SbgEComLog_SBG_ECOM_LOG_EKF_NAV, _SbgEComLog_SBG_ECOM_LOG_GPS1_POS, + _SbgEComLog_SBG_ECOM_LOG_GPS1_RAW, _SbgEComLog_SBG_ECOM_LOG_GPS1_VEL, + _SbgEComLog_SBG_ECOM_LOG_UTC_TIME, _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_40, + _SbgErrorCode_SBG_NO_ERROR, _SbgErrorCode_SBG_NULL_POINTER, _SbgErrorCode_SBG_READ_ERROR, + _SbgErrorCode_SBG_WRITE_ERROR, sbgEComCmdOutputSetConf, sbgEComHandle, +}; +use crate::bindings::{ + _SbgBinaryLogData, _SbgDebugLogType, _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_0, _SbgEComHandle, + _SbgEComLog_SBG_ECOM_LOG_EKF_QUAT, _SbgEComLog_SBG_ECOM_LOG_IMU_DATA, + _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_A, _SbgEComProtocol, _SbgErrorCode, _SbgInterface, +}; +use core::ffi::c_void; +use core::ffi::CStr; +use core::ptr::null_mut; +use core::slice::{from_raw_parts, from_raw_parts_mut}; +use core::sync::atomic::AtomicUsize; +use defmt::{debug, error, flush, info, warn}; +use heapless::Deque; +use heapless::Vec; +use messages_prost::sensor::sbg::*; + +/** + * Max buffer size for SBG messages. + */ +pub const SBG_BUFFER_SIZE: usize = 512; + +/** + * Represents the index of the buffer that is currently being used. + */ +static mut BUF_INDEX: AtomicUsize = AtomicUsize::new(0); +/** + * Points to the buffer that is currently being used. + */ +static mut BUF: &[u8; SBG_BUFFER_SIZE] = &[0; SBG_BUFFER_SIZE]; + +static mut DEQ: Deque = Deque::new(); + +static mut DATA_CALLBACK: Option = None; + +static mut SERIAL_WRITE_CALLBACK: Option)> = None; + +static mut RTC_GET_TIME: Option u32> = None; + +static mut SERIAL_FLUSH_CALLBACK: Option = None; + +pub enum CallbackData { + UtcTime(UtcTime), + Air(Air), + EkfQuat(EkfQuat), + EkfNav(EkfNav), + Imu(Imu), + GpsVel(GpsVel), + GpsPos(GpsPos), +} + +struct UARTSBGInterface { + interface: *mut bindings::SbgInterface, +} + +pub struct SBG { + UARTSBGInterface: UARTSBGInterface, + handle: _SbgEComHandle, + isInitialized: bool, +} + +impl SBG { + /** + * Creates a new SBG instance. + * Takes ownership of the serial device and RTC instance. + */ + pub fn new( + callback: fn(CallbackData), + serial_write_callback: fn(Vec), + rtc_get_time: fn() -> u32, + serial_flush_callback: fn(), + ) -> Self { + unsafe { + DATA_CALLBACK = Some(callback); + SERIAL_WRITE_CALLBACK = Some(serial_write_callback); + RTC_GET_TIME = Some(rtc_get_time); + SERIAL_FLUSH_CALLBACK = Some(serial_flush_callback); + } + // SAFETY: We are assigning the RTC instance to a static variable. + // This is safe because we are the only ones who have access to it. + let interface = UARTSBGInterface { + interface: &mut _SbgInterface { + handle: null_mut(), // SAFEY: No idea what I just did. + type_: 0, + name: [0; 48], + pDestroyFunc: Some(SBG::SbgDestroyFunc), + pWriteFunc: Some(SBG::SbgInterfaceWriteFunc), + pReadFunc: Some(SBG::SbgInterfaceReadFunc), + pFlushFunc: Some(SBG::SbgFlushFunc), + pSetSpeedFunc: Some(SBG::SbgSetSpeedFunc), + pGetSpeedFunc: Some(SBG::SbgGetSpeedFunc), + pDelayFunc: Some(SBG::SbgDelayFunc), + }, + }; + let pLargeBuffer: *mut u8 = null_mut(); + let protocol: _SbgEComProtocol = _SbgEComProtocol { + pLinkedInterface: interface.interface, + rxBuffer: [0; 4096usize], + rxBufferSize: 0, + discardSize: 0, + nextLargeTxId: 0, + pLargeBuffer, + largeBufferSize: 0, + msgClass: 0, + msgId: 0, + transferId: 0, + pageIndex: 0, + nrPages: 0, + }; + let handle: _SbgEComHandle = _SbgEComHandle { + protocolHandle: protocol, + pReceiveLogCallback: Some(SBG::SbgEComReceiveLogFunc), + pUserArg: null_mut(), + numTrials: 3, + cmdDefaultTimeOut: 500, + }; + + let isInitialized = false; + + SBG { + UARTSBGInterface: interface, + handle: handle, + isInitialized, + } + } + + /** + * Returns true if the SBG is initialized. + */ + pub fn isInitialized(&self) -> bool { + self.isInitialized + } + /** + * Reads SBG data frames for a buffer and returns the most recent data. + */ + pub fn read_data(&mut self, buffer: &[u8; SBG_BUFFER_SIZE]) { + // SAFETY: We are assigning a static mut variable. + // Buf can only be accessed from functions called by sbgEComHandle after this assignment. + // unsafe { BUF = buffer }; + for i in buffer { + unsafe { + match DEQ.push_back(*i) { + Ok(_) => (), + Err(_) => warn!("Deque SBG Error"), + } + }; + } + // SAFETY: We are assigning a static variable. + // This is safe because are the only thread reading since SBG is locked. + unsafe { + *BUF_INDEX.get_mut() = 0; + } + // SAFETY: We are calling a C function. + // This is safe because it is assumed the SBG library is safe. + unsafe { + sbgEComHandle(&mut self.handle); + } + } + + /** + * Configures the SBG to output the following data + * Air data + * IMU data + * Extended Kalman Filter Euler data + * Extended Kalman Filter Quaternions + * Extended Kalman Filter Navigation data + */ + pub fn setup(&mut self) -> u32 { + // SAFETY: We are calling a C function. + // This is safe because it is assumed the SBG library is safe. + let errorCode: _SbgErrorCode = unsafe { + sbgEComCmdOutputSetConf( + &mut self.handle, + _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_A, + _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_0, + _SbgEComLog_SBG_ECOM_LOG_GPS1_VEL, + _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_40, + ) + }; + if errorCode != _SbgErrorCode_SBG_NO_ERROR { + warn!("Unable to configure UTC Time logs to 40 cycles"); + } + + let errorCode: _SbgErrorCode = unsafe { + sbgEComCmdOutputSetConf( + &mut self.handle, + _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_A, + _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_0, + _SbgEComLog_SBG_ECOM_LOG_GPS1_POS, + _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_40, + ) + }; + if errorCode != _SbgErrorCode_SBG_NO_ERROR { + warn!("Unable to configure UTC Time logs to 40 cycles"); + } + + // SAFETY: We are calling a C function. + // This is safe because it is assumed the SBG library is safe. + let errorCode: _SbgErrorCode = unsafe { + sbgEComCmdOutputSetConf( + &mut self.handle, + _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_A, + _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_0, + _SbgEComLog_SBG_ECOM_LOG_UTC_TIME, + _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_40, + ) + }; + if errorCode != _SbgErrorCode_SBG_NO_ERROR { + warn!("Unable to configure UTC Time logs to 40 cycles"); + } + + // SAFETY: We are calling a C function. + // This is safe because it is assumed the SBG library is safe. + let errorCode: _SbgErrorCode = unsafe { + sbgEComCmdOutputSetConf( + &mut self.handle, + _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_A, + _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_0, + _SbgEComLog_SBG_ECOM_LOG_AIR_DATA, + _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_40, + ) + }; + if errorCode != _SbgErrorCode_SBG_NO_ERROR { + warn!("Unable to configure Air Data logs to 40 cycles"); + } + + // SAFETY: We are calling a C function. + // This is safe because it is assumed the SBG library is safe. + let errorCode = unsafe { + sbgEComCmdOutputSetConf( + &mut self.handle, + _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_A, + _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_0, + _SbgEComLog_SBG_ECOM_LOG_EKF_QUAT, + _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_40, + ) + }; + if errorCode != _SbgErrorCode_SBG_NO_ERROR { + warn!("Unable to configure EKF Quat logs to 40 cycles"); + } + // SAFETY: We are calling a C function. + // This is safe because it is assumed the SBG library is safe. + let errorCode = unsafe { + sbgEComCmdOutputSetConf( + &mut self.handle, + _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_A, + _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_0, + _SbgEComLog_SBG_ECOM_LOG_EKF_NAV, + _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_40, + ) + }; + if errorCode != _SbgErrorCode_SBG_NO_ERROR { + warn!("Unable to configure EKF Nav logs to 40 cycles"); + } + // SAFETY: We are calling a C function. + // This is safe because it is assumed the SBG library is safe. + let errorCode = unsafe { + sbgEComCmdOutputSetConf( + &mut self.handle, + _SbgEComOutputPort_SBG_ECOM_OUTPUT_PORT_A, + _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_0, + _SbgEComLog_SBG_ECOM_LOG_IMU_DATA, + _SbgEComOutputMode_SBG_ECOM_OUTPUT_MODE_DIV_40, + ) + }; + if errorCode != _SbgErrorCode_SBG_NO_ERROR { + warn!("Unable to configure IMU logs to 40 cycles"); + } else { + self.isInitialized = true; + }; + errorCode + } + + /** + * Allows the SBG interface to read data from the serial ports. + */ + pub unsafe extern "C" fn SbgInterfaceReadFunc( + _pInterface: *mut _SbgInterface, + pBuffer: *mut c_void, + pBytesRead: *mut usize, + bytesToRead: usize, + ) -> _SbgErrorCode { + if pBuffer.is_null() { + return _SbgErrorCode_SBG_NULL_POINTER; + } + if pBytesRead.is_null() { + return _SbgErrorCode_SBG_NULL_POINTER; + } + // SAFETY: We are casting a c_void pointer to a u8 pointer and then creating a slice from it. + // This is safe because we ensure pBuffer is valid, pBuffer is not accessed during the lifetime of this function, + // and the SBGECom library ensures the buffer given is of the correct size. + let array: &mut [u8] = unsafe { from_raw_parts_mut(pBuffer as *mut u8, bytesToRead) }; + let mut readBytes = 0; + for i in 0..(bytesToRead) { + if let Some(front) = DEQ.pop_front() { + readBytes += 1; + array[i] = front; + // info!("Read byte: {}", front); + } else { + // info!("No item in dequeue"); + break; + } + } + // info!("Bytes Read {}", readBytes); + unsafe { *pBytesRead = readBytes }; + return _SbgErrorCode_SBG_NO_ERROR; + } + + /** + * Allows the SBG interface to write to the UART peripheral + */ + pub unsafe extern "C" fn SbgInterfaceWriteFunc( + pInterface: *mut _SbgInterface, + pBuffer: *const c_void, + bytesToWrite: usize, + ) -> _SbgErrorCode { + if pInterface.is_null() { + return _SbgErrorCode_SBG_NULL_POINTER; + } + if pBuffer.is_null() { + return _SbgErrorCode_SBG_NULL_POINTER; + } + + // SAFETY: We are casting a c_void pointer to a u8 pointer and then creating a slice from it. + // This is safe because we ensure pBuffer is valid, pBuffer is not accessed during the lifetime of this function, + // and the SBGECom library ensures the buffer given is of the correct size. + let array: &[u8] = unsafe { from_raw_parts(pBuffer as *const u8, bytesToWrite) }; + let vec = array.iter().copied().collect::>(); + match unsafe { SERIAL_WRITE_CALLBACK } { + Some(callback) => callback(vec), + None => return _SbgErrorCode_SBG_WRITE_ERROR, + } + // let mut counter: usize = 0; + // loop { + // if bytesToWrite == counter { + // break; + // } + // // SAFETY: We are accessing a Uart Peripheral pointer. + // // This is safe because we ensure that the pointer is not accessed during the lifetime of this function. + // match unsafe { SERIAL_WRITE_CALLBACK } { + // Some(callback) => callback(&array[counter..counter + 1]), + // None => return _SbgErrorCode_SBG_WRITE_ERROR, + // } + // } + _SbgErrorCode_SBG_NO_ERROR + } + + /** + * Callback function for handling logs. + */ + pub unsafe extern "C" fn SbgEComReceiveLogFunc( + _pHandle: *mut _SbgEComHandle, + msgClass: u32, + msg: u32, + pLogData: *const _SbgBinaryLogData, + _pUserArg: *mut c_void, + ) -> _SbgErrorCode { + if pLogData.is_null() { + return _SbgErrorCode_SBG_NULL_POINTER; + } + + // SAFETY: DATA_CALLBACK is set once, before this function is called, + // so no race conditions can happen. + if let Some(callback) = unsafe { DATA_CALLBACK } { + if msgClass == _SbgEComClass_SBG_ECOM_CLASS_LOG_ECOM_0 { + // SAFETY: pLogData is not null, and we are checking the union flag before accessing it + unsafe { + match msg { + _SbgEComLog_SBG_ECOM_LOG_AIR_DATA => { + callback(CallbackData::Air((*pLogData).airData.into())) + } + _SbgEComLog_SBG_ECOM_LOG_EKF_QUAT => { + callback(CallbackData::EkfQuat((*pLogData).ekfQuatData.into())) + } + _SbgEComLog_SBG_ECOM_LOG_IMU_DATA => { + callback(CallbackData::Imu((*pLogData).imuData.into())) + } + _SbgEComLog_SBG_ECOM_LOG_EKF_NAV => { + callback(CallbackData::EkfNav((*pLogData).ekfNavData.into())) + } + _SbgEComLog_SBG_ECOM_LOG_GPS1_POS => { + callback(CallbackData::GpsPos((*pLogData).gpsPosData.into())) + } + _SbgEComLog_SBG_ECOM_LOG_GPS1_VEL => { + callback(CallbackData::GpsVel((*pLogData).gpsVelData.into())) + } + _SbgEComLog_SBG_ECOM_LOG_GPS1_HDT => {} + _ => {} + } + } + } + } + + _SbgErrorCode_SBG_NO_ERROR + } + + /** + * The SBG interface does not need to be destroyed. + */ + pub extern "C" fn SbgDestroyFunc(_pInterface: *mut _SbgInterface) -> _SbgErrorCode { + _SbgErrorCode_SBG_NO_ERROR + } + + /** + * Flushes the UART peripheral. + */ + pub unsafe extern "C" fn SbgFlushFunc( + pInterface: *mut _SbgInterface, + _flags: u32, + ) -> _SbgErrorCode { + if pInterface.is_null() { + return _SbgErrorCode_SBG_NULL_POINTER; + } + // SAFETY: We are casting a c_void pointer to a Uart peripheral pointer. + // This is safe because we only have one sbg object and we ensure that + // the peripheral pointer is not accessed during the lifetime of this function. + match unsafe { SERIAL_FLUSH_CALLBACK } { + Some(callback) => callback(), + None => return _SbgErrorCode_SBG_WRITE_ERROR, + } + _SbgErrorCode_SBG_NO_ERROR + } + + /** + * The baud rate is fixed to 115200 and hence this function does nothing. + */ + pub extern "C" fn SbgSetSpeedFunc( + _pInterface: *mut _SbgInterface, + _speed: u32, + ) -> _SbgErrorCode { + _SbgErrorCode_SBG_NO_ERROR + } + + /** + * The baud rate is fixed to 115200 + */ + pub extern "C" fn SbgGetSpeedFunc(_pInterface: *const _SbgInterface) -> u32 { + 115200 + } + + /** + * Optional method used to compute an expected delay to transmit/receive X bytes + */ + pub extern "C" fn SbgDelayFunc(_pInterface: *const _SbgInterface, _numBytes: usize) -> u32 { + 501 + } +} + +// SAFETY: No one besides us has the raw pointer to the SBG struct. +// We can safely transfer the SBG struct between threads. +unsafe impl Send for SBG {} + +/** + * Logs the message to the console. + * Needs to be updated to handle the Variadic arguments. + */ +#[no_mangle] +pub unsafe extern "C" fn sbgPlatformDebugLogMsg( + pFileName: *const ::core::ffi::c_char, + pFunctionName: *const ::core::ffi::c_char, + line: u32, + pCategory: *const ::core::ffi::c_char, + logType: _SbgDebugLogType, + errorCode: _SbgErrorCode, + pFormat: *const ::core::ffi::c_char, +) { + if pFileName.is_null() || pFunctionName.is_null() || pCategory.is_null() || pFormat.is_null() { + return; + } + // // SAFETY: We are converting a raw pointer to a CStr and then to a str. + // // This is safe because we check if the pointers are null and + // // the pointers can only be accessed during the lifetime of this function. + let file = unsafe { CStr::from_ptr(pFileName).to_str().unwrap() }; + let function = unsafe { CStr::from_ptr(pFunctionName).to_str().unwrap() }; + let category = unsafe { CStr::from_ptr(pCategory).to_str().unwrap() }; + let format = unsafe { CStr::from_ptr(pFormat).to_str().unwrap() }; + + // info!("{}:{}:{}:{}:{}:{}", file, function, line, category, errorCode, format); + + match logType { + // silently handle errors + // _SbgDebugLogType_SBG_DEBUG_LOG_TYPE_ERROR => error!("SBG Error"), + _SbgDebugLogType_SBG_DEBUG_LOG_TYPE_WARNING => warn!("SBG Warning"), + // _SbgDebugLogType_SBG_DEBUG_LOG_TYPE_INFO => info!("SBG Info "), + _SbgDebugLogType_SBG_DEBUG_LOG_TYPE_DEBUG => debug!("SBG Debug "), + _ => (), + }; + flush(); +} + +/** + * Returns the number of milliseconds that have passed. + */ +#[no_mangle] +pub extern "C" fn sbgGetTime() -> u32 { + // SAFETY: We are accessing a static mut variable. + // This is safe because this is the only place where we access the RTC. + match unsafe { RTC_GET_TIME } { + Some(get_time) => get_time(), + None => 0, + } +} + +/** + * Sleeps the sbg execution + */ +#[no_mangle] +pub extern "C" fn sbgSleep(ms: u32) { + let start_time = sbgGetTime(); + while (sbgGetTime() - start_time) < ms { + // do nothing + } +} diff --git a/crates/sbg-rs/wrapper.h b/crates/sbg-rs/wrapper.h new file mode 100644 index 0000000..cac0c13 --- /dev/null +++ b/crates/sbg-rs/wrapper.h @@ -0,0 +1,2 @@ +#include "sbgECom/common/sbgDefines.h" +#include "sbgECom/src/sbgEComLib.h" \ No newline at end of file diff --git a/examples/rtic-playground/Cargo.toml b/examples/rtic-playground/Cargo.toml deleted file mode 100644 index 259c6f1..0000000 --- a/examples/rtic-playground/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "rtic-playground" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -cortex-m = { workspace = true } -cortex-m-rt = { workspace = true } -rtic = { workspace = true } -rtic-monotonics = { workspace = true } -common-arm = { path = "../../crates/common-arm" } -stm32h7xx-hal = { workspace = true } -postcard = { workspace = true } -defmt = { workspace = true } -fdcan = { workspace = true } -embedded-alloc = {workspace = true} -heapless = {workspace = true} -rtic-sync = { workspace = true } -defmt-rtt = { workspace = true } -panic-probe = { workspace = true } -chrono = { workspace = true } -messages = {workspace = true} - -[[bin]] -name = "rtic-playground" -path = "src/main.rs" -test = false -doctest = false -bench = false -harness = false \ No newline at end of file diff --git a/examples/rtic-playground/src/communication.rs b/examples/rtic-playground/src/communication.rs deleted file mode 100644 index 409d365..0000000 --- a/examples/rtic-playground/src/communication.rs +++ /dev/null @@ -1,194 +0,0 @@ -use crate::data_manager::DataManager; -use crate::types::COM_ID; -use common_arm::HydraError; -use defmt::{error, info}; -use fdcan::{ - frame::{FrameFormat, TxFrameHeader}, - id::StandardId, -}; -use mavlink::peek_reader::PeekReader; -use messages::mavlink::uorocketry::MavMessage; -use messages::mavlink::{self}; -use messages::Message; -use postcard::from_bytes; - -/// Clock configuration is out of scope for this builder -/// easiest way to avoid alloc is to use no generics -pub struct CanCommandManager { - can: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::NormalOperationMode, - >, -} - -impl CanCommandManager { - pub fn new( - can: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::NormalOperationMode, - >, - ) -> Self { - Self { can } - } - pub fn send_message(&mut self, m: Message) -> Result<(), HydraError> { - let mut buf = [0u8; 64]; - let payload = postcard::to_slice(&m, &mut buf)?; - let header = TxFrameHeader { - len: payload.len() as u8, // switch to const as this never changes or swtich on message type of known size - id: StandardId::new(COM_ID.into()).unwrap().into(), - frame_format: FrameFormat::Standard, - bit_rate_switching: false, - marker: None, - }; - self.can.transmit(header, payload)?; - Ok(()) - } - pub fn process_data(&mut self, data_manager: &mut DataManager) -> Result<(), HydraError> { - let mut buf = [0u8; 64]; - while self.can.receive0(&mut buf).is_ok() { - if let Ok(data) = from_bytes::(&buf) { - info!("Received message {}", data.clone()); - data_manager.handle_command(data)?; - } else { - info!("Error: {:?}", from_bytes::(&buf).unwrap_err()); - } - } - Ok(()) - } -} - -/// Clock configuration is out of scope for this builder -/// easiest way to avoid alloc is to use no generics -pub struct CanDataManager { - can: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::NormalOperationMode, - >, -} - -impl CanDataManager { - pub fn new( - can: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::NormalOperationMode, - >, - ) -> Self { - Self { can } - } - pub fn send_message(&mut self, m: Message) -> Result<(), HydraError> { - let mut buf = [0u8; 64]; - let payload = postcard::to_slice(&m, &mut buf)?; - let header = TxFrameHeader { - len: payload.len() as u8, // switch to const as this never changes or swtich on message type of known size - id: StandardId::new(COM_ID.into()).unwrap().into(), - frame_format: FrameFormat::Fdcan, - bit_rate_switching: false, - marker: None, - }; - // self.can.abort(fdcan::Mailbox::_2); // this is needed if boards are not in sync (if they are not in sync that is a bigger problem) - - stm32h7xx_hal::nb::block!(self.can.transmit(header, payload))?; - - Ok(()) - } - pub fn process_data(&mut self) -> Result<(), HydraError> { - let mut buf = [0u8; 64]; - while self.can.receive0(&mut buf).is_ok() { - if let Ok(data) = from_bytes::(&buf) { - info!("Received message {}", data.clone()); - crate::app::send_gs::spawn(data).ok(); - } else if let Err(e) = from_bytes::(&buf) { - info!("Error: {:?}", e); - } - } - self.can - .clear_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); - Ok(()) - } -} - -pub struct RadioDevice { - transmitter: stm32h7xx_hal::serial::Tx, - pub receiver: PeekReader>, -} - -impl RadioDevice { - pub fn new(uart: stm32h7xx_hal::serial::Serial) -> Self { - let (tx, mut rx) = uart.split(); - - rx.listen(); - // setup interrupts - - RadioDevice { - transmitter: tx, - receiver: PeekReader::new(rx), - } - } -} - -pub struct RadioManager { - pub radio: RadioDevice, - mav_sequence: u8, -} - -impl RadioManager { - pub fn new(radio: RadioDevice) -> Self { - RadioManager { - radio, - mav_sequence: 0, - } - } - pub fn send_message(&mut self, payload: &[u8]) -> Result<(), HydraError> { - let mav_header = mavlink::MavHeader { - system_id: 1, - component_id: 1, - sequence: self.increment_mav_sequence(), - }; - // Create a fixed-size array and copy the payload into it - let mut fixed_payload = [0u8; 255]; - let len = payload.len().min(255); - fixed_payload[..len].copy_from_slice(&payload[..len]); - - let mav_message = mavlink::uorocketry::MavMessage::POSTCARD_MESSAGE( - mavlink::uorocketry::POSTCARD_MESSAGE_DATA { - message: fixed_payload, - }, - ); - mavlink::write_versioned_msg( - &mut self.radio.transmitter, - mavlink::MavlinkVersion::V2, - mav_header, - &mav_message, - )?; - Ok(()) - } - pub fn increment_mav_sequence(&mut self) -> u8 { - self.mav_sequence = self.mav_sequence.wrapping_add(1); - self.mav_sequence - } - pub fn receive_message(&mut self) -> Result { - let (_header, msg): (_, MavMessage) = - mavlink::read_versioned_msg(&mut self.radio.receiver, mavlink::MavlinkVersion::V2)?; - - // info!("{:?}", ); - // Do we need the header? - match msg { - mavlink::uorocketry::MavMessage::POSTCARD_MESSAGE(msg) => { - Ok(postcard::from_bytes::(&msg.message)?) - // weird Ok syntax to coerce to hydra error type. - } - mavlink::uorocketry::MavMessage::COMMAND_MESSAGE(command) => { - info!("{}", command.command); - Ok(postcard::from_bytes::(&command.command)?) - } - mavlink::uorocketry::MavMessage::HEARTBEAT(_) => { - info!("Heartbeat"); - Err(mavlink::error::MessageReadError::Io.into()) - } - _ => { - error!("Error, ErrorContext::UnkownPostcardMessage"); - Err(mavlink::error::MessageReadError::Io.into()) - } - } - } -} \ No newline at end of file diff --git a/examples/rtic-playground/src/data_manager.rs b/examples/rtic-playground/src/data_manager.rs deleted file mode 100644 index 67b5834..0000000 --- a/examples/rtic-playground/src/data_manager.rs +++ /dev/null @@ -1,186 +0,0 @@ -use common_arm::HydraError; -use messages::command::RadioRate; -use messages::state::StateData; -use messages::Message; -use stm32h7xx_hal::rcc::ResetReason; -#[derive(Clone)] -pub struct DataManager { - pub air: Option, - pub ekf_nav_1: Option, - pub ekf_nav_2: Option, - pub ekf_nav_acc: Option, - pub ekf_quat: Option, - pub imu_1: Option, - pub imu_2: Option, - pub utc_time: Option, - pub gps_vel: Option, - pub gps_vel_acc: Option, - pub gps_pos_1: Option, - pub gps_pos_2: Option, - pub gps_pos_acc: Option, - pub state: Option, - pub reset_reason: Option, - pub logging_rate: Option, - pub recovery_sensing: Option, - pub nav_pos_l1h: Option, -} - -impl DataManager { - pub fn new() -> Self { - Self { - air: None, - ekf_nav_1: None, - ekf_nav_2: None, - ekf_nav_acc: None, - ekf_quat: None, - imu_1: None, - imu_2: None, - utc_time: None, - gps_vel: None, - gps_vel_acc: None, - gps_pos_1: None, - gps_pos_2: None, - gps_pos_acc: None, - state: None, - reset_reason: None, - logging_rate: Some(RadioRate::Slow), // start slow. - recovery_sensing: None, - nav_pos_l1h: None, - } - } - - pub fn get_logging_rate(&mut self) -> RadioRate { - if let Some(rate) = self.logging_rate.take() { - let rate_cln = rate.clone(); - self.logging_rate = Some(rate); - return rate_cln; - } - self.logging_rate = Some(RadioRate::Slow); - RadioRate::Slow - } - - /// Do not clone instead take to reduce CPU load. - pub fn take_sensors(&mut self) -> [Option; 15] { - [ - self.air.take(), - self.ekf_nav_1.take(), - self.ekf_nav_2.take(), - self.ekf_nav_acc.take(), - self.ekf_quat.take(), - self.imu_1.take(), - self.imu_2.take(), - self.utc_time.take(), - self.gps_vel.take(), - self.gps_vel_acc.take(), - self.gps_pos_1.take(), - self.gps_pos_2.take(), - self.gps_pos_acc.take(), - self.nav_pos_l1h.take(), - self.recovery_sensing.take(), - ] - } - - pub fn clone_states(&self) -> [Option; 1] { - [self.state.clone()] - } - - pub fn clone_reset_reason(&self) -> Option { - self.reset_reason - } - - pub fn set_reset_reason(&mut self, reset: ResetReason) { - self.reset_reason = Some(reset); - } - - pub fn handle_command(&mut self, data: Message) -> Result<(), HydraError> { - match data.data { - messages::Data::Command(command) => match command.data { - messages::command::CommandData::PowerDown(_) => { - crate::app::sleep_system::spawn().ok(); - } - messages::command::CommandData::RadioRateChange(command_data) => { - self.logging_rate = Some(command_data.rate); - } - _ => { - // We don't care atm about these other commands. - } - }, - _ => { - // we can disregard all other messages for now. - } - } - Ok(()) - } - pub fn handle_data(&mut self, data: Message) { - match data.data { - messages::Data::Sensor(ref sensor) => match sensor.data { - messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data { - messages::sensor::SbgData::EkfNavAcc(_) => { - self.ekf_nav_acc = Some(data); - } - messages::sensor::SbgData::GpsPosAcc(_) => { - self.gps_pos_acc = Some(data); - } - messages::sensor::SbgData::Air(_) => { - self.air = Some(data); - } - messages::sensor::SbgData::EkfNav1(_) => { - self.ekf_nav_1 = Some(data); - } - messages::sensor::SbgData::EkfNav2(_) => { - self.ekf_nav_2 = Some(data); - } - messages::sensor::SbgData::EkfQuat(_) => { - self.ekf_quat = Some(data); - } - messages::sensor::SbgData::GpsVel(_) => { - self.gps_vel = Some(data); - } - messages::sensor::SbgData::GpsVelAcc(_) => { - self.gps_vel_acc = Some(data); - } - messages::sensor::SbgData::Imu1(_) => { - self.imu_1 = Some(data); - } - messages::sensor::SbgData::Imu2(_) => { - self.imu_2 = Some(data); - } - messages::sensor::SbgData::UtcTime(_) => { - self.utc_time = Some(data); - } - messages::sensor::SbgData::GpsPos1(_) => { - self.gps_pos_1 = Some(data); - } - messages::sensor::SbgData::GpsPos2(_) => { - self.gps_pos_2 = Some(data); - } - }, - messages::sensor::SensorData::RecoverySensing(_) => { - self.recovery_sensing = Some(data); - } - messages::sensor::SensorData::NavPosLlh(_) => { - self.nav_pos_l1h = Some(data); - } - messages::sensor::SensorData::ResetReason(_) => {} - }, - messages::Data::State(state) => { - self.state = Some(state.data); - } - // messages::Data::Command(command) => match command.data { - // messages::command::CommandData::RadioRateChange(command_data) => { - // self.logging_rate = Some(command_data.rate); - // } - // messages::command::CommandData::DeployDrogue(_) => {} - // messages::command::CommandData::DeployMain(_) => {} - // messages::command::CommandData::PowerDown(_) => {} - // }, - _ => {} - } - } -} - -impl Default for DataManager { - fn default() -> Self { - Self::new() - } -} diff --git a/examples/rtic-playground/src/main.rs b/examples/rtic-playground/src/main.rs deleted file mode 100644 index 2553651..0000000 --- a/examples/rtic-playground/src/main.rs +++ /dev/null @@ -1,580 +0,0 @@ -#![no_std] -#![no_main] - -mod communication; -mod data_manager; -mod types; - -use chrono::NaiveDate; -use common_arm::*; -use communication::{CanCommandManager, CanDataManager}; -use communication::{RadioDevice, RadioManager}; -use core::num::{NonZeroU16, NonZeroU8}; -use data_manager::DataManager; -use defmt::info; -use fdcan::{ - config::NominalBitTiming, - filter::{StandardFilter, StandardFilterSlot}, -}; -use messages::command::RadioRate; -use messages::{sensor, Data}; -use panic_probe as _; -use rtic_monotonics::systick::prelude::*; -use rtic_sync::{channel::*, make_channel}; -use stm32h7xx_hal::gpio::gpioa::{PA2, PA3}; -use stm32h7xx_hal::gpio::gpiob::PB4; -use stm32h7xx_hal::gpio::Speed; -use stm32h7xx_hal::gpio::{Output, PushPull}; -use stm32h7xx_hal::prelude::*; -use stm32h7xx_hal::rtc; -use stm32h7xx_hal::{rcc, rcc::rec}; -use types::COM_ID; // global logger - -const DATA_CHANNEL_CAPACITY: usize = 10; - -systick_monotonic!(Mono, 500); - -#[inline(never)] -#[defmt::panic_handler] -fn panic() -> ! { - // stm32h7xx_hal::pac::SCB::sys_reset() - cortex_m::asm::udf() -} - -#[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true, dispatchers = [EXTI0, EXTI1, EXTI2, SPI3, SPI2])] -mod app { - - use messages::Message; - use stm32h7xx_hal::gpio::{Alternate, Pin}; - - use super::*; - - #[shared] - struct SharedResources { - data_manager: DataManager, - em: ErrorManager, - // sd_manager: SdManager< - // stm32h7xx_hal::spi::Spi, - // PA4>, - // >, - radio_manager: RadioManager, - can_command_manager: CanCommandManager, - can_data_manager: CanDataManager, - sbg_power: PB4>, - rtc: rtc::Rtc, - } - #[local] - struct LocalResources { - led_red: PA2>, - led_green: PA3>, - buzzer: stm32h7xx_hal::pwm::Pwm< - stm32h7xx_hal::pac::TIM12, - 0, - stm32h7xx_hal::pwm::ComplementaryImpossible, - >, - } - - #[init] - fn init(ctx: init::Context) -> (SharedResources, LocalResources) { - // channel setup - let (_s, r) = make_channel!(Message, DATA_CHANNEL_CAPACITY); - - let core = ctx.core; - - /* Logging Setup */ - HydraLogging::set_ground_station_callback(queue_gs_message); - - let pwr = ctx.device.PWR.constrain(); - // We could use smps, but the board is not designed for it - // let pwrcfg = example_power!(pwr).freeze(); - let mut pwrcfg = pwr.freeze(); - - info!("Power enabled"); - let backup = pwrcfg.backup().unwrap(); - info!("Backup domain enabled"); - // RCC - let mut rcc = ctx.device.RCC.constrain(); - let reset = rcc.get_reset_reason(); - let fdcan_prec_unsafe = unsafe { rcc.steal_peripheral_rec() } - .FDCAN - .kernel_clk_mux(rec::FdcanClkSel::Pll1Q); - - let ccdr = rcc - .use_hse(48.MHz()) // check the clock hardware - .sys_ck(200.MHz()) - .pll1_strategy(rcc::PllConfigStrategy::Iterative) - .pll1_q_ck(32.MHz()) - .freeze(pwrcfg, &ctx.device.SYSCFG); - info!("RCC configured"); - let fdcan_prec = ccdr - .peripheral - .FDCAN - .kernel_clk_mux(rec::FdcanClkSel::Pll1Q); - - let btr = NominalBitTiming { - prescaler: NonZeroU16::new(10).unwrap(), - seg1: NonZeroU8::new(13).unwrap(), - seg2: NonZeroU8::new(2).unwrap(), - sync_jump_width: NonZeroU8::new(1).unwrap(), - }; - - // let data_bit_timing = DataBitTiming { - // prescaler: NonZeroU8::new(10).unwrap(), - // seg1: NonZeroU8::new(13).unwrap(), - // seg2: NonZeroU8::new(2).unwrap(), - // sync_jump_width: NonZeroU8::new(4).unwrap(), - // transceiver_delay_compensation: true, - // }; - - info!("CAN enabled"); - // GPIO - let gpioa = ctx.device.GPIOA.split(ccdr.peripheral.GPIOA); - let gpiod = ctx.device.GPIOD.split(ccdr.peripheral.GPIOD); - let gpiob = ctx.device.GPIOB.split(ccdr.peripheral.GPIOB); - - let pins = gpiob.pb14.into_alternate(); - let mut c0 = ctx - .device - .TIM12 - .pwm(pins, 4.kHz(), ccdr.peripheral.TIM12, &ccdr.clocks); - - c0.set_duty(c0.get_max_duty() / 4); - // PWM outputs are disabled by default - // c0.enable(); - - info!("PWM enabled"); - // assert_eq!(ccdr.clocks.pll1_q_ck().unwrap().raw(), 32_000_000); - info!("PLL1Q:"); - // https://github.com/stm32-rs/stm32h7xx-hal/issues/369 This needs to be stolen. Grrr I hate the imaturity of the stm32-hal - let can2: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::ConfigMode, - > = { - let rx = gpiob.pb12.into_alternate().speed(Speed::VeryHigh); - let tx = gpiob.pb13.into_alternate().speed(Speed::VeryHigh); - ctx.device.FDCAN2.fdcan(tx, rx, fdcan_prec) - }; - - let mut can_data = can2; - can_data.set_protocol_exception_handling(false); - - can_data.set_nominal_bit_timing(btr); - - // can_data.set_automatic_retransmit(false); // data can be dropped due to its volume. - - // can_command.set_data_bit_timing(data_bit_timing); - - can_data.set_standard_filter( - StandardFilterSlot::_0, - StandardFilter::accept_all_into_fifo0(), - ); - - can_data.set_standard_filter( - StandardFilterSlot::_1, - StandardFilter::accept_all_into_fifo0(), - ); - - can_data.set_standard_filter( - StandardFilterSlot::_2, - StandardFilter::accept_all_into_fifo0(), - ); - - can_data.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); - - can_data.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true); - - let config = can_data - .get_config() - .set_frame_transmit(fdcan::config::FrameTransmissionConfig::AllowFdCanAndBRS); - can_data.apply_config(config); - - let can_data_manager = CanDataManager::new(can_data.into_normal()); - - let can1: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::ConfigMode, - > = { - let rx = gpioa.pa11.into_alternate().speed(Speed::VeryHigh); - let tx = gpioa.pa12.into_alternate().speed(Speed::VeryHigh); - ctx.device.FDCAN1.fdcan(tx, rx, fdcan_prec_unsafe) - }; - - let mut can_command = can1; - can_command.set_protocol_exception_handling(false); - - can_command.set_nominal_bit_timing(btr); - can_command.set_standard_filter( - StandardFilterSlot::_0, - StandardFilter::accept_all_into_fifo0(), - ); - - can_command.set_standard_filter( - StandardFilterSlot::_1, - StandardFilter::accept_all_into_fifo0(), - ); - - can_command.set_standard_filter( - StandardFilterSlot::_2, - StandardFilter::accept_all_into_fifo0(), - ); - - // can_data.set_data_bit_timing(data_bit_timing); - can_command.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); - - can_command.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true); - - let config = can_command - .get_config() - .set_frame_transmit(fdcan::config::FrameTransmissionConfig::AllowFdCanAndBRS); // check this maybe don't bit switch allow. - can_command.apply_config(config); - - let can_command_manager = CanCommandManager::new(can_command.into_normal()); - - // let spi_sd: stm32h7xx_hal::spi::Spi< - // stm32h7xx_hal::stm32::SPI1, - // stm32h7xx_hal::spi::Enabled, - // u8, - // > = ctx.device.SPI1.spi( - // ( - // gpioa.pa5.into_alternate::<5>(), - // gpioa.pa6.into_alternate(), - // gpioa.pa7.into_alternate(), - // ), - // spi::Config::new(spi::MODE_0), - // 16.MHz(), - // ccdr.peripheral.SPI1, - // &ccdr.clocks, - // ); - - // let cs_sd = gpioa.pa4.into_push_pull_output(); - - // let sd_manager = SdManager::new(spi_sd, cs_sd); - - // leds - let led_red = gpioa.pa2.into_push_pull_output(); - let led_green = gpioa.pa3.into_push_pull_output(); - - // sbg power pin - let mut sbg_power = gpiob.pb4.into_push_pull_output(); - sbg_power.set_high(); - - // UART for sbg - let tx: Pin<'D', 1, Alternate<8>> = gpiod.pd1.into_alternate(); - let rx: Pin<'D', 0, Alternate<8>> = gpiod.pd0.into_alternate(); - - // let stream_tuple = StreamsTuple::new(ctx.device.DMA1, ccdr.peripheral.DMA1); - let uart_radio = ctx - .device - .UART4 - .serial((tx, rx), 57600.bps(), ccdr.peripheral.UART4, &ccdr.clocks) - .unwrap(); - // let mut sbg_manager = sbg_manager::SBGManager::new(uart_sbg, stream_tuple); - - let radio = RadioDevice::new(uart_radio); - - let radio_manager = RadioManager::new(radio); - - let mut rtc = stm32h7xx_hal::rtc::Rtc::open_or_init( - ctx.device.RTC, - backup.RTC, - stm32h7xx_hal::rtc::RtcClock::Lsi, - &ccdr.clocks, - ); - - // TODO: Get current time from some source - let now = NaiveDate::from_ymd_opt(2001, 1, 1) - .unwrap() - .and_hms_opt(0, 0, 0) - .unwrap(); - - rtc.set_date_time(now); - - /* Monotonic clock */ - Mono::start(core.SYST, 200_000_000); - - let mut data_manager = DataManager::new(); - data_manager.set_reset_reason(reset); - let em = ErrorManager::new(); - blink::spawn().ok(); - send_data_internal::spawn(r).ok(); - reset_reason_send::spawn().ok(); - state_send::spawn().ok(); - // generate_random_messages::spawn().ok(); - // sensor_send::spawn().ok(); - info!("Online"); - - ( - SharedResources { - data_manager, - em, - // sd_manager, - radio_manager, - can_command_manager, - can_data_manager, - sbg_power, - rtc, - }, - LocalResources { - led_red, - led_green, - buzzer: c0, - }, - ) - } - - #[task(priority = 3, shared = [&em, rtc])] - async fn generate_random_messages(mut cx: generate_random_messages::Context) { - loop { - cx.shared.em.run(|| { - let message = Message::new( - cx.shared - .rtc - .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), - COM_ID, - messages::state::State::new(messages::state::StateData::Initializing), - ); - spawn!(send_gs, message.clone())?; - // spawn!(send_data_internal, message)?; - Ok(()) - }); - Mono::delay(1.secs()).await; - } - } - - #[task(priority = 3, shared = [data_manager, &em, rtc])] - async fn reset_reason_send(mut cx: reset_reason_send::Context) { - let reason = cx - .shared - .data_manager - .lock(|data_manager| data_manager.clone_reset_reason()); - match reason { - Some(reason) => { - let x = match reason { - stm32h7xx_hal::rcc::ResetReason::BrownoutReset => sensor::ResetReason::BrownoutReset, - stm32h7xx_hal::rcc::ResetReason::CpuReset => sensor::ResetReason::CpuReset, - stm32h7xx_hal::rcc::ResetReason::D1EntersDStandbyErroneouslyOrCpuEntersCStopErroneously => sensor::ResetReason::D1EntersDStandbyErroneouslyOrCpuEntersCStopErroneously, - stm32h7xx_hal::rcc::ResetReason::D1ExitsDStandbyMode => sensor::ResetReason::D1ExitsDStandbyMode, - stm32h7xx_hal::rcc::ResetReason::D2ExitsDStandbyMode => sensor::ResetReason::D2ExitsDStandbyMode, - stm32h7xx_hal::rcc::ResetReason::GenericWatchdogReset => sensor::ResetReason::GenericWatchdogReset, - stm32h7xx_hal::rcc::ResetReason::IndependentWatchdogReset => sensor::ResetReason::IndependentWatchdogReset, - stm32h7xx_hal::rcc::ResetReason::PinReset => sensor::ResetReason::PinReset, - stm32h7xx_hal::rcc::ResetReason::PowerOnReset => sensor::ResetReason::PowerOnReset, - stm32h7xx_hal::rcc::ResetReason::SystemReset => sensor::ResetReason::SystemReset, - stm32h7xx_hal::rcc::ResetReason::Unknown { rcc_rsr } => sensor::ResetReason::Unknown { rcc_rsr }, - stm32h7xx_hal::rcc::ResetReason::WindowWatchdogReset => sensor::ResetReason::WindowWatchdogReset, - }; - let message = messages::Message::new( - cx.shared - .rtc - .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), - COM_ID, - sensor::Sensor::new(x), - ); - - cx.shared.em.run(|| { - spawn!(send_gs, message)?; - Ok(()) - }) - } - None => return, - } - } - - #[task(shared = [data_manager, &em, rtc])] - async fn state_send(mut cx: state_send::Context) { - let state_data = cx - .shared - .data_manager - .lock(|data_manager| data_manager.state.clone()); - cx.shared.em.run(|| { - if let Some(x) = state_data { - let message = Message::new( - cx.shared - .rtc - .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), - COM_ID, - messages::state::State::new(x), - ); - spawn!(send_gs, message)?; - } // if there is none we still return since we simply don't have data yet. - Ok(()) - }); - Mono::delay(5.secs()).await; - // spawn_after!(state_send, ExtU64::secs(5)).ok(); - } - - /** - * Sends information about the sensors. - */ - #[task(priority = 3, shared = [data_manager, &em])] - async fn sensor_send(mut cx: sensor_send::Context) { - loop { - let (sensors, logging_rate) = cx.shared.data_manager.lock(|data_manager| { - (data_manager.take_sensors(), data_manager.get_logging_rate()) - }); - - cx.shared.em.run(|| { - for msg in sensors { - match msg { - Some(x) => { - // info!("Sending sensor data {}", x.clone()); - spawn!(send_gs, x)?; - // spawn!(sd_dump, x)?; - } - None => { - info!("No sensor data to send"); - continue; - } - } - } - - Ok(()) - }); - match logging_rate { - RadioRate::Fast => { - Mono::delay(100.millis()).await; - } - RadioRate::Slow => { - Mono::delay(250.millis()).await; - } - } - } - } - - /// Receives a log message from the custom logger so that it can be sent over the radio. - pub fn queue_gs_message(d: impl Into) { - info!("Queueing message"); - send_gs_intermediate::spawn(d.into()).ok(); - } - - #[task(priority = 3, shared = [rtc, &em])] - async fn send_gs_intermediate(mut cx: send_gs_intermediate::Context, m: Data) { - cx.shared.em.run(|| { - cx.shared.rtc.lock(|rtc| { - let message = messages::Message::new( - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()), - COM_ID, - m, - ); - spawn!(send_gs, message)?; - Ok(()) - }) - }); - } - - #[task(priority = 2, binds = FDCAN1_IT0, shared = [can_command_manager, data_manager, &em])] - fn can_command(mut cx: can_command::Context) { - // info!("CAN Command"); - cx.shared.can_command_manager.lock(|can| { - cx.shared - .data_manager - .lock(|data_manager| cx.shared.em.run(|| can.process_data(data_manager))); - }) - } - - #[task(priority = 3, shared = [sbg_power])] - async fn sbg_power_on(mut cx: sbg_power_on::Context) { - loop { - cx.shared.sbg_power.lock(|sbg| { - sbg.set_high(); - }); - Mono::delay(10000.millis()).await; - } - } - - /** - * Sends a message to the radio over UART. - */ - #[task(priority = 3, shared = [&em, radio_manager])] - async fn send_gs(mut cx: send_gs::Context, m: Message) { - // info!("{}", m.clone()); - - cx.shared.radio_manager.lock(|radio_manager| { - cx.shared.em.run(|| { - // info!("Sending message {}", m); - let mut buf = [0; 255]; - let data = postcard::to_slice(&m, &mut buf)?; - radio_manager.send_message(data)?; - Ok(()) - }) - }); - } - - #[task( priority = 3, binds = FDCAN2_IT0, shared = [&em, can_data_manager, data_manager])] - fn can_data(mut cx: can_data::Context) { - cx.shared.can_data_manager.lock(|can| { - { - cx.shared.em.run(|| { - can.process_data()?; - Ok(()) - }) - } - }); - } - - #[task(priority = 2, shared = [&em, can_data_manager, data_manager])] - async fn send_data_internal( - mut cx: send_data_internal::Context, - mut receiver: Receiver<'static, Message, DATA_CHANNEL_CAPACITY>, - ) { - loop { - if let Ok(m) = receiver.recv().await { - cx.shared.can_data_manager.lock(|can| { - cx.shared.em.run(|| { - can.send_message(m)?; - Ok(()) - }) - }); - } - } - } - - #[task(priority = 2, shared = [&em, can_command_manager, data_manager])] - async fn send_command_internal(mut cx: send_command_internal::Context, m: Message) { - // while let Ok(m) = receiver.recv().await { - cx.shared.can_command_manager.lock(|can| { - cx.shared.em.run(|| { - can.send_message(m)?; - Ok(()) - }) - }); - // } - } - - #[task(priority = 1, local = [led_red, led_green, buzzer, buzzed: bool = false], shared = [&em])] - async fn blink(cx: blink::Context) { - loop { - if cx.shared.em.has_error() { - cx.local.led_red.toggle(); - if *cx.local.buzzed { - cx.local.buzzer.set_duty(0); - *cx.local.buzzed = false; - } else { - let duty = cx.local.buzzer.get_max_duty() / 4; - cx.local.buzzer.set_duty(duty); - *cx.local.buzzed = true; - } - Mono::delay(500.millis()).await; - } else { - cx.local.led_green.toggle(); - if *cx.local.buzzed { - cx.local.buzzer.set_duty(0); - *cx.local.buzzed = false; - } else { - let duty = cx.local.buzzer.get_max_duty() / 4; - cx.local.buzzer.set_duty(duty); - *cx.local.buzzed = true; - } - Mono::delay(2000.millis()).await; - } - } - } - - #[task(priority = 3, shared = [&em, sbg_power])] - async fn sleep_system(mut cx: sleep_system::Context) { - // Turn off the SBG and CAN, also start a timer to wake up the system. Put the chip in sleep mode. - cx.shared.sbg_power.lock(|sbg| { - sbg.set_low(); - }); - } -} diff --git a/examples/rtic-playground/src/types.rs b/examples/rtic-playground/src/types.rs deleted file mode 100644 index 551ed32..0000000 --- a/examples/rtic-playground/src/types.rs +++ /dev/null @@ -1,3 +0,0 @@ -use messages::node::{Node, Node::TemperatureBoard}; - -pub static COM_ID: Node = TemperatureBoard; diff --git a/examples/simple-playground/Cargo.toml b/examples/simple-playground/Cargo.toml deleted file mode 100644 index 1071590..0000000 --- a/examples/simple-playground/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "simple-playground" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -cortex-m = { workspace = true } -cortex-m-rt = { workspace = true } -rtic = { workspace = true } -rtic-monotonics = { workspace = true } -common-arm = { path = "../../crates/common-arm" } -stm32h7xx-hal = { workspace = true } -postcard = { workspace = true } -defmt = { workspace = true } -fdcan = { workspace = true } -embedded-alloc = {workspace = true} -heapless = {workspace = true} -rtic-sync = { workspace = true } -defmt-rtt = { workspace = true } -panic-probe = { workspace = true } -chrono = { workspace = true } -messages = {workspace = true} - -[[bin]] -name = "simple-playground" -path = "src/main.rs" -test = false -doctest = false -bench = false -harness = false \ No newline at end of file diff --git a/examples/simple-playground/src/main.rs b/examples/simple-playground/src/main.rs deleted file mode 100644 index 7f73a96..0000000 --- a/examples/simple-playground/src/main.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![no_std] -#![no_main] - -use common_arm as _; -use cortex_m_rt::entry; -use defmt::info; -use panic_probe as _; -use stm32h7xx_hal::pac; -use stm32h7xx_hal::prelude::*; - -#[inline(never)] -#[defmt::panic_handler] -fn panic() -> ! { - cortex_m::asm::udf() -} - -#[entry] -fn main() -> ! { - let _cp = cortex_m::Peripherals::take().unwrap(); - let dp = pac::Peripherals::take().unwrap(); - - let pwr = dp.PWR.constrain(); - let pwrcfg = pwr.freeze(); - - info!("Power enabled"); - // RCC - let mut rcc = dp.RCC.constrain(); - let reset = rcc.get_reset_reason(); - - info!("Reset reason: {:?}", reset); - - let _ccdr = rcc - .use_hse(48.MHz()) // check the clock hardware - .sys_ck(200.MHz()) - .freeze(pwrcfg, &dp.SYSCFG); - info!("RCC configured"); - - loop { - info!("Hello, world!"); - } -} diff --git a/phoenix/Cargo.toml b/phoenix/Cargo.toml index ee9bced..b4119b8 100644 --- a/phoenix/Cargo.toml +++ b/phoenix/Cargo.toml @@ -6,27 +6,92 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +nmea = { version = "0.7.0", default-features = false } cortex-m = { workspace = true } cortex-m-rt = { workspace = true } -rtic = { workspace = true } -rtic-monotonics = { workspace = true } +smlang = { workspace = true } +#rtic = { workspace = true } +#rtic-monotonics = { workspace = true } common-arm = { path = "../crates/common-arm" } -stm32h7xx-hal = { workspace = true } -postcard = { workspace = true } defmt = { workspace = true} -fdcan = { workspace = true } embedded-alloc = {workspace = true} heapless = {workspace = true} -rtic-sync = { workspace = true } -defmt-rtt = { workspace = true } +#rtic-sync = { workspace = true } panic-probe = { workspace = true } chrono = { workspace = true } -messages = { workspace = true } +messages-prost = { workspace = true } madgwick = { workspace = true } +sbg-rs = { path = "../crates/sbg-rs" } +libm = "0.2.15" +burn = {version = "0.16", default-features = false, features = ["ndarray"]} +# Change stm32h743bi to your chip name, if necessary. +embassy-stm32 = { version = "0.2.0", features = ["defmt", "stm32h733vg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-sync = { version = "0.6.2", features = ["defmt"] } +embassy-embedded-hal = { version = "0.3.0" } +embassy-executor = { version = "0.7.0", features = ["nightly", "task-arena-size-10240", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-net = { version = "0.7.0", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-usb = { version = "0.4.0", features = ["defmt"] } +embassy-futures = { version = "0.1.0" } +ublox = {version = "0.6.0", features = ['serde', 'alloc', 'ubx_proto14'], default-features = false} +defmt-rtt = {workspace = true} +embedded-hal-bus = "0.3.0" +embedded-sdmmc = "0.9.0" +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-nal-async = "0.8.0" +embedded-io-async = { version = "0.6.1" } +critical-section = "1.1" +micromath = "2.0.0" +stm32-fmc = "0.3.0" +embedded-storage = "0.3.1" +static_cell = "2" +grounded = "0.2.0" [dev-dependencies] defmt-test = { workspace = true } +[build-dependencies] +burn-import = { version = "0.17.1", default-features = false, features = ["burn-ndarray", "onnx"] } + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + [[test]] name = "sd" harness = false diff --git a/phoenix/build.rs b/phoenix/build.rs new file mode 100644 index 0000000..8f8cb0d --- /dev/null +++ b/phoenix/build.rs @@ -0,0 +1,8 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); +} diff --git a/phoenix/src/ai.rs b/phoenix/src/ai.rs new file mode 100644 index 0000000..18b661f --- /dev/null +++ b/phoenix/src/ai.rs @@ -0,0 +1,84 @@ +use crate::model; +use burn::backend::NdArray; +use burn::prelude::*; +use burn::record::Recorder; +use defmt::info; +use embassy_time::{Duration, Timer}; +use heapless::{HistoryBuffer, Vec}; + +type AiBackend = NdArray; +type AiDevice = ::Device; + +const SEQ_LENGTH: usize = 50; +const NUM_FEATURES: usize = 12; + +// --- PASTE CONSTANTS FROM PYTHON SCRIPT HERE --- +// Replace these dummy values with the actual output from clean_rocket_data.py +const SCALE_MIN: [f32; NUM_FEATURES] = [0.0f32; 12]; +const SCALE_MAX: [f32; NUM_FEATURES] = [1.0f32; 12]; +// ------------------------------------------------ + +/// Normalizes a single feature value using the pre-calculated min/max. +fn normalize_value(value: f32, min: f32, max: f32) -> f32 { + if (max - min) == 0.0 { + return 0.0; // Avoid division by zero + } + (value - min) / (max - min) +} + +#[embassy_executor::task] +pub async fn ai_task() { + info!("AI Inference Task starting..."); + + let device = AiDevice::default(); + + // 1. Create the model structure + info!("Initializing model structure..."); + let model: model::LstmNetwork = model::LstmNetwork::new(&device); + + // 2. Load the trained weights from the embedded file + info!("Loading trained weights..."); + let recorder = burn::record::NoStdInferenceRecorder::new(); + let record_bytes = include_bytes!("models/model.bin"); + info!("Loaded {} bytes of model weights.", record_bytes.len()); + let record = recorder + .load(record_bytes.to_vec(), &device) + .expect("Failed to load model weights"); + let model = model.load_record(record); + info!("Model loaded successfully."); + + let mut sensor_history: HistoryBuffer<[f32; NUM_FEATURES], SEQ_LENGTH> = HistoryBuffer::new(); + + loop { + let latest_sensor_data: [f32; NUM_FEATURES] = [0.0; 12]; // Dummy data + + let mut normalized_data = [0.0f32; NUM_FEATURES]; + for i in 0..NUM_FEATURES { + normalized_data[i] = normalize_value(latest_sensor_data[i], SCALE_MIN[i], SCALE_MAX[i]); + } + sensor_history.write(normalized_data); + + if sensor_history.len() == sensor_history.capacity() { + let mut flat_history: Vec = Vec::new(); + for frame in sensor_history.iter() { + for value in frame.iter() { + flat_history.push(*value).ok(); + } + } + + let input = Tensor::::from_floats(flat_history.as_slice(), &device) + .reshape([1, SEQ_LENGTH, NUM_FEATURES]); + + let output_log = model.forward(input); + let output_sec = (output_log.exp() - 1.0).into_data(); + let predictions = output_sec.as_slice::().unwrap(); + + info!( + "PREDICTIONS -> Burnout: {=f32}s, Apogee: {=f32}s, Impact: {=f32}s", + predictions[0], predictions[1], predictions[2] + ); + } + + Timer::after(Duration::from_millis(100)).await; // Run at 10Hz + } +} diff --git a/phoenix/src/camera.rs b/phoenix/src/camera.rs new file mode 100644 index 0000000..874a607 --- /dev/null +++ b/phoenix/src/camera.rs @@ -0,0 +1,56 @@ +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::peripherals::{PE12, PE14}; +use embedded_hal_1::digital::OutputPin; + +pub struct Cameras { + power: Output<'static>, + osd: Output<'static>, +} + +impl Cameras { + pub fn new(osd: PE14, power: PE12) -> Self { + Cameras { + osd: Output::new(osd, Level::Low, Speed::Low), + power: Output::new(power, Level::Low, Speed::Low), + } + } + + pub fn start_recording(&mut self) { + // for i in 0..3 { + self.osd.set_high(); + // Delay.delay_ms(250); + + // self.osd.set_low(); + // Delay.delay_ms(250); + // } + + // Delay.delay_ms(1000); + + // OSD is reset, now power on + self.power.set_high(); + // Delay.delay_ms(2000); + // info!("Camera on"); + // self.power.set_low(); + + // Delay.delay_ms(500); + + // self.power.set_low(); + // Delay.delay_ms(2000); + // self.power.set_high(); + + // Delay.delay_ms(1000); + // self.power.set_high(); + // Delay.delay_ms(250); + // self.power.set_low(); + } + + pub fn stop_recording(&mut self) { + // self.power.set_high(); + // Delay.delay_ms(100); + // self.power.set_low(); + // Delay.delay_ms(200); + // self.power.set_high(); + // Delay.delay_ms(500); + // self.power.set_low(); + } +} diff --git a/phoenix/src/communication.rs b/phoenix/src/communication.rs index 9a3448c..cf0c09a 100644 --- a/phoenix/src/communication.rs +++ b/phoenix/src/communication.rs @@ -1,202 +1,237 @@ -use crate::data_manager::DataManager; -use crate::types::COM_ID; -use common_arm::HydraError; -use defmt::{error, info}; -use fdcan::{ - frame::{FrameFormat, TxFrameHeader}, - id::StandardId, -}; -use mavlink::peek_reader::PeekReader; -use messages::mavlink::uorocketry::MavMessage; -use messages::mavlink::{self}; -use messages::Message; -use postcard::from_bytes; +use crate::resources::{RADIO_BUFFER_SIZE, RADIO_CHANNEL, RX_RADIO_BUF}; +use crate::RECOVERY_MANAGER; +use defmt::info; +use embassy_stm32::mode; +use embassy_stm32::mode::Async; +use embassy_stm32::peripherals::{DMA2_CH3, DMA2_CH5, PE7, PE8, UART7}; +use embassy_stm32::usart::{RingBufferedUartRx, Uart, UartTx}; +use embassy_time::Instant; +use messages_prost::mavlink; +use messages_prost::mavlink::peek_reader::PeekReader; +use messages_prost::prost::Message; +use messages_prost::radio::radio_frame::Payload; -/// Clock configuration is out of scope for this builder -/// easiest way to avoid alloc is to use no generics -pub struct CanCommandManager { - can: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::NormalOperationMode, - >, -} +pub fn init_radio( + uart: UART7, + rx: PE7, + tx: PE8, + tx_dma: DMA2_CH3, + rx_dma: DMA2_CH5, + irqs: crate::Irqs, +) -> (UartTx<'static, Async>, RingBufferedUartRx<'static>) { + let mut uart_radio_config = embassy_stm32::usart::Config::default(); + uart_radio_config.baudrate = 57600; + uart_radio_config.data_bits = embassy_stm32::usart::DataBits::DataBits8; + uart_radio_config.parity = embassy_stm32::usart::Parity::ParityNone; + uart_radio_config.stop_bits = embassy_stm32::usart::StopBits::STOP1; -impl CanCommandManager { - pub fn new( - can: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::NormalOperationMode, - >, - ) -> Self { - Self { can } - } - pub fn send_message(&mut self, m: Message) -> Result<(), HydraError> { - let mut buf = [0u8; 64]; - let payload = postcard::to_slice(&m, &mut buf)?; - let header = TxFrameHeader { - len: payload.len() as u8, // switch to const as this never changes or swtich on message type of known size - id: StandardId::new(COM_ID.into()).unwrap().into(), - frame_format: FrameFormat::Standard, - bit_rate_switching: false, - marker: None, - }; - self.can.transmit(header, payload)?; - Ok(()) - } - pub fn process_data(&mut self, data_manager: &mut DataManager) -> Result<(), HydraError> { - let mut buf = [0u8; 64]; - while self.can.receive0(&mut buf).is_ok() { - if let Ok(data) = from_bytes::(&buf) { - info!("Received message {}", data.clone()); - data_manager.handle_command(data)?; - } else { - info!("Error: {:?}", from_bytes::(&buf).unwrap_err()); - } - } - Ok(()) - } -} + let uart_radio = Uart::new(uart, rx, tx, irqs, tx_dma, rx_dma, uart_radio_config).unwrap(); -/// Clock configuration is out of scope for this builder -/// easiest way to avoid alloc is to use no generics -pub struct CanDataManager { - can: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::NormalOperationMode, - >, + let (radio_tx, radio_rx) = uart_radio.split(); + let radio_ring_rx = radio_rx.into_ring_buffered(unsafe { &mut RX_RADIO_BUF }); + + (radio_tx, radio_ring_rx) } -impl CanDataManager { - pub fn new( - can: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::NormalOperationMode, - >, - ) -> Self { - Self { can } - } - pub fn send_message(&mut self, m: Message) -> Result<(), HydraError> { - let mut buf = [0u8; 64]; - let payload = postcard::to_slice(&m, &mut buf)?; - let header = TxFrameHeader { - len: payload.len() as u8, // switch to const as this never changes or swtich on message type of known size - id: StandardId::new(COM_ID.into()).unwrap().into(), - frame_format: FrameFormat::Fdcan, - bit_rate_switching: false, - marker: None, - }; - // self.can.abort(fdcan::Mailbox::_2); // this is needed if boards are not in sync (if they are not in sync that is a bigger problem) +#[embassy_executor::task] +pub async fn radio_reader_task(mut rx: RingBufferedUartRx<'static>) { + loop { + let mut buf: [u8; RADIO_BUFFER_SIZE] = [0; RADIO_BUFFER_SIZE]; + if let Ok(len) = rx.read(&mut buf).await { + if len > 0 { + // Process the received data + info!("Received {} bytes from radio: {:?}", len, &buf[..len]); + if let Ok((_header, msg)) = mavlink::read_versioned_msg( + &mut PeekReader::new(&buf[..len]), + mavlink::MavlinkVersion::V2, + ) { + match msg { + mavlink::uorocketry::MavMessage::POSTCARD_MESSAGE(msg) => { + info!("Received postcard message"); + // decode the msg + if let Ok(recv) = + messages_prost::radio::RadioFrame::decode_length_delimited( + &mut &msg.message[..], + ) + { + // info!("Received radio frame: {:?}", recv.node); + if let Some(payload) = recv.payload { + match payload { + Payload::ArgusTemperature(_) => {} + Payload::ArgusStrain(_) => {} + Payload::ArgusPressure(_) => {} + Payload::ArgusEvent(_) => {} + Payload::ArgusState(_) => {} + Payload::Sbg(sbg_data) => { + info!( + "Received SBG data: {:?}", + sbg_data.data.is_some() + ); + } + Payload::Gps(gps_data) => { + info!("Received GPS data: {:?}", gps_data.data.len()); + // Handle GPS data + } + Payload::Madgwick(madgwick_data) => { + info!( + "Received Madgwick data: {:?}", + madgwick_data.data.is_some() + ); + // Handle Madgwick data + } + Payload::Iim20670(imu_data) => { + info!( + "Received IMU data: {:?}", + imu_data.data.is_some() + ); + // Handle IMU data + } + Payload::Log(log_data) => { + info!("Received Log data: {:?}", log_data.level); + // Handle Log data + } + Payload::PhoenixState(state) => { + info!("Received State message: {:?}", state); + // Handle State message + } + Payload::PhoenixEvent(event) => {} + Payload::Barometer(barometer_data) => { + // Handle Barometer data + } + Payload::Command(command) => { + info!("Received Command: {:?}", command.data.is_some()); + if let Some(command_data) = command.data { + match command_data { + messages_prost::command::command::Data::PowerUpCamera(power_up_camera) => { + info!("Powering up camera"); + todo!("Powering up camera not implemented yet"); + } + messages_prost::command::command::Data::PowerDownCamera(power_down_camera) => { + info!("Powering down camera"); + todo!("Powering down camera not implemented yet"); + } + messages_prost::command::command::Data::Ping(ping) => { + info!("Ping"); + let mut buf: [u8; 255] = [0; 255]; + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::Command( + messages_prost::command::Command { + node: 0, + data: Some(messages_prost::command::command::Data::Pong( + messages_prost::command::Pong { + id: ping.id, + } + )), + } + )), + millis_since_start: Instant::now().as_millis() + }; + msg.encode_length_delimited(&mut buf.as_mut()) + .expect("Failed to encode SBG GPS Position"); + RADIO_CHANNEL.send(buf).await; + } + messages_prost::command::command::Data::Pong(pong) => { + // info!("Received Pong command: {:?}", pong); + info!("Pong"); + } + messages_prost::command::command::Data::Online(online) => { + // info!("Received Online command: {:?}", online); + } + messages_prost::command::command::Data::DeployDrogue(deploy_drogue) => { + RECOVERY_MANAGER.lock(|cell| { + // *cell.borrow_mut() = Some(recovery_manager); + if let Some(recovery_manager) = cell.borrow_mut().as_mut() { + recovery_manager.arm(); + recovery_manager.fire_drogue(); + recovery_manager.disarm(); + } else { + info!("Recovery manager not initialized."); + } + }); - stm32h7xx_hal::nb::block!(self.can.transmit(header, payload))?; + // COMMAND_CHANNEL.send(command_data).await; + // info!("Received Deploy Drogue command: {:?}", deploy_drogue); + } + messages_prost::command::command::Data::DeployMain(deploy_main) => { + RECOVERY_MANAGER.lock(|cell| { + info!("Boom boom"); + // *cell.borrow_mut() = Some(recovery_manager); + if let Some(recovery_manager) = cell.borrow_mut().as_mut() { + recovery_manager.arm(); + recovery_manager.fire_main(); + recovery_manager.disarm(); + } else { + info!("Recovery manager not initialized."); + } + }); + // info!("Received Deploy Main command: {:?}", deploy_main); + // COMMAND_CHANNEL.send(command_data).await; - Ok(()) - } - pub fn process_data(&mut self) -> Result<(), HydraError> { - let mut buf = [0u8; 64]; - while self.can.receive0(&mut buf).is_ok() { - if let Ok(data) = from_bytes::(&buf) { - info!("Received message {}", data.clone()); - crate::app::send_gs::spawn(data).ok(); - } else if let Err(e) = from_bytes::(&buf) { - info!("Error: {:?}", e); - } - } - self.can - .clear_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); - Ok(()) - } - pub fn receive_message(&mut self) -> Result, HydraError> { - let mut buf = [0u8; 64]; - if self.can.receive0(&mut buf).is_ok() { - if let Ok(data) = from_bytes::(&buf) { - return Ok(Some(data)); + } + messages_prost::command::command::Data::PowerDown(power_down) => { + // info!("Received Power Down command: {:?}", power_down); + } + messages_prost::command::command::Data::RadioRateChange(rate_change) => { + // info!("Received Radio Rate Change command: {:?}", rate_change); + } + } + } + // Handle Command + } + } + } + } else { + info!("Failed to decode radio frame."); + } + } + mavlink::uorocketry::MavMessage::COMMAND_MESSAGE(command) => { + info!("Received command"); + } + mavlink::uorocketry::MavMessage::HEARTBEAT(_) => { + info!("Received heartbeat message."); + } + _ => { + info!("Unknown mavlink message."); + // info!("Received unknown MAVLink message: {:?}", msg); + } + } + } } } - Ok(None) + // Timer::after(Duration::from_millis(100)).await; } } -pub struct RadioDevice { - transmitter: stm32h7xx_hal::serial::Tx, - pub receiver: PeekReader>, -} - -impl RadioDevice { - pub fn new(uart: stm32h7xx_hal::serial::Serial) -> Self { - let (tx, mut rx) = uart.split(); - - rx.listen(); - // setup interrupts - - RadioDevice { - transmitter: tx, - receiver: PeekReader::new(rx), - } - } -} +#[embassy_executor::task] +pub async fn radio_writer_task(mut tx: UartTx<'static, mode::Async>) { + let mut sequence = 0; -pub struct RadioManager { - pub radio: RadioDevice, - mav_sequence: u8, -} + loop { + let data = RADIO_CHANNEL.receive().await; -impl RadioManager { - pub fn new(radio: RadioDevice) -> Self { - RadioManager { - radio, - mav_sequence: 0, - } - } - pub fn send_message(&mut self, payload: &[u8]) -> Result<(), HydraError> { let mav_header = mavlink::MavHeader { system_id: 1, component_id: 1, - sequence: self.increment_mav_sequence(), + sequence, }; - // Create a fixed-size array and copy the payload into it - let mut fixed_payload = [0u8; 255]; - let len = payload.len().min(255); - fixed_payload[..len].copy_from_slice(&payload[..len]); let mav_message = mavlink::uorocketry::MavMessage::POSTCARD_MESSAGE( - mavlink::uorocketry::POSTCARD_MESSAGE_DATA { - message: fixed_payload, - }, + mavlink::uorocketry::POSTCARD_MESSAGE_DATA { message: data }, ); - mavlink::write_versioned_msg( - &mut self.radio.transmitter, + match mavlink::write_versioned_msg_async( + &mut tx, mavlink::MavlinkVersion::V2, mav_header, &mav_message, - )?; - Ok(()) - } - pub fn increment_mav_sequence(&mut self) -> u8 { - self.mav_sequence = self.mav_sequence.wrapping_add(1); - self.mav_sequence - } - pub fn receive_message(&mut self) -> Result { - let (_header, msg): (_, MavMessage) = - mavlink::read_versioned_msg(&mut self.radio.receiver, mavlink::MavlinkVersion::V2)?; - - // info!("{:?}", ); - // Do we need the header? - match msg { - mavlink::uorocketry::MavMessage::POSTCARD_MESSAGE(msg) => { - Ok(postcard::from_bytes::(&msg.message)?) - // weird Ok syntax to coerce to hydra error type. - } - mavlink::uorocketry::MavMessage::COMMAND_MESSAGE(command) => { - info!("{}", command.command); - Ok(postcard::from_bytes::(&command.command)?) - } - mavlink::uorocketry::MavMessage::HEARTBEAT(_) => { - info!("Heartbeat"); - Err(mavlink::error::MessageReadError::Io.into()) + ) + .await + { + Ok(bytes) => { + sequence = sequence.wrapping_add(1); } _ => { - error!("Error, ErrorContext::UnkownPostcardMessage"); - Err(mavlink::error::MessageReadError::Io.into()) + info!("Failed to write"); } } } diff --git a/phoenix/src/data_manager.rs b/phoenix/src/data_manager.rs deleted file mode 100644 index 035757e..0000000 --- a/phoenix/src/data_manager.rs +++ /dev/null @@ -1,197 +0,0 @@ -use common_arm::HydraError; -use messages::command::RadioRate; -use messages::state::StateData; -use messages::Message; -use stm32h7xx_hal::rcc::ResetReason; -#[derive(Clone)] -pub struct DataManager { - pub air: Option, - pub ekf_nav_1: Option, - pub ekf_nav_2: Option, - pub ekf_nav_acc: Option, - pub ekf_quat: Option, - pub madgwick_quat: Option, - pub imu_1: Option, - pub imu_2: Option, - pub utc_time: Option, - pub gps_vel: Option, - pub gps_vel_acc: Option, - pub gps_pos_1: Option, - pub gps_pos_2: Option, - pub gps_pos_acc: Option, - pub state: Option, - pub reset_reason: Option, - pub logging_rate: Option, - pub recovery_sensing: Option, - pub nav_pos_l1h: Option, - // Barometer - pub baro_temperature: Option, - pub baro_pressure: Option, -} - -impl DataManager { - pub fn new() -> Self { - Self { - air: None, - ekf_nav_1: None, - ekf_nav_2: None, - ekf_nav_acc: None, - ekf_quat: None, - madgwick_quat: None, - imu_1: None, - imu_2: None, - utc_time: None, - gps_vel: None, - gps_vel_acc: None, - gps_pos_1: None, - gps_pos_2: None, - gps_pos_acc: None, - state: None, - reset_reason: None, - logging_rate: Some(RadioRate::Slow), // start slow. - recovery_sensing: None, - nav_pos_l1h: None, - baro_temperature: None, - baro_pressure: None, - } - } - - pub fn get_logging_rate(&mut self) -> RadioRate { - if let Some(rate) = self.logging_rate.take() { - let rate_cln = rate.clone(); - self.logging_rate = Some(rate); - return rate_cln; - } - self.logging_rate = Some(RadioRate::Slow); - RadioRate::Slow - } - - /// Do not clone instead take to reduce CPU load. - pub fn take_sensors(&mut self) -> [Option; 16] { - [ - self.air.take(), - self.ekf_nav_1.take(), - self.ekf_nav_2.take(), - self.ekf_nav_acc.take(), - self.ekf_quat.take(), - self.madgwick_quat.take(), - self.imu_1.take(), - self.imu_2.take(), - self.utc_time.take(), - self.gps_vel.take(), - self.gps_vel_acc.take(), - self.gps_pos_1.take(), - self.gps_pos_2.take(), - self.gps_pos_acc.take(), - self.nav_pos_l1h.take(), - self.recovery_sensing.take(), - ] - } - - pub fn clone_states(&self) -> [Option; 1] { - [self.state.clone()] - } - - pub fn clone_reset_reason(&self) -> Option { - self.reset_reason - } - - pub fn set_reset_reason(&mut self, reset: ResetReason) { - self.reset_reason = Some(reset); - } - - pub fn handle_command(&mut self, data: Message) -> Result<(), HydraError> { - match data.data { - messages::Data::Command(command) => match command.data { - messages::command::CommandData::PowerDown(_) => { - crate::app::sleep_system::spawn().ok(); - } - messages::command::CommandData::RadioRateChange(command_data) => { - self.logging_rate = Some(command_data.rate); - } - _ => { - // We don't care atm about these other commands. - } - }, - _ => { - // we can disregard all other messages for now. - } - } - Ok(()) - } - pub fn handle_data(&mut self, data: Message) { - match data.data { - messages::Data::Sensor(ref sensor) => match sensor.data { - messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data { - messages::sensor::SbgData::EkfNavAcc(_) => { - self.ekf_nav_acc = Some(data); - } - messages::sensor::SbgData::GpsPosAcc(_) => { - self.gps_pos_acc = Some(data); - } - messages::sensor::SbgData::Air(_) => { - self.air = Some(data); - } - messages::sensor::SbgData::EkfNav1(_) => { - self.ekf_nav_1 = Some(data); - } - messages::sensor::SbgData::EkfNav2(_) => { - self.ekf_nav_2 = Some(data); - } - messages::sensor::SbgData::EkfQuat(_) => { - self.ekf_quat = Some(data); - } - messages::sensor::SbgData::GpsVel(_) => { - self.gps_vel = Some(data); - } - messages::sensor::SbgData::GpsVelAcc(_) => { - self.gps_vel_acc = Some(data); - } - messages::sensor::SbgData::Imu1(_) => { - self.imu_1 = Some(data); - } - messages::sensor::SbgData::Imu2(_) => { - self.imu_2 = Some(data); - } - messages::sensor::SbgData::UtcTime(_) => { - self.utc_time = Some(data); - } - messages::sensor::SbgData::GpsPos1(_) => { - self.gps_pos_1 = Some(data); - } - messages::sensor::SbgData::GpsPos2(_) => { - self.gps_pos_2 = Some(data); - } - }, - messages::sensor::SensorData::RecoverySensing(_) => { - self.recovery_sensing = Some(data); - } - messages::sensor::SensorData::NavPosLlh(_) => { - self.nav_pos_l1h = Some(data); - } - messages::sensor::SensorData::ResetReason(_) => {} - }, - messages::Data::State(state) => { - self.state = Some(state.data); - } - // messages::Data::Command(command) => match command.data { - // messages::command::CommandData::RadioRateChange(command_data) => { - // self.logging_rate = Some(command_data.rate); - // } - // messages::command::CommandData::DeployDrogue(_) => {} - // messages::command::CommandData::DeployMain(_) => {} - // messages::command::CommandData::PowerDown(_) => {} - // }, - _ => {} - } - } - pub fn store_madgwick_result(&mut self, result: Message) { - self.madgwick_quat = Some(result); - } -} - -impl Default for DataManager { - fn default() -> Self { - Self::new() - } -} diff --git a/phoenix/src/madgwick_service.rs b/phoenix/src/madgwick_service.rs index 70c68bd..cfd8cc4 100644 --- a/phoenix/src/madgwick_service.rs +++ b/phoenix/src/madgwick_service.rs @@ -1,14 +1,13 @@ +use heapless::HistoryBuffer; use madgwick::Marg; -use messages::{Message, sensor::{self, SbgData, EkfQuat}}; -use messages::sensor::Sensor; -use messages::sensor_status::EkfStatus; - +use messages_prost::sensor::madgwick::Madgwick; +use messages_prost::sensor::madgwick::Quaternion; /// Service that implements the Madgwick sensor fusion algorithim for orientation /// This service processes IMU data (accelerometer and gyroscope) pub struct MadgwickService { madgwick: Marg, - // Store the latest quaternion - latest_quat: (f32, f32, f32, f32), + // Store the latest quaternions + quat_history: HistoryBuffer, // Store configuration parameters beta: f32, // 'beta' is the filter gain parameter that determines how much the accelerometer influences the orientation estimation; the higher the value, the more weight the accelerometer data has sample_period: f32, // 'sample_period' is the time in seconds between sensor readings; it is reciprocal of the sensor sampling frequency @@ -19,138 +18,219 @@ impl MadgwickService { const DEFAULT_BETA: f32 = 0.1; const DEFAULT_SAMPLE_PERIOD: f32 = 0.01; // 100Hz - /// Method for creating a new instance of 'MadgwickService' with default parameters - pub fn new() -> Self { - // Use the version with parameters but provide defaults incase we can't get parameters for some reason - Self::new_with_params(Self::DEFAULT_BETA, Self::DEFAULT_SAMPLE_PERIOD) + pub fn default() -> Self { + Self::new(Self::DEFAULT_BETA, Self::DEFAULT_SAMPLE_PERIOD) } - + /// New constructor that accepts parameters - pub fn new_with_params(beta: f32, sample_period: f32) -> Self { + pub fn new(beta: f32, sample_period: f32) -> Self { // Create the filter with specified parameters let mut madgwick = Marg::new(beta, sample_period); - + let mut quat_history = HistoryBuffer::new(); + // Initialize with standard measurements - let accel = madgwick::F32x3 { x: 0.0, y: 0.0, z: 1.0 }; // "z: 1.0" represents the accelerometer pointing in the positive z-direction (upwards) - let gyro = madgwick::F32x3 { x: 0.0, y: 0.0, z: 0.0 }; - let mag = madgwick::F32x3 { x: 1.0, y: 0.0, z: 0.0 }; // "x: 1.0" represents the magnetometer pointing in the positive x-direction - + let accel = madgwick::F32x3 { + x: 0.0, + y: 0.0, + z: 1.0, + }; // "z: 1.0" represents the accelerometer pointing in the positive z-direction (upwards) + let gyro = madgwick::F32x3 { + x: 0.0, + y: 0.0, + z: 0.0, + }; + let mag = madgwick::F32x3 { + x: 1.0, + y: 0.0, + z: 0.0, + }; // "x: 1.0" represents the magnetometer pointing in the positive x-direction + // Get initial quaternion from filter - let mut quat = (1.0, 0.0, 0.0, 0.0); // Default identity quaternion with no rotation - + let _quat = (1.0, 0.0, 0.0, 0.0); // Default identity quaternion with no rotation + // Apply multiple updates to ensure convergence, and stores the resulting quaternion after each update for _ in 0..5 { let updated_quat = madgwick.update(mag, gyro, accel); - quat = (updated_quat.0, updated_quat.1, updated_quat.2, updated_quat.3); + + quat_history.write(Quaternion { + w: updated_quat.0, + x: updated_quat.1, + y: updated_quat.2, + z: updated_quat.3, + }); } - + Self { madgwick, - latest_quat: quat, // Use the quaternion from the filter + quat_history, beta, sample_period, } } - + /// Method for re-initialization the filter with standard gravity readings /// This is mainly used when parameters are changed fn initialize(&mut self) { // "z: 1.0" represents the accelerometer pointing in the positive z-direction (upwards) // If our data looks really off, we can try changing the z value to -1.0 - let accel = madgwick::F32x3 { x: 0.0, y: 0.0, z: 1.0 }; - let gyro = madgwick::F32x3 { x: 0.0, y: 0.0, z: 0.0 }; - let mag = madgwick::F32x3 { x: 1.0, y: 0.0, z: 0.0 }; - + let accel = madgwick::F32x3 { + x: 0.0, + y: 0.0, + z: 1.0, + }; + let gyro = madgwick::F32x3 { + x: 0.0, + y: 0.0, + z: 0.0, + }; + let mag = madgwick::F32x3 { + x: 1.0, + y: 0.0, + z: 0.0, + }; + // Apply multiple updates to ensure convergence for _ in 0..5 { let quat = self.madgwick.update(mag, gyro, accel); - self.latest_quat = (quat.0, quat.1, quat.2, quat.3); + self.quat_history.write(Quaternion { + w: quat.0, + x: quat.1, + y: quat.2, + z: quat.3, + }); } } - + /// Method for processing incoming IMU data; returns a new Message with an updated quaternion from the filter - pub fn process_imu_data(&mut self, data: &Message) -> Option { - match &data.data { - messages::Data::Sensor(sensor) => match &sensor.data { - messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data { - SbgData::Imu1(imu_data) => { - if let (Some(accel), Some(gyro)) = (imu_data.accelerometers, imu_data.gyroscopes) { - let mag = madgwick::F32x3 { x: 0.0, y: 0.0, z: 0.0 }; - let gyro = madgwick::F32x3 { - x: gyro[0], - y: gyro[1], - z: gyro[2], - }; - - let accel = madgwick::F32x3 { - x: accel[0], - y: accel[1], - z: accel[2], - }; - - let quat = self.madgwick.update(mag, gyro, accel); - - // Store the latest quaternion - self.latest_quat = (quat.0, quat.1, quat.2, quat.3); - - Some(Message::new( - data.timestamp.clone(), - data.node.clone(), - Sensor::new( - sensor::SensorData::SbgData( - SbgData::EkfQuat( - EkfQuat { - time_stamp: imu_data.time_stamp, - quaternion: Some([quat.0, quat.1, quat.2, quat.3]), - euler_std_dev: None, - status: EkfStatus::new(0), - } - ) - ) - ) - )) - } else { - None - } - }, - _ => None, - }, - _ => None, - }, - _ => None, + pub fn process_imu_data( + &mut self, + data: &messages_prost::sensor::iim20670::Imu, + ) -> Option { + let mag = madgwick::F32x3 { + x: 0.0, + y: 0.0, + z: 0.0, + }; + + if let Some(imu) = data.data { + if let Some(accel) = imu.accelerometer { + if let Some(gyros) = imu.gyroscope { + let gyro = madgwick::F32x3 { + x: gyros.x, + y: gyros.y, + z: gyros.z, + }; + + let accel = madgwick::F32x3 { + x: accel.x, + y: accel.y, + z: accel.z, + }; + + let quat = self.madgwick.update(mag, gyro, accel); + + let prost_quat = Quaternion { + w: quat.0, + x: quat.1, + y: quat.2, + z: quat.3, + }; + + self.quat_history.write(prost_quat); + + return Some(Madgwick { + node: 0, + data: Some(prost_quat), + }); + } + } } + + None + // Store the latest quaternion + // self.latest_quat = (quat.0, quat.1, quat.2, quat.3); + + // match &data.data { + // messages::Data::Sensor(sensor) => match &sensor.data { + // messages::sensor::SensorData::SbgData(ref sbg_data) => match sbg_data { + // SbgData::Imu1(imu_data) => { + // if let (Some(accel), Some(gyro)) = (imu_data.accelerometers, imu_data.gyroscopes) { + // let mag = madgwick::F32x3 { x: 0.0, y: 0.0, z: 0.0 }; + // let gyro = madgwick::F32x3 { + // x: gyro[0], + // y: gyro[1], + // z: gyro[2], + // }; + + // let accel = madgwick::F32x3 { + // x: accel[0], + // y: accel[1], + // z: accel[2], + // }; + + // let quat = self.madgwick.update(mag, gyro, accel); + + // // Store the latest quaternion + // self.latest_quat = (quat.0, quat.1, quat.2, quat.3); + + // Some(Message::new( + // data.timestamp.clone(), + // data.node.clone(), + // Sensor::new( + // sensor::SensorData::SbgData( + // SbgData::EkfQuat( + // EkfQuat { + // time_stamp: imu_data.time_stamp, + // quaternion: Some([quat.0, quat.1, quat.2, quat.3]), + // euler_std_dev: None, + // status: EkfStatus::new(0), + // } + // ) + // ) + // ) + // )) + // } else { + // None + // } + // }, + // _ => None, + // }, + // _ => None, + // }, + // _ => None, + // } } /// Method for getting the latest quaternion method - pub fn get_quaternion(&self) -> (f32, f32, f32, f32) { - self.latest_quat + pub fn get_quaternion(&self) -> Option<&Quaternion> { + self.quat_history.last() } /// Method to set new beta value pub fn set_beta(&mut self, beta: f32) { self.beta = beta; - + self.madgwick = Marg::new(self.beta, self.sample_period); - + self.initialize(); } - + /// Method to set sample period pub fn set_sample_period(&mut self, sample_period: f32) { self.sample_period = sample_period; - + self.madgwick = Marg::new(self.beta, self.sample_period); - + self.initialize(); } - + /// Method to get current beta value pub fn get_beta(&self) -> f32 { self.beta } - + /// Method to get current sample period pub fn get_sample_period(&self) -> f32 { self.sample_period } -} \ No newline at end of file +} diff --git a/phoenix/src/main.rs b/phoenix/src/main.rs index 4a4de82..52bc6af 100644 --- a/phoenix/src/main.rs +++ b/phoenix/src/main.rs @@ -1,661 +1,250 @@ +#![feature(impl_trait_in_assoc_type)] +#![feature(ascii_char)] #![no_std] #![no_main] +mod ai; +mod camera; mod communication; -mod data_manager; mod madgwick_service; -mod types; - -use chrono::NaiveDate; -use common_arm::*; -use communication::{CanCommandManager, CanDataManager}; -use communication::{RadioDevice, RadioManager}; -use core::num::{NonZeroU16, NonZeroU8}; -use data_manager::DataManager; -use defmt::info; -use fdcan::{ - config::NominalBitTiming, - filter::{StandardFilter, StandardFilterSlot}, -}; -use messages::command::RadioRate; -use messages::{sensor, Data}; +mod model; +mod music; +mod recovery; +mod resources; +mod sd; +mod sensors; +mod state_machine; + +use core::cell::RefCell; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, OutputType, Speed}; +use embassy_stm32::spi::{Config as SpiConfig, Spi}; +use embassy_stm32::time::{khz, mhz}; +use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; +use embassy_stm32::usart::{Config as UartConfig, Uart}; +use embassy_stm32::mode; +use embassy_time::{Delay, Duration, Timer}; +use embedded_hal_bus::spi::RefCellDevice; +use static_cell::StaticCell; +// use embedded_alloc::Heap; +use crate::state_machine::StateMachine; +use defmt_rtt as _; use panic_probe as _; -use rtic_monotonics::systick::prelude::*; -use rtic_sync::{channel::*, make_channel}; -use stm32h7xx_hal::gpio::gpioa::{PA2, PA3}; -use stm32h7xx_hal::gpio::gpiob::PB4; -use stm32h7xx_hal::gpio::Speed; -use stm32h7xx_hal::gpio::{Output, PushPull}; -use stm32h7xx_hal::prelude::*; -use stm32h7xx_hal::rtc; -use stm32h7xx_hal::{rcc, rcc::rec}; -use types::COM_ID; // global logger - -const DATA_CHANNEL_CAPACITY: usize = 10; -systick_monotonic!(Mono, 500); - -#[inline(never)] -#[defmt::panic_handler] -fn panic() -> ! { - // stm32h7xx_hal::pac::SCB::sys_reset() - cortex_m::asm::udf() -} - -#[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true, dispatchers = [EXTI0, EXTI1, EXTI2, SPI3, SPI2])] -mod app { - - use common_arm::drivers::ms5611::OversamplingRatio; - use messages::Message; - use stm32h7xx_hal::gpio::{Alternate, Pin}; - - use super::*; - - #[shared] - struct SharedResources { - data_manager: DataManager, - madgwick_service: madgwick_service::MadgwickService, - em: ErrorManager, - // sd_manager: SdManager< - // stm32h7xx_hal::spi::Spi, - // PA4>, - // >, - radio_manager: RadioManager, - can_command_manager: CanCommandManager, - can_data_manager: CanDataManager, - sbg_power: PB4>, - rtc: rtc::Rtc, - } - #[local] - struct LocalResources { - led_red: PA2>, - led_green: PA3>, - buzzer: stm32h7xx_hal::pwm::Pwm< - stm32h7xx_hal::pac::TIM12, - 0, - stm32h7xx_hal::pwm::ComplementaryImpossible, - >, - // Baro uses: - // PB_08 for CS - // PE_02 for SCK - // PE_05 for MISO - // PE_06 for MOSI - baro: common_arm::drivers::ms5611::Ms5611< - stm32h7xx_hal::spi::Spi, - stm32h7xx_hal::gpio::Pin< - 'B', - 8, - stm32h7xx_hal::gpio::Output, - >, - stm32h7xx_hal::delay::DelayFromCountDownTimer< - stm32h7xx_hal::timer::Timer, - >, - >, - } - - #[init] - fn init(ctx: init::Context) -> (SharedResources, LocalResources) { - // channel setup - let (_s, r) = make_channel!(Message, DATA_CHANNEL_CAPACITY); - - let core = ctx.core; - - /* Logging Setup */ - HydraLogging::set_ground_station_callback(queue_gs_message); - - let pwr = ctx.device.PWR.constrain(); - // We could use smps, but the board is not designed for it - // let pwrcfg = example_power!(pwr).freeze(); - let mut pwrcfg = pwr.freeze(); - - info!("Power enabled"); - let backup = pwrcfg.backup().unwrap(); - info!("Backup domain enabled"); - // RCC - let mut rcc = ctx.device.RCC.constrain(); - let reset = rcc.get_reset_reason(); - let fdcan_prec_unsafe = unsafe { rcc.steal_peripheral_rec() } - .FDCAN - .kernel_clk_mux(rec::FdcanClkSel::Pll1Q); - - let ccdr = rcc - .use_hse(48.MHz()) // check the clock hardware - .sys_ck(200.MHz()) - .pll1_strategy(rcc::PllConfigStrategy::Iterative) - .pll1_q_ck(32.MHz()) - .freeze(pwrcfg, &ctx.device.SYSCFG); - info!("RCC configured"); - let fdcan_prec = ccdr - .peripheral - .FDCAN - .kernel_clk_mux(rec::FdcanClkSel::Pll1Q); - - let btr = NominalBitTiming { - prescaler: NonZeroU16::new(10).unwrap(), - seg1: NonZeroU8::new(13).unwrap(), - seg2: NonZeroU8::new(2).unwrap(), - sync_jump_width: NonZeroU8::new(1).unwrap(), - }; - - // let data_bit_timing = DataBitTiming { - // prescaler: NonZeroU8::new(10).unwrap(), - // seg1: NonZeroU8::new(13).unwrap(), - // seg2: NonZeroU8::new(2).unwrap(), - // sync_jump_width: NonZeroU8::new(4).unwrap(), - // transceiver_delay_compensation: true, - // }; - - info!("CAN enabled"); - // GPIO - let gpioa = ctx.device.GPIOA.split(ccdr.peripheral.GPIOA); - let gpiod = ctx.device.GPIOD.split(ccdr.peripheral.GPIOD); - let gpiob = ctx.device.GPIOB.split(ccdr.peripheral.GPIOB); - - let pins = gpiob.pb14.into_alternate(); - let mut c0 = ctx - .device - .TIM12 - .pwm(pins, 4.kHz(), ccdr.peripheral.TIM12, &ccdr.clocks); - - c0.set_duty(c0.get_max_duty() / 4); - // PWM outputs are disabled by default - // c0.enable(); - - info!("PWM enabled"); - // assert_eq!(ccdr.clocks.pll1_q_ck().unwrap().raw(), 32_000_000); - info!("PLL1Q:"); - // https://github.com/stm32-rs/stm32h7xx-hal/issues/369 This needs to be stolen. Grrr I hate the imaturity of the stm32-hal - let can2: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::ConfigMode, - > = { - let rx = gpiob.pb12.into_alternate().speed(Speed::VeryHigh); - let tx = gpiob.pb13.into_alternate().speed(Speed::VeryHigh); - ctx.device.FDCAN2.fdcan(tx, rx, fdcan_prec) - }; - - let mut can_data = can2; - can_data.set_protocol_exception_handling(false); - - can_data.set_nominal_bit_timing(btr); - - // can_data.set_automatic_retransmit(false); // data can be dropped due to its volume. - - // can_command.set_data_bit_timing(data_bit_timing); - - can_data.set_standard_filter( - StandardFilterSlot::_0, - StandardFilter::accept_all_into_fifo0(), - ); - - can_data.set_standard_filter( - StandardFilterSlot::_1, - StandardFilter::accept_all_into_fifo0(), - ); - - can_data.set_standard_filter( - StandardFilterSlot::_2, - StandardFilter::accept_all_into_fifo0(), - ); - - can_data.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); - - can_data.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true); - - let config = can_data - .get_config() - .set_frame_transmit(fdcan::config::FrameTransmissionConfig::AllowFdCanAndBRS); - can_data.apply_config(config); - - let can_data_manager = CanDataManager::new(can_data.into_normal()); - - let can1: fdcan::FdCan< - stm32h7xx_hal::can::Can, - fdcan::ConfigMode, - > = { - let rx = gpioa.pa11.into_alternate().speed(Speed::VeryHigh); - let tx = gpioa.pa12.into_alternate().speed(Speed::VeryHigh); - ctx.device.FDCAN1.fdcan(tx, rx, fdcan_prec_unsafe) - }; - - let mut can_command = can1; - can_command.set_protocol_exception_handling(false); - - can_command.set_nominal_bit_timing(btr); - can_command.set_standard_filter( - StandardFilterSlot::_0, - StandardFilter::accept_all_into_fifo0(), - ); - - can_command.set_standard_filter( - StandardFilterSlot::_1, - StandardFilter::accept_all_into_fifo0(), - ); - - can_command.set_standard_filter( - StandardFilterSlot::_2, - StandardFilter::accept_all_into_fifo0(), - ); - - // can_data.set_data_bit_timing(data_bit_timing); - can_command.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg); - - can_command.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true); - - let config = can_command - .get_config() - .set_frame_transmit(fdcan::config::FrameTransmissionConfig::AllowFdCanAndBRS); // check this maybe don't bit switch allow. - can_command.apply_config(config); - - let can_command_manager = CanCommandManager::new(can_command.into_normal()); - - // let spi_sd: stm32h7xx_hal::spi::Spi< - // stm32h7xx_hal::stm32::SPI1, - // stm32h7xx_hal::spi::Enabled, - // u8, - // > = ctx.device.SPI1.spi( - // ( - // gpioa.pa5.into_alternate::<5>(), - // gpioa.pa6.into_alternate(), - // gpioa.pa7.into_alternate(), - // ), - // spi::Config::new(spi::MODE_0), - // 16.MHz(), - // ccdr.peripheral.SPI1, - // &ccdr.clocks, - // ); - - // let cs_sd = gpioa.pa4.into_push_pull_output(); - - // let sd_manager = SdManager::new(spi_sd, cs_sd); - - // leds - let led_red = gpioa.pa2.into_push_pull_output(); - let led_green = gpioa.pa3.into_push_pull_output(); - - // sbg power pin - let mut sbg_power = gpiob.pb4.into_push_pull_output(); - sbg_power.set_high(); - - // Configure SPI4 for barometer - let gpioe = ctx.device.GPIOE.split(ccdr.peripheral.GPIOE); - let spi4 = ctx.device.SPI4.spi( - ( - gpioe.pe2.into_alternate(), // SCK - gpioe.pe5.into_alternate(), // MISO - gpioe.pe6.into_alternate(), // MOSI - ), - stm32h7xx_hal::spi::Config::new(stm32h7xx_hal::spi::MODE_0), - 16.MHz(), - ccdr.peripheral.SPI4, - &ccdr.clocks, - ); - let baro_cs = gpiob.pb8.into_push_pull_output(); - let timer2 = ctx - .device - .TIM2 - .timer(1.MHz(), ccdr.peripheral.TIM2, &ccdr.clocks); - let delay_tim = stm32h7xx_hal::delay::DelayFromCountDownTimer::new(timer2); - /* Monotonic clock */ - Mono::start(core.SYST, 200_000_000); - - let baro = common_arm::drivers::ms5611::Ms5611::new(spi4, baro_cs, delay_tim).unwrap(); - - // UART for sbg - let tx: Pin<'D', 1, Alternate<8>> = gpiod.pd1.into_alternate(); - let rx: Pin<'D', 0, Alternate<8>> = gpiod.pd0.into_alternate(); - - // let stream_tuple = StreamsTuple::new(ctx.device.DMA1, ccdr.peripheral.DMA1); - let uart_radio = ctx - .device - .UART4 - .serial((tx, rx), 57600.bps(), ccdr.peripheral.UART4, &ccdr.clocks) - .unwrap(); - // let mut sbg_manager = sbg_manager::SBGManager::new(uart_sbg, stream_tuple); - - let radio = RadioDevice::new(uart_radio); - - let radio_manager = RadioManager::new(radio); +// Use a modern ms5611 driver that supports embedded-hal v1.0 +use common_arm::drivers::ms5611::Ms5611; - let mut rtc = stm32h7xx_hal::rtc::Rtc::open_or_init( - ctx.device.RTC, - backup.RTC, - stm32h7xx_hal::rtc::RtcClock::Lsi, - &ccdr.clocks, - ); +// Use the asynchronous SpiDevice from embassy-embedded-hal - // TODO: Get current time from some source - let now = NaiveDate::from_ymd_opt(2001, 1, 1) - .unwrap() - .and_hms_opt(0, 0, 0) - .unwrap(); - - rtc.set_date_time(now); - - let madgwick_service = madgwick_service::MadgwickService::new(); - - let mut data_manager = DataManager::new(); - data_manager.set_reset_reason(reset); - let em = ErrorManager::new(); - blink::spawn().ok(); - send_data_internal::spawn(r).ok(); - reset_reason_send::spawn().ok(); - state_send::spawn().ok(); - baro_read::spawn().ok(); - // generate_random_messages::spawn().ok(); - // sensor_send::spawn().ok(); - info!("Online"); - - ( - SharedResources { - data_manager, - madgwick_service, - em, - // sd_manager, - radio_manager, - can_command_manager, - can_data_manager, - sbg_power, - rtc, - }, - LocalResources { - led_red, - led_green, - buzzer: c0, - baro, - }, - ) - } - - // it would be nice to have RTIC be able to return objects, but the current procedural macro - // does not allow for this. - #[task(priority = 3, local = [baro], shared = [&em, data_manager])] - async fn baro_read(mut cx: baro_read::Context) { - let baro = cx.local.baro; // Get mutable access to the driver - loop { - cx.shared.em.run(|| { - // Choose the desired Oversampling Ratio for this reading - let osr = OversamplingRatio::Osr512; // Example: Highest precision +use crate::communication::radio_writer_task; +use crate::recovery::RecoveryManager; +use crate::resources::{ + Irqs, HEAP, RECOVERY_MANAGER, RX_SBG_BUF, +}; - match baro.read_pressure_temperature(osr) { - Ok((temp_c, press_kpa)) => { - cx.shared.data_manager.lock(|dm| { - dm.baro_temperature = Some(temp_c); - dm.baro_pressure = Some(press_kpa); - }); - Ok(()) - } - Err(e) => { - info!("Baro: Driver reading failed!"); - cx.shared.data_manager.lock(|dm| { - dm.baro_temperature = None; - dm.baro_pressure = None; - }); - Err(HydraError::from(e)) - } - } - }); - Mono::delay(1000.millis()).await; - } - } +pub static IMU_BUS_CELL: StaticCell>> = StaticCell::new(); - #[task(priority = 3, shared = [&em, rtc])] - async fn generate_random_messages(mut cx: generate_random_messages::Context) { +#[embassy_executor::task] +async fn imu_task( + mut imu: sensors::iim20670::Iim20670< + RefCellDevice<'static, Spi<'static, mode::Blocking>, Output<'static>, Delay>, + Delay, + >, +) { + if imu.init().is_ok() { loop { - cx.shared.em.run(|| { - let message = Message::new( - cx.shared - .rtc - .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), - COM_ID, - messages::state::State::new(messages::state::StateData::Initializing), - ); - spawn!(send_gs, message.clone())?; - // spawn!(send_data_internal, message)?; - Ok(()) - }); - Mono::delay(1.secs()).await; - } - } - - #[task(priority = 3, shared = [data_manager, &em, rtc])] - async fn reset_reason_send(mut cx: reset_reason_send::Context) { - let reason = cx - .shared - .data_manager - .lock(|data_manager| data_manager.clone_reset_reason()); - match reason { - Some(reason) => { - let x = match reason { - stm32h7xx_hal::rcc::ResetReason::BrownoutReset => sensor::ResetReason::BrownoutReset, - stm32h7xx_hal::rcc::ResetReason::CpuReset => sensor::ResetReason::CpuReset, - stm32h7xx_hal::rcc::ResetReason::D1EntersDStandbyErroneouslyOrCpuEntersCStopErroneously => sensor::ResetReason::D1EntersDStandbyErroneouslyOrCpuEntersCStopErroneously, - stm32h7xx_hal::rcc::ResetReason::D1ExitsDStandbyMode => sensor::ResetReason::D1ExitsDStandbyMode, - stm32h7xx_hal::rcc::ResetReason::D2ExitsDStandbyMode => sensor::ResetReason::D2ExitsDStandbyMode, - stm32h7xx_hal::rcc::ResetReason::GenericWatchdogReset => sensor::ResetReason::GenericWatchdogReset, - stm32h7xx_hal::rcc::ResetReason::IndependentWatchdogReset => sensor::ResetReason::IndependentWatchdogReset, - stm32h7xx_hal::rcc::ResetReason::PinReset => sensor::ResetReason::PinReset, - stm32h7xx_hal::rcc::ResetReason::PowerOnReset => sensor::ResetReason::PowerOnReset, - stm32h7xx_hal::rcc::ResetReason::SystemReset => sensor::ResetReason::SystemReset, - stm32h7xx_hal::rcc::ResetReason::Unknown { rcc_rsr } => sensor::ResetReason::Unknown { rcc_rsr }, - stm32h7xx_hal::rcc::ResetReason::WindowWatchdogReset => sensor::ResetReason::WindowWatchdogReset, - }; - let message = messages::Message::new( - cx.shared - .rtc - .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), - COM_ID, - sensor::Sensor::new(x), - ); - - cx.shared.em.run(|| { - spawn!(send_gs, message)?; - Ok(()) - }) + if let Ok(accel) = imu.read_accel() { + info!("Accel: x={}, y={}, z={}", accel[0], accel[1], accel[2]); } - None => return, - } - } - - #[task(shared = [data_manager, &em, rtc])] - async fn state_send(mut cx: state_send::Context) { - let state_data = cx - .shared - .data_manager - .lock(|data_manager| data_manager.state.clone()); - cx.shared.em.run(|| { - if let Some(x) = state_data { - let message = Message::new( - cx.shared - .rtc - .lock(|rtc| messages::FormattedNaiveDateTime(rtc.date_time().unwrap())), - COM_ID, - messages::state::State::new(x), - ); - spawn!(send_gs, message)?; - } // if there is none we still return since we simply don't have data yet. - Ok(()) - }); - Mono::delay(5.secs()).await; - // spawn_after!(state_send, ExtU64::secs(5)).ok(); - } - - /** - * Sends information about the sensors. - */ - #[task(priority = 3, shared = [data_manager, &em])] - async fn sensor_send(mut cx: sensor_send::Context) { - loop { - let (sensors, logging_rate) = cx.shared.data_manager.lock(|data_manager| { - (data_manager.take_sensors(), data_manager.get_logging_rate()) - }); - - cx.shared.em.run(|| { - for msg in sensors { - match msg { - Some(x) => { - // info!("Sending sensor data {}", x.clone()); - spawn!(send_gs, x)?; - // spawn!(sd_dump, x)?; - } - None => { - info!("No sensor data to send"); - continue; - } - } - } - - Ok(()) - }); - match logging_rate { - RadioRate::Fast => { - Mono::delay(100.millis()).await; - } - RadioRate::Slow => { - Mono::delay(250.millis()).await; - } + if let Ok(gyro) = imu.read_gyro() { + info!("Gyro: x={}, y={}, z={}", gyro[0], gyro[1], gyro[2]); } + Timer::after(Duration::from_millis(100)).await; } + } else { + warn!("IMU initialization failed."); } +} - /// Receives a log message from the custom logger so that it can be sent over the radio. - pub fn queue_gs_message(d: impl Into) { - info!("Queueing message"); - send_gs_intermediate::spawn(d.into()).ok(); - } - - #[task(priority = 3, shared = [rtc, &em])] - async fn send_gs_intermediate(mut cx: send_gs_intermediate::Context, m: Data) { - cx.shared.em.run(|| { - cx.shared.rtc.lock(|rtc| { - let message = messages::Message::new( - messages::FormattedNaiveDateTime(rtc.date_time().unwrap()), - COM_ID, - m, - ); - spawn!(send_gs, message)?; - Ok(()) - }) - }); - } - - #[task(priority = 2, binds = FDCAN1_IT0, shared = [can_command_manager, data_manager, &em])] - fn can_command(mut cx: can_command::Context) { - // info!("CAN Command"); - cx.shared.can_command_manager.lock(|can| { - cx.shared - .data_manager - .lock(|data_manager| cx.shared.em.run(|| can.process_data(data_manager))); - }) - } - - #[task(priority = 3, shared = [sbg_power])] - async fn sbg_power_on(mut cx: sbg_power_on::Context) { - loop { - cx.shared.sbg_power.lock(|sbg| { - sbg.set_high(); - }); - Mono::delay(10000.millis()).await; - } - } - - /** - * Sends a message to the radio over UART. - */ - #[task(priority = 3, shared = [&em, radio_manager])] - async fn send_gs(mut cx: send_gs::Context, m: Message) { - // info!("{}", m.clone()); - - cx.shared.radio_manager.lock(|radio_manager| { - cx.shared.em.run(|| { - // info!("Sending message {}", m); - let mut buf = [0; 255]; - let data = postcard::to_slice(&m, &mut buf)?; - radio_manager.send_message(data)?; - Ok(()) - }) - }); - } - - #[task(priority = 3, binds = FDCAN2_IT0, shared = [&em, can_data_manager, data_manager, madgwick_service])] - fn can_data(mut cx: can_data::Context) { - cx.shared.can_data_manager.lock(|can| { - while let Ok(Some(message)) = can.receive_message() { - // process IMU data through madgwick service - cx.shared.madgwick_service.lock(|madgwick| { - if let Some(result) = madgwick.process_imu_data(&message) { - cx.shared.data_manager.lock(|dm| { - dm.store_madgwick_result(result); - }); - } - }); - } - cx.shared.em.run(|| Ok(())) +// ================================================================================= +// Main Entry Point +// ================================================================================= + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + info!("System starting..."); + { + use core::mem::MaybeUninit; + const HEAP_SIZE: usize = 40_000; + static mut HEAP_MEM: [MaybeUninit; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; + unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) } + } + + let mut config = embassy_stm32::Config::default(); + + // --- Clock configuration --- + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), + divr: None, }); - } - - #[task(priority = 2, shared = [&em, can_data_manager, data_manager])] - async fn send_data_internal( - mut cx: send_data_internal::Context, - mut receiver: Receiver<'static, Message, DATA_CHANNEL_CAPACITY>, - ) { - loop { - if let Ok(m) = receiver.recv().await { - cx.shared.can_data_manager.lock(|can| { - cx.shared.em.run(|| { - can.send_message(m)?; - Ok(()) - }) - }); - } - } - } - - #[task(priority = 2, shared = [&em, can_command_manager, data_manager])] - async fn send_command_internal(mut cx: send_command_internal::Context, m: Message) { - // while let Ok(m) = receiver.recv().await { - cx.shared.can_command_manager.lock(|can| { - cx.shared.em.run(|| { - can.send_message(m)?; - Ok(()) - }) + config.rcc.pll2 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), + divr: None, }); - // } - } - - #[task(priority = 1, local = [led_red, led_green, buzzer, buzzed: bool = false], shared = [&em])] - async fn blink(cx: blink::Context) { - loop { - if cx.shared.em.has_error() { - cx.local.led_red.toggle(); - if *cx.local.buzzed { - cx.local.buzzer.set_duty(0); - *cx.local.buzzed = false; - } else { - let duty = cx.local.buzzer.get_max_duty() / 4; - cx.local.buzzer.set_duty(duty); - *cx.local.buzzed = true; - } - Mono::delay(500.millis()).await; - } else { - cx.local.led_green.toggle(); - if *cx.local.buzzed { - cx.local.buzzer.set_duty(0); - *cx.local.buzzed = false; - } else { - let duty = cx.local.buzzer.get_max_duty() / 4; - cx.local.buzzer.set_duty(duty); - *cx.local.buzzed = true; - } - Mono::delay(2000.millis()).await; - } - } - } - - #[task(priority = 3, shared = [&em, sbg_power])] - async fn sleep_system(mut cx: sleep_system::Context) { - // Turn off the SBG and CAN, also start a timer to wake up the system. Put the chip in sleep mode. - cx.shared.sbg_power.lock(|sbg| { - sbg.set_low(); + config.rcc.pll3 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), + divr: None, }); - } + config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } + // config.rcc.ls = rcc::LsConfig::default_lse(); + let p = embassy_stm32::init(config); + + info!("Heap usage: {} bytes", HEAP.used()); + + // --- IMU Setup --- + // embassy_stm32::rcc::enable_and_reset::(); + // let mut spi_config = SpiConfig::default(); + // spi_config.frequency = mhz(1); // Max 10 MHz for IIM-20670 + // let mut imu_spi = Spi::new_blocking( + // p.SPI3, p.PB3, // SCK + // p.PB5, // MOSI + // p.PB4, // MISO + // spi_config, + // ); + // let imu_odr = Input::new(p.PC0, Pull::None); + // let imu_cs = Output::new(p.PA15, Level::Low, Speed::Low); + // let imu_nreset = Output::new(p.PD4, Level::High, Speed::Low); + // let imu_bus_ref = IMU_BUS_CELL.init(RefCell::new(imu_spi)); + // let imu_spi_device = RefCellDevice::new(imu_bus_ref, imu_cs, Delay).unwrap(); + // let mut imu = sensors::iim20670::Iim20670::new(imu_spi_device, Delay); + + // --- SBG Setup --- + let mut uart_config = UartConfig::default(); + uart_config.baudrate = 115200; + let usart = Uart::new( + p.UART4, + p.PA1, + p.PA0, + Irqs, + p.DMA1_CH1, + p.DMA1_CH0, + uart_config, + ) + .unwrap(); + let (tx, rx) = usart.split(); + let ring_rx = rx.into_ring_buffered(unsafe { &mut RX_SBG_BUF }); + let sbg_pwr = Output::new(p.PD8, Level::High, Speed::Low); + + // // --- Baro SPI Setup --- + let mut spi_config = SpiConfig::default(); + spi_config.frequency = mhz(16); + let spi_bus = Spi::new_blocking(p.SPI4, p.PE2, p.PE6, p.PE5, spi_config); + info!("SPI4 bus configured."); + let baro_cs = Output::new(p.PB8, Level::High, Speed::Low); + info!("Barometer CS pin configured."); + let baro = Ms5611::new(spi_bus, baro_cs, Delay).unwrap(); + + // --- SD Card --- + let sd_card: embedded_sdmmc::SdCard< + embedded_hal_bus::spi::RefCellDevice< + 'static, + Spi<'static, embassy_stm32::mode::Blocking>, + Output<'static>, + Delay, + >, + Delay, + > = sd::setup_sdmmc_interface(p.SPI1, p.PA5, p.PA7, p.PA6, p.PE9); + + // --- GPS Setup --- + let (ring_gps_rx, gps_tx) = sensors::gps::setup_gps( + p.PA4, p.PB2, p.UART8, p.PE0, p.PE1, p.DMA1_CH5, p.DMA1_CH6, Irqs, + ) + .await; + + // --- Recovery manager --- + let recovery_manager = RecoveryManager::new( + p.PD6, p.PD14, p.PC11, p.PD2, p.PD5, p.PD13, p.PC12, p.PD1, p.PA2, p.PB0, p.PA3, p.PC5, + p.ADC1, p.PC1, + ); + + RECOVERY_MANAGER.lock(|cell| { + *cell.borrow_mut() = Some(recovery_manager); + }); + + // --- Camera Triggers --- + // let mut cameras = Cameras::new(p.PE14, p.PE12); + + // cameras.start_recording(); + // Delay.delay_ms(10_000); + // cameras.stop_recording(); + // info!("Camera recording started and stopped."); + + // --- Buzzer 🐝 --- + let buzz_out_pin = PwmPin::new_ch1(p.PC6, OutputType::PushPull); + let mut pwm = SimplePwm::new( + p.TIM3, + Some(buzz_out_pin), + None, + None, + None, + khz(4), + Default::default(), + ); + let mut ch1 = pwm.ch1(); + info!("Duty Cycle: {}", ch1.max_duty_cycle()); + ch1.set_duty_cycle(ch1.max_duty_cycle() / 4); + ch1.enable(); + + // --- State Machine --- + let state_machine = StateMachine::new(state_machine::Context {}); + + // --- Radio --- + let (radio_tx, radio_ring_rx) = + communication::init_radio(p.UART7, p.PE7, p.PE8, p.DMA2_CH3, p.DMA2_CH5, Irqs); + + // --- Spawning Tasks --- + spawner.must_spawn(sensors::sbg_manager::uart_dma_reader_task(ring_rx)); + // spawner.must_spawn(sensors::gps::uart_gps_dma_reader_task(ring_gps_rx, gps_tx)); + spawner.must_spawn(sensors::sbg_manager::sbg_parser_task(tx)); + spawner.must_spawn(sensors::sbg_manager::sbg_receiver_task()); + spawner.must_spawn(sensors::baro::baro_reader_task(baro)); + // // spawner.must_spawn(ai::ai_task()); + // spawner.must_spawn(radio_reader_task(radio_ring_rx)); + spawner.must_spawn(radio_writer_task(radio_tx)); + spawner.must_spawn(sd::sdmmc_task(sd_card)); + // spawner.must_spawn(imu_task(imu)); + + // pass control of the spawner to the state machine + spawner.must_spawn(state_machine::sm_task(spawner, state_machine)); + + // // watch dog with 10 second timeout + // let mut watch_dog = IndependentWatchdog::new(p.IWDG1, 10_000); + // watch_dog.unleash(); + + info!("Device {} has started.", embassy_stm32::uid::uid_hex()); + music::play_song(&mut pwm, music::TWINKLE_MELODY, 1300).await; } diff --git a/phoenix/src/model.rs b/phoenix/src/model.rs new file mode 100644 index 0000000..0955d4c --- /dev/null +++ b/phoenix/src/model.rs @@ -0,0 +1,192 @@ +#![allow(dead_code)] +use burn::{ + module::Module, + nn::{ + Dropout, DropoutConfig, Initializer, LayerNorm, LayerNormConfig, Linear, LinearConfig, + LstmState, Sigmoid, Tanh, + }, + prelude::*, +}; +use heapless::Vec; + +// ================================================================================= +// This file is a `no_std` compatible version of the model used for training. +// The `StackedLstm` has been removed to be compatible with `#[derive(Module)]`. +// ================================================================================= + +// --- LstmCell --- +#[derive(Module, Debug)] +pub struct LstmCell { + pub hidden_size: usize, + pub weight_ih: Linear, + pub weight_hh: Linear, + pub norm_x: Option>, + pub norm_h: Option>, + pub norm_c: Option>, + pub dropout: Dropout, +} + +impl LstmCell { + pub fn new( + input_size: usize, + hidden_size: usize, + dropout: f64, + layer_norm: bool, + device: &B::Device, + ) -> Self { + let initializer = Initializer::XavierNormal { gain: 1.0 }; + let init_bias = Tensor::::ones([hidden_size], device); + + let mut weight_ih = LinearConfig::new(input_size, 4 * hidden_size) + .with_initializer(initializer.clone()) + .init(device); + let bias = weight_ih + .bias + .clone() + .unwrap() + .val() + .slice_assign([hidden_size..2 * hidden_size], init_bias.clone()); + weight_ih.bias = weight_ih.bias.map(|p| p.map(|_t| bias)); + + let mut weight_hh = LinearConfig::new(hidden_size, 4 * hidden_size) + .with_initializer(initializer) + .init(device); + let bias = weight_hh + .bias + .clone() + .unwrap() + .val() + .slice_assign([hidden_size..2 * hidden_size], init_bias); + weight_hh.bias = weight_hh.bias.map(|p| p.map(|_t| bias)); + + Self { + hidden_size, + weight_ih, + weight_hh, + norm_x: if layer_norm { + Some(LayerNormConfig::new(4 * hidden_size).init(device)) + } else { + None + }, + norm_h: if layer_norm { + Some(LayerNormConfig::new(hidden_size).init(device)) + } else { + None + }, + norm_c: if layer_norm { + Some(LayerNormConfig::new(hidden_size).init(device)) + } else { + None + }, + dropout: DropoutConfig::new(dropout).init(), + } + } + + pub fn forward(&self, x: Tensor, state: LstmState) -> LstmState { + let (h_prev, c_prev) = (state.hidden, state.cell); + let gates_x = self.weight_ih.forward(x); + let gates_h = self.weight_hh.forward(h_prev); + let gates_x = self + .norm_x + .as_ref() + .map_or(gates_x.clone(), |norm| norm.forward(gates_x)); + let gates = gates_x + gates_h; + let gates = gates.chunk(4, 1); + let i_t = Sigmoid::new().forward(gates[0].clone()); + let f_t = Sigmoid::new().forward(gates[1].clone()); + let g_t = Tanh::new().forward(gates[2].clone()); + let o_t = Sigmoid::new().forward(gates[3].clone()); + let c_t = f_t * c_prev + i_t * g_t; + let c_t = self + .norm_c + .as_ref() + .map_or(c_t.clone(), |norm| norm.forward(c_t)); + let h_t = o_t * Tanh::new().forward(c_t.clone()); + let h_t = self + .norm_h + .as_ref() + .map_or(h_t.clone(), |norm| norm.forward(h_t)); + let h_t = self.dropout.forward(h_t); + LstmState::new(h_t, c_t) + } + + pub fn init_state(&self, batch_size: usize, device: &B::Device) -> LstmState { + let cell = Tensor::zeros([batch_size, self.hidden_size], device); + let hidden = Tensor::zeros([batch_size, self.hidden_size], device); + LstmState::new(cell, hidden) + } +} + +// --- LstmNetwork --- +#[derive(Module, Debug)] +pub struct LstmNetwork { + pub layer_0: LstmCell, + pub layer_1: LstmCell, + pub dropout: Dropout, + pub fc: Linear, +} + +impl LstmNetwork { + pub fn new(device: &B::Device) -> Self { + const INPUT_SIZE: usize = 12; + const HIDDEN_SIZE: usize = 32; + const OUTPUT_SIZE: usize = 3; + const DROPOUT: f64 = 0.2; + const LAYER_NORM: bool = true; + + let layer_0 = LstmCell::new(INPUT_SIZE, HIDDEN_SIZE, DROPOUT, LAYER_NORM, device); + let layer_1 = LstmCell::new(HIDDEN_SIZE, HIDDEN_SIZE, 0.0, LAYER_NORM, device); + + let fc = LinearConfig::new(HIDDEN_SIZE, OUTPUT_SIZE).init(device); + let dropout = DropoutConfig::new(DROPOUT).init(); + + Self { + layer_0, + layer_1, + dropout, + fc, + } + } + + pub fn forward(&self, x: Tensor) -> Tensor { + let [batch_size, seq_length, _] = x.dims(); + let device = x.device(); + + // This avoids the need for cloning and resolves the compiler error. + let state_0 = self.layer_0.init_state(batch_size, &device); + let state_1 = self.layer_1.init_state(batch_size, &device); + + // Layer 0 forward pass + let (output_0, _) = self.run_layer(x, state_0, &self.layer_0); + + // Layer 1 forward pass + let (output_1, _) = self.run_layer(output_0, state_1, &self.layer_1); + + let output = self.dropout.forward(output_1); + self.fc.forward( + output + .slice([0..batch_size, seq_length - 1..seq_length]) + .squeeze(1), + ) + } + + // Helper function to run a single LSTM layer over a sequence + fn run_layer( + &self, + x: Tensor, + mut state: LstmState, + layer: &LstmCell, + ) -> (Tensor, LstmState) { + let [batch_size, seq_length, _] = x.dims(); + let mut outputs: Vec, 50> = Vec::new(); // 50 is SEQ_LENGTH + + for t in 0..seq_length { + let input_t = x.clone().slice([0..batch_size, t..t + 1]).squeeze(1); + state = layer.forward(input_t, state); + outputs.push(state.hidden.clone()).ok(); + } + + let stacked_output: Tensor = Tensor::stack(outputs.into_iter().collect(), 1); + (stacked_output, state) + } +} diff --git a/phoenix/src/models/model.bin b/phoenix/src/models/model.bin new file mode 100644 index 0000000..5fdd725 Binary files /dev/null and b/phoenix/src/models/model.bin differ diff --git a/phoenix/src/music.rs b/phoenix/src/music.rs new file mode 100644 index 0000000..833556c --- /dev/null +++ b/phoenix/src/music.rs @@ -0,0 +1,94 @@ +use embassy_stm32::time::Hertz; +use embassy_stm32::timer::simple_pwm::SimplePwm; +use embassy_time::{Duration, Timer}; + +// --- Melody Definitions --- + +// A rest note (silence) +const REST: u16 = 0; + +// Frequencies (in Hz) for the notes in the Super Mario Bros. theme +const NOTE_E5: u16 = 659; +const NOTE_C5: u16 = 523; +const NOTE_G5: u16 = 784; +const NOTE_G4: u16 = 392; + +// Frequencies for "Twinkle, Twinkle, Little Star" +const NOTE_C4: u16 = 262; +const NOTE_D4: u16 = 294; +const NOTE_E4: u16 = 330; +const NOTE_F4: u16 = 349; +const NOTE_A4: u16 = 440; + +/// Melody for the first part of the Super Mario Bros. theme. +/// Each tuple is (note_frequency, duration_in_beats). +pub const MARIO_MELODY: &[(u16, f32)] = &[ + (NOTE_E5, 1.0), + (NOTE_E5, 1.0), + (REST, 1.0), + (NOTE_E5, 1.0), + (REST, 1.0), + (NOTE_C5, 1.0), + (NOTE_E5, 1.0), + (REST, 1.0), + (NOTE_G5, 2.0), + (REST, 2.0), + (NOTE_G4, 2.0), + (REST, 2.0), +]; + +/// Melody for "Twinkle, Twinkle, Little Star" +pub const TWINKLE_MELODY: &[(u16, f32)] = &[ + (NOTE_C4, 1.0), + (NOTE_C4, 1.0), + (NOTE_G4, 1.0), + (NOTE_G4, 1.0), + (NOTE_A4, 1.0), + (NOTE_A4, 1.0), + (NOTE_G4, 2.0), + (REST, 0.5), + (NOTE_F4, 1.0), + (NOTE_F4, 1.0), + (NOTE_E4, 1.0), + (NOTE_E4, 1.0), + (NOTE_D4, 1.0), + (NOTE_D4, 1.0), + (NOTE_C4, 2.0), +]; + +/// A helper function to play a song on a PWM channel. +/// +/// * `pwm`: The SimplePwm instance for the timer connected to the buzzer. +/// * `melody`: A slice of (frequency, duration) tuples representing the song. +/// * `tempo_bpm`: The speed of the song in Beats Per Minute (BPM). +pub async fn play_song<'a, T: embassy_stm32::timer::GeneralInstance4Channel>( + pwm: &mut SimplePwm<'a, T>, + melody: &[(u16, f32)], + tempo_bpm: u64, +) { + // Calculate the duration of a single beat from the tempo + let beat_duration_ms = 60_000 / tempo_bpm; + let max_duty = pwm.max_duty_cycle(); + + // Set a 50% duty cycle for a nice, loud sound + pwm.ch1().set_duty_cycle(max_duty / 2); + + for &(note_freq, duration_beats) in melody { + let note_duration_ms = (duration_beats * beat_duration_ms as f32) as u64; + + if note_freq == REST { + // For a rest, disable the channel to produce silence + pwm.ch1().disable(); + } else { + // For a note, set the correct frequency and enable the channel + pwm.set_frequency(Hertz::hz(note_freq as u32)); + pwm.ch1().enable(); + } + + // Wait for the duration of the note/rest + Timer::after(Duration::from_millis(note_duration_ms)).await; + } + + // Stop the sound after the melody is over + pwm.ch1().disable(); +} diff --git a/phoenix/src/recovery.rs b/phoenix/src/recovery.rs new file mode 100644 index 0000000..3931107 --- /dev/null +++ b/phoenix/src/recovery.rs @@ -0,0 +1,486 @@ +use defmt::info; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::peripherals::{ + ADC1, PA2, PA3, PB0, PC1, PC11, PC12, PC5, PD1, PD13, PD14, PD2, PD5, PD6, +}; +use embassy_time::{Instant, Timer}; +use embedded_hal_1::delay::DelayNs; +use embedded_hal_1::digital::OutputPin; +use heapless::{HistoryBuffer, Vec}; +use libm::powf; + +use crate::resources::{EVENT_CHANNEL, PRESSURE_CHANNEL}; + +pub const MAIN_HEIGHT: f32 = GROUND_HEIGHT + 450.0; // meters ASL +pub const HEIGHT_MIN: f32 = GROUND_HEIGHT + 300.0; // meters ASL +const GROUND_HEIGHT: f32 = 300.0; // meters ASL +const ASCENT_LOCKOUT: f32 = 0.01; +pub const DATA_POINTS: usize = 15; +pub const SLOPES: usize = 14; +const VALID_DESCENT_RATE: f32 = -0.005; // meters per millise + +// --- Boom Boom Setup --- +/* + MAIN_ARM/TEST = PD6 + MAIN_FIRE = PD5 + MAIN_ARM/TEST_B = PD14 + MAIN_FIRE_B = PD13 + DROGUE_ARM/TEST = PC11 + DROGUE_FIRE = PC12 + DROGUE_ARM/TEST_B = PD2 + DROGUE_FIRE_B = PD1 + MAIN_MCU_EMATCH_SENSE = PA2 + MAIN_MCU_EMATCH_SENSE_B = PB0 + DROUGE_MCU_EMATCH_SENSE = PA3 + DROGUE_MCU_EMATCH_SENSE_B = PC5 +*/ + +struct Arming { + main: Output<'static>, + drogue: Output<'static>, + main_b: Output<'static>, + drogue_b: Output<'static>, +} + +struct Fire { + main: Output<'static>, + drogue: Output<'static>, + main_b: Output<'static>, + drogue_b: Output<'static>, +} + +struct Sensing { + adc: embassy_stm32::peripherals::ADC1, + main: PA2, + main_b: PB0, + drogue: PA3, + drogue_b: PC5, +} + +pub struct RecoveryManager { + ejection_enable: Input<'static>, + sensing: Sensing, + arming: Arming, + fire: Fire, +} + +impl RecoveryManager { + pub fn new( + main_arm: PD6, + main_arm_b: PD14, + drogue_arm: PC11, + drogue_arm_b: PD2, + main_fire: PD5, + main_fire_b: PD13, + drogue_fire: PC12, + drogue_fire_b: PD1, + main_sense: PA2, + main_b_sense: PB0, + drogue_sense: PA3, + drogue_sense_b: PC5, + adc: ADC1, + ejection_enable: PC1, + ) -> Self { + RecoveryManager { + ejection_enable: Input::new(ejection_enable, Pull::Down), + sensing: Sensing { + adc, + main: main_sense, + main_b: main_b_sense, + drogue: drogue_sense, + drogue_b: drogue_sense_b, + }, + arming: Arming { + main: Output::new(main_arm, Level::Low, Speed::Low), + main_b: Output::new(main_arm_b, Level::Low, Speed::Low), + drogue: Output::new(drogue_arm, Level::Low, Speed::Low), + drogue_b: Output::new(drogue_arm_b, Level::Low, Speed::Low), + }, + fire: Fire { + main: Output::new(main_fire, Level::Low, Speed::Low), + main_b: Output::new(main_fire_b, Level::Low, Speed::Low), + drogue: Output::new(drogue_fire, Level::Low, Speed::Low), + drogue_b: Output::new(drogue_fire_b, Level::Low, Speed::Low), + }, + } + } + + pub fn arm(&mut self) { + if self.ejection_enable.is_high() { + info!("arm ejection enabled"); + self.arming.main.set_high(); + self.arming.main_b.set_high(); + + self.arming.drogue.set_high(); + self.arming.drogue_b.set_high(); + } + } + + pub fn is_armed(&mut self) -> bool { + self.ejection_enable.is_high() + } + + pub fn disarm(&mut self) { + info!("arm ejection disabled"); + self.arming.main.set_low(); + self.arming.main_b.set_low(); + + self.arming.drogue.set_low(); + self.arming.drogue_b.set_low(); + } + + pub fn fire_main(&mut self) { + self.fire.main.set_high(); + self.fire.main_b.set_high(); + embassy_time::Delay.delay_ms(1000); + self.fire.main.set_low(); + self.fire.main_b.set_low(); + } + + pub fn fire_drogue(&mut self) { + self.fire.drogue.set_high(); + self.fire.drogue_b.set_high(); + embassy_time::Delay.delay_ms(1000); + self.fire.drogue.set_low(); + self.fire.drogue_b.set_low(); + } +} + +// #[embassy_executor::task] +// pub async fn recovery_algorithm_task() { +// info!("Barometer reader task started."); + +// // History buffers to store recent altitude readings from two different sources. +// // Each entry is a tuple of (altitude, timestamp). +// let mut historical_barometer_altitude_sbg: HistoryBuffer<(f32, Instant), 20> = +// HistoryBuffer::new(); +// let mut historical_barometer_altitude_baro: HistoryBuffer<(f32, Instant), 20> = +// HistoryBuffer::new(); + +// // These flags are declared but not used in the provided snippet. +// // They might be intended for logic to ignore faulty sensors. +// let ignore_baro = false; +// let ignore_sbg = false; + +// loop { +// // Flags to track apogee detection, not used in the provided logic. +// let baro_apogee_detected = false; +// let sbg_apogee_detected = false; + +// // Wait for a new pressure reading from the channel. +// // The reading includes pressure, temperature, a source identifier, and a timestamp. +// let reading: (f32, f32, u8, Instant) = PRESSURE_CHANNEL.receive().await; + +// // This variable will hold the calculated altitude. +// let mut altitude = 0.0; + +// // Process the reading based on its source identifier. +// if reading.2 == 1 { // Source is the barometer (baro) +// // Hypsometric Formula to convert pressure and temperature to altitude. +// altitude = +// ((powf(101.325 / reading.0, 1.0 / 5.257) - 1.0) * (reading.1 + 273.15)) / 0.0065; +// historical_barometer_altitude_baro.write((altitude, reading.3)); +// } else if reading.2 == 0 { // Source is the SBG +// info!("SBG Altitude data {}, {}", reading.0, reading.3); +// altitude = reading.0; // SBG provides altitude directly. +// historical_barometer_altitude_sbg.write((altitude, reading.3)); +// } + +// // --- Apogee Detection Logic --- +// // Ensure there are enough data points in the buffer to perform a reliable calculation. +// if historical_barometer_altitude_sbg.len() < 8 { +// info!("Not enough SBG data points to detect apogee."); +// continue; +// } + +// // Get an ordered iterator over the historical data. +// let mut buf_sbg = historical_barometer_altitude_sbg.oldest_ordered(); +// let mut buf_baro = historical_barometer_altitude_baro.oldest_ordered(); + +// // --- SBG Apogee Check --- +// if let Some(mut prev_reading) = buf_sbg.next() { +// let mut avg_sum: f32 = 0.0; +// let mut datapoints_used = 0; + +// for current_reading in buf_sbg { +// // Calculate the time difference between measurements in milliseconds. +// let time_diff_ms = (current_reading.1.as_millis() - prev_reading.1.as_millis()); +// info!("time diff: {}", time_diff_ms); +// if time_diff_ms == 0 { +// continue; // Avoid division by zero. +// } + +// // Calculate slope (vertical speed) and immediately convert it to m/s. +// // Formula: (delta_altitude_meters / delta_time_ms) * 1000 ms/s = speed_m/s +// let slope_mps = ((current_reading.0 - prev_reading.0) / time_diff_ms as f32); +// info!("SBG Slope: {} m/s", slope_mps); + +// // Lockout check: if the rocket is ascending too fast, ignore this data point. +// // This assumes ASCENT_LOCKOUT is defined in m/s. +// if slope_mps > ASCENT_LOCKOUT { +// continue; +// } + +// avg_sum += slope_mps; +// datapoints_used += 1; +// prev_reading = current_reading; // Update for the next iteration. +// } + +// // Check if we have enough valid data points for an average. +// if datapoints_used >= DATA_POINTS / 2 { +// let avg_slope_mps = avg_sum / (datapoints_used as f32); + +// // Apogee condition: if the average vertical speed indicates a sufficient descent. +// // This assumes VALID_DESCENT_RATE is a negative value in m/s (e.g., -5.0). +// if avg_slope_mps <= VALID_DESCENT_RATE { +// info!( +// "SBG Apogee detected! Average vertical speed: {} m/s", +// avg_slope_mps +// ); +// // Send an Apogee event to the state machine. +// if EVENT_CHANNEL.try_send(crate::state_machine::Events::Apogee).is_err() { +// // If sending fails, log it. This is a critical failure. +// todo!("Log failure to radio"); +// } +// break; // Exit the loop once apogee is detected. +// } +// } +// } + +// // --- Barometer Apogee Check --- +// // This logic is duplicated for the second sensor. +// if let Some(mut prev_reading) = buf_baro.next() { +// let mut avg_sum: f32 = 0.0; +// let mut datapoints_used = 0; + +// for current_reading in buf_baro { +// let time_diff_ms = current_reading.1.as_millis() - prev_reading.1.as_millis(); + +// if time_diff_ms == 0 { +// continue; +// } + +// // Calculate and convert slope to m/s, same as for the SBG. +// let slope_mps = ((current_reading.0 - prev_reading.0) / time_diff_ms as f32) * 1000.0; +// // info!("Baro Slope: {} m/s", slope_mps); + +// if slope_mps > ASCENT_LOCKOUT { +// continue; +// } + +// avg_sum += slope_mps; +// datapoints_used += 1; +// prev_reading = current_reading; +// } + +// if datapoints_used >= DATA_POINTS / 2 { +// let avg_slope_mps = avg_sum / (datapoints_used as f32); + +// if avg_slope_mps <= VALID_DESCENT_RATE { +// // info!( +// // "Baro Apogee detected! Average vertical speed: {} m/s", +// // avg_slope_mps +// // ); +// // Consider sending the Apogee event here as well, or having a voting system. +// } +// } +// } +// } +// } + + +#[embassy_executor::task] +pub async fn recovery_algorithm_task() { + info!("Barometer reader task started."); + + // --- CONFIGURATION CONSTANTS --- + // The number of consecutive negative slope readings required to confirm descent. + const CONSECUTIVE_NEGATIVE_THRESHOLD: usize = 5; + + // History buffers to store recent altitude readings from two different sources. + // Each entry is a tuple of (altitude, timestamp). + let mut historical_barometer_altitude_sbg: HistoryBuffer<(f32, Instant), DATA_POINTS> = + HistoryBuffer::new(); + let mut historical_barometer_altitude_baro: HistoryBuffer<(f32, Instant), DATA_POINTS> = + HistoryBuffer::new(); + + loop { + // Wait for a new pressure reading from the channel. + let reading: (f32, f32, u8, Instant) = PRESSURE_CHANNEL.receive().await; + + // This variable will hold the calculated altitude. + + // Process the reading based on its source identifier. + if reading.2 == 1 { + // Source is the barometer (baro) + // Hypsometric Formula to convert pressure and temperature to altitude. + let altitude = + ((powf(101.325 / reading.0, 1.0 / 5.257) - 1.0) * (reading.1 + 273.15)) / 0.0065; + historical_barometer_altitude_baro.write((altitude, reading.3)); + + // --- DEBUG PRINT: Show the current data buffer --- + let altitude_history_for_print: Vec<_, DATA_POINTS> = historical_barometer_altitude_baro + .oldest_ordered() + .map(|(alt, _)| alt) + .collect(); + // info!("[BARO] Altitude History: {:?}", altitude_history_for_print.as_slice()); + + + let mut buf_baro = historical_barometer_altitude_baro.oldest_ordered(); + + // --- Barometer Apogee Check (Identical logic) --- + if let Some(mut prev_reading) = buf_baro.next() { + let mut slopes: HistoryBuffer = HistoryBuffer::new(); + + for current_reading in buf_baro { + let time_diff_ms = current_reading.1.duration_since(prev_reading.1).as_millis(); + let alt_diff = current_reading.0 - prev_reading.0; + + // --- DEBUG PRINT: Show inputs for slope calculation --- + // info!("[BARO] Slope calc: alt_diff={}, time_diff={} ms", alt_diff, time_diff_ms); + + if time_diff_ms > 0 { + let slope_mpms = alt_diff / time_diff_ms as f32; + + // --- DEBUG PRINT: Show the calculated slope --- + // info!("[BARO] -> New Slope: {} m/ms ({} m/s)", slope_mpms, slope_mpms * 1000.0); + slopes.write(slope_mpms); + } else { + // --- DEBUG PRINT: Indicate when a calculation is skipped --- + // info!("[BARO] -> Skipping slope calc: time_diff_ms is 0"); + } + prev_reading = current_reading; + } + + if slopes.len() >= CONSECUTIVE_NEGATIVE_THRESHOLD { + let slopes_vec: Vec<_, DATA_POINTS> = slopes.oldest_ordered().collect(); + + // --- DEBUG PRINT: Show the buffer of slopes being evaluated --- + // info!("[BARO] Slopes buffer for check: {:?}", slopes_vec.as_slice()); + + let mut consecutive_negative_count = 0; + let mut sum_of_recent_slopes = 0.0; + + for slope in slopes_vec.iter().rev().take(CONSECUTIVE_NEGATIVE_THRESHOLD) { + if **slope <= 0.0 { + consecutive_negative_count += 1; + sum_of_recent_slopes += *slope; + } else { + break; + } + } + + // --- DEBUG PRINT: Show the result of the consecutive check --- + // info!("[BARO] Consecutive negative count: {}", consecutive_negative_count); + + + if consecutive_negative_count == CONSECUTIVE_NEGATIVE_THRESHOLD { + let avg_slope_mpms = + sum_of_recent_slopes / CONSECUTIVE_NEGATIVE_THRESHOLD as f32; + + if avg_slope_mpms <= VALID_DESCENT_RATE { + // info!( + // "Baro Apogee detected! Avg speed of last {} readings: {} m/s", + // CONSECUTIVE_NEGATIVE_THRESHOLD, + // avg_slope_mpms * 1000.0 + // ); + // Consider sending event or using a voting system with the SBG. + } + } + } + } + } else if reading.2 == 0 { + // Source is the SBG + let altitude = reading.0; + // info!("Altitude: {}", altitude); + historical_barometer_altitude_sbg.write((altitude, reading.3)); + + // --- Apogee Detection Logic --- + // Ensure there are enough data points in the buffer to perform a reliable calculation. + if historical_barometer_altitude_sbg.len() < DATA_POINTS { + continue; + } + + // --- DEBUG PRINT: Show the current data buffer --- + let altitude_history_for_print: Vec<_, DATA_POINTS> = historical_barometer_altitude_sbg + .oldest_ordered() + .map(|(alt, _)| alt) + .collect(); + // info!("[SBG] Altitude History: {:?}", altitude_history_for_print.as_slice()); + + let mut buf_sbg = historical_barometer_altitude_sbg.oldest_ordered(); + + // --- SBG Apogee Check --- + if let Some(mut prev_reading) = buf_sbg.next() { + let mut slopes: HistoryBuffer = HistoryBuffer::new(); + + for current_reading in buf_sbg { + let time_diff_ms = current_reading.1.duration_since(prev_reading.1).as_millis(); + let alt_diff = current_reading.0 - prev_reading.0; + + // --- DEBUG PRINT: Show inputs for slope calculation --- + // info!("[SBG] Slope calc: alt_diff={}, time_diff={} ms", alt_diff, time_diff_ms); + + if time_diff_ms > 0 { + let slope_mpms = alt_diff / time_diff_ms as f32; + + // --- DEBUG PRINT: Show the calculated slope --- + // info!("[SBG] -> New Slope: {} m/ms ({} m/s)", slope_mpms, slope_mpms * 1000.0); + slopes.write(slope_mpms); + } else { + // --- DEBUG PRINT: Indicate when a calculation is skipped --- + // info!("[SBG] -> Skipping slope calc: time_diff_ms is 0"); + } + prev_reading = current_reading; + } + + if slopes.len() >= CONSECUTIVE_NEGATIVE_THRESHOLD { + let slopes_vec: Vec<_, DATA_POINTS> = slopes.oldest_ordered().collect(); + + // --- DEBUG PRINT: Show the buffer of slopes being evaluated --- + // info!("[SBG] Slopes buffer for check: {:?}", slopes_vec.as_slice()); + + let mut consecutive_negative_count = 0; + let mut sum_of_recent_slopes = 0.0; + + for slope in slopes_vec.iter().rev().take(CONSECUTIVE_NEGATIVE_THRESHOLD) { + if **slope <= 0.0 { + consecutive_negative_count += 1; + sum_of_recent_slopes += *slope; + } else { + break; + } + } + + // --- DEBUG PRINT: Show the result of the consecutive check --- + // info!("[SBG] Consecutive negative count: {}", consecutive_negative_count); + + + if consecutive_negative_count == CONSECUTIVE_NEGATIVE_THRESHOLD { + let avg_slope_mpms = + sum_of_recent_slopes / CONSECUTIVE_NEGATIVE_THRESHOLD as f32; + + if avg_slope_mpms <= VALID_DESCENT_RATE { + // info!( + // "SBG Apogee detected! Avg speed of last {} readings: {} m/s", + // CONSECUTIVE_NEGATIVE_THRESHOLD, + // avg_slope_mpms// Convert to m/s for logging + // ); + + if EVENT_CHANNEL + .try_send(crate::state_machine::Events::Apogee) + .is_err() + { + // todo!("Log failure to radio"); + } + break; // Exit loop once apogee is detected. + } + } + } + } + } + + Timer::after_millis(100).await; + } + info!("Recovery task ended"); +} diff --git a/phoenix/src/resources.rs b/phoenix/src/resources.rs new file mode 100644 index 0000000..195e3d0 --- /dev/null +++ b/phoenix/src/resources.rs @@ -0,0 +1,77 @@ +// ================================================================================= +// Shared Resources & Types +// ================================================================================= + +use crate::recovery; +use crate::state_machine::Events; +use burn::backend::NdArray; +use core::cell::RefCell; +use embassy_stm32::rtc::Rtc; +use embassy_stm32::spi::Spi; +use embassy_stm32::{bind_interrupts, mode, peripherals, usart}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::channel::Channel; +use embassy_time::Instant; +use embedded_alloc::LlffHeap as Heap; +use messages_prost::sbg::SbgData; +use sbg_rs::sbg::SBG_BUFFER_SIZE; +use static_cell::StaticCell; + +pub type Backend = NdArray; +pub type BackendDevice = ::Device; + +type DmaBuffer = [u8; SBG_BUFFER_SIZE]; + +pub const GPS_BUFFER_SIZE: usize = 128; + +pub const RADIO_BUFFER_SIZE: usize = 255; + +pub const SD_BUFFER_SIZE: usize = 255; + +#[global_allocator] +pub static HEAP: Heap = Heap::empty(); + +pub static PRESSURE_CHANNEL: Channel = + Channel::new(); +pub static SD_CHANNEL: Channel = + Channel::new(); // file name, data +pub static SBG_CHANNEL: Channel = Channel::new(); +pub static BUFFER_CHANNEL: Channel = Channel::new(); +pub static EVENT_CHANNEL: Channel = Channel::new(); + +pub static COMMAND_CHANNEL: Channel< + CriticalSectionRawMutex, + messages_prost::command::command::Data, + 2, +> = Channel::new(); +pub static RADIO_CHANNEL: Channel = + Channel::new(); +#[link_section = ".axisram.buffers"] +pub static mut RX_SBG_BUF: [u8; SBG_BUFFER_SIZE] = [0; SBG_BUFFER_SIZE]; + +#[link_section = ".axisram.buffers"] +pub static mut RX_RADIO_BUF: [u8; SBG_BUFFER_SIZE] = [0; SBG_BUFFER_SIZE]; + +#[link_section = ".axisram.buffers"] +pub static mut RX_GPS_BUF: [u8; GPS_BUFFER_SIZE] = [0; GPS_BUFFER_SIZE]; +// The SPI bus is protected by a Mutex, so the RefCell is not needed. +pub static SPI_BUS: StaticCell< + embassy_sync::mutex::Mutex>, +> = StaticCell::new(); +pub static SPI_BUS_CELL: StaticCell>> = StaticCell::new(); + +// Static variable for the RTC +pub static RTC: Mutex>> = + Mutex::new(RefCell::new(None)); + +pub static RECOVERY_MANAGER: Mutex< + CriticalSectionRawMutex, + RefCell>, +> = Mutex::new(RefCell::new(None)); + +bind_interrupts!(pub struct Irqs { + UART4 => usart::InterruptHandler; + UART8 => usart::InterruptHandler; + UART7 => usart::InterruptHandler; +}); diff --git a/phoenix/src/sd.rs b/phoenix/src/sd.rs new file mode 100644 index 0000000..3ab62eb --- /dev/null +++ b/phoenix/src/sd.rs @@ -0,0 +1,101 @@ +use crate::resources::{SD_CHANNEL, SPI_BUS_CELL}; +use core::cell::RefCell; +use core::marker::PhantomData; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::mode::Blocking; +use embassy_stm32::peripherals::{PA5, PA6, PA7, PE9, SPI1}; +use embassy_stm32::spi::{BitOrder, Spi}; +use embassy_stm32::time::mhz; +use embassy_time::Delay; +use embedded_hal_bus::spi::RefCellDevice; +use embedded_sdmmc::{BlockDevice, SdCard, VolumeManager}; + +pub struct TimeSink { + _marker: PhantomData<*const ()>, +} + +impl TimeSink { + fn new() -> Self { + TimeSink { + _marker: PhantomData, + } + } +} + +impl embedded_sdmmc::TimeSource for TimeSink { + fn get_timestamp(&self) -> embedded_sdmmc::Timestamp { + embedded_sdmmc::Timestamp { + year_since_1970: 0, + zero_indexed_month: 0, + zero_indexed_day: 0, + hours: 0, + minutes: 0, + seconds: 0, + } + } +} + +pub fn setup_sdmmc_interface( + spi: SPI1, + sck: PA5, + mosi: PA7, + miso: PA6, + cs: PE9, +) -> SdCard, Output<'static>, Delay>, Delay> { + let mut sd_spi_config = embassy_stm32::spi::Config::default(); + + sd_spi_config.frequency = mhz(16); + sd_spi_config.bit_order = BitOrder::MsbFirst; + + let mut sd_spi_bus = Spi::new_blocking(spi, sck, mosi, miso, sd_spi_config); + + let sd_cs = Output::new(cs, Level::High, Speed::Low); + let data: [u8; 10] = [0xFF; 10]; + sd_spi_bus.blocking_write(&data).unwrap(); + // + // let sd_spi_bus_ref_cell = RefCell::new(sd_spi_bus); + // let sd_spi_device = RefCellDevice::new(&sd_spi_bus_ref_cell, sd_cs, Delay); + let spi_bus_ref = SPI_BUS_CELL.init(RefCell::new(sd_spi_bus)); + let sd_spi_device = RefCellDevice::new(spi_bus_ref, sd_cs, Delay).unwrap(); + + SdCard::new(sd_spi_device, Delay) +} + +#[embassy_executor::task] +pub async fn sdmmc_task( + sd: embedded_sdmmc::SdCard< + embedded_hal_bus::spi::RefCellDevice< + 'static, + Spi<'static, embassy_stm32::mode::Blocking>, + Output<'static>, + Delay, + >, + Delay, + >, +) { + // setup the directory object + let volume_mgr = VolumeManager::new(sd, TimeSink::new()); + if let Ok(volume0) = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0)) { + // should never fail + let root_dir = volume0.open_root_dir().unwrap(); + + loop { + let (file, data) = SD_CHANNEL.receive().await; + if let Ok(file) = + root_dir.open_file_in_dir(file, embedded_sdmmc::Mode::ReadWriteCreateOrAppend) + { + match file.write(&data) { + Err(_) => { + // todo!("Log to radio we failed to write."); + } + _ => {} + } + file.flush(); + } + } + } else { + // Log to the radio in the event this happens. + // Could trigger the fault state. + todo!("Write to the radio Fault"); + }; +} diff --git a/phoenix/src/sensors/baro.rs b/phoenix/src/sensors/baro.rs new file mode 100644 index 0000000..befa05c --- /dev/null +++ b/phoenix/src/sensors/baro.rs @@ -0,0 +1,45 @@ +use common_arm::drivers::ms5611::{Ms5611, OversamplingRatio}; +use defmt::{error, info}; +use embassy_stm32::gpio::Output; +use embassy_stm32::mode::Blocking; +use embassy_stm32::spi::Spi; +use embassy_time::Instant; +use embassy_time::{Delay, Duration, Timer}; +use messages_prost::prost::Message; + +use crate::resources::PRESSURE_CHANNEL; +use crate::resources::{RADIO_CHANNEL, SD_CHANNEL}; + +#[embassy_executor::task] +pub async fn baro_reader_task(mut baro: Ms5611, Output<'static>, Delay>) { + info!("Barometer reader task started."); + + loop { + match baro.read_pressure_temperature(OversamplingRatio::Osr4096) { + Ok(reading) => { + // pressure, temperature + + PRESSURE_CHANNEL.try_send((reading.1, reading.0, 1, embassy_time::Instant::now())); + let mut buf: [u8; 255] = [0; 255]; + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::Barometer( + messages_prost::sensor::ms5611::Barometer { + pressure_kpa: reading.1, + temperature_celsius: reading.0, + }, + )), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()) + .expect("Failed to encode SBG GPS Position"); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("baro.txt", buf)).await; + } + Err(e) => { + error!("Baro: Driver reading failed"); + } + } + Timer::after(Duration::from_millis(10)).await; + } +} diff --git a/phoenix/src/sensors/gps.rs b/phoenix/src/sensors/gps.rs new file mode 100644 index 0000000..efeded5 --- /dev/null +++ b/phoenix/src/sensors/gps.rs @@ -0,0 +1,333 @@ +// use crate::resources::{Irqs, GPS_BUFFER_SIZE, RX_GPS_BUF, SD_CHANNEL}; +// use defmt::info; +// use embassy_stm32::gpio::{Level, Output, Speed}; +// use embassy_stm32::mode; +// use embassy_stm32::peripherals::{DMA1_CH5, DMA1_CH6, PA4, PB2, PE0, PE1, UART8}; +// use embassy_stm32::usart::{Config, RingBufferedUartRx, Uart, UartTx}; +// use embassy_time::{Delay, Instant}; +// use embedded_hal_1::delay::DelayNs; +// use messages_prost::gps::Gps; +// use ublox::cfg_val::CfgVal; +// use ublox::{ +// CfgLayerSet, CfgPrtUartBuilder, CfgRstBuilder, CfgValSetBuilder, DataBits, InProtoMask, +// NavBbrMask, OutProtoMask, Parity, ResetMode, StopBits, UartMode, UartPortId, UbxPacketRequest, +// }; +// use messages_prost::prost::Message; +// use crate::resources::RADIO_CHANNEL; + +// pub async fn setup_gps( +// gps_enable: PA4, +// gps_reset: PB2, +// uart: UART8, +// rx: PE0, +// tx: PE1, +// tx_dma: DMA1_CH5, +// rx_dma: DMA1_CH6, +// irqs: Irqs, +// ) -> (RingBufferedUartRx<'static>, UartTx<'static, mode::Async>) { +// let mut gps_enable = Output::new(gps_enable, Level::High, Speed::Low); +// let mut gps_reset = Output::new(gps_reset, Level::High, Speed::Low); +// let mut uart_gps_config = Config::default(); +// uart_gps_config.baudrate = 9600; +// uart_gps_config.data_bits = embassy_stm32::usart::DataBits::DataBits8; +// uart_gps_config.parity = embassy_stm32::usart::Parity::ParityNone; +// uart_gps_config.stop_bits = embassy_stm32::usart::StopBits::STOP1; +// uart_gps_config.detect_previous_overrun = false; + +// let uart_gps = Uart::new(uart, rx, tx, irqs, tx_dma, rx_dma, uart_gps_config).unwrap(); + +// let (mut gps_tx, gps_rx) = uart_gps.split(); +// let ring_gps_rx = gps_rx.into_ring_buffered(unsafe { &mut RX_GPS_BUF }); +// gps_reset.set_low(); +// Delay.delay_ms(3000); +// gps_reset.set_high(); +// gps_enable.set_low(); +// Delay.delay_ms(2000); +// let packet: [u8; 28] = CfgPrtUartBuilder { +// portid: UartPortId::Uart1, +// reserved0: 0, +// tx_ready: 0, +// mode: UartMode::new(DataBits::Eight, Parity::None, StopBits::One), +// baud_rate: 9600, +// in_proto_mask: InProtoMask::all(), +// out_proto_mask: OutProtoMask::UBLOX, +// flags: 0, +// reserved5: 0, +// } +// .into_packet_bytes(); + +// info!("Sending GPS packet: {:?}", &packet); +// gps_tx.write(&packet).await.expect("TODO: panic message"); + +// // Delay.delay_ms(2000); + +// // let config_packet = CfgValSetBuilder { +// // version: 1, +// // // Save to RAM (to apply now) and BBR (to make it persistent) +// // layers: CfgLayerSet::BBR | CfgLayerSet::RAM, +// // reserved1: 0, +// // cfg_data: &[ +// // // --- Port Settings --- +// // CfgVal::Uart1Baudrate(38400), +// // CfgVal::Uart1InProtUbx(true), +// // CfgVal::Uart1InProtNmea(false), // Explicitly disable NMEA +// // CfgVal::Uart1InProtRtcm3x(false), +// // CfgVal::Uart1OutProtUbx(true), +// // CfgVal::Uart1OutProtNmea(false), // Explicitly disable NMEA +// // // --- Message Settings --- +// // CfgVal::MsgOutUbxNavPvtUart1(1), // Enable NAV-PVT on UART1 +// // // --- Rate Settings --- +// // CfgVal::RateMeas(200), // 200ms = 5Hz +// // CfgVal::RateNav(1), // Navigation rate = Measurement rate +// // ], +// // } +// // .into_packet_vec(); + +// // gps_tx +// // .write(config_packet.as_slice()) +// // .await +// // .expect("TODO: panic message"); + +// // Delay.delay_ms(1000); + +// // let reset_packet = CfgRstBuilder { +// // nav_bbr_mask: NavBbrMask::empty(), // .empty() preserves all BBR data +// // reset_mode: ResetMode::ControlledSoftwareReset, +// // reserved1: 0, +// // } +// // .into_packet_bytes(); + +// // info!("Sending software reset to apply configuration"); +// // gps_tx.write(&reset_packet).await.unwrap(); +// // Delay.delay_ms(500); // Give module time to reset +// (ring_gps_rx, gps_tx) +// } + +// #[embassy_executor::task] +// pub async fn uart_gps_dma_reader_task( +// mut gps_rx: RingBufferedUartRx<'static>, +// mut gps_tx: UartTx<'static, mode::Async>, +// ) { +// info!("GPS reader task spawned."); +// loop { +// let request = +// ublox::UbxPacketRequest::request_for::().into_packet_bytes(); +// info!("gps write"); +// gps_tx.write(&request).await; +// let mut buf_data: [u8; GPS_BUFFER_SIZE] = [0; GPS_BUFFER_SIZE]; +// info!("gps read"); +// gps_rx.read(&mut buf_data).await; +// info!("GPS data read: {:?}", &buf_data[..]); +// let buf: [u8; GPS_BUFFER_SIZE] = [0; GPS_BUFFER_SIZE]; +// let bytes: [u8; GPS_BUFFER_SIZE] = [0; GPS_BUFFER_SIZE]; +// let mut buf: [u8; 255] = [0; 255]; +// info!("gps sent"); +// let msg = messages_prost::radio::RadioFrame { +// node: messages_prost::common::Node::Phoenix.into(), +// payload: Some(messages_prost::radio::radio_frame::Payload::Gps( +// Gps { +// data: bytes.to_vec() +// }, +// )), +// millis_since_start: Instant::now().as_millis() +// }; +// msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); +// info!("Radio channel"); +// RADIO_CHANNEL.send(buf.clone()).await; +// info!("sd c"); +// SD_CHANNEL.send(("gps.txt", buf)).await; +// } +// } + +use crate::resources::{GPS_BUFFER_SIZE, RX_GPS_BUF}; +use defmt::info; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::mode; +use embassy_stm32::peripherals::{DMA1_CH5, DMA1_CH6, PA4, PB2, PE0, PE1, UART8}; +use embassy_stm32::usart::{Config, RingBufferedUartRx, Uart, UartTx}; +use embassy_time::Delay; +use embedded_hal_1::delay::DelayNs; +use ublox::cfg_val::CfgVal; +use ublox::PacketRef; +use ublox::{ + CfgLayerSet, CfgRstBuilder, CfgValSetBuilder, NavBbrMask, ResetMode, +}; + +/// # +/// # Setup and configure the U-BLOX GPS Module +/// # +/// This function performs a hardware reset, then configures the module to: +/// 1. Use only the UBX protocol on its UART1 interface. +/// 2. Set the measurement rate to 1 Hz. +/// 3. Automatically stream NAV-PVT messages at 1 Hz. +/// 4. Save this configuration to both RAM and Battery-Backed RAM (BBR) for persistence. +/// 5. Perform a controlled software reset to apply the new configuration. +/// +pub async fn setup_gps( + gps_enable: PA4, + gps_reset: PB2, + uart: UART8, + rx: PE0, + tx: PE1, + tx_dma: DMA1_CH5, + rx_dma: DMA1_CH6, + irqs: crate::resources::Irqs, +) -> (RingBufferedUartRx<'static>, UartTx<'static, mode::Async>) { + // --- Initialize GPIOs and UART --- + let mut gps_enable = Output::new(gps_enable, Level::High, Speed::Low); + let mut gps_reset = Output::new(gps_reset, Level::High, Speed::Low); + + let mut uart_gps_config = Config::default(); + uart_gps_config.baudrate = 9600; // Default baud rate for the module + // Other UART settings are correct by default (8N1) + + let uart_gps = Uart::new(uart, rx, tx, irqs, tx_dma, rx_dma, uart_gps_config).unwrap(); + let (mut gps_tx, gps_rx) = uart_gps.split(); + let ring_gps_rx = gps_rx.into_ring_buffered(unsafe { &mut RX_GPS_BUF }); + + // --- Hardware Reset Sequence --- + // This ensures the module is in a known state. + // Note: A hard reset like this will clear BBR if V_BCKP is not supplied. + info!("Performing hardware reset on GPS module..."); + gps_reset.set_low(); + Delay.delay_ms(500); // Keep reset low for a moment + gps_reset.set_high(); + gps_enable.set_low(); // Enable the module + Delay.delay_ms(1000); // Give the module time to boot up + info!("GPS module reset complete."); + + // --- Build Configuration Packet using CFG-VALSET --- + // This is the modern and recommended way to configure M10 series modules. + // We will configure the module to stream NAV-PVT messages at 1Hz. + let config_packet = CfgValSetBuilder { + version: 1, + // Save to RAM (to apply now) and BBR (to make it persistent across power cycles) + layers: CfgLayerSet::RAM | CfgLayerSet::BBR, + reserved1: 0, + cfg_data: &[ + // --- Port Settings: Disable NMEA, Enable UBX --- + CfgVal::Uart1InProtUbx(true), + CfgVal::Uart1InProtNmea(false), + CfgVal::Uart1OutProtUbx(true), + CfgVal::Uart1OutProtNmea(false), + // --- Message Settings: Enable NAV-PVT on UART1 --- + // The '1' means the message will be sent once per navigation solution. + CfgVal::MsgOutUbxNavPvtUart1(1), + // --- Rate Settings: Set navigation rate to 1 Hz --- + CfgVal::RateMeas(1000), // 1000ms = 1Hz + CfgVal::RateNav(1), // Navigation rate matches measurement rate + ], + } + .into_packet_vec(); + + info!("Sending GPS configuration packet..."); + gps_tx + .write(&config_packet) + .await + .expect("Failed to send GPS config"); + Delay.delay_ms(250); // Give module time to process the config + + // --- Software Reset to Apply Configuration --- + // A controlled software reset is needed to apply the settings we just sent. + // This reset mode does not clear the BBR, so our saved config is safe. + let reset_packet = CfgRstBuilder { + nav_bbr_mask: NavBbrMask::empty(), // .empty() preserves all BBR data + reset_mode: ResetMode::ControlledSoftwareReset, + reserved1: 0, + } + .into_packet_bytes(); + + info!("Sending software reset to apply configuration..."); + gps_tx.write(&reset_packet).await.unwrap(); + Delay.delay_ms(500); // Give module time to reset and apply settings + + info!("GPS setup complete. Module is now streaming NAV-PVT packets."); + + (ring_gps_rx, gps_tx) +} + +/// # +/// # GPS Reader and Parser Task +/// # +/// This task continuously reads from the UART and feeds the bytes into a UBX parser. +/// It no longer polls the device. Instead, it waits for the automatically streamed +/// NAV-PVT packets, parses them, and then acts on the valid data. +/// +#[embassy_executor::task] +pub async fn uart_gps_dma_reader_task( + mut gps_rx: RingBufferedUartRx<'static>, + mut _gps_tx: UartTx<'static, mode::Async>, // Renamed to indicate it's not used here +) { + info!("GPS reader task spawned."); + let mut parser_buf: [u8; GPS_BUFFER_SIZE] = [0; GPS_BUFFER_SIZE]; + let mut read_buf: [u8; GPS_BUFFER_SIZE] = [0; GPS_BUFFER_SIZE]; + + // Create a parser to handle the incoming UBX byte stream + let buf = ublox::FixedLinearBuffer::new(&mut parser_buf[..]); + let mut parser = ublox::Parser::new(buf); + loop { + // Wait for and read incoming data from the GPS module + let result = gps_rx.read(&mut read_buf).await; + info!("read"); + if let Ok(bytes_read) = result { + if bytes_read > 0 { + // Feed the received bytes into the parser + let mut it = parser.consume_ubx(&read_buf[..bytes_read]); + + // Iterate through any fully parsed packets + while let Some(packet) = it.next() { + match packet { + Ok(PacketRef::NavPvt(pvt)) => { + // We successfully parsed a NAV-PVT packet! + // Now you can use the structured data. + info!("Received and Parsed NAV-PVT:"); + info!( + " Timestamp: {:?}-{:?}-{:?} {:?}:{:?}:{:?} UTC", + pvt.year(), + pvt.month(), + pvt.day(), + pvt.hour(), + pvt.min(), + pvt.sec() + ); + info!( + " Fix Sats: {:?}, Fix Type: {:?}", + pvt.num_satellites(), + pvt.fix_type() as u8 + ); + info!( + " Coords (deg): lon={}, lat={}", + pvt.longitude() as f32 * 1e-7, + pvt.latitude() as f32 * 1e-7 + ); + + // TODO: Adapt this section to your specific needs. + // Instead of sending the raw buffer, you should now create your + // Gps protobuf message using the parsed data from `pvt`. + // For example: + // let gps_data = Gps { + // latitude: pvt.lat(), + // longitude: pvt.lon(), + // num_satellites: pvt.num_sv() as u32, + // // ... other fields + // }; + + // For demonstration, we'll just log. You can serialize `gps_data` + // and send it over your channels here. + } + Ok(packet) => { + // Handle other packet types if you need them + info!("Received other UBX packet: {:?}", packet.class_and_msg_id()); + } + Err(e) => { + // This can happen if the parser encounters invalid data + defmt::warn!("GPS parser error"); + } + } + } + } + } else { + defmt::error!("GPS read error"); + } + } +} diff --git a/phoenix/src/sensors/iim20670.rs b/phoenix/src/sensors/iim20670.rs new file mode 100644 index 0000000..7a400ab --- /dev/null +++ b/phoenix/src/sensors/iim20670.rs @@ -0,0 +1,248 @@ +use defmt::{info, warn, Format}; +use embedded_hal_1::delay::DelayNs; +use embedded_hal_1::spi::{Operation, SpiDevice}; + +// Register addresses from the datasheet +const GYRO_X_DATA: u8 = 0x00; +const ACCEL_X_DATA: u8 = 0x04; + +// Banked register addresses +const WHO_AM_I: u8 = 0x0E; // In Bank 1 +const ACCEL_FS_SEL: u8 = 0x14; // In Bank 6 +const GYRO_FS_SEL: u8 = 0x14; // In Bank 7 + +// Registers available in all banks +const BANK_SELECT: u8 = 0x1F; + +// Registers in Bank 0 +const TCODE_STATUS: u8 = 0x19; +const RESET_CONTROL: u8 = 0x18; + +#[derive(Debug, Format)] +pub enum Error { + /// SPI bus error + Spi(E), + /// The WHO_AM_I check failed + WhoAmI, + /// The device returned a bad response (e.g., error status bits) + BadResponse { response: [u8; 4], status: u8 }, +} + +pub struct Iim20670 { + spi: SPI, + delay: D, + accel_fs: f32, + gyro_fs: f32, +} + +impl Iim20670 +where + SPI: SpiDevice, + SPI::Error: core::fmt::Debug, + D: DelayNs, +{ + /// Creates a new driver instance. + pub fn new(spi: SPI, delay: D) -> Self { + Self { + spi, + delay, + accel_fs: 0.0, + gyro_fs: 0.0, + } + } + + /// Initializes the sensor, checks the WHO_AM_I register, and reads + /// the default full-scale settings. + pub fn init(&mut self) -> Result<(), Error> { + self.delay.delay_ms(10); + + info!("Performing hardware reset..."); + self.write_reg(RESET_CONTROL, 1 << 2)?; + self.delay.delay_ms(250); + info!("IMU startup complete after reset."); + + self.unlock_bank_select()?; + info!("Bank selection unlocked."); + + self.set_bank(1)?; + let whoami_val = self.read_reg(WHO_AM_I)?; + if (whoami_val as u8) != 0xF3 { + warn!( + "WHO_AM_I check failed. Expected 0xF3, got {:#02x}", + whoami_val + ); + return Err(Error::WhoAmI); + } + info!("WHO_AM_I check passed."); + + self.set_bank(6)?; + let accel_fs_sel = self.read_reg(ACCEL_FS_SEL)?; + self.update_accel_fs(accel_fs_sel as u8); + + self.set_bank(7)?; + let gyro_fs_sel = self.read_reg(GYRO_FS_SEL)?; + self.update_gyro_fs(gyro_fs_sel as u8); + + self.set_bank(0)?; + info!("Switched to Bank 0. IMU initialization successful."); + Ok(()) + } + + /// Reads accelerometer data [x, y, z] in g. + pub fn read_accel(&mut self) -> Result<[f32; 3], Error> { + let mut raw = [0i16; 3]; + for i in 0..3 { + raw[i] = self.read_reg(ACCEL_X_DATA + i as u8)? as i16; + } + let accel_data = [ + (raw[0] as f32 / 32768.0) * self.accel_fs, + (raw[1] as f32 / 32768.0) * self.accel_fs, + (raw[2] as f32 / 32768.0) * self.accel_fs, + ]; + Ok(accel_data) + } + + /// Reads gyroscope data [x, y, z] in degrees per second. + pub fn read_gyro(&mut self) -> Result<[f32; 3], Error> { + let mut raw = [0i16; 3]; + for i in 0..3 { + raw[i] = self.read_reg(GYRO_X_DATA + i as u8)? as i16; + } + let gyro_data = [ + (raw[0] as f32 / 32768.0) * self.gyro_fs, + (raw[1] as f32 / 32768.0) * self.gyro_fs, + (raw[2] as f32 / 32768.0) * self.gyro_fs, + ]; + Ok(gyro_data) + } + + /// Reads a 16-bit value from a register using the byte-oriented protocol. + fn read_reg(&mut self, reg: u8) -> Result> { + let mut tx_buf = [0u8; 4]; + tx_buf[0] = (reg & 0x1F) << 2; // RW=0, Addr in bits 6..2 + tx_buf[1] = 0; + tx_buf[2] = 0; + tx_buf[3] = self.calculate_crc(&[tx_buf[0], tx_buf[1], tx_buf[2]]); + + // First transfer (request) + let mut rx_buf = [0u8; 4]; + self.spi + .transaction(&mut [Operation::Transfer(&mut rx_buf, &tx_buf)]) + .map_err(Error::Spi)?; + + self.delay.delay_ms(1); + + // Second transfer (fetch data) + self.spi + .transaction(&mut [Operation::Transfer(&mut rx_buf, &tx_buf)]) + .map_err(Error::Spi)?; + + // Status is in the LSBs of the first received byte + let status = rx_buf[0] & 0b11; + if status != 0b01 { + // 0b01 is success + warn!( + "Read from reg {:#02x} failed. Status: {:#04b}, Response: {=[u8]:#02x}", + reg, status, rx_buf + ); + return Err(Error::BadResponse { + response: rx_buf, + status, + }); + } + + // Data is in the second and third bytes + Ok(u16::from_be_bytes([rx_buf[1], rx_buf[2]])) + } + + /// Writes a 16-bit value to a register using the byte-oriented protocol. + fn write_reg(&mut self, reg: u8, data: u16) -> Result<(), Error> { + let mut tx_buf = [0u8; 4]; + tx_buf[0] = (1 << 7) | ((reg & 0x1F) << 2); // RW=1, Addr in bits 6..2 + let data_bytes = data.to_be_bytes(); + tx_buf[1] = data_bytes[0]; // Data MSB + tx_buf[2] = data_bytes[1]; // Data LSB + tx_buf[3] = self.calculate_crc(&[tx_buf[0], tx_buf[1], tx_buf[2]]); + + let mut rx_buf = [0u8; 4]; + self.spi + .transaction(&mut [Operation::Transfer(&mut rx_buf, &tx_buf)]) + .map_err(Error::Spi)?; + + // Status is in the LSBs of the first received byte + let status = rx_buf[0] & 0b11; + if status != 0b01 && reg != RESET_CONTROL { + // 0b01 is success + warn!( + "Write to reg {:#02x} failed. Status: {:#04b}, Response: {=[u8]:#02x}", + reg, status, rx_buf + ); + return Err(Error::BadResponse { + response: rx_buf, + status, + }); + } + Ok(()) + } + + /// Switches the active register bank. + fn set_bank(&mut self, bank: u16) -> Result<(), Error> { + self.write_reg(BANK_SELECT, bank) + } + + /// Unlocks the bank selection register as per datasheet section 6.13. + fn unlock_bank_select(&mut self) -> Result<(), Error> { + info!("Unlocking bank select..."); + self.write_reg(TCODE_STATUS, 0b010)?; + self.write_reg(TCODE_STATUS, 0b001)?; + self.write_reg(TCODE_STATUS, 0b100)?; + Ok(()) + } + + /// Updates the internal accelerometer full-scale value based on the register value. + fn update_accel_fs(&mut self, sel_val: u8) { + self.accel_fs = match sel_val & 0b111 { + 0b001 => 16.384, // Default + 0b010 | 0b011 => 32.768, + 0b100 | 0b101 => 2.048, + 0b110 | 0b111 => 4.096, + _ => 16.384, + }; + info!("Accelerometer FS set to: {} g", self.accel_fs); + } + + /// Updates the internal gyroscope full-scale value based on the register value. + fn update_gyro_fs(&mut self, sel_val: u8) { + self.gyro_fs = match sel_val & 0b1111 { + 0b0001 => 655.0, // Default + 0b0000 | 0b1111 => 328.0, + 0b0010 | 0b0111 => 1311.0, + 0b0011 => 1966.0, + _ => 655.0, + }; + info!("Gyroscope FS set to: {} dps", self.gyro_fs); + } + + /// Calculates the CRC for a 3-byte slice, matching the C driver's logic. + fn calculate_crc(&self, data_in: &[u8; 3]) -> u8 { + let mut crc: u8 = 0xFF; + let poly: u8 = 0x1D; + + for &byte in data_in { + let mut current_byte = byte; + for _ in 0..8 { + let crc_msb = (crc & 0x80) != 0; + let data_msb = (current_byte & 0x80) != 0; + crc <<= 1; + if data_msb { + crc |= 1; + } + if crc_msb { + crc ^= poly; + } + current_byte <<= 1; + } + } + crc ^ 0xFF + } +} diff --git a/phoenix/src/sensors/imu.rs b/phoenix/src/sensors/imu.rs new file mode 100644 index 0000000..14f4579 --- /dev/null +++ b/phoenix/src/sensors/imu.rs @@ -0,0 +1,389 @@ +//! Blocking SPI driver for the TDK IIM-20670 IMU with unit conversions and self-test. + +#![no_std] + +use defmt::{error, info, warn}; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::mode::Blocking; +use embassy_stm32::peripherals::{PB4, PB5, PB6, PC0, PC10, PD4, SPI3}; +use embassy_stm32::spi::{Config, Spi}; +use embassy_stm32::time::mhz; +use embassy_time::{Delay, Duration, Timer}; +use embedded_hal_1::delay::DelayNs; +use embedded_hal_1::digital::OutputPin; +use embedded_hal_1::spi::SpiBus; + +/// Acceleration data in g's (1g = 9.8 m/s^2) +#[derive(Debug, Clone, Copy)] +pub struct Acceleration { + pub x: f32, + pub y: f32, + pub z: f32, +} + +/// Angular rate data in degrees per second (dps) +#[derive(Debug, Clone, Copy)] +pub struct AngularRate { + pub x: f32, + pub y: f32, + pub z: f32, +} + +/// Holds the raw difference values from the self-test routine. +#[derive(Debug, Clone, Copy)] +pub struct SelfTestValues { + pub accel_x_diff: i16, + pub accel_y_diff: i16, + pub accel_z_diff: i16, + pub gyro_x_diff: i16, + pub gyro_y_diff: i16, + pub gyro_z_diff: i16, +} + +/// Represents the IIM-20670 device. +pub struct Iim20670 { + spi: SPI, + cs: CS, + nreset: Option, + delay: DELAY, + accel_fsr: AccelFsr, + gyro_fsr: GyroFsr, +} + +/// Represents errors that can occur while interacting with the IIM-20670. +#[derive(Debug)] +pub enum Error { + Spi(SPIE), + Cs(CSE), + Reset(RESETE), + InvalidDeviceId, + /// The IMU returned an error status in its SPI response + ImuError(u8), +} + +#[allow(dead_code)] +mod registers { + // Bank 0 + pub const GYRO_X_DATA: u8 = 0x00; + pub const GYRO_Y_DATA: u8 = 0x01; + pub const GYRO_Z_DATA: u8 = 0x02; + pub const ACCEL_X_DATA: u8 = 0x04; + pub const ACCEL_Y_DATA: u8 = 0x05; + pub const ACCEL_Z_DATA: u8 = 0x06; + pub const SELF_TEST_CONFIG: u8 = 0x11; + pub const SELF_TEST_TRIGGER: u8 = 0x16; + pub const RESET_CTRL: u8 = 0x18; + pub const MODE_CTRL: u8 = 0x19; + pub const BANK_SELECT: u8 = 0x1F; + + // Bank 6 & 7 (for sensitivity config) + pub const SENSITIVITY_CONFIG: u8 = 0x14; +} + +#[repr(u16)] +#[derive(Clone, Copy, Debug)] +enum Bank { + Bank0 = 0x0000, + Bank1 = 0x0001, + Bank6 = 0x0006, + Bank7 = 0x0007, +} + +#[repr(u16)] +#[derive(Clone, Copy, Debug)] +pub enum GyroFsr { + Dps1966 = 0b0011, +} + +impl GyroFsr { + fn as_f32(&self) -> f32 { + 1966.0 + } +} + +#[repr(u16)] +#[derive(Clone, Copy, Debug)] +pub enum AccelFsr { + G16 = 0b001, +} + +impl AccelFsr { + fn as_f32(&self) -> f32 { + 16.384 + } +} + +struct CsGuard<'a, CS: OutputPin> { + cs: &'a mut CS, +} + +impl<'a, CS: OutputPin> CsGuard<'a, CS> { + fn new(cs: &'a mut CS) -> Result { + cs.set_low()?; + Ok(Self { cs }) + } +} + +impl<'a, CS: OutputPin> Drop for CsGuard<'a, CS> { + fn drop(&mut self) { + let _ = self.cs.set_high(); + } +} + +impl Iim20670 +where + SPI: SpiBus, + CS: OutputPin, + NRESET: OutputPin, + DELAY: DelayNs, +{ + pub fn new( + spi: SPI, + mut cs: CS, + nreset: Option, + delay: DELAY, + ) -> Result> { + info!("Starting IIM-20670 initialization..."); + cs.set_high().map_err(Error::Cs)?; + + let mut driver = Self { + spi, + cs, + nreset, + delay, + accel_fsr: AccelFsr::G16, + gyro_fsr: GyroFsr::Dps1966, + }; + + if let Some(ref mut reset_pin) = driver.nreset { + info!("Performing hardware reset..."); + reset_pin.set_high().map_err(Error::Reset)?; + driver.delay.delay_ms(1); + reset_pin.set_low().map_err(Error::Reset)?; + driver.delay.delay_ms(40); + reset_pin.set_high().map_err(Error::Reset)?; + driver.delay.delay_ms(250); + } + + // *** FIX: Perform a single read to check for life *** + info!("Attempting to read a register to verify communication..."); + let _ = driver.read_reg_16(registers::ACCEL_X_DATA)?; + + info!("IMU initialization check passed. Device is responsive."); + // We will skip other configuration for now to isolate the issue. + + Ok(driver) + } + + // ... (rest of the functions are unchanged) ... + + fn spi_transaction( + &mut self, + reg: u8, + data: u16, + is_write: bool, + ) -> Result> { + let _guard = CsGuard::new(&mut self.cs).map_err(Error::Cs)?; + + let rw_bit = if is_write { 1u32 } else { 0u32 }; + let command_part = (rw_bit << 31) | ((reg as u32) << 26) | ((data as u32) << 8); + let crc = Self::calculate_crc(command_part >> 8); + let tx_word = command_part | crc as u32; + let mut buffer = tx_word.to_be_bytes(); + + info!(" SPI TX -> {=[u8]:#X}", buffer); + self.spi + .transfer_in_place(&mut buffer) + .map_err(Error::Spi)?; + info!(" SPI RX <- {=[u8]:#X}", buffer); + + let response_word = u32::from_be_bytes(buffer); + let status = ((response_word >> 24) & 0b11) as u8; + + if status != 1 { + if status == 2 && !is_write { + warn!("IMU returned self-test status (2), which is normal during test reads."); + } else { + error!("IMU returned error status: {}", status); + return Err(Error::ImuError(status)); + } + } + + Ok(((response_word >> 8) & 0xFFFF) as u16) + } + + fn send_raw_command(&mut self, command: u32) -> Result<(), Error> { + let _guard = CsGuard::new(&mut self.cs).map_err(Error::Cs)?; + let mut buffer = command.to_be_bytes(); + info!(" SPI TX -> {=[u8]:#X}", buffer); + self.spi + .transfer_in_place(&mut buffer) + .map_err(Error::Spi)?; + info!(" SPI RX <- {=[u8]:#X}", buffer); + + let response_word = u32::from_be_bytes(buffer); + let status = ((response_word >> 24) & 0b11) as u8; + if status != 1 { + error!("IMU returned error status: {} on raw command", status); + return Err(Error::ImuError(status)); + } + Ok(()) + } + + fn unlock_banks(&mut self) -> Result<(), Error> { + info!(" unlock_banks: step 1"); + self.write_reg_16(registers::MODE_CTRL, 0b010)?; + info!(" unlock_banks: step 2"); + self.write_reg_16(registers::MODE_CTRL, 0b001)?; + info!(" unlock_banks: step 3"); + self.write_reg_16(registers::MODE_CTRL, 0b100)?; + Ok(()) + } + + fn unlock_fsr(&mut self) -> Result<(), Error> { + info!(" unlock_fsr: step 1"); + self.send_raw_command(0xE4000288)?; + info!(" unlock_fsr: step 2"); + self.send_raw_command(0xE400018B)?; + info!(" unlock_fsr: step 3"); + self.send_raw_command(0xE400048E)?; + info!(" unlock_fsr: step 4"); + self.send_raw_command(0xE40300AD)?; + info!(" unlock_fsr: step 5"); + self.send_raw_command(0xE4018017)?; + info!(" unlock_fsr: step 6"); + self.send_raw_command(0xE4028030)?; + Ok(()) + } + + fn write_reg_16(&mut self, reg: u8, data: u16) -> Result<(), Error> { + self.spi_transaction(reg, data, true)?; + Ok(()) + } + + fn read_reg_16(&mut self, reg: u8) -> Result> { + self.spi_transaction(reg, 0, false)?; + self.spi_transaction(reg, 0, false) + } + + fn calculate_crc(data_to_encode: u32) -> u8 { + let mut crc: u8 = 0xFF; + for i in (0..24).rev() { + let bit = (data_to_encode >> i) & 1; + let crc7 = (crc >> 7) & 1; + let mut crc_new = 0u8; + crc_new |= ((crc >> 6) & 1) << 7; + crc_new |= ((crc >> 5) & 1) << 6; + crc_new |= ((crc >> 4) & 1) << 5; + crc_new |= (((crc >> 3) & 1) ^ crc7) << 4; + crc_new |= (((crc >> 2) & 1) ^ crc7) << 3; + crc_new |= (((crc >> 1) & 1) ^ crc7) << 2; + crc_new |= (crc & 1) << 1; + crc_new |= (bit as u8) ^ crc7; + crc = crc_new; + } + !crc + } + + fn select_bank(&mut self, bank: Bank) -> Result<(), Error> { + info!(" Selecting bank: {:?}", bank as u16); + self.write_reg_16(registers::BANK_SELECT, bank as u16) + } + + pub fn set_gyro_fsr(&mut self, fsr: GyroFsr) -> Result<(), Error> { + info!("Setting Gyro FSR..."); + self.select_bank(Bank::Bank7)?; + self.write_reg_16(registers::SENSITIVITY_CONFIG, fsr as u16)?; + self.gyro_fsr = fsr; + self.select_bank(Bank::Bank0) + } + + pub fn set_accel_fsr(&mut self, fsr: AccelFsr) -> Result<(), Error> { + info!("Setting Accel FSR..."); + self.select_bank(Bank::Bank6)?; + self.write_reg_16(registers::SENSITIVITY_CONFIG, fsr as u16)?; + self.accel_fsr = fsr; + self.select_bank(Bank::Bank0) + } + + pub fn read_gyro_raw(&mut self) -> Result<[i16; 3], Error> { + let x = self.read_reg_16(registers::GYRO_X_DATA)? as i16; + let y = self.read_reg_16(registers::GYRO_Y_DATA)? as i16; + let z = self.read_reg_16(registers::GYRO_Z_DATA)? as i16; + Ok([x, y, z]) + } + + pub fn read_accel_raw(&mut self) -> Result<[i16; 3], Error> { + let x = self.read_reg_16(registers::ACCEL_X_DATA)? as i16; + let y = self.read_reg_16(registers::ACCEL_Y_DATA)? as i16; + let z = self.read_reg_16(registers::ACCEL_Z_DATA)? as i16; + Ok([x, y, z]) + } + + pub fn read_accel_g(&mut self) -> Result> { + let raw = self.read_accel_raw()?; + let fsr = self.accel_fsr.as_f32(); + Ok(Acceleration { + x: (raw[0] as f32 / 32767.0) * fsr, + y: (raw[1] as f32 / 32767.0) * fsr, + z: (raw[2] as f32 / 32767.0) * fsr, + }) + } + + pub fn read_gyro_dps(&mut self) -> Result> { + let raw = self.read_gyro_raw()?; + let fsr = self.gyro_fsr.as_f32(); + Ok(AngularRate { + x: (raw[0] as f32 / 32767.0) * fsr, + y: (raw[1] as f32 / 32767.0) * fsr, + z: (raw[2] as f32 / 32767.0) * fsr, + }) + } + + pub fn read_all_converted( + &mut self, + ) -> Result<(Acceleration, AngularRate), Error> { + let accel = self.read_accel_g()?; + let gyro = self.read_gyro_dps()?; + Ok((accel, gyro)) + } +} + +pub fn init_imu( + spi: SPI3, + sck: PC10, + mosi: PB5, + miso: PB4, + odr: PC0, + cs: PB6, + nreset: PD4, +) -> Iim20670, Output<'static>, Output<'static>, Delay> { + let mut imu_spi_config = Config::default(); + imu_spi_config.frequency = mhz(9); + imu_spi_config.mode = embassy_stm32::spi::Mode { + polarity: embassy_stm32::spi::Polarity::IdleLow, + phase: embassy_stm32::spi::Phase::CaptureOnFirstTransition, + }; + let imu_spi = Spi::new_blocking(spi, sck, mosi, miso, imu_spi_config); + let imu_odr = Input::new(odr, Pull::None); + let imu_cs = Output::new(cs, Level::High, Speed::Low); + let imu_nreset = Output::new(nreset, Level::High, Speed::Low); + Iim20670::new(imu_spi, imu_cs, Some(imu_nreset), Delay).unwrap() +} + +#[embassy_executor::task] +pub async fn imu_task( + mut imu: Iim20670, Output<'static>, Output<'static>, Delay>, +) { + loop { + Timer::after(Duration::from_millis(100)).await; + let data = imu.read_all_converted(); + match data { + Ok((accel, gyro)) => { + info!("Accel: x: {}, y: {}, z: {}", accel.x, accel.y, accel.z); + info!("Gyro: x: {}, y: {}, z: {}", gyro.x, gyro.y, gyro.z); + } + Err(e) => {} + } + } +} diff --git a/phoenix/src/sensors/mod.rs b/phoenix/src/sensors/mod.rs new file mode 100644 index 0000000..a182abe --- /dev/null +++ b/phoenix/src/sensors/mod.rs @@ -0,0 +1,5 @@ +pub mod baro; +pub mod gps; +pub mod iim20670; +pub mod imu; +pub mod sbg_manager; diff --git a/phoenix/src/sensors/sbg_manager.rs b/phoenix/src/sensors/sbg_manager.rs new file mode 100644 index 0000000..1591cec --- /dev/null +++ b/phoenix/src/sensors/sbg_manager.rs @@ -0,0 +1,277 @@ +use core::alloc::{GlobalAlloc, Layout}; +use core::ffi::c_void; +use core::mem::size_of; +use core::ptr; +// use crate::app::sbg_flush; +// use crate::app::sbg_handle_data; +// use crate::app::sbg_sd_task as sbg_sd; +// use crate::app::sbg_write_data; +use super::sbg_manager; +use crate::resources::{ + BUFFER_CHANNEL, PRESSURE_CHANNEL, RADIO_CHANNEL, RTC, SBG_CHANNEL, SD_CHANNEL, +}; +use crate::HEAP; +use chrono::NaiveDateTime; +use defmt::info; +use embassy_stm32::mode; +use embassy_stm32::usart::{RingBufferedUartRx, UartTx}; +use embassy_time::Instant; +use heapless::Vec; +use messages_prost::prost::Message; +use sbg_rs::sbg; +use sbg_rs::sbg::{CallbackData, SBG, SBG_BUFFER_SIZE}; +// use stm32h7xx_hal::dma::dma::StreamX; +// use stm32h7xx_hal::dma::{ +// dma::{DmaConfig, StreamsTuple}, +// PeripheralToMemory, Transfer, +// }; +// use stm32h7xx_hal::pac::UART4; +// use stm32h7xx_hal::serial::{Rx, Tx}; + +#[embassy_executor::task] +pub async fn uart_dma_reader_task(mut rx: RingBufferedUartRx<'static>) { + info!("DMA reader task spawned."); + loop { + let mut buf: [u8; SBG_BUFFER_SIZE] = [0; SBG_BUFFER_SIZE]; + if let Ok(len) = rx.read(&mut buf).await { + if len > 0 { + let _ = BUFFER_CHANNEL.send(buf).await; + } + } + } +} + +#[embassy_executor::task] +pub async fn sbg_parser_task(tx: UartTx<'static, mode::Async>) { + let mut sbg = sbg_manager::SBGManager::new(tx); + loop { + let full_buffer = BUFFER_CHANNEL.receive().await; + sbg.sbg_device.read_data(&full_buffer.try_into().unwrap()); + } +} + +#[embassy_executor::task] +pub async fn sbg_receiver_task() { + loop { + let data = SBG_CHANNEL.receive().await; + match data.data { + Some(x) => { + let mut buf: [u8; 255] = [0; 255]; + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::Sbg(data)), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()) + .expect("Failed to encode"); + RADIO_CHANNEL.send(buf.clone()).await; + + SD_CHANNEL.send(("sbg.txt", buf)).await; + } + None => { + info!("No SBG data received"); + } + } + } +} + +pub struct SBGManager { + pub sbg_device: SBG, + sbg_tx: UartTx<'static, mode::Async>, +} + +impl SBGManager { + pub fn new(sbg_tx: UartTx<'static, mode::Async>) -> Self { + let sbg: sbg::SBG = sbg::SBG::new( + |data| { + sbg_handle_data(data); + }, + |data| { + // TODO: implement later + // sbg_write_data::spawn(data).ok(); + }, + || sbg_get_time(), + || { + // TODO: implement later + // sbg_flush::spawn().ok(); + }, + ); + + SBGManager { + sbg_device: sbg, + sbg_tx, + } + } +} + +pub async fn sbg_flush() {} + +pub async fn sbg_write_data(data: Vec) {} + +pub fn sbg_get_time_millis_i64() -> i64 { + RTC.lock(|cell| { + if let Some(rtc) = cell.borrow_mut().as_mut() { + rtc.now() + .ok() + .map(|embassy_dt| { + let chrono_naive_dt: NaiveDateTime = embassy_dt.into(); + chrono_naive_dt.and_utc().timestamp_millis() + }) + .unwrap_or(0) + } else { + // Handle the case where RTC is not initialized + 0 + } + }) +} + +pub fn sbg_get_time() -> u32 { + // // We get the full i64 timestamp first. + // let timestamp_ms = sbg_get_time_millis_i64(); + + // // Convert to u32. This is a truncating cast. + // // For positive timestamps, it's equivalent to `timestamp_ms % (u32::MAX as i64 + 1)`. + // timestamp_ms as u32 + 501 +} + +/// Publishes data to the SBG channel. +pub fn sbg_handle_data(data: CallbackData) { + match data { + CallbackData::Air(x) => { + PRESSURE_CHANNEL.try_send(( + x.data.unwrap().altitude, + x.data.unwrap().air_temperature, + 0, + embassy_time::Instant::now(), + )); + SBG_CHANNEL.try_send(messages_prost::sensor::sbg::SbgData { + data: Some(messages_prost::sensor::sbg::sbg_data::Data::Air(x)), + }) + } + CallbackData::EkfNav(x) => SBG_CHANNEL.try_send(messages_prost::sensor::sbg::SbgData { + data: Some(messages_prost::sensor::sbg::sbg_data::Data::EkfNav(x)), + }), + CallbackData::EkfQuat(x) => SBG_CHANNEL.try_send(messages_prost::sensor::sbg::SbgData { + data: Some(messages_prost::sensor::sbg::sbg_data::Data::EkfQuat(x)), + }), + CallbackData::GpsPos(x) => SBG_CHANNEL.try_send(messages_prost::sensor::sbg::SbgData { + data: Some(messages_prost::sensor::sbg::sbg_data::Data::GpsPos(x)), + }), + CallbackData::GpsVel(x) => SBG_CHANNEL.try_send(messages_prost::sensor::sbg::SbgData { + data: Some(messages_prost::sensor::sbg::sbg_data::Data::GpsVel(x)), + }), + CallbackData::Imu(x) => SBG_CHANNEL.try_send(messages_prost::sensor::sbg::SbgData { + data: Some(messages_prost::sensor::sbg::sbg_data::Data::Imu(x)), + }), + CallbackData::UtcTime(x) => SBG_CHANNEL.try_send(messages_prost::sensor::sbg::SbgData { + data: Some(messages_prost::sensor::sbg::sbg_data::Data::UtcTime(x)), + }), + }; +} + +pub async fn sbg_sd_task(data: [u8; SBG_BUFFER_SIZE]) { + + // cx.shared.sd_manager.lock(|manager| { + // if let Some(mut file) = manager.file.take() { + // cx.shared.em.run(|| { + // manager.write(&mut file, &data)?; + // Ok(()) + // }); + // manager.file = Some(file); // give the file back after use + // } else if let Ok(mut file) = manager.open_file("lc24.txt") { + // cx.shared.em.run(|| { + // manager.write(&mut file, &data)?; + // Ok(()) + // }); + // manager.file = Some(file); + // } + // }); +} +/** + * Recieves data from the UART channel and sends it to the sbg library for processing. + */ +#[embassy_executor::task] +pub async fn sbg_dma() { + // loop { + // let data = UART_CHANNEL.receive().await; + // } + + // cx.shared.sbg_manager.lock(|sbg| { + // match &mut sbg.xfer { + // Some(xfer) => { + // if xfer.get_transfer_complete_flag() { + // let data = unsafe { SBG_BUFFER.assume_init_read() }.clone(); + // xfer.next_transfer( + // unsafe { (*core::ptr::addr_of_mut!(SBG_BUFFER)).assume_init_mut() }, // Uninitialised memory + // ); + // // info!("{}", data); + // xfer.clear_transfer_complete_interrupt(); + // sbg.sbg_device.read_data(&data); + // crate::app::sbg_sd_task::spawn(data).ok(); + // } + // } + // None => { + // // it should be impossible to reach here. + // info!("None"); + // } + // } + // }); +} + +/// Stored right before an allocation. Stores information that is needed to deallocate memory. +#[derive(Copy, Clone)] +struct AllocInfo { + layout: Layout, + ptr: *mut u8, +} + +/// Custom malloc for the SBG library. This uses the HEAP object initialized at the start of the +/// [`SBGManager`]. The [`Layout`] of the allocation is stored right before the returned pointed, +/// which makes it possible to implement [`free`] without any other data structures. +#[no_mangle] +pub extern "C" fn malloc(size: usize) -> *mut c_void { + if size == 0 { + return ptr::null_mut(); + } + + // Get a layout for both the requested size + let header_layout = Layout::new::(); + let requested_layout = Layout::from_size_align(size, 8).unwrap(); + let (layout, offset) = header_layout.extend(requested_layout).unwrap(); + + // Ask the allocator for memory + let orig_ptr = unsafe { HEAP.alloc(layout) }; + if orig_ptr.is_null() { + return orig_ptr as *mut c_void; + } + + // Compute the pointer that we will return + let result_ptr = unsafe { orig_ptr.add(offset) }; + + // Store the allocation information right before the returned pointer + let info_ptr = unsafe { result_ptr.sub(size_of::()) as *mut AllocInfo }; + unsafe { + info_ptr.write_unaligned(AllocInfo { + layout, + ptr: orig_ptr, + }); + } + + result_ptr as *mut c_void +} + +/// Custom free implementation for the SBG library. This uses the stored allocation information +/// right before the pointer to free up the resources. +/// +/// SAFETY: The value passed to ptr must have been obtained from a previous call to [`malloc`]. +#[no_mangle] +pub unsafe extern "C" fn free(ptr: *mut c_void) { + assert!(!ptr.is_null()); + + let info_ptr = unsafe { ptr.sub(size_of::()) as *const AllocInfo }; + let info = unsafe { info_ptr.read_unaligned() }; + unsafe { + HEAP.dealloc(info.ptr, info.layout); + } +} diff --git a/phoenix/src/state_machine.rs b/phoenix/src/state_machine.rs new file mode 100644 index 0000000..c87f5af --- /dev/null +++ b/phoenix/src/state_machine.rs @@ -0,0 +1,377 @@ +use defmt::info; +use embassy_executor::Spawner; +use embassy_time::{Instant, Timer}; +use heapless::{HistoryBuffer, Vec}; +use messages_prost::phoenix_state::{Event, State}; +use messages_prost::prost::Message; +use smlang::statemachine; + +use crate::recovery::{recovery_algorithm_task, DATA_POINTS, SLOPES}; +use crate::resources::{ + EVENT_CHANNEL, PRESSURE_CHANNEL, RADIO_CHANNEL, RECOVERY_MANAGER, SD_CHANNEL, +}; + +statemachine! { + transitions: { + *Init + Start = WaitForLaunch, + WaitForLaunch + Launch = Ascent, + Ascent + Apogee = Descent, + Descent + MainDeployment = Fuck, + Descent + DrogueDeployment = DrogueDescent, + DrogueDescent + MainDeployment = MainDescent, + MainDescent + NoMovement = Landed, + Fault + FaultCleared = _, + _ + FaultDetected = Fault, + } +} + +pub struct Context {} + +impl StateMachineContext for Context {} + +impl From for State { + fn from(value: States) -> Self { + match value { + States::Fuck => State::Fuck, + States::Init => State::Init, + States::Fault => State::Fault, + States::WaitForLaunch => State::WaitForLaunch, + States::Ascent => State::Ascent, + States::Descent => State::Descent, + States::DrogueDescent => State::DrogueDescent, + States::MainDescent => State::MainDescent, + States::Landed => State::Landed, + } + } +} + +#[embassy_executor::task] +pub async fn sm_task(spawner: Spawner, mut state_machine: StateMachine) { + info!("State Machine task started."); + let mut recovery_spawned = false; + let mut historical_barometer_altitude_sbg: HistoryBuffer<(f32, Instant), DATA_POINTS> = + HistoryBuffer::new(); + const CONSECUTIVE_NEGATIVE_THRESHOLD: usize = 7; + const NO_MOVEMENT_RATE: f32 = -0.0001; + + loop { + if let Ok(event) = EVENT_CHANNEL.try_receive() { + state_machine.process_event(event); + } + + match state_machine.state { + States::Ascent => { + let mut buf: [u8; 255] = [0; 255]; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixState( + State::Ascent.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("state.txt", buf)).await; + } + States::Fault => { + let mut buf: [u8; 255] = [0; 255]; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixState( + State::Fault.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("state.txt", buf)).await; + } + States::Init => { + let mut buf: [u8; 255] = [0; 255]; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixState( + State::Init.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("state.txt", buf)).await; + + // let mut should_start = false; + // // await both channels to be armed. + // RECOVERY_MANAGER.lock(|cell| { + // if let Some(recovery_manager) = cell.borrow_mut().as_mut() { + // if recovery_manager.is_armed() { + // // this could be it's own task this has the posibility to be bad since + // // it's just evaluated for the first arming, if disarmed it will still be potentionally live. + // should_start = true; + // } + // } + // }); + + // if should_start { + EVENT_CHANNEL.send(Events::Start).await; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixEvent( + Event::Start.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("event.txt", buf)).await; + // } + } + States::WaitForLaunch => { + let mut buf: [u8; 255] = [0; 255]; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixState( + State::WaitForLaunch.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + let (altitude, temperature, sender, timestamp) = PRESSURE_CHANNEL.receive().await; + + // sbg data + if sender == 0 && !recovery_spawned { + if altitude >= crate::recovery::HEIGHT_MIN { + info!("Height lockout reached"); + EVENT_CHANNEL.send(Events::Launch).await; + spawner.must_spawn(recovery_algorithm_task()); + recovery_spawned = true; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixEvent( + Event::Launch.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("event.txt", buf)).await; + } + } + + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("state.txt", buf)).await; + } + States::Descent => { + RECOVERY_MANAGER.lock(|cell| { + if let Some(recovery_manager) = cell.borrow_mut().as_mut() { + recovery_manager.fire_drogue(); + } + }); + + // Fire the main + EVENT_CHANNEL.send(Events::DrogueDeployment).await; + + let mut buf: [u8; 255] = [0; 255]; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixState( + State::Descent.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("state.txt", buf)).await; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixEvent( + Event::DrogueDeployment.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("event.txt", buf)).await; + } + States::DrogueDescent => { + let mut buf: [u8; 255] = [0; 255]; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixState( + State::DrogueDescent.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("state.txt", buf)).await; + + let (altitude, temperature, sender, timestamp) = PRESSURE_CHANNEL.receive().await; + + // sbg data + if sender == 0 { + if altitude <= crate::recovery::MAIN_HEIGHT { + RECOVERY_MANAGER.lock(|cell| { + if let Some(recovery_manager) = cell.borrow_mut().as_mut() { + recovery_manager.fire_main(); + } + }); + + EVENT_CHANNEL.send(Events::MainDeployment).await; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some( + messages_prost::radio::radio_frame::Payload::PhoenixEvent( + Event::MainDeployment.into(), + ), + ), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("event.txt", buf)).await; + } + } + } + States::Fuck => { + let mut buf: [u8; 255] = [0; 255]; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixState( + State::Fuck.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf).await; + SD_CHANNEL.send(("state.txt", buf)).await; + } + States::Landed => { + let mut buf: [u8; 255] = [0; 255]; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixState( + State::Landed.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf).await; + SD_CHANNEL.send(("state.txt", buf)).await; + } + States::MainDescent => { + let mut buf: [u8; 255] = [0; 255]; + + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some(messages_prost::radio::radio_frame::Payload::PhoenixState( + State::MainDescent.into(), + )), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf).await; + SD_CHANNEL.send(("state.txt", buf)).await; + + let (altitude, temperature, sender, timestamp) = PRESSURE_CHANNEL.receive().await; + + if sender == 0 { + // Source is the SBG + historical_barometer_altitude_sbg.write((altitude, timestamp)); + + // --- Apogee Detection Logic --- + // Ensure there are enough data points in the buffer to perform a reliable calculation. + if historical_barometer_altitude_sbg.len() < DATA_POINTS { + continue; + } + + // --- DEBUG PRINT: Show the current data buffer --- + let altitude_history_for_print: Vec<_, DATA_POINTS> = historical_barometer_altitude_sbg + .oldest_ordered() + .map(|(alt, _)| alt) + .collect(); + // info!("[SBG] Altitude History: {:?}", altitude_history_for_print.as_slice()); + + let mut buf_sbg = historical_barometer_altitude_sbg.oldest_ordered(); + + // --- SBG Apogee Check --- + if let Some(mut prev_reading) = buf_sbg.next() { + let mut slopes: HistoryBuffer = HistoryBuffer::new(); + + for current_reading in buf_sbg { + let time_diff_ms = current_reading.1.duration_since(prev_reading.1).as_millis(); + let alt_diff = current_reading.0 - prev_reading.0; + + + if time_diff_ms > 0 { + let slope_mpms = alt_diff / time_diff_ms as f32; + + slopes.write(slope_mpms); + } else { + } + prev_reading = current_reading; + } + + if slopes.len() >= CONSECUTIVE_NEGATIVE_THRESHOLD { + let slopes_vec: Vec<_, DATA_POINTS> = slopes.oldest_ordered().collect(); + + + let mut sum_of_recent_slopes = 0.0; + + for slope in slopes_vec.iter().rev().take(CONSECUTIVE_NEGATIVE_THRESHOLD) { + if **slope <= 0.0 { + sum_of_recent_slopes += *slope; + } else { + break; + } + } + + + + let avg_slope_mpms = + sum_of_recent_slopes / CONSECUTIVE_NEGATIVE_THRESHOLD as f32; + + // info!("slope: {}", avg_slope_mpms); + if avg_slope_mpms <= NO_MOVEMENT_RATE { + let msg = messages_prost::radio::RadioFrame { + node: messages_prost::common::Node::Phoenix.into(), + payload: Some( + messages_prost::radio::radio_frame::Payload::PhoenixEvent( + Event::NoMovement.into(), + ), + ), + millis_since_start: Instant::now().as_millis(), + }; + msg.encode_length_delimited(&mut buf.as_mut()).unwrap(); + RADIO_CHANNEL.send(buf.clone()).await; + SD_CHANNEL.send(("event.txt", buf)).await; + if EVENT_CHANNEL + .try_send(crate::state_machine::Events::NoMovement) + .is_err() + { + // todo!("Log failure to radio"); + } + } + } + } + } + } + } + + Timer::after_millis(100).await; + } +} diff --git a/phoenix/src/types.rs b/phoenix/src/types.rs deleted file mode 100644 index 551ed32..0000000 --- a/phoenix/src/types.rs +++ /dev/null @@ -1,3 +0,0 @@ -use messages::node::{Node, Node::TemperatureBoard}; - -pub static COM_ID: Node = TemperatureBoard; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 8de39d4..e0eb7a8 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "stable" -targets = ["thumbv7em-none-eabihf"] +channel = "nightly" +targets = ["thumbv7em-none-eabihf"] \ No newline at end of file