diff --git a/Cargo.lock b/Cargo.lock index 64b015e9..430e935c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,18 +17,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -132,43 +120,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "askama" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" -dependencies = [ - "askama_derive", - "itoa", - "percent-encoding", - "serde", - "serde_json", -] - -[[package]] -name = "askama_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" -dependencies = [ - "askama_parser", - "memchr", - "proc-macro2", - "quote", - "rustc-hash", - "syn 2.0.106", -] - -[[package]] -name = "askama_parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" -dependencies = [ - "memchr", - "winnow 0.7.13", -] - [[package]] name = "autocfg" version = "1.5.0" @@ -437,15 +388,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bd422bfb4f24a97243f60b6a4443e63d810c925d8da4bb2d8fde26a7c1d57ec" -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "cordyceps" version = "0.3.4" @@ -551,15 +493,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "dd-manifest-tree" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" -dependencies = [ - "yaml-rust2", -] - [[package]] name = "debug-service" version = "0.1.0" @@ -622,7 +555,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" dependencies = [ - "thiserror 2.0.16", + "thiserror", ] [[package]] @@ -632,40 +565,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" dependencies = [ "defmt 0.3.100", - "device-driver-macros", "embedded-io 0.6.1", "embedded-io-async 0.6.1", ] -[[package]] -name = "device-driver-generation" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" -dependencies = [ - "anyhow", - "askama", - "bitvec", - "convert_case", - "dd-manifest-tree", - "itertools 0.14.0", - "kdl", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "device-driver-macros" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" -dependencies = [ - "device-driver-generation", - "proc-macro2", - "syn 2.0.106", -] - [[package]] name = "document-features" version = "0.2.11" @@ -1082,15 +985,6 @@ dependencies = [ "embedded-hal-async", ] -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "env_filter" version = "0.1.4" @@ -1233,30 +1127,12 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] - [[package]] name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "heapless" version = "0.8.0" @@ -1328,7 +1204,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown", ] [[package]] @@ -1375,12 +1251,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - [[package]] name = "jiff" version = "0.2.20" @@ -1405,18 +1275,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "kdl" -version = "6.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12661358400b02cbbf1fbd05f0a483335490e8a6bd1867620f2eeb78f304a22f" -dependencies = [ - "miette", - "num", - "thiserror 1.0.69", - "winnow 0.6.24", -] - [[package]] name = "keyberon" version = "0.2.0" @@ -1529,7 +1387,7 @@ dependencies = [ "espi-device", "num_enum", "smbus-pec", - "thiserror 2.0.16", + "thiserror", ] [[package]] @@ -1538,28 +1396,6 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "cfg-if", - "miette-derive", - "unicode-width", -] - -[[package]] -name = "miette-derive" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "mimxrt600-fcb" version = "0.2.2" @@ -1651,70 +1487,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -1814,12 +1586,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - [[package]] name = "pin-project" version = "1.1.10" @@ -2078,12 +1844,6 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustc_version" version = "0.2.3" @@ -2108,12 +1868,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - [[package]] name = "scoped-tls" version = "1.0.1" @@ -2171,18 +1925,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "serde_json" -version = "1.0.143" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - [[package]] name = "serde_spanned" version = "0.6.9" @@ -2338,33 +2080,13 @@ dependencies = [ "uuid", ] -[[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.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.16", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", + "thiserror-impl", ] [[package]] @@ -2491,13 +2213,13 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.7.13", + "winnow", ] [[package]] name = "tps6699x" version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/tps6699x#aa3425136216dccfb107bff6b172a49b8972bb70" +source = "git+https://github.com/OpenDevicePartnership/tps6699x?branch=v0.2.0#c908a50747e8fcce831d4e53026072b5b6916a7b" dependencies = [ "bincode", "bitfield 0.19.2", @@ -2651,18 +2373,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unty" version = "0.0.4" @@ -2944,15 +2654,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "winnow" -version = "0.6.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.7.13" @@ -2971,17 +2672,6 @@ dependencies = [ "tap", ] -[[package]] -name = "yaml-rust2" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1a1c0bc9823338a3bdf8c61f994f23ac004c6fa32c08cd152984499b445e8d" -dependencies = [ - "arraydeque", - "encoding_rs", - "hashlink", -] - [[package]] name = "zerocopy" version = "0.8.26" diff --git a/Cargo.toml b/Cargo.toml index a495148e..cb14ddc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -114,7 +114,7 @@ time-alarm-service-interface = { path = "./time-alarm-service-interface" } time-alarm-service-relay = { path = "./time-alarm-service-relay" } type-c-interface = { path = "./type-c-interface" } syn = "2.0" -tps6699x = { git = "https://github.com/OpenDevicePartnership/tps6699x" } +tps6699x = { git = "https://github.com/OpenDevicePartnership/tps6699x", branch = "v0.2.0" } tokio = { version = "1.42.0" } uuid = { version = "=1.17.0", default-features = false } zerocopy = "0.8.26" diff --git a/examples/rt685s-evk/Cargo.lock b/examples/rt685s-evk/Cargo.lock index 96083761..95bdf66a 100644 --- a/examples/rt685s-evk/Cargo.lock +++ b/examples/rt685s-evk/Cargo.lock @@ -2,18 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.4" @@ -23,12 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "anyhow" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" - [[package]] name = "aquamarine" version = "0.6.0" @@ -43,49 +25,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "arraydeque" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" - -[[package]] -name = "askama" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" -dependencies = [ - "askama_derive", - "itoa", - "percent-encoding", - "serde", - "serde_json", -] - -[[package]] -name = "askama_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" -dependencies = [ - "askama_parser", - "memchr", - "proc-macro2", - "quote", - "rustc-hash", - "syn 2.0.106", -] - -[[package]] -name = "askama_parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" -dependencies = [ - "memchr", - "winnow 0.7.13", -] - [[package]] name = "autocfg" version = "1.5.0" @@ -259,15 +198,6 @@ dependencies = [ "heapless 0.8.0", ] -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "cordyceps" version = "0.3.4" @@ -373,15 +303,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "dd-manifest-tree" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" -dependencies = [ - "yaml-rust2", -] - [[package]] name = "defmt" version = "0.3.100" @@ -420,7 +341,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" dependencies = [ - "thiserror 2.0.16", + "thiserror", ] [[package]] @@ -440,40 +361,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" dependencies = [ "defmt 0.3.100", - "device-driver-macros", "embedded-io 0.6.1", "embedded-io-async 0.6.1", ] -[[package]] -name = "device-driver-generation" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" -dependencies = [ - "anyhow", - "askama", - "bitvec", - "convert_case", - "dd-manifest-tree", - "itertools 0.14.0", - "kdl", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "device-driver-macros" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" -dependencies = [ - "device-driver-generation", - "proc-macro2", - "syn 2.0.106", -] - [[package]] name = "document-features" version = "0.2.11" @@ -841,15 +732,6 @@ dependencies = [ "embedded-hal-async", ] -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "espi-device" version = "0.1.0" @@ -1000,24 +882,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown", -] - [[package]] name = "heapless" version = "0.8.0" @@ -1096,24 +960,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "kdl" -version = "6.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12661358400b02cbbf1fbd05f0a483335490e8a6bd1867620f2eeb78f304a22f" -dependencies = [ - "miette", - "num", - "thiserror 1.0.69", - "winnow 0.6.24", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -1171,7 +1017,7 @@ dependencies = [ "espi-device", "num_enum", "smbus-pec", - "thiserror 2.0.16", + "thiserror", ] [[package]] @@ -1180,28 +1026,6 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "cfg-if", - "miette-derive", - "unicode-width", -] - -[[package]] -name = "miette-derive" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "mimxrt600-fcb" version = "0.1.0" @@ -1270,70 +1094,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -1394,12 +1154,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1582,12 +1336,6 @@ dependencies = [ "type-c-service", ] -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustc_version" version = "0.2.3" @@ -1603,12 +1351,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - [[package]] name = "scoped-tls" version = "1.0.1" @@ -1650,18 +1392,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "serde_json" -version = "1.0.143" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -1764,33 +1494,13 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[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.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.16", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", + "thiserror-impl", ] [[package]] @@ -1855,7 +1565,7 @@ dependencies = [ [[package]] name = "tps6699x" version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/tps6699x#aa3425136216dccfb107bff6b172a49b8972bb70" +source = "git+https://github.com/OpenDevicePartnership/tps6699x?branch=v0.2.0#c908a50747e8fcce831d4e53026072b5b6916a7b" dependencies = [ "bincode", "bitfield 0.19.2", @@ -1980,18 +1690,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unty" version = "0.0.4" @@ -2016,12 +1714,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "virtue" version = "0.0.18" @@ -2067,24 +1759,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "winnow" -version = "0.6.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] - [[package]] name = "wyz" version = "0.5.1" @@ -2094,17 +1768,6 @@ dependencies = [ "tap", ] -[[package]] -name = "yaml-rust2" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1a1c0bc9823338a3bdf8c61f994f23ac004c6fa32c08cd152984499b445e8d" -dependencies = [ - "arraydeque", - "encoding_rs", - "hashlink", -] - [[package]] name = "zerocopy" version = "0.8.26" diff --git a/examples/rt685s-evk/Cargo.toml b/examples/rt685s-evk/Cargo.toml index 82b168f7..19c59959 100644 --- a/examples/rt685s-evk/Cargo.toml +++ b/examples/rt685s-evk/Cargo.toml @@ -61,7 +61,7 @@ power-policy-interface = { path = "../../power-policy-interface", features = [ power-policy-service = { path = "../../power-policy-service", features = [ "defmt", ] } -tps6699x = { git = "https://github.com/OpenDevicePartnership/tps6699x", features = [ +tps6699x = { git = "https://github.com/OpenDevicePartnership/tps6699x", branch = "v0.2.0", features = [ "defmt", "embassy", ] } diff --git a/examples/rt685s-evk/src/bin/type_c.rs b/examples/rt685s-evk/src/bin/type_c.rs index a81152a3..9aa29214 100644 --- a/examples/rt685s-evk/src/bin/type_c.rs +++ b/examples/rt685s-evk/src/bin/type_c.rs @@ -27,10 +27,11 @@ use tps6699x::asynchronous::embassy as tps6699x; use type_c_interface::port::ControllerId; use type_c_interface::port::PortRegistration; use type_c_interface::service::event::PortEvent as ServicePortEvent; -use type_c_service::driver::tps6699x::{self as tps6699x_drv}; +use type_c_service::driver::tps6699x::{self as tps6699x_drv, InterruptReceiver}; use type_c_service::service::{EventReceiver, Service}; use type_c_service::wrapper::ControllerWrapper; use type_c_service::wrapper::backing::{IntermediateStorage, ReferencedStorage, Storage}; +use type_c_service::wrapper::event_receiver::ArrayPortEventReceivers; use type_c_service::wrapper::proxy::PowerProxyDevice; extern crate rt685s_evk_example; @@ -68,7 +69,7 @@ type Wrapper<'a> = ControllerWrapper< Validator, >; type Controller<'a> = tps6699x::controller::Controller>; -type Interrupt<'a> = tps6699x::Interrupt<'a, GlobalRawMutex, BusDevice<'a>>; +type InterruptProcessor<'a> = tps6699x::interrupt::InterruptProcessor<'a, GlobalRawMutex, BusDevice<'a>>; type PowerPolicySenderType = MapSender< power_policy_interface::service::event::Event<'static, DeviceType>, @@ -92,16 +93,36 @@ type PowerPolicyServiceType = Mutex< type ServiceType = Service<'static>; #[embassy_executor::task] -async fn pd_controller_task(controller: &'static Wrapper<'static>) { +async fn pd_controller_task( + mut event_receiver: ArrayPortEventReceivers< + 'static, + 2, + InterruptReceiver<'static, GlobalRawMutex, BusDevice<'static>>, + >, + wrapper: &'static Wrapper<'static>, +) { loop { - if let Err(e) = controller.process_next_event().await { - error!("Error processing controller event: {:?}", e); + let event = event_receiver.wait_event().await; + + let output = wrapper + .process_event( + &mut event_receiver.sink_ready_timeout, + &mut event_receiver.cfu_event_receiver, + event, + ) + .await; + if let Err(e) = output { + error!("Error processing event: {:?}", e); + } + let output = output.unwrap(); + if let Err(e) = wrapper.finalize(&mut event_receiver.power_proxies, output).await { + error!("Error finalizing output: {:?}", e); } } } #[embassy_executor::task] -async fn interrupt_task(mut int_in: Input<'static>, mut interrupt: Interrupt<'static>) { +async fn interrupt_task(mut int_in: Input<'static>, mut interrupt: InterruptProcessor<'static>) { tps6699x::task::interrupt_task(&mut int_in, &mut [&mut interrupt]).await; } @@ -120,7 +141,6 @@ async fn type_c_service_task( wrappers: [&'static Wrapper<'static>; NUM_PD_CONTROLLERS], cfu_client: &'static CfuClient, ) { - info!("Starting type-c task"); type_c_service::task::task(service, event_receiver, wrappers, cfu_client).await; } @@ -140,15 +160,15 @@ async fn main(spawner: Spawner) { let device = I2cDevice::new(bus); static CONTROLLER: StaticCell> = StaticCell::new(); - let controller = CONTROLLER.init(Controller::new_tps66994(device, ADDR1).unwrap()); - let (mut tps6699x, interrupt) = controller.make_parts(); + let controller = CONTROLLER.init(Controller::new_tps66994(device, Default::default(), ADDR1).unwrap()); + let (mut tps6699x, interrupt_processor, interrupt_receiver) = controller.make_parts(); info!("Resetting PD controller"); let mut delay = Delay; tps6699x.reset(&mut delay).await.unwrap(); info!("Spawining interrupt task"); - spawner.spawn(interrupt_task(int_in, interrupt).expect("Failed to spawn interrupt task")); + spawner.spawn(interrupt_task(int_in, interrupt_processor).expect("Failed to spawn interrupt task")); // These aren't enabled by default tps6699x @@ -198,14 +218,13 @@ async fn main(spawner: Spawner) { let policy_sender1 = policy_channel1.dyn_sender(); let policy_receiver1 = policy_channel1.dyn_receiver(); + let (intermediate, power_event_receivers) = storage + .try_create_intermediate([("Pd0", policy_sender0), ("Pd1", policy_sender1)]) + .expect("Failed to create intermediate storage"); static INTERMEDIATE: StaticCell< IntermediateStorage>, > = StaticCell::new(); - let intermediate = INTERMEDIATE.init( - storage - .try_create_intermediate([("Pd0", policy_sender0), ("Pd1", policy_sender1)]) - .expect("Failed to create intermediate storage"), - ); + let intermediate = INTERMEDIATE.init(intermediate); static REFERENCED: StaticCell< ReferencedStorage>, @@ -285,5 +304,16 @@ async fn main(spawner: Spawner) { .expect("Failed to create power policy task"), ); - spawner.spawn(pd_controller_task(wrapper).expect("Failed to create pd controller task")); + spawner.spawn( + pd_controller_task( + ArrayPortEventReceivers::new( + InterruptReceiver::new(interrupt_receiver), + power_event_receivers, + &referenced.pd_controller, + &storage.cfu_device, + ), + wrapper, + ) + .expect("Failed to create pd controller task"), + ); } diff --git a/examples/rt685s-evk/src/bin/type_c_cfu.rs b/examples/rt685s-evk/src/bin/type_c_cfu.rs index 6a56ccab..ce5bcd90 100644 --- a/examples/rt685s-evk/src/bin/type_c_cfu.rs +++ b/examples/rt685s-evk/src/bin/type_c_cfu.rs @@ -30,10 +30,11 @@ use tps6699x::asynchronous::embassy as tps6699x; use type_c_interface::port::ControllerId; use type_c_interface::port::PortRegistration; use type_c_interface::service::event::PortEvent as ServicePortEvent; -use type_c_service::driver::tps6699x::{self as tps6699x_drv}; +use type_c_service::driver::tps6699x::{self as tps6699x_drv, InterruptReceiver}; use type_c_service::service::{EventReceiver, Service}; use type_c_service::wrapper::ControllerWrapper; use type_c_service::wrapper::backing::{IntermediateStorage, ReferencedStorage, Storage}; +use type_c_service::wrapper::event_receiver::ArrayPortEventReceivers; use type_c_service::wrapper::proxy::PowerProxyDevice; extern crate rt685s_evk_example; @@ -66,7 +67,7 @@ type Wrapper<'a> = ControllerWrapper< Validator, >; type Controller<'a> = tps6699x::controller::Controller>; -type Interrupt<'a> = tps6699x::Interrupt<'a, GlobalRawMutex, BusDevice<'a>>; +type InterruptProcessor<'a> = tps6699x::interrupt::InterruptProcessor<'a, GlobalRawMutex, BusDevice<'a>>; type PowerPolicySenderType = MapSender< power_policy_interface::service::event::Event<'static, DeviceType>, @@ -96,16 +97,36 @@ const PORT0_ID: GlobalPortId = GlobalPortId(0); const PORT1_ID: GlobalPortId = GlobalPortId(1); #[embassy_executor::task] -async fn pd_controller_task(controller: &'static Wrapper<'static>) { +async fn pd_controller_task( + mut event_receiver: ArrayPortEventReceivers< + 'static, + 2, + InterruptReceiver<'static, GlobalRawMutex, BusDevice<'static>>, + >, + wrapper: &'static Wrapper<'static>, +) { loop { - if let Err(e) = controller.process_next_event().await { - error!("Error processing controller event: {:?}", e); + let event = event_receiver.wait_event().await; + + let output = wrapper + .process_event( + &mut event_receiver.sink_ready_timeout, + &mut event_receiver.cfu_event_receiver, + event, + ) + .await; + if let Err(e) = output { + error!("Error processing event: {:?}", e); + } + let output = output.unwrap(); + if let Err(e) = wrapper.finalize(&mut event_receiver.power_proxies, output).await { + error!("Error finalizing output: {:?}", e); } } } #[embassy_executor::task] -async fn interrupt_task(mut int_in: Input<'static>, mut interrupt: Interrupt<'static>) { +async fn interrupt_task(mut int_in: Input<'static>, mut interrupt: InterruptProcessor<'static>) { tps6699x::task::interrupt_task(&mut int_in, &mut [&mut interrupt]).await; } @@ -204,7 +225,6 @@ async fn type_c_service_task( wrappers: [&'static Wrapper<'static>; NUM_PD_CONTROLLERS], cfu_client: &'static CfuClient, ) { - info!("Starting type-c task"); type_c_service::task::task(service, event_receiver, wrappers, cfu_client).await; } @@ -224,15 +244,15 @@ async fn main(spawner: Spawner) { let device = I2cDevice::new(bus); static CONTROLLER: StaticCell> = StaticCell::new(); - let controller = CONTROLLER.init(Controller::new_tps66994(device, ADDR1).unwrap()); - let (mut tps6699x, interrupt) = controller.make_parts(); + let controller = CONTROLLER.init(Controller::new_tps66994(device, Default::default(), ADDR1).unwrap()); + let (mut tps6699x, interrupt_processor, interrupt_receiver) = controller.make_parts(); info!("Resetting PD controller"); let mut delay = Delay; tps6699x.reset(&mut delay).await.unwrap(); info!("Spawining interrupt task"); - spawner.spawn(interrupt_task(int_in, interrupt).expect("Failed to spawn interrupt task")); + spawner.spawn(interrupt_task(int_in, interrupt_processor).expect("Failed to spawn interrupt task")); // These aren't enabled by default tps6699x @@ -257,7 +277,7 @@ async fn main(spawner: Spawner) { let storage = STORAGE.init(Storage::new( controller_context, CONTROLLER0_ID, - 0, // CFU component ID + CONTROLLER0_CFU_ID, [ PortRegistration { id: PORT0_ID, @@ -282,14 +302,13 @@ async fn main(spawner: Spawner) { let policy_sender1 = policy_channel1.dyn_sender(); let policy_receiver1 = policy_channel1.dyn_receiver(); + let (intermediate, power_event_receivers) = storage + .try_create_intermediate([("Pd0", policy_sender0), ("Pd1", policy_sender1)]) + .expect("Failed to create intermediate storage"); static INTERMEDIATE: StaticCell< IntermediateStorage>, > = StaticCell::new(); - let intermediate = INTERMEDIATE.init( - storage - .try_create_intermediate([("Pd0", policy_sender0), ("Pd1", policy_sender1)]) - .expect("Failed to create intermediate storage"), - ); + let intermediate = INTERMEDIATE.init(intermediate); static REFERENCED: StaticCell< ReferencedStorage< @@ -373,7 +392,18 @@ async fn main(spawner: Spawner) { .expect("Failed to create power policy task"), ); - spawner.spawn(pd_controller_task(wrapper).expect("Failed to create pd controller task")); + spawner.spawn( + pd_controller_task( + ArrayPortEventReceivers::new( + InterruptReceiver::new(interrupt_receiver), + power_event_receivers, + &referenced.pd_controller, + &storage.cfu_device, + ), + wrapper, + ) + .expect("Failed to create pd controller task"), + ); spawner.spawn(fw_update_task().expect("Failed to create fw update task")); } diff --git a/examples/std/Cargo.lock b/examples/std/Cargo.lock index f3e4b727..4ce67601 100644 --- a/examples/std/Cargo.lock +++ b/examples/std/Cargo.lock @@ -2,18 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -73,12 +61,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "anyhow" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" - [[package]] name = "aquamarine" version = "0.6.0" @@ -93,49 +75,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "arraydeque" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" - -[[package]] -name = "askama" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" -dependencies = [ - "askama_derive", - "itoa", - "percent-encoding", - "serde", - "serde_json", -] - -[[package]] -name = "askama_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" -dependencies = [ - "askama_parser", - "memchr", - "proc-macro2", - "quote", - "rustc-hash", - "syn 2.0.106", -] - -[[package]] -name = "askama_parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" -dependencies = [ - "memchr", - "winnow 0.7.13", -] - [[package]] name = "autocfg" version = "1.5.0" @@ -336,15 +275,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bd422bfb4f24a97243f60b6a4443e63d810c925d8da4bb2d8fde26a7c1d57ec" -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "cordyceps" version = "0.3.4" @@ -408,15 +338,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "dd-manifest-tree" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" -dependencies = [ - "yaml-rust2", -] - [[package]] name = "debug-service" version = "0.1.0" @@ -478,7 +399,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" dependencies = [ - "thiserror 2.0.16", + "thiserror", ] [[package]] @@ -487,40 +408,10 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" dependencies = [ - "device-driver-macros", "embedded-io 0.6.1", "embedded-io-async 0.6.1", ] -[[package]] -name = "device-driver-generation" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" -dependencies = [ - "anyhow", - "askama", - "bitvec", - "convert_case", - "dd-manifest-tree", - "itertools 0.14.0", - "kdl", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "device-driver-macros" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" -dependencies = [ - "device-driver-generation", - "proc-macro2", - "syn 2.0.106", -] - [[package]] name = "document-features" version = "0.2.11" @@ -810,7 +701,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58" dependencies = [ - "num 0.3.1", + "num", ] [[package]] @@ -824,15 +715,6 @@ dependencies = [ "embedded-hal-async", ] -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "env_filter" version = "0.1.4" @@ -922,24 +804,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown", -] - [[package]] name = "heapless" version = "0.8.0" @@ -1015,12 +879,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - [[package]] name = "jiff" version = "0.2.18" @@ -1045,18 +903,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "kdl" -version = "6.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12661358400b02cbbf1fbd05f0a483335490e8a6bd1867620f2eeb78f304a22f" -dependencies = [ - "miette", - "num 0.4.3", - "thiserror 1.0.69", - "winnow 0.6.24", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -1127,7 +973,7 @@ dependencies = [ "espi-device", "num_enum", "smbus-pec", - "thiserror 2.0.16", + "thiserror", ] [[package]] @@ -1136,28 +982,6 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "cfg-if", - "miette-derive", - "unicode-width", -] - -[[package]] -name = "miette-derive" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "mutex-traits" version = "1.0.1" @@ -1200,34 +1024,10 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" dependencies = [ - "num-complex 0.3.1", + "num-complex", "num-integer", "num-iter", - "num-rational 0.3.2", - "num-traits", -] - -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex 0.4.6", - "num-integer", - "num-iter", - "num-rational 0.4.2", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", + "num-rational", "num-traits", ] @@ -1240,15 +1040,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - [[package]] name = "num-integer" version = "0.1.46" @@ -1280,17 +1071,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -1347,12 +1127,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - [[package]] name = "pin-project" version = "1.1.10" @@ -1510,12 +1284,6 @@ dependencies = [ "ufmt-write", ] -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustc_version" version = "0.2.3" @@ -1531,12 +1299,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - [[package]] name = "scoped-tls" version = "1.0.1" @@ -1588,18 +1350,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "serde_json" -version = "1.0.143" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -1758,33 +1508,13 @@ dependencies = [ "embedded-sensors-hal-async", ] -[[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.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.16", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", + "thiserror-impl", ] [[package]] @@ -1810,7 +1540,7 @@ dependencies = [ [[package]] name = "tps6699x" version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/tps6699x#aa3425136216dccfb107bff6b172a49b8972bb70" +source = "git+https://github.com/OpenDevicePartnership/tps6699x?branch=v0.2.0#c908a50747e8fcce831d4e53026072b5b6916a7b" dependencies = [ "bincode", "bitfield 0.19.2", @@ -1935,18 +1665,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unty" version = "0.0.4" @@ -1977,12 +1695,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "virtue" version = "0.0.18" @@ -2262,24 +1974,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" -[[package]] -name = "winnow" -version = "0.6.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] - [[package]] name = "wyz" version = "0.5.1" @@ -2289,17 +1983,6 @@ dependencies = [ "tap", ] -[[package]] -name = "yaml-rust2" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1a1c0bc9823338a3bdf8c61f994f23ac004c6fa32c08cd152984499b445e8d" -dependencies = [ - "arraydeque", - "encoding_rs", - "hashlink", -] - [[package]] name = "zerocopy" version = "0.8.26" diff --git a/examples/std/src/bin/type_c/service.rs b/examples/std/src/bin/type_c/service.rs index 4f395a8e..048baaed 100644 --- a/examples/std/src/bin/type_c/service.rs +++ b/examples/std/src/bin/type_c/service.rs @@ -24,6 +24,7 @@ use type_c_service::service::config::Config; use type_c_service::service::{EventReceiver, Service}; use type_c_service::util::power_capability_from_current; use type_c_service::wrapper::backing::Storage; +use type_c_service::wrapper::event_receiver::ArrayPortEventReceivers; use type_c_service::wrapper::message::*; use type_c_service::wrapper::proxy::PowerProxyDevice; @@ -58,18 +59,22 @@ type ServiceType = Service<'static>; #[embassy_executor::task] async fn controller_task( + mut event_receiver: ArrayPortEventReceivers<'static, 1, mock_controller::InterruptReceiver<'static>>, wrapper: &'static Wrapper<'static>, controller: &'static Mutex>, ) { controller.lock().await.custom_function(); loop { - let event = wrapper.wait_next().await; - if let Err(e) = event { - error!("Error waiting for event: {e:?}"); - continue; - } - let output = wrapper.process_event(event.unwrap()).await; + let event = event_receiver.wait_event().await; + + let output = wrapper + .process_event( + &mut event_receiver.sink_ready_timeout, + &mut event_receiver.cfu_event_receiver, + event, + ) + .await; if let Err(e) = output { error!("Error processing event: {e:?}"); } @@ -79,7 +84,7 @@ async fn controller_task( info!("Port{}: PD alert received: {:?}", port.0, ado); } - if let Err(e) = wrapper.finalize(output).await { + if let Err(e) = wrapper.finalize(&mut event_receiver.power_proxies, output).await { error!("Error finalizing output: {e:?}"); } } @@ -96,7 +101,7 @@ async fn task(spawner: Spawner) { static CONTEXT: StaticCell = StaticCell::new(); let controller_context = CONTEXT.init(type_c_interface::service::context::Context::new()); - let (wrapper, policy_receiver, controller, state) = create_wrapper(controller_context); + let (event_receiver, wrapper, policy_receiver, controller, state) = create_wrapper(controller_context); // Create type-c service // The service is the only receiver and we only use a DynImmediatePublisher, which doesn't take a publisher slot @@ -129,17 +134,24 @@ async fn task(spawner: Spawner) { static CFU_CLIENT: OnceLock = OnceLock::new(); let cfu_client = CfuClient::new(&CFU_CLIENT).await; - spawner.spawn(power_policy_task( - ArrayEventReceivers::new([&wrapper.ports[0].proxy], [policy_receiver]), - power_service, - ).expect("Failed to create power policy task")); - spawner.spawn(type_c_service_task( - type_c_service, - EventReceiver::new(controller_context, power_policy_subscriber), - [wrapper], - cfu_client, - ).expect("Failed to create type-c service task")); - spawner.spawn(controller_task(wrapper, controller).expect("Failed to create controller task")); + spawner.spawn( + power_policy_task( + ArrayEventReceivers::new([&wrapper.ports[0].proxy], [policy_receiver]), + power_service, + ) + .expect("Failed to create power policy task"), + ); + spawner.spawn( + type_c_service_task( + type_c_service, + EventReceiver::new(controller_context, power_policy_subscriber), + [wrapper], + cfu_client, + ) + .expect("Failed to create type-c service task"), + ); + + spawner.spawn(controller_task(event_receiver, wrapper, controller).expect("Failed to create controller task")); Timer::after_millis(1000).await; info!("Simulating connection"); @@ -187,6 +199,7 @@ async fn type_c_service_task( fn create_wrapper( context: &'static Context, ) -> ( + ArrayPortEventReceivers<'static, 1, mock_controller::InterruptReceiver<'static>>, &'static Wrapper<'static>, DynamicReceiver<'static, power_policy_interface::psu::event::EventData>, &'static Mutex>, @@ -216,6 +229,10 @@ fn create_wrapper( let policy_sender = policy_channel.dyn_sender(); let policy_receiver = policy_channel.dyn_receiver(); + let (intermediate, power_event_receivers) = storage + .try_create_intermediate([("Pd0", policy_sender)]) + .expect("Failed to create intermediate storage"); + static INTERMEDIATE: StaticCell< type_c_service::wrapper::backing::IntermediateStorage< 1, @@ -223,11 +240,7 @@ fn create_wrapper( DynamicSender<'static, psu::event::EventData>, >, > = StaticCell::new(); - let intermediate = INTERMEDIATE.init( - storage - .try_create_intermediate([("Pd0", policy_sender)]) - .expect("Failed to create intermediate storage"), - ); + let intermediate = INTERMEDIATE.init(intermediate); static REFERENCED: StaticCell< type_c_service::wrapper::backing::ReferencedStorage< @@ -242,11 +255,19 @@ fn create_wrapper( .expect("Failed to create referenced storage"), ); + let event_receiver = ArrayPortEventReceivers::new( + state.create_interrupt_receiver(), + power_event_receivers, + &referenced.pd_controller, + &storage.cfu_device, + ); + static CONTROLLER: StaticCell> = StaticCell::new(); let controller = CONTROLLER.init(Mutex::new(mock_controller::Controller::new(state))); static WRAPPER: StaticCell = StaticCell::new(); ( + event_receiver, WRAPPER.init(mock_controller::Wrapper::new( controller, Default::default(), diff --git a/examples/std/src/bin/type_c/ucsi.rs b/examples/std/src/bin/type_c/ucsi.rs index 04c3c9ec..babb2ae0 100644 --- a/examples/std/src/bin/type_c/ucsi.rs +++ b/examples/std/src/bin/type_c/ucsi.rs @@ -28,6 +28,7 @@ use type_c_interface::service::event::PortEvent as ServicePortEvent; use type_c_service::service::config::Config; use type_c_service::service::{EventReceiver, Service}; use type_c_service::wrapper::backing::Storage; +use type_c_service::wrapper::event_receiver::ArrayPortEventReceivers; use type_c_service::wrapper::proxy::PowerProxyDevice; const CHANNEL_CAPACITY: usize = 4; @@ -195,10 +196,26 @@ async fn opm_task(_context: &'static Context, _state: [&'static mock_controller: } #[embassy_executor::task(pool_size = 2)] -async fn wrapper_task(wrapper: &'static mock_controller::Wrapper<'static>) { +async fn wrapper_task( + mut event_receiver: ArrayPortEventReceivers<'static, 1, mock_controller::InterruptReceiver<'static>>, + wrapper: &'static mock_controller::Wrapper<'static>, +) { loop { - if let Err(e) = wrapper.process_next_event().await { - error!("Error processing wrapper: {e:#?}"); + let event = event_receiver.wait_event().await; + + let output = wrapper + .process_event( + &mut event_receiver.sink_ready_timeout, + &mut event_receiver.cfu_event_receiver, + event, + ) + .await; + if let Err(e) = output { + error!("Error processing event: {e:?}"); + } + let output = output.unwrap(); + if let Err(e) = wrapper.finalize(&mut event_receiver.power_proxies, output).await { + error!("Error finalizing output: {e:#?}"); } } } @@ -256,11 +273,10 @@ async fn task(spawner: Spawner) { DynamicSender<'_, psu::event::EventData>, >, > = StaticCell::new(); - let intermediate0 = INTERMEDIATE0.init( - storage0 - .try_create_intermediate([("Pd0", policy_sender0)]) - .expect("Failed to create intermediate storage"), - ); + let (intermediate0, power_event_receivers0) = storage0 + .try_create_intermediate([("Pd0", policy_sender0)]) + .expect("Failed to create intermediate storage"); + let intermediate0 = INTERMEDIATE0.init(intermediate0); static REFERENCED0: StaticCell< type_c_service::wrapper::backing::ReferencedStorage< @@ -277,6 +293,12 @@ async fn task(spawner: Spawner) { static STATE0: StaticCell = StaticCell::new(); let state0 = STATE0.init(mock_controller::ControllerState::new()); + let event_receiver0 = ArrayPortEventReceivers::new( + state0.create_interrupt_receiver(), + power_event_receivers0, + &referenced0.pd_controller, + &storage0.cfu_device, + ); static CONTROLLER0: StaticCell> = StaticCell::new(); let controller0 = CONTROLLER0.init(Mutex::new(mock_controller::Controller::new(state0))); static WRAPPER0: StaticCell = StaticCell::new(); @@ -311,11 +333,10 @@ async fn task(spawner: Spawner) { DynamicSender<'_, psu::event::EventData>, >, > = StaticCell::new(); - let intermediate1 = INTERMEDIATE1.init( - storage1 - .try_create_intermediate([("Pd1", policy_sender1)]) - .expect("Failed to create intermediate storage"), - ); + let (intermediate1, power_event_receivers1) = storage1 + .try_create_intermediate([("Pd1", policy_sender1)]) + .expect("Failed to create intermediate storage"); + let intermediate1 = INTERMEDIATE1.init(intermediate1); static REFERENCED1: StaticCell< type_c_service::wrapper::backing::ReferencedStorage< @@ -332,6 +353,12 @@ async fn task(spawner: Spawner) { static STATE1: StaticCell = StaticCell::new(); let state1 = STATE1.init(mock_controller::ControllerState::new()); + let event_receiver1 = ArrayPortEventReceivers::new( + state1.create_interrupt_receiver(), + power_event_receivers1, + &referenced1.pd_controller, + &storage1.cfu_device, + ); static CONTROLLER1: StaticCell> = StaticCell::new(); let controller1 = CONTROLLER1.init(Mutex::new(mock_controller::Controller::new(state1))); static WRAPPER1: StaticCell = StaticCell::new(); @@ -403,22 +430,28 @@ async fn task(spawner: Spawner) { static CFU_CLIENT: OnceLock = OnceLock::new(); let cfu_client = CfuClient::new(&CFU_CLIENT).await; - spawner.spawn(power_policy_task( - ArrayEventReceivers::new( - [&wrapper0.ports[0].proxy, &wrapper1.ports[0].proxy], - [policy_receiver0, policy_receiver1], - ), - power_service, - ).expect("Failed to create power policy task")); - - spawner.spawn(type_c_service_task( - type_c_service, - EventReceiver::new(controller_context, power_policy_subscriber), - [wrapper0, wrapper1], - cfu_client, - ).expect("Failed to create type-c service task")); - spawner.spawn(wrapper_task(wrapper0).expect("Failed to create wrapper0 task")); - spawner.spawn(wrapper_task(wrapper1).expect("Failed to create wrapper1 task")); + spawner.spawn( + power_policy_task( + ArrayEventReceivers::new( + [&wrapper0.ports[0].proxy, &wrapper1.ports[0].proxy], + [policy_receiver0, policy_receiver1], + ), + power_service, + ) + .expect("Failed to create power policy task"), + ); + + spawner.spawn( + type_c_service_task( + type_c_service, + EventReceiver::new(controller_context, power_policy_subscriber), + [wrapper0, wrapper1], + cfu_client, + ) + .expect("Failed to create type-c service task"), + ); + spawner.spawn(wrapper_task(event_receiver0, wrapper0).expect("Failed to create wrapper0 task")); + spawner.spawn(wrapper_task(event_receiver1, wrapper1).expect("Failed to create wrapper1 task")); spawner.spawn(opm_task(controller_context, [state0, state1]).expect("Failed to create opm task")); } diff --git a/examples/std/src/bin/type_c/unconstrained.rs b/examples/std/src/bin/type_c/unconstrained.rs index 0e323904..21c20cb4 100644 --- a/examples/std/src/bin/type_c/unconstrained.rs +++ b/examples/std/src/bin/type_c/unconstrained.rs @@ -23,6 +23,7 @@ use type_c_interface::port::PortRegistration; use type_c_interface::service::event::PortEvent as ServicePortEvent; use type_c_service::service::{EventReceiver, Service}; use type_c_service::wrapper::backing::{IntermediateStorage, ReferencedStorage, Storage}; +use type_c_service::wrapper::event_receiver::ArrayPortEventReceivers; use type_c_service::wrapper::proxy::PowerProxyDevice; const CHANNEL_CAPACITY: usize = 4; @@ -67,10 +68,26 @@ type PowerPolicyServiceType = Mutex< type ServiceType = Service<'static>; #[embassy_executor::task(pool_size = 3)] -async fn controller_task(wrapper: &'static mock_controller::Wrapper<'static>) { +async fn controller_task( + mut event_receiver: ArrayPortEventReceivers<'static, 1, mock_controller::InterruptReceiver<'static>>, + wrapper: &'static mock_controller::Wrapper<'static>, +) { loop { - if let Err(e) = wrapper.process_next_event().await { - error!("Error processing wrapper: {e:#?}"); + let event = event_receiver.wait_event().await; + + let output = wrapper + .process_event( + &mut event_receiver.sink_ready_timeout, + &mut event_receiver.cfu_event_receiver, + event, + ) + .await; + if let Err(e) = output { + error!("Error processing event: {e:?}"); + } + let output = output.unwrap(); + if let Err(e) = wrapper.finalize(&mut event_receiver.power_proxies, output).await { + error!("Error finalizing output: {e:#?}"); } } } @@ -106,11 +123,10 @@ async fn task(spawner: Spawner) { static INTERMEDIATE0: StaticCell< IntermediateStorage<1, GlobalRawMutex, DynamicSender<'static, psu::event::EventData>>, > = StaticCell::new(); - let intermediate0 = INTERMEDIATE0.init( - storage0 - .try_create_intermediate([("Pd0", policy_sender0)]) - .expect("Failed to create intermediate storage"), - ); + let (intermediate0, power_event_receivers0) = storage0 + .try_create_intermediate([("Pd0", policy_sender0)]) + .expect("Failed to create intermediate storage"); + let intermediate0 = INTERMEDIATE0.init(intermediate0); static REFERENCED0: StaticCell>> = StaticCell::new(); @@ -122,6 +138,12 @@ async fn task(spawner: Spawner) { static STATE0: StaticCell = StaticCell::new(); let state0 = STATE0.init(mock_controller::ControllerState::new()); + let event_receiver0 = ArrayPortEventReceivers::new( + state0.create_interrupt_receiver(), + power_event_receivers0, + &referenced0.pd_controller, + &storage0.cfu_device, + ); static CONTROLLER0: StaticCell> = StaticCell::new(); let controller0 = CONTROLLER0.init(Mutex::new(mock_controller::Controller::new(state0))); static WRAPPER0: StaticCell = StaticCell::new(); @@ -152,11 +174,10 @@ async fn task(spawner: Spawner) { static INTERMEDIATE1: StaticCell< IntermediateStorage<1, GlobalRawMutex, DynamicSender<'static, psu::event::EventData>>, > = StaticCell::new(); - let intermediate1 = INTERMEDIATE1.init( - storage1 - .try_create_intermediate([("Pd1", policy_sender1)]) - .expect("Failed to create intermediate storage"), - ); + let (intermediate1, power_event_receivers1) = storage1 + .try_create_intermediate([("Pd1", policy_sender1)]) + .expect("Failed to create intermediate storage"); + let intermediate1 = INTERMEDIATE1.init(intermediate1); static REFERENCED1: StaticCell>> = StaticCell::new(); @@ -168,6 +189,12 @@ async fn task(spawner: Spawner) { static STATE1: StaticCell = StaticCell::new(); let state1 = STATE1.init(mock_controller::ControllerState::new()); + let event_receiver1 = ArrayPortEventReceivers::new( + state1.create_interrupt_receiver(), + power_event_receivers1, + &referenced1.pd_controller, + &storage1.cfu_device, + ); static CONTROLLER1: StaticCell> = StaticCell::new(); let controller1 = CONTROLLER1.init(Mutex::new(mock_controller::Controller::new(state1))); static WRAPPER1: StaticCell = StaticCell::new(); @@ -198,11 +225,10 @@ async fn task(spawner: Spawner) { static INTERMEDIATE2: StaticCell< IntermediateStorage<1, GlobalRawMutex, DynamicSender<'static, psu::event::EventData>>, > = StaticCell::new(); - let intermediate2 = INTERMEDIATE2.init( - storage2 - .try_create_intermediate([("Pd2", policy_sender2)]) - .expect("Failed to create intermediate storage"), - ); + let (intermediate2, power_event_receivers2) = storage2 + .try_create_intermediate([("Pd2", policy_sender2)]) + .expect("Failed to create intermediate storage"); + let intermediate2 = INTERMEDIATE2.init(intermediate2); static REFERENCED2: StaticCell>> = StaticCell::new(); @@ -214,6 +240,12 @@ async fn task(spawner: Spawner) { static STATE2: StaticCell = StaticCell::new(); let state2 = STATE2.init(mock_controller::ControllerState::new()); + let event_receiver2 = ArrayPortEventReceivers::new( + state2.create_interrupt_receiver(), + power_event_receivers2, + &referenced2.pd_controller, + &storage2.cfu_device, + ); static CONTROLLER2: StaticCell> = StaticCell::new(); let controller2 = CONTROLLER2.init(Mutex::new(mock_controller::Controller::new(state2))); static WRAPPER2: StaticCell = StaticCell::new(); @@ -259,27 +291,33 @@ async fn task(spawner: Spawner) { static CFU_CLIENT: OnceLock = OnceLock::new(); let cfu_client = CfuClient::new(&CFU_CLIENT).await; - spawner.spawn(power_policy_task( - ArrayEventReceivers::new( - [ - &wrapper0.ports[0].proxy, - &wrapper1.ports[0].proxy, - &wrapper2.ports[0].proxy, - ], - [policy_receiver0, policy_receiver1, policy_receiver2], - ), - power_service, - ).expect("Failed to create power policy task")); - spawner.spawn(type_c_service_task( - type_c_service, - EventReceiver::new(controller_context, power_policy_subscriber), - [wrapper0, wrapper1, wrapper2], - cfu_client, - ).expect("Failed to create type-c service task")); - - spawner.spawn(controller_task(wrapper0).expect("Failed to create controller0 task")); - spawner.spawn(controller_task(wrapper1).expect("Failed to create controller1 task")); - spawner.spawn(controller_task(wrapper2).expect("Failed to create controller2 task")); + spawner.spawn( + power_policy_task( + ArrayEventReceivers::new( + [ + &wrapper0.ports[0].proxy, + &wrapper1.ports[0].proxy, + &wrapper2.ports[0].proxy, + ], + [policy_receiver0, policy_receiver1, policy_receiver2], + ), + power_service, + ) + .expect("Failed to create power policy task"), + ); + spawner.spawn( + type_c_service_task( + type_c_service, + EventReceiver::new(controller_context, power_policy_subscriber), + [wrapper0, wrapper1, wrapper2], + cfu_client, + ) + .expect("Failed to create type-c service task"), + ); + + spawner.spawn(controller_task(event_receiver0, wrapper0).expect("Failed to create controller0 task")); + spawner.spawn(controller_task(event_receiver1, wrapper1).expect("Failed to create controller1 task")); + spawner.spawn(controller_task(event_receiver2, wrapper2).expect("Failed to create controller2 task")); const CAPABILITY: PowerCapability = PowerCapability { voltage_mv: 20000, diff --git a/examples/std/src/lib/type_c/mock_controller.rs b/examples/std/src/lib/type_c/mock_controller.rs index f9783011..9b248759 100644 --- a/examples/std/src/lib/type_c/mock_controller.rs +++ b/examples/std/src/lib/type_c/mock_controller.rs @@ -5,7 +5,7 @@ use embedded_usb_pd::{Error, ado::Ado}; use embedded_usb_pd::{LocalPortId, PdError}; use embedded_usb_pd::{PowerRole, type_c::Current}; use embedded_usb_pd::{type_c::ConnectionState, ucsi::lpm}; -use log::{debug, info, trace}; +use log::{debug, info}; use power_policy_interface::capability::PowerCapability; use type_c_interface::port::{ @@ -29,6 +29,10 @@ impl ControllerState { } } + pub fn create_interrupt_receiver(&self) -> InterruptReceiver<'_> { + InterruptReceiver { events: &self.events } + } + /// Simulate a connection pub async fn connect(&self, role: PowerRole, capability: PowerCapability, debug: bool, unconstrained: bool) { let mut status = PortStatus::new(); @@ -96,15 +100,11 @@ impl Default for ControllerState { pub struct Controller<'a> { state: &'a ControllerState, - events: PortEventBitfield, } impl<'a> Controller<'a> { pub fn new(state: &'a ControllerState) -> Self { - Self { - state, - events: PortEventBitfield::none(), - } + Self { state } } /// Function to demonstrate calling functions directly on the controller @@ -113,22 +113,21 @@ impl<'a> Controller<'a> { } } -impl type_c_interface::port::Controller for Controller<'_> { - type BusError = (); +pub struct InterruptReceiver<'a> { + events: &'a Signal, +} - async fn wait_port_event(&mut self) -> Result<(), Error> { - let events = self.state.events.wait().await; - trace!("Port event: {events:#?}"); - self.events = self.events.union(events); - Ok(()) +impl type_c_service::wrapper::event_receiver::InterruptReceiver for InterruptReceiver<'_> { + async fn wait_interrupt(&mut self) -> [PortEventBitfield; N] { + let events = self.events.wait().await; + let mut result = [PortEventBitfield::none(); N]; + result[0] = events; + result } +} - async fn clear_port_events(&mut self, _port: LocalPortId) -> Result> { - let events = self.events; - debug!("Clear port events: {events:#?}"); - self.events = PortEventBitfield::none(); - Ok(events) - } +impl type_c_interface::port::Controller for Controller<'_> { + type BusError = (); async fn get_port_status(&mut self, _port: LocalPortId) -> Result> { debug!("Get port status: {:#?}", *self.state.status.lock().await); diff --git a/type-c-interface/src/port/mod.rs b/type-c-interface/src/port/mod.rs index e7b19de8..149de314 100644 --- a/type-c-interface/src/port/mod.rs +++ b/type-c-interface/src/port/mod.rs @@ -15,7 +15,6 @@ use embedded_services::{GlobalRawMutex, intrusive_list}; pub mod event; -use crate::port::event::PortEventBitfield; use crate::service::event::PortEvent as ServicePortEvent; /// Length of the Other VDM data @@ -512,19 +511,6 @@ pub trait Controller { /// Type of error returned by the bus type BusError; - /// Wait for a port event to occur - /// # Implementation guide - /// This function should be drop safe. - /// Any intermediate side effects must be undone if the returned [`Future`] is dropped before completing. - fn wait_port_event(&mut self) -> impl Future>>; - /// Returns and clears current events for the given port - /// # Implementation guide - /// This function should be drop safe. - /// Any intermediate side effects must be undone if the returned [`Future`] is dropped before completing. - fn clear_port_events( - &mut self, - port: LocalPortId, - ) -> impl Future>>; /// Returns the port status fn get_port_status(&mut self, port: LocalPortId) -> impl Future>>; diff --git a/type-c-service/src/driver/tps6699x.rs b/type-c-service/src/driver/tps6699x.rs index ab7f89eb..2f4f60db 100644 --- a/type-c-service/src/driver/tps6699x.rs +++ b/type-c-service/src/driver/tps6699x.rs @@ -1,9 +1,7 @@ -use ::tps6699x::registers::field_sets::IntEventBus1; use ::tps6699x::registers::{PdCcPullUp, PpExtVbusSw, PpIntVbusSw}; use ::tps6699x::{PORT0, PORT1, TPS66993_NUM_PORTS, TPS66994_NUM_PORTS}; use bitfield::bitfield; use bitflags::bitflags; -use core::array::from_fn; use core::future::Future; use core::iter::zip; use embassy_sync::blocking_mutex::raw::RawMutex; @@ -17,7 +15,7 @@ use embedded_usb_pd::type_c::Current as TypecCurrent; use embedded_usb_pd::ucsi::lpm; use embedded_usb_pd::{DataRole, Error, LocalPortId, PdError, PlugOrientation, PowerRole}; use tps6699x::MAX_SUPPORTED_PORTS; -use tps6699x::asynchronous::embassy as tps6699x_drv; +use tps6699x::asynchronous::embassy::{self as tps6699x_drv, interrupt}; use tps6699x::asynchronous::fw_update::UpdateTarget; use tps6699x::asynchronous::fw_update::{ BorrowedUpdater, BorrowedUpdaterInProgress, disable_all_interrupts, enable_port0_interrupts, @@ -27,6 +25,7 @@ use tps6699x::command::{ vdms::{INITIATOR_WAIT_TIME_MS, MAX_NUM_DATA_OBJECTS, Version}, }; use tps6699x::fw_update::UpdateConfig as FwUpdateConfig; +use tps6699x::registers::field_sets::IntEventBus1; use tps6699x::registers::port_config::TypeCStateMachine; use type_c_interface::port::event::PortEventBitfield; use type_c_interface::port::{ATTN_VDM_LEN, DpConfig, DpStatus, PdStateMachineConfig, RetimerFwUpdateState}; @@ -48,11 +47,10 @@ struct FwUpdateState<'a, M: RawMutex, B: I2c> { /// /// This value is never read, only used to keep the interrupt guard alive #[allow(dead_code)] - guards: [Option>; MAX_SUPPORTED_PORTS], + guards: [Option>; MAX_SUPPORTED_PORTS], } pub struct Tps6699x<'a, M: RawMutex, B: I2c> { - port_events: heapless::Vec, tps6699x: tps6699x_drv::Tps6699x<'a, M, B>, update_state: Option>, /// Firmware update configuration @@ -73,7 +71,6 @@ impl<'a, M: RawMutex, B: I2c> Tps6699x<'a, M, B> { } else { Some(Self { // num_ports validated by branch - port_events: heapless::Vec::from_iter((0..num_ports).map(|_| PortEventBitfield::none())), tps6699x, update_state: None, fw_update_config, @@ -170,116 +167,6 @@ impl Controller for Tps6699x<'_, M, B> { Ok(()) } - /// Wait for an event on any port - async fn wait_port_event(&mut self) -> Result<(), Error> { - let interrupts = self - .tps6699x - .wait_interrupt_any(false, from_fn(|_| IntEventBus1::all())) - .await; - - for (interrupt, event) in zip(interrupts.iter(), self.port_events.iter_mut()) { - if *interrupt == IntEventBus1::new_zero() { - continue; - } - - { - if interrupt.plug_event() { - debug!("Event: Plug event"); - event.status.set_plug_inserted_or_removed(true); - } - if interrupt.source_caps_received() { - debug!("Event: Source Caps received"); - event.status.set_source_caps_received(true); - } - - if interrupt.sink_ready() { - debug!("Event: Sink ready"); - event.status.set_sink_ready(true); - } - - if interrupt.new_consumer_contract() { - debug!("Event: New contract as consumer, PD controller act as Sink"); - // Port is consumer and power negotiation is complete - event.status.set_new_power_contract_as_consumer(true); - } - - if interrupt.new_provider_contract() { - debug!("Event: New contract as provider, PD controller act as source"); - // Port is provider and power negotiation is complete - event.status.set_new_power_contract_as_provider(true); - } - - if interrupt.power_swap_completed() { - debug!("Event: power swap completed"); - event.status.set_power_swap_completed(true); - } - - if interrupt.data_swap_completed() { - debug!("Event: data swap completed"); - event.status.set_data_swap_completed(true); - } - - if interrupt.am_entered() { - debug!("Event: alt mode entered"); - event.status.set_alt_mode_entered(true); - } - - if interrupt.hard_reset() { - debug!("Event: hard reset"); - event.status.set_pd_hard_reset(true); - } - - if interrupt.crossbar_error() { - debug!("Event: crossbar error"); - event.notification.set_usb_mux_error_recovery(true); - } - - if interrupt.usvid_mode_entered() { - debug!("Event: user svid mode entered"); - event.notification.set_custom_mode_entered(true); - } - - if interrupt.usvid_mode_exited() { - debug!("Event: usvid mode exited"); - event.notification.set_custom_mode_exited(true); - } - - if interrupt.usvid_attention_vdm_received() { - debug!("Event: user svid attention vdm received"); - event.notification.set_custom_mode_attention_received(true); - } - - if interrupt.usvid_other_vdm_received() { - debug!("Event: user svid other vdm received"); - event.notification.set_custom_mode_other_vdm_received(true); - } - - if interrupt.discover_mode_completed() { - debug!("Event: discover mode completed"); - event.notification.set_discover_mode_completed(true); - } - - if interrupt.dp_sid_status_updated() { - debug!("Event: dp sid status updated"); - event.notification.set_dp_status_update(true); - } - - if interrupt.alert_message_received() { - debug!("Event: alert message received"); - event.notification.set_alert(true); - } - } - } - Ok(()) - } - - /// Returns and clears current events for the given port - async fn clear_port_events(&mut self, port: LocalPortId) -> Result> { - Ok(core::mem::take( - self.port_events.get_mut(port.0 as usize).ok_or(PdError::InvalidPort)?, - )) - } - /// Returns the current status of the port async fn get_port_status(&mut self, port: LocalPortId) -> Result> { let status = self.tps6699x.get_port_status(port).await?; @@ -801,3 +688,114 @@ bitfield! { /// TI FW version pub u32, ti_fw_version, set_ti_fw_version: 63, 32; } + +pub struct InterruptReceiver<'a, M: RawMutex, BUS: I2c> { + interrupt_receiver: interrupt::InterruptReceiver<'a, M, BUS>, +} + +impl<'a, M: RawMutex, BUS: I2c> InterruptReceiver<'a, M, BUS> { + pub fn new(interrupt_receiver: interrupt::InterruptReceiver<'a, M, BUS>) -> Self { + Self { interrupt_receiver } + } +} + +impl<'a, M: RawMutex, BUS: I2c> crate::wrapper::event_receiver::InterruptReceiver + for InterruptReceiver<'a, M, BUS> +{ + async fn wait_interrupt(&mut self) -> [PortEventBitfield; MAX_SUPPORTED_PORTS] { + let interrupts = self.interrupt_receiver.wait_any(false).await; + let mut port_events = [PortEventBitfield::none(); MAX_SUPPORTED_PORTS]; + for (interrupt, event) in zip(interrupts.iter(), port_events.iter_mut()) { + if *interrupt == IntEventBus1::new_zero() { + continue; + } + + if interrupt.plug_event() { + debug!("Event: Plug event"); + event.status.set_plug_inserted_or_removed(true); + } + if interrupt.source_caps_received() { + debug!("Event: Source Caps received"); + event.status.set_source_caps_received(true); + } + + if interrupt.sink_ready() { + debug!("Event: Sink ready"); + event.status.set_sink_ready(true); + } + + if interrupt.new_consumer_contract() { + debug!("Event: New contract as consumer, PD controller act as Sink"); + // Port is consumer and power negotiation is complete + event.status.set_new_power_contract_as_consumer(true); + } + + if interrupt.new_provider_contract() { + debug!("Event: New contract as provider, PD controller act as source"); + // Port is provider and power negotiation is complete + event.status.set_new_power_contract_as_provider(true); + } + + if interrupt.power_swap_completed() { + debug!("Event: power swap completed"); + event.status.set_power_swap_completed(true); + } + + if interrupt.data_swap_completed() { + debug!("Event: data swap completed"); + event.status.set_data_swap_completed(true); + } + + if interrupt.am_entered() { + debug!("Event: alt mode entered"); + event.status.set_alt_mode_entered(true); + } + + if interrupt.hard_reset() { + debug!("Event: hard reset"); + event.status.set_pd_hard_reset(true); + } + + if interrupt.crossbar_error() { + debug!("Event: crossbar error"); + event.notification.set_usb_mux_error_recovery(true); + } + + if interrupt.usvid_mode_entered() { + debug!("Event: user svid mode entered"); + event.notification.set_custom_mode_entered(true); + } + + if interrupt.usvid_mode_exited() { + debug!("Event: usvid mode exited"); + event.notification.set_custom_mode_exited(true); + } + + if interrupt.usvid_attention_vdm_received() { + debug!("Event: user svid attention vdm received"); + event.notification.set_custom_mode_attention_received(true); + } + + if interrupt.usvid_other_vdm_received() { + debug!("Event: user svid other vdm received"); + event.notification.set_custom_mode_other_vdm_received(true); + } + + if interrupt.discover_mode_completed() { + debug!("Event: discover mode completed"); + event.notification.set_discover_mode_completed(true); + } + + if interrupt.dp_sid_status_updated() { + debug!("Event: dp sid status updated"); + event.notification.set_dp_status_update(true); + } + + if interrupt.alert_message_received() { + debug!("Event: alert message received"); + event.notification.set_alert(true); + } + } + port_events + } +} diff --git a/type-c-service/src/lib.rs b/type-c-service/src/lib.rs index 7fa30c01..12d975c7 100644 --- a/type-c-service/src/lib.rs +++ b/type-c-service/src/lib.rs @@ -5,7 +5,7 @@ pub mod task; pub mod util; pub mod wrapper; -use core::future::Future; +use core::iter::Enumerate; use type_c_interface::port::event::{ PortEvent, PortEventBitfield, PortNotificationEventBitfield, PortStatusEventBitfield, @@ -13,98 +13,55 @@ use type_c_interface::port::event::{ /// Struct to convert port events into a stream of events #[derive(Clone)] -pub struct PortEventStreamer> { - /// Current port index being processed - port_index: Option, - /// Iterator over pending ports - port_iter: Iter, +pub struct PortEventStreamer> { + /// Iterator over pending event bitfields + port_iter: Enumerate, /// Notification to be streamed - pending_notifications: Option, + pending_notifications: Option<(usize, PortNotificationEventBitfield)>, } -impl> PortEventStreamer { +impl> PortEventStreamer { /// Create new PortEventStreamer - /// - /// Returns none if there are no pending ports to process. pub fn new(port_iter: Iter) -> Self { Self { - port_index: None, - port_iter, + port_iter: port_iter.enumerate(), pending_notifications: None, } } } -impl> PortEventStreamer { - /// Get the next port event, calls the closure if it needs to get pending events for the current port. - pub async fn next>, F: FnMut(usize) -> Fut>( - &mut self, - mut f: F, - ) -> Result, E> { - loop { - let port_index = if let Some(index) = self.port_index { - index - } else if let Some(next_port) = self.port_iter.next() { - // First time this function is called, get our starting port index - self.port_index = Some(next_port); - next_port - } else { - // No pending ports to process - return Ok(None); - }; - - let mut advance_port = false; - let mut ret = None; +impl> Iterator for PortEventStreamer { + type Item = (usize, PortEvent); - if let Some(mut pending) = self.pending_notifications { - if let Some(port_event) = pending.next() { - // Return a single notification - self.pending_notifications = Some(pending); - ret = Some((port_index, port_event)); - } else { - // Done with pending notifications, continue to the next port - advance_port = true; - self.pending_notifications = None; - } - } else { - // Haven't read port events yet - let event = f(port_index).await?; + fn next(&mut self) -> Option { + loop { + // Handle any pending notifications first + if let Some((port_index, pending)) = &mut self.pending_notifications + && let Some(port_event) = pending.next() + { + // Return a single notification + return Some((*port_index, port_event)); + } - if event.notification != PortNotificationEventBitfield::none() { - // Have pending notifications to stream as events, store those for the next loop/call to this function - self.pending_notifications = Some(event.notification); + // No pending notifications, fetch the next port event + if let Some((port_index, event_bitfield)) = self.port_iter.next() { + // Pending notifications for this port if there are any + if event_bitfield.notification != PortNotificationEventBitfield::none() { + self.pending_notifications = Some((port_index, event_bitfield.notification)); } else { - // No pending notifications, we can advance to the next port - advance_port = true; self.pending_notifications = None; } - if event.status != PortStatusEventBitfield::none() { - // Return the port status changed event first if there is one - ret = Some((port_index, PortEvent::StatusChanged(event.status))); - } - } - - if advance_port { - if let Some(next_port) = self.port_iter.next() { - // Move to the next port - self.port_index = Some(next_port); - } else if ret.is_none() { - // Don't have any more ports to process - // And we didn't have any events to return, we're done - return Ok(None); - } else { - // This is the last port, but we have an event to return - // We'll have to return none on the next call, achieve this by setting port_index to None - // The next call will call next() on the pending port iterator which will return None - self.port_index = None; + // Return a status changed event if there is one + if event_bitfield.status != PortStatusEventBitfield::none() { + return Some((port_index, PortEvent::StatusChanged(event_bitfield.status))); } + } else { + // No more ports to process, we're done + return None; } - // Return the event if we have one, otherwise loop to get the next event - if ret.is_some() { - return Ok(ret); - } + //Otherwise loop, to handle any remaining notifications } } } @@ -113,7 +70,6 @@ impl> PortEventStreamer { #[allow(clippy::unwrap_used)] mod tests { use super::*; - use core::sync::atomic::AtomicBool; /// Utility function to create a PortStatusChanged event fn status_changed(plug_event: bool, power_contract: bool, sink_ready: bool) -> PortStatusEventBitfield { @@ -133,155 +89,110 @@ mod tests { } /// Test iterating over port status changed events - #[tokio::test] - async fn test_port_status_changed() { - let mut streamer = PortEventStreamer::new(0..3); + #[test] + fn test_port_status_changed() { + let events = [ + status_changed(true, true, true).into(), + status_changed(true, false, true).into(), + status_changed(false, false, true).into(), + ]; + let mut streamer = PortEventStreamer::new(events.iter().copied()); - let event = streamer - .next::<(), _, _>(async |_| Ok(status_changed(true, true, true).into())) - .await; assert_eq!( - event, - Ok(Some((0, PortEvent::StatusChanged(status_changed(true, true, true))))) + streamer.next(), + Some((0, PortEvent::StatusChanged(status_changed(true, true, true)))) ); - - let event = streamer - .next::<(), _, _>(async |_| Ok(status_changed(true, false, true).into())) - .await; assert_eq!( - event, - Ok(Some((1, PortEvent::StatusChanged(status_changed(true, false, true))))) + streamer.next(), + Some((1, PortEvent::StatusChanged(status_changed(true, false, true)))) ); - - let event = streamer - .next::<(), _, _>(async |_| Ok(status_changed(false, false, true).into())) - .await; assert_eq!( - event, - Ok(Some((2, PortEvent::StatusChanged(status_changed(false, false, true))))) + streamer.next(), + Some((2, PortEvent::StatusChanged(status_changed(false, false, true)))) ); - - let event = streamer - .next::<(), _, _>(async |_| Ok(status_changed(false, false, true).into())) - .await; - assert_eq!(event, Ok(None)); + assert_eq!(streamer.next(), None); } /// Test iterating over port notifications - #[tokio::test] - async fn test_port_notification() { - let mut streamer = PortEventStreamer::new(0..1); - let event = streamer - .next::<(), _, _>(async |_| Ok(notification(true, true).into())) - .await; - assert_eq!(event, Ok(Some((0, PortEvent::Alert)))); - - let event = streamer - .next::<(), _, _>(async |_| Ok(notification(true, true).into())) - .await; - assert_eq!(event, Ok(Some((0, PortEvent::DiscoverModeCompleted)))); - - let event = streamer - .next::<(), _, _>(async |_| Ok(notification(true, true).into())) - .await; - assert_eq!(event, Ok(None)); + #[test] + fn test_port_notification() { + let events = [notification(true, true).into()]; + let mut streamer = PortEventStreamer::new(events.iter().copied()); + + assert_eq!(streamer.next(), Some((0, PortEvent::Alert))); + assert_eq!(streamer.next(), Some((0, PortEvent::DiscoverModeCompleted))); + assert_eq!(streamer.next(), None); } - /// Test the the final port with no pending notifications - #[tokio::test] - async fn test_last_notifications() { - let mut streamer = PortEventStreamer::new(0..1); - - // Test p0 events + /// Test the final port with no pending notifications + #[test] + fn test_last_notifications() { let p0_event = status_changed(true, true, true).into(); - let event = streamer.next::<(), _, _>(async |_| Ok(p0_event)).await; + let events = [p0_event]; + let mut streamer = PortEventStreamer::new(events.iter().copied()); + assert_eq!( - event, - Ok(Some((0, PortEvent::StatusChanged(status_changed(true, true, true))))) + streamer.next(), + Some((0, PortEvent::StatusChanged(status_changed(true, true, true)))) ); - - let event = streamer.next::<(), _, _>(async |_| Ok(p0_event)).await; - assert_eq!(event, Ok(None)); + assert_eq!(streamer.next(), None); } /// Test iterating over both status and notification events - #[tokio::test] - async fn test_port_event() { - let mut streamer = PortEventStreamer::new(0..2); - - // Test p0 events + #[test] + fn test_port_event() { let p0_event = PortEventBitfield { status: status_changed(true, true, true), notification: notification(true, false), }; - - let event = streamer.next::<(), _, _>(async |_| Ok(p0_event)).await; - assert_eq!( - event, - Ok(Some((0, PortEvent::StatusChanged(status_changed(true, true, true))))) - ); - - let event = streamer.next::<(), _, _>(async |_| Ok(p0_event)).await; - assert_eq!(event, Ok(Some((0, PortEvent::Alert)))); - - // Test p1 events let p1_event = PortEventBitfield { status: status_changed(false, true, false), notification: notification(false, true), }; + let events = [p0_event, p1_event]; + let mut streamer = PortEventStreamer::new(events.iter().copied()); - let event = streamer.next::<(), _, _>(async |_| Ok(p1_event)).await; assert_eq!( - event, - Ok(Some((1, PortEvent::StatusChanged(status_changed(false, true, false))))) + streamer.next(), + Some((0, PortEvent::StatusChanged(status_changed(true, true, true)))) ); - - let event = streamer.next::<(), _, _>(async |_| Ok(p1_event)).await; - assert_eq!(event, Ok(Some((1, PortEvent::DiscoverModeCompleted)))); - - let event = streamer.next::<(), _, _>(async |_| Ok(p1_event)).await; - assert_eq!(event, Ok(None)); + assert_eq!(streamer.next(), Some((0, PortEvent::Alert))); + assert_eq!( + streamer.next(), + Some((1, PortEvent::StatusChanged(status_changed(false, true, false)))) + ); + assert_eq!(streamer.next(), Some((1, PortEvent::DiscoverModeCompleted))); + assert_eq!(streamer.next(), None); } /// Test no pending ports - #[tokio::test] - async fn test_no_pending_ports() { - let mut streamer = PortEventStreamer::new(0..0); - let event = streamer - .next::<(), _, _>(async |_| Ok(status_changed(true, true, true).into())) - .await; - assert_eq!(event, Ok(None)); + #[test] + fn test_no_pending_ports() { + let events: [PortEventBitfield; 0] = []; + let mut streamer = PortEventStreamer::new(events.iter().copied()); + + assert_eq!(streamer.next(), None); } /// Test a port with a pending event with no actual event - #[tokio::test] - async fn test_empty_event() { - let mut streamer = PortEventStreamer::new(0..1); - let event = streamer.next::<(), _, _>(async |_| Ok(PortEventBitfield::none())).await; - assert_eq!(event, Ok(None)); + #[test] + fn test_empty_event() { + let events = [PortEventBitfield::none()]; + let mut streamer = PortEventStreamer::new(events.iter().copied()); + + assert_eq!(streamer.next(), None); } /// Test advancing to the next port when there are no events - #[tokio::test] - async fn test_skip_no_pending() { - let mut streamer = PortEventStreamer::new(0..2); - let event = streamer - .next::<(), _, _>(async |_| { - static HAVE_EVENTS: AtomicBool = AtomicBool::new(false); - let have_events = HAVE_EVENTS.load(core::sync::atomic::Ordering::Relaxed); - let event = Ok(status_changed(have_events, have_events, have_events).into()); - HAVE_EVENTS.store(true, core::sync::atomic::Ordering::Relaxed); - event - }) - .await; + #[test] + fn test_skip_no_pending() { + let events = [PortEventBitfield::none(), status_changed(true, true, true).into()]; + let mut streamer = PortEventStreamer::new(events.iter().copied()); + assert_eq!( - event, - Ok(Some((1, PortEvent::StatusChanged(status_changed(true, true, true))))) + streamer.next(), + Some((1, PortEvent::StatusChanged(status_changed(true, true, true)))) ); - - let event = streamer - .next::<(), _, _>(async |_| Ok(status_changed(false, false, false).into())) - .await; - assert_eq!(event, Ok(None)); + assert_eq!(streamer.next(), None); } } diff --git a/type-c-service/src/wrapper/backing.rs b/type-c-service/src/wrapper/backing.rs index 7ee663fb..24e61359 100644 --- a/type-c-service/src/wrapper/backing.rs +++ b/type-c-service/src/wrapper/backing.rs @@ -2,42 +2,17 @@ //! //! TODO: update this documentation when the type-C service is refactored //! -use core::{array::from_fn, ops::Range}; +use core::array::from_fn; use cfu_service::component::CfuDevice; use embassy_sync::{blocking_mutex::raw::RawMutex, mutex::Mutex}; -use embassy_time::Instant; use embedded_cfu_protocol::protocol_definitions::ComponentId; use embedded_services::event; use type_c_interface::port::{ControllerId, PortRegistration, PortStatus, event::PortStatusEventBitfield}; -use crate::{ - PortEventStreamer, - wrapper::{ - cfu, - proxy::{PowerProxyChannel, PowerProxyDevice, PowerProxyReceiver}, - }, -}; - -/// Internal per-controller state -#[derive(Clone)] -pub struct ControllerState { - /// If we're currently doing a firmware update - pub(crate) fw_update_state: cfu::FwUpdateState, - /// State used to keep track of where we are as we turn the event bitfields into a stream of events - pub(crate) port_event_streaming_state: Option>>, -} - -impl Default for ControllerState { - fn default() -> Self { - Self { - fw_update_state: cfu::FwUpdateState::Idle, - port_event_streaming_state: None, - } - } -} +use crate::wrapper::proxy::{PowerProxyChannel, PowerProxyDevice, PowerProxyReceiver}; /// Service registration objects pub struct Registration<'a, M: RawMutex> { @@ -59,7 +34,7 @@ pub struct Storage<'a, const N: usize, M: RawMutex> { context: &'a type_c_interface::service::context::Context, controller_id: ControllerId, pd_ports: [PortRegistration; N], - cfu_device: CfuDevice, + pub cfu_device: CfuDevice, power_proxy_channels: [PowerProxyChannel; N], } @@ -83,7 +58,7 @@ impl<'a, const N: usize, M: RawMutex> Storage<'a, N, M> { pub fn try_create_intermediate>( &self, power_policy_init: [(&'static str, S); N], - ) -> Option> { + ) -> Option<(IntermediateStorage<'_, N, M, S>, [PowerProxyReceiver<'_>; N])> { IntermediateStorage::try_from_storage(self, power_policy_init) } } @@ -98,8 +73,6 @@ pub struct PortState, /// Sender to send events to the power policy service pub(crate) power_policy_sender: S, } @@ -109,7 +82,6 @@ impl> PortState< Self { status: PortStatus::default(), sw_status_event: PortStatusEventBitfield::default(), - sink_ready_deadline: None, power_policy_sender, } } @@ -124,13 +96,15 @@ pub struct IntermediateStorage< > { storage: &'a Storage<'a, N, M>, ports: [Port<'a, M, S>; N], - power_proxy_receivers: [Mutex>; N], } impl<'a, const N: usize, M: RawMutex, S: event::Sender> IntermediateStorage<'a, N, M, S> { - fn try_from_storage(storage: &'a Storage<'a, N, M>, power_policy_init: [(&'static str, S); N]) -> Option { + fn try_from_storage( + storage: &'a Storage<'a, N, M>, + power_policy_init: [(&'static str, S); N], + ) -> Option<(Self, [PowerProxyReceiver<'a>; N])> { let mut ports = heapless::Vec::<_, N>::new(); let mut power_proxy_receivers = heapless::Vec::<_, N>::new(); @@ -145,16 +119,16 @@ impl<'a, const N: usize, M: RawMutex, S: event::Sender, > { intermediate: &'a IntermediateStorage<'a, N, M, S>, - pd_controller: type_c_interface::port::Device<'a>, + pub pd_controller: type_c_interface::port::Device<'a>, power_devices: [&'a Mutex>; N], } @@ -211,7 +185,6 @@ impl<'a, const N: usize, M: RawMutex, S: event::Sender> { pub(crate) registration: Registration<'a, M>, pub(crate) ports: &'a [Port<'a, M, S>], - pub(crate) power_receivers: &'a [Mutex>], } diff --git a/type-c-service/src/wrapper/cfu.rs b/type-c-service/src/wrapper/cfu.rs index 4e206ded..5e6af029 100644 --- a/type-c-service/src/wrapper/cfu.rs +++ b/type-c-service/src/wrapper/cfu.rs @@ -1,13 +1,11 @@ //! CFU message bridge //! TODO: remove this once we have a more generic FW update implementation -use crate::wrapper::backing::ControllerState; +use crate::wrapper::event_receiver::CfuEventReceiver; use cfu_service::component::{InternalResponseData, RequestData}; -use embassy_futures::select::{Either, select}; use embedded_cfu_protocol::protocol_definitions::*; use embedded_services::{debug, error}; use type_c_interface::port::Controller; -use super::message::EventCfu; use super::*; /// Current state of the firmware update process @@ -103,22 +101,22 @@ where async fn process_abort_update( &self, - controller_state: &mut ControllerState, + event_receiver: &mut CfuEventReceiver, controller: &mut D::Inner, ) -> InternalResponseData { // abort the update process match controller.abort_fw_update().await { Ok(_) => { debug!("FW update aborted successfully"); - controller_state.fw_update_state = FwUpdateState::Idle; + event_receiver.fw_update_state = FwUpdateState::Idle; } Err(Error::Pd(e)) => { error!("Failed to abort FW update: {:?}", e); - controller_state.fw_update_state = FwUpdateState::Recovery; + event_receiver.fw_update_state = FwUpdateState::Recovery; } Err(Error::Bus(_)) => { error!("Failed to abort FW update, bus error"); - controller_state.fw_update_state = FwUpdateState::Recovery; + event_receiver.fw_update_state = FwUpdateState::Recovery; } } @@ -128,7 +126,7 @@ where /// Process a GiveContent command async fn process_give_content( &self, - controller_state: &mut ControllerState, + event_receiver: &mut CfuEventReceiver, controller: &mut D::Inner, content: &FwUpdateContentCommand, ) -> InternalResponseData { @@ -162,14 +160,14 @@ where } // Need to start the update - self.fw_update_ticker.lock().await.reset(); + event_receiver.reset_ticker(); match controller.start_fw_update().await { Ok(_) => { debug!("FW update started successfully"); } Err(Error::Pd(e)) => { error!("Failed to start FW update: {:?}", e); - controller_state.fw_update_state = FwUpdateState::Recovery; + event_receiver.fw_update_state = FwUpdateState::Recovery; return InternalResponseData::ContentResponse(FwUpdateContentResponse::new( content.header.sequence_num, CfuUpdateContentResponseStatus::ErrorPrepare, @@ -177,7 +175,7 @@ where } Err(Error::Bus(_)) => { error!("Failed to start FW update, bus error"); - controller_state.fw_update_state = FwUpdateState::Recovery; + event_receiver.fw_update_state = FwUpdateState::Recovery; return InternalResponseData::ContentResponse(FwUpdateContentResponse::new( content.header.sequence_num, CfuUpdateContentResponseStatus::ErrorPrepare, @@ -185,7 +183,7 @@ where } } - controller_state.fw_update_state = FwUpdateState::InProgress(0); + event_receiver.fw_update_state = FwUpdateState::InProgress(0); } match controller @@ -215,16 +213,16 @@ where match controller.finalize_fw_update().await { Ok(_) => { debug!("FW update finalized successfully"); - controller_state.fw_update_state = FwUpdateState::Idle; + event_receiver.fw_update_state = FwUpdateState::Idle; } Err(Error::Pd(e)) => { error!("Failed to finalize FW update: {:?}", e); - controller_state.fw_update_state = FwUpdateState::Recovery; + event_receiver.fw_update_state = FwUpdateState::Recovery; return Self::create_offer_rejection(); } Err(Error::Bus(_)) => { error!("Failed to finalize FW update, bus error"); - controller_state.fw_update_state = FwUpdateState::Recovery; + event_receiver.fw_update_state = FwUpdateState::Recovery; return Self::create_offer_rejection(); } } @@ -237,8 +235,8 @@ where } /// Process a CFU tick - pub async fn process_cfu_tick(&self, controller_state: &mut ControllerState, controller: &mut D::Inner) { - match controller_state.fw_update_state { + pub async fn process_cfu_tick(&self, event_receiver: &mut CfuEventReceiver, controller: &mut D::Inner) { + match event_receiver.fw_update_state { FwUpdateState::Idle => { // No FW update in progress, nothing to do return; @@ -246,7 +244,7 @@ where FwUpdateState::InProgress(ticks) => { if ticks + 1 < DEFAULT_FW_UPDATE_TIMEOUT_TICKS { trace!("CFU tick: {}", ticks); - controller_state.fw_update_state = FwUpdateState::InProgress(ticks + 1); + event_receiver.fw_update_state = FwUpdateState::InProgress(ticks + 1); return; } else { error!("FW update timed out after {} ticks", ticks); @@ -258,7 +256,7 @@ where }; // Update timed out, attempt to exit the FW update - controller_state.fw_update_state = FwUpdateState::Recovery; + event_receiver.fw_update_state = FwUpdateState::Recovery; match controller.abort_fw_update().await { Ok(_) => { debug!("FW update aborted successfully"); @@ -273,17 +271,17 @@ where } } - controller_state.fw_update_state = FwUpdateState::Idle; + event_receiver.fw_update_state = FwUpdateState::Idle; } /// Process a CFU command pub async fn process_cfu_command( &self, - controller_state: &mut ControllerState, + event_receiver: &mut CfuEventReceiver, controller: &mut D::Inner, command: &RequestData, ) -> InternalResponseData { - if controller_state.fw_update_state == FwUpdateState::Recovery { + if event_receiver.fw_update_state == FwUpdateState::Recovery { debug!("FW update in recovery state, rejecting command"); return InternalResponseData::ComponentBusy; } @@ -299,11 +297,11 @@ where } RequestData::GiveContent(content) => { debug!("Got GiveContent"); - self.process_give_content(controller_state, controller, content).await + self.process_give_content(event_receiver, controller, content).await } RequestData::AbortUpdate => { debug!("Got AbortUpdate"); - self.process_abort_update(controller_state, controller).await + self.process_abort_update(event_receiver, controller).await } RequestData::FinalizeUpdate => { debug!("Got FinalizeUpdate"); @@ -328,39 +326,4 @@ where pub async fn send_cfu_response(&self, response: InternalResponseData) { self.registration.cfu_device.send_response(response).await; } - - /// Wait for a CFU command - /// - /// Returns None if the FW update ticker has ticked - /// DROP SAFETY: No state that needs to be restored - pub async fn wait_cfu_command(&self) -> EventCfu { - // Only lock long enough to grab our state - let fw_update_state = self.controller_state.lock().await.fw_update_state; - match fw_update_state { - FwUpdateState::Idle => { - // No FW update in progress, just wait for a command - EventCfu::Request(self.registration.cfu_device.wait_request().await) - } - FwUpdateState::InProgress(_) => { - match select( - self.registration.cfu_device.wait_request(), - self.fw_update_ticker.lock().await.next(), - ) - .await - { - Either::First(command) => EventCfu::Request(command), - Either::Second(_) => { - debug!("FW update ticker ticked"); - EventCfu::RecoveryTick - } - } - } - FwUpdateState::Recovery => { - // Recovery state, wait for the next attempt to recover the device - self.fw_update_ticker.lock().await.next().await; - debug!("FW update ticker ticked"); - EventCfu::RecoveryTick - } - } - } } diff --git a/type-c-service/src/wrapper/event_receiver.rs b/type-c-service/src/wrapper/event_receiver.rs new file mode 100644 index 00000000..a3f967b4 --- /dev/null +++ b/type-c-service/src/wrapper/event_receiver.rs @@ -0,0 +1,279 @@ +//! This module contains event receiver types for the controller wrapper. +use core::array; +use core::future::pending; +use core::pin::pin; +use embassy_futures::select::{Either, Either5, select, select_slice, select5}; +use embassy_time::{Instant, Ticker, Timer}; +use embedded_services::{debug, trace}; +use embedded_usb_pd::LocalPortId; + +use crate::PortEventStreamer; +use crate::wrapper::DEFAULT_FW_UPDATE_TICK_INTERVAL_MS; +use crate::wrapper::cfu::FwUpdateState; +use crate::wrapper::message::{Event, EventCfu, LocalPortEvent, PowerPolicyCommand}; +use crate::wrapper::proxy::PowerProxyReceiver; +use type_c_interface::port::event::{PortEvent, PortEventBitfield, PortStatusEventBitfield}; +use type_c_interface::port::{self}; + +/// Trait used for receiving interrupt from the controller. +pub trait InterruptReceiver { + /// Wait for the next interrupt event. + fn wait_interrupt(&mut self) -> impl Future; +} + +/// Struct to receive and stream port events from the controller. +pub struct PortEventReceiver> { + /// Receiver for the controller's interrupt events + receiver: Receiver, + /// Port event streaming state + streaming_state: Option>>, +} + +impl> PortEventReceiver { + /// Create a new instance + pub fn new(receiver: Receiver) -> Self { + Self { + receiver, + streaming_state: None, + } + } + + /// Wait for the next port event + pub async fn wait_next(&mut self) -> LocalPortEvent { + loop { + let streaming_state = if let Some(streaming_state) = &mut self.streaming_state { + // Yield to ensure we don't monopolize the executor + embassy_futures::yield_now().await; + streaming_state + } else { + let events = self.receiver.wait_interrupt().await; + self.streaming_state.insert(PortEventStreamer::new(events.into_iter())) + }; + + if let Some((port_index, event)) = streaming_state.next() { + return LocalPortEvent { + port: LocalPortId(port_index as u8), + event, + }; + } else { + self.streaming_state = None; + } + } + } +} + +/// Struct to receive power policy messages. +pub struct ArrayPowerProxyEventReceiver<'device, const N: usize> { + receivers: [PowerProxyReceiver<'device>; N], +} + +impl<'device, const N: usize> ArrayPowerProxyEventReceiver<'device, N> { + /// Create a new array power proxy event receiver + pub fn new(receivers: [PowerProxyReceiver<'device>; N]) -> Self { + Self { receivers } + } + + /// Wait for the next power policy command + pub async fn wait_next(&mut self) -> PowerPolicyCommand { + let mut futures = heapless::Vec::<_, N>::new(); + for receiver in self.receivers.iter_mut() { + // Size is fixed at compile time, so no chance of overflow + let _ = futures.push(async { receiver.receive().await }); + } + + // DROP SAFETY: Select over drop safe futures + let (request, local_id) = select_slice(pin!(futures.as_mut_slice())).await; + trace!("Power command: device{} {:#?}", local_id, request); + PowerPolicyCommand { + port: LocalPortId(local_id as u8), + request, + } + } + + /// Temporary function until the conversion to direct function calls is complete + pub async fn send_response( + &mut self, + port: LocalPortId, + response: power_policy_interface::psu::InternalResponseData, + ) -> Result<(), ()> { + self.receivers.get_mut(port.0 as usize).ok_or(())?.send(response).await; + Ok(()) + } +} + +/// Struct to receive CFU events. +pub struct CfuEventReceiver { + /// FW update ticker used to check for timeouts and recovery attempts + fw_update_ticker: Ticker, + /// CFU device used for firmware updates + cfu_device: &'static cfu_service::component::CfuDevice, + pub fw_update_state: FwUpdateState, +} + +impl CfuEventReceiver { + /// Create a new CFU event receiver + pub fn new(cfu_device: &'static cfu_service::component::CfuDevice) -> Self { + Self { + fw_update_ticker: Ticker::every(embassy_time::Duration::from_millis(DEFAULT_FW_UPDATE_TICK_INTERVAL_MS)), + cfu_device, + fw_update_state: FwUpdateState::Idle, + } + } + + /// Wait for the next CFU event + pub async fn wait_next(&mut self) -> EventCfu { + match self.fw_update_state { + FwUpdateState::Idle => { + // No FW update in progress, just wait for a command + EventCfu::Request(self.cfu_device.wait_request().await) + } + FwUpdateState::InProgress(_) => { + match select(self.cfu_device.wait_request(), self.fw_update_ticker.next()).await { + Either::First(command) => EventCfu::Request(command), + Either::Second(_) => { + debug!("FW update ticker ticked"); + EventCfu::RecoveryTick + } + } + } + FwUpdateState::Recovery => { + // Recovery state, wait for the next attempt to recover the device + self.fw_update_ticker.next().await; + debug!("FW update ticker ticked"); + EventCfu::RecoveryTick + } + } + } + + /// Reset the firmware update ticker + pub fn reset_ticker(&mut self) { + self.fw_update_ticker.reset(); + } +} + +/// Struct to receive sink ready timeout events. +pub struct SinkReadyTimeoutEvent { + timeouts: [Option; N], +} + +impl SinkReadyTimeoutEvent { + /// Create a new instance + pub fn new() -> Self { + Self { timeouts: [None; N] } + } + + /// Set a timeout for a specific port + pub fn set_timeout(&mut self, port: LocalPortId, new_timeout: Instant) { + let index = port.0 as usize; + if let Some(timeout) = self.timeouts.get_mut(index) { + *timeout = Some(new_timeout); + } + } + + /// Clear the timeout for a specific port + pub fn clear_timeout(&mut self, port: LocalPortId) { + let index = port.0 as usize; + if let Some(timeout) = self.timeouts.get_mut(index) { + *timeout = None; + } + } + + pub fn get_timeout(&self, port: LocalPortId) -> Option { + let index = port.0 as usize; + self.timeouts.get(index).copied().flatten() + } + + /// Wait for a sink ready timeout and return the port that has timed out. + /// + /// DROP SAFETY: No state to restore + pub async fn wait_next(&mut self) -> LocalPortId { + let mut futures = heapless::Vec::<_, N>::new(); + for (i, timeout) in self.timeouts.iter().enumerate() { + let timeout = *timeout; + // Size is fixed at compile time, so no chance of overflow + let _ = futures.push(async move { + if let Some(timeout) = timeout { + Timer::at(timeout).await; + debug!("Port{}: Sink ready timeout reached", i); + } else { + pending::<()>().await; + } + }); + } + + // DROP SAFETY: Select over drop safe futures + let (_, port_index) = select_slice(pin!(futures.as_mut_slice())).await; + if let Some(timeout) = self.timeouts.get_mut(port_index) { + *timeout = None; + } + LocalPortId(port_index as u8) + } +} + +impl Default for SinkReadyTimeoutEvent { + fn default() -> Self { + Self::new() + } +} + +/// Struct used for containing controller event receivers. +pub struct ArrayPortEventReceivers<'device, const N: usize, PortInterrupts: InterruptReceiver> { + /// Port event receiver + pub port_events: PortEventReceiver, + /// Power proxy event receiver + pub power_proxies: ArrayPowerProxyEventReceiver<'device, N>, + /// PD controller + pub pd_controller: &'static port::Device<'static>, + /// CFU event receiver + pub cfu_event_receiver: CfuEventReceiver, + /// Sink ready timeout event receiver + pub sink_ready_timeout: SinkReadyTimeoutEvent, +} + +impl<'device, const N: usize, PortInterrupts: InterruptReceiver> + ArrayPortEventReceivers<'device, N, PortInterrupts> +{ + /// Create a new instance + pub fn new( + port_interrupts: PortInterrupts, + power_proxies: [PowerProxyReceiver<'device>; N], + pd_controller: &'static port::Device<'static>, + cfu_device: &'static cfu_service::component::CfuDevice, + ) -> Self { + Self { + port_events: PortEventReceiver::new(port_interrupts), + power_proxies: ArrayPowerProxyEventReceiver::new(power_proxies), + pd_controller, + cfu_event_receiver: CfuEventReceiver::new(cfu_device), + sink_ready_timeout: SinkReadyTimeoutEvent::new(), + } + } + + /// Wait for the next port event from any port. + /// + /// Returns the local port ID and the event bitfield. + pub async fn wait_event(&mut self) -> Event<'device> { + match select5( + self.port_events.wait_next(), + self.power_proxies.wait_next(), + self.pd_controller.receive(), + self.cfu_event_receiver.wait_next(), + self.sink_ready_timeout.wait_next(), + ) + .await + { + Either5::First(event) => Event::PortEvent(event), + Either5::Second(command) => Event::PowerPolicyCommand(command), + Either5::Third(request) => Event::ControllerCommand(request), + Either5::Fourth(cfu_event) => Event::CfuEvent(cfu_event), + Either5::Fifth(port) => { + let mut status_event = PortStatusEventBitfield::none(); + status_event.set_sink_ready(true); + Event::PortEvent(LocalPortEvent { + port, + event: PortEvent::StatusChanged(status_event), + }) + } + } + } +} diff --git a/type-c-service/src/wrapper/mod.rs b/type-c-service/src/wrapper/mod.rs index 95ee565d..070ef069 100644 --- a/type-c-service/src/wrapper/mod.rs +++ b/type-c-service/src/wrapper/mod.rs @@ -5,44 +5,37 @@ //! * Type-C: [`type_c_interface::port::Command`] //! * CFU: [`cfu_service::Request`] //! # Event loop -//! This struct follows a standard wait/process/finalize event loop. -//! -//! [`ControllerWrapper::wait_next`] returns [`message::Event`] and does not perform any actions on the controller -//! aside from reading pending events. +//! This struct follows a standard process/finalize event loop. //! //! [`ControllerWrapper::process_event`] reads any additional data relevant to the event and returns [`message::Output`]. //! e.g. port status for a port status changed event, VDM data for a VDM event //! -//! [`ControllerWrapper::process_event`] consumes [`message::Output`] and responds to any deferred requests, performs +//! [`ControllerWrapper::finalize`] consumes [`message::Output`] and responds to any deferred requests, performs //! any caching/buffering of data, and notifies the type-C service implementation of the event if needed. -use core::array::from_fn; -use core::future::pending; -use core::ops::{DerefMut, Range}; +use core::ops::DerefMut; -use crate::wrapper::backing::{ControllerState, PortState}; +use crate::wrapper::backing::PortState; +use crate::wrapper::event_receiver::{ArrayPowerProxyEventReceiver, CfuEventReceiver, SinkReadyTimeoutEvent}; use cfu_service::CfuClient; -use embassy_futures::select::{Either, Either5, select, select_array, select5}; use embassy_sync::blocking_mutex::raw::RawMutex; -use embassy_sync::mutex::Mutex; use embassy_sync::signal::Signal; use embassy_time::Instant; use embedded_cfu_protocol::protocol_definitions::{FwUpdateOffer, FwUpdateOfferResponse, FwVersion}; use embedded_services::event; use embedded_services::sync::Lockable; -use embedded_services::{debug, error, info, trace}; +use embedded_services::{error, info, trace}; use embedded_usb_pd::ado::Ado; use embedded_usb_pd::{Error, LocalPortId, PdError}; use type_c_interface::port::event::PortEvent as InterfacePortEvent; use type_c_interface::service::event::{PortEvent as ServicePortEvent, PortEventData as ServicePortEventData}; -use crate::PortEventStreamer; use crate::wrapper::message::*; -use crate::wrapper::proxy::PowerProxyReceiver; pub mod backing; mod cfu; pub mod config; mod dp; +pub mod event_receiver; pub mod message; mod pd; mod power; @@ -82,20 +75,14 @@ pub struct ControllerWrapper< controller: &'device D, /// Trait object for validating firmware versions fw_version_validator: V, - /// FW update ticker used to check for timeouts and recovery attempts - fw_update_ticker: Mutex, /// Registration information for services pub registration: backing::Registration<'device, M>, /// SW port status event signal sw_status_event: Signal, /// General config config: config::Config, - /// Power proxy receivers - power_proxy_receivers: &'device [Mutex>], /// Port proxies pub ports: &'device [backing::Port<'device, M, S>], - /// Controller state - controller_state: Mutex, } impl< @@ -124,14 +111,9 @@ where controller, config, fw_version_validator, - fw_update_ticker: Mutex::new(embassy_time::Ticker::every(embassy_time::Duration::from_millis( - DEFAULT_FW_UPDATE_TICK_INTERVAL_MS, - ))), registration: backing.registration, sw_status_event: Signal::new(), - power_proxy_receivers: backing.power_receivers, ports: backing.ports, - controller_state: Mutex::new(backing::ControllerState::default()), } } @@ -210,8 +192,9 @@ where } /// Process port status changed events - async fn process_port_status_changed<'b>( + async fn process_port_status_changed<'b, const N: usize>( &self, + sink_ready_timeout: &mut SinkReadyTimeoutEvent, controller: &mut D::Inner, local_port_id: LocalPortId, status_event: PortStatusEventBitfield, @@ -248,7 +231,7 @@ where } self.check_sink_ready_timeout( - &mut port_state, + sink_ready_timeout, &status, local_port_id, status_event.new_power_contract_as_consumer(), @@ -315,125 +298,16 @@ where .map_err(Error::Pd) } - /// Wait for a pending port event - /// - /// DROP SAFETY: No state that needs to be restored - async fn wait_port_pending( - &self, - controller_state: &ControllerState, - controller: &mut D::Inner, - ) -> Result>, Error<::BusError>> { - if controller_state.fw_update_state.in_progress() { - // Don't process events while firmware update is in progress - debug!("Firmware update in progress, ignoring port events"); - return pending().await; - } - - let streaming_state = controller_state.port_event_streaming_state.clone(); - if let Some(streamer) = streaming_state { - // If we're converting the bitfields into an event stream yield first to prevent starving other tasks - embassy_futures::yield_now().await; - Ok(streamer) - } else { - // Otherwise, wait for the next port event - // DROP SAFETY: Safe as long as `wait_port_event` is drop safe - match select(controller.wait_port_event(), async { - self.sw_status_event.wait().await; - Ok::<_, Error<::BusError>>(()) - }) - .await - { - Either::First(r) => r?, - Either::Second(_) => (), - }; - Ok(PortEventStreamer::new(0..self.registration.num_ports())) - } - } - - /// Wait for the next event - pub async fn wait_next(&self) -> Result, Error<::BusError>> { - // This loop is to ensure that if we finish streaming events we go back to waiting for the next port event - loop { - let event = { - let controller_state = self.controller_state.lock().await; - let mut controller = self.controller.lock().await; - // DROP SAFETY: Select over drop safe functions - select5( - self.wait_port_pending(&controller_state, &mut controller), - self.wait_power_command(), - self.registration.pd_controller.receive(), - self.wait_cfu_command(), - self.wait_sink_ready_timeout(), - ) - .await - }; - match event { - Either5::First(stream) => { - let mut stream = stream?; - if let Some((port_index, event)) = stream - .next::::BusError>, _, _>(async |port_index| { - // Combine the event read from the controller with any software generated events - // Acquire the locks first to centralize the awaits here - let mut controller = self.controller.lock().await; - let mut port_state = self - .ports - .get(port_index) - .ok_or(Error::Pd(PdError::InvalidPort))? - .state - .lock() - .await; - - let hw_event = controller.clear_port_events(LocalPortId(port_index as u8)).await?; - - // No more awaits, modify state here for drop safety - let sw_event = - core::mem::replace(&mut port_state.sw_status_event, PortStatusEventBitfield::none()); - Ok(hw_event.union(sw_event.into())) - }) - .await? - { - let port_id = LocalPortId(port_index as u8); - self.controller_state.lock().await.port_event_streaming_state = Some(stream); - return Ok(Event::PortEvent(LocalPortEvent { port: port_id, event })); - } else { - self.controller_state.lock().await.port_event_streaming_state = None; - } - } - Either5::Second((port, request)) => { - return Ok(Event::PowerPolicyCommand(PowerPolicyCommand { port, request })); - } - Either5::Third(request) => return Ok(Event::ControllerCommand(request)), - Either5::Fourth(event) => return Ok(Event::CfuEvent(event)), - Either5::Fifth(port) => { - // Sink ready timeout event - debug!("Port{0}: Sink ready timeout", port.0); - self.ports - .get(port.0 as usize) - .ok_or(Error::Pd(PdError::InvalidPort))? - .state - .lock() - .await - .sink_ready_deadline = None; - let mut status_event = PortStatusEventBitfield::none(); - status_event.set_sink_ready(true); - return Ok(Event::PortEvent(LocalPortEvent { - port, - event: type_c_interface::port::event::PortEvent::StatusChanged(status_event), - })); - } - } - } - } - /// Process a port notification - async fn process_port_event<'b>( + async fn process_port_event<'b, const N: usize>( &self, + sink_ready_timeout: &mut SinkReadyTimeoutEvent, controller: &mut D::Inner, event: LocalPortEvent, ) -> Result, Error<::BusError>> { match event.event { InterfacePortEvent::StatusChanged(status_event) => { - self.process_port_status_changed(controller, event.port, status_event) + self.process_port_status_changed(sink_ready_timeout, controller, event.port, status_event) .await } InterfacePortEvent::Alert => { @@ -464,36 +338,40 @@ where /// Top-level processing function /// Only call this fn from one place in a loop. Otherwise a deadlock could occur. - pub async fn process_event<'b>( + pub async fn process_event<'b, const N: usize>( &self, + sink_ready_timeout: &mut SinkReadyTimeoutEvent, + cfu_event_receiver: &mut CfuEventReceiver, event: Event<'b>, ) -> Result, Error<::BusError>> { let mut controller = self.controller.lock().await; - let mut controller_state = self.controller_state.lock().await; match event { - Event::PortEvent(port_event) => self.process_port_event(&mut controller, port_event).await, + Event::PortEvent(port_event) => { + self.process_port_event(sink_ready_timeout, &mut controller, port_event) + .await + } Event::PowerPolicyCommand(PowerPolicyCommand { port, request }) => { let response = self - .process_power_command(&mut controller_state, &mut controller, port, &request) + .process_power_command(cfu_event_receiver, &mut controller, port, &request) .await; Ok(Output::PowerPolicyCommand(OutputPowerPolicyCommand { port, response })) } Event::ControllerCommand(request) => { let response = self - .process_pd_command(&mut controller_state, &mut controller, &request.command) + .process_pd_command(cfu_event_receiver, &mut controller, &request.command) .await; Ok(Output::ControllerCommand(OutputControllerCommand { request, response })) } Event::CfuEvent(event) => match event { EventCfu::Request(request) => { let response = self - .process_cfu_command(&mut controller_state, &mut controller, &request) + .process_cfu_command(cfu_event_receiver, &mut controller, &request) .await; Ok(Output::CfuResponse(response)) } EventCfu::RecoveryTick => { // FW Update tick, process timeouts and recovery attempts - self.process_cfu_tick(&mut controller_state, &mut controller).await; + self.process_cfu_tick(cfu_event_receiver, &mut controller).await; Ok(Output::CfuRecovery) } }, @@ -501,7 +379,11 @@ where } /// Event loop finalize - pub async fn finalize<'b>(&self, output: Output<'b>) -> Result<(), Error<::BusError>> { + pub async fn finalize<'b, const N: usize>( + &self, + event_receiver: &mut ArrayPowerProxyEventReceiver<'device, N>, + output: Output<'b>, + ) -> Result<(), Error<::BusError>> { match output { Output::Nop => Ok(()), Output::PortStatusChanged(OutputPortStatusChanged { @@ -512,13 +394,10 @@ where Output::PdAlert(OutputPdAlert { port, ado }) => self.finalize_pd_alert(port, ado).await, Output::Vdm(vdm) => self.finalize_vdm(vdm).await.map_err(Error::Pd), Output::PowerPolicyCommand(OutputPowerPolicyCommand { port, response }) => { - self.power_proxy_receivers - .get(port.0 as usize) - .ok_or(Error::Pd(PdError::InvalidPort))? - .lock() + event_receiver + .send_response(port, response) .await - .send(response) - .await; + .map_err(|_| Error::Pd(PdError::Failed))?; Ok(()) } Output::ControllerCommand(OutputControllerCommand { request, response }) => { @@ -541,18 +420,17 @@ where } /// Combined processing and finialization function - pub async fn process_and_finalize_event<'b>( + pub async fn process_and_finalize_event<'b, const N: usize>( &self, + sink_ready_timeout: &mut SinkReadyTimeoutEvent, + cfu_event_receiver: &mut CfuEventReceiver, + power_event_receiver: &mut ArrayPowerProxyEventReceiver<'device, N>, event: Event<'b>, ) -> Result<(), Error<::BusError>> { - let output = self.process_event(event).await?; - self.finalize(output).await - } - - /// Combined processing function - pub async fn process_next_event(&self) -> Result<(), Error<::BusError>> { - let event = self.wait_next().await?; - self.process_and_finalize_event(event).await + let output = self + .process_event(sink_ready_timeout, cfu_event_receiver, event) + .await?; + self.finalize(power_event_receiver, output).await } /// Register all devices with their respective services diff --git a/type-c-service/src/wrapper/pd.rs b/type-c-service/src/wrapper/pd.rs index 41a938d7..4d17e861 100644 --- a/type-c-service/src/wrapper/pd.rs +++ b/type-c-service/src/wrapper/pd.rs @@ -1,5 +1,5 @@ -use crate::wrapper::backing::ControllerState; -use embassy_time::{Duration, Timer}; +use crate::wrapper::event_receiver::SinkReadyTimeoutEvent; +use embassy_time::Duration; use embedded_services::debug; use embedded_usb_pd::constants::{T_PS_TRANSITION_EPR_MS, T_PS_TRANSITION_SPR_MS}; use embedded_usb_pd::ucsi::{self, lpm}; @@ -24,15 +24,15 @@ where /// After accepting a sink contract (new contract as consumer), the PD spec guarantees that the /// source will be available to provide power after `tPSTransition`. This allows us to handle transitions /// even for controllers that might not always broadcast sink ready events. - pub(super) fn check_sink_ready_timeout( + pub(super) fn check_sink_ready_timeout( &self, - port_state: &mut PortState, + sink_ready_timeout: &mut SinkReadyTimeoutEvent, status: &PortStatus, port: LocalPortId, new_contract: bool, sink_ready: bool, ) -> Result<(), PdError> { - let deadline = &mut port_state.sink_ready_deadline; + let timeout = sink_ready_timeout.get_timeout(port); if new_contract && !sink_ready { // Start the timeout @@ -46,42 +46,17 @@ where .0 * 2; debug!("Port{}: Sink ready timeout started for {}ms", port.0, timeout_ms); - *deadline = Some(Instant::now() + Duration::from_millis(timeout_ms as u64)); - } else if deadline.is_some() + sink_ready_timeout.set_timeout(port, Instant::now() + Duration::from_millis(timeout_ms as u64)); + } else if timeout.is_some() && (!status.is_connected() || status.available_sink_contract.is_none() || sink_ready) { // Clear the timeout debug!("Port{}: Sink ready timeout cleared", port.0); - *deadline = None; + sink_ready_timeout.clear_timeout(port); } Ok(()) } - /// Wait for a sink ready timeout and return the port that has timed out. - /// - /// DROP SAFETY: No state to restore - pub(super) async fn wait_sink_ready_timeout(&self) -> LocalPortId { - let futures: [_; MAX_SUPPORTED_PORTS] = from_fn(|i| async move { - let Some(port) = self.ports.get(i) else { - pending::<()>().await; - return; - }; - - let deadline = port.state.lock().await.sink_ready_deadline; - if let Some(deadline) = deadline { - Timer::at(deadline).await; - debug!("Port{}: Sink ready timeout reached", i); - port.state.lock().await.sink_ready_deadline = None; - } else { - pending::<()>().await; - } - }); - - // DROP SAFETY: Select over drop safe futures - let (_, port_index) = select_array(futures).await; - LocalPortId(port_index as u8) - } - /// Process a request to set the maximum sink voltage for a port async fn process_set_max_sink_voltage( &self, @@ -121,11 +96,11 @@ where /// Handle a port command async fn process_port_command( &self, - controller_state: &mut ControllerState, + cfu_event_receiver: &mut CfuEventReceiver, controller: &mut D::Inner, command: &port::PortCommand, ) -> Response<'static> { - if controller_state.fw_update_state.in_progress() { + if cfu_event_receiver.fw_update_state.in_progress() { debug!("FW update in progress, ignoring port command"); return port::Response::Port(Err(PdError::Busy)); } @@ -316,11 +291,11 @@ where async fn process_controller_command( &self, - controller_state: &mut ControllerState, + cfu_event_receiver: &mut CfuEventReceiver, controller: &mut D::Inner, command: &port::InternalCommandData, ) -> Response<'static> { - if controller_state.fw_update_state.in_progress() { + if cfu_event_receiver.fw_update_state.in_progress() { debug!("FW update in progress, ignoring controller command"); return port::Response::Controller(Err(PdError::Busy)); } @@ -352,14 +327,14 @@ where /// Handle a PD controller command pub(super) async fn process_pd_command( &self, - controller_state: &mut ControllerState, + cfu_event_receiver: &mut CfuEventReceiver, controller: &mut D::Inner, command: &port::Command, ) -> Response<'static> { match command { - port::Command::Port(command) => self.process_port_command(controller_state, controller, command).await, + port::Command::Port(command) => self.process_port_command(cfu_event_receiver, controller, command).await, port::Command::Controller(command) => { - self.process_controller_command(controller_state, controller, command) + self.process_controller_command(cfu_event_receiver, controller, command) .await } port::Command::Lpm(_) => port::Response::Ucsi(ucsi::Response { diff --git a/type-c-service/src/wrapper/power.rs b/type-c-service/src/wrapper/power.rs index bc683ab0..8e2022fa 100644 --- a/type-c-service/src/wrapper/power.rs +++ b/type-c-service/src/wrapper/power.rs @@ -1,17 +1,12 @@ //! Module contain power-policy related message handling -use core::pin::pin; - -use embassy_futures::select::select_slice; use embedded_services::debug; +use crate::wrapper::config::UnconstrainedSink; use power_policy_interface::capability::{ConsumerPowerCapability, ProviderPowerCapability, PsuType}; use power_policy_interface::psu::CommandData as PowerCommand; use power_policy_interface::psu::Error as PowerError; use power_policy_interface::psu::{CommandData, InternalResponseData, ResponseData}; -use crate::wrapper::backing::ControllerState; -use crate::wrapper::config::UnconstrainedSink; - use super::*; impl< @@ -97,42 +92,17 @@ where Ok(()) } - /// Wait for a power command - /// - /// Returns (local port ID, deferred request) - /// DROP SAFETY: Call to a select over drop safe futures - pub(super) async fn wait_power_command(&self) -> (LocalPortId, CommandData) { - let mut futures = heapless::Vec::<_, MAX_SUPPORTED_PORTS>::new(); - for receiver in self.power_proxy_receivers { - // TODO: check this at compile time - if futures - .push(async { - let mut lock = receiver.lock().await; - lock.receive().await - }) - .is_err() - { - error!("Futures vec overflow"); - } - } - - // DROP SAFETY: Select over drop safe futures - let (request, local_id) = select_slice(pin!(futures.as_mut_slice())).await; - trace!("Power command: device{} {:#?}", local_id, request); - (LocalPortId(local_id as u8), request) - } - /// Process a power command /// Returns no error because this is a top-level function pub(super) async fn process_power_command( &self, - controller_state: &mut ControllerState, + cfu_event_receiver: &mut CfuEventReceiver, controller: &mut D::Inner, port: LocalPortId, command: &CommandData, ) -> InternalResponseData { trace!("Processing power command: device{} {:#?}", port.0, command); - if controller_state.fw_update_state.in_progress() { + if cfu_event_receiver.fw_update_state.in_progress() { debug!("Port{}: Firmware update in progress", port.0); return Err(PowerError::Busy); }