commit 5341a012029261791fbb096665a09fcd22bd6041 Author: Jan-Henrik Bruhn Date: Thu Aug 26 12:26:40 2021 +0200 Add first working implementation diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..01edddb --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1369 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "async-trait" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +dependencies = [ + "proc-macro2 1.0.28", + "quote 1.0.9", + "syn 1.0.75", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "bluez-async" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ebad2b0d80a77a8ce06890024f6eff028f6a5ce0021564d0b71aaa13ce617a" +dependencies = [ + "async-trait", + "bitflags", + "bluez-generated", + "dbus", + "dbus-tokio", + "futures", + "itertools", + "log", + "serde", + "serde-xml-rs", + "serde_derive", + "thiserror", + "tokio", + "uuid", +] + +[[package]] +name = "bluez-generated" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ad8f302dd79411881cd0181f3bd9fc91a959b71c3a13159bd8a07d2c40dc7f" +dependencies = [ + "dbus", +] + +[[package]] +name = "btleplug" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d3bcb8bf1febd9a8628dade48f50cde0de915a966edc353a8cc43569dc99b5" +dependencies = [ + "async-trait", + "bitflags", + "bluez-async", + "cocoa", + "dashmap", + "dbus", + "displaydoc", + "futures", + "libc", + "log", + "objc", + "parking_lot", + "static_assertions", + "thiserror", + "tokio", + "uuid", + "windows", +] + +[[package]] +name = "bytemuck" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "catprint" +version = "0.1.0" +dependencies = [ + "btleplug", + "clap 3.0.0-beta.4", + "crc", + "dither", + "futures", + "image 0.23.14", + "tokio", + "uuid", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim 0.8.0", + "textwrap 0.11.0", + "unicode-width", + "vec_map", +] + +[[package]] +name = "clap" +version = "3.0.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcd70aa5597dbc42f7217a543f9ef2768b2ef823ba29036072d30e1d88e98406" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim 0.10.0", + "termcolor", + "textwrap 0.14.2", + "vec_map", +] + +[[package]] +name = "clap_derive" +version = "3.0.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2 1.0.28", + "quote 1.0.9", + "syn 1.0.75", +] + +[[package]] +name = "cocoa" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "const-sha1" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb58b6451e8c2a812ad979ed1d83378caa5e927eef2622017a45f251457c2c9d" + +[[package]] +name = "core-foundation" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" + +[[package]] +name = "core-graphics" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + +[[package]] +name = "crc" +version = "2.0.1-alpha.0" +source = "git+ssh://git@github.com/mrhooray/crc-rs.git#747901f88620e360ced1c70eaec02383d0f36fe0" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if", + "num_cpus", +] + +[[package]] +name = "dbus" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8862bb50aa3b2a2db5bfd2c875c73b3038aa931c411087e335ca8ca0ed430b9" +dependencies = [ + "futures-channel", + "futures-util", + "libc", + "libdbus-sys", + "winapi", +] + +[[package]] +name = "dbus-tokio" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf8ad870c4824f71f40fd16776b6ee841c89703d6c9d1608c547a2c8c3ffda" +dependencies = [ + "dbus", + "libc", + "tokio", +] + +[[package]] +name = "deflate" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4" +dependencies = [ + "adler32", + "byteorder", +] + +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + +[[package]] +name = "displaydoc" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" +dependencies = [ + "proc-macro2 1.0.28", + "quote 1.0.9", + "syn 1.0.75", +] + +[[package]] +name = "dither" +version = "1.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd42fd127073b37197721177d196d5652f2854dac010a71975bcf89cda1720d" +dependencies = [ + "image 0.21.3", + "structopt", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "futures" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" + +[[package]] +name = "futures-executor" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" + +[[package]] +name = "futures-macro" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57" +dependencies = [ + "autocfg", + "proc-macro-hack", + "proc-macro2 1.0.28", + "quote 1.0.9", + "syn 1.0.75", +] + +[[package]] +name = "futures-sink" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53" + +[[package]] +name = "futures-task" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" + +[[package]] +name = "futures-util" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" +dependencies = [ + "autocfg", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "gif" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471d90201b3b223f3451cd4ad53e34295f16a1df17b1edf3736d47761c3981af" +dependencies = [ + "color_quant", + "lzw", +] + +[[package]] +name = "gif" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a668f699973d0f573d15749b7002a9ac9e1f9c6b220e7b165601334c173d8de" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "image" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35371e467cd7b0b3d1d6013d619203658467df12d61b0ca43cd67b743b1965eb" +dependencies = [ + "byteorder", + "gif 0.10.3", + "jpeg-decoder", + "lzw", + "num-iter", + "num-rational 0.2.4", + "num-traits", + "png 0.14.1", + "scoped_threadpool", + "tiff 0.2.2", +] + +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "gif 0.11.2", + "jpeg-decoder", + "num-iter", + "num-rational 0.3.2", + "num-traits", + "png 0.16.8", + "scoped_threadpool", + "tiff 0.6.1", +] + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "inflate" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" +dependencies = [ + "adler32", +] + +[[package]] +name = "instant" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + +[[package]] +name = "jpeg-decoder" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" +dependencies = [ + "rayon", +] + +[[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.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5" + +[[package]] +name = "libdbus-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "lock_api" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lzw" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "mio" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-derive" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[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 = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "os_str_bytes" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d" + +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "png" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63daf481fdd0defa2d1d2be15c674fbfa1b0fd71882c303a91f9a79b3252c359" +dependencies = [ + "bitflags", + "deflate 0.7.20", + "inflate", + "num-iter", +] + +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate 0.8.6", + "miniz_oxide 0.3.7", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.28", + "quote 1.0.9", + "syn 1.0.75", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2 1.0.28", + "quote 1.0.9", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + +[[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.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +dependencies = [ + "unicode-xid 0.2.2", +] + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2 1.0.28", +] + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1" + +[[package]] +name = "serde-xml-rs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0bf1ba0696ccf0872866277143ff1fd14d22eec235d2b23702f95e6660f7dfa" +dependencies = [ + "log", + "serde", + "thiserror", + "xml-rs", +] + +[[package]] +name = "serde_derive" +version = "1.0.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57ae87ad533d9a56427558b516d0adac283614e347abf85b0dc0cbbf0a249f3" +dependencies = [ + "proc-macro2 1.0.28", + "quote 1.0.9", + "syn 1.0.75", +] + +[[package]] +name = "slab" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "structopt" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7" +dependencies = [ + "clap 2.33.3", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107" +dependencies = [ + "heck", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[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.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" +dependencies = [ + "proc-macro2 1.0.28", + "quote 1.0.9", + "unicode-xid 0.2.2", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +dependencies = [ + "proc-macro2 1.0.28", + "quote 1.0.9", + "syn 1.0.75", +] + +[[package]] +name = "tiff" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4834f28a0330cb9f3f2c87d2649dca723cb33802e2bdcf18da32759fbec7ce" +dependencies = [ + "byteorder", + "lzw", + "num-derive", + "num-traits", +] + +[[package]] +name = "tiff" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" +dependencies = [ + "jpeg-decoder", + "miniz_oxide 0.4.4", + "weezl", +] + +[[package]] +name = "tokio" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92036be488bb6594459f2e03b60e42df6f937fe6ca5c5ffdcb539c6b84dc40f5" +dependencies = [ + "autocfg", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" +dependencies = [ + "proc-macro2 1.0.28", + "quote 1.0.9", + "syn 1.0.75", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "weezl" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[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 = "windows" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68088239696c06152844eadc03d262f088932cce50c67e4ace86e19d95e976fe" +dependencies = [ + "const-sha1", + "windows_gen", + "windows_macros", +] + +[[package]] +name = "windows_gen" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf583322dc423ee021035b358e535015f7fd163058a31e2d37b99a939141121d" + +[[package]] +name = "windows_macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58acfb8832e9f707f8997bd161e537a1c1f603e60a5bd9c3cf53484fdcc998f3" +dependencies = [ + "syn 1.0.75", + "windows_gen", +] + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..6435684 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "catprint" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +btleplug = "0.8" +uuid = "0.8" +futures = "0.3" +tokio = {version = "1.10", features = ["rt", "macros", "rt-multi-thread"] } +crc = { git = "ssh://git@github.com/mrhooray/crc-rs.git" } +dither = "=1.3.7" # last version without nightly requirement +image = "0.23" +clap = "3.0.0-beta.4" diff --git a/src/bin/catprint.rs b/src/bin/catprint.rs new file mode 100644 index 0000000..6f1c96f --- /dev/null +++ b/src/bin/catprint.rs @@ -0,0 +1,121 @@ +use btleplug::platform::Manager; +use catprint::*; +use std::error::Error; + +use clap::{crate_authors, crate_version, AppSettings, ArgEnum, Clap}; + +#[derive(Clap)] +#[clap(version = crate_version!(), author = crate_authors!())] +#[clap(setting = AppSettings::ColoredHelp)] +struct Opts { + /// Set the device name of your printer. + #[clap(short, long, default_value = "GB02")] + device_name: String, + #[clap(subcommand)] + subcmd: SubCommand, +} + +#[derive(Clap)] +enum SubCommand { + /// Move the paper without printing + Feed(Feed), + + /// Print an image + Print(Print), +} + +#[derive(Clap)] +struct Feed { + /// Print debug info + #[clap(short, long)] + backward: bool, + /// amount to feed the paper + length: u8, +} + +#[derive(Clap)] +struct Print { + /// The image you want to print out + input_image: String, + + /// The ditherer supposed to be used. none is good for text and vector graphics + #[clap(arg_enum, short, long, default_value = "k-mean")] + ditherer: Ditherers, +} + +#[derive(ArgEnum)] +enum Ditherers { + None, + KMean, + Atkinson, + Burkes, + FloydSteinberg, + JarvisJudiceNinke, + Sierra3, + Stucki, +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let opts: Opts = Opts::parse(); + + let mut manager = Manager::new().await?; + + let device = device::Device::find(&mut manager, &opts.device_name).await?; + + match opts.subcmd { + SubCommand::Feed(feed) => main_feed(device, feed).await, + SubCommand::Print(print) => main_print(device, print).await, + } +} + +async fn main_feed(mut device: device::Device, feed: Feed) -> Result<(), Box> { + let feed_direction = if feed.backward { + protocol::FeedDirection::Reverse + } else { + protocol::FeedDirection::Forward + }; + + device.queue_command(protocol::Command::Feed(feed_direction, feed.length)); + + device.flush().await +} + +async fn main_print(mut device: device::Device, print: Print) -> Result<(), Box> { + device.queue_command(protocol::Command::Feed( + protocol::FeedDirection::Forward, + 10, + )); + + let image = image::Image::load(&std::path::PathBuf::from(print.input_image)).unwrap(); + + let image = match print.ditherer { + Ditherers::None => image, + Ditherers::KMean => image.kmean(), + Ditherers::Atkinson => image.dither(&dither::ditherer::ATKINSON), + Ditherers::Burkes => image.dither(&dither::ditherer::BURKES), + Ditherers::FloydSteinberg => image.dither(&dither::ditherer::FLOYD_STEINBERG), + Ditherers::JarvisJudiceNinke => image.dither(&dither::ditherer::JARVIS_JUDICE_NINKE), + Ditherers::Sierra3 => image.dither(&dither::ditherer::SIERRA_3), + Ditherers::Stucki => image.dither(&dither::ditherer::STUCKI), + }; + + let quality = protocol::Quality::Quality3; + let energy = 12000; + let mode = match print.ditherer { + Ditherers::None | Ditherers::KMean => protocol::DrawingMode::Text, + _ => protocol::DrawingMode::Image, + }; + + let print = image.print(mode, quality, energy); + + device.queue_commands(&print); + device.queue_command(protocol::Command::Feed( + protocol::FeedDirection::Forward, + 150, + )); + + device.flush().await?; + + Ok(()) +} diff --git a/src/device.rs b/src/device.rs new file mode 100644 index 0000000..f85cd52 --- /dev/null +++ b/src/device.rs @@ -0,0 +1,112 @@ +use btleplug::api::{Central, Manager as _, Peripheral}; +use btleplug::platform::Manager; +use std::collections::VecDeque; +use std::error::Error; +use std::time::Duration; +use tokio::time; +use uuid::Uuid; + +const TX_CHARACTERISTIC_UUID: Uuid = Uuid::from_u128(0x0000ae01_0000_1000_8000_00805f9b34fb); + +#[derive(Debug)] +pub struct Device { + peripheral: btleplug::platform::Peripheral, + tx_buffer: VecDeque, +} + +impl Device { + pub async fn find(manager: &mut Manager, name: &str) -> Result> { + let mut device_result = Err("Could not connect to device".into()); + let adapter_list = manager.adapters().await?; + if adapter_list.is_empty() { + device_result = Err("No Bluetooth adapters found".into()); + } + + for adapter in adapter_list.iter() { + println!("Starting scan..."); + adapter + .start_scan() + .await + .expect("Can't scan BLE adapter for connected devices..."); + time::sleep(Duration::from_secs(2)).await; + + let peripherals = adapter.peripherals().await?; + for peripheral in peripherals { + let properties = peripheral.properties().await?; + + if let Some(properties) = properties { + if let Some(local_name) = properties.local_name { + if local_name.contains(name) { + if !peripheral.is_connected().await? { + peripheral.connect().await?; + } + let _ = peripheral.discover_characteristics().await?; + device_result = Ok(Device { + peripheral, + tx_buffer: VecDeque::new(), + }); + break; + } + } + } + } + } + + device_result + } + + pub fn queue_command(&mut self, command: crate::protocol::Command) { + self.tx_buffer.extend(&command.to_bytes()) + } + + pub fn queue_commands(&mut self, commands: &[crate::protocol::Command]) { + for command in commands { + self.queue_command(*command) + } + } + + pub async fn flush(&mut self) -> Result<(), Box> { + const MTU_SIZE: usize = 20; + + while !self.tx_buffer.is_empty() { + let mut buf = Vec::with_capacity(MTU_SIZE); + for _ in 0..MTU_SIZE { + if let Some(byte) = self.tx_buffer.pop_front() { + buf.push(byte); + } else { + break; + } + + // this could be nicer i guess + } + + self.tx(&buf).await?; + } + + Ok(()) + } + + async fn tx(&mut self, data: &[u8]) -> Result<(), Box> { + let characteristics = self.peripheral.characteristics(); + + let tx_characteristic = characteristics + .iter() + .filter(|c| c.uuid == TX_CHARACTERISTIC_UUID) + .next() + .unwrap(); + + self.peripheral + .write( + &tx_characteristic, + data, + btleplug::api::WriteType::WithoutResponse, + ) + .await?; + + Ok(()) + } + + pub async fn destroy(self) { + self.peripheral.disconnect().await.unwrap(); + } +} diff --git a/src/image.rs b/src/image.rs new file mode 100644 index 0000000..980fa59 --- /dev/null +++ b/src/image.rs @@ -0,0 +1,130 @@ +use crate::protocol::*; +use dither::prelude::*; +use std::path::Path; + +pub struct Image { + image: Img, + mean: f64, +} + +fn rle_bytes(val: u8, mut counter: u32) -> Vec { + let mut compressed = vec![]; + if counter > 0 { + while counter > 127 { + let code = (val << 7) | 127; + compressed.push(code); + counter -= 127; + } + let code = (val << 7) | (counter as u8); + compressed.push(code); + } + compressed +} + +impl Image { + pub fn load(path: &Path) -> std::result::Result> { + let image = image::open(path)?; + + let image = image + .resize( + crate::protocol::PIXELS_PER_LINE as u32, + !0_u32, + image::imageops::FilterType::CatmullRom, + ) + .into_rgb8(); + + let image: Img> = unsafe { + Img::from_raw_buf( + image.pixels().map(|p| RGB::from(p.0)).collect(), + image.width(), + ) + }; + + let image: Img> = image.convert_with(|rgb| rgb.convert_with(f64::from)); + + let image = image.convert_with(|rgb| rgb.to_chroma_corrected_black_and_white()); + Ok(Self { image, mean: 0.5 }) + } + + pub fn kmean(self) -> Self { + let mean = self.image.iter().sum::() / self.image.len() as f64; + Self { + image: self.image, + mean, + } + } + + pub fn dither(self, ditherer: &Ditherer) -> Self { + let image = ditherer.dither(self.image, dither::create_quantize_n_bits_func(1).unwrap()); + Self { image, mean: 0.5 } + } + + /// Returns a line, bool is true if compressed, false if uncompressed + pub fn line( + &self, + y: u32, + ) -> Option<(bool, usize, [u8; crate::protocol::PIXELS_PER_LINE / 8])> { + if y > self.image.height() { + None + } else { + let mut compressed = Vec::::new(); + + let mut counter = 0_u32; + let mut last_val = 2; + for x in 0..crate::protocol::PIXELS_PER_LINE { + let x = x as u32; + let pixel = self.image.get((x, y)).unwrap(); + let val = if pixel > &self.mean { 0 } else { 1 }; + if val == last_val { + counter = counter + 1 + } else if counter > 0 { + compressed.extend(rle_bytes(last_val, counter)); + counter = 1; + } + last_val = val; + } + compressed.extend(rle_bytes(last_val, counter)); + + if compressed.len() > crate::protocol::PIXELS_PER_LINE / 8 { + let mut data = [0_u8; crate::protocol::PIXELS_PER_LINE / 8]; + for x in 0..crate::protocol::PIXELS_PER_LINE { + let x = x as u32; + let pixel = self.image.get((x, y)).unwrap(); + let val = if pixel > &self.mean { 0 } else { 1 }; + let i = (x / 8) as usize; + let j = x % 8; + let current = data[i]; + data[i] = current | (val << j); + } + + Some((false, crate::protocol::PIXELS_PER_LINE / 8, data)) + } else { + use std::convert::TryInto; + let len = compressed.len(); + compressed.resize(crate::protocol::PIXELS_PER_LINE / 8, 0); + Some((true, len, compressed.try_into().unwrap())) + } + } + } + + pub fn line_count(&self) -> u32 { + self.image.height() + } + + pub fn print(&self, mode: DrawingMode, quality: Quality, energy: u16) -> Vec { + let mut commands = vec![ + Command::SetQuality(quality), + Command::SetEnergy(energy), + Command::SetDrawingMode(mode), + ]; + + commands.push(Command::MagicLattice(LatticeType::Start)); + for y in 0..self.line_count() { + let (compressed, len, pixels) = self.line(y).unwrap(); + commands.push(Command::Print(compressed, len, pixels)); + } + commands.push(Command::MagicLattice(LatticeType::End)); + + commands + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..81df996 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +pub mod device; +pub mod image; +pub mod protocol; diff --git a/src/protocol.rs b/src/protocol.rs new file mode 100644 index 0000000..d6435b8 --- /dev/null +++ b/src/protocol.rs @@ -0,0 +1,129 @@ +pub const PIXELS_PER_LINE: usize = 384; +const CCITT: crc::Crc = crc::Crc::::new(&crc::CRC_8_SMBUS); + +#[derive(Clone, Copy, Debug)] +pub enum Command { + Feed(FeedDirection, u8), + Print(bool, usize, [u8; PIXELS_PER_LINE / 8]), // One bit per pixel in uncompressed mode + GetDeviceStatus, + SetQuality(Quality), + MagicLattice(LatticeType), + GetDeviceInfo, + UpdateDevice, //??? + SetWifi, //???? + FlowControl(Flow), + SetEnergy(u16), + DeviceId(u8), //???? + SetSpeed(u8), + SetDrawingMode(DrawingMode), +} + +#[derive(Clone, Copy, Debug)] +pub enum Flow { + Start = 0x00, + Stop = 0x10, +} + +#[derive(Clone, Copy, Debug)] +pub enum LatticeType { + Start, + End, +} + +#[derive(Clone, Copy, Debug)] +pub enum FeedDirection { + Forward, + Reverse, +} + +#[derive(Clone, Copy, Debug)] +pub enum DrawingMode { + Image = 0x0, + Text = 0x1, +} + +#[derive(Clone, Copy, Debug)] +pub enum Quality { + Quality1 = 0x31, + Quality2 = 0x32, + Quality3 = 0x33, + Quality4 = 0x34, + Quality5 = 0x35, + SpeedThin = 0x22, + SpeedModeration = 0x23, + SpeedThick = 0x25, +} + +impl Command { + fn opcode(&self) -> u8 { + use Command::*; + match self { + Feed(FeedDirection::Reverse, _) => 0xA0, + Feed(FeedDirection::Forward, _) => 0xA1, + Print(false, _, _) => 0xA2, // uncompressed + GetDeviceStatus => 0xA3, + SetQuality(_) => 0xA4, + MagicLattice(_) => 0xA6, + GetDeviceInfo => 0xA8, + UpdateDevice => 0xA9, + SetWifi => 0xAA, + FlowControl(_) => 0xAE, + SetEnergy(_) => 0xAF, + DeviceId(_) => 0xBB, + SetSpeed(_) => 0xBD, + SetDrawingMode(_) => 0xBE, + Print(true, _, _) => 0xBf, // compressed + } + } + + fn payload(&self) -> Vec { + use Command::*; + match self { + Feed(_, len) => vec![*len, 0], + Print(_, len, data) => data[0..*len].to_vec(), + GetDeviceStatus => vec![0], + SetQuality(quality) => vec![*quality as u8], + MagicLattice(LatticeType::Start) => vec![ + 0xAA, 0x55, 0x17, 0x38, 0x44, 0x5F, 0x5F, 0x5F, 0x44, 0x38, 0x2C, + ], + MagicLattice(LatticeType::End) => vec![ + 0xAA, 0x55, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, + ], + GetDeviceInfo => vec![0], + UpdateDevice => vec![0], // ???? + FlowControl(flow) => vec![*flow as u8], + SetEnergy(energy) => vec![(energy & 0xFF) as u8, ((energy >> 8) & 0xFF) as u8], + DeviceId(id) => vec![*id], // ????? + SetSpeed(speed) => vec![*speed], + SetDrawingMode(mode) => vec![*mode as u8], + + _ => vec![], + } + } + + pub fn to_bytes(&self) -> Vec { + let opcode = self.opcode(); + let payload = self.payload(); + + let mut crc = CCITT.digest(); + crc.update(&payload); + let crc = crc.finalize() as u8; + + let payload_len = payload.len(); + + let mut bytes = vec![ + 0x51, + 0x78, + opcode, + 0x00, /* Sent by host */ + payload_len as u8, + 0x00, + ]; + + bytes.extend(payload); + + bytes.extend(vec![crc, 0xFF]); + + bytes + } +}