From d1a4d553a1fb7874fa108e4d24db68131c87344f Mon Sep 17 00:00:00 2001 From: Milind Sharma Date: Wed, 18 Feb 2026 22:37:51 +0800 Subject: [PATCH] chore: bootstrap crate scaffold and proto build pipeline --- .gitignore | 1 - Cargo.lock | 716 ++++++++++++ Cargo.toml | 25 + README.md | 17 +- build.rs | 38 + proto/README.md | 17 + proto/board/board.proto | 146 +++ proto/board/board_commands.proto | 412 +++++++ proto/board/board_types.proto | 1046 ++++++++++++++++++ proto/common/commands/base_commands.proto | 103 ++ proto/common/commands/editor_commands.proto | 440 ++++++++ proto/common/commands/project_commands.proto | 82 ++ proto/common/envelope.proto | 92 ++ proto/common/types/base_types.proto | 482 ++++++++ proto/common/types/enums.proto | 122 ++ proto/common/types/project_settings.proto | 94 ++ proto/schematic/schematic_commands.proto | 24 + proto/schematic/schematic_types.proto | 75 ++ src/blocking.rs | 22 + src/client.rs | 99 ++ src/commands/base.rs | 2 + src/commands/board.rs | 2 + src/commands/editor.rs | 2 + src/commands/mod.rs | 4 + src/commands/project.rs | 2 + src/envelope.rs | 2 + src/error.rs | 13 + src/lib.rs | 21 + src/model/board.rs | 4 + src/model/common.rs | 7 + src/model/mod.rs | 2 + src/transport.rs | 2 + 32 files changed, 4113 insertions(+), 3 deletions(-) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 build.rs create mode 100644 proto/README.md create mode 100644 proto/board/board.proto create mode 100644 proto/board/board_commands.proto create mode 100644 proto/board/board_types.proto create mode 100644 proto/common/commands/base_commands.proto create mode 100644 proto/common/commands/editor_commands.proto create mode 100644 proto/common/commands/project_commands.proto create mode 100644 proto/common/envelope.proto create mode 100644 proto/common/types/base_types.proto create mode 100644 proto/common/types/enums.proto create mode 100644 proto/common/types/project_settings.proto create mode 100644 proto/schematic/schematic_commands.proto create mode 100644 proto/schematic/schematic_types.proto create mode 100644 src/blocking.rs create mode 100644 src/client.rs create mode 100644 src/commands/base.rs create mode 100644 src/commands/board.rs create mode 100644 src/commands/editor.rs create mode 100644 src/commands/mod.rs create mode 100644 src/commands/project.rs create mode 100644 src/envelope.rs create mode 100644 src/error.rs create mode 100644 src/lib.rs create mode 100644 src/model/board.rs create mode 100644 src/model/common.rs create mode 100644 src/model/mod.rs create mode 100644 src/transport.rs diff --git a/.gitignore b/.gitignore index 4e63ece..5178a04 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,6 @@ target # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ -proto/ prompts/ *.DS_Store diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..db67546 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,716 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "kicad-ipc" +version = "0.0.0" +dependencies = [ + "nng", + "prost", + "prost-build", + "prost-types", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "nng" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20a18ed7ec1c8ff1658bcfea2ce76dcedf8be21dd9e8dd2e9762ba9632d16203" +dependencies = [ + "log", + "nng-sys", +] + +[[package]] +name = "nng-sys" +version = "1.4.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d0e7f39a8fd1792a710da9351320e864dc799cf439960e332c977b2f876da6" +dependencies = [ + "cmake", + "version_check", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" +dependencies = [ + "heck", + "itertools", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..931b058 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "kicad-ipc" +version = "0.0.0" +edition = "2021" +license = "MIT" +description = "Rust bindings for the KiCad IPC API" +repository = "https://github.com/kicad-oss/kicad-ipc-rust" +readme = "README.md" + +[features] +default = ["async"] +async = ["dep:nng", "dep:prost", "dep:prost-types", "dep:tokio"] +blocking = ["async"] +tracing = ["dep:tracing"] + +[dependencies] +nng = { version = "1.0.1", optional = true } +prost = { version = "0.14.3", optional = true } +prost-types = { version = "0.14.1", optional = true } +thiserror = "2.0.12" +tokio = { version = "1.48.0", features = ["sync", "time", "rt", "macros"], optional = true } +tracing = { version = "0.1.41", optional = true } + +[build-dependencies] +prost-build = "0.14.1" diff --git a/README.md b/README.md index 1db83bb..6222a35 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,15 @@ -# KiCAD IPC API Rust -MIT licensed, entirely up-to-date, actively maintained Rust bindings for the KiCAD IPC API +# KiCad IPC API Rust + +MIT-licensed Rust bindings for the KiCad IPC API. + +## Current Status + +Early scaffold phase. Core architecture + step-by-step implementation plan: +- `/Users/milindsharma/Developer/kicad-oss/kicad-ipc-rust/prompts/IPC_RUST_EXECUTION_PLAN.md` +- `/Users/milindsharma/Developer/kicad-oss/kicad-ipc-rust/proto/README.md` + +## Roadmap + +1. Async-first layered client (`v0.1.0`) +2. Full PCB read surface + trace write capability (`v0.1.0`) +3. Blocking wrapper parity (`v0.2.0`) diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..9ff0b5a --- /dev/null +++ b/build.rs @@ -0,0 +1,38 @@ +use std::fs; +use std::io; +use std::path::{Path, PathBuf}; + +fn collect_proto_files(root: &Path, out: &mut Vec) -> io::Result<()> { + for entry in fs::read_dir(root)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + collect_proto_files(&path, out)?; + continue; + } + + if path.extension().and_then(|ext| ext.to_str()) == Some("proto") { + out.push(path); + } + } + + Ok(()) +} + +fn main() { + let proto_root = PathBuf::from("proto"); + println!("cargo:rerun-if-changed={}", proto_root.display()); + + let mut proto_files = Vec::new(); + collect_proto_files(&proto_root, &mut proto_files) + .expect("failed to enumerate proto files under ./proto"); + + proto_files.sort(); + + let mut config = prost_build::Config::new(); + config.protoc_arg("--experimental_allow_proto3_optional"); + + config + .compile_protos(&proto_files, &[proto_root]) + .expect("failed to compile KiCad protobuf schema"); +} diff --git a/proto/README.md b/proto/README.md new file mode 100644 index 0000000..e4f28bf --- /dev/null +++ b/proto/README.md @@ -0,0 +1,17 @@ +# KiCad IPC Protocol Buffer Definitions + +These `.proto` files are copied from the official KiCad source tree: + +- https://gitlab.com/kicad/code/kicad/-/tree/master/api/proto + +Rules for this repository: + +1. Keep copied files verbatim when possible. +2. Preserve original upstream copyright/license headers. +3. Use these files for build-time code generation. +4. Do not commit generated Rust protobuf output. + +Crate licensing: + +- Hand-written Rust code in this repository is MIT licensed. +- Upstream `.proto` files retain their original upstream licensing/headers. diff --git a/proto/board/board.proto b/proto/board/board.proto new file mode 100644 index 0000000..9d89b0c --- /dev/null +++ b/proto/board/board.proto @@ -0,0 +1,146 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Jon Evans + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +syntax = "proto3"; + +package kiapi.board; + +import "common/types/base_types.proto"; +import "board/board_types.proto"; + +message BoardFinish +{ + string type_name = 1; +} + +message BoardImpedanceControl +{ + bool is_controlled = 1; +} + +message BoardEdgeConnector +{ +} + +message Castellation +{ + bool has_castellated_pads = 1; +} + +message EdgePlating +{ + bool has_edge_plating = 1; +} + +message BoardEdgeSettings +{ + BoardEdgeConnector connector = 1; + Castellation castellation = 2; + EdgePlating plating = 3; +} + +message BoardStackupCopperLayer +{ + +} + +enum BoardStackupLayerType +{ + BSLT_UNKNOWN = 0; + BSLT_COPPER = 1; + BSLT_DIELECTRIC = 2; + BSLT_SILKSCREEN = 3; + BSLT_SOLDERMASK = 4; + BSLT_SOLDERPASTE = 5; + BSLT_UNDEFINED = 7; +} + +message BoardStackupDielectricProperties +{ + double epsilon_r = 1; + double loss_tangent = 2; + string material_name = 3; + kiapi.common.types.Distance thickness = 4; +} + +message BoardStackupDielectricLayer +{ + // A single dielectric slot (between copper layers) can be made up of multiple physical layers + repeated BoardStackupDielectricProperties layer = 1; +} + +message BoardStackupLayer +{ + kiapi.common.types.Distance thickness = 1; + kiapi.board.types.BoardLayer layer = 2; + bool enabled = 3; + BoardStackupLayerType type = 4; + BoardStackupDielectricLayer dielectric = 5; + kiapi.common.types.Color color = 6; + string material_name = 7; + + // The name of the layer shown in the KiCad GUI, which may be a default value like "F.Cu" or may + // have been customized by the user. This field does not apply to dielectric layers. + string user_name = 8; +} + +message BoardStackup +{ + BoardFinish finish = 1; + BoardImpedanceControl impedance = 2; + // NOTE: m_HasThicknessConstrains appears to be unused + BoardEdgeSettings edge = 3; + repeated BoardStackupLayer layers = 4; +} + +// LAYER_CLASS_* in BOARD_DESIGN_SETTINGS -- needs to become an enum class +enum BoardLayerClass +{ + BLC_UNKNOWN = 0; + BLC_SILKSCREEN = 1; + BLC_COPPER = 2; + BLC_EDGES = 3; + BLC_COURTYARD = 4; + BLC_FABRICATION = 5; + BLC_OTHER = 6; +} + +message BoardLayerGraphicsDefaults +{ + BoardLayerClass layer = 1; + kiapi.common.types.TextAttributes text = 2; + kiapi.common.types.Distance line_thickness = 3; +} + +message GraphicsDefaults +{ + repeated BoardLayerGraphicsDefaults layers = 1; +} + +// Anything that isn't stackup or design rules +message BoardSettings +{ + GraphicsDefaults graphics_defaults = 1; + // Dimension default settings +} + +message BoardDesignRules +{ +} diff --git a/proto/board/board_commands.proto b/proto/board/board_commands.proto new file mode 100644 index 0000000..1eae3ae --- /dev/null +++ b/proto/board/board_commands.proto @@ -0,0 +1,412 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Jon Evans + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +syntax = "proto3"; + +package kiapi.board.commands; + +import "common/types/base_types.proto"; +import "common/types/enums.proto"; +import "common/types/project_settings.proto"; +import "board/board.proto"; +import "board/board_types.proto"; + +/* + * Board stackup and properties + */ + +message GetBoardStackup +{ + kiapi.common.types.DocumentSpecifier board = 1; +} + +message BoardStackupResponse +{ + kiapi.board.BoardStackup stackup = 1; +} + +// Changes the stackup for the given board according to the contents of the message (**not yet implemented**) +// WARNING: any existing content on layers that are removed by this call is deleted. This operation cannot be undone. +// Returns BoardStackupResponse with the updated stackup, in normalized form +message UpdateBoardStackup +{ + kiapi.common.types.DocumentSpecifier board = 1; + kiapi.board.BoardStackup stackup = 2; +} + +message GetBoardEnabledLayers +{ + kiapi.common.types.DocumentSpecifier board = 1; +} + +message BoardEnabledLayersResponse +{ + // The number of copper layers enabled in this board. + uint32 copper_layer_count = 1; + + // A list of all layers enabled in this board, including copper layers and ones which cannot be disabled. + repeated kiapi.board.types.BoardLayer layers = 2; +} + +// Changes which layers are enabled in the board stackup +// WARNING: any existing content on layers that are removed by this call is deleted. This operation cannot be undone. +// Returns BoardEnabledLayersResponse with the updated layer set. +message SetBoardEnabledLayers +{ + kiapi.common.types.DocumentSpecifier board = 1; + + // The number of copper layers to enable in the board. Currently, this must be an even number >= 2. + uint32 copper_layer_count = 2; + + // The non-copper layers to enable. Note that any copper layers in this list are ignored; copper layers are enabled + // by setting copper_layer_count. Note that the F/B.Courtyard, Edge.Cuts, and Margin layers cannot be disabled and + // will be present in the board even if they are omitted from this list. + repeated kiapi.board.types.BoardLayer layers = 3; +} + +message GetGraphicsDefaults +{ + kiapi.common.types.DocumentSpecifier board = 1; +} + +message GraphicsDefaultsResponse +{ + kiapi.board.GraphicsDefaults defaults = 1; +} + +enum BoardOriginType +{ + BOT_UNKNOWN = 0; + BOT_GRID = 1; + BOT_DRILL = 2; +} + +// Returns a Vector2 with the specified origin point +message GetBoardOrigin +{ + kiapi.common.types.DocumentSpecifier board = 1; + + BoardOriginType type = 2; +} + +message SetBoardOrigin +{ + kiapi.common.types.DocumentSpecifier board = 1; + + BoardOriginType type = 2; + + kiapi.common.types.Vector2 origin = 3; +} + +/* + * Net management + */ + +message GetNets +{ + kiapi.common.types.DocumentSpecifier board = 1; + + // If provided, will only return nets that belong to the given netclass. + // If more than one netclass_filter is given, nets belonging to any of the given classes will + // be returned. + repeated string netclass_filter = 2; +} + +message NetsResponse +{ + repeated kiapi.board.types.Net nets = 1; +} + +// Retrieve all the copper items belonging to a certain net or set of nets +// returns kiapi.common.commands.GetItemsResponse +message GetItemsByNet +{ + // Specifies which document to query, which fields to return, etc. + kiapi.common.types.ItemHeader header = 1; + + // List of one or more types of items to retreive + repeated kiapi.common.types.KiCadObjectType types = 2; + + // A list of net codes to filter items by + repeated kiapi.board.types.NetCode net_codes = 3; +} + +// Retrieve all the copper items belonging to a certain net class or set of net classes +// returns kiapi.common.commands.GetItemsResponse +message GetItemsByNetClass +{ + // Specifies which document to query, which fields to return, etc. + kiapi.common.types.ItemHeader header = 1; + + // List of one or more types of items to retreive + repeated kiapi.common.types.KiCadObjectType types = 2; + + // A list of net class names to filter items by + repeated string net_classes = 3; +} + +// A net may be part of multiple classes that have a priority ordering, which will result in a +// composite "effective" netclass containing the merged/overridden properties of all the constituent +// netclasses it contains. This message retrieves this effective netclass for a net or list of +// nets. +// Returns NetClassForNetsResponse +message GetNetClassForNets +{ + repeated kiapi.board.types.Net net = 1; +} + +message NetClassForNetsResponse +{ + // Map of net name to netclass info + map classes = 1; +} + +/* + * Blocking operations + */ + +// Refills some or all zones on the board. +// This is a blocking operation; it will return Empty immediately, but KiCad will return +// ApiStatusCode.AS_BUSY to all future API requests until the zone fill has completed. +message RefillZones +{ + kiapi.common.types.DocumentSpecifier board = 1; + + // A list of zones to refill. If empty, all zones are refilled. + repeated kiapi.common.types.KIID zones = 2; +} + +/* + * Utilities + */ + +// Computes the polygon representation of a pad, merging any custom shapes together. +// This representation will approximate curves as a series of segments. +message GetPadShapeAsPolygon +{ + // The board to process + kiapi.common.types.DocumentSpecifier board = 1; + + // A list of one or more pads to process + repeated kiapi.common.types.KIID pads = 2; + + // The layer to process + kiapi.board.types.BoardLayer layer = 3; +} + +// Returned from GetPadShapeAsPolygon. The pads and polygons repeated fields will have the same length +// and can be treated as a list of tuples. +message PadShapeAsPolygonResponse +{ + // The pads that were processed + repeated kiapi.common.types.KIID pads = 1; + + // The polygon representation of each pad + repeated kiapi.common.types.PolygonWithHoles polygons = 2; +} + +// Tests if the given set of items with padstacks (pads or vias) has content on the given set of layers. +// This is a dynamic call rather than a property of the padstack because pads and vias can be set to only include +// shapes on connected copper layers, and whether or not the pad is connected can't be determined in isolation. +// To optimize API call performance, multiple items and multiple layers to test may be passed in with this +// command message. The return will include the results for each valid item on each valid layer. +// Note that not all layers make sense for a given item (for example, testing against BL_UNDEFINED never makes +// sense). In general, the internal KiCad APIs will not return an error when testing non-sensical layers for a given +// item, and instead will return a default of "true" for any such layers. +message CheckPadstackPresenceOnLayers +{ + kiapi.common.types.DocumentSpecifier board = 1; + + repeated kiapi.common.types.KIID items = 2; + + repeated kiapi.board.types.BoardLayer layers = 3; +} + +enum PadstackPresence +{ + PSP_UNKNOWN = 0; + PSP_PRESENT = 1; // The padstack has a shape on a given layer (is flashed) + PSP_NOT_PRESENT = 2; // The padstack has no shape on a given layer (is not flashed) +} + +message PadstackPresenceEntry +{ + kiapi.common.types.KIID item = 1; + kiapi.board.types.BoardLayer layer = 2; + PadstackPresence presence = 3; +} + +message PadstackPresenceResponse +{ + repeated PadstackPresenceEntry entries = 1; +} + +// DRC markers + +enum DrcSeverity // Since 10.0 +{ + DRS_UNKNOWN = 0; + DRS_WARNING = 1; + DRS_ERROR = 2; + DRS_EXCLUSION = 3; + DRS_IGNORE = 4; + DRS_INFO = 5; + DRS_ACTION = 6; + DRS_DEBUG = 7; + DRS_UNDEFINED = 8; +} + +// Returns InjectDrcErrorResponse +message InjectDrcError +{ + kiapi.common.types.DocumentSpecifier board = 1; + + DrcSeverity severity = 2; + + string message = 3; + + kiapi.common.types.Vector2 position = 4; + + repeated kiapi.common.types.KIID items = 5; +} + +message InjectDrcErrorResponse +{ + kiapi.common.types.KIID marker = 1; +} + +// PCB editor commands + +// returns BoardLayers +message GetVisibleLayers +{ + kiapi.common.types.DocumentSpecifier board = 1; +} + +message BoardLayerResponse +{ + kiapi.board.types.BoardLayer layer = 1; +} + +message BoardLayers +{ + repeated kiapi.board.types.BoardLayer layers = 1; +} + +message SetVisibleLayers +{ + kiapi.common.types.DocumentSpecifier board = 1; + + repeated kiapi.board.types.BoardLayer layers = 2; +} + +// returns BoardLayerResponse +message GetActiveLayer +{ + kiapi.common.types.DocumentSpecifier board = 1; +} + +message SetActiveLayer +{ + kiapi.common.types.DocumentSpecifier board = 1; + + kiapi.board.types.BoardLayer layer = 2; +} + +enum InactiveLayerDisplayMode +{ + ILDM_UNKNOWN = 0; + // Inactive layers are shown + ILDM_NORMAL = 1; + // Inactive layers are shown with dimmed colors + ILDM_DIMMED = 2; + // Inactive layers are hidden + ILDM_HIDDEN = 3; +} + +enum NetColorDisplayMode +{ + NCDM_UNKNOWN = 0; + // Net and netclass colors are shown in the ratsnest and on all copper items + NCDM_ALL = 1; + // Net and netclass colors are shown in the ratsnest only + NCDM_RATSNEST = 2; + // Net and netclass colors are not shown + NCDM_OFF = 3; +} + +enum BoardFlipMode +{ + BFM_UNKNOWN = 0; + // Normal ("non-flipped") mode + BFM_NORMAL = 1; + // "Flipped" mode, viewed from the back and mirrored around the X axis + BFM_FLIPPED_X = 2; +} + +enum RatsnestDisplayMode +{ + RDM_UNKNOWN = 0; + // Ratsnest lines are drawn to objects even if they are on hidden layers + RDM_ALL_LAYERS = 1; + // Ratsnest lines are hidden when at least one endpoint is an item on a hidden layer + RDM_VISIBLE_LAYERS = 2; +} + +message BoardEditorAppearanceSettings +{ + InactiveLayerDisplayMode inactive_layer_display = 1; + + NetColorDisplayMode net_color_display = 2; + + BoardFlipMode board_flip = 3; + + RatsnestDisplayMode ratsnest_display = 4; +} + +// Returns BoardEditorAppearanceSettings +message GetBoardEditorAppearanceSettings +{ +} + +message SetBoardEditorAppearanceSettings +{ + BoardEditorAppearanceSettings settings = 1; +} + +//// Interactive commands //// +// These commands begin an interactive operation in the editor. +// They return a response immediately, but the editor will become busy +// and will not reply to further API commands until the user has finished +// the operation. +// These commands will return an error if received in a non-interactive context. + +// Selects and begins an interactive move of the given item(s). +// NOTE: Takes ownership of the active commit, if one exists: +// the move tool will push the commit when the user confirms the move, +// or roll back the commit if the user cancels the move. Keep this in +// mind if using this command in combination with commands that create +// or modify items using an explicit commit. +message InteractiveMoveItems +{ + kiapi.common.types.DocumentSpecifier board = 1; + + repeated kiapi.common.types.KIID items = 2; +} diff --git a/proto/board/board_types.proto b/proto/board/board_types.proto new file mode 100644 index 0000000..32c2111 --- /dev/null +++ b/proto/board/board_types.proto @@ -0,0 +1,1046 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +syntax = "proto3"; + +package kiapi.board.types; + +import "google/protobuf/any.proto"; +import "common/types/base_types.proto"; + +enum BoardLayer +{ + BL_UNKNOWN = 0; + BL_UNDEFINED = 1; + BL_UNSELECTED = 2; + BL_F_Cu = 3; + BL_In1_Cu = 4; + BL_In2_Cu = 5; + BL_In3_Cu = 6; + BL_In4_Cu = 7; + BL_In5_Cu = 8; + BL_In6_Cu = 9; + BL_In7_Cu = 10; + BL_In8_Cu = 11; + BL_In9_Cu = 12; + BL_In10_Cu = 13; + BL_In11_Cu = 14; + BL_In12_Cu = 15; + BL_In13_Cu = 16; + BL_In14_Cu = 17; + BL_In15_Cu = 18; + BL_In16_Cu = 19; + BL_In17_Cu = 20; + BL_In18_Cu = 21; + BL_In19_Cu = 22; + BL_In20_Cu = 23; + BL_In21_Cu = 24; + BL_In22_Cu = 25; + BL_In23_Cu = 26; + BL_In24_Cu = 27; + BL_In25_Cu = 28; + BL_In26_Cu = 29; + BL_In27_Cu = 30; + BL_In28_Cu = 31; + BL_In29_Cu = 32; + BL_In30_Cu = 33; + BL_B_Cu = 34; + BL_B_Adhes = 35; + BL_F_Adhes = 36; + BL_B_Paste = 37; + BL_F_Paste = 38; + BL_B_SilkS = 39; + BL_F_SilkS = 40; + BL_B_Mask = 41; + BL_F_Mask = 42; + BL_Dwgs_User = 43; + BL_Cmts_User = 44; + BL_Eco1_User = 45; + BL_Eco2_User = 46; + BL_Edge_Cuts = 47; + BL_Margin = 48; + BL_B_CrtYd = 49; + BL_F_CrtYd = 50; + BL_B_Fab = 51; + BL_F_Fab = 52; + BL_User_1 = 53; + BL_User_2 = 54; + BL_User_3 = 55; + BL_User_4 = 56; + BL_User_5 = 57; + BL_User_6 = 58; + BL_User_7 = 59; + BL_User_8 = 60; + BL_User_9 = 61; + BL_Rescue = 62; + BL_User_10 = 63; + BL_User_11 = 64; + BL_User_12 = 65; + BL_User_13 = 66; + BL_User_14 = 67; + BL_User_15 = 68; + BL_User_16 = 69; + BL_User_17 = 70; + BL_User_18 = 71; + BL_User_19 = 72; + BL_User_20 = 73; + BL_User_21 = 74; + BL_User_22 = 75; + BL_User_23 = 76; + BL_User_24 = 77; + BL_User_25 = 78; + BL_User_26 = 79; + BL_User_27 = 80; + BL_User_28 = 81; + BL_User_29 = 82; + BL_User_30 = 83; + BL_User_31 = 84; + BL_User_32 = 85; + BL_User_33 = 86; + BL_User_34 = 87; + BL_User_35 = 88; + BL_User_36 = 89; + BL_User_37 = 90; + BL_User_38 = 91; + BL_User_39 = 92; + BL_User_40 = 93; + BL_User_41 = 94; + BL_User_42 = 95; + BL_User_43 = 96; + BL_User_44 = 97; + BL_User_45 = 98; +} + +message NetCode +{ + int32 value = 1; +} + +// Describes a copper item's net +message Net +{ + // A unique code representing this net + NetCode code = 1; + + // Human-readable net name + string name = 2; +} + +// Represents a track segment on a board +message Track +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.Vector2 start = 2; + kiapi.common.types.Vector2 end = 3; + kiapi.common.types.Distance width = 4; + kiapi.common.types.LockedState locked = 5; + BoardLayer layer = 6; + Net net = 7; +} + +// Represents an arc track (not a PCB_SHAPE in arc shape) +// Arc tracks in KiCad store start, midpoint, and end. +// All other values (center point, angles, etc) are inferred. +message Arc +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.Vector2 start = 2; + kiapi.common.types.Vector2 mid = 3; // Arc midpoint + kiapi.common.types.Vector2 end = 4; + kiapi.common.types.Distance width = 5; + kiapi.common.types.LockedState locked = 6; + BoardLayer layer = 7; + Net net = 8; +} + +// What copper layer shape mode the padstack uses +enum PadStackType +{ + PST_UNKNOWN = 0; + + // The same shape is used on all copper layers + PST_NORMAL = 1; + + // The padstack uses up to three different shapes (F_Cu, inner layers, B_Cu) + PST_FRONT_INNER_BACK = 2; + + // The padstack's shape may differ on arbitrary copper layers + PST_CUSTOM = 3; +} + +enum UnconnectedLayerRemoval +{ + ULR_UNKNOWN = 0; + + // Keep annular rings on all layers + ULR_KEEP = 1; + + // Remove annular rings on unconnected layers, including start and end layers. + ULR_REMOVE = 2; + + // Remove annular rings on unconnected layers, but preserve start and end layers even if unconnected. + ULR_REMOVE_EXCEPT_START_AND_END = 3; + + // Keep annular rings only on the start and end layers regardless of connections. + // Since: 10.0.0 + ULR_START_END_ONLY = 4; +} + +// The shape of a pad on a given layer +enum PadStackShape +{ + PSS_UNKNOWN = 0; + PSS_CIRCLE = 1; + PSS_RECTANGLE = 2; + PSS_OVAL = 3; + PSS_TRAPEZOID = 4; + PSS_ROUNDRECT = 5; + PSS_CHAMFEREDRECT = 6; + PSS_CUSTOM = 7; +} + +// Which corners are chamfered in a PSS_CHAMFEREDRECT +message ChamferedRectCorners +{ + bool top_left = 1; + bool top_right = 2; + bool bottom_left = 3; + bool bottom_right = 4; +} + +// enum class ZONE_CONNECTION +enum ZoneConnectionStyle +{ + ZCS_UNKNOWN = 0; + ZCS_INHERITED = 1; + ZCS_NONE = 2; + ZCS_THERMAL = 3; + ZCS_FULL = 4; + ZCS_PTH_THERMAL = 5; // Thermal reliefs for plated through holes, solid for SMD pads +} + +// Controls for how copper zones connect to a pad +message ZoneConnectionSettings +{ + ZoneConnectionStyle zone_connection = 1; + + ThermalSpokeSettings thermal_spokes = 2; +} + +message SolderMaskOverrides +{ + // Solder mask expansion/contraction + kiapi.common.types.Distance solder_mask_margin = 1; +} + +message SolderPasteOverrides +{ + // Solder paste expansion/contraction + kiapi.common.types.Distance solder_paste_margin = 1; + + // Solder paste expansion/contraction ratio + kiapi.common.types.Ratio solder_paste_margin_ratio = 2; +} + +// The defintion of a padstack on a single layer +message PadStackLayer +{ + // The board layer of this padstack entry. For Front/Inner/Back padstacks, In1_Cu is used to represent inner layers. + BoardLayer layer = 1; + + // The shape of the pad on this layer + PadStackShape shape = 2; + + // The size (x and y) of the shape on this layer + kiapi.common.types.Vector2 size = 3; + + // How much to round the corners of the shape by, as a fraction of min(size.x, size.y) + // Only used for PSS_ROUNDRECT or PSS_CHAMFEREDRECT + double corner_rounding_ratio = 4; + + // How much to round the corners of the shape by, as a fraction of min(size.x, size.y) + // Only used for PSS_CHAMFEREDRECT + double chamfer_ratio = 5; + + ChamferedRectCorners chamfered_corners = 6; + + repeated BoardGraphicShape custom_shapes = 7; + + // If shape == PSS_CUSTOM, defines the shape of the anchor (only PSS_CIRCLE and PSS_RECTANGLE supported at present) + PadStackShape custom_anchor_shape = 8; + + // Reserved for future use -- at the moment, zone connection settings are not per-layer + ZoneConnectionSettings zone_settings = 9; + + // The difference in side length between the short and long pads in a trapezoid. Only one of x or y may be nonzero. + // Only used for PSS_TRAPEZOID + kiapi.common.types.Vector2 trapezoid_delta = 10; + + // The offset of the center of this shape from the center of the pad (which is defined as the hole center) + kiapi.common.types.Vector2 offset = 11; +} + +enum SolderMaskMode +{ + SMM_UNKNOWN = 0; + SMM_MASKED = 1; + SMM_UNMASKED = 2; + SMM_FROM_DESIGN_RULES = 3; +} + +enum ViaCoveringMode +{ + VCM_UNKNOWN = 0; + VCM_COVERED = 1; + VCM_UNCOVERED = 2; + VCM_FROM_DESIGN_RULES = 3; +} + +enum ViaPluggingMode +{ + VPM_UNKNOWN = 0; + VPM_PLUGGED = 1; + VPM_UNPLUGGED = 2; + VPM_FROM_DESIGN_RULES = 3; +} + +enum SolderPasteMode +{ + SPM_UNKNOWN = 0; + SPM_PASTE = 1; + SPM_NO_PASTE = 2; + SPM_FROM_DESIGN_RULES = 3; +} + +// Properties for the outer technical layers of a padstack on the top or bottom of the stack +message PadStackOuterLayer +{ + SolderMaskMode solder_mask_mode = 1; + SolderPasteMode solder_paste_mode = 2; + + // NOTE: At present, KiCad does not support different solder mask expansion settings for the top and bottom layers + SolderMaskOverrides solder_mask_settings = 3; + + // NOTE: At present, KiCad does not support different solder paste expansion settings for the top and bottom layers + SolderPasteOverrides solder_paste_settings = 4; + + ViaPluggingMode plugging_mode = 5; + ViaCoveringMode covering_mode = 6; +} + +enum DrillShape +{ + DS_UNKNOWN = 0; + DS_CIRCLE = 1; + DS_OBLONG = 2; + DS_UNDEFINED = 3; +} + +enum ViaDrillCappingMode +{ + VDCM_UNKNOWN = 0; + VDCM_CAPPED = 1; + VDCM_UNCAPPED = 2; + VDCM_FROM_DESIGN_RULES = 3; +} + +enum ViaDrillFillingMode +{ + VDFM_UNKNOWN = 0; + VDFM_FILLED = 1; + VDFM_UNFILLED = 2; + VDFM_FROM_DESIGN_RULES = 3; +} + +enum ViaDrillPostMachiningMode +{ + VDPM_UNKNOWN = 0; + VDPM_NOT_POST_MACHINED = 1; + VDPM_COUNTERBORE = 2; + VDPM_COUNTERSINK = 3; +} + +message DrillProperties +{ + // Lowest (closest to F_Cu) layer this drill exists on. + BoardLayer start_layer = 1; + + // Highest (closest to B_Cu) layer this drill exists on. + BoardLayer end_layer = 2; + + // The diameter, in x and y, of the pad's drilled hole, if this pad has a hole. + // x and y will be the same value if the hole is round. + kiapi.common.types.Vector2 diameter = 3; + + DrillShape shape = 4; + + ViaDrillCappingMode capped = 5; + + ViaDrillFillingMode filled = 6; + +} + +message PostMachiningProperties +{ + ViaDrillPostMachiningMode mode = 1; + int32 size = 2; + int32 depth = 3; + int32 angle = 4; +} + +// A pad stack definition for a multilayer pad or via. +message PadStack +{ + // What type of pad stack this represents. + PadStackType type = 1; + + // The set of board layers this padstack has a definition for + repeated BoardLayer layers = 2; + + // Properties of the drilled hole in this padstack, if it has one + DrillProperties drill = 3; + + // How to treat pad shapes on unconnected layers. + UnconnectedLayerRemoval unconnected_layer_removal = 4; + + repeated PadStackLayer copper_layers = 5; + + // The overall rotation of this padstack (affects all layers) + kiapi.common.types.Angle angle = 6; + + // Solder mask and paste settings for the front + PadStackOuterLayer front_outer_layers = 7; + + // Solder mask and paste settings for the back + PadStackOuterLayer back_outer_layers = 8; + + // Controls for how copper zones connect to the padstack + ZoneConnectionSettings zone_settings = 9; + + // Optional secondary drill hit for backdrilling + DrillProperties secondary_drill = 10; + + // Optional tertiary drill hit for backdrilling + DrillProperties tertiary_drill = 11; + + PostMachiningProperties front_post_machining = 12; + PostMachiningProperties back_post_machining = 13; +} + +enum ViaType +{ + VT_UNKNOWN = 0; + + // Through vias always start on F_Cu and end on B_Cu + VT_THROUGH = 1; + + // Blind/buried vias can have arbitrary start and end layers + VT_BLIND_BURIED = 2; + + // Microvias, blind/buried vias, can have arbitrary start and end layers, but also have different + // size defaults and design rules + VT_MICRO = 3; + + // Blind vias start on an outer layer and end in the middle + VT_BLIND = 4; // Since V10 + + // Buried vias start and end on inner layers + VT_BURIED = 5; // Since V10 +} + +// Represents a via +message Via +{ + // The unique identifier of the via + kiapi.common.types.KIID id = 1; + + // The location of the via's center point + kiapi.common.types.Vector2 position = 2; + + // The pad stack definition for this via. + PadStack pad_stack = 3; + + kiapi.common.types.LockedState locked = 4; + + Net net = 5; + + ViaType type = 6; +} + +message BoardGraphicShape +{ + kiapi.common.types.GraphicShape shape = 1; + BoardLayer layer = 2; + Net net = 3; + kiapi.common.types.KIID id = 4; + kiapi.common.types.LockedState locked = 5; +} + +// A board-specific text object, existing on a board layer +message BoardText +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.Text text = 2; + BoardLayer layer = 3; + bool knockout = 4; + kiapi.common.types.LockedState locked = 5; +} + +// A board-specific textbox, existing on a board layer +message BoardTextBox +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.TextBox textbox = 2; + BoardLayer layer = 3; + kiapi.common.types.LockedState locked = 4; +} + +// NOTE: There has been some discussion about what to do with pad attributes and properties. +// This may be considered somewhat unstable until we decide what to do with the KiCad side. +// It is not clear what the set of mutually-exclusive pad types will be at the end of the day, +// versus what will be non-exclusive attributes/properties. +// For now, this maps to PAD_ATTRIB in KiCad. +enum PadType +{ + PT_UNKNOWN = 0; + PT_PTH = 1; + PT_SMD = 2; + PT_EDGE_CONNECTOR = 3; + PT_NPTH = 4; +} + +enum CustomPadShapeZoneFillStrategy +{ + CPSZ_UNKNOWN = 0; + CPSZ_OUTLINE = 1; + CPSZ_CONVEXHULL = 2; +} + +message ThermalSpokeSettings +{ + kiapi.common.types.Distance width = 1; + kiapi.common.types.Angle angle = 2; + kiapi.common.types.Distance gap = 3; +} + +message SymbolPinInfo +{ + // The pin name for the associated symbol pin, if one exists + string name = 1; + + // The electrical type of the associated symbol pin, if one exists (EPT_UNKNOWN if not) + kiapi.common.types.ElectricalPinType type = 2; + + // True if the pin is attached to a no-connect marker in the schematic + bool no_connect = 3; +} + +message Pad +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.LockedState locked = 2; + string number = 3; + Net net = 4; + PadType type = 5; + PadStack pad_stack = 6; + + // A pad's position is always relative to the parent footprint's origin + kiapi.common.types.Vector2 position = 7; + + // Copper-to-copper clearance override + kiapi.common.types.Distance copper_clearance_override = 8; + + // Since: 9.0.4 + kiapi.common.types.Distance pad_to_die_length = 9; + + // Information about the associated symbol pin, if one exists + // Since: 9.0.7 + SymbolPinInfo symbol_pin = 10; + + // Since: 10.0.0 + kiapi.common.types.Time pad_to_die_delay = 11; +} + +enum ZoneType +{ + ZT_UNKNOWN = 0; + ZT_COPPER = 1; + ZT_GRAPHICAL = 2; + ZT_RULE_AREA = 3; + ZT_TEARDROP = 4; +} + +enum TeardropType +{ + TDT_UNKNOWN = 0; + TDT_NONE = 1; + TDT_UNSPECIFIED = 2; + TDT_VIA_PAD = 3; + TDT_TRACK_END = 4; +} + +enum IslandRemovalMode +{ + IRM_UNKNOWN = 0; + IRM_ALWAYS = 1; + IRM_NEVER = 2; + IRM_AREA = 3; +} + +enum ZoneFillMode +{ + ZFM_UNKNOWN = 0; + ZFM_SOLID = 1; + ZFM_HATCHED = 2; +} + +enum ZoneHatchSmoothing +{ + ZHS_UNKNOWN = 0; + ZHS_NONE = 1; + ZHS_FILLET = 2; + ZHS_ARC_LOW_DEF = 3; + ZHS_ARC_HIGH_DEF = 4; +} + +enum ZoneHatchFillBorderMode +{ + ZHFBM_UNKNOWN = 0; + ZHFBM_USE_MIN_ZONE_THICKNESS = 1; + ZHFBM_USE_HATCH_THICKNESS = 2; +} + +message HatchFillSettings +{ + kiapi.common.types.Distance thickness = 1; + kiapi.common.types.Distance gap = 2; + kiapi.common.types.Angle orientation = 3; + double hatch_smoothing_ratio = 4; + double hatch_hole_min_area_ratio = 5; + ZoneHatchFillBorderMode border_mode = 6; +} + +message TeardropSettings +{ + TeardropType type = 1; +} + +message CopperZoneSettings +{ + ZoneConnectionSettings connection = 1; + + kiapi.common.types.Distance clearance = 2; + + kiapi.common.types.Distance min_thickness = 3; + + IslandRemovalMode island_mode = 4; + + uint64 min_island_area = 5; + + ZoneFillMode fill_mode = 6; + + HatchFillSettings hatch_settings = 7; + + Net net = 8; + + TeardropSettings teardrop = 9; +} + +enum PlacementRuleSourceType +{ + PRST_UNKNOWN = 0; + PRST_SHEET_NAME = 1; + PRST_COMPONENT_CLASS = 2; + PRST_GROUP = 3; + PRST_DESIGN_BLOCK = 4; +} + +message RuleAreaSettings +{ + bool keepout_copper = 1; + bool keepout_vias = 2; + bool keepout_tracks = 3; + bool keepout_pads = 4; + bool keepout_footprints = 5; + + bool placement_enabled = 6; + PlacementRuleSourceType placement_source_type = 7; + string placement_source = 8; +} + +enum ZoneBorderStyle +{ + ZBS_UNKNOWN = 0; + ZBS_SOLID = 1; + ZBS_DIAGONAL_FULL = 2; + ZBS_DIAGONAL_EDGE = 3; + ZBS_INVISIBLE = 4; +} + +message ZoneBorderSettings +{ + ZoneBorderStyle style = 1; + kiapi.common.types.Distance pitch = 2; +} + +// The set of filled polygons of a zone on a single board layer +message ZoneFilledPolygons +{ + BoardLayer layer = 1; + + kiapi.common.types.PolySet shapes = 2; +} + +message ZoneLayerProperties +{ + BoardLayer layer = 1; + + kiapi.common.types.Vector2 hatching_offset = 2; +} + + +message Zone +{ + kiapi.common.types.KIID id = 1; + + ZoneType type = 2; + + repeated BoardLayer layers = 3; + + kiapi.common.types.PolySet outline = 4; + + string name = 5; + + oneof settings { + CopperZoneSettings copper_settings = 6; + RuleAreaSettings rule_area_settings = 7; + } + + uint32 priority = 8; + + bool filled = 9; + + repeated ZoneFilledPolygons filled_polygons = 10; + + ZoneBorderSettings border = 11; + + kiapi.common.types.LockedState locked = 12; + + repeated ZoneLayerProperties layer_properties = 13; +} + +// An aligned dimension is drawn parallel to the line segment between the start and end points +message AlignedDimensionAttributes +{ + kiapi.common.types.Vector2 start = 1; + kiapi.common.types.Vector2 end = 2; + + // Perpendicular distance from dimension endpoints to crossbar + kiapi.common.types.Distance height = 3; + + // Length of extension lines past the crossbar + kiapi.common.types.Distance extension_height = 4; +} + +// An orthogonal dimension is drawn parallel to the X or Y axis of the coordinate system +message OrthogonalDimensionAttributes +{ + kiapi.common.types.Vector2 start = 1; + kiapi.common.types.Vector2 end = 2; + + // Perpendicular distance from dimension endpoints to crossbar + kiapi.common.types.Distance height = 3; + + // Length of extension lines past the crossbar + kiapi.common.types.Distance extension_height = 4; + + // Which axis the dimension is parallel to + kiapi.common.types.AxisAlignment alignment = 5; +} + +message RadialDimensionAttributes +{ + // The center of the dimensioned circle or arc + kiapi.common.types.Vector2 center = 1; + + // A point on the radius of the circle or arc + kiapi.common.types.Vector2 radius_point = 2; + + // The distance from radius_point to draw the first segment of the leader line. + // The second segment is drawn from the end of the first segment to the text position. + kiapi.common.types.Distance leader_length = 3; +} + +// The style of the optional frame applied to dimension text +enum DimensionTextBorderStyle +{ + DTBS_UNKNOWN = 0; + DTBS_NONE = 1; + DTBS_RECTANGLE = 2; + DTBS_CIRCLE = 3; + DTBS_ROUNDRECT = 4; +} + +message LeaderDimensionAttributes +{ + kiapi.common.types.Vector2 start = 1; + kiapi.common.types.Vector2 end = 2; + DimensionTextBorderStyle border_style = 3; +} + +message CenterDimensionAttributes +{ + kiapi.common.types.Vector2 center = 1; + + // A point on the end of one of the four radial spokes drawn from the center point + kiapi.common.types.Vector2 end = 2; +} + +enum DimensionUnitFormat +{ + DUF_UNKNOWN = 0; + DUF_NO_SUFFIX = 1; + DUF_BARE_SUFFIX = 2; + DUF_PAREN_SUFFIX = 3; +} + +enum DimensionArrowDirection +{ + DAD_UNKNOWN = 0; + DAD_INWARD = 1; + DAD_OUTWARD = 2; +} + +enum DimensionPrecision +{ + DP_UNKNOWN = 0; + DP_FIXED_0 = 1; // No digits after decimal point + DP_FIXED_1 = 2; // 1 digit after decimal point + DP_FIXED_2 = 3; // 2 digits after decimal point + DP_FIXED_3 = 4; // 3 digits after decimal point + DP_FIXED_4 = 5; // 4 digits after decimal point + DP_FIXED_5 = 6; // 5 digits after decimal point + DP_SCALED_IN_2 = 7; // Precision depends on unit selection; 2 digits for inches, 0 for mils, 1 for mm + DP_SCALED_IN_3 = 8; // Precision depends on unit selection; 3 digits for inches, 0 for mils, 2 for mm + DP_SCALED_IN_4 = 9; // Precision depends on unit selection; 4 digits for inches, 1 for mils, 3 for mm + DP_SCALED_IN_5 = 10; // Precision depends on unit selection; 5 digits for inches, 2 for mils, 4 for mm +} + +enum DimensionTextPosition +{ + DTP_UNKNOWN = 0; + DTP_OUTSIDE = 1; + DTP_INLINE = 2; + DTP_MANUAL = 3; +} + +enum DimensionUnit +{ + DU_UNKNOWN = 0; + DU_INCHES = 1; + DU_MILS = 2; + DU_MILLIMETERS = 3; + DU_AUTOMATIC = 4; +} + +// A dimension in KiCad is a special type of text object. +// To know the visual appearance of the dimension as rendered by KiCad, use GetTextAsShapes +message Dimension +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.LockedState locked = 2; + BoardLayer layer = 3; + kiapi.common.types.Text text = 4; + + oneof dimension_style { + AlignedDimensionAttributes aligned = 5; + OrthogonalDimensionAttributes orthogonal = 6; + RadialDimensionAttributes radial = 7; + LeaderDimensionAttributes leader = 8; + CenterDimensionAttributes center = 9; + } + + bool override_text_enabled = 10; + string override_text = 11; + string prefix = 12; + string suffix = 13; + DimensionUnit unit = 14; + DimensionUnitFormat unit_format = 15; + DimensionArrowDirection arrow_direction = 16; + DimensionPrecision precision = 17; + bool suppress_trailing_zeroes = 18; + + kiapi.common.types.Distance line_thickness = 19; + kiapi.common.types.Distance arrow_length = 20; + kiapi.common.types.Distance extension_offset = 21; + DimensionTextPosition text_position = 22; + bool keep_text_aligned = 23; +} + +message ReferenceImage +{ + // TODO +} + +message Group +{ + kiapi.common.types.KIID id = 1; + string name = 2; + repeated kiapi.common.types.KIID items = 3; +} + +message FieldId +{ + int32 id = 1; +} + +message Field +{ + FieldId id = 1; + string name = 2; + BoardText text = 3; + + // Since 9.0.1 + bool visible = 4; +} + +enum FootprintMountingStyle +{ + FMS_UNKNOWN = 0; + FMS_THROUGH_HOLE = 1; + FMS_SMD = 2; + FMS_UNSPECIFIED = 3; +} + +message FootprintAttributes +{ + string description = 1; + string keywords = 2; + bool not_in_schematic = 3; + bool exclude_from_position_files = 4; + bool exclude_from_bill_of_materials = 5; + bool exempt_from_courtyard_requirement = 6; + bool do_not_populate = 7; + FootprintMountingStyle mounting_style = 8; + + // Since: 9.0.7 + bool allow_soldermask_bridges = 9; +} + +message NetTieDefinition +{ + repeated string pad_number = 1; +} + +message FootprintDesignRuleOverrides +{ + SolderMaskOverrides solder_mask = 1; + SolderPasteOverrides solder_paste = 2; + kiapi.common.types.Distance copper_clearance = 3; + ZoneConnectionStyle zone_connection = 4; +} + +message Footprint3DModel +{ + string filename = 1; + + // Scaling factor along each axis + kiapi.common.types.Vector3D scale = 2; + + // Rotation around each axis, in degrees + kiapi.common.types.Vector3D rotation = 3; + + // Offset from footprint center + kiapi.common.types.Vector3D offset = 4; + + bool visible = 5; + + double opacity = 6; +} + +message JumperGroup +{ + repeated string pad_names = 1; +} + +message JumperSettings +{ + /// If true, duplicate pad names in this footprint are jumpered together + bool duplicate_names_are_jumpered = 1; + + repeated JumperGroup groups = 2; +} + +// A footprint definition (i.e. what would be in a library) +message Footprint +{ + kiapi.common.types.LibraryIdentifier id = 1; + kiapi.common.types.Vector2 anchor = 2; + FootprintAttributes attributes = 3; + FootprintDesignRuleOverrides overrides = 4; + repeated NetTieDefinition net_ties = 5; + repeated BoardLayer private_layers = 6; + + Field reference_field = 7; + Field value_field = 8; + Field datasheet_field = 9; + Field description_field = 10; + + // All footprint items except for mandatory fields + repeated google.protobuf.Any items = 11; + + JumperSettings jumpers = 12; +} + +// An instance of a footprint on a board +message FootprintInstance +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.Vector2 position = 2; + kiapi.common.types.Angle orientation = 3; + BoardLayer layer = 4; + kiapi.common.types.LockedState locked = 5; + Footprint definition = 6; + + Field reference_field = 7; + Field value_field = 8; + Field datasheet_field = 9; + Field description_field = 10; + + FootprintAttributes attributes = 11; + FootprintDesignRuleOverrides overrides = 12; + + // The sheet path to the associated symbol for this footprint instance, if one exists + kiapi.common.types.SheetPath symbol_path = 13; + + // The name of the hierarchical sheet the associated symbol for this footprint exists on, + // or the empty string if there is no associated symbol + // Since: 9.0.7 + string symbol_sheet_name = 14; + + // The filename of the hierarchical sheet the associated symbol for this footprint exists on, + // or the empty string if there is no associated symbol + // Since: 9.0.7 + string symbol_sheet_filename = 15; + + // The the footprint filters given by the symbol this footprint is associated with, + // or the empty string if there is no associated symbol + // Since: 9.0.7 + string symbol_footprint_filters = 16; +} diff --git a/proto/common/commands/base_commands.proto b/proto/common/commands/base_commands.proto new file mode 100644 index 0000000..39d3698 --- /dev/null +++ b/proto/common/commands/base_commands.proto @@ -0,0 +1,103 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +syntax = "proto3"; + +package kiapi.common.commands; + +import "common/types/base_types.proto"; + +message GetVersion +{ +} + +message GetVersionResponse +{ + kiapi.common.types.KiCadVersion version = 1; +} + +// A command to check if the connection to KiCad is OK +message Ping +{ +} + +// Returns the full path to the given KiCad binary +message GetKiCadBinaryPath +{ + // The short name of the binary, such as `kicad-cli` or `kicad-cli.exe`. If on Windows, an `.exe` + // extension will be assumed if not present. + string binary_name = 1; +} + +message PathResponse +{ + string path = 1; +} + +// returns kiapi.common.types.Box2 +message GetTextExtents +{ + // A temporary text item to calculate the bounding box for + kiapi.common.types.Text text = 1; +} + +message TextOrTextBox +{ + oneof inner { + kiapi.common.types.Text text = 1; + kiapi.common.types.TextBox textbox = 2; + } +} + +// Render the given text object(s) as shapes. Depending on whether the text is using +// the KiCad stroke font or a custom font, the response will be a compound shape containing +// a set of polygons or a set of segments. +message GetTextAsShapes +{ + repeated TextOrTextBox text = 1; +} + +message TextWithShapes +{ + TextOrTextBox text = 1; + + kiapi.common.types.CompoundShape shapes = 2; +} + +message GetTextAsShapesResponse +{ + repeated TextWithShapes text_with_shapes = 1; +} + +// Return a writeable path that a plugin can use for storing persistent data such as configuration +// files, etc. This path may not yet exist; actual creation of the directory for a given plugin is +// up to the plugin itself. Files in this path will not be modified if the plugin is uninstalled or +// upgraded. +// +// Returns StringResponse +message GetPluginSettingsPath +{ + // The identifier of the plugin + string identifier = 1; +} + +message StringResponse +{ + string response = 1; +} diff --git a/proto/common/commands/editor_commands.proto b/proto/common/commands/editor_commands.proto new file mode 100644 index 0000000..04a2c38 --- /dev/null +++ b/proto/common/commands/editor_commands.proto @@ -0,0 +1,440 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +/* + * Commands and responses related to manipulating editor windows + */ + +syntax = "proto3"; + +package kiapi.common.commands; + +import "google/protobuf/any.proto"; +import "common/types/base_types.proto"; +import "common/types/enums.proto"; + +// Refreshes the given frame, if that frame is open +message RefreshEditor +{ + kiapi.common.types.FrameType frame = 1; +} + +// Retrieves a list of open documents of the given type +message GetOpenDocuments +{ + // Which type of documents to query + kiapi.common.types.DocumentType type = 1; +} + +message GetOpenDocumentsResponse +{ + repeated kiapi.common.types.DocumentSpecifier documents = 1; +} + +message SaveDocument +{ + kiapi.common.types.DocumentSpecifier document = 1; +} + +// Saves the given document to a new location and opens the new copy +// Note, this is not going to be implemented anytime soon as we don't currently +// want to allow API access to changing which project is open +//message SaveDocumentAs +//{ +// kiapi.common.types.DocumentSpecifier document = 1; +// +// string path = 2; +//} + +message SaveOptions +{ + // Overwrite destination file(s) if they exist + bool overwrite = 1; + + // If the file being saved normally requires a project (for example, a board or schematic), + // this flag will cause a new project to be saved alongside the new file + bool include_project = 2; +} + +// Saves the given document to a new location and does not open the new copy +message SaveCopyOfDocument +{ + kiapi.common.types.DocumentSpecifier document = 1; + + string path = 2; + + SaveOptions options = 3; +} + +message RevertDocument +{ + kiapi.common.types.DocumentSpecifier document = 1; +} + +/* + * Runs a TOOL_ACTION using the TOOL_MANAGER of a given frame. + * WARNING: The TOOL_ACTIONs are specifically *not* an API. + * Command names may change as code is refactored, and commands may disappear. + * This API method is provided for low-level prototyping purposes only. + */ +message RunAction +{ + string action = 1; // Action name, like "eeschema.InteractiveSelection.ClearSelection" +} + +enum RunActionStatus +{ + RAS_UNKNOWN = 0; + RAS_OK = 1; // The action was submitted successfully. + RAS_INVALID = 2; // The action was unknown for the targeted frame. + RAS_FRAME_NOT_OPEN = 3; // The targeted frame was not open when the call was submitted. +} + +/* + * NOTE: At the moment, RAS_FRAME_NOT_OPEN won't be returned as the handler is inside the frame. + */ +message RunActionResponse +{ + RunActionStatus status = 1; +} + + +/* + * Begins a staged set of changes. Any modifications made to a document through the API after this + * call will be saved to a pending commit, and will not appear in KiCad until a matching call to + * END_COMMIT. + */ +message BeginCommit +{ +} + + +message BeginCommitResponse +{ + // Opaque identifier tracking a commit + kiapi.common.types.KIID id = 1; +} + + +enum CommitAction +{ + CMA_UNKNOWN = 0; + CMA_COMMIT = 1; // Commit the changes to the design + CMA_DROP = 2; // Cancel this commit +} + + +message EndCommit +{ + // The ID that was given by BeginCommit + kiapi.common.types.KIID id = 1; + + // What to do with this commit + CommitAction action = 2; + + // Optional message describing this changeset + string message = 3; +} + + +message EndCommitResponse +{ +} + +// Creates new items on a given document +message CreateItems +{ + // Specifies which document to create on, which fields are included, etc. + kiapi.common.types.ItemHeader header = 1; + + // List of items to create + repeated google.protobuf.Any items = 2; + + // Items may be created on a top-level document (sheet, board, etc) or inside a container + // (symbol, footprint). If this field is not empty, it holds the ID of a symbol or footprint + // that the items should be added to. This ID must be an existing symbol (for schematic + // documents) or footprint (for board documents). If the given container does not exist or is + // not the correct item type, the CreateItems call will fail. + kiapi.common.types.KIID container = 3; +} + +enum ItemStatusCode +{ + ISC_UNKNOWN = 0; + ISC_OK = 1; // The item was created or updated + ISC_INVALID_TYPE = 2; // The item's type is not valid for the given document + ISC_EXISTING = 3; // The item to be created had a specified KIID and that KIID was already in use + ISC_NONEXISTENT = 4; // The item to be updated did not exist in the given document + ISC_IMMUTABLE = 5; // The item to be updated is not allowed to be modified by the API + ISC_INVALID_DATA = 7; // The item to be created does not have valid data for the given document +} + +// Per-item status feedback for creation and update calls +message ItemStatus +{ + ItemStatusCode code = 1; + + string error_message = 2; +} + +message ItemCreationResult +{ + ItemStatus status = 1; + + // The created version of the item, including an updated KIID as applicable + google.protobuf.Any item = 2; +} + +message CreateItemsResponse +{ + // Specifies which document was modified, which fields are included in created_items, etc. + kiapi.common.types.ItemHeader header = 1; + + // Status of the overall request; may return IRS_OK even if no items were created + kiapi.common.types.ItemRequestStatus status = 2; + + // Status of each item to be created + repeated ItemCreationResult created_items = 3; +} + +message GetItems +{ + // Specifies which document to query, which fields to return, etc. + kiapi.common.types.ItemHeader header = 1; + + // List of one or more types of items to retreive + repeated kiapi.common.types.KiCadObjectType types = 2; +} + +message GetItemsById +{ + // Specifies which document to query, which fields to return, etc. + kiapi.common.types.ItemHeader header = 1; + + repeated kiapi.common.types.KIID items = 2; +} + +message GetItemsResponse +{ + // Specifies which document was modified, which fields are included in items, etc. + kiapi.common.types.ItemHeader header = 1; + + // Status of the overall request; may return IRS_OK even if no items were retrieved + kiapi.common.types.ItemRequestStatus status = 2; + + repeated google.protobuf.Any items = 3; +} + +// Updates items in a given document +message UpdateItems +{ + // Specifies which document to modify, which fields are included, etc. + kiapi.common.types.ItemHeader header = 1; + + // List of items to modify + repeated google.protobuf.Any items = 2; +} + + +message ItemUpdateResult +{ + ItemStatus status = 1; + + // The update version of the item + google.protobuf.Any item = 2; +} + +message UpdateItemsResponse +{ + // Specifies which document was modified, which fields are included in updated_items, etc. + kiapi.common.types.ItemHeader header = 1; + + // Status of the overall request; may return IRS_OK even if no items were modified + kiapi.common.types.ItemRequestStatus status = 2; + + // Status of each item to be created + repeated ItemUpdateResult updated_items = 3; +} + +// Deletes items in a given document +message DeleteItems +{ + // Specifies which document to modify + kiapi.common.types.ItemHeader header = 1; + + // List of item KIIDs to delete + repeated kiapi.common.types.KIID item_ids = 2; +} + +enum ItemDeletionStatus +{ + IDS_UNKNOWN = 0; + IDS_OK = 1; + IDS_NONEXISTENT = 2; // The item did not exist in the given document + IDS_IMMUTABLE = 3; // The item is not allowed to be modified by the API +} + +message ItemDeletionResult +{ + kiapi.common.types.KIID id = 1; + + ItemDeletionStatus status = 2; +} + +message DeleteItemsResponse +{ + // Specifies which document was modified, etc. + kiapi.common.types.ItemHeader header = 1; + + // Status of the overall request; may return IRS_OK even if no items were deleted + kiapi.common.types.ItemRequestStatus status = 2; + + // Status of each item requested to be deleted + repeated ItemDeletionResult deleted_items = 3; +} + +enum BoundingBoxMode +{ + BBM_UNKNOWN = 0; + BBM_ITEM_ONLY = 1; + BBM_ITEM_AND_CHILD_TEXT = 2; +} + +message GetBoundingBox +{ + kiapi.common.types.ItemHeader header = 1; + + repeated kiapi.common.types.KIID items = 2; + + // Some item types can have independently-movable text as children (e.g. footprints) + // This mode controls whether or not these are included in the box + BoundingBoxMode mode = 3; +} + +message GetBoundingBoxResponse +{ + repeated kiapi.common.types.KIID items = 1; + + repeated kiapi.common.types.Box2 boxes = 2; +} + +// Retrieves a list of items. Returns SelectionResponse +message GetSelection +{ + // Specifies which document to query for selected items. + kiapi.common.types.ItemHeader header = 1; + + // An optional list of types to filter on. + // If none are provided, all selected items will be returned. + repeated kiapi.common.types.KiCadObjectType types = 2; +} + +// The set of currently selected items +message SelectionResponse +{ + repeated google.protobuf.Any items = 1; +} + +// Adds the given items to the selection. Returns SelectionResponse +message AddToSelection +{ + kiapi.common.types.ItemHeader header = 1; + + // The items to select + repeated kiapi.common.types.KIID items = 2; +} + +// Removes the given items to the selection. Returns SelectionResponse +message RemoveFromSelection +{ + kiapi.common.types.ItemHeader header = 1; + + // The items to deselect + repeated kiapi.common.types.KIID items = 2; +} + +// Removes all items from selection +message ClearSelection +{ + kiapi.common.types.ItemHeader header = 1; +} + +// Tests if a certain point falls within tolerance of an item's geometry +message HitTest +{ + kiapi.common.types.ItemHeader header = 1; + + kiapi.common.types.KIID id = 2; + + kiapi.common.types.Vector2 position = 3; + + int32 tolerance = 4; +} + +enum HitTestResult +{ + HTR_UNKNOWN = 0; + HTR_NO_HIT = 1; + HTR_HIT = 2; +} + +message HitTestResponse +{ + HitTestResult result = 1; +} + +// returns common.types.TitleBlockInfo +message GetTitleBlockInfo +{ + kiapi.common.types.DocumentSpecifier document = 1; +} + +message SaveDocumentToString +{ + kiapi.common.types.DocumentSpecifier document = 1; +} + +message SavedDocumentResponse +{ + kiapi.common.types.DocumentSpecifier document = 1; + + string contents = 2; +} + +message SaveSelectionToString +{ +} + +message SavedSelectionResponse +{ + repeated kiapi.common.types.KIID ids = 1; + + string contents = 2; +} + +// Attempts to parse the given string as a s-expression formatted container with items, +// similar to how the Paste action inside the KiCad editor works. If the parse is successful, +// the items will be created and inserted into the editor. +// Returns CreateItemsResponse +message ParseAndCreateItemsFromString +{ + kiapi.common.types.DocumentSpecifier document = 1; + + string contents = 2; +} diff --git a/proto/common/commands/project_commands.proto b/proto/common/commands/project_commands.proto new file mode 100644 index 0000000..90c6fba --- /dev/null +++ b/proto/common/commands/project_commands.proto @@ -0,0 +1,82 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +syntax = "proto3"; + +package kiapi.common.commands; + +import "common/types/base_types.proto"; +import "common/types/project_settings.proto"; + + +message GetNetClasses +{ +} + +message NetClassesResponse +{ + repeated kiapi.common.project.NetClass net_classes = 1; +} + + +message SetNetClasses +{ + repeated kiapi.common.project.NetClass net_classes = 1; + + // Whether to merge or replace the existing netclasses with the contents of this message + // Note that this only happens at the level of netclass name: for example, if merge_mode is set to + // MMM_MERGE, the design has netclasses ["Default", "HV"], and this message has netclasses + // ["Default", "LV"], the resulting set will be ["Default", "HV", "LV"] -- the Default netclass + // will have its properties replaced with those in this message, the "LV" netclass will be added, + // and the "HV" netclass will be left alone. If merge_mode is set to MMM_REPLACE, the "HV" class + // will be erased. Note that there must always be a "Default" netclass, so it will not be erased + // even if merge_mode is MMM_REPLACE and there is no "Default" class specified in this message. + kiapi.common.types.MapMergeMode merge_mode = 3; +} + + +message ExpandTextVariables +{ + kiapi.common.types.DocumentSpecifier document = 1; + + repeated string text = 2; +} + + +message ExpandTextVariablesResponse +{ + repeated string text = 1; +} + + +// returns kiapi.common.project.TextVariables +message GetTextVariables +{ + kiapi.common.types.DocumentSpecifier document = 1; +} + + +message SetTextVariables +{ + kiapi.common.types.DocumentSpecifier document = 1; + + kiapi.common.project.TextVariables variables = 2; + // Whether to merge or replace the existing text variables map with the contents of this message + kiapi.common.types.MapMergeMode merge_mode = 3; +} diff --git a/proto/common/envelope.proto b/proto/common/envelope.proto new file mode 100644 index 0000000..81e2a62 --- /dev/null +++ b/proto/common/envelope.proto @@ -0,0 +1,92 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +syntax = "proto3"; + +package kiapi.common; + +import "google/protobuf/any.proto"; + +enum ApiStatusCode +{ + AS_UNKNOWN = 0; + AS_OK = 1; // Request succeeded + AS_TIMEOUT = 2; // Request timed out + AS_BAD_REQUEST = 3; // The request had invalid parameters or otherwise was illegal + AS_NOT_READY = 4; // KiCad has recently started and cannot handle API requests yet + AS_UNHANDLED = 5; // The request was not handled by KiCad + AS_TOKEN_MISMATCH = 6; // The kicad_token in the request didn't match this KiCad's token + AS_BUSY = 7; // KiCad is busy performing an operation and can't accept API commands + AS_UNIMPLEMENTED = 8; // The requested API call has not yet been implemented +} + +/* + * For future expansion: any header fields that should be sent with a request + */ +message ApiRequestHeader +{ + // An opaque string identifying a running instance of KiCad. If this is set to a non-empty + // string in an API request, KiCad will reject the request if the value doesn't match its own + // token. This can be used to let API clients make sure they are still talking to the same + // instance of KiCad if they are long-running. + string kicad_token = 1; + + // A string identifying an API client. Should be set by the client to a value that is unique + // to a specific instance of a client, for example the package name of the client plus its + // process ID or a random string, e.g. "com.github.me.my_awesome_plugin-73951". The main purpose + // of this name is to identify the client in debug logs. + string client_name = 2; +} + +/* + * The top-level envelope container for an API request (message from a client to the KiCad API server) + */ +message ApiRequest +{ + ApiRequestHeader header = 1; + + google.protobuf.Any message = 2; +} + +/* + * For future expansion: any header fields that should be sent with a response + */ +message ApiResponseHeader +{ + /// An opaque string identifying a running instance of KiCad. + string kicad_token = 1; +} + +message ApiResponse +{ + ApiResponseHeader header = 1; + + ApiResponseStatus status = 2; + + google.protobuf.Any message = 3; +} + +message ApiResponseStatus +{ + /// A code describing the category of error (or AS_OK if no error) + ApiStatusCode status = 1; + + /// A human-readable description of the error, if any + string error_message = 2; +} diff --git a/proto/common/types/base_types.proto b/proto/common/types/base_types.proto new file mode 100644 index 0000000..83e9ec5 --- /dev/null +++ b/proto/common/types/base_types.proto @@ -0,0 +1,482 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +/* + * base_types.proto + * Includes types used in many parts of the API + */ + +syntax = "proto3"; + +package kiapi.common.types; + +import "google/protobuf/field_mask.proto"; +import "common/types/enums.proto"; + +enum CommandStatus +{ + CS_UNKNOWN = 0; + CS_OK = 1; // Command succeeded + CS_FAILED = 2; // Command failed +} + +message CommandStatusResponse +{ + CommandStatus status = 1; +} + +/** + * Describes a particular version of KiCad + */ +message KiCadVersion +{ + uint32 major = 1; + uint32 minor = 2; + uint32 patch = 3; + + // Full identifier string, potentially containing git hashes, packager-added info, etc. + string full_version = 4; +} + +/** + * Some commands are specific to a KiCad window (frame). This list contains all addressable frames. + */ +enum FrameType +{ + FT_UNKNOWN = 0; + FT_PROJECT_MANAGER = 1; + FT_SCHEMATIC_EDITOR = 2; + FT_PCB_EDITOR = 3; + FT_SPICE_SIMULATOR = 4; + FT_SYMBOL_EDITOR = 5; + FT_FOOTPRINT_EDITOR = 6; + FT_DRAWING_SHEET_EDITOR = 7; +} + +/** + * Describes a KIID, or UUID of an object in a KiCad editor model. + */ +message KIID +{ + // The KIID's value in standard UUID format, stored as a string for easy portability + string value = 1; +} + +/** + * Identifier for the type of document being targeted by a request + */ +enum DocumentType +{ + DOCTYPE_UNKNOWN = 0; + DOCTYPE_SCHEMATIC = 1; + DOCTYPE_SYMBOL = 2; + DOCTYPE_PCB = 3; + DOCTYPE_FOOTPRINT = 4; + DOCTYPE_DRAWING_SHEET = 5; + DOCTYPE_PROJECT = 6; +} + +/** + * Describes a KiCad LIB_ID; a unique identifier for a loaded symbol or footprint + */ +message LibraryIdentifier +{ + // The library portion of the LIB_ID + string library_nickname = 1; + + // The symbol or footprint name + string entry_name = 2; +} + +/** + * Describes a unique sheet in a schematic + */ +message SheetPath +{ + // The canonical path to the sheet. The first KIID will be the root sheet, etc. + repeated KIID path = 1; + + // The path converted to a human readable form such as "/", "/child", or "/child/grandchild" + string path_human_readable = 2; +} + +/** + * Describes a KiCad project + */ +message ProjectSpecifier +{ + // The name of the project (without the kicad_pro extension) + string name = 1; + + // The path to the project directory + string path = 2; +} + +/** + * Describes a document that will be the target of a request + */ +message DocumentSpecifier +{ + DocumentType type = 1; + + oneof identifier + { + // If type == DT_SYMBOL or DT_FOOTPRINT, identifies a certain library entry + LibraryIdentifier lib_id = 2; + + // If type == DT_SCHEMATIC, identifies a sheet with a given path + SheetPath sheet_path = 3; + + // If type == DT_PCB, identifies a PCB with a given filename, e.g. "board.kicad_pcb" + string board_filename = 4; + } + + ProjectSpecifier project = 5; +} + +/** + * This header is included in requests and responses about item(s) in a document + */ +message ItemHeader +{ + // Which document is this request targeting? + DocumentSpecifier document = 1; + + // Which container within the document is this request targeting? + // If container is omitted or empty, the document is used as the container. + KIID container = 2; + + // Which fields on the item(s) are included with this request or response + google.protobuf.FieldMask field_mask = 3; +} + +/** + * Status of a request that included an ItemHeader + */ +enum ItemRequestStatus +{ + IRS_UNKNOWN = 0; + IRS_OK = 1; + IRS_DOCUMENT_NOT_FOUND = 2; // The given document is not open in KiCad + IRS_FIELD_MASK_INVALID = 3; // The given field_mask contains invalid specifiers +} + +// Describes a point or distance in 2D space. All coordinates are in nanometers. +message Vector2 +{ + int64 x_nm = 1; + int64 y_nm = 2; +} + +// Describes a point or distance in 3D space. All coordinates are in nanometers. +message Vector3 +{ + int64 x_nm = 1; + int64 y_nm = 2; + int64 z_nm = 3; +} + +message Vector3D +{ + double x_nm = 1; + double y_nm = 2; + double z_nm = 3; +} + +message Box2 +{ + kiapi.common.types.Vector2 position = 1; + kiapi.common.types.Vector2 size = 2; +} + +// Describes a quantity of distance (size, length, etc). All coordinates are in nanometers. +message Distance +{ + int64 value_nm = 1; +} + +// Corresponds to EDA_ANGLE, where the underlying storage is degrees +message Angle +{ + double value_degrees = 1; +} + +// Represents a value from 0.0 to 1.0 +message Ratio +{ + double value = 1; +} + +// Represents a time delay in attoseconds. Since 10.0.0. +message Time +{ + int64 value_as = 1; +} + +// Corresponds to COLOR4D. Each color channel is a double from 0.0 to 1.0. +message Color +{ + double r = 1; + double g = 2; + double b = 3; + double a = 4; +} + +// The formulation of arc that is used in KiCad core geometry code. +// Start, midpoint (on the arc) and end are stored. Angle, center point, etc are calculated. +message ArcStartMidEnd +{ + Vector2 start = 1; + Vector2 mid = 2; + Vector2 end = 3; +} + +message PolyLineNode +{ + oneof geometry { + Vector2 point = 1; + ArcStartMidEnd arc = 2; + } +} + +// Corresponds to class SHAPE_LINE_CHAIN: A closed or open polyline that can include arcs. +// For non-arc cases, each node is a point along the line. An implicit line segment exists +// between the last and first node if closed is true. When arcs are present, the arc start and +// end points are not duplicated by point nodes (meaning, for example, a rectangle with rounded +// corners could be represented with four arc nodes and no point nodes). +message PolyLine +{ + repeated PolyLineNode nodes = 1; + bool closed = 2; +} + +message PolygonWithHoles +{ + PolyLine outline = 1; + repeated PolyLine holes = 2; +} + +// Corresponds to SHAPE_POLY_SET: a set of polygons or polylines +message PolySet +{ + repeated PolygonWithHoles polygons = 1; +} + +// Describes whether or not an item is locked for editing or movement +enum LockedState +{ + LS_UNKNOWN = 0; + LS_UNLOCKED = 1; + LS_LOCKED = 2; +} + +message TextAttributes +{ + string font_name = 1; + HorizontalAlignment horizontal_alignment = 2; + VerticalAlignment vertical_alignment = 3; + kiapi.common.types.Angle angle = 4; + double line_spacing = 5; + kiapi.common.types.Distance stroke_width = 6; + bool italic = 7; + bool bold = 8; + bool underlined = 9; + + // Deprecated since 9.0.1 (text items are now always visible, only Fields can be hidden) + bool visible = 10; + + bool mirrored = 11; + bool multiline = 12; + bool keep_upright = 13; + kiapi.common.types.Vector2 size = 14; +} + +message Text +{ + // Reserved for future use; base text objects don't have IDs right now + // kiapi.common.types.KIID id = 1; + kiapi.common.types.Vector2 position = 2; + kiapi.common.types.TextAttributes attributes = 3; + + // Reserved for future use; base objects don't support locking right now + //kiapi.common.types.LockedState locked = 4; + + string text = 5; + string hyperlink = 6; +} + +message TextBox +{ + kiapi.common.types.Vector2 top_left = 2; + kiapi.common.types.Vector2 bottom_right = 3; + kiapi.common.types.TextAttributes attributes = 4; + + // Reserved for future use; base objects don't support locking right now + //kiapi.common.types.LockedState locked = 5; + + string text = 6; +} + +message StrokeAttributes +{ + Distance width = 1; + StrokeLineStyle style = 2; + Color color = 3; +} + +enum GraphicFillType +{ + GFT_UNKNOWN = 0; + GFT_UNFILLED = 1; + GFT_FILLED = 2; +} + +message GraphicFillAttributes +{ + GraphicFillType fill_type = 1; + + // Color of the fill (not used in board and footprints) + Color color = 2; +} + +message GraphicAttributes +{ + StrokeAttributes stroke = 1; + GraphicFillAttributes fill = 2; +} + +message GraphicSegmentAttributes +{ + kiapi.common.types.Vector2 start = 1; + kiapi.common.types.Vector2 end = 2; +} + +message GraphicRectangleAttributes +{ + kiapi.common.types.Vector2 top_left = 1; + kiapi.common.types.Vector2 bottom_right = 2; + kiapi.common.types.Distance corner_radius = 3; +} + +message GraphicArcAttributes +{ + kiapi.common.types.Vector2 start = 1; + kiapi.common.types.Vector2 mid = 2; + kiapi.common.types.Vector2 end = 3; +} + +message GraphicCircleAttributes +{ + kiapi.common.types.Vector2 center = 1; + + // A point on the radius of the circle. This is stored instead of just a radius so that the point + // by which the user can adjust the circle radius is persisted. + kiapi.common.types.Vector2 radius_point = 2; +} + +message GraphicBezierAttributes +{ + kiapi.common.types.Vector2 start = 1; + kiapi.common.types.Vector2 control1 = 2; + kiapi.common.types.Vector2 control2 = 3; + kiapi.common.types.Vector2 end = 4; +} + +message GraphicShape +{ + // Reserved for future use; base EDA_SHAPE doesn't have an ID or locked state right now + // KIID id = 1; + // LockedState locked = 2; + GraphicAttributes attributes = 3; + + oneof geometry { + GraphicSegmentAttributes segment = 4; + GraphicRectangleAttributes rectangle = 5; + GraphicArcAttributes arc = 6; + GraphicCircleAttributes circle = 7; + PolySet polygon = 8; + GraphicBezierAttributes bezier = 9; + } +} + +// A SHAPE_COMPOUND in KiCad +message CompoundShape +{ + repeated GraphicShape shapes = 1; +} + +// The text strings that can be set in a drawing sheet for the title block +message TitleBlockInfo +{ + string title = 1; + string date = 2; + string revision = 3; + string company = 4; + + // Note: not a repeated string; there can be gaps and the UI limits the count to 9 + + string comment1 = 5; + string comment2 = 6; + string comment3 = 7; + string comment4 = 8; + string comment5 = 9; + string comment6 = 10; + string comment7 = 11; + string comment8 = 12; + string comment9 = 13; +} + +enum AxisAlignment +{ + AA_UNKNOWN = 0; + AA_X_AXIS = 1; + AA_Y_AXIS = 2; +} + +enum MapMergeMode +{ + MMM_UNKNOWN = 0; + // The existing map will be merged with the incoming map; keys that are not present in the + // incoming map will be preserved with their original values + MMM_MERGE = 1; + // The existing map will be cleared and replaced with the incoming map + MMM_REPLACE = 2; +} + +enum ElectricalPinType +{ + EPT_UNKNOWN = 0; + EPT_INPUT = 1; + EPT_OUTPUT = 2; + EPT_BIDIRECTIONAL = 3; + EPT_TRISTATE = 4; + EPT_PASSIVE = 5; + + // A free pin is not internally connected and may connect to any net (route-through) + EPT_FREE = 6; + + EPT_UNSPECIFIED = 7; + EPT_POWER_INPUT = 8; + EPT_POWER_OUTPUT = 9; + EPT_OPEN_COLLECTOR = 10; + EPT_OPEN_EMITTER = 11; + + // A no-connect pin should not be connected to any net + EPT_NO_CONNECT = 12; +} diff --git a/proto/common/types/enums.proto b/proto/common/types/enums.proto new file mode 100644 index 0000000..a140cad --- /dev/null +++ b/proto/common/types/enums.proto @@ -0,0 +1,122 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +/* + * enums.proto + * Includes protobuf versions of common KiCad enums + */ + +syntax = "proto3"; + +package kiapi.common.types; + +// The set of object types (from KICAD_T) that are exposed to the API. +enum KiCadObjectType +{ + KOT_UNKNOWN = 0; + + KOT_PCB_FOOTPRINT = 1; + KOT_PCB_PAD = 2; + KOT_PCB_SHAPE = 3; + KOT_PCB_REFERENCE_IMAGE = 4; + KOT_PCB_FIELD = 5; + KOT_PCB_GENERATOR = 6; + KOT_PCB_TEXT = 7; + KOT_PCB_TEXTBOX = 8; + KOT_PCB_TABLE = 9; + KOT_PCB_TABLECELL = 10; + KOT_PCB_TRACE = 11; + KOT_PCB_VIA = 12; + KOT_PCB_ARC = 13; + KOT_PCB_MARKER = 14; + KOT_PCB_DIMENSION = 15; + KOT_PCB_ZONE = 16; + KOT_PCB_GROUP = 17; + + KOT_SCH_MARKER = 18; + KOT_SCH_JUNCTION = 19; + KOT_SCH_NO_CONNECT = 20; + KOT_SCH_BUS_WIRE_ENTRY = 21; + KOT_SCH_BUS_BUS_ENTRY = 22; + KOT_SCH_LINE = 23; + KOT_SCH_SHAPE = 24; + KOT_SCH_BITMAP = 25; + KOT_SCH_TEXTBOX = 26; + KOT_SCH_TEXT = 27; + KOT_SCH_TABLE = 28; + KOT_SCH_TABLECELL = 29; + KOT_SCH_LABEL = 30; + KOT_SCH_GLOBAL_LABEL = 31; + KOT_SCH_HIER_LABEL = 32; + KOT_SCH_DIRECTIVE_LABEL = 33; + KOT_SCH_FIELD = 34; + KOT_SCH_SYMBOL = 35; + KOT_SCH_SHEET_PIN = 36; + KOT_SCH_SHEET = 37; + KOT_SCH_PIN = 38; + + KOT_LIB_SYMBOL = 39; +// KOT_LIB_SHAPE = 40; +// KOT_LIB_TEXT = 41; +// KOT_LIB_TEXTBOX = 42; +// KOT_LIB_PIN = 43; +// KOT_LIB_FIELD = 44; + + KOT_WSG_LINE = 45; + KOT_WSG_RECT = 46; + KOT_WSG_POLY = 47; + KOT_WSG_TEXT = 48; + KOT_WSG_BITMAP = 49; + KOT_WSG_PAGE = 50; + + KOT_SCH_GROUP = 51; + KOT_PCB_BARCODE = 52; +} + +// Mapped to GR_TEXT_H_ALIGN_T +enum HorizontalAlignment +{ + HA_UNKNOWN = 0; + HA_LEFT = 1; + HA_CENTER = 2; + HA_RIGHT = 3; + HA_INDETERMINATE = 4; +} + +// Mapped to GR_TEXT_V_ALIGN_T +enum VerticalAlignment +{ + VA_UNKNOWN = 0; + VA_TOP = 1; + VA_CENTER = 2; + VA_BOTTOM = 3; + VA_INDETERMINATE = 4; +} + +// Mapped to LINE_STYLE +enum StrokeLineStyle +{ + SLS_UNKNOWN = 0; + SLS_DEFAULT = 1; + SLS_SOLID = 2; + SLS_DASH = 3; + SLS_DOT = 4; + SLS_DASHDOT = 5; + SLS_DASHDOTDOT = 6; +} diff --git a/proto/common/types/project_settings.proto b/proto/common/types/project_settings.proto new file mode 100644 index 0000000..7e8b03e --- /dev/null +++ b/proto/common/types/project_settings.proto @@ -0,0 +1,94 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +/* + * project_settings.proto + * Messages that describes project settings shared between schematics and boards + */ + +syntax = "proto3"; + +package kiapi.common.project; + +import "common/types/base_types.proto"; +import "common/types/enums.proto"; +import "board/board_types.proto"; + +message NetClassBoardSettings +{ + optional kiapi.common.types.Distance clearance = 1; + optional kiapi.common.types.Distance track_width = 2; + optional kiapi.common.types.Distance diff_pair_track_width = 3; + optional kiapi.common.types.Distance diff_pair_gap = 4; + optional kiapi.common.types.Distance diff_pair_via_gap = 5; + + // The default padstack to use for vias belonging to this netclass + // Currently KiCad only supports specifying the drill diameter and annular size on all layers for + // netclass via stacks. Complex padstacks and other via features cannot be specified here. + optional kiapi.board.types.PadStack via_stack = 6; + + // The default padstack to use for microvias belonging to this netclass + // Currently KiCad only supports specifying the drill diameter and annular size on all layers for + // netclass via stacks. Complex padstacks and other via features cannot be specified here. + optional kiapi.board.types.PadStack microvia_stack = 7; + + optional kiapi.common.types.Color color = 8; + + // Since 10.0.0 + optional string tuning_profile = 9; +} + +message NetClassSchematicSettings +{ + optional kiapi.common.types.Distance wire_width = 1; + optional kiapi.common.types.Distance bus_width = 2; + optional kiapi.common.types.Color color = 3; + optional kiapi.common.types.StrokeLineStyle line_style = 4; +} + +enum NetClassType +{ + NCT_UNKNOWN = 0; + // An explicitly-defined netclass, created by the user and saved in the project file + NCT_EXPLICIT = 1; + // An implicit (effective) netclass, made up of multiple explicit netclasses + NCT_IMPLICIT = 2; +} + +message NetClass +{ + // The name of the netclass (the literal string "Default" for the default netclass) + // May be empty for composite netclasses + string name = 1; + + optional int32 priority = 2; + + optional NetClassBoardSettings board = 3; + optional NetClassSchematicSettings schematic = 4; + + NetClassType type = 5; + + // If this is a composite netclass, a list of the names of the "real" netclasses that make it up + repeated string constituents = 6; +} + +message TextVariables +{ + map variables = 1; +} diff --git a/proto/schematic/schematic_commands.proto b/proto/schematic/schematic_commands.proto new file mode 100644 index 0000000..9de8e7e --- /dev/null +++ b/proto/schematic/schematic_commands.proto @@ -0,0 +1,24 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +syntax = "proto3"; + +package kiapi.schematic.types; + + diff --git a/proto/schematic/schematic_types.proto b/proto/schematic/schematic_types.proto new file mode 100644 index 0000000..3f872dc --- /dev/null +++ b/proto/schematic/schematic_types.proto @@ -0,0 +1,75 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +syntax = "proto3"; + +package kiapi.schematic.types; + +import "common/types/base_types.proto"; + +enum SchematicLayer +{ + SL_UNKNOWN = 0; +} + +/// Represents a schematic line segment, which may be a wire, bus, or graphical line +message Line +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.Vector2 start = 2; + kiapi.common.types.Vector2 end = 3; + + /** + * One of: LAYER_BUS, LAYER_WIRE, LAYER_NOTES + */ + SchematicLayer layer = 4; +} + +message Text +{ + kiapi.common.types.Text text = 1; +} + +message LocalLabel +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.Vector2 position = 2; + Text text = 3; +} + +message GlobalLabel +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.Vector2 position = 2; + Text text = 3; +} + +message HierarchicalLabel +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.Vector2 position = 2; + Text text = 3; +} + +message DirectiveLabel +{ + kiapi.common.types.KIID id = 1; + kiapi.common.types.Vector2 position = 2; + Text text = 3; +} diff --git a/src/blocking.rs b/src/blocking.rs new file mode 100644 index 0000000..a9837ca --- /dev/null +++ b/src/blocking.rs @@ -0,0 +1,22 @@ +use crate::client::KiCadClient; +use crate::error::KiCadError; + +#[derive(Clone, Debug)] +pub struct KiCadClientBlocking { + inner: KiCadClient, +} + +impl KiCadClientBlocking { + pub fn connect() -> Result { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_time() + .build() + .map_err(|err| KiCadError::Connection(err.to_string()))?; + let inner = runtime.block_on(KiCadClient::connect())?; + Ok(Self { inner }) + } + + pub fn inner(&self) -> &KiCadClient { + &self.inner + } +} diff --git a/src/client.rs b/src/client.rs new file mode 100644 index 0000000..a3f116b --- /dev/null +++ b/src/client.rs @@ -0,0 +1,99 @@ +use std::time::Duration; + +use crate::error::KiCadError; + +#[derive(Clone, Debug)] +pub struct KiCadClient { + config: ClientConfig, +} + +#[derive(Clone, Debug)] +struct ClientConfig { + timeout: Duration, + socket_path: Option, + token: Option, + client_name: Option, +} + +#[derive(Clone, Debug)] +pub struct ClientBuilder { + config: ClientConfig, +} + +impl ClientBuilder { + pub fn new() -> Self { + Self { + config: ClientConfig { + timeout: Duration::from_millis(3_000), + socket_path: None, + token: None, + client_name: None, + }, + } + } + + pub fn timeout(mut self, timeout: Duration) -> Self { + self.config.timeout = timeout; + self + } + + pub fn socket_path(mut self, socket_path: impl Into) -> Self { + self.config.socket_path = Some(socket_path.into()); + self + } + + pub fn token(mut self, token: impl Into) -> Self { + self.config.token = Some(token.into()); + self + } + + pub fn client_name(mut self, client_name: impl Into) -> Self { + self.config.client_name = Some(client_name.into()); + self + } + + pub async fn connect(self) -> Result { + Ok(KiCadClient { + config: self.config, + }) + } +} + +impl Default for ClientBuilder { + fn default() -> Self { + Self::new() + } +} + +impl KiCadClient { + pub fn builder() -> ClientBuilder { + ClientBuilder::new() + } + + pub async fn connect() -> Result { + ClientBuilder::new().connect().await + } + + pub fn timeout(&self) -> Duration { + self.config.timeout + } +} + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use super::ClientBuilder; + + #[tokio::test] + async fn builder_overrides_timeout() { + let timeout = Duration::from_secs(9); + let client = ClientBuilder::new() + .timeout(timeout) + .connect() + .await + .expect("builder should connect in baseline scaffold"); + + assert_eq!(client.timeout(), timeout); + } +} diff --git a/src/commands/base.rs b/src/commands/base.rs new file mode 100644 index 0000000..693366e --- /dev/null +++ b/src/commands/base.rs @@ -0,0 +1,2 @@ +#[derive(Debug, Default)] +pub struct BaseCommands; diff --git a/src/commands/board.rs b/src/commands/board.rs new file mode 100644 index 0000000..d42d8a5 --- /dev/null +++ b/src/commands/board.rs @@ -0,0 +1,2 @@ +#[derive(Debug, Default)] +pub struct BoardCommands; diff --git a/src/commands/editor.rs b/src/commands/editor.rs new file mode 100644 index 0000000..4bd65d8 --- /dev/null +++ b/src/commands/editor.rs @@ -0,0 +1,2 @@ +#[derive(Debug, Default)] +pub struct EditorCommands; diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..e5823a0 --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,4 @@ +pub mod base; +pub mod board; +pub mod editor; +pub mod project; diff --git a/src/commands/project.rs b/src/commands/project.rs new file mode 100644 index 0000000..4ba9625 --- /dev/null +++ b/src/commands/project.rs @@ -0,0 +1,2 @@ +#[derive(Debug, Default)] +pub struct ProjectCommands; diff --git a/src/envelope.rs b/src/envelope.rs new file mode 100644 index 0000000..b3c7809 --- /dev/null +++ b/src/envelope.rs @@ -0,0 +1,2 @@ +#[derive(Debug, Default)] +pub struct Envelope; diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..0cb9937 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,13 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum KiCadError { + #[error("connection failed: {0}")] + Connection(String), + #[error("invalid configuration: {0}")] + Config(String), + #[error("transport error: {0}")] + Transport(String), + #[error("protocol error: {0}")] + Protocol(String), +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a4dfb76 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,21 @@ +//! Async-first Rust bindings for the KiCad IPC API. +//! +//! This crate is intentionally layered: +//! - transport +//! - envelope +//! - command builders +//! - high-level client + +pub mod client; +pub mod envelope; +pub mod error; +pub mod model; +pub mod transport; + +pub mod commands; + +#[cfg(feature = "blocking")] +pub mod blocking; + +pub use crate::client::{ClientBuilder, KiCadClient}; +pub use crate::error::KiCadError; diff --git a/src/model/board.rs b/src/model/board.rs new file mode 100644 index 0000000..c5131c6 --- /dev/null +++ b/src/model/board.rs @@ -0,0 +1,4 @@ +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct BoardDocument { + pub board_filename: String, +} diff --git a/src/model/common.rs b/src/model/common.rs new file mode 100644 index 0000000..9c5f819 --- /dev/null +++ b/src/model/common.rs @@ -0,0 +1,7 @@ +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct VersionInfo { + pub major: u32, + pub minor: u32, + pub patch: u32, + pub full_version: String, +} diff --git a/src/model/mod.rs b/src/model/mod.rs new file mode 100644 index 0000000..e86ddca --- /dev/null +++ b/src/model/mod.rs @@ -0,0 +1,2 @@ +pub mod board; +pub mod common; diff --git a/src/transport.rs b/src/transport.rs new file mode 100644 index 0000000..c274294 --- /dev/null +++ b/src/transport.rs @@ -0,0 +1,2 @@ +#[derive(Debug, Default)] +pub struct Transport;