feat: ✨ Add chainofcommand
Works fine with a caveat that you need to press ENTER after Ctrl+C, investigate. Multiplex QEMU output for serial access.
This commit is contained in:
parent
cfe4a230de
commit
162592beaa
|
@ -45,6 +45,17 @@ jobs:
|
|||
- name: "Install build tools"
|
||||
run: cargo install cargo-make cargo-binutils
|
||||
|
||||
- name: "Prepare packages (Linux)"
|
||||
run: |
|
||||
sudo apt install software-properties-common
|
||||
sudo add-apt-repository ppa:jacob/virtualisation
|
||||
sudo apt update
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
- name: "Install dev libraries (Linux)"
|
||||
run: sudo apt install libudev-dev
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
- name: "Validate rust-lld"
|
||||
run: |
|
||||
which rust-lld || echo "Not found"
|
||||
|
@ -63,9 +74,6 @@ jobs:
|
|||
|
||||
- name: Install QEMU (Linux)
|
||||
run: |
|
||||
sudo apt install software-properties-common
|
||||
sudo add-apt-repository ppa:jacob/virtualisation
|
||||
sudo apt update
|
||||
sudo apt install qemu-system-aarch64
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
|
@ -135,6 +143,8 @@ jobs:
|
|||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- run: sudo apt update
|
||||
- run: sudo apt install libudev-dev
|
||||
- run: rustup toolchain install nightly
|
||||
- run: cargo install cargo-make
|
||||
- run: env CLIPPY_FEATURES=${{ matrix.features }} cargo make clippy
|
||||
|
|
|
@ -2,6 +2,68 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "CoreFoundation-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0e9889e6db118d49d88d84728d0e964d973a5680befb5f85f55141beea5c20b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mach 0.1.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "IOKit-sys"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99696c398cbaf669d2368076bdb3d627fb0ce51a26899d7c61228c5c0af3bf4a"
|
||||
dependencies = [
|
||||
"CoreFoundation-sys",
|
||||
"libc",
|
||||
"mach 0.1.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.1"
|
||||
|
@ -14,6 +76,18 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
|
@ -38,20 +112,193 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-a"
|
||||
version = "7.0.0"
|
||||
name = "chainofcommand"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"clap",
|
||||
"crossterm",
|
||||
"defer",
|
||||
"fehler",
|
||||
"futures",
|
||||
"seahash",
|
||||
"tokio",
|
||||
"tokio-serial",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b27f5d071b671f9799dfdf0c0afcec11de65195383d36e186639c83b00705e4f"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-a"
|
||||
version = "7.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bd95fd055d118f77d4e4d527201b6ceccd13586b19b4dac1270f7081fef0f98"
|
||||
dependencies = [
|
||||
"tock-registers",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c85525306c4291d1b73ce93c8acf9c339f9b213aef6c1d85c3830cbf1c16325c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"futures-core",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defer"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "647605a6345d5e89c3950a36a638c56478af9b414c55c6f2477c73b115f9acde"
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "fehler"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5729fe49ba028cd550747b6e62cd3d841beccab5390aa398538c31a2d983635"
|
||||
dependencies = [
|
||||
"fehler-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fehler-macros"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccb5acb1045ebbfa222e2c50679e392a71dd77030b78fb0189f2d9c5974400f9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
|
@ -61,6 +308,66 @@ dependencies = [
|
|||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.113"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mach"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mach"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "machine"
|
||||
version = "0.0.1"
|
||||
|
@ -77,6 +384,91 @@ dependencies = [
|
|||
"ux",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"ntapi",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-serial"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6f47dcdec193b77e2166faa0e3be4ee04f324ce6780c54efe7af6c3ee7360e4"
|
||||
dependencies = [
|
||||
"log",
|
||||
"mio",
|
||||
"nix 0.22.3",
|
||||
"serialport",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.22.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nucleus"
|
||||
version = "0.0.1"
|
||||
|
@ -94,25 +486,78 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.27"
|
||||
name = "num_cpus"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
|
||||
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qemu-exit"
|
||||
version = "3.0.0"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e0fa04276d522a40ed717bf874183a3b2a8bbb3fb4c646b03a7eb874ce5d543"
|
||||
checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -123,12 +568,101 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "seahash"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "serialport"
|
||||
version = "4.0.1"
|
||||
source = "git+https://github.com/metta-systems/serialport-rs?branch=macos-ENOTTY-fix#91ee1f740ee7d7c9506df8af082860a478656e18"
|
||||
dependencies = [
|
||||
"CoreFoundation-sys",
|
||||
"IOKit-sys",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"mach 0.2.3",
|
||||
"nix 0.23.1",
|
||||
"regex",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||
|
||||
[[package]]
|
||||
name = "snafu"
|
||||
version = "0.7.0"
|
||||
|
@ -152,28 +686,106 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.73"
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tock-registers"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"tokio-macros",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-serial"
|
||||
version = "5.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c75b04fbb029a3f77272b3356453c97c5dbdebcf28aa248a34fd80a442f2dda1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures",
|
||||
"log",
|
||||
"mio-serial",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
|
@ -191,3 +803,31 @@ name = "ux"
|
|||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"nucleus",
|
||||
"bin/chainboot"
|
||||
"bin/chainboot",
|
||||
"bin/chainofcommand"
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
serialport = { git = "https://github.com/metta-systems/serialport-rs", branch = "macos-ENOTTY-fix" }
|
||||
|
||||
[profile.dev]
|
||||
# See https://github.com/rust-lang/cargo/issues/7359 about why panic=abort is not working here.
|
||||
# It is still defined in the target JSON so not stricly necessary to specify it here anyway.
|
||||
|
|
5
Justfile
5
Justfile
|
@ -13,6 +13,11 @@ zellij-cb:
|
|||
cargo make zellij-cb
|
||||
zellij --layout-path emulation/layout.zellij
|
||||
|
||||
# Build chainofcommand serial loader
|
||||
chainofcommand:
|
||||
cd bin/chainofcommand
|
||||
cargo make build
|
||||
|
||||
# Build and run kernel in QEMU
|
||||
qemu:
|
||||
cargo make qemu
|
||||
|
|
|
@ -63,7 +63,7 @@ QEMU_CONTAINER_CMD = "qemu-system-aarch64"
|
|||
# QEMU has renamed the RasPi machines since version 6.2.0, use just `raspi3` for previous versions.
|
||||
QEMU_OPTS = "-M ${QEMU_MACHINE} -d int -semihosting"
|
||||
QEMU_DISASM_OPTS = "-d in_asm,unimp,int"
|
||||
QEMU_SERIAL_OPTS = "-serial null -serial stdio"
|
||||
QEMU_SERIAL_OPTS = "-serial pty -serial stdio"
|
||||
QEMU_TESTS_OPTS = "-nographic"
|
||||
# For gdb connection:
|
||||
# - if this is set, MUST have gdb attached for SYS_WRITE0 to work, otherwise QEMU will crash.
|
||||
|
@ -99,6 +99,7 @@ args = ["build", "@@split(PLATFORM_TARGET, )", "--release"]
|
|||
dependencies = ["build-qemu", "kernel-binary"]
|
||||
env = { "TARGET_FEATURES" = "${QEMU_FEATURES}" }
|
||||
script = [
|
||||
"echo Run QEMU ${QEMU_OPTS} ${QEMU_RUNNER_OPTS} with ${KERNEL_BIN}",
|
||||
"${QEMU} ${QEMU_OPTS} ${QEMU_RUNNER_OPTS} -dtb ${TARGET_DTB} -kernel ${KERNEL_BIN}"
|
||||
]
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ run_task = "zellij-config"
|
|||
disabled = true
|
||||
|
||||
[tasks.qemu-cb]
|
||||
env = { "QEMU_RUNNER_OPTS" = "${QEMU_SERIAL_OPTS}", "KERNEL_BIN" = "${CHAINBOOT_BIN}", "TARGET_DTB" = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/targets/bcm2710-rpi-3-b-plus.dtb" }
|
||||
env = { "QEMU_RUNNER_OPTS" = "${QEMU_DISASM_OPTS} -serial pty", "KERNEL_BIN" = "${CHAINBOOT_BIN}", "TARGET_DTB" = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/targets/bcm2710-rpi-3-b-plus.dtb" }
|
||||
extend = "qemu-runner"
|
||||
|
||||
[tasks.gdb]
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
[package]
|
||||
name = "chainofcommand"
|
||||
version = "0.0.1"
|
||||
authors = ["Berkus Decker <berkus+vesper@metta.systems>"]
|
||||
description = "Host server for chainboot"
|
||||
license = "BlueOak-1.0.0"
|
||||
categories = ["no-std", "embedded", "os"]
|
||||
publish = false
|
||||
edition = "2021"
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33"
|
||||
seahash = "4.1"
|
||||
anyhow = "1.0"
|
||||
fehler = "1.0"
|
||||
crossterm = { version = "0.22", features = ["event-stream"] }
|
||||
tokio-serial = "5.4"
|
||||
tokio = { version = "1.15", features = ["full"] }
|
||||
futures = "0.3"
|
||||
defer = "0.1"
|
||||
tokio-util = { version = "0.6", features = ["codec"] }
|
||||
bytes = "1.1"
|
|
@ -0,0 +1,44 @@
|
|||
[tasks.build]
|
||||
command = "cargo"
|
||||
args = ["build"]
|
||||
|
||||
[tasks.test]
|
||||
command = "cargo"
|
||||
args = ["test"]
|
||||
|
||||
[tasks.clippy]
|
||||
command = "cargo"
|
||||
args = ["clippy", "--", "-D", "warnings"]
|
||||
|
||||
[tasks.hopper]
|
||||
disabled = true
|
||||
|
||||
[tasks.kernel-binary]
|
||||
disabled = true
|
||||
|
||||
[tasks.zellij-nucleus]
|
||||
disabled = true
|
||||
|
||||
[tasks.zellij-cb]
|
||||
disabled = true
|
||||
|
||||
[tasks.zellij-cb-gdb]
|
||||
disabled = true
|
||||
|
||||
[tasks.qemu]
|
||||
disabled = true
|
||||
|
||||
[tasks.qemu-cb]
|
||||
disabled = true
|
||||
|
||||
[tasks.sdcard]
|
||||
disabled = true
|
||||
|
||||
[tasks.cb-eject]
|
||||
disabled = true
|
||||
|
||||
[tasks.gdb]
|
||||
disabled = true
|
||||
|
||||
[tasks.gdb-cb]
|
||||
disabled = true
|
|
@ -0,0 +1,436 @@
|
|||
#![feature(trait_alias)]
|
||||
|
||||
use {
|
||||
anyhow::{anyhow, Result},
|
||||
bytes::Bytes,
|
||||
clap::{App, AppSettings, Arg},
|
||||
crossterm::{
|
||||
cursor,
|
||||
event::{Event, EventStream, KeyCode, KeyEvent, KeyModifiers},
|
||||
execute, style, terminal,
|
||||
tty::IsTty,
|
||||
},
|
||||
defer::defer,
|
||||
futures::{future::FutureExt, StreamExt},
|
||||
seahash::SeaHasher,
|
||||
std::{
|
||||
fs::File,
|
||||
hash::Hasher,
|
||||
io::{BufRead, BufReader},
|
||||
path::Path,
|
||||
time::Duration,
|
||||
},
|
||||
tokio::{io::AsyncReadExt, sync::mpsc},
|
||||
tokio_serial::{SerialPortBuilderExt, SerialStream},
|
||||
};
|
||||
|
||||
trait Writable = std::io::Write + Send;
|
||||
trait ThePath = AsRef<Path> + std::fmt::Display + Clone + Sync + Send + 'static;
|
||||
|
||||
async fn expect(
|
||||
to_console2: &mpsc::Sender<Vec<u8>>,
|
||||
from_serial: &mut mpsc::Receiver<Vec<u8>>,
|
||||
m: &str,
|
||||
) -> Result<()> {
|
||||
if let Some(buf) = from_serial.recv().await {
|
||||
if buf.len() == m.len() && String::from_utf8_lossy(buf.as_ref()) == m {
|
||||
return Ok(());
|
||||
}
|
||||
to_console2.send(buf).await?;
|
||||
return Err(anyhow!("Failed to receive expected value"));
|
||||
}
|
||||
Err(anyhow!("Failed to receive expected value"))
|
||||
}
|
||||
|
||||
async fn load_kernel<P>(to_console2: &mpsc::Sender<Vec<u8>>, kernel: P) -> Result<(File, u64)>
|
||||
where
|
||||
P: ThePath,
|
||||
{
|
||||
to_console2
|
||||
.send("[>>] Loading kernel image\n".into())
|
||||
.await?;
|
||||
|
||||
let kernel_file = match std::fs::File::open(kernel.clone()) {
|
||||
Ok(file) => file,
|
||||
Err(_) => return Err(anyhow!("Couldn't open kernel file {}", kernel)),
|
||||
};
|
||||
let kernel_size: u64 = kernel_file.metadata()?.len();
|
||||
|
||||
to_console2
|
||||
.send(format!("[>>] .. {} ({} bytes)\n", kernel, kernel_size).into())
|
||||
.await?;
|
||||
|
||||
Ok((kernel_file, kernel_size))
|
||||
}
|
||||
|
||||
async fn send_kernel<P>(
|
||||
to_console2: &mpsc::Sender<Vec<u8>>,
|
||||
to_serial: &mpsc::Sender<Vec<u8>>,
|
||||
from_serial: &mut mpsc::Receiver<Vec<u8>>,
|
||||
kernel: P,
|
||||
) -> Result<()>
|
||||
where
|
||||
P: ThePath,
|
||||
{
|
||||
let (kernel_file, kernel_size) = load_kernel(to_console2, kernel).await?;
|
||||
|
||||
to_console2.send("[>>] Sending image size\n".into()).await?;
|
||||
|
||||
to_serial.send(kernel_size.to_le_bytes().into()).await?;
|
||||
|
||||
// Wait for OK response
|
||||
expect(to_console2, from_serial, "OK").await?;
|
||||
|
||||
to_console2
|
||||
.send("[>>] Sending kernel image\n".into())
|
||||
.await?;
|
||||
|
||||
let mut hasher = SeaHasher::new();
|
||||
let mut reader = BufReader::with_capacity(1, kernel_file);
|
||||
loop {
|
||||
let length = {
|
||||
let buf = reader.fill_buf()?;
|
||||
to_serial.send(buf.into()).await?;
|
||||
hasher.write(buf);
|
||||
buf.len()
|
||||
};
|
||||
if length == 0 {
|
||||
break;
|
||||
}
|
||||
reader.consume(length);
|
||||
}
|
||||
let hashed_value: u64 = hasher.finish();
|
||||
|
||||
to_console2
|
||||
.send(format!("[>>] Sending image checksum {:x}\n", hashed_value).into())
|
||||
.await?;
|
||||
|
||||
to_serial.send(hashed_value.to_le_bytes().into()).await?;
|
||||
|
||||
expect(to_console2, from_serial, "OK").await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Async reading using Tokio: https://fasterthanli.me/articles/a-terminal-case-of-linux
|
||||
|
||||
async fn serial_loop(
|
||||
mut port: tokio_serial::SerialStream,
|
||||
to_console: mpsc::Sender<Vec<u8>>,
|
||||
mut from_console: mpsc::Receiver<Vec<u8>>,
|
||||
) -> Result<()> {
|
||||
let mut buf = [0; 256];
|
||||
loop {
|
||||
tokio::select! {
|
||||
// _ = poll_send => {},
|
||||
|
||||
Some(msg) = from_console.recv() => {
|
||||
// debug!("serial write {} bytes", msg.len());
|
||||
tokio::io::AsyncWriteExt::write_all(&mut port, msg.as_ref()).await?;
|
||||
}
|
||||
|
||||
res = port.read(&mut buf) => {
|
||||
match res {
|
||||
Ok(0) => {
|
||||
// info!("Serial <EOF>");
|
||||
return Ok(());
|
||||
}
|
||||
Ok(n) => {
|
||||
// debug!("Serial read {n} bytes.");
|
||||
to_console.send(buf[0..n].to_owned()).await?;
|
||||
}
|
||||
Err(e) => {
|
||||
// if e.kind() == ErrorKind::TimedOut {
|
||||
// execute!(w, style::Print("\r\nTimeout: the serial device has been unplugged!"))?;
|
||||
// } else {
|
||||
// execute!(w, style::Print(format!("\r\nSerial Error: {:?}\r", e)))?;
|
||||
// }
|
||||
// break;
|
||||
return Err(anyhow!(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn console_loop<P>(
|
||||
to_console2: mpsc::Sender<Vec<u8>>,
|
||||
mut from_internal: mpsc::Receiver<Vec<u8>>,
|
||||
to_serial: mpsc::Sender<Vec<u8>>,
|
||||
mut from_serial: mpsc::Receiver<Vec<u8>>,
|
||||
kernel: P,
|
||||
) -> Result<()>
|
||||
where
|
||||
P: ThePath,
|
||||
{
|
||||
let mut w = std::io::stdout();
|
||||
|
||||
let mut breaks = 0;
|
||||
|
||||
let mut event_reader = EventStream::new();
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
biased;
|
||||
|
||||
Some(received) = from_internal.recv() => {
|
||||
for &x in &received[..] {
|
||||
execute!(w, style::Print(format!("{}", x as char)))?;
|
||||
}
|
||||
w.flush()?;
|
||||
}
|
||||
|
||||
Some(received) = from_serial.recv() => {
|
||||
// execute!(w, cursor::MoveToNextLine(1), style::Print(format!("[>>] Received {} bytes from serial", from_serial.len())), cursor::MoveToNextLine(1))?;
|
||||
|
||||
for &x in &received[..] {
|
||||
if x == 0x3 {
|
||||
// execute!(w, cursor::MoveToNextLine(1), style::Print("[>>] Received a BREAK"), cursor::MoveToNextLine(1))?;
|
||||
breaks += 1;
|
||||
// Await for 3 consecutive \3 to start downloading
|
||||
if breaks == 3 {
|
||||
// execute!(w, cursor::MoveToNextLine(1), style::Print("[>>] Received 3 BREAKs"), cursor::MoveToNextLine(1))?;
|
||||
breaks = 0;
|
||||
send_kernel(&to_console2, &to_serial, &mut from_serial, kernel.clone()).await?;
|
||||
to_console2.send("[>>] Send successful, pass-through\n".into()).await?;
|
||||
}
|
||||
} else {
|
||||
while breaks > 0 {
|
||||
execute!(w, style::Print(format!("{}", 3 as char)))?;
|
||||
breaks -= 1;
|
||||
}
|
||||
execute!(w, style::Print(format!("{}", x as char)))?;
|
||||
w.flush()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maybe_event = event_reader.next().fuse() => {
|
||||
match maybe_event {
|
||||
Some(Ok(Event::Key(key_event))) => {
|
||||
if key_event.code == KeyCode::Char('c') && key_event.modifiers == KeyModifiers::CONTROL {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(key) = handle_key_event(key_event) {
|
||||
to_serial.send(key.to_vec()).await?;
|
||||
// Local echo
|
||||
execute!(w, style::Print(format!("{:?}", key)))?;
|
||||
w.flush()?;
|
||||
}
|
||||
}
|
||||
Some(Ok(_)) => {},
|
||||
Some(Err(e)) => {
|
||||
execute!(w, style::Print(format!("Console read error: {:?}\r", e)))?;
|
||||
w.flush()?;
|
||||
},
|
||||
None => return Err(anyhow!("woops")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn main_loop<P>(port: SerialStream, kernel: P) -> Result<()>
|
||||
where
|
||||
P: ThePath,
|
||||
{
|
||||
// read from serial -> to_console==>from_serial -> output to console
|
||||
let (to_console, from_serial) = mpsc::channel(256);
|
||||
let (to_console2, from_internal) = mpsc::channel(256);
|
||||
|
||||
// read from console -> to_serial==>from_console -> output to serial
|
||||
let (to_serial, from_console) = mpsc::channel(256);
|
||||
|
||||
tokio::spawn(serial_loop(port, to_console.clone(), from_console));
|
||||
console_loop(to_console2, from_internal, to_serial, from_serial, kernel).await
|
||||
|
||||
// TODO: framed
|
||||
|
||||
// rx_device -> serial_reader -> app
|
||||
// app -> serial_writer -> serial_consumer -> (poll_send to drive) -> serial_sink -> tx_device
|
||||
// let (rx_device, tx_device) = split(port);
|
||||
|
||||
// let mut serial_reader = FramedRead::new(rx_device, BytesCodec::new());
|
||||
// let serial_sink = FramedWrite::new(tx_device, BytesCodec::new());
|
||||
//
|
||||
// let (serial_writer, serial_consumer) = mpsc::unbounded::<Bytes>();
|
||||
// let mut poll_send = serial_consumer.map(Ok).forward(serial_sink);
|
||||
}
|
||||
|
||||
// From remote_serial -- https://github.com/zhp-rs/remote_serial/ (Licensed under MIT License)
|
||||
fn handle_key_event(key_event: KeyEvent) -> Option<Bytes> {
|
||||
let mut buf = [0; 4];
|
||||
|
||||
let key_str: Option<&[u8]> = match key_event.code {
|
||||
KeyCode::Backspace => Some(b"\x08"),
|
||||
KeyCode::Enter => Some(b"\x0D"),
|
||||
KeyCode::Left => Some(b"\x1b[D"),
|
||||
KeyCode::Right => Some(b"\x1b[C"),
|
||||
KeyCode::Home => Some(b"\x1b[H"),
|
||||
KeyCode::End => Some(b"\x1b[F"),
|
||||
KeyCode::Up => Some(b"\x1b[A"),
|
||||
KeyCode::Down => Some(b"\x1b[B"),
|
||||
KeyCode::Tab => Some(b"\x09"),
|
||||
KeyCode::Delete => Some(b"\x1b[3~"),
|
||||
KeyCode::Insert => Some(b"\x1b[2~"),
|
||||
KeyCode::Esc => Some(b"\x1b"),
|
||||
KeyCode::Char(ch) => {
|
||||
if key_event.modifiers & KeyModifiers::CONTROL == KeyModifiers::CONTROL {
|
||||
buf[0] = ch as u8;
|
||||
if ('a'..='z').contains(&ch) || (ch == ' ') {
|
||||
buf[0] &= 0x1f;
|
||||
Some(&buf[0..1])
|
||||
} else if ('4'..='7').contains(&ch) {
|
||||
// crossterm returns Control-4 thru 7 for \x1c thru \x1f
|
||||
buf[0] = (buf[0] + 8) & 0x1f;
|
||||
Some(&buf[0..1])
|
||||
} else {
|
||||
Some(ch.encode_utf8(&mut buf).as_bytes())
|
||||
}
|
||||
} else {
|
||||
Some(ch.encode_utf8(&mut buf).as_bytes())
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
key_str.map(Bytes::copy_from_slice)
|
||||
}
|
||||
|
||||
// 1. connect to given serial port, e.g. /dev/ttyUSB23234
|
||||
// 2. Await for \3\3\3 start signal, meanwhile pass-through all traffic to console
|
||||
// 3. send selected kernel binary with checksum to the target
|
||||
// 4. go to 2
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let matches = App::new("ChainOfCommand - command chainboot protocol")
|
||||
.about("Use to send freshly built kernel to chainboot-compatible boot loader")
|
||||
.setting(AppSettings::DisableVersion)
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.help("The device path to a serial port, e.g. /dev/ttyUSB0")
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("baud")
|
||||
.help("The baud rate to connect at")
|
||||
.use_delimiter(false)
|
||||
.required(true), // .validator(valid_baud),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("kernel")
|
||||
.long("kernel")
|
||||
.help("Path of the binary kernel image to send")
|
||||
.takes_value(true)
|
||||
.default_value("kernel8.img"),
|
||||
)
|
||||
.get_matches();
|
||||
let port_name = matches.value_of("port").unwrap();
|
||||
let baud_rate = matches.value_of("baud").unwrap().parse::<u32>().unwrap();
|
||||
let kernel = matches.value_of("kernel").unwrap().to_owned();
|
||||
|
||||
// Check that STDIN is a proper tty
|
||||
if !std::io::stdin().is_tty() {
|
||||
panic!("Must have a TTY for stdin");
|
||||
}
|
||||
|
||||
// Disable line buffering, local echo, etc.
|
||||
terminal::enable_raw_mode()?;
|
||||
defer(|| terminal::disable_raw_mode().unwrap_or(()));
|
||||
|
||||
let mut serial_toggle = false;
|
||||
let mut stdout = std::io::stdout();
|
||||
|
||||
execute!(stdout, cursor::SavePosition)?;
|
||||
|
||||
loop {
|
||||
execute!(
|
||||
stdout,
|
||||
cursor::RestorePosition,
|
||||
style::Print("[>>] Opening serial port ")
|
||||
)?;
|
||||
|
||||
// tokio_serial::new() creates a builder with 8N1 setup without flow control by default.
|
||||
let port = tokio_serial::new(port_name, baud_rate).open_native_async();
|
||||
if let Err(e) = port {
|
||||
let cont = match e.kind {
|
||||
tokio_serial::ErrorKind::NoDevice => true,
|
||||
tokio_serial::ErrorKind::Io(e)
|
||||
if e == std::io::ErrorKind::NotFound
|
||||
|| e == std::io::ErrorKind::PermissionDenied =>
|
||||
{
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
if cont {
|
||||
execute!(
|
||||
stdout,
|
||||
cursor::RestorePosition,
|
||||
style::Print(format!(
|
||||
"[>>] Waiting for serial port {}\r",
|
||||
if serial_toggle { "# " } else { " #" }
|
||||
))
|
||||
)?;
|
||||
stdout.flush()?;
|
||||
serial_toggle = !serial_toggle;
|
||||
|
||||
if crossterm::event::poll(Duration::from_millis(1000))? {
|
||||
if let Event::Key(KeyEvent { code, modifiers }) = crossterm::event::read()? {
|
||||
if code == KeyCode::Char('c') && modifiers == KeyModifiers::CONTROL {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
return Err(e.into());
|
||||
}
|
||||
|
||||
execute!(
|
||||
stdout,
|
||||
style::Print("\n[>>] Waiting for handshake, pass-through"),
|
||||
)?;
|
||||
stdout.flush()?;
|
||||
|
||||
// Run in pass-through mode by default.
|
||||
// Once we receive BREAK (0x3) three times, switch to kernel send mode and upload kernel,
|
||||
// then switch back to pass-through mode.
|
||||
|
||||
// Input from STDIN should pass through to serial
|
||||
// Input from serial should pass through to STDOUT
|
||||
|
||||
let port = port?;
|
||||
|
||||
if let Err(e) = main_loop(port, kernel.clone()).await {
|
||||
execute!(stdout, style::Print(format!("\nError: {:?}\n", e)))?;
|
||||
stdout.flush()?;
|
||||
|
||||
let cont = match e.downcast_ref::<std::io::Error>() {
|
||||
Some(e)
|
||||
if e.kind() == std::io::ErrorKind::NotFound
|
||||
|| e.kind() == std::io::ErrorKind::PermissionDenied =>
|
||||
{
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
} || matches!(e.downcast_ref::<tokio_serial::Error>(), Some(e) if e.kind == tokio_serial::ErrorKind::NoDevice)
|
||||
|| matches!(
|
||||
e.downcast_ref::<tokio::sync::mpsc::error::SendError<Vec<u8>>>(),
|
||||
Some(_)
|
||||
);
|
||||
|
||||
if !cont {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// main_loop() returned Ok() we're good to finish
|
||||
break;
|
||||
}
|
||||
execute!(stdout, cursor::SavePosition)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue