v3 first commit

This commit is contained in:
guangzong chen 2022-06-08 13:51:34 -04:00
parent 10e6c3be04
commit f7941a4a5b
No known key found for this signature in database
GPG Key ID: E7F2158184087A5A
17 changed files with 541 additions and 1958 deletions

View File

@ -1,2 +0,0 @@
[build]
target = "x86_64-pc-windows-gnu"

27
CMakeLists.txt Executable file
View File

@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.21)
project(untitled)
set(CMAKE_PREFIX_PATH "C:\\Programs\\Qt\\6.2.4\\msvc2019_64")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
#OPTION(USE ntddmodm ON)
find_package(Qt6 COMPONENTS
Core
Gui
Widgets
SerialPort
Charts
REQUIRED)
add_executable(untitled main.cpp main_window.cpp main_window.h)
#add_executable(untitled WIN32 main.cpp main_window.cpp main_window.h)
target_link_libraries(untitled
Qt::Core
Qt::Gui
Qt::Widgets
Qt::Charts
Qt6::SerialPort
)

817
Cargo.lock generated
View File

@ -1,817 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "CoreFoundation-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0e9889e6db118d49d88d84728d0e964d973a5680befb5f85f55141beea5c20b"
dependencies = [
"libc",
"mach 0.1.2",
]
[[package]]
name = "IOKit-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99696c398cbaf669d2368076bdb3d627fb0ce51a26899d7c61228c5c0af3bf4a"
dependencies = [
"CoreFoundation-sys",
"libc",
"mach 0.1.2",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
[[package]]
name = "atk"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a83b21d2aa75e464db56225e1bda2dd5993311ba1095acaa8fa03d1ae67026ba"
dependencies = [
"atk-sys",
"bitflags",
"glib",
"libc",
]
[[package]]
name = "atk-sys"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "badcf670157c84bb8b1cf6b5f70b650fed78da2033c9eed84c4e49b11cbe83ea"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[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 = "cairo-rs"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9164355c892b026d6257e696dde5f3cb39beb3718297f0f161b562fe2ee3ab86"
dependencies = [
"bitflags",
"cairo-sys-rs",
"glib",
"libc",
"thiserror",
]
[[package]]
name = "cairo-sys-rs"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7c9c3928781e8a017ece15eace05230f04b647457d170d2d9641c94a444ff80"
dependencies = [
"glib-sys",
"libc",
"system-deps",
]
[[package]]
name = "cc"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
[[package]]
name = "cfg-expr"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b412e83326147c2bb881f8b40edfbf9905b9b8abaebd0e47ca190ba62fda8f0e"
dependencies = [
"smallvec",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "closure"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6173fd61b610d15a7566dd7b7620775627441c4ab9dac8906e17cb93a24b782"
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "field-offset"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92"
dependencies = [
"memoffset",
"rustc_version",
]
[[package]]
name = "futures-channel"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
[[package]]
name = "futures-executor"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377"
[[package]]
name = "futures-task"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
[[package]]
name = "futures-util"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
dependencies = [
"autocfg",
"futures-core",
"futures-task",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "gdk"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a453eae5ec10345b3a96ca1b547328bfc94edd40aa95b08f14bb4c35863db140"
dependencies = [
"bitflags",
"cairo-rs",
"gdk-pixbuf",
"gdk-sys",
"gio",
"glib",
"libc",
"pango",
]
[[package]]
name = "gdk-pixbuf"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534192cb8f01daeb8fab2c8d4baa8f9aae5b7a39130525779f5c2608e235b10f"
dependencies = [
"gdk-pixbuf-sys",
"gio",
"glib",
"libc",
]
[[package]]
name = "gdk-pixbuf-sys"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f097c0704201fbc8f69c1762dc58c6947c8bb188b8ed0bc7e65259f1894fe590"
dependencies = [
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "gdk-sys"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e091b3d3d6696949ac3b3fb3c62090e5bfd7bd6850bef5c3c5ea701de1b1f1e"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"pkg-config",
"system-deps",
]
[[package]]
name = "gio"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a29d8062af72045518271a2cd98b4e1617ce43f5b4223ad0fb9a0eff8f718c"
dependencies = [
"bitflags",
"futures-channel",
"futures-core",
"futures-io",
"gio-sys",
"glib",
"libc",
"once_cell",
"thiserror",
]
[[package]]
name = "gio-sys"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
"winapi",
]
[[package]]
name = "glib"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a930b7208e6e0ab839eea5f65ac2b82109f729621430d47fe905e2e09d33f4"
dependencies = [
"bitflags",
"futures-channel",
"futures-core",
"futures-executor",
"futures-task",
"glib-macros",
"glib-sys",
"gobject-sys",
"libc",
"once_cell",
"smallvec",
]
[[package]]
name = "glib-macros"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2aad66361f66796bfc73f530c51ef123970eb895ffba991a234fcf7bea89e518"
dependencies = [
"anyhow",
"heck",
"proc-macro-crate",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "glib-sys"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae"
dependencies = [
"libc",
"system-deps",
]
[[package]]
name = "gobject-sys"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5"
dependencies = [
"glib-sys",
"libc",
"system-deps",
]
[[package]]
name = "gtk"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6603bb79ded6ac6f3bac203794383afa8b1d6a8656d34a93a88f0b22826cd46c"
dependencies = [
"atk",
"bitflags",
"cairo-rs",
"field-offset",
"futures-channel",
"gdk",
"gdk-pixbuf",
"gio",
"glib",
"gtk-sys",
"gtk3-macros",
"libc",
"once_cell",
"pango",
"pkg-config",
]
[[package]]
name = "gtk-sys"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c14c8d3da0545785a7c5a120345b3abb534010fb8ae0f2ef3f47c027fba303e"
dependencies = [
"atk-sys",
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gdk-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]]
name = "gtk3-macros"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21de1da96dc117443fb03c2e270b2d34b7de98d0a79a19bbb689476173745b79"
dependencies = [
"anyhow",
"heck",
"proc-macro-crate",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "itertools"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
[[package]]
name = "libudev"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"
dependencies = [
"libc",
"libudev-sys",
]
[[package]]
name = "libudev-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
dependencies = [
"libc",
"pkg-config",
]
[[package]]
name = "mach"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9"
dependencies = [
"libc",
]
[[package]]
name = "mach"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
dependencies = [
"libc",
]
[[package]]
name = "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 = "nix"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0eaf8df8bab402257e0a5c17a254e4cc1f72a93588a1ddfb5d356c801aa7cb"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
"void",
]
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "pango"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1fc88307d9797976ea62722ff2ec5de3fae279c6e20100ed3f49ca1a4bf3f96"
dependencies = [
"bitflags",
"glib",
"libc",
"once_cell",
"pango-sys",
]
[[package]]
name = "pango-sys"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2367099ca5e761546ba1d501955079f097caa186bb53ce0f718dca99ac1942fe"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[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.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb"
[[package]]
name = "proc-macro-crate"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83"
dependencies = [
"thiserror",
"toml",
]
[[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",
"quote",
"syn",
"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",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rustc_version"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
dependencies = [
"semver",
]
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
[[package]]
name = "serde"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
[[package]]
name = "serial_communication_tool_v2"
version = "0.1.0"
dependencies = [
"closure",
"gio",
"glib",
"gtk",
"serialport",
]
[[package]]
name = "serialport"
version = "4.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d8cd7c0f22290ee2c01457009fa6fc1cae4153d5608a924e5dc423babc2c655"
dependencies = [
"CoreFoundation-sys",
"IOKit-sys",
"bitflags",
"cfg-if",
"libudev",
"mach 0.2.3",
"nix",
"regex",
"winapi",
]
[[package]]
name = "slab"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590"
[[package]]
name = "smallvec"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "strum"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2"
[[package]]
name = "strum_macros"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "system-deps"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6"
dependencies = [
"anyhow",
"cfg-expr",
"heck",
"itertools",
"pkg-config",
"strum",
"strum_macros",
"thiserror",
"toml",
"version-compare",
]
[[package]]
name = "thiserror"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version-compare"
version = "0.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -1,31 +0,0 @@
cargo-features=["strip"]
[package]
name = "serial_communication_tool_v2"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
gtk = "0.14.1"
gio = "0.14.6"
glib = "0.14.5"
#pretty-hex = "0.2.1"
#gtk4 = {git = "https://github.com/gtk-rs/gtk4-rs/"}
#gtk4 = "0.3.0"
#gio4_sys ="0."
#gtk4_sys = "0.3.0"
#gtk4-sys = "0.3.0"
serialport = "4.0.1"
closure = "0.3.0"
[profile.release]
opt-level = 'z'
lto = true
codegen-units = 1
panic = 'abort'
strip = "debuginfo"
#[[bin]]
#name = "win_serial_comm_tool"
#target = "x86_64-pc-windows-gnu"
#path = "src/main.rs"

View File

@ -1,62 +0,0 @@
# Serial Port tool
This is a serial tool for Linux and windows.
I am a embedded sorfware developer. USART is a very common communication protocal for communication and debug. I was using Moserial Terminal and Cutecom. But I found serveral problem in these tool. So I design this tool to help embedded software developer. This tool still work in progross. The function of this tool is limited for now.
The main thing in this tool is realiable. Tool will not crash, and get correct data from serial port. Display these data correctly and completance.
## Install
Windows
1. Install [gtk3 runtime environment](https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases/download/2021-04-29/gtk3-runtime-3.24.29-2021-04-29-ts-win64.exe)
2. Download executable file from release page.
3. Run executable file
Linux
1. Install gtk3
2. Download executable file from release page.
3. Run executable file
## Usage
This tool support following commands. `list`, `open`, `close`, `send`, `loop`, `loopend`, `clean`, `show`, `hide`, `set`.
1. `list`: List all avaliable port in log window
2. `open <port_name>`: Open port.
3. `close`: Close port.
4. `send <data>`: Send _data_ to port.
5. `loop <data>`: Send _data_ periodic. The period show in the status bar.
6. `loopend`: Stop send _data_ periodic.
7. `clear`: Clear log and receive data windows.
8. `show <window>`: Show log or hex window. The parameter, _window_, should be `log` or `hex`.
9. `hide <window>`" Inverse operation of `show`
10. `set <name> <value>`: Change port parameter.
### Set command
Supportted settings: `baudrate`, `databit`, `parity`, `stopbit`, `flowcontrol`, `period`.
1. `baudrate`: Change baudrate. Support any value.
2. `databit`: Change databit. Support value: 5, 6, 7, 8.
3. `parity`: Change parity. Support value: 0: None, 1: Odd, 2: Even.
4. `stopbit`" Change stopit. Support value: 1, 2.
5. `flowcontrol`: Change flowcontrol. Support value: hard, soft, none.
6. `period`: Change loop send periodic. This will work after port is open. Minimum value: 10ms for Linux, 15 ms for Windows. Because operation system can not run programming in real time, this value is not accurate.
## Feature list
- [x] open port
- [x] close port
- [x] send ascii to port
- [x] view recived data as hex
- [x] change port settings
- [x] send data periodic
- [ ] record output to file
- [ ] send hex to port
- [ ] send hex periodic

10
main.cpp Executable file
View File

@ -0,0 +1,10 @@
#include <QApplication>
#include <QPushButton>
#include "main_window.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
main_window win;
win.show();
return QApplication::exec();
}

175
main.ui Executable file
View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1489</width>
<height>875</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="1">
<widget class="QComboBox" name="stopbitsComboBox">
<item>
<property name="text">
<string>1</string>
</property>
</item>
<item>
<property name="text">
<string>1.5</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="dataBitsComboBox">
<item>
<property name="text">
<string>8</string>
</property>
</item>
<item>
<property name="text">
<string>7</string>
</property>
</item>
<item>
<property name="text">
<string>6</string>
</property>
</item>
<item>
<property name="text">
<string>5</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="portUpdBtn">
<property name="text">
<string>port</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Temp</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="portsComboBox"/>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="tmpFilenameEdit">
<property name="text">
<string>tmpdata</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Baudrate</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Databits</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QPushButton" name="portOpenBtn">
<property name="text">
<string>open</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Stopbis</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="baudLineEdit">
<property name="text">
<string>115200</string>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QTextEdit" name="hexTextEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
<widget class="QTextEdit" name="asciiTextEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1489</width>
<height>31</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
<slots>
<slot>update_ui_port()</slot>
<slot>open_port()</slot>
<slot>update_chart()</slot>
</slots>
</ui>

156
main_window.cpp Executable file
View File

@ -0,0 +1,156 @@
//
// Created by zong on 5/18/22.
//
#include "main_window.h"
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <iostream>
#include <queue>
#include <QFile>
#include<QMessageBox>
static bool check_exist(QString str) {
for (auto &port: QSerialPortInfo::availablePorts()) {
if (str == port.portName())
return true;
}
return false;
}
void main_window::setUiComponent() {
this->ui = new Ui::MainWindow;
ui->setupUi(this);
portsComboBox = ui->portsComboBox;
hexTextEdit = ui->hexTextEdit;
tmpFilenameEdit = ui->tmpFilenameEdit;
portOpenBtn = ui->portOpenBtn;
portsComboBox = ui->portsComboBox;
portUpdBtn = ui->portUpdBtn;
statusbar = ui->statusbar;
stopbitsComboBox = ui->stopbitsComboBox;
QObject::connect(portOpenBtn, SIGNAL(clicked()), this, SLOT(open_port()));
QObject::connect(portUpdBtn, SIGNAL(clicked()), this, SLOT(update_ui_port()));
}
main_window::main_window(QWidget *parent) : QMainWindow(parent) {
setUiComponent();
QObject::connect(&port, SIGNAL(readyRead()), this, SLOT(read_data()));
QFont font("Courier");
hexTextEdit->setFont(font);
QSerialPortInfo info;
auto tmp = QSerialPortInfo::availablePorts();
portsComboBox->clear();
for (auto &port: tmp) {
qDebug() << port.portName();
portsComboBox->addItem(port.portName());
}
hexTextEdit->setLineWrapMode(QTextEdit::FixedColumnWidth);
hexTextEdit->setLineWrapColumnOrWidth(48);
hexTextEdit->setWordWrapMode(QTextOption::WordWrap);
hexTextEdit->setFontFamily("Mono");
}
main_window::~main_window() {
delete ui;
}
void main_window::update_ui_port() {
portsComboBox->clear();
for (auto &port: QSerialPortInfo::availablePorts()) {
portsComboBox->addItem(port.portName());
}
}
void main_window::open_port() {
if (is_open) {
port.close();
QFile file;
auto filename = tmpFilenameEdit->text();
file.setFileName(filename);
file.open(QIODevice::Append);
auto val = hexTextEdit->toPlainText();
hexTextEdit->clear();
file.write(val.toUtf8());
file.close();
is_open = false;
portOpenBtn->setText("open");
return;
}
if (portsComboBox->count() == 0) { return; }
auto cur_port = portsComboBox->currentText();
if (!check_exist(cur_port)) return;
port.setPortName(cur_port);
auto stopbits = stopbitsComboBox->currentText();
if (stopbits == QString("1")) port.setStopBits(QSerialPort::OneStop);
else if (stopbits == QString("1.5")) port.setStopBits(QSerialPort::OneAndHalfStop);
else if (stopbits == QString("2")) port.setStopBits(QSerialPort::TwoStop);
else {
QMessageBox box;
box.setText("wrong stopbits settings");
box.exec();
return;
}
// TODO: read info from config
port.setBaudRate(115200);
port.setDataBits(QSerialPort::Data8);
port.setParity(QSerialPort::NoParity);
port.setFlowControl(QSerialPort::NoFlowControl);
if (port.open(QIODevice::ReadWrite)) {
is_open = true;
portOpenBtn->setText("close");
statusbar->showMessage("open port success");
} else
is_open = false;
}
#include <cstdint>
#include <QLineSeries>
static uint64_t rest = 0;
static QLineSeries linedata;
static int cnt = 0;
static long long line_cnt = 0;
void main_window::read_data() {
auto data = port.readAll();
// for (int i = 0; i < data.size(); i++) {
// linedata.append(line_cnt++, int(data[i]));
// }
cnt += data.size();
QString new_text = QString(data.toHex(' ').toUpper()) + " ";
hexTextEdit->moveCursor(QTextCursor::End);
hexTextEdit->insertPlainText(new_text);
if (cnt > 1e3) {
QFile file;
auto filename = tmpFilenameEdit->text();
file.setFileName(filename);
file.open(QIODevice::Append);
auto val = hexTextEdit->toPlainText();
hexTextEdit->clear();
file.write(val.toUtf8());
file.close();
cnt = 0;
}
}
#include <QChart>
#include <QChartView>
#include <QWidget>
void main_window::update_chart() {
// TODO: memory leakage
QChart *chart = new QChart();
linedata.append(1, 10);
linedata.append(10, 7);
chart->addSeries(&linedata);
chart->createDefaultAxes();
chart->setTitle("WIP");
QChartView *chartview = new QChartView(chart);
chartview->show();
}

62
main_window.h Executable file
View File

@ -0,0 +1,62 @@
//
// Created by zong on 5/18/22.
//
#ifndef UNTITLED_MAIN_WINDOW_H
#define UNTITLED_MAIN_WINDOW_H
#include "ui_main.h"
#include <QSerialPort>
#include <QThread>
class main_window : public QMainWindow {
Q_OBJECT
public:
explicit main_window(QWidget *parent = nullptr);
~main_window() override;
private:
Ui::MainWindow *ui;
bool is_open = false;
QSerialPort port;
QWidget *centralwidget;
QHBoxLayout *horizontalLayout;
QSplitter *splitter;
QWidget *layoutWidget;
QGridLayout *gridLayout;
QComboBox *stopbitsComboBox;
QComboBox *dataBitsComboBox;
QPushButton *portUpdBtn;
QLabel *label_4;
QComboBox *portsComboBox;
QLineEdit *tmpFilenameEdit;
QLabel *label;
QLabel *label_2;
QPushButton *portOpenBtn;
QLabel *label_3;
QLineEdit *baudLineEdit;
QSpacerItem *verticalSpacer;
QTextEdit *hexTextEdit;
QTextEdit *asciiTextEdit;
QMenuBar *menubar;
QStatusBar *statusbar;
private:
void setUiComponent();
public slots:
void update_ui_port();
void open_port();
void read_data();
void update_chart();
};
#endif //UNTITLED_MAIN_WINDOW_H

75
main_windows.cpp Executable file
View File

@ -0,0 +1,75 @@
//
// Created by zong on 5/18/22.
//
#include "main_windows.h"
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <iostream>
#include <queue>
static bool check_exist(QString str) {
for (auto &port: QSerialPortInfo::availablePorts()) {
if (str == port.portName())
return true;
}
return false;
}
main_windows::main_windows(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
QObject::connect(&port, SIGNAL(readyRead()), this, SLOT(read_data()));
QSerialPortInfo info;
auto tmp = QSerialPortInfo::availablePorts();
ui->comboBox->clear();
for (auto &port: tmp) {
qDebug() << port.portName();
ui->comboBox->addItem(port.portName());
}
}
main_windows::~main_windows() {
delete ui;
}
void main_windows::update_ui_port() {
ui->comboBox->clear();
for (auto &port: QSerialPortInfo::availablePorts()) {
ui->comboBox->addItem(port.portName());
}
}
void main_windows::open_port() {
if (is_open) {
port.close();
is_open = false;
ui->pushButton_2->setText("open");
return;
}
if (ui->comboBox->count() == 0) { return; }
auto cur_port = ui->comboBox->currentText();
if (!check_exist(cur_port)) return;
port.setPortName(cur_port);
port.setStopBits(QSerialPort::OneStop);
port.setBaudRate(115200);
port.setDataBits(QSerialPort::Data8);
port.setParity(QSerialPort::NoParity);
port.setFlowControl(QSerialPort::NoFlowControl);
if (port.open(QIODevice::ReadWrite)) {
is_open = true;
ui->pushButton_2->setText("close");
qDebug() << "open port success";
} else
is_open = false;
}
void main_windows::read_data() {
auto data = port.readAll();
qDebug() << data;
auto tmp = data.toHex(' ').toUpper();
auto new_text = QString(tmp);
ui->textEdit->insertPlainText(new_text);
// auto text = ui->textEdit-
}

36
main_windows.h Executable file
View File

@ -0,0 +1,36 @@
//
// Created by zong on 5/18/22.
//
#ifndef UNTITLED_MAIN_WINDOWS_H
#define UNTITLED_MAIN_WINDOWS_H
#include "ui_main.h"
#include <QSerialPort>
#include <QThread>
class main_windows : public QMainWindow {
Q_OBJECT
public:
explicit main_windows(QWidget *parent = nullptr);
~main_windows() override;
private:
Ui::MainWindow *ui;
bool is_open = false;
QSerialPort port;
public slots:
void update_ui_port();
void open_port();
void read_data();
};
#endif //UNTITLED_MAIN_WINDOWS_H

View File

@ -1,68 +0,0 @@
pub fn get_hex(prefix_len: u32, data: Vec<u8>) -> String {
let mut header_begin = prefix_len >> 4;
let mut counter = prefix_len % 16;
// println!("{}", header_begin);
// println!("{}", counter);
let mut ret = String::new();
for i in data {
if counter % 16 == 0 {
counter = 0;
// if header_begin != 0 {
// ret.push('\n');
// }
header_begin += 1;
ret += &format!("{:04x}\t", header_begin - 1);
}
counter += 1;
ret = ret + &*format!("{:02x} ", i);
if counter % 16 ==0 {
ret.push('\n');
}
}
return ret;
}
pub fn get_ascii(prefix_len: u32, data: Vec<u8>) -> String {
let mut header_begin = prefix_len >> 4;
let mut counter = prefix_len % 16;
// println!("{}", header_begin);
// println!("{}", counter);
let mut ret = String::new();
for i in data {
if counter % 16 == 0 {
counter = 0;
// if header_begin != 0 { ret.push('\n'); }
header_begin += 1;
ret += &format!("{:04x}\t", header_begin - 1);
}
counter += 1;
if i.is_ascii_alphanumeric() || i.is_ascii_punctuation() || i.is_ascii_graphic() {
// ret += &*(i as char).to_string();
ret.push(char::from(i));
// basic_show.push(i as char);
} else {
ret += ".";
}
if counter % 16 ==0 {
ret.push('\n');
}
}
return ret;
}
#[cfg(test)]
mod tests {
use crate::hexdump::get_hex;
#[test]
fn exploration() {
let data = vec![10, 20, 203];
let tmp = get_hex(14, data);
println!("{}", tmp);
// assert_eq!(2 + 2, 4);
}
}

View File

View File

@ -1,428 +0,0 @@
#![windows_subsystem = "windows"]
mod port;
mod hexdump;
use closure::closure;
use gtk::{Inhibit, TextView, Statusbar, Label};
use gtk::{gio, glib};
use gtk::prelude::{GtkWindowExt, BuilderExtManual, GtkMenuItemExt, WidgetExt, EntryExt, TextBufferExt, ScrolledWindowExt, AdjustmentExt};
use gio::prelude::{ApplicationExt, ApplicationExtManual};
use std::sync::mpsc::{Sender, Receiver, channel};
use serialport::{StopBits, FlowControl, Parity, DataBits};
use crate::port::*;
use gtk::prelude::TextViewExt;
use gtk::prelude::LabelExt;
use std::{str, env};
use std::time::Duration;
fn main() {
let application = gtk::Application::new(
Some("com.github.gtk-rs.examples.menu_bar_system"),
Default::default(),
);
// application.connect_startup(|app| {
// });
application.connect_activate(build_ui);
application.run();
}
fn build_ui(application: &gtk::Application) {
let builder = gtk::Builder::from_string(include_str!("test.ui"));
let ui_main_window: gtk::ApplicationWindow = builder.object("main_window").expect("Can not get window!");
ui_main_window.set_application(Some(application));
let menu_view_command: gtk::MenuItem = builder.object("view_command").expect("Can not get command item");
let command_entry: gtk::Entry = builder.object("command_entry").expect("Can not get command entry");
let tmp = command_entry.clone();
menu_view_command.connect_activate(move |_| {
if WidgetExt::is_visible(&tmp) {
tmp.hide();
} else {
tmp.show();
tmp.set_has_focus(true);
}
});
let ui_log_window: gtk::Window = builder.object("log_window").expect("Can not get log view");
let menu_log_command: gtk::MenuItem = builder.object("log_command").expect("Can not get log command");
let menu_hex_command: gtk::MenuItem = builder.object("hex_command").expect("Can not get log command");
let ui_receive_view: TextView = builder.object("receive_view").expect("can not get receive view");
let ui_baudrate: Label = builder.object("ui_baudrate").unwrap();
let ui_databit: Label = builder.object("ui_databit").unwrap();
let ui_parity: Label = builder.object("ui_parity").unwrap();
let ui_stopbit: Label = builder.object("ui_stopbit").unwrap();
let ui_period: Label = builder.object("ui_period").unwrap();
let ui_com: Label = builder.object("ui_com").unwrap();
let ui_statusbar: Statusbar = builder.object("statusbar").unwrap();
let ui_log_view: TextView = builder.object("log_view").unwrap();
let ui_hex_view: TextView = builder.object("hex_view").unwrap();
let ui_hex_window: gtk::Window = builder.object("hex_window").unwrap();
let ui_ascii_view: TextView = builder.object("ascii_view").unwrap();
let ui_hex_scroll: gtk::ScrolledWindow = builder.object("ui_hex_scroll").unwrap();
// ui_viewport.set_vscroll_policy(Sc)
ui_log_window.show();
// ui_hex_window.show();
ui_log_window.connect_delete_event(|a, _| {
a.hide();
Inhibit(true)
});
ui_hex_window.connect_delete_event(|a, _| {
a.hide();
Inhibit(true)
});
let tmp = ui_log_window.clone();
menu_log_command.connect_activate(move |_| {
if tmp.is_visible() {
tmp.hide();
} else {
tmp.show();
}
});
let tmp = ui_hex_window.clone();
menu_hex_command.connect_activate(move |_| {
if tmp.is_visible() {
tmp.hide();
} else {
tmp.show();
}
});
let mut receive_char_counter = 0;
let (sender_ui_upd, receiver_ui_upd) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
receiver_ui_upd.attach(None, move |msg| {
match msg {
Message::UiUpdateLog(text) => {
let buf = ui_log_view.buffer().unwrap();
buf.insert(&mut buf.end_iter(), text.as_str());
}
Message::UiUpdateReceiveMsg(data) => {
let mut basic_show = String::new();
for i in data.clone() {
if i.is_ascii_alphanumeric() || i.is_ascii_whitespace() || i.is_ascii_punctuation() || i.is_ascii_graphic() {
basic_show.push(i as char);
}
}
let buf = ui_hex_view.buffer().unwrap();
let hex = hexdump::get_hex(receive_char_counter, data.clone());
buf.insert(&mut buf.end_iter(), hex.as_str());
// println!("{:?}",std::mem::size_of_val(&buf));
let buf = ui_receive_view.buffer().unwrap();
buf.insert(&mut buf.end_iter(), basic_show.as_str());
let buf = ui_ascii_view.buffer().unwrap();
let ascii = hexdump::get_ascii(receive_char_counter, data.clone());
buf.insert(&mut buf.end_iter(), ascii.as_str());
receive_char_counter += data.len() as u32;
let tmp = ui_hex_scroll.vadjustment();
tmp.set_value(tmp.upper());
}
Message::UiClearReceiveMsg => ui_receive_view.buffer().unwrap().set_text(""),
Message::UiClearLog => ui_log_view.buffer().unwrap().set_text(""),
Message::UiShowLog => ui_log_window.show(),
Message::UiHideLog => ui_log_window.hide(),
Message::UiShowHex => ui_hex_window.show(),
Message::UiHideHex => ui_hex_window.hide(),
Message::UiUpdateStatusBarBaudrate(value) => ui_baudrate.set_text(value.to_string().as_str()),
Message::UiUpdateStatusBarDatabit(value) => ui_databit.set_text(value.to_string().as_str()),
Message::UiUpdateStatusBarParity(value) => ui_parity.set_text(value.to_string().as_str()),
Message::UiUpdateStatusBarStopbit(value) => ui_stopbit.set_text(value.to_string().as_str()),
Message::UiUpdateStatusBarPeriod(value) => ui_period.set_text(&*(value.to_string() + " ms")),
Message::UiUpdateStatusBarCom(value) => ui_com.set_text(value.to_string().as_str()),
_ => {}
}
glib::Continue(true)
});
let (gui2main_tx, gui2main_rx) = channel::<Message>();
std::thread::spawn(closure!(clone gui2main_tx, clone sender_ui_upd, || {main_proc(gui2main_tx, gui2main_rx, sender_ui_upd)}));
let to_ui = sender_ui_upd.clone();
command_entry.connect_activate(move |x| {
let command_buf = x.buffer();
let command = command_buf.text();
command_buf.set_text("");
process_cmd(command, to_ui.clone(), gui2main_tx.clone());
});
ui_main_window.show();
}
fn process_cmd(command: String, to_ui: glib::Sender<Message>, gui2main_tx: Sender<Message>) {
let command_split: Vec<&str> = command.split_whitespace().collect();
if command_split.len() != 0 {
let cmd = command_split[0].to_ascii_lowercase();
match cmd.as_str() {
"set" => {
if command_split.len() == 1 {
to_ui.send(Message::UiUpdateLog("No enough argument\n".to_string())).unwrap();
} else {
let args: Vec<String> = command_split[1..].to_vec().into_iter().map(|item| String::from(item)).collect();
gui2main_tx.send(Message::MainCmdSet(args)).unwrap();
}
}
"open" => {
if command_split.len() == 1 {
// to_ui.send(Message::UiUpdateLog("No enough argument\n".to_string())).unwrap();
gui2main_tx.send(Message::MainCmdOpen("".to_string())).unwrap();
} else {
let args: Vec<String> = command_split[1..].to_vec().into_iter().map(|item| String::from(item)).collect();
gui2main_tx.send(Message::MainCmdOpen(args[0].clone())).unwrap();
}
}
"close" => {
gui2main_tx.send(Message::MainCmdClose).unwrap();
}
"list" => {
to_ui.send(Message::UiUpdateLog(list_available_ports().0)).unwrap();
}
"send" => {
if command.len() <= 5 {
to_ui.send(Message::UiUpdateLog("no data!\n".parse().unwrap())).unwrap();
} else {
gui2main_tx.send(Message::MainCmdSend(command[5..].parse().unwrap())).unwrap();
}
}
"loop" => {
if command.len() <= 5 {
to_ui.send(Message::UiUpdateLog("no data!\n".parse().unwrap())).unwrap();
} else {
gui2main_tx.send(Message::MainCmdSendPeriod(command[5..].parse().unwrap())).unwrap();
}
}
"loopend" => {
gui2main_tx.send(Message::MainCmdStopPeriod).unwrap();
}
"clear" => {
to_ui.send(Message::UiClearReceiveMsg).unwrap();
to_ui.send(Message::UiClearLog).unwrap();
}
"show" => {
if command_split.len() == 1 {
to_ui.send(Message::UiUpdateLog("No enough argument\n".to_string())).unwrap();
} else {
match command_split[1] {
"log" => to_ui.send(Message::UiShowLog).unwrap(),
"hex" => to_ui.send(Message::UiShowHex).unwrap(),
_ => {}
}
}
}
"hide" => {
if command_split.len() == 1 {
to_ui.send(Message::UiUpdateLog("No enough argument\n".to_string())).unwrap();
} else {
match command_split[1] {
"log" => to_ui.send(Message::UiHideLog).unwrap(),
"hex" => to_ui.send(Message::UiHideHex).unwrap(),
_ => {}
}
}
}
_ => {}
}
}
}
fn main_proc(to_main_tx: Sender<Message>, rx: Receiver<Message>, ui_upd: glib::Sender<Message>) {
let (mut main2port_tx, _rx_port_receive) = channel::<Message>();
let mut port_default_config = PortConfig {
baud_rate: 115_200,
data_bits: DataBits::Eight,
parity: Parity::None,
flow_control: FlowControl::None,
stopbit: StopBits::One,
timeout: 10,
};
let mut port_status_open = false;
let mut default_com_port = list_available_ports().1;
ui_upd.send(Message::UiUpdateStatusBarCom(default_com_port.clone())).unwrap();
loop {
if let Ok(msg) = rx.try_recv() {
match msg {
Message::UiClearReceiveMsg => {}
Message::MainCmdOpen(arg) => {
if port_status_open {
ui_upd.send(Message::UiUpdateLog("Port Already Open\n".to_string())).unwrap();
continue;
}
let (tmp_to_port, main2port_rx) = channel::<Message>();
main2port_tx = tmp_to_port;
let port_name = if arg.is_empty() { default_com_port.clone() } else {
let mut tmp = arg.clone();
if env::consts::OS == "linux" {
let prelude = "/dev/tty";
if !arg.contains("/dev/tty"){
tmp = prelude.to_owned() + &arg;
}
}
tmp
};
default_com_port = port_name.clone();
ui_upd.send(Message::UiUpdateStatusBarCom(default_com_port.clone())).unwrap();
match port_open(port_name, port_default_config) {
Ok(port) => {
port_status_open = true;
std::thread::spawn(closure!(clone to_main_tx, || port_proc(port, to_main_tx, main2port_rx)));
ui_upd.send(Message::UiUpdateLog("open port succeed\n".to_string())).unwrap();
}
Err(e) => {
match e {
Error::PortOpenFailed(msg) => {
ui_upd.send(Message::UiUpdateLog(msg)).unwrap();
}
}
}
}
}
Message::MainCmdClose => {
if port_status_open {
main2port_tx.send(Message::PortCmdClose).unwrap();
} else {
ui_upd.send(Message::UiUpdateLog("No port opened\n".to_string())).unwrap();
}
}
Message::MainCmdSend(msg) => main2port_tx.send(Message::PortCmdSend(msg)).unwrap(),
Message::MainCmdSendPeriod(msg) => { main2port_tx.send(Message::PortPeriodSend(msg)).unwrap() }
Message::MainCmdStopPeriod=> { main2port_tx.send(Message::PortPeriodStop).unwrap() }
Message::MainCmdSet(args) => {
match args[0].as_str() {
"baudrate" => {
if args.len() != 2 {
ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap();
} else {
if let Ok(value) = args[1].parse::<u32>() {
port_default_config.baud_rate = value;
ui_upd.send(Message::UiUpdateStatusBarBaudrate(value)).unwrap();
} else {
ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap();
}
}
}
"databit" => {
if args.len() != 2 {
ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap();
} else {
if let Ok(value) = args[1].parse::<u32>() {
ui_upd.send(Message::UiUpdateStatusBarDatabit(value)).unwrap();
match value {
8 => port_default_config.data_bits = DataBits::Eight,
7 => port_default_config.data_bits = DataBits::Seven,
6 => port_default_config.data_bits = DataBits::Six,
5 => port_default_config.data_bits = DataBits::Five,
_ => { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); }
}
} else {
ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap();
}
}
}
"parity" => {
if args.len() != 2 {
ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap();
} else {
if let Ok(value) = args[1].parse::<u32>() {
match value {
0 => {
port_default_config.parity = Parity::None;
ui_upd.send(Message::UiUpdateStatusBarParity("None".to_string())).unwrap();
}
1 => {
port_default_config.parity = Parity::Odd;
ui_upd.send(Message::UiUpdateStatusBarParity("Odd".to_string())).unwrap();
}
2 => {
port_default_config.parity = Parity::Even;
ui_upd.send(Message::UiUpdateStatusBarParity("Even".to_string())).unwrap();
}
_ => { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); }
}
} else {
ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap();
}
}
}
"stopbit" => {
if args.len() != 2 {
ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap();
} else {
if let Ok(value) = args[1].parse::<u32>() {
ui_upd.send(Message::UiUpdateStatusBarStopbit(value)).unwrap();
match value {
1 => port_default_config.stopbit = StopBits::One,
2 => port_default_config.stopbit = StopBits::Two,
_ => ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(),
}
} else {
ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap();
}
}
}
"flowcontrol" => {
if args.len() != 2 {
ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap();
} else {
match args[1].as_str() {
"hard" => port_default_config.flow_control = FlowControl::Hardware,
"soft" => port_default_config.flow_control = FlowControl::Software,
"none" => port_default_config.flow_control = FlowControl::None,
_ => { ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap(); }
}
}
}
"period" => {
if args.len() != 2 {
ui_upd.send(Message::UiUpdateLog("Invalid command!\n".to_string())).unwrap();
} else {
match args[1].parse::<u64>() {
Ok(value) => {
if port_status_open {
main2port_tx.send(Message::PortPeriodDuration(value)).unwrap();
ui_upd.send(Message::UiUpdateStatusBarPeriod(value)).unwrap();
}
else{
ui_upd.send(Message::UiUpdateLog("No port open\n".parse().unwrap())).unwrap();
}
}
Err(e) => ui_upd.send(Message::UiUpdateLog(format!("{:?}\n", e))).unwrap(),
}
}
}
_ => { ui_upd.send(Message::UiUpdateLog("command does not support!\n".to_string())).unwrap(); }
}
}
Message::PortHaveData(data) => {
ui_upd.send(Message::UiUpdateReceiveMsg(data)).unwrap();
}
Message::PortCloseSucceed => {
ui_upd.send(Message::UiUpdateLog("Close port succeed\n".to_string())).unwrap();
port_status_open = false;
}
Message::PortError(msg) => {
ui_upd.send(Message::UiUpdateLog(format!("port closed by error: {}\n", msg))).unwrap();
port_status_open = false;
}
Message::PortPeriodDuration(value) => {
ui_upd.send(Message::UiUpdateStatusBarPeriod(value)).unwrap();
}
_ => {}
}
}
std::thread::sleep(Duration::from_millis(20));
}
}

View File

@ -1,144 +0,0 @@
use std::sync::mpsc::{Sender, Receiver};
use serialport::{SerialPort, DataBits, Parity, FlowControl, StopBits};
use std::time::Duration;
pub enum Message {
UiUpdateLog(String),
UiUpdateReceiveMsg(Vec<u8>),
UiClearReceiveMsg,
UiClearLog,
UiShowLog,
UiHideLog,
UiShowHex,
UiHideHex,
UiUpdateStatusBarCom(String),
UiUpdateStatusBarBaudrate(u32),
UiUpdateStatusBarParity(String),
UiUpdateStatusBarStopbit(u32),
UiUpdateStatusBarPeriod(u64),
UiUpdateStatusBarDatabit(u32),
MainCmdOpen(String),
MainCmdClose,
MainCmdSend(String),
MainCmdSet(Vec<String>),
MainCmdSendPeriod(String),
MainCmdStopPeriod,
PortCmdClose,
PortCmdSend(String),
PortPeriodSend(String),
PortPeriodStop,
PortPeriodDuration(u64),
PortCloseSucceed,
PortHaveData(Vec<u8>),
PortError(String),
}
pub enum Error {
PortOpenFailed(String),
}
#[derive(Copy, Clone)]
pub struct PortConfig {
pub baud_rate: u32,
pub data_bits: DataBits,
pub parity: Parity,
pub flow_control: FlowControl,
pub stopbit: StopBits,
pub timeout: u32,
}
pub fn port_open(port: String, config: PortConfig) -> Result<Box<dyn SerialPort>, Error> {
let port_builder = serialport::new(port, config.baud_rate)
.data_bits(config.data_bits)
.parity(config.parity)
.flow_control(config.flow_control)
.stop_bits(config.stopbit)
.timeout(Duration::from_millis(config.timeout as u64));
match port_builder.open() {
Ok(port) => { return Ok(port); }
Err(e) => {
let err_msg = format!("Open port failed with error {}\n", e).to_string();
return Err(Error::PortOpenFailed(err_msg));
}
}
}
pub fn port_proc(mut port: Box<dyn SerialPort>, to_main: Sender<Message>, from_main: Receiver<Message>) {
let mut buf: Vec<u8> = vec![0; 128];
let mut period_send = false;
let mut period_timeout = std::time::Duration::from_millis(100);
let mut period_send_msg = String::new();
let mut last_send = std::time::Instant::now();
to_main.send(Message::PortPeriodDuration(100)).unwrap();
loop {
if let Ok(msg) = from_main.try_recv() {
match msg {
Message::PortCmdClose => {
to_main.send(Message::PortCloseSucceed).unwrap();
break;
}
Message::PortCmdSend(msg) => {
match port.write(msg.as_bytes()) {
Err(e) => {
to_main.send(Message::PortError(format!("{}", e).to_string())).unwrap();
}
_ => {}
}
}
Message::PortPeriodSend(msg) => {
period_send = true;
period_send_msg = msg;
}
Message::PortPeriodStop => {
period_send = false;
}
Message::PortPeriodDuration(value) => {
period_timeout = std::time::Duration::from_millis(value);
}
_ => {}
}
}
match port.read(buf.as_mut_slice()) {
Ok(size) => to_main.send(Message::PortHaveData(buf[0..size].to_owned())).unwrap(),
Err(e) => {
if e.kind() != std::io::ErrorKind::TimedOut {
to_main.send(Message::PortError(format!("{}", e).to_string())).unwrap();
break;
}
}
}
if period_send && (last_send.elapsed() > period_timeout) {
last_send = std::time::Instant::now();
match port.write(period_send_msg.as_bytes()) {
Err(e) => to_main.send(Message::PortError(format!("{}", e).to_string())).unwrap(),
_ => {}
}
}
}
}
pub(crate) fn list_available_ports() -> (String, String) {
let mut ret = String::new();
let mut ret_portname = String::new();
match serialport::available_ports() {
Ok(ports) => {
for p in ports {
ret += &*String::from(format!("{:?}\n", p));
if ret_portname.is_empty() {
ret_portname = p.port_name;
}
}
}
Err(err) => {
ret = format!("{}", err);
}
}
(ret, ret_portname)
}

View File

@ -1,9 +0,0 @@
entry.entry1 {
/*background: linear-gradient(to right, #f00, #0f0);*/
/*color: blue;*/
font-weight: bold;
font-size: 17pt;
}
textview.textview1 {
font-size: 20px;
}

View File

@ -1,397 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkWindow" id="hex_window">
<property name="can-focus">False</property>
<property name="default-width">900</property>
<property name="default-height">400</property>
<child>
<object class="GtkScrolledWindow" id="ui_hex_scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">out</property>
<child>
<object class="GtkPaned">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="hexpand">True</property>
<child>
<object class="GtkTextView" id="hex_view">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="editable">False</property>
<property name="monospace">True</property>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">True</property>
</packing>
</child>
<child>
<object class="GtkTextView" id="ascii_view">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="editable">False</property>
<property name="monospace">True</property>
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<object class="GtkWindow" id="log_window">
<property name="can-focus">False</property>
<property name="default-width">300</property>
<property name="default-height">400</property>
<property name="icon-name">network-server</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTextView" id="log_view">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="editable">False</property>
</object>
</child>
</object>
</child>
</object>
<object class="GtkApplicationWindow" id="main_window">
<property name="can-focus">False</property>
<property name="default-width">600</property>
<property name="default-height">800</property>
<property name="icon-name">network-server</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkMenuBar" id="menu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">_File</property>
<property name="use-underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-new</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-open</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-save</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-save-as</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-quit</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">_Edit</property>
<property name="use-underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-cut</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-copy</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-paste</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-delete</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">_View</property>
<property name="use-underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkMenuItem" id="log_command">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">log</property>
<accelerator key="l" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
<object class="GtkMenuItem" id="view_command">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">command</property>
<accelerator key="p" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
<object class="GtkMenuItem" id="hex_command">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">hex</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">_Help</property>
<property name="use-underline">True</property>
<child type="submenu">
<object class="GtkMenu">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-about</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="command_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="vexpand">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTextView" id="receive_view">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="editable">False</property>
<property name="monospace">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkStatusbar" id="statusbar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="ui_com">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">COM</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ui_baudrate">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">115200</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ui_databit">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">8</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ui_parity">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">None</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ui_stopbit">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ui_period">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">100 ms</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
</interface>