From 9704a7814919ab91d2b68b0252b25d75e93a2671 Mon Sep 17 00:00:00 2001 From: mhfowler Date: Mon, 25 Oct 2021 11:30:43 +0200 Subject: [PATCH] Add peach-buttons and peach-oled --- peach-buttons/.cargo/config | 4 + peach-buttons/.gitignore | 2 + peach-buttons/.travis.yml | 7 + peach-buttons/Cargo.lock | 1460 ++++++++++++++++++ peach-buttons/Cargo.toml | 40 + peach-buttons/README.md | 106 ++ peach-buttons/debian/peach-buttons.service | 27 + peach-buttons/src/error.rs | 25 + peach-buttons/src/interrupt.rs | 63 + peach-buttons/src/lib.rs | 119 ++ peach-buttons/src/main.rs | 12 + peach-oled/.cargo/config | 4 + peach-oled/.gitignore | 2 + peach-oled/.travis.yml | 7 + peach-oled/Cargo.lock | 1603 ++++++++++++++++++++ peach-oled/Cargo.toml | 42 + peach-oled/README.md | 165 ++ peach-oled/debian/peach-oled.service | 27 + peach-oled/docs/images/peachcloud_oled.jpg | Bin 0 -> 21922 bytes peach-oled/src/error.rs | 72 + peach-oled/src/lib.rs | 448 ++++++ peach-oled/src/main.rs | 14 + 22 files changed, 4249 insertions(+) create mode 100644 peach-buttons/.cargo/config create mode 100644 peach-buttons/.gitignore create mode 100644 peach-buttons/.travis.yml create mode 100644 peach-buttons/Cargo.lock create mode 100644 peach-buttons/Cargo.toml create mode 100644 peach-buttons/README.md create mode 100644 peach-buttons/debian/peach-buttons.service create mode 100644 peach-buttons/src/error.rs create mode 100644 peach-buttons/src/interrupt.rs create mode 100644 peach-buttons/src/lib.rs create mode 100644 peach-buttons/src/main.rs create mode 100644 peach-oled/.cargo/config create mode 100644 peach-oled/.gitignore create mode 100644 peach-oled/.travis.yml create mode 100644 peach-oled/Cargo.lock create mode 100644 peach-oled/Cargo.toml create mode 100644 peach-oled/README.md create mode 100644 peach-oled/debian/peach-oled.service create mode 100644 peach-oled/docs/images/peachcloud_oled.jpg create mode 100644 peach-oled/src/error.rs create mode 100644 peach-oled/src/lib.rs create mode 100644 peach-oled/src/main.rs diff --git a/peach-buttons/.cargo/config b/peach-buttons/.cargo/config new file mode 100644 index 0000000..4b6f460 --- /dev/null +++ b/peach-buttons/.cargo/config @@ -0,0 +1,4 @@ +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" +objcopy = { path ="aarch64-linux-gnu-objcopy" } +strip = { path ="aarch64-linux-gnu-strip" } diff --git a/peach-buttons/.gitignore b/peach-buttons/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/peach-buttons/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/peach-buttons/.travis.yml b/peach-buttons/.travis.yml new file mode 100644 index 0000000..f2536c6 --- /dev/null +++ b/peach-buttons/.travis.yml @@ -0,0 +1,7 @@ +language: rust +rust: + - nightly +before_script: + - rustup component add clippy +script: + - cargo clippy -- -D warnings diff --git a/peach-buttons/Cargo.lock b/peach-buttons/Cargo.lock new file mode 100644 index 0000000..4983353 --- /dev/null +++ b/peach-buttons/Cargo.lock @@ -0,0 +1,1460 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "addr2line" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" + +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "backtrace" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" +dependencies = [ + "addr2line", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "bstr" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf" +dependencies = [ + "memchr", +] + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +dependencies = [ + "byteorder", + "iovec", +] + +[[package]] +name = "cc" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "crossbeam-channel" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" +dependencies = [ + "crossbeam-utils 0.6.6", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg 1.0.1", + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard 1.1.0", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-utils" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" +dependencies = [ + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg 1.0.1", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "env_logger" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "backtrace", + "version_check", +] + +[[package]] +name = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn 1.0.56", + "synstructure", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +dependencies = [ + "typenum", +] + +[[package]] +name = "gimli" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" + +[[package]] +name = "globset" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "gpio-cdev" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d50743080fbae298c55f0b28dd5ea4b513c53cddeddace6cbdd31db7dda981" +dependencies = [ + "bitflags", + "error-chain", + "libc", + "nix", +] + +[[package]] +name = "hermit-abi" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +dependencies = [ + "libc", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "jsonrpc-core" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b83fdc5e0218128d0d270f2f2e7a5ea716f3240c8518a58bc89e6716ba8581" +dependencies = [ + "futures", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "jsonrpc-core-client" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c889ca27072f038496a62f38356e8f827acf194d7276030120265362b2974eab" +dependencies = [ + "failure", + "futures", + "jsonrpc-core", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "jsonrpc-pubsub" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c233c4570183a45f7bde14cd7d23446d6c236de6df9442e53a60951adae9fd34" +dependencies = [ + "jsonrpc-core", + "log", + "parking_lot 0.7.1", + "serde", +] + +[[package]] +name = "jsonrpc-server-utils" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3372b3248a53abcca8f61924f188052bb0c4cd80b482b2b4eaf9f8667efb9f4" +dependencies = [ + "bytes", + "globset", + "jsonrpc-core", + "lazy_static", + "log", + "num_cpus", + "tokio", + "tokio-codec", + "unicase", +] + +[[package]] +name = "jsonrpc-test" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aedad254cd8faba2bf8d1fe00c52fe9d9944f1a8c3f789916b68a61a3414c87" +dependencies = [ + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-pubsub", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "jsonrpc-ws-server" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72d8f524c7afd11d9c71614d1f814ee1c46377869933ce42d559d6973922f79" +dependencies = [ + "jsonrpc-core", + "jsonrpc-server-utils", + "log", + "parking_lot 0.7.1", + "slab", + "ws", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" + +[[package]] +name = "lock_api" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +dependencies = [ + "owning_ref", + "scopeguard 0.3.3", +] + +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard 1.1.0", +] + +[[package]] +name = "log" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +dependencies = [ + "cfg-if 0.1.10", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "memoffset" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg 1.0.1", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +dependencies = [ + "adler", + "autocfg 1.0.1", +] + +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "mio-extras" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +dependencies = [ + "lazycell", + "log", + "mio", + "slab", +] + +[[package]] +name = "mio-uds" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" +dependencies = [ + "iovec", + "libc", + "mio", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "net2" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "nix" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "becb657d662f1cd2ef38c7ad480ec6b8cf9e96b27adb543e594f9cf0f2e6065c" +dependencies = [ + "bitflags", + "cc", + "cfg-if 0.1.10", + "libc", + "void", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "owning_ref" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "parking_lot" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +dependencies = [ + "lock_api 0.1.5", + "parking_lot_core 0.4.0", +] + +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +dependencies = [ + "lock_api 0.3.4", + "parking_lot_core 0.6.2", + "rustc_version", +] + +[[package]] +name = "parking_lot_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +dependencies = [ + "libc", + "rand", + "rustc_version", + "smallvec", + "winapi 0.3.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +dependencies = [ + "cfg-if 0.1.10", + "cloudabi", + "libc", + "redox_syscall", + "rustc_version", + "smallvec", + "winapi 0.3.9", +] + +[[package]] +name = "peach-buttons" +version = "0.1.3" +dependencies = [ + "crossbeam-channel", + "env_logger", + "gpio-cdev", + "jsonrpc-core", + "jsonrpc-pubsub", + "jsonrpc-test", + "jsonrpc-ws-server", + "log", + "snafu", +] + +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid 0.2.1", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2 1.0.24", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi 0.3.9", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi 0.3.9", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi 0.3.9", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "regex" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" + +[[package]] +name = "rustc-demangle" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scopeguard" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" + +[[package]] +name = "serde_derive" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn 1.0.56", +] + +[[package]] +name = "serde_json" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" +dependencies = [ + "maybe-uninit", +] + +[[package]] +name = "snafu" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b028158eb06caa8345bee10cccfb25fa632beccf0ef5308832b4fd4b78a7db48" +dependencies = [ + "backtrace", + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf50aaef500c248a590e2696e8bf8c7620ca2235b9bb90a70363d82dd1abec6a" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "unicode-xid 0.2.1", +] + +[[package]] +name = "synstructure" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn 1.0.56", + "unicode-xid 0.2.1", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tinyvec" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" +dependencies = [ + "bytes", + "futures", + "mio", + "num_cpus", + "tokio-codec", + "tokio-current-thread", + "tokio-executor", + "tokio-fs", + "tokio-io", + "tokio-reactor", + "tokio-sync", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", + "tokio-udp", + "tokio-uds", +] + +[[package]] +name = "tokio-codec" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" +dependencies = [ + "bytes", + "futures", + "tokio-io", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" +dependencies = [ + "futures", + "tokio-executor", +] + +[[package]] +name = "tokio-executor" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" +dependencies = [ + "crossbeam-utils 0.7.2", + "futures", +] + +[[package]] +name = "tokio-fs" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" +dependencies = [ + "futures", + "tokio-io", + "tokio-threadpool", +] + +[[package]] +name = "tokio-io" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" +dependencies = [ + "bytes", + "futures", + "log", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" +dependencies = [ + "crossbeam-utils 0.7.2", + "futures", + "lazy_static", + "log", + "mio", + "num_cpus", + "parking_lot 0.9.0", + "slab", + "tokio-executor", + "tokio-io", + "tokio-sync", +] + +[[package]] +name = "tokio-sync" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" +dependencies = [ + "fnv", + "futures", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" +dependencies = [ + "bytes", + "futures", + "iovec", + "mio", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" +dependencies = [ + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-utils 0.7.2", + "futures", + "lazy_static", + "log", + "num_cpus", + "slab", + "tokio-executor", +] + +[[package]] +name = "tokio-timer" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" +dependencies = [ + "crossbeam-utils 0.7.2", + "futures", + "slab", + "tokio-executor", +] + +[[package]] +name = "tokio-udp" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" +dependencies = [ + "bytes", + "futures", + "log", + "mio", + "tokio-codec", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "tokio-uds" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" +dependencies = [ + "bytes", + "futures", + "iovec", + "libc", + "log", + "mio", + "mio-uds", + "tokio-codec", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +dependencies = [ + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[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-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[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-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "ws" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec91ea61b83ce033c43c06c52ddc7532f465c0153281610d44c58b74083aee1a" +dependencies = [ + "byteorder", + "bytes", + "httparse", + "log", + "mio", + "mio-extras", + "rand", + "sha-1", + "slab", + "url", +] + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] diff --git a/peach-buttons/Cargo.toml b/peach-buttons/Cargo.toml new file mode 100644 index 0000000..0025c9b --- /dev/null +++ b/peach-buttons/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "peach-buttons" +version = "0.1.3" +authors = ["Andrew Reid "] +edition = "2018" +description = "peach-buttons is a GPIO microservice for handling button presses, implementing a JSON-RPC server with Publish-Subscribe extension. Each button press results in a JSON-RPC request being sent over websockets to any subscribers. A button code for the pressed button is sent with the request to subscribers, allowing state-specific actions to be taken." +homepage = "https://opencollective.com/peachcloud" +repository = "https://github.com/peachcloud/peach-buttons" +readme = "README.md" +license = "AGPL-3.0-only" +publish = false + +[package.metadata.deb] +depends = "$auto" +extended-description = """\ +peach-buttons is a GPIO microservice for handling button presses, \ +implementing a JSON-RPC server with Publish-Subscribe extention. \ +Each button press results in a JSON-RPC request being sent over websockets \ +to any subscribers.""" +maintainer-scripts="debian" +systemd-units = { unit-name = "peach-buttons" } +assets = [ + ["target/release/peach-buttons", "usr/bin/", "755"], + ["README.md", "usr/share/doc/peach-buttons/README", "644"], +] + +[badges] +travis-ci = { repository = "peachcloud/peach-buttons", branch = "master" } +maintenance = { status = "actively-developed" } + +[dependencies] +crossbeam-channel = "0.3" +env_logger = "0.6" +gpio-cdev = "0.2" +jsonrpc-core = "11" +jsonrpc-ws-server = "11" +jsonrpc-pubsub = "11" +jsonrpc-test = "11" +log = "0.4" +snafu = "0.4" diff --git a/peach-buttons/README.md b/peach-buttons/README.md new file mode 100644 index 0000000..4b3b4ae --- /dev/null +++ b/peach-buttons/README.md @@ -0,0 +1,106 @@ +# peach-buttons + +[![Build Status](https://travis-ci.com/peachcloud/peach-buttons.svg?branch=master)](https://travis-ci.com/peachcloud/peach-buttons) ![Generic badge](https://img.shields.io/badge/version-0.1.3-.svg) + +GPIO microservice module for handling button presses. `peach-buttons` implements a JSON-RPC server with [Publish-Subscribe extension](https://docs.rs/jsonrpc-pubsub/11.0.0/jsonrpc_pubsub/). Each button press results in a JSON-RPC request being sent over websockets to any subscribers. A button code for the pressed button is sent with the request to subscribers, allowing state-specific actions to be taken. + +A subscriber implementation for this microservice can be found in the [peach-menu repo](https://github.com/peachcloud/peach-menu). + +_Note: This module is a work-in-progress._ + +### Pin to Button to Button Code Mappings + +``` +4 => Center => 0, +27 => Left => 1, +23 => Right => 2, +17 => Up => 3, +22 => Down => 4, +5 => A => 5, +6 => B => 6 +``` + +_Note: `peach-buttons` utilizes the GPIO character device ABI. This API, stabilized with Linux v4.4, deprecates the legacy sysfs interface to GPIOs that is planned to be removed from the upstream kernel after year 2020._ + +### Environment + +The JSON-RPC WS server address and port can be configured with the `PEACH_BUTTONS_SERVER` environment variable: + +`export PEACH_BUTTONS_SERVER=127.0.0.1:5000` + +When not set, the value defaults to `127.0.0.1:5111`. + +Logging is made availabe with `env_logger`: + +`export RUST_LOG=info` + +Other logging levels include `debug`, `warn` and `error`. + +### Setup + +Clone this repo: + +`git clone https://github.com/peachcloud/peach-buttons.git` + +Move into the repo and compile: + +`cd peach-buttons` +`cargo build --release` + +Run the binary with sudo: + +`sudo ./target/release/peach-buttons` + +### Debian Packaging + +A `systemd` service file and Debian maintainer scripts are included in the `debian` directory, allowing `peach-buttons` to be easily bundled as a Debian package (`.deb`). The `cargo-deb` [crate](https://crates.io/crates/cargo-deb) can be used to achieve this. + +Install `cargo-deb`: + +`cargo install cargo-deb` + +Move into the repo: + +`cd peach-buttons` + +Build the package: + +`cargo deb` + +The output will be written to `target/debian/peach-buttons_0.1.0_arm64.deb` (or similar). + +Build the package (aarch64): + +`cargo deb --target aarch64-unknown-linux-gnu` + +Install the package as follows: + +`sudo dpkg -i target/debian/peach-buttons_0.1.0_arm64.deb` + +The service will be automatically enabled and started. + +Uninstall the service: + +`sudo apt-get remove peach-buttons` + +Remove configuration files (not removed with `apt-get remove`): + +`sudo apt-get purge peach-buttons` + +### Testing Subscription + +Request: + +`{"id":1,"jsonrpc":"2.0","method":"subscribe_buttons"}` + +Response: + +`{"jsonrpc":"2.0","result":1,"id":1}` + +Event: + +`{"jsonrpc":"2.0","method":"button_press","params":[0]}` + +### Licensing + +AGPL-3.0 diff --git a/peach-buttons/debian/peach-buttons.service b/peach-buttons/debian/peach-buttons.service new file mode 100644 index 0000000..090fac4 --- /dev/null +++ b/peach-buttons/debian/peach-buttons.service @@ -0,0 +1,27 @@ +[Unit] +Description=GPIO microservice for handling button presses. Implements a JSON-RPC server with Publish-Subscribe extension. + +[Service] +Type=simple +User=peach-buttons +Group=gpio-user +Environment="RUST_LOG=error" +ExecStart=/usr/bin/peach-buttons +Restart=always +CapabilityBoundingSet=~CAP_SYS_ADMIN CAP_SYS_PTRACE CAP_SYS_BOOT CAP_SYS_TIME CAP_KILL CAP_WAKE_ALARM CAP_LINUX_IMMUTABLE CAP_BLOCK_SUSPEND CAP_LEASE CAP_SYS_NICE CAP_SYS_RESOURCE CAP_RAWIO CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_* CAP_FOWNER CAP_IPC_OWNER CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_AUDIT_* +InaccessibleDirectories=/home +LockPersonality=yes +NoNewPrivileges=yes +PrivateTmp=yes +PrivateUsers=yes +ProtectControlGroups=yes +ProtectHome=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +ProtectSystem=yes +ReadOnlyDirectories=/var +RestrictAddressFamilies=~AF_INET6 AF_UNIX +SystemCallFilter=~@reboot @clock @debug @module @mount @swap @resources @privileged + +[Install] +WantedBy=multi-user.target diff --git a/peach-buttons/src/error.rs b/peach-buttons/src/error.rs new file mode 100644 index 0000000..fad43df --- /dev/null +++ b/peach-buttons/src/error.rs @@ -0,0 +1,25 @@ +use std::{error, str}; + +use jsonrpc_core::{types::error::Error, ErrorCode}; +use snafu::Snafu; + +pub type BoxError = Box; + +#[derive(Debug, Snafu)] +#[snafu(visibility(pub(crate)))] +pub enum ButtonError { + #[snafu(display("Invalid parameters. Subscription rejected"))] + RejectSubscription, +} + +impl From for Error { + fn from(err: ButtonError) -> Self { + match &err { + ButtonError::RejectSubscription => Error { + code: ErrorCode::ParseError, + message: "Invalid parameters. Subscription request rejected".to_string(), + data: None, + }, + } + } +} diff --git a/peach-buttons/src/interrupt.rs b/peach-buttons/src/interrupt.rs new file mode 100644 index 0000000..8f1375a --- /dev/null +++ b/peach-buttons/src/interrupt.rs @@ -0,0 +1,63 @@ +use std::{cell::Cell, process, thread, time::Duration}; + +use crossbeam_channel::{tick, Sender}; +use gpio_cdev::{Chip, LineRequestFlags}; +use log::{debug, error, info}; + +// initialize gpio pin and poll for state +// send button code to "subscribe_buttons" rpc method for sink notification +pub fn interrupt_handler(pin: u32, button_code: u8, button_name: String, s: Sender) { + thread::spawn(move || { + debug!("Creating handle for GPIO chip."); + let mut chip = Chip::new("/dev/gpiochip0").unwrap_or_else(|err| { + error!("Failed to create handle for GPIO chip: {}", err); + process::exit(1); + }); + + debug!("Creating handle for GPIO line at given pin."); + let input = chip.get_line(pin).unwrap_or_else(|err| { + error!( + "Failed to create handle for GPIO line at pin {}: {}", + pin, err + ); + process::exit(1); + }); + + let line_handle = input + .request(LineRequestFlags::INPUT, 0, &button_name) + .unwrap_or_else(|err| { + error!("Failed to gain kernel access for pin {}: {}", pin, err); + process::exit(1); + }); + + let ticker = tick(Duration::from_millis(2)); + let mut counter = Cell::new(0); + let mut switch = Cell::new(0); + + info!( + "Initating polling loop for {} button on pin {}", + button_name, pin + ); + loop { + ticker.recv().unwrap(); + let value = line_handle + .get_value() + .expect("Failed to get current state of this line from the kernel"); + match value { + 0 => counter.set(0), + 1 => *counter.get_mut() += 1, + _ => (), + } + if counter.get() == 10 { + if switch.get() == 0 { + *switch.get_mut() += 1 + } else { + debug!("Sending button code: {}", button_code); + s.send(button_code).unwrap_or_else(|err| { + error!("Failed to send button_code to publisher: {}", err); + }); + } + } + } + }); +} diff --git a/peach-buttons/src/lib.rs b/peach-buttons/src/lib.rs new file mode 100644 index 0000000..605517d --- /dev/null +++ b/peach-buttons/src/lib.rs @@ -0,0 +1,119 @@ +mod error; +mod interrupt; + +use std::{env, result::Result, sync::Arc, thread}; + +use crossbeam_channel::bounded; +use jsonrpc_core::futures::Future; +use jsonrpc_core::*; +use jsonrpc_pubsub::{PubSubHandler, Session, Subscriber, SubscriptionId}; +#[allow(unused_imports)] +use jsonrpc_test as test; +use jsonrpc_ws_server::{RequestContext, ServerBuilder}; +use log::{debug, error, info, warn}; + +use crate::error::{BoxError, ButtonError::RejectSubscription}; +use crate::interrupt::*; + +pub fn run() -> Result<(), BoxError> { + info!("Starting up."); + + debug!("Creating channel for message passing."); + let (s, r) = bounded(0); + + let pin = vec![4, 27, 23, 17, 22, 5, 6]; + let code = vec![0, 1, 2, 3, 4, 5, 6]; + let name = vec!["center", "left", "right", "up", "down", "#5", "#6"]; + + debug!("Setting up interrupt handlers."); + for i in 0..7 { + interrupt_handler(pin[i], code[i], name[i].to_string(), s.clone()); + } + + debug!("Creating pub-sub handler."); + let mut io = PubSubHandler::new(MetaIoHandler::default()); + + io.add_subscription( + "button_press", + ( + "subscribe_buttons", + move |params: Params, _, subscriber: Subscriber| { + debug!("Received subscription request."); + if params != Params::None { + subscriber + .reject(Error::from(RejectSubscription)) + .unwrap_or_else(|_| { + error!("Failed to send rejection error for subscription request."); + }); + return; + } + + let r1 = r.clone(); + + thread::spawn(move || { + let sink = subscriber + .assign_id_async(SubscriptionId::Number(1)) + .wait() + .unwrap(); + + info!("Listening for button code from gpio events."); + loop { + let button_code: u8 = r1.recv().unwrap(); + info!("Received button code: {}.", button_code); + match sink + .notify(Params::Array(vec![Value::Number(button_code.into())])) + .wait() + { + Ok(_) => info!("Publishing button code to subscriber over ws."), + Err(_) => { + warn!("Failed to publish button code."); + break; + } + } + } + }); + }, + ), + ("remove_buttons", |_id: SubscriptionId, _| { + // unsubscribe + futures::future::ok(Value::Bool(true)) + }), + ); + + let ws_server = + env::var("PEACH_BUTTONS_SERVER").unwrap_or_else(|_| "127.0.0.1:5111".to_string()); + + info!("Starting JSON-RPC server on {}.", ws_server); + let server = ServerBuilder::with_meta_extractor(io, |context: &RequestContext| { + Arc::new(Session::new(context.sender())) + }) + .start( + &ws_server + .parse() + .expect("Invalid WS address and port combination"), + ) + .expect("Unable to start RPC server"); + + info!("Listening for requests."); + server.wait().unwrap(); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn rpc_success() { + let rpc = { + let mut io = IoHandler::new(); + io.add_method("rpc_success_response", |_| { + Ok(Value::String("success".into())) + }); + test::Rpc::from(io) + }; + + assert_eq!(rpc.request("rpc_success_response", &()), r#""success""#); + } +} diff --git a/peach-buttons/src/main.rs b/peach-buttons/src/main.rs new file mode 100644 index 0000000..53e4815 --- /dev/null +++ b/peach-buttons/src/main.rs @@ -0,0 +1,12 @@ +use std::process; + +use log::error; + +fn main() { + env_logger::init(); + + if let Err(e) = peach_buttons::run() { + error!("Application error: {}", e); + process::exit(1); + } +} diff --git a/peach-oled/.cargo/config b/peach-oled/.cargo/config new file mode 100644 index 0000000..4b6f460 --- /dev/null +++ b/peach-oled/.cargo/config @@ -0,0 +1,4 @@ +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" +objcopy = { path ="aarch64-linux-gnu-objcopy" } +strip = { path ="aarch64-linux-gnu-strip" } diff --git a/peach-oled/.gitignore b/peach-oled/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/peach-oled/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/peach-oled/.travis.yml b/peach-oled/.travis.yml new file mode 100644 index 0000000..f2536c6 --- /dev/null +++ b/peach-oled/.travis.yml @@ -0,0 +1,7 @@ +language: rust +rust: + - nightly +before_script: + - rustup component add clippy +script: + - cargo clippy -- -D warnings diff --git a/peach-oled/Cargo.lock b/peach-oled/Cargo.lock new file mode 100644 index 0000000..99b28bd --- /dev/null +++ b/peach-oled/Cargo.lock @@ -0,0 +1,1603 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "addr2line" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" + +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "backtrace" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" +dependencies = [ + "addr2line", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c" + +[[package]] +name = "bitflags" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "bstr" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf" +dependencies = [ + "memchr", +] + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +dependencies = [ + "byteorder", + "either", + "iovec", +] + +[[package]] +name = "cast" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" +dependencies = [ + "rustc_version 0.2.3", +] + +[[package]] +name = "cc" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags 1.2.1", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg 1.0.1", + "cfg-if 0.1.10", + "crossbeam-utils", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard 1.1.0", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if 0.1.10", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg 1.0.1", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "embedded-graphics" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e7ee289ac88cbeea6f749cd72c6eb4cdeb801f4ea26795aace97b9776a2db2" +dependencies = [ + "tinybmp", + "tinytga", +] + +[[package]] +name = "embedded-hal" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "env_logger" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn 1.0.56", + "synstructure", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags 1.2.1", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" + +[[package]] +name = "futures-cpupool" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" +dependencies = [ + "futures", + "num_cpus", +] + +[[package]] +name = "gimli" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" + +[[package]] +name = "globset" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "h2" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" +dependencies = [ + "byteorder", + "bytes", + "fnv", + "futures", + "http", + "indexmap", + "log", + "slab", + "string", + "tokio-io", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + +[[package]] +name = "hermit-abi" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" +dependencies = [ + "bytes", + "futures", + "http", + "tokio-buf", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "hyper" +version = "0.12.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" +dependencies = [ + "bytes", + "futures", + "futures-cpupool", + "h2", + "http", + "http-body", + "httparse", + "iovec", + "itoa", + "log", + "net2", + "rustc_version 0.2.3", + "time", + "tokio", + "tokio-buf", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", + "want", +] + +[[package]] +name = "i2cdev" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c0eb3d9b6b02dc2508ee23439170004e44344bab9d53a490eb1f64c885b5003" +dependencies = [ + "bitflags 1.2.1", + "byteorder", + "libc", + "nix 0.14.1", +] + +[[package]] +name = "indexmap" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +dependencies = [ + "autocfg 1.0.1", + "hashbrown", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "jsonrpc-core" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b83fdc5e0218128d0d270f2f2e7a5ea716f3240c8518a58bc89e6716ba8581" +dependencies = [ + "futures", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "jsonrpc-core-client" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c889ca27072f038496a62f38356e8f827acf194d7276030120265362b2974eab" +dependencies = [ + "failure", + "futures", + "jsonrpc-core", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "jsonrpc-http-server" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "541257be6c8f75a41812575150dfa1120d3ee3a852601f2ca8ac9bcb73575c4e" +dependencies = [ + "hyper", + "jsonrpc-core", + "jsonrpc-server-utils", + "log", + "net2", + "unicase", +] + +[[package]] +name = "jsonrpc-pubsub" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c233c4570183a45f7bde14cd7d23446d6c236de6df9442e53a60951adae9fd34" +dependencies = [ + "jsonrpc-core", + "log", + "parking_lot 0.7.1", + "serde", +] + +[[package]] +name = "jsonrpc-server-utils" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3372b3248a53abcca8f61924f188052bb0c4cd80b482b2b4eaf9f8667efb9f4" +dependencies = [ + "bytes", + "globset", + "jsonrpc-core", + "lazy_static", + "log", + "num_cpus", + "tokio", + "tokio-codec", + "unicase", +] + +[[package]] +name = "jsonrpc-test" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aedad254cd8faba2bf8d1fe00c52fe9d9944f1a8c3f789916b68a61a3414c87" +dependencies = [ + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-pubsub", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" + +[[package]] +name = "linux-embedded-hal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "795096c0eecb0622afb591c3e1a97b1ba046688a7689957b70b8eee9cac8fb84" +dependencies = [ + "cast", + "embedded-hal", + "i2cdev", + "spidev", + "sysfs_gpio", +] + +[[package]] +name = "lock_api" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +dependencies = [ + "owning_ref", + "scopeguard 0.3.3", +] + +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard 1.1.0", +] + +[[package]] +name = "log" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +dependencies = [ + "cfg-if 0.1.10", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "memoffset" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg 1.0.1", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +dependencies = [ + "adler", + "autocfg 1.0.1", +] + +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "mio-uds" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" +dependencies = [ + "iovec", + "libc", + "mio", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.0.0", +] + +[[package]] +name = "nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" + +[[package]] +name = "net2" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "nix" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a7bb1da2be7da3cbffda73fc681d509ffd9e665af478d2bee1907cee0bc64b2" +dependencies = [ + "bitflags 0.4.0", + "cfg-if 0.1.10", + "libc", + "rustc_version 0.1.7", + "semver 0.1.20", + "void", +] + +[[package]] +name = "nix" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "becb657d662f1cd2ef38c7ad480ec6b8cf9e96b27adb543e594f9cf0f2e6065c" +dependencies = [ + "bitflags 1.2.1", + "cc", + "cfg-if 0.1.10", + "libc", + "void", +] + +[[package]] +name = "nix" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" +dependencies = [ + "bitflags 1.2.1", + "cc", + "cfg-if 0.1.10", + "libc", + "void", +] + +[[package]] +name = "nom" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +dependencies = [ + "memchr", + "version_check 0.1.5", +] + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check 0.9.2", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" + +[[package]] +name = "owning_ref" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "parking_lot" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +dependencies = [ + "lock_api 0.1.5", + "parking_lot_core 0.4.0", +] + +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +dependencies = [ + "lock_api 0.3.4", + "parking_lot_core 0.6.2", + "rustc_version 0.2.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +dependencies = [ + "libc", + "rand", + "rustc_version 0.2.3", + "smallvec", + "winapi 0.3.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +dependencies = [ + "cfg-if 0.1.10", + "cloudabi", + "libc", + "redox_syscall", + "rustc_version 0.2.3", + "smallvec", + "winapi 0.3.9", +] + +[[package]] +name = "peach-oled" +version = "0.1.3" +dependencies = [ + "embedded-graphics", + "env_logger", + "jsonrpc-core", + "jsonrpc-http-server", + "jsonrpc-test", + "linux-embedded-hal", + "log", + "nix 0.11.1", + "serde", + "serde_json", + "snafu", + "ssd1306", + "tinybmp", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid 0.2.1", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2 1.0.24", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi 0.3.9", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi 0.3.9", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi 0.3.9", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "regex" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" + +[[package]] +name = "rustc-demangle" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" + +[[package]] +name = "rustc_version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" +dependencies = [ + "semver 0.1.20", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scopeguard" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn 1.0.56", +] + +[[package]] +name = "serde_json" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" +dependencies = [ + "maybe-uninit", +] + +[[package]] +name = "snafu" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b028158eb06caa8345bee10cccfb25fa632beccf0ef5308832b4fd4b78a7db48" +dependencies = [ + "backtrace", + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf50aaef500c248a590e2696e8bf8c7620ca2235b9bb90a70363d82dd1abec6a" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "spidev" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba01d3ef92a37e898fecac76cd3e1b33c999395e2d70787608d9678c4293e04" +dependencies = [ + "bitflags 0.3.3", + "libc", + "nix 0.6.0", +] + +[[package]] +name = "ssd1306" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d818022001ebca8cec28b230700660a3f6a027123c8193c5e76e9764d087f3" +dependencies = [ + "embedded-graphics", + "embedded-hal", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "string" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" +dependencies = [ + "bytes", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "unicode-xid 0.2.1", +] + +[[package]] +name = "synstructure" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.8", + "syn 1.0.56", + "unicode-xid 0.2.1", +] + +[[package]] +name = "sysfs_gpio" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24961a55846623d8e4f6cec38718945116fed8d6970336a7110710a07aa9b5d1" +dependencies = [ + "nix 0.14.1", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi 0.3.9", +] + +[[package]] +name = "tinybmp" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d12b7f8b271567d6d072c49dee16b22271aabfc473e2066e3353e5af0f5230" +dependencies = [ + "nom 5.1.2", +] + +[[package]] +name = "tinytga" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc9485052c1f4b541d888f1d564dd9957671e0c21da9bca0c9824c1123e03f07" +dependencies = [ + "nom 4.2.3", +] + +[[package]] +name = "tokio" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" +dependencies = [ + "bytes", + "futures", + "mio", + "num_cpus", + "tokio-codec", + "tokio-current-thread", + "tokio-executor", + "tokio-fs", + "tokio-io", + "tokio-reactor", + "tokio-sync", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", + "tokio-udp", + "tokio-uds", +] + +[[package]] +name = "tokio-buf" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" +dependencies = [ + "bytes", + "either", + "futures", +] + +[[package]] +name = "tokio-codec" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" +dependencies = [ + "bytes", + "futures", + "tokio-io", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" +dependencies = [ + "futures", + "tokio-executor", +] + +[[package]] +name = "tokio-executor" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" +dependencies = [ + "crossbeam-utils", + "futures", +] + +[[package]] +name = "tokio-fs" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" +dependencies = [ + "futures", + "tokio-io", + "tokio-threadpool", +] + +[[package]] +name = "tokio-io" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" +dependencies = [ + "bytes", + "futures", + "log", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" +dependencies = [ + "crossbeam-utils", + "futures", + "lazy_static", + "log", + "mio", + "num_cpus", + "parking_lot 0.9.0", + "slab", + "tokio-executor", + "tokio-io", + "tokio-sync", +] + +[[package]] +name = "tokio-sync" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" +dependencies = [ + "fnv", + "futures", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" +dependencies = [ + "bytes", + "futures", + "iovec", + "mio", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" +dependencies = [ + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-utils", + "futures", + "lazy_static", + "log", + "num_cpus", + "slab", + "tokio-executor", +] + +[[package]] +name = "tokio-timer" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" +dependencies = [ + "crossbeam-utils", + "futures", + "slab", + "tokio-executor", +] + +[[package]] +name = "tokio-udp" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" +dependencies = [ + "bytes", + "futures", + "log", + "mio", + "tokio-codec", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "tokio-uds" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" +dependencies = [ + "bytes", + "futures", + "iovec", + "libc", + "log", + "mio", + "mio-uds", + "tokio-codec", + "tokio-io", + "tokio-reactor", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check 0.9.2", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "want" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" +dependencies = [ + "futures", + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[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-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[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-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] diff --git a/peach-oled/Cargo.toml b/peach-oled/Cargo.toml new file mode 100644 index 0000000..2a415d5 --- /dev/null +++ b/peach-oled/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "peach-oled" +version = "0.1.3" +authors = ["Andrew Reid "] +edition = "2018" +description = "Write and draw to OLED display using JSON-RPC over HTTP." +homepage = "https://opencollective.com/peachcloud" +repository = "https://github.com/peachcloud/peach-oled" +readme = "README.md" +license = "AGPL-3.0-only" +publish = false + +[package.metadata.deb] +depends = "$auto" +extended-description = """\ +peach-oled allows writing and drawing to a 128x64 pixel OLED display \ +with SDD1306 driver (I2C) using JSON-RPC over HTTP.""" +maintainer-scripts="debian" +systemd-units = { unit-name = "peach-oled" } +assets = [ + ["target/release/peach-oled", "usr/bin/", "755"], + ["README.md", "usr/share/doc/peach-oled/README", "644"], +] + +[badges] +travis-ci = { repository = "peachcloud/peach-oled", branch = "master" } +maintenance = { status = "actively-developed" } + +[dependencies] +jsonrpc-core = "11.0.0" +jsonrpc-http-server = "11.0.0" +jsonrpc-test = "11.0.0" +linux-embedded-hal = "0.2.2" +embedded-graphics = "0.4.7" +tinybmp = "0.1.0" +ssd1306 = "0.2.6" +serde = { version = "1.0.87", features = ["derive"] } +serde_json = "1.0.39" +log = "0.4.0" +env_logger = "0.6.1" +snafu = "0.4.1" +nix="0.11" diff --git a/peach-oled/README.md b/peach-oled/README.md new file mode 100644 index 0000000..9829aea --- /dev/null +++ b/peach-oled/README.md @@ -0,0 +1,165 @@ +# peach-oled + +[![Build Status](https://travis-ci.com/peachcloud/peach-oled.svg?branch=master)](https://travis-ci.com/peachcloud/peach-oled) ![Generic badge](https://img.shields.io/badge/version-0.1.3-.svg) + +OLED microservice module for PeachCloud. Write to a 128x64 OLED display with SDD1306 driver (I2C) using [JSON-RPC](https://www.jsonrpc.org/specification) over http. + +![Close-up, black-and-white photo of an Adafruit 128x64 1.3" OLED Bonnet. The circuit board features a 5-way joystick on the left side, two push-buttons on the right side (labelled #5 and #6), and a central OLED display. The display shows text reading: "PeachCloud" on the first line and "IP: 192.168.0.8" on the third line. A circle is displayed beneath the two lines of text and is horizontally-centered".](docs/images/peachcloud_oled.jpg) + +### JSON-RPC API + +| Method | Parameters | Description | +| --- | --- | --- | +| `clear` | | Clear the display buffer | +| `draw` | `bytes`, `width`, `height`, `x_coord`, `y_coord` | Draw graphic to display buffer for given byte array, dimensions and co-ordinates | +| `flush` | | Flush the display | +| `ping` | | Respond with `success` if microservice is running | +| `power` | `on` | Toggle the display (memory is retained while off) | +| `write` | `x_coord`, `y_coord`, `string`, `font_size` | Write message to display buffer for given co-ordinates using given font size | + +| Font Sizes | +| --- | +| `6x8` | +| `6x12` | +| `8x16` | +| `12x16` | + +### Environment + +The JSON-RPC HTTP server address and port can be configured with the `PEACH_OLED_SERVER` environment variable: + +`export PEACH_OLED_SERVER=127.0.0.1:5000` + +When not set, the value defaults to `127.0.0.1:5112`. + +Logging is made available with `env_logger`: + +`export RUST_LOG=info` + +Other logging levels include `debug`, `warn` and `error`. + +### Setup + +Clone this repo: + +`git clone https://github.com/peachcloud/peach-oled.git` + +Move into the repo and compile: + +`cd peach-oled` +`cargo build --release` + +Run the binary: + +`./target/release/peach-oled` + +### Debian Packaging + +A `systemd` service file and Debian maintainer scripts are included in the `debian` directory, allowing `peach-oled` to be easily bundled as a Debian package (`.deb`). The `cargo-deb` [crate](https://crates.io/crates/cargo-deb) can be used to achieve this. + +Install `cargo-deb`: + +`cargo install cargo-deb` + +Move into the repo: + +`cd peach-oled` + +Build the package: + +`cargo deb` + +The output will be written to `target/debian/peach-oled_0.1.0_arm64.deb` (or similar). + +Build the package (aarch64): + +`cargo deb --target aarch64-unknown-linux-gnu` + +Install the package as follows: + +`sudo dpkg -i target/debian/peach-oled_0.1.0_arm64.deb` + +The service will be automatically enabled and started. + +Uninstall the service: + +`sudo apt-get remove peach-oled` + +Remove configuration files (not removed with `apt-get remove`): + +`sudo apt-get purge peach-oled` + +### Example Usage + +**Write Text to the OLED Display** + +With microservice running, open a second terminal window and use `curl` to call server methods: + +`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "write", "params" : {"x_coord": 0, "y_coord": 0, "string": "Welcome to PeachCloud", "font_size": "6x8" }, "id":1 }' 127.0.0.1:5112` + +Server responds with: + +`{"jsonrpc":"2.0","result":success","id":1}` + +OLED will remain blank because no flush command has been issued. + +Write to the second line of the display: + +`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "write", "params" : {"x_coord": 0, "y_coord": 8, "string": "Born in cypherspace", "font_size": "6x12" }, "id":1 }' 127.0.0.1:5112` + +Flush the display: + +`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "flush", "id":1 }' 127.0.0.1:5112` + +OLED display shows: + +`Welcome to PeachCloud!` +`Born in cypherspace` + +Validation checks are performed for all three parameters: `x_coord`, `y_coord` and `string`. An appropriate error is returned if the validation checks are not satisfied: + +`{"jsonrpc":"2.0","error":{"code":1,"message":"Validation error: coordinate x out of range 0-128: 129."},"id":1}` + +`{"jsonrpc":"2.0","error":{"code":1,"message":"validation error","data":"y_coord not in range 0-57"},"id":1}` + +`{"jsonrpc":"2.0","error":{"code":1,"message":"Validation error: string length 47 out of range 0-21."},"id":1}` + +An error is returned if one or all of the expected parameters are not supplied: + +`{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid params: missing field `font_size`."},"id":1}` + +----- + +**Draw Graphic to the OLED Display** + +With microservice running, open a second terminal window and use `curl` to call server methods: + +`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "draw", "params" : {"bytes": [30, 0, 33, 0, 64, 128, 128, 64, 140, 64, 140, 64, 128, 64, 64, 128, 33, 0, 30, 0], "width": 10, "height": 10, "x_coord": 32, "y_coord": 32}, "id":1 }' 127.0.0.1:5112` + +Server responds with: + +`{"jsonrpc":"2.0","result":success","id":1}` + +OLED will remain blank because no flush command has been issued. + +Flush the display: + +`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "flush", "id":1 }' 127.0.0.1:5112` + +OLED display shows a 10x10 graphic of a dot inside a circle. + +No validation checks are currently performed on the parameters of the `draw` RPC, aside from type-checks when the parameters are parsed. + +----- + +**Clear the Display** + +`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "clear", "id":1 }' 127.0.0.1:5112` + +Server responds with: + +`{"jsonrpc":"2,0","result":"success","id":1}` + +### Licensing + +AGPL-3.0 diff --git a/peach-oled/debian/peach-oled.service b/peach-oled/debian/peach-oled.service new file mode 100644 index 0000000..4dff2d6 --- /dev/null +++ b/peach-oled/debian/peach-oled.service @@ -0,0 +1,27 @@ +[Unit] +Description=JSON-RPC microservice for writing and drawing to an OLED display over HTTP. + +[Service] +Type=simple +User=peach-oled +Group=i2c +Environment="RUST_LOG=error" +ExecStart=/usr/bin/peach-oled +Restart=always +CapabilityBoundingSet=~CAP_SYS_ADMIN CAP_SYS_PTRACE CAP_SYS_BOOT CAP_SYS_TIME CAP_KILL CAP_WAKE_ALARM CAP_LINUX_IMMUTABLE CAP_BLOCK_SUSPEND CAP_LEASE CAP_SYS_NICE CAP_SYS_RESOURCE CAP_RAWIO CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_* CAP_FOWNER CAP_IPC_OWNER CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_AUDIT_* +InaccessibleDirectories=/home +LockPersonality=yes +NoNewPrivileges=yes +PrivateTmp=yes +PrivateUsers=yes +ProtectControlGroups=yes +ProtectHome=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +ProtectSystem=yes +ReadOnlyDirectories=/var +RestrictAddressFamilies=~AF_INET6 AF_UNIX +SystemCallFilter=~@reboot @clock @debug @module @mount @swap @resources @privileged + +[Install] +WantedBy=multi-user.target diff --git a/peach-oled/docs/images/peachcloud_oled.jpg b/peach-oled/docs/images/peachcloud_oled.jpg new file mode 100644 index 0000000000000000000000000000000000000000..31055727ec10576c2821b332703062161c18fe02 GIT binary patch literal 21922 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%0Dm&FyuPi$U( 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 + +#[derive(Debug, Snafu)] +#[snafu(visibility(pub(crate)))] +pub enum OledError { + #[snafu(display("Failed to create interface for I2C device: {}", source))] + I2CError { + source: hal::i2cdev::linux::LinuxI2CError, + }, + + #[snafu(display("Coordinate {} out of range {}: {}", coord, range, value))] + InvalidCoordinate { + coord: String, + range: String, + value: i32, + }, + + // TODO: implement for validate() in src/lib.rs + #[snafu(display("Font size invalid: {}", font))] + InvalidFontSize { font: String }, + + #[snafu(display("String length out of range 0-21: {}", len))] + InvalidString { len: usize }, + + #[snafu(display("Missing expected parameter: {}", e))] + MissingParameter { e: Error }, + + #[snafu(display("Failed to parse parameter: {}", e))] + ParseError { e: Error }, +} + +impl From for Error { + fn from(err: OledError) -> Self { + match &err { + OledError::I2CError { source } => Error { + code: ErrorCode::ServerError(-32000), + message: format!("Failed to create interface for I2C device: {}", source), + data: None, + }, + OledError::InvalidCoordinate { + coord, + value, + range, + } => Error { + code: ErrorCode::ServerError(-32001), + message: format!( + "Validation error: coordinate {} out of range {}: {}", + coord, range, value + ), + data: None, + }, + OledError::InvalidFontSize { font } => Error { + code: ErrorCode::ServerError(-32002), + message: format!("Validation error: {} is not an accepted font size. Use 6x8, 6x12, 8x16 or 12x16 instead", font), + data: None, + }, + OledError::InvalidString { len } => Error { + code: ErrorCode::ServerError(-32003), + message: format!("Validation error: string length {} out of range 0-21", len), + data: None, + }, + OledError::MissingParameter { e } => e.clone(), + OledError::ParseError { e } => e.clone(), + } + } +} diff --git a/peach-oled/src/lib.rs b/peach-oled/src/lib.rs new file mode 100644 index 0000000..eabdd02 --- /dev/null +++ b/peach-oled/src/lib.rs @@ -0,0 +1,448 @@ +mod error; + +use std::{ + env, process, + result::Result, + sync::{Arc, Mutex}, +}; + +use embedded_graphics::coord::Coord; +use embedded_graphics::fonts::{Font12x16, Font6x12, Font6x8, Font8x16}; +use embedded_graphics::image::Image1BPP; +use embedded_graphics::prelude::*; +use hal::I2cdev; +use jsonrpc_core::{types::error::Error, IoHandler, Params, Value}; +use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder}; +#[allow(unused_imports)] +use jsonrpc_test as test; +use linux_embedded_hal as hal; +use log::{debug, error, info}; +use serde::Deserialize; +use snafu::{ensure, ResultExt}; +use ssd1306::prelude::*; +use ssd1306::Builder; + +use crate::error::{BoxError, I2CError, InvalidCoordinate, InvalidString, OledError}; + +//define the Graphic struct for receiving draw commands +#[derive(Debug, Deserialize)] +pub struct Graphic { + bytes: Vec, + width: u32, + height: u32, + x_coord: i32, + y_coord: i32, +} + +//define the Msg struct for receiving write commands +#[derive(Debug, Deserialize)] +pub struct Msg { + x_coord: i32, + y_coord: i32, + string: String, + font_size: String, +} + +//definte the On struct for receiving power on/off commands +#[derive(Debug, Deserialize)] +pub struct On { + on: bool, +} + +fn validate(m: &Msg) -> Result<(), OledError> { + ensure!( + m.string.len() <= 21, + InvalidString { + len: m.string.len() + } + ); + + ensure!( + m.x_coord >= 0, + InvalidCoordinate { + coord: "x".to_string(), + range: "0-128".to_string(), + value: m.x_coord, + } + ); + + ensure!( + m.x_coord < 129, + InvalidCoordinate { + coord: "x".to_string(), + range: "0-128".to_string(), + value: m.x_coord, + } + ); + + ensure!( + m.y_coord >= 0, + InvalidCoordinate { + coord: "y".to_string(), + range: "0-47".to_string(), + value: m.y_coord, + } + ); + + ensure!( + m.y_coord < 148, + InvalidCoordinate { + coord: "y".to_string(), + range: "0-47".to_string(), + value: m.y_coord, + } + ); + + Ok(()) +} + +pub fn run() -> Result<(), BoxError> { + info!("Starting up."); + + debug!("Creating interface for I2C device."); + let i2c = I2cdev::new("/dev/i2c-1").context(I2CError)?; + + let mut disp: GraphicsMode<_> = Builder::new().connect_i2c(i2c).into(); + + info!("Initializing the display."); + disp.init().unwrap_or_else(|_| { + error!("Problem initializing the OLED display."); + process::exit(1); + }); + + debug!("Flushing the display."); + disp.flush().unwrap_or_else(|_| { + error!("Problem flushing the OLED display."); + process::exit(1); + }); + + let oled = Arc::new(Mutex::new(disp)); + let oled_clone = Arc::clone(&oled); + + info!("Creating JSON-RPC I/O handler."); + let mut io = IoHandler::default(); + + io.add_method("clear", move |_| { + let mut oled = oled_clone.lock().unwrap(); + info!("Clearing the display."); + oled.clear(); + info!("Flushing the display."); + oled.flush().unwrap_or_else(|_| { + error!("Problem flushing the OLED display."); + process::exit(1); + }); + Ok(Value::String("success".into())) + }); + + let oled_clone = Arc::clone(&oled); + + io.add_method("draw", move |params: Params| { + let g: Result = params.parse(); + let g: Graphic = g?; + // TODO: add simple byte validation function + let mut oled = oled_clone.lock().unwrap(); + info!("Drawing image to the display."); + let im = + Image1BPP::new(&g.bytes, g.width, g.height).translate(Coord::new(g.x_coord, g.y_coord)); + oled.draw(im.into_iter()); + Ok(Value::String("success".into())) + }); + + let oled_clone = Arc::clone(&oled); + + io.add_method("flush", move |_| { + let mut oled = oled_clone.lock().unwrap(); + info!("Flushing the display."); + oled.flush().unwrap_or_else(|_| { + error!("Problem flushing the OLED display."); + process::exit(1); + }); + Ok(Value::String("success".into())) + }); + + let oled_clone = Arc::clone(&oled); + + io.add_method("ping", |_| Ok(Value::String("success".to_string()))); + + io.add_method("power", move |params: Params| { + let o: Result = params.parse(); + let o: On = o?; + let mut oled = oled_clone.lock().unwrap(); + if o.on { + info!("Turning the display on."); + } else { + info!("Turnin the display off."); + } + oled.display_on(o.on).unwrap_or_else(|_| { + error!("Problem turning the display on."); + process::exit(1); + }); + Ok(Value::String("success".into())) + }); + + let oled_clone = Arc::clone(&oled); + + io.add_method("write", move |params: Params| { + info!("Received a 'write' request."); + let m: Result = params.parse(); + let m: Msg = m?; + validate(&m)?; + + let mut oled = oled_clone.lock().unwrap(); + + info!("Writing to the display."); + if m.font_size == "6x8" { + oled.draw( + Font6x8::render_str(&m.string) + .translate(Coord::new(m.x_coord, m.y_coord)) + .into_iter(), + ); + } else if m.font_size == "6x12" { + oled.draw( + Font6x12::render_str(&m.string) + .translate(Coord::new(m.x_coord, m.y_coord)) + .into_iter(), + ); + } else if m.font_size == "8x16" { + oled.draw( + Font8x16::render_str(&m.string) + .translate(Coord::new(m.x_coord, m.y_coord)) + .into_iter(), + ); + } else if m.font_size == "12x16" { + oled.draw( + Font12x16::render_str(&m.string) + .translate(Coord::new(m.x_coord, m.y_coord)) + .into_iter(), + ); + } + + Ok(Value::String("success".into())) + }); + + let http_server = + env::var("PEACH_OLED_SERVER").unwrap_or_else(|_| "127.0.0.1:5112".to_string()); + + info!("Starting JSON-RPC server on {}.", http_server); + let server = ServerBuilder::new(io) + .cors(DomainsValidation::AllowOnly(vec![ + AccessControlAllowOrigin::Null, + ])) + .start_http( + &http_server + .parse() + .expect("Invalid HTTP address and port combination"), + ) + .expect("Unable to start RPC server"); + + info!("Listening for requests."); + server.wait(); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + use hal::i2cdev::linux::LinuxI2CError; + use jsonrpc_core::ErrorCode; + use nix::Error as NixError; + use std::io::Error as IoError; + use std::io::ErrorKind; + + // test to ensure correct success response + #[test] + fn rpc_success() { + let rpc = { + let mut io = IoHandler::new(); + io.add_method("rpc_success_response", |_| { + Ok(Value::String("success".into())) + }); + test::Rpc::from(io) + }; + + assert_eq!(rpc.request("rpc_success_response", &()), r#""success""#); + } + + // test to ensure correct internal error response + #[test] + fn rpc_internal_error() { + let rpc = { + let mut io = IoHandler::new(); + io.add_method("rpc_internal_error", |_| Err(Error::internal_error())); + test::Rpc::from(io) + }; + + assert_eq!( + rpc.request("rpc_internal_error", &()), + r#"{ + "code": -32603, + "message": "Internal error" +}"# + ); + } + + // test to ensure correct I2CError error response (io::Error variant) + #[test] + fn rpc_i2c_io_error() { + let rpc = { + let mut io = IoHandler::new(); + io.add_method("rpc_i2c_io_error", |_| { + let io_err = IoError::new(ErrorKind::PermissionDenied, "oh no!"); + let source = LinuxI2CError::Io(io_err); + Err(Error::from(OledError::I2CError { source })) + }); + test::Rpc::from(io) + }; + + assert_eq!( + rpc.request("rpc_i2c_io_error", &()), + r#"{ + "code": -32000, + "message": "I2C device error: oh no!" +}"# + ); + } + + // test to ensure correct I2CError error response (nix::Error variant) + #[test] + fn rpc_i2c_nix_error() { + let rpc = { + let mut io = IoHandler::new(); + io.add_method("rpc_i2c_nix_error", |_| { + let nix_err = NixError::InvalidPath; + let source = LinuxI2CError::Nix(nix_err); + Err(Error::from(OledError::I2CError { source })) + }); + test::Rpc::from(io) + }; + + assert_eq!( + rpc.request("rpc_i2c_nix_error", &()), + r#"{ + "code": -32000, + "message": "I2C device error: Invalid path" +}"# + ); + } + + // test to ensure correct InvalidCoordinate error response + #[test] + fn rpc_invalid_coord() { + let rpc = { + let mut io = IoHandler::new(); + io.add_method("rpc_invalid_coord", |_| { + Err(Error::from(OledError::InvalidCoordinate { + coord: "x".to_string(), + range: "0-128".to_string(), + value: 321, + })) + }); + test::Rpc::from(io) + }; + + assert_eq!( + rpc.request("rpc_invalid_coord", &()), + r#"{ + "code": -32001, + "message": "Validation error: coordinate x out of range 0-128: 321" +}"# + ); + } + + // test to ensure correct InvalidFontSize error response + #[test] + fn rpc_invalid_fontsize() { + let rpc = { + let mut io = IoHandler::new(); + io.add_method("rpc_invalid_fontsize", |_| { + Err(Error::from(OledError::InvalidFontSize { + font: "24x32".to_string(), + })) + }); + test::Rpc::from(io) + }; + + assert_eq!( + rpc.request("rpc_invalid_fontsize", &()), + r#"{ + "code": -32002, + "message": "Validation error: 24x32 is not an accepted font size. Use 6x8, 6x12, 8x16 or 12x16 instead" +}"# + ); + } + + // test to ensure correct InvalidString error response + #[test] + fn rpc_invalid_string() { + let rpc = { + let mut io = IoHandler::new(); + io.add_method("rpc_invalid_string", |_| { + Err(Error::from(OledError::InvalidString { len: 22 })) + }); + test::Rpc::from(io) + }; + + assert_eq!( + rpc.request("rpc_invalid_string", &()), + r#"{ + "code": -32003, + "message": "Validation error: string length 22 out of range 0-21" +}"# + ); + } + + // test to ensure correct invalid parameters error response + #[test] + fn rpc_invalid_params() { + let rpc = { + let mut io = IoHandler::new(); + io.add_method("rpc_invalid_params", |_| { + let e = Error { + code: ErrorCode::InvalidParams, + message: String::from("invalid params"), + data: Some(Value::String( + "Invalid params: invalid type: null, expected struct Msg.".into(), + )), + }; + Err(Error::from(OledError::MissingParameter { e })) + }); + test::Rpc::from(io) + }; + + assert_eq!( + rpc.request("rpc_invalid_params", &()), + r#"{ + "code": -32602, + "message": "invalid params", + "data": "Invalid params: invalid type: null, expected struct Msg." +}"# + ); + } + + // test to ensure correct parse error response + #[test] + fn rpc_parse_error() { + let rpc = { + let mut io = IoHandler::new(); + io.add_method("rpc_parse_error", |_| { + let e = Error { + code: ErrorCode::ParseError, + message: String::from("Parse error"), + data: None, + }; + Err(Error::from(OledError::ParseError { e })) + }); + test::Rpc::from(io) + }; + + assert_eq!( + rpc.request("rpc_parse_error", &()), + r#"{ + "code": -32700, + "message": "Parse error" +}"# + ); + } +} diff --git a/peach-oled/src/main.rs b/peach-oled/src/main.rs new file mode 100644 index 0000000..041d693 --- /dev/null +++ b/peach-oled/src/main.rs @@ -0,0 +1,14 @@ +use std::process; + +use log::error; + +fn main() { + // initialize the logger + env_logger::init(); + + // handle errors returned from `run` + if let Err(e) = peach_oled::run() { + error!("Application error: {}", e); + process::exit(1); + } +}