From bd5fbf6e58dad37ae26750b3b90e666710e34a6c Mon Sep 17 00:00:00 2001
From: Federico Lolli <federico.lolli@skywarder.eu>
Date: Wed, 20 Mar 2024 17:49:30 +0100
Subject: [PATCH] Added TDL integration and moved error handling from eyre to
 miette

---
 on-host/Cargo.lock   | 398 +++++++++++++++++++++++++++++++------------
 on-host/Cargo.toml   |  11 +-
 on-host/src/cli.rs   |  59 ++++++-
 on-host/src/csv.rs   |  13 ++
 on-host/src/main.rs  |  56 ++++--
 on-host/src/tdl.rs   | 191 +++++++++++++++++++++
 on-host/src/utils.rs |   6 +-
 7 files changed, 605 insertions(+), 129 deletions(-)
 create mode 100644 on-host/src/csv.rs
 create mode 100644 on-host/src/tdl.rs

diff --git a/on-host/Cargo.lock b/on-host/Cargo.lock
index da7015e..14ae33f 100644
--- a/on-host/Cargo.lock
+++ b/on-host/Cargo.lock
@@ -19,18 +19,18 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "aho-corasick"
-version = "1.1.2"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "anstream"
-version = "0.6.5"
+version = "0.6.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
+checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -42,9 +42,9 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.4"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
+checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
 
 [[package]]
 name = "anstyle-parse"
@@ -79,13 +79,14 @@ name = "arpist"
 version = "0.2.0"
 dependencies = [
  "clap",
- "color-eyre",
  "csv",
  "log",
+ "miette",
  "serde",
  "serialport",
  "simple_logger",
  "skyward_mavlink",
+ "tdl-core",
 ]
 
 [[package]]
@@ -109,6 +110,21 @@ dependencies = [
  "rustc-demangle",
 ]
 
+[[package]]
+name = "backtrace-ext"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
+dependencies = [
+ "backtrace",
+]
+
+[[package]]
+name = "beef"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
+
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -117,9 +133,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.4.2"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
 
 [[package]]
 name = "byteorder"
@@ -141,9 +157,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "clap"
-version = "4.4.11"
+version = "4.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
+checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -151,9 +167,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.4.11"
+version = "4.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
+checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
 dependencies = [
  "anstream",
  "anstyle",
@@ -163,9 +179,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.4.7"
+version = "4.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
+checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -175,22 +191,9 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
-
-[[package]]
-name = "color-eyre"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5"
-dependencies = [
- "backtrace",
- "eyre",
- "indenter",
- "once_cell",
- "owo-colors",
-]
+checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
 
 [[package]]
 name = "colorchoice"
@@ -251,15 +254,21 @@ dependencies = [
 ]
 
 [[package]]
-name = "eyre"
-version = "0.6.12"
+name = "errno"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
 dependencies = [
- "indenter",
- "once_cell",
+ "libc",
+ "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
 [[package]]
 name = "gimli"
 version = "0.28.1"
@@ -268,21 +277,15 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
 
 [[package]]
 name = "heck"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-
-[[package]]
-name = "indenter"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "io-kit-sys"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4769cb30e5dcf1710fc6730d3e94f78c47723a014a567de385e113c737394640"
+checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b"
 dependencies = [
  "core-foundation-sys",
  "mach2",
@@ -297,6 +300,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "is_ci"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
+
 [[package]]
 name = "itoa"
 version = "1.0.10"
@@ -311,9 +320,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.151"
+version = "0.2.153"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
 
 [[package]]
 name = "libudev"
@@ -335,17 +344,56 @@ dependencies = [
  "pkg-config",
 ]
 
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+
 [[package]]
 name = "log"
-version = "0.4.20"
+version = "0.4.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+
+[[package]]
+name = "logos"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "161971eb88a0da7ae0c333e1063467c5b5727e7fb6b710b8db4814eade3a42e8"
+dependencies = [
+ "logos-derive",
+]
+
+[[package]]
+name = "logos-codegen"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e31badd9de5131fdf4921f6473d457e3dd85b11b7f091ceb50e4df7c3eeb12a"
+dependencies = [
+ "beef",
+ "fnv",
+ "lazy_static",
+ "proc-macro2",
+ "quote",
+ "regex-syntax",
+ "syn",
+]
+
+[[package]]
+name = "logos-derive"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c2a69b3eb68d5bd595107c9ee58d7e07fe2bb5e360cc85b0f084dedac80de0a"
+dependencies = [
+ "logos-codegen",
+]
 
 [[package]]
 name = "mach2"
-version = "0.4.1"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8"
+checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
 dependencies = [
  "libc",
 ]
@@ -377,9 +425,40 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.6.4"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+
+[[package]]
+name = "miette"
+version = "7.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+checksum = "4edc8853320c2a0dab800fbda86253c8938f6ea88510dc92c5f1ed20e794afc1"
+dependencies = [
+ "backtrace",
+ "backtrace-ext",
+ "cfg-if",
+ "miette-derive",
+ "owo-colors",
+ "supports-color",
+ "supports-hyperlinks",
+ "supports-unicode",
+ "terminal_size",
+ "textwrap",
+ "thiserror",
+ "unicode-width",
+]
+
+[[package]]
+name = "miette-derive"
+version = "7.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
 
 [[package]]
 name = "miniz_oxide"
@@ -401,6 +480,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
 [[package]]
 name = "num-derive"
 version = "0.4.2"
@@ -423,9 +508,9 @@ dependencies = [
 
 [[package]]
 name = "num_threads"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
+checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
 dependencies = [
  "libc",
 ]
@@ -439,23 +524,17 @@ dependencies = [
  "memchr",
 ]
 
-[[package]]
-name = "once_cell"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-
 [[package]]
 name = "owo-colors"
-version = "3.5.0"
+version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
+checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f"
 
 [[package]]
 name = "pkg-config"
-version = "0.3.27"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
 
 [[package]]
 name = "powerfmt"
@@ -465,9 +544,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.78"
+version = "1.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
+checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
 dependencies = [
  "unicode-ident",
 ]
@@ -492,9 +571,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.10.2"
+version = "1.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -504,9 +583,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.3"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -525,11 +604,24 @@ version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
 
+[[package]]
+name = "rustix"
+version = "0.38.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
+dependencies = [
+ "bitflags 2.5.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
 [[package]]
 name = "ryu"
-version = "1.0.16"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
 
 [[package]]
 name = "scopeguard"
@@ -614,7 +706,7 @@ version = "4.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f5a15d0be940df84846264b09b51b10b931fb2f275becb80934e3568a016828"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "cfg-if",
  "core-foundation-sys",
  "io-kit-sys",
@@ -644,7 +736,7 @@ name = "skyward_mavlink"
 version = "0.1.0"
 source = "git+https://git.skywarder.eu/avn/swd/mavlink/mavlink-skyward-lib.git?branch=rust#41efbf48be8f7cad475a00c66b7abe40b5a0866b"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "mavlink-bindgen",
  "mavlink-core",
  "num-derive",
@@ -653,23 +745,82 @@ dependencies = [
  "serde_arrays",
 ]
 
+[[package]]
+name = "smawk"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
+
 [[package]]
 name = "strsim"
-version = "0.10.0"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
+
+[[package]]
+name = "supports-color"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9829b314621dfc575df4e409e79f9d6a66a3bd707ab73f23cb4aa3a854ac854f"
+dependencies = [
+ "is_ci",
+]
+
+[[package]]
+name = "supports-hyperlinks"
+version = "3.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+checksum = "2c0a1e5168041f5f3ff68ff7d95dcb9c8749df29f6e7e89ada40dd4c9de404ee"
+
+[[package]]
+name = "supports-unicode"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2"
 
 [[package]]
 name = "syn"
-version = "2.0.52"
+version = "2.0.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
+checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-ident",
 ]
 
+[[package]]
+name = "tdl-core"
+version = "0.1.0"
+source = "git+ssh://git@git.skywarder.eu/federico.lolli/tdl.git?branch=main#487bd1b0373915c8840ae51f283010f78b054d78"
+dependencies = [
+ "logos",
+ "miette",
+ "serde",
+ "tdl-private-macros",
+ "thiserror",
+]
+
+[[package]]
+name = "tdl-private-macros"
+version = "0.1.0"
+source = "git+ssh://git@git.skywarder.eu/federico.lolli/tdl.git?branch=main#487bd1b0373915c8840ae51f283010f78b054d78"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "terminal_size"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
+dependencies = [
+ "rustix",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "termios"
 version = "0.2.2"
@@ -679,20 +830,31 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "textwrap"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
+dependencies = [
+ "smawk",
+ "unicode-linebreak",
+ "unicode-width",
+]
+
 [[package]]
 name = "thiserror"
-version = "1.0.57"
+version = "1.0.58"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
+checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.57"
+version = "1.0.58"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
+checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -701,13 +863,14 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.31"
+version = "0.3.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e"
+checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
 dependencies = [
  "deranged",
  "itoa",
  "libc",
+ "num-conv",
  "num_threads",
  "powerfmt",
  "serde",
@@ -723,10 +886,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 
 [[package]]
 name = "time-macros"
-version = "0.2.16"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f"
+checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
 dependencies = [
+ "num-conv",
  "time-core",
 ]
 
@@ -745,6 +909,18 @@ version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
+[[package]]
+name = "unicode-linebreak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
+
 [[package]]
 name = "utf8parse"
 version = "0.2.1"
@@ -788,7 +964,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.4",
 ]
 
 [[package]]
@@ -808,17 +984,17 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.52.0"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
+ "windows_aarch64_gnullvm 0.52.4",
+ "windows_aarch64_msvc 0.52.4",
+ "windows_i686_gnu 0.52.4",
+ "windows_i686_msvc 0.52.4",
+ "windows_x86_64_gnu 0.52.4",
+ "windows_x86_64_gnullvm 0.52.4",
+ "windows_x86_64_msvc 0.52.4",
 ]
 
 [[package]]
@@ -829,9 +1005,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -841,9 +1017,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -853,9 +1029,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -865,9 +1041,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -877,9 +1053,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -889,9 +1065,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -901,6 +1077,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
diff --git a/on-host/Cargo.toml b/on-host/Cargo.toml
index adbb4c8..c0eabb2 100644
--- a/on-host/Cargo.toml
+++ b/on-host/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
 
 [dependencies]
 clap = { version = "4.4.11", features = ["derive"] }
-color-eyre = { version = "0.6.3", default-features = false }
+miette = { version = "7.2.0", features = ["fancy"] }
 csv = "1.3.0"
 log = "0.4.20"
 serde = { version = "1.0.193", features = ["derive"] }
@@ -18,3 +18,12 @@ simple_logger = { version = "4.3.3", features = ["colors"] }
 git = "https://git.skywarder.eu/avn/swd/mavlink/mavlink-skyward-lib.git"
 branch = "rust"
 features = ["serde", "lyra"]
+
+[dependencies.tdl-core]
+git = "ssh://git@git.skywarder.eu/federico.lolli/tdl.git"
+branch = "main"
+optional = true
+
+[features]
+default = []
+tdl = ["dep:tdl-core"]
diff --git a/on-host/src/cli.rs b/on-host/src/cli.rs
index 906c600..a782b74 100644
--- a/on-host/src/cli.rs
+++ b/on-host/src/cli.rs
@@ -8,15 +8,38 @@ use clap::{
     Parser,
 };
 
+#[cfg(feature = "tdl")]
 #[derive(Debug, Parser)]
 #[command(styles=get_styles())]
 pub struct Cli {
+    /// The mode to use
+    #[clap(subcommand)]
+    pub mode: ModeFile,
+
     /// The serial port to use
     #[clap(short, long, value_name = "PORT")]
     pub port: Option<String>,
 
-    /// The input csv file to read from
-    pub csv_input: PathBuf,
+    /// baud rate
+    #[clap(short, long, default_value = "115200")]
+    pub baud_rate: u32,
+
+    /// disable SYNC MODE (wait for a sync signal from the device before proceding)
+    #[clap(short, long)]
+    pub no_sync: bool,
+
+    /// The log level
+    #[clap(short, long)]
+    pub verbose: bool,
+}
+
+#[cfg(not(feature = "tdl"))]
+#[derive(Debug, Parser)]
+#[command(styles=get_styles())]
+pub struct Cli {
+    /// The serial port to use
+    #[clap(short, long, value_name = "PORT")]
+    pub port: Option<String>,
 
     /// baud rate
     #[clap(short, long, default_value = "115200")]
@@ -26,11 +49,43 @@ pub struct Cli {
     #[clap(short, long)]
     pub no_sync: bool,
 
+    /// The CSV file to read from
+    //#[clap(value_name = "CSV_FILE")]
+    pub csv_file: PathBuf,
+
     /// The log level
     #[clap(short, long)]
     pub verbose: bool,
 }
 
+#[cfg(feature = "tdl")]
+#[derive(Debug, Parser)]
+pub enum ModeFile {
+    /// build mavlink packets from a TDL file
+    Tdl {
+        /// The TDL file to read from
+        tdl_file: PathBuf,
+
+        /// initial GPS latitude
+        #[clap(short = 'n', long, value_name = "LAT")]
+        lat: f64,
+
+        /// initial GPS longitude
+        #[clap(short = 'e', long, value_name = "LON")]
+        lon: f64,
+
+        /// initial GPS altitude
+        #[clap(short = 'u', long, value_name = "ALT")]
+        alt: f64,
+    },
+
+    /// parse mavlink packets from a CSV file
+    Csv {
+        /// The CSV file to read from
+        csv_file: PathBuf,
+    },
+}
+
 pub fn get_styles() -> Styles {
     Styles::styled()
         .usage(
diff --git a/on-host/src/csv.rs b/on-host/src/csv.rs
new file mode 100644
index 0000000..3f1f9a9
--- /dev/null
+++ b/on-host/src/csv.rs
@@ -0,0 +1,13 @@
+use std::io::Read;
+
+use skyward_mavlink::lyra::MavMessage;
+
+/// Read PAYLOAD_FLIGHT_TM messages from a CSV file
+pub fn read_packets_from_csv(csv_reader: impl Read) -> std::io::Result<Vec<MavMessage>> {
+    let mut packets = Vec::new();
+    let mut rdr = csv::Reader::from_reader(csv_reader);
+    for result in rdr.deserialize() {
+        packets.push(MavMessage::PAYLOAD_FLIGHT_TM(result?));
+    }
+    Ok(packets)
+}
diff --git a/on-host/src/main.rs b/on-host/src/main.rs
index 1cad812..0e7b663 100644
--- a/on-host/src/main.rs
+++ b/on-host/src/main.rs
@@ -1,5 +1,8 @@
 mod cli;
+mod csv;
 mod packet;
+#[cfg(feature = "tdl")]
+mod tdl;
 mod utils;
 
 use std::{
@@ -9,16 +12,19 @@ use std::{
 };
 
 use clap::Parser;
-use color_eyre::eyre::{Context, Result};
 use log::{debug, error, info, warn};
+use miette::{Context, IntoDiagnostic, Result};
 use serialport::SerialPort;
 use skyward_mavlink::{
     lyra::MavMessage,
     mavlink::{write_v1_msg, MavHeader},
 };
 
+#[cfg(feature = "tdl")]
+use crate::cli::ModeFile;
 use crate::{
     cli::Cli,
+    csv::read_packets_from_csv,
     packet::PacketSequence,
     utils::{get_first_stm32_serial_port, print_stats},
 };
@@ -26,7 +32,6 @@ use crate::{
 const ACK: u8 = 0x06;
 
 fn main() -> Result<()> {
-    color_eyre::install()?;
     let args: Cli = Cli::parse();
 
     let lvl = if args.verbose {
@@ -40,7 +45,8 @@ fn main() -> Result<()> {
         .with_level(lvl)
         .with_local_timestamps()
         .env()
-        .init()?;
+        .init()
+        .into_diagnostic()?;
 
     if !args.no_sync {
         info!("SYNC mode ENABLED");
@@ -48,13 +54,7 @@ fn main() -> Result<()> {
         info!("SYNC mode DISABLED");
     }
 
-    let mut packets = Vec::new();
-
-    info!("reading from {}", args.csv_input.display());
-    let mut rdr = csv::Reader::from_reader(File::open(args.csv_input).unwrap());
-    for result in rdr.deserialize() {
-        packets.push(MavMessage::PAYLOAD_FLIGHT_TM(result.unwrap()));
-    }
+    let packets = get_packets(&args)?;
     debug!("collected {} packets", packets.len());
 
     // convert to packet sequence data structure
@@ -73,10 +73,9 @@ fn main() -> Result<()> {
     debug!("connecting to serial port {}...", port_name);
     let mut port = serialport::new(port_name, args.baud_rate)
         .open()
+        .into_diagnostic()
         .wrap_err("Failed to open serial port")?;
-    let mut write_port = port.try_clone()?;
-
-    // let mut iter = packets.into_iter();
+    let mut write_port = port.try_clone().into_diagnostic()?;
 
     // read from buffer and print to stdout
     let mut buffer = [0u8; 1000];
@@ -108,6 +107,36 @@ fn main() -> Result<()> {
     Ok(())
 }
 
+#[cfg(feature = "tdl")]
+fn get_packets(args: &Cli) -> Result<Vec<MavMessage>> {
+    let packets: Vec<MavMessage> = match &args.mode {
+        ModeFile::Csv { csv_file } => {
+            info!("reading from csv file {}", csv_file.display());
+            read_packets_from_csv(File::open(csv_file).into_diagnostic()?).into_diagnostic()?
+        }
+        ModeFile::Tdl {
+            tdl_file,
+            lat,
+            lon,
+            alt,
+        } => {
+            info!("reading from tdl file {}", tdl_file.display());
+            tdl::generate_packets_from_tdl(tdl_file, *lat, *lon, *alt)?
+        }
+    };
+    debug!("collected {} packets", packets.len());
+    Ok(packets)
+}
+
+#[cfg(not(feature = "tdl"))]
+fn get_packets(args: &Cli) -> Result<Vec<MavMessage>> {
+    info!("reading from csv file {}", args.csv_file.display());
+    let packets =
+        read_packets_from_csv(File::open(&args.csv_file).into_diagnostic()?).into_diagnostic()?;
+    debug!("collected {} packets", packets.len());
+    Ok(packets)
+}
+
 /// Wait for ACK signal from the device
 fn wait_for_ack(port: &mut Box<dyn SerialPort>, buffer: &mut [u8]) {
     // wait ACK
@@ -141,6 +170,7 @@ impl<T: AsRef<dyn SerialPort> + std::io::Write> MavLinkPort for T {
     fn write_packet(&mut self, packet: MavMessage) -> Result<()> {
         let header = MavHeader::default();
         write_v1_msg(self, header, &packet)
+            .into_diagnostic()
             .wrap_err("Failed to write mavlink message to serial port")?;
         Ok(())
     }
diff --git a/on-host/src/tdl.rs b/on-host/src/tdl.rs
new file mode 100644
index 0000000..321255d
--- /dev/null
+++ b/on-host/src/tdl.rs
@@ -0,0 +1,191 @@
+use std::{path::Path, time::Instant};
+
+use miette::{miette, Context, IntoDiagnostic, Result};
+use skyward_mavlink::lyra::{MavMessage, PAYLOAD_FLIGHT_TM_DATA};
+use tdl_core::{
+    semantics::{Executor, Point, Trajectory},
+    syntax::CachedLexer,
+};
+
+pub fn generate_packets_from_tdl(
+    tdl_file: impl AsRef<Path>,
+    gps_lat: f64,
+    gps_lon: f64,
+    gps_alt: f64,
+) -> Result<Vec<MavMessage>> {
+    let tdl_content = std::fs::read_to_string(tdl_file.as_ref())
+        .into_diagnostic()
+        .wrap_err("Failed to read TDL file")?;
+    let program = CachedLexer::new(&tdl_content)
+        .parse_program()
+        .wrap_err("Failed to parse TDL program")?;
+    let traj = Executor::new(program)
+        .run()
+        .or(Err(miette!("Failed to execute TDL program")))?;
+    let generator = PayloadFlightGenerator::new(gps_lat, gps_lon, gps_alt);
+    generator.generate_packets(traj)
+}
+
+trait MessageGenerator {
+    fn generate_packets(self, traj: Trajectory) -> Result<Vec<MavMessage>>;
+}
+
+struct PayloadFlightGenerator {
+    normalization: Option<u128>,
+    max_altitude: f64,
+    initial_gps: (f64, f64, f64),
+    last_time: Option<f64>,
+    last_pos: Option<(f64, f64, f64)>,
+    last_vel: Option<(f64, f64, f64)>,
+    last_acc: Option<(f64, f64, f64)>,
+    ada_flip: bool,
+}
+
+impl PayloadFlightGenerator {
+    fn new(lat: f64, lon: f64, alt: f64) -> Self {
+        Self {
+            initial_gps: (lat, lon, alt),
+            normalization: None,
+            max_altitude: 0.0,
+            last_time: None,
+            last_pos: None,
+            last_vel: None,
+            last_acc: None,
+            ada_flip: false,
+        }
+    }
+
+    fn compute_velocity(&self, point: Point) -> Option<(f64, f64, f64)> {
+        if let Some((x, y, z)) = self.last_pos {
+            let dt = point.time - self.last_time?;
+            let dx = point.x - x;
+            let dy = point.y - y;
+            let dz = point.z - z;
+            Some((dx / dt, dy / dt, dz / dt))
+        } else {
+            None
+        }
+    }
+
+    fn compute_acceleration(
+        &self,
+        vel: Option<(f64, f64, f64)>,
+        time: f64,
+    ) -> Option<(f64, f64, f64)> {
+        let (vx, vy, vz) = vel?;
+        if let Some((lvx, lvy, lvz)) = self.last_vel {
+            let dt = time - self.last_time?;
+            let dvx = vx - lvx;
+            let dvy = vy - lvy;
+            let dvz = vz - lvz;
+            Some((dvx / dt, dvy / dt, dvz / dt))
+        } else {
+            None
+        }
+    }
+
+    fn consume_point(&mut self, point: Point) -> PAYLOAD_FLIGHT_TM_DATA {
+        let Point { x, y, z, time: t } = point;
+
+        // normalize time relative to now
+        let time = if let Some(offset) = self.normalization {
+            (t * 1e6).floor().min(u128::MAX as f64) as u128 + offset
+        } else {
+            let time_us = (t * 1e6).floor().min(u128::MAX as f64) as u128;
+            self.normalization = Some(Instant::now().elapsed().as_micros() - time_us);
+            0
+        };
+
+        // check for overflow
+        if time > u64::MAX as u128 {
+            panic!("Time overflow");
+        }
+
+        // calculate velocity and acceleration
+        let vel = self.compute_velocity(point);
+        let acc = self.compute_acceleration(vel, t).unwrap_or_default();
+        let vel = vel.unwrap_or_default();
+        // and save them
+        self.last_time = Some(t);
+        self.last_pos = Some((x, y, z));
+        self.last_vel = Some(vel);
+        self.last_acc = Some(acc);
+
+        // check for max altitude reached
+        if z >= self.max_altitude && !self.ada_flip {
+            self.max_altitude = z;
+        } else {
+            self.ada_flip = true;
+        }
+
+        // deconstruct the tuple
+        let (x, y, z) = (x as f32, y as f32, z as f32);
+        let (vx, vy, vz) = (vel.0 as f32, vel.1 as f32, vel.2 as f32);
+        let (ax, ay, az) = (acc.0 as f32, acc.1 as f32, acc.2 as f32);
+
+        let pin = if self.ada_flip { 1 } else { 0 };
+
+        let (lat, lon, alt) = self.initial_gps;
+        let (lat, lon, alt) = (lat as f32, lon as f32, alt as f32);
+
+        PAYLOAD_FLIGHT_TM_DATA {
+            timestamp: time as u64,
+            pressure_digi: 88400.0,
+            pressure_static: 88400.0,
+            airspeed_pitot: 10.0,
+            altitude_agl: z,
+            acc_x: ax,
+            acc_y: ay,
+            acc_z: az,
+            gyro_x: 0.0,
+            gyro_y: 0.0,
+            gyro_z: 0.0,
+            mag_x: 0.0,
+            mag_y: 0.0,
+            mag_z: 0.0,
+            gps_lat: lat,
+            gps_lon: lon,
+            gps_alt: alt,
+            left_servo_angle: 0.0,
+            right_servo_angle: 0.0,
+            nas_n: y,
+            nas_e: x,
+            nas_d: -z,
+            nas_vn: vy,
+            nas_ve: vx,
+            nas_vd: -vz,
+            nas_qx: 0.0,
+            nas_qy: 0.0,
+            nas_qz: 0.0,
+            nas_qw: 1.0,
+            nas_bias_x: 0.0,
+            nas_bias_y: 0.0,
+            nas_bias_z: 0.0,
+            wes_n: 0.0,
+            wes_e: 0.0,
+            battery_voltage: 8.0,
+            cam_battery_voltage: 8.0,
+            current_consumption: 0.0,
+            temperature: 40.0,
+            fmm_state: 0,
+            nas_state: 0,
+            wes_state: 0,
+            gps_fix: 3,
+            pin_nosecone: pin,
+            cutter_presence: 0,
+            logger_error: 0,
+        }
+    }
+}
+
+impl MessageGenerator for PayloadFlightGenerator {
+    fn generate_packets(mut self, traj: Trajectory) -> Result<Vec<MavMessage>> {
+        let Trajectory { points } = traj;
+        let mut packets = Vec::new();
+        for point in points {
+            let packet = self.consume_point(point);
+            packets.push(MavMessage::PAYLOAD_FLIGHT_TM(packet));
+        }
+        Ok(packets)
+    }
+}
diff --git a/on-host/src/utils.rs b/on-host/src/utils.rs
index e8e6c3d..c2398a3 100644
--- a/on-host/src/utils.rs
+++ b/on-host/src/utils.rs
@@ -1,9 +1,11 @@
-use color_eyre::eyre::{Context, Result};
 use log::info;
+use miette::{Context, IntoDiagnostic, Result};
 
 /// Get the first serial port that contains "STM32" or "ST-LINK" in its product name
 pub fn get_first_stm32_serial_port() -> Result<Option<String>> {
-    let ports = serialport::available_ports().wrap_err("No serial ports found!")?;
+    let ports = serialport::available_ports()
+        .into_diagnostic()
+        .wrap_err("No serial ports found!")?;
     for port in ports {
         if let serialport::SerialPortType::UsbPort(info) = port.port_type {
             if let Some(p) = info.product {
-- 
GitLab