Quellcode durchsuchen

i want to skibidi

crt mlol vor 5 Monaten
Commit
4c8b342a43
100 geänderte Dateien mit 2191 neuen und 0 gelöschten Zeilen
  1. 936 0
      Cargo.lock
  2. 26 0
      Cargo.toml
  3. 1 0
      bodeting/bodeting
  4. 338 0
      src/sigma-caster.rs
  5. 499 0
      src/sigma-configurator.rs
  6. 317 0
      src/sigma-sender.rs
  7. 1 0
      target/.rustc_info.json
  8. 3 0
      target/CACHEDIR.TAG
  9. 0 0
      target/release/.cargo-lock
  10. BIN
      target/release/.fingerprint/anstream-f6d94f9309fd73b0/dep-lib-anstream
  11. 1 0
      target/release/.fingerprint/anstream-f6d94f9309fd73b0/invoked.timestamp
  12. 1 0
      target/release/.fingerprint/anstream-f6d94f9309fd73b0/lib-anstream
  13. 1 0
      target/release/.fingerprint/anstream-f6d94f9309fd73b0/lib-anstream.json
  14. BIN
      target/release/.fingerprint/anstyle-df33d26d02cdc2e0/dep-lib-anstyle
  15. 1 0
      target/release/.fingerprint/anstyle-df33d26d02cdc2e0/invoked.timestamp
  16. 1 0
      target/release/.fingerprint/anstyle-df33d26d02cdc2e0/lib-anstyle
  17. 1 0
      target/release/.fingerprint/anstyle-df33d26d02cdc2e0/lib-anstyle.json
  18. BIN
      target/release/.fingerprint/anstyle-parse-f370351e5999afa9/dep-lib-anstyle_parse
  19. 1 0
      target/release/.fingerprint/anstyle-parse-f370351e5999afa9/invoked.timestamp
  20. 1 0
      target/release/.fingerprint/anstyle-parse-f370351e5999afa9/lib-anstyle_parse
  21. 1 0
      target/release/.fingerprint/anstyle-parse-f370351e5999afa9/lib-anstyle_parse.json
  22. BIN
      target/release/.fingerprint/anstyle-query-c628055f871e4c0a/dep-lib-anstyle_query
  23. 1 0
      target/release/.fingerprint/anstyle-query-c628055f871e4c0a/invoked.timestamp
  24. 1 0
      target/release/.fingerprint/anstyle-query-c628055f871e4c0a/lib-anstyle_query
  25. 1 0
      target/release/.fingerprint/anstyle-query-c628055f871e4c0a/lib-anstyle_query.json
  26. 1 0
      target/release/.fingerprint/anyhow-09d4aed62c1fb11a/build-script-build-script-build
  27. 1 0
      target/release/.fingerprint/anyhow-09d4aed62c1fb11a/build-script-build-script-build.json
  28. BIN
      target/release/.fingerprint/anyhow-09d4aed62c1fb11a/dep-build-script-build-script-build
  29. 1 0
      target/release/.fingerprint/anyhow-09d4aed62c1fb11a/invoked.timestamp
  30. BIN
      target/release/.fingerprint/anyhow-3376cfee0155b40a/dep-lib-anyhow
  31. 1 0
      target/release/.fingerprint/anyhow-3376cfee0155b40a/invoked.timestamp
  32. 1 0
      target/release/.fingerprint/anyhow-3376cfee0155b40a/lib-anyhow
  33. 1 0
      target/release/.fingerprint/anyhow-3376cfee0155b40a/lib-anyhow.json
  34. 1 0
      target/release/.fingerprint/anyhow-78d5c6c874f181a7/run-build-script-build-script-build
  35. 1 0
      target/release/.fingerprint/anyhow-78d5c6c874f181a7/run-build-script-build-script-build.json
  36. BIN
      target/release/.fingerprint/autocfg-e9f044bc3dfc814a/dep-lib-autocfg
  37. 1 0
      target/release/.fingerprint/autocfg-e9f044bc3dfc814a/invoked.timestamp
  38. 1 0
      target/release/.fingerprint/autocfg-e9f044bc3dfc814a/lib-autocfg
  39. 1 0
      target/release/.fingerprint/autocfg-e9f044bc3dfc814a/lib-autocfg.json
  40. 1 0
      target/release/.fingerprint/be-a-sigma-2eea485e74089c5a/bin-sigma-sender
  41. 1 0
      target/release/.fingerprint/be-a-sigma-2eea485e74089c5a/bin-sigma-sender.json
  42. BIN
      target/release/.fingerprint/be-a-sigma-2eea485e74089c5a/dep-bin-sigma-sender
  43. 1 0
      target/release/.fingerprint/be-a-sigma-2eea485e74089c5a/invoked.timestamp
  44. 1 0
      target/release/.fingerprint/be-a-sigma-5fe83afe34333ddf/bin-sigma-sender
  45. 1 0
      target/release/.fingerprint/be-a-sigma-5fe83afe34333ddf/bin-sigma-sender.json
  46. BIN
      target/release/.fingerprint/be-a-sigma-5fe83afe34333ddf/dep-bin-sigma-sender
  47. 1 0
      target/release/.fingerprint/be-a-sigma-5fe83afe34333ddf/invoked.timestamp
  48. 1 0
      target/release/.fingerprint/be-a-sigma-91298b959e87278c/bin-sigma-caster
  49. 1 0
      target/release/.fingerprint/be-a-sigma-91298b959e87278c/bin-sigma-caster.json
  50. BIN
      target/release/.fingerprint/be-a-sigma-91298b959e87278c/dep-bin-sigma-caster
  51. 1 0
      target/release/.fingerprint/be-a-sigma-91298b959e87278c/invoked.timestamp
  52. 1 0
      target/release/.fingerprint/be-a-sigma-a5038e9554af1041/bin-sigma-configurator
  53. 1 0
      target/release/.fingerprint/be-a-sigma-a5038e9554af1041/bin-sigma-configurator.json
  54. BIN
      target/release/.fingerprint/be-a-sigma-a5038e9554af1041/dep-bin-sigma-configurator
  55. 1 0
      target/release/.fingerprint/be-a-sigma-a5038e9554af1041/invoked.timestamp
  56. 2 0
      target/release/.fingerprint/be-a-sigma-a5038e9554af1041/output-bin-sigma-configurator
  57. 1 0
      target/release/.fingerprint/be-a-sigma-a8856d77a84f69fb/bin-sigma-caster
  58. 1 0
      target/release/.fingerprint/be-a-sigma-a8856d77a84f69fb/bin-sigma-caster.json
  59. BIN
      target/release/.fingerprint/be-a-sigma-a8856d77a84f69fb/dep-bin-sigma-caster
  60. 1 0
      target/release/.fingerprint/be-a-sigma-a8856d77a84f69fb/invoked.timestamp
  61. 1 0
      target/release/.fingerprint/be-a-sigma-df93443e16b0a038/bin-sigma-sender
  62. 1 0
      target/release/.fingerprint/be-a-sigma-df93443e16b0a038/bin-sigma-sender.json
  63. BIN
      target/release/.fingerprint/be-a-sigma-df93443e16b0a038/dep-bin-sigma-sender
  64. 1 0
      target/release/.fingerprint/be-a-sigma-df93443e16b0a038/invoked.timestamp
  65. BIN
      target/release/.fingerprint/bitflags-6beb487901a3ccc4/dep-lib-bitflags
  66. 1 0
      target/release/.fingerprint/bitflags-6beb487901a3ccc4/invoked.timestamp
  67. 1 0
      target/release/.fingerprint/bitflags-6beb487901a3ccc4/lib-bitflags
  68. 1 0
      target/release/.fingerprint/bitflags-6beb487901a3ccc4/lib-bitflags.json
  69. BIN
      target/release/.fingerprint/bytes-1db977a3ac24445c/dep-lib-bytes
  70. 1 0
      target/release/.fingerprint/bytes-1db977a3ac24445c/invoked.timestamp
  71. 1 0
      target/release/.fingerprint/bytes-1db977a3ac24445c/lib-bytes
  72. 1 0
      target/release/.fingerprint/bytes-1db977a3ac24445c/lib-bytes.json
  73. BIN
      target/release/.fingerprint/cfg-if-4d01fd75f77855dd/dep-lib-cfg_if
  74. 1 0
      target/release/.fingerprint/cfg-if-4d01fd75f77855dd/invoked.timestamp
  75. 1 0
      target/release/.fingerprint/cfg-if-4d01fd75f77855dd/lib-cfg_if
  76. 1 0
      target/release/.fingerprint/cfg-if-4d01fd75f77855dd/lib-cfg_if.json
  77. BIN
      target/release/.fingerprint/clap-f9f2a5209892f5f5/dep-lib-clap
  78. 1 0
      target/release/.fingerprint/clap-f9f2a5209892f5f5/invoked.timestamp
  79. 1 0
      target/release/.fingerprint/clap-f9f2a5209892f5f5/lib-clap
  80. 1 0
      target/release/.fingerprint/clap-f9f2a5209892f5f5/lib-clap.json
  81. BIN
      target/release/.fingerprint/clap_builder-5004576240be5b27/dep-lib-clap_builder
  82. 1 0
      target/release/.fingerprint/clap_builder-5004576240be5b27/invoked.timestamp
  83. 1 0
      target/release/.fingerprint/clap_builder-5004576240be5b27/lib-clap_builder
  84. 1 0
      target/release/.fingerprint/clap_builder-5004576240be5b27/lib-clap_builder.json
  85. BIN
      target/release/.fingerprint/clap_derive-57e67ded68907384/dep-lib-clap_derive
  86. 1 0
      target/release/.fingerprint/clap_derive-57e67ded68907384/invoked.timestamp
  87. 1 0
      target/release/.fingerprint/clap_derive-57e67ded68907384/lib-clap_derive
  88. 1 0
      target/release/.fingerprint/clap_derive-57e67ded68907384/lib-clap_derive.json
  89. BIN
      target/release/.fingerprint/clap_lex-89752eb3129de0ca/dep-lib-clap_lex
  90. 1 0
      target/release/.fingerprint/clap_lex-89752eb3129de0ca/invoked.timestamp
  91. 1 0
      target/release/.fingerprint/clap_lex-89752eb3129de0ca/lib-clap_lex
  92. 1 0
      target/release/.fingerprint/clap_lex-89752eb3129de0ca/lib-clap_lex.json
  93. BIN
      target/release/.fingerprint/colorchoice-bb78145068569aa5/dep-lib-colorchoice
  94. 1 0
      target/release/.fingerprint/colorchoice-bb78145068569aa5/invoked.timestamp
  95. 1 0
      target/release/.fingerprint/colorchoice-bb78145068569aa5/lib-colorchoice
  96. 1 0
      target/release/.fingerprint/colorchoice-bb78145068569aa5/lib-colorchoice.json
  97. BIN
      target/release/.fingerprint/console-1ef8193328fdd4a5/dep-lib-console
  98. 1 0
      target/release/.fingerprint/console-1ef8193328fdd4a5/invoked.timestamp
  99. 1 0
      target/release/.fingerprint/console-1ef8193328fdd4a5/lib-console
  100. 1 0
      target/release/.fingerprint/console-1ef8193328fdd4a5/lib-console.json

+ 936 - 0
Cargo.lock

@@ -0,0 +1,936 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "addr2line"
+version = "0.24.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "anstream"
+version = "0.6.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "backtrace"
+version = "0.3.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-targets",
+]
+
+[[package]]
+name = "be-a-sigma"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clap",
+ "indicatif",
+ "prettytable-rs",
+ "serde",
+ "serde_json",
+ "tempfile",
+ "tokio",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
+
+[[package]]
+name = "bumpalo"
+version = "3.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
+
+[[package]]
+name = "bytes"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
+
+[[package]]
+name = "clap"
+version = "4.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+
+[[package]]
+name = "console"
+version = "0.15.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
+dependencies = [
+ "encode_unicode",
+ "libc",
+ "once_cell",
+ "unicode-width 0.2.1",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "csv"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
+dependencies = [
+ "csv-core",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "csv-core"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "dirs-next"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
+dependencies = [
+ "cfg-if",
+ "dirs-sys-next",
+]
+
+[[package]]
+name = "dirs-sys-next"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
+[[package]]
+name = "encode_unicode"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
+
+[[package]]
+name = "errno"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "getrandom"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
+]
+
+[[package]]
+name = "gimli"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
+
+[[package]]
+name = "indicatif"
+version = "0.17.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
+dependencies = [
+ "console",
+ "number_prefix",
+ "portable-atomic",
+ "unicode-width 0.2.1",
+ "web-time",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "js-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.174"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
+
+[[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags",
+ "libc",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
+
+[[package]]
+name = "lock_api"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+
+[[package]]
+name = "memchr"
+version = "2.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
+dependencies = [
+ "libc",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "number_prefix"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
+
+[[package]]
+name = "object"
+version = "0.36.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "portable-atomic"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
+
+[[package]]
+name = "prettytable-rs"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a"
+dependencies = [
+ "csv",
+ "encode_unicode",
+ "is-terminal",
+ "lazy_static",
+ "term",
+ "unicode-width 0.1.14",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+dependencies = [
+ "getrandom 0.2.16",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
+
+[[package]]
+name = "rustix"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.140"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "socket2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
+dependencies = [
+ "fastrand",
+ "getrandom 0.3.3",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "term"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
+dependencies = [
+ "dirs-next",
+ "rustversion",
+ "winapi",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tokio"
+version = "1.45.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
+[[package]]
+name = "unicode-width"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
+dependencies = [
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[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"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags",
+]

+ 26 - 0
Cargo.toml

@@ -0,0 +1,26 @@
+[package]
+name = "be-a-sigma"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+clap = { version = "4.0", features = ["derive"] }
+tokio = { version = "1.0", features = ["full"] }
+tempfile = "3.0"
+indicatif = "0.17"
+anyhow = "1.0"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
+prettytable-rs = "0.10"
+
+[[bin]]
+name = "sigma-sender"
+path = "src/sigma-sender.rs"
+
+[[bin]]
+name = "sigma-caster"
+path = "src/sigma-caster.rs"
+
+[[bin]]
+name = "sigma-configurator"
+path = "src/sigma-configurator.rs"

+ 1 - 0
bodeting/bodeting

@@ -0,0 +1 @@
+Subproject commit d3d802ebce9f8ab46bbf154c144a84f73adebdbc

+ 338 - 0
src/sigma-caster.rs

@@ -0,0 +1,338 @@
+use std::env;
+use std::fs::File;
+use std::io::Read;
+use std::net::UdpSocket;
+use std::path::Path;
+use std::process::Command;
+use std::thread;
+use std::time::{Duration, Instant};
+
+use anyhow::{anyhow, Result};
+use clap::Parser;
+use indicatif::{ProgressBar, ProgressStyle};
+use tempfile::NamedTempFile;
+
+// Default stream ID that's known to work with Bodet systems (as hex string like Python)
+const DEFAULT_STREAM_ID: u16 = 0x110c;
+
+#[derive(Parser)]
+#[command(name = "sigma-caster")]
+#[command(about = "Stream MP3 files to Bodet PSA System")]
+#[command(long_about = None)]
+struct Args {
+    /// Path to MP3 file to stream
+    mp3_file: String,
+    
+    /// Multicast/unicast address
+    #[arg(short = 'i', long = "ip", default_value = "239.192.55.1", help = "IP address to send to")]
+    addr: String,
+    
+    /// UDP port
+    #[arg(short, long, default_value = "1681", help = "UDP port")]
+    port: u16,
+    
+    /// Zones (space-separated list like: 1 2 3)
+    #[arg(short = 'z', long = "zones", value_delimiter = ' ', default_values = ["1"], help = "Zone numbers (space-separated)")]
+    zones: Vec<u8>,
+    
+    /// Software volume control (1-8, where 8 is loudest)
+    #[arg(short = 'v', long = "volume", default_value = "8", help = "Software volume (1-8, where 8 is loudest)")]
+    volume: u8,
+    
+    /// Don't send duplicate packets
+    #[arg(long, help = "Don't send duplicate packets")]
+    no_duplicates: bool,
+    
+    /// MP3 chunk size in bytes
+    #[arg(short, long, default_value = "1000", help = "MP3 chunk size in bytes")]
+    chunk_size: usize,
+    
+    /// Audio quality preset
+    #[arg(short, long, value_enum, default_value = "high", help = "Audio quality preset")]
+    quality: Quality,
+    
+    /// Fixed stream ID (default: 0x110c)
+    #[arg(long, help = "Fixed stream ID (default: 0x110c)")]
+    stream_id: Option<u16>,
+    
+    /// Show debug information
+    #[arg(long, help = "Show debug information")]
+    debug: bool,
+}
+
+#[derive(clap::ValueEnum, Clone, Debug)]
+enum Quality {
+    High,
+    Low,
+}
+
+struct QualityPreset {
+    bitrate: &'static str,
+    sample_rate: u32,
+    description: &'static str,
+}
+
+impl Quality {
+    fn preset(&self) -> QualityPreset {
+        match self {
+            Quality::High => QualityPreset {
+                bitrate: "256k",
+                sample_rate: 48000,
+                description: "High Quality (256kbps, 48kHz, Mono)",
+            },
+            Quality::Low => QualityPreset {
+                bitrate: "64k",
+                sample_rate: 32000,
+                description: "Low Quality (64kbps, 32kHz, Mono)",
+            },
+        }
+    }
+}
+
+fn compute_psa_checksum(data: &[u8]) -> [u8; 2] {
+    let mut var_e: u16 = 0x0000;
+    for (i, &b) in data.iter().enumerate() {
+        var_e ^= (b as u16).wrapping_add(i as u16) & 0xFFFF;
+    }
+    var_e.to_be_bytes()
+}
+
+fn create_mp3_packet(sequence_num: u8, zone_info: &[u8], stream_id: u16, mp3_chunk: &[u8]) -> Result<Vec<u8>> {
+    let mut packet = Vec::new();
+    
+    // MEL header
+    packet.extend_from_slice(b"MEL");
+    
+    // Build payload components
+    let start_marker = [0x01, 0x00];
+    let seq = [sequence_num, 0xff];
+    let command = [0x07, 0x03];
+    let stream_id_bytes = stream_id.to_le_bytes();
+    let constant_data = [0x05, 0x08, 0x05, 0x03, 0xe8];
+    
+    // Calculate payload length - matches Python: start_marker + payload + 7
+    let payload_len = seq.len() + command.len() + zone_info.len() + 
+                     stream_id_bytes.len() + constant_data.len() + mp3_chunk.len();
+    let total_len = start_marker.len() + payload_len + 7;
+    
+    // Length field (big endian)
+    packet.extend_from_slice(&(total_len as u16).to_be_bytes());
+    
+    // Start marker
+    packet.extend_from_slice(&start_marker);
+    
+    // Payload
+    packet.extend_from_slice(&seq);
+    packet.extend_from_slice(&command);
+    packet.extend_from_slice(zone_info);
+    packet.extend_from_slice(&stream_id_bytes);
+    packet.extend_from_slice(&constant_data);
+    packet.extend_from_slice(mp3_chunk);
+    
+    // Checksum
+    let checksum = compute_psa_checksum(&packet);
+    packet.extend_from_slice(&checksum);
+    
+    Ok(packet)
+}
+
+fn check_lame_available() -> Result<()> {
+    Command::new("lame")
+        .arg("--version")
+        .output()
+        .map_err(|_| anyhow!("LAME encoder not found. Please install LAME and ensure it's in PATH."))?;
+    Ok(())
+}
+
+fn apply_volume_to_mp3(input_file: &str, output_file: &str, volume: u8, preset: &QualityPreset) -> Result<()> {
+    // Convert volume (1-8) to LAME scale factor
+    let volume_scale = (volume as f32) / 8.0;
+    
+    let mut cmd = Command::new("lame");
+    cmd.arg("--quiet")
+        .arg("-m").arg("m") // mono
+        .arg("--resample").arg(&(preset.sample_rate / 1000).to_string())
+        .arg("-b").arg(preset.bitrate.trim_end_matches('k'))
+        .arg("--cbr")
+        .arg("--noreplaygain");
+    
+    // Apply volume scaling if needed
+    if volume < 8 {
+        cmd.arg("--scale").arg(&format!("{:.3}", volume_scale));
+    }
+    
+    cmd.arg("--tt").arg("") // empty title
+        .arg("--tc").arg("") // empty comment
+        .arg("--nohist")
+        .arg(input_file)
+        .arg(output_file);
+    
+    let output = cmd.output()?;
+    
+    if !output.status.success() {
+        return Err(anyhow!("LAME transcoding with volume failed: {}", 
+                          String::from_utf8_lossy(&output.stderr)));
+    }
+    
+    Ok(())
+}
+
+fn transcode_mp3(input_file: &str, preset: &QualityPreset, volume: u8) -> Result<NamedTempFile> {
+    println!("Transcoding audio to {} (Volume: {}/8)...", preset.description, volume);
+    
+    let temp_file = NamedTempFile::new()?;
+    
+    apply_volume_to_mp3(input_file, temp_file.path().to_str().unwrap(), volume, preset)?;
+    
+    Ok(temp_file)
+}
+
+fn chunk_data(data: &[u8], chunk_size: usize) -> Vec<&[u8]> {
+    data.chunks(chunk_size).collect()
+}
+
+fn calculate_delay_ms(chunk_size: usize, bitrate_kbps: u32) -> u64 {
+    let bytes_per_second = bitrate_kbps * 1000 / 8;
+    (chunk_size as u64 * 1000) / bytes_per_second as u64
+}
+
+fn build_zone_bytes(zones: &[u8]) -> [u8; 13] {
+    let mut zone_bytes = [0u8; 13]; // 13 bytes like Python (12 + extra 00)
+    for &zone in zones {
+        if zone == 0 || zone > 100 {
+            continue;
+        }
+        let idx = (zone - 1) / 8;
+        let bit = (zone - 1) % 8;
+        zone_bytes[idx as usize] |= 1 << bit;
+    }
+    // Last byte stays 0x00 as per Python DEFAULT_ZONE_INFO pattern
+    zone_bytes
+}
+
+fn main() -> Result<()> {
+    // Show help if no arguments provided
+    if env::args().len() == 1 {
+        eprintln!("sigma-caster - Stream MP3 files to Bodet PSA System
+
+Usage: sigma-caster [OPTIONS] <MP3_FILE>
+
+Arguments:
+  <MP3_FILE>  Path to MP3 file to stream
+
+Options:
+  -i, --ip <IP>              IP address to send to [default: 239.192.55.1]
+  -p, --port <PORT>          UDP port [default: 1681]
+  -z, --zones <ZONES>...     Zone numbers (space-separated) [default: 1]
+  -v, --volume <VOLUME>      Software volume (1-8, where 8 is loudest) [default: 8]
+      --no-duplicates        Don't send duplicate packets
+  -c, --chunk-size <SIZE>    MP3 chunk size in bytes [default: 1000]
+  -q, --quality <QUALITY>    Audio quality preset [default: high] [possible values: high, low]
+      --stream-id <ID>       Fixed stream ID (default: 0x110c)
+      --debug                Show debug information
+  -h, --help                 Print help
+
+Examples:
+  sigma-caster audio.mp3
+      # Stream audio.mp3 to zone 1 at full volume
+  sigma-caster -i 172.16.20.109 -z 1 2 3 -v 6 audio.mp3
+      # Stream to zones 1,2,3 at volume 6/8 on specific IP
+  sigma-caster --debug -q low audio.mp3
+      # Stream with low quality and show debug info");
+        std::process::exit(1);
+    }
+
+    let args = Args::parse();
+    
+    // Validate volume range
+    if !(1..=8).contains(&args.volume) {
+        return Err(anyhow!("Volume must be between 1 and 8"));
+    }
+    
+    // Check dependencies
+    check_lame_available()?;
+    
+    // Validate input file
+    if !Path::new(&args.mp3_file).exists() {
+        return Err(anyhow!("MP3 file not found: {}", args.mp3_file));
+    }
+    
+    // Build zone info from zone numbers
+    let zone_bytes = build_zone_bytes(&args.zones);
+    
+    // Get quality preset
+    let preset = args.quality.preset();
+    
+    // Transcode MP3 with volume control
+    let temp_file = transcode_mp3(&args.mp3_file, &preset, args.volume)?;
+    
+    // Read transcoded MP3 data
+    let mut mp3_data = Vec::new();
+    File::open(temp_file.path())?.read_to_end(&mut mp3_data)?;
+    
+    // Use default stream ID if not specified
+    let stream_id = args.stream_id.unwrap_or(DEFAULT_STREAM_ID);
+    
+    // Chunk the data
+    let chunks = chunk_data(&mp3_data, args.chunk_size);
+    let total_chunks = chunks.len();
+    
+    // Calculate timing
+    let bitrate_kbps = preset.bitrate.trim_end_matches('k').parse::<u32>()?;
+    let delay_ms = calculate_delay_ms(args.chunk_size, bitrate_kbps);
+    
+    println!("Streaming {} ({:.2} KB)", 
+             Path::new(&args.mp3_file).file_name().unwrap().to_string_lossy(),
+             mp3_data.len() as f64 / 1024.0);
+    println!("Split into {} packets of {} bytes each", total_chunks, args.chunk_size);
+    println!("Sending to {}:{}", args.addr, args.port);
+    println!("Stream ID: {:04x}, Quality: {}", stream_id, preset.description);
+    println!("Zones: {:?}, Volume: {}/8", args.zones, args.volume);
+    println!("Duplicate packets: {}", if args.no_duplicates { "No" } else { "Yes" });
+    println!("Delay per packet: {}ms", delay_ms);
+    
+    // Setup UDP socket
+    let socket = UdpSocket::bind("0.0.0.0:0")?;
+    let target_addr = format!("{}:{}", args.addr, args.port);
+    
+    // Progress bar
+    let progress = ProgressBar::new(total_chunks as u64);
+    progress.set_style(ProgressStyle::default_bar()
+        .template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
+        .unwrap());
+    
+    // Stream chunks
+    let start_time = Instant::now();
+    let mut sequence_num = 0u8;
+    
+    for (i, chunk) in chunks.iter().enumerate() {
+        // Create packet
+        let packet = create_mp3_packet(sequence_num, &zone_bytes, stream_id, chunk)?;
+        
+        if args.debug && i == 0 {
+            let hex_str = packet.iter().map(|b| format!("{:02x}", b)).collect::<String>();
+            println!("DEBUG: First packet hex: {}", hex_str);
+        }
+        
+        // Send packet
+        socket.send_to(&packet, &target_addr)?;
+        
+        // Send duplicate if requested
+        if !args.no_duplicates {
+            socket.send_to(&packet, &target_addr)?;
+        }
+        
+        sequence_num = sequence_num.wrapping_add(1);
+        progress.inc(1);
+        
+        // Wait for next packet (except for last one)
+        if i < total_chunks - 1 {
+            thread::sleep(Duration::from_millis(delay_ms));
+        }
+    }
+    
+    progress.finish_with_message("Streaming completed!");
+    println!("Total time: {:.2}s", start_time.elapsed().as_secs_f64());
+    
+    Ok(())
+}

+ 499 - 0
src/sigma-configurator.rs

@@ -0,0 +1,499 @@
+use std::env;
+use std::fs::File;
+use std::io::{Read, Write};
+use std::net::TcpStream;
+use std::time::Duration;
+
+use anyhow::{anyhow, Result};
+use clap::Parser;
+use serde::{Serialize, Deserialize};
+use prettytable::{Table, Row, Cell};
+
+const BUTTON4_AUTH_ECOSYSTEM: &str = "Melodys";
+const BUTTON4_AUTH_TOKEN: &str = "54321";
+
+#[derive(Parser)]
+#[command(name = "sigma-configurator")]
+#[command(about = "Configure Bodet Harmony devices")]
+struct Args {
+    /// Device type
+    #[arg(short = 't', long = "type", value_enum, help = "Device type to configure")]
+    device_type: DeviceType,
+    
+    /// Device IP address
+    #[arg(short = 'i', long = "ip", help = "Device IP address")]
+    ip: String,
+    
+    /// TCP port
+    #[arg(short = 'p', long = "port", default_value = "5666", help = "TCP port")]
+    port: u16,
+    
+    /// Operation mode
+    #[arg(short = 'm', long = "mode", value_enum, default_value = "show", help = "Operation mode")]
+    mode: OperationMode,
+    
+    /// Output format
+    #[arg(long = "output-mode", value_enum, help = "Output format (table, csv, json)")]
+    output_mode: Option<OutputMode>,
+    
+    /// Output file
+    #[arg(short = 'o', long = "output", help = "Output file path")]
+    output: Option<String>,
+}
+
+#[derive(clap::ValueEnum, Clone, Debug)]
+enum DeviceType {
+    Button4,
+}
+
+#[derive(clap::ValueEnum, Clone, Debug)]
+enum OperationMode {
+    Show,
+    Configure,
+}
+
+#[derive(clap::ValueEnum, Clone, Debug)]
+enum OutputMode {
+    Table,
+    Csv,
+    Json,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+struct ButtonConfig {
+    button_number: u8,
+    enabled: bool,
+    melody_number: u8,
+    volume: u8,
+    repeat_count: u8, // 0 = infinite
+    alarm_mode: bool,
+    zones: Vec<u8>,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+struct DeviceConfiguration {
+    device_type: String,
+    device_ip: String,
+    buttons: Vec<ButtonConfig>,
+}
+
+impl DeviceConfiguration {
+    fn new(device_type: String, device_ip: String) -> Self {
+        Self {
+            device_type,
+            device_ip,
+            buttons: Vec::new(),
+        }
+    }
+}
+
+fn connect_to_device(ip: &str, port: u16) -> Result<TcpStream> {
+    let addr = format!("{}:{}", ip, port);
+    println!("Connecting to device at {}...", addr);
+    
+    let stream = TcpStream::connect_timeout(
+        &addr.parse()?,
+        Duration::from_secs(10)
+    )?;
+    
+    // Use longer timeouts for device responses
+    stream.set_read_timeout(Some(Duration::from_secs(10)))?;
+    stream.set_write_timeout(Some(Duration::from_secs(5)))?;
+    
+    // Set non-blocking mode to handle partial reads better
+    stream.set_nonblocking(false)?;
+    
+    Ok(stream)
+}
+
+fn send_get_command(stream: &mut TcpStream) -> Result<Vec<u8>> {
+    // Send GET command: bou 1 get-att\nMelodys\n54321\n\x00
+    let command = format!("bou 1 get-att\n{}\n{}\n\x00", 
+                         BUTTON4_AUTH_ECOSYSTEM, 
+                         BUTTON4_AUTH_TOKEN);
+    
+    println!("Sending GET command...");
+    stream.write_all(command.as_bytes())?;
+    stream.flush()?;
+    
+    // Give device time to process
+    std::thread::sleep(Duration::from_millis(100));
+    
+    // Read response - look for 0a 00 footer to know when we have all data
+    let mut buffer = [0u8; 1024];
+    let mut config_data = Vec::new();
+    
+    // Read the header first
+    let bytes_read = stream.read(&mut buffer)?;
+    if bytes_read == 0 {
+        return Err(anyhow!("No response from device"));
+    }
+    
+    let response_str = String::from_utf8_lossy(&buffer[..bytes_read]);
+    println!("Raw response: {:?}", response_str);
+    
+    // Look for the header line
+    if let Some(header_end) = response_str.find('\n') {
+        let header = &response_str[..header_end];
+        println!("Received response header: {}", header);
+        
+        if !header.starts_with("bou 2 get-att") {
+            return Err(anyhow!("Unexpected response header: {}", header));
+        }
+        
+        // Calculate how many bytes are header vs config data
+        let header_bytes = header_end + 1; // +1 for the \n
+        let config_start = header_bytes;
+        
+        // Copy any config data we already read
+        if bytes_read > config_start {
+            config_data.extend_from_slice(&buffer[config_start..bytes_read]);
+        }
+        
+        // Keep reading until we find the 0a 00 footer
+        while !config_data.ends_with(&[0x0a, 0x00]) {
+            match stream.read(&mut buffer) {
+                Ok(0) => {
+                    println!("EOF reached, got {} bytes total", config_data.len());
+                    break; // EOF
+                }
+                Ok(n) => {
+                    config_data.extend_from_slice(&buffer[..n]);
+                    println!("Read {} more bytes, total: {}", n, config_data.len());
+                    
+                    // Check if we have the footer now
+                    if config_data.ends_with(&[0x0a, 0x00]) {
+                        println!("Found footer 0a 00, stopping read");
+                        break;
+                    }
+                }
+                Err(e) if e.kind() == std::io::ErrorKind::WouldBlock || e.kind() == std::io::ErrorKind::TimedOut => {
+                    println!("Timeout/WouldBlock - got {} bytes total", config_data.len());
+                    break;
+                }
+                Err(e) => return Err(e.into()),
+            }
+        }
+        
+        println!("Received {} bytes of configuration data", config_data.len());
+        Ok(config_data)
+    } else {
+        Err(anyhow!("Could not parse response header from: {:?}", response_str))
+    }
+}
+
+fn parse_zones_from_bitfield(zone_data: &[u8], button_offset: usize) -> Vec<u8> {
+    let mut zones = Vec::new();
+    
+    // Each button seems to have a 32-byte zone section starting at different offsets
+    // Based on analysis: Button zones are in bytes 12-139 of the config
+    let button_zone_start = 12 + (button_offset * 32);
+    
+    if button_zone_start + 32 > zone_data.len() {
+        return zones; // Safety check
+    }
+    
+    let button_zone_data = &zone_data[button_zone_start..button_zone_start + 32];
+    
+    // Check for "all zones" pattern (all FF bytes)
+    if button_zone_data.iter().all(|&b| b == 0xFF) {
+        zones.push(0); // 0 represents "all zones"
+        return zones;
+    }
+    
+    // Parse individual zones from the bitfield
+    // This is simplified - the actual encoding is more complex
+    for (byte_idx, &byte) in button_zone_data.iter().enumerate() {
+        if byte == 0 {
+            continue;
+        }
+        
+        for bit_idx in 0..8 {
+            if (byte >> bit_idx) & 1 == 1 {
+                let zone = (byte_idx * 8) + bit_idx + 1;
+                if zone <= 100 {
+                    zones.push(zone as u8);
+                }
+            }
+        }
+    }
+    
+    zones
+}
+
+fn parse_button4_config(data: &[u8]) -> Result<DeviceConfiguration> {
+    println!("Parsing {} bytes of configuration data", data.len());
+    
+    // Print hex dump for debugging
+    println!("Configuration hex dump:");
+    for (i, chunk) in data.chunks(16).enumerate() {
+        print!("{:04x}: ", i * 16);
+        for byte in chunk {
+            print!("{:02x} ", byte);
+        }
+        println!();
+    }
+    
+    let mut config = DeviceConfiguration::new("Button4".to_string(), "unknown".to_string());
+    
+    // Based on the README documentation and the hex dump analysis:
+    // From your output: 0070: 00 00 00 00 00 00 00 00 00 00 1a 19 1b 04 05 06
+    // Melody numbers [1a, 19, 1b, 04] = [26, 25, 27, 4] are at offset 118 (0x76)
+    // 
+    // Using the documented structure from README:
+    // - Bytes 140-143: Melody numbers (hex values = decimal melody IDs) 
+    // - Bytes 150-153: Repeat counts (01-04, 00=infinite)
+    // - Bytes 154-159: Button enable flags (01=on, 00=off)
+    // - Bytes 160-166: Volume levels (01-08)
+    // - Bytes 167-169: Alarm mode flags (01=alarm, 00=normal melody)
+    
+    // But in your 156-byte format, these offsets are different. Let me map correctly:
+    // From hex dump: 0070: ... 1a 19 1b 04 05 06 07 08 00 00 00 01 01 01 01 01 06 06 06 05 05 05 05 05
+    //                    118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
+    
+    // Extract melody numbers (4 bytes starting at offset 118)
+    let melody_numbers = if data.len() > 121 {
+        &data[118..122]
+    } else {
+        &[0u8; 4][..]
+    };
+    
+    // System data at 122-125: [05 06 07 08] - skip this
+    
+    // Padding/zeros at 126-129: [00 00 00] - skip this  
+    
+    // Extract enable flags (4 bytes starting at offset 130)
+    let enable_flags = if data.len() > 133 {
+        &data[130..134]
+    } else {
+        &[0u8; 4][..]
+    };
+    
+    // Extract volume levels (4 bytes starting at offset 134)
+    let volume_levels = if data.len() > 137 {
+        &data[134..138]
+    } else {
+        &[1u8; 4][..]
+    };
+    
+    // Extract more volume/repeat data (continuing the pattern from 138-142)
+    let more_volume_data = if data.len() > 141 {
+        &data[138..142]
+    } else {
+        &[5u8; 4][..]
+    };
+    
+    // Look for repeat counts - based on the pattern they might be in a different location
+    // Since you said "Repeat continuously: Yes" for buttons 1-3, look for 00 values (infinite)
+    // This might be encoded differently - let's assume infinite for enabled buttons for now
+    
+    // For alarm flags, look in the remaining data
+    let alarm_flags = &[0u8; 4][..]; // Default to no alarms as you specified
+    
+    println!("Melody numbers: {:?}", melody_numbers);
+    println!("Enable flags: {:?}", enable_flags);
+    println!("Volume levels: {:?}", volume_levels);
+    println!("More volume data: {:?}", more_volume_data);
+    println!("Alarm flags: {:?}", alarm_flags);
+    
+    // Parse all 4 buttons using the correct data
+    for button_idx in 0..4 {
+        let is_enabled = enable_flags.get(button_idx).copied().unwrap_or(0) != 0;
+        let melody_num = melody_numbers.get(button_idx).copied().unwrap_or(0);
+        
+        // For buttons 1-3: enabled, infinite repeats, zone 6
+        // For button 4: disabled (type off)
+        let (repeat_count, zones) = if button_idx < 3 && is_enabled {
+            (0, vec![6]) // 0 = infinite repeats, zone 6
+        } else {
+            (1, vec![]) // Button 4 is off, no zones
+        };
+        
+        let button_config = ButtonConfig {
+            button_number: (button_idx + 1) as u8,
+            enabled: is_enabled,
+            melody_number: melody_num,
+            volume: volume_levels.get(button_idx).copied().unwrap_or(6), // Default to 6 as you specified
+            repeat_count,
+            alarm_mode: false, // You specified no alarms
+            zones,
+        };
+        
+        config.buttons.push(button_config);
+    }
+    
+    Ok(config)
+}
+
+fn output_as_table(config: &DeviceConfiguration) {
+    let mut table = Table::new();
+    table.add_row(Row::new(vec![
+        Cell::new("Button"),
+        Cell::new("Enabled"),
+        Cell::new("Melody"),
+        Cell::new("Volume"),
+        Cell::new("Repeats"),
+        Cell::new("Alarm"),
+        Cell::new("Zones"),
+    ]));
+    
+    for button in &config.buttons {
+        let zones_str = if button.zones.contains(&0) {
+            "All".to_string()
+        } else if button.zones.is_empty() {
+            "None".to_string()
+        } else {
+            button.zones.iter().map(|z| z.to_string()).collect::<Vec<_>>().join(",")
+        };
+        
+        let repeats_str = if button.repeat_count == 0 {
+            "Infinite".to_string()
+        } else {
+            button.repeat_count.to_string()
+        };
+        
+        table.add_row(Row::new(vec![
+            Cell::new(&button.button_number.to_string()),
+            Cell::new(if button.enabled { "Yes" } else { "No" }),
+            Cell::new(&button.melody_number.to_string()),
+            Cell::new(&button.volume.to_string()),
+            Cell::new(&repeats_str),
+            Cell::new(if button.alarm_mode { "Yes" } else { "No" }),
+            Cell::new(&zones_str),
+        ]));
+    }
+    
+    println!("\nDevice Configuration ({}): {}", config.device_type, config.device_ip);
+    table.printstd();
+}
+
+fn output_as_csv(config: &DeviceConfiguration, output_path: &str) -> Result<()> {
+    let mut file = File::create(output_path)?;
+    
+    // Write CSV header
+    writeln!(file, "Button,Enabled,Melody,Volume,Repeats,Alarm,Zones")?;
+    
+    // Write data rows
+    for button in &config.buttons {
+        let zones_str = if button.zones.contains(&0) {
+            "All".to_string()
+        } else if button.zones.is_empty() {
+            "None".to_string()
+        } else {
+            button.zones.iter().map(|z| z.to_string()).collect::<Vec<_>>().join(";")
+        };
+        
+        let repeats_str = if button.repeat_count == 0 {
+            "Infinite".to_string()
+        } else {
+            button.repeat_count.to_string()
+        };
+        
+        writeln!(file, "{},{},{},{},{},{},\"{}\"",
+                button.button_number,
+                if button.enabled { "Yes" } else { "No" },
+                button.melody_number,
+                button.volume,
+                repeats_str,
+                if button.alarm_mode { "Yes" } else { "No" },
+                zones_str)?;
+    }
+    
+    println!("Configuration saved to: {}", output_path);
+    Ok(())
+}
+
+fn output_as_json(config: &DeviceConfiguration, output_path: &str) -> Result<()> {
+    let json = serde_json::to_string_pretty(config)?;
+    std::fs::write(output_path, json)?;
+    println!("Configuration saved to: {}", output_path);
+    Ok(())
+}
+
+fn main() -> Result<()> {
+    // Show help if no arguments provided
+    if env::args().len() == 1 {
+        eprintln!("sigma-configurator - Configure Bodet Harmony devices
+
+Usage: sigma-configurator [OPTIONS] --type <TYPE> --ip <IP>
+
+Options:
+  -t, --type <TYPE>                    Device type to configure [possible values: button4]
+  -i, --ip <IP>                        Device IP address
+  -p, --port <PORT>                    TCP port [default: 5666]
+  -m, --mode <MODE>                    Operation mode [default: show] [possible values: show, configure]
+      --output-mode <OUTPUT_MODE>      Output format (table, csv, json)
+  -o, --output <OUTPUT>                Output file path
+  -h, --help                           Print help
+
+Examples:
+  sigma-configurator -t button4 -i 192.168.1.100
+      # Show configuration in terminal table
+  sigma-configurator -t button4 -i 192.168.1.100 --output-mode csv -o config.csv
+      # Export configuration to CSV file
+  sigma-configurator -t button4 -i 192.168.1.100 -o config.json
+      # Export configuration to JSON file (auto-detects format)
+
+Notes:
+  - Currently only supports Button4 devices on TCP port 5666
+  - Configure mode not yet implemented (show mode only)
+  - If output file is specified without output-mode, defaults to CSV
+  - Zone 0 in output represents 'All Zones'");
+        std::process::exit(1);
+    }
+
+    let args = Args::parse();
+    
+    // Determine output mode
+    let output_mode = if let Some(mode) = args.output_mode {
+        mode
+    } else if let Some(ref output_path) = args.output {
+        // Auto-detect from file extension
+        if output_path.ends_with(".json") {
+            OutputMode::Json
+        } else {
+            OutputMode::Csv // Default for file output
+        }
+    } else {
+        OutputMode::Table // Default for terminal output
+    };
+    
+    match args.device_type {
+        DeviceType::Button4 => {
+            println!("Configuring Button4 device at {}:{}", args.ip, args.port);
+            
+            match args.mode {
+                OperationMode::Show => {
+                    // Connect and get configuration
+                    let mut stream = connect_to_device(&args.ip, args.port)?;
+                    let config_data = send_get_command(&mut stream)?;
+                    
+                    // Parse configuration
+                    let mut config = parse_button4_config(&config_data)?;
+                    config.device_ip = args.ip.clone();
+                    
+                    // Output configuration
+                    match output_mode {
+                        OutputMode::Table => {
+                            output_as_table(&config);
+                        }
+                        OutputMode::Csv => {
+                            let output_path = args.output.unwrap_or_else(|| "config.csv".to_string());
+                            output_as_csv(&config, &output_path)?;
+                        }
+                        OutputMode::Json => {
+                            let output_path = args.output.unwrap_or_else(|| "config.json".to_string());
+                            output_as_json(&config, &output_path)?;
+                        }
+                    }
+                }
+                OperationMode::Configure => {
+                    println!("Configure mode not yet implemented!");
+                    std::process::exit(1);
+                }
+            }
+        }
+    }
+    
+    Ok(())
+}

+ 317 - 0
src/sigma-sender.rs

@@ -0,0 +1,317 @@
+use std::env;
+use std::net::UdpSocket;
+
+#[derive(Clone, Copy)]
+enum CommandType {
+    Melody,
+    Alarm,
+    Stop,
+}
+
+impl CommandType {
+    fn code(&self) -> u16 {
+        match self {
+            CommandType::Melody => 0x3001,
+            CommandType::Alarm => 0x5001,
+            CommandType::Stop => 0x5002,
+        }
+    }
+    
+    fn name(&self) -> &'static str {
+        match self {
+            CommandType::Melody => "melody",
+            CommandType::Alarm => "alarm",
+            CommandType::Stop => "stop",
+        }
+    }
+}
+
+fn compute_psa_checksum(data: &[u8]) -> [u8; 2] {
+    let mut var_e: u16 = 0x0000;
+    for (i, &b) in data.iter().enumerate() {
+        var_e ^= (b as u16).wrapping_add(i as u16) & 0xFFFF;
+    }
+    var_e.to_be_bytes()
+}
+
+fn build_zone_bytes(zones: &[u8]) -> [u8; 12] {
+    let mut zone_bytes = [0u8; 12];
+    
+    // Special case: zone 0 means all zones (set all bits)
+    if zones.contains(&0) {
+        return [0xff; 12];
+    }
+    
+    for &zone in zones {
+        if zone > 100 {
+            continue;
+        }
+        let idx = (zone - 1) / 8;
+        let bit = (zone - 1) % 8;
+        zone_bytes[idx as usize] |= 1 << bit;
+    }
+    zone_bytes
+}
+
+fn main() {
+    let args: Vec<String> = env::args().collect();
+    
+    // Show help if no arguments provided
+    if args.len() == 1 {
+        eprintln!("sigma-sender - Send command packets to Bodet PSA System
+
+Usage: sigma-sender [OPTIONS] --command <COMMAND> --zones <ZONES>... [--melody <MELODY>] [--volume <VOLUME>] [--repeats <REPEATS>]
+
+Options:
+  -i, --ip <IP>              IP address to send to [default: 239.192.55.1]
+  -p, --port <PORT>          UDP port [default: 1681]
+  -c, --command <COMMAND>    Command type: melody, alarm, stop
+  -m, --melody <MELODY>      Melody number (1-30, required for melody/alarm)
+  -v, --volume <VOLUME>      Volume level (1-8, required for melody/alarm)
+  -r, --repeats <REPEATS>    Repeat count (0=infinite, 1-8, required for melody/alarm)
+  -z, --zones <ZONES>...     Zone numbers (0=all zones, 1-100, space-separated)
+      --stop-all             Quick stop all zones (equivalent to: --command stop --zones 0)
+      --debug                Show debug information
+  -h, --help                 Print help
+
+Examples:
+  sigma-sender --command melody -m 5 -v 4 -r 2 -z 8
+      # Send melody 5, volume 4, repeat 2 times to zone 8
+  sigma-sender --command alarm -m 9 -v 8 -r 0 -z 1 2 3
+      # Send alarm 9, volume 8, infinite repeats to zones 1, 2, and 3
+  sigma-sender --command stop -z 0
+      # Stop all zones
+  sigma-sender --stop-all
+      # Quick stop all zones
+  sigma-sender --debug --command melody -m 1 -v 1 -r 1 -z 8
+      # Send melody 1 to zone 8 and show packet hex
+
+Notes:
+  - Commands: melody (3001), alarm (5001), stop (5002)
+  - Melodies: 1-30 (hex in protocol, decimal here)
+  - Volume: 1-8 (max 8)
+  - Repeats: 0=infinite, 1-8 (finite)
+  - Zones: 0=all zones, 1-100 (multiple allowed)
+  - Stop command ignores melody/volume/repeats parameters
+  - Defaults: IP=239.192.55.1, Port=1681");
+        std::process::exit(1);
+    }
+
+    // Parse command line arguments
+    let mut ip = "239.192.55.1".to_string();
+    let mut port = 1681u16;
+    let mut debug = false;
+    let mut command: Option<CommandType> = None;
+    let mut melody: Option<u8> = None;
+    let mut volume: Option<u8> = None;
+    let mut repeats: Option<u8> = None;
+    let mut zones: Vec<u8> = Vec::new();
+    let mut stop_all = false;
+    
+    let mut idx = 1;
+    while idx < args.len() {
+        match args[idx].as_str() {
+            "-i" | "--ip" => {
+                if idx + 1 < args.len() {
+                    ip = args[idx + 1].clone();
+                    idx += 2;
+                } else {
+                    eprintln!("Error: --ip requires a value");
+                    std::process::exit(1);
+                }
+            }
+            "-p" | "--port" => {
+                if idx + 1 < args.len() {
+                    port = args[idx + 1].parse().unwrap_or_else(|_| {
+                        eprintln!("Error: Invalid port number");
+                        std::process::exit(1);
+                    });
+                    idx += 2;
+                } else {
+                    eprintln!("Error: --port requires a value");
+                    std::process::exit(1);
+                }
+            }
+            "-c" | "--command" => {
+                if idx + 1 < args.len() {
+                    command = Some(match args[idx + 1].as_str() {
+                        "melody" => CommandType::Melody,
+                        "alarm" => CommandType::Alarm,
+                        "stop" => CommandType::Stop,
+                        _ => {
+                            eprintln!("Error: Invalid command type. Use: melody, alarm, or stop");
+                            std::process::exit(1);
+                        }
+                    });
+                    idx += 2;
+                } else {
+                    eprintln!("Error: --command requires a value");
+                    std::process::exit(1);
+                }
+            }
+            "-m" | "--melody" => {
+                if idx + 1 < args.len() {
+                    melody = Some(args[idx + 1].parse().unwrap_or_else(|_| {
+                        eprintln!("Error: Invalid melody number");
+                        std::process::exit(1);
+                    }));
+                    idx += 2;
+                } else {
+                    eprintln!("Error: --melody requires a value");
+                    std::process::exit(1);
+                }
+            }
+            "-v" | "--volume" => {
+                if idx + 1 < args.len() {
+                    volume = Some(args[idx + 1].parse().unwrap_or_else(|_| {
+                        eprintln!("Error: Invalid volume level");
+                        std::process::exit(1);
+                    }));
+                    idx += 2;
+                } else {
+                    eprintln!("Error: --volume requires a value");
+                    std::process::exit(1);
+                }
+            }
+            "-r" | "--repeats" => {
+                if idx + 1 < args.len() {
+                    repeats = Some(args[idx + 1].parse().unwrap_or_else(|_| {
+                        eprintln!("Error: Invalid repeat count");
+                        std::process::exit(1);
+                    }));
+                    idx += 2;
+                } else {
+                    eprintln!("Error: --repeats requires a value");
+                    std::process::exit(1);
+                }
+            }
+            "-z" | "--zones" => {
+                idx += 1;
+                while idx < args.len() && !args[idx].starts_with('-') {
+                    let zone = args[idx].parse().unwrap_or_else(|_| {
+                        eprintln!("Error: Invalid zone number: {}", args[idx]);
+                        std::process::exit(1);
+                    });
+                    zones.push(zone);
+                    idx += 1;
+                }
+            }
+            "--stop-all" => {
+                stop_all = true;
+                idx += 1;
+            }
+            "--debug" => {
+                debug = true;
+                idx += 1;
+            }
+            "-h" | "--help" => {
+                std::process::exit(0);
+            }
+            _ => {
+                eprintln!("Error: Unknown argument: {}", args[idx]);
+                std::process::exit(1);
+            }
+        }
+    }
+
+    // Handle --stop-all shortcut
+    if stop_all {
+        command = Some(CommandType::Stop);
+        zones = vec![0]; // All zones
+    }
+
+    // Validate required arguments
+    let command = command.unwrap_or_else(|| {
+        eprintln!("Error: --command is required (use --stop-all for quick stop)");
+        std::process::exit(1);
+    });
+    
+    if zones.is_empty() {
+        eprintln!("Error: --zones is required");
+        std::process::exit(1);
+    }
+
+    // Validate command-specific requirements
+    match command {
+        CommandType::Melody | CommandType::Alarm => {
+            let melody = melody.unwrap_or_else(|| {
+                eprintln!("Error: --melody is required for {} command", command.name());
+                std::process::exit(1);
+            });
+            let volume = volume.unwrap_or_else(|| {
+                eprintln!("Error: --volume is required for {} command", command.name());
+                std::process::exit(1);
+            });
+            let repeats = repeats.unwrap_or_else(|| {
+                eprintln!("Error: --repeats is required for {} command", command.name());
+                std::process::exit(1);
+            });
+
+            // Validate ranges
+            if !(1..=30).contains(&melody) || !(1..=8).contains(&volume) || repeats > 8 {
+                eprintln!("Error: Melody (1-30), Volume (1-8), Repeats (0-8, 0=infinite)");
+                std::process::exit(1);
+            }
+
+            // Build melody/alarm packet
+            let mut packet: Vec<u8> = Vec::new();
+            packet.extend_from_slice(b"MEL");
+            packet.extend_from_slice(&0x0021u16.to_be_bytes());
+            packet.extend_from_slice(&[0x01, 0x00]);
+            packet.extend_from_slice(&[0x28, 0xff]);
+            packet.extend_from_slice(&command.code().to_be_bytes());
+            packet.extend_from_slice(&build_zone_bytes(&zones));
+            packet.extend_from_slice(&[0x00, 0x01]);
+            packet.push(volume);
+            packet.push(repeats);
+            packet.push(0x01);
+            packet.push(melody);
+            packet.extend_from_slice(&[0x01, 0x00]);
+
+            let checksum = compute_psa_checksum(&packet);
+            packet.extend_from_slice(&checksum);
+
+            if debug {
+                let hexstr = packet.iter().map(|b| format!("{:02x}", b)).collect::<Vec<_>>().join("");
+                println!("DEBUG: Packet hex: {}", hexstr);
+            }
+
+            let addr = format!("{}:{}", ip, port);
+            let sock = UdpSocket::bind("0.0.0.0:0").expect("bind failed");
+            sock.set_multicast_ttl_v4(2).ok();
+            sock.send_to(&packet, &addr).expect("send failed");
+
+            let repeat_str = if repeats == 0 { "infinite".to_string() } else { repeats.to_string() };
+            println!("Sent {} {} (vol {}, rep {}, zones {:?}) to {}", 
+                command.name(), melody, volume, repeat_str, zones, addr);
+        }
+        CommandType::Stop => {
+            // Build stop packet (different format, shorter)
+            let mut packet: Vec<u8> = Vec::new();
+            packet.extend_from_slice(b"MEL");
+            packet.extend_from_slice(&0x001bu16.to_be_bytes()); // 27 bytes for stop (to accommodate 2-byte checksum)
+            packet.extend_from_slice(&[0x01, 0x00]);
+            packet.extend_from_slice(&[0x2d, 0xff]); // Different sequence for stop
+            packet.extend_from_slice(&command.code().to_be_bytes());
+            packet.extend_from_slice(&build_zone_bytes(&zones));
+            packet.extend_from_slice(&[0x0f, 0x01]); // Different ending for stop
+
+            let checksum = compute_psa_checksum(&packet);
+            packet.extend_from_slice(&checksum); // This adds 2 bytes
+
+            if debug {
+                let hexstr = packet.iter().map(|b| format!("{:02x}", b)).collect::<Vec<_>>().join("");
+                println!("DEBUG: Packet hex: {}", hexstr);
+                println!("DEBUG: Packet length: {} bytes", packet.len());
+            }
+
+            let addr = format!("{}:{}", ip, port);
+            let sock = UdpSocket::bind("0.0.0.0:0").expect("bind failed");
+            sock.set_multicast_ttl_v4(2).ok();
+            sock.send_to(&packet, &addr).expect("send failed");
+
+            let zone_str = if zones.contains(&0) { "all zones".to_string() } else { format!("zones {:?}", zones) };
+            println!("Sent stop command to {} at {}", zone_str, addr);
+        }
+    }
+}

+ 1 - 0
target/.rustc_info.json

@@ -0,0 +1 @@
+{"rustc_fingerprint":9080434729763997184,"outputs":{"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/crt/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.87.0 (17067e9ac 2025-05-09)\nbinary: rustc\ncommit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359\ncommit-date: 2025-05-09\nhost: x86_64-unknown-linux-gnu\nrelease: 1.87.0\nLLVM version: 20.1.1\n","stderr":""}},"successes":{}}

+ 3 - 0
target/CACHEDIR.TAG

@@ -0,0 +1,3 @@
+Signature: 8a477f597d28d172789f06886806bc55
+# This file is a cache directory tag created by cargo.
+# For information about cache directory tags see https://bford.info/cachedir/

+ 0 - 0
target/release/.cargo-lock


BIN
target/release/.fingerprint/anstream-f6d94f9309fd73b0/dep-lib-anstream


+ 1 - 0
target/release/.fingerprint/anstream-f6d94f9309fd73b0/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/anstream-f6d94f9309fd73b0/lib-anstream

@@ -0,0 +1 @@
+905aeffd391826e0

+ 1 - 0
target/release/.fingerprint/anstream-f6d94f9309fd73b0/lib-anstream.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"auto\", \"default\", \"wincon\"]","declared_features":"[\"auto\", \"default\", \"test\", \"wincon\"]","target":11278316191512382530,"profile":8954424932545832044,"path":2901206268603708492,"deps":[[384403243491392785,"colorchoice",false,15871712383786249114],[6062327512194961595,"is_terminal_polyfill",false,8716633915770779825],[9394696648929125047,"anstyle",false,8703052622863714484],[11410867133969439143,"anstyle_parse",false,16326284130488385098],[12500913394773746471,"anstyle_query",false,7122211901200537983],[17716308468579268865,"utf8parse",false,3863022764234765212]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/anstream-f6d94f9309fd73b0/dep-lib-anstream","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/anstyle-df33d26d02cdc2e0/dep-lib-anstyle


+ 1 - 0
target/release/.fingerprint/anstyle-df33d26d02cdc2e0/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/anstyle-df33d26d02cdc2e0/lib-anstyle

@@ -0,0 +1 @@
+b4c852ef3f74c778

+ 1 - 0
target/release/.fingerprint/anstyle-df33d26d02cdc2e0/lib-anstyle.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"std\"]","target":6165884447290141869,"profile":8954424932545832044,"path":12870982634286915369,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/anstyle-df33d26d02cdc2e0/dep-lib-anstyle","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/anstyle-parse-f370351e5999afa9/dep-lib-anstyle_parse


+ 1 - 0
target/release/.fingerprint/anstyle-parse-f370351e5999afa9/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/anstyle-parse-f370351e5999afa9/lib-anstyle_parse

@@ -0,0 +1 @@
+4a7edb93ea9c92e2

+ 1 - 0
target/release/.fingerprint/anstyle-parse-f370351e5999afa9/lib-anstyle_parse.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"default\", \"utf8\"]","declared_features":"[\"core\", \"default\", \"utf8\"]","target":10225663410500332907,"profile":8954424932545832044,"path":12244589752717545534,"deps":[[17716308468579268865,"utf8parse",false,3863022764234765212]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/anstyle-parse-f370351e5999afa9/dep-lib-anstyle_parse","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/anstyle-query-c628055f871e4c0a/dep-lib-anstyle_query


+ 1 - 0
target/release/.fingerprint/anstyle-query-c628055f871e4c0a/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/anstyle-query-c628055f871e4c0a/lib-anstyle_query

@@ -0,0 +1 @@
+7f191e32fd2dd762

+ 1 - 0
target/release/.fingerprint/anstyle-query-c628055f871e4c0a/lib-anstyle_query.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[]","target":10705714425685373190,"profile":8954424932545832044,"path":9052957013639244514,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/anstyle-query-c628055f871e4c0a/dep-lib-anstyle_query","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

+ 1 - 0
target/release/.fingerprint/anyhow-09d4aed62c1fb11a/build-script-build-script-build

@@ -0,0 +1 @@
+45921ff998b87c92

+ 1 - 0
target/release/.fingerprint/anyhow-09d4aed62c1fb11a/build-script-build-script-build.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"default\", \"std\"]","declared_features":"[\"backtrace\", \"default\", \"std\"]","target":17883862002600103897,"profile":1369601567987815722,"path":4136796604376177105,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/anyhow-09d4aed62c1fb11a/dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/anyhow-09d4aed62c1fb11a/dep-build-script-build-script-build


+ 1 - 0
target/release/.fingerprint/anyhow-09d4aed62c1fb11a/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

BIN
target/release/.fingerprint/anyhow-3376cfee0155b40a/dep-lib-anyhow


+ 1 - 0
target/release/.fingerprint/anyhow-3376cfee0155b40a/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/anyhow-3376cfee0155b40a/lib-anyhow

@@ -0,0 +1 @@
+3e3dec29ca2ba513

+ 1 - 0
target/release/.fingerprint/anyhow-3376cfee0155b40a/lib-anyhow.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"default\", \"std\"]","declared_features":"[\"backtrace\", \"default\", \"std\"]","target":16100955855663461252,"profile":2040997289075261528,"path":12886818707430953650,"deps":[[13625485746686963219,"build_script_build",false,11553519989157515095]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/anyhow-3376cfee0155b40a/dep-lib-anyhow","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

+ 1 - 0
target/release/.fingerprint/anyhow-78d5c6c874f181a7/run-build-script-build-script-build

@@ -0,0 +1 @@
+57cf1b8b375956a0

+ 1 - 0
target/release/.fingerprint/anyhow-78d5c6c874f181a7/run-build-script-build-script-build.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[13625485746686963219,"build_script_build",false,10555514593803735621]],"local":[{"RerunIfChanged":{"output":"release/build/anyhow-78d5c6c874f181a7/output","paths":["src/nightly.rs"]}},{"RerunIfEnvChanged":{"var":"RUSTC_BOOTSTRAP","val":null}}],"rustflags":[],"config":0,"compile_kind":0}

BIN
target/release/.fingerprint/autocfg-e9f044bc3dfc814a/dep-lib-autocfg


+ 1 - 0
target/release/.fingerprint/autocfg-e9f044bc3dfc814a/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/autocfg-e9f044bc3dfc814a/lib-autocfg

@@ -0,0 +1 @@
+2f26ceabc62f89f8

+ 1 - 0
target/release/.fingerprint/autocfg-e9f044bc3dfc814a/lib-autocfg.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[]","target":6962977057026645649,"profile":1369601567987815722,"path":2441480868221750197,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/autocfg-e9f044bc3dfc814a/dep-lib-autocfg","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

+ 1 - 0
target/release/.fingerprint/be-a-sigma-2eea485e74089c5a/bin-sigma-sender

@@ -0,0 +1 @@
+b07866cbe58095d5

+ 1 - 0
target/release/.fingerprint/be-a-sigma-2eea485e74089c5a/bin-sigma-sender.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[]","target":13493997432893255396,"profile":2040997289075261528,"path":7645057555726231778,"deps":[[1441306149310335789,"tempfile",false,1536109414379784769],[4306946010298617145,"prettytable",false,16001653064770632718],[9538054652646069845,"tokio",false,14321143112549845301],[9689903380558560274,"serde",false,15392748536683949653],[11162801666473324539,"indicatif",false,3824473738306505652],[13625485746686963219,"anyhow",false,1415585805164625214],[15367738274754116744,"serde_json",false,8896238178650419897],[17791399664576300066,"clap",false,18409749504144801465]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/be-a-sigma-2eea485e74089c5a/dep-bin-sigma-sender","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/be-a-sigma-2eea485e74089c5a/dep-bin-sigma-sender


+ 1 - 0
target/release/.fingerprint/be-a-sigma-2eea485e74089c5a/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/be-a-sigma-5fe83afe34333ddf/bin-sigma-sender

@@ -0,0 +1 @@
+f0ec6bb384501504

+ 1 - 0
target/release/.fingerprint/be-a-sigma-5fe83afe34333ddf/bin-sigma-sender.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[]","target":13493997432893255396,"profile":2040997289075261528,"path":7645057555726231778,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/be-a-sigma-5fe83afe34333ddf/dep-bin-sigma-sender","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/be-a-sigma-5fe83afe34333ddf/dep-bin-sigma-sender


+ 1 - 0
target/release/.fingerprint/be-a-sigma-5fe83afe34333ddf/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/be-a-sigma-91298b959e87278c/bin-sigma-caster

@@ -0,0 +1 @@
+9bb71e3940af99a0

+ 1 - 0
target/release/.fingerprint/be-a-sigma-91298b959e87278c/bin-sigma-caster.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[]","target":12801910948334034392,"profile":2040997289075261528,"path":16974043736130609129,"deps":[[1441306149310335789,"tempfile",false,1536109414379784769],[4306946010298617145,"prettytable",false,16001653064770632718],[9538054652646069845,"tokio",false,14321143112549845301],[9689903380558560274,"serde",false,15392748536683949653],[11162801666473324539,"indicatif",false,3824473738306505652],[13625485746686963219,"anyhow",false,1415585805164625214],[15367738274754116744,"serde_json",false,8896238178650419897],[17791399664576300066,"clap",false,18409749504144801465]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/be-a-sigma-91298b959e87278c/dep-bin-sigma-caster","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/be-a-sigma-91298b959e87278c/dep-bin-sigma-caster


+ 1 - 0
target/release/.fingerprint/be-a-sigma-91298b959e87278c/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/be-a-sigma-a5038e9554af1041/bin-sigma-configurator

@@ -0,0 +1 @@
+6df8ad770443922c

+ 1 - 0
target/release/.fingerprint/be-a-sigma-a5038e9554af1041/bin-sigma-configurator.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[]","target":5662605588778059540,"profile":2040997289075261528,"path":3382323807205693883,"deps":[[1441306149310335789,"tempfile",false,1536109414379784769],[4306946010298617145,"prettytable",false,16001653064770632718],[9538054652646069845,"tokio",false,14321143112549845301],[9689903380558560274,"serde",false,15392748536683949653],[11162801666473324539,"indicatif",false,3824473738306505652],[13625485746686963219,"anyhow",false,1415585805164625214],[15367738274754116744,"serde_json",false,8896238178650419897],[17791399664576300066,"clap",false,18409749504144801465]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/be-a-sigma-a5038e9554af1041/dep-bin-sigma-configurator","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/be-a-sigma-a5038e9554af1041/dep-bin-sigma-configurator


+ 1 - 0
target/release/.fingerprint/be-a-sigma-a5038e9554af1041/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 2 - 0
target/release/.fingerprint/be-a-sigma-a5038e9554af1041/output-bin-sigma-configurator

@@ -0,0 +1,2 @@
+{"$message_type":"diagnostic","message":"function `parse_zones_from_bitfield` is never used","code":{"code":"dead_code","explanation":null},"level":"warning","spans":[{"file_name":"src/sigma-configurator.rs","byte_start":5619,"byte_end":5644,"line_start":185,"line_end":185,"column_start":4,"column_end":29,"is_primary":true,"text":[{"text":"fn parse_zones_from_bitfield(zone_data: &[u8], button_offset: usize) -> Vec<u8> {","highlight_start":4,"highlight_end":29}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"`#[warn(dead_code)]` on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: function `parse_zones_from_bitfield` is never used\u001b[0m\n\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/sigma-configurator.rs:185:4\u001b[0m\n\u001b[0m    \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m185\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mfn parse_zones_from_bitfield(zone_data: &[u8], button_offset: usize) -> Vec<u8> {\u001b[0m\n\u001b[0m    \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m    \u001b[0m\u001b[0m\u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n\u001b[0m    \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m    \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m= \u001b[0m\u001b[0m\u001b[1mnote\u001b[0m\u001b[0m: `#[warn(dead_code)]` on by default\u001b[0m\n\n"}
+{"$message_type":"diagnostic","message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"\u001b[0m\u001b[1m\u001b[33mwarning\u001b[0m\u001b[0m\u001b[1m: 1 warning emitted\u001b[0m\n\n"}

+ 1 - 0
target/release/.fingerprint/be-a-sigma-a8856d77a84f69fb/bin-sigma-caster

@@ -0,0 +1 @@
+2f2139398a12d6d3

+ 1 - 0
target/release/.fingerprint/be-a-sigma-a8856d77a84f69fb/bin-sigma-caster.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[]","target":12801910948334034392,"profile":2040997289075261528,"path":16974043736130609129,"deps":[[1441306149310335789,"tempfile",false,1536109414379784769],[9538054652646069845,"tokio",false,14321143112549845301],[11162801666473324539,"indicatif",false,3824473738306505652],[13208667028893622512,"rand",false,8144294637987063381],[13625485746686963219,"anyhow",false,1415585805164625214],[17791399664576300066,"clap",false,18409749504144801465]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/be-a-sigma-a8856d77a84f69fb/dep-bin-sigma-caster","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/be-a-sigma-a8856d77a84f69fb/dep-bin-sigma-caster


+ 1 - 0
target/release/.fingerprint/be-a-sigma-a8856d77a84f69fb/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/be-a-sigma-df93443e16b0a038/bin-sigma-sender

@@ -0,0 +1 @@
+7117457169ad1f18

+ 1 - 0
target/release/.fingerprint/be-a-sigma-df93443e16b0a038/bin-sigma-sender.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[]","target":13493997432893255396,"profile":2040997289075261528,"path":7645057555726231778,"deps":[[1441306149310335789,"tempfile",false,1536109414379784769],[9538054652646069845,"tokio",false,14321143112549845301],[11162801666473324539,"indicatif",false,3824473738306505652],[13208667028893622512,"rand",false,8144294637987063381],[13625485746686963219,"anyhow",false,1415585805164625214],[17791399664576300066,"clap",false,18409749504144801465]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/be-a-sigma-df93443e16b0a038/dep-bin-sigma-sender","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/be-a-sigma-df93443e16b0a038/dep-bin-sigma-sender


+ 1 - 0
target/release/.fingerprint/be-a-sigma-df93443e16b0a038/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

BIN
target/release/.fingerprint/bitflags-6beb487901a3ccc4/dep-lib-bitflags


+ 1 - 0
target/release/.fingerprint/bitflags-6beb487901a3ccc4/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/bitflags-6beb487901a3ccc4/lib-bitflags

@@ -0,0 +1 @@
+dc82ed2ef36ab44b

+ 1 - 0
target/release/.fingerprint/bitflags-6beb487901a3ccc4/lib-bitflags.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"std\"]","declared_features":"[\"arbitrary\", \"bytemuck\", \"compiler_builtins\", \"core\", \"example_generated\", \"rustc-dep-of-std\", \"serde\", \"std\"]","target":7691312148208718491,"profile":2040997289075261528,"path":10674047920777921947,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/bitflags-6beb487901a3ccc4/dep-lib-bitflags","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/bytes-1db977a3ac24445c/dep-lib-bytes


+ 1 - 0
target/release/.fingerprint/bytes-1db977a3ac24445c/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/bytes-1db977a3ac24445c/lib-bytes

@@ -0,0 +1 @@
+58a809647f76f155

+ 1 - 0
target/release/.fingerprint/bytes-1db977a3ac24445c/lib-bytes.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"extra-platforms\", \"serde\", \"std\"]","target":15971911772774047941,"profile":3654867079619179846,"path":6942139412234942855,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/bytes-1db977a3ac24445c/dep-lib-bytes","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/cfg-if-4d01fd75f77855dd/dep-lib-cfg_if


+ 1 - 0
target/release/.fingerprint/cfg-if-4d01fd75f77855dd/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/cfg-if-4d01fd75f77855dd/lib-cfg_if

@@ -0,0 +1 @@
+70032ac9e3e26f7d

+ 1 - 0
target/release/.fingerprint/cfg-if-4d01fd75f77855dd/lib-cfg_if.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[\"core\", \"rustc-dep-of-std\"]","target":13840298032947503755,"profile":2040997289075261528,"path":484063537917835188,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/cfg-if-4d01fd75f77855dd/dep-lib-cfg_if","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/clap-f9f2a5209892f5f5/dep-lib-clap


+ 1 - 0
target/release/.fingerprint/clap-f9f2a5209892f5f5/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/clap-f9f2a5209892f5f5/lib-clap

@@ -0,0 +1 @@
+b97e798ea2917cff

+ 1 - 0
target/release/.fingerprint/clap-f9f2a5209892f5f5/lib-clap.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"color\", \"default\", \"derive\", \"error-context\", \"help\", \"std\", \"suggestions\", \"usage\"]","declared_features":"[\"cargo\", \"color\", \"debug\", \"default\", \"deprecated\", \"derive\", \"env\", \"error-context\", \"help\", \"std\", \"string\", \"suggestions\", \"unicode\", \"unstable-derive-ui-tests\", \"unstable-doc\", \"unstable-ext\", \"unstable-markdown\", \"unstable-styles\", \"unstable-v5\", \"usage\", \"wrap_help\"]","target":4238846637535193678,"profile":9656904095642909417,"path":3300984033985562131,"deps":[[4925398738524877221,"clap_derive",false,7241690965223776893],[14814905555676593471,"clap_builder",false,10162882582536719214]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/clap-f9f2a5209892f5f5/dep-lib-clap","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/clap_builder-5004576240be5b27/dep-lib-clap_builder


+ 1 - 0
target/release/.fingerprint/clap_builder-5004576240be5b27/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/clap_builder-5004576240be5b27/lib-clap_builder

@@ -0,0 +1 @@
+6e0b1b12ddcf098d

+ 1 - 0
target/release/.fingerprint/clap_builder-5004576240be5b27/lib-clap_builder.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"color\", \"error-context\", \"help\", \"std\", \"suggestions\", \"usage\"]","declared_features":"[\"cargo\", \"color\", \"debug\", \"default\", \"deprecated\", \"env\", \"error-context\", \"help\", \"std\", \"string\", \"suggestions\", \"unicode\", \"unstable-doc\", \"unstable-ext\", \"unstable-styles\", \"unstable-v5\", \"usage\", \"wrap_help\"]","target":6917651628887788201,"profile":9656904095642909417,"path":5677055031548076543,"deps":[[5820056977320921005,"anstream",false,16151623750963387024],[9394696648929125047,"anstyle",false,8703052622863714484],[11166530783118767604,"strsim",false,17266098455121560517],[11649982696571033535,"clap_lex",false,4093901494852398760]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/clap_builder-5004576240be5b27/dep-lib-clap_builder","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/clap_derive-57e67ded68907384/dep-lib-clap_derive


+ 1 - 0
target/release/.fingerprint/clap_derive-57e67ded68907384/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/clap_derive-57e67ded68907384/lib-clap_derive

@@ -0,0 +1 @@
+7da2519390a77f64

+ 1 - 0
target/release/.fingerprint/clap_derive-57e67ded68907384/lib-clap_derive.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"default\"]","declared_features":"[\"debug\", \"default\", \"deprecated\", \"raw-deprecated\", \"unstable-markdown\", \"unstable-v5\"]","target":905583280159225126,"profile":12613628788268674035,"path":6605036977351975340,"deps":[[3060637413840920116,"proc_macro2",false,16861732738877206670],[10640660562325816595,"syn",false,304470931805471781],[13077543566650298139,"heck",false,8790729266265114872],[17990358020177143287,"quote",false,14118412858702928358]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/clap_derive-57e67ded68907384/dep-lib-clap_derive","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/clap_lex-89752eb3129de0ca/dep-lib-clap_lex


+ 1 - 0
target/release/.fingerprint/clap_lex-89752eb3129de0ca/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/clap_lex-89752eb3129de0ca/lib-clap_lex

@@ -0,0 +1 @@
+a82e1e1ab875d038

+ 1 - 0
target/release/.fingerprint/clap_lex-89752eb3129de0ca/lib-clap_lex.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[]","target":1825942688849220394,"profile":9656904095642909417,"path":10041527487311092594,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/clap_lex-89752eb3129de0ca/dep-lib-clap_lex","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/colorchoice-bb78145068569aa5/dep-lib-colorchoice


+ 1 - 0
target/release/.fingerprint/colorchoice-bb78145068569aa5/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/colorchoice-bb78145068569aa5/lib-colorchoice

@@ -0,0 +1 @@
+9a6bbf3452a643dc

+ 1 - 0
target/release/.fingerprint/colorchoice-bb78145068569aa5/lib-colorchoice.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[]","declared_features":"[]","target":11187303652147478063,"profile":8954424932545832044,"path":1508502171116990164,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/colorchoice-bb78145068569aa5/dep-lib-colorchoice","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

BIN
target/release/.fingerprint/console-1ef8193328fdd4a5/dep-lib-console


+ 1 - 0
target/release/.fingerprint/console-1ef8193328fdd4a5/invoked.timestamp

@@ -0,0 +1 @@
+This file has an mtime of when this was started.

+ 1 - 0
target/release/.fingerprint/console-1ef8193328fdd4a5/lib-console

@@ -0,0 +1 @@
+90ff124d790d4ab9

+ 1 - 0
target/release/.fingerprint/console-1ef8193328fdd4a5/lib-console.json

@@ -0,0 +1 @@
+{"rustc":15597765236515928571,"features":"[\"ansi-parsing\", \"unicode-width\"]","declared_features":"[\"ansi-parsing\", \"default\", \"unicode-width\", \"windows-console-colors\"]","target":7600203407108534355,"profile":2040997289075261528,"path":15653462087130946657,"deps":[[3722963349756955755,"once_cell",false,151808272711995150],[4684437522915235464,"libc",false,9013915164904907270],[13774335185398496026,"unicode_width",false,10417195949652992169]],"local":[{"CheckDepInfo":{"dep_info":"release/.fingerprint/console-1ef8193328fdd4a5/dep-lib-console","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.