diff --git a/Cargo.lock b/Cargo.lock index a1520c7..15ba0e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,6 +142,15 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "async_runtime" +version = "0.1.0" +source = "git+https://github.com/qorix-group/qor-runtime.git?rev=cfb01d7c55fe9021dd5539660167792826b88182#cfb01d7c55fe9021dd5539660167792826b88182" +dependencies = [ + "foundation", + "iceoryx2-pal-concurrency-sync", +] + [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -225,6 +234,8 @@ version = "1.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -253,6 +264,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "clang-sys" version = "1.8.1" @@ -264,12 +281,49 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "4.5.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +dependencies = [ + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + [[package]] name = "cobs" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +[[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", +] + [[package]] name = "colorchoice" version = "1.0.3" @@ -295,6 +349,94 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +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 = "cxx" +version = "1.0.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b4ab2681454aacfe7ce296ebc6df86791009f237f8020b0c752e8b245ba7c1d" +dependencies = [ + "cc", + "cxxbridge-cmd", + "cxxbridge-flags", + "cxxbridge-macro", + "foldhash", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e431f7ba795550f2b11c32509b3b35927d899f0ad13a1d1e030a317a08facbe" +dependencies = [ + "cc", + "codespan-reporting", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.96", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cbc41933767955d04c2a90151806029b93df5fd8b682ba22a967433347480a9" +dependencies = [ + "clap", + "codespan-reporting", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9133547634329a5b76e5f58d1e53c16d627699bbcd421b9007796311165f9667" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e89d77ad5fd6066a3d42d94de3f72a2f23f95006da808177624429b5183596" +dependencies = [ + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.96", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "deranged" version = "0.3.11" @@ -420,12 +562,16 @@ dependencies = [ name = "feo-mini-adas" version = "0.1.0" dependencies = [ + "async_runtime", "cc", "feo", "feo-log", "feo-logger", "feo-time", "feo-tracing", + "foundation", + "logging_tracing", + "orchestration", ] [[package]] @@ -487,6 +633,31 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foundation" +version = "0.1.0" +source = "git+https://github.com/qorix-group/qor-runtime.git?rev=cfb01d7c55fe9021dd5539660167792826b88182#cfb01d7c55fe9021dd5539660167792826b88182" +dependencies = [ + "iceoryx2-bb-container", + "iceoryx2-bb-derive-macros", + "iceoryx2-bb-elementary", + "iceoryx2-bb-lock-free", + "iceoryx2-bb-memory", + "iceoryx2-bb-posix", + "iceoryx2-bb-system-types", + "iceoryx2-bb-testing", + "iceoryx2-bb-threadsafe", + "iceoryx2-pal-concurrency-sync", + "tracing", + "tracing-subscriber", +] + [[package]] name = "futures" version = "0.3.31" @@ -584,7 +755,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -619,6 +802,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.15.2" @@ -800,6 +989,26 @@ dependencies = [ "serde", ] +[[package]] +name = "iceoryx2-bb-testing" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26bd3a76016023d6b5bf48b0a284248454f2b273158e924f3c0802d069b26fc1" +dependencies = [ + "iceoryx2-pal-configuration", +] + +[[package]] +name = "iceoryx2-bb-threadsafe" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4db459bf7eb91676e87e3fa6623be86dcfc2d87a7bb2b5e2552692d6d6ab9400" +dependencies = [ + "iceoryx2-bb-container", + "iceoryx2-bb-log", + "iceoryx2-bb-posix", +] + [[package]] name = "iceoryx2-cal" version = "0.5.0" @@ -857,7 +1066,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] @@ -913,6 +1122,16 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.2", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -937,9 +1156,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libloading" @@ -951,6 +1170,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "link-cplusplus" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" +dependencies = [ + "cc", +] + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -992,25 +1220,32 @@ dependencies = [ ] [[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +name = "logging_tracing" +version = "0.1.0" +source = "git+https://github.com/qorix-group/qor-runtime.git?rev=cfb01d7c55fe9021dd5539660167792826b88182#cfb01d7c55fe9021dd5539660167792826b88182" +dependencies = [ + "tracing", + "tracing-appender", + "tracing-perfetto-sdk-layer", + "tracing-perfetto-sdk-schema", + "tracing-subscriber", +] [[package]] -name = "mini-adas-recording" +name = "matchers" version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "cc", - "feo", - "feo-log", - "feo-logger", - "feo-time", - "feo-tracing", - "postcard", - "serde", + "regex-automata 0.1.10", ] +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1034,7 +1269,7 @@ checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -1044,6 +1279,18 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -1054,6 +1301,16 @@ dependencies = [ "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-conv" version = "0.1.0" @@ -1081,6 +1338,20 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "orchestration" +version = "0.1.0" +source = "git+https://github.com/qorix-group/qor-runtime.git?rev=cfb01d7c55fe9021dd5539660167792826b88182#cfb01d7c55fe9021dd5539660167792826b88182" +dependencies = [ + "async_runtime", + "foundation", + "iceoryx2", + "libc", + "logging_tracing", + "tracing", + "tracing-subscriber", +] + [[package]] name = "ouroboros" version = "0.18.5" @@ -1105,6 +1376,25 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + [[package]] name = "perfetto-model" version = "0.1.0" @@ -1293,6 +1583,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rand" version = "0.8.5" @@ -1320,7 +1616,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "redox_syscall" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +dependencies = [ + "bitflags", ] [[package]] @@ -1331,8 +1636,17 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -1343,9 +1657,15 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.5", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.5" @@ -1392,6 +1712,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + [[package]] name = "ryu" version = "1.0.18" @@ -1404,6 +1730,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scratch" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52" + [[package]] name = "semver" version = "1.0.24" @@ -1457,6 +1789,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" +[[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" @@ -1481,6 +1822,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" + [[package]] name = "socket2" version = "0.5.8" @@ -1512,6 +1859,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "1.0.109" @@ -1542,12 +1895,21 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", - "getrandom", + "getrandom 0.2.15", "once_cell", "rustix", "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 = "termsize" version = "0.1.9" @@ -1558,6 +1920,66 @@ dependencies = [ "winapi", ] +[[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.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[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.96", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "thread-id" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99043e46c5a15af379c06add30d9c93a6c0e8849de00d244c4a2c417da128d80" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "time" version = "0.3.37" @@ -1691,6 +2113,18 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror 1.0.69", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.28" @@ -1709,6 +2143,61 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-perfetto-sdk-layer" +version = "0.12.0" +source = "git+https://github.com/qorix-group/tracing-perfetto-sdk.git?branch=qor_adaptations#1ac565c2bff2715a3e34714e5777e28572c6e6d6" +dependencies = [ + "bytes", + "cxx", + "dashmap", + "libc", + "nix", + "prost", + "thiserror 2.0.12", + "thread-id", + "thread_local", + "tracing", + "tracing-perfetto-sdk-schema", + "tracing-perfetto-sdk-sys", + "tracing-subscriber", +] + +[[package]] +name = "tracing-perfetto-sdk-schema" +version = "0.12.0" +source = "git+https://github.com/qorix-group/tracing-perfetto-sdk.git?branch=qor_adaptations#1ac565c2bff2715a3e34714e5777e28572c6e6d6" +dependencies = [ + "anyhow", + "prost", + "prost-build", + "prost-types", +] + +[[package]] +name = "tracing-perfetto-sdk-sys" +version = "0.12.0" +source = "git+https://github.com/qorix-group/tracing-perfetto-sdk.git?branch=qor_adaptations#1ac565c2bff2715a3e34714e5777e28572c6e6d6" +dependencies = [ + "anyhow", + "bytes", + "cc", + "cxx", + "cxx-build", ] [[package]] @@ -1730,7 +2219,16 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", "tracing-core", + "tracing-log", ] [[package]] @@ -1751,6 +2249,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "version_check" version = "0.9.5" @@ -1763,6 +2267,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -1858,6 +2371,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2021,6 +2543,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + [[package]] name = "yansi" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 14e118d..7534f85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = [ "examples/rust/feo-mini-adas", "examples/rust/greeter", "examples/rust/greetings", - "examples/rust/mini-adas-recording", + # "examples/rust/mini-adas-recording", "feo", "feo-log", "feo-logger", @@ -15,7 +15,21 @@ members = [ ] resolver = "2" + [workspace.dependencies] + +async_runtime = { git = "https://github.com/qorix-group/qor-runtime.git" , rev = "cfb01d7c55fe9021dd5539660167792826b88182" } +orchestration = { git = "https://github.com/qorix-group/qor-runtime.git" , rev = "cfb01d7c55fe9021dd5539660167792826b88182" } +logging_tracing = { git = "https://github.com/qorix-group/qor-runtime.git" , rev = "cfb01d7c55fe9021dd5539660167792826b88182" } +foundation = { git = "https://github.com/qorix-group/qor-runtime.git", rev = "cfb01d7c55fe9021dd5539660167792826b88182" } + + +#async_runtime = { path = "../performance_stack_rust/async_runtime" } +#orchestration = { path = "../performance_stack_rust/orchestration" } +#logging_tracing = { path = "../performance_stack_rust/logging_tracing" } +#foundation = { path = "../performance_stack_rust/foundation" } + + anyhow = "1.0.49" argh = "0.1.13" async-stream = "0.3.6" diff --git a/README.md b/README.md index 19d2b15..006dcff 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # score-feo +## Disclaimer +This is port of FEO for `qor-runtime`. Currently, this builds only with `cargo build` as there are some issues +with integration for `bazel` due to using native perfetto sdk as tracing for system events. This is WIP. + ## Rust setup You can build the Rust code both with `bazel` and with `cargo`. diff --git a/doc/feo_agent.png b/doc/feo_agent.png new file mode 100755 index 0000000..0d42397 Binary files /dev/null and b/doc/feo_agent.png differ diff --git a/doc/feo_executor.png b/doc/feo_executor.png new file mode 100755 index 0000000..2353239 Binary files /dev/null and b/doc/feo_executor.png differ diff --git a/doc/orch_feo.md b/doc/orch_feo.md new file mode 100644 index 0000000..9c00a27 --- /dev/null +++ b/doc/orch_feo.md @@ -0,0 +1,383 @@ +# Orchestration & FEO + +## Static view + + + +## FEO agents +FEO agents are responsible to wait on `Executor` commands and execute them. Below we describe how each part of FEO agent is transcoded by `Orchestration API`. + +### Startup (A) +Each FEO agent on startup is suppose to: +- let primary process know it's alive +- wait for startup signal +- report started and enter into normal execution (waiting for orders) + +This is encoded by using combination of `Sequence` and `Concurrency` `actions`: + +```mermaid +graph LR; + Trigger["Trigger(application_id/agent_id/alive)"]-->SyncS["Sync(application_id/startup)"] + + SyncS --> Activity1["Activity1.startup()"]; + SyncS --> Activity2["Activity2.startup()"]; + SyncS --> Activity3["Activity3.startup()"]; + + Activity1 --> TriggerE["Trigger(application_id/agent_id/startup_completed)"] + Activity2 -->TriggerE; + Activity3 -->TriggerE; + + TriggerE --> SyncSS["Sync(application_id/start)"] + + subgraph Concurrency + Activity1 + Activity2 + Activity3 + end + + subgraph Sequence + SyncS + TriggerE + Concurrency + Trigger + SyncSS + end + +``` + +### Step (B) +Each activity step function is encoded by simple `Sequence` of `actions`: + +```mermaid +graph LR; + Sync["Sync(application_id/activity_id/step)"]-->Step; + Step["ActivityN.step()"]--> Trigger["Sync(application_id/activity_id/step_completed)"]; + + subgraph Sequence + Sync + Step + Trigger + end +``` + +### Shutdown (C) + +The shutdown functionality is encoded by simple `Sequence` and `Concurrency` `actions`: + +```mermaid +graph LR; + + Activity1["Activity1.shutdown()"]; + Activity2["Activity2.shutdown()"]; + Activity3["Activity3.shutdown()"]; + + Activity1 --> TriggerE["Trigger(application_id/agent_id/shutdown_completed)"] + Activity2 -->TriggerE; + Activity3 -->TriggerE; + + subgraph Concurrency + Activity1 + Activity2 + Activity3 + end + + subgraph Sequence + SyncS + TriggerE + Concurrency + end + +``` + +### Shutdown request (D) +The agent shall all time wait for a request to shutdown, this is relized simply by registering hook: + +```mermaid +graph LR; + Sync["Sync(application_id/shutdown)"] +``` + +### Overall FEO agent +The overall FEO agent implemented by `Orchestration API` is a `Program` that is composed using above functionalities as below: + + + + + +## FEO Executor +The executor is responsible for +- coordinate startup +- executing graph logic for activities +- coordinate shutdown +- .... + +### Startup (A) +The startup coordination is build as below: + +```mermaid +graph LR; + SyncA1["Sync(application_id/agent_id_1/alive)"]; + SyncA2["Sync(application_id/agent_id_2/alive)"]; + SyncA3["Sync(application_id/agent_id_2/alive)"]; + + SyncA1 --> TriggerS; + SyncA2 --> TriggerS; + SyncA3 --> TriggerS; + + TriggerS["TriggerA1(application_id/startup)"]; + + TriggerS --> SyncA1C; + TriggerS --> SyncA2C; + TriggerS --> SyncA3C; + + + SyncA1C["Sync(application_id/agent_id_1/startup_completed)"]; + SyncA2C["Sync(application_id/agent_id_2/startup_completed)"]; + SyncA3C["Sync(application_id/agent_id_2/startup_completed)"]; + + TriggerSE["TriggerA1(application_id/start)"]; + + SyncA1C --> TriggerSE; + SyncA2C --> TriggerSE; + SyncA3C --> TriggerSE; + + subgraph Concurrency2 + SyncA1C + SyncA2C + SyncA3C + end + + subgraph Concurrency1 + SyncA1 + SyncA2 + SyncA3 + end + + subgraph Sequence + Concurrency1 + TriggerS + Concurrency2 + TriggerSE + end +``` + +### Graph execution (B) +The graph of activities is translated currently with below schema: +- each activity is separate concurrent branch that can run as soon as all conditions are met +- each activity without dependency can run immediately in single cycle +- each activity with dependencies is translated into `Sequence` of `Sync` actions for corresponding "done" event before it can run +- each run execution is encoded as `Trigger` (start) & `Sync` (wait for finish) action + + +The above bolis down to translate below graph: + +```mermaid +graph TD; +0 --> 2; +1 --> 2; + +2 --> 3; + +2 --> 4; +2 --> 5; + +4 --> 6; +5 --> 7; +``` + +into + +```mermaid +graph TD; + + %% Activity 0 + TriggerA0E["Trigger(application_id/0/step)"]; + SyncA0EC["Sync(application_id/0/step_completed)"]; + + + TriggerA0E --> SyncA0EC; + + subgraph Sequence0 + direction TB + TriggerA0E + SyncA0EC + end + + %% Activity 1 + TriggerA1E["Trigger(application_id/1/step)"]; + SyncA1EC["Sync(application_id/1/step_completed)"]; + + + TriggerA1E --> SyncA1EC; + + subgraph Sequence1 + direction TB + TriggerA1E + SyncA1EC + end + + + + %% Activity 2 + + SyncA2D1["Sync(application_id/0/step_completed)"]; + SyncA2D2["Sync(application_id/1/step_completed)"]; + + TriggerA2E["Trigger(application_id/2/step)"]; + SyncA2EC["Sync(application_id/2/step_completed)"]; + + SyncA2D1 --> SyncA2D2; + SyncA2D2 --> TriggerA2E; + TriggerA2E --> SyncA2EC; + + subgraph Sequence2 + direction TB + SyncA2D1 + SyncA2D2 + TriggerA2E + SyncA2EC + end + + %% Activity 3 + + SyncA3D1["Sync(application_id/2/step_completed)"]; + + TriggerA3E["Trigger(application_id/3/step)"]; + SyncA3EC["Sync(application_id/3/step_completed)"]; + + + SyncA3D1 --> TriggerA3E; + TriggerA3E --> SyncA3EC; + + subgraph Sequence3 + direction TB + SyncA3D1 + TriggerA3E + SyncA3EC + end + + %% Activity 4 + + SyncA4D1["Sync(application_id/2/step_completed)"]; + + TriggerA4E["Trigger(application_id/4/step)"]; + SyncA4EC["Sync(application_id/4/step_completed)"]; + + + SyncA4D1 --> TriggerA4E; + TriggerA4E --> SyncA4EC; + + subgraph Sequence4 + direction TB + SyncA4D1 + TriggerA4E + SyncA4EC + end + + %% Activity 5 + + SyncA5D1["Sync(application_id/2/step_completed)"]; + + TriggerA5E["Trigger(application_id/5/step)"]; + SyncA5EC["Sync(application_id/5/step_completed)"]; + + + SyncA5D1 --> TriggerA5E; + TriggerA5E --> SyncA5EC; + + subgraph Sequence5 + direction TB + SyncA5D1 + TriggerA5E + SyncA5EC + end + + %% Activity 6 + + SyncA6D1["Sync(application_id/4/step_completed)"]; + + TriggerA6E["Trigger(application_id/6/step)"]; + SyncA6EC["Sync(application_id/6/step_completed)"]; + + + SyncA6D1 --> TriggerA6E; + TriggerA6E --> SyncA6EC; + + subgraph Sequence6 + direction TB + SyncA6D1 + TriggerA6E + SyncA6EC + end + + %% Activity 7 + + SyncA7D1["Sync(application_id/5/step_completed)"]; + + TriggerA7E["Trigger(application_id/7/step)"]; + SyncA7EC["Sync(application_id/7/step_completed)"]; + + + SyncA7D1 --> TriggerA7E; + TriggerA7E --> SyncA7EC; + + subgraph Sequence7 + direction TB + SyncA7D1 + TriggerA7E + SyncA7EC + end + + + subgraph Concurrency + Sequence0 + Sequence1 + Sequence2 + Sequence3 + Sequence4 + Sequence5 + Sequence6 + Sequence7 + end + +``` + +### Shutdown (C) +The shutdown coordination is build as below: + +```mermaid +graph LR; + + ExecS["Trigger(application_id/shutdown)"] --> Sync1["Sync(application_id/agent_1_id/shutdown_completed)"]; + + ExecS --> Sync2["Sync(application_id/agent_2_id/shutdown_completed)"]; + ExecS --> Sync3["Sync(application_id/agent_3_id/shutdown_completed)"]; + + subgraph Sequence + ExecS + Concurrency + end + + subgraph Concurrency + Sync1 + Sync2 + Sync3 + end + +``` + + +### Shutdown request (D) + +The primary process can connect any source to start shutdown routine. Currently this is not used in FEO as such signals is not defined. + + +### Overall FEO executor +The overall FEO executor implemented by `Orchestration API` is a `Program` that is composed using above functionalities as below: + + + +Additionally `ProgramBuilder` let us configure: +- cycle time +- overall error reaction +- ... \ No newline at end of file diff --git a/doc/static_view.drawio.svg b/doc/static_view.drawio.svg new file mode 100644 index 0000000..30fb60e --- /dev/null +++ b/doc/static_view.drawio.svg @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + FEO + + + + + + FEO + + + + + + + + + + + + + + + ASYNC RUNTIME + + + + + + ASYNC RUNTIME + + + + + + + + + + + + + + + ORCHESTRATION + + + + + + ORCHESTRATION + + + + + + + + + + + + + + + MIDDLWARE API 1 + + + + + + MIDDLWARE API 1 + + + + + + + + + + + + + + + + MIDDLWARE API N + + + + + + + MIDDLWARE API N + + + + + + + + + + + + + + + + + + Task chain control + + + + + + Task chain... + + + + + + + + + + + + + + + + + + + + + Potential usage of async API in FEO + + + + + + Potential usage... + + + + + + + + + + + + + + + MD API 2 + + + + + + MD API 2 + + + + + + + + + + + + + + + + + + Current integration + + + + + + Current integration + + + + + + + + + + + + + + + Possible usage + + + + + + Possible usage + + + + + + + + + + + + + + + Legend + + + + + + Legend + + + + + + + + + + Text is not SVG - cannot display + + + + \ No newline at end of file diff --git a/examples/rust/feo-mini-adas/Cargo.toml b/examples/rust/feo-mini-adas/Cargo.toml index bad9b98..136cca0 100644 --- a/examples/rust/feo-mini-adas/Cargo.toml +++ b/examples/rust/feo-mini-adas/Cargo.toml @@ -10,6 +10,11 @@ feo-logger = { workspace = true } feo-time = { workspace = true } feo-tracing = { workspace = true } +async_runtime = { workspace = true } +orchestration = { workspace = true } +logging_tracing = { workspace = true } +foundation = { workspace = true } + [build-dependencies] cc = { workspace = true } diff --git a/examples/rust/feo-mini-adas/src/activities/components.rs b/examples/rust/feo-mini-adas/src/activities/components.rs index ff15b09..1f6141a 100644 --- a/examples/rust/feo-mini-adas/src/activities/components.rs +++ b/examples/rust/feo-mini-adas/src/activities/components.rs @@ -11,10 +11,12 @@ use feo::com::{ActivityInput, ActivityOutput}; use feo::prelude::{Activity, ActivityId}; use feo_log::debug; use feo_tracing::{instrument, tracing}; +use orchestration::prelude::*; use std::ffi::c_void; use std::hash::{BuildHasher as _, Hasher as _, RandomState}; use std::mem::MaybeUninit; use std::ops::Range; +use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; @@ -37,14 +39,14 @@ pub struct Camera { } impl Camera { - pub fn build(activity_id: ActivityId, image_topic: &str) -> Box { - Box::new(Self { + pub fn build(activity_id: ActivityId, image_topic: &str) -> Self { + Self { activity_id, output_image: ActivityOutput::get(image_topic), num_people: 4, num_cars: 10, distance_obstacle: 40.0, - }) + } } fn get_image(&mut self) -> CameraImage { @@ -65,6 +67,8 @@ impl Camera { } } +unsafe impl Send for Camera {} + impl Activity for Camera { fn id(&self) -> ActivityId { self.activity_id @@ -105,12 +109,12 @@ pub struct Radar { } impl Radar { - pub fn build(activity_id: ActivityId, radar_topic: &str) -> Box { - Box::new(Self { + pub fn build(activity_id: ActivityId, radar_topic: &str) -> Self { + Self { activity_id, output_scan: ActivityOutput::get(radar_topic), distance_obstacle: 40.0, - }) + } } fn get_scan(&mut self) -> RadarScan { @@ -128,6 +132,8 @@ impl Radar { } } +unsafe impl Send for Radar {} + impl Activity for Radar { fn id(&self) -> ActivityId { self.activity_id @@ -170,19 +176,54 @@ pub struct NeuralNet { output_scene: ActivityOutput, } +unsafe impl Send for NeuralNet {} // TODO: Both Feo and runtime has to fix this, runtime will support not send soon, but maybe + // feo itself shall not provoke !Send without any good reason - issues comes out of iceoryx2 + +pub trait ActivityAdapterTrait: Send { + type T; // Activity Type + + /// + /// This let you use async context in step function so You are free now to use non blocking sleep, non blocking wait on IO etc. + /// There is no problem to create trait with plain `fn` but then async context is lost for activity + /// + fn step_runtime( + instance: Arc>, + ) -> impl std::future::Future + Send; + + fn start(&mut self) -> ActionResult; + + fn stop(&mut self) -> ActionResult; + + fn get_act_id(&self) -> ActivityId; +} + impl NeuralNet { pub fn build( activity_id: ActivityId, image_topic: &str, scan_topic: &str, scene_topic: &str, - ) -> Box { - Box::new(Self { + ) -> Self { + Self { activity_id, input_image: ActivityInput::get(image_topic), input_scan: ActivityInput::get(scan_topic), output_scene: ActivityOutput::get(scene_topic), - }) + } + } + + pub fn build_val( + activity_id: ActivityId, + image_topic: &str, + scan_topic: &str, + scene_topic: &str, + ) -> Self { + Self { + activity_id, + input_image: ActivityInput::get(image_topic), + input_scan: ActivityInput::get(scan_topic), + output_scene: ActivityOutput::get(scene_topic), + } } fn infer(image: &CameraImage, radar: &RadarScan, scene: &mut MaybeUninit) { @@ -258,17 +299,19 @@ pub struct EmergencyBraking { output_brake_instruction: ActivityOutput, } +unsafe impl Send for EmergencyBraking {} + impl EmergencyBraking { pub fn build( activity_id: ActivityId, scene_topic: &str, brake_instruction_topic: &str, - ) -> Box { - Box::new(Self { + ) -> Self { + Self { activity_id, input_scene: ActivityInput::get(scene_topic), output_brake_instruction: ActivityOutput::get(brake_instruction_topic), - }) + } } } @@ -333,12 +376,14 @@ pub struct BrakeController { input_brake_instruction: ActivityInput, } +unsafe impl Send for BrakeController {} + impl BrakeController { - pub fn build(activity_id: ActivityId, brake_instruction_topic: &str) -> Box { - Box::new(Self { + pub fn build(activity_id: ActivityId, brake_instruction_topic: &str) -> Self { + Self { activity_id, input_brake_instruction: ActivityInput::get(brake_instruction_topic), - }) + } } } @@ -382,12 +427,14 @@ pub struct EnvironmentRenderer { input_scene: ActivityInput, } +unsafe impl Send for EnvironmentRenderer {} + impl EnvironmentRenderer { - pub fn build(activity_id: ActivityId, scene_topic: &str) -> Box { - Box::new(Self { + pub fn build(activity_id: ActivityId, scene_topic: &str) -> Self { + Self { activity_id, input_scene: ActivityInput::get(scene_topic), - }) + } } } @@ -431,21 +478,19 @@ pub struct LaneAssist { cpp_activity: *mut c_void, } +unsafe impl Send for LaneAssist {} + impl LaneAssist { - pub fn build( - activity_id: ActivityId, - scene_topic: &str, - steering_topic: &str, - ) -> Box { + pub fn build(activity_id: ActivityId, scene_topic: &str, steering_topic: &str) -> Self { // Create C++ activity in heap memory of C++ let cpp_activity = unsafe { create_lane_assist(activity_id.into()) }; - Box::new(Self { + Self { activity_id, input_scene: ActivityInput::get(scene_topic), output_steering: ActivityOutput::get(steering_topic), cpp_activity, - }) + } } } @@ -507,12 +552,14 @@ pub struct SteeringController { input_steering: ActivityInput, } +unsafe impl Send for SteeringController {} + impl SteeringController { - pub fn build(activity_id: ActivityId, steering_topic: &str) -> Box { - Box::new(Self { + pub fn build(activity_id: ActivityId, steering_topic: &str) -> Self { + Self { activity_id, input_steering: ActivityInput::get(steering_topic), - }) + } } } @@ -582,3 +629,214 @@ fn sleep_random() { gen_random_in_range(SLEEP_RANGE) as u64 )); } + +impl ActivityAdapterTrait for EnvironmentRenderer { + type T = EnvironmentRenderer; + + fn step_runtime( + instance: Arc>, + ) -> impl std::future::Future + Send { + async move { + instance.lock().unwrap().step(); + Ok(()) + } + } + + fn start(&mut self) -> ActionResult { + self.startup(); + Ok(()) + } + + fn stop(&mut self) -> ActionResult { + self.shutdown(); + Ok(()) + } + + fn get_act_id(&self) -> ActivityId { + self.activity_id + } +} + +impl ActivityAdapterTrait for NeuralNet { + type T = NeuralNet; + + fn step_runtime( + instance: Arc>, + ) -> impl std::future::Future + Send { + async move { + instance.lock().unwrap().step(); + Ok(()) + } + } + + fn start(&mut self) -> ActionResult { + self.startup(); + Ok(()) + } + + fn stop(&mut self) -> ActionResult { + self.shutdown(); + Ok(()) + } + + fn get_act_id(&self) -> ActivityId { + self.activity_id + } +} + +impl ActivityAdapterTrait for EmergencyBraking { + type T = EmergencyBraking; + + fn step_runtime( + instance: Arc>, + ) -> impl std::future::Future + Send { + async move { + instance.lock().unwrap().step(); + Ok(()) + } + } + + fn start(&mut self) -> ActionResult { + self.startup(); + Ok(()) + } + + fn stop(&mut self) -> ActionResult { + self.shutdown(); + Ok(()) + } + + fn get_act_id(&self) -> ActivityId { + self.activity_id + } +} + +impl ActivityAdapterTrait for BrakeController { + type T = BrakeController; + + fn step_runtime( + instance: Arc>, + ) -> impl std::future::Future + Send { + async move { + instance.lock().unwrap().step(); + Ok(()) + } + } + fn start(&mut self) -> ActionResult { + self.startup(); + Ok(()) + } + + fn stop(&mut self) -> ActionResult { + self.shutdown(); + Ok(()) + } + + fn get_act_id(&self) -> ActivityId { + self.activity_id + } +} + +impl ActivityAdapterTrait for LaneAssist { + type T = LaneAssist; + + fn step_runtime( + instance: Arc>, + ) -> impl std::future::Future + Send { + async move { + instance.lock().unwrap().step(); + Ok(()) + } + } + + fn start(&mut self) -> ActionResult { + self.startup(); + Ok(()) + } + + fn stop(&mut self) -> ActionResult { + self.shutdown(); + Ok(()) + } + + fn get_act_id(&self) -> ActivityId { + self.activity_id + } +} + +impl ActivityAdapterTrait for SteeringController { + type T = SteeringController; + + async fn step_runtime(instance: Arc>) -> ActionResult { + instance.lock().unwrap().step(); + Ok(()) + } + + fn start(&mut self) -> ActionResult { + self.startup(); + Ok(()) + } + + fn stop(&mut self) -> ActionResult { + self.shutdown(); + Ok(()) + } + + fn get_act_id(&self) -> ActivityId { + self.activity_id + } +} + +impl ActivityAdapterTrait for Radar { + type T = Radar; + + fn step_runtime( + instance: Arc>, + ) -> impl std::future::Future + Send { + async move { + instance.lock().unwrap().step(); + Ok(()) + } + } + + fn start(&mut self) -> ActionResult { + self.startup(); + Ok(()) + } + + fn stop(&mut self) -> ActionResult { + self.shutdown(); + Ok(()) + } + + fn get_act_id(&self) -> ActivityId { + self.activity_id + } +} + +impl ActivityAdapterTrait for Camera { + type T = Camera; + + fn step_runtime( + instance: Arc>, + ) -> impl std::future::Future + Send { + async move { + instance.lock().unwrap().step(); + Ok(()) + } + } + + fn start(&mut self) -> ActionResult { + self.startup(); + Ok(()) + } + + fn stop(&mut self) -> ActionResult { + self.shutdown(); + Ok(()) + } + + fn get_act_id(&self) -> ActivityId { + self.activity_id + } +} diff --git a/examples/rust/feo-mini-adas/src/activities/mod.rs b/examples/rust/feo-mini-adas/src/activities/mod.rs index 2a065ef..a3f6dd8 100644 --- a/examples/rust/feo-mini-adas/src/activities/mod.rs +++ b/examples/rust/feo-mini-adas/src/activities/mod.rs @@ -4,3 +4,4 @@ pub mod components; pub mod messages; +pub mod runtime_adapters; diff --git a/examples/rust/feo-mini-adas/src/activities/runtime_adapters.rs b/examples/rust/feo-mini-adas/src/activities/runtime_adapters.rs new file mode 100644 index 0000000..f56953a --- /dev/null +++ b/examples/rust/feo-mini-adas/src/activities/runtime_adapters.rs @@ -0,0 +1,390 @@ +// Copyright (c) 2025 Qorix GmbH +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: Apache-2.0 +// + +// +// Well known issues: +// - currently activity must be hidden behind Mutex - subject to be lifted +// - !Send issues due to iceoryx +// - ... +// +use std::{ + sync::{Arc, Mutex}, + time::Duration, +}; + +use async_runtime::runtime::runtime::AsyncRuntime; +use feo::{configuration::primary_agent::ActivityDependencies, prelude::ActivityId}; +use foundation::threading::thread_wait_barrier::{ThreadReadyNotifier, ThreadWaitBarrier}; +use orchestration::{ + prelude::*, + program::{Program, ProgramBuilder}, +}; + +use super::components::ActivityAdapterTrait; +use logging_tracing::prelude::*; + +pub struct ActivityDetails { + binded_hooks: ( + Option>, + Option>, + Option>, + ), + + id: ActivityId, +} + +pub struct ActivityDetailsBuilder { + data: Vec, +} + +impl ActivityDetailsBuilder { + pub fn new() -> Self { + Self { data: vec![] } + } + + pub fn add_activity, U: FnMut() -> T>( + mut self, + mut builder: U, + ) -> Self { + let wrapped = Arc::new(Mutex::new(builder())); + self.data.push(activity_into_invokes(&wrapped)); + self + } + + pub fn build(self) -> Vec { + self.data + } +} + +/// +/// Returns startup, step, shutdown for activity as invoke actions +/// +pub fn activity_into_invokes(obj: &Arc>) -> ActivityDetails +where + T: 'static + Send + ActivityAdapterTrait, +{ + let start = Invoke::from_arc(obj.clone(), T::start); + let step = Invoke::from_arc_mtx(obj.clone(), T::step_runtime); + let stop = Invoke::from_arc(obj.clone(), T::stop); + ActivityDetails { + binded_hooks: (Some(start), Some(step), Some(stop)), + id: obj.lock().unwrap().get_act_id(), + } +} + +/// +/// Responsible to react on request coming from primary process +/// +pub struct LocalFeoAgent { + activities: Vec, + agent_name: &'static str, + app_name: &'static str, +} + +impl LocalFeoAgent { + pub fn run_agent( + app_name: &'static str, + activities: Vec, + agent_name: &'static str, + runtime: &mut AsyncRuntime, + ) { + // Since runtime `enter_engine` is now not blocking, we do it manually here. + let waiter = Arc::new(ThreadWaitBarrier::new(1)); + let notifier = waiter.get_notifier().unwrap(); + + runtime + .enter_engine( + // + async move { + let mut agent = LocalFeoAgent::new(app_name, activities, agent_name); + let mut program = agent.create_program(); + + info!("{:?}", program); + + program.run().await; + info!("Finished"); + notifier.ready(); + }, + ) + .unwrap_or_default(); + + waiter + .wait_for_all(Duration::new(2000, 0)) + .unwrap_or_default(); + } + + pub fn new( + app_name: &'static str, + activities: Vec, + agent_name: &'static str, + ) -> Self { + Self { + activities, + agent_name, + app_name, + } + } + + pub fn create_program(&mut self) -> Program { + let mut program = ProgramBuilder::new("local"); + + program = program.with_startup_hook(self.create_startup()); + program = program.with_body(self.create_body()); + program = program.with_shutdown_notification(self.create_shutdown_notification()); + program = program.with_shutdown_hook(self.create_shutdown()); + + program.build() + } + + fn create_startup(&mut self) -> Box { + let mut seq = Sequence::new() + .with_step(Trigger::new( + format!("{}/{}/alive", self.app_name, self.agent_name).as_str(), + )) + .with_step(Sync::new(format!("{}/startup", self.app_name).as_str())); + + let mut concurrent = Concurrency::new(); + + // startups from al activities + for e in &mut self.activities { + concurrent = concurrent.with_branch(e.binded_hooks.0.take().unwrap()); + } + + seq = seq.with_step(concurrent); + seq.with_step(Trigger::new( + format!("{}/{}/startup_completed", self.app_name, self.agent_name).as_str(), + )) + } + + fn create_body(&mut self) -> Box { + let mut concurrent = Concurrency::new(); + + for e in &mut self.activities { + concurrent = concurrent.with_branch( + Sequence::new() + .with_step(Sync::new( + format!("{}/{}/step", self.app_name, e.id).as_str(), + )) + .with_step(e.binded_hooks.1.take().unwrap()) + .with_step(Trigger::new( + format!("{}/{}/step_completed", self.app_name, e.id).as_str(), + )), + ); + } + + concurrent + } + + fn create_shutdown_notification(&mut self) -> Box { + let seq = + Sequence::new().with_step(Sync::new(format!("{}/shutdown", self.app_name).as_str())); + + seq + } + + fn create_shutdown(&mut self) -> Box { + let mut seq = Sequence::new(); + + let mut concurrent = Concurrency::new(); + + // shutdown from all activities + for e in &mut self.activities { + concurrent = concurrent.with_branch(e.binded_hooks.2.take().unwrap()); + } + + seq = seq.with_step(concurrent); + seq.with_step(Trigger::new( + format!("{}/{}/shutdown_completed", self.app_name, self.agent_name).as_str(), + )) + } +} + +/// +/// Responsible for controlling Task Chain execution across processes according to provided configuration +/// +pub struct GlobalOrchestrator { + agents: Vec, + cycle: Duration, + app_name: &'static str, +} + +impl GlobalOrchestrator { + pub fn run_primary( + app_name: &'static str, + agents: Vec, + cycle: Duration, + graph: ActivityDependencies, + local_activities: Vec, + local_agent_name: &'static str, + runtime: &mut AsyncRuntime, + ) { + // Since runtime `enter_engine` is now not blocking, we do it manually here. + let waiter = Arc::new(ThreadWaitBarrier::new(1)); + let notifier = waiter.get_notifier().unwrap(); + + runtime + .enter_engine( + // + async move { + let local_agent_program = async_runtime::spawn(async move { + let mut agent = + LocalFeoAgent::new(app_name, local_activities, local_agent_name); + let mut program = agent.create_program(); + + program.run().await; + info!("Finished local program"); + }); + + let global_orch = GlobalOrchestrator::new(app_name, agents, cycle); + global_orch.run(&graph).await; + + local_agent_program.await; + notifier.ready(); + }, + ) + .unwrap_or_default(); + + waiter + .wait_for_all(Duration::new(2000, 0)) + .unwrap_or_default(); + } + + pub fn new(app_name: &'static str, agents: Vec, cycle: Duration) -> Self { + Self { + agents, + cycle, + app_name, + } + } + + pub async fn run(&self, graph: &ActivityDependencies) { + let mut program = ProgramBuilder::new("main") + .with_startup_hook(self.startup()) + .with_body(self.generate_body(&graph)) + .with_shutdown_notification(self.orch_shutdown_notification()) + .with_shutdown_hook(self.shutdown()) + .with_cycle_time(self.cycle) + .build(); + + info!("Executor starts syncing with agents and execution of activity chain 20 times for demo..."); + info!("{:?}", program); + + program.run_n(20).await; + + info!("Done"); + } + + fn sync_to_agents(&self) -> Box { + let mut top = Concurrency::new_with_id(NamedId::new_static("sync_to_agents")); + + for name in &self.agents { + let sub_sequence = Sync::new(format!("{}/{}/alive", self.app_name, name).as_str()); + + top = top.with_branch(sub_sequence); + } + + top + } + + fn release_agents(&self) -> Box { + Sequence::new_with_id(NamedId::new_static("release_agents")) + .with_step(Trigger::new(format!("{}/startup", self.app_name).as_str())) + } + + fn wait_startup_completed(&self) -> Box { + let mut top = Sequence::new_with_id(NamedId::new_static("wait_startup_completed")); + + for name in &self.agents { + let sub_sequence = + Sync::new(format!("{}/{}/startup_completed", self.app_name, name).as_str()); + + top = top.with_step(sub_sequence); + } + + top + } + + fn startup(&self) -> Box { + let seq = Sequence::new_with_id(NamedId::new_static("startup")) + .with_step(self.sync_to_agents()) + .with_step(self.release_agents()) + .with_step(self.wait_startup_completed()); + + seq + } + + fn shutdown_agents(&self) -> Box { + Sequence::new_with_id(NamedId::new_static("shutdown_agents")) + .with_step(Trigger::new(format!("{}/shutdown", self.app_name).as_str())) + } + + fn wait_shutdown_completed(&self) -> Box { + let mut top = Sequence::new_with_id(NamedId::new_static("wait_shutdown_completed")); + + for name in &self.agents { + let sub_sequence = + Sync::new(format!("{}/{}/shutdown_completed", self.app_name, name).as_str()); + + top = top.with_step(sub_sequence); + } + + top + } + + fn shutdown(&self) -> Box { + let seq = Sequence::new_with_id(NamedId::new_static("shutdown")) + .with_step(self.shutdown_agents()) + .with_step(self.wait_shutdown_completed()); + + seq + } + + // This can be used to stop orchestration from another application for demo. + fn orch_shutdown_notification(&self) -> Box { + let seq = Sequence::new_with_id(NamedId::new_static("shutdown")) + .with_step(Sync::new("qorix_orch_shutdown_event")); + + seq + } + + // Converts a dependency graph into an execution sequence. + fn generate_body(&self, graph: &ActivityDependencies) -> Box { + let mut body = Concurrency::new(); + + // For now simply mapping, without optimization + for node in graph { + if node.1.is_empty() { + body = body.with_branch(self.generate_step(node.0)); + continue; + } + + let mut s = Sequence::new(); + for dep in node.1 { + s = s.with_step(Sync::new( + format!("{}/{}/step_completed", self.app_name, dep).as_str(), + )); + } + + s = s.with_step(self.generate_step(node.0)); + + body = body.with_branch(s); + } + body + } + + fn generate_step(&self, id: &ActivityId) -> Box { + Sequence::new() + .with_step(Trigger::new( + format!("{}/{}/step", self.app_name, id).as_str(), + )) + .with_step(Sync::new( + format!("{}/{}/step_completed", self.app_name, id).as_str(), + )) + } +} diff --git a/examples/rust/feo-mini-adas/src/bin/adas_primary.rs b/examples/rust/feo-mini-adas/src/bin/adas_primary.rs index d2de884..361b81e 100644 --- a/examples/rust/feo-mini-adas/src/bin/adas_primary.rs +++ b/examples/rust/feo-mini-adas/src/bin/adas_primary.rs @@ -2,82 +2,79 @@ // // SPDX-License-Identifier: Apache-2.0 +use async_runtime::runtime::runtime::AsyncRuntimeBuilder; +use async_runtime::scheduler::execution_engine::ExecutionEngineBuilder; use configuration::primary_agent::Builder; use feo::configuration::worker_pool; use feo::prelude::*; use feo::signalling::{channel, Signal}; use feo_log::{info, LevelFilter}; -use feo_mini_adas::config; +use feo_mini_adas::activities::components::{Camera, Radar}; +use feo_mini_adas::activities::runtime_adapters::{ + activity_into_invokes, ActivityDetailsBuilder, GlobalOrchestrator, LocalFeoAgent, +}; +use feo_mini_adas::config::{self, *}; use feo_time::Duration; -use std::collections::HashMap; +use foundation::threading::thread_wait_barrier::*; +use logging_tracing::prelude::*; +use logging_tracing::{TraceScope, TracingLibraryBuilder}; +use orchestration::prelude::Event; + use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::sync::{Arc, Mutex}; const AGENT_ID: AgentId = AgentId::new(100); const BIND_ADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8081); -const DEFAULT_FEO_CYCLE_TIME: Duration = Duration::from_secs(5); +const DEFAULT_FEO_CYCLE_TIME: Duration = Duration::from_millis(500); fn main() { - feo_logger::init(LevelFilter::Debug, true, true); - feo_tracing::init(feo_tracing::LevelFilter::TRACE); - let params = Params::from_args(); - info!("Starting primary agent {AGENT_ID}. Waiting for connections",); - - // Initialize topics. Do not drop. - let _topic_guards = config::initialize_topics(); - - // Create local worker pool - let (worker_pool, agent_map, ready_channel) = { - let pool_configuration = config::pool_configuration(); - let mut worker_pool_builder = worker_pool::Builder::default(); - let mut agent_map: HashMap>> = HashMap::new(); - - // Recreate the HashMap without the builder on the lowest level. - for (agent_id, assignments) in pool_configuration.into_iter() { - for (worker_id, activities) in assignments.into_iter() { - for (activity_id, builder) in activities { - if agent_id == AGENT_ID { - worker_pool_builder.activity(worker_id, activity_id, builder); - } - - // Reinsert with same structure but without the builder on the lowest level. - agent_map - .entry(agent_id) - .or_default() - .entry(worker_id) - .and_modify(|act_ids| act_ids.push(activity_id)) - .or_insert_with(|| vec![activity_id]); - } - } - } - - let (worker_pool, ready_channel) = match worker_pool_builder.build() { - Some((pool, sender, receiver)) => (Some(pool), (sender, receiver)), - None => { - let ready_channel = channel::(); - (None, ready_channel) - } - }; - - (worker_pool, agent_map, ready_channel) - }; - - let activity_dependencies = config::activity_dependencies(); - - // Construct the agent - let agent = Builder::default() - .id(AGENT_ID) - .cycle_time(params.feo_cycle_time) - .bind(BIND_ADDR) - .agent_map(agent_map) - .worker_pool(worker_pool) - .activity_dependencies(activity_dependencies) - .intra_proc_ready_channel(ready_channel.0, ready_channel.1) + //Initialize in LogMode with AppScope + let mut logger = TracingLibraryBuilder::new() + .global_log_level(Level::TRACE) + .enable_tracing(TraceScope::SystemScope) + .enable_logging(false) + .build(); + + logger.init_log_trace(); + + let _topic_guards = initialize_topics(); + + let agents: Vec = vec![ + PRIMARY_NAME.to_string(), + SECONDARY1_NAME.to_string(), + SECONDARY2_NAME.to_string(), + ]; + + let mut runtime = AsyncRuntimeBuilder::new() + .with_engine( + ExecutionEngineBuilder::new() + .task_queue_size(256) + .workers(2), + ) + .build() + .unwrap(); + + Event::get_instance() + .lock() + .unwrap() + .create_polling_thread(); + + let activities = ActivityDetailsBuilder::new() + .add_activity(|| Radar::build(1.into(), TOPIC_RADAR_FRONT)) + .add_activity(|| Camera::build(0.into(), TOPIC_CAMERA_FRONT)) .build(); - // Start the agent loop and never return. - primary::run(agent); + GlobalOrchestrator::run_primary( + APPLICATION_NAME, + agents, + params.feo_cycle_time, + activity_dependencies(), + activities, + PRIMARY_NAME, + &mut runtime, + ) } /// Parameters of the primary diff --git a/examples/rust/feo-mini-adas/src/bin/adas_secondary_1.rs b/examples/rust/feo-mini-adas/src/bin/adas_secondary_1.rs index 6d1c54d..98e016a 100644 --- a/examples/rust/feo-mini-adas/src/bin/adas_secondary_1.rs +++ b/examples/rust/feo-mini-adas/src/bin/adas_secondary_1.rs @@ -2,12 +2,31 @@ // // SPDX-License-Identifier: Apache-2.0 +use async_runtime::{ + runtime::{runtime::AsyncRuntimeBuilder, *}, + scheduler::execution_engine::ExecutionEngineBuilder, +}; +use feo_mini_adas::activities::runtime_adapters::{ + activity_into_invokes, ActivityDetailsBuilder, LocalFeoAgent, +}; +use foundation::threading::thread_wait_barrier::*; + use configuration::secondary_agent::Builder; use feo::configuration::worker_pool; use feo::prelude::*; use feo_log::{info, LevelFilter}; -use feo_mini_adas::config; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use feo_mini_adas::{ + activities::components::{EnvironmentRenderer, NeuralNet}, + config::{self, *}, +}; + +use logging_tracing::{prelude::*, TracingLibrary}; +use orchestration::actions::event::Event; +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::{Arc, Mutex}, + time::Duration, +}; /// This agent's ID const AGENT_ID: AgentId = AgentId::new(101); @@ -15,35 +34,39 @@ const AGENT_ID: AgentId = AgentId::new(101); const PRIMARY_ADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8081); fn main() { - feo_logger::init(LevelFilter::Debug, true, true); - feo_tracing::init(feo_tracing::LevelFilter::TRACE); - - info!("Starting agent {AGENT_ID}"); - - // Create worker pool builder activity builder for local worker pool - let mut worker_pool_builder = worker_pool::Builder::default(); + let mut logger = TracingLibraryBuilder::new() + .global_log_level(Level::DEBUG) + .enable_tracing(TraceScope::SystemScope) + .enable_logging(false) + .build(); - let mut worker_pool_configuration = config::pool_configuration(); - let assignments = worker_pool_configuration - .remove(&AGENT_ID) - .expect("missing agent id in pool configuration"); + logger.init_log_trace(); - // Assign activities to workers - for (worker_id, activities) in assignments { - for (activity_id, builder) in activities { - worker_pool_builder.activity(worker_id, activity_id, builder); - } - } + let mut runtime = AsyncRuntimeBuilder::new() + .with_engine( + ExecutionEngineBuilder::new() + .task_queue_size(256) + .workers(1), + ) + .build() + .unwrap(); - let (worker_pool, _, receiver) = worker_pool_builder.build().expect("Worker pool is empty"); + Event::get_instance() + .lock() + .unwrap() + .create_polling_thread(); - // Construct the agent - let agent = Builder::default() - .id(AGENT_ID) - .primary(PRIMARY_ADDR) - .worker_pool(worker_pool, receiver) + let activities = ActivityDetailsBuilder::new() + .add_activity(|| EnvironmentRenderer::build(3.into(), TOPIC_INFERRED_SCENE)) + .add_activity(|| { + NeuralNet::build_val( + 2.into(), + TOPIC_CAMERA_FRONT, + TOPIC_RADAR_FRONT, + TOPIC_INFERRED_SCENE, + ) + }) .build(); - // Start the agent loop and never return. - secondary::run(agent); + LocalFeoAgent::run_agent(APPLICATION_NAME, activities, SECONDARY1_NAME, &mut runtime) } diff --git a/examples/rust/feo-mini-adas/src/bin/adas_secondary_2.rs b/examples/rust/feo-mini-adas/src/bin/adas_secondary_2.rs index 8252ed7..b299faf 100644 --- a/examples/rust/feo-mini-adas/src/bin/adas_secondary_2.rs +++ b/examples/rust/feo-mini-adas/src/bin/adas_secondary_2.rs @@ -2,12 +2,28 @@ // // SPDX-License-Identifier: Apache-2.0 +use async_runtime::{ + runtime::runtime::AsyncRuntimeBuilder, scheduler::execution_engine::ExecutionEngineBuilder, +}; use configuration::secondary_agent::Builder; use feo::configuration::worker_pool; use feo::prelude::*; use feo_log::{info, LevelFilter}; -use feo_mini_adas::config; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use feo_mini_adas::{ + activities::{ + components::{BrakeController, EmergencyBraking, LaneAssist, SteeringController}, + runtime_adapters::{activity_into_invokes, ActivityDetailsBuilder, LocalFeoAgent}, + }, + config::{self, *}, +}; +use foundation::threading::thread_wait_barrier::*; +use logging_tracing::{prelude::*, TraceScope, TracingLibraryBuilder}; +use orchestration::prelude::Event; +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::{Arc, Mutex}, + time::Duration, +}; /// This agent's ID const AGENT_ID: AgentId = AgentId::new(102); @@ -15,35 +31,39 @@ const AGENT_ID: AgentId = AgentId::new(102); const PRIMARY_ADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8081); fn main() { - feo_logger::init(LevelFilter::Debug, true, true); - feo_tracing::init(feo_tracing::LevelFilter::TRACE); + // feo_logger::init(LevelFilter::Debug, true, true); + // feo_tracing::init(feo_tracing::LevelFilter::TRACE); - info!("Starting agent {AGENT_ID}"); - - // Create worker pool builder activity builder for local worker pool - let mut worker_pool_builder = worker_pool::Builder::default(); + let mut logger = TracingLibraryBuilder::new() + .global_log_level(Level::DEBUG) + .enable_tracing(TraceScope::SystemScope) + .enable_logging(false) + .build(); - let mut worker_pool_configuration = config::pool_configuration(); - let assignments = worker_pool_configuration - .remove(&AGENT_ID) - .expect("missing agent id in pool configuration"); + logger.init_log_trace(); - // Assign activities to workers - for (worker_id, activities) in assignments { - for (activity_id, builder) in activities { - worker_pool_builder.activity(worker_id, activity_id, builder); - } - } + let mut runtime = AsyncRuntimeBuilder::new() + .with_engine( + ExecutionEngineBuilder::new() + .task_queue_size(256) + .workers(2), + ) + .build() + .unwrap(); - let (worker_pool, _, receiver) = worker_pool_builder.build().expect("Worker pool is empty"); + Event::get_instance() + .lock() + .unwrap() + .create_polling_thread(); - // Construct the agent - let agent = Builder::default() - .id(AGENT_ID) - .primary(PRIMARY_ADDR) - .worker_pool(worker_pool, receiver) + let activities = ActivityDetailsBuilder::new() + .add_activity(|| { + EmergencyBraking::build(4.into(), TOPIC_INFERRED_SCENE, TOPIC_CONTROL_BRAKES) + }) + .add_activity(|| BrakeController::build(6.into(), TOPIC_CONTROL_BRAKES)) + .add_activity(|| LaneAssist::build(5.into(), TOPIC_INFERRED_SCENE, TOPIC_CONTROL_STEERING)) + .add_activity(|| SteeringController::build(7.into(), TOPIC_CONTROL_STEERING)) .build(); - // Start the agent loop and never return. - secondary::run(agent); + LocalFeoAgent::run_agent(APPLICATION_NAME, activities, SECONDARY2_NAME, &mut runtime) } diff --git a/examples/rust/feo-mini-adas/src/bin/adas_single_process.rs b/examples/rust/feo-mini-adas/src/bin/adas_single_process.rs new file mode 100644 index 0000000..941a2f6 --- /dev/null +++ b/examples/rust/feo-mini-adas/src/bin/adas_single_process.rs @@ -0,0 +1,161 @@ +// Copyright 2025 Qorix +// +// This is the single process version of the feo-mini-adas example +// +// Copyright 2025 Accenture. +// +// SPDX-License-Identifier: Apache-2.0 +use async_runtime::runtime::runtime::AsyncRuntimeBuilder; +use async_runtime::scheduler::execution_engine::ExecutionEngineBuilder; +use feo::com::TopicHandle; +use feo_mini_adas::activities::components::{ + BrakeController, Camera, EmergencyBraking, EnvironmentRenderer, LaneAssist, NeuralNet, Radar, + SteeringController, +}; +use feo_mini_adas::activities::runtime_adapters::{ + activity_into_invokes, ActivityDetailsBuilder, GlobalOrchestrator, LocalFeoAgent, +}; +use feo_mini_adas::config::*; +use feo_time::Duration; +use foundation::threading::thread_wait_barrier::*; +use logging_tracing::prelude::*; +use logging_tracing::{TraceScope, TracingLibrary, TracingLibraryBuilder}; +use orchestration::prelude::Event; +use orchestration::program::ProgramBuilder; +use std::sync::{Arc, Mutex}; + +// ****************************************************************** // +// ** RUNTIME SETTINGS ** // +// ****************************************************************** // + +const ENGINE_TASK_QUEUE_SIZE: usize = 256; +const ENGINE_NUM_OF_WORKERS: usize = 3; + +const TRACE_SCOPE: TraceScope = TraceScope::SystemScope; +const LOG_LEVEL: Level = Level::INFO; +const LOG_ENABLE: bool = true; + +const DEFAULT_FEO_CYCLE_TIME: Duration = Duration::from_secs(1); + +// ****************************************************************** // +// ** PROGRAMS ** // +// ****************************************************************** // + +/// The entry point of the application +async fn main_program() { + let agents: Vec = vec![ + PRIMARY_NAME.to_string(), + SECONDARY1_NAME.to_string(), + SECONDARY2_NAME.to_string(), + ]; + + let primary_agent_program = async_runtime::spawn(primary_agent_program()); + let secondary_1_agent_program = async_runtime::spawn(secondary_1_agent_program()); + let secondary_2_agent_program = async_runtime::spawn(secondary_2_agent_program()); + + let global_orch = GlobalOrchestrator::new(APPLICATION_NAME, agents, DEFAULT_FEO_CYCLE_TIME); + global_orch.run(&activity_dependencies()).await; + primary_agent_program.await; + secondary_1_agent_program.await; + secondary_2_agent_program.await; +} + +async fn primary_agent_program() { + info!("Starting primary agent {PRIMARY_NAME}. Waiting for connections",); + + let activities = ActivityDetailsBuilder::new() + .add_activity(|| Radar::build(1.into(), TOPIC_RADAR_FRONT)) + .add_activity(|| Camera::build(0.into(), TOPIC_CAMERA_FRONT)) + .build(); + + let mut agent = LocalFeoAgent::new(APPLICATION_NAME, activities, PRIMARY_NAME); + let mut program = agent.create_program(); + + program.run().await; +} + +async fn secondary_1_agent_program() { + info!("Starting secondary_1 agent {SECONDARY1_NAME}",); + + let activities = ActivityDetailsBuilder::new() + .add_activity(|| EnvironmentRenderer::build(3.into(), TOPIC_INFERRED_SCENE)) + .add_activity(|| { + NeuralNet::build_val( + 2.into(), + TOPIC_CAMERA_FRONT, + TOPIC_RADAR_FRONT, + TOPIC_INFERRED_SCENE, + ) + }) + .build(); + + let mut agent = LocalFeoAgent::new(APPLICATION_NAME, activities, SECONDARY1_NAME); + let mut program = agent.create_program(); + + program.run().await; +} + +async fn secondary_2_agent_program() { + info!("Starting secondary_2 agent {SECONDARY2_NAME}",); + let activities = ActivityDetailsBuilder::new() + .add_activity(|| { + EmergencyBraking::build(4.into(), TOPIC_INFERRED_SCENE, TOPIC_CONTROL_BRAKES) + }) + .add_activity(|| BrakeController::build(6.into(), TOPIC_CONTROL_BRAKES)) + .add_activity(|| LaneAssist::build(5.into(), TOPIC_INFERRED_SCENE, TOPIC_CONTROL_STEERING)) + .add_activity(|| SteeringController::build(7.into(), TOPIC_CONTROL_STEERING)) + .build(); + + let mut agent = LocalFeoAgent::new(APPLICATION_NAME, activities, SECONDARY2_NAME); + let mut program = agent.create_program(); + + program.run().await; +} + +/// Init routine that should be called before the application execution +fn init() -> (TracingLibrary, Vec) { + // Initialize logger and topic registration + let mut logger = TracingLibraryBuilder::new() + .global_log_level(LOG_LEVEL) + .enable_tracing(TRACE_SCOPE) + .enable_logging(LOG_ENABLE) + .build(); + logger.init_log_trace(); + let topic_handles = initialize_topics(); + + // Start the orchestrator's event polling thread + Event::get_instance() + .lock() + .unwrap() + .create_polling_thread(); + + (logger, topic_handles) +} + +fn main() { + // Init and keep logger and topic handles alive + let (_logger_guard, _topics_guard) = init(); + + // Since runtime `enter_engine` is now not blocking, we do it manually here. + let waiter = Arc::new(ThreadWaitBarrier::new(1)); + let notifier = waiter.get_notifier().unwrap(); + + // Run the main program + AsyncRuntimeBuilder::new() + .with_engine( + ExecutionEngineBuilder::new() + .task_queue_size(ENGINE_TASK_QUEUE_SIZE) + .workers(ENGINE_NUM_OF_WORKERS), + ) + .build() + .unwrap() + .enter_engine(async { + main_program().await; + notifier.ready(); + }) + .unwrap_or_default(); + + waiter + .wait_for_all(Duration::new(2000, 0)) + .unwrap_or_default(); +} diff --git a/examples/rust/feo-mini-adas/src/bin/run.sh b/examples/rust/feo-mini-adas/src/bin/run.sh new file mode 100755 index 0000000..68a97b9 --- /dev/null +++ b/examples/rust/feo-mini-adas/src/bin/run.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +SESSION_NAME="feo" +BIN1="../../../../../target/debug/adas_primary" +BIN2="../../../../../target/debug/adas_secondary_1" +BIN3="../../../../../target/debug/adas_secondary_2" + +tmux new-session -d -s $SESSION_NAME -n main + + +tmux set-option -g mouse on + +tmux send-keys "$BIN1" + +tmux split-window -v + +tmux send-keys "$BIN2" + +tmux split-window -v + +tmux send-keys "$BIN3" + +tmux select-layout even-vertical + +tmux bind -n C-q kill-session + + +tmux attach-session -t $SESSION_NAME + diff --git a/examples/rust/feo-mini-adas/src/config.rs b/examples/rust/feo-mini-adas/src/config.rs index 9c60177..a9b765a 100644 --- a/examples/rust/feo-mini-adas/src/config.rs +++ b/examples/rust/feo-mini-adas/src/config.rs @@ -26,95 +26,19 @@ pub const TOPIC_CONTROL_STEERING: &str = "feo/com/vehicle/control/steering"; pub const TOPIC_CAMERA_FRONT: &str = "feo/com/vehicle/camera/front"; pub const TOPIC_RADAR_FRONT: &str = "feo/com/vehicle/radar/front"; -pub fn pool_configuration() -> HashMap>> { - // Assign activities to different workers - let w40: WorkerAssignment = ( - 40.into(), - vec![( - 0.into(), - Box::new(|id| Camera::build(id, TOPIC_CAMERA_FRONT)), - )], - ); - let w41: WorkerAssignment = ( - 41.into(), - vec![(1.into(), Box::new(|id| Radar::build(id, TOPIC_RADAR_FRONT)))], - ); - - let w42: WorkerAssignment = ( - 42.into(), - vec![ - ( - 2.into(), - Box::new(|id| { - NeuralNet::build( - id, - TOPIC_CAMERA_FRONT, - TOPIC_RADAR_FRONT, - TOPIC_INFERRED_SCENE, - ) - }), - ), - ( - 3.into(), - Box::new(|id| EnvironmentRenderer::build(id, TOPIC_INFERRED_SCENE)), - ), - ], - ); - - let w43: WorkerAssignment = ( - 43.into(), - vec![ - ( - 4.into(), - Box::new(|id| { - EmergencyBraking::build(id, TOPIC_INFERRED_SCENE, TOPIC_CONTROL_BRAKES) - }), - ), - ( - 6.into(), - Box::new(|id| BrakeController::build(id, TOPIC_CONTROL_BRAKES)), - ), - ], - ); - let w44: WorkerAssignment = ( - 44.into(), - vec![ - ( - 5.into(), - Box::new(|id| LaneAssist::build(id, TOPIC_INFERRED_SCENE, TOPIC_CONTROL_STEERING)), - ), - ( - 7.into(), - Box::new(|id| SteeringController::build(id, TOPIC_CONTROL_STEERING)), - ), - ], - ); - - // Assign workers to pools with exactly one pool belonging to one agent - let a0: AgentAssignment = (100.into(), vec![w40, w41]); - let a1: AgentAssignment = (101.into(), vec![w42]); - let a2: AgentAssignment = (102.into(), vec![w43, w44]); - - let assignments = vec![a0, a1, a2]; - - let mut agent_map = HashMap::new(); - for (agent, workers) in assignments { - let mut worker_map = HashMap::new(); - for (worker_id, activities) in workers { - let previous = worker_map.insert(worker_id, activities); - assert!( - previous.is_none(), - "Duplicate worker {worker_id} in assignment list" - ); - } - let previous = agent_map.insert(agent, worker_map); - assert!( - previous.is_none(), - "Duplicate agent {agent} in assignment list" - ); - } - agent_map -} +pub const CAM_ACTIVITY_NAME: &'static str = "cam_activity"; +pub const RADAR_ACTIVITY_NAME: &'static str = "radar_activity"; +pub const NEURAL_NET_ACTIVITY_NAME: &'static str = "neuralnet_activity"; +pub const ENV_READER_ACTIVITY_NAME: &'static str = "env_reader_activity"; +pub const EMG_BREAK_ACTIVITY_NAME: &'static str = "emg_break_activity"; +pub const BREAK_CTL_ACTIVITY_NAME: &'static str = "break_ctl_activity"; +pub const LANE_ASST_ACTIVITY_NAME: &'static str = "lane_asst_activity"; +pub const STR_CTL_ACTIVITY_NAME: &'static str = "str_ctl_activity"; + +pub const APPLICATION_NAME: &'static str = "adas_feo"; +pub const PRIMARY_NAME: &'static str = "primary_agent"; +pub const SECONDARY1_NAME: &'static str = "secondary1_agent"; +pub const SECONDARY2_NAME: &'static str = "secondary2_agent"; pub fn activity_dependencies() -> ActivityDependencies { // Primary | Secondary1 | Secondary2 diff --git a/feo/Cargo.toml b/feo/Cargo.toml index 50c6bf7..74798a7 100644 --- a/feo/Cargo.toml +++ b/feo/Cargo.toml @@ -13,6 +13,8 @@ mio = { workspace = true } postcard = { workspace = true, features = ["experimental-derive"], optional = true} serde = { workspace = true, optional = true } + + [dev-dependencies] feo-logger = { workspace = true } diff --git a/feo/src/activity.rs b/feo/src/activity.rs index dbfaf71..70a4284 100644 --- a/feo/src/activity.rs +++ b/feo/src/activity.rs @@ -40,7 +40,7 @@ impl Display for ActivityId { } /// Activity trait, to be implemented by any activity intended to run in a WorkerPool -pub trait Activity { +pub trait Activity: Send { /// Get the ID of the activity fn id(&self) -> ActivityId;